]> git.kernelconcepts.de Git - karo-tx-linux.git/commitdiff
Merge tag 'staging-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh...
authorLinus Torvalds <torvalds@linux-foundation.org>
Sat, 1 Feb 2014 18:29:59 +0000 (10:29 -0800)
committerLinus Torvalds <torvalds@linux-foundation.org>
Sat, 1 Feb 2014 18:29:59 +0000 (10:29 -0800)
Pull rtl8812ae staging wireless driver from Greg KH:
 "Here's a single staging driver for a wireless chipset that has shown
  up in the SteamBox hardware.  It is merged separately from the "main"
  staging pull request to sync up with the wireless api changes that
  came in from the networking tree.

  It's self-contained and works for me and others.  Larry will be
  replacing it with a "real" driver for 3.15, but for now this one is
  needed"

* tag 'staging-3.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/staging:
  staging: r8821ae: Enable build by reverting BROKEN marking
  staging: r8821ae: Fix build problems
  Staging: rtl8812ae: disable due to build errors
  Staging: rtl8821ae: add TODO file
  Staging: rtl8821ae: removed unused functions and variables
  Staging: rtl8821ae: rc.c: fix up function prototypes
  Staging: rtl8812ae: Add Realtek 8821 PCI WIFI driver

2661 files changed:
CREDITS
Documentation/ABI/testing/configfs-usb-gadget
Documentation/ABI/testing/configfs-usb-gadget-acm
Documentation/ABI/testing/configfs-usb-gadget-ecm
Documentation/ABI/testing/configfs-usb-gadget-eem
Documentation/ABI/testing/configfs-usb-gadget-ffs
Documentation/ABI/testing/configfs-usb-gadget-loopback
Documentation/ABI/testing/configfs-usb-gadget-mass-storage
Documentation/ABI/testing/configfs-usb-gadget-ncm
Documentation/ABI/testing/configfs-usb-gadget-obex
Documentation/ABI/testing/configfs-usb-gadget-phonet
Documentation/ABI/testing/configfs-usb-gadget-rndis
Documentation/ABI/testing/configfs-usb-gadget-serial
Documentation/ABI/testing/configfs-usb-gadget-sourcesink
Documentation/ABI/testing/configfs-usb-gadget-subset
Documentation/ABI/testing/sysfs-bus-rbd
Documentation/DocBook/media/v4l/compat.xml
Documentation/DocBook/media/v4l/controls.xml
Documentation/DocBook/media/v4l/dev-overlay.xml
Documentation/DocBook/media/v4l/media-ioc-enum-links.xml
Documentation/DocBook/media/v4l/subdev-formats.xml
Documentation/DocBook/media/v4l/v4l2.xml
Documentation/DocBook/media/v4l/vidioc-cropcap.xml
Documentation/DocBook/media/v4l/vidioc-streamon.xml
Documentation/block/biodoc.txt
Documentation/block/biovecs.txt [new file with mode: 0644]
Documentation/blockdev/zram.txt [moved from drivers/staging/zram/zram.txt with 90% similarity]
Documentation/cgroups/resource_counter.txt
Documentation/debugging-via-ohci1394.txt
Documentation/devicetree/bindings/arm/bcm/kona-timer.txt
Documentation/devicetree/bindings/arm/davinci/nand.txt [deleted file]
Documentation/devicetree/bindings/clock/bcm-kona-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/corenet-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/apll.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/autoidle.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/clockdomain.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/composite.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/divider.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/dpll.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/fixed-factor-clock.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/gate.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/interface.txt [new file with mode: 0644]
Documentation/devicetree/bindings/clock/ti/mux.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/bcm2835-dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/dma/fsl-imx-sdma.txt
Documentation/devicetree/bindings/dma/moxa,moxart-dma.txt [new file with mode: 0644]
Documentation/devicetree/bindings/gpu/nvidia,tegra20-host1x.txt
Documentation/devicetree/bindings/leds/tca6507.txt
Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt [new file with mode: 0644]
Documentation/devicetree/bindings/media/samsung-s5k5baf.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mmc/kona-sdhci.txt
Documentation/devicetree/bindings/mtd/davinci-nand.txt [new file with mode: 0644]
Documentation/devicetree/bindings/mtd/gpmi-nand.txt
Documentation/devicetree/bindings/mtd/pxa3xx-nand.txt
Documentation/devicetree/bindings/net/davinci_emac.txt
Documentation/devicetree/bindings/panel/auo,b101aw03.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/chunghwa,claa101wa01a.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/samsung,ltn101nt05.txt [new file with mode: 0644]
Documentation/devicetree/bindings/panel/simple-panel.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/atmel-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/pwm/pxa-pwm.txt [new file with mode: 0644]
Documentation/devicetree/bindings/sound/simple-card.txt
Documentation/devicetree/bindings/video/ssd1289fb.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/atmel-wdt.txt
Documentation/devicetree/bindings/watchdog/davinci-wdt.txt
Documentation/devicetree/bindings/watchdog/gpio-wdt.txt [new file with mode: 0644]
Documentation/devicetree/bindings/watchdog/samsung-wdt.txt
Documentation/filesystems/btrfs.txt
Documentation/filesystems/nfs/nfs41-server.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/vfs.txt
Documentation/hwmon/adm1025
Documentation/hwmon/adm1031
Documentation/hwmon/adm9240
Documentation/hwmon/ds1621
Documentation/hwmon/emc6w201
Documentation/hwmon/f71805f
Documentation/hwmon/gl518sm
Documentation/hwmon/it87
Documentation/hwmon/lm63
Documentation/hwmon/lm70
Documentation/hwmon/lm78
Documentation/hwmon/lm83
Documentation/hwmon/lm87
Documentation/hwmon/lm90
Documentation/hwmon/lm92
Documentation/hwmon/max1619
Documentation/hwmon/pc87360
Documentation/hwmon/pc87427
Documentation/hwmon/pcf8591
Documentation/hwmon/smsc47m1
Documentation/hwmon/w83627ehf
Documentation/hwmon/w83795
Documentation/hwmon/w83l785ts
Documentation/i2c/busses/i2c-i801
Documentation/i2c/busses/i2c-parport
Documentation/i2c/busses/i2c-parport-light
Documentation/i2c/busses/i2c-piix4
Documentation/i2c/busses/i2c-taos-evm
Documentation/i2c/busses/i2c-viapro
Documentation/ioctl/ioctl-number.txt
Documentation/kernel-parameters.txt
Documentation/kmsg/s390/zcrypt [deleted file]
Documentation/leds/leds-lp55xx.txt
Documentation/misc-devices/eeprom
Documentation/mtd/nand/pxa3xx-nand.txt [new file with mode: 0644]
Documentation/networking/ip-sysctl.txt
Documentation/networking/packet_mmap.txt
Documentation/power/basic-pm-debugging.txt
Documentation/scheduler/00-INDEX
Documentation/scheduler/sched-deadline.txt [new file with mode: 0644]
Documentation/sysctl/kernel.txt
Documentation/sysctl/vm.txt
Documentation/video4linux/omap4_camera.txt [new file with mode: 0644]
Documentation/video4linux/si476x.txt
Documentation/virtual/kvm/api.txt
MAINTAINERS
Makefile
arch/alpha/Kconfig
arch/alpha/include/asm/ptrace.h
arch/alpha/include/asm/thread_info.h
arch/alpha/kernel/Makefile
arch/alpha/kernel/audit.c [new file with mode: 0644]
arch/alpha/kernel/entry.S
arch/alpha/kernel/ptrace.c
arch/alpha/lib/csum_partial_copy.c
arch/arc/include/asm/linkage.h
arch/arm/Kconfig
arch/arm/Makefile
arch/arm/boot/dts/Makefile
arch/arm/boot/dts/am33xx-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/am33xx.dtsi
arch/arm/boot/dts/am3517.dtsi
arch/arm/boot/dts/am35xx-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/am4372.dtsi
arch/arm/boot/dts/am43xx-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/at91sam9260.dtsi
arch/arm/boot/dts/at91sam9263.dtsi
arch/arm/boot/dts/at91sam9g45.dtsi
arch/arm/boot/dts/at91sam9n12.dtsi
arch/arm/boot/dts/at91sam9x5.dtsi
arch/arm/boot/dts/bcm11351-brt.dts
arch/arm/boot/dts/bcm11351.dtsi
arch/arm/boot/dts/bcm28155-ap.dts
arch/arm/boot/dts/dra7.dtsi
arch/arm/boot/dts/dra7xx-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6dl-cubox-i.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6dl-hummingboard.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6q-cubox-i.dts [new file with mode: 0644]
arch/arm/boot/dts/imx6qdl-cubox-i.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi [new file with mode: 0644]
arch/arm/boot/dts/imx6qdl-microsom.dtsi [new file with mode: 0644]
arch/arm/boot/dts/kizbox.dts
arch/arm/boot/dts/moxart-uc7112lx.dts
arch/arm/boot/dts/moxart.dtsi
arch/arm/boot/dts/omap3.dtsi
arch/arm/boot/dts/omap3430es1-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap34xx.dtsi
arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap36xx-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap36xx.dtsi
arch/arm/boot/dts/omap3xxx-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap4.dtsi
arch/arm/boot/dts/omap443x-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap443x.dtsi
arch/arm/boot/dts/omap4460.dtsi
arch/arm/boot/dts/omap446x-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap44xx-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/omap5.dtsi
arch/arm/boot/dts/omap54xx-clocks.dtsi [new file with mode: 0644]
arch/arm/boot/dts/sama5d3.dtsi
arch/arm/configs/bcm_defconfig
arch/arm/include/asm/io.h
arch/arm/kernel/entry-armv.S
arch/arm/kernel/head.S
arch/arm/kernel/io.c
arch/arm/kernel/setup.c
arch/arm/mach-imx/mach-imx6q.c
arch/arm/mach-imx/mach-mx31moboard.c
arch/arm/mach-omap2/Kconfig
arch/arm/mach-omap2/Makefile
arch/arm/mach-omap2/board-rx51-peripherals.c
arch/arm/mach-omap2/cclock33xx_data.c [deleted file]
arch/arm/mach-omap2/cclock44xx_data.c [deleted file]
arch/arm/mach-omap2/clkt_clksel.c
arch/arm/mach-omap2/clkt_dpll.c
arch/arm/mach-omap2/clkt_iclk.c
arch/arm/mach-omap2/clock.c
arch/arm/mach-omap2/clock.h
arch/arm/mach-omap2/clock36xx.c
arch/arm/mach-omap2/clock3xxx.h
arch/arm/mach-omap2/common.h
arch/arm/mach-omap2/dpll3xxx.c
arch/arm/mach-omap2/dpll44xx.c
arch/arm/mach-omap2/io.c
arch/arm/mach-omap2/omap_hwmod.c
arch/arm/mach-omap2/prm.h
arch/arm/mach-omap2/prm_common.c
arch/arm/mach-omap2/timer.c
arch/arm/mm/init.c
arch/arm/plat-samsung/include/plat/regs-nand.h [deleted file]
arch/arm/xen/enlighten.c
arch/arm64/include/asm/dma-contiguous.h
arch/arm64/include/asm/pgtable.h
arch/arm64/kernel/process.c
arch/arm64/kernel/smp.c
arch/arm64/kernel/suspend.c
arch/arm64/mm/cache.S
arch/arm64/mm/proc-macros.S
arch/arm64/mm/proc.S
arch/blackfin/configs/BF527-EZKIT_defconfig
arch/blackfin/configs/BF538-EZKIT_defconfig
arch/blackfin/configs/BF561-ACVILON_defconfig
arch/blackfin/configs/BlackStamp_defconfig
arch/blackfin/configs/CM-BF533_defconfig
arch/blackfin/configs/CM-BF548_defconfig
arch/blackfin/configs/CM-BF561_defconfig
arch/blackfin/configs/DNP5370_defconfig
arch/blackfin/configs/H8606_defconfig
arch/blackfin/configs/IP0X_defconfig
arch/blackfin/configs/PNAV-10_defconfig
arch/blackfin/configs/SRV1_defconfig
arch/blackfin/configs/TCM-BF518_defconfig
arch/blackfin/include/asm/def_LPBlackfin.h
arch/blackfin/include/uapi/asm/byteorder.h
arch/blackfin/include/uapi/asm/cachectl.h
arch/blackfin/include/uapi/asm/fcntl.h
arch/blackfin/include/uapi/asm/ioctls.h
arch/blackfin/include/uapi/asm/poll.h
arch/blackfin/include/uapi/asm/posix_types.h
arch/blackfin/include/uapi/asm/sigcontext.h
arch/blackfin/include/uapi/asm/siginfo.h
arch/blackfin/include/uapi/asm/signal.h
arch/blackfin/include/uapi/asm/stat.h
arch/blackfin/include/uapi/asm/swab.h
arch/blackfin/kernel/setup.c
arch/blackfin/mach-bf533/boards/stamp.c
arch/blackfin/mach-bf609/Kconfig
arch/blackfin/mach-bf609/boards/ezkit.c
arch/blackfin/mach-bf609/clock.c
arch/blackfin/mach-bf609/include/mach/anomaly.h
arch/blackfin/mach-common/cache-c.c
arch/blackfin/mach-common/clocks-init.c
arch/blackfin/mach-common/ints-priority.c
arch/blackfin/mach-common/scb-init.c
arch/blackfin/mach-common/smp.c
arch/cris/Kconfig
arch/cris/arch-v10/drivers/gpio.c
arch/cris/arch-v10/drivers/sync_serial.c
arch/cris/arch-v10/kernel/Makefile
arch/cris/arch-v10/kernel/debugport.c
arch/cris/arch-v10/kernel/entry.S
arch/cris/arch-v10/kernel/head.S
arch/cris/arch-v10/kernel/irq.c
arch/cris/arch-v10/kernel/process.c
arch/cris/arch-v10/kernel/time.c
arch/cris/arch-v10/lib/dram_init.S
arch/cris/arch-v32/drivers/axisflashmap.c
arch/cris/arch-v32/drivers/mach-a3/gpio.c
arch/cris/arch-v32/drivers/mach-fs/gpio.c
arch/cris/arch-v32/drivers/sync_serial.c
arch/cris/arch-v32/kernel/entry.S
arch/cris/arch-v32/kernel/fasttimer.c
arch/cris/arch-v32/kernel/irq.c
arch/cris/arch-v32/kernel/smp.c
arch/cris/arch-v32/kernel/time.c
arch/cris/arch-v32/mach-a3/arbiter.c
arch/cris/arch-v32/mach-fs/arbiter.c
arch/cris/boot/rescue/kimagerescue.S
arch/cris/include/arch-v10/arch/io.h
arch/cris/include/arch-v10/arch/irq.h
arch/cris/include/arch-v32/arch/irq.h
arch/cris/include/asm/unistd.h
arch/cris/include/uapi/asm/unistd.h
arch/cris/kernel/irq.c
arch/frv/Makefile
arch/m68k/emu/nfblock.c
arch/microblaze/Kconfig
arch/microblaze/Makefile
arch/microblaze/include/asm/cpuinfo.h
arch/microblaze/include/asm/io.h
arch/microblaze/include/asm/sections.h
arch/microblaze/include/uapi/asm/Kbuild
arch/microblaze/include/uapi/asm/types.h [deleted file]
arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c
arch/microblaze/kernel/cpu/cpuinfo-static.c
arch/microblaze/kernel/cpu/cpuinfo.c
arch/microblaze/kernel/head.S
arch/microblaze/kernel/hw_exception_handler.S
arch/microblaze/kernel/setup.c
arch/microblaze/kernel/timer.c
arch/microblaze/kernel/vmlinux.lds.S
arch/mips/Kconfig
arch/mips/Makefile
arch/mips/alchemy/common/power.c
arch/mips/ar7/time.c
arch/mips/ath79/common.h
arch/mips/bcm47xx/Kconfig
arch/mips/bcm47xx/Makefile
arch/mips/bcm47xx/bcm47xx_private.h [new file with mode: 0644]
arch/mips/bcm47xx/board.c
arch/mips/bcm47xx/buttons.c [new file with mode: 0644]
arch/mips/bcm47xx/irq.c
arch/mips/bcm47xx/leds.c [new file with mode: 0644]
arch/mips/bcm47xx/nvram.c
arch/mips/bcm47xx/prom.c
arch/mips/bcm47xx/serial.c
arch/mips/bcm47xx/setup.c
arch/mips/bcm47xx/sprom.c
arch/mips/bcm47xx/wgt634u.c [deleted file]
arch/mips/bcm63xx/Kconfig
arch/mips/bcm63xx/Makefile
arch/mips/bcm63xx/boards/board_bcm963xx.c
arch/mips/bcm63xx/clk.c
arch/mips/bcm63xx/cpu.c
arch/mips/bcm63xx/dev-hsspi.c [new file with mode: 0644]
arch/mips/bcm63xx/early_printk.c
arch/mips/bcm63xx/prom.c
arch/mips/boot/compressed/Makefile
arch/mips/boot/compressed/dbg.c
arch/mips/boot/compressed/decompress.c
arch/mips/boot/compressed/string.c [new file with mode: 0644]
arch/mips/boot/compressed/uart-16550.c
arch/mips/cavium-octeon/executive/cvmx-cmd-queue.c
arch/mips/cavium-octeon/executive/cvmx-helper-board.c
arch/mips/cavium-octeon/executive/cvmx-helper-util.c
arch/mips/cavium-octeon/executive/cvmx-helper.c
arch/mips/cavium-octeon/executive/cvmx-pko.c
arch/mips/cavium-octeon/executive/cvmx-spi.c
arch/mips/cavium-octeon/octeon-platform.c
arch/mips/cavium-octeon/octeon_3xxx.dts
arch/mips/cavium-octeon/smp.c
arch/mips/configs/ar7_defconfig
arch/mips/configs/bcm47xx_defconfig
arch/mips/configs/bcm63xx_defconfig
arch/mips/configs/cobalt_defconfig
arch/mips/configs/gpr_defconfig
arch/mips/configs/jmr3927_defconfig
arch/mips/configs/lasat_defconfig
arch/mips/configs/maltasmvp_defconfig
arch/mips/configs/markeins_defconfig
arch/mips/configs/mtx1_defconfig
arch/mips/configs/pnx8335_stb225_defconfig
arch/mips/configs/qi_lb60_defconfig [new file with mode: 0644]
arch/mips/configs/rb532_defconfig
arch/mips/configs/rbtx49xx_defconfig
arch/mips/fw/arc/file.c
arch/mips/include/asm/amon.h
arch/mips/include/asm/asmmacro-32.h
arch/mips/include/asm/asmmacro-64.h
arch/mips/include/asm/asmmacro.h
arch/mips/include/asm/bmips.h
arch/mips/include/asm/cpu-features.h
arch/mips/include/asm/cpu-info.h
arch/mips/include/asm/cpu-type.h
arch/mips/include/asm/cpu.h
arch/mips/include/asm/dma-coherence.h
arch/mips/include/asm/elf.h
arch/mips/include/asm/fpu.h
arch/mips/include/asm/highmem.h
arch/mips/include/asm/kvm_host.h
arch/mips/include/asm/mach-ath79/ar71xx_regs.h
arch/mips/include/asm/mach-bcm47xx/bcm47xx.h
arch/mips/include/asm/mach-bcm47xx/bcm47xx_board.h
arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h [new file with mode: 0644]
arch/mips/include/asm/mach-bcm63xx/bcm63xx_cpu.h
arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_hsspi.h [new file with mode: 0644]
arch/mips/include/asm/mach-bcm63xx/bcm63xx_regs.h
arch/mips/include/asm/mach-generic/dma-coherence.h
arch/mips/include/asm/mach-generic/floppy.h
arch/mips/include/asm/mach-generic/ide.h
arch/mips/include/asm/mach-jazz/floppy.h
arch/mips/include/asm/mach-jz4740/platform.h
arch/mips/include/asm/mach-netlogic/irq.h
arch/mips/include/asm/mach-netlogic/multi-node.h
arch/mips/include/asm/mach-netlogic/topology.h [new file with mode: 0644]
arch/mips/include/asm/mips-boards/piix4.h
arch/mips/include/asm/mipsregs.h
arch/mips/include/asm/netlogic/common.h
arch/mips/include/asm/netlogic/mips-extns.h
arch/mips/include/asm/netlogic/xlp-hal/bridge.h
arch/mips/include/asm/netlogic/xlp-hal/iomap.h
arch/mips/include/asm/netlogic/xlp-hal/pcibus.h
arch/mips/include/asm/netlogic/xlp-hal/pic.h
arch/mips/include/asm/netlogic/xlp-hal/sys.h
arch/mips/include/asm/netlogic/xlp-hal/uart.h
arch/mips/include/asm/netlogic/xlp-hal/xlp.h
arch/mips/include/asm/netlogic/xlr/xlr.h
arch/mips/include/asm/octeon/cvmx-helper-board.h
arch/mips/include/asm/page.h
arch/mips/include/asm/rtlx.h
arch/mips/include/asm/switch_to.h
arch/mips/include/asm/syscall.h
arch/mips/include/asm/thread_info.h
arch/mips/include/asm/tlb.h
arch/mips/include/asm/vpe.h
arch/mips/include/uapi/asm/inst.h
arch/mips/jz4740/board-qi_lb60.c
arch/mips/jz4740/platform.c
arch/mips/kernel/Makefile
arch/mips/kernel/binfmt_elfo32.c
arch/mips/kernel/bmips_vec.S
arch/mips/kernel/cpu-probe.c
arch/mips/kernel/crash.c
arch/mips/kernel/genex.S
arch/mips/kernel/idle.c
arch/mips/kernel/proc.c
arch/mips/kernel/process.c
arch/mips/kernel/ptrace.c
arch/mips/kernel/ptrace32.c
arch/mips/kernel/r4k_fpu.S
arch/mips/kernel/r4k_switch.S
arch/mips/kernel/rtlx-cmp.c [new file with mode: 0644]
arch/mips/kernel/rtlx-mt.c [new file with mode: 0644]
arch/mips/kernel/rtlx.c
arch/mips/kernel/segment.c [new file with mode: 0644]
arch/mips/kernel/signal.c
arch/mips/kernel/signal32.c
arch/mips/kernel/smp-bmips.c
arch/mips/kernel/smp-cmp.c
arch/mips/kernel/smp-mt.c
arch/mips/kernel/spram.c
arch/mips/kernel/sync-r4k.c
arch/mips/kernel/traps.c
arch/mips/kernel/vpe-cmp.c [new file with mode: 0644]
arch/mips/kernel/vpe-mt.c [new file with mode: 0644]
arch/mips/kernel/vpe.c
arch/mips/kvm/kvm_mips.c
arch/mips/kvm/kvm_tlb.c
arch/mips/lantiq/xway/clk.c
arch/mips/lantiq/xway/dma.c
arch/mips/lasat/at93c.c
arch/mips/lasat/picvue.c
arch/mips/lib/uncached.c
arch/mips/loongson/lemote-2f/clock.c
arch/mips/math-emu/cp1emu.c
arch/mips/math-emu/kernel_linkage.c
arch/mips/mm/c-octeon.c
arch/mips/mm/c-r3k.c
arch/mips/mm/c-r4k.c
arch/mips/mm/cache.c
arch/mips/mm/cex-sb1.S
arch/mips/mm/dma-default.c
arch/mips/mm/hugetlbpage.c
arch/mips/mm/init.c
arch/mips/mm/page.c
arch/mips/mm/sc-mips.c
arch/mips/mm/sc-rm7k.c
arch/mips/mm/tlb-r3k.c
arch/mips/mm/tlb-r4k.c
arch/mips/mm/tlb-r8k.c
arch/mips/mm/tlbex.c
arch/mips/mm/uasm-micromips.c
arch/mips/mm/uasm-mips.c
arch/mips/mti-malta/Makefile
arch/mips/mti-malta/malta-amon.c
arch/mips/mti-malta/malta-console.c [deleted file]
arch/mips/mti-malta/malta-init.c
arch/mips/mti-malta/malta-int.c
arch/mips/mti-malta/malta-platform.c
arch/mips/mti-malta/malta-time.c
arch/mips/mti-sead3/Makefile
arch/mips/mti-sead3/sead3-pic32-bus.c
arch/mips/mti-sead3/sead3-setup.c
arch/mips/mti-sead3/sead3-time.c
arch/mips/mti-sead3/sead3.dts
arch/mips/netlogic/Kconfig
arch/mips/netlogic/common/earlycons.c
arch/mips/netlogic/common/irq.c
arch/mips/netlogic/common/reset.S
arch/mips/netlogic/common/smp.c
arch/mips/netlogic/common/smpboot.S
arch/mips/netlogic/dts/Makefile
arch/mips/netlogic/dts/xlp_gvp.dts [new file with mode: 0644]
arch/mips/netlogic/xlp/dt.c
arch/mips/netlogic/xlp/nlm_hal.c
arch/mips/netlogic/xlp/setup.c
arch/mips/netlogic/xlp/usb-init-xlp2.c
arch/mips/netlogic/xlp/wakeup.c
arch/mips/netlogic/xlr/platform.c
arch/mips/netlogic/xlr/setup.c
arch/mips/netlogic/xlr/wakeup.c
arch/mips/oprofile/common.c
arch/mips/oprofile/op_model_mipsxx.c
arch/mips/pci/Makefile
arch/mips/pci/fixup-malta.c
arch/mips/pci/fixup-rc32434.c
arch/mips/pci/fixup-sb1250.c
arch/mips/pci/msi-xlp.c [new file with mode: 0644]
arch/mips/pci/ops-bcm63xx.c
arch/mips/pci/ops-bonito64.c
arch/mips/pci/ops-lantiq.c
arch/mips/pci/ops-loongson2.c
arch/mips/pci/ops-mace.c
arch/mips/pci/ops-msc.c
arch/mips/pci/ops-nile4.c
arch/mips/pci/ops-rc32434.c
arch/mips/pci/pci-ip27.c
arch/mips/pci/pci-malta.c
arch/mips/pci/pci-rt3883.c
arch/mips/pci/pci-xlp.c
arch/mips/pmcs-msp71xx/Kconfig
arch/mips/ralink/Kconfig
arch/mips/sgi-ip27/ip27-console.c
arch/mips/sgi-ip27/ip27-irq-pci.c
arch/mips/sgi-ip27/ip27-klconfig.c
arch/mips/sgi-ip27/ip27-xtalk.c
arch/mn10300/Makefile
arch/openrisc/kernel/entry.S
arch/openrisc/kernel/signal.c
arch/powerpc/Kconfig
arch/powerpc/boot/.gitignore
arch/powerpc/boot/Makefile
arch/powerpc/boot/dts/ac14xx.dts
arch/powerpc/boot/dts/fsl/elo3-dma-2.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/fsl/p1020si-post.dtsi
arch/powerpc/boot/dts/fsl/p1021si-post.dtsi
arch/powerpc/boot/dts/fsl/p1022si-post.dtsi
arch/powerpc/boot/dts/fsl/p1023si-post.dtsi
arch/powerpc/boot/dts/kilauea.dts
arch/powerpc/boot/dts/mpc5121.dtsi
arch/powerpc/boot/dts/mpc5125twr.dts
arch/powerpc/boot/dts/mvme5100.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1010rdb-pa.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1010rdb-pa.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/p1010rdb-pa_36b.dts [moved from arch/powerpc/boot/dts/p1010rdb_36b.dts with 64% similarity]
arch/powerpc/boot/dts/p1010rdb-pb.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1010rdb-pb_36b.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1010rdb.dts [deleted file]
arch/powerpc/boot/dts/p1010rdb.dtsi
arch/powerpc/boot/dts/p1010rdb_32b.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/p1010rdb_36b.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/p1022ds.dtsi
arch/powerpc/boot/dts/p1025twr.dts [new file with mode: 0644]
arch/powerpc/boot/dts/p1025twr.dtsi [new file with mode: 0644]
arch/powerpc/boot/dts/virtex440-ml507.dts
arch/powerpc/boot/mvme5100.c [new file with mode: 0644]
arch/powerpc/boot/wrapper
arch/powerpc/configs/85xx/p1023_defconfig [deleted file]
arch/powerpc/configs/adder875_defconfig
arch/powerpc/configs/ep88xc_defconfig
arch/powerpc/configs/mpc85xx_defconfig
arch/powerpc/configs/mpc85xx_smp_defconfig
arch/powerpc/configs/mpc866_ads_defconfig
arch/powerpc/configs/mpc885_ads_defconfig
arch/powerpc/configs/mvme5100_defconfig [new file with mode: 0644]
arch/powerpc/configs/ppc64_defconfig
arch/powerpc/configs/tqm8xx_defconfig
arch/powerpc/include/asm/bitops.h
arch/powerpc/include/asm/cache.h
arch/powerpc/include/asm/clk_interface.h [deleted file]
arch/powerpc/include/asm/cmpxchg.h
arch/powerpc/include/asm/code-patching.h
arch/powerpc/include/asm/cputable.h
arch/powerpc/include/asm/eeh.h
arch/powerpc/include/asm/epapr_hcalls.h
arch/powerpc/include/asm/exception-64s.h
arch/powerpc/include/asm/fsl_lbc.h
arch/powerpc/include/asm/hardirq.h
arch/powerpc/include/asm/io.h
arch/powerpc/include/asm/iommu.h
arch/powerpc/include/asm/kvm_asm.h
arch/powerpc/include/asm/kvm_book3s.h
arch/powerpc/include/asm/kvm_book3s_asm.h
arch/powerpc/include/asm/kvm_booke.h
arch/powerpc/include/asm/kvm_host.h
arch/powerpc/include/asm/kvm_para.h
arch/powerpc/include/asm/kvm_ppc.h
arch/powerpc/include/asm/lppaca.h
arch/powerpc/include/asm/mce.h [new file with mode: 0644]
arch/powerpc/include/asm/mmu-book3e.h
arch/powerpc/include/asm/mmu.h
arch/powerpc/include/asm/mpc5121.h
arch/powerpc/include/asm/opal.h
arch/powerpc/include/asm/paca.h
arch/powerpc/include/asm/pgtable-ppc64.h
arch/powerpc/include/asm/pgtable.h
arch/powerpc/include/asm/ppc_asm.h
arch/powerpc/include/asm/processor.h
arch/powerpc/include/asm/ps3.h
arch/powerpc/include/asm/pte-hash64.h
arch/powerpc/include/asm/reg.h
arch/powerpc/include/asm/reg_booke.h
arch/powerpc/include/asm/spinlock.h
arch/powerpc/include/asm/switch_to.h
arch/powerpc/include/asm/systbl.h
arch/powerpc/include/asm/thread_info.h
arch/powerpc/include/asm/tm.h
arch/powerpc/include/asm/topology.h
arch/powerpc/include/asm/unistd.h
arch/powerpc/include/asm/vio.h
arch/powerpc/include/uapi/asm/kvm.h
arch/powerpc/include/uapi/asm/tm.h
arch/powerpc/include/uapi/asm/unistd.h
arch/powerpc/kernel/Makefile
arch/powerpc/kernel/asm-offsets.c
arch/powerpc/kernel/cacheinfo.c
arch/powerpc/kernel/clock.c [deleted file]
arch/powerpc/kernel/cpu_setup_fsl_booke.S
arch/powerpc/kernel/cpu_setup_power.S
arch/powerpc/kernel/cputable.c
arch/powerpc/kernel/crash.c
arch/powerpc/kernel/dma-iommu.c
arch/powerpc/kernel/eeh.c
arch/powerpc/kernel/eeh_driver.c
arch/powerpc/kernel/eeh_pe.c
arch/powerpc/kernel/entry_64.S
arch/powerpc/kernel/exceptions-64e.S
arch/powerpc/kernel/exceptions-64s.S
arch/powerpc/kernel/fpu.S
arch/powerpc/kernel/fsl_booke_entry_mapping.S
arch/powerpc/kernel/head_64.S
arch/powerpc/kernel/head_fsl_booke.S
arch/powerpc/kernel/hw_breakpoint.c
arch/powerpc/kernel/idle_power7.S
arch/powerpc/kernel/iomap.c
arch/powerpc/kernel/iommu.c
arch/powerpc/kernel/irq.c
arch/powerpc/kernel/kgdb.c
arch/powerpc/kernel/kvm.c
arch/powerpc/kernel/mce.c [new file with mode: 0644]
arch/powerpc/kernel/mce_power.c [new file with mode: 0644]
arch/powerpc/kernel/misc_32.S
arch/powerpc/kernel/misc_64.S
arch/powerpc/kernel/paca.c
arch/powerpc/kernel/process.c
arch/powerpc/kernel/prom.c
arch/powerpc/kernel/setup_64.c
arch/powerpc/kernel/signal.c
arch/powerpc/kernel/signal_32.c
arch/powerpc/kernel/signal_64.c
arch/powerpc/kernel/smp-tbsync.c
arch/powerpc/kernel/smp.c
arch/powerpc/kernel/swsusp_booke.S
arch/powerpc/kernel/syscalls.c
arch/powerpc/kernel/sysfs.c
arch/powerpc/kernel/time.c
arch/powerpc/kernel/traps.c
arch/powerpc/kernel/vdso32/vdso32_wrapper.S
arch/powerpc/kernel/vdso64/vdso64_wrapper.S
arch/powerpc/kernel/vector.S
arch/powerpc/kernel/vio.c
arch/powerpc/kvm/44x.c
arch/powerpc/kvm/book3s.c
arch/powerpc/kvm/book3s_32_mmu_host.c
arch/powerpc/kvm/book3s_64_mmu_hv.c
arch/powerpc/kvm/book3s_exports.c
arch/powerpc/kvm/book3s_hv.c
arch/powerpc/kvm/book3s_hv_interrupts.S
arch/powerpc/kvm/book3s_hv_ras.c
arch/powerpc/kvm/book3s_hv_rm_mmu.c
arch/powerpc/kvm/book3s_hv_rmhandlers.S
arch/powerpc/kvm/book3s_paired_singles.c
arch/powerpc/kvm/book3s_pr.c
arch/powerpc/kvm/book3s_rmhandlers.S
arch/powerpc/kvm/book3s_segment.S
arch/powerpc/kvm/book3s_xics.c
arch/powerpc/kvm/booke.c
arch/powerpc/kvm/booke.h
arch/powerpc/kvm/bookehv_interrupts.S
arch/powerpc/kvm/e500.c
arch/powerpc/kvm/e500.h
arch/powerpc/kvm/e500_mmu.c
arch/powerpc/kvm/e500_mmu_host.c
arch/powerpc/kvm/e500mc.c
arch/powerpc/kvm/emulate.c
arch/powerpc/kvm/mpic.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/lib/code-patching.c
arch/powerpc/lib/crtsavres.S
arch/powerpc/math-emu/math_efp.c
arch/powerpc/mm/fsl_booke_mmu.c
arch/powerpc/mm/hash_low_64.S
arch/powerpc/mm/hash_utils_64.c
arch/powerpc/mm/hugepage-hash64.c
arch/powerpc/mm/hugetlbpage-book3e.c
arch/powerpc/mm/hugetlbpage-hash64.c
arch/powerpc/mm/hugetlbpage.c
arch/powerpc/mm/mem.c
arch/powerpc/mm/mmu_decl.h
arch/powerpc/mm/numa.c
arch/powerpc/mm/pgtable.c
arch/powerpc/mm/pgtable_32.c
arch/powerpc/mm/pgtable_64.c
arch/powerpc/mm/slice.c
arch/powerpc/mm/tlb_hash64.c
arch/powerpc/mm/tlb_low_64e.S
arch/powerpc/mm/tlb_nohash.c
arch/powerpc/mm/tlb_nohash_low.S
arch/powerpc/oprofile/op_model_7450.c
arch/powerpc/oprofile/op_model_cell.c
arch/powerpc/oprofile/op_model_fsl_emb.c
arch/powerpc/oprofile/op_model_pa6t.c
arch/powerpc/oprofile/op_model_power4.c
arch/powerpc/oprofile/op_model_rs64.c
arch/powerpc/platforms/512x/Kconfig
arch/powerpc/platforms/512x/Makefile
arch/powerpc/platforms/512x/clock-commonclk.c [new file with mode: 0644]
arch/powerpc/platforms/512x/clock.c [deleted file]
arch/powerpc/platforms/512x/mpc512x_shared.c
arch/powerpc/platforms/52xx/Kconfig
arch/powerpc/platforms/83xx/Kconfig
arch/powerpc/platforms/83xx/mcu_mpc8349emitx.c
arch/powerpc/platforms/83xx/suspend.c
arch/powerpc/platforms/85xx/Kconfig
arch/powerpc/platforms/85xx/Makefile
arch/powerpc/platforms/85xx/common.c
arch/powerpc/platforms/85xx/mpc85xx.h
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/platforms/85xx/mpc85xx_rdb.c
arch/powerpc/platforms/85xx/sgy_cts1000.c
arch/powerpc/platforms/85xx/smp.c
arch/powerpc/platforms/85xx/twr_p102x.c [new file with mode: 0644]
arch/powerpc/platforms/8xx/Kconfig
arch/powerpc/platforms/Kconfig.cputype
arch/powerpc/platforms/cell/beat_htab.c
arch/powerpc/platforms/cell/iommu.c
arch/powerpc/platforms/chrp/smp.c
arch/powerpc/platforms/embedded6xx/Kconfig
arch/powerpc/platforms/embedded6xx/Makefile
arch/powerpc/platforms/embedded6xx/hlwd-pic.c
arch/powerpc/platforms/embedded6xx/mvme5100.c [new file with mode: 0644]
arch/powerpc/platforms/pasemi/dma_lib.c
arch/powerpc/platforms/pasemi/iommu.c
arch/powerpc/platforms/powermac/pfunc_core.c
arch/powerpc/platforms/powernv/Kconfig
arch/powerpc/platforms/powernv/Makefile
arch/powerpc/platforms/powernv/eeh-ioda.c
arch/powerpc/platforms/powernv/eeh-powernv.c
arch/powerpc/platforms/powernv/opal-flash.c
arch/powerpc/platforms/powernv/opal-memory-errors.c [new file with mode: 0644]
arch/powerpc/platforms/powernv/opal-rtc.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-p5ioc2.c
arch/powerpc/platforms/powernv/pci.c
arch/powerpc/platforms/powernv/pci.h
arch/powerpc/platforms/powernv/setup.c
arch/powerpc/platforms/ps3/spu.c
arch/powerpc/platforms/pseries/Kconfig
arch/powerpc/platforms/pseries/Makefile
arch/powerpc/platforms/pseries/cmm.c
arch/powerpc/platforms/pseries/dtl.c
arch/powerpc/platforms/pseries/eeh_pseries.c
arch/powerpc/platforms/pseries/iommu.c
arch/powerpc/platforms/pseries/lpar.c
arch/powerpc/platforms/pseries/setup.c
arch/powerpc/platforms/wsp/wsp_pci.c
arch/powerpc/sysdev/Kconfig
arch/powerpc/sysdev/axonram.c
arch/powerpc/sysdev/cpm2_pic.c
arch/powerpc/sysdev/dart_iommu.c
arch/powerpc/sysdev/fsl_ifc.c
arch/powerpc/sysdev/fsl_lbc.c
arch/powerpc/sysdev/fsl_pci.c
arch/powerpc/sysdev/ge/ge_pic.h
arch/powerpc/sysdev/i8259.c
arch/powerpc/sysdev/indirect_pci.c
arch/powerpc/sysdev/mpc8xx_pic.c
arch/powerpc/sysdev/mpic_timer.c
arch/powerpc/sysdev/qe_lib/qe_io.c
arch/powerpc/sysdev/qe_lib/ucc.c
arch/powerpc/sysdev/qe_lib/ucc_fast.c
arch/powerpc/sysdev/qe_lib/ucc_slow.c
arch/powerpc/sysdev/udbg_memcons.c
arch/powerpc/sysdev/xics/icp-hv.c
arch/powerpc/xmon/xmon.c
arch/s390/Kconfig
arch/s390/hypfs/Makefile
arch/s390/hypfs/hypfs.h
arch/s390/hypfs/hypfs_dbfs.c
arch/s390/hypfs/hypfs_sprp.c [new file with mode: 0644]
arch/s390/hypfs/inode.c
arch/s390/include/asm/cmpxchg.h
arch/s390/include/asm/kvm_host.h
arch/s390/include/asm/sclp.h
arch/s390/include/uapi/asm/hypfs.h [new file with mode: 0644]
arch/s390/include/uapi/asm/statfs.h
arch/s390/include/uapi/asm/unistd.h
arch/s390/kernel/compat_linux.c
arch/s390/kernel/compat_wrapper.S
arch/s390/kernel/syscalls.S
arch/s390/kvm/intercept.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/kvm-s390.h
arch/s390/lib/uaccess.h
arch/s390/lib/uaccess_pt.c
arch/score/lib/checksum.S
arch/sparc/include/uapi/asm/unistd.h
arch/sparc/kernel/cpumap.c
arch/sparc/kernel/ebus.c
arch/sparc/kernel/hvtramp.S
arch/sparc/kernel/of_device_common.c
arch/sparc/kernel/pci.c
arch/sparc/kernel/pci_common.c
arch/sparc/kernel/process_32.c
arch/sparc/kernel/sparc_ksyms_32.c
arch/sparc/kernel/sparc_ksyms_64.c
arch/sparc/kernel/systbls_32.S
arch/sparc/kernel/systbls_64.S
arch/sparc/kernel/trampoline_32.S
arch/sparc/kernel/trampoline_64.S
arch/sparc/mm/hugetlbpage.c
arch/sparc/mm/tlb.c
arch/sparc/prom/p1275.c
arch/unicore32/kernel/early_printk.c
arch/x86/Makefile
arch/x86/boot/Makefile
arch/x86/boot/cpuflags.c
arch/x86/boot/video.h
arch/x86/include/asm/kvm_para.h
arch/x86/include/asm/page_types.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/paravirt_types.h
arch/x86/include/asm/pgtable_types.h
arch/x86/include/asm/thread_info.h
arch/x86/include/asm/uv/uv.h
arch/x86/include/asm/xen/page.h
arch/x86/include/uapi/asm/sembuf.h
arch/x86/kernel/apic/x2apic_uv_x.c
arch/x86/kernel/kvm.c
arch/x86/kernel/setup.c
arch/x86/kernel/vsmp_64.c
arch/x86/kvm/cpuid.h
arch/x86/kvm/lapic.h
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/lguest/boot.c
arch/x86/math-emu/errors.c
arch/x86/platform/intel-mid/device_libs/platform_ipc.h
arch/x86/platform/intel-mid/device_libs/platform_msic.h
arch/x86/platform/intel-mid/intel_mid_weak_decls.h
arch/x86/platform/intel-mid/mfld.c
arch/x86/platform/intel-mid/mrfl.c
arch/x86/platform/uv/uv_nmi.c
arch/x86/realmode/rm/Makefile
arch/x86/tools/relocs.c
arch/x86/tools/relocs.h
arch/x86/tools/relocs_common.c
arch/x86/xen/grant-table.c
arch/x86/xen/irq.c
arch/x86/xen/mmu.c
arch/x86/xen/p2m.c
arch/x86/xen/setup.c
arch/x86/xen/spinlock.c
arch/xtensa/platforms/iss/simdisk.c
block/blk-core.c
block/blk-exec.c
block/blk-flush.c
block/blk-integrity.c
block/blk-lib.c
block/blk-map.c
block/blk-merge.c
block/blk-mq-cpu.c
block/blk-mq-tag.c
block/blk-mq.c
block/blk-mq.h
block/blk-settings.c
block/blk-sysfs.c
block/blk-throttle.c
block/cmdline-parser.c
block/elevator.c
block/scsi_ioctl.c
drivers/acpi/acpi_processor.c
drivers/acpi/acpica/acglobal.h
drivers/acpi/bus.c
drivers/acpi/device_pm.c
drivers/acpi/processor_core.c
drivers/acpi/scan.c
drivers/acpi/sysfs.c
drivers/bcma/Kconfig
drivers/bcma/driver_gpio.c
drivers/block/Kconfig
drivers/block/Makefile
drivers/block/aoe/aoe.h
drivers/block/aoe/aoecmd.c
drivers/block/brd.c
drivers/block/cciss.c
drivers/block/drbd/drbd_actlog.c
drivers/block/drbd/drbd_bitmap.c
drivers/block/drbd/drbd_main.c
drivers/block/drbd/drbd_receiver.c
drivers/block/drbd/drbd_req.c
drivers/block/drbd/drbd_req.h
drivers/block/drbd/drbd_worker.c
drivers/block/floppy.c
drivers/block/loop.c
drivers/block/mg_disk.c
drivers/block/mtip32xx/mtip32xx.c
drivers/block/mtip32xx/mtip32xx.h
drivers/block/nbd.c
drivers/block/null_blk.c
drivers/block/nvme-core.c
drivers/block/paride/pg.c
drivers/block/pktcdvd.c
drivers/block/ps3disk.c
drivers/block/ps3vram.c
drivers/block/rbd.c
drivers/block/rsxx/dev.c
drivers/block/rsxx/dma.c
drivers/block/sx8.c
drivers/block/umem.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkfront.c
drivers/block/zram/Kconfig [moved from drivers/staging/zram/Kconfig with 93% similarity]
drivers/block/zram/Makefile [moved from drivers/staging/zram/Makefile with 100% similarity]
drivers/block/zram/zram_drv.c [moved from drivers/staging/zram/zram_drv.c with 87% similarity]
drivers/block/zram/zram_drv.h [moved from drivers/staging/zram/zram_drv.h with 74% similarity]
drivers/cdrom/gdrom.c
drivers/char/Makefile
drivers/char/agp/Kconfig
drivers/char/agp/Makefile
drivers/char/agp/intel-agp.c
drivers/char/agp/intel-gtt.c
drivers/char/i8k.c
drivers/char/ipmi/ipmi_si_intf.c
drivers/clk/Makefile
drivers/clk/clk-si5351.c
drivers/clk/clk-si5351.h
drivers/clk/clk.c
drivers/clk/qcom/Makefile
drivers/clk/samsung/clk-pll.c
drivers/clk/sunxi/clk-sunxi.c
drivers/clk/ti/Makefile [new file with mode: 0644]
drivers/clk/ti/apll.c [new file with mode: 0644]
drivers/clk/ti/autoidle.c [new file with mode: 0644]
drivers/clk/ti/clk-33xx.c [new file with mode: 0644]
drivers/clk/ti/clk-3xxx.c [new file with mode: 0644]
drivers/clk/ti/clk-43xx.c [new file with mode: 0644]
drivers/clk/ti/clk-44xx.c [new file with mode: 0644]
drivers/clk/ti/clk-54xx.c [new file with mode: 0644]
drivers/clk/ti/clk-7xx.c [new file with mode: 0644]
drivers/clk/ti/clk.c [new file with mode: 0644]
drivers/clk/ti/clockdomain.c [new file with mode: 0644]
drivers/clk/ti/composite.c [new file with mode: 0644]
drivers/clk/ti/divider.c [new file with mode: 0644]
drivers/clk/ti/dpll.c [new file with mode: 0644]
drivers/clk/ti/fixed-factor.c [new file with mode: 0644]
drivers/clk/ti/gate.c [new file with mode: 0644]
drivers/clk/ti/interface.c [new file with mode: 0644]
drivers/clk/ti/mux.c [new file with mode: 0644]
drivers/cpufreq/acpi-cpufreq.c
drivers/cpuidle/Kconfig
drivers/cpuidle/Kconfig.powerpc [new file with mode: 0644]
drivers/cpuidle/Makefile
drivers/cpuidle/cpuidle-powernv.c [new file with mode: 0644]
drivers/cpuidle/cpuidle-pseries.c [moved from arch/powerpc/platforms/pseries/processor_idle.c with 74% similarity]
drivers/devfreq/Kconfig
drivers/dma/Kconfig
drivers/dma/Makefile
drivers/dma/acpi-dma.c
drivers/dma/amba-pl08x.c
drivers/dma/bcm2835-dma.c [new file with mode: 0644]
drivers/dma/cppi41.c
drivers/dma/dmatest.c
drivers/dma/dw/core.c
drivers/dma/edma.c
drivers/dma/fsldma.h
drivers/dma/imx-sdma.c
drivers/dma/k3dma.c
drivers/dma/mmp_pdma.c
drivers/dma/mmp_tdma.c
drivers/dma/moxart-dma.c [new file with mode: 0644]
drivers/dma/omap-dma.c
drivers/dma/pl330.c
drivers/dma/ppc4xx/adma.c
drivers/dma/sirf-dma.c
drivers/dma/tegra20-apb-dma.c
drivers/dma/virt-dma.h
drivers/firewire/core-transaction.c
drivers/firewire/core.h
drivers/firewire/ohci.c
drivers/firmware/google/Kconfig
drivers/gpu/drm/Kconfig
drivers/gpu/drm/Makefile
drivers/gpu/drm/armada/Kconfig
drivers/gpu/drm/armada/armada_drv.c
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_ttm.c
drivers/gpu/drm/bochs/Kconfig [new file with mode: 0644]
drivers/gpu/drm/bochs/Makefile [new file with mode: 0644]
drivers/gpu/drm/bochs/bochs.h [new file with mode: 0644]
drivers/gpu/drm/bochs/bochs_drv.c [new file with mode: 0644]
drivers/gpu/drm/bochs/bochs_fbdev.c [new file with mode: 0644]
drivers/gpu/drm/bochs/bochs_hw.c [new file with mode: 0644]
drivers/gpu/drm/bochs/bochs_kms.c [new file with mode: 0644]
drivers/gpu/drm/bochs/bochs_mm.c [new file with mode: 0644]
drivers/gpu/drm/cirrus/cirrus_drv.h
drivers/gpu/drm/cirrus/cirrus_fbdev.c
drivers/gpu/drm/cirrus/cirrus_main.c
drivers/gpu/drm/cirrus/cirrus_mode.c
drivers/gpu/drm/cirrus/cirrus_ttm.c
drivers/gpu/drm/drm_agpsupport.c
drivers/gpu/drm/drm_buffer.c
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_drv.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_edid_load.c
drivers/gpu/drm/drm_fb_helper.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_info.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_memory.c
drivers/gpu/drm/drm_mipi_dsi.c [new file with mode: 0644]
drivers/gpu/drm/drm_panel.c [new file with mode: 0644]
drivers/gpu/drm/drm_pci.c
drivers/gpu/drm/drm_platform.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/drm_usb.c
drivers/gpu/drm/drm_vm.c
drivers/gpu/drm/exynos/exynos_drm_drv.c
drivers/gpu/drm/exynos/exynos_drm_drv.h
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_mixer.c
drivers/gpu/drm/gma500/accel_2d.c
drivers/gpu/drm/gma500/cdv_intel_dp.c
drivers/gpu/drm/gma500/gma_display.c
drivers/gpu/drm/gma500/psb_drv.h
drivers/gpu/drm/gma500/psb_intel_drv.h
drivers/gpu/drm/gma500/psb_irq.c
drivers/gpu/drm/gma500/psb_irq.h
drivers/gpu/drm/i810/i810_dma.c
drivers/gpu/drm/i810/i810_drv.c
drivers/gpu/drm/i915/Kconfig
drivers/gpu/drm/i915/Makefile
drivers/gpu/drm/i915/dvo_ns2501.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_stolen.c
drivers/gpu/drm/i915/i915_gpu_error.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/i915_reg.h
drivers/gpu/drm/i915/i915_suspend.c
drivers/gpu/drm/i915/i915_sysfs.c
drivers/gpu/drm/i915/i915_ums.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_bios.h
drivers/gpu/drm/i915/intel_crt.c
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_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_i2c.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_opregion.c
drivers/gpu/drm/i915/intel_overlay.c
drivers/gpu/drm/i915/intel_panel.c
drivers/gpu/drm/i915/intel_pm.c
drivers/gpu/drm/i915/intel_ringbuffer.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_sdvo_regs.h
drivers/gpu/drm/i915/intel_sideband.c
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.h
drivers/gpu/drm/mga/mga_ioc32.c
drivers/gpu/drm/mga/mga_irq.c
drivers/gpu/drm/mga/mga_state.c
drivers/gpu/drm/mgag200/mgag200_cursor.c
drivers/gpu/drm/mgag200/mgag200_fb.c
drivers/gpu/drm/mgag200/mgag200_main.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/NOTES
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/a3xx_gpu.h
drivers/gpu/drm/msm/adreno/adreno_common.xml.h
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.h
drivers/gpu/drm/msm/hdmi/hdmi.xml.h
drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
drivers/gpu/drm/msm/hdmi/hdmi_connector.c
drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c [new file with mode: 0644]
drivers/gpu/drm/msm/hdmi/qfprom.xml.h
drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h [moved from drivers/gpu/drm/msm/mdp4/mdp4.xml.h with 94% similarity]
drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c [moved from drivers/gpu/drm/msm/mdp4/mdp4_crtc.c with 96% similarity]
drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c [moved from drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c with 98% similarity]
drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c [moved from drivers/gpu/drm/msm/mdp4/mdp4_kms.c with 89% similarity]
drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h [moved from drivers/gpu/drm/msm/mdp4/mdp4_kms.h with 79% similarity]
drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c [moved from drivers/gpu/drm/msm/mdp4/mdp4_plane.c with 98% similarity]
drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp_common.xml.h [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp_format.c [moved from drivers/gpu/drm/msm/mdp4/mdp4_format.c with 85% similarity]
drivers/gpu/drm/msm/mdp/mdp_kms.c [new file with mode: 0644]
drivers/gpu/drm/msm/mdp/mdp_kms.h [new file with mode: 0644]
drivers/gpu/drm/msm/mdp4/mdp4_irq.c [deleted file]
drivers/gpu/drm/msm/msm_drv.c
drivers/gpu/drm/msm/msm_drv.h
drivers/gpu/drm/msm/msm_fb.c
drivers/gpu/drm/msm/msm_gem.c
drivers/gpu/drm/msm/msm_gem.h
drivers/gpu/drm/msm/msm_gpu.c
drivers/gpu/drm/msm/msm_gpu.h
drivers/gpu/drm/msm/msm_iommu.c [new file with mode: 0644]
drivers/gpu/drm/msm/msm_kms.h [new file with mode: 0644]
drivers/gpu/drm/msm/msm_mmu.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/Makefile
drivers/gpu/drm/nouveau/core/core/engine.c
drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
drivers/gpu/drm/nouveau/core/engine/device/nv04.c
drivers/gpu/drm/nouveau/core/engine/device/nv10.c
drivers/gpu/drm/nouveau/core/engine/device/nv20.c
drivers/gpu/drm/nouveau/core/engine/device/nv30.c
drivers/gpu/drm/nouveau/core/engine/device/nv40.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/nv04.c
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/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/vga.c
drivers/gpu/drm/nouveau/core/engine/falcon.c
drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5 [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5 [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
drivers/gpu/drm/nouveau/core/engine/graph/nv108.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
drivers/gpu/drm/nouveau/core/include/core/class.h
drivers/gpu/drm/nouveau/core/include/core/device.h
drivers/gpu/drm/nouveau/core/include/engine/fifo.h
drivers/gpu/drm/nouveau/core/include/engine/graph.h
drivers/gpu/drm/nouveau/core/include/subdev/bar.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h
drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h
drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
drivers/gpu/drm/nouveau/core/include/subdev/fb.h
drivers/gpu/drm/nouveau/core/include/subdev/instmem.h
drivers/gpu/drm/nouveau/core/include/subdev/vm.h
drivers/gpu/drm/nouveau/core/subdev/bar/base.c
drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/bar/priv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/bios/init.c
drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.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/nv04.c
drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c
drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
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/instmem/base.c
drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h
drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h [new file with mode: 0644]
drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.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/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/vm/base.c
drivers/gpu/drm/nouveau/dispnv04/disp.c
drivers/gpu/drm/nouveau/dispnv04/disp.h
drivers/gpu/drm/nouveau/dispnv04/overlay.c
drivers/gpu/drm/nouveau/nouveau_acpi.c
drivers/gpu/drm/nouveau/nouveau_bo.c
drivers/gpu/drm/nouveau/nouveau_display.c
drivers/gpu/drm/nouveau/nouveau_display.h
drivers/gpu/drm/nouveau/nouveau_dma.c
drivers/gpu/drm/nouveau/nouveau_dma.h
drivers/gpu/drm/nouveau/nouveau_drm.c
drivers/gpu/drm/nouveau/nouveau_drm.h
drivers/gpu/drm/nouveau/nouveau_fence.c
drivers/gpu/drm/nouveau/nouveau_gem.c
drivers/gpu/drm/nouveau/nouveau_sgdma.c
drivers/gpu/drm/nouveau/nouveau_ttm.c
drivers/gpu/drm/nouveau/nv50_display.c
drivers/gpu/drm/omapdrm/omap_crtc.c
drivers/gpu/drm/omapdrm/omap_debugfs.c
drivers/gpu/drm/omapdrm/omap_dmm_tiler.c
drivers/gpu/drm/omapdrm/omap_drv.c
drivers/gpu/drm/omapdrm/omap_drv.h
drivers/gpu/drm/omapdrm/omap_encoder.c
drivers/gpu/drm/omapdrm/omap_fb.c
drivers/gpu/drm/omapdrm/omap_irq.c
drivers/gpu/drm/panel/Kconfig [new file with mode: 0644]
drivers/gpu/drm/panel/Makefile [new file with mode: 0644]
drivers/gpu/drm/panel/panel-simple.c [new file with mode: 0644]
drivers/gpu/drm/qxl/qxl_display.c
drivers/gpu/drm/qxl/qxl_drv.h
drivers/gpu/drm/qxl/qxl_ioctl.c
drivers/gpu/drm/qxl/qxl_irq.c
drivers/gpu/drm/qxl/qxl_kms.c
drivers/gpu/drm/r128/r128_cce.c
drivers/gpu/drm/r128/r128_drv.h
drivers/gpu/drm/r128/r128_ioc32.c
drivers/gpu/drm/r128/r128_irq.c
drivers/gpu/drm/r128/r128_state.c
drivers/gpu/drm/radeon/atombios_crtc.c
drivers/gpu/drm/radeon/atombios_dp.c
drivers/gpu/drm/radeon/atombios_i2c.c
drivers/gpu/drm/radeon/btc_dpm.c
drivers/gpu/drm/radeon/ci_dpm.c
drivers/gpu/drm/radeon/ci_smc.c
drivers/gpu/drm/radeon/cik.c
drivers/gpu/drm/radeon/cik_sdma.c
drivers/gpu/drm/radeon/cikd.h
drivers/gpu/drm/radeon/cypress_dpm.c
drivers/gpu/drm/radeon/evergreen.c
drivers/gpu/drm/radeon/evergreen_cs.c
drivers/gpu/drm/radeon/evergreen_reg.h
drivers/gpu/drm/radeon/evergreend.h
drivers/gpu/drm/radeon/kv_dpm.c
drivers/gpu/drm/radeon/ni.c
drivers/gpu/drm/radeon/ni_dma.c
drivers/gpu/drm/radeon/ni_dpm.c
drivers/gpu/drm/radeon/nid.h
drivers/gpu/drm/radeon/pptable.h
drivers/gpu/drm/radeon/r100.c
drivers/gpu/drm/radeon/r300.c
drivers/gpu/drm/radeon/r300_cmdbuf.c
drivers/gpu/drm/radeon/r420.c
drivers/gpu/drm/radeon/r520.c
drivers/gpu/drm/radeon/r600.c
drivers/gpu/drm/radeon/r600_cp.c
drivers/gpu/drm/radeon/r600_cs.c
drivers/gpu/drm/radeon/r600_dma.c
drivers/gpu/drm/radeon/r600_dpm.c
drivers/gpu/drm/radeon/r600_dpm.h
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_combios.c
drivers/gpu/drm/radeon/radeon_connectors.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_fence.c
drivers/gpu/drm/radeon/radeon_gart.c
drivers/gpu/drm/radeon/radeon_gem.c
drivers/gpu/drm/radeon/radeon_i2c.c
drivers/gpu/drm/radeon/radeon_irq.c
drivers/gpu/drm/radeon/radeon_irq_kms.c
drivers/gpu/drm/radeon/radeon_kms.c
drivers/gpu/drm/radeon/radeon_mem.c
drivers/gpu/drm/radeon/radeon_mode.h
drivers/gpu/drm/radeon/radeon_object.c
drivers/gpu/drm/radeon/radeon_pm.c
drivers/gpu/drm/radeon/radeon_ring.c
drivers/gpu/drm/radeon/radeon_sa.c
drivers/gpu/drm/radeon/radeon_state.c
drivers/gpu/drm/radeon/radeon_trace.h
drivers/gpu/drm/radeon/radeon_ttm.c
drivers/gpu/drm/radeon/radeon_uvd.c
drivers/gpu/drm/radeon/rs400.c
drivers/gpu/drm/radeon/rs600.c
drivers/gpu/drm/radeon/rs690.c
drivers/gpu/drm/radeon/rs780_dpm.c
drivers/gpu/drm/radeon/rv515.c
drivers/gpu/drm/radeon/rv6xx_dpm.c
drivers/gpu/drm/radeon/rv770.c
drivers/gpu/drm/radeon/rv770_dpm.c
drivers/gpu/drm/radeon/rv770_dpm.h
drivers/gpu/drm/radeon/rv770d.h
drivers/gpu/drm/radeon/si.c
drivers/gpu/drm/radeon/si_dpm.c
drivers/gpu/drm/radeon/si_smc.c
drivers/gpu/drm/radeon/sid.h
drivers/gpu/drm/radeon/sislands_smc.h
drivers/gpu/drm/radeon/sumo_dpm.c
drivers/gpu/drm/radeon/sumo_smc.c
drivers/gpu/drm/radeon/trinity_dpm.c
drivers/gpu/drm/radeon/trinity_smc.c
drivers/gpu/drm/radeon/uvd_v2_2.c
drivers/gpu/drm/rcar-du/rcar_du_crtc.c
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_kms.c
drivers/gpu/drm/rcar-du/rcar_du_lvdsenc.c
drivers/gpu/drm/rcar-du/rcar_du_plane.c
drivers/gpu/drm/savage/savage_bci.c
drivers/gpu/drm/savage/savage_state.c
drivers/gpu/drm/shmobile/shmob_drm_crtc.c
drivers/gpu/drm/shmobile/shmob_drm_drv.c
drivers/gpu/drm/sis/sis_drv.c
drivers/gpu/drm/sis/sis_mm.c
drivers/gpu/drm/tegra/Kconfig
drivers/gpu/drm/tegra/Makefile
drivers/gpu/drm/tegra/bus.c
drivers/gpu/drm/tegra/dc.c
drivers/gpu/drm/tegra/dc.h
drivers/gpu/drm/tegra/drm.c
drivers/gpu/drm/tegra/drm.h
drivers/gpu/drm/tegra/dsi.c [new file with mode: 0644]
drivers/gpu/drm/tegra/dsi.h [new file with mode: 0644]
drivers/gpu/drm/tegra/fb.c
drivers/gpu/drm/tegra/gem.c
drivers/gpu/drm/tegra/gem.h
drivers/gpu/drm/tegra/hdmi.c
drivers/gpu/drm/tegra/mipi-phy.c [new file with mode: 0644]
drivers/gpu/drm/tegra/mipi-phy.h [new file with mode: 0644]
drivers/gpu/drm/tegra/output.c
drivers/gpu/drm/tegra/rgb.c
drivers/gpu/drm/tilcdc/tilcdc_drv.c
drivers/gpu/drm/ttm/ttm_bo.c
drivers/gpu/drm/ttm/ttm_bo_util.c
drivers/gpu/drm/ttm/ttm_bo_vm.c
drivers/gpu/drm/ttm/ttm_lock.c
drivers/gpu/drm/ttm/ttm_object.c
drivers/gpu/drm/ttm/ttm_tt.c
drivers/gpu/drm/udl/udl_fb.c
drivers/gpu/drm/via/via_dma.c
drivers/gpu/drm/via/via_dmablit.c
drivers/gpu/drm/via/via_drv.c
drivers/gpu/drm/via/via_drv.h
drivers/gpu/drm/via/via_irq.c
drivers/gpu/drm/via/via_video.c
drivers/gpu/drm/vmwgfx/Makefile
drivers/gpu/drm/vmwgfx/svga3d_reg.h
drivers/gpu/drm/vmwgfx/svga_reg.h
drivers/gpu/drm/vmwgfx/vmwgfx_buffer.c
drivers/gpu/drm/vmwgfx/vmwgfx_context.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_fence.c
drivers/gpu/drm/vmwgfx/vmwgfx_fifo.c
drivers/gpu/drm/vmwgfx/vmwgfx_gmr.c
drivers/gpu/drm/vmwgfx/vmwgfx_gmrid_manager.c
drivers/gpu/drm/vmwgfx/vmwgfx_ioctl.c
drivers/gpu/drm/vmwgfx/vmwgfx_irq.c
drivers/gpu/drm/vmwgfx/vmwgfx_kms.c
drivers/gpu/drm/vmwgfx/vmwgfx_mob.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_resource.c
drivers/gpu/drm/vmwgfx/vmwgfx_shader.c [new file with mode: 0644]
drivers/gpu/drm/vmwgfx/vmwgfx_surface.c
drivers/gpu/host1x/Kconfig
drivers/gpu/host1x/Makefile
drivers/gpu/host1x/bus.c
drivers/gpu/host1x/channel.c
drivers/gpu/host1x/debug.c
drivers/gpu/host1x/dev.c
drivers/gpu/host1x/dev.h
drivers/gpu/host1x/hw/host1x02.c
drivers/gpu/host1x/hw/host1x02_hardware.h [new file with mode: 0644]
drivers/gpu/host1x/hw/host1x04.c [new file with mode: 0644]
drivers/gpu/host1x/hw/host1x04.h [new file with mode: 0644]
drivers/gpu/host1x/hw/host1x04_hardware.h [new file with mode: 0644]
drivers/gpu/host1x/hw/hw_host1x02_uclass.h
drivers/gpu/host1x/hw/hw_host1x04_channel.h [new file with mode: 0644]
drivers/gpu/host1x/hw/hw_host1x04_sync.h [new file with mode: 0644]
drivers/gpu/host1x/hw/hw_host1x04_uclass.h [new file with mode: 0644]
drivers/gpu/host1x/hw/intr_hw.c
drivers/gpu/host1x/job.c
drivers/gpu/host1x/mipi.c [new file with mode: 0644]
drivers/gpu/host1x/syncpt.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hv/channel.c
drivers/hwmon/Kconfig
drivers/hwmon/adm1025.c
drivers/hwmon/adm1029.c
drivers/hwmon/adm1031.c
drivers/hwmon/adt7475.c
drivers/hwmon/ds1621.c
drivers/hwmon/emc6w201.c
drivers/hwmon/f71805f.c
drivers/hwmon/gl518sm.c
drivers/hwmon/it87.c
drivers/hwmon/lm63.c
drivers/hwmon/lm78.c
drivers/hwmon/lm83.c
drivers/hwmon/lm85.c
drivers/hwmon/lm87.c
drivers/hwmon/lm90.c
drivers/hwmon/lm92.c
drivers/hwmon/lm93.c
drivers/hwmon/max1619.c
drivers/hwmon/max6642.c
drivers/hwmon/nct6775.c
drivers/hwmon/pc87360.c
drivers/hwmon/pc87427.c
drivers/hwmon/pcf8591.c
drivers/hwmon/sis5595.c
drivers/hwmon/smsc47b397.c
drivers/hwmon/smsc47m1.c
drivers/hwmon/w83627ehf.c
drivers/hwmon/w83627hf.c
drivers/hwmon/w83781d.c
drivers/hwmon/w83795.c
drivers/hwmon/w83l785ts.c
drivers/i2c/algos/i2c-algo-bit.c
drivers/i2c/algos/i2c-algo-pca.c
drivers/i2c/algos/i2c-algo-pcf.c
drivers/i2c/busses/Kconfig
drivers/i2c/busses/i2c-acorn.c
drivers/i2c/busses/i2c-ali1535.c
drivers/i2c/busses/i2c-ali1563.c
drivers/i2c/busses/i2c-ali15x3.c
drivers/i2c/busses/i2c-amd756-s4882.c
drivers/i2c/busses/i2c-amd756.c
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-au1550.c
drivers/i2c/busses/i2c-cbus-gpio.c
drivers/i2c/busses/i2c-cpm.c
drivers/i2c/busses/i2c-eg20t.c
drivers/i2c/busses/i2c-exynos5.c
drivers/i2c/busses/i2c-highlander.c
drivers/i2c/busses/i2c-hydra.c
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-ibm_iic.c
drivers/i2c/busses/i2c-iop3xx.c
drivers/i2c/busses/i2c-isch.c
drivers/i2c/busses/i2c-ismt.c
drivers/i2c/busses/i2c-mpc.c
drivers/i2c/busses/i2c-nforce2-s4985.c
drivers/i2c/busses/i2c-nforce2.c
drivers/i2c/busses/i2c-ocores.c
drivers/i2c/busses/i2c-octeon.c
drivers/i2c/busses/i2c-parport-light.c
drivers/i2c/busses/i2c-parport.c
drivers/i2c/busses/i2c-parport.h
drivers/i2c/busses/i2c-pca-platform.c
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-pmcmsp.c
drivers/i2c/busses/i2c-powermac.c
drivers/i2c/busses/i2c-puv3.c
drivers/i2c/busses/i2c-rcar.c
drivers/i2c/busses/i2c-scmi.c
drivers/i2c/busses/i2c-sh7760.c
drivers/i2c/busses/i2c-simtec.c
drivers/i2c/busses/i2c-sis630.c
drivers/i2c/busses/i2c-sis96x.c
drivers/i2c/busses/i2c-taos-evm.c
drivers/i2c/busses/i2c-via.c
drivers/i2c/busses/i2c-viapro.c
drivers/i2c/busses/i2c-xiic.c
drivers/i2c/busses/i2c-xlr.c
drivers/i2c/busses/scx200_i2c.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-smbus.c
drivers/i2c/i2c-stub.c
drivers/i2c/muxes/i2c-arb-gpio-challenge.c
drivers/i2c/muxes/i2c-mux-gpio.c
drivers/i2c/muxes/i2c-mux-pca9541.c
drivers/i2c/muxes/i2c-mux-pca954x.c
drivers/i2c/muxes/i2c-mux-pinctrl.c
drivers/ide/ide-cd_verbose.c
drivers/ide/ide-pio-blacklist.c
drivers/infiniband/ulp/isert/ib_isert.c
drivers/infiniband/ulp/isert/ib_isert.h
drivers/iommu/Kconfig
drivers/iommu/amd_iommu.c
drivers/iommu/arm-smmu.c
drivers/iommu/dmar.c
drivers/iommu/fsl_pamu_domain.c
drivers/iommu/intel-iommu.c
drivers/iommu/intel_irq_remapping.c
drivers/iommu/irq_remapping.c
drivers/iommu/of_iommu.c
drivers/iommu/shmobile-iommu.c
drivers/iommu/shmobile-ipmmu.c
drivers/iommu/shmobile-ipmmu.h
drivers/leds/led-triggers.c
drivers/leds/leds-lp5521.c
drivers/leds/leds-lp5523.c
drivers/leds/leds-lp55xx-common.c
drivers/leds/leds-mc13783.c
drivers/leds/leds-pwm.c
drivers/leds/leds-s3c24xx.c
drivers/leds/leds-tca6507.c
drivers/macintosh/windfarm_lm75_sensor.c
drivers/macintosh/windfarm_max6690_sensor.c
drivers/md/bcache/Makefile
drivers/md/bcache/alloc.c
drivers/md/bcache/bcache.h
drivers/md/bcache/bset.c
drivers/md/bcache/bset.h
drivers/md/bcache/btree.c
drivers/md/bcache/btree.h
drivers/md/bcache/closure.c
drivers/md/bcache/closure.h
drivers/md/bcache/debug.c
drivers/md/bcache/debug.h
drivers/md/bcache/extents.c [new file with mode: 0644]
drivers/md/bcache/extents.h [new file with mode: 0644]
drivers/md/bcache/io.c
drivers/md/bcache/journal.c
drivers/md/bcache/journal.h
drivers/md/bcache/movinggc.c
drivers/md/bcache/request.c
drivers/md/bcache/request.h
drivers/md/bcache/super.c
drivers/md/bcache/sysfs.c
drivers/md/bcache/util.c
drivers/md/bcache/util.h
drivers/md/bcache/writeback.c
drivers/md/bcache/writeback.h
drivers/md/dm-bio-record.h
drivers/md/dm-bufio.c
drivers/md/dm-cache-policy-mq.c
drivers/md/dm-cache-target.c
drivers/md/dm-crypt.c
drivers/md/dm-delay.c
drivers/md/dm-flakey.c
drivers/md/dm-io.c
drivers/md/dm-linear.c
drivers/md/dm-raid1.c
drivers/md/dm-region-hash.c
drivers/md/dm-snap.c
drivers/md/dm-stripe.c
drivers/md/dm-switch.c
drivers/md/dm-thin.c
drivers/md/dm-verity.c
drivers/md/dm.c
drivers/md/faulty.c
drivers/md/linear.c
drivers/md/md.c
drivers/md/multipath.c
drivers/md/raid0.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/md/raid5.c
drivers/media/Kconfig
drivers/media/dvb-core/dvb-usb-ids.h
drivers/media/dvb-frontends/Kconfig
drivers/media/dvb-frontends/Makefile
drivers/media/dvb-frontends/a8293.c
drivers/media/dvb-frontends/cx24117.c
drivers/media/dvb-frontends/dib8000.c
drivers/media/dvb-frontends/drxk.h
drivers/media/dvb-frontends/drxk_hard.c
drivers/media/dvb-frontends/m88ds3103.c [new file with mode: 0644]
drivers/media/dvb-frontends/m88ds3103.h [new file with mode: 0644]
drivers/media/dvb-frontends/m88ds3103_priv.h [new file with mode: 0644]
drivers/media/dvb-frontends/m88rs2000.c
drivers/media/dvb-frontends/m88rs2000.h
drivers/media/dvb-frontends/nxt200x.c
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/ad9389b.c
drivers/media/i2c/adv7511.c
drivers/media/i2c/adv7604.c
drivers/media/i2c/adv7842.c
drivers/media/i2c/lm3560.c
drivers/media/i2c/mt9m032.c
drivers/media/i2c/mt9p031.c
drivers/media/i2c/mt9t001.c
drivers/media/i2c/mt9v032.c
drivers/media/i2c/s5k5baf.c [new file with mode: 0644]
drivers/media/i2c/saa6588.c
drivers/media/i2c/saa6752hs.c [moved from drivers/media/pci/saa7134/saa6752hs.c with 98% similarity]
drivers/media/i2c/smiapp/smiapp-core.c
drivers/media/i2c/soc_camera/mt9m111.c
drivers/media/i2c/tvp5150.c
drivers/media/i2c/vs6624.c
drivers/media/media-entity.c
drivers/media/pci/bt8xx/bttv-driver.c
drivers/media/pci/cx18/cx18-driver.c
drivers/media/pci/cx25821/cx25821-alsa.c
drivers/media/pci/cx25821/cx25821-core.c
drivers/media/pci/cx88/cx88-alsa.c
drivers/media/pci/saa7134/Kconfig
drivers/media/pci/saa7134/Makefile
drivers/media/pci/saa7134/saa7134-core.c
drivers/media/pci/saa7134/saa7134-empress.c
drivers/media/pci/saa7134/saa7134-vbi.c
drivers/media/pci/saa7134/saa7134-video.c
drivers/media/pci/saa7134/saa7134.h
drivers/media/pci/sta2x11/sta2x11_vip.c
drivers/media/platform/Kconfig
drivers/media/platform/Makefile
drivers/media/platform/davinci/vpbe_display.c
drivers/media/platform/davinci/vpif_capture.c
drivers/media/platform/davinci/vpif_display.c
drivers/media/platform/exynos4-is/Kconfig
drivers/media/platform/exynos4-is/fimc-capture.c
drivers/media/platform/exynos4-is/fimc-core.c
drivers/media/platform/exynos4-is/fimc-core.h
drivers/media/platform/exynos4-is/fimc-is-regs.c
drivers/media/platform/exynos4-is/fimc-is-regs.h
drivers/media/platform/exynos4-is/fimc-is.c
drivers/media/platform/exynos4-is/fimc-lite-reg.c
drivers/media/platform/exynos4-is/fimc-lite.c
drivers/media/platform/exynos4-is/fimc-m2m.c
drivers/media/platform/exynos4-is/mipi-csis.c
drivers/media/platform/fsl-viu.c
drivers/media/platform/m2m-deinterlace.c
drivers/media/platform/mem2mem_testdev.c
drivers/media/platform/omap3isp/isp.c
drivers/media/platform/omap3isp/isp.h
drivers/media/platform/omap3isp/ispccdc.c
drivers/media/platform/omap3isp/ispccp2.c
drivers/media/platform/omap3isp/ispcsi2.c
drivers/media/platform/omap3isp/isppreview.c
drivers/media/platform/omap3isp/ispqueue.c
drivers/media/platform/omap3isp/ispresizer.c
drivers/media/platform/omap3isp/ispstat.c
drivers/media/platform/omap3isp/ispvideo.c
drivers/media/platform/omap3isp/ispvideo.h
drivers/media/platform/s5p-g2d/g2d.c
drivers/media/platform/s5p-g2d/g2d.h
drivers/media/platform/s5p-jpeg/Makefile
drivers/media/platform/s5p-jpeg/jpeg-core.c
drivers/media/platform/s5p-jpeg/jpeg-core.h
drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c [new file with mode: 0644]
drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h [new file with mode: 0644]
drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c [moved from drivers/media/platform/s5p-jpeg/jpeg-hw.h with 70% similarity]
drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h [new file with mode: 0644]
drivers/media/platform/s5p-jpeg/jpeg-regs.h
drivers/media/platform/s5p-mfc/s5p_mfc.c
drivers/media/platform/s5p-mfc/s5p_mfc_common.h
drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
drivers/media/platform/s5p-tv/mixer_drv.c
drivers/media/platform/s5p-tv/mixer_video.c
drivers/media/platform/s5p-tv/sdo_drv.c
drivers/media/platform/sh_vou.c
drivers/media/platform/soc_camera/atmel-isi.c
drivers/media/platform/soc_camera/mx2_camera.c
drivers/media/platform/soc_camera/rcar_vin.c
drivers/media/platform/soc_camera/soc_scale_crop.c
drivers/media/platform/ti-vpe/Makefile
drivers/media/platform/ti-vpe/csc.c [new file with mode: 0644]
drivers/media/platform/ti-vpe/csc.h [new file with mode: 0644]
drivers/media/platform/ti-vpe/sc.c [new file with mode: 0644]
drivers/media/platform/ti-vpe/sc.h [new file with mode: 0644]
drivers/media/platform/ti-vpe/sc_coeff.h [new file with mode: 0644]
drivers/media/platform/ti-vpe/vpdma.c
drivers/media/platform/ti-vpe/vpdma.h
drivers/media/platform/ti-vpe/vpdma_priv.h
drivers/media/platform/ti-vpe/vpe.c
drivers/media/platform/ti-vpe/vpe_regs.h
drivers/media/platform/vsp1/Makefile
drivers/media/platform/vsp1/vsp1.h
drivers/media/platform/vsp1/vsp1_drv.c
drivers/media/platform/vsp1/vsp1_entity.c
drivers/media/platform/vsp1/vsp1_entity.h
drivers/media/platform/vsp1/vsp1_hsit.c [new file with mode: 0644]
drivers/media/platform/vsp1/vsp1_hsit.h [new file with mode: 0644]
drivers/media/platform/vsp1/vsp1_lut.c [new file with mode: 0644]
drivers/media/platform/vsp1/vsp1_lut.h [new file with mode: 0644]
drivers/media/platform/vsp1/vsp1_regs.h
drivers/media/platform/vsp1/vsp1_rpf.c
drivers/media/platform/vsp1/vsp1_rwpf.c
drivers/media/platform/vsp1/vsp1_rwpf.h
drivers/media/platform/vsp1/vsp1_sru.c [new file with mode: 0644]
drivers/media/platform/vsp1/vsp1_sru.h [new file with mode: 0644]
drivers/media/platform/vsp1/vsp1_video.c
drivers/media/platform/vsp1/vsp1_wpf.c
drivers/media/radio/Kconfig
drivers/media/radio/Makefile
drivers/media/radio/radio-raremono.c [new file with mode: 0644]
drivers/media/radio/si470x/radio-si470x-usb.c
drivers/media/radio/si470x/radio-si470x.h
drivers/media/radio/si4713/Kconfig [new file with mode: 0644]
drivers/media/radio/si4713/Makefile [new file with mode: 0644]
drivers/media/radio/si4713/radio-platform-si4713.c [moved from drivers/media/radio/radio-si4713.c with 100% similarity]
drivers/media/radio/si4713/radio-usb-si4713.c [new file with mode: 0644]
drivers/media/radio/si4713/si4713.c [moved from drivers/media/radio/si4713-i2c.c with 86% similarity]
drivers/media/radio/si4713/si4713.h [moved from drivers/media/radio/si4713-i2c.h with 98% similarity]
drivers/media/radio/tea575x.c
drivers/media/rc/imon.c
drivers/media/rc/keymaps/Makefile
drivers/media/rc/keymaps/rc-su3000.c [new file with mode: 0644]
drivers/media/rc/mceusb.c
drivers/media/rc/rc-main.c
drivers/media/rc/st_rc.c
drivers/media/tuners/Kconfig
drivers/media/tuners/Makefile
drivers/media/tuners/e4000.c
drivers/media/tuners/m88ts2022.c [new file with mode: 0644]
drivers/media/tuners/m88ts2022.h [new file with mode: 0644]
drivers/media/tuners/m88ts2022_priv.h [new file with mode: 0644]
drivers/media/tuners/tuner-xc2028.c
drivers/media/usb/Kconfig
drivers/media/usb/Makefile
drivers/media/usb/au0828/au0828-core.c
drivers/media/usb/au0828/au0828-dvb.c
drivers/media/usb/au0828/au0828.h
drivers/media/usb/cx231xx/Kconfig
drivers/media/usb/cx231xx/cx231xx-cards.c
drivers/media/usb/cx231xx/cx231xx-i2c.c
drivers/media/usb/dvb-usb-v2/anysee.c
drivers/media/usb/dvb-usb-v2/az6007.c
drivers/media/usb/dvb-usb-v2/ec168.c
drivers/media/usb/dvb-usb-v2/it913x.c
drivers/media/usb/dvb-usb-v2/rtl28xxu.c
drivers/media/usb/dvb-usb/cxusb.c
drivers/media/usb/dvb-usb/dw2102.c
drivers/media/usb/em28xx/Kconfig
drivers/media/usb/em28xx/Makefile
drivers/media/usb/em28xx/em28xx-audio.c
drivers/media/usb/em28xx/em28xx-camera.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-i2c.c
drivers/media/usb/em28xx/em28xx-input.c
drivers/media/usb/em28xx/em28xx-reg.h
drivers/media/usb/em28xx/em28xx-v4l.h [new file with mode: 0644]
drivers/media/usb/em28xx/em28xx-vbi.c
drivers/media/usb/em28xx/em28xx-video.c
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/pwc/pwc-if.c
drivers/media/v4l2-core/Kconfig
drivers/media/v4l2-core/Makefile
drivers/media/v4l2-core/v4l2-ctrls.c
drivers/media/v4l2-core/v4l2-dev.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/v4l2-mem2mem.c
drivers/media/v4l2-core/v4l2-of.c
drivers/media/v4l2-core/videobuf2-core.c
drivers/media/v4l2-core/videobuf2-dma-sg.c
drivers/message/fusion/mptsas.c
drivers/misc/eeprom/eeprom.c
drivers/mtd/Kconfig
drivers/mtd/afs.c
drivers/mtd/ar7part.c
drivers/mtd/bcm47xxpart.c
drivers/mtd/bcm63xxpart.c
drivers/mtd/cmdlinepart.c
drivers/mtd/devices/docg3.c
drivers/mtd/devices/m25p80.c
drivers/mtd/devices/ms02-nv.c
drivers/mtd/devices/mtd_dataflash.c
drivers/mtd/devices/mtdram.c
drivers/mtd/lpddr/lpddr_cmds.c
drivers/mtd/maps/ixp4xx.c
drivers/mtd/maps/lantiq-flash.c
drivers/mtd/maps/pxa2xx-flash.c
drivers/mtd/maps/sun_uflash.c
drivers/mtd/mtdcore.c
drivers/mtd/mtdpart.c
drivers/mtd/nand/Kconfig
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/au1550nd.c
drivers/mtd/nand/bf5xx_nand.c
drivers/mtd/nand/cafe_nand.c
drivers/mtd/nand/cmx270_nand.c
drivers/mtd/nand/cs553x_nand.c
drivers/mtd/nand/davinci_nand.c
drivers/mtd/nand/denali.c
drivers/mtd/nand/denali.h
drivers/mtd/nand/denali_dt.c
drivers/mtd/nand/denali_pci.c
drivers/mtd/nand/diskonchip.c
drivers/mtd/nand/fsl_elbc_nand.c
drivers/mtd/nand/fsl_ifc_nand.c
drivers/mtd/nand/fsmc_nand.c
drivers/mtd/nand/gpio.c
drivers/mtd/nand/gpmi-nand/gpmi-lib.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.c
drivers/mtd/nand/gpmi-nand/gpmi-nand.h
drivers/mtd/nand/jz4740_nand.c
drivers/mtd/nand/lpc32xx_mlc.c
drivers/mtd/nand/lpc32xx_slc.c
drivers/mtd/nand/mpc5121_nfc.c
drivers/mtd/nand/mxc_nand.c
drivers/mtd/nand/nand_base.c
drivers/mtd/nand/nand_ids.c
drivers/mtd/nand/nuc900_nand.c
drivers/mtd/nand/omap2.c
drivers/mtd/nand/orion_nand.c
drivers/mtd/nand/pasemi_nand.c
drivers/mtd/nand/plat_nand.c
drivers/mtd/nand/pxa3xx_nand.c
drivers/mtd/nand/s3c2410.c
drivers/mtd/nand/sh_flctl.c
drivers/mtd/nand/sharpsl.c
drivers/mtd/nand/tmio_nand.c
drivers/mtd/nand/txx9ndfmc.c
drivers/mtd/ofpart.c
drivers/mtd/onenand/generic.c
drivers/mtd/redboot.c
drivers/mtd/tests/mtd_nandecctest.c
drivers/mtd/ubi/attach.c
drivers/mtd/ubi/build.c
drivers/mtd/ubi/io.c
drivers/net/bonding/bond_main.c
drivers/net/bonding/bonding.h
drivers/net/can/mscan/mpc5xxx_can.c
drivers/net/ethernet/8390/apne.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_ethtool.c
drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
drivers/net/ethernet/ibm/ibmveth.c
drivers/net/ethernet/intel/i40e/i40e_main.c
drivers/net/ethernet/marvell/sky2.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
drivers/net/hyperv/hyperv_net.h
drivers/net/hyperv/netvsc.c
drivers/net/phy/mdio_bus.c
drivers/net/tun.c
drivers/net/xen-netfront.c
drivers/pci/probe.c
drivers/pci/remove.c
drivers/platform/chrome/Kconfig
drivers/platform/chrome/Makefile
drivers/platform/chrome/chromeos_laptop.c
drivers/platform/chrome/chromeos_pstore.c [new file with mode: 0644]
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/asus-wmi.c
drivers/platform/x86/compal-laptop.c
drivers/platform/x86/dell-laptop.c
drivers/platform/x86/eeepc-laptop.c
drivers/platform/x86/fujitsu-laptop.c
drivers/platform/x86/hp-wireless.c [new file with mode: 0644]
drivers/platform/x86/hp_accel.c
drivers/platform/x86/intel_baytrail.c [new file with mode: 0644]
drivers/platform/x86/intel_baytrail.h [new file with mode: 0644]
drivers/platform/x86/intel_scu_ipc.c
drivers/platform/x86/mxm-wmi.c
drivers/platform/x86/sony-laptop.c
drivers/platform/x86/toshiba_acpi.c
drivers/pwm/Kconfig
drivers/pwm/Makefile
drivers/pwm/core.c
drivers/pwm/pwm-atmel.c [new file with mode: 0644]
drivers/pwm/pwm-ep93xx.c
drivers/pwm/pwm-jz4740.c
drivers/pwm/pwm-pxa.c
drivers/pwm/pwm-tiecap.c
drivers/pwm/pwm-tiehrpwm.c
drivers/pwm/sysfs.c
drivers/s390/block/dasd_diag.c
drivers/s390/block/dasd_eckd.c
drivers/s390/block/dasd_fba.c
drivers/s390/block/dcssblk.c
drivers/s390/block/scm_blk.c
drivers/s390/block/scm_blk_cluster.c
drivers/s390/block/xpram.c
drivers/s390/char/sclp_cmd.c
drivers/s390/char/vmur.c
drivers/s390/kvm/virtio_ccw.c
drivers/s390/net/qeth_core.h
drivers/s390/net/qeth_core_main.c
drivers/s390/net/qeth_l2_main.c
drivers/s390/net/qeth_l3_main.c
drivers/sbus/char/bbc_i2c.c
drivers/sbus/char/display7seg.c
drivers/sbus/char/envctrl.c
drivers/sbus/char/flash.c
drivers/sbus/char/uctrl.c
drivers/scsi/libsas/sas_expander.c
drivers/scsi/mpt2sas/mpt2sas_transport.c
drivers/scsi/mpt3sas/mpt3sas_transport.c
drivers/scsi/osd/osd_initiator.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_target.c
drivers/scsi/qla2xxx/qla_target.h
drivers/scsi/qla2xxx/tcm_qla2xxx.c
drivers/scsi/qla2xxx/tcm_qla2xxx.h
drivers/scsi/sd.c
drivers/scsi/sd_dif.c
drivers/spi/spi-mpc512x-psc.c
drivers/ssb/Kconfig
drivers/ssb/driver_gpio.c
drivers/ssb/main.c
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/lustre/lustre/llite/lloop.c
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/as102/as102_drv.c
drivers/staging/media/as102/as102_drv.h
drivers/staging/media/as102/as102_fe.c
drivers/staging/media/as102/as102_fw.c
drivers/staging/media/as102/as102_usb_drv.c
drivers/staging/media/as102/as10x_cmd.c
drivers/staging/media/as102/as10x_cmd_cfg.c
drivers/staging/media/as102/as10x_cmd_stream.c
drivers/staging/media/bcm2048/Kconfig [new file with mode: 0644]
drivers/staging/media/bcm2048/Makefile [new file with mode: 0644]
drivers/staging/media/bcm2048/TODO [new file with mode: 0644]
drivers/staging/media/bcm2048/radio-bcm2048.c [new file with mode: 0644]
drivers/staging/media/bcm2048/radio-bcm2048.h [new file with mode: 0644]
drivers/staging/media/davinci_vpfe/dm365_isif.c
drivers/staging/media/davinci_vpfe/vpfe_video.c
drivers/staging/media/lirc/lirc_parallel.c
drivers/staging/media/lirc/lirc_serial.c
drivers/staging/media/omap24xx/Kconfig [new file with mode: 0644]
drivers/staging/media/omap24xx/Makefile [new file with mode: 0644]
drivers/staging/media/omap24xx/omap24xxcam-dma.c [moved from drivers/media/platform/omap24xxcam-dma.c with 100% similarity]
drivers/staging/media/omap24xx/omap24xxcam.c [moved from drivers/media/platform/omap24xxcam.c with 100% similarity]
drivers/staging/media/omap24xx/omap24xxcam.h [moved from drivers/media/platform/omap24xxcam.h with 99% similarity]
drivers/staging/media/omap24xx/tcm825x.c [moved from drivers/media/i2c/tcm825x.c with 99% similarity]
drivers/staging/media/omap24xx/tcm825x.h [moved from drivers/media/i2c/tcm825x.h with 99% similarity]
drivers/staging/media/omap24xx/v4l2-int-device.c [moved from drivers/media/v4l2-core/v4l2-int-device.c with 99% similarity]
drivers/staging/media/omap24xx/v4l2-int-device.h [moved from include/media/v4l2-int-device.h with 100% similarity]
drivers/staging/media/omap4iss/Kconfig [new file with mode: 0644]
drivers/staging/media/omap4iss/Makefile [new file with mode: 0644]
drivers/staging/media/omap4iss/TODO [new file with mode: 0644]
drivers/staging/media/omap4iss/iss.c [new file with mode: 0644]
drivers/staging/media/omap4iss/iss.h [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_csi2.c [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_csi2.h [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_csiphy.c [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_csiphy.h [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_ipipe.c [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_ipipe.h [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_ipipeif.c [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_ipipeif.h [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_regs.h [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_resizer.c [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_resizer.h [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_video.c [new file with mode: 0644]
drivers/staging/media/omap4iss/iss_video.h [new file with mode: 0644]
drivers/staging/media/sn9c102/Kconfig [moved from drivers/media/usb/sn9c102/Kconfig with 52% similarity]
drivers/staging/media/sn9c102/Makefile [moved from drivers/media/usb/sn9c102/Makefile with 100% similarity]
drivers/staging/media/sn9c102/sn9c102.h [moved from drivers/media/usb/sn9c102/sn9c102.h with 100% similarity]
drivers/staging/media/sn9c102/sn9c102.txt [moved from Documentation/video4linux/sn9c102.txt with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_config.h [moved from drivers/media/usb/sn9c102/sn9c102_config.h with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_core.c [moved from drivers/media/usb/sn9c102/sn9c102_core.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_devtable.h [moved from drivers/media/usb/sn9c102/sn9c102_devtable.h with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_hv7131d.c [moved from drivers/media/usb/sn9c102/sn9c102_hv7131d.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_hv7131r.c [moved from drivers/media/usb/sn9c102/sn9c102_hv7131r.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_mi0343.c [moved from drivers/media/usb/sn9c102/sn9c102_mi0343.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_mi0360.c [moved from drivers/media/usb/sn9c102/sn9c102_mi0360.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_mt9v111.c [moved from drivers/media/usb/sn9c102/sn9c102_mt9v111.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_ov7630.c [moved from drivers/media/usb/sn9c102/sn9c102_ov7630.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_ov7660.c [moved from drivers/media/usb/sn9c102/sn9c102_ov7660.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_pas106b.c [moved from drivers/media/usb/sn9c102/sn9c102_pas106b.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_pas202bcb.c [moved from drivers/media/usb/sn9c102/sn9c102_pas202bcb.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_sensor.h [moved from drivers/media/usb/sn9c102/sn9c102_sensor.h with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_tas5110c1b.c [moved from drivers/media/usb/sn9c102/sn9c102_tas5110c1b.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_tas5110d.c [moved from drivers/media/usb/sn9c102/sn9c102_tas5110d.c with 100% similarity]
drivers/staging/media/sn9c102/sn9c102_tas5130d1b.c [moved from drivers/media/usb/sn9c102/sn9c102_tas5130d1b.c with 100% similarity]
drivers/staging/media/solo6x10/solo6x10-v4l2-enc.c
drivers/staging/media/solo6x10/solo6x10-v4l2.c
drivers/staging/media/solo6x10/solo6x10.h
drivers/staging/zsmalloc/Kconfig [deleted file]
drivers/staging/zsmalloc/Makefile [deleted file]
drivers/target/Kconfig
drivers/target/iscsi/iscsi_target.c
drivers/target/iscsi/iscsi_target_nego.c
drivers/target/iscsi/iscsi_target_util.c
drivers/target/iscsi/iscsi_target_util.h
drivers/target/loopback/tcm_loop.c
drivers/target/target_core_alua.c
drivers/target/target_core_alua.h
drivers/target/target_core_configfs.c
drivers/target/target_core_device.c
drivers/target/target_core_fabric_configfs.c
drivers/target/target_core_file.c
drivers/target/target_core_file.h
drivers/target/target_core_iblock.c
drivers/target/target_core_internal.h
drivers/target/target_core_pr.h
drivers/target/target_core_rd.c
drivers/target/target_core_rd.h
drivers/target/target_core_sbc.c
drivers/target/target_core_spc.c
drivers/target/target_core_tpg.c
drivers/target/target_core_transport.c
drivers/target/target_core_ua.c
drivers/target/target_core_xcopy.c
drivers/target/tcm_fc/tfc_cmd.c
drivers/target/tcm_fc/tfc_conf.c
drivers/tty/Kconfig
drivers/tty/hvc/hvc_iucv.c
drivers/tty/serial/bcm63xx_uart.c
drivers/tty/serial/icom.c
drivers/tty/serial/mpc52xx_uart.c
drivers/tty/serial/pch_uart.c
drivers/tty/serial/samsung.c
drivers/usb/host/fsl-mph-dr-of.c
drivers/vfio/vfio_iommu_spapr_tce.c
drivers/vhost/scsi.c
drivers/video/backlight/lcd.c
drivers/video/backlight/pwm_bl.c
drivers/video/fbmem.c
drivers/video/omap2/dss/dispc.c
drivers/watchdog/Kconfig
drivers/watchdog/Makefile
drivers/watchdog/alim1535_wdt.c
drivers/watchdog/alim7101_wdt.c
drivers/watchdog/at91sam9_wdt.c
drivers/watchdog/bcm_kona_wdt.c [new file with mode: 0644]
drivers/watchdog/davinci_wdt.c
drivers/watchdog/dw_wdt.c
drivers/watchdog/gpio_wdt.c [new file with mode: 0644]
drivers/watchdog/hpwdt.c
drivers/watchdog/i6300esb.c
drivers/watchdog/imx2_wdt.c
drivers/watchdog/moxart_wdt.c
drivers/watchdog/mpc8xxx_wdt.c
drivers/watchdog/nv_tco.c
drivers/watchdog/pcwd_pci.c
drivers/watchdog/s3c2410_wdt.c
drivers/watchdog/sirfsoc_wdt.c
drivers/watchdog/sp5100_tco.c
drivers/watchdog/via_wdt.c
drivers/watchdog/w83627hf_wdt.c
drivers/watchdog/watchdog_core.c
drivers/watchdog/wdt_pci.c
drivers/xen/gntdev.c
drivers/xen/grant-table.c
drivers/xen/swiotlb-xen.c
drivers/xen/xen-selfballoon.c
fs/9p/acl.c
fs/Kconfig
fs/Makefile
fs/affs/super.c
fs/afs/internal.h
fs/afs/proc.c
fs/befs/linuxvfs.c
fs/bio-integrity.c
fs/bio.c
fs/btrfs/Kconfig
fs/btrfs/Makefile
fs/btrfs/acl.c
fs/btrfs/backref.c
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/delayed-inode.h
fs/btrfs/delayed-ref.c
fs/btrfs/delayed-ref.h
fs/btrfs/dev-replace.c
fs/btrfs/dir-item.c
fs/btrfs/disk-io.c
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/extent_io.h
fs/btrfs/extent_map.c
fs/btrfs/file-item.c
fs/btrfs/file.c
fs/btrfs/free-space-cache.c
fs/btrfs/hash.c [new file with mode: 0644]
fs/btrfs/hash.h
fs/btrfs/inode-item.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/lzo.c
fs/btrfs/ordered-data.c
fs/btrfs/orphan.c
fs/btrfs/print-tree.c
fs/btrfs/props.c [new file with mode: 0644]
fs/btrfs/props.h [new file with mode: 0644]
fs/btrfs/qgroup.c
fs/btrfs/raid56.c
fs/btrfs/reada.c
fs/btrfs/relocation.c
fs/btrfs/root-tree.c
fs/btrfs/scrub.c
fs/btrfs/send.c
fs/btrfs/super.c
fs/btrfs/sysfs.c
fs/btrfs/sysfs.h [new file with mode: 0644]
fs/btrfs/tests/btrfs-tests.h
fs/btrfs/transaction.c
fs/btrfs/transaction.h
fs/btrfs/tree-log.c
fs/btrfs/ulist.c
fs/btrfs/ulist.h
fs/btrfs/uuid-tree.c
fs/btrfs/volumes.c
fs/btrfs/xattr.c
fs/btrfs/xattr.h
fs/btrfs/zlib.c
fs/buffer.c
fs/ceph/Kconfig
fs/ceph/Makefile
fs/ceph/acl.c [new file with mode: 0644]
fs/ceph/addr.c
fs/ceph/cache.h
fs/ceph/caps.c
fs/ceph/dir.c
fs/ceph/file.c
fs/ceph/inode.c
fs/ceph/ioctl.c
fs/ceph/mds_client.c
fs/ceph/mds_client.h
fs/ceph/strings.c
fs/ceph/super.c
fs/ceph/super.h
fs/ceph/xattr.c
fs/cramfs/inode.c
fs/cramfs/internal.h [moved from include/linux/cramfs_fs.h with 70% similarity]
fs/cramfs/uncompress.c
fs/dcache.c
fs/dcookies.c
fs/direct-io.c
fs/ecryptfs/inode.c
fs/efs/super.c
fs/eventfd.c
fs/exofs/inode.c
fs/exofs/ore.c
fs/ext2/acl.c
fs/ext2/acl.h
fs/ext2/file.c
fs/ext2/inode.c
fs/ext2/namei.c
fs/ext2/xattr.c
fs/ext2/xattr.h
fs/ext3/acl.c
fs/ext3/acl.h
fs/ext3/file.c
fs/ext3/inode.c
fs/ext3/namei.c
fs/ext3/xattr.c
fs/ext3/xattr.h
fs/ext4/acl.c
fs/ext4/acl.h
fs/ext4/extents.c
fs/ext4/file.c
fs/ext4/inline.c
fs/ext4/inode.c
fs/ext4/ioctl.c
fs/ext4/namei.c
fs/ext4/page-io.c
fs/ext4/xattr.c
fs/ext4/xattr.h
fs/f2fs/acl.c
fs/f2fs/acl.h
fs/f2fs/data.c
fs/f2fs/f2fs.h
fs/f2fs/file.c
fs/f2fs/namei.c
fs/f2fs/xattr.c
fs/f2fs/xattr.h
fs/file.c
fs/fuse/file.c
fs/generic_acl.c [deleted file]
fs/gfs2/acl.c
fs/gfs2/acl.h
fs/gfs2/inode.c
fs/gfs2/lops.c
fs/gfs2/ops_fstype.c
fs/gfs2/xattr.c
fs/hfsplus/acl.h
fs/hfsplus/dir.c
fs/hfsplus/inode.c
fs/hfsplus/posix_acl.c
fs/hfsplus/wrapper.c
fs/hfsplus/xattr.c
fs/hfsplus/xattr.h
fs/jffs2/acl.c
fs/jffs2/acl.h
fs/jffs2/dir.c
fs/jffs2/file.c
fs/jffs2/fs.c
fs/jffs2/malloc.c
fs/jffs2/symlink.c
fs/jffs2/xattr.c
fs/jfs/acl.c
fs/jfs/file.c
fs/jfs/jfs_acl.h
fs/jfs/jfs_logmgr.c
fs/jfs/jfs_metapage.c
fs/jfs/jfs_xattr.h
fs/jfs/namei.c
fs/jfs/super.c
fs/jfs/xattr.c
fs/logfs/dev_bdev.c
fs/mount.h
fs/mpage.c
fs/namei.c
fs/nfs/blocklayout/blocklayout.c
fs/nfs/dir.c
fs/nfs/direct.c
fs/nfs/file.c
fs/nfs/inode.c
fs/nfs/nfs3acl.c
fs/nfs/nfs3proc.c
fs/nfs/nfs3super.c
fs/nfs/nfs4_fs.h
fs/nfs/nfs4client.c
fs/nfs/nfs4filelayout.c
fs/nfs/nfs4filelayoutdev.c
fs/nfs/nfs4proc.c
fs/nfs/nfs4state.c
fs/nfs/nfs4super.c
fs/nfs/nfs4xdr.c
fs/nfs/nfstrace.h
fs/nfs/pnfs.c
fs/nfs/pnfs.h
fs/nfs/read.c
fs/nfs/write.c
fs/nfsd/acl.h
fs/nfsd/cache.h
fs/nfsd/idmap.h
fs/nfsd/netns.h
fs/nfsd/nfs2acl.c
fs/nfsd/nfs3acl.c
fs/nfsd/nfs3xdr.c
fs/nfsd/nfs4acl.c
fs/nfsd/nfs4idmap.c
fs/nfsd/nfs4proc.c
fs/nfsd/nfs4state.c
fs/nfsd/nfs4xdr.c
fs/nfsd/nfscache.c
fs/nfsd/nfssvc.c
fs/nfsd/nfsxdr.c
fs/nfsd/vfs.c
fs/nfsd/vfs.h
fs/nfsd/xdr3.h
fs/nfsd/xdr4.h
fs/nilfs2/segbuf.c
fs/nls/mac-celtic.c
fs/nls/mac-centeuro.c
fs/nls/mac-croatian.c
fs/nls/mac-cyrillic.c
fs/nls/mac-gaelic.c
fs/nls/mac-greek.c
fs/nls/mac-iceland.c
fs/nls/mac-inuit.c
fs/nls/mac-roman.c
fs/nls/mac-romanian.c
fs/nls/mac-turkish.c
fs/nls/nls_ascii.c
fs/nls/nls_base.c
fs/nls/nls_cp1250.c
fs/nls/nls_cp1251.c
fs/nls/nls_cp1255.c
fs/nls/nls_cp437.c
fs/nls/nls_cp737.c
fs/nls/nls_cp775.c
fs/nls/nls_cp850.c
fs/nls/nls_cp852.c
fs/nls/nls_cp855.c
fs/nls/nls_cp857.c
fs/nls/nls_cp860.c
fs/nls/nls_cp861.c
fs/nls/nls_cp862.c
fs/nls/nls_cp863.c
fs/nls/nls_cp864.c
fs/nls/nls_cp865.c
fs/nls/nls_cp866.c
fs/nls/nls_cp869.c
fs/nls/nls_cp874.c
fs/nls/nls_cp932.c
fs/nls/nls_cp936.c
fs/nls/nls_cp949.c
fs/nls/nls_cp950.c
fs/nls/nls_euc-jp.c
fs/nls/nls_iso8859-1.c
fs/nls/nls_iso8859-13.c
fs/nls/nls_iso8859-14.c
fs/nls/nls_iso8859-15.c
fs/nls/nls_iso8859-2.c
fs/nls/nls_iso8859-3.c
fs/nls/nls_iso8859-4.c
fs/nls/nls_iso8859-5.c
fs/nls/nls_iso8859-6.c
fs/nls/nls_iso8859-7.c
fs/nls/nls_iso8859-9.c
fs/nls/nls_koi8-r.c
fs/nls/nls_koi8-ru.c
fs/nls/nls_koi8-u.c
fs/nls/nls_utf8.c
fs/notify/fanotify/fanotify.c
fs/notify/fanotify/fanotify.h
fs/notify/fanotify/fanotify_user.c
fs/notify/inotify/inotify_fsnotify.c
fs/notify/notification.c
fs/ocfs2/acl.c
fs/ocfs2/acl.h
fs/ocfs2/cluster/heartbeat.c
fs/ocfs2/file.c
fs/ocfs2/namei.c
fs/ocfs2/refcounttree.c
fs/ocfs2/xattr.c
fs/ocfs2/xattr.h
fs/posix_acl.c
fs/qnx4/inode.c
fs/qnx4/qnx4.h
fs/read_write.c
fs/reiserfs/acl.h
fs/reiserfs/file.c
fs/reiserfs/namei.c
fs/reiserfs/procfs.c
fs/reiserfs/reiserfs.h
fs/reiserfs/super.c
fs/reiserfs/xattr.c
fs/reiserfs/xattr_acl.c
fs/xattr_acl.c [deleted file]
fs/xfs/xfs_acl.c
fs/xfs/xfs_acl.h
fs/xfs/xfs_aops.c
fs/xfs/xfs_buf.c
fs/xfs/xfs_buf.h
fs/xfs/xfs_file.c
fs/xfs/xfs_ioctl.c
fs/xfs/xfs_iops.c
fs/xfs/xfs_iops.h
fs/xfs/xfs_xattr.c
include/acpi/acpixf.h
include/asm-generic/pgtable.h
include/drm/drmP.h
include/drm/drm_agpsupport.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_dp_helper.h
include/drm/drm_mipi_dsi.h [new file with mode: 0644]
include/drm/drm_os_linux.h
include/drm/drm_panel.h [new file with mode: 0644]
include/drm/ttm/ttm_bo_driver.h
include/drm/ttm/ttm_object.h
include/dt-bindings/clock/mpc512x-clock.h [new file with mode: 0644]
include/dt-bindings/clock/qcom,mmcc-msm8974.h
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/bio.h
include/linux/blk-mq.h
include/linux/blk_types.h
include/linux/blkdev.h
include/linux/bootmem.h
include/linux/ceph/buffer.h
include/linux/ceph/ceph_features.h
include/linux/ceph/ceph_fs.h
include/linux/ceph/libceph.h
include/linux/ceph/messenger.h
include/linux/ceph/osd_client.h
include/linux/ceph/osdmap.h
include/linux/ceph/rados.h
include/linux/clk-provider.h
include/linux/clk/ti.h [new file with mode: 0644]
include/linux/cmdline-parser.h
include/linux/compat.h
include/linux/cramfs_fs_sb.h [deleted file]
include/linux/crush/crush.h
include/linux/crush/mapper.h
include/linux/dm-io.h
include/linux/dma_remapping.h
include/linux/dmaengine.h
include/linux/dmar.h
include/linux/fb.h
include/linux/fdtable.h
include/linux/fs.h
include/linux/fsnotify_backend.h
include/linux/generic_acl.h [deleted file]
include/linux/host1x.h
include/linux/i2c-smbus.h
include/linux/i2c.h
include/linux/intel-iommu.h
include/linux/interrupt.h
include/linux/iommu.h
include/linux/ipc.h
include/linux/ipc_namespace.h
include/linux/jiffies.h
include/linux/kgdb.h
include/linux/linkage.h
include/linux/mfd/mc13xxx.h
include/linux/mm.h
include/linux/msg.h
include/linux/mtd/mtdram.h
include/linux/mtd/nand.h
include/linux/mtd/partitions.h
include/linux/nfs_fs.h
include/linux/nls.h
include/linux/of_fdt.h
include/linux/of_mtd.h
include/linux/percpu_ida.h
include/linux/platform_data/dma-imx-sdma.h
include/linux/platform_data/dma-imx.h
include/linux/platform_data/dma-mmp_tdma.h
include/linux/platform_data/dma-mv_xor.h
include/linux/platform_data/leds-kirkwood-netxbig.h
include/linux/platform_data/leds-kirkwood-ns2.h
include/linux/platform_data/mtd-nand-omap2.h
include/linux/platform_data/mtd-nand-pxa3xx.h
include/linux/platform_data/mtd-onenand-omap2.h
include/linux/platform_data/mtd-orion_nand.h
include/linux/platform_data/si5351.h
include/linux/platform_data/vsp1.h
include/linux/posix_acl.h
include/linux/posix_acl_xattr.h
include/linux/rcupdate.h
include/linux/rwsem.h
include/linux/sched/sysctl.h
include/linux/serial_bcm63xx.h [new file with mode: 0644]
include/linux/shm.h
include/linux/skbuff.h
include/linux/smp.h
include/linux/splice.h
include/linux/ssb/ssb.h
include/linux/sunrpc/rpc_pipe_fs.h
include/linux/sunrpc/svc.h
include/linux/tick.h
include/linux/vmstat.h
include/linux/zsmalloc.h [moved from drivers/staging/zsmalloc/zsmalloc.h with 97% similarity]
include/math-emu/op-common.h
include/media/adv7604.h
include/media/adv7842.h
include/media/atmel-isi.h
include/media/media-entity.h
include/media/omap4iss.h [new file with mode: 0644]
include/media/rc-map.h
include/media/saa6588.h
include/media/saa6752hs.h [deleted file]
include/media/si4713.h
include/media/v4l2-fh.h
include/media/v4l2-mem2mem.h
include/media/v4l2-of.h
include/media/videobuf2-core.h
include/scsi/osd_ore.h
include/scsi/scsi.h
include/target/iscsi/iscsi_transport.h
include/target/target_core_backend.h
include/target/target_core_base.h
include/target/target_core_fabric.h
include/trace/events/bcache.h
include/trace/events/block.h
include/trace/events/btrfs.h
include/trace/events/f2fs.h
include/trace/events/sunrpc.h
include/trace/events/v4l2.h [new file with mode: 0644]
include/uapi/asm-generic/ipcbuf.h
include/uapi/asm-generic/msgbuf.h
include/uapi/asm-generic/shmbuf.h
include/uapi/drm/drm.h
include/uapi/drm/i915_drm.h
include/uapi/drm/radeon_drm.h
include/uapi/drm/vmwgfx_drm.h
include/uapi/linux/bcache.h
include/uapi/linux/btrfs.h
include/uapi/linux/fd.h
include/uapi/linux/media.h
include/uapi/linux/mqueue.h
include/uapi/linux/msg.h
include/uapi/linux/resource.h
include/uapi/linux/shm.h
include/uapi/linux/timex.h
include/uapi/linux/v4l2-controls.h
include/uapi/linux/v4l2-mediabus.h
include/uapi/linux/videodev2.h
include/uapi/linux/vsp1.h [new file with mode: 0644]
include/uapi/linux/xattr.h
include/xen/grant_table.h
init/Kconfig
init/do_mounts_rd.c
init/main.c
ipc/compat.c
ipc/compat_mq.c
ipc/ipc_sysctl.c
ipc/mqueue.c
ipc/msg.c
ipc/sem.c
ipc/shm.c
ipc/util.c
ipc/util.h
kernel/debug/debug_core.c
kernel/debug/debug_core.h
kernel/hung_task.c
kernel/kexec.c
kernel/power/block_io.c
kernel/rcu/update.c
kernel/sched/core.c
kernel/sched/deadline.c
kernel/smp.c
kernel/softirq.c
kernel/sysctl.c
kernel/time/tick-sched.c
kernel/trace/blktrace.c
kernel/trace/trace.c
lib/Kconfig.debug
lib/dma-debug.c
lib/dynamic_debug.c
lib/genalloc.c
lib/kobject.c
lib/percpu_ida.c
lib/swiotlb.c
mm/Kconfig
mm/Makefile
mm/bounce.c
mm/filemap.c
mm/huge_memory.c
mm/internal.h
mm/memblock.c
mm/memcontrol.c
mm/mempolicy.c
mm/migrate.c
mm/mm_init.c
mm/oom_kill.c
mm/page-writeback.c
mm/page_io.c
mm/readahead.c
mm/shmem.c
mm/slab_common.c
mm/slub.c
mm/vmalloc.c
mm/vmscan.c
mm/zsmalloc.c [moved from drivers/staging/zsmalloc/zsmalloc-main.c with 99% similarity]
net/ceph/buffer.c
net/ceph/ceph_common.c
net/ceph/crush/crush.c
net/ceph/crush/mapper.c
net/ceph/debugfs.c
net/ceph/messenger.c
net/ceph/mon_client.c
net/ceph/osd_client.c
net/ceph/osdmap.c
net/compat.c
net/core/skbuff.c
net/ieee802154/6lowpan_iphc.c
net/ipv4/ip_gre.c
net/ipv4/ip_input.c
net/ipv4/ip_tunnel.c
net/ipv6/ip6_input.c
net/llc/llc_output.c
net/rxrpc/ar-connection.c
net/rxrpc/ar-recvmsg.c
net/sched/sch_tbf.c
net/sunrpc/auth_gss/auth_gss.c
net/sunrpc/auth_gss/gss_krb5_keys.c
net/sunrpc/auth_gss/gss_rpc_upcall.c
net/sunrpc/auth_gss/svcauth_gss.c
net/sunrpc/cache.c
net/sunrpc/clnt.c
net/sunrpc/netns.h
net/sunrpc/rpc_pipe.c
net/sunrpc/sunrpc_syms.c
net/sunrpc/svc.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c
scripts/checkpatch.pl
scripts/mod/modpost.c
scripts/setlocalversion
sound/core/init.c
sound/pci/cs46xx/cs46xx_lib.c
sound/pci/hda/hda_codec.h
sound/pci/hda/hda_proc.c
sound/pci/hda/patch_hdmi.c
sound/pci/hda/patch_realtek.c
sound/pci/oxygen/Makefile
sound/pci/oxygen/cs4245.h
sound/pci/oxygen/oxygen.h
sound/pci/oxygen/oxygen_io.c
sound/pci/oxygen/oxygen_mixer.c
sound/pci/oxygen/oxygen_regs.h
sound/pci/oxygen/xonar_dg.c
sound/pci/oxygen/xonar_dg.h
sound/pci/oxygen/xonar_dg_mixer.c [new file with mode: 0644]
sound/soc/codecs/tlv320aic32x4.c
sound/soc/codecs/tlv320aic32x4.h
sound/soc/codecs/wm5100.c
sound/soc/codecs/wm5110.c
sound/soc/fsl/fsl_ssi.c
sound/soc/omap/Kconfig
sound/soc/samsung/Kconfig
sound/soc/samsung/h1940_uda1380.c
sound/soc/samsung/i2s.c
sound/soc/samsung/neo1973_wm8753.c
sound/soc/samsung/rx1950_uda1380.c
sound/soc/samsung/s3c-i2s-v2.c
sound/soc/samsung/s3c2412-i2s.c
sound/soc/samsung/s3c24xx-i2s.c
sound/soc/samsung/smartq_wm8987.c
sound/soc/samsung/smdk_wm8994.c

diff --git a/CREDITS b/CREDITS
index 4c7738f493570eb9d0c70e6db67c527bcbe6e691..e371c5504a5053c32b50caf9d2251f793814bcb1 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -823,8 +823,8 @@ S: D-69231 Rauenberg
 S: Germany
 
 N: Jean Delvare
-E: khali@linux-fr.org
-W: http://khali.linux-fr.org/
+E: jdelvare@suse.de
+W: http://jdelvare.nerim.net/
 D: Several hardware monitoring drivers
 S: France
 
index 01e769d6984d575bc431b3be14f014434633427b..37559a06393b56c743ee9b45c129f268bc16aa6c 100644 (file)
@@ -1,13 +1,13 @@
 What:          /config/usb-gadget
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                This group contains sub-groups corresponding to created
                USB gadgets.
 
 What:          /config/usb-gadget/gadget
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
 
                The attributes of a gadget:
@@ -27,7 +27,7 @@ Description:
 
 What:          /config/usb-gadget/gadget/configs
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                This group contains a USB gadget's configurations
 
@@ -58,20 +58,20 @@ Description:
 
 What:          /config/usb-gadget/gadget/functions
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                This group contains functions available to this USB gadget.
 
 What:          /config/usb-gadget/gadget/strings
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                This group contains subdirectories for language-specific
                strings for this gadget.
 
 What:          /config/usb-gadget/gadget/strings/language
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                The attributes:
 
index 5708a568b5f6fb63fa7493e7ff33831ab5acbd90..d21092d75a0587ea8d7edbcd48a9af344388396d 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/acm.name
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
 
                This item contains just one readonly attribute: port_num.
index 6b9a582ce0b55afbca2f25688577cc4ea15cc675..0addf7704b4c0ee9639406abfd7f16184d7402fd 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/ecm.name
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                The attributes:
 
index dbddf36b48b3c037f2822f06469c4e85d4e23928..a4c57158fcdef28a8805157b24015eb4edb38568 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/eem.name
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                The attributes:
 
index 14343e237e83910e54255d14f7c85cf5837a7957..e39b27653c65c15f4911db846c7ca98859bf0463 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/ffs.name
 Date:          Nov 2013
-KenelVersion:  3.13
+KernelVersion: 3.13
 Description:   The purpose of this directory is to create and remove it.
 
                A corresponding USB function instance is created/removed.
index 852b2365a5b57a2e0c7f56030815b7397fddb695..9aae5bfb990887a6ad3faee29830d1603a7ecb19 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/Loopback.name
 Date:          Nov 2013
-KenelVersion:  3.13
+KernelVersion: 3.13
 Description:
                The attributes:
 
index ad72a37ee9ff24fab43631db8c8a0b01f02f4252..9931fb0d63ba44ce155d3e859a5bac2df451298a 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/mass_storage.name
 Date:          Oct 2013
-KenelVersion:  3.13
+KernelVersion: 3.13
 Description:
                The attributes:
 
@@ -13,7 +13,7 @@ Description:
 
 What:          /config/usb-gadget/gadget/functions/mass_storage.name/lun.name
 Date:          Oct 2013
-KenelVersion:  3.13
+KernelVersion: 3.13
 Description:
                The attributes:
 
index bc309f42357d60a3843eed7f71b4c0e9fd55d660..6fe723effc7894aeccfc297a34219cd0a5725565 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/ncm.name
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                The attributes:
 
index aaa5c96fb7c609de47de1a716c1d233ce7f43368..a6a9327ed9ba51ea6bd0d2aa7d844ccb00cb32cb 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/obex.name
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
 
                This item contains just one readonly attribute: port_num.
index 3e3b742cdfd73aa4c3d04da9e061cb9a932d5257..7037a358e6c48f672b0aab94ec5159a29fe9fcdc 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/phonet.name
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
 
                This item contains just one readonly attribute: ifname.
index 822e6dad8fc08e5644a7e8297464f04d804e4d8f..e32879b84b4d092ffc3aa3c655c470ec5135c9fd 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/rndis.name
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                The attributes:
 
index 16f130c1501f009f0d021138d48a8b27da58ee52..474d249f760be01f1311ba17842b4c4e827c8079 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/gser.name
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
 
                This item contains just one readonly attribute: port_num.
index a30f3093ef6caeb9b0891474884c40432e898000..29477c319f61bf16f1259962237f4b3f0a7e6287 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/SourceSink.name
 Date:          Nov 2013
-KenelVersion:  3.13
+KernelVersion: 3.13
 Description:
                The attributes:
 
index 154ae597cd99a84604decdd1a667f18707bda7e1..9373e2c51ea454e6de4031908ed5cdee4a04e9b6 100644 (file)
@@ -1,6 +1,6 @@
 What:          /config/usb-gadget/gadget/functions/geth.name
 Date:          Jun 2013
-KenelVersion:  3.11
+KernelVersion: 3.11
 Description:
                The attributes:
 
index 0a306476424ef06cf6222e6e13541804bc546333..501adc2a9ec723841c5246b19875a9bc14471ada 100644 (file)
@@ -18,6 +18,28 @@ Removal of a device:
 
   $ echo <dev-id> > /sys/bus/rbd/remove
 
+What:          /sys/bus/rbd/add_single_major
+Date:          December 2013
+KernelVersion: 3.14
+Contact:       Sage Weil <sage@inktank.com>
+Description:   Available only if rbd module is inserted with single_major
+               parameter set to true.
+               Usage is the same as for /sys/bus/rbd/add.  If present,
+               should be used instead of the latter: any attempts to use
+               /sys/bus/rbd/add if /sys/bus/rbd/add_single_major is
+               available will fail for backwards compatibility reasons.
+
+What:          /sys/bus/rbd/remove_single_major
+Date:          December 2013
+KernelVersion: 3.14
+Contact:       Sage Weil <sage@inktank.com>
+Description:   Available only if rbd module is inserted with single_major
+               parameter set to true.
+               Usage is the same as for /sys/bus/rbd/remove.  If present,
+               should be used instead of the latter: any attempts to use
+               /sys/bus/rbd/remove if /sys/bus/rbd/remove_single_major is
+               available will fail for backwards compatibility reasons.
+
 Entries under /sys/bus/rbd/devices/<dev-id>/
 --------------------------------------------
 
@@ -33,6 +55,10 @@ major
 
        The block device major number.
 
+minor
+
+       The block device minor number.  (December 2013, since 3.14.)
+
 name
 
        The name of the rbd image.
index 0c7195e3e0937b41c71756eee2cbfe51963cd7f9..c4cac6dbf9af048ba522f343d2ade0231f6c1e65 100644 (file)
@@ -2523,6 +2523,18 @@ that used it. It was originally scheduled for removal in 2.6.35.
       </orderedlist>
     </section>
 
+    <section>
+      <title>V4L2 in Linux 3.14</title>
+      <orderedlist>
+        <listitem>
+               <para> In struct <structname>v4l2_rect</structname>, the type
+of <structfield>width</structfield> and <structfield>height</structfield>
+fields changed from _s32 to _u32.
+         </para>
+        </listitem>
+      </orderedlist>
+    </section>
+
     <section id="other">
       <title>Relation of V4L2 to other Linux multimedia APIs</title>
 
index 7a3b49b3cc3bafbb7f4a8892521e30700dd70496..a5a3188e5af7961889f27c61b295cbf04a2e1c8b 100644 (file)
@@ -3161,6 +3161,47 @@ V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD as a golden frame.</entry>
                </entrytbl>
              </row>
 
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_MIN_QP</constant></entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Minimum quantization parameter for VP8.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_MAX_QP</constant></entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Maximum quantization parameter for VP8.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for an I frame for VP8.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Quantization parameter for a P frame for VP8.</entry>
+             </row>
+
+             <row><entry></entry></row>
+             <row>
+               <entry spanname="id"><constant>V4L2_CID_MPEG_VIDEO_VPX_PROFILE</constant>&nbsp;</entry>
+               <entry>integer</entry>
+             </row>
+             <row><entry spanname="descr">Select the desired profile for VPx encoder.
+Acceptable values are 0, 1, 2 and 3 corresponding to encoder profiles 0, 1, 2 and 3.</entry>
+             </row>
+
           <row><entry></entry></row>
         </tbody>
       </tgroup>
index 40d1d76814394815f5067785dd31a5d5fb957b35..cc6e0c5c960cebfc838d143927a0734c5241b4d3 100644 (file)
@@ -346,17 +346,14 @@ rectangle, in pixels.</entry>
 rectangle, in pixels. Offsets increase to the right and down.</entry>
          </row>
          <row>
-           <entry>__s32</entry>
+           <entry>__u32</entry>
            <entry><structfield>width</structfield></entry>
            <entry>Width of the rectangle, in pixels.</entry>
          </row>
          <row>
-           <entry>__s32</entry>
+           <entry>__u32</entry>
            <entry><structfield>height</structfield></entry>
-           <entry>Height of the rectangle, in pixels. Width and
-height cannot be negative, the fields are signed for hysterical
-reasons. <!-- video4linux-list@redhat.com on 22 Oct 2002 subject
-"Re:[V4L][patches!] Re:v4l2/kernel-2.5" --></entry>
+           <entry>Height of the rectangle, in pixels.</entry>
          </row>
        </tbody>
       </tgroup>
index 355df43badc5d7dc34123f829bed0ef028c4539a..cf8548556c7dcb0d28cef102ae5cba261b122899 100644 (file)
            <entry>Output pad, relative to the entity. Output pads source data
            and are origins of links.</entry>
          </row>
+         <row>
+           <entry><constant>MEDIA_PAD_FL_MUST_CONNECT</constant></entry>
+           <entry>If this flag is set and the pad is linked to any other
+           pad, then at least one of those links must be enabled for the
+           entity to be able to stream. There could be temporary reasons
+           (e.g. device configuration dependent) for the pad to need
+           enabled links even when this flag isn't set; the absence of the
+           flag doesn't imply there is none.</entry>
+         </row>
        </tbody>
       </tgroup>
     </table>
index f72c1cc93a9b0d6aa8b888afb7f80393620f9bda..7331ce116f4cc14f5cb7456fd00dad9cee9c1782 100644 (file)
@@ -89,7 +89,7 @@
       <constant>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</constant>.
       </para>
 
-      <para>The following tables list existing packet RGB formats.</para>
+      <para>The following tables list existing packed RGB formats.</para>
 
       <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-rgb">
        <title>RGB formats</title>
        </mediaobject>
       </figure>
 
-      <para>The following table lists existing packet Bayer formats. The data
+      <para>The following table lists existing packed Bayer formats. The data
       organization is given as an example for the first pixel only.</para>
 
       <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-bayer">
       U, Y, V, Y order will be named <constant>V4L2_MBUS_FMT_UYVY8_2X8</constant>.
       </para>
 
-       <para><xref linkend="v4l2-mbus-pixelcode-yuv8"/> list existing packet YUV
+       <para><xref linkend="v4l2-mbus-pixelcode-yuv8"/> lists existing packed YUV
        formats and describes the organization of each pixel data in each sample.
        When a format pattern is split across multiple samples each of the samples
        in the pattern is described.</para>
       </table>
     </section>
 
+    <section>
+      <title>HSV/HSL Formats</title>
+
+      <para>Those formats transfer pixel data as RGB values in a cylindrical-coordinate
+      system using Hue-Saturation-Value or Hue-Saturation-Lightness components. The
+      format code is made of the following information.
+      <itemizedlist>
+       <listitem><para>The hue, saturation, value or lightness and optional alpha
+       components order code, as encoded in a pixel sample. The only currently
+       supported value is AHSV.
+       </para></listitem>
+       <listitem><para>The number of bits per component, for each component. The values
+       can be different for all components. The only currently supported value is 8888.
+       </para></listitem>
+       <listitem><para>The number of bus samples per pixel. Pixels that are wider than
+       the bus width must be transferred in multiple samples. The only currently
+       supported value is 1.</para></listitem>
+       <listitem><para>The bus width.</para></listitem>
+       <listitem><para>For formats where the total number of bits per pixel is smaller
+       than the number of bus samples per pixel times the bus width, a padding
+       value stating if the bytes are padded in their most high order bits
+       (PADHI) or low order bits (PADLO).</para></listitem>
+       <listitem><para>For formats where the number of bus samples per pixel is larger
+       than 1, an endianness value stating if the pixel is transferred MSB first
+       (BE) or LSB first (LE).</para></listitem>
+      </itemizedlist>
+      </para>
+
+      <para>The following table lists existing HSV/HSL formats.</para>
+
+      <table pgwide="0" frame="none" id="v4l2-mbus-pixelcode-hsv">
+       <title>HSV/HSL formats</title>
+       <tgroup cols="27">
+         <colspec colname="id" align="left" />
+         <colspec colname="code" align="center"/>
+         <colspec colname="bit" />
+         <colspec colnum="4" colname="b31" align="center" />
+         <colspec colnum="5" colname="b20" align="center" />
+         <colspec colnum="6" colname="b29" align="center" />
+         <colspec colnum="7" colname="b28" align="center" />
+         <colspec colnum="8" colname="b27" align="center" />
+         <colspec colnum="9" colname="b26" align="center" />
+         <colspec colnum="10" colname="b25" align="center" />
+         <colspec colnum="11" colname="b24" align="center" />
+         <colspec colnum="12" colname="b23" align="center" />
+         <colspec colnum="13" colname="b22" align="center" />
+         <colspec colnum="14" colname="b21" align="center" />
+         <colspec colnum="15" colname="b20" align="center" />
+         <colspec colnum="16" colname="b19" align="center" />
+         <colspec colnum="17" colname="b18" align="center" />
+         <colspec colnum="18" colname="b17" align="center" />
+         <colspec colnum="19" colname="b16" align="center" />
+         <colspec colnum="20" colname="b15" align="center" />
+         <colspec colnum="21" colname="b14" align="center" />
+         <colspec colnum="22" colname="b13" align="center" />
+         <colspec colnum="23" colname="b12" align="center" />
+         <colspec colnum="24" colname="b11" align="center" />
+         <colspec colnum="25" colname="b10" align="center" />
+         <colspec colnum="26" colname="b09" align="center" />
+         <colspec colnum="27" colname="b08" align="center" />
+         <colspec colnum="28" colname="b07" align="center" />
+         <colspec colnum="29" colname="b06" align="center" />
+         <colspec colnum="30" colname="b05" align="center" />
+         <colspec colnum="31" colname="b04" align="center" />
+         <colspec colnum="32" colname="b03" align="center" />
+         <colspec colnum="33" colname="b02" align="center" />
+         <colspec colnum="34" colname="b01" align="center" />
+         <colspec colnum="35" colname="b00" align="center" />
+         <spanspec namest="b31" nameend="b00" spanname="b0" />
+         <thead>
+           <row>
+             <entry>Identifier</entry>
+             <entry>Code</entry>
+             <entry></entry>
+             <entry spanname="b0">Data organization</entry>
+           </row>
+           <row>
+             <entry></entry>
+             <entry></entry>
+             <entry>Bit</entry>
+             <entry>31</entry>
+             <entry>30</entry>
+             <entry>29</entry>
+             <entry>28</entry>
+             <entry>27</entry>
+             <entry>26</entry>
+             <entry>25</entry>
+             <entry>24</entry>
+             <entry>23</entry>
+             <entry>22</entry>
+             <entry>21</entry>
+             <entry>20</entry>
+             <entry>19</entry>
+             <entry>18</entry>
+             <entry>17</entry>
+             <entry>16</entry>
+             <entry>15</entry>
+             <entry>14</entry>
+             <entry>13</entry>
+             <entry>12</entry>
+             <entry>11</entry>
+             <entry>10</entry>
+             <entry>9</entry>
+             <entry>8</entry>
+             <entry>7</entry>
+             <entry>6</entry>
+             <entry>5</entry>
+             <entry>4</entry>
+             <entry>3</entry>
+             <entry>2</entry>
+             <entry>1</entry>
+             <entry>0</entry>
+           </row>
+         </thead>
+         <tbody valign="top">
+           <row id="V4L2-MBUS-FMT-AHSV8888-1X32">
+             <entry>V4L2_MBUS_FMT_AHSV8888_1X32</entry>
+             <entry>0x6001</entry>
+             <entry></entry>
+             <entry>a<subscript>7</subscript></entry>
+             <entry>a<subscript>6</subscript></entry>
+             <entry>a<subscript>5</subscript></entry>
+             <entry>a<subscript>4</subscript></entry>
+             <entry>a<subscript>3</subscript></entry>
+             <entry>a<subscript>2</subscript></entry>
+             <entry>a<subscript>1</subscript></entry>
+             <entry>a<subscript>0</subscript></entry>
+             <entry>h<subscript>7</subscript></entry>
+             <entry>h<subscript>6</subscript></entry>
+             <entry>h<subscript>5</subscript></entry>
+             <entry>h<subscript>4</subscript></entry>
+             <entry>h<subscript>3</subscript></entry>
+             <entry>h<subscript>2</subscript></entry>
+             <entry>h<subscript>1</subscript></entry>
+             <entry>h<subscript>0</subscript></entry>
+             <entry>s<subscript>7</subscript></entry>
+             <entry>s<subscript>6</subscript></entry>
+             <entry>s<subscript>5</subscript></entry>
+             <entry>s<subscript>4</subscript></entry>
+             <entry>s<subscript>3</subscript></entry>
+             <entry>s<subscript>2</subscript></entry>
+             <entry>s<subscript>1</subscript></entry>
+             <entry>s<subscript>0</subscript></entry>
+             <entry>v<subscript>7</subscript></entry>
+             <entry>v<subscript>6</subscript></entry>
+             <entry>v<subscript>5</subscript></entry>
+             <entry>v<subscript>4</subscript></entry>
+             <entry>v<subscript>3</subscript></entry>
+             <entry>v<subscript>2</subscript></entry>
+             <entry>v<subscript>1</subscript></entry>
+             <entry>v<subscript>0</subscript></entry>
+           </row>
+         </tbody>
+       </tgroup>
+      </table>
+    </section>
+
     <section>
       <title>JPEG Compressed Formats</title>
 
index 8469fe13945c524afe06a7c759d44d14e1911495..74b7f27af71a71e4f17d718a590a013e1b5908d4 100644 (file)
@@ -140,6 +140,14 @@ structs, ioctls) must be noted in more detail in the history chapter
 (compat.xml), along with the possible impact on existing drivers and
 applications. -->
 
+      <revision>
+       <revnumber>3.14</revnumber>
+       <date>2013-11-25</date>
+       <authorinitials>rr</authorinitials>
+       <revremark>Set width and height as unsigned on v4l2_rect.
+       </revremark>
+      </revision>
+
       <revision>
        <revnumber>3.11</revnumber>
        <date>2013-05-26</date>
@@ -501,7 +509,7 @@ and discussions on the V4L mailing list.</revremark>
 </partinfo>
 
 <title>Video for Linux Two API Specification</title>
- <subtitle>Revision 3.11</subtitle>
+ <subtitle>Revision 3.14</subtitle>
 
   <chapter id="common">
     &sub-common;
index bf7cc979fdfa6bbba9d92c0d5f7e7b68cc6a1518..1f5ed64cd75a0e5c2aeb3cc0ea4c7ff670aceeea 100644 (file)
@@ -133,18 +133,14 @@ rectangle, in pixels.</entry>
 rectangle, in pixels.</entry>
          </row>
          <row>
-           <entry>__s32</entry>
+           <entry>__u32</entry>
            <entry><structfield>width</structfield></entry>
            <entry>Width of the rectangle, in pixels.</entry>
          </row>
          <row>
-           <entry>__s32</entry>
+           <entry>__u32</entry>
            <entry><structfield>height</structfield></entry>
-           <entry>Height of the rectangle, in pixels. Width
-and height cannot be negative, the fields are signed for
-hysterical reasons. <!-- video4linux-list@redhat.com
-on 22 Oct 2002 subject "Re:[V4L][patches!] Re:v4l2/kernel-2.5" -->
-</entry>
+           <entry>Height of the rectangle, in pixels.</entry>
          </row>
        </tbody>
       </tgroup>
index 716ea15e54a174be6321f19aa4be69fe00487f28..65dff55079d71763942fc8991ee8ae76a80bc65d 100644 (file)
@@ -59,7 +59,7 @@ buffers are filled (if there are any empty buffers in the incoming
 queue) until <constant>VIDIOC_STREAMON</constant> has been called.
 Accordingly the output hardware is disabled, no video signal is
 produced until <constant>VIDIOC_STREAMON</constant> has been called.
-The ioctl will succeed only when at least one output buffer is in the
+The ioctl will succeed when at least one output buffer is in the
 incoming queue.</para>
 
     <para>The <constant>VIDIOC_STREAMOFF</constant> ioctl, apart of
index 8df5e8e6dceba06846042d0c6155fd4e986addd8..2101e718670d0248110caa4320e51e83c715fad2 100644 (file)
@@ -447,14 +447,13 @@ struct bio_vec {
  * main unit of I/O for the block layer and lower layers (ie drivers)
  */
 struct bio {
-       sector_t            bi_sector;
        struct bio          *bi_next;    /* request queue link */
        struct block_device *bi_bdev;   /* target device */
        unsigned long       bi_flags;    /* status, command, etc */
        unsigned long       bi_rw;       /* low bits: r/w, high: priority */
 
        unsigned int    bi_vcnt;     /* how may bio_vec's */
-       unsigned int    bi_idx;         /* current index into bio_vec array */
+       struct bvec_iter        bi_iter;        /* current index into bio_vec array */
 
        unsigned int    bi_size;     /* total size in bytes */
        unsigned short  bi_phys_segments; /* segments after physaddr coalesce*/
@@ -480,7 +479,7 @@ With this multipage bio design:
 - Code that traverses the req list can find all the segments of a bio
   by using rq_for_each_segment.  This handles the fact that a request
   has multiple bios, each of which can have multiple segments.
-- Drivers which can't process a large bio in one shot can use the bi_idx
+- Drivers which can't process a large bio in one shot can use the bi_iter
   field to keep track of the next bio_vec entry to process.
   (e.g a 1MB bio_vec needs to be handled in max 128kB chunks for IDE)
   [TBD: Should preferably also have a bi_voffset and bi_vlen to avoid modifying
@@ -589,7 +588,7 @@ driver should not modify these values. The block layer sets up the
 nr_sectors and current_nr_sectors fields (based on the corresponding
 hard_xxx values and the number of bytes transferred) and updates it on
 every transfer that invokes end_that_request_first. It does the same for the
-buffer, bio, bio->bi_idx fields too.
+buffer, bio, bio->bi_iter fields too.
 
 The buffer field is just a virtual address mapping of the current segment
 of the i/o buffer in cases where the buffer resides in low-memory. For high
diff --git a/Documentation/block/biovecs.txt b/Documentation/block/biovecs.txt
new file mode 100644 (file)
index 0000000..74a32ad
--- /dev/null
@@ -0,0 +1,111 @@
+
+Immutable biovecs and biovec iterators:
+=======================================
+
+Kent Overstreet <kmo@daterainc.com>
+
+As of 3.13, biovecs should never be modified after a bio has been submitted.
+Instead, we have a new struct bvec_iter which represents a range of a biovec -
+the iterator will be modified as the bio is completed, not the biovec.
+
+More specifically, old code that needed to partially complete a bio would
+update bi_sector and bi_size, and advance bi_idx to the next biovec. If it
+ended up partway through a biovec, it would increment bv_offset and decrement
+bv_len by the number of bytes completed in that biovec.
+
+In the new scheme of things, everything that must be mutated in order to
+partially complete a bio is segregated into struct bvec_iter: bi_sector,
+bi_size and bi_idx have been moved there; and instead of modifying bv_offset
+and bv_len, struct bvec_iter has bi_bvec_done, which represents the number of
+bytes completed in the current bvec.
+
+There are a bunch of new helper macros for hiding the gory details - in
+particular, presenting the illusion of partially completed biovecs so that
+normal code doesn't have to deal with bi_bvec_done.
+
+ * Driver code should no longer refer to biovecs directly; we now have
+   bio_iovec() and bio_iovec_iter() macros that return literal struct biovecs,
+   constructed from the raw biovecs but taking into account bi_bvec_done and
+   bi_size.
+
+   bio_for_each_segment() has been updated to take a bvec_iter argument
+   instead of an integer (that corresponded to bi_idx); for a lot of code the
+   conversion just required changing the types of the arguments to
+   bio_for_each_segment().
+
+ * Advancing a bvec_iter is done with bio_advance_iter(); bio_advance() is a
+   wrapper around bio_advance_iter() that operates on bio->bi_iter, and also
+   advances the bio integrity's iter if present.
+
+   There is a lower level advance function - bvec_iter_advance() - which takes
+   a pointer to a biovec, not a bio; this is used by the bio integrity code.
+
+What's all this get us?
+=======================
+
+Having a real iterator, and making biovecs immutable, has a number of
+advantages:
+
+ * Before, iterating over bios was very awkward when you weren't processing
+   exactly one bvec at a time - for example, bio_copy_data() in fs/bio.c,
+   which copies the contents of one bio into another. Because the biovecs
+   wouldn't necessarily be the same size, the old code was tricky convoluted -
+   it had to walk two different bios at the same time, keeping both bi_idx and
+   and offset into the current biovec for each.
+
+   The new code is much more straightforward - have a look. This sort of
+   pattern comes up in a lot of places; a lot of drivers were essentially open
+   coding bvec iterators before, and having common implementation considerably
+   simplifies a lot of code.
+
+ * Before, any code that might need to use the biovec after the bio had been
+   completed (perhaps to copy the data somewhere else, or perhaps to resubmit
+   it somewhere else if there was an error) had to save the entire bvec array
+   - again, this was being done in a fair number of places.
+
+ * Biovecs can be shared between multiple bios - a bvec iter can represent an
+   arbitrary range of an existing biovec, both starting and ending midway
+   through biovecs. This is what enables efficient splitting of arbitrary
+   bios. Note that this means we _only_ use bi_size to determine when we've
+   reached the end of a bio, not bi_vcnt - and the bio_iovec() macro takes
+   bi_size into account when constructing biovecs.
+
+ * Splitting bios is now much simpler. The old bio_split() didn't even work on
+   bios with more than a single bvec! Now, we can efficiently split arbitrary
+   size bios - because the new bio can share the old bio's biovec.
+
+   Care must be taken to ensure the biovec isn't freed while the split bio is
+   still using it, in case the original bio completes first, though. Using
+   bio_chain() when splitting bios helps with this.
+
+ * Submitting partially completed bios is now perfectly fine - this comes up
+   occasionally in stacking block drivers and various code (e.g. md and
+   bcache) had some ugly workarounds for this.
+
+   It used to be the case that submitting a partially completed bio would work
+   fine to _most_ devices, but since accessing the raw bvec array was the
+   norm, not all drivers would respect bi_idx and those would break. Now,
+   since all drivers _must_ go through the bvec iterator - and have been
+   audited to make sure they are - submitting partially completed bios is
+   perfectly fine.
+
+Other implications:
+===================
+
+ * Almost all usage of bi_idx is now incorrect and has been removed; instead,
+   where previously you would have used bi_idx you'd now use a bvec_iter,
+   probably passing it to one of the helper macros.
+
+   I.e. instead of using bio_iovec_idx() (or bio->bi_iovec[bio->bi_idx]), you
+   now use bio_iter_iovec(), which takes a bvec_iter and returns a
+   literal struct bio_vec - constructed on the fly from the raw biovec but
+   taking into account bi_bvec_done (and bi_size).
+
+ * bi_vcnt can't be trusted or relied upon by driver code - i.e. anything that
+   doesn't actually own the bio. The reason is twofold: firstly, it's not
+   actually needed for iterating over the bio anymore - we only use bi_size.
+   Secondly, when cloning a bio and reusing (a portion of) the original bio's
+   biovec, in order to calculate bi_vcnt for the new bio we'd have to iterate
+   over all the biovecs in the new bio - which is silly as it's not needed.
+
+   So, don't use bi_vcnt anymore.
similarity index 90%
rename from drivers/staging/zram/zram.txt
rename to Documentation/blockdev/zram.txt
index 765d790ae83102bc11d2770cd01a1b6501c2fe8e..2eccddffa6c8fde5cdd4d5cc49cecab0b82b8206 100644 (file)
@@ -1,8 +1,6 @@
 zram: Compressed RAM based block devices
 ----------------------------------------
 
-Project home: http://compcache.googlecode.com/
-
 * Introduction
 
 The zram module creates RAM based block devices named /dev/zram<id>
@@ -69,9 +67,5 @@ Following shows a typical sequence of steps for using zram.
        resets the disksize to zero. You must set the disksize again
        before reusing the device.
 
-Please report any problems at:
- - Mailing list: linux-mm-cc at laptop dot org
- - Issue tracker: http://code.google.com/p/compcache/issues/list
-
 Nitin Gupta
 ngupta@vflare.org
index 52e1da16a3094218f6e5d36d6bd2a0a16551810e..5108afb3645c49d948cd97e7c827b2d5599e499e 100644 (file)
@@ -95,7 +95,7 @@ to work with it.
 
  f. u64 res_counter_uncharge_until
                (struct res_counter *rc, struct res_counter *top,
-                unsinged long val)
+                unsigned long val)
 
        Almost same as res_counter_uncharge() but propagation of uncharge
        stops when rc == top. This is useful when kill a res_counter in
index 611f5a5499b153c9594ad37e7237f7a35489b3bd..fa0151a712f9c5a0d9fe43db6e0746ff4046a5e0 100644 (file)
@@ -22,10 +22,12 @@ locations such as buffers like the printk buffer or the process table.
 Retrieving a full system memory dump is also possible over the FireWire,
 using data transfer rates in the order of 10MB/s or more.
 
-Memory access is currently limited to the low 4G of physical address
-space which can be a problem on IA64 machines where memory is located
-mostly above that limit, but it is rarely a problem on more common
-hardware such as hardware based on x86, x86-64 and PowerPC.
+With most FireWire controllers, memory access is limited to the low 4 GB
+of physical address space.  This can be a problem on IA64 machines where
+memory is located mostly above that limit, but it is rarely a problem on
+more common hardware such as x86, x86-64 and PowerPC.  However, at least
+Agere/LSI FW643e and FW643e2 controllers are known to support access to
+physical addresses above 4 GB.
 
 Together with a early initialization of the OHCI-1394 controller for debugging,
 this facility proved most useful for examining long debugs logs in the printk
@@ -36,17 +38,11 @@ available (notebooks) or too slow for extensive debug information (like ACPI).
 Drivers
 -------
 
-The ohci1394 driver in drivers/ieee1394 initializes the OHCI-1394 controllers
-to a working state and enables physical DMA by default for all remote nodes.
-This can be turned off by ohci1394's module parameter phys_dma=0.
-
-The alternative firewire-ohci driver in drivers/firewire uses filtered physical
+The firewire-ohci driver in drivers/firewire uses filtered physical
 DMA by default, which is more secure but not suitable for remote debugging.
-Compile the driver with CONFIG_FIREWIRE_OHCI_REMOTE_DMA (Kernel hacking menu:
-Remote debugging over FireWire with firewire-ohci) to get unfiltered physical
-DMA.
+Pass the remote_dma=1 parameter to the driver to get unfiltered physical DMA.
 
-Because ohci1394 and firewire-ohci depend on the PCI enumeration to be
+Because the firewire-ohci driver depends on the PCI enumeration to be
 completed, an initialization routine which runs pretty early has been
 implemented for x86.  This routine runs long before console_init() can be
 called, i.e. before the printk buffer appears on the console.
@@ -64,7 +60,7 @@ be used to view the printk buffer of a remote machine, even with live update.
 
 Bernhard Kaindl enhanced firescope to support accessing 64-bit machines
 from 32-bit firescope and vice versa:
-- http://halobates.de/firewire/firescope-0.2.2.tar.bz2
+- http://v3.sk/~lkundrak/firescope/
 
 and he implemented fast system dump (alpha version - read README.txt):
 - http://halobates.de/firewire/firedump-0.1.tar.bz2
@@ -92,11 +88,11 @@ Step-by-step instructions for using firescope with early OHCI initialization:
 
 1) Verify that your hardware is supported:
 
-   Load the ohci1394 or the fw-ohci module and check your kernel logs.
+   Load the firewire-ohci module and check your kernel logs.
    You should see a line similar to
 
-   ohci1394: fw-host0: OHCI-1394 1.1 (PCI): IRQ=[18]  MMIO=[fe9ff800-fe9fffff]
-   ... Max Packet=[2048]  IR/IT contexts=[4/8]
+   firewire_ohci 0000:15:00.1: added OHCI v1.0 device as card 2, 4 IR + 4 IT
+   ... contexts, quirks 0x11
 
    when loading the driver. If you have no supported controller, many PCI,
    CardBus and even some Express cards which are fully compliant to OHCI-1394
@@ -105,6 +101,9 @@ Step-by-step instructions for using firescope with early OHCI initialization:
    compliant, they are based on TI PCILynx chips and require drivers for Win-
    dows operating systems.
 
+   The mentioned kernel log message contains ">4 GB phys DMA" in case of
+   OHCI-1394 controllers which support accesses above this limit.
+
 2) Establish a working FireWire cable connection:
 
    Any FireWire cable, as long at it provides electrically and mechanically
@@ -113,20 +112,18 @@ Step-by-step instructions for using firescope with early OHCI initialization:
 
    If an driver is running on both machines you should see a line like
 
-   ieee1394: Node added: ID:BUS[0-01:1023]  GUID[0090270001b84bba]
+   firewire_core 0000:15:00.1: created device fw1: GUID 00061b0020105917, S400
 
    on both machines in the kernel log when the cable is plugged in
    and connects the two machines.
 
 3) Test physical DMA using firescope:
 
-   On the debug host,
-       - load the raw1394 module,
-       - make sure that /dev/raw1394 is accessible,
+   On the debug host, make sure that /dev/fw* is accessible,
    then start firescope:
 
        $ firescope
-       Port 0 (ohci1394) opened, 2 nodes detected
+       Port 0 (/dev/fw1) opened, 2 nodes detected
 
        FireScope
        ---------
index 17d88b233d1bce30a6d0f6a1752181936dc2a07e..39adf54b4388b919bc7ed465b93e4200e86000cc 100644 (file)
@@ -8,13 +8,18 @@ Required properties:
 - DEPRECATED: compatible : "bcm,kona-timer"
 - reg : Register range for the timer
 - interrupts : interrupt for the timer
+- clocks: phandle + clock specifier pair of the external clock
 - clock-frequency: frequency that the clock operates
 
+Only one of clocks or clock-frequency should be specified.
+
+Refer to clocks/clock-bindings.txt for generic clock consumer properties.
+
 Example:
        timer@35006000 {
                compatible = "brcm,kona-timer";
                reg = <0x35006000 0x1000>;
                interrupts = <0x0 7 0x4>;
-               clock-frequency = <32768>;
+               clocks = <&hub_timer_clk>;
        };
 
diff --git a/Documentation/devicetree/bindings/arm/davinci/nand.txt b/Documentation/devicetree/bindings/arm/davinci/nand.txt
deleted file mode 100644 (file)
index 3545ea7..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-* Texas Instruments Davinci NAND
-
-This file provides information, what the device node for the
-davinci nand interface contain.
-
-Required properties:
-- compatible: "ti,davinci-nand";
-- reg : contain 2 offset/length values:
-        - offset and length for the access window
-        - offset and length for accessing the aemif control registers
-- ti,davinci-chipselect: Indicates on the davinci_nand driver which
-                         chipselect is used for accessing the nand.
-
-Recommended properties :
-- ti,davinci-mask-ale: mask for ale
-- ti,davinci-mask-cle: mask for cle
-- ti,davinci-mask-chipsel: mask for chipselect
-- ti,davinci-ecc-mode: ECC mode valid values for davinci driver:
-               - "none"
-               - "soft"
-               - "hw"
-- ti,davinci-ecc-bits: used ECC bits, currently supported 1 or 4.
-- ti,davinci-nand-buswidth: buswidth 8 or 16
-- ti,davinci-nand-use-bbt: use flash based bad block table support.
-
-nand device bindings may contain additional sub-nodes describing
-partitions of the address space. See partition.txt for more detail.
-
-Example(da850 EVM ):
-nand_cs3@62000000 {
-       compatible = "ti,davinci-nand";
-       reg = <0x62000000 0x807ff
-               0x68000000 0x8000>;
-       ti,davinci-chipselect = <1>;
-       ti,davinci-mask-ale = <0>;
-       ti,davinci-mask-cle = <0>;
-       ti,davinci-mask-chipsel = <0>;
-       ti,davinci-ecc-mode = "hw";
-       ti,davinci-ecc-bits = <4>;
-       ti,davinci-nand-use-bbt;
-
-       partition@180000 {
-               label = "ubifs";
-               reg = <0x180000 0x7e80000>;
-       };
-};
diff --git a/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt b/Documentation/devicetree/bindings/clock/bcm-kona-clock.txt
new file mode 100644 (file)
index 0000000..56d1f49
--- /dev/null
@@ -0,0 +1,93 @@
+Broadcom Kona Family Clocks
+
+This binding is associated with Broadcom SoCs having "Kona" style
+clock control units (CCUs).  A CCU is a clock provider that manages
+a set of clock signals.  Each CCU is represented by a node in the
+device tree.
+
+This binding uses the common clock binding:
+    Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible
+       Shall have one of the following values:
+       - "brcm,bcm11351-root-ccu"
+       - "brcm,bcm11351-aon-ccu"
+       - "brcm,bcm11351-hub-ccu"
+       - "brcm,bcm11351-master-ccu"
+       - "brcm,bcm11351-slave-ccu"
+- reg
+       Shall define the base and range of the address space
+       containing clock control registers
+- #clock-cells
+       Shall have value <1>.  The permitted clock-specifier values
+       are defined below.
+- clock-output-names
+       Shall be an ordered list of strings defining the names of
+       the clocks provided by the CCU.
+
+
+BCM281XX family SoCs use Kona CCUs.  The following table defines
+the set of CCUs and clock specifiers for BCM281XX clocks.  When
+a clock consumer references a clocks, its symbolic specifier
+(rather than its numeric index value) should be used.  These
+specifiers are defined in "include/dt-bindings/clock/bcm281xx.h".
+
+    CCU     Clock           Type    Index   Specifier
+    ---     -----           ----    -----   ---------
+    root    frac_1m         peri      0     BCM281XX_ROOT_CCU_FRAC_1M
+
+    aon     hub_timer       peri      0     BCM281XX_AON_CCU_HUB_TIMER
+    aon     pmu_bsc         peri      1     BCM281XX_AON_CCU_PMU_BSC
+    aon     pmu_bsc_var     peri      2     BCM281XX_AON_CCU_PMU_BSC_VAR
+
+    hub     tmon_1m         peri      0     BCM281XX_HUB_CCU_TMON_1M
+
+    master  sdio1           peri      0     BCM281XX_MASTER_CCU_SDIO1
+    master  sdio2           peri      1     BCM281XX_MASTER_CCU_SDIO2
+    master  sdio3           peri      2     BCM281XX_MASTER_CCU_SDIO3
+    master  sdio4           peri      3     BCM281XX_MASTER_CCU_SDIO4
+    master  dmac            peri      4     BCM281XX_MASTER_CCU_DMAC
+    master  usb_ic          peri      5     BCM281XX_MASTER_CCU_USB_IC
+    master  hsic2_48m       peri      6     BCM281XX_MASTER_CCU_HSIC_48M
+    master  hsic2_12m       peri      7     BCM281XX_MASTER_CCU_HSIC_12M
+
+    slave   uartb           peri      0     BCM281XX_SLAVE_CCU_UARTB
+    slave   uartb2          peri      1     BCM281XX_SLAVE_CCU_UARTB2
+    slave   uartb3          peri      2     BCM281XX_SLAVE_CCU_UARTB3
+    slave   uartb4          peri      3     BCM281XX_SLAVE_CCU_UARTB4
+    slave   ssp0            peri      4     BCM281XX_SLAVE_CCU_SSP0
+    slave   ssp2            peri      5     BCM281XX_SLAVE_CCU_SSP2
+    slave   bsc1            peri      6     BCM281XX_SLAVE_CCU_BSC1
+    slave   bsc2            peri      7     BCM281XX_SLAVE_CCU_BSC2
+    slave   bsc3            peri      8     BCM281XX_SLAVE_CCU_BSC3
+    slave   pwm             peri      9     BCM281XX_SLAVE_CCU_PWM
+
+
+Device tree example:
+
+       slave_ccu: slave_ccu {
+               compatible = "brcm,bcm11351-slave-ccu";
+               reg = <0x3e011000 0x0f00>;
+               #clock-cells = <1>;
+               clock-output-names = "uartb",
+                                    "uartb2",
+                                    "uartb3",
+                                    "uartb4";
+       };
+
+       ref_crystal_clk: ref_crystal {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <26000000>;
+       };
+
+       uart@3e002000 {
+               compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
+               status = "disabled";
+               reg = <0x3e002000 0x1000>;
+               clocks = <&slave_ccu BCM281XX_SLAVE_CCU_UARTB3>;
+               interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+               reg-shift = <2>;
+               reg-io-width = <4>;
+       };
diff --git a/Documentation/devicetree/bindings/clock/corenet-clock.txt b/Documentation/devicetree/bindings/clock/corenet-clock.txt
new file mode 100644 (file)
index 0000000..24711af
--- /dev/null
@@ -0,0 +1,134 @@
+* Clock Block on Freescale CoreNet Platforms
+
+Freescale CoreNet chips take primary clocking input from the external
+SYSCLK signal. The SYSCLK input (frequency) is multiplied using
+multiple phase locked loops (PLL) to create a variety of frequencies
+which can then be passed to a variety of internal logic, including
+cores and peripheral IP blocks.
+Please refer to the Reference Manual for details.
+
+1. Clock Block Binding
+
+Required properties:
+- compatible: Should contain a specific clock block compatible string
+       and a single chassis clock compatible string.
+       Clock block strings include, but not limited to, one of the:
+       * "fsl,p2041-clockgen"
+       * "fsl,p3041-clockgen"
+       * "fsl,p4080-clockgen"
+       * "fsl,p5020-clockgen"
+       * "fsl,p5040-clockgen"
+       * "fsl,t4240-clockgen"
+       * "fsl,b4420-clockgen"
+       * "fsl,b4860-clockgen"
+       Chassis clock strings include:
+       * "fsl,qoriq-clockgen-1.0": for chassis 1.0 clocks
+       * "fsl,qoriq-clockgen-2.0": for chassis 2.0 clocks
+- reg: Describes the address of the device's resources within the
+       address space defined by its parent bus, and resource zero
+       represents the clock register set
+- clock-frequency: Input system clock frequency
+
+Recommended properties:
+- ranges: Allows valid translation between child's address space and
+       parent's. Must be present if the device has sub-nodes.
+- #address-cells: Specifies the number of cells used to represent
+       physical base addresses.  Must be present if the device has
+       sub-nodes and set to 1 if present
+- #size-cells: Specifies the number of cells used to represent
+       the size of an address. Must be present if the device has
+       sub-nodes and set to 1 if present
+
+2. Clock Provider/Consumer Binding
+
+Most of the bindings are from the common clock binding[1].
+ [1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : Should include one of the following:
+       * "fsl,qoriq-core-pll-1.0" for core PLL clocks (v1.0)
+       * "fsl,qoriq-core-pll-2.0" for core PLL clocks (v2.0)
+       * "fsl,qoriq-core-mux-1.0" for core mux clocks (v1.0)
+       * "fsl,qoriq-core-mux-2.0" for core mux clocks (v2.0)
+       * "fsl,qoriq-sysclk-1.0": for input system clock (v1.0).
+               It takes parent's clock-frequency as its clock.
+       * "fsl,qoriq-sysclk-2.0": for input system clock (v2.0).
+               It takes parent's clock-frequency as its clock.
+- #clock-cells: From common clock binding. The number of cells in a
+       clock-specifier. Should be <0> for "fsl,qoriq-sysclk-[1,2].0"
+       clocks, or <1> for "fsl,qoriq-core-pll-[1,2].0" clocks.
+       For "fsl,qoriq-core-pll-[1,2].0" clocks, the single
+       clock-specifier cell may take the following values:
+       * 0 - equal to the PLL frequency
+       * 1 - equal to the PLL frequency divided by 2
+       * 2 - equal to the PLL frequency divided by 4
+
+Recommended properties:
+- clocks: Should be the phandle of input parent clock
+- clock-names: From common clock binding, indicates the clock name
+- clock-output-names: From common clock binding, indicates the names of
+       output clocks
+- reg: Should be the offset and length of clock block base address.
+       The length should be 4.
+
+Example for clock block and clock provider:
+/ {
+       clockgen: global-utilities@e1000 {
+               compatible = "fsl,p5020-clockgen", "fsl,qoriq-clockgen-1.0";
+               ranges = <0x0 0xe1000 0x1000>;
+               clock-frequency = <133333333>;
+               reg = <0xe1000 0x1000>;
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               sysclk: sysclk {
+                       #clock-cells = <0>;
+                       compatible = "fsl,qoriq-sysclk-1.0";
+                       clock-output-names = "sysclk";
+               }
+
+               pll0: pll0@800 {
+                       #clock-cells = <1>;
+                       reg = <0x800 0x4>;
+                       compatible = "fsl,qoriq-core-pll-1.0";
+                       clocks = <&sysclk>;
+                       clock-output-names = "pll0", "pll0-div2";
+               };
+
+               pll1: pll1@820 {
+                       #clock-cells = <1>;
+                       reg = <0x820 0x4>;
+                       compatible = "fsl,qoriq-core-pll-1.0";
+                       clocks = <&sysclk>;
+                       clock-output-names = "pll1", "pll1-div2";
+               };
+
+               mux0: mux0@0 {
+                       #clock-cells = <0>;
+                       reg = <0x0 0x4>;
+                       compatible = "fsl,qoriq-core-mux-1.0";
+                       clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+                       clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+                       clock-output-names = "cmux0";
+               };
+
+               mux1: mux1@20 {
+                       #clock-cells = <0>;
+                       reg = <0x20 0x4>;
+                       compatible = "fsl,qoriq-core-mux-1.0";
+                       clocks = <&pll0 0>, <&pll0 1>, <&pll1 0>, <&pll1 1>;
+                       clock-names = "pll0", "pll0-div2", "pll1", "pll1-div2";
+                       clock-output-names = "cmux1";
+               };
+       };
+  }
+
+Example for clock consumer:
+
+/ {
+       cpu0: PowerPC,e5500@0 {
+               ...
+               clocks = <&mux0>;
+               ...
+       };
+  }
diff --git a/Documentation/devicetree/bindings/clock/ti/apll.txt b/Documentation/devicetree/bindings/clock/ti/apll.txt
new file mode 100644 (file)
index 0000000..7faf5a6
--- /dev/null
@@ -0,0 +1,31 @@
+Binding for Texas Instruments APLL clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1].  It assumes a
+register-mapped APLL with usually two selectable input clocks
+(reference clock and bypass clock), with analog phase locked
+loop logic for multiplying the input clock to a desired output
+clock. This clock also typically supports different operation
+modes (locked, low power stop etc.) APLL mostly behaves like
+a subtype of a DPLL [2], although a simplified one at that.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/ti/dpll.txt
+
+Required properties:
+- compatible : shall be "ti,dra7-apll-clock"
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of parent clocks (clk-ref and clk-bypass)
+- reg : address and length of the register set for controlling the APLL.
+  It contains the information of registers in the following order:
+       "control" - contains the control register base address
+       "idlest" - contains the idlest register base address
+
+Examples:
+       apll_pcie_ck: apll_pcie_ck@4a008200 {
+               #clock-cells = <0>;
+               clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>;
+               reg = <0x4a00821c 0x4>, <0x4a008220 0x4>;
+               compatible = "ti,dra7-apll-clock";
+       };
diff --git a/Documentation/devicetree/bindings/clock/ti/autoidle.txt b/Documentation/devicetree/bindings/clock/ti/autoidle.txt
new file mode 100644 (file)
index 0000000..7c735dd
--- /dev/null
@@ -0,0 +1,39 @@
+Binding for Texas Instruments autoidle clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1]. It assumes a register mapped
+clock which can be put to idle automatically by hardware based on the usage
+and a configuration bit setting. Autoidle clock is never an individual
+clock, it is always a derivative of some basic clock like a gate, divider,
+or fixed-factor.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- reg : offset for the register controlling the autoidle
+- ti,autoidle-shift : bit shift of the autoidle enable bit
+- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0
+
+Examples:
+       dpll_core_m4_ck: dpll_core_m4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2d38>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck {
+               #clock-cells = <0>;
+               compatible = "ti,fixed-factor-clock";
+               clocks = <&dpll_usb_ck>;
+               ti,clock-div = <1>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01b4>;
+               ti,clock-mult = <1>;
+               ti,invert-autoidle-bit;
+       };
diff --git a/Documentation/devicetree/bindings/clock/ti/clockdomain.txt b/Documentation/devicetree/bindings/clock/ti/clockdomain.txt
new file mode 100644 (file)
index 0000000..cb76b3f
--- /dev/null
@@ -0,0 +1,24 @@
+Binding for Texas Instruments clockdomain.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1] in consumer role.
+Every clock on TI SoC belongs to one clockdomain, but software
+only needs this information for specific clocks which require
+their parent clockdomain to be controlled when the clock is
+enabled/disabled. This binding doesn't define a new clock
+binding type, it is used to group existing clock nodes under
+hardware hierarchy.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "ti,clockdomain"
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of clocks within this domain
+
+Examples:
+       dss_clkdm: dss_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>;
+       };
diff --git a/Documentation/devicetree/bindings/clock/ti/composite.txt b/Documentation/devicetree/bindings/clock/ti/composite.txt
new file mode 100644 (file)
index 0000000..5f43c47
--- /dev/null
@@ -0,0 +1,54 @@
+Binding for TI composite clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1]. It assumes a
+register-mapped composite clock with multiple different sub-types;
+
+a multiplexer clock with multiple input clock signals or parents, one
+of which can be selected as output, this behaves exactly as [2]
+
+an adjustable clock rate divider, this behaves exactly as [3]
+
+a gating function which can be used to enable and disable the output
+clock, this behaves exactly as [4]
+
+The binding must provide a list of the component clocks that shall be
+merged to this clock. The component clocks shall be of one of the
+"ti,*composite*-clock" types.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/ti/mux.txt
+[3] Documentation/devicetree/bindings/clock/ti/divider.txt
+[4] Documentation/devicetree/bindings/clock/ti/gate.txt
+
+Required properties:
+- compatible : shall be: "ti,composite-clock"
+- clocks : link phandles of component clocks
+- #clock-cells : from common clock binding; shall be set to 0.
+
+Examples:
+
+usb_l4_gate_ick: usb_l4_gate_ick {
+       #clock-cells = <0>;
+       compatible = "ti,composite-interface-clock";
+       clocks = <&l4_ick>;
+       ti,bit-shift = <5>;
+       reg = <0x0a10>;
+};
+
+usb_l4_div_ick: usb_l4_div_ick {
+       #clock-cells = <0>;
+       compatible = "ti,composite-divider-clock";
+       clocks = <&l4_ick>;
+       ti,bit-shift = <4>;
+       ti,max-div = <1>;
+       reg = <0x0a40>;
+       ti,index-starts-at-one;
+};
+
+usb_l4_ick: usb_l4_ick {
+       #clock-cells = <0>;
+       compatible = "ti,composite-clock";
+       clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>;
+};
diff --git a/Documentation/devicetree/bindings/clock/ti/divider.txt b/Documentation/devicetree/bindings/clock/ti/divider.txt
new file mode 100644 (file)
index 0000000..35a6f5c
--- /dev/null
@@ -0,0 +1,114 @@
+Binding for TI divider clock
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1].  It assumes a
+register-mapped adjustable clock rate divider that does not gate and has
+only one input clock or parent.  By default the value programmed into
+the register is one less than the actual divisor value.  E.g:
+
+register value         actual divisor value
+0                      1
+1                      2
+2                      3
+
+This assumption may be modified by the following optional properties:
+
+ti,index-starts-at-one - valid divisor values start at 1, not the default
+of 0.  E.g:
+register value         actual divisor value
+1                      1
+2                      2
+3                      3
+
+ti,index-power-of-two - valid divisor values are powers of two.  E.g:
+register value         actual divisor value
+0                      1
+1                      2
+2                      4
+
+Additionally an array of valid dividers may be supplied like so:
+
+       ti,dividers = <4>, <8>, <0>, <16>;
+
+Which will map the resulting values to a divisor table by their index:
+register value         actual divisor value
+0                      4
+1                      8
+2                      <invalid divisor, skipped>
+3                      16
+
+Any zero value in this array means the corresponding bit-value is invalid
+and must not be used.
+
+The binding must also provide the register to control the divider and
+unless the divider array is provided, min and max dividers. Optionally
+the number of bits to shift that mask, if necessary. If the shift value
+is missing it is the same as supplying a zero shift.
+
+This binding can also optionally provide support to the hardware autoidle
+feature, see [2].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt
+
+Required properties:
+- compatible : shall be "ti,divider-clock" or "ti,composite-divider-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link to phandle of parent clock
+- reg : offset for register controlling adjustable divider
+
+Optional properties:
+- clock-output-names : from common clock binding.
+- ti,dividers : array of integers defining divisors
+- ti,bit-shift : number of bits to shift the divider value, defaults to 0
+- ti,min-div : min divisor for dividing the input clock rate, only
+  needed if the first divisor is offset from the default value (1)
+- ti,max-div : max divisor for dividing the input clock rate, only needed
+  if ti,dividers is not defined.
+- ti,index-starts-at-one : valid divisor programming starts at 1, not zero,
+  only valid if ti,dividers is not defined.
+- ti,index-power-of-two : valid divisor programming must be a power of two,
+  only valid if ti,dividers is not defined.
+- ti,autoidle-shift : bit shift of the autoidle enable bit for the clock,
+  see [2]
+- ti,invert-autoidle-bit : autoidle is enabled by setting the bit to 0,
+  see [2]
+- ti,set-rate-parent : clk_set_rate is propagated to parent
+
+Examples:
+dpll_usb_m2_ck: dpll_usb_m2_ck@4a008190 {
+       #clock-cells = <0>;
+       compatible = "ti,divider-clock";
+       clocks = <&dpll_usb_ck>;
+       ti,max-div = <127>;
+       reg = <0x190>;
+       ti,index-starts-at-one;
+};
+
+aess_fclk: aess_fclk@4a004528 {
+       #clock-cells = <0>;
+       compatible = "ti,divider-clock";
+       clocks = <&abe_clk>;
+       ti,bit-shift = <24>;
+       reg = <0x528>;
+       ti,max-div = <2>;
+};
+
+dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck {
+       #clock-cells = <0>;
+       compatible = "ti,composite-divider-clock";
+       clocks = <&dpll_core_x2_ck>;
+       ti,max-div = <31>;
+       reg = <0x0134>;
+       ti,index-starts-at-one;
+};
+
+ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 {
+       #clock-cells = <0>;
+       compatible = "ti,composite-divider-clock";
+       clocks = <&corex2_fck>;
+       ti,bit-shift = <8>;
+       reg = <0x0a40>;
+       ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
+};
diff --git a/Documentation/devicetree/bindings/clock/ti/dpll.txt b/Documentation/devicetree/bindings/clock/ti/dpll.txt
new file mode 100644 (file)
index 0000000..30bfdb7
--- /dev/null
@@ -0,0 +1,75 @@
+Binding for Texas Instruments DPLL clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1].  It assumes a
+register-mapped DPLL with usually two selectable input clocks
+(reference clock and bypass clock), with digital phase locked
+loop logic for multiplying the input clock to a desired output
+clock. This clock also typically supports different operation
+modes (locked, low power stop etc.) This binding has several
+sub-types, which effectively result in slightly different setup
+for the actual DPLL clock.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be one of:
+               "ti,omap3-dpll-clock",
+               "ti,omap3-dpll-core-clock",
+               "ti,omap3-dpll-per-clock",
+               "ti,omap3-dpll-per-j-type-clock",
+               "ti,omap4-dpll-clock",
+               "ti,omap4-dpll-x2-clock",
+               "ti,omap4-dpll-core-clock",
+               "ti,omap4-dpll-m4xen-clock",
+               "ti,omap4-dpll-j-type-clock",
+               "ti,am3-dpll-no-gate-clock",
+               "ti,am3-dpll-j-type-clock",
+               "ti,am3-dpll-no-gate-j-type-clock",
+               "ti,am3-dpll-clock",
+               "ti,am3-dpll-core-clock",
+               "ti,am3-dpll-x2-clock",
+
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of parent clocks, first entry lists reference clock
+  and second entry bypass clock
+- reg : offsets for the register set for controlling the DPLL.
+  Registers are listed in following order:
+       "control" - contains the control register base address
+       "idlest" - contains the idle status register base address
+       "mult-div1" - contains the multiplier / divider register base address
+       "autoidle" - contains the autoidle register base address (optional)
+  ti,am3-* dpll types do not have autoidle register
+
+Optional properties:
+- DPLL mode setting - defining any one or more of the following overrides
+  default setting.
+       - ti,low-power-stop : DPLL supports low power stop mode, gating output
+       - ti,low-power-bypass : DPLL output matches rate of parent bypass clock
+       - ti,lock : DPLL locks in programmed rate
+
+Examples:
+       dpll_core_ck: dpll_core_ck@44e00490 {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-core-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x490>, <0x45c>, <0x488>, <0x468>;
+       };
+
+       dpll2_ck: dpll2_ck@48004004 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-dpll-clock";
+               clocks = <&sys_ck>, <&dpll2_fck>;
+               ti,low-power-stop;
+               ti,low-power-bypass;
+               ti,lock;
+               reg = <0x4>, <0x24>, <0x34>, <0x40>;
+       };
+
+       dpll_core_ck: dpll_core_ck@44e00490 {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-core-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x90>, <0x5c>, <0x68>;
+       };
diff --git a/Documentation/devicetree/bindings/clock/ti/fixed-factor-clock.txt b/Documentation/devicetree/bindings/clock/ti/fixed-factor-clock.txt
new file mode 100644 (file)
index 0000000..662b36d
--- /dev/null
@@ -0,0 +1,43 @@
+Binding for TI fixed factor rate clock sources.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1], and also uses the autoidle
+support from TI autoidle clock [2].
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/ti/autoidle.txt
+
+Required properties:
+- compatible : shall be "ti,fixed-factor-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- ti,clock-div: fixed divider.
+- ti,clock-mult: fixed multiplier.
+- clocks: parent clock.
+
+Optional properties:
+- ti,autoidle-shift: bit shift of the autoidle enable bit for the clock,
+  see [2]
+- reg: offset for the autoidle register of this clock, see [2]
+- ti,invert-autoidle-bit: autoidle is enabled by setting the bit to 0, see [2]
+- ti,set-rate-parent: clk_set_rate is propagated to parent
+
+Example:
+       clock {
+               compatible = "ti,fixed-factor-clock";
+               clocks = <&parentclk>;
+               #clock-cells = <0>;
+               ti,clock-div = <2>;
+               ti,clock-mult = <1>;
+       };
+
+       dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck {
+               #clock-cells = <0>;
+               compatible = "ti,fixed-factor-clock";
+               clocks = <&dpll_usb_ck>;
+               ti,clock-div = <1>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01b4>;
+               ti,clock-mult = <1>;
+               ti,invert-autoidle-bit;
+       };
diff --git a/Documentation/devicetree/bindings/clock/ti/gate.txt b/Documentation/devicetree/bindings/clock/ti/gate.txt
new file mode 100644 (file)
index 0000000..125281a
--- /dev/null
@@ -0,0 +1,85 @@
+Binding for Texas Instruments gate clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1]. This clock is
+quite much similar to the basic gate-clock [2], however,
+it supports a number of additional features. If no register
+is provided for this clock, the code assumes that a clockdomain
+will be controlled instead and the corresponding hw-ops for
+that is used.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/gate-clock.txt
+[3] Documentation/devicetree/bindings/clock/ti/clockdomain.txt
+
+Required properties:
+- compatible : shall be one of:
+  "ti,gate-clock" - basic gate clock
+  "ti,wait-gate-clock" - gate clock which waits until clock is active before
+                        returning from clk_enable()
+  "ti,dss-gate-clock" - gate clock with DSS specific hardware handling
+  "ti,am35xx-gate-clock" - gate clock with AM35xx specific hardware handling
+  "ti,clkdm-gate-clock" - clockdomain gate clock, which derives its functional
+                         clock directly from a clockdomain, see [3] how
+                         to map clockdomains properly
+  "ti,hsdiv-gate-clock" - gate clock with OMAP36xx specific hardware handling,
+                         required for a hardware errata
+- #clock-cells : from common clock binding; shall be set to 0
+- clocks : link to phandle of parent clock
+- reg : offset for register controlling adjustable gate, not needed for
+       ti,clkdm-gate-clock type
+
+Optional properties:
+- ti,bit-shift : bit shift for programming the clock gate, invalid for
+                ti,clkdm-gate-clock type
+- ti,set-bit-to-disable : inverts default gate programming. Setting the bit
+  gates the clock and clearing the bit ungates the clock.
+
+Examples:
+       mmchs2_fck: mmchs2_fck@48004a00 {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&core_96m_fck>;
+               reg = <0x48004a00 0x4>;
+               ti,bit-shift = <25>;
+       };
+
+       uart4_fck_am35xx: uart4_fck_am35xx {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_48m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <23>;
+       };
+
+       dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2@48004e00 {
+               #clock-cells = <0>;
+               compatible = "ti,dss-gate-clock";
+               clocks = <&dpll4_m4x2_ck>;
+               reg = <0x48004e00 0x4>;
+               ti,bit-shift = <0>;
+       };
+
+       emac_ick: emac_ick@4800259c {
+               #clock-cells = <0>;
+               compatible = "ti,am35xx-gate-clock";
+               clocks = <&ipss_ick>;
+               reg = <0x4800259c 0x4>;
+               ti,bit-shift = <1>;
+       };
+
+       emu_src_ck: emu_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,clkdm-gate-clock";
+               clocks = <&emu_src_mux_ck>;
+       };
+
+       dpll4_m2x2_ck: dpll4_m2x2_ck@48004d00 {
+               #clock-cells = <0>;
+               compatible = "ti,hsdiv-gate-clock";
+               clocks = <&dpll4_m2x2_mul_ck>;
+               ti,bit-shift = <0x1b>;
+               reg = <0x48004d00 0x4>;
+               ti,set-bit-to-disable;
+       };
diff --git a/Documentation/devicetree/bindings/clock/ti/interface.txt b/Documentation/devicetree/bindings/clock/ti/interface.txt
new file mode 100644 (file)
index 0000000..064e8ca
--- /dev/null
@@ -0,0 +1,54 @@
+Binding for Texas Instruments interface clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1]. This clock is
+quite much similar to the basic gate-clock [2], however,
+it supports a number of additional features, including
+companion clock finding (match corresponding functional gate
+clock) and hardware autoidle enable / disable.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+[2] Documentation/devicetree/bindings/clock/gate-clock.txt
+
+Required properties:
+- compatible : shall be one of:
+  "ti,omap3-interface-clock" - basic OMAP3 interface clock
+  "ti,omap3-no-wait-interface-clock" - interface clock which has no hardware
+                                      capability for waiting clock to be ready
+  "ti,omap3-hsotgusb-interface-clock" - interface clock with USB specific HW
+                                       handling
+  "ti,omap3-dss-interface-clock" - interface clock with DSS specific HW handling
+  "ti,omap3-ssi-interface-clock" - interface clock with SSI specific HW handling
+  "ti,am35xx-interface-clock" - interface clock with AM35xx specific HW handling
+- #clock-cells : from common clock binding; shall be set to 0
+- clocks : link to phandle of parent clock
+- reg : base address for the control register
+
+Optional properties:
+- ti,bit-shift : bit shift for the bit enabling/disabling the clock (default 0)
+
+Examples:
+       aes1_ick: aes1_ick@48004a14 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&security_l4_ick2>;
+               reg = <0x48004a14 0x4>;
+               ti,bit-shift = <3>;
+       };
+
+       cam_ick: cam_ick@48004f10 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-no-wait-interface-clock";
+               clocks = <&l4_ick>;
+               reg = <0x48004f10 0x4>;
+               ti,bit-shift = <0>;
+       };
+
+       ssi_ick_3430es2: ssi_ick_3430es2@48004a10 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-ssi-interface-clock";
+               clocks = <&ssi_l4_ick>;
+               reg = <0x48004a10 0x4>;
+               ti,bit-shift = <0>;
+       };
diff --git a/Documentation/devicetree/bindings/clock/ti/mux.txt b/Documentation/devicetree/bindings/clock/ti/mux.txt
new file mode 100644 (file)
index 0000000..2d0d170
--- /dev/null
@@ -0,0 +1,76 @@
+Binding for TI mux clock.
+
+Binding status: Unstable - ABI compatibility may be broken in the future
+
+This binding uses the common clock binding[1].  It assumes a
+register-mapped multiplexer with multiple input clock signals or
+parents, one of which can be selected as output.  This clock does not
+gate or adjust the parent rate via a divider or multiplier.
+
+By default the "clocks" property lists the parents in the same order
+as they are programmed into the regster.  E.g:
+
+       clocks = <&foo_clock>, <&bar_clock>, <&baz_clock>;
+
+results in programming the register as follows:
+
+register value         selected parent clock
+0                      foo_clock
+1                      bar_clock
+2                      baz_clock
+
+Some clock controller IPs do not allow a value of zero to be programmed
+into the register, instead indexing begins at 1.  The optional property
+"index-starts-at-one" modified the scheme as follows:
+
+register value         selected clock parent
+1                      foo_clock
+2                      bar_clock
+3                      baz_clock
+
+The binding must provide the register to control the mux. Optionally
+the number of bits to shift the control field in the register can be
+supplied. If the shift value is missing it is the same as supplying
+a zero shift.
+
+[1] Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Required properties:
+- compatible : shall be "ti,mux-clock" or "ti,composite-mux-clock".
+- #clock-cells : from common clock binding; shall be set to 0.
+- clocks : link phandles of parent clocks
+- reg : register offset for register controlling adjustable mux
+
+Optional properties:
+- ti,bit-shift : number of bits to shift the bit-mask, defaults to
+  0 if not present
+- ti,index-starts-at-one : valid input select programming starts at 1, not
+  zero
+- ti,set-rate-parent : clk_set_rate is propagated to parent clock,
+  not supported by the composite-mux-clock subtype
+
+Examples:
+
+sys_clkin_ck: sys_clkin_ck@4a306110 {
+       #clock-cells = <0>;
+       compatible = "ti,mux-clock";
+       clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>;
+       reg = <0x0110>;
+       ti,index-starts-at-one;
+};
+
+abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck@4a306108 {
+       #clock-cells = <0>;
+       compatible = "ti,mux-clock";
+       clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+       ti,bit-shift = <24>;
+       reg = <0x0108>;
+};
+
+mcbsp5_mux_fck: mcbsp5_mux_fck {
+       #clock-cells = <0>;
+       compatible = "ti,composite-mux-clock";
+       clocks = <&core_96m_fck>, <&mcbsp_clks>;
+       ti,bit-shift = <4>;
+       reg = <0x02d8>;
+};
diff --git a/Documentation/devicetree/bindings/dma/bcm2835-dma.txt b/Documentation/devicetree/bindings/dma/bcm2835-dma.txt
new file mode 100644 (file)
index 0000000..1396078
--- /dev/null
@@ -0,0 +1,57 @@
+* BCM2835 DMA controller
+
+The BCM2835 DMA controller has 16 channels in total.
+Only the lower 13 channels have an associated IRQ.
+Some arbitrary channels are used by the firmware
+(1,3,6,7 in the current firmware version).
+The channels 0,2 and 3 have special functionality
+and should not be used by the driver.
+
+Required properties:
+- compatible: Should be "brcm,bcm2835-dma".
+- reg: Should contain DMA registers location and length.
+- interrupts: Should contain the DMA interrupts associated
+               to the DMA channels in ascending order.
+- #dma-cells: Must be <1>, the cell in the dmas property of the
+               client device represents the DREQ number.
+- brcm,dma-channel-mask: Bit mask representing the channels
+                        not used by the firmware in ascending order,
+                        i.e. first channel corresponds to LSB.
+
+Example:
+
+dma: dma@7e007000 {
+       compatible = "brcm,bcm2835-dma";
+       reg = <0x7e007000 0xf00>;
+       interrupts = <1 16>,
+                    <1 17>,
+                    <1 18>,
+                    <1 19>,
+                    <1 20>,
+                    <1 21>,
+                    <1 22>,
+                    <1 23>,
+                    <1 24>,
+                    <1 25>,
+                    <1 26>,
+                    <1 27>,
+                    <1 28>;
+
+       #dma-cells = <1>;
+       brcm,dma-channel-mask = <0x7f35>;
+};
+
+DMA clients connected to the BCM2835 DMA controller must use the format
+described in the dma.txt file, using a two-cell specifier for each channel.
+
+Example:
+
+bcm2835_i2s: i2s@7e203000 {
+       compatible = "brcm,bcm2835-i2s";
+       reg = < 0x7e203000 0x20>,
+             < 0x7e101098 0x02>;
+
+       dmas = <&dma 2>,
+              <&dma 3>;
+       dma-names = "tx", "rx";
+};
index 4fa814d3832124adb80f29ee777849739acbb7e4..68b83ecc385007216d391f1a0edf06527dad5fb9 100644 (file)
@@ -42,6 +42,7 @@ The full ID of peripheral types can be found below.
        19      IPU Memory
        20      ASRC
        21      ESAI
+       22      SSI Dual FIFO   (needs firmware ver >= 2)
 
 The third cell specifies the transfer priority as below.
 
diff --git a/Documentation/devicetree/bindings/dma/moxa,moxart-dma.txt b/Documentation/devicetree/bindings/dma/moxa,moxart-dma.txt
new file mode 100644 (file)
index 0000000..8a9f355
--- /dev/null
@@ -0,0 +1,45 @@
+MOXA ART DMA Controller
+
+See dma.txt first
+
+Required properties:
+
+- compatible : Must be "moxa,moxart-dma"
+- reg :                Should contain registers location and length
+- interrupts : Should contain an interrupt-specifier for the sole
+               interrupt generated by the device
+- #dma-cells : Should be 1, a single cell holding a line request number
+
+Example:
+
+       dma: dma@90500000 {
+               compatible = "moxa,moxart-dma";
+               reg = <0x90500080 0x40>;
+               interrupts = <24 0>;
+               #dma-cells = <1>;
+       };
+
+
+Clients:
+
+DMA clients connected to the MOXA ART DMA controller must use the format
+described in the dma.txt file, using a two-cell specifier for each channel:
+a phandle plus one integer cells.
+The two cells in order are:
+
+1. A phandle pointing to the DMA controller.
+2. Peripheral identifier for the hardware handshaking interface.
+
+Example:
+Use specific request line passing from dma
+For example, MMC request line is 5
+
+       sdhci: sdhci@98e00000 {
+               compatible = "moxa,moxart-sdhci";
+               reg = <0x98e00000 0x5C>;
+               interrupts = <5 0>;
+               clocks = <&clk_apb>;
+               dmas =  <&dma 5>,
+                       <&dma 5>;
+               dma-names = "tx", "rx";
+       };
index ab45c02aa658f666b78b1f4bedf4dc87255033db..efaeec8961b64bddba0df9d48af9af65e630f659 100644 (file)
@@ -118,6 +118,9 @@ of the following host1x client modules:
     See ../reset/reset.txt for details.
   - reset-names: Must include the following entries:
     - dc
+  - nvidia,head: The number of the display controller head. This is used to
+    setup the various types of output to receive video data from the given
+    head.
 
   Each display controller node has a child node, named "rgb", that represents
   the RGB output associated with the controller. It can take the following
@@ -125,6 +128,7 @@ of the following host1x client modules:
   - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
   - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
   - nvidia,edid: supplies a binary EDID blob
+  - nvidia,panel: phandle of a display panel
 
 - hdmi: High Definition Multimedia Interface
 
@@ -149,6 +153,7 @@ of the following host1x client modules:
   - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
   - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
   - nvidia,edid: supplies a binary EDID blob
+  - nvidia,panel: phandle of a display panel
 
 - tvo: TV encoder output
 
@@ -169,11 +174,21 @@ of the following host1x client modules:
   - clock-names: Must include the following entries:
     - dsi
       This MUST be the first entry.
+    - lp
     - parent
   - resets: Must contain an entry for each entry in reset-names.
     See ../reset/reset.txt for details.
   - reset-names: Must include the following entries:
     - dsi
+  - nvidia,mipi-calibrate: Should contain a phandle and a specifier specifying
+    which pads are used by this DSI output and need to be calibrated. See also
+    ../mipi/nvidia,tegra114-mipi.txt.
+
+  Optional properties:
+  - nvidia,ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+  - nvidia,hpd-gpio: specifies a GPIO used for hotplug detection
+  - nvidia,edid: supplies a binary EDID blob
+  - nvidia,panel: phandle of a display panel
 
 Example:
 
@@ -253,7 +268,7 @@ Example:
                        interrupts = <0 73 0x04>;
                        clocks = <&tegra_car TEGRA20_CLK_DISP1>,
                                 <&tegra_car TEGRA20_CLK_PLL_P>;
-                       clock-names = "disp1", "parent";
+                       clock-names = "dc", "parent";
                        resets = <&tegra_car 27>;
                        reset-names = "dc";
 
@@ -268,7 +283,7 @@ Example:
                        interrupts = <0 74 0x04>;
                        clocks = <&tegra_car TEGRA20_CLK_DISP2>,
                                 <&tegra_car TEGRA20_CLK_PLL_P>;
-                       clock-names = "disp2", "parent";
+                       clock-names = "dc", "parent";
                        resets = <&tegra_car 26>;
                        reset-names = "dc";
 
index 80ff3dfb1f325e89993184324e8ed053fd15e867..d7221b84987cd684169bee2765a050cba3511c75 100644 (file)
@@ -2,6 +2,13 @@ LEDs connected to tca6507
 
 Required properties:
 - compatible : should be : "ti,tca6507".
+- #address-cells: must be 1
+- #size-cells: must be 0
+- reg: typically 0x45.
+
+Optional properties:
+- gpio-controller: allows lines to be used as output-only GPIOs.
+- #gpio-cells: if present, must be 0.
 
 Each led is represented as a sub-node of the ti,tca6507 device.
 
@@ -10,6 +17,7 @@ LED sub-node properties:
 - reg : number of LED line (could be from 0 to 6)
 - linux,default-trigger : (optional)
    see Documentation/devicetree/bindings/leds/common.txt
+- compatible: either "led" (the default) or "gpio".
 
 Examples:
 
@@ -19,6 +27,9 @@ tca6507@45 {
        #size-cells = <0>;
        reg = <0x45>;
 
+       gpio-controller;
+       #gpio-cells = <2>;
+
        led0: red-aux@0 {
                label = "red:aux";
                reg = <0x0>;
@@ -29,5 +40,10 @@ tca6507@45 {
                reg = <0x5>;
                linux,default-trigger = "default-on";
        };
+
+       wifi-reset@6 {
+               reg = <0x6>;
+               compatible = "gpio";
+       };
 };
 
diff --git a/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt
new file mode 100644 (file)
index 0000000..937b755
--- /dev/null
@@ -0,0 +1,11 @@
+Samsung S5P/EXYNOS SoC series JPEG codec
+
+Required properties:
+
+- compatible   : should be one of:
+                 "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg";
+- reg          : address and length of the JPEG codec IP register set;
+- interrupts   : specifies the JPEG codec IP interrupt;
+- clocks       : should contain the JPEG codec IP gate clock specifier, from the
+                 common clock bindings;
+- clock-names  : should contain "jpeg" entry.
diff --git a/Documentation/devicetree/bindings/media/samsung-s5k5baf.txt b/Documentation/devicetree/bindings/media/samsung-s5k5baf.txt
new file mode 100644 (file)
index 0000000..1f51e04
--- /dev/null
@@ -0,0 +1,58 @@
+Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor with embedded SoC ISP
+--------------------------------------------------------------------
+
+Required properties:
+
+- compatible     : "samsung,s5k5baf";
+- reg            : I2C slave address of the sensor;
+- vdda-supply    : analog power supply 2.8V (2.6V to 3.0V);
+- vddreg-supply          : regulator input power supply 1.8V (1.7V to 1.9V)
+                   or 2.8V (2.6V to 3.0);
+- vddio-supply   : I/O power supply 1.8V (1.65V to 1.95V)
+                   or 2.8V (2.5V to 3.1V);
+- stbyn-gpios    : GPIO connected to STDBYN pin;
+- rstn-gpios     : GPIO connected to RSTN pin;
+- clocks         : list of phandle and clock specifier pairs
+                   according to common clock bindings for the
+                   clocks described in clock-names;
+- clock-names    : should include "mclk" for the sensor's master clock;
+
+Optional properties:
+
+- clock-frequency : the frequency at which the "mclk" clock should be
+                   configured to operate, in Hz; if this property is not
+                   specified default 24 MHz value will be used.
+
+The device node should contain one 'port' child node with one child 'endpoint'
+node, according to the bindings defined in Documentation/devicetree/bindings/
+media/video-interfaces.txt. The following are properties specific to those
+nodes.
+
+endpoint node
+-------------
+
+- data-lanes : (optional) specifies MIPI CSI-2 data lanes as covered in
+              video-interfaces.txt. If present it should be <1> - the device
+              supports only one data lane without re-mapping.
+
+Example:
+
+s5k5bafx@2d {
+       compatible = "samsung,s5k5baf";
+       reg = <0x2d>;
+       vdda-supply = <&cam_io_en_reg>;
+       vddreg-supply = <&vt_core_15v_reg>;
+       vddio-supply = <&vtcam_reg>;
+       stbyn-gpios = <&gpl2 0 1>;
+       rstn-gpios = <&gpl2 1 1>;
+       clock-names = "mclk";
+       clocks = <&clock_cam 0>;
+       clock-frequency = <24000000>;
+
+       port {
+               s5k5bafx_ep: endpoint {
+                       remote-endpoint = <&csis1_ep>;
+                       data-lanes = <1>;
+               };
+       };
+};
diff --git a/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt b/Documentation/devicetree/bindings/mipi/dsi/mipi-dsi-bus.txt
new file mode 100644 (file)
index 0000000..973c272
--- /dev/null
@@ -0,0 +1,98 @@
+MIPI DSI (Display Serial Interface) busses
+==========================================
+
+The MIPI Display Serial Interface specifies a serial bus and a protocol for
+communication between a host and up to four peripherals. This document will
+define the syntax used to represent a DSI bus in a device tree.
+
+This document describes DSI bus-specific properties only or defines existing
+standard properties in the context of the DSI bus.
+
+Each DSI host provides a DSI bus. The DSI host controller's node contains a
+set of properties that characterize the bus. Child nodes describe individual
+peripherals on that bus.
+
+The following assumes that only a single peripheral is connected to a DSI
+host. Experience shows that this is true for the large majority of setups.
+
+DSI host
+--------
+
+In addition to the standard properties and those defined by the parent bus of
+a DSI host, the following properties apply to a node representing a DSI host.
+
+Required properties:
+- #address-cells: The number of cells required to represent an address on the
+  bus. DSI peripherals are addressed using a 2-bit virtual channel number, so
+  a maximum of 4 devices can be addressed on a single bus. Hence the value of
+  this property should be 1.
+- #size-cells: Should be 0. There are cases where it makes sense to use a
+  different value here. See below.
+
+DSI peripheral
+--------------
+
+Peripherals are represented as child nodes of the DSI host's node. Properties
+described here apply to all DSI peripherals, but individual bindings may want
+to define additional, device-specific properties.
+
+Required properties:
+- reg: The virtual channel number of a DSI peripheral. Must be in the range
+  from 0 to 3.
+
+Some DSI peripherals respond to more than a single virtual channel. In that
+case two alternative representations can be chosen:
+- The reg property can take multiple entries, one for each virtual channel
+  that the peripheral responds to.
+- If the virtual channels that a peripheral responds to are consecutive, the
+  #size-cells can be set to 1. The first cell of each entry in the reg
+  property is the number of the first virtual channel and the second cell is
+  the number of consecutive virtual channels.
+
+Example
+-------
+
+       dsi-host {
+               ...
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               /* peripheral responds to virtual channel 0 */
+               peripheral@0 {
+                       compatible = "...";
+                       reg = <0>;
+               };
+
+               ...
+       };
+
+       dsi-host {
+               ...
+
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               /* peripheral responds to virtual channels 0 and 2 */
+               peripheral@0 {
+                       compatible = "...";
+                       reg = <0, 2>;
+               };
+
+               ...
+       };
+
+       dsi-host {
+               ...
+
+               #address-cells = <1>;
+               #size-cells = <1>;
+
+               /* peripheral responds to virtual channels 1, 2 and 3 */
+               peripheral@1 {
+                       compatible = "...";
+                       reg = <1 3>;
+               };
+
+               ...
+       };
diff --git a/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt b/Documentation/devicetree/bindings/mipi/nvidia,tegra114-mipi.txt
new file mode 100644 (file)
index 0000000..e4a25ce
--- /dev/null
@@ -0,0 +1,41 @@
+NVIDIA Tegra MIPI pad calibration controller
+
+Required properties:
+- compatible: "nvidia,tegra<chip>-mipi"
+- reg: Physical base address and length of the controller's registers.
+- clocks: Must contain an entry for each entry in clock-names.
+  See ../clocks/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+  - mipi-cal
+- #nvidia,mipi-calibrate-cells: Should be 1. The cell is a bitmask of the pads
+  that need to be calibrated for a given device.
+
+User nodes need to contain an nvidia,mipi-calibrate property that has a
+phandle to refer to the calibration controller node and a bitmask of the pads
+that need to be calibrated.
+
+Example:
+
+       mipi: mipi@700e3000 {
+               compatible = "nvidia,tegra114-mipi";
+               reg = <0x700e3000 0x100>;
+               clocks = <&tegra_car TEGRA114_CLK_MIPI_CAL>;
+               clock-names = "mipi-cal";
+               #nvidia,mipi-calibrate-cells = <1>;
+       };
+
+       ...
+
+       host1x@50000000 {
+               ...
+
+               dsi@54300000 {
+                       ...
+
+                       nvidia,mipi-calibrate = <&mipi 0x060>;
+
+                       ...
+               };
+
+               ...
+       };
index 789fb07a426da61020b5caac68fd8ede83e712ec..aaba2483b4ff8c79f34030b28b3f546c03084032 100644 (file)
@@ -6,12 +6,16 @@ and the properties present in the bcm281xx SDHCI
 Required properties:
 - compatible : Should be "brcm,kona-sdhci"
 - DEPRECATED: compatible : Should be "bcm,kona-sdhci"
+- clocks: phandle + clock specifier pair of the external clock
+
+Refer to clocks/clock-bindings.txt for generic clock consumer properties.
 
 Example:
 
 sdio2: sdio@0x3f1a0000 {
        compatible = "brcm,kona-sdhci";
        reg = <0x3f1a0000 0x10000>;
+       clocks = <&sdio3_clk>;
        interrupts = <0x0 74 0x4>;
 };
 
diff --git a/Documentation/devicetree/bindings/mtd/davinci-nand.txt b/Documentation/devicetree/bindings/mtd/davinci-nand.txt
new file mode 100644 (file)
index 0000000..cfb18ab
--- /dev/null
@@ -0,0 +1,94 @@
+Device tree bindings for Texas instruments Davinci/Keystone NAND controller
+
+This file provides information, what the device node for the davinci/keystone
+NAND interface contains.
+
+Documentation:
+Davinci DM646x - http://www.ti.com/lit/ug/sprueq7c/sprueq7c.pdf
+Kestone - http://www.ti.com/lit/ug/sprugz3a/sprugz3a.pdf
+
+Required properties:
+
+- compatible:                  "ti,davinci-nand"
+                               "ti,keystone-nand"
+
+- reg:                         Contains 2 offset/length values:
+                               - offset and length for the access window.
+                               - offset and length for accessing the AEMIF
+                               control registers.
+
+- ti,davinci-chipselect:       number of chipselect. Indicates on the
+                               davinci_nand driver which chipselect is used
+                               for accessing the nand.
+                               Can be in the range [0-3].
+
+Recommended properties :
+
+- ti,davinci-mask-ale:         mask for ALE. Needed for executing address
+                               phase. These offset will be added to the base
+                               address for the chip select space the NAND Flash
+                               device is connected to.
+                               If not set equal to 0x08.
+
+- ti,davinci-mask-cle:         mask for CLE. Needed for executing command
+                               phase. These offset will be added to the base
+                               address for the chip select space the NAND Flash
+                               device is connected to.
+                               If not set equal to 0x10.
+
+- ti,davinci-mask-chipsel:     mask for chipselect address. Needed to mask
+                               addresses for given chipselect.
+
+- nand-ecc-mode:               operation mode of the NAND ecc mode. ECC mode
+                               valid values for davinci driver:
+                               - "none"
+                               - "soft"
+                               - "hw"
+
+- ti,davinci-ecc-bits:         used ECC bits, currently supported 1 or 4.
+
+- nand-bus-width:              buswidth 8 or 16. If not present 8.
+
+- nand-on-flash-bbt:           use flash based bad block table support. OOB
+                               identifier is saved in OOB area. If not present
+                               false.
+
+Deprecated properties:
+
+- ti,davinci-ecc-mode:         operation mode of the NAND ecc mode. ECC mode
+                               valid values for davinci driver:
+                               - "none"
+                               - "soft"
+                               - "hw"
+
+- ti,davinci-nand-buswidth:    buswidth 8 or 16. If not present 8.
+
+- ti,davinci-nand-use-bbt:     use flash based bad block table support. OOB
+                               identifier is saved in OOB area. If not present
+                               false.
+
+Nand device bindings may contain additional sub-nodes describing partitions of
+the address space. See partition.txt for more detail. The NAND Flash timing
+values must be programmed in the chip select’s node of AEMIF
+memory-controller (see Documentation/devicetree/bindings/memory-controllers/
+davinci-aemif.txt).
+
+Example(da850 EVM ):
+
+nand_cs3@62000000 {
+       compatible = "ti,davinci-nand";
+       reg = <0x62000000 0x807ff
+              0x68000000 0x8000>;
+       ti,davinci-chipselect = <1>;
+       ti,davinci-mask-ale = <0>;
+       ti,davinci-mask-cle = <0>;
+       ti,davinci-mask-chipsel = <0>;
+       nand-ecc-mode = "hw";
+       ti,davinci-ecc-bits = <4>;
+       nand-on-flash-bbt;
+
+       partition@180000 {
+               label = "ubifs";
+               reg = <0x180000 0x7e80000>;
+       };
+};
index 551b2a179d016df4bd9bb8e611f38633d57d6640..458d5963468826647d2469c23f542bde3ffe047c 100644 (file)
@@ -17,6 +17,14 @@ Required properties:
 Optional properties:
   - nand-on-flash-bbt: boolean to enable on flash bbt option if not
                        present false
+  - fsl,use-minimum-ecc: Protect this NAND flash with the minimum ECC
+                       strength required. The required ECC strength is
+                       automatically discoverable for some flash
+                       (e.g., according to the ONFI standard).
+                       However, note that if this strength is not
+                       discoverable or this property is not enabled,
+                       the software may chooses an implementation-defined
+                       ECC scheme.
 
 The device tree may optionally contain sub-nodes describing partitions of the
 address space. See partition.txt for more detail.
index f1421e2bbab7387a87e1885794b9688780d6de73..86e0a5601ff5dfb05d9eeed35eb3e638ea58cc7b 100644 (file)
@@ -2,7 +2,9 @@ PXA3xx NAND DT bindings
 
 Required properties:
 
- - compatible:         Should be "marvell,pxa3xx-nand"
+ - compatible:         Should be set to one of the following:
+                       marvell,pxa3xx-nand
+                       marvell,armada370-nand
  - reg:                The register base for the controller
  - interrupts:         The interrupt to map
  - #address-cells:     Set to <1> if the node includes partitions
@@ -13,6 +15,8 @@ Optional properties:
  - marvell,nand-keep-config:   Set to keep the NAND controller config as set
                                by the bootloader
  - num-cs:                     Number of chipselect lines to usw
+ - nand-on-flash-bbt:          boolean to enable on flash bbt option if
+                               not present false
 
 Example:
 
index ca0911a20e8b21595c23d3eae2e8e4869dec65cc..6e356d15154a9603c8ce2b73f57edbd0c326c60c 100644 (file)
@@ -10,8 +10,6 @@ Required properties:
 - ti,davinci-ctrl-mod-reg-offset: offset to control module register
 - ti,davinci-ctrl-ram-offset: offset to control module ram
 - ti,davinci-ctrl-ram-size: size of control module ram
-- ti,davinci-rmii-en: use RMII
-- ti,davinci-no-bd-ram: has the emac controller BD RAM
 - interrupts: interrupt mapping for the davinci emac interrupts sources:
               4 sources: <Receive Threshold Interrupt
                          Receive Interrupt
@@ -22,6 +20,8 @@ Optional properties:
 - phy-handle: Contains a phandle to an Ethernet PHY.
               If absent, davinci_emac driver defaults to 100/FULL.
 - local-mac-address : 6 bytes, mac address
+- ti,davinci-rmii-en: 1 byte, 1 means use RMII
+- ti,davinci-no-bd-ram: boolean, does EMAC have BD RAM?
 
 Example (enbw_cmc board):
        eth0: emac@1e20000 {
diff --git a/Documentation/devicetree/bindings/panel/auo,b101aw03.txt b/Documentation/devicetree/bindings/panel/auo,b101aw03.txt
new file mode 100644 (file)
index 0000000..72e088a
--- /dev/null
@@ -0,0 +1,7 @@
+AU Optronics Corporation 10.1" WSVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "auo,b101aw03"
+
+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/panel/chunghwa,claa101wa01a.txt b/Documentation/devicetree/bindings/panel/chunghwa,claa101wa01a.txt
new file mode 100644 (file)
index 0000000..f24614e
--- /dev/null
@@ -0,0 +1,7 @@
+Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "chunghwa,claa101wa01a"
+
+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/panel/chunghwa,claa101wb03.txt b/Documentation/devicetree/bindings/panel/chunghwa,claa101wb03.txt
new file mode 100644 (file)
index 0000000..0ab2c05
--- /dev/null
@@ -0,0 +1,7 @@
+Chunghwa Picture Tubes Ltd. 10.1" WXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "chunghwa,claa101wb03"
+
+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/panel/panasonic,vvx10f004b00.txt b/Documentation/devicetree/bindings/panel/panasonic,vvx10f004b00.txt
new file mode 100644 (file)
index 0000000..d328b03
--- /dev/null
@@ -0,0 +1,7 @@
+Panasonic Corporation 10.1" WUXGA TFT LCD panel
+
+Required properties:
+- compatible: should be "panasonic,vvx10f004b00"
+
+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/panel/samsung,ltn101nt05.txt b/Documentation/devicetree/bindings/panel/samsung,ltn101nt05.txt
new file mode 100644 (file)
index 0000000..ef522c6
--- /dev/null
@@ -0,0 +1,7 @@
+Samsung Electronics 10.1" WSVGA TFT LCD panel
+
+Required properties:
+- compatible: should be "samsung,ltn101nt05"
+
+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/panel/simple-panel.txt b/Documentation/devicetree/bindings/panel/simple-panel.txt
new file mode 100644 (file)
index 0000000..1341bbf
--- /dev/null
@@ -0,0 +1,21 @@
+Simple display panel
+
+Required properties:
+- power-supply: regulator to provide the supply voltage
+
+Optional properties:
+- ddc-i2c-bus: phandle of an I2C controller used for DDC EDID probing
+- enable-gpios: GPIO pin to enable or disable the panel
+- backlight: phandle of the backlight device attached to the panel
+
+Example:
+
+       panel: panel {
+               compatible = "cptt,claa101wb01";
+               ddc-i2c-bus = <&panelddc>;
+
+               power-supply = <&vdd_pnl_reg>;
+               enable-gpios = <&gpio 90 0>;
+
+               backlight = <&backlight>;
+       };
diff --git a/Documentation/devicetree/bindings/pwm/atmel-pwm.txt b/Documentation/devicetree/bindings/pwm/atmel-pwm.txt
new file mode 100644 (file)
index 0000000..02331b9
--- /dev/null
@@ -0,0 +1,33 @@
+Atmel PWM controller
+
+Required properties:
+  - compatible: should be one of:
+    - "atmel,at91sam9rl-pwm"
+    - "atmel,sama5d3-pwm"
+  - reg: physical base address and length of the controller's registers
+  - #pwm-cells: Should be 3. See pwm.txt in this directory for a
+    description of the cells format.
+
+Example:
+
+       pwm0: pwm@f8034000 {
+               compatible = "atmel,at91sam9rl-pwm";
+               reg = <0xf8034000 0x400>;
+               #pwm-cells = <3>;
+       };
+
+       pwmleds {
+               compatible = "pwm-leds";
+
+               d1 {
+                       label = "d1";
+                       pwms = <&pwm0 3 5000 0>
+                       max-brightness = <255>;
+               };
+
+               d2 {
+                       label = "d2";
+                       pwms = <&pwm0 1 5000 1>
+                       max-brightness = <255>;
+               };
+       };
diff --git a/Documentation/devicetree/bindings/pwm/pxa-pwm.txt b/Documentation/devicetree/bindings/pwm/pxa-pwm.txt
new file mode 100644 (file)
index 0000000..5ae9f1e
--- /dev/null
@@ -0,0 +1,30 @@
+Marvell PWM controller
+
+Required properties:
+- compatible: should be one or more of:
+  - "marvell,pxa250-pwm"
+  - "marvell,pxa270-pwm"
+  - "marvell,pxa168-pwm"
+  - "marvell,pxa910-pwm"
+- reg: Physical base address and length of the registers used by the PWM channel
+  Note that one device instance must be created for each PWM that is used, so the
+  length covers only the register window for one PWM output, not that of the
+  entire PWM controller.  Currently length is 0x10 for all supported devices.
+- #pwm-cells: Should be 1.  This cell is used to specify the period in
+  nanoseconds.
+
+Example PWM device node:
+
+pwm0: pwm@40b00000 {
+       compatible = "marvell,pxa250-pwm";
+       reg = <0x40b00000 0x10>;
+       #pwm-cells = <1>;
+};
+
+Example PWM client node:
+
+backlight {
+       compatible = "pwm-backlight";
+       pwms = <&pwm0 5000000>;
+       ...
+}
index e9e20ec67d62b349d021099a755bbd5eca2a6b2a..19c84df5fffa35d8a65adae8f39db947da969147 100644 (file)
@@ -43,7 +43,7 @@ Example:
 sound {
        compatible = "simple-audio-card";
        simple-audio-card,format = "left_j";
-       simple-audio-routing =
+       simple-audio-card,routing =
                "MIC_IN", "Mic Jack",
                "Headphone Jack", "HP_OUT",
                "Ext Spk", "LINE_OUT";
diff --git a/Documentation/devicetree/bindings/video/ssd1289fb.txt b/Documentation/devicetree/bindings/video/ssd1289fb.txt
new file mode 100644 (file)
index 0000000..4fcd5e6
--- /dev/null
@@ -0,0 +1,13 @@
+* Solomon SSD1289 Framebuffer Driver
+
+Required properties:
+  - compatible: Should be "solomon,ssd1289fb". The only supported bus for
+    now is lbc.
+  - reg: Should contain address of the controller on the LBC bus. The detail
+    was described in Documentation/devicetree/bindings/powerpc/fsl/lbc.txt
+
+Examples:
+display@2,0 {
+       compatible = "solomon,ssd1289fb";
+       reg = <0x2 0x0000 0x0004>;
+};
index fcdd48f7dcffc0f71540dacb48aa4f501c6dd5de..f90e294d7631f9b538ba3e5e72c2ab1b096a5479 100644 (file)
@@ -9,11 +9,37 @@ Required properties:
 
 Optional properties:
 - timeout-sec: contains the watchdog timeout in seconds.
+- interrupts : Should contain WDT interrupt.
+- atmel,max-heartbeat-sec : Should contain the maximum heartbeat value in
+       seconds. This value should be less or equal to 16. It is used to
+       compute the WDV field.
+- atmel,min-heartbeat-sec : Should contain the minimum heartbeat value in
+       seconds. This value must be smaller than the max-heartbeat-sec value.
+       It is used to compute the WDD field.
+- atmel,watchdog-type : Should be "hardware" or "software". Hardware watchdog
+       use the at91 watchdog reset. Software watchdog use the watchdog
+       interrupt to trigger a software reset.
+- atmel,reset-type : Should be "proc" or "all".
+       "all" : assert peripherals and processor reset signals
+       "proc" : assert the processor reset signal
+       This is valid only when using "hardware" watchdog.
+- atmel,disable : Should be present if you want to disable the watchdog.
+- atmel,idle-halt : Should be present if you want to stop the watchdog when
+       entering idle state.
+- atmel,dbg-halt : Should be present if you want to stop the watchdog when
+       entering debug state.
 
 Example:
-
        watchdog@fffffd40 {
                compatible = "atmel,at91sam9260-wdt";
                reg = <0xfffffd40 0x10>;
-               timeout-sec = <10>;
+               interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+               timeout-sec = <15>;
+               atmel,watchdog-type = "hardware";
+               atmel,reset-type = "all";
+               atmel,dbg-halt;
+               atmel,idle-halt;
+               atmel,max-heartbeat-sec = <16>;
+               atmel,min-heartbeat-sec = <0>;
+               status = "okay";
        };
index 75558ccd9a051e59af9233f279a660c27fa58f97..e60b9a13bdcbd5887078e110280dffe5e39ba5e5 100644 (file)
@@ -1,12 +1,24 @@
-DaVinci Watchdog Timer (WDT) Controller
+Texas Instruments DaVinci/Keystone Watchdog Timer (WDT) Controller
 
 Required properties:
-- compatible : Should be "ti,davinci-wdt"
+- compatible : Should be "ti,davinci-wdt", "ti,keystone-wdt"
 - reg : Should contain WDT registers location and length
 
+Optional properties:
+- timeout-sec : Contains the watchdog timeout in seconds
+- clocks : the clock feeding the watchdog timer.
+          Needed if platform uses clocks.
+          See clock-bindings.txt
+
+Documentation:
+Davinci DM646x - http://www.ti.com/lit/ug/spruer5b/spruer5b.pdf
+Keystone - http://www.ti.com/lit/ug/sprugv5a/sprugv5a.pdf
+
 Examples:
 
 wdt: wdt@2320000 {
        compatible = "ti,davinci-wdt";
        reg = <0x02320000 0x80>;
+       timeout-sec = <30>;
+       clocks = <&clkwdtimer0>;
 };
diff --git a/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt b/Documentation/devicetree/bindings/watchdog/gpio-wdt.txt
new file mode 100644 (file)
index 0000000..37afec1
--- /dev/null
@@ -0,0 +1,23 @@
+* GPIO-controlled Watchdog
+
+Required Properties:
+- compatible: Should contain "linux,wdt-gpio".
+- gpios: From common gpio binding; gpio connection to WDT reset pin.
+- hw_algo: The algorithm used by the driver. Should be one of the
+  following values:
+  - toggle: Either a high-to-low or a low-to-high transition clears
+    the WDT counter. The watchdog timer is disabled when GPIO is
+    left floating or connected to a three-state buffer.
+  - level: Low or high level starts counting WDT timeout,
+    the opposite level disables the WDT. Active level is determined
+    by the GPIO flags.
+- hw_margin_ms: Maximum time to reset watchdog circuit (milliseconds).
+
+Example:
+       watchdog: watchdog {
+               /* ADM706 */
+               compatible = "linux,wdt-gpio";
+               gpios = <&gpio3 9 GPIO_ACTIVE_LOW>;
+               hw_algo = "toggle";
+               hw_margin_ms = <1600>;
+       };
index 2aa486cc1ff6a17ba8f1d95b75800a76941d2f5f..cfff37511aac0e3e1f3d42f6e9805c087a8bc286 100644 (file)
@@ -5,10 +5,29 @@ after a preset amount of time during which the WDT reset event has not
 occurred.
 
 Required properties:
-- compatible : should be "samsung,s3c2410-wdt"
+- compatible : should be one among the following
+       (a) "samsung,s3c2410-wdt" for Exynos4 and previous SoCs
+       (b) "samsung,exynos5250-wdt" for Exynos5250
+       (c) "samsung,exynos5420-wdt" for Exynos5420
+
 - reg : base physical address of the controller and length of memory mapped
        region.
 - interrupts : interrupt number to the cpu.
+- samsung,syscon-phandle : reference to syscon node (This property required only
+       in case of compatible being "samsung,exynos5250-wdt" or "samsung,exynos5420-wdt".
+       In case of Exynos5250 and 5420 this property points to syscon node holding the PMU
+       base address)
 
 Optional properties:
 - timeout-sec : contains the watchdog timeout in seconds.
+
+Example:
+
+watchdog@101D0000 {
+       compatible = "samsung,exynos5250-wdt";
+       reg = <0x101D0000 0x100>;
+       interrupts = <0 42 0>;
+       clocks = <&clock 336>;
+       clock-names = "watchdog";
+       samsung,syscon-phandle = <&pmu_syscon>;
+};
index 5dd282dda55c5eca0fe50b6b1cfc0116d3cc7432..d11cc2f8077b9ea6e4284419fd40121c13d0d1c2 100644 (file)
@@ -38,7 +38,7 @@ Mount Options
 =============
 
 When mounting a btrfs filesystem, the following option are accepted.
-Unless otherwise specified, all options default to off.
+Options with (*) are default options and will not show in the mount options.
 
   alloc_start=<bytes>
        Debugging option to force all block allocations above a certain
@@ -46,10 +46,12 @@ Unless otherwise specified, all options default to off.
        bytes, optionally with a K, M, or G suffix, case insensitive.
        Default is 1MB.
 
+  noautodefrag(*)
   autodefrag
-       Detect small random writes into files and queue them up for the
-       defrag process.  Works best for small files; Not well suited for
-       large database workloads.
+       Disable/enable auto defragmentation.
+       Auto defragmentation detects small random writes into files and queue
+       them up for the defrag process.  Works best for small files;
+       Not well suited for large database workloads.
 
   check_int
   check_int_data
@@ -96,21 +98,26 @@ Unless otherwise specified, all options default to off.
        can be avoided.  Especially useful when trying to mount a multi-device
        setup as root.  May be specified multiple times for multiple devices.
 
+  nodiscard(*)
   discard
-       Issue frequent commands to let the block device reclaim space freed by
-       the filesystem.  This is useful for SSD devices, thinly provisioned
+       Disable/enable discard mount option.
+       Discard issues frequent commands to let the block device reclaim space
+       freed by the filesystem.
+       This is useful for SSD devices, thinly provisioned
        LUNs and virtual machine images, but may have a significant
        performance impact.  (The fstrim command is also available to
        initiate batch trims from userspace).
 
+  noenospc_debug(*)
   enospc_debug
-       Debugging option to be more verbose in some ENOSPC conditions.
+       Disable/enable debugging option to be more verbose in some ENOSPC conditions.
 
   fatal_errors=<action>
        Action to take when encountering a fatal error: 
          "bug" - BUG() on a fatal error.  This is the default.
          "panic" - panic() on a fatal error.
 
+  noflushoncommit(*)
   flushoncommit
        The 'flushoncommit' mount option forces any data dirtied by a write in a
        prior transaction to commit as part of the current commit.  This makes
@@ -134,26 +141,32 @@ Unless otherwise specified, all options default to off.
        Specify that 1 metadata chunk should be allocated after every <value>
        data chunks.  Off by default.
 
+  acl(*)
   noacl
-       Disable support for Posix Access Control Lists (ACLs).  See the
+       Enable/disable support for Posix Access Control Lists (ACLs).  See the
        acl(5) manual page for more information about ACLs.
 
+  barrier(*)
   nobarrier
-        Disables the use of block layer write barriers.  Write barriers ensure
-       that certain IOs make it through the device cache and are on persistent
-       storage.  If used on a device with a volatile (non-battery-backed)
-       write-back cache, this option will lead to filesystem corruption on a
-       system crash or power loss.
+        Enable/disable the use of block layer write barriers.  Write barriers
+       ensure that certain IOs make it through the device cache and are on
+       persistent storage. If disabled on a device with a volatile
+       (non-battery-backed) write-back cache, nobarrier option will lead to
+       filesystem corruption on a system crash or power loss.
 
+  datacow(*)
   nodatacow
-       Disable data copy-on-write for newly created files.  Implies nodatasum,
-       and disables all compression.
+       Enable/disable data copy-on-write for newly created files.
+       Nodatacow implies nodatasum, and disables all compression.
 
+  datasum(*)
   nodatasum
-       Disable data checksumming for newly created files.
+       Enable/disable data checksumming for newly created files.
+       Datasum implies datacow.
 
+  treelog(*)
   notreelog
-       Disable the tree logging used for fsync and O_SYNC writes.
+       Enable/disable the tree logging used for fsync and O_SYNC writes.
 
   recovery
        Enable autorecovery attempts if a bad tree root is found at mount time.
index 01c2db769791832b989b738d413cea2ecefcba68..b930ad08778000e43fd27c605fb50bd0f9d03d41 100644 (file)
@@ -5,11 +5,11 @@ Server support for minorversion 1 can be controlled using the
 by reading this file will contain either "+4.1" or "-4.1"
 correspondingly.
 
-Currently, server support for minorversion 1 is disabled by default.
-It can be enabled at run time by writing the string "+4.1" to
+Currently, server support for minorversion 1 is enabled by default.
+It can be disabled at run time by writing the string "-4.1" to
 the /proc/fs/nfsd/versions control file.  Note that to write this
-control file, the nfsd service must be taken down.  Use your user-mode
-nfs-utils to set this up; see rpc.nfsd(8)
+control file, the nfsd service must be taken down.  You can use rpc.nfsd
+for this; see rpc.nfsd(8).
 
 (Warning: older servers will interpret "+4.1" and "-4.1" as "+4" and
 "-4", respectively.  Therefore, code meant to work on both new and old
@@ -29,29 +29,6 @@ are still under development out of tree.
 See http://wiki.linux-nfs.org/wiki/index.php/PNFS_prototype_design
 for more information.
 
-The current implementation is intended for developers only: while it
-does support ordinary file operations on clients we have tested against
-(including the linux client), it is incomplete in ways which may limit
-features unexpectedly, cause known bugs in rare cases, or cause
-interoperability problems with future clients.  Known issues:
-
-       - gss support is questionable: currently mounts with kerberos
-         from a linux client are possible, but we aren't really
-         conformant with the spec (for example, we don't use kerberos
-         on the backchannel correctly).
-       - We do not support SSV, which provides security for shared
-         client-server state (thus preventing unauthorized tampering
-         with locks and opens, for example).  It is mandatory for
-         servers to support this, though no clients use it yet.
-
-In addition, some limitations are inherited from the current NFSv4
-implementation:
-
-       - Incomplete delegation enforcement: if a file is renamed or
-         unlinked by a local process, a client holding a delegation may
-         continue to indefinitely allow opens of the file under the old
-         name.
-
 The table below, taken from the NFSv4.1 document, lists
 the operations that are mandatory to implement (REQ), optional
 (OPT), and NFSv4.0 operations that are required not to implement (MNI)
@@ -169,6 +146,16 @@ NS*| CB_WANTS_CANCELLED      | OPT       | FDELG,      | Section 20.10 |
 
 Implementation notes:
 
+SSV:
+* The spec claims this is mandatory, but we don't actually know of any
+  implementations, so we're ignoring it for now.  The server returns
+  NFS4ERR_ENCR_ALG_UNSUPP on EXCHANGE_ID, which should be future-proof.
+
+GSS on the backchannel:
+* Again, theoretically required but not widely implemented (in
+  particular, the current Linux client doesn't request it).  We return
+  NFS4ERR_ENCR_ALG_UNSUPP on CREATE_SESSION.
+
 DELEGPURGE:
 * mandatory only for servers that support CLAIM_DELEGATE_PREV and/or
   CLAIM_DELEG_PREV_FH (which allows clients to keep delegations that
@@ -176,7 +163,6 @@ DELEGPURGE:
   now.
 
 EXCHANGE_ID:
-* only SP4_NONE state protection supported
 * implementation ids are ignored
 
 CREATE_SESSION:
index 31f76178c987f1b0d65b778f72848cd5f1b705d7..f00bee144addc5dcda3f7784c3b943824efbafd4 100644 (file)
@@ -1386,8 +1386,8 @@ may allocate from based on an estimation of its current memory and swap use.
 For example, if a task is using all allowed memory, its badness score will be
 1000.  If it is using half of its allowed memory, its score will be 500.
 
-There is an additional factor included in the badness score: root
-processes are given 3% extra memory over other tasks.
+There is an additional factor included in the badness score: the current memory
+and swap usage is discounted by 3% for root processes.
 
 The amount of "allowed" memory depends on the context in which the oom killer
 was called.  If it is due to the memory assigned to the allocating task's cpuset
index deb48b5fd88327d8249b19aa8de16aab6855c191..c53784c119c8ea29a532c4e0d9460dd4801690fd 100644 (file)
@@ -782,7 +782,7 @@ struct file_operations
 ----------------------
 
 This describes how the VFS can manipulate an open file. As of kernel
-3.5, the following members are defined:
+3.12, the following members are defined:
 
 struct file_operations {
        struct module *owner;
@@ -803,9 +803,6 @@ struct file_operations {
        int (*aio_fsync) (struct kiocb *, int datasync);
        int (*fasync) (int, struct file *, int);
        int (*lock) (struct file *, int, struct file_lock *);
-       ssize_t (*readv) (struct file *, const struct iovec *, unsigned long, loff_t *);
-       ssize_t (*writev) (struct file *, const struct iovec *, unsigned long, loff_t *);
-       ssize_t (*sendfile) (struct file *, loff_t *, size_t, read_actor_t, void *);
        ssize_t (*sendpage) (struct file *, struct page *, int, size_t, loff_t *, int);
        unsigned long (*get_unmapped_area)(struct file *, unsigned long, unsigned long, unsigned long, unsigned long);
        int (*check_flags)(int);
@@ -814,6 +811,7 @@ struct file_operations {
        ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
        int (*setlease)(struct file *, long arg, struct file_lock **);
        long (*fallocate)(struct file *, int mode, loff_t offset, loff_t len);
+       int (*show_fdinfo)(struct seq_file *m, struct file *f);
 };
 
 Again, all methods are called without any locks being held, unless
@@ -864,12 +862,6 @@ otherwise noted.
   lock: called by the fcntl(2) system call for F_GETLK, F_SETLK, and F_SETLKW
        commands
 
-  readv: called by the readv(2) system call
-
-  writev: called by the writev(2) system call
-
-  sendfile: called by the sendfile(2) system call
-
   get_unmapped_area: called by the mmap(2) system call
 
   check_flags: called by the fcntl(2) system call for F_SETFL command
index 39d2b781b5d6144f5f46eff8a5a873b908be044d..99f05049c68a89330f4be3b099c205853935792d 100644 (file)
@@ -18,7 +18,7 @@ The NE1619 presents some differences with the original ADM1025:
 
 Authors:
         Chen-Yuan Wu <gwu@esoft.com>,
-        Jean Delvare <khali@linux-fr.org>
+        Jean Delvare <jdelvare@suse.de>
 
 Description
 -----------
index be92a77da1d5116d9e828903a61f58fffc1feea3..a143117c99cb3dea9cc7a5a4a17670a81d5e1d4c 100644 (file)
@@ -16,7 +16,7 @@ Supported chips:
 
 Authors:
         Alexandre d'Alton <alex@alexdalton.org>
-        Jean Delvare <khali@linux-fr.org>
+        Jean Delvare <jdelvare@suse.de>
 
 Description
 -----------
index 36e8ec6aa868c1b6fa0a5cee9fc42ba10e83364a..9b174fc700cce8ce6716f281a4593e7b19182920 100644 (file)
@@ -25,7 +25,7 @@ Authors:
     Philip Edelbrock <phil@netroedge.com>,
     Michiel Rook <michiel@grendelproject.nl>,
     Grant Coady <gcoady.lk@gmail.com> with guidance
-        from Jean Delvare <khali@linux-fr.org>
+        from Jean Delvare <jdelvare@suse.de>
 
 Interface
 ---------
index 896cdc972ca8edcd9e7ae31081aeb39cc4d91eb3..f775e612f5820a5488da463f7fcfb86ffaa8cd9b 100644 (file)
@@ -31,7 +31,7 @@ Authors:
         Christian W. Zuckschwerdt <zany@triq.net>
         valuable contributions by Jan M. Sendler <sendler@sendler.de>
         ported to 2.6 by Aurelien Jarno <aurelien@aurel32.net>
-        with the help of Jean Delvare <khali@linux-fr.org>
+        with the help of Jean Delvare <jdelvare@suse.de>
 
 Module Parameters
 ------------------
index 32f355aaf56b6b4dcd10e61e2a7db90b82dbbfa7..757629b128978d5edadecfdc9932ba7e6cffed9f 100644 (file)
@@ -7,7 +7,7 @@ Supported chips:
     Addresses scanned: I2C 0x2c, 0x2d, 0x2e
     Datasheet: Not public
 
-Author: Jean Delvare <khali@linux-fr.org>
+Author: Jean Delvare <jdelvare@suse.de>
 
 
 Description
index f0d55976740adfeabfb7258d4109a7d4c930c6ac..48a356084bc671fbe8b473461deac358497640da 100644 (file)
@@ -15,7 +15,7 @@ Supported chips:
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: Available from the Fintek website
 
-Author: Jean Delvare <khali@linux-fr.org>
+Author: Jean Delvare <jdelvare@suse.de>
 
 Thanks to Denis Kieft from Barracuda Networks for the donation of a
 test system (custom Jetway K8M8MS motherboard, with CPU and RAM) and
index 26f9f3c02dc7e6febbf9835415abf994fecc82e5..494bb55b6e7261d55cc4a859fc4b1abb513fec7e 100644 (file)
@@ -14,7 +14,7 @@ Authors:
         Frodo Looijaard <frodol@dds.nl>,
         Kyösti Mälkki <kmalkki@cc.hut.fi>
         Hong-Gunn Chew <hglinux@gunnet.org>
-        Jean Delvare <khali@linux-fr.org>
+        Jean Delvare <jdelvare@suse.de>
 
 Description
 -----------
index c263740f0cba83b5c3f17e95ecae83326da06458..0c1635082c9951c6b9c1b038a283ba5ef68ae0bf 100644 (file)
@@ -2,6 +2,10 @@ Kernel driver it87
 ==================
 
 Supported chips:
+  * IT8603E
+    Prefix: 'it8603'
+    Addresses scanned: from Super I/O config space (8 I/O ports)
+    Datasheet: Not publicly available
   * IT8705F
     Prefix: 'it87'
     Addresses scanned: from Super I/O config space (8 I/O ports)
@@ -53,7 +57,7 @@ Supported chips:
 
 Authors:
     Christophe Gauthron
-    Jean Delvare <khali@linux-fr.org>
+    Jean Delvare <jdelvare@suse.de>
 
 
 Module Parameters
@@ -90,7 +94,7 @@ motherboard models.
 Description
 -----------
 
-This driver implements support for the IT8705F, IT8712F, IT8716F,
+This driver implements support for the IT8603E, IT8705F, IT8712F, IT8716F,
 IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E, IT8771E, IT8772E,
 IT8782F, IT8783E/F, and SiS950 chips.
 
@@ -129,6 +133,10 @@ to userspace applications.
 The IT8728F, IT8771E, and IT8772E are considered compatible with the IT8721F,
 until a datasheet becomes available (hopefully.)
 
+The IT8603E is a custom design, hardware monitoring part is similar to
+IT8728F. It only supports 16-bit fan mode, the full speed mode of the
+fan is not supported (value 0 of pwmX_enable).
+
 Temperatures are measured in degrees Celsius. An alarm is triggered once
 when the Overtemperature Shutdown limit is crossed.
 
@@ -145,13 +153,16 @@ alarm is triggered if the voltage has crossed a programmable minimum or
 maximum limit. Note that minimum in this case always means 'closest to
 zero'; this is important for negative voltage measurements. All voltage
 inputs can measure voltages between 0 and 4.08 volts, with a resolution of
-0.016 volt (except IT8721F/IT8758E and IT8728F: 0.012 volt.) The battery
-voltage in8 does not have limit registers.
-
-On the IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs are
-internal and scaled inside the chip (in7 (optional for IT8782F and IT8783E/F),
-in8 and optionally in3). The driver handles this transparently so user-space
-doesn't have to care.
+0.016 volt (except IT8603E, IT8721F/IT8758E and IT8728F: 0.012 volt.) The
+battery voltage in8 does not have limit registers.
+
+On the IT8603E, IT8721F/IT8758E, IT8782F, and IT8783E/F, some voltage inputs
+are internal and scaled inside the chip:
+* in3 (optional)
+* in7 (optional for IT8782F and IT8783E/F)
+* in8 (always)
+* in9 (relevant for IT8603E only)
+The driver handles this transparently so user-space doesn't have to care.
 
 The VID lines (IT8712F/IT8716F/IT8718F/IT8720F) encode the core voltage value:
 the voltage level your processor should work with. This is hardcoded by
index 4d30d209881a2861ad95c07208a7179ead236b03..4a00461512a61e4b57fc544c9e8d725834f9333a 100644 (file)
@@ -18,7 +18,7 @@ Supported chips:
     Datasheet: Publicly available at the National Semiconductor website
                http://www.national.com/pf/LM/LM96163.html
 
-Author: Jean Delvare <khali@linux-fr.org>
+Author: Jean Delvare <jdelvare@suse.de>
 
 Thanks go to Tyan and especially Alex Buckingham for setting up a remote
 access to their S4882 test platform for this driver.
index 86d182942c51498524429f34e7ed979b68dc75b3..1bb2db4406717ec02f4033553fd7df6c16d2951a 100644 (file)
@@ -43,5 +43,5 @@ data (0.03125 degrees celsius resolution).
 
 Thanks to
 ---------
-Jean Delvare <khali@linux-fr.org> for mentoring the hwmon-side driver
+Jean Delvare <jdelvare@suse.de> for mentoring the hwmon-side driver
 development.
index 2bdc881a0c1238da62e9e3dd912057a817874f4c..4dd47731789f1b30a191eb6b0b33e76137acf103 100644 (file)
@@ -14,7 +14,7 @@ Supported chips:
                http://www.national.com/
 
 Authors: Frodo Looijaard <frodol@dds.nl>
-         Jean Delvare <khali@linux-fr.org>
+         Jean Delvare <jdelvare@suse.de>
 
 Description
 -----------
index a04d1fe9269cc9f2e129de63a2cdd18625704bca..50be5cb26de930c5798d0506153dc5352858cc9b 100644 (file)
@@ -13,7 +13,7 @@ Supported chips:
                http://www.national.com/pf/LM/LM82.html
 
 
-Author: Jean Delvare <khali@linux-fr.org>
+Author: Jean Delvare <jdelvare@suse.de>
 
 Description
 -----------
index 6b47b67fd968e8a05c0eb811f329f33774e96e5b..a2339fd9acb97019d70eeaa4b2f05c08546f310b 100644 (file)
@@ -17,7 +17,7 @@ Authors:
         Mark Studebaker <mdsxyz123@yahoo.com>,
         Stephen Rousset <stephen.rousset@rocketlogix.com>,
         Dan Eaton <dan.eaton@rocketlogix.com>,
-        Jean Delvare <khali@linux-fr.org>,
+        Jean Delvare <jdelvare@suse.de>,
         Original 2.6 port Jeff Oliver
 
 Description
index ab81013cc3907a45ffb039a1f72a98d83f1b46b8..8122675d30f627564578d2c5f4c1c371e8861849 100644 (file)
@@ -129,7 +129,7 @@ Supported chips:
                http://www.ti.com/litv/pdf/sbos686
 
 
-Author: Jean Delvare <khali@linux-fr.org>
+Author: Jean Delvare <jdelvare@suse.de>
 
 
 Description
index 7705bfaa070856666a2cce8678ca8b1dac886376..22f68ad032cf983c200a36975691442f53f2b8d9 100644 (file)
@@ -19,7 +19,7 @@ Supported chips:
 
 Authors:
         Abraham van der Merwe <abraham@2d3d.co.za>
-        Jean Delvare <khali@linux-fr.org>
+        Jean Delvare <jdelvare@suse.de>
 
 
 Description
index e6d87398cc8f01e8c450713f5933347627d05752..518bae3a80c472245cf18421facdbd7fa41f4477 100644 (file)
@@ -10,7 +10,7 @@ Supported chips:
 
 Authors:
         Oleksij Rempel <bug-track@fisher-privat.net>,
-        Jean Delvare <khali@linux-fr.org>
+        Jean Delvare <jdelvare@suse.de>
 
 Description
 -----------
index cbac32b59c8c96a1bc86a3455a3ee4cbe3342db5..d5f5cf16ce5987299aed1758d3d6731e0cd695e1 100644 (file)
@@ -7,7 +7,7 @@ Supported chips:
     Addresses scanned: none, address read from Super I/O config space
     Datasheets: No longer available
 
-Authors: Jean Delvare <khali@linux-fr.org>
+Authors: Jean Delvare <jdelvare@suse.de>
 
 Thanks to Sandeep Mehta, Tonko de Rooy and Daniel Ceregatti for testing.
 Thanks to Rudolf Marek for helping me investigate conversion issues.
index 8fdd08c9e48b5ceac48b100ee4cedbdf78fcc242..c313eb66e08adb03eb6a71ea0553da3e47e96351 100644 (file)
@@ -7,7 +7,7 @@ Supported chips:
     Addresses scanned: none, address read from Super I/O config space
     Datasheet: No longer available
 
-Author: Jean Delvare <khali@linux-fr.org>
+Author: Jean Delvare <jdelvare@suse.de>
 
 Thanks to Amir Habibi at Candelis for setting up a test system, and to
 Michael Kress for testing several iterations of this driver.
index ac020b3bb7b3769939a3574505ab1d3a0b173900..447c0702c0ecbf90ed25a7780579546ad52bed7b 100644 (file)
@@ -11,7 +11,7 @@ Supported chips:
 Authors:
         Aurelien Jarno <aurelien@aurel32.net>
         valuable contributions by Jan M. Sendler <sendler@sendler.de>,
-        Jean Delvare <khali@linux-fr.org>
+        Jean Delvare <jdelvare@suse.de>
 
 
 Description
index 2a13378dcf2213642fb6faf12f479babadbe6d61..10a24b42068636333445553ac1fbcc031b84e3f2 100644 (file)
@@ -25,7 +25,7 @@ Authors:
         With assistance from Bruce Allen <ballen@uwm.edu>, and his
         fan.c program: http://www.lsc-group.phys.uwm.edu/%7Eballen/driver/
         Gabriele Gorla <gorlik@yahoo.com>,
-        Jean Delvare <khali@linux-fr.org>
+        Jean Delvare <jdelvare@suse.de>
 
 Description
 -----------
index ceaf6f652b00662d19b2ece7b8792ee92799e4fa..735c42a85eadcab4a68d8cfc06a5aa4a946e9146 100644 (file)
@@ -36,7 +36,7 @@ Supported chips:
     Datasheet: Available from Nuvoton upon request
 
 Authors:
-        Jean Delvare <khali@linux-fr.org>
+        Jean Delvare <jdelvare@suse.de>
         Yuan Mu (Winbond)
         Rudolf Marek <r.marek@assembler.cz>
         David Hubbard <david.c.hubbard@gmail.com>
index 9f160371f463dbd11663999eedb5f538fce739e2..d3e678216b9adb87e6c052b950916e7f857222e8 100644 (file)
@@ -13,7 +13,7 @@ Supported chips:
 
 Authors:
     Wei Song (Nuvoton)
-    Jean Delvare <khali@linux-fr.org>
+    Jean Delvare <jdelvare@suse.de>
 
 
 Pin mapping
index bd1fa9d4468d9ba238c05c62cd562807c122e1ad..c8978478871f27d20d8f030b66c359a578360cbf 100644 (file)
@@ -9,7 +9,7 @@ Supported chips:
                http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf
 
 Authors:
-        Jean Delvare <khali@linux-fr.org>
+        Jean Delvare <jdelvare@suse.de>
 
 Description
 -----------
index 7b0dcdb57173ce2246303c2f20eec1e94a5c6b8b..aaaf069306a3ec13dd4dc86372ebb7416b12dd31 100644 (file)
@@ -33,7 +33,7 @@ and the additional 'Integrated Device Function' controllers are supported.
 
 Authors: 
        Mark Studebaker <mdsxyz123@yahoo.com>
-       Jean Delvare <khali@linux-fr.org>
+       Jean Delvare <jdelvare@suse.de>
 
 
 Module Parameters
index 2461c7b53b2c1e489ae699e95a25e1bd2ac8fe45..0e2d17b460fddc79b4127b8771c6edb58565780a 100644 (file)
@@ -1,6 +1,6 @@
 Kernel driver i2c-parport
 
-Author: Jean Delvare <khali@linux-fr.org> 
+Author: Jean Delvare <jdelvare@suse.de>
 
 This is a unified driver for several i2c-over-parallel-port adapters,
 such as the ones made by Philips, Velleman or ELV. This driver is
index c22ee063e1e52e6f5d03d6cf191bf564a7492857..7071b8ba0af4c88b9b73c100d1a0766a2ca20618 100644 (file)
@@ -1,6 +1,6 @@
 Kernel driver i2c-parport-light
 
-Author: Jean Delvare <khali@linux-fr.org> 
+Author: Jean Delvare <jdelvare@suse.de>
 
 This driver is a light version of i2c-parport. It doesn't depend        
 on the parport driver, and uses direct I/O access instead. This might be
index c097e0f020fe1d786bed67fd3ed9e06fd99f7b63..aa959fd22450de6793e02d73f2fa657ac31c4bce 100644 (file)
@@ -13,7 +13,7 @@ Supported adapters:
   * AMD SP5100 (SB700 derivative found on some server mainboards)
     Datasheet: Publicly available at the AMD website
     http://support.amd.com/us/Embedded_TechDocs/44413.pdf
-  * AMD Hudson-2, CZ
+  * AMD Hudson-2, ML, CZ
     Datasheet: Not publicly available
   * Standard Microsystems (SMSC) SLC90E66 (Victory66) southbridge
     Datasheet: Publicly available at the SMSC website http://www.smsc.com
index 63f62bcbf59200524b628d7b04859e1c09f9069f..60299555dcf01f44d1f3324691e44b642829573e 100644 (file)
@@ -1,6 +1,6 @@
 Kernel driver i2c-taos-evm
 
-Author: Jean Delvare <khali@linux-fr.org>
+Author: Jean Delvare <jdelvare@suse.de>
 
 This is a driver for the evaluation modules for TAOS I2C/SMBus chips.
 The modules include an SMBus master with limited capabilities, which can
index b88f91ae580ef53c72b5081d93f392c4b9d05278..ab64ce21c25442f68a262c19cf64aa5167bdfdbb 100644 (file)
@@ -28,7 +28,7 @@ Supported adapters:
 Authors:
        Kyösti Mälkki <kmalkki@cc.hut.fi>,
        Mark D. Studebaker <mdsxyz123@yahoo.com>,
-       Jean Delvare <khali@linux-fr.org>
+       Jean Delvare <jdelvare@suse.de>
 
 Module Parameters
 -----------------
index 7cbfa3c4fc3d327c8b1d9c3ef8a4c1228998a69b..d7e43fa88575b1845a38b9471eba70910d67d344 100644 (file)
@@ -73,6 +73,7 @@ Code  Seq#(hex)       Include File            Comments
 0x09   all     linux/raid/md_u.h
 0x10   00-0F   drivers/char/s390/vmcp.h
 0x10   10-1F   arch/s390/include/uapi/sclp_ctl.h
+0x10   20-2F   arch/s390/include/uapi/asm/hypfs.h
 0x12   all     linux/fs.h
                linux/blkpg.h
 0x1b   all     InfiniBand Subsystem    <http://infiniband.sourceforge.net/>
index be6ba33d4ff1ae85bc6bad162e5f9d6a210bbc32..8f441dab03963624c0f32eb8f030c2b3c9a38f9d 100644 (file)
@@ -3124,7 +3124,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        controller if no parameter or 1 is given or disable
                        it if 0 is given (See Documentation/cgroups/memory.txt)
 
-       swiotlb=        [IA-64] Number of I/O TLB slabs
+       swiotlb=        [ARM,IA-64,PPC,MIPS,X86]
+                       Format: { <int> | force }
+                       <int> -- Number of I/O TLB slabs
+                       force -- force using of bounce buffers even if they
+                                wouldn't be automatically used by the kernel
 
        switches=       [HW,M68k]
 
diff --git a/Documentation/kmsg/s390/zcrypt b/Documentation/kmsg/s390/zcrypt
deleted file mode 100644 (file)
index 7fb2087..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*?
- * Text: "Cryptographic device %x failed and was set offline\n"
- * Severity: Error
- * Parameter:
- *   @1: device index
- * Description:
- * A cryptographic device failed to process a cryptographic request.
- * The cryptographic device driver could not correct the error and
- * set the device offline. The application that issued the
- * request received an indication that the request has failed.
- * User action:
- * Use the lszcrypt command to confirm that the cryptographic
- * hardware is still configured to your LPAR or z/VM guest virtual
- * machine. If the device is available to your Linux instance the
- * command output contains a line that begins with 'card<device index>',
- * where <device index> is the two-digit decimal number in the message text.
- * After ensuring that the device is available, use the chzcrypt command to
- * set it online again.
- * If the error persists, contact your support organization.
- */
index 82713ff92eb3e5c72a82ff6f1dc9d637e7f04376..bcea12a0c5847e12211a14d43f356d0f1a1e77f0 100644 (file)
@@ -73,6 +73,10 @@ select_engine : Select which engine is used for running program
 run_engine    : Start program which is loaded via the firmware interface
 firmware      : Load program data
 
+In case of LP5523, one more command is required, 'enginex_leds'.
+It is used for selecting LED output(s) at each engine number.
+In more details, please refer to 'leds-lp5523.txt'.
+
 For example, run blinking pattern in engine #1 of LP5521
 echo 1 > /sys/bus/i2c/devices/xxxx/select_engine
 echo 1 > /sys/class/firmware/lp5521/loading
@@ -81,10 +85,12 @@ echo 0 > /sys/class/firmware/lp5521/loading
 echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
 
 For example, run blinking pattern in engine #3 of LP55231
+Two LEDs are configured as pattern output channels.
 echo 3 > /sys/bus/i2c/devices/xxxx/select_engine
 echo 1 > /sys/class/firmware/lp55231/loading
 echo "9d0740ff7e0040007e00a0010000" > /sys/class/firmware/lp55231/data
 echo 0 > /sys/class/firmware/lp55231/loading
+echo "000001100" > /sys/bus/i2c/devices/xxxx/engine3_leds
 echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
 
 To start blinking patterns in engine #2 and #3 simultaneously,
@@ -99,17 +105,19 @@ done
 echo 1 > /sys/class/leds/red/device/run_engine
 
 Here is another example for LP5523.
+Full LED strings are selected by 'engine2_leds'.
 echo 2 > /sys/bus/i2c/devices/xxxx/select_engine
 echo 1 > /sys/class/firmware/lp5523/loading
 echo "9d80400004ff05ff437f0000" > /sys/class/firmware/lp5523/data
 echo 0 > /sys/class/firmware/lp5523/loading
+echo "111111111" > /sys/bus/i2c/devices/xxxx/engine2_leds
 echo 1 > /sys/bus/i2c/devices/xxxx/run_engine
 
 As soon as 'loading' is set to 0, registered callback is called.
 Inside the callback, the selected engine is loaded and memory is updated.
 To run programmed pattern, 'run_engine' attribute should be enabled.
 
-The pattern sqeuence of LP8501 is same as LP5523.
+The pattern sqeuence of LP8501 is similar to LP5523.
 However pattern data is specific.
 Ex 1) Engine 1 is used
 echo 1 > /sys/bus/i2c/devices/xxxx/select_engine
index f7e8104b5764fa277b09ef4e7c9a9ab8634719b3..ba692011f221337f553ba5eb489be5548eaaa96b 100644 (file)
@@ -38,7 +38,7 @@ Supported chips:
 Authors:
         Frodo Looijaard <frodol@dds.nl>,
         Philip Edelbrock <phil@netroedge.com>,
-        Jean Delvare <khali@linux-fr.org>,
+        Jean Delvare <jdelvare@suse.de>,
         Greg Kroah-Hartman <greg@kroah.com>,
         IBM Corp.
 
diff --git a/Documentation/mtd/nand/pxa3xx-nand.txt b/Documentation/mtd/nand/pxa3xx-nand.txt
new file mode 100644 (file)
index 0000000..840fd41
--- /dev/null
@@ -0,0 +1,113 @@
+
+About this document
+===================
+
+Some notes about Marvell's NAND controller available in PXA and Armada 370/XP
+SoC (aka NFCv1 and NFCv2), with an emphasis on the latter.
+
+NFCv2 controller background
+===========================
+
+The controller has a 2176 bytes FIFO buffer. Therefore, in order to support
+larger pages, I/O operations on 4 KiB and 8 KiB pages is done with a set of
+chunked transfers.
+
+For instance, if we choose a 2048 data chunk and set "BCH" ECC (see below)
+we'll have this layout in the pages:
+
+  ------------------------------------------------------------------------------
+  | 2048B data | 32B spare | 30B ECC || 2048B data | 32B spare | 30B ECC | ... |
+  ------------------------------------------------------------------------------
+
+The driver reads the data and spare portions independently and builds an internal
+buffer with this layout (in the 4 KiB page case):
+
+  ------------------------------------------
+  |     4096B data     |     64B spare     |
+  ------------------------------------------
+
+Also, for the READOOB command the driver disables the ECC and reads a 'spare + ECC'
+OOB, one per chunk read.
+
+  -------------------------------------------------------------------
+  |     4096B data     |  32B spare | 30B ECC | 32B spare | 30B ECC |
+  -------------------------------------------------------------------
+
+So, in order to achieve reading (for instance), we issue several READ0 commands
+(with some additional controller-specific magic) and read two chunks of 2080B
+(2048 data + 32 spare) each.
+The driver accommodates this data to expose the NAND core a contiguous buffer
+(4096 data + spare) or (4096 + spare + ECC + spare + ECC).
+
+ECC
+===
+
+The controller has built-in hardware ECC capabilities. In addition it is
+configurable between two modes: 1) Hamming, 2) BCH.
+
+Note that the actual BCH mode: BCH-4 or BCH-8 will depend on the way
+the controller is configured to transfer the data.
+
+In the BCH mode the ECC code will be calculated for each transfered chunk
+and expected to be located (when reading/programming) right after the spare
+bytes as the figure above shows.
+
+So, repeating the above scheme, a 2048B data chunk will be followed by 32B
+spare, and then the ECC controller will read/write the ECC code (30B in
+this case):
+
+  ------------------------------------
+  | 2048B data | 32B spare | 30B ECC |
+  ------------------------------------
+
+If the ECC mode is 'BCH' then the ECC is *always* 30 bytes long.
+If the ECC mode is 'Hamming' the ECC is 6 bytes long, for each 512B block.
+So in Hamming mode, a 2048B page will have a 24B ECC.
+
+Despite all of the above, the controller requires the driver to only read or
+write in multiples of 8-bytes, because the data buffer is 64-bits.
+
+OOB
+===
+
+Because of the above scheme, and because the "spare" OOB is really located in
+the middle of a page, spare OOB cannot be read or write independently of the
+data area. In other words, in order to read the OOB (aka READOOB), the entire
+page (aka READ0) has to be read.
+
+In the same sense, in order to write to the spare OOB the driver has to write
+an *entire* page.
+
+Factory bad blocks handling
+===========================
+
+Given the ECC BCH requires to layout the device's pages in a split
+data/OOB/data/OOB way, the controller has a view of the flash page that's
+different from the specified (aka the manufacturer's) view. In other words,
+
+Factory view:
+
+  -----------------------------------------------
+  |                    Data           |x  OOB   |
+  -----------------------------------------------
+
+Driver's view:
+
+  -----------------------------------------------
+  |      Data      | OOB |      Data   x  | OOB |
+  -----------------------------------------------
+
+It can be seen from the above, that the factory bad block marker must be
+searched within the 'data' region, and not in the usual OOB region.
+
+In addition, this means under regular usage the driver will write such
+position (since it belongs to the data region) and every used block is
+likely to be marked as bad.
+
+For this reason, marking the block as bad in the OOB is explicitly
+disabled by using the NAND_BBT_NO_OOB_BBM option in the driver. The rationale
+for this is that there's no point in marking a block as bad, because good
+blocks are also 'marked as bad' (in the OOB BBM sense) under normal usage.
+
+Instead, the driver relies on the bad block table alone, and should only perform
+the bad block scan on the very first time (when the device hasn't been used).
index 5de03740cdd50c4177d649bc1675c7e412526651..ab42c95f9985c0172109308c052cfe426a5bed9a 100644 (file)
@@ -1088,6 +1088,12 @@ igmpv3_unsolicited_report_interval - INTEGER
        IGMPv3 report retransmit will take place.
        Default: 1000 (1 seconds)
 
+promote_secondaries - BOOLEAN
+       When a primary IP address is removed from this interface
+       promote a corresponding secondary IP address instead of
+       removing all the corresponding secondary IP addresses.
+
+
 tag - INTEGER
        Allows you to write a number, which can be used as required.
        Default value is 0.
index 91ffe1d9e8cab8bd1c42314fb065b6ace17632bb..1404674c0a0282af7d077cf55a5da076875bd2ed 100644 (file)
@@ -583,6 +583,7 @@ Currently implemented fanout policies are:
   - PACKET_FANOUT_CPU: schedule to socket by CPU packet arrives on
   - PACKET_FANOUT_RND: schedule to socket by random selection
   - PACKET_FANOUT_ROLLOVER: if one socket is full, rollover to another
+  - PACKET_FANOUT_QM: schedule to socket by skbs recorded queue_mapping
 
 Minimal example code by David S. Miller (try things like "./test eth0 hash",
 "./test eth0 lb", etc.):
index e9b54de8fdf7509e7d2cf2d3ec73deca5cf6f2e3..edeecd447d23dc8ff26e66debe0d874b9482f087 100644 (file)
@@ -172,7 +172,7 @@ you can boot the kernel with the 'no_console_suspend' parameter and try to log
 kernel messages using the serial console.  This may provide you with some
 information about the reasons of the suspend (resume) failure.  Alternatively,
 it may be possible to use a FireWire port for debugging with firescope
-(ftp://ftp.firstfloor.org/pub/ak/firescope/).  On x86 it is also possible to
+(http://v3.sk/~lkundrak/firescope/).  On x86 it is also possible to
 use the PM_TRACE mechanism documented in Documentation/power/s2ram.txt .
 
 2. Testing suspend to RAM (STR)
index d2651c47ae27fd439786a2ed72259c421b1d5eeb..46702e4f89c937d3d5a900b2da0f8af57163bc7f 100644 (file)
@@ -10,5 +10,7 @@ sched-nice-design.txt
        - How and why the scheduler's nice levels are implemented.
 sched-rt-group.txt
        - real-time group scheduling.
+sched-deadline.txt
+       - deadline scheduling.
 sched-stats.txt
        - information on schedstats (Linux Scheduler Statistics).
diff --git a/Documentation/scheduler/sched-deadline.txt b/Documentation/scheduler/sched-deadline.txt
new file mode 100644 (file)
index 0000000..18adc92
--- /dev/null
@@ -0,0 +1,281 @@
+                         Deadline Task Scheduling
+                         ------------------------
+
+CONTENTS
+========
+
+ 0. WARNING
+ 1. Overview
+ 2. Scheduling algorithm
+ 3. Scheduling Real-Time Tasks
+ 4. Bandwidth management
+   4.1 System-wide settings
+   4.2 Task interface
+   4.3 Default behavior
+ 5. Tasks CPU affinity
+   5.1 SCHED_DEADLINE and cpusets HOWTO
+ 6. Future plans
+
+
+0. WARNING
+==========
+
+ Fiddling with these settings can result in an unpredictable or even unstable
+ system behavior. As for -rt (group) scheduling, it is assumed that root users
+ know what they're doing.
+
+
+1. Overview
+===========
+
+ The SCHED_DEADLINE policy contained inside the sched_dl scheduling class is
+ basically an implementation of the Earliest Deadline First (EDF) scheduling
+ algorithm, augmented with a mechanism (called Constant Bandwidth Server, CBS)
+ that makes it possible to isolate the behavior of tasks between each other.
+
+
+2. Scheduling algorithm
+==================
+
+ SCHED_DEADLINE uses three parameters, named "runtime", "period", and
+ "deadline" to schedule tasks. A SCHED_DEADLINE task is guaranteed to 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.
+
+ 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.
+
+ In more details, the CBS algorithm assigns scheduling deadlines to
+ tasks in the following way:
+
+  - Each SCHED_DEADLINE task is characterised by the "runtime",
+    "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;
+
+  - When a SCHED_DEADLINE task wakes up (becomes ready for execution),
+    the scheduler checks if
+
+                    current 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
+
+         scheduling deadline = current time + deadline
+         current runtime = runtime
+
+    otherwise, the scheduling deadline and the current runtime are
+    left unchanged;
+
+  - When a SCHED_DEADLINE task executes for an amount of time t, its
+    current runtime is decreased as
+
+         current runtime = current 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
+    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
+    updated as
+
+         scheduling deadline = scheduling deadline + period
+         current runtime = current runtime + runtime
+
+
+3. Scheduling Real-Time Tasks
+=============================
+
+ * BIG FAT WARNING ******************************************************
+ *
+ * This section contains a (not-thorough) summary on classical deadline
+ * scheduling theory, and how it applies to SCHED_DEADLINE.
+ * The reader can "safely" skip to Section 4 if only interested in seeing
+ * how the scheduling policy can be used. Anyway, we strongly recommend
+ * to come back here and continue reading (once the urge for testing is
+ * satisfied :P) to be sure of fully understanding all technical details.
+ ************************************************************************
+
+ There are no limitations on what kind of task can exploit this new
+ scheduling discipline, even if it must be said that it is particularly
+ suited for periodic or sporadic real-time tasks that need guarantees on their
+ timing behavior, e.g., multimedia, streaming, control applications, etc.
+
+ A typical real-time task is composed of a repetition of computation phases
+ (task instances, or jobs) which are activated on a periodic or sporadic
+ fashion.
+ Each job J_j (where J_j is the j^th job of the task) is characterised by an
+ arrival time r_j (the time when the job starts), an amount of computation
+ time c_j needed to finish the job, and a job absolute deadline d_j, which
+ is the time within which the job should be finished. The maximum execution
+ time max_j{c_j} is called "Worst Case Execution Time" (WCET) for the task.
+ 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.
+
+ 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
+ must be scheduled by setting:
+
+  - runtime >= WCET
+  - deadline = D
+  - period <= P
+
+ IOW, if runtime >= WCET and if period is >= P, then the scheduling deadlines
+ 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]).
+
+ References:
+  1 - C. L. Liu and J. W. Layland. Scheduling algorithms for multiprogram-
+      ming in a hard-real-time environment. Journal of the Association for
+      Computing Machinery, 20(1), 1973.
+  2 - L. Abeni , G. Buttazzo. Integrating Multimedia Applications in Hard
+      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
+
+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,
+ 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
+ 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.
+
+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.
+
+ This means that, for a root_domain comprising M CPUs, -deadline tasks
+ can be created while the sum of their bandwidths stays below:
+
+   M * (sched_rt_runtime_us / sched_rt_period_us)
+
+ It is also possible to disable this bandwidth management logic, and
+ be thus free of oversubscribing the system up to any arbitrary level.
+ This is done by writing -1 in /proc/sys/kernel/sched_rt_runtime_us.
+
+
+4.2 Task interface
+------------------
+
+ Specifying a periodic/sporadic task that executes for a given amount of
+ runtime at each instance, and that is scheduled according to the urgency of
+ its own timing constraints needs, in general, a way of declaring:
+  - a (maximum/typical) instance execution time,
+  - a minimum interval between consecutive instances,
+  - a time constraint by which each instance must be completed.
+
+ Therefore:
+  * a new struct sched_attr, containing all the necessary fields is
+    provided;
+  * the new scheduling related syscalls that manipulate it, i.e.,
+    sched_setattr() and sched_getattr() are implemented.
+
+
+4.3 Default behavior
+---------------------
+
+ The default value for SCHED_DEADLINE bandwidth is to have rt_runtime equal to
+ 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.
+
+ A -deadline task cannot fork.
+
+5. Tasks CPU affinity
+=====================
+
+ -deadline tasks cannot have an affinity mask smaller that the entire
+ root_domain they are created on. However, affinities can be specified
+ through the cpuset facility (Documentation/cgroups/cpusets.txt).
+
+5.1 SCHED_DEADLINE and cpusets HOWTO
+------------------------------------
+
+ An example of a simple configuration (pin a -deadline task to CPU0)
+ follows (rt-app is used to create a -deadline task).
+
+ mkdir /dev/cpuset
+ mount -t cgroup -o cpuset cpuset /dev/cpuset
+ cd /dev/cpuset
+ mkdir cpu0
+ echo 0 > cpu0/cpuset.cpus
+ echo 0 > cpu0/cpuset.mems
+ echo 1 > cpuset.cpu_exclusive
+ echo 0 > cpuset.sched_load_balance
+ echo 1 > cpu0/cpuset.cpu_exclusive
+ echo 1 > cpu0/cpuset.mem_exclusive
+ echo $$ > cpu0/tasks
+ rt-app -t 100000:10000:d:0 -D5 (it is now actually superfluous to specify
+ task affinity)
+
+6. Future plans
+===============
+
+ Still missing:
+
+  - refinements to deadline inheritance, especially regarding the possibility
+    of retaining bandwidth isolation among non-interacting tasks. This is
+    being studied from both theoretical and practical points of view, and
+    hopefully we should be able to produce some demonstrative code soon;
+  - (c)group based bandwidth management, and maybe scheduling;
+  - access control for non-root users (and related security concerns to
+    address), which is the best way to allow unprivileged use of the mechanisms
+    and how to prevent non-root users "cheat" the system?
+
+ As already discussed, we are planning also to merge this work with the EDF
+ 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.
index ee9a2f983b9901d74266f9bfa9c1a2da68c49450..e55124e7c40cd0eef8afb92c34913cd68c42faac 100644 (file)
@@ -33,6 +33,10 @@ show up in /proc/sys/kernel:
 - domainname
 - hostname
 - hotplug
+- hung_task_panic
+- hung_task_check_count
+- hung_task_timeout_secs
+- hung_task_warnings
 - kexec_load_disabled
 - kptr_restrict
 - kstack_depth_to_print       [ X86 only ]
@@ -288,6 +292,44 @@ Default value is "/sbin/hotplug".
 
 ==============================================================
 
+hung_task_panic:
+
+Controls the kernel's behavior when a hung task is detected.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+0: continue operation. This is the default behavior.
+
+1: panic immediately.
+
+==============================================================
+
+hung_task_check_count:
+
+The upper bound on the number of tasks that are checked.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+==============================================================
+
+hung_task_timeout_secs:
+
+Check interval. When a task in D state did not get scheduled
+for more than this value report a warning.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+0: means infinite timeout - no checking done.
+
+==============================================================
+
+hung_task_warning:
+
+The maximum number of warnings to report. During a check interval
+When this value is reached, no more the warnings will be reported.
+This file shows up if CONFIG_DETECT_HUNG_TASK is enabled.
+
+-1: report an infinite number of warnings.
+
+==============================================================
+
 kexec_load_disabled:
 
 A toggle indicating if the kexec_load syscall has been disabled. This
index 9f5481bdc5a43f942fb833f3131901249d2d5c50..d614a9b6a28048ecf879e96b3aada686ecadb6cb 100644 (file)
@@ -696,7 +696,9 @@ swappiness
 
 This control is used to define how aggressive the kernel will swap
 memory pages.  Higher values will increase agressiveness, lower values
-decrease the amount of swap.
+decrease the amount of swap.  A value of 0 instructs the kernel not to
+initiate swap until the amount of free and file-backed pages is less
+than the high water mark in a zone.
 
 The default value is 60.
 
diff --git a/Documentation/video4linux/omap4_camera.txt b/Documentation/video4linux/omap4_camera.txt
new file mode 100644 (file)
index 0000000..25d9b40
--- /dev/null
@@ -0,0 +1,60 @@
+                              OMAP4 ISS Driver
+                              ================
+
+Introduction
+------------
+
+The OMAP44XX family of chips contains the Imaging SubSystem (a.k.a. ISS),
+Which contains several components that can be categorized in 3 big groups:
+
+- Interfaces (2 Interfaces: CSI2-A & CSI2-B/CCP2)
+- ISP (Image Signal Processor)
+- SIMCOP (Still Image Coprocessor)
+
+For more information, please look in [1] for latest version of:
+       "OMAP4430 Multimedia Device Silicon Revision 2.x"
+
+As of Revision AB, the ISS is described in detail in section 8.
+
+This driver is supporting _only_ the CSI2-A/B interfaces for now.
+
+It makes use of the Media Controller framework [2], and inherited most of the
+code from OMAP3 ISP driver (found under drivers/media/platform/omap3isp/*),
+except that it doesn't need an IOMMU now for ISS buffers memory mapping.
+
+Supports usage of MMAP buffers only (for now).
+
+Tested platforms
+----------------
+
+- OMAP4430SDP, w/ ES2.1 GP & SEVM4430-CAM-V1-0 (Contains IMX060 & OV5640, in
+  which only the last one is supported, outputting YUV422 frames).
+
+- TI Blaze MDP, w/ OMAP4430 ES2.2 EMU (Contains 1 IMX060 & 2 OV5650 sensors, in
+  which only the OV5650 are supported, outputting RAW10 frames).
+
+- PandaBoard, Rev. A2, w/ OMAP4430 ES2.1 GP & OV adapter board, tested with
+  following sensors:
+  * OV5640
+  * OV5650
+
+- Tested on mainline kernel:
+
+       http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=summary
+
+  Tag: v3.3 (commit c16fa4f2ad19908a47c63d8fa436a1178438c7e7)
+
+File list
+---------
+drivers/staging/media/omap4iss/
+include/media/omap4iss.h
+
+References
+----------
+
+[1] http://focus.ti.com/general/docs/wtbu/wtbudocumentcenter.tsp?navigationId=12037&templateId=6123#62
+[2] http://lwn.net/Articles/420485/
+[3] http://www.spinics.net/lists/linux-media/msg44370.html
+--
+Author: Sergio Aguirre <sergio.a.aguirre@gmail.com>
+Copyright (C) 2012, Texas Instruments
index 2f9b4875ab8a33c276e38166fa97080223a82d61..616607955aafc4799d97da813e6c94b662596cab 100644 (file)
@@ -147,7 +147,7 @@ The drivers exposes following files:
   --------------------------------------------------------------------
   0x12         | readfreq      | Current tuned frequency
   --------------------------------------------------------------------
-  0x14         | freqoff       | Singed frequency offset in units of
+  0x14         | freqoff       | Signed frequency offset in units of
                |               | 2ppm
   --------------------------------------------------------------------
   0x15         | rssi          | Signed value of RSSI in dBuV
index 366bf4b47ef48bb56a6d0dd96d6951a65c8e2129..6cd63a9010fbbfd7f011a9f3085a7b688da29fba 100644 (file)
@@ -1838,6 +1838,7 @@ registers, find a list below:
   PPC   | KVM_REG_PPC_LPCR     | 64
   PPC   | KVM_REG_PPC_PPR      | 64
   PPC   | KVM_REG_PPC_ARCH_COMPAT 32
+  PPC   | KVM_REG_PPC_DABRX     | 32
   PPC   | KVM_REG_PPC_TM_GPR0  | 64
           ...
   PPC   | KVM_REG_PPC_TM_GPR31 | 64
index 2507f38b208f7a6773d31a8f0921c9cc8c4210a8..dc2fd2298090ebf5e9df83c2e83696eadad2fc7c 100644 (file)
@@ -309,36 +309,36 @@ F:        sound/pci/ad1889.*
 
 AD525X ANALOG DEVICES DIGITAL POTENTIOMETERS DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD5254
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/misc/ad525x_dpot.c
 
 AD5398 CURRENT REGULATOR DRIVER (AD5398/AD5821)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD5398
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/regulator/ad5398.c
 
 AD714X CAPACITANCE TOUCH SENSOR DRIVER (AD7142/3/7/8/7A)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD7142
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/input/misc/ad714x.c
 
 AD7877 TOUCHSCREEN DRIVER
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD7877
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/input/touchscreen/ad7877.c
 
 AD7879 TOUCHSCREEN DRIVER (AD7879/AD7889)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/AD7879
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/input/touchscreen/ad7879.c
 
@@ -347,7 +347,7 @@ M:  Jiri Kosina <jkosina@suse.cz>
 S:     Maintained
 
 ADM1025 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/adm1025
@@ -374,8 +374,8 @@ F:  include/media/adp1653.h
 
 ADP5520 BACKLIGHT DRIVER WITH IO EXPANDER (ADP5520/ADP5501)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP5520
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/mfd/adp5520.c
 F:     drivers/video/backlight/adp5520_bl.c
@@ -385,16 +385,16 @@ F:        drivers/input/keyboard/adp5520-keys.c
 
 ADP5588 QWERTY KEYPAD AND IO EXPANDER DRIVER (ADP5588/ADP5587)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP5588
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/input/keyboard/adp5588-keys.c
 F:     drivers/gpio/gpio-adp5588.c
 
 ADP8860 BACKLIGHT DRIVER (ADP8860/ADP8861/ADP8863)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADP8860
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/video/backlight/adp8860_bl.c
 
@@ -412,7 +412,7 @@ S:  Maintained
 F:     drivers/macintosh/therm_adt746x.c
 
 ADT7475 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/adt7475
@@ -420,8 +420,8 @@ F:  drivers/hwmon/adt7475.c
 
 ADXL34X THREE-AXIS DIGITAL ACCELEROMETER DRIVER (ADXL345/ADXL346)
 M:     Michael Hennerich <michael.hennerich@analog.com>
-L:     device-drivers-devel@blackfin.uclinux.org
 W:     http://wiki.analog.com/ADXL345
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     drivers/input/misc/adxl34x.c
 
@@ -627,9 +627,9 @@ F:  drivers/media/i2c/adv7842*
 
 ANALOG DEVICES INC ASOC CODEC DRIVERS
 M:     Lars-Peter Clausen <lars@metafoo.de>
-L:     device-drivers-devel@blackfin.uclinux.org
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://wiki.analog.com/
+W:     http://ez.analog.com/community/linux-device-drivers
 S:     Supported
 F:     sound/soc/codecs/adau*
 F:     sound/soc/codecs/adav*
@@ -639,7 +639,7 @@ F:  sound/soc/codecs/ssm*
 F:     sound/soc/codecs/sigmadsp.*
 
 ANALOG DEVICES INC ASOC DRIVERS
-L:     uclinux-dist-devel@blackfin.uclinux.org
+L:     adi-buildroot-devel@lists.sourceforge.net
 L:     alsa-devel@alsa-project.org (moderated for non-subscribers)
 W:     http://blackfin.uclinux.org/
 S:     Supported
@@ -1742,56 +1742,54 @@ F:      fs/bfs/
 F:     include/uapi/linux/bfs_fs.h
 
 BLACKFIN ARCHITECTURE
-M:     Mike Frysinger <vapier@gentoo.org>
-L:     uclinux-dist-devel@blackfin.uclinux.org
+M:     Steven Miao <realmz6@gmail.com>
+L:     adi-buildroot-devel@lists.sourceforge.net
 W:     http://blackfin.uclinux.org
 S:     Supported
 F:     arch/blackfin/
 
 BLACKFIN EMAC DRIVER
-L:     uclinux-dist-devel@blackfin.uclinux.org
+L:     adi-buildroot-devel@lists.sourceforge.net
 W:     http://blackfin.uclinux.org
 S:     Supported
 F:     drivers/net/ethernet/adi/
 
 BLACKFIN RTC DRIVER
-M:     Mike Frysinger <vapier.adi@gmail.com>
-L:     uclinux-dist-devel@blackfin.uclinux.org
+L:     adi-buildroot-devel@lists.sourceforge.net
 W:     http://blackfin.uclinux.org
 S:     Supported
 F:     drivers/rtc/rtc-bfin.c
 
 BLACKFIN SDH DRIVER
 M:     Sonic Zhang <sonic.zhang@analog.com>
-L:     uclinux-dist-devel@blackfin.uclinux.org
+L:     adi-buildroot-devel@lists.sourceforge.net
 W:     http://blackfin.uclinux.org
 S:     Supported
 F:     drivers/mmc/host/bfin_sdh.c
 
 BLACKFIN SERIAL DRIVER
 M:     Sonic Zhang <sonic.zhang@analog.com>
-L:     uclinux-dist-devel@blackfin.uclinux.org
+L:     adi-buildroot-devel@lists.sourceforge.net
 W:     http://blackfin.uclinux.org
 S:     Supported
 F:     drivers/tty/serial/bfin_uart.c
 
 BLACKFIN WATCHDOG DRIVER
-M:     Mike Frysinger <vapier.adi@gmail.com>
-L:     uclinux-dist-devel@blackfin.uclinux.org
+L:     adi-buildroot-devel@lists.sourceforge.net
 W:     http://blackfin.uclinux.org
 S:     Supported
 F:     drivers/watchdog/bfin_wdt.c
 
 BLACKFIN I2C TWI DRIVER
 M:     Sonic Zhang <sonic.zhang@analog.com>
-L:     uclinux-dist-devel@blackfin.uclinux.org
+L:     adi-buildroot-devel@lists.sourceforge.net
 W:     http://blackfin.uclinux.org/
 S:     Supported
 F:     drivers/i2c/busses/i2c-bfin-twi.c
 
 BLACKFIN MEDIA DRIVER
 M:     Scott Jiang <scott.jiang.linux@gmail.com>
-L:     uclinux-dist-devel@blackfin.uclinux.org
+L:     adi-buildroot-devel@lists.sourceforge.net
 W:     http://blackfin.uclinux.org/
 S:     Supported
 F:     drivers/media/platform/blackfin/
@@ -2224,6 +2222,7 @@ F:        include/linux/clk.h
 CLOCKSOURCE, CLOCKEVENT DRIVERS
 M:     Daniel Lezcano <daniel.lezcano@linaro.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
+L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Supported
 F:     drivers/clocksource
@@ -3389,7 +3388,7 @@ F:        drivers/video/exynos/exynos_mipi*
 F:     include/video/exynos_mipi*
 
 F71805F HARDWARE MONITORING DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/f71805f
@@ -3916,7 +3915,7 @@ S:        Odd Fixes
 F:     drivers/tty/hvc/
 
 HARDWARE MONITORING
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 M:     Guenter Roeck <linux@roeck-us.net>
 L:     lm-sensors@lm-sensors.org
 W:     http://www.lm-sensors.org/
@@ -4025,6 +4024,7 @@ F:        include/uapi/linux/hid*
 
 HIGH-RESOLUTION TIMERS, CLOCKEVENTS, DYNTICKS
 M:     Thomas Gleixner <tglx@linutronix.de>
+L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Maintained
 F:     Documentation/timers/
@@ -4144,7 +4144,7 @@ F:        include/linux/hyperv.h
 F:     tools/hv/
 
 I2C OVER PARALLEL PORT
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 F:     Documentation/i2c/busses/i2c-parport
@@ -4153,7 +4153,7 @@ F:        drivers/i2c/busses/i2c-parport.c
 F:     drivers/i2c/busses/i2c-parport-light.c
 
 I2C/SMBUS CONTROLLER DRIVERS FOR PC
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 F:     Documentation/i2c/busses/i2c-ali1535
@@ -4194,7 +4194,7 @@ F:        drivers/i2c/busses/i2c-ismt.c
 F:     Documentation/i2c/busses/i2c-ismt
 
 I2C/SMBUS STUB DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 F:     drivers/i2c/i2c-stub.c
@@ -4213,7 +4213,7 @@ F:        include/uapi/linux/i2c.h
 F:     include/uapi/linux/i2c-*.h
 
 I2C-TAOS-EVM DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     linux-i2c@vger.kernel.org
 S:     Maintained
 F:     Documentation/i2c/busses/i2c-taos-evm
@@ -4696,6 +4696,7 @@ F:        net/irda/
 
 IRQ SUBSYSTEM
 M:     Thomas Gleixner <tglx@linutronix.de>
+L:     linux-kernel@vger.kernel.org
 S:     Maintained
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git irq/core
 F:     kernel/irq/
@@ -4770,7 +4771,7 @@ S:        Maintained
 F:     drivers/isdn/hardware/eicon/
 
 IT87 HARDWARE MONITORING DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/it87
@@ -5140,7 +5141,7 @@ F:        drivers/leds/
 F:     include/linux/leds.h
 
 LEGACY EEPROM DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 S:     Maintained
 F:     Documentation/misc-devices/eeprom
 F:     drivers/misc/eeprom/eeprom.c
@@ -5288,21 +5289,21 @@ S:      Maintained
 F:     drivers/hwmon/lm73.c
 
 LM78 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/lm78
 F:     drivers/hwmon/lm78.c
 
 LM83 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/lm83
 F:     drivers/hwmon/lm83.c
 
 LM90 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/lm90
@@ -5327,6 +5328,7 @@ F:        drivers/media/usb/dvb-usb-v2/lmedm04*
 LOCKDEP AND LOCKSTAT
 M:     Peter Zijlstra <peterz@infradead.org>
 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
@@ -5423,6 +5425,16 @@ W:       http://www.tazenda.demon.co.uk/phil/linux-hp
 S:     Maintained
 F:     arch/m68k/hp300/
 
+M88DS3103 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/dvb-frontends/m88ds3103*
+
 M88RS2000 MEDIA DRIVER
 M:     Malcolm Priestley <tvboxspy@gmail.com>
 L:     linux-media@vger.kernel.org
@@ -5431,6 +5443,16 @@ Q:       http://patchwork.linuxtv.org/project/linux-media/list/
 S:     Maintained
 F:     drivers/media/dvb-frontends/m88rs2000*
 
+M88TS2022 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/tuners/m88ts2022*
+
 MA901 MASTERKIT USB FM RADIO DRIVER
 M:      Alexey Klimov <klimov.linux@gmail.com>
 L:      linux-media@vger.kernel.org
@@ -5622,10 +5644,11 @@ F:      mm/page_cgroup.c
 
 MEMORY TECHNOLOGY DEVICES (MTD)
 M:     David Woodhouse <dwmw2@infradead.org>
+M:     Brian Norris <computersforpeace@gmail.com>
 L:     linux-mtd@lists.infradead.org
 W:     http://www.linux-mtd.infradead.org/
 Q:     http://patchwork.ozlabs.org/project/linux-mtd/list/
-T:     git git://git.infradead.org/mtd-2.6.git
+T:     git git://git.infradead.org/linux-mtd.git
 S:     Maintained
 F:     drivers/mtd/
 F:     include/linux/mtd/
@@ -6494,7 +6517,7 @@ S:        Maintained
 F:     drivers/char/pc8736x_gpio.c
 
 PC87427 HARDWARE MONITORING DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/pc87427
@@ -6623,6 +6646,7 @@ M:        Peter Zijlstra <a.p.zijlstra@chello.nl>
 M:     Paul Mackerras <paulus@samba.org>
 M:     Ingo Molnar <mingo@redhat.com>
 M:     Arnaldo Carvalho de Melo <acme@ghostprotocols.net>
+L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git perf/core
 S:     Supported
 F:     kernel/events/*
@@ -6746,6 +6770,7 @@ F:        drivers/scsi/pm8001/
 
 POSIX CLOCKS and TIMERS
 M:     Thomas Gleixner <tglx@linutronix.de>
+L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Supported
 F:     fs/timerfd.c
@@ -6942,6 +6967,12 @@ F:       include/sound/pxa2xx-lib.h
 F:     sound/arm/pxa*
 F:     sound/soc/pxa/
 
+PXA3xx NAND FLASH DRIVER
+M:     Ezequiel Garcia <ezequiel.garcia@free-electrons.com>
+L:     linux-mtd@lists.infradead.org
+S:     Maintained
+F:     drivers/mtd/nand/pxa3xx-nand.c
+
 MMP SUPPORT
 M:     Eric Miao <eric.y.miao@gmail.com>
 M:     Haojian Zhuang <haojian.zhuang@gmail.com>
@@ -7075,7 +7106,7 @@ F:        drivers/media/parport/*-qcam*
 RADOS BLOCK DEVICE (RBD)
 M:     Yehuda Sadeh <yehuda@inktank.com>
 M:     Sage Weil <sage@inktank.com>
-M:     Alex Elder <elder@inktank.com>
+M:     Alex Elder <elder@kernel.org>
 M:     ceph-devel@vger.kernel.org
 W:     http://ceph.com/
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph-client.git
@@ -7148,6 +7179,7 @@ F:        drivers/net/wireless/ray*
 RCUTORTURE MODULE
 M:     Josh Triplett <josh@freedesktop.org>
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
+L:     linux-kernel@vger.kernel.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
 F:     Documentation/RCU/torture.txt
@@ -7155,6 +7187,7 @@ F:        kernel/rcu/torture.c
 
 RCUTORTURE TEST FRAMEWORK
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
+L:     linux-kernel@vger.kernel.org
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
 F:     tools/testing/selftests/rcutorture
@@ -7178,6 +7211,7 @@ F:        net/rds/
 READ-COPY UPDATE (RCU)
 M:     Dipankar Sarma <dipankar@in.ibm.com>
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
+L:     linux-kernel@vger.kernel.org
 W:     http://www.rdrop.com/users/paulmck/RCU/
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
@@ -7457,6 +7491,13 @@ L:       linux-media@vger.kernel.org
 S:     Supported
 F:     drivers/media/i2c/s5c73m3/*
 
+SAMSUNG S5K5BAF CAMERA DRIVER
+M:     Kyungmin Park <kyungmin.park@samsung.com>
+M:     Andrzej Hajda <a.hajda@samsung.com>
+L:     linux-media@vger.kernel.org
+S:     Supported
+F:     drivers/media/i2c/s5k5baf.c
+
 SAMSUNG SOC CLOCK DRIVERS
 M:     Tomasz Figa <t.figa@samsung.com>
 S:     Supported
@@ -7487,6 +7528,7 @@ F:        drivers/mmc/host/dw_mmc*
 TIMEKEEPING, CLOCKSOURCE CORE, NTP
 M:     John Stultz <john.stultz@linaro.org>
 M:     Thomas Gleixner <tglx@linutronix.de>
+L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
 S:     Supported
 F:     include/linux/clocksource.h
@@ -7512,6 +7554,7 @@ F:        drivers/watchdog/sc1200wdt.c
 SCHEDULER
 M:     Ingo Molnar <mingo@redhat.com>
 M:     Peter Zijlstra <peterz@infradead.org>
+L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched/core
 S:     Maintained
 F:     kernel/sched/
@@ -7758,7 +7801,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 W:     http://linuxtv.org
 S:     Odd Fixes
-F:     drivers/media/radio/si4713-i2c.?
+F:     drivers/media/radio/si4713/si4713.?
 
 SI4713 FM RADIO TRANSMITTER PLATFORM DRIVER
 M:     Eduardo Valentin <edubezval@gmail.com>
@@ -7766,7 +7809,15 @@ L:       linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 W:     http://linuxtv.org
 S:     Odd Fixes
-F:     drivers/media/radio/radio-si4713.c
+F:     drivers/media/radio/si4713/radio-platform-si4713.c
+
+SI4713 FM RADIO TRANSMITTER USB 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:     Maintained
+F:     drivers/media/radio/si4713/radio-usb-si4713.c
 
 SIANO DVB DRIVER
 M:     Mauro Carvalho Chehab <m.chehab@samsung.com>
@@ -7879,6 +7930,7 @@ F:        mm/sl?b.c
 SLEEPABLE READ-COPY UPDATE (SRCU)
 M:     Lai Jiangshan <laijs@cn.fujitsu.com>
 M:     "Paul E. McKenney" <paulmck@linux.vnet.ibm.com>
+L:     linux-kernel@vger.kernel.org
 W:     http://www.rdrop.com/users/paulmck/RCU/
 S:     Supported
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu.git
@@ -7938,7 +7990,7 @@ F:        Documentation/hwmon/sch5627
 F:     drivers/hwmon/sch5627.c
 
 SMSC47B397 HARDWARE MONITOR DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     Documentation/hwmon/smsc47b397
@@ -8617,6 +8669,14 @@ L:       linux-xtensa@linux-xtensa.org
 S:     Maintained
 F:     arch/xtensa/
 
+THANKO'S RAREMONO AM/FM/SW RADIO RECEIVER USB 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:     Maintained
+F:     drivers/media/radio/radio-raremono.c
+
 THERMAL
 M:      Zhang Rui <rui.zhang@intel.com>
 M:      Eduardo Valentin <eduardo.valentin@ti.com>
@@ -8955,7 +9015,7 @@ UNSORTED BLOCK IMAGES (UBI)
 M:     Artem Bityutskiy <dedekind1@gmail.com>
 W:     http://www.linux-mtd.infradead.org/
 L:     linux-mtd@lists.infradead.org
-T:     git git://git.infradead.org/ubi-2.6.git
+T:     git git://git.infradead.org/ubifs-2.6.git
 S:     Maintained
 F:     drivers/mtd/ubi/
 F:     include/linux/mtd/ubi.h
@@ -9149,8 +9209,7 @@ L:        linux-media@vger.kernel.org
 T:     git git://linuxtv.org/media_tree.git
 W:     http://www.linux-projects.org
 S:     Maintained
-F:     Documentation/video4linux/sn9c102.txt
-F:     drivers/media/usb/sn9c102/
+F:     drivers/staging/media/sn9c102/
 
 USB SUBSYSTEM
 M:     Greg Kroah-Hartman <gregkh@linuxfoundation.org>
@@ -9456,7 +9515,7 @@ F:        Documentation/hwmon/w83793
 F:     drivers/hwmon/w83793.c
 
 W83795 HARDWARE MONITORING DRIVER
-M:     Jean Delvare <khali@linux-fr.org>
+M:     Jean Delvare <jdelvare@suse.de>
 L:     lm-sensors@lm-sensors.org
 S:     Maintained
 F:     drivers/hwmon/w83795.c
@@ -9582,6 +9641,7 @@ M:        Thomas Gleixner <tglx@linutronix.de>
 M:     Ingo Molnar <mingo@redhat.com>
 M:     "H. Peter Anvin" <hpa@zytor.com>
 M:     x86@kernel.org
+L:     linux-kernel@vger.kernel.org
 T:     git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git x86/core
 S:     Maintained
 F:     Documentation/x86/
@@ -9735,11 +9795,27 @@ T:      Mercurial http://linuxtv.org/hg/v4l-dvb
 S:     Odd Fixes
 F:     drivers/media/pci/zoran/
 
+ZRAM COMPRESSED RAM BLOCK DEVICE DRVIER
+M:     Minchan Kim <minchan@kernel.org>
+M:     Nitin Gupta <ngupta@vflare.org>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     drivers/block/zram/
+F:     Documentation/blockdev/zram.txt
+
 ZS DECSTATION Z85C30 SERIAL DRIVER
 M:     "Maciej W. Rozycki" <macro@linux-mips.org>
 S:     Maintained
 F:     drivers/tty/serial/zs.*
 
+ZSMALLOC COMPRESSED SLAB MEMORY ALLOCATOR
+M:     Minchan Kim <minchan@kernel.org>
+M:     Nitin Gupta <ngupta@vflare.org>
+L:     linux-mm@kvack.org
+S:     Maintained
+F:     mm/zsmalloc.c
+F:     include/linux/zsmalloc.h
+
 ZSWAP COMPRESSED SWAP CACHING
 M:     Seth Jennings <sjenning@linux.vnet.ibm.com>
 L:     linux-mm@kvack.org
index 455fd484b20edb92a0c916c1be3cc7adffc6cfa4..4231023c0b80429ff4e44f315eb099743d4d043a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -311,9 +311,15 @@ endif
 # If the user is running make -s (silent mode), suppress echoing of
 # commands
 
+ifneq ($(filter 4.%,$(MAKE_VERSION)),) # make-4
+ifneq ($(filter %s ,$(firstword x$(MAKEFLAGS))),)
+  quiet=silent_
+endif
+else                                   # make-3.8x
 ifneq ($(filter s% -s%,$(MAKEFLAGS)),)
   quiet=silent_
 endif
+endif
 
 export quiet Q KBUILD_VERBOSE
 
@@ -633,7 +639,7 @@ endif
 
 ifdef CONFIG_DEBUG_INFO
 KBUILD_CFLAGS  += -g
-KBUILD_AFLAGS  += -gdwarf-2
+KBUILD_AFLAGS  += -Wa,--gdwarf-2
 endif
 
 ifdef CONFIG_DEBUG_INFO_REDUCED
@@ -682,6 +688,9 @@ KBUILD_CFLAGS   += $(call cc-option,-Werror=implicit-int)
 # require functions to have arguments in prototypes, not empty 'int foo()'
 KBUILD_CFLAGS   += $(call cc-option,-Werror=strict-prototypes)
 
+# Prohibit date/time macros, which would make the build non-deterministic
+KBUILD_CFLAGS   += $(call cc-option,-Werror=date-time)
+
 # use the deterministic mode of AR if available
 KBUILD_ARFLAGS := $(call ar-option,D)
 
index 97a2d9a096b948cd0e325e8188d591a11fedef7a..f6c6b345388c85a8172d3558d098ed925161a9a8 100644 (file)
@@ -17,6 +17,7 @@ config ALPHA
        select ARCH_WANT_IPC_PARSE_VERSION
        select ARCH_HAVE_NMI_SAFE_CMPXCHG
        select ARCH_HAS_ATOMIC64_DEC_IF_POSITIVE
+       select AUDIT_ARCH
        select GENERIC_CLOCKEVENTS
        select GENERIC_SMP_IDLE_THREAD
        select GENERIC_STRNCPY_FROM_USER
@@ -77,6 +78,8 @@ config GENERIC_ISA_DMA
 source "init/Kconfig"
 source "kernel/Kconfig.freezer"
 
+config AUDIT_ARCH
+       bool
 
 menu "System setup"
 
index 21128505ddbe31e006718355d90e791a2f9c532e..9047c2fe8f23f4bf7378e04cf8dc2ef6fb79524d 100644 (file)
@@ -19,4 +19,9 @@
 
 #define force_successful_syscall_return() (current_pt_regs()->r0 = 0)
 
+static inline unsigned long regs_return_value(struct pt_regs *regs)
+{
+       return regs->r0;
+}
+
 #endif
index 453597b91f3a6560320524e4ef7a4338a5ae8e10..3d6ce6d56fc9ee9ad6fc4276f97f3d5633df6886 100644 (file)
@@ -70,6 +70,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
 #define TIF_NOTIFY_RESUME      1       /* callback before returning to user */
 #define TIF_SIGPENDING         2       /* signal pending */
 #define TIF_NEED_RESCHED       3       /* rescheduling necessary */
+#define TIF_SYSCALL_AUDIT      4       /* syscall audit active */
 #define TIF_DIE_IF_KERNEL      9       /* dik recursion lock */
 #define TIF_MEMDIE             13      /* is terminating due to OOM killer */
 
@@ -77,6 +78,7 @@ register struct thread_info *__current_thread_info __asm__("$8");
 #define _TIF_SIGPENDING                (1<<TIF_SIGPENDING)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_NOTIFY_RESUME     (1<<TIF_NOTIFY_RESUME)
+#define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 
 /* Work to do on interrupt/exception return.  */
 #define _TIF_WORK_MASK         (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
index 0d54650e78fc6b622272d88ac6406273f8e9a282..3ecac0106c8a1aa1e2fb85b5b868cf9e73eb1091 100644 (file)
@@ -17,6 +17,7 @@ obj-$(CONFIG_SRM_ENV) += srm_env.o
 obj-$(CONFIG_MODULES)  += module.o
 obj-$(CONFIG_PERF_EVENTS) += perf_event.o
 obj-$(CONFIG_RTC_DRV_ALPHA) += rtc.o
+obj-$(CONFIG_AUDIT)    += audit.o
 
 ifdef CONFIG_ALPHA_GENERIC
 
diff --git a/arch/alpha/kernel/audit.c b/arch/alpha/kernel/audit.c
new file mode 100644 (file)
index 0000000..96a9d18
--- /dev/null
@@ -0,0 +1,60 @@
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/audit.h>
+#include <asm/unistd.h>
+
+static unsigned dir_class[] = {
+#include <asm-generic/audit_dir_write.h>
+~0U
+};
+
+static unsigned read_class[] = {
+#include <asm-generic/audit_read.h>
+~0U
+};
+
+static unsigned write_class[] = {
+#include <asm-generic/audit_write.h>
+~0U
+};
+
+static unsigned chattr_class[] = {
+#include <asm-generic/audit_change_attr.h>
+~0U
+};
+
+static unsigned signal_class[] = {
+#include <asm-generic/audit_signal.h>
+~0U
+};
+
+int audit_classify_arch(int arch)
+{
+       return 0;
+}
+
+int audit_classify_syscall(int abi, unsigned syscall)
+{
+       switch(syscall) {
+       case __NR_open:
+               return 2;
+       case __NR_openat:
+               return 3;
+       case __NR_execve:
+               return 5;
+       default:
+               return 0;
+       }
+}
+
+static int __init audit_classes_init(void)
+{
+       audit_register_class(AUDIT_CLASS_WRITE, write_class);
+       audit_register_class(AUDIT_CLASS_READ, read_class);
+       audit_register_class(AUDIT_CLASS_DIR_WRITE, dir_class);
+       audit_register_class(AUDIT_CLASS_CHATTR, chattr_class);
+       audit_register_class(AUDIT_CLASS_SIGNAL, signal_class);
+       return 0;
+}
+
+__initcall(audit_classes_init);
index a969b95ee5ac78a64d79dd4ffa815b4b4a0f5e98..98703d99b565af7a10cc44322d3ae1ec1230cf64 100644 (file)
@@ -465,7 +465,11 @@ entSys:
        .cfi_rel_offset $16, SP_OFF+24
        .cfi_rel_offset $17, SP_OFF+32
        .cfi_rel_offset $18, SP_OFF+40
-       blbs    $3, strace
+#ifdef CONFIG_AUDITSYSCALL
+       lda     $6, _TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT
+       and     $3, $6, $3
+#endif
+       bne     $3, strace
        beq     $4, 1f
        ldq     $27, 0($5)
 1:     jsr     $26, ($27), alpha_ni_syscall
index 2a4a80ff4a2064262ea04298dee0a3d6e12f66be..86d835157b546f08f7eff0cc58a5f3dccbc5b359 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/security.h>
 #include <linux/signal.h>
 #include <linux/tracehook.h>
+#include <linux/audit.h>
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
@@ -316,15 +317,18 @@ long arch_ptrace(struct task_struct *child, long request,
 asmlinkage unsigned long syscall_trace_enter(void)
 {
        unsigned long ret = 0;
+       struct pt_regs *regs = current_pt_regs();
        if (test_thread_flag(TIF_SYSCALL_TRACE) &&
            tracehook_report_syscall_entry(current_pt_regs()))
                ret = -1UL;
+       audit_syscall_entry(AUDIT_ARCH_ALPHA, regs->r0, regs->r16, regs->r17, regs->r18, regs->r19);
        return ret ?: current_pt_regs()->r0;
 }
 
 asmlinkage void
 syscall_trace_leave(void)
 {
+       audit_syscall_exit(current_pt_regs());
        if (test_thread_flag(TIF_SYSCALL_TRACE))
                tracehook_report_syscall_exit(current_pt_regs(), 0);
 }
index ff3c10721caf67be1873f5c5b88623fc65fd89ea..5675dca8dbb1412e0b2fcea1c748ec9d757a3e8c 100644 (file)
@@ -378,6 +378,11 @@ csum_partial_copy_from_user(const void __user *src, void *dst, int len,
 __wsum
 csum_partial_copy_nocheck(const void *src, void *dst, int len, __wsum sum)
 {
-       return csum_partial_copy_from_user((__force const void __user *)src,
-                       dst, len, sum, NULL);
+       __wsum checksum;
+       mm_segment_t oldfs = get_fs();
+       set_fs(KERNEL_DS);
+       checksum = csum_partial_copy_from_user((__force const void __user *)src,
+                                               dst, len, sum, NULL);
+       set_fs(oldfs);
+       return checksum;
 }
index 0283e9e44e0d8cf368066484a4e502d5f1b399ef..66ee5527aefc08d7e5e3af13dbf553ce67d7c6c7 100644 (file)
@@ -11,6 +11,8 @@
 
 #ifdef __ASSEMBLY__
 
+#define ASM_NL          `      /* use '`' to mark new line in macro */
+
 /* Can't use the ENTRY macro in linux/linkage.h
  * gas considers ';' as comment vs. newline
  */
index dc6ef9a2c649df04d0d8de515b5565978164dde5..e254198177914ca13050f37519a6ca43e0da596d 100644 (file)
@@ -1905,6 +1905,7 @@ config XEN
        depends on !GENERIC_ATOMIC64
        select ARM_PSCI
        select SWIOTLB_XEN
+       select ARCH_DMA_ADDR_T_64BIT
        help
          Say Y if you want to run Linux in a Virtual Machine on Xen on ARM.
 
index 23d5e3946589a6c5e240b7d0060d84efee71d5d5..08a9ef58d9c3567f1b78862ed136546416ad241d 100644 (file)
@@ -96,7 +96,7 @@ tune-$(CONFIG_CPU_V6K)                =$(call cc-option,-mtune=arm1136j-s,-mtune=strongarm)
 tune-y := $(tune-y)
 
 ifeq ($(CONFIG_AEABI),y)
-CFLAGS_ABI     :=-mabi=aapcs-linux -mno-thumb-interwork
+CFLAGS_ABI     :=-mabi=aapcs-linux -mno-thumb-interwork -mfpu=vfp
 else
 CFLAGS_ABI     :=$(call cc-option,-mapcs-32,-mabi=apcs-gnu) $(call cc-option,-mno-thumb-interwork,)
 endif
index ede21c16fdc03f38d585de84d1f13b83192f5bf9..b9d6a8b485e0bdeba13c1848391fca3ca263341b 100644 (file)
@@ -152,10 +152,13 @@ dtb-$(CONFIG_ARCH_MXC) += \
        imx53-mba53.dtb \
        imx53-qsb.dtb \
        imx53-smd.dtb \
+       imx6dl-cubox-i.dtb \
+       imx6dl-hummingboard.dtb \
        imx6dl-sabreauto.dtb \
        imx6dl-sabresd.dtb \
        imx6dl-wandboard.dtb \
        imx6q-arm2.dtb \
+       imx6q-cubox-i.dtb \
        imx6q-phytec-pbab01.dtb \
        imx6q-sabreauto.dtb \
        imx6q-sabrelite.dtb \
diff --git a/arch/arm/boot/dts/am33xx-clocks.dtsi b/arch/arm/boot/dts/am33xx-clocks.dtsi
new file mode 100644 (file)
index 0000000..9ccfe50
--- /dev/null
@@ -0,0 +1,664 @@
+/*
+ * Device Tree Source for AM33xx clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&scrm_clocks {
+       sys_clkin_ck: sys_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&virt_19200000_ck>, <&virt_24000000_ck>, <&virt_25000000_ck>, <&virt_26000000_ck>;
+               ti,bit-shift = <22>;
+               reg = <0x0040>;
+       };
+
+       adc_tsc_fck: adc_tsc_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dcan0_fck: dcan0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dcan1_fck: dcan1_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       mcasp0_fck: mcasp0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       mcasp1_fck: mcasp1_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       smartreflex0_fck: smartreflex0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       smartreflex1_fck: smartreflex1_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       sha0_fck: sha0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       aes0_fck: aes0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       rng_fck: rng_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       ehrpwm0_gate_tbclk: ehrpwm0_gate_tbclk {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_per_m2_ck>;
+               ti,bit-shift = <0>;
+               reg = <0x0664>;
+       };
+
+       ehrpwm0_tbclk: ehrpwm0_tbclk {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&ehrpwm0_gate_tbclk>;
+       };
+
+       ehrpwm1_gate_tbclk: ehrpwm1_gate_tbclk {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_per_m2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0664>;
+       };
+
+       ehrpwm1_tbclk: ehrpwm1_tbclk {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&ehrpwm1_gate_tbclk>;
+       };
+
+       ehrpwm2_gate_tbclk: ehrpwm2_gate_tbclk {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_per_m2_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x0664>;
+       };
+
+       ehrpwm2_tbclk: ehrpwm2_tbclk {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&ehrpwm2_gate_tbclk>;
+       };
+};
+&prcm_clocks {
+       clk_32768_ck: clk_32768_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       clk_rc32k_ck: clk_rc32k_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32000>;
+       };
+
+       virt_19200000_ck: virt_19200000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <19200000>;
+       };
+
+       virt_24000000_ck: virt_24000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <24000000>;
+       };
+
+       virt_25000000_ck: virt_25000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <25000000>;
+       };
+
+       virt_26000000_ck: virt_26000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <26000000>;
+       };
+
+       tclkin_ck: tclkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       dpll_core_ck: dpll_core_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-core-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x0490>, <0x045c>, <0x0468>;
+       };
+
+       dpll_core_x2_ck: dpll_core_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-x2-clock";
+               clocks = <&dpll_core_ck>;
+       };
+
+       dpll_core_m4_ck: dpll_core_m4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               reg = <0x0480>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_core_m5_ck: dpll_core_m5_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               reg = <0x0484>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_core_m6_ck: dpll_core_m6_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               reg = <0x04d8>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_mpu_ck: dpll_mpu_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x0488>, <0x0420>, <0x042c>;
+       };
+
+       dpll_mpu_m2_ck: dpll_mpu_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_mpu_ck>;
+               ti,max-div = <31>;
+               reg = <0x04a8>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_ddr_ck: dpll_ddr_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-no-gate-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x0494>, <0x0434>, <0x0440>;
+       };
+
+       dpll_ddr_m2_ck: dpll_ddr_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_ddr_ck>;
+               ti,max-div = <31>;
+               reg = <0x04a0>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_ddr_m2_div2_ck: dpll_ddr_m2_div2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_ddr_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       dpll_disp_ck: dpll_disp_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-no-gate-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x0498>, <0x0448>, <0x0454>;
+       };
+
+       dpll_disp_m2_ck: dpll_disp_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_disp_ck>;
+               ti,max-div = <31>;
+               reg = <0x04a4>;
+               ti,index-starts-at-one;
+               ti,set-rate-parent;
+       };
+
+       dpll_per_ck: dpll_per_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-no-gate-j-type-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x048c>, <0x0470>, <0x049c>;
+       };
+
+       dpll_per_m2_ck: dpll_per_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_ck>;
+               ti,max-div = <31>;
+               reg = <0x04ac>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_per_m2_div4_wkupdm_ck: dpll_per_m2_div4_wkupdm_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       dpll_per_m2_div4_ck: dpll_per_m2_div4_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       cefuse_fck: cefuse_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_clkin_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0a20>;
+       };
+
+       clk_24mhz: clk_24mhz {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <8>;
+       };
+
+       clkdiv32k_ck: clkdiv32k_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&clk_24mhz>;
+               clock-mult = <1>;
+               clock-div = <732>;
+       };
+
+       clkdiv32k_ick: clkdiv32k_ick {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x014c>;
+       };
+
+       l3_gclk: l3_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       pruss_ocp_gclk: pruss_ocp_gclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&l3_gclk>, <&dpll_disp_m2_ck>;
+               reg = <0x0530>;
+       };
+
+       mmu_fck: mmu_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_core_m4_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0914>;
+       };
+
+       timer1_fck: timer1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&clkdiv32k_ick>, <&tclkin_ck>, <&clk_rc32k_ck>, <&clk_32768_ck>;
+               reg = <0x0528>;
+       };
+
+       timer2_fck: timer2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x0508>;
+       };
+
+       timer3_fck: timer3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x050c>;
+       };
+
+       timer4_fck: timer4_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x0510>;
+       };
+
+       timer5_fck: timer5_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x0518>;
+       };
+
+       timer6_fck: timer6_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x051c>;
+       };
+
+       timer7_fck: timer7_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x0504>;
+       };
+
+       usbotg_fck: usbotg_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_per_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x047c>;
+       };
+
+       dpll_core_m4_div2_ck: dpll_core_m4_div2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       ieee5000_fck: ieee5000_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_core_m4_div2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x00e4>;
+       };
+
+       wdt1_fck: wdt1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&clk_rc32k_ck>, <&clkdiv32k_ick>;
+               reg = <0x0538>;
+       };
+
+       l4_rtc_gclk: l4_rtc_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       l4hs_gclk: l4hs_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l3s_gclk: l3s_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_div2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l4fw_gclk: l4fw_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_div2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l4ls_gclk: l4ls_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_div2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       sysclk_div_ck: sysclk_div_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       cpsw_125mhz_gclk: cpsw_125mhz_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m5_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       cpsw_cpts_rft_clk: cpsw_cpts_rft_clk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_core_m5_ck>, <&dpll_core_m4_ck>;
+               reg = <0x0520>;
+       };
+
+       gpio0_dbclk_mux_ck: gpio0_dbclk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&clk_rc32k_ck>, <&clk_32768_ck>, <&clkdiv32k_ick>;
+               reg = <0x053c>;
+       };
+
+       gpio0_dbclk: gpio0_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&gpio0_dbclk_mux_ck>;
+               ti,bit-shift = <18>;
+               reg = <0x0408>;
+       };
+
+       gpio1_dbclk: gpio1_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ick>;
+               ti,bit-shift = <18>;
+               reg = <0x00ac>;
+       };
+
+       gpio2_dbclk: gpio2_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ick>;
+               ti,bit-shift = <18>;
+               reg = <0x00b0>;
+       };
+
+       gpio3_dbclk: gpio3_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ick>;
+               ti,bit-shift = <18>;
+               reg = <0x00b4>;
+       };
+
+       lcd_gclk: lcd_gclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_disp_m2_ck>, <&dpll_core_m5_ck>, <&dpll_per_m2_ck>;
+               reg = <0x0534>;
+               ti,set-rate-parent;
+       };
+
+       mmc_clk: mmc_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       gfx_fclk_clksel_ck: gfx_fclk_clksel_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_core_m4_ck>, <&dpll_per_m2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x052c>;
+       };
+
+       gfx_fck_div_ck: gfx_fck_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&gfx_fclk_clksel_ck>;
+               reg = <0x052c>;
+               ti,max-div = <2>;
+       };
+
+       sysclkout_pre_ck: sysclkout_pre_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&clk_32768_ck>, <&l3_gclk>, <&dpll_ddr_m2_ck>, <&dpll_per_m2_ck>, <&lcd_gclk>;
+               reg = <0x0700>;
+       };
+
+       clkout2_div_ck: clkout2_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&sysclkout_pre_ck>;
+               ti,bit-shift = <3>;
+               ti,max-div = <8>;
+               reg = <0x0700>;
+       };
+
+       dbg_sysclk_ck: dbg_sysclk_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_clkin_ck>;
+               ti,bit-shift = <19>;
+               reg = <0x0414>;
+       };
+
+       dbg_clka_ck: dbg_clka_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_core_m4_ck>;
+               ti,bit-shift = <30>;
+               reg = <0x0414>;
+       };
+
+       stm_pmd_clock_mux_ck: stm_pmd_clock_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dbg_sysclk_ck>, <&dbg_clka_ck>;
+               ti,bit-shift = <22>;
+               reg = <0x0414>;
+       };
+
+       trace_pmd_clk_mux_ck: trace_pmd_clk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dbg_sysclk_ck>, <&dbg_clka_ck>;
+               ti,bit-shift = <20>;
+               reg = <0x0414>;
+       };
+
+       stm_clk_div_ck: stm_clk_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&stm_pmd_clock_mux_ck>;
+               ti,bit-shift = <27>;
+               ti,max-div = <64>;
+               reg = <0x0414>;
+               ti,index-power-of-two;
+       };
+
+       trace_clk_div_ck: trace_clk_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&trace_pmd_clk_mux_ck>;
+               ti,bit-shift = <24>;
+               ti,max-div = <64>;
+               reg = <0x0414>;
+               ti,index-power-of-two;
+       };
+
+       clkout2_ck: clkout2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkout2_div_ck>;
+               ti,bit-shift = <7>;
+               reg = <0x0700>;
+       };
+};
+
+&prcm_clockdomains {
+       clk_24mhz_clkdm: clk_24mhz_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&clkdiv32k_ick>;
+       };
+};
index f6d8ffe98d0bfa15bc516b8fde2847f3568fcdd2..6d95d3df33c7913dc0feb76598f6e94ea15cf0fa 100644 (file)
                ranges;
                ti,hwmods = "l3_main";
 
+               prcm: prcm@44e00000 {
+                       compatible = "ti,am3-prcm";
+                       reg = <0x44e00000 0x4000>;
+
+                       prcm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       prcm_clockdomains: clockdomains {
+                       };
+               };
+
+               scrm: scrm@44e10000 {
+                       compatible = "ti,am3-scrm";
+                       reg = <0x44e10000 0x2000>;
+
+                       scrm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       scrm_clockdomains: clockdomains {
+                       };
+               };
+
                intc: interrupt-controller@48200000 {
                        compatible = "ti,omap2-intc";
                        interrupt-controller;
                };
        };
 };
+
+/include/ "am33xx-clocks.dtsi"
index 2fbe02faa8b18f2b18dd0e8bedff0256db4ff501..788391f916844130d8d6cdb2722479163863a707 100644 (file)
@@ -61,3 +61,6 @@
                };
        };
 };
+
+/include/ "am35xx-clocks.dtsi"
+/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi"
diff --git a/arch/arm/boot/dts/am35xx-clocks.dtsi b/arch/arm/boot/dts/am35xx-clocks.dtsi
new file mode 100644 (file)
index 0000000..df489d3
--- /dev/null
@@ -0,0 +1,128 @@
+/*
+ * Device Tree Source for OMAP3 clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&scrm_clocks {
+       emac_ick: emac_ick {
+               #clock-cells = <0>;
+               compatible = "ti,am35xx-gate-clock";
+               clocks = <&ipss_ick>;
+               reg = <0x059c>;
+               ti,bit-shift = <1>;
+       };
+
+       emac_fck: emac_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&rmii_ck>;
+               reg = <0x059c>;
+               ti,bit-shift = <9>;
+       };
+
+       vpfe_ick: vpfe_ick {
+               #clock-cells = <0>;
+               compatible = "ti,am35xx-gate-clock";
+               clocks = <&ipss_ick>;
+               reg = <0x059c>;
+               ti,bit-shift = <2>;
+       };
+
+       vpfe_fck: vpfe_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&pclk_ck>;
+               reg = <0x059c>;
+               ti,bit-shift = <10>;
+       };
+
+       hsotgusb_ick_am35xx: hsotgusb_ick_am35xx {
+               #clock-cells = <0>;
+               compatible = "ti,am35xx-gate-clock";
+               clocks = <&ipss_ick>;
+               reg = <0x059c>;
+               ti,bit-shift = <0>;
+       };
+
+       hsotgusb_fck_am35xx: hsotgusb_fck_am35xx {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_ck>;
+               reg = <0x059c>;
+               ti,bit-shift = <8>;
+       };
+
+       hecc_ck: hecc_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am35xx-gate-clock";
+               clocks = <&sys_ck>;
+               reg = <0x059c>;
+               ti,bit-shift = <3>;
+       };
+};
+&cm_clocks {
+       ipss_ick: ipss_ick {
+               #clock-cells = <0>;
+               compatible = "ti,am35xx-interface-clock";
+               clocks = <&core_l3_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <4>;
+       };
+
+       rmii_ck: rmii_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <50000000>;
+       };
+
+       pclk_ck: pclk_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <27000000>;
+       };
+
+       uart4_ick_am35xx: uart4_ick_am35xx {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <23>;
+       };
+
+       uart4_fck_am35xx: uart4_fck_am35xx {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_48m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <23>;
+       };
+};
+
+&cm_clockdomains {
+       core_l3_clkdm: core_l3_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&sdrc_ick>, <&ipss_ick>, <&emac_ick>, <&vpfe_ick>,
+                        <&hsotgusb_ick_am35xx>, <&hsotgusb_fck_am35xx>,
+                        <&hecc_ck>;
+       };
+
+       core_l4_clkdm: core_l4_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&cpefuse_fck>, <&ts_fck>, <&usbtll_fck>,
+                        <&usbtll_ick>, <&mmchs3_ick>, <&mmchs3_fck>,
+                        <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>,
+                        <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>,
+                        <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>,
+                        <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>,
+                        <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>,
+                        <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>,
+                        <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>,
+                        <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>,
+                        <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>,
+                        <&uart4_ick_am35xx>, <&uart4_fck_am35xx>;
+       };
+};
index 974d103ab3b1e673fe255e28e5c13d8544ad2565..c6bd4d986c290aaeb7bd4e0f78e2d48489c2bee4 100644 (file)
                ranges;
                ti,hwmods = "l3_main";
 
+               prcm: prcm@44df0000 {
+                       compatible = "ti,am4-prcm";
+                       reg = <0x44df0000 0x11000>;
+
+                       prcm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       prcm_clockdomains: clockdomains {
+                       };
+               };
+
+               scrm: scrm@44e10000 {
+                       compatible = "ti,am4-scrm";
+                       reg = <0x44e10000 0x2000>;
+
+                       scrm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       scrm_clockdomains: clockdomains {
+                       };
+               };
+
                edma: edma@49000000 {
                        compatible = "ti,edma3";
                        ti,hwmods = "tpcc", "tptc0", "tptc1", "tptc2";
                };
        };
 };
+
+/include/ "am43xx-clocks.dtsi"
diff --git a/arch/arm/boot/dts/am43xx-clocks.dtsi b/arch/arm/boot/dts/am43xx-clocks.dtsi
new file mode 100644 (file)
index 0000000..142009c
--- /dev/null
@@ -0,0 +1,656 @@
+/*
+ * Device Tree Source for AM43xx clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&scrm_clocks {
+       sys_clkin_ck: sys_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&virt_19200000_ck>, <&virt_24000000_ck>, <&virt_25000000_ck>, <&virt_26000000_ck>;
+               ti,bit-shift = <22>;
+               reg = <0x0040>;
+       };
+
+       adc_tsc_fck: adc_tsc_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dcan0_fck: dcan0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dcan1_fck: dcan1_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       mcasp0_fck: mcasp0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       mcasp1_fck: mcasp1_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       smartreflex0_fck: smartreflex0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       smartreflex1_fck: smartreflex1_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       sha0_fck: sha0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       aes0_fck: aes0_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+};
+&prcm_clocks {
+       clk_32768_ck: clk_32768_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       clk_rc32k_ck: clk_rc32k_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       virt_19200000_ck: virt_19200000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <19200000>;
+       };
+
+       virt_24000000_ck: virt_24000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <24000000>;
+       };
+
+       virt_25000000_ck: virt_25000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <25000000>;
+       };
+
+       virt_26000000_ck: virt_26000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <26000000>;
+       };
+
+       tclkin_ck: tclkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <26000000>;
+       };
+
+       dpll_core_ck: dpll_core_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-core-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x2d20>, <0x2d24>, <0x2d2c>;
+       };
+
+       dpll_core_x2_ck: dpll_core_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-x2-clock";
+               clocks = <&dpll_core_ck>;
+       };
+
+       dpll_core_m4_ck: dpll_core_m4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2d38>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_m5_ck: dpll_core_m5_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2d3c>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_m6_ck: dpll_core_m6_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2d40>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_mpu_ck: dpll_mpu_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x2d60>, <0x2d64>, <0x2d6c>;
+       };
+
+       dpll_mpu_m2_ck: dpll_mpu_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_mpu_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2d70>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_ddr_ck: dpll_ddr_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x2da0>, <0x2da4>, <0x2dac>;
+       };
+
+       dpll_ddr_m2_ck: dpll_ddr_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_ddr_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2db0>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_disp_ck: dpll_disp_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x2e20>, <0x2e24>, <0x2e2c>;
+       };
+
+       dpll_disp_m2_ck: dpll_disp_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_disp_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2e30>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_ck: dpll_per_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-j-type-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x2de0>, <0x2de4>, <0x2dec>;
+       };
+
+       dpll_per_m2_ck: dpll_per_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_ck>;
+               ti,max-div = <127>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2df0>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_m2_div4_wkupdm_ck: dpll_per_m2_div4_wkupdm_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       dpll_per_m2_div4_ck: dpll_per_m2_div4_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       clk_24mhz: clk_24mhz {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <8>;
+       };
+
+       clkdiv32k_ck: clkdiv32k_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&clk_24mhz>;
+               clock-mult = <1>;
+               clock-div = <732>;
+       };
+
+       clkdiv32k_ick: clkdiv32k_ick {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x2a38>;
+       };
+
+       sysclk_div: sysclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       pruss_ocp_gclk: pruss_ocp_gclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sysclk_div>, <&dpll_disp_m2_ck>;
+               reg = <0x4248>;
+       };
+
+       clk_32k_tpm_ck: clk_32k_tpm_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       timer1_fck: timer1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&clkdiv32k_ick>, <&tclkin_ck>, <&clk_rc32k_ck>, <&clk_32768_ck>, <&clk_32k_tpm_ck>;
+               reg = <0x4200>;
+       };
+
+       timer2_fck: timer2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x4204>;
+       };
+
+       timer3_fck: timer3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x4208>;
+       };
+
+       timer4_fck: timer4_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x420c>;
+       };
+
+       timer5_fck: timer5_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x4210>;
+       };
+
+       timer6_fck: timer6_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x4214>;
+       };
+
+       timer7_fck: timer7_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>;
+               reg = <0x4218>;
+       };
+
+       wdt1_fck: wdt1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&clk_rc32k_ck>, <&clkdiv32k_ick>;
+               reg = <0x422c>;
+       };
+
+       l3_gclk: l3_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_core_m4_div2_ck: dpll_core_m4_div2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sysclk_div>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       l4hs_gclk: l4hs_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l3s_gclk: l3s_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_div2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l4ls_gclk: l4ls_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4_div2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       cpsw_125mhz_gclk: cpsw_125mhz_gclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m5_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       cpsw_cpts_rft_clk: cpsw_cpts_rft_clk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sysclk_div>, <&dpll_core_m5_ck>, <&dpll_disp_m2_ck>;
+               reg = <0x4238>;
+       };
+
+       clk_32k_mosc_ck: clk_32k_mosc_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       gpio0_dbclk_mux_ck: gpio0_dbclk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&clk_rc32k_ck>, <&clk_32768_ck>, <&clkdiv32k_ick>, <&clk_32k_mosc_ck>, <&clk_32k_tpm_ck>;
+               reg = <0x4240>;
+       };
+
+       gpio0_dbclk: gpio0_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&gpio0_dbclk_mux_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x2b68>;
+       };
+
+       gpio1_dbclk: gpio1_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ick>;
+               ti,bit-shift = <8>;
+               reg = <0x8c78>;
+       };
+
+       gpio2_dbclk: gpio2_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ick>;
+               ti,bit-shift = <8>;
+               reg = <0x8c80>;
+       };
+
+       gpio3_dbclk: gpio3_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ick>;
+               ti,bit-shift = <8>;
+               reg = <0x8c88>;
+       };
+
+       gpio4_dbclk: gpio4_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ick>;
+               ti,bit-shift = <8>;
+               reg = <0x8c90>;
+       };
+
+       gpio5_dbclk: gpio5_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&clkdiv32k_ick>;
+               ti,bit-shift = <8>;
+               reg = <0x8c98>;
+       };
+
+       mmc_clk: mmc_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       gfx_fclk_clksel_ck: gfx_fclk_clksel_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sysclk_div>, <&dpll_per_m2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x423c>;
+       };
+
+       gfx_fck_div_ck: gfx_fck_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&gfx_fclk_clksel_ck>;
+               reg = <0x423c>;
+               ti,max-div = <2>;
+       };
+
+       disp_clk: disp_clk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_disp_m2_ck>, <&dpll_core_m5_ck>, <&dpll_per_m2_ck>;
+               reg = <0x4244>;
+       };
+
+       dpll_extdev_ck: dpll_extdev_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-clock";
+               clocks = <&sys_clkin_ck>, <&sys_clkin_ck>;
+               reg = <0x2e60>, <0x2e64>, <0x2e6c>;
+       };
+
+       dpll_extdev_m2_ck: dpll_extdev_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_extdev_ck>;
+               ti,max-div = <127>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2e70>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       mux_synctimer32k_ck: mux_synctimer32k_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&clk_32768_ck>, <&clk_32k_tpm_ck>, <&clkdiv32k_ick>;
+               reg = <0x4230>;
+       };
+
+       synctimer_32kclk: synctimer_32kclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&mux_synctimer32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x2a30>;
+       };
+
+       timer8_fck: timer8_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>;
+               reg = <0x421c>;
+       };
+
+       timer9_fck: timer9_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>;
+               reg = <0x4220>;
+       };
+
+       timer10_fck: timer10_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>;
+               reg = <0x4224>;
+       };
+
+       timer11_fck: timer11_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&tclkin_ck>, <&sys_clkin_ck>, <&clkdiv32k_ick>, <&clk_32k_tpm_ck>;
+               reg = <0x4228>;
+       };
+
+       cpsw_50m_clkdiv: cpsw_50m_clkdiv {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m5_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       cpsw_5m_clkdiv: cpsw_5m_clkdiv {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&cpsw_50m_clkdiv>;
+               clock-mult = <1>;
+               clock-div = <10>;
+       };
+
+       dpll_ddr_x2_ck: dpll_ddr_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,am3-dpll-x2-clock";
+               clocks = <&dpll_ddr_ck>;
+       };
+
+       dpll_ddr_m4_ck: dpll_ddr_m4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_ddr_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x2db8>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_clkdcoldo: dpll_per_clkdcoldo {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dll_aging_clk_div: dll_aging_clk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&sys_clkin_ck>;
+               reg = <0x4250>;
+               ti,dividers = <8>, <16>, <32>;
+       };
+
+       div_core_25m_ck: div_core_25m_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sysclk_div>;
+               clock-mult = <1>;
+               clock-div = <8>;
+       };
+
+       func_12m_clk: func_12m_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <16>;
+       };
+
+       vtp_clk_div: vtp_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       usbphy_32khz_clkmux: usbphy_32khz_clkmux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&clk_32768_ck>, <&clk_32k_tpm_ck>;
+               reg = <0x4260>;
+       };
+};
index 56ee8282a7a8ef201f1833135ddfb3b4d81e38a9..997901f7ed7381c77ff6c669f4f7571474ebd4b2 100644 (file)
                        watchdog@fffffd40 {
                                compatible = "atmel,at91sam9260-wdt";
                                reg = <0xfffffd40 0x10>;
+                               interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+                               atmel,watchdog-type = "hardware";
+                               atmel,reset-type = "all";
+                               atmel,dbg-halt;
+                               atmel,idle-halt;
                                status = "disabled";
                        };
                };
index c8fa9b9f07e34e0b38e089c5a5cbd9fab9c5507e..0042f73068b0c913f729cb6e0fd5b3b5b01609d5 100644 (file)
                        watchdog@fffffd40 {
                                compatible = "atmel,at91sam9260-wdt";
                                reg = <0xfffffd40 0x10>;
+                               interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+                               atmel,watchdog-type = "hardware";
+                               atmel,reset-type = "all";
+                               atmel,dbg-halt;
+                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index ef0857cb171c4aab25aac34b6bf9048e18f59d9b..cbcc058b26b4ebea4ba81ff24e4ff21c3edc95ee 100644 (file)
                        watchdog@fffffd40 {
                                compatible = "atmel,at91sam9260-wdt";
                                reg = <0xfffffd40 0x10>;
+                               interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+                               atmel,watchdog-type = "hardware";
+                               atmel,reset-type = "all";
+                               atmel,dbg-halt;
+                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index 7248270a3ea61525ac75f5f6a206ca6f3afd277f..394e6ce2afb75547f229c55348ff527376e98927 100644 (file)
                        watchdog@fffffe40 {
                                compatible = "atmel,at91sam9260-wdt";
                                reg = <0xfffffe40 0x10>;
+                               interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+                               atmel,watchdog-type = "hardware";
+                               atmel,reset-type = "all";
+                               atmel,dbg-halt;
+                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index 6e5e9cfc3c4997f98af3b5608b743ddd97cd0d8d..174219de92fa7380d4e6dc8a2a9916fa05e70a6e 100644 (file)
                        watchdog@fffffe40 {
                                compatible = "atmel,at91sam9260-wdt";
                                reg = <0xfffffe40 0x10>;
+                               interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
+                               atmel,watchdog-type = "hardware";
+                               atmel,reset-type = "all";
+                               atmel,dbg-halt;
+                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index 23cd16d736bf782f0be04f6e8413462ac8e60f86..396b70459cdc0b62eb68ae84fae87bdd6a77baa3 100644 (file)
                status = "okay";
        };
 
+       usbotg: usb@3f120000 {
+               status = "okay";
+       };
 
+       usbphy: usb-phy@3f130000 {
+               status = "okay";
+       };
 };
index dd8e878741c0984441967dc022171b9d045d297f..e491b82f8d67099ce25b4d1f08cdc6777bf55d7f 100644 (file)
@@ -43,7 +43,7 @@
                compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
                status = "disabled";
                reg = <0x3e000000 0x1000>;
-               clock-frequency = <13000000>;
+               clocks = <&uartb_clk>;
                interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
                reg-shift = <2>;
                reg-io-width = <4>;
@@ -53,7 +53,7 @@
                compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
                status = "disabled";
                reg = <0x3e001000 0x1000>;
-               clock-frequency = <13000000>;
+               clocks = <&uartb2_clk>;
                interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
                reg-shift = <2>;
                reg-io-width = <4>;
@@ -63,7 +63,7 @@
                compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
                status = "disabled";
                reg = <0x3e002000 0x1000>;
-               clock-frequency = <13000000>;
+               clocks = <&uartb3_clk>;
                interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
                reg-shift = <2>;
                reg-io-width = <4>;
@@ -73,7 +73,7 @@
                compatible = "brcm,bcm11351-dw-apb-uart", "snps,dw-apb-uart";
                status = "disabled";
                reg = <0x3e003000 0x1000>;
-               clock-frequency = <13000000>;
+               clocks = <&uartb4_clk>;
                interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
                reg-shift = <2>;
                reg-io-width = <4>;
@@ -95,7 +95,7 @@
                compatible = "brcm,kona-timer";
                reg = <0x35006000 0x1000>;
                interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
-               clock-frequency = <32768>;
+               clocks = <&hub_timer_clk>;
        };
 
        gpio: gpio@35003000 {
                compatible = "brcm,kona-sdhci";
                reg = <0x3f180000 0x10000>;
                interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&sdio1_clk>;
                status = "disabled";
        };
 
                compatible = "brcm,kona-sdhci";
                reg = <0x3f190000 0x10000>;
                interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&sdio2_clk>;
                status = "disabled";
        };
 
                compatible = "brcm,kona-sdhci";
                reg = <0x3f1a0000 0x10000>;
                interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&sdio3_clk>;
                status = "disabled";
        };
 
                compatible = "brcm,kona-sdhci";
                reg = <0x3f1b0000 0x10000>;
                interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&sdio4_clk>;
                status = "disabled";
        };
 
                compatible = "brcm,capri-pinctrl";
                reg = <0x35004800 0x430>;
        };
+
+       i2c@3e016000 {
+               compatible = "brcm,bcm11351-i2c", "brcm,kona-i2c";
+               reg = <0x3e016000 0x80>;
+               interrupts = <GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&bsc1_clk>;
+               status = "disabled";
+       };
+
+       i2c@3e017000 {
+               compatible = "brcm,bcm11351-i2c", "brcm,kona-i2c";
+               reg = <0x3e017000 0x80>;
+               interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&bsc2_clk>;
+               status = "disabled";
+       };
+
+       i2c@3e018000 {
+               compatible = "brcm,bcm11351-i2c", "brcm,kona-i2c";
+               reg = <0x3e018000 0x80>;
+               interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&bsc3_clk>;
+               status = "disabled";
+       };
+
+       i2c@3500d000 {
+               compatible = "brcm,bcm11351-i2c", "brcm,kona-i2c";
+               reg = <0x3500d000 0x80>;
+               interrupts = <GIC_SPI 14 IRQ_TYPE_LEVEL_HIGH>;
+               #address-cells = <1>;
+               #size-cells = <0>;
+               clocks = <&pmu_bsc_clk>;
+               status = "disabled";
+       };
+
+       clocks {
+               bsc1_clk: bsc1 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <13000000>;
+                       #clock-cells = <0>;
+               };
+
+               bsc2_clk: bsc2 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <13000000>;
+                       #clock-cells = <0>;
+               };
+
+               bsc3_clk: bsc3 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <13000000>;
+                       #clock-cells = <0>;
+               };
+
+               pmu_bsc_clk: pmu_bsc {
+                       compatible = "fixed-clock";
+                       clock-frequency = <13000000>;
+                       #clock-cells = <0>;
+               };
+
+               hub_timer_clk: hub_timer {
+                       compatible = "fixed-clock";
+                       clock-frequency = <32768>;
+                       #clock-cells = <0>;
+               };
+
+               pwm_clk: pwm {
+                       compatible = "fixed-clock";
+                       clock-frequency = <26000000>;
+                       #clock-cells = <0>;
+               };
+
+               sdio1_clk: sdio1 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <48000000>;
+                       #clock-cells = <0>;
+               };
+
+               sdio2_clk: sdio2 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <48000000>;
+                       #clock-cells = <0>;
+               };
+
+               sdio3_clk: sdio3 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <48000000>;
+                       #clock-cells = <0>;
+               };
+
+               sdio4_clk: sdio4 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <48000000>;
+                       #clock-cells = <0>;
+               };
+
+               tmon_1m_clk: tmon_1m {
+                       compatible = "fixed-clock";
+                       clock-frequency = <1000000>;
+                       #clock-cells = <0>;
+               };
+
+               uartb_clk: uartb {
+                       compatible = "fixed-clock";
+                       clock-frequency = <13000000>;
+                       #clock-cells = <0>;
+               };
+
+               uartb2_clk: uartb2 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <13000000>;
+                       #clock-cells = <0>;
+               };
+
+               uartb3_clk: uartb3 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <13000000>;
+                       #clock-cells = <0>;
+               };
+
+               uartb4_clk: uartb4 {
+                       compatible = "fixed-clock";
+                       clock-frequency = <13000000>;
+                       #clock-cells = <0>;
+               };
+
+               usb_otg_ahb_clk: usb_otg_ahb {
+                       compatible = "fixed-clock";
+                       clock-frequency = <52000000>;
+                       #clock-cells = <0>;
+               };
+       };
+
+       usbotg: usb@3f120000 {
+               compatible = "snps,dwc2";
+               reg = <0x3f120000 0x10000>;
+               interrupts = <GIC_SPI 47 IRQ_TYPE_LEVEL_HIGH>;
+               clocks = <&usb_otg_ahb_clk>;
+               clock-names = "otg";
+               phys = <&usbphy>;
+               phy-names = "usb2-phy";
+               status = "disabled";
+       };
+
+       usbphy: usb-phy@3f130000 {
+               compatible = "brcm,kona-usb2-phy";
+               reg = <0x3f130000 0x28>;
+               #phy-cells = <0>;
+               status = "disabled";
+       };
 };
index 08e47c285227a941d0bf7852c815054bd0d10a82..c7fa9fbb999cf6452e8d312396d9a10bcf0545ac 100644 (file)
                status = "okay";
        };
 
+       i2c@3e016000 {
+               status="okay";
+               clock-frequency = <400000>;
+       };
+
+       i2c@3e017000 {
+               status="okay";
+               clock-frequency = <400000>;
+       };
+
+       i2c@3e018000 {
+               status="okay";
+               clock-frequency = <400000>;
+       };
+
+       i2c@3500d000 {
+               status="okay";
+               clock-frequency = <400000>;
+       };
+
        sdio1: sdio@3f180000 {
                max-frequency = <48000000>;
                status = "okay";
                cd-gpios = <&gpio 14 0>;
                status = "okay";
        };
+
+       usbotg: usb@3f120000 {
+               status = "okay";
+       };
+
+       usbphy: usb-phy@3f130000 {
+               status = "okay";
+       };
 };
index d0df4c4e8b0a1bd422f33015a51656d8c063b5d9..1fd75aa4639da23c8e1b05bd1c5e28730f01c791 100644 (file)
                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
 
+               prm: prm@4ae06000 {
+                       compatible = "ti,dra7-prm";
+                       reg = <0x4ae06000 0x3000>;
+
+                       prm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       prm_clockdomains: clockdomains {
+                       };
+               };
+
+               cm_core_aon: cm_core_aon@4a005000 {
+                       compatible = "ti,dra7-cm-core-aon";
+                       reg = <0x4a005000 0x2000>;
+
+                       cm_core_aon_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       cm_core_aon_clockdomains: clockdomains {
+                       };
+               };
+
+               cm_core: cm_core@4a008000 {
+                       compatible = "ti,dra7-cm-core";
+                       reg = <0x4a008000 0x3000>;
+
+                       cm_core_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       cm_core_clockdomains: clockdomains {
+                       };
+               };
+
                counter32k: counter@4ae04000 {
                        compatible = "ti,omap-counter32k";
                        reg = <0x4ae04000 0x40>;
                };
        };
 };
+
+/include/ "dra7xx-clocks.dtsi"
diff --git a/arch/arm/boot/dts/dra7xx-clocks.dtsi b/arch/arm/boot/dts/dra7xx-clocks.dtsi
new file mode 100644 (file)
index 0000000..e96da9a
--- /dev/null
@@ -0,0 +1,2015 @@
+/*
+ * Device Tree Source for DRA7xx clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&cm_core_aon_clocks {
+       atl_clkin0_ck: atl_clkin0_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       atl_clkin1_ck: atl_clkin1_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       atl_clkin2_ck: atl_clkin2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       atlclkin3_ck: atlclkin3_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       hdmi_clkin_ck: hdmi_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       mlb_clkin_ck: mlb_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       mlbp_clkin_ck: mlbp_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       pciesref_acs_clk_ck: pciesref_acs_clk_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <100000000>;
+       };
+
+       ref_clkin0_ck: ref_clkin0_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       ref_clkin1_ck: ref_clkin1_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       ref_clkin2_ck: ref_clkin2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       ref_clkin3_ck: ref_clkin3_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       rmii_clk_ck: rmii_clk_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       sdvenc_clkin_ck: sdvenc_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       secure_32k_clk_src_ck: secure_32k_clk_src_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       sys_32k_ck: sys_32k_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       virt_12000000_ck: virt_12000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       virt_13000000_ck: virt_13000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <13000000>;
+       };
+
+       virt_16800000_ck: virt_16800000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <16800000>;
+       };
+
+       virt_19200000_ck: virt_19200000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <19200000>;
+       };
+
+       virt_20000000_ck: virt_20000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <20000000>;
+       };
+
+       virt_26000000_ck: virt_26000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <26000000>;
+       };
+
+       virt_27000000_ck: virt_27000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <27000000>;
+       };
+
+       virt_38400000_ck: virt_38400000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <38400000>;
+       };
+
+       sys_clkin2: sys_clkin2 {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <22579200>;
+       };
+
+       usb_otg_clkin_ck: usb_otg_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       video1_clkin_ck: video1_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       video1_m2_clkin_ck: video1_m2_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       video2_clkin_ck: video2_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       video2_m2_clkin_ck: video2_m2_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       dpll_abe_ck: dpll_abe_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-m4xen-clock";
+               clocks = <&abe_dpll_clk_mux>, <&abe_dpll_bypass_clk_mux>;
+               reg = <0x01e0>, <0x01e4>, <0x01ec>, <0x01e8>;
+       };
+
+       dpll_abe_x2_ck: dpll_abe_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_abe_ck>;
+       };
+
+       dpll_abe_m2x2_ck: dpll_abe_m2x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01f0>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       abe_clk: abe_clk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_m2x2_ck>;
+               ti,max-div = <4>;
+               reg = <0x0108>;
+               ti,index-power-of-two;
+       };
+
+       dpll_abe_m2_ck: dpll_abe_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01f0>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_abe_m3x2_ck: dpll_abe_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01f4>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_ck: dpll_core_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-core-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>;
+       };
+
+       dpll_core_x2_ck: dpll_core_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_core_ck>;
+       };
+
+       dpll_core_h12x2_ck: dpll_core_h12x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x013c>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       mpu_dpll_hs_clk_div: mpu_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_h12x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_mpu_ck: dpll_mpu_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin1>, <&mpu_dpll_hs_clk_div>;
+               reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>;
+       };
+
+       dpll_mpu_m2_ck: dpll_mpu_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_mpu_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0170>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       mpu_dclk_div: mpu_dclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_mpu_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dsp_dpll_hs_clk_div: dsp_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_h12x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_dsp_ck: dpll_dsp_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin1>, <&dsp_dpll_hs_clk_div>;
+               reg = <0x0234>, <0x0238>, <0x0240>, <0x023c>;
+       };
+
+       dpll_dsp_m2_ck: dpll_dsp_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_dsp_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0244>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       iva_dpll_hs_clk_div: iva_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_h12x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_iva_ck: dpll_iva_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin1>, <&iva_dpll_hs_clk_div>;
+               reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>;
+       };
+
+       dpll_iva_m2_ck: dpll_iva_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_iva_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01b0>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       iva_dclk: iva_dclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_iva_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_gpu_ck: dpll_gpu_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               reg = <0x02d8>, <0x02dc>, <0x02e4>, <0x02e0>;
+       };
+
+       dpll_gpu_m2_ck: dpll_gpu_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_gpu_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x02e8>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_m2_ck: dpll_core_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0130>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       core_dpll_out_dclk_div: core_dpll_out_dclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_ddr_ck: dpll_ddr_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               reg = <0x0210>, <0x0214>, <0x021c>, <0x0218>;
+       };
+
+       dpll_ddr_m2_ck: dpll_ddr_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_ddr_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0220>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_gmac_ck: dpll_gmac_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin1>, <&dpll_abe_m3x2_ck>;
+               reg = <0x02a8>, <0x02ac>, <0x02b4>, <0x02b0>;
+       };
+
+       dpll_gmac_m2_ck: dpll_gmac_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_gmac_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x02b8>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       video2_dclk_div: video2_dclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&video2_m2_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       video1_dclk_div: video1_dclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&video1_m2_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       hdmi_dclk_div: hdmi_dclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&hdmi_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       per_dpll_hs_clk_div: per_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m3x2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       usb_dpll_hs_clk_div: usb_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m3x2_ck>;
+               clock-mult = <1>;
+               clock-div = <3>;
+       };
+
+       eve_dpll_hs_clk_div: eve_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_h12x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_eve_ck: dpll_eve_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin1>, <&eve_dpll_hs_clk_div>;
+               reg = <0x0284>, <0x0288>, <0x0290>, <0x028c>;
+       };
+
+       dpll_eve_m2_ck: dpll_eve_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_eve_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0294>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       eve_dclk_div: eve_dclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_eve_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_core_h13x2_ck: dpll_core_h13x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0140>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h14x2_ck: dpll_core_h14x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0144>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h22x2_ck: dpll_core_h22x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0154>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h23x2_ck: dpll_core_h23x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0158>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h24x2_ck: dpll_core_h24x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x015c>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_ddr_x2_ck: dpll_ddr_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_ddr_ck>;
+       };
+
+       dpll_ddr_h11x2_ck: dpll_ddr_h11x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_ddr_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0228>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_dsp_x2_ck: dpll_dsp_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_dsp_ck>;
+       };
+
+       dpll_dsp_m3x2_ck: dpll_dsp_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_dsp_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0248>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_gmac_x2_ck: dpll_gmac_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_gmac_ck>;
+       };
+
+       dpll_gmac_h11x2_ck: dpll_gmac_h11x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_gmac_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x02c0>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_gmac_h12x2_ck: dpll_gmac_h12x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_gmac_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x02c4>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_gmac_h13x2_ck: dpll_gmac_h13x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_gmac_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x02c8>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_gmac_m3x2_ck: dpll_gmac_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_gmac_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x02bc>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       gmii_m_clk_div: gmii_m_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_gmac_h11x2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       hdmi_clk2_div: hdmi_clk2_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&hdmi_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       hdmi_div_clk: hdmi_div_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&hdmi_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l3_iclk_div: l3_iclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_h12x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l4_root_clk_div: l4_root_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l3_iclk_div>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       video1_clk2_div: video1_clk2_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&video1_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       video1_div_clk: video1_div_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&video1_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       video2_clk2_div: video2_clk2_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&video2_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       video2_div_clk: video2_div_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&video2_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       ipu1_gfclk_mux: ipu1_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_abe_m2x2_ck>, <&dpll_core_h22x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0520>;
+       };
+
+       mcasp1_ahclkr_mux: mcasp1_ahclkr_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <28>;
+               reg = <0x0550>;
+       };
+
+       mcasp1_ahclkx_mux: mcasp1_ahclkx_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0550>;
+       };
+
+       mcasp1_aux_gfclk_mux: mcasp1_aux_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>;
+               ti,bit-shift = <22>;
+               reg = <0x0550>;
+       };
+
+       timer5_gfclk_mux: timer5_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>;
+               ti,bit-shift = <24>;
+               reg = <0x0558>;
+       };
+
+       timer6_gfclk_mux: timer6_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>;
+               ti,bit-shift = <24>;
+               reg = <0x0560>;
+       };
+
+       timer7_gfclk_mux: timer7_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>;
+               ti,bit-shift = <24>;
+               reg = <0x0568>;
+       };
+
+       timer8_gfclk_mux: timer8_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>, <&clkoutmux0_clk_mux>;
+               ti,bit-shift = <24>;
+               reg = <0x0570>;
+       };
+
+       uart6_gfclk_mux: uart6_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0580>;
+       };
+
+       dummy_ck: dummy_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+};
+&prm_clocks {
+       sys_clkin1: sys_clkin1 {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&virt_12000000_ck>, <&virt_20000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>;
+               reg = <0x0110>;
+               ti,index-starts-at-one;
+       };
+
+       abe_dpll_sys_clk_mux: abe_dpll_sys_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&sys_clkin2>;
+               reg = <0x0118>;
+       };
+
+       abe_dpll_bypass_clk_mux: abe_dpll_bypass_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_dpll_sys_clk_mux>, <&sys_32k_ck>;
+               reg = <0x0114>;
+       };
+
+       abe_dpll_clk_mux: abe_dpll_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_dpll_sys_clk_mux>, <&sys_32k_ck>;
+               reg = <0x010c>;
+       };
+
+       abe_24m_fclk: abe_24m_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_m2x2_ck>;
+               reg = <0x011c>;
+               ti,dividers = <8>, <16>;
+       };
+
+       aess_fclk: aess_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&abe_clk>;
+               reg = <0x0178>;
+               ti,max-div = <2>;
+       };
+
+       abe_giclk_div: abe_giclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&aess_fclk>;
+               reg = <0x0174>;
+               ti,max-div = <2>;
+       };
+
+       abe_lp_clk_div: abe_lp_clk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_m2x2_ck>;
+               reg = <0x01d8>;
+               ti,dividers = <16>, <32>;
+       };
+
+       abe_sys_clk_div: abe_sys_clk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&sys_clkin1>;
+               reg = <0x0120>;
+               ti,max-div = <2>;
+       };
+
+       adc_gfclk_mux: adc_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&sys_clkin2>, <&sys_32k_ck>;
+               reg = <0x01dc>;
+       };
+
+       sys_clk1_dclk_div: sys_clk1_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&sys_clkin1>;
+               ti,max-div = <64>;
+               reg = <0x01c8>;
+               ti,index-power-of-two;
+       };
+
+       sys_clk2_dclk_div: sys_clk2_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&sys_clkin2>;
+               ti,max-div = <64>;
+               reg = <0x01cc>;
+               ti,index-power-of-two;
+       };
+
+       per_abe_x1_dclk_div: per_abe_x1_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_m2_ck>;
+               ti,max-div = <64>;
+               reg = <0x01bc>;
+               ti,index-power-of-two;
+       };
+
+       dsp_gclk_div: dsp_gclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_dsp_m2_ck>;
+               ti,max-div = <64>;
+               reg = <0x018c>;
+               ti,index-power-of-two;
+       };
+
+       gpu_dclk: gpu_dclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_gpu_m2_ck>;
+               ti,max-div = <64>;
+               reg = <0x01a0>;
+               ti,index-power-of-two;
+       };
+
+       emif_phy_dclk_div: emif_phy_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_ddr_m2_ck>;
+               ti,max-div = <64>;
+               reg = <0x0190>;
+               ti,index-power-of-two;
+       };
+
+       gmac_250m_dclk_div: gmac_250m_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_gmac_m2_ck>;
+               ti,max-div = <64>;
+               reg = <0x019c>;
+               ti,index-power-of-two;
+       };
+
+       l3init_480m_dclk_div: l3init_480m_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_usb_m2_ck>;
+               ti,max-div = <64>;
+               reg = <0x01ac>;
+               ti,index-power-of-two;
+       };
+
+       usb_otg_dclk_div: usb_otg_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&usb_otg_clkin_ck>;
+               ti,max-div = <64>;
+               reg = <0x0184>;
+               ti,index-power-of-two;
+       };
+
+       sata_dclk_div: sata_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&sys_clkin1>;
+               ti,max-div = <64>;
+               reg = <0x01c0>;
+               ti,index-power-of-two;
+       };
+
+       pcie2_dclk_div: pcie2_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_pcie_ref_m2_ck>;
+               ti,max-div = <64>;
+               reg = <0x01b8>;
+               ti,index-power-of-two;
+       };
+
+       pcie_dclk_div: pcie_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&apll_pcie_m2_ck>;
+               ti,max-div = <64>;
+               reg = <0x01b4>;
+               ti,index-power-of-two;
+       };
+
+       emu_dclk_div: emu_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&sys_clkin1>;
+               ti,max-div = <64>;
+               reg = <0x0194>;
+               ti,index-power-of-two;
+       };
+
+       secure_32k_dclk_div: secure_32k_dclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&secure_32k_clk_src_ck>;
+               ti,max-div = <64>;
+               reg = <0x01c4>;
+               ti,index-power-of-two;
+       };
+
+       clkoutmux0_clk_mux: clkoutmux0_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clk1_dclk_div>, <&sys_clk2_dclk_div>, <&per_abe_x1_dclk_div>, <&mpu_dclk_div>, <&dsp_gclk_div>, <&iva_dclk>, <&gpu_dclk>, <&core_dpll_out_dclk_div>, <&emif_phy_dclk_div>, <&gmac_250m_dclk_div>, <&video2_dclk_div>, <&video1_dclk_div>, <&hdmi_dclk_div>, <&func_96m_aon_dclk_div>, <&l3init_480m_dclk_div>, <&usb_otg_dclk_div>, <&sata_dclk_div>, <&pcie2_dclk_div>, <&pcie_dclk_div>, <&emu_dclk_div>, <&secure_32k_dclk_div>, <&eve_dclk_div>;
+               reg = <0x0158>;
+       };
+
+       clkoutmux1_clk_mux: clkoutmux1_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clk1_dclk_div>, <&sys_clk2_dclk_div>, <&per_abe_x1_dclk_div>, <&mpu_dclk_div>, <&dsp_gclk_div>, <&iva_dclk>, <&gpu_dclk>, <&core_dpll_out_dclk_div>, <&emif_phy_dclk_div>, <&gmac_250m_dclk_div>, <&video2_dclk_div>, <&video1_dclk_div>, <&hdmi_dclk_div>, <&func_96m_aon_dclk_div>, <&l3init_480m_dclk_div>, <&usb_otg_dclk_div>, <&sata_dclk_div>, <&pcie2_dclk_div>, <&pcie_dclk_div>, <&emu_dclk_div>, <&secure_32k_dclk_div>, <&eve_dclk_div>;
+               reg = <0x015c>;
+       };
+
+       clkoutmux2_clk_mux: clkoutmux2_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clk1_dclk_div>, <&sys_clk2_dclk_div>, <&per_abe_x1_dclk_div>, <&mpu_dclk_div>, <&dsp_gclk_div>, <&iva_dclk>, <&gpu_dclk>, <&core_dpll_out_dclk_div>, <&emif_phy_dclk_div>, <&gmac_250m_dclk_div>, <&video2_dclk_div>, <&video1_dclk_div>, <&hdmi_dclk_div>, <&func_96m_aon_dclk_div>, <&l3init_480m_dclk_div>, <&usb_otg_dclk_div>, <&sata_dclk_div>, <&pcie2_dclk_div>, <&pcie_dclk_div>, <&emu_dclk_div>, <&secure_32k_dclk_div>, <&eve_dclk_div>;
+               reg = <0x0160>;
+       };
+
+       custefuse_sys_gfclk_div: custefuse_sys_gfclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin1>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       eve_clk: eve_clk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_eve_m2_ck>, <&dpll_dsp_m3x2_ck>;
+               reg = <0x0180>;
+       };
+
+       hdmi_dpll_clk_mux: hdmi_dpll_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&sys_clkin2>;
+               reg = <0x01a4>;
+       };
+
+       mlb_clk: mlb_clk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&mlb_clkin_ck>;
+               ti,max-div = <64>;
+               reg = <0x0134>;
+               ti,index-power-of-two;
+       };
+
+       mlbp_clk: mlbp_clk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&mlbp_clkin_ck>;
+               ti,max-div = <64>;
+               reg = <0x0130>;
+               ti,index-power-of-two;
+       };
+
+       per_abe_x1_gfclk2_div: per_abe_x1_gfclk2_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_m2_ck>;
+               ti,max-div = <64>;
+               reg = <0x0138>;
+               ti,index-power-of-two;
+       };
+
+       timer_sys_clk_div: timer_sys_clk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&sys_clkin1>;
+               reg = <0x0144>;
+               ti,max-div = <2>;
+       };
+
+       video1_dpll_clk_mux: video1_dpll_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&sys_clkin2>;
+               reg = <0x01d0>;
+       };
+
+       video2_dpll_clk_mux: video2_dpll_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&sys_clkin2>;
+               reg = <0x01d4>;
+       };
+
+       wkupaon_iclk_mux: wkupaon_iclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&abe_lp_clk_div>;
+               reg = <0x0108>;
+       };
+
+       gpio1_dbclk: gpio1_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1838>;
+       };
+
+       dcan1_sys_clk_mux: dcan1_sys_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin1>, <&sys_clkin2>;
+               ti,bit-shift = <24>;
+               reg = <0x1888>;
+       };
+
+       timer1_gfclk_mux: timer1_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1840>;
+       };
+
+       uart10_gfclk_mux: uart10_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1880>;
+       };
+};
+&cm_core_clocks {
+       dpll_pcie_ref_ck: dpll_pcie_ref_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin1>, <&sys_clkin1>;
+               reg = <0x0200>, <0x0204>, <0x020c>, <0x0208>;
+       };
+
+       dpll_pcie_ref_m2ldo_ck: dpll_pcie_ref_m2ldo_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_pcie_ref_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0210>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       apll_pcie_in_clk_mux: apll_pcie_in_clk_mux@4ae06118 {
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_pcie_ref_ck>, <&pciesref_acs_clk_ck>;
+               #clock-cells = <0>;
+               reg = <0x021c 0x4>;
+               ti,bit-shift = <7>;
+       };
+
+       apll_pcie_ck: apll_pcie_ck {
+               #clock-cells = <0>;
+               compatible = "ti,dra7-apll-clock";
+               clocks = <&apll_pcie_in_clk_mux>, <&dpll_pcie_ref_ck>;
+               reg = <0x021c>, <0x0220>;
+       };
+
+       optfclk_pciephy_div: optfclk_pciephy_div@4a00821c {
+               compatible = "ti,divider-clock";
+               clocks = <&apll_pcie_ck>;
+               #clock-cells = <0>;
+               reg = <0x021c>;
+               ti,bit-shift = <8>;
+               ti,max-div = <2>;
+       };
+
+       optfclk_pciephy_clk: optfclk_pciephy_clk@4a0093b0 {
+               compatible = "ti,gate-clock";
+               clocks = <&apll_pcie_ck>;
+               #clock-cells = <0>;
+               reg = <0x13b0>;
+               ti,bit-shift = <9>;
+       };
+
+       optfclk_pciephy_div_clk: optfclk_pciephy_div_clk@4a0093b0 {
+               compatible = "ti,gate-clock";
+               clocks = <&optfclk_pciephy_div>;
+               #clock-cells = <0>;
+               reg = <0x13b0>;
+               ti,bit-shift = <10>;
+       };
+
+       apll_pcie_clkvcoldo: apll_pcie_clkvcoldo {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&apll_pcie_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       apll_pcie_clkvcoldo_div: apll_pcie_clkvcoldo_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&apll_pcie_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       apll_pcie_m2_ck: apll_pcie_m2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&apll_pcie_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_per_ck: dpll_per_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin1>, <&per_dpll_hs_clk_div>;
+               reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>;
+       };
+
+       dpll_per_m2_ck: dpll_per_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0150>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       func_96m_aon_dclk_div: func_96m_aon_dclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_usb_ck: dpll_usb_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-j-type-clock";
+               clocks = <&sys_clkin1>, <&usb_dpll_hs_clk_div>;
+               reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>;
+       };
+
+       dpll_usb_m2_ck: dpll_usb_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_usb_ck>;
+               ti,max-div = <127>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0190>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_pcie_ref_m2_ck: dpll_pcie_ref_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_pcie_ref_ck>;
+               ti,max-div = <127>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0210>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_x2_ck: dpll_per_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_per_ck>;
+       };
+
+       dpll_per_h11x2_ck: dpll_per_h11x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0158>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_h12x2_ck: dpll_per_h12x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x015c>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_h13x2_ck: dpll_per_h13x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0160>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_h14x2_ck: dpll_per_h14x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0164>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_m2x2_ck: dpll_per_m2x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0150>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_usb_clkdcoldo: dpll_usb_clkdcoldo {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_usb_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       func_128m_clk: func_128m_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_h11x2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       func_12m_fclk: func_12m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <16>;
+       };
+
+       func_24m_clk: func_24m_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       func_48m_fclk: func_48m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       func_96m_fclk: func_96m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       l3init_60m_fclk: l3init_60m_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_usb_m2_ck>;
+               reg = <0x0104>;
+               ti,dividers = <1>, <8>;
+       };
+
+       dss_32khz_clk: dss_32khz_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <11>;
+               reg = <0x1120>;
+       };
+
+       dss_48mhz_clk: dss_48mhz_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_48m_fclk>;
+               ti,bit-shift = <9>;
+               reg = <0x1120>;
+       };
+
+       dss_dss_clk: dss_dss_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_per_h12x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1120>;
+       };
+
+       dss_hdmi_clk: dss_hdmi_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&hdmi_dpll_clk_mux>;
+               ti,bit-shift = <10>;
+               reg = <0x1120>;
+       };
+
+       dss_video1_clk: dss_video1_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&video1_dpll_clk_mux>;
+               ti,bit-shift = <12>;
+               reg = <0x1120>;
+       };
+
+       dss_video2_clk: dss_video2_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&video2_dpll_clk_mux>;
+               ti,bit-shift = <13>;
+               reg = <0x1120>;
+       };
+
+       gpio2_dbclk: gpio2_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1760>;
+       };
+
+       gpio3_dbclk: gpio3_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1768>;
+       };
+
+       gpio4_dbclk: gpio4_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1770>;
+       };
+
+       gpio5_dbclk: gpio5_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1778>;
+       };
+
+       gpio6_dbclk: gpio6_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1780>;
+       };
+
+       gpio7_dbclk: gpio7_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1810>;
+       };
+
+       gpio8_dbclk: gpio8_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1818>;
+       };
+
+       mmc1_clk32k: mmc1_clk32k {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1328>;
+       };
+
+       mmc2_clk32k: mmc2_clk32k {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1330>;
+       };
+
+       mmc3_clk32k: mmc3_clk32k {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1820>;
+       };
+
+       mmc4_clk32k: mmc4_clk32k {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1828>;
+       };
+
+       sata_ref_clk: sata_ref_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_clkin1>;
+               ti,bit-shift = <8>;
+               reg = <0x1388>;
+       };
+
+       usb_otg_ss1_refclk960m: usb_otg_ss1_refclk960m {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_usb_clkdcoldo>;
+               ti,bit-shift = <8>;
+               reg = <0x13f0>;
+       };
+
+       usb_otg_ss2_refclk960m: usb_otg_ss2_refclk960m {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_usb_clkdcoldo>;
+               ti,bit-shift = <8>;
+               reg = <0x1340>;
+       };
+
+       usb_phy1_always_on_clk32k: usb_phy1_always_on_clk32k {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0640>;
+       };
+
+       usb_phy2_always_on_clk32k: usb_phy2_always_on_clk32k {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0688>;
+       };
+
+       usb_phy3_always_on_clk32k: usb_phy3_always_on_clk32k {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0698>;
+       };
+
+       atl_dpll_clk_mux: atl_dpll_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_32k_ck>, <&video1_clkin_ck>, <&video2_clkin_ck>, <&hdmi_clkin_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0c00>;
+       };
+
+       atl_gfclk_mux: atl_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&l3_iclk_div>, <&dpll_abe_m2_ck>, <&atl_dpll_clk_mux>;
+               ti,bit-shift = <26>;
+               reg = <0x0c00>;
+       };
+
+       gmac_gmii_ref_clk_div: gmac_gmii_ref_clk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_gmac_m2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x13d0>;
+               ti,dividers = <2>;
+       };
+
+       gmac_rft_clk_mux: gmac_rft_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&video1_clkin_ck>, <&video2_clkin_ck>, <&dpll_abe_m2_ck>, <&hdmi_clkin_ck>, <&l3_iclk_div>;
+               ti,bit-shift = <25>;
+               reg = <0x13d0>;
+       };
+
+       gpu_core_gclk_mux: gpu_core_gclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>, <&dpll_gpu_m2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1220>;
+       };
+
+       gpu_hyd_gclk_mux: gpu_hyd_gclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>, <&dpll_gpu_m2_ck>;
+               ti,bit-shift = <26>;
+               reg = <0x1220>;
+       };
+
+       l3instr_ts_gclk_div: l3instr_ts_gclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&wkupaon_iclk_mux>;
+               ti,bit-shift = <24>;
+               reg = <0x0e50>;
+               ti,dividers = <8>, <16>, <32>;
+       };
+
+       mcasp2_ahclkr_mux: mcasp2_ahclkr_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <28>;
+               reg = <0x1860>;
+       };
+
+       mcasp2_ahclkx_mux: mcasp2_ahclkx_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <28>;
+               reg = <0x1860>;
+       };
+
+       mcasp2_aux_gfclk_mux: mcasp2_aux_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>;
+               ti,bit-shift = <22>;
+               reg = <0x1860>;
+       };
+
+       mcasp3_ahclkx_mux: mcasp3_ahclkx_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1868>;
+       };
+
+       mcasp3_aux_gfclk_mux: mcasp3_aux_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>;
+               ti,bit-shift = <22>;
+               reg = <0x1868>;
+       };
+
+       mcasp4_ahclkx_mux: mcasp4_ahclkx_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1898>;
+       };
+
+       mcasp4_aux_gfclk_mux: mcasp4_aux_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>;
+               ti,bit-shift = <22>;
+               reg = <0x1898>;
+       };
+
+       mcasp5_ahclkx_mux: mcasp5_ahclkx_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1878>;
+       };
+
+       mcasp5_aux_gfclk_mux: mcasp5_aux_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>;
+               ti,bit-shift = <22>;
+               reg = <0x1878>;
+       };
+
+       mcasp6_ahclkx_mux: mcasp6_ahclkx_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1904>;
+       };
+
+       mcasp6_aux_gfclk_mux: mcasp6_aux_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>;
+               ti,bit-shift = <22>;
+               reg = <0x1904>;
+       };
+
+       mcasp7_ahclkx_mux: mcasp7_ahclkx_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1908>;
+       };
+
+       mcasp7_aux_gfclk_mux: mcasp7_aux_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>;
+               ti,bit-shift = <22>;
+               reg = <0x1908>;
+       };
+
+       mcasp8_ahclk_mux: mcasp8_ahclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&abe_sys_clk_div>, <&func_24m_clk>, <&atlclkin3_ck>, <&atl_clkin2_ck>, <&atl_clkin1_ck>, <&atl_clkin0_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&mlb_clk>, <&mlbp_clk>;
+               ti,bit-shift = <22>;
+               reg = <0x1890>;
+       };
+
+       mcasp8_aux_gfclk_mux: mcasp8_aux_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&per_abe_x1_gfclk2_div>, <&video1_clk2_div>, <&video2_clk2_div>, <&hdmi_clk2_div>;
+               ti,bit-shift = <24>;
+               reg = <0x1890>;
+       };
+
+       mmc1_fclk_mux: mmc1_fclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1328>;
+       };
+
+       mmc1_fclk_div: mmc1_fclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&mmc1_fclk_mux>;
+               ti,bit-shift = <25>;
+               ti,max-div = <4>;
+               reg = <0x1328>;
+               ti,index-power-of-two;
+       };
+
+       mmc2_fclk_mux: mmc2_fclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1330>;
+       };
+
+       mmc2_fclk_div: mmc2_fclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&mmc2_fclk_mux>;
+               ti,bit-shift = <25>;
+               ti,max-div = <4>;
+               reg = <0x1330>;
+               ti,index-power-of-two;
+       };
+
+       mmc3_gfclk_mux: mmc3_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1820>;
+       };
+
+       mmc3_gfclk_div: mmc3_gfclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&mmc3_gfclk_mux>;
+               ti,bit-shift = <25>;
+               ti,max-div = <4>;
+               reg = <0x1820>;
+               ti,index-power-of-two;
+       };
+
+       mmc4_gfclk_mux: mmc4_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1828>;
+       };
+
+       mmc4_gfclk_div: mmc4_gfclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&mmc4_gfclk_mux>;
+               ti,bit-shift = <25>;
+               ti,max-div = <4>;
+               reg = <0x1828>;
+               ti,index-power-of-two;
+       };
+
+       qspi_gfclk_mux: qspi_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_128m_clk>, <&dpll_per_h13x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1838>;
+       };
+
+       qspi_gfclk_div: qspi_gfclk_div {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&qspi_gfclk_mux>;
+               ti,bit-shift = <25>;
+               ti,max-div = <4>;
+               reg = <0x1838>;
+               ti,index-power-of-two;
+       };
+
+       timer10_gfclk_mux: timer10_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1728>;
+       };
+
+       timer11_gfclk_mux: timer11_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1730>;
+       };
+
+       timer13_gfclk_mux: timer13_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x17c8>;
+       };
+
+       timer14_gfclk_mux: timer14_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x17d0>;
+       };
+
+       timer15_gfclk_mux: timer15_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x17d8>;
+       };
+
+       timer16_gfclk_mux: timer16_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1830>;
+       };
+
+       timer2_gfclk_mux: timer2_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1738>;
+       };
+
+       timer3_gfclk_mux: timer3_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1740>;
+       };
+
+       timer4_gfclk_mux: timer4_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1748>;
+       };
+
+       timer9_gfclk_mux: timer9_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&timer_sys_clk_div>, <&sys_32k_ck>, <&sys_clkin2>, <&ref_clkin0_ck>, <&ref_clkin1_ck>, <&ref_clkin2_ck>, <&ref_clkin3_ck>, <&abe_giclk_div>, <&video1_div_clk>, <&video2_div_clk>, <&hdmi_div_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x1750>;
+       };
+
+       uart1_gfclk_mux: uart1_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1840>;
+       };
+
+       uart2_gfclk_mux: uart2_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1848>;
+       };
+
+       uart3_gfclk_mux: uart3_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1850>;
+       };
+
+       uart4_gfclk_mux: uart4_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1858>;
+       };
+
+       uart5_gfclk_mux: uart5_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1870>;
+       };
+
+       uart7_gfclk_mux: uart7_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x18d0>;
+       };
+
+       uart8_gfclk_mux: uart8_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x18e0>;
+       };
+
+       uart9_gfclk_mux: uart9_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_48m_fclk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x18e8>;
+       };
+
+       vip1_gclk_mux: vip1_gclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&l3_iclk_div>, <&dpll_core_h23x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1020>;
+       };
+
+       vip2_gclk_mux: vip2_gclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&l3_iclk_div>, <&dpll_core_h23x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1028>;
+       };
+
+       vip3_gclk_mux: vip3_gclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&l3_iclk_div>, <&dpll_core_h23x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1030>;
+       };
+};
+
+&cm_core_clockdomains {
+       coreaon_clkdm: coreaon_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dpll_usb_ck>;
+       };
+};
diff --git a/arch/arm/boot/dts/imx6dl-cubox-i.dts b/arch/arm/boot/dts/imx6dl-cubox-i.dts
new file mode 100644 (file)
index 0000000..58aa8f2
--- /dev/null
@@ -0,0 +1,12 @@
+/*
+ * Copyright (C) 2014 Russell King
+ */
+/dts-v1/;
+
+#include "imx6dl.dtsi"
+#include "imx6qdl-cubox-i.dtsi"
+
+/ {
+       model = "SolidRun Cubox-i Solo/DualLite";
+       compatible = "solidrun,cubox-i/dl", "fsl,imx6dl";
+};
diff --git a/arch/arm/boot/dts/imx6dl-hummingboard.dts b/arch/arm/boot/dts/imx6dl-hummingboard.dts
new file mode 100644 (file)
index 0000000..fd8fc7c
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2013,2014 Russell King
+ */
+/dts-v1/;
+
+#include "imx6dl.dtsi"
+#include "imx6qdl-microsom.dtsi"
+#include "imx6qdl-microsom-ar8035.dtsi"
+
+/ {
+       model = "SolidRun HummingBoard DL/Solo";
+       compatible = "solidrun,hummingboard", "fsl,imx6dl";
+
+       ir_recv: ir-receiver {
+               compatible = "gpio-ir-receiver";
+               gpios = <&gpio1 2 1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_hummingboard_gpio1_2>;
+       };
+
+       regulators {
+               compatible = "simple-bus";
+
+               reg_3p3v: 3p3v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3P3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+               };
+
+               reg_usbh1_vbus: usb-h1-vbus {
+                       compatible = "regulator-fixed";
+                       enable-active-high;
+                       gpio = <&gpio1 0 0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_hummingboard_usbh1_vbus>;
+                       regulator-name = "usb_h1_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+               };
+
+               reg_usbotg_vbus: usb-otg-vbus {
+                       compatible = "regulator-fixed";
+                       enable-active-high;
+                       gpio = <&gpio3 22 0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_hummingboard_usbotg_vbus>;
+                       regulator-name = "usb_otg_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+               };
+       };
+
+       codec: spdif-transmitter {
+               compatible = "linux,spdif-dit";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_hummingboard_spdif>;
+       };
+
+       sound-spdif {
+               compatible = "fsl,imx-audio-spdif";
+               model = "imx-spdif";
+               /* IMX6 doesn't implement this yet */
+               spdif-controller = <&spdif>;
+               spdif-out;
+       };
+};
+
+&can1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hummingboard_flexcan1>;
+       status = "okay";
+};
+
+&i2c1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_hummingboard_i2c1>;
+
+       /*
+        * Not fitted on Carrier-1 board... yet
+       status = "okay";
+
+       rtc: pcf8523@68 {
+               compatible = "nxp,pcf8523";
+               reg = <0x68>;
+       };
+        */
+};
+
+&iomuxc {
+       hummingboard {
+               pinctrl_hummingboard_flexcan1: hummingboard-flexcan1 {
+                       fsl,pins = <
+                               MX6QDL_PAD_SD3_CLK__FLEXCAN1_RX 0x80000000
+                               MX6QDL_PAD_SD3_CMD__FLEXCAN1_TX 0x80000000
+                       >;
+               };
+
+               pinctrl_hummingboard_gpio1_2: hummingboard-gpio1_2 {
+                       fsl,pins = <
+                               MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x80000000
+                       >;
+               };
+
+               pinctrl_hummingboard_i2c1: hummingboard-i2c1 {
+                       fsl,pins = <
+                               MX6QDL_PAD_EIM_D21__I2C1_SCL 0x4001b8b1
+                               MX6QDL_PAD_EIM_D28__I2C1_SDA 0x4001b8b1
+                       >;
+               };
+
+               pinctrl_hummingboard_spdif: hummingboard-spdif {
+                       fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0>;
+               };
+
+               pinctrl_hummingboard_usbh1_vbus: hummingboard-usbh1-vbus {
+                       fsl,pins = <MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x1b0b0>;
+               };
+
+               pinctrl_hummingboard_usbotg_vbus: hummingboard-usbotg-vbus {
+                       fsl,pins = <MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x1b0b0>;
+               };
+
+               pinctrl_hummingboard_usdhc2_aux: hummingboard-usdhc2-aux {
+                       fsl,pins = <
+                               MX6QDL_PAD_GPIO_4__GPIO1_IO04    0x1f071
+                       >;
+               };
+
+               pinctrl_hummingboard_usdhc2: hummingboard-usdhc2 {
+                       fsl,pins = <
+                               MX6QDL_PAD_SD2_CMD__SD2_CMD    0x17059
+                               MX6QDL_PAD_SD2_CLK__SD2_CLK    0x10059
+                               MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
+                               MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
+                               MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
+                               MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059
+                       >;
+               };
+       };
+};
+
+&spdif {
+       status = "okay";
+};
+
+&usbh1 {
+       vbus-supply = <&reg_usbh1_vbus>;
+       status = "okay";
+};
+
+&usbotg {
+       vbus-supply = <&reg_usbotg_vbus>;
+       status = "okay";
+};
+
+&usdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <
+               &pinctrl_hummingboard_usdhc2_aux
+               &pinctrl_hummingboard_usdhc2
+       >;
+       vmmc-supply = <&reg_3p3v>;
+       cd-gpios = <&gpio1 4 0>;
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6q-cubox-i.dts b/arch/arm/boot/dts/imx6q-cubox-i.dts
new file mode 100644 (file)
index 0000000..bc5f31e
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2014 Russell King
+ */
+/dts-v1/;
+
+#include "imx6q.dtsi"
+#include "imx6qdl-cubox-i.dtsi"
+
+/ {
+       model = "SolidRun Cubox-i Dual/Quad";
+       compatible = "solidrun,cubox-i/q", "fsl,imx6q";
+};
+
+&sata {
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi b/arch/arm/boot/dts/imx6qdl-cubox-i.dtsi
new file mode 100644 (file)
index 0000000..64daa3b
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2014 Russell King
+ */
+#include "imx6qdl-microsom.dtsi"
+#include "imx6qdl-microsom-ar8035.dtsi"
+
+/ {
+       ir_recv: ir-receiver {
+               compatible = "gpio-ir-receiver";
+               gpios = <&gpio3 9 1>;
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_cubox_i_ir>;
+       };
+
+       regulators {
+               compatible = "simple-bus";
+
+               reg_3p3v: 3p3v {
+                       compatible = "regulator-fixed";
+                       regulator-name = "3P3V";
+                       regulator-min-microvolt = <3300000>;
+                       regulator-max-microvolt = <3300000>;
+                       regulator-always-on;
+               };
+
+               reg_usbh1_vbus: usb-h1-vbus {
+                       compatible = "regulator-fixed";
+                       enable-active-high;
+                       gpio = <&gpio1 0 0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_cubox_i_usbh1_vbus>;
+                       regulator-name = "usb_h1_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+               };
+
+               reg_usbotg_vbus: usb-otg-vbus {
+                       compatible = "regulator-fixed";
+                       enable-active-high;
+                       gpio = <&gpio3 22 0>;
+                       pinctrl-names = "default";
+                       pinctrl-0 = <&pinctrl_cubox_i_usbotg_vbus>;
+                       regulator-name = "usb_otg_vbus";
+                       regulator-min-microvolt = <5000000>;
+                       regulator-max-microvolt = <5000000>;
+               };
+       };
+
+       codec: spdif-transmitter {
+               compatible = "linux,spdif-dit";
+               pinctrl-names = "default";
+               pinctrl-0 = <&pinctrl_cubox_i_spdif>;
+       };
+
+       sound-spdif {
+               compatible = "fsl,imx-audio-spdif";
+               model = "imx-spdif";
+               /* IMX6 doesn't implement this yet */
+               spdif-controller = <&spdif>;
+               spdif-out;
+       };
+};
+
+&i2c3 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_cubox_i_i2c3>;
+
+       status = "okay";
+
+       rtc: pcf8523@68 {
+               compatible = "nxp,pcf8523";
+               reg = <0x68>;
+       };
+};
+
+&iomuxc {
+       cubox_i {
+               pinctrl_cubox_i_i2c3: cubox-i-i2c3 {
+                       fsl,pins = <
+                               MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
+                               MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
+                       >;
+               };
+
+               pinctrl_cubox_i_ir: cubox-i-ir {
+                       fsl,pins = <
+                               MX6QDL_PAD_EIM_DA9__GPIO3_IO09 0x80000000
+                       >;
+               };
+
+               pinctrl_cubox_i_spdif: cubox-i-spdif {
+                       fsl,pins = <MX6QDL_PAD_GPIO_17__SPDIF_OUT 0x1b0b0>;
+               };
+
+               pinctrl_cubox_i_usbh1_vbus: cubox-i-usbh1-vbus {
+                       fsl,pins = <MX6QDL_PAD_GPIO_0__GPIO1_IO00 0x4001b0b0>;
+               };
+
+               pinctrl_cubox_i_usbotg_vbus: cubox-i-usbotg-vbus {
+                       fsl,pins = <MX6QDL_PAD_EIM_D22__GPIO3_IO22 0x4001b0b0>;
+               };
+
+               pinctrl_cubox_i_usdhc2_aux: cubox-i-usdhc2-aux {
+                       fsl,pins = <
+                               MX6QDL_PAD_GPIO_4__GPIO1_IO04    0x1f071
+                               MX6QDL_PAD_KEY_ROW1__SD2_VSELECT 0x1b071
+                       >;
+               };
+
+               pinctrl_cubox_i_usdhc2: cubox-i-usdhc2 {
+                       fsl,pins = <
+                               MX6QDL_PAD_SD2_CMD__SD2_CMD    0x17059
+                               MX6QDL_PAD_SD2_CLK__SD2_CLK    0x10059
+                               MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
+                               MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
+                               MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
+                               MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x13059
+                       >;
+               };
+       };
+};
+
+&spdif {
+       status = "okay";
+};
+
+&usbh1 {
+       vbus-supply = <&reg_usbh1_vbus>;
+       status = "okay";
+};
+
+&usbotg {
+       vbus-supply = <&reg_usbotg_vbus>;
+       status = "okay";
+};
+
+&usdhc2 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_cubox_i_usdhc2_aux &pinctrl_cubox_i_usdhc2>;
+       vmmc-supply = <&reg_3p3v>;
+       cd-gpios = <&gpio1 4 0>;
+       status = "okay";
+};
diff --git a/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi b/arch/arm/boot/dts/imx6qdl-microsom-ar8035.dtsi
new file mode 100644 (file)
index 0000000..a3cb2ff
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2013,2014 Russell King
+ *
+ * This describes the hookup for an AR8035 to the iMX6 on the SolidRun
+ * MicroSOM.
+ */
+&fec {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_microsom_enet_ar8035>;
+       phy-mode = "rgmii";
+       phy-reset-duration = <2>;
+       phy-reset-gpios = <&gpio4 15 0>;
+       status = "okay";
+};
+
+&iomuxc {
+       enet {
+               pinctrl_microsom_enet_ar8035: microsom-enet-ar8035 {
+                       fsl,pins = <
+                               MX6QDL_PAD_ENET_MDIO__ENET_MDIO         0x1b0b0
+                               MX6QDL_PAD_ENET_MDC__ENET_MDC           0x1b0b0
+                               /* AR8035 reset */
+                               MX6QDL_PAD_KEY_ROW4__GPIO4_IO15         0x130b0
+                               /* AR8035 interrupt */
+                               MX6QDL_PAD_DI0_PIN2__GPIO4_IO18         0x80000000
+                               /* GPIO16 -> AR8035 25MHz */
+                               MX6QDL_PAD_GPIO_16__ENET_REF_CLK        0xc0000000
+                               MX6QDL_PAD_RGMII_TXC__RGMII_TXC         0x80000000
+                               MX6QDL_PAD_RGMII_TD0__RGMII_TD0         0x1b0b0
+                               MX6QDL_PAD_RGMII_TD1__RGMII_TD1         0x1b0b0
+                               MX6QDL_PAD_RGMII_TD2__RGMII_TD2         0x1b0b0
+                               MX6QDL_PAD_RGMII_TD3__RGMII_TD3         0x1b0b0
+                               MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL   0x1b0b0
+                               /* AR8035 CLK_25M --> ENET_REF_CLK (V22) */
+                               MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK    0x0a0b1
+                               /* AR8035 pin strapping: IO voltage: pull up */
+                               MX6QDL_PAD_RGMII_RXC__RGMII_RXC         0x1b0b0
+                               /* AR8035 pin strapping: PHYADDR#0: pull down */
+                               MX6QDL_PAD_RGMII_RD0__RGMII_RD0         0x130b0
+                               /* AR8035 pin strapping: PHYADDR#1: pull down */
+                               MX6QDL_PAD_RGMII_RD1__RGMII_RD1         0x130b0
+                               /* AR8035 pin strapping: MODE#1: pull up */
+                               MX6QDL_PAD_RGMII_RD2__RGMII_RD2         0x1b0b0
+                               /* AR8035 pin strapping: MODE#3: pull up */
+                               MX6QDL_PAD_RGMII_RD3__RGMII_RD3         0x1b0b0
+                               /* AR8035 pin strapping: MODE#0: pull down */
+                               MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL   0x130b0
+
+                               /*
+                                * As the RMII pins are also connected to RGMII
+                                * so that an AR8030 can be placed, set these
+                                * to high-z with the same pulls as above.
+                                * Use the GPIO settings to avoid changing the
+                                * input select registers.
+                                */
+                               MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25      0x03000
+                               MX6QDL_PAD_ENET_RXD0__GPIO1_IO27        0x03000
+                               MX6QDL_PAD_ENET_RXD1__GPIO1_IO26        0x03000
+                       >;
+               };
+       };
+};
diff --git a/arch/arm/boot/dts/imx6qdl-microsom.dtsi b/arch/arm/boot/dts/imx6qdl-microsom.dtsi
new file mode 100644 (file)
index 0000000..d729d0b
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013,2014 Russell King
+ */
+
+&iomuxc {
+       microsom {
+               pinctrl_microsom_uart1: microsom-uart1 {
+                       fsl,pins = <
+                               MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA    0x1b0b1
+                               MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA    0x1b0b1
+                       >;
+               };
+
+               pinctrl_microsom_usbotg: microsom-usbotg {
+                       /*
+                        * Similar to pinctrl_usbotg_2, but we want it
+                        * pulled down for a fixed host connection.
+                        */
+                       fsl,pins = <MX6QDL_PAD_GPIO_1__USB_OTG_ID 0x13059>;
+               };
+       };
+};
+
+&uart1 {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_microsom_uart1>;
+       status = "okay";
+};
+
+&usbotg {
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_microsom_usbotg>;
+};
index 02df1914a47c8f971cbe8fb852cea0963833bcff..928f6eef2d592cc6b0fe0318c275cd3c98e75583 100644 (file)
                                status = "okay";
                        };
 
+                       watchdog@fffffd40 {
+                               timeout-sec = <15>;
+                               atmel,max-heartbeat-sec = <16>;
+                               atmel,min-heartbeat-sec = <0>;
+                               status = "okay";
+                       };
                };
 
                nand0: nand@40000000 {
index 90749d55de0d45d05ebcd00d514ac9706799576c..10d088df0c35177a573bd695337ac1010a2dc138 100644 (file)
                reg = <0x0 0x2000000>;
        };
 
+       clocks {
+               ref12: ref12M {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <12000000>;
+               };
+       };
+
        flash@80000000,0 {
                compatible = "numonyx,js28f128", "cfi-flash";
                reg = <0x80000000 0x1000000>;
index da1d8effef9797708fc236c3dd51d3fafb104eba..1fd27ed65a01fc868d918a2a593534153bd45415 100644 (file)
        clocks {
                #address-cells = <1>;
                #size-cells = <0>;
-
-               ref12: ref12M {
-                       compatible = "fixed-clock";
-                       #clock-cells = <0>;
-                       clock-frequency = <12000000>;
-               };
        };
 
        soc {
index 427395c083f59e63c3b41bfeeefaa0fab1b66ee0..a5fc83b9c83545ce61738abf4695ceaa47453980 100644 (file)
                        interrupts = <0>;
                };
 
+               prm: prm@48306000 {
+                       compatible = "ti,omap3-prm";
+                       reg = <0x48306000 0x4000>;
+
+                       prm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       prm_clockdomains: clockdomains {
+                       };
+               };
+
+               cm: cm@48004000 {
+                       compatible = "ti,omap3-cm";
+                       reg = <0x48004000 0x4000>;
+
+                       cm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       cm_clockdomains: clockdomains {
+                       };
+               };
+
+               scrm: scrm@48002000 {
+                       compatible = "ti,omap3-scrm";
+                       reg = <0x48002000 0x2000>;
+
+                       scrm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       scrm_clockdomains: clockdomains {
+                       };
+               };
+
                counter32k: counter@48320000 {
                        compatible = "ti,omap-counter32k";
                        reg = <0x48320000 0x20>;
                };
        };
 };
+
+/include/ "omap3xxx-clocks.dtsi"
diff --git a/arch/arm/boot/dts/omap3430es1-clocks.dtsi b/arch/arm/boot/dts/omap3430es1-clocks.dtsi
new file mode 100644 (file)
index 0000000..02f6c7f
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Device Tree Source for OMAP3430 ES1 clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&cm_clocks {
+       gfx_l3_ck: gfx_l3_ck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&l3_ick>;
+               reg = <0x0b10>;
+               ti,bit-shift = <0>;
+       };
+
+       gfx_l3_fck: gfx_l3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&l3_ick>;
+               ti,max-div = <7>;
+               reg = <0x0b40>;
+               ti,index-starts-at-one;
+       };
+
+       gfx_l3_ick: gfx_l3_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&gfx_l3_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       gfx_cg1_ck: gfx_cg1_ck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&gfx_l3_fck>;
+               reg = <0x0b00>;
+               ti,bit-shift = <1>;
+       };
+
+       gfx_cg2_ck: gfx_cg2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&gfx_l3_fck>;
+               reg = <0x0b00>;
+               ti,bit-shift = <2>;
+       };
+
+       d2d_26m_fck: d2d_26m_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&sys_ck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <3>;
+       };
+
+       fshostusb_fck: fshostusb_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_48m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <5>;
+       };
+
+       ssi_ssr_gate_fck_3430es1: ssi_ssr_gate_fck_3430es1 {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&corex2_fck>;
+               ti,bit-shift = <0>;
+               reg = <0x0a00>;
+       };
+
+       ssi_ssr_div_fck_3430es1: ssi_ssr_div_fck_3430es1 {
+               #clock-cells = <0>;
+               compatible = "ti,composite-divider-clock";
+               clocks = <&corex2_fck>;
+               ti,bit-shift = <8>;
+               reg = <0x0a40>;
+               ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
+       };
+
+       ssi_ssr_fck_3430es1: ssi_ssr_fck_3430es1 {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&ssi_ssr_gate_fck_3430es1>, <&ssi_ssr_div_fck_3430es1>;
+       };
+
+       ssi_sst_fck_3430es1: ssi_sst_fck_3430es1 {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&ssi_ssr_fck_3430es1>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       hsotgusb_ick_3430es1: hsotgusb_ick_3430es1 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-no-wait-interface-clock";
+               clocks = <&core_l3_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <4>;
+       };
+
+       fac_ick: fac_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <8>;
+       };
+
+       ssi_l4_ick: ssi_l4_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l4_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       ssi_ick_3430es1: ssi_ick_3430es1 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-no-wait-interface-clock";
+               clocks = <&ssi_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <0>;
+       };
+
+       usb_l4_gate_ick: usb_l4_gate_ick {
+               #clock-cells = <0>;
+               compatible = "ti,composite-interface-clock";
+               clocks = <&l4_ick>;
+               ti,bit-shift = <5>;
+               reg = <0x0a10>;
+       };
+
+       usb_l4_div_ick: usb_l4_div_ick {
+               #clock-cells = <0>;
+               compatible = "ti,composite-divider-clock";
+               clocks = <&l4_ick>;
+               ti,bit-shift = <4>;
+               ti,max-div = <1>;
+               reg = <0x0a40>;
+               ti,index-starts-at-one;
+       };
+
+       usb_l4_ick: usb_l4_ick {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&usb_l4_gate_ick>, <&usb_l4_div_ick>;
+       };
+
+       dss1_alwon_fck_3430es1: dss1_alwon_fck_3430es1 {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll4_m4x2_ck>;
+               ti,bit-shift = <0>;
+               reg = <0x0e00>;
+               ti,set-rate-parent;
+       };
+
+       dss_ick_3430es1: dss_ick_3430es1 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-no-wait-interface-clock";
+               clocks = <&l4_ick>;
+               reg = <0x0e10>;
+               ti,bit-shift = <0>;
+       };
+};
+
+&cm_clockdomains {
+       core_l3_clkdm: core_l3_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&sdrc_ick>, <&hsotgusb_ick_3430es1>;
+       };
+
+       gfx_3430es1_clkdm: gfx_3430es1_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&gfx_l3_ck>, <&gfx_cg1_ck>, <&gfx_cg2_ck>;
+       };
+
+       dss_clkdm: dss_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>,
+                        <&dss1_alwon_fck_3430es1>, <&dss_ick_3430es1>;
+       };
+
+       d2d_clkdm: d2d_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&d2d_26m_fck>;
+       };
+
+       core_l4_clkdm: core_l4_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>,
+                        <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>,
+                        <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>,
+                        <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>,
+                        <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>,
+                        <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>,
+                        <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>,
+                        <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>,
+                        <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>,
+                        <&fshostusb_fck>, <&fac_ick>, <&ssi_ick_3430es1>;
+       };
+};
diff --git a/arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi b/arch/arm/boot/dts/omap34xx-omap36xx-clocks.dtsi
new file mode 100644 (file)
index 0000000..b02017b
--- /dev/null
@@ -0,0 +1,268 @@
+/*
+ * Device Tree Source for OMAP34XX/OMAP36XX clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&cm_clocks {
+       security_l4_ick2: security_l4_ick2 {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l4_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       aes1_ick: aes1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&security_l4_ick2>;
+               ti,bit-shift = <3>;
+               reg = <0x0a14>;
+       };
+
+       rng_ick: rng_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&security_l4_ick2>;
+               reg = <0x0a14>;
+               ti,bit-shift = <2>;
+       };
+
+       sha11_ick: sha11_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&security_l4_ick2>;
+               reg = <0x0a14>;
+               ti,bit-shift = <1>;
+       };
+
+       des1_ick: des1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&security_l4_ick2>;
+               reg = <0x0a14>;
+               ti,bit-shift = <0>;
+       };
+
+       cam_mclk: cam_mclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll4_m5x2_ck>;
+               ti,bit-shift = <0>;
+               reg = <0x0f00>;
+               ti,set-rate-parent;
+       };
+
+       cam_ick: cam_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-no-wait-interface-clock";
+               clocks = <&l4_ick>;
+               reg = <0x0f10>;
+               ti,bit-shift = <0>;
+       };
+
+       csi2_96m_fck: csi2_96m_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&core_96m_fck>;
+               reg = <0x0f00>;
+               ti,bit-shift = <1>;
+       };
+
+       security_l3_ick: security_l3_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l3_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       pka_ick: pka_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&security_l3_ick>;
+               reg = <0x0a14>;
+               ti,bit-shift = <4>;
+       };
+
+       icr_ick: icr_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <29>;
+       };
+
+       des2_ick: des2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <26>;
+       };
+
+       mspro_ick: mspro_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <23>;
+       };
+
+       mailboxes_ick: mailboxes_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <7>;
+       };
+
+       ssi_l4_ick: ssi_l4_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l4_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       sr1_fck: sr1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&sys_ck>;
+               reg = <0x0c00>;
+               ti,bit-shift = <6>;
+       };
+
+       sr2_fck: sr2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&sys_ck>;
+               reg = <0x0c00>;
+               ti,bit-shift = <7>;
+       };
+
+       sr_l4_ick: sr_l4_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l4_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll2_fck: dpll2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&core_ck>;
+               ti,bit-shift = <19>;
+               ti,max-div = <7>;
+               reg = <0x0040>;
+               ti,index-starts-at-one;
+       };
+
+       dpll2_ck: dpll2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-dpll-clock";
+               clocks = <&sys_ck>, <&dpll2_fck>;
+               reg = <0x0004>, <0x0024>, <0x0040>, <0x0034>;
+               ti,low-power-stop;
+               ti,lock;
+               ti,low-power-bypass;
+       };
+
+       dpll2_m2_ck: dpll2_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll2_ck>;
+               ti,max-div = <31>;
+               reg = <0x0044>;
+               ti,index-starts-at-one;
+       };
+
+       iva2_ck: iva2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&dpll2_m2_ck>;
+               reg = <0x0000>;
+               ti,bit-shift = <0>;
+       };
+
+       modem_fck: modem_fck {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&sys_ck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <31>;
+       };
+
+       sad2d_ick: sad2d_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&l3_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <3>;
+       };
+
+       mad2d_ick: mad2d_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&l3_ick>;
+               reg = <0x0a18>;
+               ti,bit-shift = <3>;
+       };
+
+       mspro_fck: mspro_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_96m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <23>;
+       };
+};
+
+&cm_clockdomains {
+       cam_clkdm: cam_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&cam_ick>, <&csi2_96m_fck>;
+       };
+
+       iva2_clkdm: iva2_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&iva2_ck>;
+       };
+
+       dpll2_clkdm: dpll2_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dpll2_ck>;
+       };
+
+       wkup_clkdm: wkup_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&gpio1_dbck>, <&wdt2_fck>, <&wdt2_ick>, <&wdt1_ick>,
+                        <&gpio1_ick>, <&omap_32ksync_ick>, <&gpt12_ick>,
+                        <&gpt1_ick>, <&sr1_fck>, <&sr2_fck>;
+       };
+
+       d2d_clkdm: d2d_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&modem_fck>, <&sad2d_ick>, <&mad2d_ick>;
+       };
+
+       core_l4_clkdm: core_l4_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>,
+                        <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>,
+                        <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>,
+                        <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>,
+                        <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>,
+                        <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>,
+                        <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>,
+                        <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>,
+                        <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>, <&icr_ick>,
+                        <&des2_ick>, <&mspro_ick>, <&mailboxes_ick>,
+                        <&mspro_fck>;
+       };
+};
index 77d124678c9587905b4da1fb9ee18b9759883efe..2e92360da1f36d29d094ef67c8183a8824c0f047 100644 (file)
@@ -39,3 +39,7 @@
                };
        };
 };
+
+/include/ "omap34xx-omap36xx-clocks.dtsi"
+/include/ "omap36xx-omap3430es2plus-clocks.dtsi"
+/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi"
diff --git a/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi b/arch/arm/boot/dts/omap36xx-am35xx-omap3430es2plus-clocks.dtsi
new file mode 100644 (file)
index 0000000..af9ae53
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Device Tree Source for OMAP36xx/AM35xx/OMAP34xx clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&prm_clocks {
+       corex2_d3_fck: corex2_d3_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&corex2_fck>;
+               clock-mult = <1>;
+               clock-div = <3>;
+       };
+
+       corex2_d5_fck: corex2_d5_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&corex2_fck>;
+               clock-mult = <1>;
+               clock-div = <5>;
+       };
+};
+&cm_clocks {
+       dpll5_ck: dpll5_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-dpll-clock";
+               clocks = <&sys_ck>, <&sys_ck>;
+               reg = <0x0d04>, <0x0d24>, <0x0d4c>, <0x0d34>;
+               ti,low-power-stop;
+               ti,lock;
+       };
+
+       dpll5_m2_ck: dpll5_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll5_ck>;
+               ti,max-div = <31>;
+               reg = <0x0d50>;
+               ti,index-starts-at-one;
+       };
+
+       sgx_gate_fck: sgx_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&core_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0b00>;
+       };
+
+       core_d3_ck: core_d3_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&core_ck>;
+               clock-mult = <1>;
+               clock-div = <3>;
+       };
+
+       core_d4_ck: core_d4_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&core_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       core_d6_ck: core_d6_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&core_ck>;
+               clock-mult = <1>;
+               clock-div = <6>;
+       };
+
+       omap_192m_alwon_fck: omap_192m_alwon_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll4_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       core_d2_ck: core_d2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&core_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       sgx_mux_fck: sgx_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&core_d3_ck>, <&core_d4_ck>, <&core_d6_ck>, <&cm_96m_fck>, <&omap_192m_alwon_fck>, <&core_d2_ck>, <&corex2_d3_fck>, <&corex2_d5_fck>;
+               reg = <0x0b40>;
+       };
+
+       sgx_fck: sgx_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&sgx_gate_fck>, <&sgx_mux_fck>;
+       };
+
+       sgx_ick: sgx_ick {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&l3_ick>;
+               reg = <0x0b10>;
+               ti,bit-shift = <0>;
+       };
+
+       cpefuse_fck: cpefuse_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_ck>;
+               reg = <0x0a08>;
+               ti,bit-shift = <0>;
+       };
+
+       ts_fck: ts_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&omap_32k_fck>;
+               reg = <0x0a08>;
+               ti,bit-shift = <1>;
+       };
+
+       usbtll_fck: usbtll_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&dpll5_m2_ck>;
+               reg = <0x0a08>;
+               ti,bit-shift = <2>;
+       };
+
+       usbtll_ick: usbtll_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a18>;
+               ti,bit-shift = <2>;
+       };
+
+       mmchs3_ick: mmchs3_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <30>;
+       };
+
+       mmchs3_fck: mmchs3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_96m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <30>;
+       };
+
+       dss1_alwon_fck_3430es2: dss1_alwon_fck_3430es2 {
+               #clock-cells = <0>;
+               compatible = "ti,dss-gate-clock";
+               clocks = <&dpll4_m4x2_ck>;
+               ti,bit-shift = <0>;
+               reg = <0x0e00>;
+               ti,set-rate-parent;
+       };
+
+       dss_ick_3430es2: dss_ick_3430es2 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-dss-interface-clock";
+               clocks = <&l4_ick>;
+               reg = <0x0e10>;
+               ti,bit-shift = <0>;
+       };
+
+       usbhost_120m_fck: usbhost_120m_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll5_m2_ck>;
+               reg = <0x1400>;
+               ti,bit-shift = <1>;
+       };
+
+       usbhost_48m_fck: usbhost_48m_fck {
+               #clock-cells = <0>;
+               compatible = "ti,dss-gate-clock";
+               clocks = <&omap_48m_fck>;
+               reg = <0x1400>;
+               ti,bit-shift = <0>;
+       };
+
+       usbhost_ick: usbhost_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-dss-interface-clock";
+               clocks = <&l4_ick>;
+               reg = <0x1410>;
+               ti,bit-shift = <0>;
+       };
+};
+
+&cm_clockdomains {
+       dpll5_clkdm: dpll5_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dpll5_ck>;
+       };
+
+       sgx_clkdm: sgx_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&sgx_ick>;
+       };
+
+       dss_clkdm: dss_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>,
+                        <&dss1_alwon_fck_3430es2>, <&dss_ick_3430es2>;
+       };
+
+       core_l4_clkdm: core_l4_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>,
+                        <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>,
+                        <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>,
+                        <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>,
+                        <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>,
+                        <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>,
+                        <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>,
+                        <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>,
+                        <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>,
+                        <&cpefuse_fck>, <&ts_fck>, <&usbtll_fck>,
+                        <&usbtll_ick>, <&mmchs3_ick>, <&mmchs3_fck>;
+       };
+
+       usbhost_clkdm: usbhost_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&usbhost_120m_fck>, <&usbhost_48m_fck>,
+                        <&usbhost_ick>;
+       };
+};
diff --git a/arch/arm/boot/dts/omap36xx-clocks.dtsi b/arch/arm/boot/dts/omap36xx-clocks.dtsi
new file mode 100644 (file)
index 0000000..2fcf253
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Device Tree Source for OMAP36xx clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&cm_clocks {
+       dpll4_ck: dpll4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-dpll-per-j-type-clock";
+               clocks = <&sys_ck>, <&sys_ck>;
+               reg = <0x0d00>, <0x0d20>, <0x0d44>, <0x0d30>;
+       };
+
+       dpll4_m5x2_ck: dpll4_m5x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,hsdiv-gate-clock";
+               clocks = <&dpll4_m5x2_mul_ck>;
+               ti,bit-shift = <0x1e>;
+               reg = <0x0d00>;
+               ti,set-rate-parent;
+               ti,set-bit-to-disable;
+       };
+
+       dpll4_m2x2_ck: dpll4_m2x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,hsdiv-gate-clock";
+               clocks = <&dpll4_m2x2_mul_ck>;
+               ti,bit-shift = <0x1b>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       dpll3_m3x2_ck: dpll3_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,hsdiv-gate-clock";
+               clocks = <&dpll3_m3x2_mul_ck>;
+               ti,bit-shift = <0xc>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       dpll4_m3x2_ck: dpll4_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,hsdiv-gate-clock";
+               clocks = <&dpll4_m3x2_mul_ck>;
+               ti,bit-shift = <0x1c>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       dpll4_m6x2_ck: dpll4_m6x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,hsdiv-gate-clock";
+               clocks = <&dpll4_m6x2_mul_ck>;
+               ti,bit-shift = <0x1f>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       uart4_fck: uart4_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&per_48m_fck>;
+               reg = <0x1000>;
+               ti,bit-shift = <18>;
+       };
+};
+
+&cm_clockdomains {
+       dpll4_clkdm: dpll4_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dpll4_ck>;
+       };
+
+       per_clkdm: per_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&uart3_fck>, <&gpio6_dbck>, <&gpio5_dbck>,
+                        <&gpio4_dbck>, <&gpio3_dbck>, <&gpio2_dbck>,
+                        <&wdt3_fck>, <&gpio6_ick>, <&gpio5_ick>, <&gpio4_ick>,
+                        <&gpio3_ick>, <&gpio2_ick>, <&wdt3_ick>, <&uart3_ick>,
+                        <&uart4_ick>, <&gpt9_ick>, <&gpt8_ick>, <&gpt7_ick>,
+                        <&gpt6_ick>, <&gpt5_ick>, <&gpt4_ick>, <&gpt3_ick>,
+                        <&gpt2_ick>, <&mcbsp2_ick>, <&mcbsp3_ick>,
+                        <&mcbsp4_ick>, <&uart4_fck>;
+       };
+};
diff --git a/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi b/arch/arm/boot/dts/omap36xx-omap3430es2plus-clocks.dtsi
new file mode 100644 (file)
index 0000000..8ed475d
--- /dev/null
@@ -0,0 +1,198 @@
+/*
+ * Device Tree Source for OMAP34xx/OMAP36xx clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&cm_clocks {
+       ssi_ssr_gate_fck_3430es2: ssi_ssr_gate_fck_3430es2 {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&corex2_fck>;
+               ti,bit-shift = <0>;
+               reg = <0x0a00>;
+       };
+
+       ssi_ssr_div_fck_3430es2: ssi_ssr_div_fck_3430es2 {
+               #clock-cells = <0>;
+               compatible = "ti,composite-divider-clock";
+               clocks = <&corex2_fck>;
+               ti,bit-shift = <8>;
+               reg = <0x0a40>;
+               ti,dividers = <0>, <1>, <2>, <3>, <4>, <0>, <6>, <0>, <8>;
+       };
+
+       ssi_ssr_fck_3430es2: ssi_ssr_fck_3430es2 {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&ssi_ssr_gate_fck_3430es2>, <&ssi_ssr_div_fck_3430es2>;
+       };
+
+       ssi_sst_fck_3430es2: ssi_sst_fck_3430es2 {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&ssi_ssr_fck_3430es2>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       hsotgusb_ick_3430es2: hsotgusb_ick_3430es2 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-hsotgusb-interface-clock";
+               clocks = <&core_l3_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <4>;
+       };
+
+       ssi_l4_ick: ssi_l4_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l4_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       ssi_ick_3430es2: ssi_ick_3430es2 {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-ssi-interface-clock";
+               clocks = <&ssi_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <0>;
+       };
+
+       usim_gate_fck: usim_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&omap_96m_fck>;
+               ti,bit-shift = <9>;
+               reg = <0x0c00>;
+       };
+
+       sys_d2_ck: sys_d2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       omap_96m_d2_fck: omap_96m_d2_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_96m_fck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       omap_96m_d4_fck: omap_96m_d4_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_96m_fck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       omap_96m_d8_fck: omap_96m_d8_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_96m_fck>;
+               clock-mult = <1>;
+               clock-div = <8>;
+       };
+
+       omap_96m_d10_fck: omap_96m_d10_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_96m_fck>;
+               clock-mult = <1>;
+               clock-div = <10>;
+       };
+
+       dpll5_m2_d4_ck: dpll5_m2_d4_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll5_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       dpll5_m2_d8_ck: dpll5_m2_d8_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll5_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <8>;
+       };
+
+       dpll5_m2_d16_ck: dpll5_m2_d16_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll5_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <16>;
+       };
+
+       dpll5_m2_d20_ck: dpll5_m2_d20_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll5_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <20>;
+       };
+
+       usim_mux_fck: usim_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_ck>, <&sys_d2_ck>, <&omap_96m_d2_fck>, <&omap_96m_d4_fck>, <&omap_96m_d8_fck>, <&omap_96m_d10_fck>, <&dpll5_m2_d4_ck>, <&dpll5_m2_d8_ck>, <&dpll5_m2_d16_ck>, <&dpll5_m2_d20_ck>;
+               ti,bit-shift = <3>;
+               reg = <0x0c40>;
+               ti,index-starts-at-one;
+       };
+
+       usim_fck: usim_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&usim_gate_fck>, <&usim_mux_fck>;
+       };
+
+       usim_ick: usim_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&wkup_l4_ick>;
+               reg = <0x0c10>;
+               ti,bit-shift = <9>;
+       };
+};
+
+&cm_clockdomains {
+       core_l3_clkdm: core_l3_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&sdrc_ick>, <&hsotgusb_ick_3430es2>;
+       };
+
+       wkup_clkdm: wkup_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&gpio1_dbck>, <&wdt2_fck>, <&wdt2_ick>, <&wdt1_ick>,
+                        <&gpio1_ick>, <&omap_32ksync_ick>, <&gpt12_ick>,
+                        <&gpt1_ick>, <&usim_ick>;
+       };
+
+       core_l4_clkdm: core_l4_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&cpefuse_fck>, <&ts_fck>, <&usbtll_fck>,
+                        <&usbtll_ick>, <&mmchs3_ick>, <&mmchs3_fck>,
+                        <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>,
+                        <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>,
+                        <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>,
+                        <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>,
+                        <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>,
+                        <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>,
+                        <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>,
+                        <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>,
+                        <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>,
+                        <&ssi_ick_3430es2>;
+       };
+};
index b7c7bd96c4041e70752e64c7f70c16c4d7ff4456..7e8dee9175d6a4d1d796a5a9389b4a9c3300125d 100644 (file)
@@ -51,3 +51,8 @@
                };
        };
 };
+
+/include/ "omap36xx-clocks.dtsi"
+/include/ "omap34xx-omap36xx-clocks.dtsi"
+/include/ "omap36xx-omap3430es2plus-clocks.dtsi"
+/include/ "omap36xx-am35xx-omap3430es2plus-clocks.dtsi"
diff --git a/arch/arm/boot/dts/omap3xxx-clocks.dtsi b/arch/arm/boot/dts/omap3xxx-clocks.dtsi
new file mode 100644 (file)
index 0000000..cb04d4b
--- /dev/null
@@ -0,0 +1,1660 @@
+/*
+ * Device Tree Source for OMAP3 clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&prm_clocks {
+       virt_16_8m_ck: virt_16_8m_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <16800000>;
+       };
+
+       osc_sys_ck: osc_sys_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&virt_12m_ck>, <&virt_13m_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_38_4m_ck>, <&virt_16_8m_ck>;
+               reg = <0x0d40>;
+       };
+
+       sys_ck: sys_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&osc_sys_ck>;
+               ti,bit-shift = <6>;
+               ti,max-div = <3>;
+               reg = <0x1270>;
+               ti,index-starts-at-one;
+       };
+
+       sys_clkout1: sys_clkout1 {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&osc_sys_ck>;
+               reg = <0x0d70>;
+               ti,bit-shift = <7>;
+       };
+
+       dpll3_x2_ck: dpll3_x2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll3_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       dpll3_m2x2_ck: dpll3_m2x2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll3_m2_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       dpll4_x2_ck: dpll4_x2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll4_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       corex2_fck: corex2_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll3_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       wkup_l4_ick: wkup_l4_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+};
+&scrm_clocks {
+       mcbsp5_mux_fck: mcbsp5_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&core_96m_fck>, <&mcbsp_clks>;
+               ti,bit-shift = <4>;
+               reg = <0x02d8>;
+       };
+
+       mcbsp5_fck: mcbsp5_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&mcbsp5_gate_fck>, <&mcbsp5_mux_fck>;
+       };
+
+       mcbsp1_mux_fck: mcbsp1_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&core_96m_fck>, <&mcbsp_clks>;
+               ti,bit-shift = <2>;
+               reg = <0x0274>;
+       };
+
+       mcbsp1_fck: mcbsp1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&mcbsp1_gate_fck>, <&mcbsp1_mux_fck>;
+       };
+
+       mcbsp2_mux_fck: mcbsp2_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&per_96m_fck>, <&mcbsp_clks>;
+               ti,bit-shift = <6>;
+               reg = <0x0274>;
+       };
+
+       mcbsp2_fck: mcbsp2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&mcbsp2_gate_fck>, <&mcbsp2_mux_fck>;
+       };
+
+       mcbsp3_mux_fck: mcbsp3_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&per_96m_fck>, <&mcbsp_clks>;
+               reg = <0x02d8>;
+       };
+
+       mcbsp3_fck: mcbsp3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&mcbsp3_gate_fck>, <&mcbsp3_mux_fck>;
+       };
+
+       mcbsp4_mux_fck: mcbsp4_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&per_96m_fck>, <&mcbsp_clks>;
+               ti,bit-shift = <2>;
+               reg = <0x02d8>;
+       };
+
+       mcbsp4_fck: mcbsp4_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&mcbsp4_gate_fck>, <&mcbsp4_mux_fck>;
+       };
+};
+&cm_clocks {
+       dummy_apb_pclk: dummy_apb_pclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0x0>;
+       };
+
+       omap_32k_fck: omap_32k_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       virt_12m_ck: virt_12m_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       virt_13m_ck: virt_13m_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <13000000>;
+       };
+
+       virt_19200000_ck: virt_19200000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <19200000>;
+       };
+
+       virt_26000000_ck: virt_26000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <26000000>;
+       };
+
+       virt_38_4m_ck: virt_38_4m_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <38400000>;
+       };
+
+       dpll4_ck: dpll4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-dpll-per-clock";
+               clocks = <&sys_ck>, <&sys_ck>;
+               reg = <0x0d00>, <0x0d20>, <0x0d44>, <0x0d30>;
+       };
+
+       dpll4_m2_ck: dpll4_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll4_ck>;
+               ti,max-div = <63>;
+               reg = <0x0d48>;
+               ti,index-starts-at-one;
+       };
+
+       dpll4_m2x2_mul_ck: dpll4_m2x2_mul_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll4_m2_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       dpll4_m2x2_ck: dpll4_m2x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll4_m2x2_mul_ck>;
+               ti,bit-shift = <0x1b>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       omap_96m_alwon_fck: omap_96m_alwon_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll4_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll3_ck: dpll3_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-dpll-core-clock";
+               clocks = <&sys_ck>, <&sys_ck>;
+               reg = <0x0d00>, <0x0d20>, <0x0d40>, <0x0d30>;
+       };
+
+       dpll3_m3_ck: dpll3_m3_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll3_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <31>;
+               reg = <0x1140>;
+               ti,index-starts-at-one;
+       };
+
+       dpll3_m3x2_mul_ck: dpll3_m3x2_mul_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll3_m3_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       dpll3_m3x2_ck: dpll3_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll3_m3x2_mul_ck>;
+               ti,bit-shift = <0xc>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       emu_core_alwon_ck: emu_core_alwon_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll3_m3x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       sys_altclk: sys_altclk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0x0>;
+       };
+
+       mcbsp_clks: mcbsp_clks {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0x0>;
+       };
+
+       dpll3_m2_ck: dpll3_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll3_ck>;
+               ti,bit-shift = <27>;
+               ti,max-div = <31>;
+               reg = <0x0d40>;
+               ti,index-starts-at-one;
+       };
+
+       core_ck: core_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll3_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll1_fck: dpll1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&core_ck>;
+               ti,bit-shift = <19>;
+               ti,max-div = <7>;
+               reg = <0x0940>;
+               ti,index-starts-at-one;
+       };
+
+       dpll1_ck: dpll1_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-dpll-clock";
+               clocks = <&sys_ck>, <&dpll1_fck>;
+               reg = <0x0904>, <0x0924>, <0x0940>, <0x0934>;
+       };
+
+       dpll1_x2_ck: dpll1_x2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll1_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       dpll1_x2m2_ck: dpll1_x2m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll1_x2_ck>;
+               ti,max-div = <31>;
+               reg = <0x0944>;
+               ti,index-starts-at-one;
+       };
+
+       cm_96m_fck: cm_96m_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_96m_alwon_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       omap_96m_fck: omap_96m_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&cm_96m_fck>, <&sys_ck>;
+               ti,bit-shift = <6>;
+               reg = <0x0d40>;
+       };
+
+       dpll4_m3_ck: dpll4_m3_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll4_ck>;
+               ti,bit-shift = <8>;
+               ti,max-div = <32>;
+               reg = <0x0e40>;
+               ti,index-starts-at-one;
+       };
+
+       dpll4_m3x2_mul_ck: dpll4_m3x2_mul_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll4_m3_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       dpll4_m3x2_ck: dpll4_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll4_m3x2_mul_ck>;
+               ti,bit-shift = <0x1c>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       omap_54m_fck: omap_54m_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll4_m3x2_ck>, <&sys_altclk>;
+               ti,bit-shift = <5>;
+               reg = <0x0d40>;
+       };
+
+       cm_96m_d2_fck: cm_96m_d2_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&cm_96m_fck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       omap_48m_fck: omap_48m_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&cm_96m_d2_fck>, <&sys_altclk>;
+               ti,bit-shift = <3>;
+               reg = <0x0d40>;
+       };
+
+       omap_12m_fck: omap_12m_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_48m_fck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       dpll4_m4_ck: dpll4_m4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll4_ck>;
+               ti,max-div = <32>;
+               reg = <0x0e40>;
+               ti,index-starts-at-one;
+       };
+
+       dpll4_m4x2_mul_ck: dpll4_m4x2_mul_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll4_m4_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       dpll4_m4x2_ck: dpll4_m4x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll4_m4x2_mul_ck>;
+               ti,bit-shift = <0x1d>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       dpll4_m5_ck: dpll4_m5_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll4_ck>;
+               ti,max-div = <63>;
+               reg = <0x0f40>;
+               ti,index-starts-at-one;
+       };
+
+       dpll4_m5x2_mul_ck: dpll4_m5x2_mul_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll4_m5_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       dpll4_m5x2_ck: dpll4_m5x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll4_m5x2_mul_ck>;
+               ti,bit-shift = <0x1e>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       dpll4_m6_ck: dpll4_m6_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll4_ck>;
+               ti,bit-shift = <24>;
+               ti,max-div = <63>;
+               reg = <0x1140>;
+               ti,index-starts-at-one;
+       };
+
+       dpll4_m6x2_mul_ck: dpll4_m6x2_mul_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll4_m6_ck>;
+               clock-mult = <2>;
+               clock-div = <1>;
+       };
+
+       dpll4_m6x2_ck: dpll4_m6x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll4_m6x2_mul_ck>;
+               ti,bit-shift = <0x1f>;
+               reg = <0x0d00>;
+               ti,set-bit-to-disable;
+       };
+
+       emu_per_alwon_ck: emu_per_alwon_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll4_m6x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       clkout2_src_gate_ck: clkout2_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&core_ck>;
+               ti,bit-shift = <7>;
+               reg = <0x0d70>;
+       };
+
+       clkout2_src_mux_ck: clkout2_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&core_ck>, <&sys_ck>, <&cm_96m_fck>, <&omap_54m_fck>;
+               reg = <0x0d70>;
+       };
+
+       clkout2_src_ck: clkout2_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&clkout2_src_gate_ck>, <&clkout2_src_mux_ck>;
+       };
+
+       sys_clkout2: sys_clkout2 {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&clkout2_src_ck>;
+               ti,bit-shift = <3>;
+               ti,max-div = <64>;
+               reg = <0x0d70>;
+               ti,index-power-of-two;
+       };
+
+       mpu_ck: mpu_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll1_x2m2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       arm_fck: arm_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&mpu_ck>;
+               reg = <0x0924>;
+               ti,max-div = <2>;
+       };
+
+       emu_mpu_alwon_ck: emu_mpu_alwon_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&mpu_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l3_ick: l3_ick {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&core_ck>;
+               ti,max-div = <3>;
+               reg = <0x0a40>;
+               ti,index-starts-at-one;
+       };
+
+       l4_ick: l4_ick {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&l3_ick>;
+               ti,bit-shift = <2>;
+               ti,max-div = <3>;
+               reg = <0x0a40>;
+               ti,index-starts-at-one;
+       };
+
+       rm_ick: rm_ick {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&l4_ick>;
+               ti,bit-shift = <1>;
+               ti,max-div = <3>;
+               reg = <0x0c40>;
+               ti,index-starts-at-one;
+       };
+
+       gpt10_gate_fck: gpt10_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <11>;
+               reg = <0x0a00>;
+       };
+
+       gpt10_mux_fck: gpt10_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               ti,bit-shift = <6>;
+               reg = <0x0a40>;
+       };
+
+       gpt10_fck: gpt10_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt10_gate_fck>, <&gpt10_mux_fck>;
+       };
+
+       gpt11_gate_fck: gpt11_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <12>;
+               reg = <0x0a00>;
+       };
+
+       gpt11_mux_fck: gpt11_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               ti,bit-shift = <7>;
+               reg = <0x0a40>;
+       };
+
+       gpt11_fck: gpt11_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt11_gate_fck>, <&gpt11_mux_fck>;
+       };
+
+       core_96m_fck: core_96m_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_96m_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       mmchs2_fck: mmchs2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_96m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <25>;
+       };
+
+       mmchs1_fck: mmchs1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_96m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <24>;
+       };
+
+       i2c3_fck: i2c3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_96m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <17>;
+       };
+
+       i2c2_fck: i2c2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_96m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <16>;
+       };
+
+       i2c1_fck: i2c1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_96m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <15>;
+       };
+
+       mcbsp5_gate_fck: mcbsp5_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&mcbsp_clks>;
+               ti,bit-shift = <10>;
+               reg = <0x0a00>;
+       };
+
+       mcbsp1_gate_fck: mcbsp1_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&mcbsp_clks>;
+               ti,bit-shift = <9>;
+               reg = <0x0a00>;
+       };
+
+       core_48m_fck: core_48m_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_48m_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       mcspi4_fck: mcspi4_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_48m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <21>;
+       };
+
+       mcspi3_fck: mcspi3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_48m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <20>;
+       };
+
+       mcspi2_fck: mcspi2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_48m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <19>;
+       };
+
+       mcspi1_fck: mcspi1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_48m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <18>;
+       };
+
+       uart2_fck: uart2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_48m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <14>;
+       };
+
+       uart1_fck: uart1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_48m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <13>;
+       };
+
+       core_12m_fck: core_12m_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_12m_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       hdq_fck: hdq_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_12m_fck>;
+               reg = <0x0a00>;
+               ti,bit-shift = <22>;
+       };
+
+       core_l3_ick: core_l3_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l3_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       sdrc_ick: sdrc_ick {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&core_l3_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <1>;
+       };
+
+       gpmc_fck: gpmc_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&core_l3_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       core_l4_ick: core_l4_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l4_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       mmchs2_ick: mmchs2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <25>;
+       };
+
+       mmchs1_ick: mmchs1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <24>;
+       };
+
+       hdq_ick: hdq_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <22>;
+       };
+
+       mcspi4_ick: mcspi4_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <21>;
+       };
+
+       mcspi3_ick: mcspi3_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <20>;
+       };
+
+       mcspi2_ick: mcspi2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <19>;
+       };
+
+       mcspi1_ick: mcspi1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <18>;
+       };
+
+       i2c3_ick: i2c3_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <17>;
+       };
+
+       i2c2_ick: i2c2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <16>;
+       };
+
+       i2c1_ick: i2c1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <15>;
+       };
+
+       uart2_ick: uart2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <14>;
+       };
+
+       uart1_ick: uart1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <13>;
+       };
+
+       gpt11_ick: gpt11_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <12>;
+       };
+
+       gpt10_ick: gpt10_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <11>;
+       };
+
+       mcbsp5_ick: mcbsp5_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <10>;
+       };
+
+       mcbsp1_ick: mcbsp1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <9>;
+       };
+
+       omapctrl_ick: omapctrl_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <6>;
+       };
+
+       dss_tv_fck: dss_tv_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&omap_54m_fck>;
+               reg = <0x0e00>;
+               ti,bit-shift = <2>;
+       };
+
+       dss_96m_fck: dss_96m_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&omap_96m_fck>;
+               reg = <0x0e00>;
+               ti,bit-shift = <2>;
+       };
+
+       dss2_alwon_fck: dss2_alwon_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_ck>;
+               reg = <0x0e00>;
+               ti,bit-shift = <1>;
+       };
+
+       dummy_ck: dummy_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       gpt1_gate_fck: gpt1_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <0>;
+               reg = <0x0c00>;
+       };
+
+       gpt1_mux_fck: gpt1_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               reg = <0x0c40>;
+       };
+
+       gpt1_fck: gpt1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt1_gate_fck>, <&gpt1_mux_fck>;
+       };
+
+       aes2_ick: aes2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               ti,bit-shift = <28>;
+               reg = <0x0a10>;
+       };
+
+       wkup_32k_fck: wkup_32k_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_32k_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       gpio1_dbck: gpio1_dbck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&wkup_32k_fck>;
+               reg = <0x0c00>;
+               ti,bit-shift = <3>;
+       };
+
+       sha12_ick: sha12_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&core_l4_ick>;
+               reg = <0x0a10>;
+               ti,bit-shift = <27>;
+       };
+
+       wdt2_fck: wdt2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&wkup_32k_fck>;
+               reg = <0x0c00>;
+               ti,bit-shift = <5>;
+       };
+
+       wdt2_ick: wdt2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&wkup_l4_ick>;
+               reg = <0x0c10>;
+               ti,bit-shift = <5>;
+       };
+
+       wdt1_ick: wdt1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&wkup_l4_ick>;
+               reg = <0x0c10>;
+               ti,bit-shift = <4>;
+       };
+
+       gpio1_ick: gpio1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&wkup_l4_ick>;
+               reg = <0x0c10>;
+               ti,bit-shift = <3>;
+       };
+
+       omap_32ksync_ick: omap_32ksync_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&wkup_l4_ick>;
+               reg = <0x0c10>;
+               ti,bit-shift = <2>;
+       };
+
+       gpt12_ick: gpt12_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&wkup_l4_ick>;
+               reg = <0x0c10>;
+               ti,bit-shift = <1>;
+       };
+
+       gpt1_ick: gpt1_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&wkup_l4_ick>;
+               reg = <0x0c10>;
+               ti,bit-shift = <0>;
+       };
+
+       per_96m_fck: per_96m_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_96m_alwon_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       per_48m_fck: per_48m_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_48m_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       uart3_fck: uart3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&per_48m_fck>;
+               reg = <0x1000>;
+               ti,bit-shift = <11>;
+       };
+
+       gpt2_gate_fck: gpt2_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <3>;
+               reg = <0x1000>;
+       };
+
+       gpt2_mux_fck: gpt2_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               reg = <0x1040>;
+       };
+
+       gpt2_fck: gpt2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt2_gate_fck>, <&gpt2_mux_fck>;
+       };
+
+       gpt3_gate_fck: gpt3_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <4>;
+               reg = <0x1000>;
+       };
+
+       gpt3_mux_fck: gpt3_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x1040>;
+       };
+
+       gpt3_fck: gpt3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt3_gate_fck>, <&gpt3_mux_fck>;
+       };
+
+       gpt4_gate_fck: gpt4_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <5>;
+               reg = <0x1000>;
+       };
+
+       gpt4_mux_fck: gpt4_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x1040>;
+       };
+
+       gpt4_fck: gpt4_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt4_gate_fck>, <&gpt4_mux_fck>;
+       };
+
+       gpt5_gate_fck: gpt5_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <6>;
+               reg = <0x1000>;
+       };
+
+       gpt5_mux_fck: gpt5_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               ti,bit-shift = <3>;
+               reg = <0x1040>;
+       };
+
+       gpt5_fck: gpt5_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt5_gate_fck>, <&gpt5_mux_fck>;
+       };
+
+       gpt6_gate_fck: gpt6_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <7>;
+               reg = <0x1000>;
+       };
+
+       gpt6_mux_fck: gpt6_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               ti,bit-shift = <4>;
+               reg = <0x1040>;
+       };
+
+       gpt6_fck: gpt6_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt6_gate_fck>, <&gpt6_mux_fck>;
+       };
+
+       gpt7_gate_fck: gpt7_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1000>;
+       };
+
+       gpt7_mux_fck: gpt7_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               ti,bit-shift = <5>;
+               reg = <0x1040>;
+       };
+
+       gpt7_fck: gpt7_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt7_gate_fck>, <&gpt7_mux_fck>;
+       };
+
+       gpt8_gate_fck: gpt8_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <9>;
+               reg = <0x1000>;
+       };
+
+       gpt8_mux_fck: gpt8_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               ti,bit-shift = <6>;
+               reg = <0x1040>;
+       };
+
+       gpt8_fck: gpt8_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt8_gate_fck>, <&gpt8_mux_fck>;
+       };
+
+       gpt9_gate_fck: gpt9_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&sys_ck>;
+               ti,bit-shift = <10>;
+               reg = <0x1000>;
+       };
+
+       gpt9_mux_fck: gpt9_mux_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&omap_32k_fck>, <&sys_ck>;
+               ti,bit-shift = <7>;
+               reg = <0x1040>;
+       };
+
+       gpt9_fck: gpt9_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&gpt9_gate_fck>, <&gpt9_mux_fck>;
+       };
+
+       per_32k_alwon_fck: per_32k_alwon_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&omap_32k_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       gpio6_dbck: gpio6_dbck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&per_32k_alwon_fck>;
+               reg = <0x1000>;
+               ti,bit-shift = <17>;
+       };
+
+       gpio5_dbck: gpio5_dbck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&per_32k_alwon_fck>;
+               reg = <0x1000>;
+               ti,bit-shift = <16>;
+       };
+
+       gpio4_dbck: gpio4_dbck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&per_32k_alwon_fck>;
+               reg = <0x1000>;
+               ti,bit-shift = <15>;
+       };
+
+       gpio3_dbck: gpio3_dbck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&per_32k_alwon_fck>;
+               reg = <0x1000>;
+               ti,bit-shift = <14>;
+       };
+
+       gpio2_dbck: gpio2_dbck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&per_32k_alwon_fck>;
+               reg = <0x1000>;
+               ti,bit-shift = <13>;
+       };
+
+       wdt3_fck: wdt3_fck {
+               #clock-cells = <0>;
+               compatible = "ti,wait-gate-clock";
+               clocks = <&per_32k_alwon_fck>;
+               reg = <0x1000>;
+               ti,bit-shift = <12>;
+       };
+
+       per_l4_ick: per_l4_ick {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l4_ick>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       gpio6_ick: gpio6_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <17>;
+       };
+
+       gpio5_ick: gpio5_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <16>;
+       };
+
+       gpio4_ick: gpio4_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <15>;
+       };
+
+       gpio3_ick: gpio3_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <14>;
+       };
+
+       gpio2_ick: gpio2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <13>;
+       };
+
+       wdt3_ick: wdt3_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <12>;
+       };
+
+       uart3_ick: uart3_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <11>;
+       };
+
+       uart4_ick: uart4_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <18>;
+       };
+
+       gpt9_ick: gpt9_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <10>;
+       };
+
+       gpt8_ick: gpt8_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <9>;
+       };
+
+       gpt7_ick: gpt7_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <8>;
+       };
+
+       gpt6_ick: gpt6_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <7>;
+       };
+
+       gpt5_ick: gpt5_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <6>;
+       };
+
+       gpt4_ick: gpt4_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <5>;
+       };
+
+       gpt3_ick: gpt3_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <4>;
+       };
+
+       gpt2_ick: gpt2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <3>;
+       };
+
+       mcbsp2_ick: mcbsp2_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <0>;
+       };
+
+       mcbsp3_ick: mcbsp3_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <1>;
+       };
+
+       mcbsp4_ick: mcbsp4_ick {
+               #clock-cells = <0>;
+               compatible = "ti,omap3-interface-clock";
+               clocks = <&per_l4_ick>;
+               reg = <0x1010>;
+               ti,bit-shift = <2>;
+       };
+
+       mcbsp2_gate_fck: mcbsp2_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&mcbsp_clks>;
+               ti,bit-shift = <0>;
+               reg = <0x1000>;
+       };
+
+       mcbsp3_gate_fck: mcbsp3_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&mcbsp_clks>;
+               ti,bit-shift = <1>;
+               reg = <0x1000>;
+       };
+
+       mcbsp4_gate_fck: mcbsp4_gate_fck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-gate-clock";
+               clocks = <&mcbsp_clks>;
+               ti,bit-shift = <2>;
+               reg = <0x1000>;
+       };
+
+       emu_src_mux_ck: emu_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_ck>, <&emu_core_alwon_ck>, <&emu_per_alwon_ck>, <&emu_mpu_alwon_ck>;
+               reg = <0x1140>;
+       };
+
+       emu_src_ck: emu_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,clkdm-gate-clock";
+               clocks = <&emu_src_mux_ck>;
+       };
+
+       pclk_fck: pclk_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&emu_src_ck>;
+               ti,bit-shift = <8>;
+               ti,max-div = <7>;
+               reg = <0x1140>;
+               ti,index-starts-at-one;
+       };
+
+       pclkx2_fck: pclkx2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&emu_src_ck>;
+               ti,bit-shift = <6>;
+               ti,max-div = <3>;
+               reg = <0x1140>;
+               ti,index-starts-at-one;
+       };
+
+       atclk_fck: atclk_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&emu_src_ck>;
+               ti,bit-shift = <4>;
+               ti,max-div = <3>;
+               reg = <0x1140>;
+               ti,index-starts-at-one;
+       };
+
+       traceclk_src_fck: traceclk_src_fck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_ck>, <&emu_core_alwon_ck>, <&emu_per_alwon_ck>, <&emu_mpu_alwon_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x1140>;
+       };
+
+       traceclk_fck: traceclk_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&traceclk_src_fck>;
+               ti,bit-shift = <11>;
+               ti,max-div = <7>;
+               reg = <0x1140>;
+               ti,index-starts-at-one;
+       };
+
+       secure_32k_fck: secure_32k_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       gpt12_fck: gpt12_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&secure_32k_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       wdt1_fck: wdt1_fck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&secure_32k_fck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+};
+
+&cm_clockdomains {
+       core_l3_clkdm: core_l3_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&sdrc_ick>;
+       };
+
+       dpll3_clkdm: dpll3_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dpll3_ck>;
+       };
+
+       dpll1_clkdm: dpll1_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dpll1_ck>;
+       };
+
+       per_clkdm: per_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&uart3_fck>, <&gpio6_dbck>, <&gpio5_dbck>,
+                        <&gpio4_dbck>, <&gpio3_dbck>, <&gpio2_dbck>,
+                        <&wdt3_fck>, <&gpio6_ick>, <&gpio5_ick>, <&gpio4_ick>,
+                        <&gpio3_ick>, <&gpio2_ick>, <&wdt3_ick>, <&uart3_ick>,
+                        <&uart4_ick>, <&gpt9_ick>, <&gpt8_ick>, <&gpt7_ick>,
+                        <&gpt6_ick>, <&gpt5_ick>, <&gpt4_ick>, <&gpt3_ick>,
+                        <&gpt2_ick>, <&mcbsp2_ick>, <&mcbsp3_ick>,
+                        <&mcbsp4_ick>;
+       };
+
+       emu_clkdm: emu_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&emu_src_ck>;
+       };
+
+       dpll4_clkdm: dpll4_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dpll4_ck>;
+       };
+
+       wkup_clkdm: wkup_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&gpio1_dbck>, <&wdt2_fck>, <&wdt2_ick>, <&wdt1_ick>,
+                        <&gpio1_ick>, <&omap_32ksync_ick>, <&gpt12_ick>,
+                        <&gpt1_ick>;
+       };
+
+       dss_clkdm: dss_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dss_tv_fck>, <&dss_96m_fck>, <&dss2_alwon_fck>;
+       };
+
+       core_l4_clkdm: core_l4_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&mmchs2_fck>, <&mmchs1_fck>, <&i2c3_fck>, <&i2c2_fck>,
+                        <&i2c1_fck>, <&mcspi4_fck>, <&mcspi3_fck>,
+                        <&mcspi2_fck>, <&mcspi1_fck>, <&uart2_fck>,
+                        <&uart1_fck>, <&hdq_fck>, <&mmchs2_ick>, <&mmchs1_ick>,
+                        <&hdq_ick>, <&mcspi4_ick>, <&mcspi3_ick>,
+                        <&mcspi2_ick>, <&mcspi1_ick>, <&i2c3_ick>, <&i2c2_ick>,
+                        <&i2c1_ick>, <&uart2_ick>, <&uart1_ick>, <&gpt11_ick>,
+                        <&gpt10_ick>, <&mcbsp5_ick>, <&mcbsp1_ick>,
+                        <&omapctrl_ick>, <&aes2_ick>, <&sha12_ick>;
+       };
+};
index a1e05853afcd583c15da3ad259c8f715992b2d7f..d3f8a6e8ca205ef1585c279c1ce50dc8703fa6b5 100644 (file)
                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
 
+               cm1: cm1@4a004000 {
+                       compatible = "ti,omap4-cm1";
+                       reg = <0x4a004000 0x2000>;
+
+                       cm1_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       cm1_clockdomains: clockdomains {
+                       };
+               };
+
+               prm: prm@4a306000 {
+                       compatible = "ti,omap4-prm";
+                       reg = <0x4a306000 0x3000>;
+
+                       prm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       prm_clockdomains: clockdomains {
+                       };
+               };
+
+               cm2: cm2@4a008000 {
+                       compatible = "ti,omap4-cm2";
+                       reg = <0x4a008000 0x3000>;
+
+                       cm2_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       cm2_clockdomains: clockdomains {
+                       };
+               };
+
+               scrm: scrm@4a30a000 {
+                       compatible = "ti,omap4-scrm";
+                       reg = <0x4a30a000 0x2000>;
+
+                       scrm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       scrm_clockdomains: clockdomains {
+                       };
+               };
+
                counter32k: counter@4a304000 {
                        compatible = "ti,omap-counter32k";
                        reg = <0x4a304000 0x20>;
                };
        };
 };
+
+/include/ "omap44xx-clocks.dtsi"
diff --git a/arch/arm/boot/dts/omap443x-clocks.dtsi b/arch/arm/boot/dts/omap443x-clocks.dtsi
new file mode 100644 (file)
index 0000000..2bd2166
--- /dev/null
@@ -0,0 +1,18 @@
+/*
+ * Device Tree Source for OMAP4 clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&prm_clocks {
+       bandgap_fclk: bandgap_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1888>;
+       };
+};
index ab607a19a6137fe0c9f3fa779f6934131cc623f3..8c1cfad30d603714ce267820186dd8c6635ff923 100644 (file)
@@ -44,3 +44,5 @@
                };
        };
 };
+
+/include/ "omap443x-clocks.dtsi"
index 11566bed00358485634f1def11ffb980a2a48981..6b32f520741a9cb1398bf586a614a9358f04d3e5 100644 (file)
@@ -52,3 +52,5 @@
                };
        };
 };
+
+/include/ "omap446x-clocks.dtsi"
diff --git a/arch/arm/boot/dts/omap446x-clocks.dtsi b/arch/arm/boot/dts/omap446x-clocks.dtsi
new file mode 100644 (file)
index 0000000..be033e9
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Device Tree Source for OMAP4 clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&prm_clocks {
+       div_ts_ck: div_ts_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&l4_wkup_clk_mux_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1888>;
+               ti,dividers = <8>, <16>, <32>;
+       };
+
+       bandgap_ts_fclk: bandgap_ts_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&div_ts_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1888>;
+       };
+};
diff --git a/arch/arm/boot/dts/omap44xx-clocks.dtsi b/arch/arm/boot/dts/omap44xx-clocks.dtsi
new file mode 100644 (file)
index 0000000..c821ff5
--- /dev/null
@@ -0,0 +1,1651 @@
+/*
+ * Device Tree Source for OMAP4 clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&cm1_clocks {
+       extalt_clkin_ck: extalt_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <59000000>;
+       };
+
+       pad_clks_src_ck: pad_clks_src_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       pad_clks_ck: pad_clks_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&pad_clks_src_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0108>;
+       };
+
+       pad_slimbus_core_clks_ck: pad_slimbus_core_clks_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       secure_32k_clk_src_ck: secure_32k_clk_src_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       slimbus_src_clk: slimbus_src_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       slimbus_clk: slimbus_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&slimbus_src_clk>;
+               ti,bit-shift = <10>;
+               reg = <0x0108>;
+       };
+
+       sys_32k_ck: sys_32k_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       virt_12000000_ck: virt_12000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       virt_13000000_ck: virt_13000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <13000000>;
+       };
+
+       virt_16800000_ck: virt_16800000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <16800000>;
+       };
+
+       virt_19200000_ck: virt_19200000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <19200000>;
+       };
+
+       virt_26000000_ck: virt_26000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <26000000>;
+       };
+
+       virt_27000000_ck: virt_27000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <27000000>;
+       };
+
+       virt_38400000_ck: virt_38400000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <38400000>;
+       };
+
+       tie_low_clock_ck: tie_low_clock_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+
+       utmi_phy_clkout_ck: utmi_phy_clkout_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <60000000>;
+       };
+
+       xclk60mhsp1_ck: xclk60mhsp1_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <60000000>;
+       };
+
+       xclk60mhsp2_ck: xclk60mhsp2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <60000000>;
+       };
+
+       xclk60motg_ck: xclk60motg_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <60000000>;
+       };
+
+       dpll_abe_ck: dpll_abe_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-m4xen-clock";
+               clocks = <&abe_dpll_refclk_mux_ck>, <&abe_dpll_bypass_clk_mux_ck>;
+               reg = <0x01e0>, <0x01e4>, <0x01ec>, <0x01e8>;
+       };
+
+       dpll_abe_x2_ck: dpll_abe_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_abe_ck>;
+               reg = <0x01f0>;
+       };
+
+       dpll_abe_m2x2_ck: dpll_abe_m2x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01f0>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       abe_24m_fclk: abe_24m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <8>;
+       };
+
+       abe_clk: abe_clk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_m2x2_ck>;
+               ti,max-div = <4>;
+               reg = <0x0108>;
+               ti,index-power-of-two;
+       };
+
+       aess_fclk: aess_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&abe_clk>;
+               ti,bit-shift = <24>;
+               ti,max-div = <2>;
+               reg = <0x0528>;
+       };
+
+       dpll_abe_m3x2_ck: dpll_abe_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01f4>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       core_hsd_byp_clk_mux_ck: core_hsd_byp_clk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&dpll_abe_m3x2_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x012c>;
+       };
+
+       dpll_core_ck: dpll_core_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-core-clock";
+               clocks = <&sys_clkin_ck>, <&core_hsd_byp_clk_mux_ck>;
+               reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>;
+       };
+
+       dpll_core_x2_ck: dpll_core_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_core_ck>;
+       };
+
+       dpll_core_m6x2_ck: dpll_core_m6x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0140>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_m2_ck: dpll_core_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0130>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       ddrphy_ck: ddrphy_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       dpll_core_m5x2_ck: dpll_core_m5x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x013c>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       div_core_ck: div_core_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_m5x2_ck>;
+               reg = <0x0100>;
+               ti,max-div = <2>;
+       };
+
+       div_iva_hs_clk: div_iva_hs_clk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_m5x2_ck>;
+               ti,max-div = <4>;
+               reg = <0x01dc>;
+               ti,index-power-of-two;
+       };
+
+       div_mpu_hs_clk: div_mpu_hs_clk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_m5x2_ck>;
+               ti,max-div = <4>;
+               reg = <0x019c>;
+               ti,index-power-of-two;
+       };
+
+       dpll_core_m4x2_ck: dpll_core_m4x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0138>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dll_clk_div_ck: dll_clk_div_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_m4x2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       dpll_abe_m2_ck: dpll_abe_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_ck>;
+               ti,max-div = <31>;
+               reg = <0x01f0>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_core_m3x2_gate_ck: dpll_core_m3x2_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0134>;
+       };
+
+       dpll_core_m3x2_div_ck: dpll_core_m3x2_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               reg = <0x0134>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_core_m3x2_ck: dpll_core_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&dpll_core_m3x2_gate_ck>, <&dpll_core_m3x2_div_ck>;
+       };
+
+       dpll_core_m7x2_ck: dpll_core_m7x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0144>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       iva_hsd_byp_clk_mux_ck: iva_hsd_byp_clk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&div_iva_hs_clk>;
+               ti,bit-shift = <23>;
+               reg = <0x01ac>;
+       };
+
+       dpll_iva_ck: dpll_iva_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin_ck>, <&iva_hsd_byp_clk_mux_ck>;
+               reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>;
+       };
+
+       dpll_iva_x2_ck: dpll_iva_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_iva_ck>;
+       };
+
+       dpll_iva_m4x2_ck: dpll_iva_m4x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_iva_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01b8>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_iva_m5x2_ck: dpll_iva_m5x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_iva_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01bc>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_mpu_ck: dpll_mpu_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin_ck>, <&div_mpu_hs_clk>;
+               reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>;
+       };
+
+       dpll_mpu_m2_ck: dpll_mpu_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_mpu_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0170>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       per_hs_clk_div_ck: per_hs_clk_div_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m3x2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       usb_hs_clk_div_ck: usb_hs_clk_div_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m3x2_ck>;
+               clock-mult = <1>;
+               clock-div = <3>;
+       };
+
+       l3_div_ck: l3_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&div_core_ck>;
+               ti,bit-shift = <4>;
+               ti,max-div = <2>;
+               reg = <0x0100>;
+       };
+
+       l4_div_ck: l4_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&l3_div_ck>;
+               ti,bit-shift = <8>;
+               ti,max-div = <2>;
+               reg = <0x0100>;
+       };
+
+       lp_clk_div_ck: lp_clk_div_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <16>;
+       };
+
+       mpu_periphclk: mpu_periphclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_mpu_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       ocp_abe_iclk: ocp_abe_iclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&aess_fclk>;
+               ti,bit-shift = <24>;
+               reg = <0x0528>;
+               ti,dividers = <2>, <1>;
+       };
+
+       per_abe_24m_fclk: per_abe_24m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       dmic_sync_mux_ck: dmic_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>;
+               ti,bit-shift = <25>;
+               reg = <0x0538>;
+       };
+
+       func_dmic_abe_gfclk: func_dmic_abe_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dmic_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0538>;
+       };
+
+       mcasp_sync_mux_ck: mcasp_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>;
+               ti,bit-shift = <25>;
+               reg = <0x0540>;
+       };
+
+       func_mcasp_abe_gfclk: func_mcasp_abe_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&mcasp_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0540>;
+       };
+
+       mcbsp1_sync_mux_ck: mcbsp1_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>;
+               ti,bit-shift = <25>;
+               reg = <0x0548>;
+       };
+
+       func_mcbsp1_gfclk: func_mcbsp1_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&mcbsp1_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0548>;
+       };
+
+       mcbsp2_sync_mux_ck: mcbsp2_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>;
+               ti,bit-shift = <25>;
+               reg = <0x0550>;
+       };
+
+       func_mcbsp2_gfclk: func_mcbsp2_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&mcbsp2_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0550>;
+       };
+
+       mcbsp3_sync_mux_ck: mcbsp3_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&syc_clk_div_ck>, <&func_24m_clk>;
+               ti,bit-shift = <25>;
+               reg = <0x0558>;
+       };
+
+       func_mcbsp3_gfclk: func_mcbsp3_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&mcbsp3_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0558>;
+       };
+
+       slimbus1_fclk_1: slimbus1_fclk_1 {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_24m_clk>;
+               ti,bit-shift = <9>;
+               reg = <0x0560>;
+       };
+
+       slimbus1_fclk_0: slimbus1_fclk_0 {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&abe_24m_fclk>;
+               ti,bit-shift = <8>;
+               reg = <0x0560>;
+       };
+
+       slimbus1_fclk_2: slimbus1_fclk_2 {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&pad_clks_ck>;
+               ti,bit-shift = <10>;
+               reg = <0x0560>;
+       };
+
+       slimbus1_slimbus_clk: slimbus1_slimbus_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&slimbus_clk>;
+               ti,bit-shift = <11>;
+               reg = <0x0560>;
+       };
+
+       timer5_sync_mux: timer5_sync_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&syc_clk_div_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0568>;
+       };
+
+       timer6_sync_mux: timer6_sync_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&syc_clk_div_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0570>;
+       };
+
+       timer7_sync_mux: timer7_sync_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&syc_clk_div_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0578>;
+       };
+
+       timer8_sync_mux: timer8_sync_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&syc_clk_div_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0580>;
+       };
+
+       dummy_ck: dummy_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+};
+&prm_clocks {
+       sys_clkin_ck: sys_clkin_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>;
+               reg = <0x0110>;
+               ti,index-starts-at-one;
+       };
+
+       abe_dpll_bypass_clk_mux_ck: abe_dpll_bypass_clk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0108>;
+       };
+
+       abe_dpll_refclk_mux_ck: abe_dpll_refclk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+               reg = <0x010c>;
+       };
+
+       dbgclk_mux_ck: dbgclk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l4_wkup_clk_mux_ck: l4_wkup_clk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&lp_clk_div_ck>;
+               reg = <0x0108>;
+       };
+
+       syc_clk_div_ck: syc_clk_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&sys_clkin_ck>;
+               reg = <0x0100>;
+               ti,max-div = <2>;
+       };
+
+       gpio1_dbclk: gpio1_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1838>;
+       };
+
+       dmt1_clk_mux: dmt1_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1840>;
+       };
+
+       usim_ck: usim_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_m4x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1858>;
+               ti,dividers = <14>, <18>;
+       };
+
+       usim_fclk: usim_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&usim_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1858>;
+       };
+
+       pmd_stm_clock_mux_ck: pmd_stm_clock_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&dpll_core_m6x2_ck>, <&tie_low_clock_ck>;
+               ti,bit-shift = <20>;
+               reg = <0x1a20>;
+       };
+
+       pmd_trace_clk_mux_ck: pmd_trace_clk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&dpll_core_m6x2_ck>, <&tie_low_clock_ck>;
+               ti,bit-shift = <22>;
+               reg = <0x1a20>;
+       };
+
+       stm_clk_div_ck: stm_clk_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&pmd_stm_clock_mux_ck>;
+               ti,bit-shift = <27>;
+               ti,max-div = <64>;
+               reg = <0x1a20>;
+               ti,index-power-of-two;
+       };
+
+       trace_clk_div_div_ck: trace_clk_div_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&pmd_trace_clk_mux_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1a20>;
+               ti,dividers = <0>, <1>, <2>, <0>, <4>;
+       };
+
+       trace_clk_div_ck: trace_clk_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,clkdm-gate-clock";
+               clocks = <&trace_clk_div_div_ck>;
+       };
+};
+
+&prm_clockdomains {
+       emu_sys_clkdm: emu_sys_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&trace_clk_div_ck>;
+       };
+};
+
+&cm2_clocks {
+       per_hsd_byp_clk_mux_ck: per_hsd_byp_clk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&per_hs_clk_div_ck>;
+               ti,bit-shift = <23>;
+               reg = <0x014c>;
+       };
+
+       dpll_per_ck: dpll_per_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin_ck>, <&per_hsd_byp_clk_mux_ck>;
+               reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>;
+       };
+
+       dpll_per_m2_ck: dpll_per_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_ck>;
+               ti,max-div = <31>;
+               reg = <0x0150>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_per_x2_ck: dpll_per_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_per_ck>;
+               reg = <0x0150>;
+       };
+
+       dpll_per_m2x2_ck: dpll_per_m2x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0150>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_m3x2_gate_ck: dpll_per_m3x2_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0154>;
+       };
+
+       dpll_per_m3x2_div_ck: dpll_per_m3x2_div_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <31>;
+               reg = <0x0154>;
+               ti,index-starts-at-one;
+       };
+
+       dpll_per_m3x2_ck: dpll_per_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&dpll_per_m3x2_gate_ck>, <&dpll_per_m3x2_div_ck>;
+       };
+
+       dpll_per_m4x2_ck: dpll_per_m4x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0158>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_m5x2_ck: dpll_per_m5x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x015c>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_m6x2_ck: dpll_per_m6x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0160>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_m7x2_ck: dpll_per_m7x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0164>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_usb_ck: dpll_usb_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-j-type-clock";
+               clocks = <&sys_clkin_ck>, <&usb_hs_clk_div_ck>;
+               reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>;
+       };
+
+       dpll_usb_clkdcoldo_ck: dpll_usb_clkdcoldo_ck {
+               #clock-cells = <0>;
+               compatible = "ti,fixed-factor-clock";
+               clocks = <&dpll_usb_ck>;
+               ti,clock-div = <1>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01b4>;
+               ti,clock-mult = <1>;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_usb_m2_ck: dpll_usb_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_usb_ck>;
+               ti,max-div = <127>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0190>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       ducati_clk_mux_ck: ducati_clk_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&div_core_ck>, <&dpll_per_m6x2_ck>;
+               reg = <0x0100>;
+       };
+
+       func_12m_fclk: func_12m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <16>;
+       };
+
+       func_24m_clk: func_24m_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       func_24mc_fclk: func_24mc_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <8>;
+       };
+
+       func_48m_fclk: func_48m_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               reg = <0x0108>;
+               ti,dividers = <4>, <8>;
+       };
+
+       func_48mc_fclk: func_48mc_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       func_64m_fclk: func_64m_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_m4x2_ck>;
+               reg = <0x0108>;
+               ti,dividers = <2>, <4>;
+       };
+
+       func_96m_fclk: func_96m_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               reg = <0x0108>;
+               ti,dividers = <2>, <4>;
+       };
+
+       init_60m_fclk: init_60m_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_usb_m2_ck>;
+               reg = <0x0104>;
+               ti,dividers = <1>, <8>;
+       };
+
+       per_abe_nc_fclk: per_abe_nc_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_m2_ck>;
+               reg = <0x0108>;
+               ti,max-div = <2>;
+       };
+
+       aes1_fck: aes1_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3_div_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x15a0>;
+       };
+
+       aes2_fck: aes2_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3_div_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x15a8>;
+       };
+
+       dss_sys_clk: dss_sys_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&syc_clk_div_ck>;
+               ti,bit-shift = <10>;
+               reg = <0x1120>;
+       };
+
+       dss_tv_clk: dss_tv_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&extalt_clkin_ck>;
+               ti,bit-shift = <11>;
+               reg = <0x1120>;
+       };
+
+       dss_dss_clk: dss_dss_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_per_m5x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1120>;
+               ti,set-rate-parent;
+       };
+
+       dss_48mhz_clk: dss_48mhz_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_48mc_fclk>;
+               ti,bit-shift = <9>;
+               reg = <0x1120>;
+       };
+
+       dss_fck: dss_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3_div_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x1120>;
+       };
+
+       fdif_fck: fdif_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_m4x2_ck>;
+               ti,bit-shift = <24>;
+               ti,max-div = <4>;
+               reg = <0x1028>;
+               ti,index-power-of-two;
+       };
+
+       gpio2_dbclk: gpio2_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1460>;
+       };
+
+       gpio3_dbclk: gpio3_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1468>;
+       };
+
+       gpio4_dbclk: gpio4_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1470>;
+       };
+
+       gpio5_dbclk: gpio5_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1478>;
+       };
+
+       gpio6_dbclk: gpio6_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1480>;
+       };
+
+       sgx_clk_mux: sgx_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_core_m7x2_ck>, <&dpll_per_m7x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1220>;
+       };
+
+       hsi_fck: hsi_fck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               ti,max-div = <4>;
+               reg = <0x1338>;
+               ti,index-power-of-two;
+       };
+
+       iss_ctrlclk: iss_ctrlclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_96m_fclk>;
+               ti,bit-shift = <8>;
+               reg = <0x1020>;
+       };
+
+       mcbsp4_sync_mux_ck: mcbsp4_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_96m_fclk>, <&per_abe_nc_fclk>;
+               ti,bit-shift = <25>;
+               reg = <0x14e0>;
+       };
+
+       per_mcbsp4_gfclk: per_mcbsp4_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&mcbsp4_sync_mux_ck>, <&pad_clks_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x14e0>;
+       };
+
+       hsmmc1_fclk: hsmmc1_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_64m_fclk>, <&func_96m_fclk>;
+               ti,bit-shift = <24>;
+               reg = <0x1328>;
+       };
+
+       hsmmc2_fclk: hsmmc2_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_64m_fclk>, <&func_96m_fclk>;
+               ti,bit-shift = <24>;
+               reg = <0x1330>;
+       };
+
+       ocp2scp_usb_phy_phy_48m: ocp2scp_usb_phy_phy_48m {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_48m_fclk>;
+               ti,bit-shift = <8>;
+               reg = <0x13e0>;
+       };
+
+       sha2md5_fck: sha2md5_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3_div_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x15c8>;
+       };
+
+       slimbus2_fclk_1: slimbus2_fclk_1 {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&per_abe_24m_fclk>;
+               ti,bit-shift = <9>;
+               reg = <0x1538>;
+       };
+
+       slimbus2_fclk_0: slimbus2_fclk_0 {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_24mc_fclk>;
+               ti,bit-shift = <8>;
+               reg = <0x1538>;
+       };
+
+       slimbus2_slimbus_clk: slimbus2_slimbus_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&pad_slimbus_core_clks_ck>;
+               ti,bit-shift = <10>;
+               reg = <0x1538>;
+       };
+
+       smartreflex_core_fck: smartreflex_core_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l4_wkup_clk_mux_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0638>;
+       };
+
+       smartreflex_iva_fck: smartreflex_iva_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l4_wkup_clk_mux_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0630>;
+       };
+
+       smartreflex_mpu_fck: smartreflex_mpu_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l4_wkup_clk_mux_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0628>;
+       };
+
+       cm2_dm10_mux: cm2_dm10_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1428>;
+       };
+
+       cm2_dm11_mux: cm2_dm11_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1430>;
+       };
+
+       cm2_dm2_mux: cm2_dm2_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1438>;
+       };
+
+       cm2_dm3_mux: cm2_dm3_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1440>;
+       };
+
+       cm2_dm4_mux: cm2_dm4_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1448>;
+       };
+
+       cm2_dm9_mux: cm2_dm9_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin_ck>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1450>;
+       };
+
+       usb_host_fs_fck: usb_host_fs_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_48mc_fclk>;
+               ti,bit-shift = <1>;
+               reg = <0x13d0>;
+       };
+
+       utmi_p1_gfclk: utmi_p1_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&init_60m_fclk>, <&xclk60mhsp1_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1358>;
+       };
+
+       usb_host_hs_utmi_p1_clk: usb_host_hs_utmi_p1_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&utmi_p1_gfclk>;
+               ti,bit-shift = <8>;
+               reg = <0x1358>;
+       };
+
+       utmi_p2_gfclk: utmi_p2_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&init_60m_fclk>, <&xclk60mhsp2_ck>;
+               ti,bit-shift = <25>;
+               reg = <0x1358>;
+       };
+
+       usb_host_hs_utmi_p2_clk: usb_host_hs_utmi_p2_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&utmi_p2_gfclk>;
+               ti,bit-shift = <9>;
+               reg = <0x1358>;
+       };
+
+       usb_host_hs_utmi_p3_clk: usb_host_hs_utmi_p3_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&init_60m_fclk>;
+               ti,bit-shift = <10>;
+               reg = <0x1358>;
+       };
+
+       usb_host_hs_hsic480m_p1_clk: usb_host_hs_hsic480m_p1_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_usb_m2_ck>;
+               ti,bit-shift = <13>;
+               reg = <0x1358>;
+       };
+
+       usb_host_hs_hsic60m_p1_clk: usb_host_hs_hsic60m_p1_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&init_60m_fclk>;
+               ti,bit-shift = <11>;
+               reg = <0x1358>;
+       };
+
+       usb_host_hs_hsic60m_p2_clk: usb_host_hs_hsic60m_p2_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&init_60m_fclk>;
+               ti,bit-shift = <12>;
+               reg = <0x1358>;
+       };
+
+       usb_host_hs_hsic480m_p2_clk: usb_host_hs_hsic480m_p2_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_usb_m2_ck>;
+               ti,bit-shift = <14>;
+               reg = <0x1358>;
+       };
+
+       usb_host_hs_func48mclk: usb_host_hs_func48mclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_48mc_fclk>;
+               ti,bit-shift = <15>;
+               reg = <0x1358>;
+       };
+
+       usb_host_hs_fck: usb_host_hs_fck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&init_60m_fclk>;
+               ti,bit-shift = <1>;
+               reg = <0x1358>;
+       };
+
+       otg_60m_gfclk: otg_60m_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&utmi_phy_clkout_ck>, <&xclk60motg_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1360>;
+       };
+
+       usb_otg_hs_xclk: usb_otg_hs_xclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&otg_60m_gfclk>;
+               ti,bit-shift = <8>;
+               reg = <0x1360>;
+       };
+
+       usb_otg_hs_ick: usb_otg_hs_ick {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3_div_ck>;
+               ti,bit-shift = <0>;
+               reg = <0x1360>;
+       };
+
+       usb_phy_cm_clk32k: usb_phy_cm_clk32k {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0640>;
+       };
+
+       usb_tll_hs_usb_ch2_clk: usb_tll_hs_usb_ch2_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&init_60m_fclk>;
+               ti,bit-shift = <10>;
+               reg = <0x1368>;
+       };
+
+       usb_tll_hs_usb_ch0_clk: usb_tll_hs_usb_ch0_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&init_60m_fclk>;
+               ti,bit-shift = <8>;
+               reg = <0x1368>;
+       };
+
+       usb_tll_hs_usb_ch1_clk: usb_tll_hs_usb_ch1_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&init_60m_fclk>;
+               ti,bit-shift = <9>;
+               reg = <0x1368>;
+       };
+
+       usb_tll_hs_ick: usb_tll_hs_ick {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l4_div_ck>;
+               ti,bit-shift = <0>;
+               reg = <0x1368>;
+       };
+};
+
+&cm2_clockdomains {
+       l3_init_clkdm: l3_init_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dpll_usb_ck>, <&usb_host_fs_fck>;
+       };
+};
+
+&scrm_clocks {
+       auxclk0_src_gate_ck: auxclk0_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0310>;
+       };
+
+       auxclk0_src_mux_ck: auxclk0_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0310>;
+       };
+
+       auxclk0_src_ck: auxclk0_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk0_src_gate_ck>, <&auxclk0_src_mux_ck>;
+       };
+
+       auxclk0_ck: auxclk0_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk0_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x0310>;
+       };
+
+       auxclk1_src_gate_ck: auxclk1_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0314>;
+       };
+
+       auxclk1_src_mux_ck: auxclk1_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0314>;
+       };
+
+       auxclk1_src_ck: auxclk1_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk1_src_gate_ck>, <&auxclk1_src_mux_ck>;
+       };
+
+       auxclk1_ck: auxclk1_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk1_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x0314>;
+       };
+
+       auxclk2_src_gate_ck: auxclk2_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0318>;
+       };
+
+       auxclk2_src_mux_ck: auxclk2_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0318>;
+       };
+
+       auxclk2_src_ck: auxclk2_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk2_src_gate_ck>, <&auxclk2_src_mux_ck>;
+       };
+
+       auxclk2_ck: auxclk2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk2_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x0318>;
+       };
+
+       auxclk3_src_gate_ck: auxclk3_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x031c>;
+       };
+
+       auxclk3_src_mux_ck: auxclk3_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x031c>;
+       };
+
+       auxclk3_src_ck: auxclk3_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk3_src_gate_ck>, <&auxclk3_src_mux_ck>;
+       };
+
+       auxclk3_ck: auxclk3_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk3_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x031c>;
+       };
+
+       auxclk4_src_gate_ck: auxclk4_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0320>;
+       };
+
+       auxclk4_src_mux_ck: auxclk4_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0320>;
+       };
+
+       auxclk4_src_ck: auxclk4_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk4_src_gate_ck>, <&auxclk4_src_mux_ck>;
+       };
+
+       auxclk4_ck: auxclk4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk4_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x0320>;
+       };
+
+       auxclk5_src_gate_ck: auxclk5_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0324>;
+       };
+
+       auxclk5_src_mux_ck: auxclk5_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin_ck>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0324>;
+       };
+
+       auxclk5_src_ck: auxclk5_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk5_src_gate_ck>, <&auxclk5_src_mux_ck>;
+       };
+
+       auxclk5_ck: auxclk5_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk5_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x0324>;
+       };
+
+       auxclkreq0_ck: auxclkreq0_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x0210>;
+       };
+
+       auxclkreq1_ck: auxclkreq1_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x0214>;
+       };
+
+       auxclkreq2_ck: auxclkreq2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x0218>;
+       };
+
+       auxclkreq3_ck: auxclkreq3_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x021c>;
+       };
+
+       auxclkreq4_ck: auxclkreq4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x0220>;
+       };
+
+       auxclkreq5_ck: auxclkreq5_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>, <&auxclk5_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x0224>;
+       };
+};
index ab9a21ae82f34a7a19a27529a8c8bfd04bef5610..a72813a9663eccd7075b185489cbda4694fd0003 100644 (file)
                interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>,
                             <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
 
+               prm: prm@4ae06000 {
+                       compatible = "ti,omap5-prm";
+                       reg = <0x4ae06000 0x3000>;
+
+                       prm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       prm_clockdomains: clockdomains {
+                       };
+               };
+
+               cm_core_aon: cm_core_aon@4a004000 {
+                       compatible = "ti,omap5-cm-core-aon";
+                       reg = <0x4a004000 0x2000>;
+
+                       cm_core_aon_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       cm_core_aon_clockdomains: clockdomains {
+                       };
+               };
+
+               scrm: scrm@4ae0a000 {
+                       compatible = "ti,omap5-scrm";
+                       reg = <0x4ae0a000 0x2000>;
+
+                       scrm_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       scrm_clockdomains: clockdomains {
+                       };
+               };
+
+               cm_core: cm_core@4a008000 {
+                       compatible = "ti,omap5-cm-core";
+                       reg = <0x4a008000 0x3000>;
+
+                       cm_core_clocks: clocks {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
+                       };
+
+                       cm_core_clockdomains: clockdomains {
+                       };
+               };
+
                counter32k: counter@4ae04000 {
                        compatible = "ti,omap-counter32k";
                        reg = <0x4ae04000 0x40>;
                };
        };
 };
+
+/include/ "omap54xx-clocks.dtsi"
diff --git a/arch/arm/boot/dts/omap54xx-clocks.dtsi b/arch/arm/boot/dts/omap54xx-clocks.dtsi
new file mode 100644 (file)
index 0000000..d487fda
--- /dev/null
@@ -0,0 +1,1399 @@
+/*
+ * Device Tree Source for OMAP5 clock data
+ *
+ * Copyright (C) 2013 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.
+ */
+&cm_core_aon_clocks {
+       pad_clks_src_ck: pad_clks_src_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       pad_clks_ck: pad_clks_ck {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&pad_clks_src_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0108>;
+       };
+
+       secure_32k_clk_src_ck: secure_32k_clk_src_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       slimbus_src_clk: slimbus_src_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       slimbus_clk: slimbus_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&slimbus_src_clk>;
+               ti,bit-shift = <10>;
+               reg = <0x0108>;
+       };
+
+       sys_32k_ck: sys_32k_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <32768>;
+       };
+
+       virt_12000000_ck: virt_12000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <12000000>;
+       };
+
+       virt_13000000_ck: virt_13000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <13000000>;
+       };
+
+       virt_16800000_ck: virt_16800000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <16800000>;
+       };
+
+       virt_19200000_ck: virt_19200000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <19200000>;
+       };
+
+       virt_26000000_ck: virt_26000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <26000000>;
+       };
+
+       virt_27000000_ck: virt_27000000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <27000000>;
+       };
+
+       virt_38400000_ck: virt_38400000_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <38400000>;
+       };
+
+       xclk60mhsp1_ck: xclk60mhsp1_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <60000000>;
+       };
+
+       xclk60mhsp2_ck: xclk60mhsp2_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <60000000>;
+       };
+
+       dpll_abe_ck: dpll_abe_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-m4xen-clock";
+               clocks = <&abe_dpll_clk_mux>, <&abe_dpll_bypass_clk_mux>;
+               reg = <0x01e0>, <0x01e4>, <0x01ec>, <0x01e8>;
+       };
+
+       dpll_abe_x2_ck: dpll_abe_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_abe_ck>;
+       };
+
+       dpll_abe_m2x2_ck: dpll_abe_m2x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01f0>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       abe_24m_fclk: abe_24m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <8>;
+       };
+
+       abe_clk: abe_clk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_m2x2_ck>;
+               ti,max-div = <4>;
+               reg = <0x0108>;
+               ti,index-power-of-two;
+       };
+
+       abe_iclk: abe_iclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&abe_clk>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       abe_lp_clk_div: abe_lp_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <16>;
+       };
+
+       dpll_abe_m3x2_ck: dpll_abe_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_abe_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01f4>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_ck: dpll_core_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-core-clock";
+               clocks = <&sys_clkin>, <&dpll_abe_m3x2_ck>;
+               reg = <0x0120>, <0x0124>, <0x012c>, <0x0128>;
+       };
+
+       dpll_core_x2_ck: dpll_core_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_core_ck>;
+       };
+
+       dpll_core_h21x2_ck: dpll_core_h21x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0150>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       c2c_fclk: c2c_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_h21x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       c2c_iclk: c2c_iclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&c2c_fclk>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       dpll_core_h11x2_ck: dpll_core_h11x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0138>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h12x2_ck: dpll_core_h12x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x013c>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h13x2_ck: dpll_core_h13x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0140>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h14x2_ck: dpll_core_h14x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0144>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h22x2_ck: dpll_core_h22x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0154>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h23x2_ck: dpll_core_h23x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0158>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_h24x2_ck: dpll_core_h24x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x015c>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_m2_ck: dpll_core_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0130>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_core_m3x2_ck: dpll_core_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_core_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0134>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       iva_dpll_hs_clk_div: iva_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_h12x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_iva_ck: dpll_iva_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin>, <&iva_dpll_hs_clk_div>;
+               reg = <0x01a0>, <0x01a4>, <0x01ac>, <0x01a8>;
+       };
+
+       dpll_iva_x2_ck: dpll_iva_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_iva_ck>;
+       };
+
+       dpll_iva_h11x2_ck: dpll_iva_h11x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_iva_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01b8>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_iva_h12x2_ck: dpll_iva_h12x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_iva_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01bc>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       mpu_dpll_hs_clk_div: mpu_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_h12x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_mpu_ck: dpll_mpu_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin>, <&mpu_dpll_hs_clk_div>;
+               reg = <0x0160>, <0x0164>, <0x016c>, <0x0168>;
+       };
+
+       dpll_mpu_m2_ck: dpll_mpu_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_mpu_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0170>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       per_dpll_hs_clk_div: per_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m3x2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       usb_dpll_hs_clk_div: usb_dpll_hs_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_abe_m3x2_ck>;
+               clock-mult = <1>;
+               clock-div = <3>;
+       };
+
+       l3_iclk_div: l3_iclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_core_h12x2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       gpu_l3_iclk: gpu_l3_iclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l3_iclk_div>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       l4_root_clk_div: l4_root_clk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&l3_iclk_div>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       slimbus1_slimbus_clk: slimbus1_slimbus_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&slimbus_clk>;
+               ti,bit-shift = <11>;
+               reg = <0x0560>;
+       };
+
+       aess_fclk: aess_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&abe_clk>;
+               ti,bit-shift = <24>;
+               ti,max-div = <2>;
+               reg = <0x0528>;
+       };
+
+       dmic_sync_mux_ck: dmic_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>;
+               ti,bit-shift = <26>;
+               reg = <0x0538>;
+       };
+
+       dmic_gfclk: dmic_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dmic_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0538>;
+       };
+
+       mcasp_sync_mux_ck: mcasp_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>;
+               ti,bit-shift = <26>;
+               reg = <0x0540>;
+       };
+
+       mcasp_gfclk: mcasp_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&mcasp_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0540>;
+       };
+
+       mcbsp1_sync_mux_ck: mcbsp1_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>;
+               ti,bit-shift = <26>;
+               reg = <0x0548>;
+       };
+
+       mcbsp1_gfclk: mcbsp1_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&mcbsp1_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0548>;
+       };
+
+       mcbsp2_sync_mux_ck: mcbsp2_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>;
+               ti,bit-shift = <26>;
+               reg = <0x0550>;
+       };
+
+       mcbsp2_gfclk: mcbsp2_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&mcbsp2_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0550>;
+       };
+
+       mcbsp3_sync_mux_ck: mcbsp3_sync_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&abe_24m_fclk>, <&dss_syc_gfclk_div>, <&func_24m_clk>;
+               ti,bit-shift = <26>;
+               reg = <0x0558>;
+       };
+
+       mcbsp3_gfclk: mcbsp3_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&mcbsp3_sync_mux_ck>, <&pad_clks_ck>, <&slimbus_clk>;
+               ti,bit-shift = <24>;
+               reg = <0x0558>;
+       };
+
+       timer5_gfclk_mux: timer5_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0568>;
+       };
+
+       timer6_gfclk_mux: timer6_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0570>;
+       };
+
+       timer7_gfclk_mux: timer7_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0578>;
+       };
+
+       timer8_gfclk_mux: timer8_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dss_syc_gfclk_div>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x0580>;
+       };
+
+       dummy_ck: dummy_ck {
+               #clock-cells = <0>;
+               compatible = "fixed-clock";
+               clock-frequency = <0>;
+       };
+};
+&prm_clocks {
+       sys_clkin: sys_clkin {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&virt_12000000_ck>, <&virt_13000000_ck>, <&virt_16800000_ck>, <&virt_19200000_ck>, <&virt_26000000_ck>, <&virt_27000000_ck>, <&virt_38400000_ck>;
+               reg = <0x0110>;
+               ti,index-starts-at-one;
+       };
+
+       abe_dpll_bypass_clk_mux: abe_dpll_bypass_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&sys_32k_ck>;
+               reg = <0x0108>;
+       };
+
+       abe_dpll_clk_mux: abe_dpll_clk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&sys_32k_ck>;
+               reg = <0x010c>;
+       };
+
+       custefuse_sys_gfclk_div: custefuse_sys_gfclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       dss_syc_gfclk_div: dss_syc_gfclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&sys_clkin>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       wkupaon_iclk_mux: wkupaon_iclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&abe_lp_clk_div>;
+               reg = <0x0108>;
+       };
+
+       l3instr_ts_gclk_div: l3instr_ts_gclk_div {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&wkupaon_iclk_mux>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       gpio1_dbclk: gpio1_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1938>;
+       };
+
+       timer1_gfclk_mux: timer1_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1940>;
+       };
+};
+&cm_core_clocks {
+       dpll_per_ck: dpll_per_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin>, <&per_dpll_hs_clk_div>;
+               reg = <0x0140>, <0x0144>, <0x014c>, <0x0148>;
+       };
+
+       dpll_per_x2_ck: dpll_per_x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-x2-clock";
+               clocks = <&dpll_per_ck>;
+       };
+
+       dpll_per_h11x2_ck: dpll_per_h11x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0158>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_h12x2_ck: dpll_per_h12x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x015c>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_h14x2_ck: dpll_per_h14x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <63>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0164>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_m2_ck: dpll_per_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0150>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_m2x2_ck: dpll_per_m2x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0150>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_per_m3x2_ck: dpll_per_m3x2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_x2_ck>;
+               ti,max-div = <31>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0154>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_unipro1_ck: dpll_unipro1_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin>, <&sys_clkin>;
+               reg = <0x0200>, <0x0204>, <0x020c>, <0x0208>;
+       };
+
+       dpll_unipro1_clkdcoldo: dpll_unipro1_clkdcoldo {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_unipro1_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_unipro1_m2_ck: dpll_unipro1_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_unipro1_ck>;
+               ti,max-div = <127>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0210>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_unipro2_ck: dpll_unipro2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-clock";
+               clocks = <&sys_clkin>, <&sys_clkin>;
+               reg = <0x01c0>, <0x01c4>, <0x01cc>, <0x01c8>;
+       };
+
+       dpll_unipro2_clkdcoldo: dpll_unipro2_clkdcoldo {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_unipro2_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_unipro2_m2_ck: dpll_unipro2_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_unipro2_ck>;
+               ti,max-div = <127>;
+               ti,autoidle-shift = <8>;
+               reg = <0x01d0>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       dpll_usb_ck: dpll_usb_ck {
+               #clock-cells = <0>;
+               compatible = "ti,omap4-dpll-j-type-clock";
+               clocks = <&sys_clkin>, <&usb_dpll_hs_clk_div>;
+               reg = <0x0180>, <0x0184>, <0x018c>, <0x0188>;
+       };
+
+       dpll_usb_clkdcoldo: dpll_usb_clkdcoldo {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_usb_ck>;
+               clock-mult = <1>;
+               clock-div = <1>;
+       };
+
+       dpll_usb_m2_ck: dpll_usb_m2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_usb_ck>;
+               ti,max-div = <127>;
+               ti,autoidle-shift = <8>;
+               reg = <0x0190>;
+               ti,index-starts-at-one;
+               ti,invert-autoidle-bit;
+       };
+
+       func_128m_clk: func_128m_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_h11x2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       func_12m_fclk: func_12m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <16>;
+       };
+
+       func_24m_clk: func_24m_clk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       func_48m_fclk: func_48m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <4>;
+       };
+
+       func_96m_fclk: func_96m_fclk {
+               #clock-cells = <0>;
+               compatible = "fixed-factor-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               clock-mult = <1>;
+               clock-div = <2>;
+       };
+
+       l3init_60m_fclk: l3init_60m_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_usb_m2_ck>;
+               reg = <0x0104>;
+               ti,dividers = <1>, <8>;
+       };
+
+       dss_32khz_clk: dss_32khz_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <11>;
+               reg = <0x1420>;
+       };
+
+       dss_48mhz_clk: dss_48mhz_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_48m_fclk>;
+               ti,bit-shift = <9>;
+               reg = <0x1420>;
+       };
+
+       dss_dss_clk: dss_dss_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_per_h12x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1420>;
+       };
+
+       dss_sys_clk: dss_sys_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dss_syc_gfclk_div>;
+               ti,bit-shift = <10>;
+               reg = <0x1420>;
+       };
+
+       gpio2_dbclk: gpio2_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1060>;
+       };
+
+       gpio3_dbclk: gpio3_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1068>;
+       };
+
+       gpio4_dbclk: gpio4_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1070>;
+       };
+
+       gpio5_dbclk: gpio5_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1078>;
+       };
+
+       gpio6_dbclk: gpio6_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1080>;
+       };
+
+       gpio7_dbclk: gpio7_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1110>;
+       };
+
+       gpio8_dbclk: gpio8_dbclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1118>;
+       };
+
+       iss_ctrlclk: iss_ctrlclk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&func_96m_fclk>;
+               ti,bit-shift = <8>;
+               reg = <0x1320>;
+       };
+
+       lli_txphy_clk: lli_txphy_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_unipro1_clkdcoldo>;
+               ti,bit-shift = <8>;
+               reg = <0x0f20>;
+       };
+
+       lli_txphy_ls_clk: lli_txphy_ls_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_unipro1_m2_ck>;
+               ti,bit-shift = <9>;
+               reg = <0x0f20>;
+       };
+
+       mmc1_32khz_clk: mmc1_32khz_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x1628>;
+       };
+
+       sata_ref_clk: sata_ref_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_clkin>;
+               ti,bit-shift = <8>;
+               reg = <0x1688>;
+       };
+
+       usb_host_hs_hsic480m_p1_clk: usb_host_hs_hsic480m_p1_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_usb_m2_ck>;
+               ti,bit-shift = <13>;
+               reg = <0x1658>;
+       };
+
+       usb_host_hs_hsic480m_p2_clk: usb_host_hs_hsic480m_p2_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_usb_m2_ck>;
+               ti,bit-shift = <14>;
+               reg = <0x1658>;
+       };
+
+       usb_host_hs_hsic480m_p3_clk: usb_host_hs_hsic480m_p3_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_usb_m2_ck>;
+               ti,bit-shift = <7>;
+               reg = <0x1658>;
+       };
+
+       usb_host_hs_hsic60m_p1_clk: usb_host_hs_hsic60m_p1_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3init_60m_fclk>;
+               ti,bit-shift = <11>;
+               reg = <0x1658>;
+       };
+
+       usb_host_hs_hsic60m_p2_clk: usb_host_hs_hsic60m_p2_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3init_60m_fclk>;
+               ti,bit-shift = <12>;
+               reg = <0x1658>;
+       };
+
+       usb_host_hs_hsic60m_p3_clk: usb_host_hs_hsic60m_p3_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3init_60m_fclk>;
+               ti,bit-shift = <6>;
+               reg = <0x1658>;
+       };
+
+       utmi_p1_gfclk: utmi_p1_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&l3init_60m_fclk>, <&xclk60mhsp1_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1658>;
+       };
+
+       usb_host_hs_utmi_p1_clk: usb_host_hs_utmi_p1_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&utmi_p1_gfclk>;
+               ti,bit-shift = <8>;
+               reg = <0x1658>;
+       };
+
+       utmi_p2_gfclk: utmi_p2_gfclk {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&l3init_60m_fclk>, <&xclk60mhsp2_ck>;
+               ti,bit-shift = <25>;
+               reg = <0x1658>;
+       };
+
+       usb_host_hs_utmi_p2_clk: usb_host_hs_utmi_p2_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&utmi_p2_gfclk>;
+               ti,bit-shift = <9>;
+               reg = <0x1658>;
+       };
+
+       usb_host_hs_utmi_p3_clk: usb_host_hs_utmi_p3_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3init_60m_fclk>;
+               ti,bit-shift = <10>;
+               reg = <0x1658>;
+       };
+
+       usb_otg_ss_refclk960m: usb_otg_ss_refclk960m {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&dpll_usb_clkdcoldo>;
+               ti,bit-shift = <8>;
+               reg = <0x16f0>;
+       };
+
+       usb_phy_cm_clk32k: usb_phy_cm_clk32k {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&sys_32k_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0640>;
+       };
+
+       usb_tll_hs_usb_ch0_clk: usb_tll_hs_usb_ch0_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3init_60m_fclk>;
+               ti,bit-shift = <8>;
+               reg = <0x1668>;
+       };
+
+       usb_tll_hs_usb_ch1_clk: usb_tll_hs_usb_ch1_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3init_60m_fclk>;
+               ti,bit-shift = <9>;
+               reg = <0x1668>;
+       };
+
+       usb_tll_hs_usb_ch2_clk: usb_tll_hs_usb_ch2_clk {
+               #clock-cells = <0>;
+               compatible = "ti,gate-clock";
+               clocks = <&l3init_60m_fclk>;
+               ti,bit-shift = <10>;
+               reg = <0x1668>;
+       };
+
+       fdif_fclk: fdif_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_h11x2_ck>;
+               ti,bit-shift = <24>;
+               ti,max-div = <2>;
+               reg = <0x1328>;
+       };
+
+       gpu_core_gclk_mux: gpu_core_gclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1520>;
+       };
+
+       gpu_hyd_gclk_mux: gpu_hyd_gclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&dpll_core_h14x2_ck>, <&dpll_per_h14x2_ck>;
+               ti,bit-shift = <25>;
+               reg = <0x1520>;
+       };
+
+       hsi_fclk: hsi_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               ti,max-div = <2>;
+               reg = <0x1638>;
+       };
+
+       mmc1_fclk_mux: mmc1_fclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1628>;
+       };
+
+       mmc1_fclk: mmc1_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&mmc1_fclk_mux>;
+               ti,bit-shift = <25>;
+               ti,max-div = <2>;
+               reg = <0x1628>;
+       };
+
+       mmc2_fclk_mux: mmc2_fclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&func_128m_clk>, <&dpll_per_m2x2_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1630>;
+       };
+
+       mmc2_fclk: mmc2_fclk {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&mmc2_fclk_mux>;
+               ti,bit-shift = <25>;
+               ti,max-div = <2>;
+               reg = <0x1630>;
+       };
+
+       timer10_gfclk_mux: timer10_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1028>;
+       };
+
+       timer11_gfclk_mux: timer11_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1030>;
+       };
+
+       timer2_gfclk_mux: timer2_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1038>;
+       };
+
+       timer3_gfclk_mux: timer3_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1040>;
+       };
+
+       timer4_gfclk_mux: timer4_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1048>;
+       };
+
+       timer9_gfclk_mux: timer9_gfclk_mux {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&sys_clkin>, <&sys_32k_ck>;
+               ti,bit-shift = <24>;
+               reg = <0x1050>;
+       };
+};
+
+&cm_core_clockdomains {
+       l3init_clkdm: l3init_clkdm {
+               compatible = "ti,clockdomain";
+               clocks = <&dpll_usb_ck>;
+       };
+};
+
+&scrm_clocks {
+       auxclk0_src_gate_ck: auxclk0_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0310>;
+       };
+
+       auxclk0_src_mux_ck: auxclk0_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0310>;
+       };
+
+       auxclk0_src_ck: auxclk0_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk0_src_gate_ck>, <&auxclk0_src_mux_ck>;
+       };
+
+       auxclk0_ck: auxclk0_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk0_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x0310>;
+       };
+
+       auxclk1_src_gate_ck: auxclk1_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0314>;
+       };
+
+       auxclk1_src_mux_ck: auxclk1_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0314>;
+       };
+
+       auxclk1_src_ck: auxclk1_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk1_src_gate_ck>, <&auxclk1_src_mux_ck>;
+       };
+
+       auxclk1_ck: auxclk1_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk1_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x0314>;
+       };
+
+       auxclk2_src_gate_ck: auxclk2_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0318>;
+       };
+
+       auxclk2_src_mux_ck: auxclk2_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0318>;
+       };
+
+       auxclk2_src_ck: auxclk2_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk2_src_gate_ck>, <&auxclk2_src_mux_ck>;
+       };
+
+       auxclk2_ck: auxclk2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk2_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x0318>;
+       };
+
+       auxclk3_src_gate_ck: auxclk3_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x031c>;
+       };
+
+       auxclk3_src_mux_ck: auxclk3_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x031c>;
+       };
+
+       auxclk3_src_ck: auxclk3_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk3_src_gate_ck>, <&auxclk3_src_mux_ck>;
+       };
+
+       auxclk3_ck: auxclk3_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk3_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x031c>;
+       };
+
+       auxclk4_src_gate_ck: auxclk4_src_gate_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-no-wait-gate-clock";
+               clocks = <&dpll_core_m3x2_ck>;
+               ti,bit-shift = <8>;
+               reg = <0x0320>;
+       };
+
+       auxclk4_src_mux_ck: auxclk4_src_mux_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-mux-clock";
+               clocks = <&sys_clkin>, <&dpll_core_m3x2_ck>, <&dpll_per_m3x2_ck>;
+               ti,bit-shift = <1>;
+               reg = <0x0320>;
+       };
+
+       auxclk4_src_ck: auxclk4_src_ck {
+               #clock-cells = <0>;
+               compatible = "ti,composite-clock";
+               clocks = <&auxclk4_src_gate_ck>, <&auxclk4_src_mux_ck>;
+       };
+
+       auxclk4_ck: auxclk4_ck {
+               #clock-cells = <0>;
+               compatible = "ti,divider-clock";
+               clocks = <&auxclk4_src_ck>;
+               ti,bit-shift = <16>;
+               ti,max-div = <16>;
+               reg = <0x0320>;
+       };
+
+       auxclkreq0_ck: auxclkreq0_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x0210>;
+       };
+
+       auxclkreq1_ck: auxclkreq1_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x0214>;
+       };
+
+       auxclkreq2_ck: auxclkreq2_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x0218>;
+       };
+
+       auxclkreq3_ck: auxclkreq3_ck {
+               #clock-cells = <0>;
+               compatible = "ti,mux-clock";
+               clocks = <&auxclk0_ck>, <&auxclk1_ck>, <&auxclk2_ck>, <&auxclk3_ck>, <&auxclk4_ck>;
+               ti,bit-shift = <2>;
+               reg = <0x021c>;
+       };
+};
index 1105558d188b2fe485aaf0cd9c4ba2ecc482b31b..52447c17537a17c6035bf33694909e7252b78733 100644 (file)
                        watchdog@fffffe40 {
                                compatible = "atmel,at91sam9260-wdt";
                                reg = <0xfffffe40 0x10>;
+                               interrupts = <4 IRQ_TYPE_LEVEL_HIGH 7>;
+                               atmel,watchdog-type = "hardware";
+                               atmel,reset-type = "all";
+                               atmel,dbg-halt;
+                               atmel,idle-halt;
                                status = "disabled";
                        };
 
index 2c38fdf1951d377ee648778a847fb3776fabc70a..2519d6de064012be7b17ca38c9e2f6e921780d8c 100644 (file)
@@ -126,3 +126,6 @@ CONFIG_CRC7=y
 CONFIG_XZ_DEC=y
 CONFIG_AVERAGE=y
 CONFIG_PINCTRL_CAPRI=y
+CONFIG_WATCHDOG=y
+CONFIG_BCM_KONA_WDT=y
+CONFIG_BCM_KONA_WDT_DEBUG=y
index fbeb39c869e9fdcedace1d61688247c14141cab3..8aa4cca74501f394b74d35fb69657553bc54daa3 100644 (file)
 #define isa_page_to_bus page_to_phys
 #define isa_bus_to_virt phys_to_virt
 
+/*
+ * Atomic MMIO-wide IO modify
+ */
+extern void atomic_io_modify(void __iomem *reg, u32 mask, u32 set);
+extern void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set);
+
 /*
  * Generic IO read/write.  These perform native-endian accesses.  Note
  * that some architectures will want to re-define __raw_{read,write}w.
index b3fb8c9e1ff2d75f15666a9233dee2d1b3ccb6bc..1879e8dd2acc18a7837f0eee71beb8241c1aa9c0 100644 (file)
@@ -451,9 +451,11 @@ __und_usr_thumb:
        .arch   armv6t2
 #endif
 2:     ldrht   r5, [r4]
+ARM_BE8(rev16  r5, r5)                         @ little endian instruction
        cmp     r5, #0xe800                     @ 32bit instruction if xx != 0
        blo     __und_usr_fault_16              @ 16bit undefined instruction
 3:     ldrht   r0, [r2]
+ARM_BE8(rev16  r0, r0)                         @ little endian instruction
        add     r2, r2, #2                      @ r2 is PC + 2, make it PC + 4
        str     r2, [sp, #S_PC]                 @ it's a 2x16bit instr, update
        orr     r0, r0, r5, lsl #16
index 32f317e5828adafc2bdec200705a9d12c686711c..914616e0bdcd0c0108376a9e5834e9cb73219b51 100644 (file)
@@ -52,7 +52,8 @@
        .equ    swapper_pg_dir, KERNEL_RAM_VADDR - PG_DIR_SIZE
 
        .macro  pgtbl, rd, phys
-       add     \rd, \phys, #TEXT_OFFSET - PG_DIR_SIZE
+       add     \rd, \phys, #TEXT_OFFSET
+       sub     \rd, \rd, #PG_DIR_SIZE
        .endm
 
 /*
index dcd5b4d8614374519a80eb0772c8cd12df1320e0..9203cf883330a3c64460f07d572994f5f8263a83 100644 (file)
@@ -1,6 +1,41 @@
 #include <linux/export.h>
 #include <linux/types.h>
 #include <linux/io.h>
+#include <linux/spinlock.h>
+
+static DEFINE_RAW_SPINLOCK(__io_lock);
+
+/*
+ * Generic atomic MMIO modify.
+ *
+ * Allows thread-safe access to registers shared by unrelated subsystems.
+ * The access is protected by a single MMIO-wide lock.
+ */
+void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set)
+{
+       unsigned long flags;
+       u32 value;
+
+       raw_spin_lock_irqsave(&__io_lock, flags);
+       value = readl_relaxed(reg) & ~mask;
+       value |= (set & mask);
+       writel_relaxed(value, reg);
+       raw_spin_unlock_irqrestore(&__io_lock, flags);
+}
+EXPORT_SYMBOL(atomic_io_modify_relaxed);
+
+void atomic_io_modify(void __iomem *reg, u32 mask, u32 set)
+{
+       unsigned long flags;
+       u32 value;
+
+       raw_spin_lock_irqsave(&__io_lock, flags);
+       value = readl_relaxed(reg) & ~mask;
+       value |= (set & mask);
+       writel(value, reg);
+       raw_spin_unlock_irqrestore(&__io_lock, flags);
+}
+EXPORT_SYMBOL(atomic_io_modify);
 
 /*
  * Copy data from IO memory space to "real" memory space.
index 1e8b030dbefd8b2b19da27d9ca8ecabfaf610bba..b0df9761de6dc1109f727e0300ff91448f8fd55b 100644 (file)
@@ -731,7 +731,7 @@ static void __init request_standard_resources(const struct machine_desc *mdesc)
        kernel_data.end     = virt_to_phys(_end - 1);
 
        for_each_memblock(memory, region) {
-               res = memblock_virt_alloc(sizeof(*res), 0);
+               res = memblock_virt_alloc_low(sizeof(*res), 0);
                res->name  = "System RAM";
                res->start = __pfn_to_phys(memblock_region_memory_base_pfn(region));
                res->end = __pfn_to_phys(memblock_region_memory_end_pfn(region)) - 1;
index d2ea6e60ea7b2042f6ff8d73503db73f95fd9770..76e5db4fce35a96eb7b5f7abeaf6c60e70fddcf3 100644 (file)
@@ -133,6 +133,39 @@ static int ar8031_phy_fixup(struct phy_device *dev)
 
 #define PHY_ID_AR8031  0x004dd074
 
+static int ar8035_phy_fixup(struct phy_device *dev)
+{
+       u16 val;
+
+       /* Ar803x phy SmartEEE feature cause link status generates glitch,
+        * which cause ethernet link down/up issue, so disable SmartEEE
+        */
+       phy_write(dev, 0xd, 0x3);
+       phy_write(dev, 0xe, 0x805d);
+       phy_write(dev, 0xd, 0x4003);
+
+       val = phy_read(dev, 0xe);
+       phy_write(dev, 0xe, val & ~(1 << 8));
+
+       /*
+        * Enable 125MHz clock from CLK_25M on the AR8031.  This
+        * is fed in to the IMX6 on the ENET_REF_CLK (V22) pad.
+        * Also, introduce a tx clock delay.
+        *
+        * This is the same as is the AR8031 fixup.
+        */
+       ar8031_phy_fixup(dev);
+
+       /*check phy power*/
+       val = phy_read(dev, 0x0);
+       if (val & BMCR_PDOWN)
+               phy_write(dev, 0x0, val & ~BMCR_PDOWN);
+
+       return 0;
+}
+
+#define PHY_ID_AR8035 0x004dd072
+
 static void __init imx6q_enet_phy_init(void)
 {
        if (IS_BUILTIN(CONFIG_PHYLIB)) {
@@ -142,6 +175,8 @@ static void __init imx6q_enet_phy_init(void)
                                ksz9031rn_phy_fixup);
                phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
                                ar8031_phy_fixup);
+               phy_register_fixup_for_uid(PHY_ID_AR8035, 0xffffffef,
+                               ar8035_phy_fixup);
        }
 }
 
index 6f424eced1816914bf59e39e48608b50bb338fe5..b3738e616f197bef538f2610bd519ad066f8cddd 100644 (file)
@@ -236,32 +236,26 @@ static struct mc13xxx_led_platform_data moboard_led[] = {
        {
                .id = MC13783_LED_R1,
                .name = "coreboard-led-4:red",
-               .max_current = 2,
        },
        {
                .id = MC13783_LED_G1,
                .name = "coreboard-led-4:green",
-               .max_current = 2,
        },
        {
                .id = MC13783_LED_B1,
                .name = "coreboard-led-4:blue",
-               .max_current = 2,
        },
        {
                .id = MC13783_LED_R2,
                .name = "coreboard-led-5:red",
-               .max_current = 3,
        },
        {
                .id = MC13783_LED_G2,
                .name = "coreboard-led-5:green",
-               .max_current = 3,
        },
        {
                .id = MC13783_LED_B2,
                .name = "coreboard-led-5:blue",
-               .max_current = 3,
        },
 };
 
@@ -271,8 +265,14 @@ static struct mc13xxx_leds_platform_data moboard_leds = {
        .led_control[0] = MC13783_LED_C0_ENABLE | MC13783_LED_C0_ABMODE(0),
        .led_control[1] = MC13783_LED_C1_SLEWLIM,
        .led_control[2] = MC13783_LED_C2_SLEWLIM,
-       .led_control[3] = MC13783_LED_C3_PERIOD(0),
-       .led_control[4] = MC13783_LED_C3_PERIOD(0),
+       .led_control[3] = MC13783_LED_C3_PERIOD(0) |
+                         MC13783_LED_C3_CURRENT_R1(2) |
+                         MC13783_LED_C3_CURRENT_G1(2) |
+                         MC13783_LED_C3_CURRENT_B1(2),
+       .led_control[4] = MC13783_LED_C4_PERIOD(0) |
+                         MC13783_LED_C4_CURRENT_R2(3) |
+                         MC13783_LED_C4_CURRENT_G2(3) |
+                         MC13783_LED_C4_CURRENT_B2(3),
 };
 
 static struct mc13xxx_buttons_platform_data moboard_buttons = {
index 4191ae08f4c81a2c95059df01fac77f883f30b70..653b489479e0ee2d4166d6d033d315a1e56430e4 100644 (file)
@@ -76,6 +76,16 @@ config SOC_AM43XX
        select ARM_GIC
        select MACH_OMAP_GENERIC
 
+config SOC_DRA7XX
+       bool "TI DRA7XX"
+       depends on ARCH_MULTI_V7
+       select ARCH_OMAP2PLUS
+       select ARM_CPU_SUSPEND if PM
+       select ARM_GIC
+       select CPU_V7
+       select HAVE_SMP
+       select HAVE_ARM_ARCH_TIMER
+
 config ARCH_OMAP2PLUS
        bool
        select ARCH_HAS_BANDGAP
@@ -128,14 +138,6 @@ config SOC_HAS_REALTIME_COUNTER
        depends on SOC_OMAP5 || SOC_DRA7XX
        default y
 
-config SOC_DRA7XX
-       bool "TI DRA7XX"
-       select ARM_ARCH_TIMER
-       select CPU_V7
-       select ARM_GIC
-       select HAVE_SMP
-       select COMMON_CLK
-
 comment "OMAP Core Type"
        depends on ARCH_OMAP2
 
index f78b177e8f4fd17849c3265200b319fc17d52198..e6eec6f72fd3ed76b30af03bb4923fbacc62af7c 100644 (file)
@@ -130,6 +130,7 @@ obj-$(CONFIG_SOC_AM33XX)            += $(voltagedomain-common)
 obj-$(CONFIG_SOC_AM43XX)               += $(voltagedomain-common)
 obj-$(CONFIG_SOC_OMAP5)                        += $(voltagedomain-common)
 obj-$(CONFIG_SOC_OMAP5)                += voltagedomains54xx_data.o
+obj-$(CONFIG_SOC_DRA7XX)               += $(voltagedomain-common)
 
 # OMAP powerdomain framework
 powerdomain-common                     += powerdomain.o powerdomain-common.o
@@ -184,12 +185,14 @@ obj-$(CONFIG_ARCH_OMAP3)          += clock34xx.o clkt34xx_dpll3m2.o
 obj-$(CONFIG_ARCH_OMAP3)               += clock3517.o clock36xx.o
 obj-$(CONFIG_ARCH_OMAP3)               += dpll3xxx.o cclock3xxx_data.o
 obj-$(CONFIG_ARCH_OMAP3)               += clkt_iclk.o
-obj-$(CONFIG_ARCH_OMAP4)               += $(clock-common) cclock44xx_data.o
+obj-$(CONFIG_ARCH_OMAP4)               += $(clock-common)
 obj-$(CONFIG_ARCH_OMAP4)               += dpll3xxx.o dpll44xx.o
 obj-$(CONFIG_SOC_AM33XX)               += $(clock-common) dpll3xxx.o
-obj-$(CONFIG_SOC_AM33XX)               += cclock33xx_data.o
 obj-$(CONFIG_SOC_OMAP5)                        += $(clock-common)
 obj-$(CONFIG_SOC_OMAP5)                        += dpll3xxx.o dpll44xx.o
+obj-$(CONFIG_SOC_DRA7XX)               += $(clock-common)
+obj-$(CONFIG_SOC_DRA7XX)               += dpll3xxx.o dpll44xx.o
+obj-$(CONFIG_SOC_AM43XX)               += $(clock-common) dpll3xxx.o
 
 # OMAP2 clock rate set data (old "OPP" data)
 obj-$(CONFIG_SOC_OMAP2420)             += opp2420_data.o
index f093af17f5e6a9de4943fc16d2d4d8116aab1045..8760bbe3baab9234da17c5a55d3126de189a5778 100644 (file)
@@ -760,7 +760,14 @@ static struct regulator_init_data rx51_vintdig = {
        },
 };
 
+static const char * const si4713_supply_names[] = {
+       "vio",
+       "vdd",
+};
+
 static struct si4713_platform_data rx51_si4713_i2c_data __initdata_or_module = {
+       .supplies       = ARRAY_SIZE(si4713_supply_names),
+       .supply_names   = si4713_supply_names,
        .gpio_reset     = RX51_FMTX_RESET_GPIO,
 };
 
diff --git a/arch/arm/mach-omap2/cclock33xx_data.c b/arch/arm/mach-omap2/cclock33xx_data.c
deleted file mode 100644 (file)
index 865d30e..0000000
+++ /dev/null
@@ -1,1064 +0,0 @@
-/*
- * AM33XX Clock data
- *
- * Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/
- * Vaibhav Hiremath <hvaibhav@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/clk-private.h>
-#include <linux/clkdev.h>
-#include <linux/io.h>
-
-#include "am33xx.h"
-#include "soc.h"
-#include "iomap.h"
-#include "clock.h"
-#include "control.h"
-#include "cm.h"
-#include "cm33xx.h"
-#include "cm-regbits-33xx.h"
-#include "prm.h"
-
-/* Modulemode control */
-#define AM33XX_MODULEMODE_HWCTRL_SHIFT         0
-#define AM33XX_MODULEMODE_SWCTRL_SHIFT         1
-
-/*LIST_HEAD(clocks);*/
-
-/* Root clocks */
-
-/* RTC 32k */
-DEFINE_CLK_FIXED_RATE(clk_32768_ck, CLK_IS_ROOT, 32768, 0x0);
-
-/* On-Chip 32KHz RC OSC */
-DEFINE_CLK_FIXED_RATE(clk_rc32k_ck, CLK_IS_ROOT, 32000, 0x0);
-
-/* Crystal input clks */
-DEFINE_CLK_FIXED_RATE(virt_19200000_ck, CLK_IS_ROOT, 19200000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_24000000_ck, CLK_IS_ROOT, 24000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_25000000_ck, CLK_IS_ROOT, 25000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_26000000_ck, CLK_IS_ROOT, 26000000, 0x0);
-
-/* Oscillator clock */
-/* 19.2, 24, 25 or 26 MHz */
-static const char *sys_clkin_ck_parents[] = {
-       "virt_19200000_ck", "virt_24000000_ck", "virt_25000000_ck",
-       "virt_26000000_ck",
-};
-
-/*
- * sys_clk in: input to the dpll and also used as funtional clock for,
- *   adc_tsc, smartreflex0-1, timer1-7, mcasp0-1, dcan0-1, cefuse
- *
- */
-DEFINE_CLK_MUX(sys_clkin_ck, sys_clkin_ck_parents, NULL, 0x0,
-              AM33XX_CTRL_REGADDR(AM33XX_CONTROL_STATUS),
-              AM33XX_CONTROL_STATUS_SYSBOOT1_SHIFT,
-              AM33XX_CONTROL_STATUS_SYSBOOT1_WIDTH,
-              0, NULL);
-
-/* External clock - 12 MHz */
-DEFINE_CLK_FIXED_RATE(tclkin_ck, CLK_IS_ROOT, 12000000, 0x0);
-
-/* Module clocks and DPLL outputs */
-
-/* DPLL_CORE */
-static struct dpll_data dpll_core_dd = {
-       .mult_div1_reg  = AM33XX_CM_CLKSEL_DPLL_CORE,
-       .clk_bypass     = &sys_clkin_ck,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = AM33XX_CM_CLKMODE_DPLL_CORE,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .idlest_reg     = AM33XX_CM_IDLEST_DPLL_CORE,
-       .mult_mask      = AM33XX_DPLL_MULT_MASK,
-       .div1_mask      = AM33XX_DPLL_DIV_MASK,
-       .enable_mask    = AM33XX_DPLL_EN_MASK,
-       .idlest_mask    = AM33XX_ST_DPLL_CLK_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-};
-
-/* CLKDCOLDO output */
-static const char *dpll_core_ck_parents[] = {
-       "sys_clkin_ck",
-};
-
-static struct clk dpll_core_ck;
-
-static const struct clk_ops dpll_core_ck_ops = {
-       .recalc_rate    = &omap3_dpll_recalc,
-       .get_parent     = &omap2_init_dpll_parent,
-};
-
-static struct clk_hw_omap dpll_core_ck_hw = {
-       .hw     = {
-               .clk    = &dpll_core_ck,
-       },
-       .dpll_data      = &dpll_core_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_core_ck, dpll_core_ck_parents, dpll_core_ck_ops);
-
-static const char *dpll_core_x2_ck_parents[] = {
-       "dpll_core_ck",
-};
-
-static struct clk dpll_core_x2_ck;
-
-static const struct clk_ops dpll_x2_ck_ops = {
-       .recalc_rate    = &omap3_clkoutx2_recalc,
-};
-
-static struct clk_hw_omap dpll_core_x2_ck_hw = {
-       .hw     = {
-               .clk    = &dpll_core_x2_ck,
-       },
-       .flags          = CLOCK_CLKOUTX2,
-};
-
-DEFINE_STRUCT_CLK(dpll_core_x2_ck, dpll_core_x2_ck_parents, dpll_x2_ck_ops);
-
-DEFINE_CLK_DIVIDER(dpll_core_m4_ck, "dpll_core_x2_ck", &dpll_core_x2_ck,
-                  0x0, AM33XX_CM_DIV_M4_DPLL_CORE,
-                  AM33XX_HSDIVIDER_CLKOUT1_DIV_SHIFT,
-                  AM33XX_HSDIVIDER_CLKOUT1_DIV_WIDTH, CLK_DIVIDER_ONE_BASED,
-                  NULL);
-
-DEFINE_CLK_DIVIDER(dpll_core_m5_ck, "dpll_core_x2_ck", &dpll_core_x2_ck,
-                  0x0, AM33XX_CM_DIV_M5_DPLL_CORE,
-                  AM33XX_HSDIVIDER_CLKOUT2_DIV_SHIFT,
-                  AM33XX_HSDIVIDER_CLKOUT2_DIV_WIDTH,
-                  CLK_DIVIDER_ONE_BASED, NULL);
-
-DEFINE_CLK_DIVIDER(dpll_core_m6_ck, "dpll_core_x2_ck", &dpll_core_x2_ck,
-                  0x0, AM33XX_CM_DIV_M6_DPLL_CORE,
-                  AM33XX_HSDIVIDER_CLKOUT3_DIV_SHIFT,
-                  AM33XX_HSDIVIDER_CLKOUT3_DIV_WIDTH,
-                  CLK_DIVIDER_ONE_BASED, NULL);
-
-
-/* DPLL_MPU */
-static struct dpll_data dpll_mpu_dd = {
-       .mult_div1_reg  = AM33XX_CM_CLKSEL_DPLL_MPU,
-       .clk_bypass     = &sys_clkin_ck,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = AM33XX_CM_CLKMODE_DPLL_MPU,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .idlest_reg     = AM33XX_CM_IDLEST_DPLL_MPU,
-       .mult_mask      = AM33XX_DPLL_MULT_MASK,
-       .div1_mask      = AM33XX_DPLL_DIV_MASK,
-       .enable_mask    = AM33XX_DPLL_EN_MASK,
-       .idlest_mask    = AM33XX_ST_DPLL_CLK_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-};
-
-/* CLKOUT: fdpll/M2 */
-static struct clk dpll_mpu_ck;
-
-static const struct clk_ops dpll_mpu_ck_ops = {
-       .enable         = &omap3_noncore_dpll_enable,
-       .disable        = &omap3_noncore_dpll_disable,
-       .recalc_rate    = &omap3_dpll_recalc,
-       .round_rate     = &omap2_dpll_round_rate,
-       .set_rate       = &omap3_noncore_dpll_set_rate,
-       .get_parent     = &omap2_init_dpll_parent,
-};
-
-static struct clk_hw_omap dpll_mpu_ck_hw = {
-       .hw = {
-               .clk    = &dpll_mpu_ck,
-       },
-       .dpll_data      = &dpll_mpu_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_core_ck_parents, dpll_mpu_ck_ops);
-
-/*
- * TODO: Add clksel here (sys_clkin, CORE_CLKOUTM6, PER_CLKOUTM2
- * and ALT_CLK1/2)
- */
-DEFINE_CLK_DIVIDER(dpll_mpu_m2_ck, "dpll_mpu_ck", &dpll_mpu_ck,
-                  0x0, AM33XX_CM_DIV_M2_DPLL_MPU, AM33XX_DPLL_CLKOUT_DIV_SHIFT,
-                  AM33XX_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL);
-
-/* DPLL_DDR */
-static struct dpll_data dpll_ddr_dd = {
-       .mult_div1_reg  = AM33XX_CM_CLKSEL_DPLL_DDR,
-       .clk_bypass     = &sys_clkin_ck,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = AM33XX_CM_CLKMODE_DPLL_DDR,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .idlest_reg     = AM33XX_CM_IDLEST_DPLL_DDR,
-       .mult_mask      = AM33XX_DPLL_MULT_MASK,
-       .div1_mask      = AM33XX_DPLL_DIV_MASK,
-       .enable_mask    = AM33XX_DPLL_EN_MASK,
-       .idlest_mask    = AM33XX_ST_DPLL_CLK_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-};
-
-/* CLKOUT: fdpll/M2 */
-static struct clk dpll_ddr_ck;
-
-static const struct clk_ops dpll_ddr_ck_ops = {
-       .recalc_rate    = &omap3_dpll_recalc,
-       .get_parent     = &omap2_init_dpll_parent,
-       .round_rate     = &omap2_dpll_round_rate,
-       .set_rate       = &omap3_noncore_dpll_set_rate,
-};
-
-static struct clk_hw_omap dpll_ddr_ck_hw = {
-       .hw = {
-               .clk    = &dpll_ddr_ck,
-       },
-       .dpll_data      = &dpll_ddr_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_ddr_ck, dpll_core_ck_parents, dpll_ddr_ck_ops);
-
-/*
- * TODO: Add clksel here (sys_clkin, CORE_CLKOUTM6, PER_CLKOUTM2
- * and ALT_CLK1/2)
- */
-DEFINE_CLK_DIVIDER(dpll_ddr_m2_ck, "dpll_ddr_ck", &dpll_ddr_ck,
-                  0x0, AM33XX_CM_DIV_M2_DPLL_DDR,
-                  AM33XX_DPLL_CLKOUT_DIV_SHIFT, AM33XX_DPLL_CLKOUT_DIV_WIDTH,
-                  CLK_DIVIDER_ONE_BASED, NULL);
-
-/* emif_fck functional clock */
-DEFINE_CLK_FIXED_FACTOR(dpll_ddr_m2_div2_ck, "dpll_ddr_m2_ck", &dpll_ddr_m2_ck,
-                       0x0, 1, 2);
-
-/* DPLL_DISP */
-static struct dpll_data dpll_disp_dd = {
-       .mult_div1_reg  = AM33XX_CM_CLKSEL_DPLL_DISP,
-       .clk_bypass     = &sys_clkin_ck,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = AM33XX_CM_CLKMODE_DPLL_DISP,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .idlest_reg     = AM33XX_CM_IDLEST_DPLL_DISP,
-       .mult_mask      = AM33XX_DPLL_MULT_MASK,
-       .div1_mask      = AM33XX_DPLL_DIV_MASK,
-       .enable_mask    = AM33XX_DPLL_EN_MASK,
-       .idlest_mask    = AM33XX_ST_DPLL_CLK_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-};
-
-/* CLKOUT: fdpll/M2 */
-static struct clk dpll_disp_ck;
-
-static struct clk_hw_omap dpll_disp_ck_hw = {
-       .hw = {
-               .clk    = &dpll_disp_ck,
-       },
-       .dpll_data      = &dpll_disp_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_disp_ck, dpll_core_ck_parents, dpll_ddr_ck_ops);
-
-/*
- * TODO: Add clksel here (sys_clkin, CORE_CLKOUTM6, PER_CLKOUTM2
- * and ALT_CLK1/2)
- */
-DEFINE_CLK_DIVIDER(dpll_disp_m2_ck, "dpll_disp_ck", &dpll_disp_ck,
-                  CLK_SET_RATE_PARENT, AM33XX_CM_DIV_M2_DPLL_DISP,
-                  AM33XX_DPLL_CLKOUT_DIV_SHIFT, AM33XX_DPLL_CLKOUT_DIV_WIDTH,
-                  CLK_DIVIDER_ONE_BASED, NULL);
-
-/* DPLL_PER */
-static struct dpll_data dpll_per_dd = {
-       .mult_div1_reg  = AM33XX_CM_CLKSEL_DPLL_PERIPH,
-       .clk_bypass     = &sys_clkin_ck,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = AM33XX_CM_CLKMODE_DPLL_PER,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .idlest_reg     = AM33XX_CM_IDLEST_DPLL_PER,
-       .mult_mask      = AM33XX_DPLL_MULT_PERIPH_MASK,
-       .div1_mask      = AM33XX_DPLL_PER_DIV_MASK,
-       .enable_mask    = AM33XX_DPLL_EN_MASK,
-       .idlest_mask    = AM33XX_ST_DPLL_CLK_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-       .flags          = DPLL_J_TYPE,
-};
-
-/* CLKDCOLDO */
-static struct clk dpll_per_ck;
-
-static struct clk_hw_omap dpll_per_ck_hw = {
-       .hw     = {
-               .clk    = &dpll_per_ck,
-       },
-       .dpll_data      = &dpll_per_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_per_ck, dpll_core_ck_parents, dpll_ddr_ck_ops);
-
-/* CLKOUT: fdpll/M2 */
-DEFINE_CLK_DIVIDER(dpll_per_m2_ck, "dpll_per_ck", &dpll_per_ck, 0x0,
-                  AM33XX_CM_DIV_M2_DPLL_PER, AM33XX_DPLL_CLKOUT_DIV_SHIFT,
-                  AM33XX_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED,
-                  NULL);
-
-DEFINE_CLK_FIXED_FACTOR(dpll_per_m2_div4_wkupdm_ck, "dpll_per_m2_ck",
-                       &dpll_per_m2_ck, 0x0, 1, 4);
-
-DEFINE_CLK_FIXED_FACTOR(dpll_per_m2_div4_ck, "dpll_per_m2_ck",
-                       &dpll_per_m2_ck, 0x0, 1, 4);
-
-DEFINE_CLK_FIXED_FACTOR(dpll_core_m4_div2_ck, "dpll_core_m4_ck",
-                       &dpll_core_m4_ck, 0x0, 1, 2);
-
-DEFINE_CLK_FIXED_FACTOR(l4_rtc_gclk, "dpll_core_m4_ck", &dpll_core_m4_ck, 0x0,
-                       1, 2);
-
-DEFINE_CLK_FIXED_FACTOR(clk_24mhz, "dpll_per_m2_ck", &dpll_per_m2_ck, 0x0, 1,
-                       8);
-
-/*
- * Below clock nodes describes clockdomains derived out
- * of core clock.
- */
-static const struct clk_ops clk_ops_null = {
-};
-
-static const char *l3_gclk_parents[] = {
-       "dpll_core_m4_ck"
-};
-
-static struct clk l3_gclk;
-DEFINE_STRUCT_CLK_HW_OMAP(l3_gclk, NULL);
-DEFINE_STRUCT_CLK(l3_gclk, l3_gclk_parents, clk_ops_null);
-
-static struct clk l4hs_gclk;
-DEFINE_STRUCT_CLK_HW_OMAP(l4hs_gclk, NULL);
-DEFINE_STRUCT_CLK(l4hs_gclk, l3_gclk_parents, clk_ops_null);
-
-static const char *l3s_gclk_parents[] = {
-       "dpll_core_m4_div2_ck"
-};
-
-static struct clk l3s_gclk;
-DEFINE_STRUCT_CLK_HW_OMAP(l3s_gclk, NULL);
-DEFINE_STRUCT_CLK(l3s_gclk, l3s_gclk_parents, clk_ops_null);
-
-static struct clk l4fw_gclk;
-DEFINE_STRUCT_CLK_HW_OMAP(l4fw_gclk, NULL);
-DEFINE_STRUCT_CLK(l4fw_gclk, l3s_gclk_parents, clk_ops_null);
-
-static struct clk l4ls_gclk;
-DEFINE_STRUCT_CLK_HW_OMAP(l4ls_gclk, NULL);
-DEFINE_STRUCT_CLK(l4ls_gclk, l3s_gclk_parents, clk_ops_null);
-
-static struct clk sysclk_div_ck;
-DEFINE_STRUCT_CLK_HW_OMAP(sysclk_div_ck, NULL);
-DEFINE_STRUCT_CLK(sysclk_div_ck, l3_gclk_parents, clk_ops_null);
-
-/*
- * In order to match the clock domain with hwmod clockdomain entry,
- * separate clock nodes is required for the modules which are
- * directly getting their funtioncal clock from sys_clkin.
- */
-static struct clk adc_tsc_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(adc_tsc_fck, NULL);
-DEFINE_STRUCT_CLK(adc_tsc_fck, dpll_core_ck_parents, clk_ops_null);
-
-static struct clk dcan0_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(dcan0_fck, NULL);
-DEFINE_STRUCT_CLK(dcan0_fck, dpll_core_ck_parents, clk_ops_null);
-
-static struct clk dcan1_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(dcan1_fck, NULL);
-DEFINE_STRUCT_CLK(dcan1_fck, dpll_core_ck_parents, clk_ops_null);
-
-static struct clk mcasp0_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(mcasp0_fck, NULL);
-DEFINE_STRUCT_CLK(mcasp0_fck, dpll_core_ck_parents, clk_ops_null);
-
-static struct clk mcasp1_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(mcasp1_fck, NULL);
-DEFINE_STRUCT_CLK(mcasp1_fck, dpll_core_ck_parents, clk_ops_null);
-
-static struct clk smartreflex0_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(smartreflex0_fck, NULL);
-DEFINE_STRUCT_CLK(smartreflex0_fck, dpll_core_ck_parents, clk_ops_null);
-
-static struct clk smartreflex1_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(smartreflex1_fck, NULL);
-DEFINE_STRUCT_CLK(smartreflex1_fck, dpll_core_ck_parents, clk_ops_null);
-
-static struct clk sha0_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(sha0_fck, NULL);
-DEFINE_STRUCT_CLK(sha0_fck, dpll_core_ck_parents, clk_ops_null);
-
-static struct clk aes0_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(aes0_fck, NULL);
-DEFINE_STRUCT_CLK(aes0_fck, dpll_core_ck_parents, clk_ops_null);
-
-static struct clk rng_fck;
-DEFINE_STRUCT_CLK_HW_OMAP(rng_fck, NULL);
-DEFINE_STRUCT_CLK(rng_fck, dpll_core_ck_parents, clk_ops_null);
-
-/*
- * Modules clock nodes
- *
- * The following clock leaf nodes are added for the moment because:
- *
- *  - hwmod data is not present for these modules, either hwmod
- *    control is not required or its not populated.
- *  - Driver code is not yet migrated to use hwmod/runtime pm
- *  - Modules outside kernel access (to disable them by default)
- *
- *     - mmu (gfx domain)
- *     - cefuse
- *     - usbotg_fck (its additional clock and not really a modulemode)
- *     - ieee5000
- */
-
-DEFINE_CLK_GATE(mmu_fck, "dpll_core_m4_ck", &dpll_core_m4_ck, 0x0,
-               AM33XX_CM_GFX_MMUDATA_CLKCTRL, AM33XX_MODULEMODE_SWCTRL_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_GATE(cefuse_fck, "sys_clkin_ck", &sys_clkin_ck, 0x0,
-               AM33XX_CM_CEFUSE_CEFUSE_CLKCTRL, AM33XX_MODULEMODE_SWCTRL_SHIFT,
-               0x0, NULL);
-
-/*
- * clkdiv32 is generated from fixed division of 732.4219
- */
-DEFINE_CLK_FIXED_FACTOR(clkdiv32k_ck, "clk_24mhz", &clk_24mhz, 0x0, 1, 732);
-
-static struct clk clkdiv32k_ick;
-
-static const char *clkdiv32k_ick_parent_names[] = {
-       "clkdiv32k_ck",
-};
-
-static const struct clk_ops clkdiv32k_ick_ops = {
-       .enable         = &omap2_dflt_clk_enable,
-       .disable        = &omap2_dflt_clk_disable,
-       .is_enabled     = &omap2_dflt_clk_is_enabled,
-       .init           = &omap2_init_clk_clkdm,
-};
-
-static struct clk_hw_omap clkdiv32k_ick_hw = {
-       .hw     = {
-               .clk    = &clkdiv32k_ick,
-       },
-       .enable_reg     = AM33XX_CM_PER_CLKDIV32K_CLKCTRL,
-       .enable_bit     = AM33XX_MODULEMODE_SWCTRL_SHIFT,
-       .clkdm_name     = "clk_24mhz_clkdm",
-};
-
-DEFINE_STRUCT_CLK(clkdiv32k_ick, clkdiv32k_ick_parent_names, clkdiv32k_ick_ops);
-
-/* "usbotg_fck" is an additional clock and not really a modulemode */
-DEFINE_CLK_GATE(usbotg_fck, "dpll_per_ck", &dpll_per_ck, 0x0,
-               AM33XX_CM_CLKDCOLDO_DPLL_PER, AM33XX_ST_DPLL_CLKDCOLDO_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_GATE(ieee5000_fck, "dpll_core_m4_div2_ck", &dpll_core_m4_div2_ck,
-               0x0, AM33XX_CM_PER_IEEE5000_CLKCTRL,
-               AM33XX_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-/* Timers */
-static const struct clksel timer1_clkmux_sel[] = {
-       { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
-       { .parent = &clkdiv32k_ick, .rates = div_1_1_rates },
-       { .parent = &tclkin_ck, .rates = div_1_2_rates },
-       { .parent = &clk_rc32k_ck, .rates = div_1_3_rates },
-       { .parent = &clk_32768_ck, .rates = div_1_4_rates },
-       { .parent = NULL },
-};
-
-static const char *timer1_ck_parents[] = {
-       "sys_clkin_ck", "clkdiv32k_ick", "tclkin_ck", "clk_rc32k_ck",
-       "clk_32768_ck",
-};
-
-static struct clk timer1_fck;
-
-static const struct clk_ops timer1_fck_ops = {
-       .recalc_rate    = &omap2_clksel_recalc,
-       .get_parent     = &omap2_clksel_find_parent_index,
-       .set_parent     = &omap2_clksel_set_parent,
-       .init           = &omap2_init_clk_clkdm,
-};
-
-static struct clk_hw_omap timer1_fck_hw = {
-       .hw     = {
-               .clk    = &timer1_fck,
-       },
-       .clkdm_name     = "l4ls_clkdm",
-       .clksel         = timer1_clkmux_sel,
-       .clksel_reg     = AM33XX_CLKSEL_TIMER1MS_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_2_MASK,
-};
-
-DEFINE_STRUCT_CLK(timer1_fck, timer1_ck_parents, timer1_fck_ops);
-
-static const struct clksel timer2_to_7_clk_sel[] = {
-       { .parent = &tclkin_ck, .rates = div_1_0_rates },
-       { .parent = &sys_clkin_ck, .rates = div_1_1_rates },
-       { .parent = &clkdiv32k_ick, .rates = div_1_2_rates },
-       { .parent = NULL },
-};
-
-static const char *timer2_to_7_ck_parents[] = {
-       "tclkin_ck", "sys_clkin_ck", "clkdiv32k_ick",
-};
-
-static struct clk timer2_fck;
-
-static struct clk_hw_omap timer2_fck_hw = {
-       .hw     = {
-               .clk    = &timer2_fck,
-       },
-       .clkdm_name     = "l4ls_clkdm",
-       .clksel         = timer2_to_7_clk_sel,
-       .clksel_reg     = AM33XX_CLKSEL_TIMER2_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_1_MASK,
-};
-
-DEFINE_STRUCT_CLK(timer2_fck, timer2_to_7_ck_parents, timer1_fck_ops);
-
-static struct clk timer3_fck;
-
-static struct clk_hw_omap timer3_fck_hw = {
-       .hw     = {
-               .clk    = &timer3_fck,
-       },
-       .clkdm_name     = "l4ls_clkdm",
-       .clksel         = timer2_to_7_clk_sel,
-       .clksel_reg     = AM33XX_CLKSEL_TIMER3_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_1_MASK,
-};
-
-DEFINE_STRUCT_CLK(timer3_fck, timer2_to_7_ck_parents, timer1_fck_ops);
-
-static struct clk timer4_fck;
-
-static struct clk_hw_omap timer4_fck_hw = {
-       .hw     = {
-               .clk    = &timer4_fck,
-       },
-       .clkdm_name     = "l4ls_clkdm",
-       .clksel         = timer2_to_7_clk_sel,
-       .clksel_reg     = AM33XX_CLKSEL_TIMER4_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_1_MASK,
-};
-
-DEFINE_STRUCT_CLK(timer4_fck, timer2_to_7_ck_parents, timer1_fck_ops);
-
-static struct clk timer5_fck;
-
-static struct clk_hw_omap timer5_fck_hw = {
-       .hw     = {
-               .clk    = &timer5_fck,
-       },
-       .clkdm_name     = "l4ls_clkdm",
-       .clksel         = timer2_to_7_clk_sel,
-       .clksel_reg     = AM33XX_CLKSEL_TIMER5_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_1_MASK,
-};
-
-DEFINE_STRUCT_CLK(timer5_fck, timer2_to_7_ck_parents, timer1_fck_ops);
-
-static struct clk timer6_fck;
-
-static struct clk_hw_omap timer6_fck_hw = {
-       .hw     = {
-               .clk    = &timer6_fck,
-       },
-       .clkdm_name     = "l4ls_clkdm",
-       .clksel         = timer2_to_7_clk_sel,
-       .clksel_reg     = AM33XX_CLKSEL_TIMER6_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_1_MASK,
-};
-
-DEFINE_STRUCT_CLK(timer6_fck, timer2_to_7_ck_parents, timer1_fck_ops);
-
-static struct clk timer7_fck;
-
-static struct clk_hw_omap timer7_fck_hw = {
-       .hw     = {
-               .clk    = &timer7_fck,
-       },
-       .clkdm_name     = "l4ls_clkdm",
-       .clksel         = timer2_to_7_clk_sel,
-       .clksel_reg     = AM33XX_CLKSEL_TIMER7_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_1_MASK,
-};
-
-DEFINE_STRUCT_CLK(timer7_fck, timer2_to_7_ck_parents, timer1_fck_ops);
-
-DEFINE_CLK_FIXED_FACTOR(cpsw_125mhz_gclk,
-                       "dpll_core_m5_ck",
-                       &dpll_core_m5_ck,
-                       0x0,
-                       1, 2);
-
-static const struct clk_ops cpsw_fck_ops = {
-       .recalc_rate    = &omap2_clksel_recalc,
-       .get_parent     = &omap2_clksel_find_parent_index,
-       .set_parent     = &omap2_clksel_set_parent,
-};
-
-static const struct clksel cpsw_cpts_rft_clkmux_sel[] = {
-       { .parent = &dpll_core_m5_ck, .rates = div_1_0_rates },
-       { .parent = &dpll_core_m4_ck, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-static const char *cpsw_cpts_rft_ck_parents[] = {
-       "dpll_core_m5_ck", "dpll_core_m4_ck",
-};
-
-static struct clk cpsw_cpts_rft_clk;
-
-static struct clk_hw_omap cpsw_cpts_rft_clk_hw = {
-       .hw     = {
-               .clk    = &cpsw_cpts_rft_clk,
-       },
-       .clkdm_name     = "cpsw_125mhz_clkdm",
-       .clksel         = cpsw_cpts_rft_clkmux_sel,
-       .clksel_reg     = AM33XX_CM_CPTS_RFT_CLKSEL,
-       .clksel_mask    = AM33XX_CLKSEL_0_0_MASK,
-};
-
-DEFINE_STRUCT_CLK(cpsw_cpts_rft_clk, cpsw_cpts_rft_ck_parents, cpsw_fck_ops);
-
-
-/* gpio */
-static const char *gpio0_ck_parents[] = {
-       "clk_rc32k_ck", "clk_32768_ck", "clkdiv32k_ick",
-};
-
-static const struct clksel gpio0_dbclk_mux_sel[] = {
-       { .parent = &clk_rc32k_ck, .rates = div_1_0_rates },
-       { .parent = &clk_32768_ck, .rates = div_1_1_rates },
-       { .parent = &clkdiv32k_ick, .rates = div_1_2_rates },
-       { .parent = NULL },
-};
-
-static const struct clk_ops gpio_fck_ops = {
-       .recalc_rate    = &omap2_clksel_recalc,
-       .get_parent     = &omap2_clksel_find_parent_index,
-       .set_parent     = &omap2_clksel_set_parent,
-       .init           = &omap2_init_clk_clkdm,
-};
-
-static struct clk gpio0_dbclk_mux_ck;
-
-static struct clk_hw_omap gpio0_dbclk_mux_ck_hw = {
-       .hw     = {
-               .clk    = &gpio0_dbclk_mux_ck,
-       },
-       .clkdm_name     = "l4_wkup_clkdm",
-       .clksel         = gpio0_dbclk_mux_sel,
-       .clksel_reg     = AM33XX_CLKSEL_GPIO0_DBCLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_1_MASK,
-};
-
-DEFINE_STRUCT_CLK(gpio0_dbclk_mux_ck, gpio0_ck_parents, gpio_fck_ops);
-
-DEFINE_CLK_GATE(gpio0_dbclk, "gpio0_dbclk_mux_ck", &gpio0_dbclk_mux_ck, 0x0,
-               AM33XX_CM_WKUP_GPIO0_CLKCTRL,
-               AM33XX_OPTFCLKEN_GPIO0_GDBCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(gpio1_dbclk, "clkdiv32k_ick", &clkdiv32k_ick, 0x0,
-               AM33XX_CM_PER_GPIO1_CLKCTRL,
-               AM33XX_OPTFCLKEN_GPIO_1_GDBCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(gpio2_dbclk, "clkdiv32k_ick", &clkdiv32k_ick, 0x0,
-               AM33XX_CM_PER_GPIO2_CLKCTRL,
-               AM33XX_OPTFCLKEN_GPIO_2_GDBCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(gpio3_dbclk, "clkdiv32k_ick", &clkdiv32k_ick, 0x0,
-               AM33XX_CM_PER_GPIO3_CLKCTRL,
-               AM33XX_OPTFCLKEN_GPIO_3_GDBCLK_SHIFT, 0x0, NULL);
-
-
-static const char *pruss_ck_parents[] = {
-       "l3_gclk", "dpll_disp_m2_ck",
-};
-
-static const struct clksel pruss_ocp_clk_mux_sel[] = {
-       { .parent = &l3_gclk, .rates = div_1_0_rates },
-       { .parent = &dpll_disp_m2_ck, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-static struct clk pruss_ocp_gclk;
-
-static struct clk_hw_omap pruss_ocp_gclk_hw = {
-       .hw     = {
-               .clk    = &pruss_ocp_gclk,
-       },
-       .clkdm_name     = "pruss_ocp_clkdm",
-       .clksel         = pruss_ocp_clk_mux_sel,
-       .clksel_reg     = AM33XX_CLKSEL_PRUSS_OCP_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_0_MASK,
-};
-
-DEFINE_STRUCT_CLK(pruss_ocp_gclk, pruss_ck_parents, gpio_fck_ops);
-
-static const char *lcd_ck_parents[] = {
-       "dpll_disp_m2_ck", "dpll_core_m5_ck", "dpll_per_m2_ck",
-};
-
-static const struct clksel lcd_clk_mux_sel[] = {
-       { .parent = &dpll_disp_m2_ck, .rates = div_1_0_rates },
-       { .parent = &dpll_core_m5_ck, .rates = div_1_1_rates },
-       { .parent = &dpll_per_m2_ck, .rates = div_1_2_rates },
-       { .parent = NULL },
-};
-
-static struct clk lcd_gclk;
-
-static struct clk_hw_omap lcd_gclk_hw = {
-       .hw     = {
-               .clk    = &lcd_gclk,
-       },
-       .clkdm_name     = "lcdc_clkdm",
-       .clksel         = lcd_clk_mux_sel,
-       .clksel_reg     = AM33XX_CLKSEL_LCDC_PIXEL_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_1_MASK,
-};
-
-DEFINE_STRUCT_CLK_FLAGS(lcd_gclk, lcd_ck_parents,
-                       gpio_fck_ops, CLK_SET_RATE_PARENT);
-
-DEFINE_CLK_FIXED_FACTOR(mmc_clk, "dpll_per_m2_ck", &dpll_per_m2_ck, 0x0, 1, 2);
-
-static const char *gfx_ck_parents[] = {
-       "dpll_core_m4_ck", "dpll_per_m2_ck",
-};
-
-static const struct clksel gfx_clksel_sel[] = {
-       { .parent = &dpll_core_m4_ck, .rates = div_1_0_rates },
-       { .parent = &dpll_per_m2_ck, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-static struct clk gfx_fclk_clksel_ck;
-
-static struct clk_hw_omap gfx_fclk_clksel_ck_hw = {
-       .hw     = {
-               .clk    = &gfx_fclk_clksel_ck,
-       },
-       .clksel         = gfx_clksel_sel,
-       .clksel_reg     = AM33XX_CLKSEL_GFX_FCLK,
-       .clksel_mask    = AM33XX_CLKSEL_GFX_FCLK_MASK,
-};
-
-DEFINE_STRUCT_CLK(gfx_fclk_clksel_ck, gfx_ck_parents, gpio_fck_ops);
-
-static const struct clk_div_table div_1_0_2_1_rates[] = {
-       { .div = 1, .val = 0, },
-       { .div = 2, .val = 1, },
-       { .div = 0 },
-};
-
-DEFINE_CLK_DIVIDER_TABLE(gfx_fck_div_ck, "gfx_fclk_clksel_ck",
-                        &gfx_fclk_clksel_ck, 0x0, AM33XX_CLKSEL_GFX_FCLK,
-                        AM33XX_CLKSEL_0_0_SHIFT, AM33XX_CLKSEL_0_0_WIDTH,
-                        0x0, div_1_0_2_1_rates, NULL);
-
-static const char *sysclkout_ck_parents[] = {
-       "clk_32768_ck", "l3_gclk", "dpll_ddr_m2_ck", "dpll_per_m2_ck",
-       "lcd_gclk",
-};
-
-static const struct clksel sysclkout_pre_sel[] = {
-       { .parent = &clk_32768_ck, .rates = div_1_0_rates },
-       { .parent = &l3_gclk, .rates = div_1_1_rates },
-       { .parent = &dpll_ddr_m2_ck, .rates = div_1_2_rates },
-       { .parent = &dpll_per_m2_ck, .rates = div_1_3_rates },
-       { .parent = &lcd_gclk, .rates = div_1_4_rates },
-       { .parent = NULL },
-};
-
-static struct clk sysclkout_pre_ck;
-
-static struct clk_hw_omap sysclkout_pre_ck_hw = {
-       .hw     = {
-               .clk    = &sysclkout_pre_ck,
-       },
-       .clksel         = sysclkout_pre_sel,
-       .clksel_reg     = AM33XX_CM_CLKOUT_CTRL,
-       .clksel_mask    = AM33XX_CLKOUT2SOURCE_MASK,
-};
-
-DEFINE_STRUCT_CLK(sysclkout_pre_ck, sysclkout_ck_parents, gpio_fck_ops);
-
-/* Divide by 8 clock rates with default clock is 1/1*/
-static const struct clk_div_table div8_rates[] = {
-       { .div = 1, .val = 0, },
-       { .div = 2, .val = 1, },
-       { .div = 3, .val = 2, },
-       { .div = 4, .val = 3, },
-       { .div = 5, .val = 4, },
-       { .div = 6, .val = 5, },
-       { .div = 7, .val = 6, },
-       { .div = 8, .val = 7, },
-       { .div = 0 },
-};
-
-DEFINE_CLK_DIVIDER_TABLE(clkout2_div_ck, "sysclkout_pre_ck", &sysclkout_pre_ck,
-                        0x0, AM33XX_CM_CLKOUT_CTRL, AM33XX_CLKOUT2DIV_SHIFT,
-                        AM33XX_CLKOUT2DIV_WIDTH, 0x0, div8_rates, NULL);
-
-DEFINE_CLK_GATE(clkout2_ck, "clkout2_div_ck", &clkout2_div_ck, 0x0,
-               AM33XX_CM_CLKOUT_CTRL, AM33XX_CLKOUT2EN_SHIFT, 0x0, NULL);
-
-static const char *wdt_ck_parents[] = {
-       "clk_rc32k_ck", "clkdiv32k_ick",
-};
-
-static const struct clksel wdt_clkmux_sel[] = {
-       { .parent = &clk_rc32k_ck, .rates = div_1_0_rates },
-       { .parent = &clkdiv32k_ick, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-static struct clk wdt1_fck;
-
-static struct clk_hw_omap wdt1_fck_hw = {
-       .hw     = {
-               .clk    = &wdt1_fck,
-       },
-       .clkdm_name     = "l4_wkup_clkdm",
-       .clksel         = wdt_clkmux_sel,
-       .clksel_reg     = AM33XX_CLKSEL_WDT1_CLK,
-       .clksel_mask    = AM33XX_CLKSEL_0_1_MASK,
-};
-
-DEFINE_STRUCT_CLK(wdt1_fck, wdt_ck_parents, gpio_fck_ops);
-
-static const char *pwmss_clk_parents[] = {
-       "dpll_per_m2_ck",
-};
-
-static const struct clk_ops ehrpwm_tbclk_ops = {
-       .enable         = &omap2_dflt_clk_enable,
-       .disable        = &omap2_dflt_clk_disable,
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(ehrpwm0_tbclk, "l4ls_clkdm",
-                        NULL, NULL, 0,
-                        AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL),
-                        AM33XX_PWMSS0_TBCLKEN_SHIFT,
-                        NULL, pwmss_clk_parents, ehrpwm_tbclk_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(ehrpwm1_tbclk, "l4ls_clkdm",
-                        NULL, NULL, 0,
-                        AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL),
-                        AM33XX_PWMSS1_TBCLKEN_SHIFT,
-                        NULL, pwmss_clk_parents, ehrpwm_tbclk_ops);
-
-DEFINE_CLK_OMAP_MUX_GATE(ehrpwm2_tbclk, "l4ls_clkdm",
-                        NULL, NULL, 0,
-                        AM33XX_CTRL_REGADDR(AM33XX_PWMSS_TBCLK_CLKCTRL),
-                        AM33XX_PWMSS2_TBCLKEN_SHIFT,
-                        NULL, pwmss_clk_parents, ehrpwm_tbclk_ops);
-
-/*
- * debugss optional clocks
- */
-DEFINE_CLK_GATE(dbg_sysclk_ck, "sys_clkin_ck", &sys_clkin_ck,
-               0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL,
-               AM33XX_OPTFCLKEN_DBGSYSCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(dbg_clka_ck, "dpll_core_m4_ck", &dpll_core_m4_ck,
-               0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL,
-               AM33XX_OPTCLK_DEBUG_CLKA_SHIFT, 0x0, NULL);
-
-static const char *stm_pmd_clock_mux_ck_parents[] = {
-       "dbg_sysclk_ck", "dbg_clka_ck",
-};
-
-DEFINE_CLK_MUX(stm_pmd_clock_mux_ck, stm_pmd_clock_mux_ck_parents, NULL, 0x0,
-              AM33XX_CM_WKUP_DEBUGSS_CLKCTRL, AM33XX_STM_PMD_CLKSEL_SHIFT,
-              AM33XX_STM_PMD_CLKSEL_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_MUX(trace_pmd_clk_mux_ck, stm_pmd_clock_mux_ck_parents, NULL, 0x0,
-              AM33XX_CM_WKUP_DEBUGSS_CLKCTRL,
-              AM33XX_TRC_PMD_CLKSEL_SHIFT,
-              AM33XX_TRC_PMD_CLKSEL_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_DIVIDER(stm_clk_div_ck, "stm_pmd_clock_mux_ck",
-                  &stm_pmd_clock_mux_ck, 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL,
-                  AM33XX_STM_PMD_CLKDIVSEL_SHIFT,
-                  AM33XX_STM_PMD_CLKDIVSEL_WIDTH, CLK_DIVIDER_POWER_OF_TWO,
-                  NULL);
-
-DEFINE_CLK_DIVIDER(trace_clk_div_ck, "trace_pmd_clk_mux_ck",
-                  &trace_pmd_clk_mux_ck, 0x0, AM33XX_CM_WKUP_DEBUGSS_CLKCTRL,
-                  AM33XX_TRC_PMD_CLKDIVSEL_SHIFT,
-                  AM33XX_TRC_PMD_CLKDIVSEL_WIDTH, CLK_DIVIDER_POWER_OF_TWO,
-                  NULL);
-
-/*
- * clkdev
- */
-static struct omap_clk am33xx_clks[] = {
-       CLK(NULL,       "clk_32768_ck",         &clk_32768_ck),
-       CLK(NULL,       "clk_rc32k_ck",         &clk_rc32k_ck),
-       CLK(NULL,       "virt_19200000_ck",     &virt_19200000_ck),
-       CLK(NULL,       "virt_24000000_ck",     &virt_24000000_ck),
-       CLK(NULL,       "virt_25000000_ck",     &virt_25000000_ck),
-       CLK(NULL,       "virt_26000000_ck",     &virt_26000000_ck),
-       CLK(NULL,       "sys_clkin_ck",         &sys_clkin_ck),
-       CLK(NULL,       "tclkin_ck",            &tclkin_ck),
-       CLK(NULL,       "dpll_core_ck",         &dpll_core_ck),
-       CLK(NULL,       "dpll_core_x2_ck",      &dpll_core_x2_ck),
-       CLK(NULL,       "dpll_core_m4_ck",      &dpll_core_m4_ck),
-       CLK(NULL,       "dpll_core_m5_ck",      &dpll_core_m5_ck),
-       CLK(NULL,       "dpll_core_m6_ck",      &dpll_core_m6_ck),
-       CLK(NULL,       "dpll_mpu_ck",          &dpll_mpu_ck),
-       CLK("cpu0",     NULL,                   &dpll_mpu_ck),
-       CLK(NULL,       "dpll_mpu_m2_ck",       &dpll_mpu_m2_ck),
-       CLK(NULL,       "dpll_ddr_ck",          &dpll_ddr_ck),
-       CLK(NULL,       "dpll_ddr_m2_ck",       &dpll_ddr_m2_ck),
-       CLK(NULL,       "dpll_ddr_m2_div2_ck",  &dpll_ddr_m2_div2_ck),
-       CLK(NULL,       "dpll_disp_ck",         &dpll_disp_ck),
-       CLK(NULL,       "dpll_disp_m2_ck",      &dpll_disp_m2_ck),
-       CLK(NULL,       "dpll_per_ck",          &dpll_per_ck),
-       CLK(NULL,       "dpll_per_m2_ck",       &dpll_per_m2_ck),
-       CLK(NULL,       "dpll_per_m2_div4_wkupdm_ck",   &dpll_per_m2_div4_wkupdm_ck),
-       CLK(NULL,       "dpll_per_m2_div4_ck",  &dpll_per_m2_div4_ck),
-       CLK(NULL,       "adc_tsc_fck",          &adc_tsc_fck),
-       CLK(NULL,       "cefuse_fck",           &cefuse_fck),
-       CLK(NULL,       "clkdiv32k_ck",         &clkdiv32k_ck),
-       CLK(NULL,       "clkdiv32k_ick",        &clkdiv32k_ick),
-       CLK(NULL,       "dcan0_fck",            &dcan0_fck),
-       CLK("481cc000.d_can",   NULL,           &dcan0_fck),
-       CLK(NULL,       "dcan1_fck",            &dcan1_fck),
-       CLK("481d0000.d_can",   NULL,           &dcan1_fck),
-       CLK(NULL,       "pruss_ocp_gclk",       &pruss_ocp_gclk),
-       CLK(NULL,       "mcasp0_fck",           &mcasp0_fck),
-       CLK(NULL,       "mcasp1_fck",           &mcasp1_fck),
-       CLK(NULL,       "mmu_fck",              &mmu_fck),
-       CLK(NULL,       "smartreflex0_fck",     &smartreflex0_fck),
-       CLK(NULL,       "smartreflex1_fck",     &smartreflex1_fck),
-       CLK(NULL,       "sha0_fck",             &sha0_fck),
-       CLK(NULL,       "aes0_fck",             &aes0_fck),
-       CLK(NULL,       "rng_fck",              &rng_fck),
-       CLK(NULL,       "timer1_fck",           &timer1_fck),
-       CLK(NULL,       "timer2_fck",           &timer2_fck),
-       CLK(NULL,       "timer3_fck",           &timer3_fck),
-       CLK(NULL,       "timer4_fck",           &timer4_fck),
-       CLK(NULL,       "timer5_fck",           &timer5_fck),
-       CLK(NULL,       "timer6_fck",           &timer6_fck),
-       CLK(NULL,       "timer7_fck",           &timer7_fck),
-       CLK(NULL,       "usbotg_fck",           &usbotg_fck),
-       CLK(NULL,       "ieee5000_fck",         &ieee5000_fck),
-       CLK(NULL,       "wdt1_fck",             &wdt1_fck),
-       CLK(NULL,       "l4_rtc_gclk",          &l4_rtc_gclk),
-       CLK(NULL,       "l3_gclk",              &l3_gclk),
-       CLK(NULL,       "dpll_core_m4_div2_ck", &dpll_core_m4_div2_ck),
-       CLK(NULL,       "l4hs_gclk",            &l4hs_gclk),
-       CLK(NULL,       "l3s_gclk",             &l3s_gclk),
-       CLK(NULL,       "l4fw_gclk",            &l4fw_gclk),
-       CLK(NULL,       "l4ls_gclk",            &l4ls_gclk),
-       CLK(NULL,       "clk_24mhz",            &clk_24mhz),
-       CLK(NULL,       "sysclk_div_ck",        &sysclk_div_ck),
-       CLK(NULL,       "cpsw_125mhz_gclk",     &cpsw_125mhz_gclk),
-       CLK(NULL,       "cpsw_cpts_rft_clk",    &cpsw_cpts_rft_clk),
-       CLK(NULL,       "gpio0_dbclk_mux_ck",   &gpio0_dbclk_mux_ck),
-       CLK(NULL,       "gpio0_dbclk",          &gpio0_dbclk),
-       CLK(NULL,       "gpio1_dbclk",          &gpio1_dbclk),
-       CLK(NULL,       "gpio2_dbclk",          &gpio2_dbclk),
-       CLK(NULL,       "gpio3_dbclk",          &gpio3_dbclk),
-       CLK(NULL,       "lcd_gclk",             &lcd_gclk),
-       CLK(NULL,       "mmc_clk",              &mmc_clk),
-       CLK(NULL,       "gfx_fclk_clksel_ck",   &gfx_fclk_clksel_ck),
-       CLK(NULL,       "gfx_fck_div_ck",       &gfx_fck_div_ck),
-       CLK(NULL,       "sysclkout_pre_ck",     &sysclkout_pre_ck),
-       CLK(NULL,       "clkout2_div_ck",       &clkout2_div_ck),
-       CLK(NULL,       "timer_32k_ck",         &clkdiv32k_ick),
-       CLK(NULL,       "timer_sys_ck",         &sys_clkin_ck),
-       CLK(NULL,       "dbg_sysclk_ck",        &dbg_sysclk_ck),
-       CLK(NULL,       "dbg_clka_ck",          &dbg_clka_ck),
-       CLK(NULL,       "stm_pmd_clock_mux_ck", &stm_pmd_clock_mux_ck),
-       CLK(NULL,       "trace_pmd_clk_mux_ck", &trace_pmd_clk_mux_ck),
-       CLK(NULL,       "stm_clk_div_ck",       &stm_clk_div_ck),
-       CLK(NULL,       "trace_clk_div_ck",     &trace_clk_div_ck),
-       CLK(NULL,       "clkout2_ck",           &clkout2_ck),
-       CLK("48300200.ehrpwm",  "tbclk",        &ehrpwm0_tbclk),
-       CLK("48302200.ehrpwm",  "tbclk",        &ehrpwm1_tbclk),
-       CLK("48304200.ehrpwm",  "tbclk",        &ehrpwm2_tbclk),
-};
-
-
-static const char *enable_init_clks[] = {
-       "dpll_ddr_m2_ck",
-       "dpll_mpu_m2_ck",
-       "l3_gclk",
-       "l4hs_gclk",
-       "l4fw_gclk",
-       "l4ls_gclk",
-       "clkout2_ck",   /* Required for external peripherals like, Audio codecs */
-};
-
-int __init am33xx_clk_init(void)
-{
-       if (soc_is_am33xx())
-               cpu_mask = RATE_IN_AM33XX;
-
-       omap_clocks_register(am33xx_clks, ARRAY_SIZE(am33xx_clks));
-
-       omap2_clk_disable_autoidle_all();
-
-       omap2_clk_enable_init_clocks(enable_init_clks,
-                                    ARRAY_SIZE(enable_init_clks));
-
-       /* TRM ERRATA: Timer 3 & 6 default parent (TCLKIN) may not be always
-        *    physically present, in such a case HWMOD enabling of
-        *    clock would be failure with default parent. And timer
-        *    probe thinks clock is already enabled, this leads to
-        *    crash upon accessing timer 3 & 6 registers in probe.
-        *    Fix by setting parent of both these timers to master
-        *    oscillator clock.
-        */
-
-       clk_set_parent(&timer3_fck, &sys_clkin_ck);
-       clk_set_parent(&timer6_fck, &sys_clkin_ck);
-       /*
-        * The On-Chip 32K RC Osc clock is not an accurate clock-source as per
-        * the design/spec, so as a result, for example, timer which supposed
-        * to get expired @60Sec, but will expire somewhere ~@40Sec, which is
-        * not expected by any use-case, so change WDT1 clock source to PRCM
-        * 32KHz clock.
-        */
-       clk_set_parent(&wdt1_fck, &clkdiv32k_ick);
-
-       return 0;
-}
diff --git a/arch/arm/mach-omap2/cclock44xx_data.c b/arch/arm/mach-omap2/cclock44xx_data.c
deleted file mode 100644 (file)
index ec0dc0b..0000000
+++ /dev/null
@@ -1,1735 +0,0 @@
-/*
- * OMAP4 Clock data
- *
- * Copyright (C) 2009-2012 Texas Instruments, Inc.
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- * Paul Walmsley (paul@pwsan.com)
- * Rajendra Nayak (rnayak@ti.com)
- * Benoit Cousson (b-cousson@ti.com)
- * Mike Turquette (mturquette@ti.com)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * XXX Some of the ES1 clocks have been removed/changed; once support
- * is added for discriminating clocks by ES level, these should be added back
- * in.
- *
- * XXX All of the remaining MODULEMODE clock nodes should be removed
- * once the drivers are updated to use pm_runtime or to use the appropriate
- * upstream clock node for rate/parent selection.
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/clk-private.h>
-#include <linux/clkdev.h>
-#include <linux/io.h>
-
-#include "soc.h"
-#include "iomap.h"
-#include "clock.h"
-#include "clock44xx.h"
-#include "cm1_44xx.h"
-#include "cm2_44xx.h"
-#include "cm-regbits-44xx.h"
-#include "prm44xx.h"
-#include "prm-regbits-44xx.h"
-#include "control.h"
-#include "scrm44xx.h"
-
-/* OMAP4 modulemode control */
-#define OMAP4430_MODULEMODE_HWCTRL_SHIFT               0
-#define OMAP4430_MODULEMODE_SWCTRL_SHIFT               1
-
-/*
- * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section
- * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK
- * must be set to 196.608 MHz" and hence, the DPLL locked frequency is
- * half of this value.
- */
-#define OMAP4_DPLL_ABE_DEFFREQ                         98304000
-
-/*
- * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section
- * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred
- * locked frequency for the USB DPLL is 960MHz.
- */
-#define OMAP4_DPLL_USB_DEFFREQ                         960000000
-
-/* Root clocks */
-
-DEFINE_CLK_FIXED_RATE(extalt_clkin_ck, CLK_IS_ROOT, 59000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(pad_clks_src_ck, CLK_IS_ROOT, 12000000, 0x0);
-
-DEFINE_CLK_GATE(pad_clks_ck, "pad_clks_src_ck", &pad_clks_src_ck, 0x0,
-               OMAP4430_CM_CLKSEL_ABE, OMAP4430_PAD_CLKS_GATE_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_FIXED_RATE(pad_slimbus_core_clks_ck, CLK_IS_ROOT, 12000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(secure_32k_clk_src_ck, CLK_IS_ROOT, 32768, 0x0);
-
-DEFINE_CLK_FIXED_RATE(slimbus_src_clk, CLK_IS_ROOT, 12000000, 0x0);
-
-DEFINE_CLK_GATE(slimbus_clk, "slimbus_src_clk", &slimbus_src_clk, 0x0,
-               OMAP4430_CM_CLKSEL_ABE, OMAP4430_SLIMBUS_CLK_GATE_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_FIXED_RATE(sys_32k_ck, CLK_IS_ROOT, 32768, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_12000000_ck, CLK_IS_ROOT, 12000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_13000000_ck, CLK_IS_ROOT, 13000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_16800000_ck, CLK_IS_ROOT, 16800000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_19200000_ck, CLK_IS_ROOT, 19200000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_26000000_ck, CLK_IS_ROOT, 26000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_27000000_ck, CLK_IS_ROOT, 27000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(virt_38400000_ck, CLK_IS_ROOT, 38400000, 0x0);
-
-static const char *sys_clkin_ck_parents[] = {
-       "virt_12000000_ck", "virt_13000000_ck", "virt_16800000_ck",
-       "virt_19200000_ck", "virt_26000000_ck", "virt_27000000_ck",
-       "virt_38400000_ck",
-};
-
-DEFINE_CLK_MUX(sys_clkin_ck, sys_clkin_ck_parents, NULL, 0x0,
-              OMAP4430_CM_SYS_CLKSEL, OMAP4430_SYS_CLKSEL_SHIFT,
-              OMAP4430_SYS_CLKSEL_WIDTH, CLK_MUX_INDEX_ONE, NULL);
-
-DEFINE_CLK_FIXED_RATE(tie_low_clock_ck, CLK_IS_ROOT, 0, 0x0);
-
-DEFINE_CLK_FIXED_RATE(utmi_phy_clkout_ck, CLK_IS_ROOT, 60000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(xclk60mhsp1_ck, CLK_IS_ROOT, 60000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(xclk60mhsp2_ck, CLK_IS_ROOT, 60000000, 0x0);
-
-DEFINE_CLK_FIXED_RATE(xclk60motg_ck, CLK_IS_ROOT, 60000000, 0x0);
-
-/* Module clocks and DPLL outputs */
-
-static const char *abe_dpll_bypass_clk_mux_ck_parents[] = {
-       "sys_clkin_ck", "sys_32k_ck",
-};
-
-DEFINE_CLK_MUX(abe_dpll_bypass_clk_mux_ck, abe_dpll_bypass_clk_mux_ck_parents,
-              NULL, 0x0, OMAP4430_CM_L4_WKUP_CLKSEL, OMAP4430_CLKSEL_SHIFT,
-              OMAP4430_CLKSEL_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_MUX(abe_dpll_refclk_mux_ck, abe_dpll_bypass_clk_mux_ck_parents, NULL,
-              0x0, OMAP4430_CM_ABE_PLL_REF_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT,
-              OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL);
-
-/* DPLL_ABE */
-static struct dpll_data dpll_abe_dd = {
-       .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_ABE,
-       .clk_bypass     = &abe_dpll_bypass_clk_mux_ck,
-       .clk_ref        = &abe_dpll_refclk_mux_ck,
-       .control_reg    = OMAP4430_CM_CLKMODE_DPLL_ABE,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_ABE,
-       .idlest_reg     = OMAP4430_CM_IDLEST_DPLL_ABE,
-       .mult_mask      = OMAP4430_DPLL_MULT_MASK,
-       .div1_mask      = OMAP4430_DPLL_DIV_MASK,
-       .enable_mask    = OMAP4430_DPLL_EN_MASK,
-       .autoidle_mask  = OMAP4430_AUTO_DPLL_MODE_MASK,
-       .idlest_mask    = OMAP4430_ST_DPLL_CLK_MASK,
-       .m4xen_mask     = OMAP4430_DPLL_REGM4XEN_MASK,
-       .lpmode_mask    = OMAP4430_DPLL_LPMODE_EN_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-};
-
-
-static const char *dpll_abe_ck_parents[] = {
-       "abe_dpll_refclk_mux_ck",
-};
-
-static struct clk dpll_abe_ck;
-
-static const struct clk_ops dpll_abe_ck_ops = {
-       .enable         = &omap3_noncore_dpll_enable,
-       .disable        = &omap3_noncore_dpll_disable,
-       .recalc_rate    = &omap4_dpll_regm4xen_recalc,
-       .round_rate     = &omap4_dpll_regm4xen_round_rate,
-       .set_rate       = &omap3_noncore_dpll_set_rate,
-       .get_parent     = &omap2_init_dpll_parent,
-};
-
-static struct clk_hw_omap dpll_abe_ck_hw = {
-       .hw = {
-               .clk = &dpll_abe_ck,
-       },
-       .dpll_data      = &dpll_abe_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_abe_ck, dpll_abe_ck_parents, dpll_abe_ck_ops);
-
-static const char *dpll_abe_x2_ck_parents[] = {
-       "dpll_abe_ck",
-};
-
-static struct clk dpll_abe_x2_ck;
-
-static const struct clk_ops dpll_abe_x2_ck_ops = {
-       .recalc_rate    = &omap3_clkoutx2_recalc,
-};
-
-static struct clk_hw_omap dpll_abe_x2_ck_hw = {
-       .hw = {
-               .clk = &dpll_abe_x2_ck,
-       },
-       .flags          = CLOCK_CLKOUTX2,
-       .clksel_reg     = OMAP4430_CM_DIV_M2_DPLL_ABE,
-       .ops            = &clkhwops_omap4_dpllmx,
-};
-
-DEFINE_STRUCT_CLK(dpll_abe_x2_ck, dpll_abe_x2_ck_parents, dpll_abe_x2_ck_ops);
-
-static const struct clk_ops omap_hsdivider_ops = {
-       .set_rate       = &omap2_clksel_set_rate,
-       .recalc_rate    = &omap2_clksel_recalc,
-       .round_rate     = &omap2_clksel_round_rate,
-};
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_abe_m2x2_ck, "dpll_abe_x2_ck", &dpll_abe_x2_ck,
-                         0x0, OMAP4430_CM_DIV_M2_DPLL_ABE,
-                         OMAP4430_DPLL_CLKOUT_DIV_MASK);
-
-DEFINE_CLK_FIXED_FACTOR(abe_24m_fclk, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck,
-                       0x0, 1, 8);
-
-DEFINE_CLK_DIVIDER(abe_clk, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck, 0x0,
-                  OMAP4430_CM_CLKSEL_ABE, OMAP4430_CLKSEL_OPP_SHIFT,
-                  OMAP4430_CLKSEL_OPP_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL);
-
-DEFINE_CLK_DIVIDER(aess_fclk, "abe_clk", &abe_clk, 0x0,
-                  OMAP4430_CM1_ABE_AESS_CLKCTRL,
-                  OMAP4430_CLKSEL_AESS_FCLK_SHIFT,
-                  OMAP4430_CLKSEL_AESS_FCLK_WIDTH,
-                  0x0, NULL);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_abe_m3x2_ck, "dpll_abe_x2_ck", &dpll_abe_x2_ck,
-                         0x0, OMAP4430_CM_DIV_M3_DPLL_ABE,
-                         OMAP4430_DPLL_CLKOUTHIF_DIV_MASK);
-
-static const char *core_hsd_byp_clk_mux_ck_parents[] = {
-       "sys_clkin_ck", "dpll_abe_m3x2_ck",
-};
-
-DEFINE_CLK_MUX(core_hsd_byp_clk_mux_ck, core_hsd_byp_clk_mux_ck_parents, NULL,
-              0x0, OMAP4430_CM_CLKSEL_DPLL_CORE,
-              OMAP4430_DPLL_BYP_CLKSEL_SHIFT, OMAP4430_DPLL_BYP_CLKSEL_WIDTH,
-              0x0, NULL);
-
-/* DPLL_CORE */
-static struct dpll_data dpll_core_dd = {
-       .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_CORE,
-       .clk_bypass     = &core_hsd_byp_clk_mux_ck,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = OMAP4430_CM_CLKMODE_DPLL_CORE,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_CORE,
-       .idlest_reg     = OMAP4430_CM_IDLEST_DPLL_CORE,
-       .mult_mask      = OMAP4430_DPLL_MULT_MASK,
-       .div1_mask      = OMAP4430_DPLL_DIV_MASK,
-       .enable_mask    = OMAP4430_DPLL_EN_MASK,
-       .autoidle_mask  = OMAP4430_AUTO_DPLL_MODE_MASK,
-       .idlest_mask    = OMAP4430_ST_DPLL_CLK_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-};
-
-
-static const char *dpll_core_ck_parents[] = {
-       "sys_clkin_ck", "core_hsd_byp_clk_mux_ck"
-};
-
-static struct clk dpll_core_ck;
-
-static const struct clk_ops dpll_core_ck_ops = {
-       .recalc_rate    = &omap3_dpll_recalc,
-       .get_parent     = &omap2_init_dpll_parent,
-};
-
-static struct clk_hw_omap dpll_core_ck_hw = {
-       .hw = {
-               .clk = &dpll_core_ck,
-       },
-       .dpll_data      = &dpll_core_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_core_ck, dpll_core_ck_parents, dpll_core_ck_ops);
-
-static const char *dpll_core_x2_ck_parents[] = {
-       "dpll_core_ck",
-};
-
-static struct clk dpll_core_x2_ck;
-
-static struct clk_hw_omap dpll_core_x2_ck_hw = {
-       .hw = {
-               .clk = &dpll_core_x2_ck,
-       },
-};
-
-DEFINE_STRUCT_CLK(dpll_core_x2_ck, dpll_core_x2_ck_parents, dpll_abe_x2_ck_ops);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m6x2_ck, "dpll_core_x2_ck",
-                         &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M6_DPLL_CORE,
-                         OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m2_ck, "dpll_core_ck", &dpll_core_ck, 0x0,
-                         OMAP4430_CM_DIV_M2_DPLL_CORE,
-                         OMAP4430_DPLL_CLKOUT_DIV_MASK);
-
-DEFINE_CLK_FIXED_FACTOR(ddrphy_ck, "dpll_core_m2_ck", &dpll_core_m2_ck, 0x0, 1,
-                       2);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m5x2_ck, "dpll_core_x2_ck",
-                         &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M5_DPLL_CORE,
-                         OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK);
-
-DEFINE_CLK_DIVIDER(div_core_ck, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck, 0x0,
-                  OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_CORE_SHIFT,
-                  OMAP4430_CLKSEL_CORE_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_DIVIDER(div_iva_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck,
-                  0x0, OMAP4430_CM_BYPCLK_DPLL_IVA, OMAP4430_CLKSEL_0_1_SHIFT,
-                  OMAP4430_CLKSEL_0_1_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL);
-
-DEFINE_CLK_DIVIDER(div_mpu_hs_clk, "dpll_core_m5x2_ck", &dpll_core_m5x2_ck,
-                  0x0, OMAP4430_CM_BYPCLK_DPLL_MPU, OMAP4430_CLKSEL_0_1_SHIFT,
-                  OMAP4430_CLKSEL_0_1_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m4x2_ck, "dpll_core_x2_ck",
-                         &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M4_DPLL_CORE,
-                         OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK);
-
-DEFINE_CLK_FIXED_FACTOR(dll_clk_div_ck, "dpll_core_m4x2_ck", &dpll_core_m4x2_ck,
-                       0x0, 1, 2);
-
-DEFINE_CLK_DIVIDER(dpll_abe_m2_ck, "dpll_abe_ck", &dpll_abe_ck, 0x0,
-                  OMAP4430_CM_DIV_M2_DPLL_ABE, OMAP4430_DPLL_CLKOUT_DIV_SHIFT,
-                  OMAP4430_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL);
-
-static const struct clk_ops dpll_hsd_ops = {
-       .enable         = &omap2_dflt_clk_enable,
-       .disable        = &omap2_dflt_clk_disable,
-       .is_enabled     = &omap2_dflt_clk_is_enabled,
-       .recalc_rate    = &omap2_clksel_recalc,
-       .get_parent     = &omap2_clksel_find_parent_index,
-       .set_parent     = &omap2_clksel_set_parent,
-       .init           = &omap2_init_clk_clkdm,
-};
-
-static const struct clk_ops func_dmic_abe_gfclk_ops = {
-       .recalc_rate    = &omap2_clksel_recalc,
-       .get_parent     = &omap2_clksel_find_parent_index,
-       .set_parent     = &omap2_clksel_set_parent,
-};
-
-static const char *dpll_core_m3x2_ck_parents[] = {
-       "dpll_core_x2_ck",
-};
-
-static const struct clksel dpll_core_m3x2_div[] = {
-       { .parent = &dpll_core_x2_ck, .rates = div31_1to31_rates },
-       { .parent = NULL },
-};
-
-/* XXX Missing round_rate, set_rate in ops */
-DEFINE_CLK_OMAP_MUX_GATE(dpll_core_m3x2_ck, NULL, dpll_core_m3x2_div,
-                        OMAP4430_CM_DIV_M3_DPLL_CORE,
-                        OMAP4430_DPLL_CLKOUTHIF_DIV_MASK,
-                        OMAP4430_CM_DIV_M3_DPLL_CORE,
-                        OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL,
-                        dpll_core_m3x2_ck_parents, dpll_hsd_ops);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_core_m7x2_ck, "dpll_core_x2_ck",
-                         &dpll_core_x2_ck, 0x0, OMAP4430_CM_DIV_M7_DPLL_CORE,
-                         OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK);
-
-static const char *iva_hsd_byp_clk_mux_ck_parents[] = {
-       "sys_clkin_ck", "div_iva_hs_clk",
-};
-
-DEFINE_CLK_MUX(iva_hsd_byp_clk_mux_ck, iva_hsd_byp_clk_mux_ck_parents, NULL,
-              0x0, OMAP4430_CM_CLKSEL_DPLL_IVA, OMAP4430_DPLL_BYP_CLKSEL_SHIFT,
-              OMAP4430_DPLL_BYP_CLKSEL_WIDTH, 0x0, NULL);
-
-/* DPLL_IVA */
-static struct dpll_data dpll_iva_dd = {
-       .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_IVA,
-       .clk_bypass     = &iva_hsd_byp_clk_mux_ck,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = OMAP4430_CM_CLKMODE_DPLL_IVA,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_IVA,
-       .idlest_reg     = OMAP4430_CM_IDLEST_DPLL_IVA,
-       .mult_mask      = OMAP4430_DPLL_MULT_MASK,
-       .div1_mask      = OMAP4430_DPLL_DIV_MASK,
-       .enable_mask    = OMAP4430_DPLL_EN_MASK,
-       .autoidle_mask  = OMAP4430_AUTO_DPLL_MODE_MASK,
-       .idlest_mask    = OMAP4430_ST_DPLL_CLK_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-};
-
-static const char *dpll_iva_ck_parents[] = {
-       "sys_clkin_ck", "iva_hsd_byp_clk_mux_ck"
-};
-
-static struct clk dpll_iva_ck;
-
-static const struct clk_ops dpll_ck_ops = {
-       .enable         = &omap3_noncore_dpll_enable,
-       .disable        = &omap3_noncore_dpll_disable,
-       .recalc_rate    = &omap3_dpll_recalc,
-       .round_rate     = &omap2_dpll_round_rate,
-       .set_rate       = &omap3_noncore_dpll_set_rate,
-       .get_parent     = &omap2_init_dpll_parent,
-};
-
-static struct clk_hw_omap dpll_iva_ck_hw = {
-       .hw = {
-               .clk = &dpll_iva_ck,
-       },
-       .dpll_data      = &dpll_iva_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_iva_ck, dpll_iva_ck_parents, dpll_ck_ops);
-
-static const char *dpll_iva_x2_ck_parents[] = {
-       "dpll_iva_ck",
-};
-
-static struct clk dpll_iva_x2_ck;
-
-static struct clk_hw_omap dpll_iva_x2_ck_hw = {
-       .hw = {
-               .clk = &dpll_iva_x2_ck,
-       },
-};
-
-DEFINE_STRUCT_CLK(dpll_iva_x2_ck, dpll_iva_x2_ck_parents, dpll_abe_x2_ck_ops);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_iva_m4x2_ck, "dpll_iva_x2_ck", &dpll_iva_x2_ck,
-                         0x0, OMAP4430_CM_DIV_M4_DPLL_IVA,
-                         OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_iva_m5x2_ck, "dpll_iva_x2_ck", &dpll_iva_x2_ck,
-                         0x0, OMAP4430_CM_DIV_M5_DPLL_IVA,
-                         OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK);
-
-/* DPLL_MPU */
-static struct dpll_data dpll_mpu_dd = {
-       .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_MPU,
-       .clk_bypass     = &div_mpu_hs_clk,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = OMAP4430_CM_CLKMODE_DPLL_MPU,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_MPU,
-       .idlest_reg     = OMAP4430_CM_IDLEST_DPLL_MPU,
-       .mult_mask      = OMAP4430_DPLL_MULT_MASK,
-       .div1_mask      = OMAP4430_DPLL_DIV_MASK,
-       .enable_mask    = OMAP4430_DPLL_EN_MASK,
-       .autoidle_mask  = OMAP4430_AUTO_DPLL_MODE_MASK,
-       .idlest_mask    = OMAP4430_ST_DPLL_CLK_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-};
-
-static const char *dpll_mpu_ck_parents[] = {
-       "sys_clkin_ck", "div_mpu_hs_clk"
-};
-
-static struct clk dpll_mpu_ck;
-
-static struct clk_hw_omap dpll_mpu_ck_hw = {
-       .hw = {
-               .clk = &dpll_mpu_ck,
-       },
-       .dpll_data      = &dpll_mpu_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_mpu_ck, dpll_mpu_ck_parents, dpll_ck_ops);
-
-DEFINE_CLK_FIXED_FACTOR(mpu_periphclk, "dpll_mpu_ck", &dpll_mpu_ck, 0x0, 1, 2);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_mpu_m2_ck, "dpll_mpu_ck", &dpll_mpu_ck, 0x0,
-                         OMAP4430_CM_DIV_M2_DPLL_MPU,
-                         OMAP4430_DPLL_CLKOUT_DIV_MASK);
-
-DEFINE_CLK_FIXED_FACTOR(per_hs_clk_div_ck, "dpll_abe_m3x2_ck",
-                       &dpll_abe_m3x2_ck, 0x0, 1, 2);
-
-static const char *per_hsd_byp_clk_mux_ck_parents[] = {
-       "sys_clkin_ck", "per_hs_clk_div_ck",
-};
-
-DEFINE_CLK_MUX(per_hsd_byp_clk_mux_ck, per_hsd_byp_clk_mux_ck_parents, NULL,
-              0x0, OMAP4430_CM_CLKSEL_DPLL_PER, OMAP4430_DPLL_BYP_CLKSEL_SHIFT,
-              OMAP4430_DPLL_BYP_CLKSEL_WIDTH, 0x0, NULL);
-
-/* DPLL_PER */
-static struct dpll_data dpll_per_dd = {
-       .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_PER,
-       .clk_bypass     = &per_hsd_byp_clk_mux_ck,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = OMAP4430_CM_CLKMODE_DPLL_PER,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_PER,
-       .idlest_reg     = OMAP4430_CM_IDLEST_DPLL_PER,
-       .mult_mask      = OMAP4430_DPLL_MULT_MASK,
-       .div1_mask      = OMAP4430_DPLL_DIV_MASK,
-       .enable_mask    = OMAP4430_DPLL_EN_MASK,
-       .autoidle_mask  = OMAP4430_AUTO_DPLL_MODE_MASK,
-       .idlest_mask    = OMAP4430_ST_DPLL_CLK_MASK,
-       .max_multiplier = 2047,
-       .max_divider    = 128,
-       .min_divider    = 1,
-};
-
-static const char *dpll_per_ck_parents[] = {
-       "sys_clkin_ck", "per_hsd_byp_clk_mux_ck"
-};
-
-static struct clk dpll_per_ck;
-
-static struct clk_hw_omap dpll_per_ck_hw = {
-       .hw = {
-               .clk = &dpll_per_ck,
-       },
-       .dpll_data      = &dpll_per_dd,
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_per_ck, dpll_per_ck_parents, dpll_ck_ops);
-
-DEFINE_CLK_DIVIDER(dpll_per_m2_ck, "dpll_per_ck", &dpll_per_ck, 0x0,
-                  OMAP4430_CM_DIV_M2_DPLL_PER, OMAP4430_DPLL_CLKOUT_DIV_SHIFT,
-                  OMAP4430_DPLL_CLKOUT_DIV_WIDTH, CLK_DIVIDER_ONE_BASED, NULL);
-
-static const char *dpll_per_x2_ck_parents[] = {
-       "dpll_per_ck",
-};
-
-static struct clk dpll_per_x2_ck;
-
-static struct clk_hw_omap dpll_per_x2_ck_hw = {
-       .hw = {
-               .clk = &dpll_per_x2_ck,
-       },
-       .flags          = CLOCK_CLKOUTX2,
-       .clksel_reg     = OMAP4430_CM_DIV_M2_DPLL_PER,
-       .ops            = &clkhwops_omap4_dpllmx,
-};
-
-DEFINE_STRUCT_CLK(dpll_per_x2_ck, dpll_per_x2_ck_parents, dpll_abe_x2_ck_ops);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m2x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck,
-                         0x0, OMAP4430_CM_DIV_M2_DPLL_PER,
-                         OMAP4430_DPLL_CLKOUT_DIV_MASK);
-
-static const char *dpll_per_m3x2_ck_parents[] = {
-       "dpll_per_x2_ck",
-};
-
-static const struct clksel dpll_per_m3x2_div[] = {
-       { .parent = &dpll_per_x2_ck, .rates = div31_1to31_rates },
-       { .parent = NULL },
-};
-
-/* XXX Missing round_rate, set_rate in ops */
-DEFINE_CLK_OMAP_MUX_GATE(dpll_per_m3x2_ck, NULL, dpll_per_m3x2_div,
-                        OMAP4430_CM_DIV_M3_DPLL_PER,
-                        OMAP4430_DPLL_CLKOUTHIF_DIV_MASK,
-                        OMAP4430_CM_DIV_M3_DPLL_PER,
-                        OMAP4430_DPLL_CLKOUTHIF_GATE_CTRL_SHIFT, NULL,
-                        dpll_per_m3x2_ck_parents, dpll_hsd_ops);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m4x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck,
-                         0x0, OMAP4430_CM_DIV_M4_DPLL_PER,
-                         OMAP4430_HSDIVIDER_CLKOUT1_DIV_MASK);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m5x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck,
-                         0x0, OMAP4430_CM_DIV_M5_DPLL_PER,
-                         OMAP4430_HSDIVIDER_CLKOUT2_DIV_MASK);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m6x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck,
-                         0x0, OMAP4430_CM_DIV_M6_DPLL_PER,
-                         OMAP4430_HSDIVIDER_CLKOUT3_DIV_MASK);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_per_m7x2_ck, "dpll_per_x2_ck", &dpll_per_x2_ck,
-                         0x0, OMAP4430_CM_DIV_M7_DPLL_PER,
-                         OMAP4430_HSDIVIDER_CLKOUT4_DIV_MASK);
-
-DEFINE_CLK_FIXED_FACTOR(usb_hs_clk_div_ck, "dpll_abe_m3x2_ck",
-                       &dpll_abe_m3x2_ck, 0x0, 1, 3);
-
-/* DPLL_USB */
-static struct dpll_data dpll_usb_dd = {
-       .mult_div1_reg  = OMAP4430_CM_CLKSEL_DPLL_USB,
-       .clk_bypass     = &usb_hs_clk_div_ck,
-       .flags          = DPLL_J_TYPE,
-       .clk_ref        = &sys_clkin_ck,
-       .control_reg    = OMAP4430_CM_CLKMODE_DPLL_USB,
-       .modes          = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
-       .autoidle_reg   = OMAP4430_CM_AUTOIDLE_DPLL_USB,
-       .idlest_reg     = OMAP4430_CM_IDLEST_DPLL_USB,
-       .mult_mask      = OMAP4430_DPLL_MULT_USB_MASK,
-       .div1_mask      = OMAP4430_DPLL_DIV_0_7_MASK,
-       .enable_mask    = OMAP4430_DPLL_EN_MASK,
-       .autoidle_mask  = OMAP4430_AUTO_DPLL_MODE_MASK,
-       .idlest_mask    = OMAP4430_ST_DPLL_CLK_MASK,
-       .sddiv_mask     = OMAP4430_DPLL_SD_DIV_MASK,
-       .max_multiplier = 4095,
-       .max_divider    = 256,
-       .min_divider    = 1,
-};
-
-static const char *dpll_usb_ck_parents[] = {
-       "sys_clkin_ck", "usb_hs_clk_div_ck"
-};
-
-static struct clk dpll_usb_ck;
-
-static const struct clk_ops dpll_usb_ck_ops = {
-       .enable         = &omap3_noncore_dpll_enable,
-       .disable        = &omap3_noncore_dpll_disable,
-       .recalc_rate    = &omap3_dpll_recalc,
-       .round_rate     = &omap2_dpll_round_rate,
-       .set_rate       = &omap3_noncore_dpll_set_rate,
-       .get_parent     = &omap2_init_dpll_parent,
-       .init           = &omap2_init_clk_clkdm,
-};
-
-static struct clk_hw_omap dpll_usb_ck_hw = {
-       .hw = {
-               .clk = &dpll_usb_ck,
-       },
-       .dpll_data      = &dpll_usb_dd,
-       .clkdm_name     = "l3_init_clkdm",
-       .ops            = &clkhwops_omap3_dpll,
-};
-
-DEFINE_STRUCT_CLK(dpll_usb_ck, dpll_usb_ck_parents, dpll_usb_ck_ops);
-
-static const char *dpll_usb_clkdcoldo_ck_parents[] = {
-       "dpll_usb_ck",
-};
-
-static struct clk dpll_usb_clkdcoldo_ck;
-
-static const struct clk_ops dpll_usb_clkdcoldo_ck_ops = {
-};
-
-static struct clk_hw_omap dpll_usb_clkdcoldo_ck_hw = {
-       .hw = {
-               .clk = &dpll_usb_clkdcoldo_ck,
-       },
-       .clksel_reg     = OMAP4430_CM_CLKDCOLDO_DPLL_USB,
-       .ops            = &clkhwops_omap4_dpllmx,
-};
-
-DEFINE_STRUCT_CLK(dpll_usb_clkdcoldo_ck, dpll_usb_clkdcoldo_ck_parents,
-                 dpll_usb_clkdcoldo_ck_ops);
-
-DEFINE_CLK_OMAP_HSDIVIDER(dpll_usb_m2_ck, "dpll_usb_ck", &dpll_usb_ck, 0x0,
-                         OMAP4430_CM_DIV_M2_DPLL_USB,
-                         OMAP4430_DPLL_CLKOUT_DIV_0_6_MASK);
-
-static const char *ducati_clk_mux_ck_parents[] = {
-       "div_core_ck", "dpll_per_m6x2_ck",
-};
-
-DEFINE_CLK_MUX(ducati_clk_mux_ck, ducati_clk_mux_ck_parents, NULL, 0x0,
-              OMAP4430_CM_CLKSEL_DUCATI_ISS_ROOT, OMAP4430_CLKSEL_0_0_SHIFT,
-              OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_FIXED_FACTOR(func_12m_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck,
-                       0x0, 1, 16);
-
-DEFINE_CLK_FIXED_FACTOR(func_24m_clk, "dpll_per_m2_ck", &dpll_per_m2_ck, 0x0,
-                       1, 4);
-
-DEFINE_CLK_FIXED_FACTOR(func_24mc_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck,
-                       0x0, 1, 8);
-
-static const struct clk_div_table func_48m_fclk_rates[] = {
-       { .div = 4, .val = 0 },
-       { .div = 8, .val = 1 },
-       { .div = 0 },
-};
-DEFINE_CLK_DIVIDER_TABLE(func_48m_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck,
-                        0x0, OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT,
-                        OMAP4430_SCALE_FCLK_WIDTH, 0x0, func_48m_fclk_rates,
-                        NULL);
-
-DEFINE_CLK_FIXED_FACTOR(func_48mc_fclk,        "dpll_per_m2x2_ck", &dpll_per_m2x2_ck,
-                       0x0, 1, 4);
-
-static const struct clk_div_table func_64m_fclk_rates[] = {
-       { .div = 2, .val = 0 },
-       { .div = 4, .val = 1 },
-       { .div = 0 },
-};
-DEFINE_CLK_DIVIDER_TABLE(func_64m_fclk, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck,
-                        0x0, OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT,
-                        OMAP4430_SCALE_FCLK_WIDTH, 0x0, func_64m_fclk_rates,
-                        NULL);
-
-static const struct clk_div_table func_96m_fclk_rates[] = {
-       { .div = 2, .val = 0 },
-       { .div = 4, .val = 1 },
-       { .div = 0 },
-};
-DEFINE_CLK_DIVIDER_TABLE(func_96m_fclk, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck,
-                        0x0, OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT,
-                        OMAP4430_SCALE_FCLK_WIDTH, 0x0, func_96m_fclk_rates,
-                        NULL);
-
-static const struct clk_div_table init_60m_fclk_rates[] = {
-       { .div = 1, .val = 0 },
-       { .div = 8, .val = 1 },
-       { .div = 0 },
-};
-DEFINE_CLK_DIVIDER_TABLE(init_60m_fclk, "dpll_usb_m2_ck", &dpll_usb_m2_ck,
-                        0x0, OMAP4430_CM_CLKSEL_USB_60MHZ,
-                        OMAP4430_CLKSEL_0_0_SHIFT, OMAP4430_CLKSEL_0_0_WIDTH,
-                        0x0, init_60m_fclk_rates, NULL);
-
-DEFINE_CLK_DIVIDER(l3_div_ck, "div_core_ck", &div_core_ck, 0x0,
-                  OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_L3_SHIFT,
-                  OMAP4430_CLKSEL_L3_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_DIVIDER(l4_div_ck, "l3_div_ck", &l3_div_ck, 0x0,
-                  OMAP4430_CM_CLKSEL_CORE, OMAP4430_CLKSEL_L4_SHIFT,
-                  OMAP4430_CLKSEL_L4_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_FIXED_FACTOR(lp_clk_div_ck, "dpll_abe_m2x2_ck", &dpll_abe_m2x2_ck,
-                       0x0, 1, 16);
-
-static const char *l4_wkup_clk_mux_ck_parents[] = {
-       "sys_clkin_ck", "lp_clk_div_ck",
-};
-
-DEFINE_CLK_MUX(l4_wkup_clk_mux_ck, l4_wkup_clk_mux_ck_parents, NULL, 0x0,
-              OMAP4430_CM_L4_WKUP_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT,
-              OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL);
-
-static const struct clk_div_table ocp_abe_iclk_rates[] = {
-       { .div = 2, .val = 0 },
-       { .div = 1, .val = 1 },
-       { .div = 0 },
-};
-DEFINE_CLK_DIVIDER_TABLE(ocp_abe_iclk, "aess_fclk", &aess_fclk, 0x0,
-                        OMAP4430_CM1_ABE_AESS_CLKCTRL,
-                        OMAP4430_CLKSEL_AESS_FCLK_SHIFT,
-                        OMAP4430_CLKSEL_AESS_FCLK_WIDTH,
-                        0x0, ocp_abe_iclk_rates, NULL);
-
-DEFINE_CLK_FIXED_FACTOR(per_abe_24m_fclk, "dpll_abe_m2_ck", &dpll_abe_m2_ck,
-                       0x0, 1, 4);
-
-DEFINE_CLK_DIVIDER(per_abe_nc_fclk, "dpll_abe_m2_ck", &dpll_abe_m2_ck, 0x0,
-                  OMAP4430_CM_SCALE_FCLK, OMAP4430_SCALE_FCLK_SHIFT,
-                  OMAP4430_SCALE_FCLK_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_DIVIDER(syc_clk_div_ck, "sys_clkin_ck", &sys_clkin_ck, 0x0,
-                  OMAP4430_CM_ABE_DSS_SYS_CLKSEL, OMAP4430_CLKSEL_0_0_SHIFT,
-                  OMAP4430_CLKSEL_0_0_WIDTH, 0x0, NULL);
-
-static const char *dbgclk_mux_ck_parents[] = {
-       "sys_clkin_ck"
-};
-
-static struct clk dbgclk_mux_ck;
-DEFINE_STRUCT_CLK_HW_OMAP(dbgclk_mux_ck, NULL);
-DEFINE_STRUCT_CLK(dbgclk_mux_ck, dbgclk_mux_ck_parents,
-                 dpll_usb_clkdcoldo_ck_ops);
-
-/* Leaf clocks controlled by modules */
-
-DEFINE_CLK_GATE(aes1_fck, "l3_div_ck", &l3_div_ck, 0x0,
-               OMAP4430_CM_L4SEC_AES1_CLKCTRL,
-               OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(aes2_fck, "l3_div_ck", &l3_div_ck, 0x0,
-               OMAP4430_CM_L4SEC_AES2_CLKCTRL,
-               OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(bandgap_fclk, "sys_32k_ck", &sys_32k_ck, 0x0,
-               OMAP4430_CM_WKUP_BANDGAP_CLKCTRL,
-               OMAP4430_OPTFCLKEN_BGAP_32K_SHIFT, 0x0, NULL);
-
-static const struct clk_div_table div_ts_ck_rates[] = {
-       { .div = 8, .val = 0 },
-       { .div = 16, .val = 1 },
-       { .div = 32, .val = 2 },
-       { .div = 0 },
-};
-DEFINE_CLK_DIVIDER_TABLE(div_ts_ck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck,
-                        0x0, OMAP4430_CM_WKUP_BANDGAP_CLKCTRL,
-                        OMAP4430_CLKSEL_24_25_SHIFT,
-                        OMAP4430_CLKSEL_24_25_WIDTH, 0x0, div_ts_ck_rates,
-                        NULL);
-
-DEFINE_CLK_GATE(bandgap_ts_fclk, "div_ts_ck", &div_ts_ck, 0x0,
-               OMAP4430_CM_WKUP_BANDGAP_CLKCTRL,
-               OMAP4460_OPTFCLKEN_TS_FCLK_SHIFT,
-               0x0, NULL);
-
-static const char *dmic_sync_mux_ck_parents[] = {
-       "abe_24m_fclk", "syc_clk_div_ck", "func_24m_clk",
-};
-
-DEFINE_CLK_MUX(dmic_sync_mux_ck, dmic_sync_mux_ck_parents, NULL,
-              0x0, OMAP4430_CM1_ABE_DMIC_CLKCTRL,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL);
-
-static const struct clksel func_dmic_abe_gfclk_sel[] = {
-       { .parent = &dmic_sync_mux_ck, .rates = div_1_0_rates },
-       { .parent = &pad_clks_ck, .rates = div_1_1_rates },
-       { .parent = &slimbus_clk, .rates = div_1_2_rates },
-       { .parent = NULL },
-};
-
-static const char *func_dmic_abe_gfclk_parents[] = {
-       "dmic_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
-};
-
-DEFINE_CLK_OMAP_MUX(func_dmic_abe_gfclk, "abe_clkdm", func_dmic_abe_gfclk_sel,
-                   OMAP4430_CM1_ABE_DMIC_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK,
-                   func_dmic_abe_gfclk_parents, func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_GATE(dss_sys_clk, "syc_clk_div_ck", &syc_clk_div_ck, 0x0,
-               OMAP4430_CM_DSS_DSS_CLKCTRL,
-               OMAP4430_OPTFCLKEN_SYS_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(dss_tv_clk, "extalt_clkin_ck", &extalt_clkin_ck, 0x0,
-               OMAP4430_CM_DSS_DSS_CLKCTRL,
-               OMAP4430_OPTFCLKEN_TV_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(dss_dss_clk, "dpll_per_m5x2_ck", &dpll_per_m5x2_ck,
-               CLK_SET_RATE_PARENT,
-               OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_OPTFCLKEN_DSSCLK_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_GATE(dss_48mhz_clk, "func_48mc_fclk", &func_48mc_fclk, 0x0,
-               OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_OPTFCLKEN_48MHZ_CLK_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_GATE(dss_fck, "l3_div_ck", &l3_div_ck, 0x0,
-               OMAP4430_CM_DSS_DSS_CLKCTRL, OMAP4430_MODULEMODE_SWCTRL_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_DIVIDER(fdif_fck, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, 0x0,
-                  OMAP4430_CM_CAM_FDIF_CLKCTRL, OMAP4430_CLKSEL_FCLK_SHIFT,
-                  OMAP4430_CLKSEL_FCLK_WIDTH, CLK_DIVIDER_POWER_OF_TWO, NULL);
-
-DEFINE_CLK_GATE(gpio1_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
-               OMAP4430_CM_WKUP_GPIO1_CLKCTRL,
-               OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(gpio2_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
-               OMAP4430_CM_L4PER_GPIO2_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_GATE(gpio3_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
-               OMAP4430_CM_L4PER_GPIO3_CLKCTRL,
-               OMAP4430_OPTFCLKEN_DBCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(gpio4_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
-               OMAP4430_CM_L4PER_GPIO4_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_GATE(gpio5_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
-               OMAP4430_CM_L4PER_GPIO5_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_GATE(gpio6_dbclk, "sys_32k_ck", &sys_32k_ck, 0x0,
-               OMAP4430_CM_L4PER_GPIO6_CLKCTRL, OMAP4430_OPTFCLKEN_DBCLK_SHIFT,
-               0x0, NULL);
-
-static const struct clksel sgx_clk_mux_sel[] = {
-       { .parent = &dpll_core_m7x2_ck, .rates = div_1_0_rates },
-       { .parent = &dpll_per_m7x2_ck, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-static const char *sgx_clk_mux_parents[] = {
-       "dpll_core_m7x2_ck", "dpll_per_m7x2_ck",
-};
-
-DEFINE_CLK_OMAP_MUX(sgx_clk_mux, "l3_gfx_clkdm", sgx_clk_mux_sel,
-                   OMAP4430_CM_GFX_GFX_CLKCTRL, OMAP4430_CLKSEL_SGX_FCLK_MASK,
-                   sgx_clk_mux_parents, func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_DIVIDER(hsi_fck, "dpll_per_m2x2_ck", &dpll_per_m2x2_ck, 0x0,
-                  OMAP4430_CM_L3INIT_HSI_CLKCTRL, OMAP4430_CLKSEL_24_25_SHIFT,
-                  OMAP4430_CLKSEL_24_25_WIDTH, CLK_DIVIDER_POWER_OF_TWO,
-                  NULL);
-
-DEFINE_CLK_GATE(iss_ctrlclk, "func_96m_fclk", &func_96m_fclk, 0x0,
-               OMAP4430_CM_CAM_ISS_CLKCTRL, OMAP4430_OPTFCLKEN_CTRLCLK_SHIFT,
-               0x0, NULL);
-
-DEFINE_CLK_MUX(mcasp_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0,
-              OMAP4430_CM1_ABE_MCASP_CLKCTRL,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL);
-
-static const struct clksel func_mcasp_abe_gfclk_sel[] = {
-       { .parent = &mcasp_sync_mux_ck, .rates = div_1_0_rates },
-       { .parent = &pad_clks_ck, .rates = div_1_1_rates },
-       { .parent = &slimbus_clk, .rates = div_1_2_rates },
-       { .parent = NULL },
-};
-
-static const char *func_mcasp_abe_gfclk_parents[] = {
-       "mcasp_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
-};
-
-DEFINE_CLK_OMAP_MUX(func_mcasp_abe_gfclk, "abe_clkdm", func_mcasp_abe_gfclk_sel,
-                   OMAP4430_CM1_ABE_MCASP_CLKCTRL, OMAP4430_CLKSEL_SOURCE_MASK,
-                   func_mcasp_abe_gfclk_parents, func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_MUX(mcbsp1_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0,
-              OMAP4430_CM1_ABE_MCBSP1_CLKCTRL,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL);
-
-static const struct clksel func_mcbsp1_gfclk_sel[] = {
-       { .parent = &mcbsp1_sync_mux_ck, .rates = div_1_0_rates },
-       { .parent = &pad_clks_ck, .rates = div_1_1_rates },
-       { .parent = &slimbus_clk, .rates = div_1_2_rates },
-       { .parent = NULL },
-};
-
-static const char *func_mcbsp1_gfclk_parents[] = {
-       "mcbsp1_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
-};
-
-DEFINE_CLK_OMAP_MUX(func_mcbsp1_gfclk, "abe_clkdm", func_mcbsp1_gfclk_sel,
-                   OMAP4430_CM1_ABE_MCBSP1_CLKCTRL,
-                   OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp1_gfclk_parents,
-                   func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_MUX(mcbsp2_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0,
-              OMAP4430_CM1_ABE_MCBSP2_CLKCTRL,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL);
-
-static const struct clksel func_mcbsp2_gfclk_sel[] = {
-       { .parent = &mcbsp2_sync_mux_ck, .rates = div_1_0_rates },
-       { .parent = &pad_clks_ck, .rates = div_1_1_rates },
-       { .parent = &slimbus_clk, .rates = div_1_2_rates },
-       { .parent = NULL },
-};
-
-static const char *func_mcbsp2_gfclk_parents[] = {
-       "mcbsp2_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
-};
-
-DEFINE_CLK_OMAP_MUX(func_mcbsp2_gfclk, "abe_clkdm", func_mcbsp2_gfclk_sel,
-                   OMAP4430_CM1_ABE_MCBSP2_CLKCTRL,
-                   OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp2_gfclk_parents,
-                   func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_MUX(mcbsp3_sync_mux_ck, dmic_sync_mux_ck_parents, NULL, 0x0,
-              OMAP4430_CM1_ABE_MCBSP3_CLKCTRL,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL);
-
-static const struct clksel func_mcbsp3_gfclk_sel[] = {
-       { .parent = &mcbsp3_sync_mux_ck, .rates = div_1_0_rates },
-       { .parent = &pad_clks_ck, .rates = div_1_1_rates },
-       { .parent = &slimbus_clk, .rates = div_1_2_rates },
-       { .parent = NULL },
-};
-
-static const char *func_mcbsp3_gfclk_parents[] = {
-       "mcbsp3_sync_mux_ck", "pad_clks_ck", "slimbus_clk",
-};
-
-DEFINE_CLK_OMAP_MUX(func_mcbsp3_gfclk, "abe_clkdm", func_mcbsp3_gfclk_sel,
-                   OMAP4430_CM1_ABE_MCBSP3_CLKCTRL,
-                   OMAP4430_CLKSEL_SOURCE_MASK, func_mcbsp3_gfclk_parents,
-                   func_dmic_abe_gfclk_ops);
-
-static const char *mcbsp4_sync_mux_ck_parents[] = {
-       "func_96m_fclk", "per_abe_nc_fclk",
-};
-
-DEFINE_CLK_MUX(mcbsp4_sync_mux_ck, mcbsp4_sync_mux_ck_parents, NULL, 0x0,
-              OMAP4430_CM_L4PER_MCBSP4_CLKCTRL,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_SHIFT,
-              OMAP4430_CLKSEL_INTERNAL_SOURCE_WIDTH, 0x0, NULL);
-
-static const struct clksel per_mcbsp4_gfclk_sel[] = {
-       { .parent = &mcbsp4_sync_mux_ck, .rates = div_1_0_rates },
-       { .parent = &pad_clks_ck, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-static const char *per_mcbsp4_gfclk_parents[] = {
-       "mcbsp4_sync_mux_ck", "pad_clks_ck",
-};
-
-DEFINE_CLK_OMAP_MUX(per_mcbsp4_gfclk, "l4_per_clkdm", per_mcbsp4_gfclk_sel,
-                   OMAP4430_CM_L4PER_MCBSP4_CLKCTRL,
-                   OMAP4430_CLKSEL_SOURCE_24_24_MASK, per_mcbsp4_gfclk_parents,
-                   func_dmic_abe_gfclk_ops);
-
-static const struct clksel hsmmc1_fclk_sel[] = {
-       { .parent = &func_64m_fclk, .rates = div_1_0_rates },
-       { .parent = &func_96m_fclk, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-static const char *hsmmc1_fclk_parents[] = {
-       "func_64m_fclk", "func_96m_fclk",
-};
-
-DEFINE_CLK_OMAP_MUX(hsmmc1_fclk, "l3_init_clkdm", hsmmc1_fclk_sel,
-                   OMAP4430_CM_L3INIT_MMC1_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(hsmmc2_fclk, "l3_init_clkdm", hsmmc1_fclk_sel,
-                   OMAP4430_CM_L3INIT_MMC2_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   hsmmc1_fclk_parents, func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_GATE(ocp2scp_usb_phy_phy_48m, "func_48m_fclk", &func_48m_fclk, 0x0,
-               OMAP4430_CM_L3INIT_USBPHYOCP2SCP_CLKCTRL,
-               OMAP4430_OPTFCLKEN_PHY_48M_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(sha2md5_fck, "l3_div_ck", &l3_div_ck, 0x0,
-               OMAP4430_CM_L4SEC_SHA2MD51_CLKCTRL,
-               OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(slimbus1_fclk_1, "func_24m_clk", &func_24m_clk, 0x0,
-               OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
-               OMAP4430_OPTFCLKEN_FCLK1_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(slimbus1_fclk_0, "abe_24m_fclk", &abe_24m_fclk, 0x0,
-               OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
-               OMAP4430_OPTFCLKEN_FCLK0_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(slimbus1_fclk_2, "pad_clks_ck", &pad_clks_ck, 0x0,
-               OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
-               OMAP4430_OPTFCLKEN_FCLK2_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(slimbus1_slimbus_clk, "slimbus_clk", &slimbus_clk, 0x0,
-               OMAP4430_CM1_ABE_SLIMBUS_CLKCTRL,
-               OMAP4430_OPTFCLKEN_SLIMBUS_CLK_11_11_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(slimbus2_fclk_1, "per_abe_24m_fclk", &per_abe_24m_fclk, 0x0,
-               OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
-               OMAP4430_OPTFCLKEN_PERABE24M_GFCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(slimbus2_fclk_0, "func_24mc_fclk", &func_24mc_fclk, 0x0,
-               OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
-               OMAP4430_OPTFCLKEN_PER24MC_GFCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(slimbus2_slimbus_clk, "pad_slimbus_core_clks_ck",
-               &pad_slimbus_core_clks_ck, 0x0,
-               OMAP4430_CM_L4PER_SLIMBUS2_CLKCTRL,
-               OMAP4430_OPTFCLKEN_SLIMBUS_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(smartreflex_core_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck,
-               0x0, OMAP4430_CM_ALWON_SR_CORE_CLKCTRL,
-               OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(smartreflex_iva_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck,
-               0x0, OMAP4430_CM_ALWON_SR_IVA_CLKCTRL,
-               OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(smartreflex_mpu_fck, "l4_wkup_clk_mux_ck", &l4_wkup_clk_mux_ck,
-               0x0, OMAP4430_CM_ALWON_SR_MPU_CLKCTRL,
-               OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-static const struct clksel dmt1_clk_mux_sel[] = {
-       { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
-       { .parent = &sys_32k_ck, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-DEFINE_CLK_OMAP_MUX(dmt1_clk_mux, "l4_wkup_clkdm", dmt1_clk_mux_sel,
-                   OMAP4430_CM_WKUP_TIMER1_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   abe_dpll_bypass_clk_mux_ck_parents,
-                   func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(cm2_dm10_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
-                   OMAP4430_CM_L4PER_DMTIMER10_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   abe_dpll_bypass_clk_mux_ck_parents,
-                   func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(cm2_dm11_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
-                   OMAP4430_CM_L4PER_DMTIMER11_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   abe_dpll_bypass_clk_mux_ck_parents,
-                   func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(cm2_dm2_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
-                   OMAP4430_CM_L4PER_DMTIMER2_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   abe_dpll_bypass_clk_mux_ck_parents,
-                   func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(cm2_dm3_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
-                   OMAP4430_CM_L4PER_DMTIMER3_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   abe_dpll_bypass_clk_mux_ck_parents,
-                   func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(cm2_dm4_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
-                   OMAP4430_CM_L4PER_DMTIMER4_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   abe_dpll_bypass_clk_mux_ck_parents,
-                   func_dmic_abe_gfclk_ops);
-
-static const struct clksel timer5_sync_mux_sel[] = {
-       { .parent = &syc_clk_div_ck, .rates = div_1_0_rates },
-       { .parent = &sys_32k_ck, .rates = div_1_1_rates },
-       { .parent = NULL },
-};
-
-static const char *timer5_sync_mux_parents[] = {
-       "syc_clk_div_ck", "sys_32k_ck",
-};
-
-DEFINE_CLK_OMAP_MUX(timer5_sync_mux, "abe_clkdm", timer5_sync_mux_sel,
-                   OMAP4430_CM1_ABE_TIMER5_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   timer5_sync_mux_parents, func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(timer6_sync_mux, "abe_clkdm", timer5_sync_mux_sel,
-                   OMAP4430_CM1_ABE_TIMER6_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   timer5_sync_mux_parents, func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(timer7_sync_mux, "abe_clkdm", timer5_sync_mux_sel,
-                   OMAP4430_CM1_ABE_TIMER7_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   timer5_sync_mux_parents, func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(timer8_sync_mux, "abe_clkdm", timer5_sync_mux_sel,
-                   OMAP4430_CM1_ABE_TIMER8_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   timer5_sync_mux_parents, func_dmic_abe_gfclk_ops);
-
-DEFINE_CLK_OMAP_MUX(cm2_dm9_mux, "l4_per_clkdm", dmt1_clk_mux_sel,
-                   OMAP4430_CM_L4PER_DMTIMER9_CLKCTRL, OMAP4430_CLKSEL_MASK,
-                   abe_dpll_bypass_clk_mux_ck_parents,
-                   func_dmic_abe_gfclk_ops);
-
-static struct clk usb_host_fs_fck;
-
-static const char *usb_host_fs_fck_parent_names[] = {
-       "func_48mc_fclk",
-};
-
-static const struct clk_ops usb_host_fs_fck_ops = {
-       .enable         = &omap2_dflt_clk_enable,
-       .disable        = &omap2_dflt_clk_disable,
-       .is_enabled     = &omap2_dflt_clk_is_enabled,
-};
-
-static struct clk_hw_omap usb_host_fs_fck_hw = {
-       .hw = {
-               .clk = &usb_host_fs_fck,
-       },
-       .enable_reg     = OMAP4430_CM_L3INIT_USB_HOST_FS_CLKCTRL,
-       .enable_bit     = OMAP4430_MODULEMODE_SWCTRL_SHIFT,
-       .clkdm_name     = "l3_init_clkdm",
-};
-
-DEFINE_STRUCT_CLK(usb_host_fs_fck, usb_host_fs_fck_parent_names,
-                 usb_host_fs_fck_ops);
-
-static const char *utmi_p1_gfclk_parents[] = {
-       "init_60m_fclk", "xclk60mhsp1_ck",
-};
-
-DEFINE_CLK_MUX(utmi_p1_gfclk, utmi_p1_gfclk_parents, NULL, 0x0,
-              OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-              OMAP4430_CLKSEL_UTMI_P1_SHIFT, OMAP4430_CLKSEL_UTMI_P1_WIDTH,
-              0x0, NULL);
-
-DEFINE_CLK_GATE(usb_host_hs_utmi_p1_clk, "utmi_p1_gfclk", &utmi_p1_gfclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-               OMAP4430_OPTFCLKEN_UTMI_P1_CLK_SHIFT, 0x0, NULL);
-
-static const char *utmi_p2_gfclk_parents[] = {
-       "init_60m_fclk", "xclk60mhsp2_ck",
-};
-
-DEFINE_CLK_MUX(utmi_p2_gfclk, utmi_p2_gfclk_parents, NULL, 0x0,
-              OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-              OMAP4430_CLKSEL_UTMI_P2_SHIFT, OMAP4430_CLKSEL_UTMI_P2_WIDTH,
-              0x0, NULL);
-
-DEFINE_CLK_GATE(usb_host_hs_utmi_p2_clk, "utmi_p2_gfclk", &utmi_p2_gfclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-               OMAP4430_OPTFCLKEN_UTMI_P2_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_host_hs_utmi_p3_clk, "init_60m_fclk", &init_60m_fclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-               OMAP4430_OPTFCLKEN_UTMI_P3_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_host_hs_hsic480m_p1_clk, "dpll_usb_m2_ck",
-               &dpll_usb_m2_ck, 0x0,
-               OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-               OMAP4430_OPTFCLKEN_HSIC480M_P1_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_host_hs_hsic60m_p1_clk, "init_60m_fclk",
-               &init_60m_fclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-               OMAP4430_OPTFCLKEN_HSIC60M_P1_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_host_hs_hsic60m_p2_clk, "init_60m_fclk",
-               &init_60m_fclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-               OMAP4430_OPTFCLKEN_HSIC60M_P2_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_host_hs_hsic480m_p2_clk, "dpll_usb_m2_ck",
-               &dpll_usb_m2_ck, 0x0,
-               OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-               OMAP4430_OPTFCLKEN_HSIC480M_P2_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_host_hs_func48mclk, "func_48mc_fclk", &func_48mc_fclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-               OMAP4430_OPTFCLKEN_FUNC48MCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_host_hs_fck, "init_60m_fclk", &init_60m_fclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_HOST_CLKCTRL,
-               OMAP4430_MODULEMODE_SWCTRL_SHIFT, 0x0, NULL);
-
-static const char *otg_60m_gfclk_parents[] = {
-       "utmi_phy_clkout_ck", "xclk60motg_ck",
-};
-
-DEFINE_CLK_MUX(otg_60m_gfclk, otg_60m_gfclk_parents, NULL, 0x0,
-              OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL, OMAP4430_CLKSEL_60M_SHIFT,
-              OMAP4430_CLKSEL_60M_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_otg_hs_xclk, "otg_60m_gfclk", &otg_60m_gfclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
-               OMAP4430_OPTFCLKEN_XCLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_otg_hs_ick, "l3_div_ck", &l3_div_ck, 0x0,
-               OMAP4430_CM_L3INIT_USB_OTG_CLKCTRL,
-               OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_phy_cm_clk32k, "sys_32k_ck", &sys_32k_ck, 0x0,
-               OMAP4430_CM_ALWON_USBPHY_CLKCTRL,
-               OMAP4430_OPTFCLKEN_CLK32K_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_tll_hs_usb_ch2_clk, "init_60m_fclk", &init_60m_fclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
-               OMAP4430_OPTFCLKEN_USB_CH2_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_tll_hs_usb_ch0_clk, "init_60m_fclk", &init_60m_fclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
-               OMAP4430_OPTFCLKEN_USB_CH0_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_tll_hs_usb_ch1_clk, "init_60m_fclk", &init_60m_fclk, 0x0,
-               OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
-               OMAP4430_OPTFCLKEN_USB_CH1_CLK_SHIFT, 0x0, NULL);
-
-DEFINE_CLK_GATE(usb_tll_hs_ick, "l4_div_ck", &l4_div_ck, 0x0,
-               OMAP4430_CM_L3INIT_USB_TLL_CLKCTRL,
-               OMAP4430_MODULEMODE_HWCTRL_SHIFT, 0x0, NULL);
-
-static const struct clk_div_table usim_ck_rates[] = {
-       { .div = 14, .val = 0 },
-       { .div = 18, .val = 1 },
-       { .div = 0 },
-};
-DEFINE_CLK_DIVIDER_TABLE(usim_ck, "dpll_per_m4x2_ck", &dpll_per_m4x2_ck, 0x0,
-                        OMAP4430_CM_WKUP_USIM_CLKCTRL,
-                        OMAP4430_CLKSEL_DIV_SHIFT, OMAP4430_CLKSEL_DIV_WIDTH,
-                        0x0, usim_ck_rates, NULL);
-
-DEFINE_CLK_GATE(usim_fclk, "usim_ck", &usim_ck, 0x0,
-               OMAP4430_CM_WKUP_USIM_CLKCTRL, OMAP4430_OPTFCLKEN_FCLK_SHIFT,
-               0x0, NULL);
-
-/* Remaining optional clocks */
-static const char *pmd_stm_clock_mux_ck_parents[] = {
-       "sys_clkin_ck", "dpll_core_m6x2_ck", "tie_low_clock_ck",
-};
-
-DEFINE_CLK_MUX(pmd_stm_clock_mux_ck, pmd_stm_clock_mux_ck_parents, NULL, 0x0,
-              OMAP4430_CM_EMU_DEBUGSS_CLKCTRL, OMAP4430_PMD_STM_MUX_CTRL_SHIFT,
-              OMAP4430_PMD_STM_MUX_CTRL_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_MUX(pmd_trace_clk_mux_ck, pmd_stm_clock_mux_ck_parents, NULL, 0x0,
-              OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
-              OMAP4430_PMD_TRACE_MUX_CTRL_SHIFT,
-              OMAP4430_PMD_TRACE_MUX_CTRL_WIDTH, 0x0, NULL);
-
-DEFINE_CLK_DIVIDER(stm_clk_div_ck, "pmd_stm_clock_mux_ck",
-                  &pmd_stm_clock_mux_ck, 0x0, OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
-                  OMAP4430_CLKSEL_PMD_STM_CLK_SHIFT,
-                  OMAP4430_CLKSEL_PMD_STM_CLK_WIDTH, CLK_DIVIDER_POWER_OF_TWO,
-                  NULL);
-
-static const char *trace_clk_div_ck_parents[] = {
-       "pmd_trace_clk_mux_ck",
-};
-
-static const struct clksel trace_clk_div_div[] = {
-       { .parent = &pmd_trace_clk_mux_ck, .rates = div3_1to4_rates },
-       { .parent = NULL },
-};
-
-static struct clk trace_clk_div_ck;
-
-static const struct clk_ops trace_clk_div_ck_ops = {
-       .recalc_rate    = &omap2_clksel_recalc,
-       .set_rate       = &omap2_clksel_set_rate,
-       .round_rate     = &omap2_clksel_round_rate,
-       .init           = &omap2_init_clk_clkdm,
-       .enable         = &omap2_clkops_enable_clkdm,
-       .disable        = &omap2_clkops_disable_clkdm,
-};
-
-static struct clk_hw_omap trace_clk_div_ck_hw = {
-       .hw = {
-               .clk = &trace_clk_div_ck,
-       },
-       .clkdm_name     = "emu_sys_clkdm",
-       .clksel         = trace_clk_div_div,
-       .clksel_reg     = OMAP4430_CM_EMU_DEBUGSS_CLKCTRL,
-       .clksel_mask    = OMAP4430_CLKSEL_PMD_TRACE_CLK_MASK,
-};
-
-DEFINE_STRUCT_CLK(trace_clk_div_ck, trace_clk_div_ck_parents,
-                 trace_clk_div_ck_ops);
-
-/* SCRM aux clk nodes */
-
-static const struct clksel auxclk_src_sel[] = {
-       { .parent = &sys_clkin_ck, .rates = div_1_0_rates },
-       { .parent = &dpll_core_m3x2_ck, .rates = div_1_1_rates },
-       { .parent = &dpll_per_m3x2_ck, .rates = div_1_2_rates },
-       { .parent = NULL },
-};
-
-static const char *auxclk_src_ck_parents[] = {
-       "sys_clkin_ck", "dpll_core_m3x2_ck", "dpll_per_m3x2_ck",
-};
-
-static const struct clk_ops auxclk_src_ck_ops = {
-       .enable         = &omap2_dflt_clk_enable,
-       .disable        = &omap2_dflt_clk_disable,
-       .is_enabled     = &omap2_dflt_clk_is_enabled,
-       .recalc_rate    = &omap2_clksel_recalc,
-       .get_parent     = &omap2_clksel_find_parent_index,
-};
-
-DEFINE_CLK_OMAP_MUX_GATE(auxclk0_src_ck, NULL, auxclk_src_sel,
-                        OMAP4_SCRM_AUXCLK0, OMAP4_SRCSELECT_MASK,
-                        OMAP4_SCRM_AUXCLK0, OMAP4_ENABLE_SHIFT, NULL,
-                        auxclk_src_ck_parents, auxclk_src_ck_ops);
-
-DEFINE_CLK_DIVIDER(auxclk0_ck, "auxclk0_src_ck", &auxclk0_src_ck, 0x0,
-                  OMAP4_SCRM_AUXCLK0, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH,
-                  0x0, NULL);
-
-DEFINE_CLK_OMAP_MUX_GATE(auxclk1_src_ck, NULL, auxclk_src_sel,
-                        OMAP4_SCRM_AUXCLK1, OMAP4_SRCSELECT_MASK,
-                        OMAP4_SCRM_AUXCLK1, OMAP4_ENABLE_SHIFT, NULL,
-                        auxclk_src_ck_parents, auxclk_src_ck_ops);
-
-DEFINE_CLK_DIVIDER(auxclk1_ck, "auxclk1_src_ck", &auxclk1_src_ck, 0x0,
-                  OMAP4_SCRM_AUXCLK1, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH,
-                  0x0, NULL);
-
-DEFINE_CLK_OMAP_MUX_GATE(auxclk2_src_ck, NULL, auxclk_src_sel,
-                        OMAP4_SCRM_AUXCLK2, OMAP4_SRCSELECT_MASK,
-                        OMAP4_SCRM_AUXCLK2, OMAP4_ENABLE_SHIFT, NULL,
-                        auxclk_src_ck_parents, auxclk_src_ck_ops);
-
-DEFINE_CLK_DIVIDER(auxclk2_ck, "auxclk2_src_ck", &auxclk2_src_ck, 0x0,
-                  OMAP4_SCRM_AUXCLK2, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH,
-                  0x0, NULL);
-
-DEFINE_CLK_OMAP_MUX_GATE(auxclk3_src_ck, NULL, auxclk_src_sel,
-                        OMAP4_SCRM_AUXCLK3, OMAP4_SRCSELECT_MASK,
-                        OMAP4_SCRM_AUXCLK3, OMAP4_ENABLE_SHIFT, NULL,
-                        auxclk_src_ck_parents, auxclk_src_ck_ops);
-
-DEFINE_CLK_DIVIDER(auxclk3_ck, "auxclk3_src_ck", &auxclk3_src_ck, 0x0,
-                  OMAP4_SCRM_AUXCLK3, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH,
-                  0x0, NULL);
-
-DEFINE_CLK_OMAP_MUX_GATE(auxclk4_src_ck, NULL, auxclk_src_sel,
-                        OMAP4_SCRM_AUXCLK4, OMAP4_SRCSELECT_MASK,
-                        OMAP4_SCRM_AUXCLK4, OMAP4_ENABLE_SHIFT, NULL,
-                        auxclk_src_ck_parents, auxclk_src_ck_ops);
-
-DEFINE_CLK_DIVIDER(auxclk4_ck, "auxclk4_src_ck", &auxclk4_src_ck, 0x0,
-                  OMAP4_SCRM_AUXCLK4, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH,
-                  0x0, NULL);
-
-DEFINE_CLK_OMAP_MUX_GATE(auxclk5_src_ck, NULL, auxclk_src_sel,
-                        OMAP4_SCRM_AUXCLK5, OMAP4_SRCSELECT_MASK,
-                        OMAP4_SCRM_AUXCLK5, OMAP4_ENABLE_SHIFT, NULL,
-                        auxclk_src_ck_parents, auxclk_src_ck_ops);
-
-DEFINE_CLK_DIVIDER(auxclk5_ck, "auxclk5_src_ck", &auxclk5_src_ck, 0x0,
-                  OMAP4_SCRM_AUXCLK5, OMAP4_CLKDIV_SHIFT, OMAP4_CLKDIV_WIDTH,
-                  0x0, NULL);
-
-static const char *auxclkreq_ck_parents[] = {
-       "auxclk0_ck", "auxclk1_ck", "auxclk2_ck", "auxclk3_ck", "auxclk4_ck",
-       "auxclk5_ck",
-};
-
-DEFINE_CLK_MUX(auxclkreq0_ck, auxclkreq_ck_parents, NULL, 0x0,
-              OMAP4_SCRM_AUXCLKREQ0, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH,
-              0x0, NULL);
-
-DEFINE_CLK_MUX(auxclkreq1_ck, auxclkreq_ck_parents, NULL, 0x0,
-              OMAP4_SCRM_AUXCLKREQ1, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH,
-              0x0, NULL);
-
-DEFINE_CLK_MUX(auxclkreq2_ck, auxclkreq_ck_parents, NULL, 0x0,
-              OMAP4_SCRM_AUXCLKREQ2, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH,
-              0x0, NULL);
-
-DEFINE_CLK_MUX(auxclkreq3_ck, auxclkreq_ck_parents, NULL, 0x0,
-              OMAP4_SCRM_AUXCLKREQ3, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH,
-              0x0, NULL);
-
-DEFINE_CLK_MUX(auxclkreq4_ck, auxclkreq_ck_parents, NULL, 0x0,
-              OMAP4_SCRM_AUXCLKREQ4, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH,
-              0x0, NULL);
-
-DEFINE_CLK_MUX(auxclkreq5_ck, auxclkreq_ck_parents, NULL, 0x0,
-              OMAP4_SCRM_AUXCLKREQ5, OMAP4_MAPPING_SHIFT, OMAP4_MAPPING_WIDTH,
-              0x0, NULL);
-
-/*
- * clocks specific to omap4460
- */
-static struct omap_clk omap446x_clks[] = {
-       CLK(NULL,       "div_ts_ck",                    &div_ts_ck),
-       CLK(NULL,       "bandgap_ts_fclk",              &bandgap_ts_fclk),
-};
-
-/*
- * clocks specific to omap4430
- */
-static struct omap_clk omap443x_clks[] = {
-       CLK(NULL,       "bandgap_fclk",                 &bandgap_fclk),
-};
-
-/*
- * clocks common to omap44xx
- */
-static struct omap_clk omap44xx_clks[] = {
-       CLK(NULL,       "extalt_clkin_ck",              &extalt_clkin_ck),
-       CLK(NULL,       "pad_clks_src_ck",              &pad_clks_src_ck),
-       CLK(NULL,       "pad_clks_ck",                  &pad_clks_ck),
-       CLK(NULL,       "pad_slimbus_core_clks_ck",     &pad_slimbus_core_clks_ck),
-       CLK(NULL,       "secure_32k_clk_src_ck",        &secure_32k_clk_src_ck),
-       CLK(NULL,       "slimbus_src_clk",              &slimbus_src_clk),
-       CLK(NULL,       "slimbus_clk",                  &slimbus_clk),
-       CLK(NULL,       "sys_32k_ck",                   &sys_32k_ck),
-       CLK(NULL,       "virt_12000000_ck",             &virt_12000000_ck),
-       CLK(NULL,       "virt_13000000_ck",             &virt_13000000_ck),
-       CLK(NULL,       "virt_16800000_ck",             &virt_16800000_ck),
-       CLK(NULL,       "virt_19200000_ck",             &virt_19200000_ck),
-       CLK(NULL,       "virt_26000000_ck",             &virt_26000000_ck),
-       CLK(NULL,       "virt_27000000_ck",             &virt_27000000_ck),
-       CLK(NULL,       "virt_38400000_ck",             &virt_38400000_ck),
-       CLK(NULL,       "sys_clkin_ck",                 &sys_clkin_ck),
-       CLK(NULL,       "tie_low_clock_ck",             &tie_low_clock_ck),
-       CLK(NULL,       "utmi_phy_clkout_ck",           &utmi_phy_clkout_ck),
-       CLK(NULL,       "xclk60mhsp1_ck",               &xclk60mhsp1_ck),
-       CLK(NULL,       "xclk60mhsp2_ck",               &xclk60mhsp2_ck),
-       CLK(NULL,       "xclk60motg_ck",                &xclk60motg_ck),
-       CLK(NULL,       "abe_dpll_bypass_clk_mux_ck",   &abe_dpll_bypass_clk_mux_ck),
-       CLK(NULL,       "abe_dpll_refclk_mux_ck",       &abe_dpll_refclk_mux_ck),
-       CLK(NULL,       "dpll_abe_ck",                  &dpll_abe_ck),
-       CLK(NULL,       "dpll_abe_x2_ck",               &dpll_abe_x2_ck),
-       CLK(NULL,       "dpll_abe_m2x2_ck",             &dpll_abe_m2x2_ck),
-       CLK(NULL,       "abe_24m_fclk",                 &abe_24m_fclk),
-       CLK(NULL,       "abe_clk",                      &abe_clk),
-       CLK(NULL,       "aess_fclk",                    &aess_fclk),
-       CLK(NULL,       "dpll_abe_m3x2_ck",             &dpll_abe_m3x2_ck),
-       CLK(NULL,       "core_hsd_byp_clk_mux_ck",      &core_hsd_byp_clk_mux_ck),
-       CLK(NULL,       "dpll_core_ck",                 &dpll_core_ck),
-       CLK(NULL,       "dpll_core_x2_ck",              &dpll_core_x2_ck),
-       CLK(NULL,       "dpll_core_m6x2_ck",            &dpll_core_m6x2_ck),
-       CLK(NULL,       "dbgclk_mux_ck",                &dbgclk_mux_ck),
-       CLK(NULL,       "dpll_core_m2_ck",              &dpll_core_m2_ck),
-       CLK(NULL,       "ddrphy_ck",                    &ddrphy_ck),
-       CLK(NULL,       "dpll_core_m5x2_ck",            &dpll_core_m5x2_ck),
-       CLK(NULL,       "div_core_ck",                  &div_core_ck),
-       CLK(NULL,       "div_iva_hs_clk",               &div_iva_hs_clk),
-       CLK(NULL,       "div_mpu_hs_clk",               &div_mpu_hs_clk),
-       CLK(NULL,       "dpll_core_m4x2_ck",            &dpll_core_m4x2_ck),
-       CLK(NULL,       "dll_clk_div_ck",               &dll_clk_div_ck),
-       CLK(NULL,       "dpll_abe_m2_ck",               &dpll_abe_m2_ck),
-       CLK(NULL,       "dpll_core_m3x2_ck",            &dpll_core_m3x2_ck),
-       CLK(NULL,       "dpll_core_m7x2_ck",            &dpll_core_m7x2_ck),
-       CLK(NULL,       "iva_hsd_byp_clk_mux_ck",       &iva_hsd_byp_clk_mux_ck),
-       CLK(NULL,       "dpll_iva_ck",                  &dpll_iva_ck),
-       CLK(NULL,       "dpll_iva_x2_ck",               &dpll_iva_x2_ck),
-       CLK(NULL,       "dpll_iva_m4x2_ck",             &dpll_iva_m4x2_ck),
-       CLK(NULL,       "dpll_iva_m5x2_ck",             &dpll_iva_m5x2_ck),
-       CLK(NULL,       "dpll_mpu_ck",                  &dpll_mpu_ck),
-       CLK(NULL,       "dpll_mpu_m2_ck",               &dpll_mpu_m2_ck),
-       CLK(NULL,       "per_hs_clk_div_ck",            &per_hs_clk_div_ck),
-       CLK(NULL,       "per_hsd_byp_clk_mux_ck",       &per_hsd_byp_clk_mux_ck),
-       CLK(NULL,       "dpll_per_ck",                  &dpll_per_ck),
-       CLK(NULL,       "dpll_per_m2_ck",               &dpll_per_m2_ck),
-       CLK(NULL,       "dpll_per_x2_ck",               &dpll_per_x2_ck),
-       CLK(NULL,       "dpll_per_m2x2_ck",             &dpll_per_m2x2_ck),
-       CLK(NULL,       "dpll_per_m3x2_ck",             &dpll_per_m3x2_ck),
-       CLK(NULL,       "dpll_per_m4x2_ck",             &dpll_per_m4x2_ck),
-       CLK(NULL,       "dpll_per_m5x2_ck",             &dpll_per_m5x2_ck),
-       CLK(NULL,       "dpll_per_m6x2_ck",             &dpll_per_m6x2_ck),
-       CLK(NULL,       "dpll_per_m7x2_ck",             &dpll_per_m7x2_ck),
-       CLK(NULL,       "usb_hs_clk_div_ck",            &usb_hs_clk_div_ck),
-       CLK(NULL,       "dpll_usb_ck",                  &dpll_usb_ck),
-       CLK(NULL,       "dpll_usb_clkdcoldo_ck",        &dpll_usb_clkdcoldo_ck),
-       CLK(NULL,       "dpll_usb_m2_ck",               &dpll_usb_m2_ck),
-       CLK(NULL,       "ducati_clk_mux_ck",            &ducati_clk_mux_ck),
-       CLK(NULL,       "func_12m_fclk",                &func_12m_fclk),
-       CLK(NULL,       "func_24m_clk",                 &func_24m_clk),
-       CLK(NULL,       "func_24mc_fclk",               &func_24mc_fclk),
-       CLK(NULL,       "func_48m_fclk",                &func_48m_fclk),
-       CLK(NULL,       "func_48mc_fclk",               &func_48mc_fclk),
-       CLK(NULL,       "func_64m_fclk",                &func_64m_fclk),
-       CLK(NULL,       "func_96m_fclk",                &func_96m_fclk),
-       CLK(NULL,       "init_60m_fclk",                &init_60m_fclk),
-       CLK(NULL,       "l3_div_ck",                    &l3_div_ck),
-       CLK(NULL,       "l4_div_ck",                    &l4_div_ck),
-       CLK(NULL,       "lp_clk_div_ck",                &lp_clk_div_ck),
-       CLK(NULL,       "l4_wkup_clk_mux_ck",           &l4_wkup_clk_mux_ck),
-       CLK("smp_twd",  NULL,                           &mpu_periphclk),
-       CLK(NULL,       "ocp_abe_iclk",                 &ocp_abe_iclk),
-       CLK(NULL,       "per_abe_24m_fclk",             &per_abe_24m_fclk),
-       CLK(NULL,       "per_abe_nc_fclk",              &per_abe_nc_fclk),
-       CLK(NULL,       "syc_clk_div_ck",               &syc_clk_div_ck),
-       CLK(NULL,       "aes1_fck",                     &aes1_fck),
-       CLK(NULL,       "aes2_fck",                     &aes2_fck),
-       CLK(NULL,       "dmic_sync_mux_ck",             &dmic_sync_mux_ck),
-       CLK(NULL,       "func_dmic_abe_gfclk",          &func_dmic_abe_gfclk),
-       CLK(NULL,       "dss_sys_clk",                  &dss_sys_clk),
-       CLK(NULL,       "dss_tv_clk",                   &dss_tv_clk),
-       CLK(NULL,       "dss_dss_clk",                  &dss_dss_clk),
-       CLK(NULL,       "dss_48mhz_clk",                &dss_48mhz_clk),
-       CLK(NULL,       "dss_fck",                      &dss_fck),
-       CLK("omapdss_dss",      "ick",                  &dss_fck),
-       CLK(NULL,       "fdif_fck",                     &fdif_fck),
-       CLK(NULL,       "gpio1_dbclk",                  &gpio1_dbclk),
-       CLK(NULL,       "gpio2_dbclk",                  &gpio2_dbclk),
-       CLK(NULL,       "gpio3_dbclk",                  &gpio3_dbclk),
-       CLK(NULL,       "gpio4_dbclk",                  &gpio4_dbclk),
-       CLK(NULL,       "gpio5_dbclk",                  &gpio5_dbclk),
-       CLK(NULL,       "gpio6_dbclk",                  &gpio6_dbclk),
-       CLK(NULL,       "sgx_clk_mux",                  &sgx_clk_mux),
-       CLK(NULL,       "hsi_fck",                      &hsi_fck),
-       CLK(NULL,       "iss_ctrlclk",                  &iss_ctrlclk),
-       CLK(NULL,       "mcasp_sync_mux_ck",            &mcasp_sync_mux_ck),
-       CLK(NULL,       "func_mcasp_abe_gfclk",         &func_mcasp_abe_gfclk),
-       CLK(NULL,       "mcbsp1_sync_mux_ck",           &mcbsp1_sync_mux_ck),
-       CLK(NULL,       "func_mcbsp1_gfclk",            &func_mcbsp1_gfclk),
-       CLK(NULL,       "mcbsp2_sync_mux_ck",           &mcbsp2_sync_mux_ck),
-       CLK(NULL,       "func_mcbsp2_gfclk",            &func_mcbsp2_gfclk),
-       CLK(NULL,       "mcbsp3_sync_mux_ck",           &mcbsp3_sync_mux_ck),
-       CLK(NULL,       "func_mcbsp3_gfclk",            &func_mcbsp3_gfclk),
-       CLK(NULL,       "mcbsp4_sync_mux_ck",           &mcbsp4_sync_mux_ck),
-       CLK(NULL,       "per_mcbsp4_gfclk",             &per_mcbsp4_gfclk),
-       CLK(NULL,       "hsmmc1_fclk",                  &hsmmc1_fclk),
-       CLK(NULL,       "hsmmc2_fclk",                  &hsmmc2_fclk),
-       CLK(NULL,       "ocp2scp_usb_phy_phy_48m",      &ocp2scp_usb_phy_phy_48m),
-       CLK(NULL,       "sha2md5_fck",                  &sha2md5_fck),
-       CLK(NULL,       "slimbus1_fclk_1",              &slimbus1_fclk_1),
-       CLK(NULL,       "slimbus1_fclk_0",              &slimbus1_fclk_0),
-       CLK(NULL,       "slimbus1_fclk_2",              &slimbus1_fclk_2),
-       CLK(NULL,       "slimbus1_slimbus_clk",         &slimbus1_slimbus_clk),
-       CLK(NULL,       "slimbus2_fclk_1",              &slimbus2_fclk_1),
-       CLK(NULL,       "slimbus2_fclk_0",              &slimbus2_fclk_0),
-       CLK(NULL,       "slimbus2_slimbus_clk",         &slimbus2_slimbus_clk),
-       CLK(NULL,       "smartreflex_core_fck",         &smartreflex_core_fck),
-       CLK(NULL,       "smartreflex_iva_fck",          &smartreflex_iva_fck),
-       CLK(NULL,       "smartreflex_mpu_fck",          &smartreflex_mpu_fck),
-       CLK(NULL,       "dmt1_clk_mux",                 &dmt1_clk_mux),
-       CLK(NULL,       "cm2_dm10_mux",                 &cm2_dm10_mux),
-       CLK(NULL,       "cm2_dm11_mux",                 &cm2_dm11_mux),
-       CLK(NULL,       "cm2_dm2_mux",                  &cm2_dm2_mux),
-       CLK(NULL,       "cm2_dm3_mux",                  &cm2_dm3_mux),
-       CLK(NULL,       "cm2_dm4_mux",                  &cm2_dm4_mux),
-       CLK(NULL,       "timer5_sync_mux",              &timer5_sync_mux),
-       CLK(NULL,       "timer6_sync_mux",              &timer6_sync_mux),
-       CLK(NULL,       "timer7_sync_mux",              &timer7_sync_mux),
-       CLK(NULL,       "timer8_sync_mux",              &timer8_sync_mux),
-       CLK(NULL,       "cm2_dm9_mux",                  &cm2_dm9_mux),
-       CLK(NULL,       "usb_host_fs_fck",              &usb_host_fs_fck),
-       CLK("usbhs_omap",       "fs_fck",               &usb_host_fs_fck),
-       CLK(NULL,       "utmi_p1_gfclk",                &utmi_p1_gfclk),
-       CLK(NULL,       "usb_host_hs_utmi_p1_clk",      &usb_host_hs_utmi_p1_clk),
-       CLK(NULL,       "utmi_p2_gfclk",                &utmi_p2_gfclk),
-       CLK(NULL,       "usb_host_hs_utmi_p2_clk",      &usb_host_hs_utmi_p2_clk),
-       CLK(NULL,       "usb_host_hs_utmi_p3_clk",      &usb_host_hs_utmi_p3_clk),
-       CLK(NULL,       "usb_host_hs_hsic480m_p1_clk",  &usb_host_hs_hsic480m_p1_clk),
-       CLK(NULL,       "usb_host_hs_hsic60m_p1_clk",   &usb_host_hs_hsic60m_p1_clk),
-       CLK(NULL,       "usb_host_hs_hsic60m_p2_clk",   &usb_host_hs_hsic60m_p2_clk),
-       CLK(NULL,       "usb_host_hs_hsic480m_p2_clk",  &usb_host_hs_hsic480m_p2_clk),
-       CLK(NULL,       "usb_host_hs_func48mclk",       &usb_host_hs_func48mclk),
-       CLK(NULL,       "usb_host_hs_fck",              &usb_host_hs_fck),
-       CLK("usbhs_omap",       "hs_fck",               &usb_host_hs_fck),
-       CLK(NULL,       "otg_60m_gfclk",                &otg_60m_gfclk),
-       CLK(NULL,       "usb_otg_hs_xclk",              &usb_otg_hs_xclk),
-       CLK(NULL,       "usb_otg_hs_ick",               &usb_otg_hs_ick),
-       CLK("musb-omap2430",    "ick",                  &usb_otg_hs_ick),
-       CLK(NULL,       "usb_phy_cm_clk32k",            &usb_phy_cm_clk32k),
-       CLK(NULL,       "usb_tll_hs_usb_ch2_clk",       &usb_tll_hs_usb_ch2_clk),
-       CLK(NULL,       "usb_tll_hs_usb_ch0_clk",       &usb_tll_hs_usb_ch0_clk),
-       CLK(NULL,       "usb_tll_hs_usb_ch1_clk",       &usb_tll_hs_usb_ch1_clk),
-       CLK(NULL,       "usb_tll_hs_ick",               &usb_tll_hs_ick),
-       CLK("usbhs_omap",       "usbtll_ick",           &usb_tll_hs_ick),
-       CLK("usbhs_tll",        "usbtll_ick",           &usb_tll_hs_ick),
-       CLK(NULL,       "usim_ck",                      &usim_ck),
-       CLK(NULL,       "usim_fclk",                    &usim_fclk),
-       CLK(NULL,       "pmd_stm_clock_mux_ck",         &pmd_stm_clock_mux_ck),
-       CLK(NULL,       "pmd_trace_clk_mux_ck",         &pmd_trace_clk_mux_ck),
-       CLK(NULL,       "stm_clk_div_ck",               &stm_clk_div_ck),
-       CLK(NULL,       "trace_clk_div_ck",             &trace_clk_div_ck),
-       CLK(NULL,       "auxclk0_src_ck",               &auxclk0_src_ck),
-       CLK(NULL,       "auxclk0_ck",                   &auxclk0_ck),
-       CLK(NULL,       "auxclkreq0_ck",                &auxclkreq0_ck),
-       CLK(NULL,       "auxclk1_src_ck",               &auxclk1_src_ck),
-       CLK(NULL,       "auxclk1_ck",                   &auxclk1_ck),
-       CLK(NULL,       "auxclkreq1_ck",                &auxclkreq1_ck),
-       CLK(NULL,       "auxclk2_src_ck",               &auxclk2_src_ck),
-       CLK(NULL,       "auxclk2_ck",                   &auxclk2_ck),
-       CLK(NULL,       "auxclkreq2_ck",                &auxclkreq2_ck),
-       CLK(NULL,       "auxclk3_src_ck",               &auxclk3_src_ck),
-       CLK(NULL,       "auxclk3_ck",                   &auxclk3_ck),
-       CLK(NULL,       "auxclkreq3_ck",                &auxclkreq3_ck),
-       CLK(NULL,       "auxclk4_src_ck",               &auxclk4_src_ck),
-       CLK(NULL,       "auxclk4_ck",                   &auxclk4_ck),
-       CLK(NULL,       "auxclkreq4_ck",                &auxclkreq4_ck),
-       CLK(NULL,       "auxclk5_src_ck",               &auxclk5_src_ck),
-       CLK(NULL,       "auxclk5_ck",                   &auxclk5_ck),
-       CLK(NULL,       "auxclkreq5_ck",                &auxclkreq5_ck),
-       CLK("50000000.gpmc",    "fck",                  &dummy_ck),
-       CLK("omap_i2c.1",       "ick",                  &dummy_ck),
-       CLK("omap_i2c.2",       "ick",                  &dummy_ck),
-       CLK("omap_i2c.3",       "ick",                  &dummy_ck),
-       CLK("omap_i2c.4",       "ick",                  &dummy_ck),
-       CLK(NULL,       "mailboxes_ick",                &dummy_ck),
-       CLK("omap_hsmmc.0",     "ick",                  &dummy_ck),
-       CLK("omap_hsmmc.1",     "ick",                  &dummy_ck),
-       CLK("omap_hsmmc.2",     "ick",                  &dummy_ck),
-       CLK("omap_hsmmc.3",     "ick",                  &dummy_ck),
-       CLK("omap_hsmmc.4",     "ick",                  &dummy_ck),
-       CLK("omap-mcbsp.1",     "ick",                  &dummy_ck),
-       CLK("omap-mcbsp.2",     "ick",                  &dummy_ck),
-       CLK("omap-mcbsp.3",     "ick",                  &dummy_ck),
-       CLK("omap-mcbsp.4",     "ick",                  &dummy_ck),
-       CLK("omap2_mcspi.1",    "ick",                  &dummy_ck),
-       CLK("omap2_mcspi.2",    "ick",                  &dummy_ck),
-       CLK("omap2_mcspi.3",    "ick",                  &dummy_ck),
-       CLK("omap2_mcspi.4",    "ick",                  &dummy_ck),
-       CLK(NULL,       "uart1_ick",                    &dummy_ck),
-       CLK(NULL,       "uart2_ick",                    &dummy_ck),
-       CLK(NULL,       "uart3_ick",                    &dummy_ck),
-       CLK(NULL,       "uart4_ick",                    &dummy_ck),
-       CLK("usbhs_omap",       "usbhost_ick",          &dummy_ck),
-       CLK("usbhs_omap",       "usbtll_fck",           &dummy_ck),
-       CLK("usbhs_tll",        "usbtll_fck",           &dummy_ck),
-       CLK("omap_wdt", "ick",                          &dummy_ck),
-       CLK(NULL,       "timer_32k_ck", &sys_32k_ck),
-       /* TODO: Remove "omap_timer.X" aliases once DT migration is complete */
-       CLK("omap_timer.1",     "timer_sys_ck", &sys_clkin_ck),
-       CLK("omap_timer.2",     "timer_sys_ck", &sys_clkin_ck),
-       CLK("omap_timer.3",     "timer_sys_ck", &sys_clkin_ck),
-       CLK("omap_timer.4",     "timer_sys_ck", &sys_clkin_ck),
-       CLK("omap_timer.9",     "timer_sys_ck", &sys_clkin_ck),
-       CLK("omap_timer.10",    "timer_sys_ck", &sys_clkin_ck),
-       CLK("omap_timer.11",    "timer_sys_ck", &sys_clkin_ck),
-       CLK("omap_timer.5",     "timer_sys_ck", &syc_clk_div_ck),
-       CLK("omap_timer.6",     "timer_sys_ck", &syc_clk_div_ck),
-       CLK("omap_timer.7",     "timer_sys_ck", &syc_clk_div_ck),
-       CLK("omap_timer.8",     "timer_sys_ck", &syc_clk_div_ck),
-       CLK("4a318000.timer",   "timer_sys_ck", &sys_clkin_ck),
-       CLK("48032000.timer",   "timer_sys_ck", &sys_clkin_ck),
-       CLK("48034000.timer",   "timer_sys_ck", &sys_clkin_ck),
-       CLK("48036000.timer",   "timer_sys_ck", &sys_clkin_ck),
-       CLK("4803e000.timer",   "timer_sys_ck", &sys_clkin_ck),
-       CLK("48086000.timer",   "timer_sys_ck", &sys_clkin_ck),
-       CLK("48088000.timer",   "timer_sys_ck", &sys_clkin_ck),
-       CLK("40138000.timer",   "timer_sys_ck", &syc_clk_div_ck),
-       CLK("4013a000.timer",   "timer_sys_ck", &syc_clk_div_ck),
-       CLK("4013c000.timer",   "timer_sys_ck", &syc_clk_div_ck),
-       CLK("4013e000.timer",   "timer_sys_ck", &syc_clk_div_ck),
-       CLK(NULL,       "cpufreq_ck",   &dpll_mpu_ck),
-};
-
-int __init omap4xxx_clk_init(void)
-{
-       int rc;
-
-       if (cpu_is_omap443x()) {
-               cpu_mask = RATE_IN_4430;
-               omap_clocks_register(omap443x_clks, ARRAY_SIZE(omap443x_clks));
-       } else if (cpu_is_omap446x() || cpu_is_omap447x()) {
-               cpu_mask = RATE_IN_4460 | RATE_IN_4430;
-               omap_clocks_register(omap446x_clks, ARRAY_SIZE(omap446x_clks));
-               if (cpu_is_omap447x())
-                       pr_warn("WARNING: OMAP4470 clock data incomplete!\n");
-       } else {
-               return 0;
-       }
-
-       omap_clocks_register(omap44xx_clks, ARRAY_SIZE(omap44xx_clks));
-
-       omap2_clk_disable_autoidle_all();
-
-       /*
-        * A set rate of ABE DPLL inturn triggers a set rate of USB DPLL
-        * when its in bypass. So always lock USB before ABE DPLL.
-        */
-       /*
-        * Lock USB DPLL on OMAP4 devices so that the L3INIT power
-        * domain can transition to retention state when not in use.
-        */
-       rc = clk_set_rate(&dpll_usb_ck, OMAP4_DPLL_USB_DEFFREQ);
-       if (rc)
-               pr_err("%s: failed to configure USB DPLL!\n", __func__);
-
-       /*
-        * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power
-        * state when turning the ABE clock domain. Workaround this by
-        * locking the ABE DPLL on boot.
-        * Lock the ABE DPLL in any case to avoid issues with audio.
-        */
-       rc = clk_set_parent(&abe_dpll_refclk_mux_ck, &sys_32k_ck);
-       if (!rc)
-               rc = clk_set_rate(&dpll_abe_ck, OMAP4_DPLL_ABE_DEFFREQ);
-       if (rc)
-               pr_err("%s: failed to configure ABE DPLL!\n", __func__);
-
-       return 0;
-}
index 0ec9f6fdf0463bb6ff435f250c748db075c62ca4..7ee26108ac0d36b76b156b93b619b2cbee0b89d7 100644 (file)
@@ -97,12 +97,12 @@ static void _write_clksel_reg(struct clk_hw_omap *clk, u32 field_val)
 {
        u32 v;
 
-       v = __raw_readl(clk->clksel_reg);
+       v = omap2_clk_readl(clk, clk->clksel_reg);
        v &= ~clk->clksel_mask;
        v |= field_val << __ffs(clk->clksel_mask);
-       __raw_writel(v, clk->clksel_reg);
+       omap2_clk_writel(v, clk, clk->clksel_reg);
 
-       v = __raw_readl(clk->clksel_reg); /* OCP barrier */
+       v = omap2_clk_readl(clk, clk->clksel_reg); /* OCP barrier */
 }
 
 /**
@@ -204,7 +204,7 @@ static u32 _read_divisor(struct clk_hw_omap *clk)
        if (!clk->clksel || !clk->clksel_mask)
                return 0;
 
-       v = __raw_readl(clk->clksel_reg);
+       v = omap2_clk_readl(clk, clk->clksel_reg);
        v &= clk->clksel_mask;
        v >>= __ffs(clk->clksel_mask);
 
@@ -320,7 +320,7 @@ u8 omap2_clksel_find_parent_index(struct clk_hw *hw)
        WARN((!clk->clksel || !clk->clksel_mask),
             "clock: %s: attempt to call on a non-clksel clock", clk_name);
 
-       r = __raw_readl(clk->clksel_reg) & clk->clksel_mask;
+       r = omap2_clk_readl(clk, clk->clksel_reg) & clk->clksel_mask;
        r >>= __ffs(clk->clksel_mask);
 
        for (clks = clk->clksel; clks->parent && !found; clks++) {
index 924c230f89484473f057246fb7f3a8b53a28c2bd..47f9562ca7aa0f3007cfac811ffceb90b7cce80e 100644 (file)
@@ -196,7 +196,7 @@ u8 omap2_init_dpll_parent(struct clk_hw *hw)
        if (!dd)
                return -EINVAL;
 
-       v = __raw_readl(dd->control_reg);
+       v = omap2_clk_readl(clk, dd->control_reg);
        v &= dd->enable_mask;
        v >>= __ffs(dd->enable_mask);
 
@@ -243,7 +243,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
                return 0;
 
        /* Return bypass rate if DPLL is bypassed */
-       v = __raw_readl(dd->control_reg);
+       v = omap2_clk_readl(clk, dd->control_reg);
        v &= dd->enable_mask;
        v >>= __ffs(dd->enable_mask);
 
@@ -262,7 +262,7 @@ unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk)
                        return __clk_get_rate(dd->clk_bypass);
        }
 
-       v = __raw_readl(dd->mult_div1_reg);
+       v = omap2_clk_readl(clk, dd->mult_div1_reg);
        dpll_mult = v & dd->mult_mask;
        dpll_mult >>= __ffs(dd->mult_mask);
        dpll_div = v & dd->div1_mask;
index f10eb03ce3e27493ee1d52b18444ff52d4cf1507..333f0a66617165fa23448e19cd6b59c8856c78d3 100644 (file)
 /* XXX */
 void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk)
 {
-       u32 v, r;
+       u32 v;
+       void __iomem *r;
 
-       r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
+       r = (__force void __iomem *)
+               ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
 
-       v = __raw_readl((__force void __iomem *)r);
+       v = omap2_clk_readl(clk, r);
        v |= (1 << clk->enable_bit);
-       __raw_writel(v, (__force void __iomem *)r);
+       omap2_clk_writel(v, clk, r);
 }
 
 /* XXX */
 void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk)
 {
-       u32 v, r;
+       u32 v;
+       void __iomem *r;
 
-       r = ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
+       r = (__force void __iomem *)
+               ((__force u32)clk->enable_reg ^ (CM_AUTOIDLE ^ CM_ICLKEN));
 
-       v = __raw_readl((__force void __iomem *)r);
+       v = omap2_clk_readl(clk, r);
        v &= ~(1 << clk->enable_bit);
-       __raw_writel(v, (__force void __iomem *)r);
+       omap2_clk_writel(v, clk, r);
 }
 
 /* Public data */
index c7c5d31e90829141373662f32ffb39ce6c32637a..591581a665321c09fafbe78fd9c5bdbcae53c5a4 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/clk-private.h>
 #include <asm/cpu.h>
 
-
 #include <trace/events/power.h>
 
 #include "soc.h"
@@ -56,6 +55,31 @@ u16 cpu_mask;
 static bool clkdm_control = true;
 
 static LIST_HEAD(clk_hw_omap_clocks);
+void __iomem *clk_memmaps[CLK_MAX_MEMMAPS];
+
+void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg)
+{
+       if (clk->flags & MEMMAP_ADDRESSING) {
+               struct clk_omap_reg *r = (struct clk_omap_reg *)&reg;
+               writel_relaxed(val, clk_memmaps[r->index] + r->offset);
+       } else {
+               writel_relaxed(val, reg);
+       }
+}
+
+u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg)
+{
+       u32 val;
+
+       if (clk->flags & MEMMAP_ADDRESSING) {
+               struct clk_omap_reg *r = (struct clk_omap_reg *)&reg;
+               val = readl_relaxed(clk_memmaps[r->index] + r->offset);
+       } else {
+               val = readl_relaxed(reg);
+       }
+
+       return val;
+}
 
 /*
  * Used for clocks that have the same value as the parent clock,
@@ -87,6 +111,7 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw,
 
 /**
  * _wait_idlest_generic - wait for a module to leave the idle state
+ * @clk: module clock to wait for (needed for register offsets)
  * @reg: virtual address of module IDLEST register
  * @mask: value to mask against to determine if the module is active
  * @idlest: idle state indicator (0 or 1) for the clock
@@ -98,14 +123,14 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw,
  * elapsed.  XXX Deprecated - should be moved into drivers for the
  * individual IP block that the IDLEST register exists in.
  */
-static int _wait_idlest_generic(void __iomem *reg, u32 mask, u8 idlest,
-                               const char *name)
+static int _wait_idlest_generic(struct clk_hw_omap *clk, void __iomem *reg,
+                               u32 mask, u8 idlest, const char *name)
 {
        int i = 0, ena = 0;
 
        ena = (idlest) ? 0 : mask;
 
-       omap_test_timeout(((__raw_readl(reg) & mask) == ena),
+       omap_test_timeout(((omap2_clk_readl(clk, reg) & mask) == ena),
                          MAX_MODULE_ENABLE_WAIT, i);
 
        if (i < MAX_MODULE_ENABLE_WAIT)
@@ -138,7 +163,7 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
        /* Not all modules have multiple clocks that their IDLEST depends on */
        if (clk->ops->find_companion) {
                clk->ops->find_companion(clk, &companion_reg, &other_bit);
-               if (!(__raw_readl(companion_reg) & (1 << other_bit)))
+               if (!(omap2_clk_readl(clk, companion_reg) & (1 << other_bit)))
                        return;
        }
 
@@ -146,8 +171,8 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
        r = cm_split_idlest_reg(idlest_reg, &prcm_mod, &idlest_reg_id);
        if (r) {
                /* IDLEST register not in the CM module */
-               _wait_idlest_generic(idlest_reg, (1 << idlest_bit), idlest_val,
-                                    __clk_get_name(clk->hw.clk));
+               _wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit),
+                                    idlest_val, __clk_get_name(clk->hw.clk));
        } else {
                cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit);
        };
@@ -309,13 +334,13 @@ int omap2_dflt_clk_enable(struct clk_hw *hw)
        }
 
        /* FIXME should not have INVERT_ENABLE bit here */
-       v = __raw_readl(clk->enable_reg);
+       v = omap2_clk_readl(clk, clk->enable_reg);
        if (clk->flags & INVERT_ENABLE)
                v &= ~(1 << clk->enable_bit);
        else
                v |= (1 << clk->enable_bit);
-       __raw_writel(v, clk->enable_reg);
-       v = __raw_readl(clk->enable_reg); /* OCP barrier */
+       omap2_clk_writel(v, clk, clk->enable_reg);
+       v = omap2_clk_readl(clk, clk->enable_reg); /* OCP barrier */
 
        if (clk->ops && clk->ops->find_idlest)
                _omap2_module_wait_ready(clk);
@@ -353,12 +378,12 @@ void omap2_dflt_clk_disable(struct clk_hw *hw)
                return;
        }
 
-       v = __raw_readl(clk->enable_reg);
+       v = omap2_clk_readl(clk, clk->enable_reg);
        if (clk->flags & INVERT_ENABLE)
                v |= (1 << clk->enable_bit);
        else
                v &= ~(1 << clk->enable_bit);
-       __raw_writel(v, clk->enable_reg);
+       omap2_clk_writel(v, clk, clk->enable_reg);
        /* No OCP barrier needed here since it is a disable operation */
 
        if (clkdm_control && clk->clkdm)
@@ -454,7 +479,7 @@ int omap2_dflt_clk_is_enabled(struct clk_hw *hw)
        struct clk_hw_omap *clk = to_clk_hw_omap(hw);
        u32 v;
 
-       v = __raw_readl(clk->enable_reg);
+       v = omap2_clk_readl(clk, clk->enable_reg);
 
        if (clk->flags & INVERT_ENABLE)
                v ^= BIT(clk->enable_bit);
@@ -520,6 +545,9 @@ int omap2_clk_enable_autoidle_all(void)
        list_for_each_entry(c, &clk_hw_omap_clocks, node)
                if (c->ops && c->ops->allow_idle)
                        c->ops->allow_idle(c);
+
+       of_ti_clk_allow_autoidle_all();
+
        return 0;
 }
 
@@ -539,6 +567,9 @@ int omap2_clk_disable_autoidle_all(void)
        list_for_each_entry(c, &clk_hw_omap_clocks, node)
                if (c->ops && c->ops->deny_idle)
                        c->ops->deny_idle(c);
+
+       of_ti_clk_deny_autoidle_all();
+
        return 0;
 }
 
index 82916cc82c920d6fb7d08dcec444dded07ede0bb..bda767a9dea862d7223d86d1a59c0b1505e091f9 100644 (file)
@@ -21,6 +21,7 @@
 
 #include <linux/clkdev.h>
 #include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
 
 struct omap_clk {
        u16                             cpu;
@@ -37,7 +38,6 @@ struct omap_clk {
        }
 
 struct clockdomain;
-#define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw)
 
 #define DEFINE_STRUCT_CLK(_name, _parent_array_name, _clkops_name)     \
        static struct clk _name = {                             \
@@ -178,141 +178,6 @@ struct clksel {
        const struct clksel_rate *rates;
 };
 
-/**
- * struct dpll_data - DPLL registers and integration data
- * @mult_div1_reg: register containing the DPLL M and N bitfields
- * @mult_mask: mask of the DPLL M bitfield in @mult_div1_reg
- * @div1_mask: mask of the DPLL N bitfield in @mult_div1_reg
- * @clk_bypass: struct clk pointer to the clock's bypass clock input
- * @clk_ref: struct clk pointer to the clock's reference clock input
- * @control_reg: register containing the DPLL mode bitfield
- * @enable_mask: mask of the DPLL mode bitfield in @control_reg
- * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate()
- * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate()
- * @last_rounded_m4xen: cache of the last M4X result of
- *                     omap4_dpll_regm4xen_round_rate()
- * @last_rounded_lpmode: cache of the last lpmode result of
- *                      omap4_dpll_lpmode_recalc()
- * @max_multiplier: maximum valid non-bypass multiplier value (actual)
- * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate()
- * @min_divider: minimum valid non-bypass divider value (actual)
- * @max_divider: maximum valid non-bypass divider value (actual)
- * @modes: possible values of @enable_mask
- * @autoidle_reg: register containing the DPLL autoidle mode bitfield
- * @idlest_reg: register containing the DPLL idle status bitfield
- * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg
- * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg
- * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg
- * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg
- * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg
- * @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg
- * @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs
- * @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs
- * @flags: DPLL type/features (see below)
- *
- * Possible values for @flags:
- * DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs)
- *
- * @freqsel_mask is only used on the OMAP34xx family and AM35xx.
- *
- * XXX Some DPLLs have multiple bypass inputs, so it's not technically
- * correct to only have one @clk_bypass pointer.
- *
- * XXX The runtime-variable fields (@last_rounded_rate, @last_rounded_m,
- * @last_rounded_n) should be separated from the runtime-fixed fields
- * and placed into a different structure, so that the runtime-fixed data
- * can be placed into read-only space.
- */
-struct dpll_data {
-       void __iomem            *mult_div1_reg;
-       u32                     mult_mask;
-       u32                     div1_mask;
-       struct clk              *clk_bypass;
-       struct clk              *clk_ref;
-       void __iomem            *control_reg;
-       u32                     enable_mask;
-       unsigned long           last_rounded_rate;
-       u16                     last_rounded_m;
-       u8                      last_rounded_m4xen;
-       u8                      last_rounded_lpmode;
-       u16                     max_multiplier;
-       u8                      last_rounded_n;
-       u8                      min_divider;
-       u16                     max_divider;
-       u8                      modes;
-       void __iomem            *autoidle_reg;
-       void __iomem            *idlest_reg;
-       u32                     autoidle_mask;
-       u32                     freqsel_mask;
-       u32                     idlest_mask;
-       u32                     dco_mask;
-       u32                     sddiv_mask;
-       u32                     lpmode_mask;
-       u32                     m4xen_mask;
-       u8                      auto_recal_bit;
-       u8                      recal_en_bit;
-       u8                      recal_st_bit;
-       u8                      flags;
-};
-
-/*
- * struct clk.flags possibilities
- *
- * XXX document the rest of the clock flags here
- *
- * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL
- *     bits share the same register.  This flag allows the
- *     omap4_dpllmx*() code to determine which GATE_CTRL bit field
- *     should be used.  This is a temporary solution - a better approach
- *     would be to associate clock type-specific data with the clock,
- *     similar to the struct dpll_data approach.
- */
-#define ENABLE_REG_32BIT       (1 << 0)        /* Use 32-bit access */
-#define CLOCK_IDLE_CONTROL     (1 << 1)
-#define CLOCK_NO_IDLE_PARENT   (1 << 2)
-#define ENABLE_ON_INIT         (1 << 3)        /* Enable upon framework init */
-#define INVERT_ENABLE          (1 << 4)        /* 0 enables, 1 disables */
-#define CLOCK_CLKOUTX2         (1 << 5)
-
-/**
- * struct clk_hw_omap - OMAP struct clk
- * @node: list_head connecting this clock into the full clock list
- * @enable_reg: register to write to enable the clock (see @enable_bit)
- * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg)
- * @flags: see "struct clk.flags possibilities" above
- * @clksel_reg: for clksel clks, register va containing src/divisor select
- * @clksel_mask: bitmask in @clksel_reg for the src/divisor selector
- * @clksel: for clksel clks, pointer to struct clksel for this clock
- * @dpll_data: for DPLLs, pointer to struct dpll_data for this clock
- * @clkdm_name: clockdomain name that this clock is contained in
- * @clkdm: pointer to struct clockdomain, resolved from @clkdm_name at runtime
- * @rate_offset: bitshift for rate selection bitfield (OMAP1 only)
- * @src_offset: bitshift for source selection bitfield (OMAP1 only)
- *
- * XXX @rate_offset, @src_offset should probably be removed and OMAP1
- * clock code converted to use clksel.
- *
- */
-
-struct clk_hw_omap_ops;
-
-struct clk_hw_omap {
-       struct clk_hw           hw;
-       struct list_head        node;
-       unsigned long           fixed_rate;
-       u8                      fixed_div;
-       void __iomem            *enable_reg;
-       u8                      enable_bit;
-       u8                      flags;
-       void __iomem            *clksel_reg;
-       u32                     clksel_mask;
-       const struct clksel     *clksel;
-       struct dpll_data        *dpll_data;
-       const char              *clkdm_name;
-       struct clockdomain      *clkdm;
-       const struct clk_hw_omap_ops    *ops;
-};
-
 struct clk_hw_omap_ops {
        void                    (*find_idlest)(struct clk_hw_omap *oclk,
                                        void __iomem **idlest_reg,
@@ -348,36 +213,13 @@ unsigned long omap_fixed_divisor_recalc(struct clk_hw *hw,
 #define OMAP4XXX_EN_DPLL_FRBYPASS              0x6
 #define OMAP4XXX_EN_DPLL_LOCKED                        0x7
 
-/* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */
-#define DPLL_LOW_POWER_STOP    0x1
-#define DPLL_LOW_POWER_BYPASS  0x5
-#define DPLL_LOCKED            0x7
-
-/* DPLL Type and DCO Selection Flags */
-#define DPLL_J_TYPE            0x1
-
-long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
-                       unsigned long *parent_rate);
-unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
-int omap3_noncore_dpll_enable(struct clk_hw *hw);
-void omap3_noncore_dpll_disable(struct clk_hw *hw);
-int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
-                               unsigned long parent_rate);
 u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk);
 void omap3_dpll_allow_idle(struct clk_hw_omap *clk);
 void omap3_dpll_deny_idle(struct clk_hw_omap *clk);
-unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
-                                   unsigned long parent_rate);
 int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk);
 void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk);
 void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk);
-unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
-                               unsigned long parent_rate);
-long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
-                                   unsigned long target_rate,
-                                   unsigned long *parent_rate);
 
-void omap2_init_clk_clkdm(struct clk_hw *clk);
 void __init omap2_clk_disable_clkdm_control(void);
 
 /* clkt_clksel.c public functions */
@@ -396,29 +238,25 @@ int omap2_clksel_set_parent(struct clk_hw *hw, u8 field_val);
 extern void omap2_clkt_iclk_allow_idle(struct clk_hw_omap *clk);
 extern void omap2_clkt_iclk_deny_idle(struct clk_hw_omap *clk);
 
-u8 omap2_init_dpll_parent(struct clk_hw *hw);
 unsigned long omap2_get_dpll_rate(struct clk_hw_omap *clk);
 
-int omap2_dflt_clk_enable(struct clk_hw *hw);
-void omap2_dflt_clk_disable(struct clk_hw *hw);
-int omap2_dflt_clk_is_enabled(struct clk_hw *hw);
 void omap2_clk_dflt_find_companion(struct clk_hw_omap *clk,
                                   void __iomem **other_reg,
                                   u8 *other_bit);
 void omap2_clk_dflt_find_idlest(struct clk_hw_omap *clk,
                                void __iomem **idlest_reg,
                                u8 *idlest_bit, u8 *idlest_val);
-void omap2_init_clk_hw_omap_clocks(struct clk *clk);
 int omap2_clk_enable_autoidle_all(void);
-int omap2_clk_disable_autoidle_all(void);
 int omap2_clk_allow_idle(struct clk *clk);
 int omap2_clk_deny_idle(struct clk *clk);
-void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks);
 int omap2_clk_switch_mpurate_at_boot(const char *mpurate_ck_name);
 void omap2_clk_print_new_rates(const char *hfclkin_ck_name,
                               const char *core_ck_name,
                               const char *mpu_ck_name);
 
+u32 omap2_clk_readl(struct clk_hw_omap *clk, void __iomem *reg);
+void omap2_clk_writel(u32 val, struct clk_hw_omap *clk, void __iomem *reg);
+
 extern u16 cpu_mask;
 
 extern const struct clkops clkops_omap2_dflt_wait;
@@ -433,19 +271,12 @@ extern const struct clksel_rate gfx_l3_rates[];
 extern const struct clksel_rate dsp_ick_rates[];
 extern struct clk dummy_ck;
 
-extern const struct clk_hw_omap_ops clkhwops_omap3_dpll;
 extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
 extern const struct clk_hw_omap_ops clkhwops_wait;
-extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx;
-extern const struct clk_hw_omap_ops clkhwops_iclk;
 extern const struct clk_hw_omap_ops clkhwops_omap3430es2_ssi_wait;
-extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait;
 extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait;
-extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait;
-extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait;
 extern const struct clk_hw_omap_ops clkhwops_omap3430es2_hsotgusb_wait;
 extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait;
-extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait;
 extern const struct clk_hw_omap_ops clkhwops_apll54;
 extern const struct clk_hw_omap_ops clkhwops_apll96;
 extern const struct clk_hw_omap_ops clkhwops_omap2xxx_dpll;
@@ -460,6 +291,8 @@ extern const struct clksel_rate div_1_3_rates[];
 extern const struct clksel_rate div_1_4_rates[];
 extern const struct clksel_rate div31_1to31_rates[];
 
+extern void __iomem *clk_memmaps[];
+
 extern int am33xx_clk_init(void);
 
 extern int omap2_clkops_enable_clkdm(struct clk_hw *hw);
index bbd6a3f717e64e5b23cce67591f374d4dcb7b2f3..91ccb962e09e9ed7a59e45c1399de556048724d7 100644 (file)
@@ -43,6 +43,7 @@ int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
        struct clk_divider *parent;
        struct clk_hw *parent_hw;
        u32 dummy_v, orig_v;
+       struct clk_hw_omap *omap_clk = to_clk_hw_omap(clk);
        int ret;
 
        /* Clear PWRDN bit of HSDIVIDER */
@@ -53,15 +54,15 @@ int omap36xx_pwrdn_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
 
        /* Restore the dividers */
        if (!ret) {
-               orig_v = __raw_readl(parent->reg);
+               orig_v = omap2_clk_readl(omap_clk, parent->reg);
                dummy_v = orig_v;
 
                /* Write any other value different from the Read value */
                dummy_v ^= (1 << parent->shift);
-               __raw_writel(dummy_v, parent->reg);
+               omap2_clk_writel(dummy_v, omap_clk, parent->reg);
 
                /* Write the original divider */
-               __raw_writel(orig_v, parent->reg);
+               omap2_clk_writel(orig_v, omap_clk, parent->reg);
        }
 
        return ret;
index 8cd4b0a882aec39418c8adcd4e41daab0a010c0d..78d9f562e3ce796b76821c812ea3a7cf56050fb0 100644 (file)
@@ -9,11 +9,8 @@
 #define __ARCH_ARM_MACH_OMAP2_CLOCK3XXX_H
 
 int omap3xxx_clk_init(void);
-int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate,
-                                       unsigned long parent_rate);
 int omap3_core_dpll_m2_set_rate(struct clk_hw *clk, unsigned long rate,
                                        unsigned long parent_rate);
-void omap3_clk_lock_dpll5(void);
 
 extern struct clk *sdrc_ick_p;
 extern struct clk *arm_fck_p;
index 240db38f232c66226bca15be02aa144a8021acce..e515278351600436a691a77770153690f29348d4 100644 (file)
@@ -306,7 +306,7 @@ struct omap_hwmod;
 extern int omap_dss_reset(struct omap_hwmod *);
 
 /* SoC specific clock initializer */
-extern int (*omap_clk_init)(void);
+int omap_clk_init(void);
 
 #endif /* __ASSEMBLER__ */
 #endif /* __ARCH_ARM_MACH_OMAP2PLUS_COMMON_H */
index 3a0296cfcace879a322a6c414b4b9de9bb0cce62..3185ced807c952804d50199fd3ff7bc8ea68fb8f 100644 (file)
@@ -50,10 +50,10 @@ static void _omap3_dpll_write_clken(struct clk_hw_omap *clk, u8 clken_bits)
 
        dd = clk->dpll_data;
 
-       v = __raw_readl(dd->control_reg);
+       v = omap2_clk_readl(clk, dd->control_reg);
        v &= ~dd->enable_mask;
        v |= clken_bits << __ffs(dd->enable_mask);
-       __raw_writel(v, dd->control_reg);
+       omap2_clk_writel(v, clk, dd->control_reg);
 }
 
 /* _omap3_wait_dpll_status: wait for a DPLL to enter a specific state */
@@ -69,8 +69,8 @@ static int _omap3_wait_dpll_status(struct clk_hw_omap *clk, u8 state)
 
        state <<= __ffs(dd->idlest_mask);
 
-       while (((__raw_readl(dd->idlest_reg) & dd->idlest_mask) != state) &&
-              i < MAX_DPLL_WAIT_TRIES) {
+       while (((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask)
+               != state) && i < MAX_DPLL_WAIT_TRIES) {
                i++;
                udelay(1);
        }
@@ -147,7 +147,7 @@ static int _omap3_noncore_dpll_lock(struct clk_hw_omap *clk)
        state <<= __ffs(dd->idlest_mask);
 
        /* Check if already locked */
-       if ((__raw_readl(dd->idlest_reg) & dd->idlest_mask) == state)
+       if ((omap2_clk_readl(clk, dd->idlest_reg) & dd->idlest_mask) == state)
                goto done;
 
        ai = omap3_dpll_autoidle_read(clk);
@@ -311,14 +311,14 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
         * only since freqsel field is no longer present on other devices.
         */
        if (cpu_is_omap343x()) {
-               v = __raw_readl(dd->control_reg);
+               v = omap2_clk_readl(clk, dd->control_reg);
                v &= ~dd->freqsel_mask;
                v |= freqsel << __ffs(dd->freqsel_mask);
-               __raw_writel(v, dd->control_reg);
+               omap2_clk_writel(v, clk, dd->control_reg);
        }
 
        /* Set DPLL multiplier, divider */
-       v = __raw_readl(dd->mult_div1_reg);
+       v = omap2_clk_readl(clk, dd->mult_div1_reg);
        v &= ~(dd->mult_mask | dd->div1_mask);
        v |= dd->last_rounded_m << __ffs(dd->mult_mask);
        v |= (dd->last_rounded_n - 1) << __ffs(dd->div1_mask);
@@ -336,11 +336,11 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
                v |= sd_div << __ffs(dd->sddiv_mask);
        }
 
-       __raw_writel(v, dd->mult_div1_reg);
+       omap2_clk_writel(v, clk, dd->mult_div1_reg);
 
        /* Set 4X multiplier and low-power mode */
        if (dd->m4xen_mask || dd->lpmode_mask) {
-               v = __raw_readl(dd->control_reg);
+               v = omap2_clk_readl(clk, dd->control_reg);
 
                if (dd->m4xen_mask) {
                        if (dd->last_rounded_m4xen)
@@ -356,7 +356,7 @@ static int omap3_noncore_dpll_program(struct clk_hw_omap *clk, u16 freqsel)
                                v &= ~dd->lpmode_mask;
                }
 
-               __raw_writel(v, dd->control_reg);
+               omap2_clk_writel(v, clk, dd->control_reg);
        }
 
        /* We let the clock framework set the other output dividers later */
@@ -554,7 +554,7 @@ u32 omap3_dpll_autoidle_read(struct clk_hw_omap *clk)
        if (!dd->autoidle_reg)
                return -EINVAL;
 
-       v = __raw_readl(dd->autoidle_reg);
+       v = omap2_clk_readl(clk, dd->autoidle_reg);
        v &= dd->autoidle_mask;
        v >>= __ffs(dd->autoidle_mask);
 
@@ -588,10 +588,10 @@ void omap3_dpll_allow_idle(struct clk_hw_omap *clk)
         * by writing 0x5 instead of 0x1.  Add some mechanism to
         * optionally enter this mode.
         */
-       v = __raw_readl(dd->autoidle_reg);
+       v = omap2_clk_readl(clk, dd->autoidle_reg);
        v &= ~dd->autoidle_mask;
        v |= DPLL_AUTOIDLE_LOW_POWER_STOP << __ffs(dd->autoidle_mask);
-       __raw_writel(v, dd->autoidle_reg);
+       omap2_clk_writel(v, clk, dd->autoidle_reg);
 
 }
 
@@ -614,10 +614,10 @@ void omap3_dpll_deny_idle(struct clk_hw_omap *clk)
        if (!dd->autoidle_reg)
                return;
 
-       v = __raw_readl(dd->autoidle_reg);
+       v = omap2_clk_readl(clk, dd->autoidle_reg);
        v &= ~dd->autoidle_mask;
        v |= DPLL_AUTOIDLE_DISABLE << __ffs(dd->autoidle_mask);
-       __raw_writel(v, dd->autoidle_reg);
+       omap2_clk_writel(v, clk, dd->autoidle_reg);
 
 }
 
@@ -639,6 +639,9 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
        struct clk_hw_omap *pclk = NULL;
        struct clk *parent;
 
+       if (!parent_rate)
+               return 0;
+
        /* Walk up the parents of clk, looking for a DPLL */
        do {
                do {
@@ -660,7 +663,7 @@ unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
 
        WARN_ON(!dd->enable_mask);
 
-       v = __raw_readl(dd->control_reg) & dd->enable_mask;
+       v = omap2_clk_readl(pclk, dd->control_reg) & dd->enable_mask;
        v >>= __ffs(dd->enable_mask);
        if ((v != OMAP3XXX_EN_DPLL_LOCKED) || (dd->flags & DPLL_J_TYPE))
                rate = parent_rate;
index d28b0f7267151dfdcf2909b1647c9a5b80ba661b..52f9438b92f2a5d165b548b323bacb8680588bae 100644 (file)
@@ -42,7 +42,7 @@ int omap4_dpllmx_gatectrl_read(struct clk_hw_omap *clk)
                        OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
                        OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
 
-       v = __raw_readl(clk->clksel_reg);
+       v = omap2_clk_readl(clk, clk->clksel_reg);
        v &= mask;
        v >>= __ffs(mask);
 
@@ -61,10 +61,10 @@ void omap4_dpllmx_allow_gatectrl(struct clk_hw_omap *clk)
                        OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
                        OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
 
-       v = __raw_readl(clk->clksel_reg);
+       v = omap2_clk_readl(clk, clk->clksel_reg);
        /* Clear the bit to allow gatectrl */
        v &= ~mask;
-       __raw_writel(v, clk->clksel_reg);
+       omap2_clk_writel(v, clk, clk->clksel_reg);
 }
 
 void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk)
@@ -79,10 +79,10 @@ void omap4_dpllmx_deny_gatectrl(struct clk_hw_omap *clk)
                        OMAP4430_DPLL_CLKOUTX2_GATE_CTRL_MASK :
                        OMAP4430_DPLL_CLKOUT_GATE_CTRL_MASK;
 
-       v = __raw_readl(clk->clksel_reg);
+       v = omap2_clk_readl(clk, clk->clksel_reg);
        /* Set the bit to deny gatectrl */
        v |= mask;
-       __raw_writel(v, clk->clksel_reg);
+       omap2_clk_writel(v, clk, clk->clksel_reg);
 }
 
 const struct clk_hw_omap_ops clkhwops_omap4_dpllmx = {
@@ -140,7 +140,7 @@ unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
        rate = omap2_get_dpll_rate(clk);
 
        /* regm4xen adds a multiplier of 4 to DPLL calculations */
-       v = __raw_readl(dd->control_reg);
+       v = omap2_clk_readl(clk, dd->control_reg);
        if (v & OMAP4430_DPLL_REGM4XEN_MASK)
                rate *= OMAP4430_REGM4XEN_MULT;
 
index 07b68d5a7940e402705568114b7e0523cdda44f8..47381fd8746f6f673a6c2aeaa25ca11436c3809e 100644 (file)
 #include "prm44xx.h"
 
 /*
- * omap_clk_init: points to a function that does the SoC-specific
+ * omap_clk_soc_init: points to a function that does the SoC-specific
  * clock initializations
  */
-int (*omap_clk_init)(void);
+static int (*omap_clk_soc_init)(void);
 
 /*
  * The machine specific code may provide the extra mapping besides the
@@ -419,7 +419,7 @@ void __init omap2420_init_early(void)
        omap242x_clockdomains_init();
        omap2420_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap_clk_init = omap2420_clk_init;
+       omap_clk_soc_init = omap2420_clk_init;
 }
 
 void __init omap2420_init_late(void)
@@ -448,7 +448,7 @@ void __init omap2430_init_early(void)
        omap243x_clockdomains_init();
        omap2430_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap_clk_init = omap2430_clk_init;
+       omap_clk_soc_init = omap2430_clk_init;
 }
 
 void __init omap2430_init_late(void)
@@ -482,27 +482,35 @@ void __init omap3_init_early(void)
        omap3xxx_clockdomains_init();
        omap3xxx_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap_clk_init = omap3xxx_clk_init;
+       omap_clk_soc_init = omap3xxx_clk_init;
 }
 
 void __init omap3430_init_early(void)
 {
        omap3_init_early();
+       if (of_have_populated_dt())
+               omap_clk_soc_init = omap3430_dt_clk_init;
 }
 
 void __init omap35xx_init_early(void)
 {
        omap3_init_early();
+       if (of_have_populated_dt())
+               omap_clk_soc_init = omap3430_dt_clk_init;
 }
 
 void __init omap3630_init_early(void)
 {
        omap3_init_early();
+       if (of_have_populated_dt())
+               omap_clk_soc_init = omap3630_dt_clk_init;
 }
 
 void __init am35xx_init_early(void)
 {
        omap3_init_early();
+       if (of_have_populated_dt())
+               omap_clk_soc_init = am35xx_dt_clk_init;
 }
 
 void __init ti81xx_init_early(void)
@@ -520,7 +528,10 @@ void __init ti81xx_init_early(void)
        omap3xxx_clockdomains_init();
        omap3xxx_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap_clk_init = omap3xxx_clk_init;
+       if (of_have_populated_dt())
+               omap_clk_soc_init = ti81xx_dt_clk_init;
+       else
+               omap_clk_soc_init = omap3xxx_clk_init;
 }
 
 void __init omap3_init_late(void)
@@ -581,7 +592,7 @@ void __init am33xx_init_early(void)
        am33xx_clockdomains_init();
        am33xx_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap_clk_init = am33xx_clk_init;
+       omap_clk_soc_init = am33xx_dt_clk_init;
 }
 
 void __init am33xx_init_late(void)
@@ -606,6 +617,7 @@ void __init am43xx_init_early(void)
        am43xx_clockdomains_init();
        am43xx_hwmod_init();
        omap_hwmod_init_postsetup();
+       omap_clk_soc_init = am43xx_dt_clk_init;
 }
 
 void __init am43xx_init_late(void)
@@ -635,7 +647,7 @@ void __init omap4430_init_early(void)
        omap44xx_clockdomains_init();
        omap44xx_hwmod_init();
        omap_hwmod_init_postsetup();
-       omap_clk_init = omap4xxx_clk_init;
+       omap_clk_soc_init = omap4xxx_dt_clk_init;
 }
 
 void __init omap4430_init_late(void)
@@ -666,6 +678,7 @@ void __init omap5_init_early(void)
        omap54xx_clockdomains_init();
        omap54xx_hwmod_init();
        omap_hwmod_init_postsetup();
+       omap_clk_soc_init = omap5xxx_dt_clk_init;
 }
 
 void __init omap5_init_late(void)
@@ -691,6 +704,7 @@ void __init dra7xx_init_early(void)
        dra7xx_clockdomains_init();
        dra7xx_hwmod_init();
        omap_hwmod_init_postsetup();
+       omap_clk_soc_init = dra7xx_dt_clk_init;
 }
 
 void __init dra7xx_init_late(void)
@@ -710,3 +724,17 @@ void __init omap_sdrc_init(struct omap_sdrc_params *sdrc_cs0,
                _omap2_init_reprogram_sdrc();
        }
 }
+
+int __init omap_clk_init(void)
+{
+       int ret = 0;
+
+       if (!omap_clk_soc_init)
+               return 0;
+
+       ret = of_prcm_init();
+       if (!ret)
+               ret = omap_clk_soc_init();
+
+       return ret;
+}
index f7a6fd35b1e43f6dc9d36256508928b9ba135ea9..42d81885c700c498babd2dd2e5d322e3af2c3f19 100644 (file)
@@ -686,6 +686,8 @@ static struct clockdomain *_get_clkdm(struct omap_hwmod *oh)
        if (oh->clkdm) {
                return oh->clkdm;
        } else if (oh->_clk) {
+               if (__clk_get_flags(oh->_clk) & CLK_IS_BASIC)
+                       return NULL;
                clk = to_clk_hw_omap(__clk_get_hw(oh->_clk));
                return  clk->clkdm;
        }
@@ -1576,7 +1578,7 @@ static int _init_clkdm(struct omap_hwmod *oh)
        if (!oh->clkdm) {
                pr_warning("omap_hwmod: %s: could not associate to clkdm %s\n",
                        oh->name, oh->clkdm_name);
-               return -EINVAL;
+               return 0;
        }
 
        pr_debug("omap_hwmod: %s: associated to clkdm %s\n",
@@ -4231,6 +4233,7 @@ void __init omap_hwmod_init(void)
                soc_ops.assert_hardreset = _omap2_assert_hardreset;
                soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
                soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
+               soc_ops.init_clkdm = _init_clkdm;
        } else if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx()) {
                soc_ops.enable_module = _omap4_enable_module;
                soc_ops.disable_module = _omap4_disable_module;
index ac25ae6667cf92c448d37a9fc25058d69f26be19..623db40fdbbda48c50888d620b6a8a28b8a27c17 100644 (file)
@@ -18,6 +18,7 @@
 # ifndef __ASSEMBLER__
 extern void __iomem *prm_base;
 extern void omap2_set_globals_prm(void __iomem *prm);
+int of_prcm_init(void);
 # endif
 
 
index a2e1174ad1b6a6632ad904e4a0b8c5f37dea1e79..b4c4ab9c8044476d0777ed04cb8c9595d2f29f83 100644 (file)
 #include <linux/irq.h>
 #include <linux/interrupt.h>
 #include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
 
 #include "soc.h"
 #include "prm2xxx_3xxx.h"
@@ -30,6 +34,7 @@
 #include "prm3xxx.h"
 #include "prm44xx.h"
 #include "common.h"
+#include "clock.h"
 
 /*
  * OMAP_PRCM_MAX_NR_PENDING_REG: maximum number of PRM_IRQ*_MPU regs
@@ -464,3 +469,64 @@ int prm_unregister(struct prm_ll_data *pld)
 
        return 0;
 }
+
+static struct of_device_id omap_prcm_dt_match_table[] = {
+       { .compatible = "ti,am3-prcm" },
+       { .compatible = "ti,am3-scrm" },
+       { .compatible = "ti,am4-prcm" },
+       { .compatible = "ti,am4-scrm" },
+       { .compatible = "ti,omap3-prm" },
+       { .compatible = "ti,omap3-cm" },
+       { .compatible = "ti,omap3-scrm" },
+       { .compatible = "ti,omap4-cm1" },
+       { .compatible = "ti,omap4-prm" },
+       { .compatible = "ti,omap4-cm2" },
+       { .compatible = "ti,omap4-scrm" },
+       { .compatible = "ti,omap5-prm" },
+       { .compatible = "ti,omap5-cm-core-aon" },
+       { .compatible = "ti,omap5-scrm" },
+       { .compatible = "ti,omap5-cm-core" },
+       { .compatible = "ti,dra7-prm" },
+       { .compatible = "ti,dra7-cm-core-aon" },
+       { .compatible = "ti,dra7-cm-core" },
+       { }
+};
+
+static struct clk_hw_omap memmap_dummy_ck = {
+       .flags = MEMMAP_ADDRESSING,
+};
+
+static u32 prm_clk_readl(void __iomem *reg)
+{
+       return omap2_clk_readl(&memmap_dummy_ck, reg);
+}
+
+static void prm_clk_writel(u32 val, void __iomem *reg)
+{
+       omap2_clk_writel(val, &memmap_dummy_ck, reg);
+}
+
+static struct ti_clk_ll_ops omap_clk_ll_ops = {
+       .clk_readl = prm_clk_readl,
+       .clk_writel = prm_clk_writel,
+};
+
+int __init of_prcm_init(void)
+{
+       struct device_node *np;
+       void __iomem *mem;
+       int memmap_index = 0;
+
+       ti_clk_ll_ops = &omap_clk_ll_ops;
+
+       for_each_matching_node(np, omap_prcm_dt_match_table) {
+               mem = of_iomap(np, 0);
+               clk_memmaps[memmap_index] = mem;
+               ti_dt_clk_init_provider(np, memmap_index);
+               memmap_index++;
+       }
+
+       ti_dt_clockdomains_setup();
+
+       return 0;
+}
index ec084d158f642b3cf919adbbb0c6fd97e64f6317..74044aaf438b6f2c5fa9c093d40e15077b06f153 100644 (file)
@@ -570,8 +570,7 @@ static inline void __init realtime_counter_init(void)
                               clksrc_nr, clksrc_src, clksrc_prop)      \
 void __init omap##name##_gptimer_timer_init(void)                      \
 {                                                                      \
-       if (omap_clk_init)                                              \
-               omap_clk_init();                                        \
+       omap_clk_init();                                        \
        omap_dmtimer_init();                                            \
        omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop);    \
        omap2_gptimer_clocksource_init((clksrc_nr), clksrc_src,         \
@@ -582,8 +581,7 @@ void __init omap##name##_gptimer_timer_init(void)                   \
                                clksrc_nr, clksrc_src, clksrc_prop)     \
 void __init omap##name##_sync32k_timer_init(void)              \
 {                                                                      \
-       if (omap_clk_init)                                              \
-               omap_clk_init();                                        \
+       omap_clk_init();                                        \
        omap_dmtimer_init();                                            \
        omap2_gp_clockevent_init((clkev_nr), clkev_src, clkev_prop);    \
        /* Enable the use of clocksource="gp_timer" kernel parameter */ \
index f57fb338cc8aaa2ee533ca77be3e06994a74b25f..804d61566a53dd235750f44ed6ad7875df246b70 100644 (file)
@@ -290,10 +290,11 @@ void __init arm_memblock_init(struct meminfo *mi,
 #endif
 #ifdef CONFIG_BLK_DEV_INITRD
        /* FDT scan will populate initrd_start */
-       if (initrd_start) {
+       if (initrd_start && !phys_initrd_size) {
                phys_initrd_start = __virt_to_phys(initrd_start);
                phys_initrd_size = initrd_end - initrd_start;
        }
+       initrd_start = initrd_end = 0;
        if (phys_initrd_size &&
            !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
                pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",
diff --git a/arch/arm/plat-samsung/include/plat/regs-nand.h b/arch/arm/plat-samsung/include/plat/regs-nand.h
deleted file mode 100644 (file)
index 238efea..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/* arch/arm/mach-s3c2410/include/mach/regs-nand.h
- *
- * Copyright (c) 2004-2005 Simtec Electronics <linux@simtec.co.uk>
- *     http://www.simtec.co.uk/products/SWLINUX/
- *
- * 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.
- *
- * S3C2410 NAND register definitions
-*/
-
-#ifndef __ASM_ARM_REGS_NAND
-#define __ASM_ARM_REGS_NAND
-
-
-#define S3C2410_NFREG(x) (x)
-
-#define S3C2410_NFCONF  S3C2410_NFREG(0x00)
-#define S3C2410_NFCMD   S3C2410_NFREG(0x04)
-#define S3C2410_NFADDR  S3C2410_NFREG(0x08)
-#define S3C2410_NFDATA  S3C2410_NFREG(0x0C)
-#define S3C2410_NFSTAT  S3C2410_NFREG(0x10)
-#define S3C2410_NFECC   S3C2410_NFREG(0x14)
-
-#define S3C2440_NFCONT   S3C2410_NFREG(0x04)
-#define S3C2440_NFCMD    S3C2410_NFREG(0x08)
-#define S3C2440_NFADDR   S3C2410_NFREG(0x0C)
-#define S3C2440_NFDATA   S3C2410_NFREG(0x10)
-#define S3C2440_NFECCD0  S3C2410_NFREG(0x14)
-#define S3C2440_NFECCD1  S3C2410_NFREG(0x18)
-#define S3C2440_NFECCD   S3C2410_NFREG(0x1C)
-#define S3C2440_NFSTAT   S3C2410_NFREG(0x20)
-#define S3C2440_NFESTAT0 S3C2410_NFREG(0x24)
-#define S3C2440_NFESTAT1 S3C2410_NFREG(0x28)
-#define S3C2440_NFMECC0  S3C2410_NFREG(0x2C)
-#define S3C2440_NFMECC1  S3C2410_NFREG(0x30)
-#define S3C2440_NFSECC   S3C2410_NFREG(0x34)
-#define S3C2440_NFSBLK   S3C2410_NFREG(0x38)
-#define S3C2440_NFEBLK   S3C2410_NFREG(0x3C)
-
-#define S3C2412_NFSBLK         S3C2410_NFREG(0x20)
-#define S3C2412_NFEBLK         S3C2410_NFREG(0x24)
-#define S3C2412_NFSTAT         S3C2410_NFREG(0x28)
-#define S3C2412_NFMECC_ERR0    S3C2410_NFREG(0x2C)
-#define S3C2412_NFMECC_ERR1    S3C2410_NFREG(0x30)
-#define S3C2412_NFMECC0                S3C2410_NFREG(0x34)
-#define S3C2412_NFMECC1                S3C2410_NFREG(0x38)
-#define S3C2412_NFSECC         S3C2410_NFREG(0x3C)
-
-#define S3C2410_NFCONF_EN          (1<<15)
-#define S3C2410_NFCONF_512BYTE     (1<<14)
-#define S3C2410_NFCONF_4STEP       (1<<13)
-#define S3C2410_NFCONF_INITECC     (1<<12)
-#define S3C2410_NFCONF_nFCE        (1<<11)
-#define S3C2410_NFCONF_TACLS(x)    ((x)<<8)
-#define S3C2410_NFCONF_TWRPH0(x)   ((x)<<4)
-#define S3C2410_NFCONF_TWRPH1(x)   ((x)<<0)
-
-#define S3C2410_NFSTAT_BUSY        (1<<0)
-
-#define S3C2440_NFCONF_BUSWIDTH_8      (0<<0)
-#define S3C2440_NFCONF_BUSWIDTH_16     (1<<0)
-#define S3C2440_NFCONF_ADVFLASH                (1<<3)
-#define S3C2440_NFCONF_TACLS(x)                ((x)<<12)
-#define S3C2440_NFCONF_TWRPH0(x)       ((x)<<8)
-#define S3C2440_NFCONF_TWRPH1(x)       ((x)<<4)
-
-#define S3C2440_NFCONT_LOCKTIGHT       (1<<13)
-#define S3C2440_NFCONT_SOFTLOCK                (1<<12)
-#define S3C2440_NFCONT_ILLEGALACC_EN   (1<<10)
-#define S3C2440_NFCONT_RNBINT_EN       (1<<9)
-#define S3C2440_NFCONT_RN_FALLING      (1<<8)
-#define S3C2440_NFCONT_SPARE_ECCLOCK   (1<<6)
-#define S3C2440_NFCONT_MAIN_ECCLOCK    (1<<5)
-#define S3C2440_NFCONT_INITECC         (1<<4)
-#define S3C2440_NFCONT_nFCE            (1<<1)
-#define S3C2440_NFCONT_ENABLE          (1<<0)
-
-#define S3C2440_NFSTAT_READY           (1<<0)
-#define S3C2440_NFSTAT_nCE             (1<<1)
-#define S3C2440_NFSTAT_RnB_CHANGE      (1<<2)
-#define S3C2440_NFSTAT_ILLEGAL_ACCESS  (1<<3)
-
-#define S3C2412_NFCONF_NANDBOOT                (1<<31)
-#define S3C2412_NFCONF_ECCCLKCON       (1<<30)
-#define S3C2412_NFCONF_ECC_MLC         (1<<24)
-#define S3C2412_NFCONF_TACLS_MASK      (7<<12) /* 1 extra bit of Tacls */
-
-#define S3C2412_NFCONT_ECC4_DIRWR      (1<<18)
-#define S3C2412_NFCONT_LOCKTIGHT       (1<<17)
-#define S3C2412_NFCONT_SOFTLOCK                (1<<16)
-#define S3C2412_NFCONT_ECC4_ENCINT     (1<<13)
-#define S3C2412_NFCONT_ECC4_DECINT     (1<<12)
-#define S3C2412_NFCONT_MAIN_ECC_LOCK   (1<<7)
-#define S3C2412_NFCONT_INIT_MAIN_ECC   (1<<5)
-#define S3C2412_NFCONT_nFCE1           (1<<2)
-#define S3C2412_NFCONT_nFCE0           (1<<1)
-
-#define S3C2412_NFSTAT_ECC_ENCDONE     (1<<7)
-#define S3C2412_NFSTAT_ECC_DECDONE     (1<<6)
-#define S3C2412_NFSTAT_ILLEGAL_ACCESS  (1<<5)
-#define S3C2412_NFSTAT_RnB_CHANGE      (1<<4)
-#define S3C2412_NFSTAT_nFCE1           (1<<3)
-#define S3C2412_NFSTAT_nFCE0           (1<<2)
-#define S3C2412_NFSTAT_Res1            (1<<1)
-#define S3C2412_NFSTAT_READY           (1<<0)
-
-#define S3C2412_NFECCERR_SERRDATA(x)   (((x) >> 21) & 0xf)
-#define S3C2412_NFECCERR_SERRBIT(x)    (((x) >> 18) & 0x7)
-#define S3C2412_NFECCERR_MERRDATA(x)   (((x) >> 7) & 0x3ff)
-#define S3C2412_NFECCERR_MERRBIT(x)    (((x) >> 4) & 0x7)
-#define S3C2412_NFECCERR_SPARE_ERR(x)  (((x) >> 2) & 0x3)
-#define S3C2412_NFECCERR_MAIN_ERR(x)   (((x) >> 2) & 0x3)
-#define S3C2412_NFECCERR_NONE          (0)
-#define S3C2412_NFECCERR_1BIT          (1)
-#define S3C2412_NFECCERR_MULTIBIT      (2)
-#define S3C2412_NFECCERR_ECCAREA       (3)
-
-
-
-#endif /* __ASM_ARM_REGS_NAND */
-
index 2162172c0ddc765e62011c8d2a8b4006786550cf..b96723e258a0857a0b148f3299947ba757a28c10 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/of_address.h>
 #include <linux/cpuidle.h>
 #include <linux/cpufreq.h>
+#include <linux/cpu.h>
 
 #include <linux/mm.h>
 
@@ -154,7 +155,7 @@ int xen_unmap_domain_mfn_range(struct vm_area_struct *vma,
 }
 EXPORT_SYMBOL_GPL(xen_unmap_domain_mfn_range);
 
-static void __init xen_percpu_init(void *unused)
+static void xen_percpu_init(void)
 {
        struct vcpu_register_vcpu_info info;
        struct vcpu_info *vcpup;
@@ -193,6 +194,31 @@ static void xen_power_off(void)
                BUG();
 }
 
+static int xen_cpu_notification(struct notifier_block *self,
+                               unsigned long action,
+                               void *hcpu)
+{
+       switch (action) {
+       case CPU_STARTING:
+               xen_percpu_init();
+               break;
+       default:
+               break;
+       }
+
+       return NOTIFY_OK;
+}
+
+static struct notifier_block xen_cpu_notifier = {
+       .notifier_call = xen_cpu_notification,
+};
+
+static irqreturn_t xen_arm_callback(int irq, void *arg)
+{
+       xen_hvm_evtchn_do_upcall();
+       return IRQ_HANDLED;
+}
+
 /*
  * see Documentation/devicetree/bindings/arm/xen.txt for the
  * documentation of the Xen Device Tree format.
@@ -208,7 +234,7 @@ static int __init xen_guest_init(void)
        const char *version = NULL;
        const char *xen_prefix = "xen,xen-";
        struct resource res;
-       unsigned long grant_frames;
+       phys_addr_t grant_frames;
 
        node = of_find_compatible_node(NULL, NULL, "xen,xen");
        if (!node) {
@@ -227,8 +253,12 @@ static int __init xen_guest_init(void)
                return 0;
        grant_frames = res.start;
        xen_events_irq = irq_of_parse_and_map(node, 0);
-       pr_info("Xen %s support found, events_irq=%d gnttab_frame_pfn=%lx\n",
-                       version, xen_events_irq, (grant_frames >> PAGE_SHIFT));
+       pr_info("Xen %s support found, events_irq=%d gnttab_frame=%pa\n",
+                       version, xen_events_irq, &grant_frames);
+
+       if (xen_events_irq < 0)
+               return -ENODEV;
+
        xen_domain_type = XEN_HVM_DOMAIN;
 
        xen_setup_features();
@@ -281,9 +311,21 @@ static int __init xen_guest_init(void)
        disable_cpuidle();
        disable_cpufreq();
 
+       xen_init_IRQ();
+
+       if (request_percpu_irq(xen_events_irq, xen_arm_callback,
+                              "events", &xen_vcpu)) {
+               pr_err("Error request IRQ %d\n", xen_events_irq);
+               return -EINVAL;
+       }
+
+       xen_percpu_init();
+
+       register_cpu_notifier(&xen_cpu_notifier);
+
        return 0;
 }
-core_initcall(xen_guest_init);
+early_initcall(xen_guest_init);
 
 static int __init xen_pm_init(void)
 {
@@ -297,31 +339,6 @@ static int __init xen_pm_init(void)
 }
 late_initcall(xen_pm_init);
 
-static irqreturn_t xen_arm_callback(int irq, void *arg)
-{
-       xen_hvm_evtchn_do_upcall();
-       return IRQ_HANDLED;
-}
-
-static int __init xen_init_events(void)
-{
-       if (!xen_domain() || xen_events_irq < 0)
-               return -ENODEV;
-
-       xen_init_IRQ();
-
-       if (request_percpu_irq(xen_events_irq, xen_arm_callback,
-                       "events", &xen_vcpu)) {
-               pr_err("Error requesting IRQ %d\n", xen_events_irq);
-               return -EINVAL;
-       }
-
-       on_each_cpu(xen_percpu_init, NULL, 0);
-
-       return 0;
-}
-postcore_initcall(xen_init_events);
-
 /* In the hypervisor.S file. */
 EXPORT_SYMBOL_GPL(HYPERVISOR_event_channel_op);
 EXPORT_SYMBOL_GPL(HYPERVISOR_grant_table_op);
index d6aacb61ff4ae19de6fdf46607b5c0d5e8ff221e..14c4c0ca7f2a217851219355040c017cfe4a87a2 100644 (file)
@@ -18,7 +18,6 @@
 #ifdef CONFIG_DMA_CMA
 
 #include <linux/types.h>
-#include <asm-generic/dma-contiguous.h>
 
 static inline void
 dma_contiguous_early_fixup(phys_addr_t base, unsigned long size) { }
index 7f2b60affbb49509f290a5a56e5842fd1f29f4eb..b524dcd17243d712b4d461cf77d4dd56ed04c8bb 100644 (file)
@@ -28,7 +28,7 @@
 #define PTE_FILE               (_AT(pteval_t, 1) << 2) /* only when !pte_present() */
 #define PTE_DIRTY              (_AT(pteval_t, 1) << 55)
 #define PTE_SPECIAL            (_AT(pteval_t, 1) << 56)
-                               /* bit 57 for PMD_SECT_SPLITTING */
+#define PTE_WRITE              (_AT(pteval_t, 1) << 57)
 #define PTE_PROT_NONE          (_AT(pteval_t, 1) << 58) /* only when !PTE_VALID */
 
 /*
@@ -67,15 +67,15 @@ extern pgprot_t pgprot_default;
 
 #define _MOD_PROT(p, b)                __pgprot_modify(p, 0, b)
 
-#define PAGE_NONE              __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN)
-#define PAGE_SHARED            _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
-#define PAGE_SHARED_EXEC       _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN)
-#define PAGE_COPY              _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
-#define PAGE_COPY_EXEC         _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY)
-#define PAGE_READONLY          _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
-#define PAGE_READONLY_EXEC     _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY)
-#define PAGE_KERNEL            _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY)
-#define PAGE_KERNEL_EXEC       _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY)
+#define PAGE_NONE              __pgprot_modify(pgprot_default, PTE_TYPE_MASK, PTE_PROT_NONE | PTE_PXN | PTE_UXN)
+#define PAGE_SHARED            _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
+#define PAGE_SHARED_EXEC       _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE)
+#define PAGE_COPY              _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
+#define PAGE_COPY_EXEC         _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN)
+#define PAGE_READONLY          _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
+#define PAGE_READONLY_EXEC     _MOD_PROT(pgprot_default, PTE_USER | PTE_NG | PTE_PXN)
+#define PAGE_KERNEL            _MOD_PROT(pgprot_default, PTE_PXN | PTE_UXN | PTE_DIRTY | PTE_WRITE)
+#define PAGE_KERNEL_EXEC       _MOD_PROT(pgprot_default, PTE_UXN | PTE_DIRTY | PTE_WRITE)
 
 #define PAGE_HYP               _MOD_PROT(pgprot_default, PTE_HYP)
 #define PAGE_HYP_DEVICE                __pgprot(PROT_DEVICE_nGnRE | PTE_HYP)
@@ -83,13 +83,13 @@ extern pgprot_t pgprot_default;
 #define PAGE_S2                        __pgprot_modify(pgprot_default, PTE_S2_MEMATTR_MASK, PTE_S2_MEMATTR(MT_S2_NORMAL) | PTE_S2_RDONLY)
 #define PAGE_S2_DEVICE         __pgprot(PROT_DEFAULT | PTE_S2_MEMATTR(MT_S2_DEVICE_nGnRE) | PTE_S2_RDWR | PTE_UXN)
 
-#define __PAGE_NONE            __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE | PTE_RDONLY | PTE_PXN | PTE_UXN)
-#define __PAGE_SHARED          __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
-#define __PAGE_SHARED_EXEC     __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
-#define __PAGE_COPY            __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
-#define __PAGE_COPY_EXEC       __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY)
-#define __PAGE_READONLY                __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_RDONLY)
-#define __PAGE_READONLY_EXEC   __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_RDONLY)
+#define __PAGE_NONE            __pgprot(((_PAGE_DEFAULT) & ~PTE_TYPE_MASK) | PTE_PROT_NONE | PTE_PXN | PTE_UXN)
+#define __PAGE_SHARED          __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN | PTE_WRITE)
+#define __PAGE_SHARED_EXEC     __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_WRITE)
+#define __PAGE_COPY            __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
+#define __PAGE_COPY_EXEC       __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
+#define __PAGE_READONLY                __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN | PTE_UXN)
+#define __PAGE_READONLY_EXEC   __pgprot(_PAGE_DEFAULT | PTE_USER | PTE_NG | PTE_PXN)
 
 #endif /* __ASSEMBLY__ */
 
@@ -140,22 +140,53 @@ extern struct page *empty_zero_page;
 #define pte_dirty(pte)         (pte_val(pte) & PTE_DIRTY)
 #define pte_young(pte)         (pte_val(pte) & PTE_AF)
 #define pte_special(pte)       (pte_val(pte) & PTE_SPECIAL)
-#define pte_write(pte)         (!(pte_val(pte) & PTE_RDONLY))
+#define pte_write(pte)         (pte_val(pte) & PTE_WRITE)
 #define pte_exec(pte)          (!(pte_val(pte) & PTE_UXN))
 
 #define pte_valid_user(pte) \
        ((pte_val(pte) & (PTE_VALID | PTE_USER)) == (PTE_VALID | PTE_USER))
 
-#define PTE_BIT_FUNC(fn,op) \
-static inline pte_t pte_##fn(pte_t pte) { pte_val(pte) op; return pte; }
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+       pte_val(pte) &= ~PTE_WRITE;
+       return pte;
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+       pte_val(pte) |= PTE_WRITE;
+       return pte;
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+       pte_val(pte) &= ~PTE_DIRTY;
+       return pte;
+}
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{
+       pte_val(pte) |= PTE_DIRTY;
+       return pte;
+}
 
-PTE_BIT_FUNC(wrprotect, |= PTE_RDONLY);
-PTE_BIT_FUNC(mkwrite,   &= ~PTE_RDONLY);
-PTE_BIT_FUNC(mkclean,   &= ~PTE_DIRTY);
-PTE_BIT_FUNC(mkdirty,   |= PTE_DIRTY);
-PTE_BIT_FUNC(mkold,     &= ~PTE_AF);
-PTE_BIT_FUNC(mkyoung,   |= PTE_AF);
-PTE_BIT_FUNC(mkspecial, |= PTE_SPECIAL);
+static inline pte_t pte_mkold(pte_t pte)
+{
+       pte_val(pte) &= ~PTE_AF;
+       return pte;
+}
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+       pte_val(pte) |= PTE_AF;
+       return pte;
+}
+
+static inline pte_t pte_mkspecial(pte_t pte)
+{
+       pte_val(pte) |= PTE_SPECIAL;
+       return pte;
+}
 
 static inline void set_pte(pte_t *ptep, pte_t pte)
 {
@@ -170,8 +201,10 @@ static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
        if (pte_valid_user(pte)) {
                if (pte_exec(pte))
                        __sync_icache_dcache(pte, addr);
-               if (!pte_dirty(pte))
-                       pte = pte_wrprotect(pte);
+               if (pte_dirty(pte) && pte_write(pte))
+                       pte_val(pte) &= ~PTE_RDONLY;
+               else
+                       pte_val(pte) |= PTE_RDONLY;
        }
 
        set_pte(ptep, pte);
@@ -345,7 +378,7 @@ static inline pmd_t *pmd_offset(pud_t *pud, unsigned long addr)
 static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 {
        const pteval_t mask = PTE_USER | PTE_PXN | PTE_UXN | PTE_RDONLY |
-                             PTE_PROT_NONE | PTE_VALID;
+                             PTE_PROT_NONE | PTE_VALID | PTE_WRITE;
        pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
        return pte;
 }
index 248a15db37f2c05b86345e03d7a9294db2eaa3fc..1c0a9be2ffa85ad87245ac5837c94149e246533a 100644 (file)
@@ -85,11 +85,6 @@ EXPORT_SYMBOL_GPL(pm_power_off);
 void (*arm_pm_restart)(enum reboot_mode reboot_mode, const char *cmd);
 EXPORT_SYMBOL_GPL(arm_pm_restart);
 
-void arch_cpu_idle_prepare(void)
-{
-       local_fiq_enable();
-}
-
 /*
  * This is our default idle handler.
  */
@@ -138,7 +133,6 @@ void machine_restart(char *cmd)
 
        /* Disable interrupts first */
        local_irq_disable();
-       local_fiq_disable();
 
        /* Now call the architecture specific reboot code. */
        if (arm_pm_restart)
index 1b7617ab499be776b3c524286b06b77ea70e8bc8..7cfb92a4ab66523212ec91392b6ee269fa0d97a9 100644 (file)
@@ -161,7 +161,6 @@ asmlinkage void secondary_start_kernel(void)
        complete(&cpu_running);
 
        local_irq_enable();
-       local_fiq_enable();
        local_async_enable();
 
        /*
@@ -495,7 +494,6 @@ static void ipi_cpu_stop(unsigned int cpu)
 
        set_cpu_online(cpu, false);
 
-       local_fiq_disable();
        local_irq_disable();
 
        while (1)
index 430344e2c98957fddb607a1298bb772c934a777b..1fa9ce4afd8fa2c88b63fbc058ad95db193f9d0e 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/percpu.h>
 #include <linux/slab.h>
 #include <asm/cacheflush.h>
 #include <asm/cpu_ops.h>
@@ -89,6 +90,13 @@ int cpu_suspend(unsigned long arg)
        if (ret == 0) {
                cpu_switch_mm(mm->pgd, mm);
                flush_tlb_all();
+
+               /*
+                * Restore per-cpu offset before any kernel
+                * subsystem relying on it has a chance to run.
+                */
+               set_my_cpu_offset(per_cpu_offset(cpu));
+
                /*
                 * Restore HW breakpoint registers to sane values
                 * before debug exceptions are possibly reenabled
index 48a386094fa3cf98a7e8af3ae8d3b9ba5cce6c21..1ea9f26d1b703585537d82cf30aa44ddbe879917 100644 (file)
@@ -146,7 +146,7 @@ ENDPROC(flush_icache_range)
 ENDPROC(__flush_cache_user_range)
 
 /*
- *     __flush_kern_dcache_page(kaddr)
+ *     __flush_dcache_area(kaddr, size)
  *
  *     Ensure that the data held in the page kaddr is written back to the
  *     page in question.
index 8957b822010b474dfaf21d58573ce01a2808883f..005d29e2977da0848248975354c537a4f648d405 100644 (file)
@@ -38,8 +38,7 @@
  */
        .macro  dcache_line_size, reg, tmp
        mrs     \tmp, ctr_el0                   // read CTR
-       lsr     \tmp, \tmp, #16
-       and     \tmp, \tmp, #0xf                // cache line size encoding
+       ubfm    \tmp, \tmp, #16, #19            // cache line size encoding
        mov     \reg, #4                        // bytes per word
        lsl     \reg, \reg, \tmp                // actual cache line size
        .endm
index bed1f1de1caf07139e04ba52a6e7e2a0212e96ac..1333e6f9a8e50bd7e8996a67a392feaa4aaf95e0 100644 (file)
@@ -150,7 +150,7 @@ ENDPROC(cpu_do_resume)
 #endif
 
 /*
- *     cpu_switch_mm(pgd_phys, tsk)
+ *     cpu_do_switch_mm(pgd_phys, tsk)
  *
  *     Set the translation table base pointer to be pgd_phys.
  *
index 90b1753236446fcef1ce1225abc0decd92dd092d..af2738c7441b4cd4ffe9f78c5e03425c67b413bb 100644 (file)
@@ -146,6 +146,7 @@ CONFIG_USB_DEVICEFS=y
 CONFIG_USB_OTG_BLACKLIST_HUB=y
 CONFIG_USB_MON=y
 CONFIG_USB_MUSB_HDRC=y
+CONFIG_MUSB_PIO_ONLY=y
 CONFIG_USB_MUSB_BLACKFIN=y
 CONFIG_MUSB_PIO_ONLY=y
 CONFIG_USB_STORAGE=y
index 972aa6263ad0a9e7163c7b3b191afceef4282d70..be03be6ba5436eef23950abef36f4dbf294ce7cc 100644 (file)
@@ -59,7 +59,6 @@ CONFIG_BFIN_SIR=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=y
index 91988370b75e03b9603abdd7939faed63f496220..802f9c421621764869672bd8002b8bb893d950eb 100644 (file)
@@ -49,7 +49,6 @@ CONFIG_SYN_COOKIES=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
index 7b982d0502adddfb1f8142f9550944985b5725c8..3853c473b443193dac482e2994c1d131328a80fe 100644 (file)
@@ -44,7 +44,6 @@ CONFIG_IP_PNP=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=y
index c940a1e3ab3685fa85f6db0fd132a5d928d484f8..5e0db82b679ea669e72d28f1bdffb10fb5bfec19 100644 (file)
@@ -36,7 +36,6 @@ CONFIG_UNIX=y
 # CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
index e961483f1879bf2c3c13fdefdeb2b8db999d78b1..b9af4fa69984d20e0868cc293a46a1fe5f9e8264 100644 (file)
@@ -53,7 +53,6 @@ CONFIG_INET_XFRM_MODE_BEET=m
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
index 24936b91a6ee225ab491c168b42200ee4e2004c8..d6dd98e671463b4d86e83e3febcc376e46581faa 100644 (file)
@@ -51,7 +51,6 @@ CONFIG_INET=y
 # CONFIG_WIRELESS is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
index 89162d0fff9ea6325be99d8a45a21f0d8c45c224..2b58cb2212837f2dcafd49eda71efaef9fa8e2aa 100644 (file)
@@ -36,7 +36,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
 CONFIG_MTD_DEBUG=y
 CONFIG_MTD_DEBUG_VERBOSE=1
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_NFTL=y
index a26436bf50fff23db967e47b2e2ba3c5c765d5df..f754e490bbfd00a570995da744290cfa0db1d894 100644 (file)
@@ -36,7 +36,6 @@ CONFIG_IRTTY_SIR=m
 # CONFIG_WIRELESS is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAM=y
index 647991514ac9b8fc98065b1a6878b1b7c7e72908..629516578760cff5507fbe3482c603397ef65b53 100644 (file)
@@ -43,7 +43,6 @@ CONFIG_IP_NF_TARGET_REJECT=y
 CONFIG_IP_NF_MANGLE=y
 # CONFIG_WIRELESS is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 8fd9b446d6583f595e2b44ec57a7c6f771581c9f..a6a7298962edcda479759327b2b2c1e8ac25656a 100644 (file)
@@ -46,7 +46,6 @@ CONFIG_IP_PNP=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_RAM=y
index 0520c160230de103d8b85b907c48f64abab4e2b3..bc216646fe1864579ce444d6da28170147ea6523 100644 (file)
@@ -38,7 +38,6 @@ CONFIG_IRTTY_SIR=m
 # CONFIG_WIRELESS is not set
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=m
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_JEDECPROBE=m
index e4ed865b885e3a0279f53250afe78f17dcfefd35..ea88158ab432c7a7f2897c8d061e41cf2c40df84 100644 (file)
@@ -54,7 +54,6 @@ CONFIG_IP_PNP=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FW_LOADER is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
index ca67145c6a45987600407d44f80919b0e718b25e..c5c8d8a3a5fadaf597145af8b75060f02f4843de 100644 (file)
@@ -544,6 +544,7 @@ do { \
 #define DCBS_P                 0x04    /* L1 Data Cache Bank Select */
 #define PORT_PREF0_P           0x12    /* DAG0 Port Preference */
 #define PORT_PREF1_P           0x13    /* DAG1 Port Preference */
+#define RDCHK                  0x9     /* Enable L1 Parity Check */
 
 /* Masks */
 #define ENDM               0x00000001  /* (doesn't really exist) Enable
index 9558416d578b58f939e1969c268fe58da6c19331..3b125da5dcb233d8541558676b4c577289a8fe40 100644 (file)
@@ -1 +1,6 @@
+#ifndef _UAPI__BFIN_ASM_BYTEORDER_H
+#define _UAPI__BFIN_ASM_BYTEORDER_H
+
 #include <linux/byteorder/little_endian.h>
+
+#endif /* _UAPI__BFIN_ASM_BYTEORDER_H */
index 03255df6c1ea0acaaa8c232f9608f878ca9c5fbf..4fdab75dee15972853c5a417f4e8c0421e1bb573 100644 (file)
@@ -7,8 +7,8 @@
  * Licensed under the GPL-2 or later.
  */
 
-#ifndef        _ASM_CACHECTL
-#define        _ASM_CACHECTL
+#ifndef _UAPI_ASM_CACHECTL
+#define _UAPI_ASM_CACHECTL
 
 /*
  * Options for cacheflush system call
@@ -17,4 +17,4 @@
 #define        DCACHE  (1<<1)          /* writeback and flush data cache */
 #define        BCACHE  (ICACHE|DCACHE) /* flush both caches              */
 
-#endif /* _ASM_CACHECTL */
+#endif /* _UAPI_ASM_CACHECTL */
index 251c911d59c1181efbbafbeaa94b37b2c7f08c08..f51ad9a4f617ad221a4cba6bdb656d912252408d 100644 (file)
@@ -4,8 +4,8 @@
  * Licensed under the GPL-2 or later.
  */
 
-#ifndef _BFIN_FCNTL_H
-#define _BFIN_FCNTL_H
+#ifndef _UAPI_BFIN_FCNTL_H
+#define _UAPI_BFIN_FCNTL_H
 
 #define O_DIRECTORY     040000 /* must be a directory */
 #define O_NOFOLLOW     0100000 /* don't follow links */
@@ -14,4 +14,4 @@
 
 #include <asm-generic/fcntl.h>
 
-#endif
+#endif /* _UAPI_BFIN_FCNTL_H */
index eca8d75b0a8a4c5f36964a61c779d3aa04f208d9..9a41c20fc83da49a829b84e866d369eb8f937265 100644 (file)
@@ -1,7 +1,7 @@
-#ifndef __ARCH_BFIN_IOCTLS_H__
-#define __ARCH_BFIN_IOCTLS_H__
+#ifndef _UAPI__ARCH_BFIN_IOCTLS_H__
+#define _UAPI__ARCH_BFIN_IOCTLS_H__
 
 #define FIOQSIZE       0x545E
 #include <asm-generic/ioctls.h>
 
-#endif
+#endif /* _UAPI__ARCH_BFIN_IOCTLS_H__ */
index 072d8966c5c3cc4fe94082df0e00ee41cff7ffd6..99c7d6816da0bd3af15380153fb7f7bb57056f99 100644 (file)
@@ -5,12 +5,12 @@
  *
  */
 
-#ifndef __BFIN_POLL_H
-#define __BFIN_POLL_H
+#ifndef _UAPI__BFIN_POLL_H
+#define _UAPI__BFIN_POLL_H
 
 #define POLLWRNORM     4 /* POLLOUT */
 #define POLLWRBAND     256
 
 #include <asm-generic/poll.h>
 
-#endif
+#endif /* _UAPI__BFIN_POLL_H */
index 1bd3436db6a7b7d080bdf4bcb1a09db621fde1b0..9608ef64dc473d7c4dbefbe0d415283b390a0d5f 100644 (file)
@@ -4,8 +4,8 @@
  * Licensed under the GPL-2 or later.
  */
 
-#ifndef __ARCH_BFIN_POSIX_TYPES_H
-#define __ARCH_BFIN_POSIX_TYPES_H
+#ifndef _UAPI__ARCH_BFIN_POSIX_TYPES_H
+#define _UAPI__ARCH_BFIN_POSIX_TYPES_H
 
 typedef unsigned short __kernel_mode_t;
 #define __kernel_mode_t __kernel_mode_t
@@ -27,4 +27,4 @@ typedef unsigned short __kernel_old_dev_t;
 
 #include <asm-generic/posix_types.h>
 
-#endif
+#endif /* _UAPI__ARCH_BFIN_POSIX_TYPES_H */
index 906bdc1f5fda7c8b54e36775bab5bf92515a228d..b58f12dc27bd232f2143afbed6ac3b6073a1200e 100644 (file)
@@ -4,8 +4,8 @@
  * Licensed under the GPL-2 or later.
  */
 
-#ifndef _ASM_BLACKFIN_SIGCONTEXT_H
-#define _ASM_BLACKFIN_SIGCONTEXT_H
+#ifndef _UAPI_ASM_BLACKFIN_SIGCONTEXT_H
+#define _UAPI_ASM_BLACKFIN_SIGCONTEXT_H
 
 /* Add new entries at the end of the structure only.  */
 struct sigcontext {
@@ -58,4 +58,4 @@ struct sigcontext {
        unsigned long sc_seqstat;
 };
 
-#endif
+#endif /* _UAPI_ASM_BLACKFIN_SIGCONTEXT_H */
index 3e81306394e20fdb4630d08a9f25b575a5f64b9b..c72f4e6e386fa34b2b120e14baa3ee932caadee9 100644 (file)
@@ -4,8 +4,8 @@
  * Licensed under the GPL-2 or later.
  */
 
-#ifndef _BFIN_SIGINFO_H
-#define _BFIN_SIGINFO_H
+#ifndef _UAPI_BFIN_SIGINFO_H
+#define _UAPI_BFIN_SIGINFO_H
 
 #include <linux/types.h>
 #include <asm-generic/siginfo.h>
@@ -38,4 +38,4 @@
  */
 #define SEGV_STACKFLOW (__SI_FAULT|3)  /* stack overflow */
 
-#endif
+#endif /* _UAPI_BFIN_SIGINFO_H */
index 77a3bf37b69d6b3759ae678f8a90e61483a4cfe8..f0a0d8b6663a6905bea90c968a6dc43f5c686ed2 100644 (file)
@@ -1,7 +1,7 @@
-#ifndef _BLACKFIN_SIGNAL_H
-#define _BLACKFIN_SIGNAL_H
+#ifndef _UAPI_BLACKFIN_SIGNAL_H
+#define _UAPI_BLACKFIN_SIGNAL_H
 
 #define SA_RESTORER 0x04000000
 #include <asm-generic/signal.h>
 
-#endif
+#endif /* _UAPI_BLACKFIN_SIGNAL_H */
index 2e27665c4e91956c1bb7cc7525c0815c4c1ab485..d3068a750b94fd333256b1c6aee0a511067150e6 100644 (file)
@@ -4,8 +4,8 @@
  * Licensed under the GPL-2.
  */
 
-#ifndef _BFIN_STAT_H
-#define _BFIN_STAT_H
+#ifndef _UAPI_BFIN_STAT_H
+#define _UAPI_BFIN_STAT_H
 
 struct stat {
        unsigned short st_dev;
@@ -66,4 +66,4 @@ struct stat64 {
        unsigned long long st_ino;
 };
 
-#endif                         /* _BFIN_STAT_H */
+#endif /* _UAPI_BFIN_STAT_H */
index 89de6507ca2bbd38adcae0503fafff08b8fae61f..f5626b77684a71bae2385af1c5ba8ca8aab848e8 100644 (file)
@@ -4,8 +4,8 @@
  * Licensed under the GPL-2 or later.
  */
 
-#ifndef _BLACKFIN_SWAB_H
-#define _BLACKFIN_SWAB_H
+#ifndef _UAPI_BLACKFIN_SWAB_H
+#define _UAPI_BLACKFIN_SWAB_H
 
 #include <linux/types.h>
 #include <asm-generic/swab.h>
@@ -47,4 +47,4 @@ static __inline__ __attribute_const__ __u16 __arch_swab16(__u16 xx)
 
 #endif /* __GNUC__ */
 
-#endif                         /* _BLACKFIN_SWAB_H */
+#endif /* _UAPI_BLACKFIN_SWAB_H */
index 3961930421274b9f89e47f691554c6dbad61ecb6..4f424ae3b36de8225e5bee3977bde03a82548bb4 100644 (file)
@@ -17,7 +17,7 @@
 #ifdef CONFIG_MTD_UCLINUX
 #include <linux/mtd/map.h>
 #include <linux/ext2_fs.h>
-#include <linux/cramfs_fs.h>
+#include <uapi/linux/cramfs_fs.h>
 #include <linux/romfs_fs.h>
 #endif
 
index 4a8c2e3fd7e5649b469738ae163721854f279d99..4da70c47cc055223087c18baa6287e3976a14a08 100644 (file)
@@ -370,7 +370,8 @@ static struct platform_device bfin_sir0_device = {
 #endif
 #endif
 
-#if defined(CONFIG_SERIAL_BFIN_SPORT) || defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
+#if defined(CONFIG_SERIAL_BFIN_SPORT) || \
+       defined(CONFIG_SERIAL_BFIN_SPORT_MODULE)
 #ifdef CONFIG_SERIAL_BFIN_SPORT0_UART
 static struct resource bfin_sport0_uart_resources[] = {
        {
@@ -441,6 +442,50 @@ static struct platform_device bfin_sport1_uart_device = {
 #endif
 #endif
 
+#if defined(CONFIG_BFIN_SPORT) || defined(CONFIG_BFIN_SPORT_MODULE)
+static struct resource bfin_sport0_resources[] = {
+       {
+               .start = SPORT0_TCR1,
+               .end = SPORT0_MRCS3+4,
+               .flags = IORESOURCE_MEM,
+       },
+       {
+               .start = IRQ_SPORT0_TX,
+               .end = IRQ_SPORT0_TX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_RX,
+               .end = IRQ_SPORT0_RX+1,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = IRQ_SPORT0_ERROR,
+               .end = IRQ_SPORT0_ERROR,
+               .flags = IORESOURCE_IRQ,
+       },
+       {
+               .start = CH_SPORT0_TX,
+               .end = CH_SPORT0_TX,
+               .flags = IORESOURCE_DMA,
+       },
+       {
+               .start = CH_SPORT0_RX,
+               .end = CH_SPORT0_RX,
+               .flags = IORESOURCE_DMA,
+       },
+};
+static struct platform_device bfin_sport0_device = {
+       .name = "bfin_sport_raw",
+       .id = 0,
+       .num_resources = ARRAY_SIZE(bfin_sport0_resources),
+       .resource = bfin_sport0_resources,
+       .dev = {
+               .platform_data = &bfin_sport0_peripherals,
+       },
+};
+#endif
+
 #if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
 #include <linux/input.h>
 #include <linux/gpio_keys.h>
index b0fca44110b032dc59dc7b5d9485ba2724bf573c..6584190faeb809c2b73b698bc565b84cdfa98dfa 100644 (file)
@@ -17,6 +17,12 @@ config SEC_IRQ_PRIORITY_LEVELS
          Divide the total number of interrupt priority levels into sub-levels.
          There is 2 ^ (SEC_IRQ_PRIORITY_LEVELS + 1) different levels.
 
+config L1_PARITY_CHECK
+       bool "Enable L1 parity check"
+       default n
+       help
+         Enable the L1 parity check in L1 sram. A fault event is raised
+         when L1 parity error is found.
 
 comment "System Cross Bar Priority Assignment"
 
index 05194e95981b8f61b4ff14aebf3cfab9f1746746..8de8bc690b36f8653d1f2a5dc897a18e07c07532 100644 (file)
@@ -1025,7 +1025,9 @@ static struct adv7842_platform_data adv7842_data = {
        .ain_sel = ADV7842_AIN10_11_12_NC_SYNC_4_1,
        .prim_mode = ADV7842_PRIM_MODE_SDP,
        .vid_std_select = ADV7842_SDP_VID_STD_CVBS_SD_4x1,
-       .inp_color_space = ADV7842_INP_COLOR_SPACE_AUTO,
+       .hdmi_free_run_enable = 1,
+       .sdp_free_run_auto = 1,
+       .llc_dll_phase = 0x10,
        .i2c_sdp_io = 0x40,
        .i2c_sdp = 0x41,
        .i2c_cp = 0x42,
index dab8849af884a5a2032081eff51005c6daf08151..13644ed25489de4b46285ca3cd8953785310feff 100644 (file)
@@ -120,6 +120,7 @@ void clk_disable(struct clk *clk)
 }
 EXPORT_SYMBOL(clk_disable);
 
+
 unsigned long clk_get_rate(struct clk *clk)
 {
        unsigned long ret = 0;
@@ -131,7 +132,7 @@ EXPORT_SYMBOL(clk_get_rate);
 
 long clk_round_rate(struct clk *clk, unsigned long rate)
 {
-       long ret = -EIO;
+       long ret = 0;
        if (clk->ops && clk->ops->round_rate)
                ret = clk->ops->round_rate(clk, rate);
        return ret;
index 7a07374308aca4e0aba7b28276bd1114eb9a6f4a..696786e9a53147c8c51b8489b0375a77aceaf240 100644 (file)
 /* TRU_STAT.ADDRERR and TRU_ERRADDR.ADDR May Not Reflect the Correct Status */
 #define ANOMALY_16000003 (1)
 /* The EPPI Data Enable (DEN) Signal is Not Functional */
-#define ANOMALY_16000004 (1)
+#define ANOMALY_16000004 (__SILICON_REVISION__ < 1)
 /* Using L1 Instruction Cache with Parity Enabled is Unreliable */
-#define ANOMALY_16000005 (1)
+#define ANOMALY_16000005 (__SILICON_REVISION__ < 1)
 /* SEQSTAT.SYSNMI Clears Upon Entering the NMI ISR */
-#define ANOMALY_16000006 (1)
+#define ANOMALY_16000006 (__SILICON_REVISION__ < 1)
 /* DDR2 Memory Reads May Fail Intermittently */
 #define ANOMALY_16000007 (1)
 /* Instruction Memory Stalls Can Cause IFLUSH to Fail */
 /* Speculative Fetches Can Cause Undesired External FIFO Operations */
 #define ANOMALY_16000017 (1)
 /* RSI Boot Cleanup Routine Does Not Clear Registers */
-#define ANOMALY_16000018 (1)
+#define ANOMALY_16000018 (__SILICON_REVISION__ < 1)
 /* SPI Master Boot Device Auto-detection Frequency is Set Incorrectly */
-#define ANOMALY_16000019 (1)
+#define ANOMALY_16000019 (__SILICON_REVISION__ < 1)
 /* rom_SysControl() Fails to Set DDR0_CTL.INIT for Wakeup From Hibernate */
-#define ANOMALY_16000020 (1)
+#define ANOMALY_16000020 (__SILICON_REVISION__ < 1)
 /* rom_SysControl() Fails to Save and Restore DDR0_PHYCTL3 for Hibernate/Wakeup Sequence */
-#define ANOMALY_16000021 (1)
+#define ANOMALY_16000021 (__SILICON_REVISION__ < 1)
 /* Boot Code Fails to Enable Parity Fault Detection */
-#define ANOMALY_16000022 (1)
+#define ANOMALY_16000022 (__SILICON_REVISION__ < 1)
+/* Rom_SysControl Does not Update CGU0_CLKOUTSEL */
+#define ANOMALY_16000023 (__SILICON_REVISION__ < 1)
+/* Spurious Fault Signaled After Clearing an Externally Generated Fault */
+#define ANOMALY_16000024 (1)
+/* SPORT May Drive Data Pins During Inactive Channels in Multichannel Mode */
+#define ANOMALY_16000025 (1)
 /* USB DMA interrupt status do not show the DMA channel interrupt in the DMA ISR */
-#define ANOMALY_16000027 (1)
+#define ANOMALY_16000027 (__SILICON_REVISION__ < 1)
+/* Default SPI Master Boot Mode Setting is Incorrect */
+#define ANOMALY_16000028 (__SILICON_REVISION__ < 1)
+/* PPI tDFSPI Timing Does Not Meet Data Sheet Specification */
+#define ANOMALY_16000027 (__SILICON_REVISION__ < 1)
 /* Interrupted Core Reads of MMRs May Cause Data Loss */
-#define ANOMALY_16000030 (1)
+#define ANOMALY_16000030 (__SILICON_REVISION__ < 1)
+/* Incorrect Default USB_PLL_OSC.PLLM Value */
+#define ANOMALY_16000031 (__SILICON_REVISION__ < 1)
+/* Core Reads of System MMRs May Cause the Core to Hang */
+#define ANOMALY_16000032 (__SILICON_REVISION__ < 1)
+/* PPI Data Underflow on First Word Not Reported in Certain Modes */
+#define ANOMALY_16000033 (1)
+/* CNV1 Red Pixel Substitution feature not functional in the PVP */
+#define ANOMALY_16000034 (__SILICON_REVISION__ < 1)
+/* IPF0 Output Port Color Separation feature not functional */
+#define ANOMALY_16000035 (__SILICON_REVISION__ < 1)
+/* Spurious USB Wake From Hibernate May Occur When USB_VBUS is Low */
+#define ANOMALY_16000036 (__SILICON_REVISION__ < 1)
+/* Core RAISE 2 Instruction Not Latched When Executed at Priority Level 0, 1, or 2 */
+#define ANOMALY_16000037 (__SILICON_REVISION__ < 1)
+/* Spurious Unhandled NMI or L1 Memory Parity Error Interrupt May Occur Upon Entering the NMI ISR */
+#define ANOMALY_16000038 (__SILICON_REVISION__ < 1)
+/* CGU_STAT.PLOCKERR Bit May be Unreliable */
+#define ANOMALY_16000039 (1)
+/* JTAG Emulator Reads of SDU_IDCODE Alter Register Contents */
+#define ANOMALY_16000040 (1)
+/* IFLUSH Instruction Causes Parity Error When Parity Is Enabled */
+#define ANOMALY_16000041 (1)
+/* Instruction Cache Failure When Parity Is Enabled */
+#define ANOMALY_16000042 (__SILICON_REVISION__ == 1)
 
 /* Anomalies that don't exist on this proc */
 #define ANOMALY_05000158 (0)
index 0e1e451fd7d81aed622ef16bbbe0c0dcbf12502d..f4adedc9289563d38eb9872be94c53538b1fee6c 100644 (file)
@@ -6,7 +6,6 @@
  * Licensed under the GPL-2 or later.
  */
 
-#include <linux/init.h>
 #include <asm/blackfin.h>
 #include <asm/cplbinit.h>
 
@@ -42,6 +41,16 @@ bfin_cache_init(struct cplb_entry *cplb_tbl, unsigned long cplb_addr,
                 unsigned long mem_mask)
 {
        int i;
+#ifdef CONFIG_L1_PARITY_CHECK
+       u32 ctrl;
+
+       if (cplb_addr == DCPLB_ADDR0) {
+               ctrl = bfin_read32(mem_control) | (1 << RDCHK);
+               CSYNC();
+               bfin_write32(mem_control, ctrl);
+               SSYNC();
+       }
+#endif
 
        for (i = 0; i < MAX_CPLBS; i++) {
                bfin_write32(cplb_addr + i * 4, cplb_tbl[i].addr);
index 2308ce52f849b582ed8046bdfca9476bdad49e0e..d436bd907fc8c6e036a16b9f57241121cc5a0f2e 100644 (file)
@@ -7,7 +7,6 @@
  */
 
 #include <linux/linkage.h>
-#include <linux/init.h>
 #include <asm/blackfin.h>
 
 #include <asm/dma.h>
index ca75613231c84474ad276c667eb4cd415027532e..867b7cef204cb91f0ed15e9386ba7ea0b2089d96 100644 (file)
@@ -471,13 +471,8 @@ void handle_sec_ssi_fault(uint32_t gstat)
 
 }
 
-void handle_sec_fault(unsigned int irq, struct irq_desc *desc)
+void handle_sec_fault(uint32_t sec_gstat)
 {
-       uint32_t sec_gstat;
-
-       raw_spin_lock(&desc->lock);
-
-       sec_gstat = bfin_read32(SEC_GSTAT);
        if (sec_gstat & SEC_GSTAT_ERR) {
 
                switch (sec_gstat & SEC_GSTAT_ERRC) {
@@ -494,18 +489,16 @@ void handle_sec_fault(unsigned int irq, struct irq_desc *desc)
 
 
        }
-
-       raw_spin_unlock(&desc->lock);
-
-       handle_fasteoi_irq(irq, desc);
 }
 
-void handle_core_fault(unsigned int irq, struct irq_desc *desc)
+static struct irqaction bfin_fault_irq = {
+       .name = "Blackfin fault",
+};
+
+static irqreturn_t bfin_fault_routine(int irq, void *data)
 {
        struct pt_regs *fp = get_irq_regs();
 
-       raw_spin_lock(&desc->lock);
-
        switch (irq) {
        case IRQ_C0_DBL_FAULT:
                double_fault_c(fp);
@@ -522,11 +515,15 @@ void handle_core_fault(unsigned int irq, struct irq_desc *desc)
        case IRQ_C0_NMI_L1_PARITY_ERR:
                panic("Core 0 NMI L1 parity error");
                break;
+       case IRQ_SEC_ERR:
+               pr_err("SEC error\n");
+               handle_sec_fault(bfin_read32(SEC_GSTAT));
+               break;
        default:
-               panic("Core 1 fault %d occurs unexpectedly", irq);
+               panic("Unknown fault %d", irq);
        }
 
-       raw_spin_unlock(&desc->lock);
+       return IRQ_HANDLED;
 }
 #endif /* SEC_GCTL */
 
@@ -1195,12 +1192,7 @@ int __init init_arch_irq(void)
                                handle_percpu_irq);
                } else {
                        irq_set_chip(irq, &bfin_sec_irqchip);
-                       if (irq == IRQ_SEC_ERR)
-                               irq_set_handler(irq, handle_sec_fault);
-                       else if (irq >= IRQ_C0_DBL_FAULT && irq < CORE_IRQS)
-                               irq_set_handler(irq, handle_core_fault);
-                       else
-                               irq_set_handler(irq, handle_fasteoi_irq);
+                       irq_set_handler(irq, handle_fasteoi_irq);
                        __irq_set_preflow_handler(irq, bfin_sec_preflow_handler);
                }
        }
@@ -1239,6 +1231,13 @@ int __init init_arch_irq(void)
        register_syscore_ops(&sec_pm_syscore_ops);
 #endif
 
+       bfin_fault_irq.handler = bfin_fault_routine;
+#ifdef CONFIG_L1_PARITY_CHECK
+       setup_irq(IRQ_C0_NMI_L1_PARITY_ERR, &bfin_fault_irq);
+#endif
+       setup_irq(IRQ_C0_DBL_FAULT, &bfin_fault_irq);
+       setup_irq(IRQ_SEC_ERR, &bfin_fault_irq);
+
        return 0;
 }
 
index 2cbfb0b5679ee841ba337d7eaa39ec10a5d694db..8923398db66f01eef7777faaa08f2d324674e4ed 100644 (file)
@@ -6,7 +6,6 @@
  * Licensed under the GPL-2 or later.
  */
 
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <asm/scb.h>
index 2bbae07838198912aa4beda231a0f96eaa647bd5..ba6c30d8534d0dec77cac409788aa37c03772748 100644 (file)
@@ -53,7 +53,6 @@ enum ipi_message_type {
        BFIN_IPI_TIMER,
        BFIN_IPI_RESCHEDULE,
        BFIN_IPI_CALL_FUNC,
-       BFIN_IPI_CALL_FUNC_SINGLE,
        BFIN_IPI_CPU_STOP,
 };
 
@@ -162,9 +161,6 @@ static irqreturn_t ipi_handler_int1(int irq, void *dev_instance)
                        case BFIN_IPI_CALL_FUNC:
                                generic_smp_call_function_interrupt();
                                break;
-                       case BFIN_IPI_CALL_FUNC_SINGLE:
-                               generic_smp_call_function_single_interrupt();
-                               break;
                        case BFIN_IPI_CPU_STOP:
                                ipi_cpu_stop(cpu);
                                break;
@@ -210,7 +206,7 @@ void send_ipi(const struct cpumask *cpumask, enum ipi_message_type msg)
 
 void arch_send_call_function_single_ipi(int cpu)
 {
-       send_ipi(cpumask_of(cpu), BFIN_IPI_CALL_FUNC_SINGLE);
+       send_ipi(cpumask_of(cpu), BFIN_IPI_CALL_FUNC);
 }
 
 void arch_send_call_function_ipi_mask(const struct cpumask *mask)
index 9c957c81c6885acd595c42d1c470a1390cef6feb..ed0fcdf7e9905cb3050b50c6d467b2a5c8ba5f74 100644 (file)
@@ -122,12 +122,6 @@ config ETRAX100LX_V2
        help
          Support version 2 of the ETRAX 100LX.
 
-config SVINTO_SIM
-       bool "ETRAX-100LX-for-xsim-simulator"
-       select ARCH_USES_GETTIMEOFFSET
-       help
-         Support the xsim ETRAX Simulator.
-
 config ETRAXFS
        bool "ETRAX-FS-V32"
        help
index 609d5510410e06e869567268a20edf133c588853..f4374bae4fb4e632a5f81102514efa4ec1477ed0 100644 (file)
@@ -838,13 +838,13 @@ static int __init gpio_init(void)
         * in some tests.
         */
        res = request_irq(TIMER0_IRQ_NBR, gpio_poll_timer_interrupt,
-               IRQF_SHARED | IRQF_DISABLED, "gpio poll", gpio_name);
+               IRQF_SHARED, "gpio poll", gpio_name);
        if (res) {
                printk(KERN_CRIT "err: timer0 irq for gpio\n");
                return res;
        }
        res = request_irq(PA_IRQ_NBR, gpio_interrupt,
-               IRQF_SHARED | IRQF_DISABLED, "gpio PA", gpio_name);
+               IRQF_SHARED, "gpio PA", gpio_name);
        if (res)
                printk(KERN_CRIT "err: PA irq for gpio\n");
 
index a1c498d18d3184d196fa184e7bfe890c982ca53e..29eb02ab3f259fa0317986400f25c3ede747a6c1 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/timer.h>
+#include <linux/wait.h>
 #include <asm/irq.h>
 #include <asm/dma.h>
 #include <asm/io.h>
@@ -580,7 +581,7 @@ static int sync_serial_open(struct inode *inode, struct file *file)
                        if (port == &ports[0]) {
                                if (request_irq(8,
                                                manual_interrupt,
-                                               IRQF_SHARED | IRQF_DISABLED,
+                                               IRQF_SHARED,
                                                "synchronous serial manual irq",
                                                &ports[0])) {
                                        printk(KERN_CRIT "Can't alloc "
@@ -590,7 +591,7 @@ static int sync_serial_open(struct inode *inode, struct file *file)
                        } else if (port == &ports[1]) {
                                if (request_irq(8,
                                                manual_interrupt,
-                                               IRQF_SHARED | IRQF_DISABLED,
+                                               IRQF_SHARED,
                                                "synchronous serial manual irq",
                                                &ports[1])) {
                                        printk(KERN_CRIT "Can't alloc "
@@ -1136,7 +1137,8 @@ static ssize_t sync_serial_read(struct file *file, char *buf,
                if (file->f_flags & O_NONBLOCK)
                        return -EAGAIN;
 
-               interruptible_sleep_on(&port->in_wait_q);
+               wait_event_interruptible(port->in_wait_q,
+                                        !(start == end && !port->full));
                if (signal_pending(current))
                        return -EINTR;
 
index dcfec41d353300b59656fc6ad7c8bd288d84d5d6..4841e822cdd1aec04d38e7c23d63bb360e767b5e 100644 (file)
@@ -1,4 +1,3 @@
-# $Id: Makefile,v 1.6 2004/12/13 12:21:51 starvik Exp $
 #
 # Makefile for the linux kernel.
 #
index f932c85fbde48403f11b9056994411d1d50cbccc..7d307cce8bd8f63a4d1928ed82501ef99cee4bd0 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/delay.h>
 #include <linux/tty.h>
 #include <arch/svinto.h>
-#include <asm/io.h>             /* Get SIMCOUT. */
 
 extern void reset_watchdog(void);
 
@@ -318,12 +317,6 @@ console_write(struct console *co, const char *buf, unsigned int len)
        if (!port)
                return;
 
-#ifdef CONFIG_SVINTO_SIM
-       /* no use to simulate the serial debug output */
-       SIMCOUT(buf, len);
-       return;
-#endif
-
         console_write_direct(co, buf, len);
 }
 
index 897bba67bf7afed9a0b392db5d652349ae352f6c..81570fcd0412815917617ee4a3063c2a76c32976 100644 (file)
@@ -13,8 +13,8 @@
  * after a timer-interrupt and after each system call.
  *
  * Stack layout in 'ret_from_system_call':
- *     ptrace needs to have all regs on the stack.
- *     if the order here is changed, it needs to be 
+ *     ptrace needs to have all regs on the stack.
+ *     if the order here is changed, it needs to be
  *     updated in fork.c:copy_process, signal.c:do_signal,
  *     ptrace.c and ptrace.h
  *
@@ -31,7 +31,7 @@
 #include <asm/pgtable.h>
 
        ;; functions exported from this file
-       
+
        .globl system_call
        .globl ret_from_intr
        .globl ret_from_fork
        .globl do_sigtrap
        .globl gdb_handle_breakpoint
        .globl sys_call_table
-       
+
        ;; below are various parts of system_call which are not in the fast-path
-       
-#ifdef CONFIG_PREEMPT  
+
+#ifdef CONFIG_PREEMPT
        ; Check if preemptive kernel scheduling should be done
 _resume_kernel:
        di
@@ -74,7 +74,7 @@ _need_resched:
        nop
 #else
 #define _resume_kernel _Rexit
-#endif 
+#endif
 
        ; Called at exit from fork. schedule_tail must be called to drop
        ; spinlock if CONFIG_PREEMPT
@@ -91,16 +91,16 @@ ret_from_kernel_thread:
        ba  ret_from_sys_call
 
 ret_from_intr:
-       ;; check for resched if preemptive kernel or if we're going back to user-mode 
+       ;; check for resched if preemptive kernel or if we're going back to user-mode
        ;; this test matches the user_regs(regs) macro
        ;; we cannot simply test $dccr, because that does not necessarily
        ;; reflect what mode we'll return into.
-       
+
        move.d  [$sp + PT_dccr], $r0; regs->dccr
        btstq   8, $r0          ; U-flag
        bpl     _resume_kernel
-       ; Note that di below is in delay slot 
-       
+       ; Note that di below is in delay slot
+
 _resume_userspace:
        di                      ; so need_resched and sigpending don't change
 
@@ -113,7 +113,7 @@ _resume_userspace:
        nop
        ba      _Rexit
        nop
-       
+
        ;; The system_call is called by a BREAK instruction, which works like
        ;; an interrupt call but it stores the return PC in BRP instead of IRP.
        ;; Since we dont really want to have two epilogues (one for system calls
@@ -123,7 +123,7 @@ _resume_userspace:
        ;;
        ;; Since we can't have system calls inside interrupts, it should not matter
        ;; that we don't stack IRP.
-       ;; 
+       ;;
        ;; In r9 we have the wanted syscall number. Arguments come in r10,r11,r12,r13,mof,srp
        ;;
        ;; This function looks on the _surface_ like spaghetti programming, but it's
@@ -140,7 +140,7 @@ system_call:
        movem   $r13, [$sp]     ; push r0-r13
        push    $r10            ; push orig_r10
        clear.d [$sp=$sp-4]     ; frametype == 0, normal stackframe
-       
+
        movs.w  -ENOSYS, $r0
        move.d  $r0, [$sp+PT_r10]       ; put the default return value in r10 in the frame
 
@@ -148,17 +148,17 @@ system_call:
 
        movs.w  -8192, $r0      ; THREAD_SIZE == 8192
        and.d   $sp, $r0
-       
+
        move.d  [$r0+TI_flags], $r0
        btstq   TIF_SYSCALL_TRACE, $r0
        bmi     _syscall_trace_entry
-       nop     
+       nop
 
-_syscall_traced:       
+_syscall_traced:
 
        ;; check for sanity in the requested syscall number
-       
-       cmpu.w  NR_syscalls, $r9        
+
+       cmpu.w  NR_syscalls, $r9
        bcc     ret_from_sys_call
        lslq    2, $r9          ;  multiply by 4, in the delay slot
 
@@ -166,28 +166,28 @@ _syscall_traced:
        ;; of the register structure itself. some syscalls need this.
 
        push    $sp
-       
+
        ;; the parameter carrying registers r10, r11, r12 and 13 are intact.
-       ;; the fifth and sixth parameters (if any) was in mof and srp 
+       ;; the fifth and sixth parameters (if any) was in mof and srp
        ;; respectively, and we need to put them on the stack.
 
        push    $srp
        push    $mof
-       
+
        jsr     [$r9+sys_call_table]    ; actually do the system call
        addq    3*4, $sp                ; pop the mof, srp and regs parameters
        move.d  $r10, [$sp+PT_r10]      ; save the return value
 
        moveq   1, $r9          ; "parameter" to ret_from_sys_call to show it was a sys call
-       
+
        ;; fall through into ret_from_sys_call to return
-       
+
 ret_from_sys_call:
        ;; r9 is a parameter - if >=1 we came from a syscall, if 0, from an irq
-               
+
        ;; get the current task-struct pointer (see top for defs)
 
-       movs.w  -8192, $r0      ; THREAD_SIZE == 8192 
+       movs.w  -8192, $r0      ; THREAD_SIZE == 8192
        and.d   $sp, $r0
 
        di                      ; make sure need_resched and sigpending don't change
@@ -202,7 +202,7 @@ _Rexit:
        bne     _RBFexit        ; was not CRIS_FRAME_NORMAL, handle otherwise
        addq    4, $sp          ; skip orig_r10, in delayslot
        movem   [$sp+], $r13    ; registers r0-r13
-       pop     $mof            ; multiply overflow register 
+       pop     $mof            ; multiply overflow register
        pop     $dccr           ; condition codes
        pop     $srp            ; subroutine return pointer
        ;; now we have a 4-word SBFS frame which we do not want to restore
@@ -216,14 +216,14 @@ _Rexit:
 
 _RBFexit:
        movem   [$sp+], $r13    ; registers r0-r13, in delay slot
-       pop     $mof            ; multiply overflow register 
+       pop     $mof            ; multiply overflow register
        pop     $dccr           ; condition codes
        pop     $srp            ; subroutine return pointer
        rbf     [$sp+]          ; return by popping the CPU status
 
        ;; We get here after doing a syscall if extra work might need to be done
        ;; perform syscall exit tracing if needed
-       
+
 _syscall_exit_work:
        ;; $r0 contains current at this point and irq's are disabled
 
@@ -231,22 +231,22 @@ _syscall_exit_work:
        btstq   TIF_SYSCALL_TRACE, $r1
        bpl     _work_pending
        nop
-       
+
        ei
 
        move.d  $r9, $r1        ; preserve r9
        jsr     do_syscall_trace
        move.d  $r1, $r9
-       
+
        ba      _resume_userspace
        nop
-       
+
 _work_pending:
        move.d  [$r0+TI_flags], $r1
        btstq   TIF_NEED_RESCHED, $r1
        bpl     _work_notifysig ; was neither trace nor sched, must be signal/notify
        nop
-       
+
 _work_resched:
        move.d  $r9, $r1        ; preserve r9
        jsr     schedule
@@ -268,17 +268,17 @@ _work_notifysig:
        move.d  $sp, $r11       ; the regs param
        move.d  $r1, $r12       ; the thread_info_flags parameter
        jsr     do_notify_resume
-       
+
        ba _Rexit
        nop
 
        ;; We get here as a sidetrack when we've entered a syscall with the
        ;; trace-bit set. We need to call do_syscall_trace and then continue
        ;; with the call.
-       
+
 _syscall_trace_entry:
        ;; PT_r10 in the frame contains -ENOSYS as required, at this point
-       
+
        jsr     do_syscall_trace
 
        ;; now re-enter the syscall code to do the syscall itself
@@ -292,10 +292,10 @@ _syscall_trace_entry:
        move.d  [$sp+PT_r13],      $r13
        move    [$sp+PT_mof],      $mof
        move    [$sp+PT_srp],      $srp
-       
+
        ba      _syscall_traced
        nop
-       
+
        ;; resume performs the actual task-switching, by switching stack pointers
        ;; input arguments: r10 = prev, r11 = next, r12 = thread offset in task struct
        ;; returns old current in r10
@@ -303,29 +303,29 @@ _syscall_trace_entry:
        ;; TODO:  see the i386 version. The switch_to which calls resume in our version
        ;;        could really be an inline asm of this.
 
-resume:        
-       push    $srp                     ; we keep the old/new PC on the stack 
+resume:
+       push    $srp                     ; we keep the old/new PC on the stack
        add.d   $r12, $r10               ; r10 = current tasks tss
        move    $dccr, [$r10+THREAD_dccr]; save irq enable state
        di
 
        move    $usp, [$r10+ THREAD_usp] ; save user-mode stackpointer
-       
+
        ;; See copy_thread for the reason why register R9 is saved.
        subq    10*4, $sp
        movem   $r9, [$sp]               ; save non-scratch registers and R9.
-       
+
        move.d  $sp, [$r10+THREAD_ksp]   ; save the kernel stack pointer for the old task
        move.d  $sp, $r10                ; return last running task in r10
        and.d   -8192, $r10              ; get thread_info from stackpointer
-       move.d  [$r10+TI_task], $r10     ; get task  
+       move.d  [$r10+TI_task], $r10     ; get task
        add.d   $r12, $r11               ; find the new tasks tss
        move.d  [$r11+THREAD_ksp], $sp   ; switch into the new stackframe by restoring kernel sp
 
        movem   [$sp+], $r9              ; restore non-scratch registers and R9.
 
        move    [$r11+THREAD_usp], $usp ; restore user-mode stackpointer
-       
+
        move    [$r11+THREAD_dccr], $dccr ; restore irq enable status
        jump    [$sp+]                   ; restore PC
 
@@ -401,7 +401,7 @@ mmu_bus_fault:
        push    $r10            ; frametype == 1, BUSFAULT frame type
 
        move.d  $sp, $r10       ; pt_regs argument to handle_mmu_bus_fault
-               
+
        jsr     handle_mmu_bus_fault  ; in arch/cris/arch-v10/mm/fault.c
 
        ;; now we need to return through the normal path, we cannot just
@@ -410,10 +410,10 @@ mmu_bus_fault:
        ;; whatever.
 
        moveq   0, $r9          ; busfault is equivalent to an irq
-               
+
        ba      ret_from_intr
        nop
-               
+
        ;; special handlers for breakpoint and NMI
 hwbreakpoint:
        push    $dccr
@@ -429,7 +429,7 @@ hwbreakpoint:
        pop     $dccr
        retb
        nop
-       
+
 IRQ1_interrupt:
        ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
        move    $brp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
@@ -457,7 +457,7 @@ IRQ1_interrupt:
        ba      _Rexit          ; Return the standard way
        nop
 wdog:
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
 ;; Check if we're waiting for reset to happen, as signalled by
 ;; hard_reset_now setting cause_of_death to a magic value.  If so, just
 ;; get stuck until reset happens.
@@ -500,7 +500,7 @@ Watchdog_bite:
        move.d  $r10, [$r11]
 
 #endif
-       
+
 ;; Note that we don't do "setf m" here (or after two necessary NOPs),
 ;; since *not* doing that saves us from re-entrancy checks.  We don't want
 ;; to get here again due to possible subsequent NMIs; we want the watchdog
@@ -523,16 +523,16 @@ _watchdogmsg:
        .ascii  "Oops: bitten by watchdog\n\0"
        .previous
 
-#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */
+#endif /* CONFIG_ETRAX_WATCHDOG */
 
-spurious_interrupt:    
+spurious_interrupt:
        di
        jump hard_reset_now
 
        ;; this handles the case when multiple interrupts arrive at the same time
        ;; we jump to the first set interrupt bit in a priority fashion
        ;; the hardware will call the unserved interrupts after the handler finishes
-       
+
 multiple_interrupt:
        ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
        move    $irp,[$sp=$sp-16]; instruction pointer and room for a fake SBFS frame
@@ -551,7 +551,7 @@ multiple_interrupt:
        jump    ret_from_intr
 
 do_sigtrap:
-       ;; 
+       ;;
        ;; SIGTRAP the process that executed the break instruction.
        ;; Make a frame that Rexit in entry.S expects.
        ;;
@@ -568,30 +568,30 @@ do_sigtrap:
        movs.w  -8192,$r9               ; THREAD_SIZE == 8192
        and.d   $sp, $r9
        move.d  [$r9+TI_task], $r10
-       move.d  [$r10+TASK_pid], $r10   ; current->pid as arg1. 
+       move.d  [$r10+TASK_pid], $r10   ; current->pid as arg1.
        moveq   5, $r11                 ; SIGTRAP as arg2.
-       jsr     sys_kill       
+       jsr     sys_kill
        jump    ret_from_intr           ; Use the return routine for interrupts.
 
-gdb_handle_breakpoint: 
+gdb_handle_breakpoint:
        push    $dccr
        push    $r0
 #ifdef CONFIG_ETRAX_KGDB
-       move    $dccr, $r0              ; U-flag not affected by previous insns. 
+       move    $dccr, $r0              ; U-flag not affected by previous insns.
        btstq   8, $r0                  ; Test the U-flag.
-       bmi     _ugdb_handle_breakpoint ; Go to user mode debugging. 
-       nop                             ; Empty delay slot (cannot pop r0 here). 
+       bmi     _ugdb_handle_breakpoint ; Go to user mode debugging.
+       nop                             ; Empty delay slot (cannot pop r0 here).
        pop     $r0                     ; Restore r0.
-       ba      kgdb_handle_breakpoint  ; Go to kernel debugging. 
+       ba      kgdb_handle_breakpoint  ; Go to kernel debugging.
        pop     $dccr                   ; Restore dccr in delay slot.
 #endif
-       
-_ugdb_handle_breakpoint:       
+
+_ugdb_handle_breakpoint:
        move    $brp, $r0               ; Use r0 temporarily for calculation.
        subq    2, $r0                  ; Set to address of previous instruction.
        move    $r0, $brp
-       pop     $r0                     ; Restore r0. 
-       ba      do_sigtrap              ; SIGTRAP the offending process. 
+       pop     $r0                     ; Restore r0.
+       ba      do_sigtrap              ; SIGTRAP the offending process.
        pop     $dccr                   ; Restore dccr in delay slot.
 
        .data
@@ -602,7 +602,7 @@ hw_bp_trig_ptr:
        .dword hw_bp_trigs
 
        .section .rodata,"a"
-sys_call_table:        
+sys_call_table:
        .long sys_restart_syscall       /* 0 - old "setup()" system call, used for restarting */
        .long sys_exit
        .long sys_fork
@@ -713,7 +713,7 @@ sys_call_table:
        .long sys_newlstat
        .long sys_newfstat
        .long sys_ni_syscall    /* old sys_uname holder */
-       .long sys_ni_syscall    /* sys_iopl in i386 */
+       .long sys_ni_syscall    /* 110 */ /* sys_iopl in i386 */
        .long sys_vhangup
        .long sys_ni_syscall    /* old "idle" system call */
        .long sys_ni_syscall    /* vm86old in i386 */
@@ -730,7 +730,7 @@ sys_call_table:
        .long sys_adjtimex
        .long sys_mprotect      /* 125 */
        .long sys_sigprocmask
-       .long sys_ni_syscall    /* old "create_module" */ 
+       .long sys_ni_syscall    /* old "create_module" */
        .long sys_init_module
        .long sys_delete_module
        .long sys_ni_syscall    /* 130: old "get_kernel_syms" */
@@ -795,7 +795,7 @@ sys_call_table:
        .long sys_ni_syscall    /* streams2 */
        .long sys_vfork         /* 190 */
        .long sys_getrlimit
-       .long sys_mmap2
+       .long sys_mmap2         /* mmap_pgoff */
        .long sys_truncate64
        .long sys_ftruncate64
        .long sys_stat64        /* 195 */
@@ -861,21 +861,21 @@ sys_call_table:
        .long sys_epoll_ctl     /* 255 */
        .long sys_epoll_wait
        .long sys_remap_file_pages
-       .long sys_set_tid_address
-       .long sys_timer_create
-       .long sys_timer_settime         /* 260 */
-       .long sys_timer_gettime
-       .long sys_timer_getoverrun
-       .long sys_timer_delete
-       .long sys_clock_settime
-       .long sys_clock_gettime         /* 265 */
-       .long sys_clock_getres
-       .long sys_clock_nanosleep
+       .long sys_set_tid_address
+       .long sys_timer_create
+       .long sys_timer_settime         /* 260 */
+       .long sys_timer_gettime
+       .long sys_timer_getoverrun
+       .long sys_timer_delete
+       .long sys_clock_settime
+       .long sys_clock_gettime         /* 265 */
+       .long sys_clock_getres
+       .long sys_clock_nanosleep
        .long sys_statfs64
-       .long sys_fstatfs64     
-       .long sys_tgkill        /* 270 */
+       .long sys_fstatfs64
+       .long sys_tgkill                /* 270 */
        .long sys_utimes
-       .long sys_fadvise64_64
+       .long sys_fadvise64_64
        .long sys_ni_syscall    /* sys_vserver */
        .long sys_ni_syscall    /* sys_mbind */
        .long sys_ni_syscall    /* 275 sys_get_mempolicy */
@@ -886,7 +886,7 @@ sys_call_table:
        .long sys_mq_timedreceive       /* 280 */
        .long sys_mq_notify
        .long sys_mq_getsetattr
-       .long sys_ni_syscall            /* reserved for kexec */
+       .long sys_ni_syscall
        .long sys_waitid
        .long sys_ni_syscall            /* 285 */ /* available */
        .long sys_add_key
@@ -939,6 +939,22 @@ sys_call_table:
        .long sys_preadv
        .long sys_pwritev
        .long sys_setns                 /* 335 */
+       .long sys_name_to_handle_at
+       .long sys_open_by_handle_at
+       .long sys_rt_tgsigqueueinfo
+       .long sys_perf_event_open
+       .long sys_recvmmsg              /* 340 */
+       .long sys_accept4
+       .long sys_fanotify_init
+       .long sys_fanotify_mark
+       .long sys_prlimit64
+       .long sys_clock_adjtime         /* 345 */
+       .long sys_syncfs
+       .long sys_sendmmsg
+       .long sys_process_vm_readv
+       .long sys_process_vm_writev
+       .long sys_kcmp                  /* 350 */
+       .long sys_finit_module
 
         /*
          * NOTE!! This doesn't have to be exact - we just have
@@ -950,4 +966,4 @@ sys_call_table:
        .rept NR_syscalls-(.-sys_call_table)/4
                .long sys_ni_syscall
        .endr
-       
+
index a1f2014b4e3b3cae8006c75215f34ecc74688290..4a146e1749c93ce2b2e9d35cec6c167bf4815232 100644 (file)
@@ -1,12 +1,10 @@
 /*
  * Head of the kernel - alter with care
  *
- * Copyright (C) 2000, 2001 Axis Communications AB
+ * Copyright (C) 2000, 2001, 2010 Axis Communications AB
  *
- * Authors:    Bjorn Wesen (bjornw@axis.com)
- * 
  */
-       
+
 #define ASSEMBLER_MACROS_ONLY
 /* The IO_* macros use the ## token concatenation operator, so
    -traditional must not be used when assembling this file.  */
 
 #define START_ETHERNET_CLOCK IO_STATE(R_NETWORK_GEN_CONFIG, enable, on) |\
                              IO_STATE(R_NETWORK_GEN_CONFIG, phy, mii_clk)
-                               
+
        ;; exported symbols
-               
+
        .globl  etrax_irv
        .globl  romfs_start
        .globl  romfs_length
        .globl  romfs_in_flash
        .globl  swapper_pg_dir
-                                       
+
        .text
 
        ;; This is the entry point of the kernel. We are in supervisor mode.
        ;; put a nop (2 bytes) here first so we dont accidentally skip the di
        ;;
        ;; NOTICE! The registers r8 and r9 are used as parameters carrying
-       ;; information from the decompressor (if the kernel was compressed). 
+       ;; information from the decompressor (if the kernel was compressed).
        ;; They should not be used in the code below until read.
-       
-       nop     
+
+       nop
        di
 
        ;; First setup the kseg_c mapping from where the kernel is linked
 
 #ifdef CONFIG_CRIS_LOW_MAP
        ; kseg mappings, temporary map of 0xc0->0x40
-       move.d    IO_FIELD (R_MMU_KBASE_HI, base_c, 4)          \
+       move.d    IO_FIELD (R_MMU_KBASE_HI, base_c, 4)          \
                | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb)        \
                | IO_FIELD (R_MMU_KBASE_HI, base_9, 9)          \
                | IO_FIELD (R_MMU_KBASE_HI, base_8, 8), $r0
        move.d  $r0, [R_MMU_KBASE_HI]
 
-       ; temporary map of 0x40->0x40 and 0x60->0x40 
-       move.d    IO_FIELD (R_MMU_KBASE_LO, base_6, 4)          \
+       ; temporary map of 0x40->0x40 and 0x60->0x40
+       move.d    IO_FIELD (R_MMU_KBASE_LO, base_6, 4)          \
                | IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0
        move.d  $r0, [R_MMU_KBASE_LO]
 
        ; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped
-       move.d    IO_STATE (R_MMU_CONFIG, mmu_enable, enable)   \
+       move.d    IO_STATE (R_MMU_CONFIG, mmu_enable, enable)   \
                | IO_STATE (R_MMU_CONFIG, inv_excp, enable)     \
                | IO_STATE (R_MMU_CONFIG, acc_excp, enable)     \
                | IO_STATE (R_MMU_CONFIG, we_excp, enable)      \
        move.d  $r0, [R_MMU_CONFIG]
 #else
        ; kseg mappings
-       move.d    IO_FIELD (R_MMU_KBASE_HI, base_e, 8)          \
+       move.d    IO_FIELD (R_MMU_KBASE_HI, base_e, 8)          \
                | IO_FIELD (R_MMU_KBASE_HI, base_c, 4)          \
                | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), $r0
        move.d  $r0, [R_MMU_KBASE_HI]
 
-       ; temporary map of 0x40->0x40 and 0x00->0x00 
+       ; temporary map of 0x40->0x40 and 0x00->0x00
        move.d    IO_FIELD (R_MMU_KBASE_LO, base_4, 4), $r0
        move.d  $r0, [R_MMU_KBASE_LO]
 
        ; mmu enable, segs f,e,c,b,4,0 segment mapped
-       move.d    IO_STATE (R_MMU_CONFIG, mmu_enable, enable)   \
+       move.d    IO_STATE (R_MMU_CONFIG, mmu_enable, enable)   \
                | IO_STATE (R_MMU_CONFIG, inv_excp, enable)     \
                | IO_STATE (R_MMU_CONFIG, acc_excp, enable)     \
                | IO_STATE (R_MMU_CONFIG, we_excp, enable)      \
        ;;
        ;; In both cases, we start in un-cached mode, and need to jump into a
        ;; cached PC after we're done fiddling around with the segments.
-       ;; 
+       ;;
        ;; arch/etrax100/etrax100.ld sets some symbols that define the start
        ;; and end of each segment.
 
        ;; Check if we start from DRAM or FLASH by testing PC
-       
+
        move.d  $pc,$r0
        and.d   0x7fffffff,$r0  ; get rid of the non-cache bit
        cmp.d   0x10000,$r0     ; arbitrary... just something above this code
@@ -163,30 +161,28 @@ _inflash0:
        ;; after init.
        .section ".init.text", "ax"
 _inflash:
-#ifdef CONFIG_ETRAX_ETHERNET   
+#ifdef CONFIG_ETRAX_ETHERNET
        ;; Start MII clock to make sure it is running when tranceiver is reset
        move.d START_ETHERNET_CLOCK, $r0
        move.d $r0, [R_NETWORK_GEN_CONFIG]
 #endif
 
        ;; Set up waitstates etc according to kernel configuration.
-#ifndef CONFIG_SVINTO_SIM
        move.d   CONFIG_ETRAX_DEF_R_WAITSTATES, $r0
        move.d   $r0, [R_WAITSTATES]
 
        move.d   CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0
        move.d   $r0, [R_BUS_CONFIG]
-#endif
 
        ;; We need to initialze DRAM registers before we start using the DRAM
 
        cmp.d   RAM_INIT_MAGIC, $r8     ; Already initialized?
        beq     _dram_init_finished
        nop
-       
+
 #include "../lib/dram_init.S"
 
-_dram_init_finished:           
+_dram_init_finished:
        ;; Copy text+data to DRAM
        ;; This is fragile - the calculation of r4 as the image size depends
        ;; on that the labels below actually are the first and last positions
@@ -198,7 +194,7 @@ _dram_init_finished:
        ;; between the physical start of the flash and the flash-image start,
        ;; and when run with compression, the kernel is actually unpacked to
        ;; DRAM and we never get here in the first place :))
-       
+
        moveq   0, $r0                  ; source
        move.d  text_start, $r1         ; destination
        move.d  __vmlinux_end, $r2      ; end destination
@@ -229,10 +225,10 @@ _dram_init_finished:
        add.d   0xf0000000, $r4 ; add flash start in virtual memory (cached)
 #endif
        move.d  $r4, [romfs_start]
-1:     
+1:
        moveq   1, $r0
        move.d  $r0, [romfs_in_flash]
-               
+
        jump    _start_it       ; enter code, cached this time
 
 _inram:
@@ -241,7 +237,7 @@ _inram:
 
        moveq   0, $r0
        move.d  $r0, [romfs_length] ; default if there is no cramfs
-       
+
        ;; The kernel could have been unpacked to DRAM by the loader, but
        ;; the cramfs image could still be in the Flash directly after the
        ;; compressed kernel image. The loader passes the address of the
@@ -251,7 +247,7 @@ _inram:
        ;; (Notice that if this is not booted from the loader, r9 will be
        ;;  garbage but we do sanity checks on it, the chance that it points
        ;;  to a cramfs magic is small.. )
-       
+
        cmp.d   0x0ffffff8, $r9
        bhs     _no_romfs_in_flash      ; r9 points outside the flash area
        nop
@@ -274,7 +270,7 @@ _inram:
        jump    _start_it       ; enter code, cached this time
 
 _no_romfs_in_flash:
-       
+
        ;; Check if there is a cramfs (magic value).
        ;; Notice that we check for cramfs magic value - which is
        ;; the "rom fs" we'll possibly use in 2.4 if not JFFS (which does
@@ -286,8 +282,8 @@ _no_romfs_in_flash:
        bne     2f
        nop
 
-       ;; Ok. What is its size ? 
-       
+       ;; Ok. What is its size ?
+
        move.d  [$r0 + 4], $r2  ; cramfs_super.size (again, no need to swapwb)
 
        ;; We want to copy it to the end of the BSS
@@ -303,7 +299,7 @@ _no_romfs_in_flash:
 
        add.d   $r2, $r0
        add.d   $r2, $r1
-               
+
        ;; Go ahead. Make my loop.
 
        lsrq    1, $r2          ; size is in bytes, we copy words
@@ -314,14 +310,14 @@ _no_romfs_in_flash:
        bne     1b
        nop
 
-2:             
+2:
        ;; Dont worry that the BSS is tainted. It will be cleared later.
 
        moveq   0, $r0
        move.d  $r0, [romfs_in_flash]
 
        jump    _start_it       ; better skip the additional cramfs check below
-       
+
 _start_it:
 
        ;; Check if kernel command line is supplied
@@ -348,7 +344,7 @@ no_command_line:
        move.d  ibr_start,$r0   ; this symbol is set by the linker script 
        move    $r0,$ibr
        move.d  $r0,[etrax_irv] ; set the interrupt base register and pointer
-       
+
        ;; Clear BSS region, from _bss_start to _end
 
        move.d  __bss_start, $r0
@@ -357,7 +353,7 @@ no_command_line:
        cmp.d   $r1, $r0
        blo     1b
        nop
-       
+
 #ifdef CONFIG_BLK_DEV_ETRAXIDE
        ;; disable ATA before enabling it in genconfig below
        moveq   0,$r0
@@ -380,7 +376,7 @@ no_command_line:
 
 #ifdef CONFIG_JULIETTE
        ;; configure external DMA channel 0 before enabling it in genconfig
-       
+
        moveq   0,$r0
        move.d  $r0,[R_EXT_DMA_0_ADDR]
        ; cnt enable, word size, output, stop, size 0
@@ -395,7 +391,7 @@ no_command_line:
        move.d  $r0,[R_EXT_DMA_0_CMD]
 
        ;; reset dma4 and wait for completion
-       
+
        moveq   IO_STATE (R_DMA_CH4_CMD, cmd, reset),$r0
        move.b  $r0,[R_DMA_CH4_CMD]
 1:     move.b  [R_DMA_CH4_CMD],$r0
@@ -405,7 +401,7 @@ no_command_line:
        nop
 
        ;; reset dma5 and wait for completion
-       
+
        moveq   IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0
        move.b  $r0,[R_DMA_CH5_CMD]
 1:     move.b  [R_DMA_CH5_CMD],$r0
@@ -413,8 +409,8 @@ no_command_line:
        cmp.b   IO_STATE (R_DMA_CH5_CMD, cmd, reset),$r0
        beq     1b
        nop
-#endif 
-                       
+#endif
+
        ;; Etrax product HW genconfig setup
 
        moveq   0,$r0
@@ -468,7 +464,6 @@ no_command_line:
 
        move.d  $r0,[genconfig_shadow] ; init a shadow register of R_GEN_CONFIG
 
-#ifndef CONFIG_SVINTO_SIM
        move.d  $r0,[R_GEN_CONFIG]
 
 #if 0
@@ -486,7 +481,7 @@ no_command_line:
        beq     1b
        nop
 #endif
-       
+
        moveq   IO_STATE (R_DMA_CH8_CMD, cmd, reset),$r0
        move.b  $r0,[R_DMA_CH8_CMD]     ; reset (ser1 dma out)
        move.b  $r0,[R_DMA_CH9_CMD]     ; reset (ser1 dma in)
@@ -503,7 +498,7 @@ no_command_line:
 
        ;; setup port PA and PB default initial directions and data
        ;; including their shadow registers
-               
+
        move.b  CONFIG_ETRAX_DEF_R_PORT_PA_DIR,$r0
 #if defined(CONFIG_BLUETOOTH) && defined(CONFIG_BLUETOOTH_RESET_PA7)
        or.b    IO_STATE (R_PORT_PA_DIR, dir7, output),$r0
@@ -520,7 +515,7 @@ no_command_line:
 #endif
        move.b  $r0,[port_pa_data_shadow]
        move.b  $r0,[R_PORT_PA_DATA]
-       
+
        move.b  CONFIG_ETRAX_DEF_R_PORT_PB_CONFIG,$r0
        move.b  $r0,[port_pb_config_shadow]
        move.b  $r0,[R_PORT_PB_CONFIG]
@@ -562,13 +557,13 @@ no_command_line:
 #endif
        move.d  $r0,[port_g_data_shadow]
        move.d  $r0,[R_PORT_G_DATA]
-       
+
        ;; setup the serial port 0 at 115200 baud for debug purposes
-       
+
        moveq     IO_STATE (R_SERIAL0_XOFF, tx_stop, enable)            \
                | IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable)         \
                | IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),$r0
-       move.d  $r0,[R_SERIAL0_XOFF] 
+       move.d  $r0,[R_SERIAL0_XOFF]
 
        ; 115.2kbaud for both transmit and receive
        move.b    IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz)          \
@@ -584,8 +579,8 @@ no_command_line:
                | IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even)          \
                | IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable)    \
                | IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),$r0
-       move.b  $r0,[R_SERIAL0_REC_CTRL] 
-       
+       move.b  $r0,[R_SERIAL0_REC_CTRL]
+
        ; Set up and enable the serial0 transmitter.
        move.b    IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0)                  \
                | IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable)       \
@@ -598,11 +593,11 @@ no_command_line:
        move.b  $r0,[R_SERIAL0_TR_CTRL]
 
        ;; setup the serial port 1 at 115200 baud for debug purposes
-       
+
        moveq     IO_STATE (R_SERIAL1_XOFF, tx_stop, enable)            \
                | IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable)         \
                | IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),$r0
-       move.d  $r0,[R_SERIAL1_XOFF] 
+       move.d  $r0,[R_SERIAL1_XOFF]
 
        ; 115.2kbaud for both transmit and receive
        move.b    IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz)          \
@@ -618,8 +613,8 @@ no_command_line:
                | IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even)          \
                | IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable)    \
                | IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),$r0
-       move.b  $r0,[R_SERIAL1_REC_CTRL] 
-       
+       move.b  $r0,[R_SERIAL1_REC_CTRL]
+
        ; Set up and enable the serial1 transmitter.
        move.b    IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0)                  \
                | IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable)       \
@@ -666,14 +661,14 @@ no_command_line:
                | IO_STATE (R_SERIAL2_TR_CTRL, tr_bitnr, tr_8bit),$r0
        move.b  $r0,[R_SERIAL2_TR_CTRL]
 #endif
-       
-#ifdef CONFIG_ETRAX_SERIAL_PORT3       
+
+#ifdef CONFIG_ETRAX_SERIAL_PORT3
        ;; setup the serial port 3 at 115200 baud for debug purposes
-       
+
        moveq     IO_STATE (R_SERIAL3_XOFF, tx_stop, enable)            \
                | IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable)         \
                | IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),$r0
-       move.d  $r0,[R_SERIAL3_XOFF] 
+       move.d  $r0,[R_SERIAL3_XOFF]
 
        ; 115.2kbaud for both transmit and receive
        move.b    IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz)          \
@@ -689,8 +684,8 @@ no_command_line:
                | IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even)          \
                | IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable)    \
                | IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),$r0
-       move.b  $r0,[R_SERIAL3_REC_CTRL] 
-       
+       move.b  $r0,[R_SERIAL3_REC_CTRL]
+
        ; Set up and enable the serial3 transmitter.
        move.b    IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0)                  \
                | IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable)       \
@@ -702,13 +697,11 @@ no_command_line:
                | IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),$r0
        move.b  $r0,[R_SERIAL3_TR_CTRL]
 #endif
-       
-#endif /* CONFIG_SVINTO_SIM */
 
        jump    start_kernel    ; jump into the C-function start_kernel in init/main.c
-               
+
        .data
-etrax_irv:     
+etrax_irv:
        .dword  0
 romfs_start:
        .dword  0
@@ -716,13 +709,13 @@ romfs_length:
        .dword  0
 romfs_in_flash:
        .dword  0
-       
+
        ;; put some special pages at the beginning of the kernel aligned
        ;; to page boundaries - the kernel cannot start until after this
 
 #ifdef CONFIG_CRIS_LOW_MAP
 swapper_pg_dir = 0x60002000
-#else  
+#else
 swapper_pg_dir = 0xc0002000
 #endif
 
index ba0e5965d6e3ed2f901e48cf1c5ee2d52435d960..09cae80a834a341d11c5790d8b267b9cc742be35 100644 (file)
@@ -5,7 +5,7 @@
  *
  *      Authors: Bjorn Wesen (bjornw@axis.com)
  *
- *      This file contains the interrupt vectors and some 
+ *      This file contains the interrupt vectors and some
  *      helper functions
  *
  */
@@ -182,19 +182,14 @@ void do_multiple_IRQ(struct pt_regs* regs)
    setting the irq vector table.
 */
 
-void __init
-init_IRQ(void)
+void __init init_IRQ(void)
 {
        int i;
 
        /* clear all interrupt masks */
-
-#ifndef CONFIG_SVINTO_SIM
        *R_IRQ_MASK0_CLR = 0xffffffff;
        *R_IRQ_MASK1_CLR = 0xffffffff;
        *R_IRQ_MASK2_CLR = 0xffffffff;
-#endif
-
        *R_VECT_MASK_CLR = 0xffffffff;
 
         for (i = 0; i < 256; i++)
@@ -211,25 +206,20 @@ init_IRQ(void)
            executed by the associated break handler, rather than just a jump
            address. therefore we need to setup a default breakpoint handler
            for all breakpoints */
-
        for (i = 0; i < 16; i++)
                 set_break_vector(i, do_sigtrap);
-        
-       /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
 
+       /* except IRQ 15 which is the multiple-IRQ handler on Etrax100 */
        set_int_vector(15, multiple_interrupt);
-       
-       /* 0 and 1 which are special breakpoint/NMI traps */
 
+       /* 0 and 1 which are special breakpoint/NMI traps */
        set_int_vector(0, hwbreakpoint);
        set_int_vector(1, IRQ1_interrupt);
 
        /* and irq 14 which is the mmu bus fault handler */
-
        set_int_vector(14, mmu_bus_fault);
 
        /* setup the system-call trap, which is reached by BREAK 13 */
-
        set_break_vector(13, system_call);
 
         /* setup a breakpoint handler for debugging used for both user and
index 753e9a03cf870565bb4ba0619a3b529e1b9a430d..02b783457be0a92a0e346f21675f0f06b59b4288 100644 (file)
@@ -56,14 +56,14 @@ void hard_reset_now (void)
         * code to know about it than the watchdog handler in entry.S and
         * this code, implementing hard reset through the watchdog.
         */
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
        extern int cause_of_death;
 #endif
 
        printk("*** HARD RESET ***\n");
        local_irq_disable();
 
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
        cause_of_death = 0xbedead;
 #else
        /* Since we dont plan to keep on resetting the watchdog,
index fce7c541d70de8331b47ccab308a6798b9491bb5..b5eb5cd2f60b1381b990d7ead6cba07d6c72f405 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/mm.h>
-#include <arch/svinto.h>
 #include <asm/types.h>
 #include <asm/signal.h>
 #include <asm/io.h>
@@ -34,7 +33,7 @@ unsigned long get_ns_in_jiffie(void)
 
        local_irq_save(flags);
        timer_count = *R_TIMER0_DATA;
-       presc_count = *R_TIM_PRESC_STATUS;  
+       presc_count = *R_TIM_PRESC_STATUS;
        /* presc_count might be wrapped */
        t1 = *R_TIMER0_DATA;
 
@@ -50,7 +49,7 @@ unsigned long get_ns_in_jiffie(void)
                presc_count =  PRESCALE_VALUE - presc_count - PRESCALE_VALUE/2;
        }
 
-       ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) + 
+       ns = ( (TIMER0_DIV - timer_count) * ((1000000000/HZ)/TIMER0_DIV )) +
             ( (presc_count) * (1000000000/PRESCALE_FREQ));
        return ns;
 }
@@ -80,7 +79,7 @@ static u32 cris_v10_gettimeoffset(void)
  * by the R_WATCHDOG register. The R_WATCHDOG register contains an enable bit
  * and a 3-bit key value. The effect of writing to the R_WATCHDOG register is
  * described in the table below:
- * 
+ *
  *   Watchdog    Value written:
  *   state:      To enable:  To key:      Operation:
  *   --------    ----------  -------      ----------
@@ -89,15 +88,15 @@ static u32 cris_v10_gettimeoffset(void)
  *   started         0       ~key         Stop watchdog
  *   started         1       ~key         Restart watchdog with key = ~key.
  *   started         X       new_key_val  Change key to new_key_val.
- * 
+ *
  * Note: '~' is the bitwise NOT operator.
- * 
+ *
  */
 
 /* right now, starting the watchdog is the same as resetting it */
 #define start_watchdog reset_watchdog
 
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#ifdef CONFIG_ETRAX_WATCHDOG
 static int watchdog_key = 0;  /* arbitrary number */
 #endif
 
@@ -107,10 +106,9 @@ static int watchdog_key = 0;  /* arbitrary number */
 
 #define WATCHDOG_MIN_FREE_PAGES 8
 
-void
-reset_watchdog(void)
+void reset_watchdog(void)
 {
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
        /* only keep watchdog happy as long as we have memory left! */
        if(nr_free_pages() > WATCHDOG_MIN_FREE_PAGES) {
                /* reset the watchdog with the inverse of the old key */
@@ -123,28 +121,23 @@ reset_watchdog(void)
 
 /* stop the watchdog - we still need the correct key */
 
-void 
-stop_watchdog(void)
+void stop_watchdog(void)
 {
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#ifdef CONFIG_ETRAX_WATCHDOG
        watchdog_key ^= 0x7; /* invert key, which is 3 bits */
        *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
                IO_STATE(R_WATCHDOG, enable, stop);
-#endif 
+#endif
 }
 
 
+extern void cris_do_profile(struct pt_regs *regs);
+
 /*
  * timer_interrupt() needs to keep up the real-time clock,
  * as well as call the "xtime_update()" routine every clocktick
  */
-
-//static unsigned short myjiff; /* used by our debug routine print_timestamp */
-
-extern void cris_do_profile(struct pt_regs *regs);
-
-static inline irqreturn_t
-timer_interrupt(int irq, void *dev_id)
+static inline irqreturn_t timer_interrupt(int irq, void *dev_id)
 {
        struct pt_regs *regs = get_irq_regs();
        /* acknowledge the timer irq */
@@ -160,44 +153,39 @@ timer_interrupt(int irq, void *dev_id)
                IO_STATE( R_TIMER_CTRL, tm0, run) |
                IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
 #else
-       *R_TIMER_CTRL = r_timer_ctrl_shadow | 
-               IO_STATE(R_TIMER_CTRL, i0, clr);
+       *R_TIMER_CTRL = r_timer_ctrl_shadow | IO_STATE(R_TIMER_CTRL, i0, clr);
 #endif
 
        /* reset watchdog otherwise it resets us! */
        reset_watchdog();
-       
+
        /* Update statistics. */
        update_process_times(user_mode(regs));
 
        /* call the real timer interrupt handler */
-
        xtime_update(1);
-       
+
         cris_do_profile(regs); /* Save profiling information */
         return IRQ_HANDLED;
 }
 
-/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain
- * it needs to be IRQF_DISABLED to make the jiffies update work properly
- */
+/* timer is IRQF_SHARED so drivers can add stuff to the timer irq chain */
 
 static struct irqaction irq2  = {
        .handler = timer_interrupt,
-       .flags = IRQF_SHARED | IRQF_DISABLED,
+       .flags = IRQF_SHARED,
        .name = "timer",
 };
 
-void __init
-time_init(void)
-{      
+void __init time_init(void)
+{
        arch_gettimeoffset = cris_v10_gettimeoffset;
 
-       /* probe for the RTC and read it if it exists 
-        * Before the RTC can be probed the loops_per_usec variable needs 
-        * to be initialized to make usleep work. A better value for 
-        * loops_per_usec is calculated by the kernel later once the 
-        * clock has started.  
+       /* probe for the RTC and read it if it exists
+        * Before the RTC can be probed the loops_per_usec variable needs
+        * to be initialized to make usleep work. A better value for
+        * loops_per_usec is calculated by the kernel later once the
+        * clock has started.
         */
        loops_per_usec = 50;
 
@@ -208,7 +196,7 @@ time_init(void)
         * Remember that linux/timex.h contains #defines that rely on the
         * timer settings below (hz and divide factor) !!!
         */
-       
+
 #ifdef USE_CASCADE_TIMERS
        *R_TIMER_CTRL =
                IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
@@ -219,8 +207,8 @@ time_init(void)
                IO_STATE( R_TIMER_CTRL, i0, nop) |
                IO_STATE( R_TIMER_CTRL, tm0, stop_ld) |
                IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
-       
-       *R_TIMER_CTRL = r_timer_ctrl_shadow = 
+
+       *R_TIMER_CTRL = r_timer_ctrl_shadow =
                IO_FIELD( R_TIMER_CTRL, timerdiv1, 0) |
                IO_FIELD( R_TIMER_CTRL, timerdiv0, 0) |
                IO_STATE( R_TIMER_CTRL, i1, nop) |
@@ -230,18 +218,18 @@ time_init(void)
                IO_STATE( R_TIMER_CTRL, tm0, run) |
                IO_STATE( R_TIMER_CTRL, clksel0, c6250kHz);
 #else
-       *R_TIMER_CTRL = 
-               IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | 
+       *R_TIMER_CTRL =
+               IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      |
                IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV)      |
-               IO_STATE(R_TIMER_CTRL, i1,        nop)      | 
+               IO_STATE(R_TIMER_CTRL, i1,        nop)      |
                IO_STATE(R_TIMER_CTRL, tm1,       stop_ld)  |
                IO_STATE(R_TIMER_CTRL, clksel1,   c19k2Hz)  |
                IO_STATE(R_TIMER_CTRL, i0,        nop)      |
                IO_STATE(R_TIMER_CTRL, tm0,       stop_ld)  |
                IO_STATE(R_TIMER_CTRL, clksel0,   flexible);
-       
+
        *R_TIMER_CTRL = r_timer_ctrl_shadow =
-               IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      | 
+               IO_FIELD(R_TIMER_CTRL, timerdiv1, 192)      |
                IO_FIELD(R_TIMER_CTRL, timerdiv0, TIMER0_DIV)      |
                IO_STATE(R_TIMER_CTRL, i1,        nop)      |
                IO_STATE(R_TIMER_CTRL, tm1,       run)      |
@@ -253,16 +241,14 @@ time_init(void)
        *R_TIMER_PRESCALE = PRESCALE_VALUE;
 #endif
 
-       *R_IRQ_MASK0_SET =
-               IO_STATE(R_IRQ_MASK0_SET, timer0, set); /* unmask the timer irq */
-       
-       /* now actually register the timer irq handler that calls timer_interrupt() */
-       
+       /* unmask the timer irq */
+       *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, timer0, set);
+
+       /* now actually register the irq handler that calls timer_interrupt() */
        setup_irq(2, &irq2); /* irq 2 is the timer0 irq in etrax */
 
        /* enable watchdog if we should use one */
-
-#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_WATCHDOG)
        printk("Enabling watchdog...\n");
        start_watchdog();
 
@@ -275,9 +261,7 @@ time_init(void)
           driver or infrastructure support yet.  */
        asm ("setf m");
 
-       *R_IRQ_MASK0_SET =
-               IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set);
-       *R_VECT_MASK_SET =
-               IO_STATE(R_VECT_MASK_SET, nmi, set);
+       *R_IRQ_MASK0_SET = IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set);
+       *R_VECT_MASK_SET = IO_STATE(R_VECT_MASK_SET, nmi, set);
 #endif
 }
index b9190ff7d0a4debd99f51399f4bedab39805626f..e541d3d8f9223997cc9825510f265c5fb929f96a 100644 (file)
@@ -5,9 +5,7 @@
  * Note: This file may not modify r9 because r9 is used to carry
  *       information from the decompresser to the kernel
  *
- * Copyright (C) 2000, 2001 Axis Communications AB
- *
- * Authors:  Mikael Starvik (starvik@axis.com)
+ * Copyright (C) 2000-2012 Axis Communications AB
  *
  */
 
 
 
        ;; WARNING! The registers r8 and r9 are used as parameters carrying
-       ;; information from the decompressor (if the kernel was compressed). 
+       ;; information from the decompressor (if the kernel was compressed).
        ;; They should not be used in the code below.
 
-#ifndef CONFIG_SVINTO_SIM      
        move.d   CONFIG_ETRAX_DEF_R_WAITSTATES, $r0
        move.d   $r0, [R_WAITSTATES]
 
        move.d   CONFIG_ETRAX_DEF_R_BUS_CONFIG, $r0
        move.d   $r0, [R_BUS_CONFIG]
-       
+
 #ifndef CONFIG_ETRAX_SDRAM
        move.d   CONFIG_ETRAX_DEF_R_DRAM_CONFIG, $r0
        move.d   $r0, [R_DRAM_CONFIG]
        ;; Samsung SDRAMs seem to require to be initialized twice to work properly.
        moveq    2, $r6 
 _sdram_init:
-       
+
        ; Refer to ETRAX 100LX Designers Reference for a description of SDRAM initialization
-       
+
        ; Bank configuration
        move.d   CONFIG_ETRAX_DEF_R_SDRAM_CONFIG, $r0
        move.d   $r0, [R_SDRAM_CONFIG]
 
-       ; Calculate value of mrs_data 
+       ; Calculate value of mrs_data
        ; CAS latency = 2 && bus_width = 32 => 0x40
        ; CAS latency = 3 && bus_width = 32 => 0x60
        ; CAS latency = 2 && bus_width = 16 => 0x20
@@ -56,22 +53,22 @@ _sdram_init:
        and.d    0x00ff0000, $r2
        bne      _set_timing
        lsrq     16, $r2
-       
+
        move.d   0x40, $r2       ; Assume 32 bits and CAS latency = 2
        move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1
        move.d   $r1, $r3
-       and.d    0x03, $r1       ; Get CAS latency
+       and.d    0x03, $r1       ; Get CAS latency
        and.d    0x1000, $r3     ; 50 or 100 MHz?
        beq      _speed_50
        nop
-_speed_100:            
+_speed_100:
        cmp.d    0x00, $r1      ; CAS latency = 2?
        beq      _bw_check
        nop
-       or.d     0x20, $r2      ; CAS latency = 3 
+       or.d     0x20, $r2      ; CAS latency = 3
        ba       _bw_check
        nop
-_speed_50:                     
+_speed_50:
        cmp.d    0x01, $r1      ; CAS latency = 2?
        beq      _bw_check
        nop
@@ -86,19 +83,19 @@ _bw_check:
        ; Set timing parameters. Starts master clock
 _set_timing:
        move.d   CONFIG_ETRAX_DEF_R_SDRAM_TIMING, $r1
-       and.d    0x8000f9ff, $r1 ; Make sure mrs data and command is 0 
+       and.d    0x8000f9ff, $r1 ; Make sure mrs data and command is 0
        or.d     0x80000000, $r1        ; Make sure sdram enable bit is set
        move.d   $r1, $r5
        or.d     0x0000c000, $r1 ; ref = disable
        lslq     16, $r2                ; mrs data starts at bit 16
-       or.d     $r2, $r1 
-       move.d   $r1, [R_SDRAM_TIMING]  
-               
+       or.d     $r2, $r1
+       move.d   $r1, [R_SDRAM_TIMING]
+
        ; Wait 200us
        move.d   10000, $r2
 1:     bne      1b
        subq     1, $r2
-       
+
        ; Issue initialization command sequence
        move.d   _sdram_commands_start, $r2
        and.d    0x000fffff, $r2 ; Make sure commands are read from flash
@@ -144,7 +141,6 @@ _sdram_commands_start:
        .byte   2       ; refresh
        .byte   0       ; nop
        .byte   1       ; mrs
-       .byte   0       ; nop 
-_sdram_commands_end:           
-#endif
+       .byte   0       ; nop
+_sdram_commands_end:
 #endif
index 1b6ad6247204c0b9d09f63f7e4731aaf70cb83cd..28dd77144e8fe8e24a0ac94cd309b5ac1587aac4 100644 (file)
@@ -24,8 +24,6 @@
 #include <linux/mtd/mtdram.h>
 #include <linux/mtd/partitions.h>
 
-#include <linux/cramfs_fs.h>
-
 #include <asm/axisflashmap.h>
 #include <asm/mmu.h>
 
index 0b86deedacb97b9a0e919b79d484a35f43b456cc..74f9fe80940c73cd2d66bf9a8e9d5d23c4e5ab38 100644 (file)
@@ -978,7 +978,7 @@ static int __init gpio_init(void)
        CRIS_LED_DISK_WRITE(0);
 
        int res2 = request_irq(GIO_INTR_VECT, gpio_interrupt,
-               IRQF_SHARED | IRQF_DISABLED, "gpio", &alarmlist);
+               IRQF_SHARED, "gpio", &alarmlist);
        if (res2) {
                printk(KERN_ERR "err: irq for gpio\n");
                return res2;
index a2ac0917f1a615989243bd3c1d0dc091c7f2d552..9e54273af0ca81dd4d95d462cdf869bd1d21e0f4 100644 (file)
@@ -964,11 +964,11 @@ gpio_init(void)
         * in some tests.
         */
        if (request_irq(TIMER0_INTR_VECT, gpio_poll_timer_interrupt,
-                       IRQF_SHARED | IRQF_DISABLED, "gpio poll", &alarmlist))
+                       IRQF_SHARED, "gpio poll", &alarmlist))
                printk(KERN_ERR "timer0 irq for gpio\n");
 
        if (request_irq(GIO_INTR_VECT, gpio_pa_interrupt,
-                       IRQF_SHARED | IRQF_DISABLED, "gpio PA", &alarmlist))
+                       IRQF_SHARED, "gpio PA", &alarmlist))
                printk(KERN_ERR "PA irq for gpio\n");
 
 #ifdef CONFIG_ETRAX_VIRTUAL_GPIO
index 219f704e3221b9b6998cd12055fc51fb607ad26c..bbb806b68838e074660c830931955ff355502c7e 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/init.h>
 #include <linux/timer.h>
 #include <linux/spinlock.h>
+#include <linux/wait.h>
 
 #include <asm/io.h>
 #include <dma.h>
@@ -1144,7 +1145,8 @@ static ssize_t sync_serial_read(struct file * file, char * buf,
                if (file->f_flags & O_NONBLOCK)
                        return -EAGAIN;
 
-               interruptible_sleep_on(&port->in_wait_q);
+               wait_event_interruptible(port->in_wait_q,
+                                        !(start == end && !port->full));
                if (signal_pending(current))
                        return -EINTR;
 
index faa644111feb7f4acb1eb87929177fdc3cdc3dc6..2f19ac6217aafd2754d7f423b5441d988aacbae7 100644 (file)
@@ -424,7 +424,7 @@ nmi_interrupt:
        bpl     1f
        nop
        jsr     handle_watchdog_bite    ; In time.c.
-        move.d $sp, $r10               ; Pointer to registers
+       move.d  $sp, $r10               ; Pointer to registers
 1:     btstq   REG_BIT(intr_vect, r_nmi, ext), $r0
        bpl     1f
        nop
@@ -452,7 +452,7 @@ spurious_interrupt:
        nop
 
        ;; This handles the case when multiple interrupts arrive at the same
-       ;; time. Jump to the first set interrupt bit in a priotiry fashion. The
+       ;; time. Jump to the first set interrupt bit in a priority fashion. The
        ;; hardware will call the unserved interrupts after the handler
        ;; finishes.
        .type   multiple_interrupt, @function
@@ -885,13 +885,29 @@ sys_call_table:
        .long sys_preadv
        .long sys_pwritev
        .long sys_setns                 /* 335 */
-
-        /*
-         * NOTE!! This doesn't have to be exact - we just have
-         * to make sure we have _enough_ of the "sys_ni_syscall"
-         * entries. Don't panic if you notice that this hasn't
-         * been shrunk every time we add a new system call.
-         */
+       .long sys_name_to_handle_at
+       .long sys_open_by_handle_at
+       .long sys_rt_tgsigqueueinfo
+       .long sys_perf_event_open
+       .long sys_recvmmsg              /* 340 */
+       .long sys_accept4
+       .long sys_fanotify_init
+       .long sys_fanotify_mark
+       .long sys_prlimit64
+       .long sys_clock_adjtime         /* 345 */
+       .long sys_syncfs
+       .long sys_sendmmsg
+       .long sys_process_vm_readv
+       .long sys_process_vm_writev
+       .long sys_kcmp                  /* 350 */
+       .long sys_finit_module
+
+       /*
+        * NOTE!! This doesn't have to be exact - we just have
+        * to make sure we have _enough_ of the "sys_ni_syscall"
+        * entries. Don't panic if you notice that this hasn't
+        * been shrunk every time we add a new system call.
+        */
 
        .rept NR_syscalls - (.-sys_call_table) / 4
                .long sys_ni_syscall
index f6644535b17e199637f810b8fcbea2fcef548b0c..b130c2c5fdd892d389debe80cd0297bb88bae32f 100644 (file)
@@ -786,7 +786,7 @@ int fast_timer_init(void)
     proc_create("fasttimer", 0, NULL, &proc_fasttimer_fops);
 #endif /* PROC_FS */
                if (request_irq(TIMER0_INTR_VECT, timer_trig_interrupt,
-                               IRQF_SHARED | IRQF_DISABLED,
+                               IRQF_SHARED,
                                "fast timer int", &fast_timer_list))
                        printk(KERN_ERR "err: fasttimer irq\n");
     fast_timer_is_init = 1;
index 5ebe6e841820ec45a5a653d66993b7b2b5952bef..25437ae2812838ccf0d5e378563588e1de9096a5 100644 (file)
@@ -331,11 +331,11 @@ extern void do_IRQ(int irq, struct pt_regs * regs);
 void
 crisv32_do_IRQ(int irq, int block, struct pt_regs* regs)
 {
-       /* Interrupts that may not be moved to another CPU and
-         * are IRQF_DISABLED may skip blocking. This is currently
-         * only valid for the timer IRQ and the IPI and is used
-         * for the timer interrupt to avoid watchdog starvation.
-         */
+       /* Interrupts that may not be moved to another CPU may
+        * skip blocking. This is currently only valid for the
+        * timer IRQ and the IPI and is used for the timer
+        * interrupt to avoid watchdog starvation.
+        */
        if (!block) {
                do_IRQ(irq, regs);
                return;
index fe8e6039db2a04aa3c133385322fe6573b7b2b11..0698582467ca773c3cf704690fc9b105610b4ab0 100644 (file)
@@ -64,7 +64,7 @@ static irqreturn_t crisv32_ipi_interrupt(int irq, void *dev_id);
 static int send_ipi(int vector, int wait, cpumask_t cpu_mask);
 static struct irqaction irq_ipi  = {
        .handler = crisv32_ipi_interrupt,
-       .flags = IRQF_DISABLED,
+       .flags = 0,
        .name = "ipi",
 };
 
index 8c4b45efd7b6712f8dc13da94c55bc8ee51ca369..ee66866538f891a7ff574efd4b82d836b4b3f894 100644 (file)
@@ -216,12 +216,10 @@ static inline irqreturn_t timer_interrupt(int irq, void *dev_id)
         return IRQ_HANDLED;
 }
 
-/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain.
- * It needs to be IRQF_DISABLED to make the jiffies update work properly.
- */
+/* Timer is IRQF_SHARED so drivers can add stuff to the timer irq chain. */
 static struct irqaction irq_timer = {
        .handler = timer_interrupt,
-       .flags = IRQF_SHARED | IRQF_DISABLED,
+       .flags = IRQF_SHARED,
        .name = "timer"
 };
 
index 15f5c9de26399893e78d8f82e7783aa1cb8b0757..ab5c421a4de86fb3af3614e01ec5bd8ebdb5af8d 100644 (file)
@@ -256,11 +256,11 @@ static void crisv32_arbiter_init(void)
        crisv32_arbiter_config(1, EXT_REGION, 0);
 
        if (request_irq(MEMARB_FOO_INTR_VECT, crisv32_foo_arbiter_irq,
-                       IRQF_DISABLED, "arbiter", NULL))
+                       0, "arbiter", NULL))
                printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
 
        if (request_irq(MEMARB_BAR_INTR_VECT, crisv32_bar_arbiter_irq,
-                       IRQF_DISABLED, "arbiter", NULL))
+                       0, "arbiter", NULL))
                printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
 
 #ifndef CONFIG_ETRAX_KGDB
index 3f8ebb5c14771300e49106f78dc58acaba67d037..c97f4d8120f9e43747b120fd8fc8ef814c0060ed 100644 (file)
@@ -184,7 +184,7 @@ static void crisv32_arbiter_init(void)
        crisv32_arbiter_config(EXT_REGION, 0);
        crisv32_arbiter_config(INT_REGION, 0);
 
-       if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, IRQF_DISABLED,
+       if (request_irq(MEMARB_INTR_VECT, crisv32_arbiter_irq, 0,
                        "arbiter", NULL))
                printk(KERN_ERR "Couldn't allocate arbiter IRQ\n");
 
index 6f7b3e61260bea02079919f2ea2bf32131ab176a..655b511fecf37ff3e9ada767f8a8b06ba488377b 100644 (file)
@@ -50,7 +50,6 @@
 
        nop
        di
-#ifndef CONFIG_SVINTO_SIM
        ;; setup port PA and PB default initial directions and data
        ;; (so we can flash LEDs, and so that DTR and others are set)
 
@@ -67,7 +66,6 @@
        ;; We need to setup the bus registers before we start using the DRAM
 #include "../../lib/dram_init.S"
 
-#endif
        ;; Setup the stack to a suitably high address.
        ;; We assume 8 MB is the minimum DRAM in an eLinux
        ;; product and put the sp at the top for now.
index f627ad0b8a3d6a59a5f27ae660af4afee84a819b..4a724172877f81cd88b2c25dbdcabce144455d0a 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef _ASM_ARCH_CRIS_IO_H
 #define _ASM_ARCH_CRIS_IO_H
 
-#include <arch/svinto.h>
-
 /* Etrax shadow registers - which live in arch/cris/kernel/shadows.c */
 
 extern unsigned long gen_config_ii_shadow;
@@ -34,7 +32,7 @@ extern volatile unsigned long *port_csp4_addr;
 
 /* The LED's on various Etrax-based products are set differently. */
 
-#if defined(CONFIG_ETRAX_NO_LEDS) || defined(CONFIG_SVINTO_SIM)
+#if defined(CONFIG_ETRAX_NO_LEDS)
 #undef CONFIG_ETRAX_PA_LEDS
 #undef CONFIG_ETRAX_PB_LEDS
 #undef CONFIG_ETRAX_CSP0_LEDS
@@ -171,29 +169,4 @@ extern volatile unsigned long *port_csp4_addr;
 #define SOFT_SHUTDOWN()
 #endif
 
-/* Console I/O for simulated etrax100.  Use #ifdef so erroneous
-   use will be evident. */
-#ifdef CONFIG_SVINTO_SIM
-  /* Let's use the ucsim interface since it lets us do write(2, ...) */
-#define SIMCOUT(s,len)                                                 \
-  asm ("moveq 4,$r9    \n\t"                                           \
-       "moveq 2,$r10   \n\t"                                           \
-       "move.d %0,$r11 \n\t"                                           \
-       "move.d %1,$r12 \n\t"                                           \
-       "push $irp      \n\t"                                           \
-       "move 0f,$irp   \n\t"                                           \
-       "jump -6809     \n"                                             \
-       "0:             \n\t"                                           \
-       "pop $irp"                                                      \
-       : : "rm" (s), "rm" (len) : "r9","r10","r11","r12","memory")
-#define TRACE_ON() __extension__ \
- ({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \
-                              (255)); _Foofoo; })
-
-#define TRACE_OFF() do { __asm__ volatile ("bmod [%0],%0" :: "r" (254)); } while (0)
-#define SIM_END() do { __asm__ volatile ("bmod [%0],%0" :: "r" (28)); } while (0)
-#define CRIS_CYCLES() __extension__ \
- ({ unsigned long c; asm ("bmod [%1],%0" : "=r" (c) : "r" (27)); c;})
-#endif /* ! defined CONFIG_SVINTO_SIM */
-
 #endif
index ca2675ae08ed95d1c3de56ad0a507af390b348e3..6aecb835037d3cf2c02da7c637f7653ce43cd4a5 100644 (file)
@@ -141,9 +141,9 @@ __asm__ ( \
  * handler is run and it prioritizes the timer interrupt. However if we had BLOCK'ed
  * it here, we would not get the multiple_irq at all.
  *
- * The non-blocking here is based on the knowledge that the timer interrupt is 
- * registered as a fast interrupt (IRQF_DISABLED) so that we _know_ there will not
- * be an sti() before the timer irq handler is run to acknowledge the interrupt.
+ * The non-blocking here is based on the knowledge that the timer interrupt runs
+ * with interrupts disabled, and therefore there will not be an sti() before the
+ * timer irq handler is run to acknowledge the interrupt.
  */
 
 #define BUILD_TIMER_IRQ(nr,mask) \
index fe3cdd22bed4590315268c156e28076c26cff238..0c1b4d3a34e749b222c1d0ec0af3a56a4b80b952 100644 (file)
@@ -102,9 +102,9 @@ __asm__ (                           \
  * multiple_irq handler is run and it prioritizes the timer interrupt. However
  * if we had BLOCK'edit here, we would not get the multiple_irq at all.
  *
- * The non-blocking here is based on the knowledge that the timer interrupt is
- * registered as a fast interrupt (IRQF_DISABLED) so that we _know_ there will not
- * be an sti() before the timer irq handler is run to acknowledge the interrupt.
+ * The non-blocking here is based on the knowledge that the timer interrupt runs
+ * with interrupts disabled, and therefore there will not be an sti() before the
+ * timer irq handler is run to acknowledge the interrupt.
  */
 #define BUILD_TIMER_IRQ(nr, mask)      \
 void IRQ_NAME(nr);                     \
index 0ff3f6889842b7bb0922ec2b777595719556f004..5cc7d1991e482bf0e3eef50e598877595c15b69a 100644 (file)
@@ -4,7 +4,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define NR_syscalls 336
+#define NR_syscalls 360
 
 #include <arch/unistd.h>
 
index 48842896f6c2fbe418a42260dc33486b54ff71a8..f3287face443b4094a35231c972912970178e1ec 100644 (file)
 #define __NR_preadv            333
 #define __NR_pwritev           334
 #define __NR_setns             335
+#define __NR_name_to_handle_at 336
+#define __NR_open_by_handle_at 337
+#define __NR_rt_tgsigqueueinfo 338
+#define __NR_perf_event_open   339
+#define __NR_recvmmsg          340
+#define __NR_accept4           341
+#define __NR_fanotify_init     342
+#define __NR_fanotify_mark     343
+#define __NR_prlimit64         344
+#define __NR_clock_adjtime     345
+#define __NR_syncfs            346
+#define __NR_sendmmsg          347
+#define __NR_process_vm_readv  348
+#define __NR_process_vm_writev 349
+#define __NR_kcmp              350
+#define __NR_finit_module      351
 
 #endif /* _UAPI_ASM_CRIS_UNISTD_H_ */
index d36836dbbc0722758f9e116537c5e413a6e4871a..dd0be5de55d5b6ea27a2410b984e3bba0e5b9e72 100644 (file)
@@ -40,9 +40,6 @@
 
 /* called by the assembler IRQ entry functions defined in irq.h
  * to dispatch the interrupts to registered handlers
- * interrupts are disabled upon entry - depending on if the
- * interrupt was registered with IRQF_DISABLED or not, interrupts
- * are re-enabled or not.
  */
 
 asmlinkage void do_IRQ(int irq, struct pt_regs * regs)
index 4d1b1e9baef102ed79013098b27918a4cea051a9..2a8fb730d1caa1dee26dc5819742d2e0972b2cce 100644 (file)
@@ -74,13 +74,6 @@ KBUILD_CFLAGS        += -mno-fdpic -mgpr-32 -msoft-float -mno-media
 KBUILD_CFLAGS  += -ffixed-fcc3 -ffixed-cc3 -ffixed-gr15 -ffixed-icc2
 KBUILD_AFLAGS  += -mno-fdpic
 
-# make sure the .S files get compiled with debug info
-# and disable optimisations that are unhelpful whilst debugging
-ifdef CONFIG_DEBUG_INFO
-#KBUILD_CFLAGS += -O1
-KBUILD_AFLAGS  += -Wa,--gdwarf2
-endif
-
 head-y         := arch/frv/kernel/head.o
 
 core-y         += arch/frv/kernel/ arch/frv/mm/
index 0721858fbd1ef6618b288bcbea33369995e35653..2d75ae246167a37f07d71a9bb743702fff686092 100644 (file)
@@ -62,17 +62,18 @@ struct nfhd_device {
 static void nfhd_make_request(struct request_queue *queue, struct bio *bio)
 {
        struct nfhd_device *dev = queue->queuedata;
-       struct bio_vec *bvec;
-       int i, dir, len, shift;
-       sector_t sec = bio->bi_sector;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
+       int dir, len, shift;
+       sector_t sec = bio->bi_iter.bi_sector;
 
        dir = bio_data_dir(bio);
        shift = dev->bshift;
-       bio_for_each_segment(bvec, bio, i) {
-               len = bvec->bv_len;
+       bio_for_each_segment(bvec, bio, iter) {
+               len = bvec.bv_len;
                len >>= 9;
                nfhd_read_write(dev->id, 0, dir, sec >> shift, len >> shift,
-                               bvec_to_phys(bvec));
+                               bvec_to_phys(&bvec));
                sec += len;
        }
        bio_endio(bio, 0);
index 8d581ab06c5df6bc1e4d61da48324f65212c7992..79b9bcdfe4982ab433a89a5851b1551d47d7be7e 100644 (file)
@@ -26,6 +26,8 @@ config MICROBLAZE
        select GENERIC_CPU_DEVICES
        select GENERIC_ATOMIC64
        select GENERIC_CLOCKEVENTS
+       select COMMON_CLK
+       select GENERIC_SCHED_CLOCK
        select GENERIC_IDLE_POLL_SETUP
        select MODULES_USE_ELF_RELA
        select CLONE_BACKWARDS3
index 40350a3c24e907f01f3c193018abb6a34ee35541..a69eaf2ab1301466c662e27f37837c86d8193d61 100644 (file)
@@ -1,3 +1,5 @@
+KBUILD_DEFCONFIG := mmu_defconfig
+
 ifeq ($(CONFIG_MMU),y)
 UTS_SYSNAME = -DUTS_SYSNAME=\"Linux\"
 else
index 7d6831ac8a46eec66c4f1fc00ac28aa48000ed64..3337417fcdca3b6794d0e46dd65d150a472c00d6 100644 (file)
@@ -91,15 +91,18 @@ extern struct cpuinfo cpuinfo;
 
 /* fwd declarations of the various CPUinfo populators */
 void setup_cpuinfo(void);
+void setup_cpuinfo_clk(void);
 
 void set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu);
 void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu);
 
 static inline unsigned int fcpu(struct device_node *cpu, char *n)
 {
-       const __be32 *val;
-       return (val = of_get_property(cpu, n, NULL)) ?
-                                                       be32_to_cpup(val) : 0;
+       u32 val = 0;
+
+       of_property_read_u32(cpu, n, &val);
+
+       return val;
 }
 
 #endif /* _ASM_MICROBLAZE_CPUINFO_H */
index 2565cb94f32f0857bb4d925527c2ee9c77c7ea89..a2cea72060777a5df8fd1065f80e627d56a29787 100644 (file)
@@ -342,4 +342,12 @@ static inline void outsl(unsigned long addr, const void *buffer, int count)
 #define iowrite32_rep(p, src, count) \
        outsl((unsigned long) (p), (src), (count))
 
+#define readb_relaxed  readb
+#define readw_relaxed  readw
+#define readl_relaxed  readl
+
+#define writeb_relaxed writeb
+#define writew_relaxed writew
+#define writel_relaxed writel
+
 #endif /* _ASM_MICROBLAZE_IO_H */
index c07ed5d2a82034f11cbadc6e836d4e31761d380f..1b281d3ea734418a0f39d12625e8ac1a749a6b1c 100644 (file)
@@ -16,7 +16,6 @@
 # ifndef __ASSEMBLY__
 extern char _ssbss[], _esbss[];
 extern unsigned long __ivt_start[], __ivt_end[];
-extern char _etext[], _stext[];
 
 extern u32 _fdt_start[], _fdt_end[];
 
index 6d7d7f4aaae8679846945e11c5ab0872c5cfdfb5..1aac99f87df15841b93241f6bfad81733250b183 100644 (file)
@@ -1,6 +1,8 @@
 # UAPI Header export list
 include include/uapi/asm-generic/Kbuild.asm
 
+generic-y += types.h
+
 header-y += auxvec.h
 header-y += bitsperlong.h
 header-y += byteorder.h
@@ -31,5 +33,4 @@ header-y += statfs.h
 header-y += swab.h
 header-y += termbits.h
 header-y += termios.h
-header-y += types.h
 header-y += unistd.h
diff --git a/arch/microblaze/include/uapi/asm/types.h b/arch/microblaze/include/uapi/asm/types.h
deleted file mode 100644 (file)
index b9e79bc..0000000
+++ /dev/null
@@ -1 +0,0 @@
-#include <asm-generic/types.h>
index ee46894154101cad22e70e4ccbf91b44172cee2d..93c26cf50de525db0a5bee58baa6b84bf92a53c3 100644 (file)
@@ -112,7 +112,4 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu)
        CI(num_wr_brk, NUMBER_OF_WR_ADDR_BRK);
 
        CI(fpga_family_code, TARGET_FAMILY);
-
-       /* take timebase-frequency from DTS */
-       ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
 }
index 592bb2e838c4f5e0d0d25685d59373a73b7a579a..4854285b26e77876121de423b94db2059adcaa1a 100644 (file)
@@ -113,8 +113,6 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu)
        ci->num_rd_brk = fcpu(cpu, "xlnx,number-of-rd-addr-brk");
        ci->num_wr_brk = fcpu(cpu, "xlnx,number-of-wr-addr-brk");
 
-       ci->cpu_clock_freq = fcpu(cpu, "timebase-frequency");
-
        ci->pvr_user1 = fcpu(cpu, "xlnx,pvr-user1");
        ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2");
 
index c9203b1007aad889a1cb742448b27397ccd83be9..234acad79b9ec482ac8b240f84332ba8f30e2b83 100644 (file)
@@ -8,6 +8,7 @@
  * for more details.
  */
 
+#include <linux/clk.h>
 #include <linux/init.h>
 #include <asm/cpuinfo.h>
 #include <asm/pvr.h>
@@ -39,6 +40,7 @@ const struct cpu_ver_key cpu_ver_lookup[] = {
        {"8.30.a", 0x17},
        {"8.40.a", 0x18},
        {"8.40.b", 0x19},
+       {"8.50.a", 0x1a},
        {"9.0", 0x1b},
        {"9.1", 0x1d},
        {NULL, 0},
@@ -68,11 +70,10 @@ const struct family_string_key family_string_lookup[] = {
 };
 
 struct cpuinfo cpuinfo;
+static struct device_node *cpu;
 
 void __init setup_cpuinfo(void)
 {
-       struct device_node *cpu = NULL;
-
        cpu = (struct device_node *) of_find_node_by_type(NULL, "cpu");
        if (!cpu)
                pr_err("You don't have cpu!!!\n");
@@ -102,3 +103,22 @@ void __init setup_cpuinfo(void)
                pr_warn("%s: Stream instructions enabled"
                        " - USERSPACE CAN LOCK THIS KERNEL!\n", __func__);
 }
+
+void __init setup_cpuinfo_clk(void)
+{
+       struct clk *clk;
+
+       clk = of_clk_get(cpu, 0);
+       if (IS_ERR(clk)) {
+               pr_err("ERROR: CPU CCF input clock not found\n");
+               /* take timebase-frequency from DTS */
+               cpuinfo.cpu_clock_freq = fcpu(cpu, "timebase-frequency");
+       } else {
+               cpuinfo.cpu_clock_freq = clk_get_rate(clk);
+       }
+
+       if (!cpuinfo.cpu_clock_freq) {
+               pr_err("ERROR: CPU clock frequency not setup\n");
+               BUG();
+       }
+}
index 817b7eec95b6de981edb751b8d13bd7cb657abd8..b7fb0438458ca8960bd0a730ec9c0da520112136 100644 (file)
@@ -64,6 +64,10 @@ real_start:
 #endif
 
        mts     rmsr, r0
+/* Disable stack protection from bootloader */
+       mts     rslr, r0
+       addi    r8, r0, 0xFFFFFFF
+       mts     rshr, r8
 /*
  * According to Xilinx, msrclr instruction behaves like 'mfs rX,rpc'
  * if the msrclr instruction is not enabled. We use this to detect
index fc6b89f4dd31d2fbd73227535457f395a825b00f..0b11a4469debae739005dcfccd5c92f82da5c5ea 100644 (file)
                or      r3, r0, NUM_TO_REG (regnum);
 
        /* Shift right instruction depending on available configuration */
-       #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL > 0
-       #define BSRLI(rD, rA, imm)      \
-               bsrli rD, rA, imm
-       #else
-       #define BSRLI(rD, rA, imm) BSRLI ## imm (rD, rA)
+       #if CONFIG_XILINX_MICROBLAZE0_USE_BARREL == 0
        /* Only the used shift constants defined here - add more if needed */
        #define BSRLI2(rD, rA)                          \
                srl rD, rA;             /* << 1 */      \
                srl rD, rD;             /* << 2 */
+       #define BSRLI4(rD, rA)          \
+               BSRLI2(rD, rA);         \
+               BSRLI2(rD, rD)
        #define BSRLI10(rD, rA)                         \
                srl rD, rA;             /* << 1 */      \
                srl rD, rD;             /* << 2 */      \
        #define BSRLI20(rD, rA)         \
                BSRLI10(rD, rA);        \
                BSRLI10(rD, rD)
+
+       .macro  bsrli, rD, rA, IMM
+       .if (\IMM) == 2
+               BSRLI2(\rD, \rA)
+       .elseif (\IMM) == 10
+               BSRLI10(\rD, \rA)
+       .elseif (\IMM) == 12
+               BSRLI2(\rD, \rA)
+               BSRLI10(\rD, \rD)
+       .elseif (\IMM) == 14
+               BSRLI4(\rD, \rA)
+               BSRLI10(\rD, \rD)
+       .elseif (\IMM) == 20
+               BSRLI20(\rD, \rA)
+       .elseif (\IMM) == 24
+               BSRLI4(\rD, \rA)
+               BSRLI20(\rD, \rD)
+       .elseif (\IMM) == 28
+               BSRLI4(\rD, \rA)
+               BSRLI4(\rD, \rD)
+               BSRLI20(\rD, \rD)
+       .else
+       .error "BSRLI shift macros \IMM"
+       .endif
+       .endm
        #endif
+
 #endif /* CONFIG_MMU */
 
 .extern other_exception_handler /* Defined in exception.c */
@@ -604,7 +629,7 @@ ex_handler_done:
        ex4:
                tophys(r4,r4)
                /* Create L1 (pgdir/pmd) address */
-               BSRLI(r5,r3, PGDIR_SHIFT - 2)
+               bsrli   r5, r3, PGDIR_SHIFT - 2
                andi    r5, r5, PAGE_SIZE - 4
 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
                or      r4, r4, r5
@@ -613,7 +638,7 @@ ex_handler_done:
                beqi    r5, ex2                 /* Bail if no table */
 
                tophys(r5,r5)
-               BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */
+               bsrli   r6, r3, PTE_SHIFT /* Compute PTE address */
                andi    r6, r6, PAGE_SIZE - 4
                or      r5, r5, r6
                lwi     r4, r5, 0               /* Get Linux PTE */
@@ -705,7 +730,7 @@ ex_handler_done:
        ex6:
                tophys(r4,r4)
                /* Create L1 (pgdir/pmd) address */
-               BSRLI(r5,r3, PGDIR_SHIFT - 2)
+               bsrli   r5, r3, PGDIR_SHIFT - 2
                andi    r5, r5, PAGE_SIZE - 4
 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
                or      r4, r4, r5
@@ -714,7 +739,7 @@ ex_handler_done:
                beqi    r5, ex7                 /* Bail if no table */
 
                tophys(r5,r5)
-               BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */
+               bsrli   r6, r3, PTE_SHIFT /* Compute PTE address */
                andi    r6, r6, PAGE_SIZE - 4
                or      r5, r5, r6
                lwi     r4, r5, 0               /* Get Linux PTE */
@@ -776,7 +801,7 @@ ex_handler_done:
        ex9:
                tophys(r4,r4)
                /* Create L1 (pgdir/pmd) address */
-               BSRLI(r5,r3, PGDIR_SHIFT - 2)
+               bsrli   r5, r3, PGDIR_SHIFT - 2
                andi    r5, r5, PAGE_SIZE - 4
 /* Assume pgdir aligned on 4K boundary, no need for "andi r4,r4,0xfffff003" */
                or      r4, r4, r5
@@ -785,7 +810,7 @@ ex_handler_done:
                beqi    r5, ex10                /* Bail if no table */
 
                tophys(r5,r5)
-               BSRLI(r6,r3,PTE_SHIFT) /* Compute PTE address */
+               bsrli   r6, r3, PTE_SHIFT /* Compute PTE address */
                andi    r6, r6, PAGE_SIZE - 4
                or      r5, r5, r6
                lwi     r4, r5, 0               /* Get Linux PTE */
@@ -922,7 +947,7 @@ ex_handler_done:
 .ent _unaligned_data_exception
 _unaligned_data_exception:
        andi    r8, r3, 0x3E0;  /* Mask and extract the register operand */
-       BSRLI(r8,r8,2);         /* r8 >> 2 = register operand * 8 */
+       bsrli   r8, r8, 2;              /* r8 >> 2 = register operand * 8 */
        andi    r6, r3, 0x400;  /* Extract ESR[S] */
        bneid   r6, ex_sw_vm;
        andi    r6, r3, 0x800;  /* Extract ESR[W] - delay slot */
index 8de8ebc309f15b0ca080cdf6f7c93e54fd168d74..67cc4b282cc127fb48f2847d601adebab5aaf9e1 100644 (file)
@@ -9,6 +9,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/clk-provider.h>
 #include <linux/clocksource.h>
 #include <linux/string.h>
 #include <linux/seq_file.h>
@@ -136,7 +137,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
        lockdep_init();
 
 /* initialize device tree for usage in early_printk */
-       early_init_devtree((void *)_fdt_start);
+       early_init_devtree(_fdt_start);
 
 #ifdef CONFIG_EARLY_PRINTK
        setup_early_printk(NULL);
@@ -152,8 +153,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
        if (fdt)
                pr_info("FDT at 0x%08x\n", fdt);
        else
-               pr_info("Compiled-in FDT at 0x%08x\n",
-                                       (unsigned int)_fdt_start);
+               pr_info("Compiled-in FDT at %p\n", _fdt_start);
 
 #ifdef CONFIG_MTD_UCLINUX
        pr_info("Found romfs @ 0x%08x (0x%08x)\n",
@@ -175,7 +175,7 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
 #else
        if (!msr) {
                pr_info("!!!Your kernel not setup MSR instruction but ");
-               pr_cont"CPU have it %x\n", msr);
+               pr_cont("CPU have it %x\n", msr);
        }
 #endif
 
@@ -196,6 +196,8 @@ void __init machine_early_init(const char *cmdline, unsigned int ram,
 
 void __init time_init(void)
 {
+       of_clk_init(NULL);
+       setup_cpuinfo_clk();
        clocksource_of_init();
 }
 
index 3e39b1082fdf8433a030e851dfe37f2b63f8b766..fb0c61443f196ebbe7776e2d88108280bbc80025 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
+#include <linux/sched_clock.h>
 #include <linux/clk.h>
 #include <linux/clockchips.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <asm/cpuinfo.h>
-#include <linux/cnt32_to_63.h>
 
 static void __iomem *timer_baseaddr;
 
@@ -167,10 +167,15 @@ static __init void xilinx_clockevent_init(void)
        clockevents_register_device(&clockevent_xilinx_timer);
 }
 
+static u64 xilinx_clock_read(void)
+{
+       return in_be32(timer_baseaddr + TCR1);
+}
+
 static cycle_t xilinx_read(struct clocksource *cs)
 {
        /* reading actual value of timer 1 */
-       return (cycle_t) (in_be32(timer_baseaddr + TCR1));
+       return (cycle_t)xilinx_clock_read();
 }
 
 static struct timecounter xilinx_tc = {
@@ -222,17 +227,17 @@ static int __init xilinx_clocksource_init(void)
        return 0;
 }
 
-/*
- * We have to protect accesses before timer initialization
- * and return 0 for sched_clock function below.
- */
-static int timer_initialized;
-
 static void __init xilinx_timer_init(struct device_node *timer)
 {
+       struct clk *clk;
+       static int initialized;
        u32 irq;
        u32 timer_num = 1;
-       int ret;
+
+       if (initialized)
+               return;
+
+       initialized = 1;
 
        timer_baseaddr = of_iomap(timer, 0);
        if (!timer_baseaddr) {
@@ -250,10 +255,20 @@ static void __init xilinx_timer_init(struct device_node *timer)
 
        pr_info("%s: irq=%d\n", timer->full_name, irq);
 
-       /* If there is clock-frequency property than use it */
-       ret = of_property_read_u32(timer, "clock-frequency", &timer_clock_freq);
-       if (ret < 0)
+       clk = of_clk_get(timer, 0);
+       if (IS_ERR(clk)) {
+               pr_err("ERROR: timer CCF input clock not found\n");
+               /* If there is clock-frequency property than use it */
+               of_property_read_u32(timer, "clock-frequency",
+                                   &timer_clock_freq);
+       } else {
+               timer_clock_freq = clk_get_rate(clk);
+       }
+
+       if (!timer_clock_freq) {
+               pr_err("ERROR: Using CPU clock frequency\n");
                timer_clock_freq = cpuinfo.cpu_clock_freq;
+       }
 
        freq_div_hz = timer_clock_freq / HZ;
 
@@ -263,18 +278,8 @@ static void __init xilinx_timer_init(struct device_node *timer)
 #endif
        xilinx_clocksource_init();
        xilinx_clockevent_init();
-       timer_initialized = 1;
-}
 
-unsigned long long notrace sched_clock(void)
-{
-       if (timer_initialized) {
-               struct clocksource *cs = &clocksource_microblaze;
-
-               cycle_t cyc = cnt32_to_63(cs->read(NULL)) & LLONG_MAX;
-               return clocksource_cyc2ns(cyc, cs->mult, cs->shift);
-       }
-       return 0;
+       sched_clock_register(xilinx_clock_read, 32, timer_clock_freq);
 }
 
 CLOCKSOURCE_OF_DECLARE(xilinx_timer, "xlnx,xps-timer-1.00.a",
index 936d01a689d74157f3a63e53eff1de725fa67f9d..be9488d697347c330f9b226d1a5a5c9ba2d97714 100644 (file)
@@ -51,6 +51,7 @@ SECTIONS {
        . = ALIGN(16);
        RODATA
        EXCEPTION_TABLE(16)
+       NOTES
 
        /*
         * sdata2 section can go anywhere, but must be word aligned
index c02f1c03a22e7e1dd2ce0d1de16f702104cac47c..dcae3a7035db55a278b1a8cac80faa5ac2199003 100644 (file)
@@ -116,7 +116,6 @@ config BCM47XX
        select CEVT_R4K
        select CSRC_R4K
        select DMA_NONCOHERENT
-       select FW_CFE
        select HW_HAS_PCI
        select IRQ_CPU
        select SYS_HAS_CPU_MIPS32_R1
@@ -124,6 +123,7 @@ config BCM47XX
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_LITTLE_ENDIAN
        select SYS_HAS_EARLY_PRINTK
+       select EARLY_PRINTK_8250 if EARLY_PRINTK
        help
         Support for BCM47XX based boards
 
@@ -134,14 +134,13 @@ config BCM63XX
        select CSRC_R4K
        select DMA_NONCOHERENT
        select IRQ_CPU
-       select SYS_HAS_CPU_MIPS32_R1
-       select SYS_HAS_CPU_BMIPS4350 if !BCM63XX_CPU_6338 && !BCM63XX_CPU_6345 && !BCM63XX_CPU_6348
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_HAS_EARLY_PRINTK
        select SWAP_IO_SPACE
        select ARCH_REQUIRE_GPIOLIB
        select HAVE_CLK
+       select MIPS_L1_CACHE_SHIFT_4
        help
         Support for BCM63XX based boards
 
@@ -186,6 +185,7 @@ config MACH_DECSTATION
        select SYS_SUPPORTS_128HZ
        select SYS_SUPPORTS_256HZ
        select SYS_SUPPORTS_1024HZ
+       select MIPS_L1_CACHE_SHIFT_4
        help
          This enables support for DEC's MIPS based workstations.  For details
          see the Linux/MIPS FAQ on <http://www.linux-mips.org/> and the
@@ -305,7 +305,7 @@ config MIPS_MALTA
        select CEVT_R4K
        select CSRC_R4K
        select CSRC_GIC
-       select DMA_NONCOHERENT
+       select DMA_MAYBE_COHERENT
        select GENERIC_ISA_DMA
        select HAVE_PCSPKR_PLATFORM
        select IRQ_CPU
@@ -324,7 +324,6 @@ config MIPS_MALTA
        select SYS_HAS_CPU_MIPS64_R2
        select SYS_HAS_CPU_NEVADA
        select SYS_HAS_CPU_RM7000
-       select SYS_HAS_EARLY_PRINTK
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
@@ -349,6 +348,7 @@ config MIPS_SEAD3
        select DMA_NONCOHERENT
        select IRQ_CPU
        select IRQ_GIC
+       select LIBFDT
        select MIPS_MSC
        select SYS_HAS_CPU_MIPS32_R1
        select SYS_HAS_CPU_MIPS32_R2
@@ -471,6 +471,7 @@ config SGI_IP22
        select SYS_SUPPORTS_32BIT_KERNEL
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
+       select MIPS_L1_CACHE_SHIFT_7
        help
          This are the SGI Indy, Challenge S and Indigo2, as well as certain
          OEM variants like the Tandem CMN B006S. To compile a Linux kernel
@@ -491,6 +492,7 @@ config SGI_IP27
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_NUMA
        select SYS_SUPPORTS_SMP
+       select MIPS_L1_CACHE_SHIFT_7
        help
          This are the SGI Origin 200, Origin 2000 and Onyx 2 Graphics
          workstations.  To compile a Linux kernel that runs on these, say Y
@@ -697,6 +699,7 @@ config MIKROTIK_RB532
        select SWAP_IO_SPACE
        select BOOT_RAW
        select ARCH_REQUIRE_GPIOLIB
+       select MIPS_L1_CACHE_SHIFT_4
        help
          Support the Mikrotik(tm) RouterBoard 532 series,
          based on the IDT RC32434 SoC.
@@ -779,6 +782,7 @@ config NLM_XLP_BOARD
        select CEVT_R4K
        select CSRC_R4K
        select IRQ_CPU
+       select ARCH_SUPPORTS_MSI
        select ZONE_DMA32 if 64BIT
        select SYNC_R4K
        select SYS_HAS_EARLY_PRINTK
@@ -897,6 +901,10 @@ config FW_CFE
 config ARCH_DMA_ADDR_T_64BIT
        def_bool (HIGHMEM && 64BIT_PHYS_ADDR) || 64BIT
 
+config DMA_MAYBE_COHERENT
+       select DMA_NONCOHERENT
+       bool
+
 config DMA_COHERENT
        bool
 
@@ -1091,11 +1099,24 @@ config FW_SNIPROM
 config BOOT_ELF32
        bool
 
+config MIPS_L1_CACHE_SHIFT_4
+       bool
+
+config MIPS_L1_CACHE_SHIFT_5
+       bool
+
+config MIPS_L1_CACHE_SHIFT_6
+       bool
+
+config MIPS_L1_CACHE_SHIFT_7
+       bool
+
 config MIPS_L1_CACHE_SHIFT
        int
-       default "4" if MACH_DECSTATION || MIKROTIK_RB532 || PMC_MSP4200_EVAL || SOC_RT288X
-       default "6" if MIPS_CPU_SCACHE
-       default "7" if SGI_IP22 || SGI_IP27 || SGI_IP28 || SNI_RM || CPU_CAVIUM_OCTEON
+       default "4" if MIPS_L1_CACHE_SHIFT_4
+       default "5" if MIPS_L1_CACHE_SHIFT_5
+       default "6" if MIPS_L1_CACHE_SHIFT_6
+       default "7" if MIPS_L1_CACHE_SHIFT_7
        default "5"
 
 config HAVE_STD_PC_SERIAL_PORT
@@ -1375,47 +1396,31 @@ config CPU_CAVIUM_OCTEON
        select LIBFDT
        select USE_OF
        select USB_EHCI_BIG_ENDIAN_MMIO
+       select SYS_HAS_DMA_OPS
+       select MIPS_L1_CACHE_SHIFT_7
        help
          The Cavium Octeon processor is a highly integrated chip containing
          many ethernet hardware widgets for networking tasks. The processor
          can have up to 16 Mips64v2 cores and 8 integrated gigabit ethernets.
          Full details can be found at http://www.caviumnetworks.com.
 
-config CPU_BMIPS3300
-       bool "BMIPS3300"
-       depends on SYS_HAS_CPU_BMIPS3300
-       select CPU_BMIPS
-       help
-         Broadcom BMIPS3300 processors.
-
-config CPU_BMIPS4350
-       bool "BMIPS4350"
-       depends on SYS_HAS_CPU_BMIPS4350
-       select CPU_BMIPS
-       select SYS_SUPPORTS_SMP
-       select SYS_SUPPORTS_HOTPLUG_CPU
-       help
-         Broadcom BMIPS4350 ("VIPER") processors.
-
-config CPU_BMIPS4380
-       bool "BMIPS4380"
-       depends on SYS_HAS_CPU_BMIPS4380
-       select CPU_BMIPS
-       select SYS_SUPPORTS_SMP
-       select SYS_SUPPORTS_HOTPLUG_CPU
-       help
-         Broadcom BMIPS4380 processors.
-
-config CPU_BMIPS5000
-       bool "BMIPS5000"
-       depends on SYS_HAS_CPU_BMIPS5000
-       select CPU_BMIPS
+config CPU_BMIPS
+       bool "Broadcom BMIPS"
+       depends on SYS_HAS_CPU_BMIPS
+       select CPU_MIPS32
+       select CPU_BMIPS32_3300 if SYS_HAS_CPU_BMIPS32_3300
+       select CPU_BMIPS4350 if SYS_HAS_CPU_BMIPS4350
+       select CPU_BMIPS4380 if SYS_HAS_CPU_BMIPS4380
+       select CPU_BMIPS5000 if SYS_HAS_CPU_BMIPS5000
+       select CPU_SUPPORTS_32BIT_KERNEL
+       select DMA_NONCOHERENT
+       select IRQ_CPU
+       select SWAP_IO_SPACE
+       select WEAK_ORDERING
        select CPU_SUPPORTS_HIGHMEM
-       select MIPS_CPU_SCACHE
-       select SYS_SUPPORTS_SMP
-       select SYS_SUPPORTS_HOTPLUG_CPU
+       select CPU_HAS_PREFETCH
        help
-         Broadcom BMIPS5000 processors.
+         Support for BMIPS32/3300/4350/4380 and BMIPS5000 processors.
 
 config CPU_XLR
        bool "Netlogic XLR SoC"
@@ -1498,14 +1503,25 @@ config CPU_LOONGSON1
        select CPU_SUPPORTS_32BIT_KERNEL
        select CPU_SUPPORTS_HIGHMEM
 
-config CPU_BMIPS
+config CPU_BMIPS32_3300
+       select SMP_UP if SMP
        bool
-       select CPU_MIPS32
-       select CPU_SUPPORTS_32BIT_KERNEL
-       select DMA_NONCOHERENT
-       select IRQ_CPU
-       select SWAP_IO_SPACE
-       select WEAK_ORDERING
+
+config CPU_BMIPS4350
+       bool
+       select SYS_SUPPORTS_SMP
+       select SYS_SUPPORTS_HOTPLUG_CPU
+
+config CPU_BMIPS4380
+       bool
+       select SYS_SUPPORTS_SMP
+       select SYS_SUPPORTS_HOTPLUG_CPU
+
+config CPU_BMIPS5000
+       bool
+       select MIPS_CPU_SCACHE
+       select SYS_SUPPORTS_SMP
+       select SYS_SUPPORTS_HOTPLUG_CPU
 
 config SYS_HAS_CPU_LOONGSON2E
        bool
@@ -1579,17 +1595,24 @@ config SYS_HAS_CPU_SB1
 config SYS_HAS_CPU_CAVIUM_OCTEON
        bool
 
-config SYS_HAS_CPU_BMIPS3300
+config SYS_HAS_CPU_BMIPS
+       bool
+
+config SYS_HAS_CPU_BMIPS32_3300
        bool
+       select SYS_HAS_CPU_BMIPS
 
 config SYS_HAS_CPU_BMIPS4350
        bool
+       select SYS_HAS_CPU_BMIPS
 
 config SYS_HAS_CPU_BMIPS4380
        bool
+       select SYS_HAS_CPU_BMIPS
 
 config SYS_HAS_CPU_BMIPS5000
        bool
+       select SYS_HAS_CPU_BMIPS
 
 config SYS_HAS_CPU_XLR
        bool
@@ -1797,6 +1820,7 @@ config IP22_CPU_SCACHE
 config MIPS_CPU_SCACHE
        bool
        select BOARD_SCACHE
+       select MIPS_L1_CACHE_SHIFT_6
 
 config R5000_CPU_SCACHE
        bool
@@ -1833,59 +1857,48 @@ choice
        prompt "MIPS MT options"
 
 config MIPS_MT_DISABLED
-       bool "Disable multithreading support."
+       bool "Disable multithreading support"
        help
-         Use this option if your workload can't take advantage of
-         MIPS hardware multithreading support.  On systems that don't have
-         the option of an MT-enabled processor this option will be the only
-         option in this menu.
+         Use this option if your platform does not support the MT ASE
+         which is hardware multithreading support. On systems without
+         an MT-enabled processor, this will be the only option that is
+         available in this menu.
 
 config MIPS_MT_SMP
        bool "Use 1 TC on each available VPE for SMP"
        depends on SYS_SUPPORTS_MULTITHREADING
        select CPU_MIPSR2_IRQ_VI
        select CPU_MIPSR2_IRQ_EI
+       select SYNC_R4K
        select MIPS_MT
        select SMP
-       select SYS_SUPPORTS_SCHED_SMT if SMP
-       select SYS_SUPPORTS_SMP
        select SMP_UP
+       select SYS_SUPPORTS_SMP
+       select SYS_SUPPORTS_SCHED_SMT
        select MIPS_PERF_SHARED_TC_COUNTERS
        help
-         This is a kernel model which is known a VSMP but lately has been
-         marketesed into SMVP.
-         Virtual SMP uses the processor's VPEs  to implement virtual
-         processors. In currently available configuration of the 34K processor
-         this allows for a dual processor. Both processors will share the same
-         primary caches; each will obtain the half of the TLB for it's own
-         exclusive use. For a layman this model can be described as similar to
-         what Intel calls Hyperthreading.
-
-         For further information see http://www.linux-mips.org/wiki/34K#VSMP
+         This is a kernel model which is known as SMVP. This is supported
+         on cores with the MT ASE and uses the available VPEs to implement
+         virtual processors which supports SMP. This is equivalent to the
+         Intel Hyperthreading feature. For further information go to
+         <http://www.imgtec.com/mips/mips-multithreading.asp>.
 
 config MIPS_MT_SMTC
-       bool "SMTC: Use all TCs on all VPEs for SMP"
+       bool "Use all TCs on all VPEs for SMP (DEPRECATED)"
        depends on CPU_MIPS32_R2
-       #depends on CPU_MIPS64_R2               # once there is hardware ...
        depends on SYS_SUPPORTS_MULTITHREADING
        select CPU_MIPSR2_IRQ_VI
        select CPU_MIPSR2_IRQ_EI
        select MIPS_MT
-       select NR_CPUS_DEFAULT_8
        select SMP
-       select SYS_SUPPORTS_SMP
        select SMP_UP
+       select SYS_SUPPORTS_SMP
+       select NR_CPUS_DEFAULT_8
        help
-         This is a kernel model which is known a SMTC or lately has been
-         marketesed into SMVP.
-         is presenting the available TC's of the core as processors to Linux.
-         On currently available 34K processors this means a Linux system will
-         see up to 5 processors. The implementation of the SMTC kernel differs
-         significantly from VSMP and cannot efficiently coexist in the same
-         kernel binary so the choice between VSMP and SMTC is a compile time
-         decision.
-
-         For further information see http://www.linux-mips.org/wiki/34K#SMTC
+         This is a kernel model which is known as SMTC. This is
+         supported on cores with the MT ASE and presents all TCs
+         available on all VPEs to support SMP. For further
+         information see <http://www.linux-mips.org/wiki/34K#SMTC>.
 
 endchoice
 
@@ -1922,6 +1935,16 @@ config MIPS_VPE_LOADER
          Includes a loader for loading an elf relocatable object
          onto another VPE and running it.
 
+config MIPS_VPE_LOADER_CMP
+       bool
+       default "y"
+       depends on MIPS_VPE_LOADER && MIPS_CMP
+
+config MIPS_VPE_LOADER_MT
+       bool
+       default "y"
+       depends on MIPS_VPE_LOADER && !MIPS_CMP
+
 config MIPS_MT_SMTC_IM_BACKSTOP
        bool "Use per-TC register bits as backstop for inhibited IM bits"
        depends on MIPS_MT_SMTC
@@ -1955,24 +1978,29 @@ config MIPS_VPE_LOADER_TOM
          you to ensure the amount you put in the option and the space your
          program requires is less or equal to the amount physically present.
 
-# this should possibly be in drivers/char, but it is rather cpu related. Hmmm
 config MIPS_VPE_APSP_API
        bool "Enable support for AP/SP API (RTLX)"
        depends on MIPS_VPE_LOADER
        help
 
+config MIPS_VPE_APSP_API_CMP
+       bool
+       default "y"
+       depends on MIPS_VPE_APSP_API && MIPS_CMP
+
+config MIPS_VPE_APSP_API_MT
+       bool
+       default "y"
+       depends on MIPS_VPE_APSP_API && !MIPS_CMP
+
 config MIPS_CMP
-       bool "MIPS CMP framework support"
-       depends on SYS_SUPPORTS_MIPS_CMP
-       select SMP
+       bool "MIPS CMP support"
+       depends on SYS_SUPPORTS_MIPS_CMP && MIPS_MT_SMP
        select SYNC_R4K
-       select SYS_SUPPORTS_SMP
-       select SYS_SUPPORTS_SCHED_SMT if SMP
        select WEAK_ORDERING
        default n
        help
-         This is a placeholder option for the GCMP work. It will need to
-         be handled differently...
+         Enable Coherency Manager processor (CMP) support.
 
 config SB1_PASS_1_WORKAROUNDS
        bool
@@ -2324,6 +2352,23 @@ config SECCOMP
 
          If unsure, say Y. Only embedded should say N here.
 
+config MIPS_O32_FP64_SUPPORT
+       bool "Support for O32 binaries using 64-bit FP"
+       depends on 32BIT || MIPS32_O32
+       default y
+       help
+         When this is enabled, the kernel will support use of 64-bit floating
+         point registers with binaries using the O32 ABI along with the
+         EF_MIPS_FP64 ELF header flag (typically built with -mfp64). On
+         32-bit MIPS systems this support is at the cost of increasing the
+         size and complexity of the compiled FPU emulator. Thus if you are
+         running a MIPS32 system and know that none of your userland binaries
+         will require 64-bit floating point, you may wish to reduce the size
+         of your kernel & potentially improve FP emulation performance by
+         saying N here.
+
+         If unsure, say Y.
+
 config USE_OF
        bool
        select OF
index efe50787cd897c4391575cefcef73ecb40ff3385..9b8556de99937698653ade0f0ddbca55b7f198d9 100644 (file)
@@ -114,7 +114,7 @@ cflags-$(CONFIG_CPU_BIG_ENDIAN)             += $(shell $(CC) -dumpmachine |grep -q 'mips.*e
 cflags-$(CONFIG_CPU_LITTLE_ENDIAN)     += $(shell $(CC) -dumpmachine |grep -q 'mips.*el-.*' || echo -EL $(undef-all) $(predef-le))
 
 cflags-$(CONFIG_CPU_HAS_SMARTMIPS)     += $(call cc-option,-msmartmips)
-cflags-$(CONFIG_CPU_MICROMIPS) += $(call cc-option,-mmicromips -mno-jals)
+cflags-$(CONFIG_CPU_MICROMIPS) += $(call cc-option,-mmicromips)
 
 cflags-$(CONFIG_SB1XXX_CORELIS)        += $(call cc-option,-mno-sched-prolog) \
                                   -fno-omit-frame-pointer
index 0c7fce2a3c12f0e6d4f7bea9cedf1a17fe0ea271..bdb28dee8fddcd13a20fcbaef733aa91aeb4bf50 100644 (file)
@@ -29,7 +29,6 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/sysctl.h>
 #include <linux/jiffies.h>
index 22c93213b233db0090a2c8175cee864f2cf62619..1dc6c3b37f91dd086505276373d44687474531dd 100644 (file)
@@ -18,7 +18,6 @@
  * Setting up the clock on the MIPS boards.
  */
 
-#include <linux/init.h>
 #include <linux/time.h>
 #include <linux/err.h>
 #include <linux/clk.h>
index 648d2dafbc56bf59b60671c1792173685f04e8b1..a3120714f0b75455efedc1fb589bcffcc938f65a 100644 (file)
@@ -15,7 +15,6 @@
 #define __ATH79_COMMON_H
 
 #include <linux/types.h>
-#include <linux/init.h>
 
 #define ATH79_MEM_SIZE_MIN     (2 * 1024 * 1024)
 #define ATH79_MEM_SIZE_MAX     (128 * 1024 * 1024)
index 2b8b118398c458573652c5b9e058a302ddcaf766..09cb6f7aa3dbf4b368c5bfb456c491c90d176757 100644 (file)
@@ -2,6 +2,7 @@ if BCM47XX
 
 config BCM47XX_SSB
        bool "SSB Support for Broadcom BCM47XX"
+       select SYS_HAS_CPU_BMIPS32_3300
        select SSB
        select SSB_DRIVER_MIPS
        select SSB_DRIVER_EXTIF
@@ -11,6 +12,7 @@ config BCM47XX_SSB
        select SSB_PCICORE_HOSTMODE if PCI
        select SSB_DRIVER_GPIO
        select GPIOLIB
+       select LEDS_GPIO_REGISTER
        default y
        help
         Add support for old Broadcom BCM47xx boards with Sonics Silicon Backplane support.
@@ -20,6 +22,7 @@ config BCM47XX_SSB
 config BCM47XX_BCMA
        bool "BCMA Support for Broadcom BCM47XX"
        select SYS_HAS_CPU_MIPS32_R2
+       select CPU_MIPSR2_IRQ_VI
        select BCMA
        select BCMA_HOST_SOC
        select BCMA_DRIVER_MIPS
@@ -27,6 +30,7 @@ config BCM47XX_BCMA
        select BCMA_DRIVER_PCI_HOSTMODE if PCI
        select BCMA_DRIVER_GPIO
        select GPIOLIB
+       select LEDS_GPIO_REGISTER
        default y
        help
         Add support for new Broadcom BCM47xx boards with Broadcom specific Advanced Microcontroller Bus.
index c52daf9b05c638afbe4062ea204bb6522c15ccd1..4688b6a6211b7adeaf22ef8b4ba57f1b5c18ebbd 100644 (file)
@@ -4,5 +4,4 @@
 #
 
 obj-y                          += irq.o nvram.o prom.o serial.o setup.o time.o sprom.o
-obj-y                          += board.o
-obj-$(CONFIG_BCM47XX_SSB)      += wgt634u.o
+obj-y                          += board.o buttons.o leds.o
diff --git a/arch/mips/bcm47xx/bcm47xx_private.h b/arch/mips/bcm47xx/bcm47xx_private.h
new file mode 100644 (file)
index 0000000..5c94ace
--- /dev/null
@@ -0,0 +1,12 @@
+#ifndef LINUX_BCM47XX_PRIVATE_H_
+#define LINUX_BCM47XX_PRIVATE_H_
+
+#include <linux/kernel.h>
+
+/* buttons.c */
+int __init bcm47xx_buttons_register(void);
+
+/* leds.c */
+void __init bcm47xx_leds_register(void);
+
+#endif
index f3f6bfe68a2ae4e2dbd44c10fc26dda63628bb90..6d612e2b949b20f3875f7993b29de8e77435194c 100644 (file)
@@ -36,26 +36,32 @@ static const
 struct bcm47xx_board_type_list1 bcm47xx_board_list_model_name[] __initconst = {
        {{BCM47XX_BOARD_DLINK_DIR130, "D-Link DIR-130"}, "DIR-130"},
        {{BCM47XX_BOARD_DLINK_DIR330, "D-Link DIR-330"}, "DIR-330"},
-       { {0}, 0},
+       { {0}, NULL},
 };
 
 /* model_no */
 static const
 struct bcm47xx_board_type_list1 bcm47xx_board_list_model_no[] __initconst = {
        {{BCM47XX_BOARD_ASUS_WL700GE, "Asus WL700"}, "WL700"},
-       { {0}, 0},
+       { {0}, NULL},
 };
 
 /* machine_name */
 static const
 struct bcm47xx_board_type_list1 bcm47xx_board_list_machine_name[] __initconst = {
        {{BCM47XX_BOARD_LINKSYS_WRTSL54GS, "Linksys WRTSL54GS"}, "WRTSL54GS"},
-       { {0}, 0},
+       { {0}, NULL},
 };
 
 /* hardware_version */
 static const
 struct bcm47xx_board_type_list1 bcm47xx_board_list_hardware_version[] __initconst = {
+       {{BCM47XX_BOARD_ASUS_RTN10U, "Asus RT-N10U"}, "RTN10U"},
+       {{BCM47XX_BOARD_ASUS_RTN12, "Asus RT-N12"}, "RT-N12"},
+       {{BCM47XX_BOARD_ASUS_RTN12B1, "Asus RT-N12B1"}, "RTN12B1"},
+       {{BCM47XX_BOARD_ASUS_RTN12C1, "Asus RT-N12C1"}, "RTN12C1"},
+       {{BCM47XX_BOARD_ASUS_RTN12D1, "Asus RT-N12D1"}, "RTN12D1"},
+       {{BCM47XX_BOARD_ASUS_RTN12HP, "Asus RT-N12HP"}, "RTN12HP"},
        {{BCM47XX_BOARD_ASUS_RTN16, "Asus RT-N16"}, "RT-N16-"},
        {{BCM47XX_BOARD_ASUS_WL320GE, "Asus WL320GE"}, "WL320G-"},
        {{BCM47XX_BOARD_ASUS_WL330GE, "Asus WL330GE"}, "WL330GE-"},
@@ -66,7 +72,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_hardware_version[] __initcons
        {{BCM47XX_BOARD_ASUS_WL520GC, "Asus WL520GC"}, "WL520GC-"},
        {{BCM47XX_BOARD_ASUS_WL520GU, "Asus WL520GU"}, "WL520GU-"},
        {{BCM47XX_BOARD_BELKIN_F7D4301, "Belkin F7D4301"}, "F7D4301"},
-       { {0}, 0},
+       { {0}, NULL},
 };
 
 /* productid */
@@ -75,19 +81,13 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_productid[] __initconst = {
        {{BCM47XX_BOARD_ASUS_RTAC66U, "Asus RT-AC66U"}, "RT-AC66U"},
        {{BCM47XX_BOARD_ASUS_RTN10, "Asus RT-N10"}, "RT-N10"},
        {{BCM47XX_BOARD_ASUS_RTN10D, "Asus RT-N10D"}, "RT-N10D"},
-       {{BCM47XX_BOARD_ASUS_RTN10U, "Asus RT-N10U"}, "RT-N10U"},
-       {{BCM47XX_BOARD_ASUS_RTN12, "Asus RT-N12"}, "RT-N12"},
-       {{BCM47XX_BOARD_ASUS_RTN12B1, "Asus RT-N12B1"}, "RT-N12B1"},
-       {{BCM47XX_BOARD_ASUS_RTN12C1, "Asus RT-N12C1"}, "RT-N12C1"},
-       {{BCM47XX_BOARD_ASUS_RTN12D1, "Asus RT-N12D1"}, "RT-N12D1"},
-       {{BCM47XX_BOARD_ASUS_RTN12HP, "Asus RT-N12HP"}, "RT-N12HP"},
        {{BCM47XX_BOARD_ASUS_RTN15U, "Asus RT-N15U"}, "RT-N15U"},
        {{BCM47XX_BOARD_ASUS_RTN16, "Asus RT-N16"}, "RT-N16"},
        {{BCM47XX_BOARD_ASUS_RTN53, "Asus RT-N53"}, "RT-N53"},
        {{BCM47XX_BOARD_ASUS_RTN66U, "Asus RT-N66U"}, "RT-N66U"},
        {{BCM47XX_BOARD_ASUS_WL300G, "Asus WL300G"}, "WL300g"},
        {{BCM47XX_BOARD_ASUS_WLHDD, "Asus WLHDD"}, "WLHDD"},
-       { {0}, 0},
+       { {0}, NULL},
 };
 
 /* ModelId */
@@ -97,7 +97,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_ModelId[] __initconst = {
        {{BCM47XX_BOARD_MOTOROLA_WE800G, "Motorola WE800G"}, "WE800G"},
        {{BCM47XX_BOARD_MOTOROLA_WR850GP, "Motorola WR850GP"}, "WR850GP"},
        {{BCM47XX_BOARD_MOTOROLA_WR850GV2V3, "Motorola WR850G"}, "WR850G"},
-       { {0}, 0},
+       { {0}, NULL},
 };
 
 /* melco_id or buf1falo_id */
@@ -112,7 +112,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_melco_id[] __initconst = {
        {{BCM47XX_BOARD_BUFFALO_WZR_G300N, "Buffalo WZR-G300N"}, "31120"},
        {{BCM47XX_BOARD_BUFFALO_WZR_RS_G54, "Buffalo WZR-RS-G54"}, "30083"},
        {{BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP, "Buffalo WZR-RS-G54HP"}, "30103"},
-       { {0}, 0},
+       { {0}, NULL},
 };
 
 /* boot_hw_model, boot_hw_ver */
@@ -143,7 +143,7 @@ struct bcm47xx_board_type_list2 bcm47xx_board_list_boot_hw[] __initconst = {
        {{BCM47XX_BOARD_LINKSYS_WRT54G3GV2, "Linksys WRT54G3GV2-VF"}, "WRT54G3GV2-VF", "1.0"},
        {{BCM47XX_BOARD_LINKSYS_WRT610NV1, "Linksys WRT610N V1"}, "WRT610N", "1.0"},
        {{BCM47XX_BOARD_LINKSYS_WRT610NV2, "Linksys WRT610N V2"}, "WRT610N", "2.0"},
-       { {0}, 0},
+       { {0}, NULL},
 };
 
 /* board_id */
@@ -165,7 +165,7 @@ struct bcm47xx_board_type_list1 bcm47xx_board_list_board_id[] __initconst = {
        {{BCM47XX_BOARD_NETGEAR_WNR3500V2, "Netgear WNR3500 V2"}, "U12H127T00_NETGEAR"},
        {{BCM47XX_BOARD_NETGEAR_WNR3500V2VC, "Netgear WNR3500 V2vc"}, "U12H127T70_NETGEAR"},
        {{BCM47XX_BOARD_NETGEAR_WNR834BV2, "Netgear WNR834B V2"}, "U12H081T00_NETGEAR"},
-       { {0}, 0},
+       { {0}, NULL},
 };
 
 /* boardtype, boardnum, boardrev */
@@ -174,7 +174,9 @@ struct bcm47xx_board_type_list3 bcm47xx_board_list_board[] __initconst = {
        {{BCM47XX_BOARD_HUAWEI_E970, "Huawei E970"}, "0x048e", "0x5347", "0x11"},
        {{BCM47XX_BOARD_PHICOMM_M1, "Phicomm M1"}, "0x0590", "80", "0x1104"},
        {{BCM47XX_BOARD_ZTE_H218N, "ZTE H218N"}, "0x053d", "1234", "0x1305"},
-       { {0}, 0},
+       {{BCM47XX_BOARD_NETGEAR_WNR3500L, "Netgear WNR3500L"}, "0x04CF", "3500", "02"},
+       {{BCM47XX_BOARD_LINKSYS_WRT54GSV1, "Linksys WRT54GS V1"}, "0x0101", "42", "0x10"},
+       { {0}, NULL},
 };
 
 static const
diff --git a/arch/mips/bcm47xx/buttons.c b/arch/mips/bcm47xx/buttons.c
new file mode 100644 (file)
index 0000000..872c62e
--- /dev/null
@@ -0,0 +1,531 @@
+#include "bcm47xx_private.h"
+
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/interrupt.h>
+#include <bcm47xx_board.h>
+#include <bcm47xx.h>
+
+/**************************************************
+ * Database
+ **************************************************/
+
+#define BCM47XX_GPIO_KEY(_gpio, _code)                                 \
+       {                                                               \
+               .code           = _code,                                \
+               .gpio           = _gpio,                                \
+               .active_low     = 1,                                    \
+       }
+
+/* Asus */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_rtn12[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(1, KEY_RESTART),
+       BCM47XX_GPIO_KEY(4, BTN_0), /* Router mode */
+       BCM47XX_GPIO_KEY(5, BTN_1), /* Repeater mode */
+       BCM47XX_GPIO_KEY(6, BTN_2), /* AP mode */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_rtn16[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(8, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_rtn66u[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(9, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl300g[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl320ge[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl330ge[] __initconst = {
+       BCM47XX_GPIO_KEY(2, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl500gd[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl500gpv1[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_RESTART),
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl500gpv2[] __initconst = {
+       BCM47XX_GPIO_KEY(2, KEY_RESTART),
+       BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl500w[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+       BCM47XX_GPIO_KEY(7, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl520gc[] __initconst = {
+       BCM47XX_GPIO_KEY(2, KEY_RESTART),
+       BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl520gu[] __initconst = {
+       BCM47XX_GPIO_KEY(2, KEY_RESTART),
+       BCM47XX_GPIO_KEY(3, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wl700ge[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_POWER), /* Hard disk power switch */
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON), /* EZSetup */
+       BCM47XX_GPIO_KEY(6, KEY_COPY), /* Copy data from USB to internal disk */
+       BCM47XX_GPIO_KEY(7, KEY_RESTART), /* Hard reset */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_asus_wlhdd[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+/* Huawei */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_huawei_e970[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+/* Belkin */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_belkin_f7d4301[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+       BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON),
+};
+
+/* Buffalo */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_whr2_a54g54[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_whr_g125[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(4, KEY_RESTART),
+       BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_whr_g54s[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(4, KEY_RESTART),
+       BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_whr_hp_g54[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(4, KEY_RESTART),
+       BCM47XX_GPIO_KEY(5, BTN_0), /* Router / AP mode swtich */
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_wzr_g300n[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_wzr_rs_g54[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(4, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_buffalo_wzr_rs_g54hp[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(4, KEY_RESTART),
+};
+
+/* Dell */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_dell_tm2300[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_RESTART),
+};
+
+/* D-Link */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_dlink_dir130[] __initconst = {
+       BCM47XX_GPIO_KEY(3, KEY_RESTART),
+       BCM47XX_GPIO_KEY(7, KEY_UNKNOWN),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_dlink_dir330[] __initconst = {
+       BCM47XX_GPIO_KEY(3, KEY_RESTART),
+       BCM47XX_GPIO_KEY(7, KEY_UNKNOWN),
+};
+
+/* Linksys */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e1000v1[] __initconst = {
+       BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e1000v21[] __initconst = {
+       BCM47XX_GPIO_KEY(9, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(10, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e2000v1[] __initconst = {
+       BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(8, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e3000v1[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e3200v1[] __initconst = {
+       BCM47XX_GPIO_KEY(5, KEY_RESTART),
+       BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_e4200v1[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt150nv1[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt150nv11[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt160nv1[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt160nv3[] __initconst = {
+       BCM47XX_GPIO_KEY(5, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt300nv11[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_UNKNOWN),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt310nv1[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+       BCM47XX_GPIO_KEY(8, KEY_UNKNOWN),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt610nv1[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+       BCM47XX_GPIO_KEY(8, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_linksys_wrt610nv2[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+/* Motorola */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_motorola_we800g[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_motorola_wr850gp[] __initconst = {
+       BCM47XX_GPIO_KEY(5, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_motorola_wr850gv2v3[] __initconst = {
+       BCM47XX_GPIO_KEY(5, KEY_RESTART),
+};
+
+/* Netgear */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_netgear_wndr3400v1[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_RESTART),
+       BCM47XX_GPIO_KEY(6, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(8, KEY_RFKILL),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_netgear_wndr3700v3[] __initconst = {
+       BCM47XX_GPIO_KEY(2, KEY_RFKILL),
+       BCM47XX_GPIO_KEY(3, KEY_RESTART),
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_netgear_wndr4500v1[] __initconst = {
+       BCM47XX_GPIO_KEY(4, KEY_WPS_BUTTON),
+       BCM47XX_GPIO_KEY(5, KEY_RFKILL),
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+static const struct gpio_keys_button
+bcm47xx_buttons_netgear_wnr834bv2[] __initconst = {
+       BCM47XX_GPIO_KEY(6, KEY_RESTART),
+};
+
+/* SimpleTech */
+
+static const struct gpio_keys_button
+bcm47xx_buttons_simpletech_simpleshare[] __initconst = {
+       BCM47XX_GPIO_KEY(0, KEY_RESTART),
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static struct gpio_keys_platform_data bcm47xx_button_pdata;
+
+static struct platform_device bcm47xx_buttons_gpio_keys = {
+       .name = "gpio-keys",
+       .dev = {
+               .platform_data = &bcm47xx_button_pdata,
+       }
+};
+
+/* Copy data from __initconst */
+static int __init bcm47xx_buttons_copy(const struct gpio_keys_button *buttons,
+                                      size_t nbuttons)
+{
+       size_t size = nbuttons * sizeof(*buttons);
+
+       bcm47xx_button_pdata.buttons = kmalloc(size, GFP_KERNEL);
+       if (!bcm47xx_button_pdata.buttons)
+               return -ENOMEM;
+       memcpy(bcm47xx_button_pdata.buttons, buttons, size);
+       bcm47xx_button_pdata.nbuttons = nbuttons;
+
+       return 0;
+}
+
+#define bcm47xx_copy_bdata(dev_buttons)                                        \
+       bcm47xx_buttons_copy(dev_buttons, ARRAY_SIZE(dev_buttons));
+
+int __init bcm47xx_buttons_register(void)
+{
+       enum bcm47xx_board board = bcm47xx_board_get();
+       int err;
+
+       switch (board) {
+       case BCM47XX_BOARD_ASUS_RTN12:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn12);
+               break;
+       case BCM47XX_BOARD_ASUS_RTN16:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn16);
+               break;
+       case BCM47XX_BOARD_ASUS_RTN66U:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_rtn66u);
+               break;
+       case BCM47XX_BOARD_ASUS_WL300G:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl300g);
+               break;
+       case BCM47XX_BOARD_ASUS_WL320GE:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl320ge);
+               break;
+       case BCM47XX_BOARD_ASUS_WL330GE:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl330ge);
+               break;
+       case BCM47XX_BOARD_ASUS_WL500GD:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gd);
+               break;
+       case BCM47XX_BOARD_ASUS_WL500GPV1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gpv1);
+               break;
+       case BCM47XX_BOARD_ASUS_WL500GPV2:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500gpv2);
+               break;
+       case BCM47XX_BOARD_ASUS_WL500W:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl500w);
+               break;
+       case BCM47XX_BOARD_ASUS_WL520GC:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl520gc);
+               break;
+       case BCM47XX_BOARD_ASUS_WL520GU:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl520gu);
+               break;
+       case BCM47XX_BOARD_ASUS_WL700GE:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wl700ge);
+               break;
+       case BCM47XX_BOARD_ASUS_WLHDD:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_asus_wlhdd);
+               break;
+
+       case BCM47XX_BOARD_BELKIN_F7D4301:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_belkin_f7d4301);
+               break;
+
+       case BCM47XX_BOARD_BUFFALO_WHR2_A54G54:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr2_a54g54);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WHR_G125:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_g125);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WHR_G54S:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_g54s);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WHR_HP_G54:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_whr_hp_g54);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WZR_G300N:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_g300n);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WZR_RS_G54:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_rs_g54);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_buffalo_wzr_rs_g54hp);
+               break;
+
+       case BCM47XX_BOARD_DELL_TM2300:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_dell_tm2300);
+               break;
+
+       case BCM47XX_BOARD_DLINK_DIR130:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_dlink_dir130);
+               break;
+       case BCM47XX_BOARD_DLINK_DIR330:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_dlink_dir330);
+               break;
+
+       case BCM47XX_BOARD_HUAWEI_E970:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_huawei_e970);
+               break;
+
+       case BCM47XX_BOARD_LINKSYS_E1000V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e1000v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E1000V21:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e1000v21);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E2000V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e2000v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E3000V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e3000v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E3200V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e3200v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E4200V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_e4200v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT150NV1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt150nv1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT150NV11:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt150nv11);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT160NV1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt160nv1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT160NV3:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt160nv3);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT300NV11:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt300nv11);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT310NV1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt310nv1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT610NV1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT610NV2:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_linksys_wrt610nv2);
+               break;
+
+       case BCM47XX_BOARD_MOTOROLA_WE800G:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_we800g);
+               break;
+       case BCM47XX_BOARD_MOTOROLA_WR850GP:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_wr850gp);
+               break;
+       case BCM47XX_BOARD_MOTOROLA_WR850GV2V3:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_motorola_wr850gv2v3);
+               break;
+
+       case BCM47XX_BOARD_NETGEAR_WNDR3400V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr3400v1);
+               break;
+       case BCM47XX_BOARD_NETGEAR_WNDR3700V3:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr3700v3);
+               break;
+       case BCM47XX_BOARD_NETGEAR_WNDR4500V1:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wndr4500v1);
+               break;
+       case BCM47XX_BOARD_NETGEAR_WNR834BV2:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_netgear_wnr834bv2);
+               break;
+
+       case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE:
+               err = bcm47xx_copy_bdata(bcm47xx_buttons_simpletech_simpleshare);
+               break;
+
+       default:
+               pr_debug("No buttons configuration found for this device\n");
+               return -ENOTSUPP;
+       }
+
+       if (err)
+               return -ENOMEM;
+
+       err = platform_device_register(&bcm47xx_buttons_gpio_keys);
+       if (err) {
+               pr_err("Failed to register platform device: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
index 8cf3833b2d293626189b0d1a8f130e6fe726ae37..e0585b76ec1941228ae5e489f8e25ab1375d2fc1 100644 (file)
 #include <linux/types.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <asm/setup.h>
 #include <asm/irq_cpu.h>
 #include <bcm47xx.h>
 
-void plat_irq_dispatch(void)
+asmlinkage void plat_irq_dispatch(void)
 {
        u32 cause;
 
@@ -50,6 +51,18 @@ void plat_irq_dispatch(void)
                do_IRQ(6);
 }
 
+#define DEFINE_HWx_IRQDISPATCH(x)                                      \
+       static void bcm47xx_hw ## x ## _irqdispatch(void)               \
+       {                                                               \
+               do_IRQ(x);                                              \
+       }
+DEFINE_HWx_IRQDISPATCH(2)
+DEFINE_HWx_IRQDISPATCH(3)
+DEFINE_HWx_IRQDISPATCH(4)
+DEFINE_HWx_IRQDISPATCH(5)
+DEFINE_HWx_IRQDISPATCH(6)
+DEFINE_HWx_IRQDISPATCH(7)
+
 void __init arch_init_irq(void)
 {
 #ifdef CONFIG_BCM47XX_BCMA
@@ -64,4 +77,14 @@ void __init arch_init_irq(void)
        }
 #endif
        mips_cpu_irq_init();
+
+       if (cpu_has_vint) {
+               pr_info("Setting up vectored interrupts\n");
+               set_vi_handler(2, bcm47xx_hw2_irqdispatch);
+               set_vi_handler(3, bcm47xx_hw3_irqdispatch);
+               set_vi_handler(4, bcm47xx_hw4_irqdispatch);
+               set_vi_handler(5, bcm47xx_hw5_irqdispatch);
+               set_vi_handler(6, bcm47xx_hw6_irqdispatch);
+               set_vi_handler(7, bcm47xx_hw7_irqdispatch);
+       }
 }
diff --git a/arch/mips/bcm47xx/leds.c b/arch/mips/bcm47xx/leds.c
new file mode 100644 (file)
index 0000000..647d155
--- /dev/null
@@ -0,0 +1,542 @@
+#include "bcm47xx_private.h"
+
+#include <linux/leds.h>
+#include <bcm47xx_board.h>
+
+/**************************************************
+ * Database
+ **************************************************/
+
+#define BCM47XX_GPIO_LED(_gpio, _color, _function, _active_low,                \
+                        _default_state)                                \
+       {                                                               \
+               .name           = "bcm47xx:" _color ":" _function,      \
+               .gpio           = _gpio,                                \
+               .active_low     = _active_low,                          \
+               .default_state  = _default_state,                       \
+       }
+
+#define BCM47XX_GPIO_LED_TRIGGER(_gpio, _color, _function, _active_low,        \
+                                _default_trigger)                      \
+       {                                                               \
+               .name           = "bcm47xx:" _color ":" _function,      \
+               .gpio           = _gpio,                                \
+               .active_low     = _active_low,                          \
+               .default_state  = LEDS_GPIO_DEFSTATE_OFF,               \
+               .default_trigger        = _default_trigger,             \
+       }
+
+/* Asus */
+
+static const struct gpio_led
+bcm47xx_leds_asus_rtn12[] __initconst = {
+       BCM47XX_GPIO_LED(2, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(7, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_rtn16[] __initconst = {
+       BCM47XX_GPIO_LED(1, "blue", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(7, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_rtn66u[] __initconst = {
+       BCM47XX_GPIO_LED(12, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(15, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl300g[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl320ge[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(2, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(11, "unk", "link", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl330ge[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl500gd[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl500gpv1[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl500gpv2[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl500w[] __initconst = {
+       BCM47XX_GPIO_LED(5, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl520gc[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl520gu[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(1, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wl700ge[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON), /* Labeled "READY" (there is no "power" LED). Originally ON, flashing on USB activity. */
+};
+
+static const struct gpio_led
+bcm47xx_leds_asus_wlhdd[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(2, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Belkin */
+
+static const struct gpio_led
+bcm47xx_leds_belkin_f7d4301[] __initconst = {
+       BCM47XX_GPIO_LED(10, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(11, "amber", "power", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(12, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(13, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(14, "unk", "usb0", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(15, "unk", "usb1", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Buffalo */
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_whr2_a54g54[] __initconst = {
+       BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_whr_g125[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_whr_g54s[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_whr_hp_g54[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(2, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(3, "unk", "internal", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_wzr_g300n[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "bridge", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_wzr_rs_g54[] __initconst = {
+       BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(1, "unk", "vpn", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_buffalo_wzr_rs_g54hp[] __initconst = {
+       BCM47XX_GPIO_LED(6, "unk", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(1, "unk", "vpn", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Dell */
+
+static const struct gpio_led
+bcm47xx_leds_dell_tm2300[] __initconst = {
+       BCM47XX_GPIO_LED(6, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(7, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+/* D-Link */
+
+static const struct gpio_led
+bcm47xx_leds_dlink_dir130[] __initconst = {
+       BCM47XX_GPIO_LED_TRIGGER(0, "green", "status", 1, "timer"), /* Originally blinking when device is ready, separated from "power" LED */
+       BCM47XX_GPIO_LED(6, "blue", "unk", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_dlink_dir330[] __initconst = {
+       BCM47XX_GPIO_LED_TRIGGER(0, "green", "status", 1, "timer"), /* Originally blinking when device is ready, separated from "power" LED */
+       BCM47XX_GPIO_LED(4, "unk", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(6, "blue", "unk", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Huawei */
+
+static const struct gpio_led
+bcm47xx_leds_huawei_e970[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Linksys */
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e1000v1[] __initconst = {
+       BCM47XX_GPIO_LED(0, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(1, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(2, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(4, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e1000v21[] __initconst = {
+       BCM47XX_GPIO_LED(5, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(6, "unk", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(7, "amber", "wps", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(8, "blue", "wps", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e2000v1[] __initconst = {
+       BCM47XX_GPIO_LED(1, "blue", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(2, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(4, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e3000v1[] __initconst = {
+       BCM47XX_GPIO_LED(0, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(1, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(5, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e3200v1[] __initconst = {
+       BCM47XX_GPIO_LED(3, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_e4200v1[] __initconst = {
+       BCM47XX_GPIO_LED(5, "white", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt150nv1[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt150nv11[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt160nv1[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(5, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt160nv3[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(2, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(4, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt300nv11[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(5, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt310nv1[] __initconst = {
+       BCM47XX_GPIO_LED(1, "blue", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(3, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(9, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt610nv1[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "usb",  1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(1, "unk", "power",  0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(3, "amber", "wps",  1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(9, "blue", "wps",  1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_linksys_wrt610nv2[] __initconst = {
+       BCM47XX_GPIO_LED(0, "amber", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(1, "unk", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(3, "blue", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(5, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(7, "unk", "usb", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Motorola */
+
+static const struct gpio_led
+bcm47xx_leds_motorola_we800g[] __initconst = {
+       BCM47XX_GPIO_LED(1, "amber", "wlan", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(2, "unk", "unk", 1, LEDS_GPIO_DEFSTATE_OFF), /* There are only 3 LEDs: Power, Wireless and Device (ethernet) */
+       BCM47XX_GPIO_LED(4, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+};
+
+static const struct gpio_led
+bcm47xx_leds_motorola_wr850gp[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(6, "unk", "dmz", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_motorola_wr850gv2v3[] __initconst = {
+       BCM47XX_GPIO_LED(0, "unk", "wlan", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(1, "unk", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(7, "unk", "diag", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* Netgear */
+
+static const struct gpio_led
+bcm47xx_leds_netgear_wndr3400v1[] __initconst = {
+       BCM47XX_GPIO_LED(2, "green", "usb", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(3, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(7, "amber", "power", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_netgear_wndr4500v1[] __initconst = {
+       BCM47XX_GPIO_LED(1, "green", "wps", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(2, "green", "power", 1, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(3, "amber", "power", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(8, "green", "usb1", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(9, "green", "2ghz", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(11, "blue", "5ghz", 1, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(14, "green", "usb2", 1, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+static const struct gpio_led
+bcm47xx_leds_netgear_wnr834bv2[] __initconst = {
+       BCM47XX_GPIO_LED(2, "green", "power", 0, LEDS_GPIO_DEFSTATE_ON),
+       BCM47XX_GPIO_LED(3, "amber", "power", 0, LEDS_GPIO_DEFSTATE_OFF),
+       BCM47XX_GPIO_LED(7, "unk", "connected", 0, LEDS_GPIO_DEFSTATE_OFF),
+};
+
+/* SimpleTech */
+
+static const struct gpio_led
+bcm47xx_leds_simpletech_simpleshare[] __initconst = {
+       BCM47XX_GPIO_LED(1, "unk", "status", 1, LEDS_GPIO_DEFSTATE_OFF), /* "Ready" LED */
+};
+
+/**************************************************
+ * Init
+ **************************************************/
+
+static struct gpio_led_platform_data bcm47xx_leds_pdata;
+
+#define bcm47xx_set_pdata(dev_leds) do {                               \
+       bcm47xx_leds_pdata.leds = dev_leds;                             \
+       bcm47xx_leds_pdata.num_leds = ARRAY_SIZE(dev_leds);             \
+} while (0)
+
+void __init bcm47xx_leds_register(void)
+{
+       enum bcm47xx_board board = bcm47xx_board_get();
+
+       switch (board) {
+       case BCM47XX_BOARD_ASUS_RTN12:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_rtn12);
+               break;
+       case BCM47XX_BOARD_ASUS_RTN16:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_rtn16);
+               break;
+       case BCM47XX_BOARD_ASUS_RTN66U:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_rtn66u);
+               break;
+       case BCM47XX_BOARD_ASUS_WL300G:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl300g);
+               break;
+       case BCM47XX_BOARD_ASUS_WL320GE:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl320ge);
+               break;
+       case BCM47XX_BOARD_ASUS_WL330GE:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl330ge);
+               break;
+       case BCM47XX_BOARD_ASUS_WL500GD:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gd);
+               break;
+       case BCM47XX_BOARD_ASUS_WL500GPV1:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gpv1);
+               break;
+       case BCM47XX_BOARD_ASUS_WL500GPV2:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl500gpv2);
+               break;
+       case BCM47XX_BOARD_ASUS_WL500W:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl500w);
+               break;
+       case BCM47XX_BOARD_ASUS_WL520GC:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl520gc);
+               break;
+       case BCM47XX_BOARD_ASUS_WL520GU:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl520gu);
+               break;
+       case BCM47XX_BOARD_ASUS_WL700GE:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wl700ge);
+               break;
+       case BCM47XX_BOARD_ASUS_WLHDD:
+               bcm47xx_set_pdata(bcm47xx_leds_asus_wlhdd);
+               break;
+
+       case BCM47XX_BOARD_BELKIN_F7D4301:
+               bcm47xx_set_pdata(bcm47xx_leds_belkin_f7d4301);
+               break;
+
+       case BCM47XX_BOARD_BUFFALO_WHR2_A54G54:
+               bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr2_a54g54);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WHR_G125:
+               bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_g125);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WHR_G54S:
+               bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_g54s);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WHR_HP_G54:
+               bcm47xx_set_pdata(bcm47xx_leds_buffalo_whr_hp_g54);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WZR_G300N:
+               bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_g300n);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WZR_RS_G54:
+               bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_rs_g54);
+               break;
+       case BCM47XX_BOARD_BUFFALO_WZR_RS_G54HP:
+               bcm47xx_set_pdata(bcm47xx_leds_buffalo_wzr_rs_g54hp);
+               break;
+
+       case BCM47XX_BOARD_DELL_TM2300:
+               bcm47xx_set_pdata(bcm47xx_leds_dell_tm2300);
+               break;
+
+       case BCM47XX_BOARD_DLINK_DIR130:
+               bcm47xx_set_pdata(bcm47xx_leds_dlink_dir130);
+               break;
+       case BCM47XX_BOARD_DLINK_DIR330:
+               bcm47xx_set_pdata(bcm47xx_leds_dlink_dir330);
+               break;
+
+       case BCM47XX_BOARD_HUAWEI_E970:
+               bcm47xx_set_pdata(bcm47xx_leds_huawei_e970);
+               break;
+
+       case BCM47XX_BOARD_LINKSYS_E1000V1:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_e1000v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E1000V21:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_e1000v21);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E2000V1:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_e2000v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E3000V1:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_e3000v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E3200V1:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_e3200v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_E4200V1:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_e4200v1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT150NV1:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt150nv1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT150NV11:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt150nv11);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT160NV1:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt160nv1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT160NV3:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt160nv3);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT300NV11:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt300nv11);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT310NV1:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt310nv1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT610NV1:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv1);
+               break;
+       case BCM47XX_BOARD_LINKSYS_WRT610NV2:
+               bcm47xx_set_pdata(bcm47xx_leds_linksys_wrt610nv2);
+               break;
+
+       case BCM47XX_BOARD_MOTOROLA_WE800G:
+               bcm47xx_set_pdata(bcm47xx_leds_motorola_we800g);
+               break;
+       case BCM47XX_BOARD_MOTOROLA_WR850GP:
+               bcm47xx_set_pdata(bcm47xx_leds_motorola_wr850gp);
+               break;
+       case BCM47XX_BOARD_MOTOROLA_WR850GV2V3:
+               bcm47xx_set_pdata(bcm47xx_leds_motorola_wr850gv2v3);
+               break;
+
+       case BCM47XX_BOARD_NETGEAR_WNDR3400V1:
+               bcm47xx_set_pdata(bcm47xx_leds_netgear_wndr3400v1);
+               break;
+       case BCM47XX_BOARD_NETGEAR_WNDR4500V1:
+               bcm47xx_set_pdata(bcm47xx_leds_netgear_wndr4500v1);
+               break;
+       case BCM47XX_BOARD_NETGEAR_WNR834BV2:
+               bcm47xx_set_pdata(bcm47xx_leds_netgear_wnr834bv2);
+               break;
+
+       case BCM47XX_BOARD_SIMPLETECH_SIMPLESHARE:
+               bcm47xx_set_pdata(bcm47xx_leds_simpletech_simpleshare);
+               break;
+
+       default:
+               pr_debug("No LEDs configuration found for this device\n");
+               return;
+       }
+
+       gpio_led_register_device(-1, &bcm47xx_leds_pdata);
+}
index b4c585b1c62eb6279504daea7e1f3a2e7d0b777d..6decb27cf48b4343e9358283775f82df82ed0aa5 100644 (file)
@@ -11,7 +11,6 @@
  * option) any later version.
  */
 
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/ssb/ssb.h>
 #include <asm/mach-bcm47xx/bcm47xx.h>
 
 static char nvram_buf[NVRAM_SPACE];
+static const u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
 
 static u32 find_nvram_size(u32 end)
 {
        struct nvram_header *header;
-       u32 nvram_sizes[] = {0x8000, 0xF000, 0x10000};
        int i;
 
        for (i = 0; i < ARRAY_SIZE(nvram_sizes); i++) {
index 5cba318bc1cd8e1ce32a8535ecbf79acf1000bf5..0af808dfd1ca778fdf95022bf4a6b93e561334ad 100644 (file)
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
+#include <linux/ssb/ssb_driver_chipcommon.h>
+#include <linux/ssb/ssb_regs.h>
 #include <linux/smp.h>
 #include <asm/bootinfo.h>
-#include <asm/fw/cfe/cfe_api.h>
-#include <asm/fw/cfe/cfe_error.h>
 #include <bcm47xx.h>
 #include <bcm47xx_board.h>
 
-static int cfe_cons_handle;
 
-static u16 get_chip_id(void)
-{
-       switch (bcm47xx_bus_type) {
-#ifdef CONFIG_BCM47XX_SSB
-       case BCM47XX_BUS_TYPE_SSB:
-               return bcm47xx_bus.ssb.chip_id;
-#endif
-#ifdef CONFIG_BCM47XX_BCMA
-       case BCM47XX_BUS_TYPE_BCMA:
-               return bcm47xx_bus.bcma.bus.chipinfo.id;
-#endif
-       }
-       return 0;
-}
+static char bcm47xx_system_type[20] = "Broadcom BCM47XX";
 
 const char *get_system_type(void)
 {
-       static char buf[50];
-       u16 chip_id = get_chip_id();
-
-       snprintf(buf, sizeof(buf),
-                (chip_id > 0x9999) ? "Broadcom BCM%d (%s)" :
-                                     "Broadcom BCM%04X (%s)",
-                chip_id, bcm47xx_board_get_name());
-
-       return buf;
-}
-
-void prom_putchar(char c)
-{
-       while (cfe_write(cfe_cons_handle, &c, 1) == 0)
-               ;
+       return bcm47xx_system_type;
 }
 
-static __init void prom_init_cfe(void)
+__init void bcm47xx_set_system_type(u16 chip_id)
 {
-       uint32_t cfe_ept;
-       uint32_t cfe_handle;
-       uint32_t cfe_eptseal;
-       int argc = fw_arg0;
-       char **envp = (char **) fw_arg2;
-       int *prom_vec = (int *) fw_arg3;
-
-       /*
-        * Check if a loader was used; if NOT, the 4 arguments are
-        * what CFE gives us (handle, 0, EPT and EPTSEAL)
-        */
-       if (argc < 0) {
-               cfe_handle = (uint32_t)argc;
-               cfe_ept = (uint32_t)envp;
-               cfe_eptseal = (uint32_t)prom_vec;
-       } else {
-               if ((int)prom_vec < 0) {
-                       /*
-                        * Old loader; all it gives us is the handle,
-                        * so use the "known" entrypoint and assume
-                        * the seal.
-                        */
-                       cfe_handle = (uint32_t)prom_vec;
-                       cfe_ept = 0xBFC00500;
-                       cfe_eptseal = CFE_EPTSEAL;
-               } else {
-                       /*
-                        * Newer loaders bundle the handle/ept/eptseal
-                        * Note: prom_vec is in the loader's useg
-                        * which is still alive in the TLB.
-                        */
-                       cfe_handle = prom_vec[0];
-                       cfe_ept = prom_vec[2];
-                       cfe_eptseal = prom_vec[3];
-               }
-       }
-
-       if (cfe_eptseal != CFE_EPTSEAL) {
-               /* too early for panic to do any good */
-               printk(KERN_ERR "CFE's entrypoint seal doesn't match.");
-               while (1) ;
-       }
-
-       cfe_init(cfe_handle, cfe_ept);
-}
-
-static __init void prom_init_console(void)
-{
-       /* Initialize CFE console */
-       cfe_cons_handle = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE);
-}
-
-static __init void prom_init_cmdline(void)
-{
-       static char buf[COMMAND_LINE_SIZE] __initdata;
-
-       /* Get the kernel command line from CFE */
-       if (cfe_getenv("LINUX_CMDLINE", buf, COMMAND_LINE_SIZE) >= 0) {
-               buf[COMMAND_LINE_SIZE - 1] = 0;
-               strcpy(arcs_cmdline, buf);
-       }
-
-       /* Force a console handover by adding a console= argument if needed,
-        * as CFE is not available anymore later in the boot process. */
-       if ((strstr(arcs_cmdline, "console=")) == NULL) {
-               /* Try to read the default serial port used by CFE */
-               if ((cfe_getenv("BOOT_CONSOLE", buf, COMMAND_LINE_SIZE) < 0)
-                   || (strncmp("uart", buf, 4)))
-                       /* Default to uart0 */
-                       strcpy(buf, "uart0");
-
-               /* Compute the new command line */
-               snprintf(arcs_cmdline, COMMAND_LINE_SIZE, "%s console=ttyS%c,115200",
-                        arcs_cmdline, buf[4]);
-       }
+       snprintf(bcm47xx_system_type, sizeof(bcm47xx_system_type),
+                (chip_id > 0x9999) ? "Broadcom BCM%d" :
+                                     "Broadcom BCM%04X",
+                chip_id);
 }
 
 static __init void prom_init_mem(void)
@@ -195,12 +96,16 @@ static __init void prom_init_mem(void)
        add_memory_region(0, mem, BOOT_MEM_RAM);
 }
 
+/*
+ * This is the first serial on the chip common core, it is at this position
+ * for sb (ssb) and ai (bcma) bus.
+ */
+#define BCM47XX_SERIAL_ADDR (SSB_ENUM_BASE + SSB_CHIPCO_UART0_DATA)
+
 void __init prom_init(void)
 {
-       prom_init_cfe();
-       prom_init_console();
-       prom_init_cmdline();
        prom_init_mem();
+       setup_8250_early_printk_port(CKSEG1ADDR(BCM47XX_SERIAL_ADDR), 0, 0);
 }
 
 void __init prom_free_prom_memory(void)
index b8ef965705cf6ca4b7ceb890528d63e5236fb34e..2f5bbd68e9a0b7f3fe475953c4b212f3f07dc41e 100644 (file)
@@ -31,7 +31,8 @@ static int __init uart8250_init_ssb(void)
 
        memset(&uart8250_data, 0,  sizeof(uart8250_data));
 
-       for (i = 0; i < mcore->nr_serial_ports; i++) {
+       for (i = 0; i < mcore->nr_serial_ports &&
+                   i < ARRAY_SIZE(uart8250_data) - 1; i++) {
                struct plat_serial8250_port *p = &(uart8250_data[i]);
                struct ssb_serial_port *ssb_port = &(mcore->serial_ports[i]);
 
@@ -55,7 +56,8 @@ static int __init uart8250_init_bcma(void)
 
        memset(&uart8250_data, 0,  sizeof(uart8250_data));
 
-       for (i = 0; i < cc->nr_serial_ports; i++) {
+       for (i = 0; i < cc->nr_serial_ports &&
+                   i < ARRAY_SIZE(uart8250_data) - 1; i++) {
                struct plat_serial8250_port *p = &(uart8250_data[i]);
                struct bcma_serial_port *bcma_port;
                bcma_port = &(cc->serial_ports[i]);
index 9057728ac56b4cfa2130b122f2130df966ca7275..025be218ea1518bebfac47c2ec2cef514fff4e83 100644 (file)
@@ -26,6 +26,8 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
+#include "bcm47xx_private.h"
+
 #include <linux/export.h>
 #include <linux/types.h>
 #include <linux/ethtool.h>
@@ -35,6 +37,8 @@
 #include <linux/ssb/ssb_embedded.h>
 #include <linux/bcma/bcma_soc.h>
 #include <asm/bootinfo.h>
+#include <asm/idle.h>
+#include <asm/prom.h>
 #include <asm/reboot.h>
 #include <asm/time.h>
 #include <bcm47xx.h>
@@ -213,12 +217,14 @@ void __init plat_mem_setup(void)
 #ifdef CONFIG_BCM47XX_BCMA
                bcm47xx_bus_type = BCM47XX_BUS_TYPE_BCMA;
                bcm47xx_register_bcma();
+               bcm47xx_set_system_type(bcm47xx_bus.bcma.bus.chipinfo.id);
 #endif
        } else {
                printk(KERN_INFO "bcm47xx: using ssb bus\n");
 #ifdef CONFIG_BCM47XX_SSB
                bcm47xx_bus_type = BCM47XX_BUS_TYPE_SSB;
                bcm47xx_register_ssb();
+               bcm47xx_set_system_type(bcm47xx_bus.ssb.chip_id);
 #endif
        }
 
@@ -226,8 +232,34 @@ void __init plat_mem_setup(void)
        _machine_halt = bcm47xx_machine_halt;
        pm_power_off = bcm47xx_machine_halt;
        bcm47xx_board_detect();
+       mips_set_machine_name(bcm47xx_board_get_name());
 }
 
+static int __init bcm47xx_cpu_fixes(void)
+{
+       switch (bcm47xx_bus_type) {
+#ifdef CONFIG_BCM47XX_SSB
+       case BCM47XX_BUS_TYPE_SSB:
+               /* Nothing to do */
+               break;
+#endif
+#ifdef CONFIG_BCM47XX_BCMA
+       case BCM47XX_BUS_TYPE_BCMA:
+               /* The BCM4706 has a problem with the CPU wait instruction.
+                * When r4k_wait or r4k_wait_irqoff is used will just hang and
+                * not return from a msleep(). Removing the cpu_wait
+                * functionality is a workaround for this problem. The BCM4716
+                * does not have this problem.
+                */
+               if (bcm47xx_bus.bcma.bus.chipinfo.id == BCMA_CHIP_ID_BCM4706)
+                       cpu_wait = NULL;
+               break;
+#endif
+       }
+       return 0;
+}
+arch_initcall(bcm47xx_cpu_fixes);
+
 static struct fixed_phy_status bcm47xx_fixed_phy_status __initdata = {
        .link   = 1,
        .speed  = SPEED_100,
@@ -248,6 +280,9 @@ static int __init bcm47xx_register_bus_complete(void)
                break;
 #endif
        }
+       bcm47xx_buttons_register();
+       bcm47xx_leds_register();
+
        fixed_phy_add(PHY_POLL, 0, &bcm47xx_fixed_phy_status);
        return 0;
 }
index ad03c931b90557658bc904c81a2c8990285dabea..a8b5408dd3495f48a19a7ad35ddca3b5724d6005 100644 (file)
@@ -135,7 +135,7 @@ static void nvram_read_leddc(const char *prefix, const char *name,
 }
 
 static void nvram_read_macaddr(const char *prefix, const char *name,
-                              u8 (*val)[6], bool fallback)
+                              u8 val[6], bool fallback)
 {
        char buf[100];
        int err;
@@ -144,11 +144,11 @@ static void nvram_read_macaddr(const char *prefix, const char *name,
        if (err < 0)
                return;
 
-       bcm47xx_nvram_parse_macaddr(buf, *val);
+       bcm47xx_nvram_parse_macaddr(buf, val);
 }
 
 static void nvram_read_alpha2(const char *prefix, const char *name,
-                            char (*val)[2], bool fallback)
+                            char val[2], bool fallback)
 {
        char buf[10];
        int err;
@@ -162,7 +162,7 @@ static void nvram_read_alpha2(const char *prefix, const char *name,
                pr_warn("alpha2 is too long %s\n", buf);
                return;
        }
-       memcpy(val, buf, sizeof(val));
+       memcpy(val, buf, 2);
 }
 
 static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,
@@ -180,7 +180,7 @@ static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,
                      fallback);
        nvram_read_s8(prefix, NULL, "ag1", &sprom->antenna_gain.a1, 0,
                      fallback);
-       nvram_read_alpha2(prefix, "ccode", &sprom->alpha2, fallback);
+       nvram_read_alpha2(prefix, "ccode", sprom->alpha2, fallback);
 }
 
 static void bcm47xx_fill_sprom_r12389(struct ssb_sprom *sprom,
@@ -633,20 +633,20 @@ static void bcm47xx_fill_sprom_path_r45(struct ssb_sprom *sprom,
 static void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom,
                                        const char *prefix, bool fallback)
 {
-       nvram_read_macaddr(prefix, "et0macaddr", &sprom->et0mac, fallback);
+       nvram_read_macaddr(prefix, "et0macaddr", sprom->et0mac, fallback);
        nvram_read_u8(prefix, NULL, "et0mdcport", &sprom->et0mdcport, 0,
                      fallback);
        nvram_read_u8(prefix, NULL, "et0phyaddr", &sprom->et0phyaddr, 0,
                      fallback);
 
-       nvram_read_macaddr(prefix, "et1macaddr", &sprom->et1mac, fallback);
+       nvram_read_macaddr(prefix, "et1macaddr", sprom->et1mac, fallback);
        nvram_read_u8(prefix, NULL, "et1mdcport", &sprom->et1mdcport, 0,
                      fallback);
        nvram_read_u8(prefix, NULL, "et1phyaddr", &sprom->et1phyaddr, 0,
                      fallback);
 
-       nvram_read_macaddr(prefix, "macaddr", &sprom->il0mac, fallback);
-       nvram_read_macaddr(prefix, "il0macaddr", &sprom->il0mac, fallback);
+       nvram_read_macaddr(prefix, "macaddr", sprom->il0mac, fallback);
+       nvram_read_macaddr(prefix, "il0macaddr", sprom->il0mac, fallback);
 }
 
 static void bcm47xx_fill_board_data(struct ssb_sprom *sprom, const char *prefix,
diff --git a/arch/mips/bcm47xx/wgt634u.c b/arch/mips/bcm47xx/wgt634u.c
deleted file mode 100644 (file)
index c63a4c2..0000000
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * This file is subject to the terms and conditions of the GNU General Public
- * License.  See the file "COPYING" in the main directory of this archive
- * for more details.
- *
- * Copyright (C) 2007 Aurelien Jarno <aurelien@aurel32.net>
- */
-
-#include <linux/platform_device.h>
-#include <linux/module.h>
-#include <linux/leds.h>
-#include <linux/mtd/physmap.h>
-#include <linux/ssb/ssb.h>
-#include <linux/ssb/ssb_embedded.h>
-#include <linux/interrupt.h>
-#include <linux/reboot.h>
-#include <linux/gpio.h>
-#include <asm/mach-bcm47xx/bcm47xx.h>
-
-/* GPIO definitions for the WGT634U */
-#define WGT634U_GPIO_LED       3
-#define WGT634U_GPIO_RESET     2
-#define WGT634U_GPIO_TP1       7
-#define WGT634U_GPIO_TP2       6
-#define WGT634U_GPIO_TP3       5
-#define WGT634U_GPIO_TP4       4
-#define WGT634U_GPIO_TP5       1
-
-static struct gpio_led wgt634u_leds[] = {
-       {
-               .name = "power",
-               .gpio = WGT634U_GPIO_LED,
-               .active_low = 1,
-               .default_trigger = "heartbeat",
-       },
-};
-
-static struct gpio_led_platform_data wgt634u_led_data = {
-       .num_leds =     ARRAY_SIZE(wgt634u_leds),
-       .leds =         wgt634u_leds,
-};
-
-static struct platform_device wgt634u_gpio_leds = {
-       .name =         "leds-gpio",
-       .id =           -1,
-       .dev = {
-               .platform_data = &wgt634u_led_data,
-       }
-};
-
-
-/* 8MiB flash. The struct mtd_partition matches original Netgear WGT634U
-   firmware. */
-static struct mtd_partition wgt634u_partitions[] = {
-       {
-               .name       = "cfe",
-               .offset     = 0,
-               .size       = 0x60000,          /* 384k */
-               .mask_flags = MTD_WRITEABLE     /* force read-only */
-       },
-       {
-               .name   = "config",
-               .offset = 0x60000,
-               .size   = 0x20000               /* 128k */
-       },
-       {
-               .name   = "linux",
-               .offset = 0x80000,
-               .size   = 0x140000              /* 1280k */
-       },
-       {
-               .name   = "jffs",
-               .offset = 0x1c0000,
-               .size   = 0x620000              /* 6272k */
-       },
-       {
-               .name   = "nvram",
-               .offset = 0x7e0000,
-               .size   = 0x20000               /* 128k */
-       },
-};
-
-static struct physmap_flash_data wgt634u_flash_data = {
-       .parts    = wgt634u_partitions,
-       .nr_parts = ARRAY_SIZE(wgt634u_partitions)
-};
-
-static struct resource wgt634u_flash_resource = {
-       .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device wgt634u_flash = {
-       .name          = "physmap-flash",
-       .id            = 0,
-       .dev           = { .platform_data = &wgt634u_flash_data, },
-       .resource      = &wgt634u_flash_resource,
-       .num_resources = 1,
-};
-
-/* Platform devices */
-static struct platform_device *wgt634u_devices[] __initdata = {
-       &wgt634u_flash,
-       &wgt634u_gpio_leds,
-};
-
-static irqreturn_t gpio_interrupt(int irq, void *ignored)
-{
-       int state;
-
-       /* Interrupts are shared, check if the current one is
-          a GPIO interrupt. */
-       if (!ssb_chipco_irq_status(&bcm47xx_bus.ssb.chipco,
-                                  SSB_CHIPCO_IRQ_GPIO))
-               return IRQ_NONE;
-
-       state = gpio_get_value(WGT634U_GPIO_RESET);
-
-       /* Interrupt are level triggered, revert the interrupt polarity
-          to clear the interrupt. */
-       ssb_gpio_polarity(&bcm47xx_bus.ssb, 1 << WGT634U_GPIO_RESET,
-                         state ? 1 << WGT634U_GPIO_RESET : 0);
-
-       if (!state) {
-               printk(KERN_INFO "Reset button pressed");
-               ctrl_alt_del();
-       }
-
-       return IRQ_HANDLED;
-}
-
-static int __init wgt634u_init(void)
-{
-       /* There is no easy way to detect that we are running on a WGT634U
-        * machine. Use the MAC address as an heuristic. Netgear Inc. has
-        * been allocated ranges 00:09:5b:xx:xx:xx and 00:0f:b5:xx:xx:xx.
-        */
-       u8 *et0mac;
-
-       if (bcm47xx_bus_type != BCM47XX_BUS_TYPE_SSB)
-               return -ENODEV;
-
-       et0mac = bcm47xx_bus.ssb.sprom.et0mac;
-
-       if (et0mac[0] == 0x00 &&
-           ((et0mac[1] == 0x09 && et0mac[2] == 0x5b) ||
-            (et0mac[1] == 0x0f && et0mac[2] == 0xb5))) {
-               struct ssb_mipscore *mcore = &bcm47xx_bus.ssb.mipscore;
-
-               printk(KERN_INFO "WGT634U machine detected.\n");
-
-               if (!request_irq(gpio_to_irq(WGT634U_GPIO_RESET),
-                                gpio_interrupt, IRQF_SHARED,
-                                "WGT634U GPIO", &bcm47xx_bus.ssb.chipco)) {
-                       gpio_direction_input(WGT634U_GPIO_RESET);
-                       ssb_gpio_intmask(&bcm47xx_bus.ssb,
-                                        1 << WGT634U_GPIO_RESET,
-                                        1 << WGT634U_GPIO_RESET);
-                       ssb_chipco_irq_mask(&bcm47xx_bus.ssb.chipco,
-                                           SSB_CHIPCO_IRQ_GPIO,
-                                           SSB_CHIPCO_IRQ_GPIO);
-               }
-
-               wgt634u_flash_data.width = mcore->pflash.buswidth;
-               wgt634u_flash_resource.start = mcore->pflash.window;
-               wgt634u_flash_resource.end = mcore->pflash.window
-                                          + mcore->pflash.window_size
-                                          - 1;
-               return platform_add_devices(wgt634u_devices,
-                                           ARRAY_SIZE(wgt634u_devices));
-       } else
-               return -ENODEV;
-}
-
-module_init(wgt634u_init);
index b78306ce56c73b5dc3cf4d083bdb3185b2ed52e7..a057fdf111c6c3f233f02c8fc2fbb7ebd7823880 100644 (file)
@@ -3,33 +3,41 @@ menu "CPU support"
 
 config BCM63XX_CPU_3368
        bool "support 3368 CPU"
+       select SYS_HAS_CPU_BMIPS4350
        select HW_HAS_PCI
 
 config BCM63XX_CPU_6328
        bool "support 6328 CPU"
+       select SYS_HAS_CPU_BMIPS4350
        select HW_HAS_PCI
 
 config BCM63XX_CPU_6338
        bool "support 6338 CPU"
+       select SYS_HAS_CPU_BMIPS32_3300
        select HW_HAS_PCI
 
 config BCM63XX_CPU_6345
        bool "support 6345 CPU"
+       select SYS_HAS_CPU_BMIPS32_3300
 
 config BCM63XX_CPU_6348
        bool "support 6348 CPU"
+       select SYS_HAS_CPU_BMIPS32_3300
        select HW_HAS_PCI
 
 config BCM63XX_CPU_6358
        bool "support 6358 CPU"
+       select SYS_HAS_CPU_BMIPS4350
        select HW_HAS_PCI
 
 config BCM63XX_CPU_6362
        bool "support 6362 CPU"
+       select SYS_HAS_CPU_BMIPS4350
        select HW_HAS_PCI
 
 config BCM63XX_CPU_6368
        bool "support 6368 CPU"
+       select SYS_HAS_CPU_BMIPS4350
        select HW_HAS_PCI
 endmenu
 
index ac2807397c1c8c80be2d525eeb8cc5307ff7c406..9019f54aee69feee4dde1471d8bbfaf72a8126ab 100644 (file)
@@ -1,7 +1,7 @@
 obj-y          += clk.o cpu.o cs.o gpio.o irq.o nvram.o prom.o reset.o \
                   setup.o timer.o dev-dsp.o dev-enet.o dev-flash.o \
-                  dev-pcmcia.o dev-rng.o dev-spi.o dev-uart.o dev-wdt.o \
-                  dev-usb-usbd.o
+                  dev-pcmcia.o dev-rng.o dev-spi.o dev-hsspi.o dev-uart.o \
+                  dev-wdt.o dev-usb-usbd.o
 obj-$(CONFIG_EARLY_PRINTK)     += early_printk.o
 
 obj-y          += boards/
index 5b974eb125fcee5f3ec2c034db14cb564a63f2f8..33727e7f0c79f756a004dc4d5fd964b31b3d6058 100644 (file)
@@ -23,6 +23,7 @@
 #include <bcm63xx_dev_enet.h>
 #include <bcm63xx_dev_dsp.h>
 #include <bcm63xx_dev_flash.h>
+#include <bcm63xx_dev_hsspi.h>
 #include <bcm63xx_dev_pcmcia.h>
 #include <bcm63xx_dev_spi.h>
 #include <bcm63xx_dev_usb_usbd.h>
@@ -915,6 +916,8 @@ int __init board_register_devices(void)
 
        bcm63xx_spi_register();
 
+       bcm63xx_hsspi_register();
+
        bcm63xx_flash_register();
 
        bcm63xx_led_data.num_leds = ARRAY_SIZE(board.leds);
index 43da4ae04cc248f4a94f5e79ee2c07f434988ef6..637565284732d396354b5a1eb056bb74e2703380 100644 (file)
@@ -225,6 +225,28 @@ static struct clk clk_spi = {
        .set    = spi_set,
 };
 
+/*
+ * HSSPI clock
+ */
+static void hsspi_set(struct clk *clk, int enable)
+{
+       u32 mask;
+
+       if (BCMCPU_IS_6328())
+               mask = CKCTL_6328_HSSPI_EN;
+       else if (BCMCPU_IS_6362())
+               mask = CKCTL_6362_HSSPI_EN;
+       else
+               return;
+
+       bcm_hwclock_set(mask, enable);
+}
+
+static struct clk clk_hsspi = {
+       .set    = hsspi_set,
+};
+
+
 /*
  * XTM clock
  */
@@ -346,6 +368,8 @@ struct clk *clk_get(struct device *dev, const char *id)
                return &clk_usbd;
        if (!strcmp(id, "spi"))
                return &clk_spi;
+       if (!strcmp(id, "hsspi"))
+               return &clk_hsspi;
        if (!strcmp(id, "xtm"))
                return &clk_xtm;
        if (!strcmp(id, "periph"))
@@ -366,3 +390,21 @@ void clk_put(struct clk *clk)
 }
 
 EXPORT_SYMBOL(clk_put);
+
+#define HSSPI_PLL_HZ_6328      133333333
+#define HSSPI_PLL_HZ_6362      400000000
+
+static int __init bcm63xx_clk_init(void)
+{
+       switch (bcm63xx_get_cpu_id()) {
+       case BCM6328_CPU_ID:
+               clk_hsspi.rate = HSSPI_PLL_HZ_6328;
+               break;
+       case BCM6362_CPU_ID:
+               clk_hsspi.rate = HSSPI_PLL_HZ_6362;
+               break;
+       }
+
+       return 0;
+}
+arch_initcall(bcm63xx_clk_init);
index b713cd64b08740f083f2a25026ee063f8ae5cfdd..1b1b8a89959bb1f3998726f83675de7f9cde0784 100644 (file)
@@ -123,7 +123,9 @@ unsigned int bcm63xx_get_memory_size(void)
 
 static unsigned int detect_cpu_clock(void)
 {
-       switch (bcm63xx_get_cpu_id()) {
+       u16 cpu_id = bcm63xx_get_cpu_id();
+
+       switch (cpu_id) {
        case BCM3368_CPU_ID:
                return 300000000;
 
@@ -249,7 +251,7 @@ static unsigned int detect_cpu_clock(void)
        }
 
        default:
-               BUG();
+               panic("Failed to detect clock for CPU with id=%04X\n", cpu_id);
        }
 }
 
diff --git a/arch/mips/bcm63xx/dev-hsspi.c b/arch/mips/bcm63xx/dev-hsspi.c
new file mode 100644 (file)
index 0000000..696abc4
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2012 Jonas Gorski <jonas.gorski@gmail.com>
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include <bcm63xx_cpu.h>
+#include <bcm63xx_dev_hsspi.h>
+#include <bcm63xx_regs.h>
+
+static struct resource spi_resources[] = {
+       {
+               .start          = -1, /* filled at runtime */
+               .end            = -1, /* filled at runtime */
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = -1, /* filled at runtime */
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device bcm63xx_hsspi_device = {
+       .name           = "bcm63xx-hsspi",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(spi_resources),
+       .resource       = spi_resources,
+};
+
+int __init bcm63xx_hsspi_register(void)
+{
+       if (!BCMCPU_IS_6328() && !BCMCPU_IS_6362())
+               return -ENODEV;
+
+       spi_resources[0].start = bcm63xx_regset_address(RSET_HSSPI);
+       spi_resources[0].end = spi_resources[0].start;
+       spi_resources[0].end += RSET_HSSPI_SIZE - 1;
+       spi_resources[1].start = bcm63xx_get_irq_number(IRQ_HSSPI);
+
+       return platform_device_register(&bcm63xx_hsspi_device);
+}
index aa8f7f9cc7a4b6c8783b97253c2bea11d7bc6921..6092226a6d766e07bb4f5bc9ae47a0be341de6e7 100644 (file)
@@ -6,9 +6,8 @@
  * Copyright (C) 2008 Maxime Bizon <mbizon@freebox.fr>
  */
 
-#include <linux/init.h>
 #include <bcm63xx_io.h>
-#include <bcm63xx_regs.h>
+#include <linux/serial_bcm63xx.h>
 
 static void wait_xfered(void)
 {
index 8ac4e095e68e24b2ba3b43ba8ecc4d07e298557e..e1f27d653f603d17413b04aa0e9f540f10cf504a 100644 (file)
@@ -59,14 +59,12 @@ void __init prom_init(void)
        /* do low level board init */
        board_prom_init();
 
-       if (IS_ENABLED(CONFIG_CPU_BMIPS4350) && IS_ENABLED(CONFIG_SMP)) {
-               /* set up SMP */
-               register_smp_ops(&bmips_smp_ops);
-
+       /* set up SMP */
+       if (!register_bmips_smp_ops()) {
                /*
-                * BCM6328 might not have its second CPU enabled, while BCM6358
-                * needs special handling for its shared TLB, so disable SMP
-                * for now.
+                * BCM6328 might not have its second CPU enabled, while BCM3368
+                * and BCM6358 need special handling for their shared TLB, so
+                * disable SMP for now.
                 */
                if (BCMCPU_IS_6328()) {
                        reg = bcm_readl(BCM_6328_OTP_BASE +
@@ -74,7 +72,7 @@ void __init prom_init(void)
 
                        if (reg & OTP_6328_REG3_TP1_DISABLED)
                                bmips_smp_enabled = 0;
-               } else if (BCMCPU_IS_6358()) {
+               } else if (BCMCPU_IS_3368() || BCMCPU_IS_6358()) {
                        bmips_smp_enabled = 0;
                }
 
index ca0c343c9ea5ed024b87a5e314b4118d9ecff04e..61af6b6ab13da251df276d72a3e8322aa4ccfcca 100644 (file)
@@ -27,10 +27,10 @@ KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
        -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
        -DKERNEL_ENTRY=$(VMLINUX_ENTRY_ADDRESS)
 
-targets := head.o decompress.o dbg.o uart-16550.o uart-alchemy.o
+targets := head.o decompress.o string.o dbg.o uart-16550.o uart-alchemy.o
 
 # decompressor objects (linked with vmlinuz)
-vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/dbg.o
+vmlinuzobjs-y := $(obj)/head.o $(obj)/decompress.o $(obj)/string.o $(obj)/dbg.o
 
 ifdef CONFIG_DEBUG_ZBOOT
 vmlinuzobjs-$(CONFIG_SYS_SUPPORTS_ZBOOT_UART16550) += $(obj)/uart-16550.o
index 134a6162e39413679609450387aa2f692eb3a9ce..06c6a5bd175d97ebb463d159836951f7fffd8f84 100644 (file)
@@ -6,7 +6,6 @@
  * need to implement your own putc().
  */
 #include <linux/compiler.h>
-#include <linux/init.h>
 #include <linux/types.h>
 
 void __weak putc(char c)
index a8c6fd6a440667cf58c35d4655862783de7d271f..c00c4ddf45148133a0cb1c405e9aefb17ea57c3f 100644 (file)
@@ -43,33 +43,11 @@ void error(char *x)
 /* activate the code for pre-boot environment */
 #define STATIC static
 
-#if defined(CONFIG_KERNEL_GZIP) || defined(CONFIG_KERNEL_XZ) || \
-       defined(CONFIG_KERNEL_LZ4)
-void *memcpy(void *dest, const void *src, size_t n)
-{
-       int i;
-       const char *s = src;
-       char *d = dest;
-
-       for (i = 0; i < n; i++)
-               d[i] = s[i];
-       return dest;
-}
-#endif
 #ifdef CONFIG_KERNEL_GZIP
 #include "../../../../lib/decompress_inflate.c"
 #endif
 
 #ifdef CONFIG_KERNEL_BZIP2
-void *memset(void *s, int c, size_t n)
-{
-       int i;
-       char *ss = s;
-
-       for (i = 0; i < n; i++)
-               ss[i] = c;
-       return s;
-}
 #include "../../../../lib/decompress_bunzip2.c"
 #endif
 
diff --git a/arch/mips/boot/compressed/string.c b/arch/mips/boot/compressed/string.c
new file mode 100644 (file)
index 0000000..9de9885
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * arch/mips/boot/compressed/string.c
+ *
+ * Very small subset of simple string routines
+ */
+
+#include <linux/types.h>
+
+void *memcpy(void *dest, const void *src, size_t n)
+{
+       int i;
+       const char *s = src;
+       char *d = dest;
+
+       for (i = 0; i < n; i++)
+               d[i] = s[i];
+       return dest;
+}
+
+void *memset(void *s, int c, size_t n)
+{
+       int i;
+       char *ss = s;
+
+       for (i = 0; i < n; i++)
+               ss[i] = c;
+       return s;
+}
index c01d343ce6add9d6049cdcabae281c9d03d401b5..237494b7a21afcc0b7c10e77e5fdc07ca880477c 100644 (file)
@@ -4,7 +4,6 @@
 
 #include <linux/types.h>
 #include <linux/serial_reg.h>
-#include <linux/init.h>
 
 #include <asm/addrspace.h>
 
@@ -19,8 +18,8 @@
 #endif
 
 #ifdef CONFIG_MACH_JZ4740
-#define UART0_BASE  0xB0030000
-#define PORT(offset) (UART0_BASE + (4 * offset))
+#include <asm/mach-jz4740/base.h>
+#define PORT(offset) (CKSEG1ADDR(JZ4740_UART0_BASE_ADDR) + (4 * offset))
 #endif
 
 #ifdef CONFIG_CPU_XLR
index 132bccc66a93654e50fb03c77c9de125434f385c..8241fc6aa17d8668c21373febf27960e8b495e57 100644 (file)
@@ -47,6 +47,7 @@
  * state. It points to a bootmem named block.
  */
 __cvmx_cmd_queue_all_state_t *__cvmx_cmd_queue_state_ptr;
+EXPORT_SYMBOL_GPL(__cvmx_cmd_queue_state_ptr);
 
 /**
  * Initialize the Global queue state pointer.
index 0a1283ce47f549d2fa8be1df16d42a83c8bc3ffd..b764df64be4093bf1c211ed77897fa0484f3eb5d 100644 (file)
@@ -722,3 +722,30 @@ int __cvmx_helper_board_hardware_enable(int interface)
        }
        return 0;
 }
+
+/**
+ * Get the clock type used for the USB block based on board type.
+ * Used by the USB code for auto configuration of clock type.
+ *
+ * Return USB clock type enumeration
+ */
+enum cvmx_helper_board_usb_clock_types __cvmx_helper_board_usb_get_clock_type(void)
+{
+       switch (cvmx_sysinfo_get()->board_type) {
+       case CVMX_BOARD_TYPE_BBGW_REF:
+       case CVMX_BOARD_TYPE_LANAI2_A:
+       case CVMX_BOARD_TYPE_LANAI2_U:
+       case CVMX_BOARD_TYPE_LANAI2_G:
+       case CVMX_BOARD_TYPE_NIC10E_66:
+       case CVMX_BOARD_TYPE_UBNT_E100:
+               return USB_CLOCK_TYPE_CRYSTAL_12;
+       case CVMX_BOARD_TYPE_NIC10E:
+               return USB_CLOCK_TYPE_REF_12;
+       default:
+               break;
+       }
+       /* Most boards except NIC10e use a 12MHz crystal */
+       if (OCTEON_IS_MODEL(OCTEON_FAM_2))
+               return USB_CLOCK_TYPE_CRYSTAL_12;
+       return USB_CLOCK_TYPE_REF_48;
+}
index 65d2bc9a0bde4a4d4f9f8129a2fe79f67e71a550..453d7f66459aabd517990dd4e0efdf07fd679f2d 100644 (file)
@@ -251,6 +251,7 @@ int cvmx_helper_setup_red(int pass_thresh, int drop_thresh)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_setup_red);
 
 /**
  * Setup the common GMX settings that determine the number of
@@ -384,6 +385,7 @@ int cvmx_helper_get_ipd_port(int interface, int port)
        }
        return -1;
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_get_ipd_port);
 
 /**
  * Returns the interface number for an IPD/PKO port number.
@@ -408,6 +410,7 @@ int cvmx_helper_get_interface_num(int ipd_port)
 
        return -1;
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_num);
 
 /**
  * Returns the interface index number for an IPD/PKO port
@@ -431,3 +434,4 @@ int cvmx_helper_get_interface_index_num(int ipd_port)
 
        return -1;
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_get_interface_index_num);
index d63d20dfbfb0d0b23bd5b681e658595f7a7b76b4..8553ad5c72b61f7f5d2d9ad5c5c719977aad66f8 100644 (file)
@@ -67,7 +67,7 @@ void (*cvmx_override_pko_queue_priority) (int pko_port,
 void (*cvmx_override_ipd_port_setup) (int ipd_port);
 
 /* Port count per interface */
-static int interface_port_count[4] = { 0, 0, 0, 0 };
+static int interface_port_count[5];
 
 /* Port last configured link info index by IPD/PKO port */
 static cvmx_helper_link_info_t
@@ -88,6 +88,7 @@ int cvmx_helper_get_number_of_interfaces(void)
        else
                return 3;
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_get_number_of_interfaces);
 
 /**
  * Return the number of ports on an interface. Depending on the
@@ -102,6 +103,7 @@ int cvmx_helper_ports_on_interface(int interface)
 {
        return interface_port_count[interface];
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_ports_on_interface);
 
 /**
  * Get the operating mode of an interface. Depending on the Octeon
@@ -179,6 +181,7 @@ cvmx_helper_interface_mode_t cvmx_helper_interface_get_mode(int interface)
                        return CVMX_HELPER_INTERFACE_MODE_RGMII;
        }
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_interface_get_mode);
 
 /**
  * Configure the IPD/PIP tagging and QoS options for a specific
@@ -825,6 +828,7 @@ int cvmx_helper_ipd_and_packet_input_enable(void)
                __cvmx_helper_errata_fix_ipd_ptr_alignment();
        return 0;
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_ipd_and_packet_input_enable);
 
 /**
  * Initialize the PIP, IPD, and PKO hardware to support
@@ -903,6 +907,7 @@ int cvmx_helper_initialize_packet_io_global(void)
 #endif
        return result;
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_initialize_packet_io_global);
 
 /**
  * Does core local initialization for packet io
@@ -947,6 +952,7 @@ cvmx_helper_link_info_t cvmx_helper_link_autoconf(int ipd_port)
         */
        return port_link_info[ipd_port];
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_link_autoconf);
 
 /**
  * Return the link state of an IPD/PKO port as returned by
@@ -1005,6 +1011,7 @@ cvmx_helper_link_info_t cvmx_helper_link_get(int ipd_port)
        }
        return result;
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_link_get);
 
 /**
  * Configure an IPD/PKO port for the specified link state. This
@@ -1060,6 +1067,7 @@ int cvmx_helper_link_set(int ipd_port, cvmx_helper_link_info_t link_info)
                port_link_info[ipd_port].u64 = link_info.u64;
        return result;
 }
+EXPORT_SYMBOL_GPL(cvmx_helper_link_set);
 
 /**
  * Configure a port for internal and/or external loopback. Internal loopback
index f2c877541597c6258282f1fb57b955a7ebffd744..008b881cdf6477be82045ede5fa76867724f26cb 100644 (file)
@@ -140,7 +140,7 @@ void cvmx_pko_disable(void)
        pko_reg_flags.s.ena_pko = 0;
        cvmx_write_csr(CVMX_PKO_REG_FLAGS, pko_reg_flags.u64);
 }
-
+EXPORT_SYMBOL_GPL(cvmx_pko_disable);
 
 /**
  * Reset the packet output.
@@ -182,6 +182,7 @@ void cvmx_pko_shutdown(void)
        }
        __cvmx_pko_reset();
 }
+EXPORT_SYMBOL_GPL(cvmx_pko_shutdown);
 
 /**
  * Configure a output port and the associated queues for use.
index ef5198d13a0edda220a3e91159da54fe0effe3d3..459e3b1eb61f47ee1f7e0bdb8fa31d9f979a4ea0 100644 (file)
@@ -177,6 +177,7 @@ int cvmx_spi_restart_interface(int interface, cvmx_spi_mode_t mode, int timeout)
 
        return res;
 }
+EXPORT_SYMBOL_GPL(cvmx_spi_restart_interface);
 
 /**
  * Callback to perform SPI4 reset
index 1830874ff1e24e4ddab1150e438edbb6342cc000..6df0f4d8f197a867f3dd80befb9fb00a4b8ca4a8 100644 (file)
@@ -171,6 +171,7 @@ device_initcall(octeon_ohci_device_init);
 static struct of_device_id __initdata octeon_ids[] = {
        { .compatible = "simple-bus", },
        { .compatible = "cavium,octeon-6335-uctl", },
+       { .compatible = "cavium,octeon-5750-usbn", },
        { .compatible = "cavium,octeon-3860-bootbus", },
        { .compatible = "cavium,mdio-mux", },
        { .compatible = "gpio-leds", },
@@ -336,14 +337,14 @@ static void __init octeon_fdt_pip_iface(int pip, int idx, u64 *pmac)
        int p;
        int count = 0;
 
-       if (cvmx_helper_interface_enumerate(idx) == 0)
-               count = cvmx_helper_ports_on_interface(idx);
-
        snprintf(name_buffer, sizeof(name_buffer), "interface@%d", idx);
        iface = fdt_subnode_offset(initial_boot_params, pip, name_buffer);
        if (iface < 0)
                return;
 
+       if (cvmx_helper_interface_enumerate(idx) == 0)
+               count = cvmx_helper_ports_on_interface(idx);
+
        for (p = 0; p < 16; p++)
                octeon_fdt_pip_port(iface, idx, p, count - 1, pmac);
 }
@@ -682,6 +683,37 @@ end_led:
                }
        }
 
+       /* DWC2 USB */
+       alias_prop = fdt_getprop(initial_boot_params, aliases,
+                                "usbn", NULL);
+       if (alias_prop) {
+               int usbn = fdt_path_offset(initial_boot_params, alias_prop);
+
+               if (usbn >= 0 && (current_cpu_type() == CPU_CAVIUM_OCTEON2 ||
+                                 !octeon_has_feature(OCTEON_FEATURE_USB))) {
+                       pr_debug("Deleting usbn\n");
+                       fdt_nop_node(initial_boot_params, usbn);
+                       fdt_nop_property(initial_boot_params, aliases, "usbn");
+               } else  {
+                       __be32 new_f[1];
+                       enum cvmx_helper_board_usb_clock_types c;
+                       c = __cvmx_helper_board_usb_get_clock_type();
+                       switch (c) {
+                       case USB_CLOCK_TYPE_REF_48:
+                               new_f[0] = cpu_to_be32(48000000);
+                               fdt_setprop_inplace(initial_boot_params, usbn,
+                                                   "refclk-frequency",  new_f, sizeof(new_f));
+                               /* Fall through ...*/
+                       case USB_CLOCK_TYPE_REF_12:
+                               /* Missing "refclk-type" defaults to external. */
+                               fdt_nop_property(initial_boot_params, usbn, "refclk-type");
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
        return 0;
 }
 
index 88cb42d4cc49f8d89c37e10210d03ffb9f57a508..fa33115bde3337914f913767fcd4e8fbaf8d7e6c 100644 (file)
                                big-endian-regs;
                        };
                };
+
+               usbn: usbn@1180068000000 {
+                       compatible = "cavium,octeon-5750-usbn";
+                       reg = <0x11800 0x68000000 0x0 0x1000>;
+                       ranges; /* Direct mapping */
+                       #address-cells = <2>;
+                       #size-cells = <2>;
+                       /* 12MHz, 24MHz and 48MHz allowed */
+                       refclk-frequency = <12000000>;
+                       /* Either "crystal" or "external" */
+                       refclk-type = "crystal";
+
+                       usbc@16f0010000000 {
+                               compatible = "cavium,octeon-5750-usbc";
+                               reg = <0x16f00 0x10000000 0x0 0x80000>;
+                               interrupts = <0 56>;
+                       };
+               };
        };
 
        aliases {
                flash0 = &flash0;
                cf0 = &cf0;
                uctl = &uctl;
+               usbn = &usbn;
                led0 = &led0;
        };
  };
index 24a2167db7780398e67d7b8d369bbc4ac015469a..67a078ffc4641a16c659c93bb049e3c3fb8193ba 100644 (file)
@@ -6,7 +6,6 @@
  * Copyright (C) 2004-2008, 2009, 2010 Cavium Networks
  */
 #include <linux/cpu.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
index 80e012fa409c8da0ee7a7d65b541aa35e424abc6..320772caf054619c27e2c6185d8e1df5bf028fb4 100644 (file)
@@ -86,7 +86,6 @@ CONFIG_MAC80211_RC_DEFAULT_PID=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_FIRMWARE_IN_KERNEL is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 4ca8e5c99225f64ff77347b9e2be2184b586f399..0db4eb319e0a3f9afdc9264d4ca4b21a7e3dd53c 100644 (file)
 CONFIG_BCM47XX=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_KEXEC=y
-# CONFIG_SECCOMP is not set
-CONFIG_EXPERIMENTAL=y
-# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_BSD_PROCESS_ACCT_V3=y
-CONFIG_TASKSTATS=y
-CONFIG_TASK_DELAY_ACCT=y
-CONFIG_TASK_XACCT=y
-CONFIG_TASK_IO_ACCOUNTING=y
-CONFIG_AUDIT=y
-CONFIG_TINY_RCU=y
-CONFIG_CGROUPS=y
-CONFIG_CGROUP_CPUACCT=y
-CONFIG_RELAY=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_UIDGID_STRICT_TYPE_CHECKS=y
 CONFIG_BLK_DEV_INITRD=y
-CONFIG_RD_LZMA=y
-CONFIG_EXPERT=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_EMBEDDED=y
 CONFIG_SLAB=y
 CONFIG_MODULES=y
 CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
 CONFIG_PCI=y
-CONFIG_BINFMT_MISC=m
+# CONFIG_SUSPEND is not set
 CONFIG_NET=y
 CONFIG_PACKET=y
 CONFIG_UNIX=y
-CONFIG_XFRM_USER=m
-CONFIG_NET_KEY=m
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
 CONFIG_IP_ADVANCED_ROUTER=y
 CONFIG_IP_MULTIPLE_TABLES=y
 CONFIG_IP_ROUTE_MULTIPATH=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_NET_IPIP=m
-CONFIG_NET_IPGRE=m
-CONFIG_NET_IPGRE_BROADCAST=y
 CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
 CONFIG_SYN_COOKIES=y
-CONFIG_INET_AH=m
-CONFIG_INET_ESP=m
-CONFIG_INET_IPCOMP=m
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
-CONFIG_INET_XFRM_MODE_BEET=m
-CONFIG_INET_DIAG=m
 CONFIG_TCP_CONG_ADVANCED=y
-CONFIG_TCP_CONG_BIC=y
-CONFIG_TCP_CONG_CUBIC=m
-CONFIG_TCP_CONG_HSTCP=m
-CONFIG_TCP_CONG_HYBLA=m
-CONFIG_TCP_CONG_SCALABLE=m
-CONFIG_TCP_CONG_LP=m
-CONFIG_TCP_CONG_VENO=m
-CONFIG_TCP_CONG_YEAH=m
-CONFIG_TCP_CONG_ILLINOIS=m
 CONFIG_IPV6_PRIVACY=y
-CONFIG_INET6_AH=m
-CONFIG_INET6_ESP=m
-CONFIG_INET6_IPCOMP=m
-CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION=m
-CONFIG_IPV6_TUNNEL=m
 CONFIG_IPV6_MULTIPLE_TABLES=y
 CONFIG_IPV6_SUBTREES=y
-CONFIG_NETWORK_SECMARK=y
+CONFIG_IPV6_MROUTE=y
 CONFIG_NETFILTER=y
-CONFIG_NETFILTER_NETLINK_QUEUE=m
-CONFIG_NF_CONNTRACK=m
-CONFIG_NF_CONNTRACK_SECMARK=y
-CONFIG_NF_CONNTRACK_EVENTS=y
-CONFIG_NF_CT_PROTO_UDPLITE=m
-CONFIG_NF_CONNTRACK_AMANDA=m
-CONFIG_NF_CONNTRACK_FTP=m
-CONFIG_NF_CONNTRACK_H323=m
-CONFIG_NF_CONNTRACK_IRC=m
-CONFIG_NF_CONNTRACK_NETBIOS_NS=m
-CONFIG_NF_CONNTRACK_PPTP=m
-CONFIG_NF_CONNTRACK_SANE=m
-CONFIG_NF_CONNTRACK_SIP=m
-CONFIG_NF_CONNTRACK_TFTP=m
-CONFIG_NF_CT_NETLINK=m
-CONFIG_NETFILTER_XT_TARGET_CLASSIFY=m
-CONFIG_NETFILTER_XT_TARGET_CONNMARK=m
-CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=m
-CONFIG_NETFILTER_XT_TARGET_DSCP=m
-CONFIG_NETFILTER_XT_TARGET_MARK=m
-CONFIG_NETFILTER_XT_TARGET_NFLOG=m
-CONFIG_NETFILTER_XT_TARGET_NFQUEUE=m
-CONFIG_NETFILTER_XT_TARGET_TRACE=m
-CONFIG_NETFILTER_XT_TARGET_SECMARK=m
-CONFIG_NETFILTER_XT_TARGET_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_COMMENT=m
-CONFIG_NETFILTER_XT_MATCH_CONNBYTES=m
-CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_CONNMARK=m
-CONFIG_NETFILTER_XT_MATCH_CONNTRACK=m
-CONFIG_NETFILTER_XT_MATCH_DSCP=m
-CONFIG_NETFILTER_XT_MATCH_ESP=m
-CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=m
-CONFIG_NETFILTER_XT_MATCH_HELPER=m
-CONFIG_NETFILTER_XT_MATCH_LENGTH=m
-CONFIG_NETFILTER_XT_MATCH_LIMIT=m
-CONFIG_NETFILTER_XT_MATCH_MAC=m
-CONFIG_NETFILTER_XT_MATCH_MARK=m
-CONFIG_NETFILTER_XT_MATCH_MULTIPORT=m
-CONFIG_NETFILTER_XT_MATCH_POLICY=m
-CONFIG_NETFILTER_XT_MATCH_PHYSDEV=m
-CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
-CONFIG_NETFILTER_XT_MATCH_QUOTA=m
-CONFIG_NETFILTER_XT_MATCH_REALM=m
-CONFIG_NETFILTER_XT_MATCH_STATE=m
-CONFIG_NETFILTER_XT_MATCH_STATISTIC=m
-CONFIG_NETFILTER_XT_MATCH_STRING=m
-CONFIG_NETFILTER_XT_MATCH_TCPMSS=m
-CONFIG_NETFILTER_XT_MATCH_TIME=m
-CONFIG_NETFILTER_XT_MATCH_U32=m
-CONFIG_IP_VS=m
-CONFIG_IP_VS_PROTO_TCP=y
-CONFIG_IP_VS_PROTO_UDP=y
-CONFIG_IP_VS_PROTO_ESP=y
-CONFIG_IP_VS_PROTO_AH=y
-CONFIG_IP_VS_RR=m
-CONFIG_IP_VS_WRR=m
-CONFIG_IP_VS_LC=m
-CONFIG_IP_VS_WLC=m
-CONFIG_IP_VS_LBLC=m
-CONFIG_IP_VS_LBLCR=m
-CONFIG_IP_VS_DH=m
-CONFIG_IP_VS_SH=m
-CONFIG_IP_VS_SED=m
-CONFIG_IP_VS_NQ=m
-CONFIG_IP_VS_FTP=m
-CONFIG_NF_CONNTRACK_IPV4=m
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_NF_NAT=m
-CONFIG_IP_NF_TARGET_MASQUERADE=m
-CONFIG_IP_NF_TARGET_NETMAP=m
-CONFIG_IP_NF_TARGET_REDIRECT=m
-CONFIG_NF_NAT_SNMP_BASIC=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_CLUSTERIP=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-CONFIG_NF_CONNTRACK_IPV6=m
-CONFIG_IP6_NF_QUEUE=m
-CONFIG_IP6_NF_IPTABLES=m
-CONFIG_IP6_NF_MATCH_AH=m
-CONFIG_IP6_NF_MATCH_EUI64=m
-CONFIG_IP6_NF_MATCH_FRAG=m
-CONFIG_IP6_NF_MATCH_OPTS=m
-CONFIG_IP6_NF_MATCH_HL=m
-CONFIG_IP6_NF_MATCH_IPV6HEADER=m
-CONFIG_IP6_NF_MATCH_MH=m
-CONFIG_IP6_NF_MATCH_RT=m
-CONFIG_IP6_NF_TARGET_HL=m
-CONFIG_IP6_NF_TARGET_LOG=m
-CONFIG_IP6_NF_FILTER=m
-CONFIG_IP6_NF_TARGET_REJECT=m
-CONFIG_IP6_NF_MANGLE=m
-CONFIG_IP6_NF_RAW=m
-CONFIG_BRIDGE_NF_EBTABLES=m
-CONFIG_BRIDGE_EBT_BROUTE=m
-CONFIG_BRIDGE_EBT_T_FILTER=m
-CONFIG_BRIDGE_EBT_T_NAT=m
-CONFIG_BRIDGE_EBT_802_3=m
-CONFIG_BRIDGE_EBT_AMONG=m
-CONFIG_BRIDGE_EBT_ARP=m
-CONFIG_BRIDGE_EBT_IP=m
-CONFIG_BRIDGE_EBT_LIMIT=m
-CONFIG_BRIDGE_EBT_MARK=m
-CONFIG_BRIDGE_EBT_PKTTYPE=m
-CONFIG_BRIDGE_EBT_STP=m
-CONFIG_BRIDGE_EBT_VLAN=m
-CONFIG_BRIDGE_EBT_ARPREPLY=m
-CONFIG_BRIDGE_EBT_DNAT=m
-CONFIG_BRIDGE_EBT_MARK_T=m
-CONFIG_BRIDGE_EBT_REDIRECT=m
-CONFIG_BRIDGE_EBT_SNAT=m
-CONFIG_BRIDGE_EBT_LOG=m
-CONFIG_BRIDGE_EBT_ULOG=m
-CONFIG_IP_DCCP=m
-CONFIG_TIPC=m
-CONFIG_TIPC_ADVANCED=y
-CONFIG_ATM=m
-CONFIG_ATM_CLIP=m
-CONFIG_ATM_LANE=m
-CONFIG_ATM_MPOA=m
-CONFIG_ATM_BR2684=m
-CONFIG_BRIDGE=m
-CONFIG_VLAN_8021Q=m
+CONFIG_VLAN_8021Q=y
 CONFIG_NET_SCHED=y
-CONFIG_NET_SCH_CBQ=m
-CONFIG_NET_SCH_HTB=m
-CONFIG_NET_SCH_HFSC=m
-CONFIG_NET_SCH_ATM=m
-CONFIG_NET_SCH_PRIO=m
-CONFIG_NET_SCH_RED=m
-CONFIG_NET_SCH_SFQ=m
-CONFIG_NET_SCH_TEQL=m
-CONFIG_NET_SCH_TBF=m
-CONFIG_NET_SCH_GRED=m
-CONFIG_NET_SCH_DSMARK=m
-CONFIG_NET_SCH_NETEM=m
-CONFIG_NET_SCH_INGRESS=m
-CONFIG_NET_CLS_BASIC=m
-CONFIG_NET_CLS_TCINDEX=m
-CONFIG_NET_CLS_ROUTE4=m
-CONFIG_NET_CLS_FW=m
-CONFIG_NET_CLS_U32=m
-CONFIG_CLS_U32_PERF=y
-CONFIG_CLS_U32_MARK=y
-CONFIG_NET_CLS_RSVP=m
-CONFIG_NET_CLS_RSVP6=m
-CONFIG_NET_EMATCH=y
-CONFIG_NET_EMATCH_CMP=m
-CONFIG_NET_EMATCH_NBYTE=m
-CONFIG_NET_EMATCH_U32=m
-CONFIG_NET_EMATCH_META=m
-CONFIG_NET_EMATCH_TEXT=m
-CONFIG_NET_CLS_ACT=y
-CONFIG_NET_ACT_POLICE=m
-CONFIG_NET_ACT_GACT=m
-CONFIG_GACT_PROB=y
-CONFIG_NET_ACT_MIRRED=m
-CONFIG_NET_ACT_IPT=m
-CONFIG_NET_ACT_NAT=m
-CONFIG_NET_ACT_PEDIT=m
-CONFIG_NET_ACT_SIMP=m
-CONFIG_NET_CLS_IND=y
-CONFIG_NET_PKTGEN=m
-CONFIG_BT=m
-CONFIG_BT_HCIUART=m
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-CONFIG_BT_HCIUART_LL=y
-CONFIG_BT_HCIBCM203X=m
-CONFIG_BT_HCIBPA10X=m
-CONFIG_BT_HCIBFUSB=m
-CONFIG_BT_HCIVHCI=m
-CONFIG_CFG80211=m
-CONFIG_MAC80211=m
-CONFIG_MAC80211_RC_PID=y
-CONFIG_MAC80211_RC_DEFAULT_PID=y
-CONFIG_MAC80211_MESH=y
-CONFIG_RFKILL=m
-CONFIG_RFKILL_INPUT=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_FW_LOADER=m
-CONFIG_CONNECTOR=m
+CONFIG_NET_SCH_FQ_CODEL=y
+CONFIG_HAMRADIO=y
+CONFIG_CFG80211=y
+CONFIG_MAC80211=y
 CONFIG_MTD=y
-CONFIG_MTD_CONCAT=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
+CONFIG_MTD_BCM47XX_PARTS=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_CFI_STAA=y
-CONFIG_MTD_RAM=y
-CONFIG_MTD_ROM=y
-CONFIG_MTD_ABSENT=y
+CONFIG_MTD_COMPLEX_MAPPINGS=y
 CONFIG_MTD_PHYSMAP=y
-CONFIG_BLK_DEV_LOOP=m
-CONFIG_BLK_DEV_CRYPTOLOOP=m
-CONFIG_BLK_DEV_NBD=m
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=16384
-CONFIG_ATA_OVER_ETH=m
-CONFIG_RAID_ATTRS=m
-CONFIG_SCSI=y
-CONFIG_SCSI_TGT=m
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
-CONFIG_BLK_DEV_SR_VENDOR=y
-CONFIG_CHR_DEV_SG=m
-CONFIG_CHR_DEV_SCH=m
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_CONSTANTS=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_SCSI_SCAN_ASYNC=y
-CONFIG_ISCSI_TCP=m
+CONFIG_MTD_BCM47XXSFLASH=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_BCM47XXNFLASH=y
 CONFIG_NETDEVICES=y
-CONFIG_DUMMY=m
-CONFIG_EQUALIZER=m
-CONFIG_TUN=m
-CONFIG_VETH=m
-CONFIG_PHYLIB=m
-CONFIG_MARVELL_PHY=m
-CONFIG_DAVICOM_PHY=m
-CONFIG_QSEMI_PHY=m
-CONFIG_LXT_PHY=m
-CONFIG_CICADA_PHY=m
-CONFIG_VITESSE_PHY=m
-CONFIG_SMSC_PHY=m
-CONFIG_BROADCOM_PHY=m
-CONFIG_ICPLUS_PHY=m
-CONFIG_MDIO_BITBANG=m
-CONFIG_NET_ETHERNET=y
-CONFIG_NET_PCI=y
 CONFIG_B44=y
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
-CONFIG_ATH_COMMON=m
-CONFIG_ATH5K=m
-CONFIG_B43=m
-CONFIG_B43LEGACY=m
-CONFIG_ZD1211RW=m
-CONFIG_USB_CATC=m
-CONFIG_USB_KAWETH=m
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_RTL8150=m
-CONFIG_USB_USBNET=m
-CONFIG_USB_NET_DM9601=m
-CONFIG_USB_NET_GL620A=m
-CONFIG_USB_NET_PLUSB=m
-CONFIG_USB_NET_MCS7830=m
-CONFIG_USB_NET_RNDIS_HOST=m
-CONFIG_USB_ALI_M5632=y
-CONFIG_USB_AN2720=y
-CONFIG_USB_EPSON2888=y
-CONFIG_USB_KC2190=y
-CONFIG_USB_SIERRA_NET=m
-CONFIG_ATM_DUMMY=m
-CONFIG_ATM_TCP=m
-CONFIG_PPP=m
-CONFIG_PPP_ASYNC=m
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-CONFIG_PPP_MPPE=m
-CONFIG_PPPOE=m
-CONFIG_PPPOATM=m
-CONFIG_SLIP=m
-CONFIG_INPUT_EVDEV=m
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
+CONFIG_TIGON3=y
+CONFIG_BGMAC=y
+CONFIG_ATH_CARDS=y
+CONFIG_ATH5K=y
+CONFIG_B43=y
+CONFIG_B43LEGACY=y
+CONFIG_BRCMSMAC=y
+CONFIG_ISDN=y
 CONFIG_SERIAL_8250=y
+# CONFIG_SERIAL_8250_DEPRECATED_OPTIONS is not set
 CONFIG_SERIAL_8250_CONSOLE=y
 # CONFIG_SERIAL_8250_PCI is not set
 CONFIG_SERIAL_8250_NR_UARTS=2
 CONFIG_SERIAL_8250_RUNTIME_UARTS=2
-# CONFIG_LEGACY_PTYS is not set
-# CONFIG_HW_RANDOM is not set
-CONFIG_W1=m
-CONFIG_W1_MASTER_MATROX=m
-CONFIG_W1_MASTER_DS2490=m
-CONFIG_W1_SLAVE_THERM=m
-CONFIG_W1_SLAVE_SMEM=m
-CONFIG_W1_SLAVE_DS2433=m
-CONFIG_W1_SLAVE_DS2760=m
-# CONFIG_HWMON is not set
-CONFIG_THERMAL=y
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_HW_RANDOM=y
+CONFIG_GPIO_SYSFS=y
 CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
 CONFIG_BCM47XX_WDT=y
+CONFIG_SSB_DEBUG=y
 CONFIG_SSB_DRIVER_GIGE=y
-CONFIG_DISPLAY_SUPPORT=m
-CONFIG_SOUND=m
-CONFIG_SND=m
-CONFIG_SND_SEQUENCER=m
-CONFIG_SND_SEQ_DUMMY=m
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_SEQUENCER_OSS=y
-CONFIG_SND_DUMMY=m
-CONFIG_SND_VIRMIDI=m
-CONFIG_SND_USB_AUDIO=m
-CONFIG_HID=m
-CONFIG_USB_HID=m
-CONFIG_USB_HIDDEV=y
+CONFIG_BCMA_DRIVER_GMAC_CMN=y
 CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-# CONFIG_USB_DEVICE_CLASS is not set
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_ROOT_HUB_TT=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_U132_HCD=m
-CONFIG_USB_R8A66597_HCD=m
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
-CONFIG_USB_STORAGE=y
-CONFIG_USB_STORAGE_DATAFAB=y
-CONFIG_USB_STORAGE_FREECOM=y
-CONFIG_USB_STORAGE_USBAT=y
-CONFIG_USB_STORAGE_SDDR09=y
-CONFIG_USB_STORAGE_SDDR55=y
-CONFIG_USB_STORAGE_JUMPSHOT=y
-CONFIG_USB_STORAGE_ALAUDA=y
-CONFIG_USB_STORAGE_ONETOUCH=y
-CONFIG_USB_STORAGE_KARMA=y
-CONFIG_USB_MDC800=m
-CONFIG_USB_MICROTEK=m
-CONFIG_USB_SERIAL=m
-CONFIG_USB_SERIAL_GENERIC=y
-CONFIG_USB_SERIAL_AIRCABLE=m
-CONFIG_USB_SERIAL_ARK3116=m
-CONFIG_USB_SERIAL_BELKIN=m
-CONFIG_USB_SERIAL_CH341=m
-CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-CONFIG_USB_SERIAL_CYPRESS_M8=m
-CONFIG_USB_SERIAL_EMPEG=m
-CONFIG_USB_SERIAL_FTDI_SIO=m
-CONFIG_USB_SERIAL_FUNSOFT=m
-CONFIG_USB_SERIAL_VISOR=m
-CONFIG_USB_SERIAL_IPAQ=m
-CONFIG_USB_SERIAL_IR=m
-CONFIG_USB_SERIAL_GARMIN=m
-CONFIG_USB_SERIAL_IPW=m
-CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-CONFIG_USB_SERIAL_KLSI=m
-CONFIG_USB_SERIAL_KOBIL_SCT=m
-CONFIG_USB_SERIAL_MCT_U232=m
-CONFIG_USB_SERIAL_MOS7720=m
-CONFIG_USB_SERIAL_MOS7840=m
-CONFIG_USB_SERIAL_NAVMAN=m
-CONFIG_USB_SERIAL_PL2303=m
-CONFIG_USB_SERIAL_OTI6858=m
-CONFIG_USB_SERIAL_HP4X=m
-CONFIG_USB_SERIAL_SAFE=m
-CONFIG_USB_SERIAL_SIERRAWIRELESS=m
-CONFIG_USB_SERIAL_CYBERJACK=m
-CONFIG_USB_SERIAL_XIRCOM=m
-CONFIG_USB_SERIAL_OPTION=m
-CONFIG_USB_SERIAL_OMNINET=m
-CONFIG_USB_SERIAL_DEBUG=m
-CONFIG_USB_ADUTUX=m
-CONFIG_USB_RIO500=m
-CONFIG_USB_LEGOTOWER=m
-CONFIG_USB_LCD=m
-CONFIG_USB_LED=m
-CONFIG_USB_CYPRESS_CY7C63=m
-CONFIG_USB_CYTHERM=m
-CONFIG_USB_IDMOUSE=m
-CONFIG_USB_FTDI_ELAN=m
-CONFIG_USB_SISUSBVGA=m
-CONFIG_USB_LD=m
-CONFIG_USB_TRANCEVIBRATOR=m
-CONFIG_USB_IOWARRIOR=m
-CONFIG_USB_TEST=m
-CONFIG_USB_ATM=m
-CONFIG_USB_SPEEDTOUCH=m
-CONFIG_USB_CXACRU=m
-CONFIG_USB_UEAGLEATM=m
-CONFIG_USB_XUSBATM=m
-CONFIG_USB_GADGET=m
-CONFIG_USB_GADGET_NET2280=y
-CONFIG_USB_ZERO=m
-CONFIG_USB_ETH=m
-CONFIG_USB_GADGETFS=m
-CONFIG_USB_MASS_STORAGE=m
-CONFIG_USB_G_SERIAL=m
-CONFIG_USB_MIDI_GADGET=m
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
+CONFIG_USB_HCD_BCMA=y
+CONFIG_USB_HCD_SSB=y
 CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
 CONFIG_LEDS_TRIGGER_DEFAULT_ON=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT2_FS_XATTR=y
-CONFIG_EXT2_FS_POSIX_ACL=y
-CONFIG_EXT2_FS_SECURITY=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_EXT3_FS_POSIX_ACL=y
-CONFIG_EXT3_FS_SECURITY=y
-CONFIG_REISERFS_FS=m
-CONFIG_REISERFS_FS_XATTR=y
-CONFIG_REISERFS_FS_POSIX_ACL=y
-CONFIG_REISERFS_FS_SECURITY=y
-CONFIG_JFS_FS=m
-CONFIG_JFS_POSIX_ACL=y
-CONFIG_JFS_SECURITY=y
-CONFIG_XFS_FS=m
-CONFIG_XFS_QUOTA=y
-CONFIG_XFS_POSIX_ACL=y
-CONFIG_XFS_RT=y
-CONFIG_GFS2_FS=m
-CONFIG_QUOTA=y
-CONFIG_QUOTA_NETLINK_INTERFACE=y
-CONFIG_QFMT_V1=m
-CONFIG_QFMT_V2=m
-CONFIG_AUTOFS_FS=m
-CONFIG_AUTOFS4_FS=m
-CONFIG_FUSE_FS=m
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_NTFS_FS=m
-CONFIG_NTFS_RW=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_TMPFS_POSIX_ACL=y
-CONFIG_ADFS_FS=m
-CONFIG_AFFS_FS=m
-CONFIG_HFS_FS=m
-CONFIG_HFSPLUS_FS=m
-CONFIG_BEFS_FS=m
-CONFIG_BFS_FS=m
-CONFIG_EFS_FS=m
-CONFIG_JFFS2_FS=m
-CONFIG_JFFS2_FS_XATTR=y
-CONFIG_CRAMFS=m
-CONFIG_VXFS_FS=m
-CONFIG_MINIX_FS=m
-CONFIG_HPFS_FS=m
-CONFIG_QNX4FS_FS=m
-CONFIG_ROMFS_FS=m
-CONFIG_SYSV_FS=m
-CONFIG_UFS_FS=m
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_NFSD=m
-CONFIG_NFSD_V3_ACL=y
-CONFIG_NFSD_V4=y
-CONFIG_RPCSEC_GSS_SPKM3=m
-CONFIG_CIFS=m
-CONFIG_CIFS_XATTR=y
-CONFIG_CIFS_POSIX=y
-CONFIG_NCP_FS=m
-CONFIG_NCPFS_NFS_NS=y
-CONFIG_NCPFS_OS2_NS=y
-CONFIG_NCPFS_NLS=y
-CONFIG_NCPFS_EXTRAS=y
-CONFIG_CODA_FS=m
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_KARMA_PARTITION=y
-CONFIG_NLS_CODEPAGE_437=m
-CONFIG_NLS_CODEPAGE_737=m
-CONFIG_NLS_CODEPAGE_775=m
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-CONFIG_NLS_CODEPAGE_855=m
-CONFIG_NLS_CODEPAGE_857=m
-CONFIG_NLS_CODEPAGE_860=m
-CONFIG_NLS_CODEPAGE_861=m
-CONFIG_NLS_CODEPAGE_862=m
-CONFIG_NLS_CODEPAGE_863=m
-CONFIG_NLS_CODEPAGE_864=m
-CONFIG_NLS_CODEPAGE_865=m
-CONFIG_NLS_CODEPAGE_866=m
-CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-CONFIG_NLS_ISO8859_5=m
-CONFIG_NLS_ISO8859_6=m
-CONFIG_NLS_ISO8859_7=m
-CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_KOI8_R=m
-CONFIG_NLS_KOI8_U=m
-CONFIG_DLM=m
-CONFIG_DLM_DEBUG=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_INFO_REDUCED=y
+CONFIG_STRIP_ASM_SYMS=y
 CONFIG_DEBUG_FS=y
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_TEST=m
-CONFIG_CRYPTO_LRW=m
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_XTS=m
-CONFIG_CRYPTO_HMAC=y
-CONFIG_CRYPTO_XCBC=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=y
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_TGR192=m
-CONFIG_CRYPTO_WP512=m
-CONFIG_CRYPTO_ANUBIS=m
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_CAMELLIA=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_FCRYPT=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_SEED=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRC16=m
-CONFIG_CRC7=m
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,115200"
+CONFIG_CRC32_SARWATE=y
index 919005139f5a310442baf561dc6749a2326ec044..3fec26410f344f0bb3af8a36252a515235104507 100644 (file)
@@ -44,7 +44,6 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 # CONFIG_STANDALONE is not set
 # CONFIG_PREVENT_FIRMWARE_BUILD is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CFI=y
 CONFIG_MTD_CFI_INTELEXT=y
 CONFIG_MTD_CFI_AMDSTD=y
index 5419adb219a84080eab0d4df2e6c20bf9eaa6b3e..23b66934e18d1f51eaf4d4083937b4e36ab41c49 100644 (file)
@@ -19,7 +19,6 @@ CONFIG_INET=y
 # CONFIG_IPV6 is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLKDEVS=y
 CONFIG_MTD_JEDECPROBE=y
index fb64589015fc2bb6841e4e23676d030003590940..8f219dac95988c29bc0367df12d7b97e59f519b9 100644 (file)
@@ -165,7 +165,6 @@ CONFIG_YAM=m
 CONFIG_CFG80211=y
 CONFIG_MAC80211=y
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index db5705e18b366564f660a4c74e201e70b34e29e3..9bc08f2751206f6138a56d4b33f40e228bb45194 100644 (file)
@@ -22,7 +22,6 @@ CONFIG_IP_PNP_BOOTP=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_CFI=y
index d9f3db29ab95aa637471ec8468a02b7335eae489..0179c7fa014f1c093099198bebe5585057eb93f2 100644 (file)
@@ -31,7 +31,6 @@ CONFIG_INET=y
 # CONFIG_INET_DIAG is not set
 # CONFIG_IPV6 is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index 8a666021b870cac9f3ac958d6455e06f4f12199b..d75931850392a1fa485c95963a57690a2ab8bc6f 100644 (file)
@@ -4,7 +4,7 @@ CONFIG_CPU_MIPS32_R2=y
 CONFIG_MIPS_MT_SMP=y
 CONFIG_SCHED_SMT=y
 CONFIG_MIPS_CMP=y
-CONFIG_NR_CPUS=8
+CONFIG_NR_CPUS=2
 CONFIG_HZ_100=y
 CONFIG_LOCALVERSION="cmp"
 CONFIG_SYSVIPC=y
@@ -58,7 +58,6 @@ CONFIG_ATALK=m
 CONFIG_DEV_APPLETALK=m
 CONFIG_IPDDP=m
 CONFIG_IPDDP_ENCAP=y
-CONFIG_IPDDP_DECAP=y
 CONFIG_NET_SCHED=y
 CONFIG_NET_SCH_CBQ=m
 CONFIG_NET_SCH_HTB=m
index 636f82b89fd30e97ed54baa75c3bca623c46745f..4c2c0c4b9bb1dc269fcd2283981ddd631cf97ab0 100644 (file)
@@ -124,7 +124,6 @@ CONFIG_IP6_NF_MANGLE=m
 CONFIG_IP6_NF_RAW=m
 CONFIG_FW_LOADER=m
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
index 9fa8f16068d8c26ea03a3211e5ea2b0b46150a78..593946afc483ecc0084985754c7f8336ad39627a 100644 (file)
@@ -246,7 +246,6 @@ CONFIG_BT_HCIBTUART=m
 CONFIG_BT_HCIVHCI=m
 CONFIG_CONNECTOR=m
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_CFI=y
index f2925769dfa3b581923b8d7575b132e78b7c9297..c887066ecc2a7873167508de506b6059a4876b7d 100644 (file)
@@ -31,7 +31,6 @@ CONFIG_INET_AH=y
 # CONFIG_IPV6 is not set
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
diff --git a/arch/mips/configs/qi_lb60_defconfig b/arch/mips/configs/qi_lb60_defconfig
new file mode 100644 (file)
index 0000000..2b96547
--- /dev/null
@@ -0,0 +1,188 @@
+CONFIG_MACH_JZ4740=y
+# CONFIG_COMPACTION is not set
+# CONFIG_CROSS_MEMORY_ATTACH is not set
+CONFIG_HZ_100=y
+CONFIG_PREEMPT=y
+# CONFIG_SECCOMP is not set
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SYSVIPC=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_EMBEDDED=y
+# CONFIG_VM_EVENT_COUNTERS is not set
+# CONFIG_COMPAT_BRK is not set
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_IOSCHED_CFQ is not set
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_IP_MULTIPLE_TABLES=y
+CONFIG_IP_ROUTE_MULTIPATH=y
+CONFIG_IP_ROUTE_VERBOSE=y
+CONFIG_IP_MROUTE=y
+CONFIG_IP_MROUTE_MULTIPLE_TABLES=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_INET_DIAG is not set
+CONFIG_TCP_CONG_ADVANCED=y
+# CONFIG_TCP_CONG_BIC is not set
+# CONFIG_TCP_CONG_CUBIC is not set
+CONFIG_TCP_CONG_WESTWOOD=y
+# CONFIG_TCP_CONG_HTCP is not set
+# CONFIG_IPV6 is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+# CONFIG_FIRMWARE_IN_KERNEL is not set
+CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_NAND=y
+CONFIG_MTD_NAND_JZ4740=y
+CONFIG_MTD_UBI=y
+CONFIG_NETDEVICES=y
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_MATRIX=y
+# CONFIG_INPUT_MOUSE is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_SERIO is not set
+CONFIG_LEGACY_PTY_COUNT=2
+# CONFIG_DEVKMEM is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+# CONFIG_SERIAL_8250_DMA is not set
+CONFIG_SERIAL_8250_NR_UARTS=2
+CONFIG_SERIAL_8250_RUNTIME_UARTS=2
+# CONFIG_HW_RANDOM is not set
+CONFIG_SPI=y
+CONFIG_SPI_GPIO=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_BATTERY_JZ4740=y
+CONFIG_CHARGER_GPIO=y
+# CONFIG_HWMON is not set
+CONFIG_MFD_JZ4740_ADC=y
+CONFIG_REGULATOR=y
+CONFIG_REGULATOR_FIXED_VOLTAGE=y
+CONFIG_FB=y
+CONFIG_FB_JZ4740=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CLASS_DEVICE is not set
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_SOUND=y
+CONFIG_SND=y
+# CONFIG_SND_SUPPORT_OLD_API is not set
+# CONFIG_SND_VERBOSE_PROCFS is not set
+# CONFIG_SND_DRIVERS is not set
+# CONFIG_SND_SPI is not set
+# CONFIG_SND_MIPS is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_JZ4740_SOC=y
+CONFIG_SND_JZ4740_SOC_QI_LB60=y
+CONFIG_USB=y
+CONFIG_USB_OTG_BLACKLIST_HUB=y
+CONFIG_USB_MUSB_HDRC=y
+CONFIG_USB_MUSB_GADGET=y
+CONFIG_USB_MUSB_JZ4740=y
+CONFIG_NOP_USB_XCEIV=y
+CONFIG_USB_GADGET=y
+CONFIG_USB_GADGET_DEBUG=y
+CONFIG_USB_ETH=y
+# CONFIG_USB_ETH_RNDIS is not set
+CONFIG_MMC=y
+CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_MMC_JZ4740=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_DRV_JZ4740=y
+CONFIG_DMADEVICES=y
+CONFIG_DMA_JZ4740=y
+CONFIG_PWM=y
+CONFIG_PWM_JZ4740=y
+CONFIG_EXT2_FS=y
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+# CONFIG_EXT3_FS_XATTR is not set
+# CONFIG_DNOTIFY is not set
+CONFIG_VFAT_FS=y
+CONFIG_PROC_KCORE=y
+# CONFIG_PROC_PAGE_MONITOR is not set
+CONFIG_TMPFS=y
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_SUMMARY=y
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+# CONFIG_JFFS2_ZLIB is not set
+CONFIG_UBIFS_FS=y
+CONFIG_UBIFS_FS_ADVANCED_COMPR=y
+# CONFIG_NETWORK_FILESYSTEMS is not set
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=y
+CONFIG_NLS_CODEPAGE_775=y
+CONFIG_NLS_CODEPAGE_850=y
+CONFIG_NLS_CODEPAGE_852=y
+CONFIG_NLS_CODEPAGE_855=y
+CONFIG_NLS_CODEPAGE_857=y
+CONFIG_NLS_CODEPAGE_860=y
+CONFIG_NLS_CODEPAGE_861=y
+CONFIG_NLS_CODEPAGE_862=y
+CONFIG_NLS_CODEPAGE_863=y
+CONFIG_NLS_CODEPAGE_864=y
+CONFIG_NLS_CODEPAGE_865=y
+CONFIG_NLS_CODEPAGE_866=y
+CONFIG_NLS_CODEPAGE_869=y
+CONFIG_NLS_CODEPAGE_936=y
+CONFIG_NLS_CODEPAGE_950=y
+CONFIG_NLS_CODEPAGE_932=y
+CONFIG_NLS_CODEPAGE_949=y
+CONFIG_NLS_CODEPAGE_874=y
+CONFIG_NLS_ISO8859_8=y
+CONFIG_NLS_CODEPAGE_1250=y
+CONFIG_NLS_CODEPAGE_1251=y
+CONFIG_NLS_ASCII=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=y
+CONFIG_NLS_ISO8859_3=y
+CONFIG_NLS_ISO8859_4=y
+CONFIG_NLS_ISO8859_5=y
+CONFIG_NLS_ISO8859_6=y
+CONFIG_NLS_ISO8859_7=y
+CONFIG_NLS_ISO8859_9=y
+CONFIG_NLS_ISO8859_13=y
+CONFIG_NLS_ISO8859_14=y
+CONFIG_NLS_ISO8859_15=y
+CONFIG_NLS_KOI8_R=y
+CONFIG_NLS_KOI8_U=y
+CONFIG_NLS_UTF8=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_INFO=y
+CONFIG_STRIP_ASM_SYMS=y
+CONFIG_READABLE_ASM=y
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_MEMORY_INIT=y
+CONFIG_DEBUG_STACKOVERFLOW=y
+CONFIG_PANIC_ON_OOPS=y
+# CONFIG_FTRACE is not set
+CONFIG_KGDB=y
+CONFIG_RUNTIME_DEBUG=y
+CONFIG_CRYPTO_ZLIB=y
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_FONTS=y
+CONFIG_FONT_SUN8x16=y
index b85b121397c8413e385809b6e3b32ac2228ad96e..5d9d708e12e5126702936c4bcb71c7150cb9c952 100644 (file)
@@ -114,7 +114,6 @@ CONFIG_NET_CLS_IND=y
 CONFIG_HAMRADIO=y
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=y
 CONFIG_MTD_BLOCK2MTD=y
index 9cba856277ff91f9fa62eadd07ce783eebf6f691..f8bf9b4c1343d07f3fceb2e6c6453a1d509c345f 100644 (file)
@@ -35,7 +35,6 @@ CONFIG_IP_PNP=y
 # CONFIG_IPV6 is not set
 # CONFIG_WIRELESS is not set
 CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
 CONFIG_MTD_CMDLINE_PARTS=y
 CONFIG_MTD_CHAR=y
 CONFIG_MTD_BLOCK=m
index a8b08032348fb5a9a37b1dc57da504301f4235c6..49fd3ff13fe5949218063d2e84d2a358e5fc0dbd 100644 (file)
@@ -8,7 +8,6 @@
  * Copyright (C) 1994, 1995, 1996, 1999 Ralf Baechle
  * Copyright (C) 1999 Silicon Graphics, Inc.
  */
-#include <linux/init.h>
 
 #include <asm/fw/arc/types.h>
 #include <asm/sgialib.h>
index c3dc1a68dd8d906f88bbb72769652f66d7aebc8d..3cc03c64a9c79075e82b0b236d28cf7d53e5aba3 100644 (file)
@@ -1,7 +1,12 @@
 /*
- * Amon support
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ *
+ * Arbitrary Monitor Support (AMON)
  */
-
-int amon_cpu_avail(int);
-void amon_cpu_start(int, unsigned long, unsigned long,
-                   unsigned long, unsigned long);
+int amon_cpu_avail(int cpu);
+int amon_cpu_start(int cpu, unsigned long pc, unsigned long sp,
+                  unsigned long gp, unsigned long a0);
index 2413afe21b3369f4b5bc1145fcb8c1082c8ceb72..70e1f176f123c12c07faf378dc0fac16b0a67bec 100644 (file)
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
 
-       .macro  fpu_save_double thread status tmp1=t0
-       cfc1    \tmp1,  fcr31
-       sdc1    $f0,  THREAD_FPR0(\thread)
-       sdc1    $f2,  THREAD_FPR2(\thread)
-       sdc1    $f4,  THREAD_FPR4(\thread)
-       sdc1    $f6,  THREAD_FPR6(\thread)
-       sdc1    $f8,  THREAD_FPR8(\thread)
-       sdc1    $f10, THREAD_FPR10(\thread)
-       sdc1    $f12, THREAD_FPR12(\thread)
-       sdc1    $f14, THREAD_FPR14(\thread)
-       sdc1    $f16, THREAD_FPR16(\thread)
-       sdc1    $f18, THREAD_FPR18(\thread)
-       sdc1    $f20, THREAD_FPR20(\thread)
-       sdc1    $f22, THREAD_FPR22(\thread)
-       sdc1    $f24, THREAD_FPR24(\thread)
-       sdc1    $f26, THREAD_FPR26(\thread)
-       sdc1    $f28, THREAD_FPR28(\thread)
-       sdc1    $f30, THREAD_FPR30(\thread)
-       sw      \tmp1, THREAD_FCR31(\thread)
-       .endm
-
        .macro  fpu_save_single thread tmp=t0
        cfc1    \tmp,  fcr31
        swc1    $f0,  THREAD_FPR0(\thread)
        sw      \tmp, THREAD_FCR31(\thread)
        .endm
 
-       .macro  fpu_restore_double thread status tmp=t0
-       lw      \tmp, THREAD_FCR31(\thread)
-       ldc1    $f0,  THREAD_FPR0(\thread)
-       ldc1    $f2,  THREAD_FPR2(\thread)
-       ldc1    $f4,  THREAD_FPR4(\thread)
-       ldc1    $f6,  THREAD_FPR6(\thread)
-       ldc1    $f8,  THREAD_FPR8(\thread)
-       ldc1    $f10, THREAD_FPR10(\thread)
-       ldc1    $f12, THREAD_FPR12(\thread)
-       ldc1    $f14, THREAD_FPR14(\thread)
-       ldc1    $f16, THREAD_FPR16(\thread)
-       ldc1    $f18, THREAD_FPR18(\thread)
-       ldc1    $f20, THREAD_FPR20(\thread)
-       ldc1    $f22, THREAD_FPR22(\thread)
-       ldc1    $f24, THREAD_FPR24(\thread)
-       ldc1    $f26, THREAD_FPR26(\thread)
-       ldc1    $f28, THREAD_FPR28(\thread)
-       ldc1    $f30, THREAD_FPR30(\thread)
-       ctc1    \tmp, fcr31
-       .endm
-
        .macro  fpu_restore_single thread tmp=t0
        lw      \tmp, THREAD_FCR31(\thread)
        lwc1    $f0,  THREAD_FPR0(\thread)
index 08a527dfe4a32df9ec954c28f6e99665adb1a18b..38ea609465b10c8e507536f365e72bc103257b92 100644 (file)
 #include <asm/fpregdef.h>
 #include <asm/mipsregs.h>
 
-       .macro  fpu_save_16even thread tmp=t0
-       cfc1    \tmp, fcr31
-       sdc1    $f0,  THREAD_FPR0(\thread)
-       sdc1    $f2,  THREAD_FPR2(\thread)
-       sdc1    $f4,  THREAD_FPR4(\thread)
-       sdc1    $f6,  THREAD_FPR6(\thread)
-       sdc1    $f8,  THREAD_FPR8(\thread)
-       sdc1    $f10, THREAD_FPR10(\thread)
-       sdc1    $f12, THREAD_FPR12(\thread)
-       sdc1    $f14, THREAD_FPR14(\thread)
-       sdc1    $f16, THREAD_FPR16(\thread)
-       sdc1    $f18, THREAD_FPR18(\thread)
-       sdc1    $f20, THREAD_FPR20(\thread)
-       sdc1    $f22, THREAD_FPR22(\thread)
-       sdc1    $f24, THREAD_FPR24(\thread)
-       sdc1    $f26, THREAD_FPR26(\thread)
-       sdc1    $f28, THREAD_FPR28(\thread)
-       sdc1    $f30, THREAD_FPR30(\thread)
-       sw      \tmp, THREAD_FCR31(\thread)
-       .endm
-
-       .macro  fpu_save_16odd thread
-       sdc1    $f1,  THREAD_FPR1(\thread)
-       sdc1    $f3,  THREAD_FPR3(\thread)
-       sdc1    $f5,  THREAD_FPR5(\thread)
-       sdc1    $f7,  THREAD_FPR7(\thread)
-       sdc1    $f9,  THREAD_FPR9(\thread)
-       sdc1    $f11, THREAD_FPR11(\thread)
-       sdc1    $f13, THREAD_FPR13(\thread)
-       sdc1    $f15, THREAD_FPR15(\thread)
-       sdc1    $f17, THREAD_FPR17(\thread)
-       sdc1    $f19, THREAD_FPR19(\thread)
-       sdc1    $f21, THREAD_FPR21(\thread)
-       sdc1    $f23, THREAD_FPR23(\thread)
-       sdc1    $f25, THREAD_FPR25(\thread)
-       sdc1    $f27, THREAD_FPR27(\thread)
-       sdc1    $f29, THREAD_FPR29(\thread)
-       sdc1    $f31, THREAD_FPR31(\thread)
-       .endm
-
-       .macro  fpu_save_double thread status tmp
-       sll     \tmp, \status, 5
-       bgez    \tmp, 2f
-       fpu_save_16odd \thread
-2:
-       fpu_save_16even \thread \tmp
-       .endm
-
-       .macro  fpu_restore_16even thread tmp=t0
-       lw      \tmp, THREAD_FCR31(\thread)
-       ldc1    $f0,  THREAD_FPR0(\thread)
-       ldc1    $f2,  THREAD_FPR2(\thread)
-       ldc1    $f4,  THREAD_FPR4(\thread)
-       ldc1    $f6,  THREAD_FPR6(\thread)
-       ldc1    $f8,  THREAD_FPR8(\thread)
-       ldc1    $f10, THREAD_FPR10(\thread)
-       ldc1    $f12, THREAD_FPR12(\thread)
-       ldc1    $f14, THREAD_FPR14(\thread)
-       ldc1    $f16, THREAD_FPR16(\thread)
-       ldc1    $f18, THREAD_FPR18(\thread)
-       ldc1    $f20, THREAD_FPR20(\thread)
-       ldc1    $f22, THREAD_FPR22(\thread)
-       ldc1    $f24, THREAD_FPR24(\thread)
-       ldc1    $f26, THREAD_FPR26(\thread)
-       ldc1    $f28, THREAD_FPR28(\thread)
-       ldc1    $f30, THREAD_FPR30(\thread)
-       ctc1    \tmp, fcr31
-       .endm
-
-       .macro  fpu_restore_16odd thread
-       ldc1    $f1,  THREAD_FPR1(\thread)
-       ldc1    $f3,  THREAD_FPR3(\thread)
-       ldc1    $f5,  THREAD_FPR5(\thread)
-       ldc1    $f7,  THREAD_FPR7(\thread)
-       ldc1    $f9,  THREAD_FPR9(\thread)
-       ldc1    $f11, THREAD_FPR11(\thread)
-       ldc1    $f13, THREAD_FPR13(\thread)
-       ldc1    $f15, THREAD_FPR15(\thread)
-       ldc1    $f17, THREAD_FPR17(\thread)
-       ldc1    $f19, THREAD_FPR19(\thread)
-       ldc1    $f21, THREAD_FPR21(\thread)
-       ldc1    $f23, THREAD_FPR23(\thread)
-       ldc1    $f25, THREAD_FPR25(\thread)
-       ldc1    $f27, THREAD_FPR27(\thread)
-       ldc1    $f29, THREAD_FPR29(\thread)
-       ldc1    $f31, THREAD_FPR31(\thread)
-       .endm
-
-       .macro  fpu_restore_double thread status tmp
-       sll     \tmp, \status, 5
-       bgez    \tmp, 1f                                # 16 register mode?
-
-       fpu_restore_16odd \thread
-1:     fpu_restore_16even \thread \tmp
-       .endm
-
        .macro  cpu_save_nonscratch thread
        LONG_S  s0, THREAD_REG16(\thread)
        LONG_S  s1, THREAD_REG17(\thread)
index 6c8342ae74db88cd3187d1964274aa03c6031165..3220c93ea981da828e94820bb6ec7c9a570db70f 100644 (file)
        .endm
 #endif /* CONFIG_MIPS_MT_SMTC */
 
+       .macro  fpu_save_16even thread tmp=t0
+       cfc1    \tmp, fcr31
+       sdc1    $f0,  THREAD_FPR0(\thread)
+       sdc1    $f2,  THREAD_FPR2(\thread)
+       sdc1    $f4,  THREAD_FPR4(\thread)
+       sdc1    $f6,  THREAD_FPR6(\thread)
+       sdc1    $f8,  THREAD_FPR8(\thread)
+       sdc1    $f10, THREAD_FPR10(\thread)
+       sdc1    $f12, THREAD_FPR12(\thread)
+       sdc1    $f14, THREAD_FPR14(\thread)
+       sdc1    $f16, THREAD_FPR16(\thread)
+       sdc1    $f18, THREAD_FPR18(\thread)
+       sdc1    $f20, THREAD_FPR20(\thread)
+       sdc1    $f22, THREAD_FPR22(\thread)
+       sdc1    $f24, THREAD_FPR24(\thread)
+       sdc1    $f26, THREAD_FPR26(\thread)
+       sdc1    $f28, THREAD_FPR28(\thread)
+       sdc1    $f30, THREAD_FPR30(\thread)
+       sw      \tmp, THREAD_FCR31(\thread)
+       .endm
+
+       .macro  fpu_save_16odd thread
+       .set    push
+       .set    mips64r2
+       sdc1    $f1,  THREAD_FPR1(\thread)
+       sdc1    $f3,  THREAD_FPR3(\thread)
+       sdc1    $f5,  THREAD_FPR5(\thread)
+       sdc1    $f7,  THREAD_FPR7(\thread)
+       sdc1    $f9,  THREAD_FPR9(\thread)
+       sdc1    $f11, THREAD_FPR11(\thread)
+       sdc1    $f13, THREAD_FPR13(\thread)
+       sdc1    $f15, THREAD_FPR15(\thread)
+       sdc1    $f17, THREAD_FPR17(\thread)
+       sdc1    $f19, THREAD_FPR19(\thread)
+       sdc1    $f21, THREAD_FPR21(\thread)
+       sdc1    $f23, THREAD_FPR23(\thread)
+       sdc1    $f25, THREAD_FPR25(\thread)
+       sdc1    $f27, THREAD_FPR27(\thread)
+       sdc1    $f29, THREAD_FPR29(\thread)
+       sdc1    $f31, THREAD_FPR31(\thread)
+       .set    pop
+       .endm
+
+       .macro  fpu_save_double thread status tmp
+#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+       sll     \tmp, \status, 5
+       bgez    \tmp, 10f
+       fpu_save_16odd \thread
+10:
+#endif
+       fpu_save_16even \thread \tmp
+       .endm
+
+       .macro  fpu_restore_16even thread tmp=t0
+       lw      \tmp, THREAD_FCR31(\thread)
+       ldc1    $f0,  THREAD_FPR0(\thread)
+       ldc1    $f2,  THREAD_FPR2(\thread)
+       ldc1    $f4,  THREAD_FPR4(\thread)
+       ldc1    $f6,  THREAD_FPR6(\thread)
+       ldc1    $f8,  THREAD_FPR8(\thread)
+       ldc1    $f10, THREAD_FPR10(\thread)
+       ldc1    $f12, THREAD_FPR12(\thread)
+       ldc1    $f14, THREAD_FPR14(\thread)
+       ldc1    $f16, THREAD_FPR16(\thread)
+       ldc1    $f18, THREAD_FPR18(\thread)
+       ldc1    $f20, THREAD_FPR20(\thread)
+       ldc1    $f22, THREAD_FPR22(\thread)
+       ldc1    $f24, THREAD_FPR24(\thread)
+       ldc1    $f26, THREAD_FPR26(\thread)
+       ldc1    $f28, THREAD_FPR28(\thread)
+       ldc1    $f30, THREAD_FPR30(\thread)
+       ctc1    \tmp, fcr31
+       .endm
+
+       .macro  fpu_restore_16odd thread
+       .set    push
+       .set    mips64r2
+       ldc1    $f1,  THREAD_FPR1(\thread)
+       ldc1    $f3,  THREAD_FPR3(\thread)
+       ldc1    $f5,  THREAD_FPR5(\thread)
+       ldc1    $f7,  THREAD_FPR7(\thread)
+       ldc1    $f9,  THREAD_FPR9(\thread)
+       ldc1    $f11, THREAD_FPR11(\thread)
+       ldc1    $f13, THREAD_FPR13(\thread)
+       ldc1    $f15, THREAD_FPR15(\thread)
+       ldc1    $f17, THREAD_FPR17(\thread)
+       ldc1    $f19, THREAD_FPR19(\thread)
+       ldc1    $f21, THREAD_FPR21(\thread)
+       ldc1    $f23, THREAD_FPR23(\thread)
+       ldc1    $f25, THREAD_FPR25(\thread)
+       ldc1    $f27, THREAD_FPR27(\thread)
+       ldc1    $f29, THREAD_FPR29(\thread)
+       ldc1    $f31, THREAD_FPR31(\thread)
+       .set    pop
+       .endm
+
+       .macro  fpu_restore_double thread status tmp
+#if defined(CONFIG_MIPS64) || defined(CONFIG_CPU_MIPS32_R2)
+       sll     \tmp, \status, 5
+       bgez    \tmp, 10f                               # 16 register mode?
+
+       fpu_restore_16odd \thread
+10:
+#endif
+       fpu_restore_16even \thread \tmp
+       .endm
+
 /*
  * Temporary until all gas have MT ASE support
  */
index 27bd060d716e334e65be1e547a8c478d45273fa7..cbaccebf5065cd30c7c7f0e30550b0003edacd8d 100644 (file)
 
 #include <linux/cpumask.h>
 #include <asm/r4kcache.h>
+#include <asm/smp-ops.h>
+
+extern struct plat_smp_ops bmips43xx_smp_ops;
+extern struct plat_smp_ops bmips5000_smp_ops;
+
+static inline int register_bmips_smp_ops(void)
+{
+#if IS_ENABLED(CONFIG_CPU_BMIPS) && IS_ENABLED(CONFIG_SMP)
+       switch (current_cpu_type()) {
+       case CPU_BMIPS32:
+       case CPU_BMIPS3300:
+               return register_up_smp_ops();
+       case CPU_BMIPS4350:
+       case CPU_BMIPS4380:
+               register_smp_ops(&bmips43xx_smp_ops);
+               break;
+       case CPU_BMIPS5000:
+               register_smp_ops(&bmips5000_smp_ops);
+               break;
+       default:
+               return -ENODEV;
+       }
+
+       return 0;
+#else
+       return -ENODEV;
+#endif
+}
 
-extern struct plat_smp_ops bmips_smp_ops;
 extern char bmips_reset_nmi_vec;
 extern char bmips_reset_nmi_vec_end;
 extern char bmips_smp_movevec;
index d445d060e346ab689a177bf584cfebd5b9dfca51..6e70b03b6aab8dbcad47703bc9d3a325adec859b 100644 (file)
 #ifndef cpu_has_tlb
 #define cpu_has_tlb            (cpu_data[0].options & MIPS_CPU_TLB)
 #endif
+#ifndef cpu_has_tlbinv
+#define cpu_has_tlbinv         (cpu_data[0].options & MIPS_CPU_TLBINV)
+#endif
+#ifndef cpu_has_segments
+#define cpu_has_segments       (cpu_data[0].options & MIPS_CPU_SEGMENTS)
+#endif
+
 
 /*
  * For the moment we don't consider R6000 and R8000 so we can assume that
index 21c8e29c8f91e87486f90d3aaa7fbe79220add5b..8f7adf0ac1e383539e742df12133bfc3c0fdbda4 100644 (file)
@@ -52,6 +52,9 @@ struct cpuinfo_mips {
        unsigned int            cputype;
        int                     isa_level;
        int                     tlbsize;
+       int                     tlbsizevtlb;
+       int                     tlbsizeftlbsets;
+       int                     tlbsizeftlbways;
        struct cache_desc       icache; /* Primary I-cache */
        struct cache_desc       dcache; /* Primary D or combined I/D cache */
        struct cache_desc       scache; /* Secondary cache */
index 4a402cc60c03e4d3aded6429d93df4fed4f0dc46..02f591bd95ca635b82e6016eedcffa5ea1978b93 100644 (file)
@@ -27,10 +27,7 @@ static inline int __pure __get_cpu_type(const int cpu_type)
 #ifdef CONFIG_SYS_HAS_CPU_MIPS32_R1
        case CPU_4KC:
        case CPU_ALCHEMY:
-       case CPU_BMIPS3300:
-       case CPU_BMIPS4350:
        case CPU_PR4450:
-       case CPU_BMIPS32:
        case CPU_JZRISC:
 #endif
 
@@ -47,6 +44,8 @@ static inline int __pure __get_cpu_type(const int cpu_type)
        case CPU_74K:
        case CPU_M14KC:
        case CPU_M14KEC:
+       case CPU_INTERAPTIV:
+       case CPU_PROAPTIV:
 #endif
 
 #ifdef CONFIG_SYS_HAS_CPU_MIPS64_R1
@@ -163,6 +162,16 @@ static inline int __pure __get_cpu_type(const int cpu_type)
        case CPU_CAVIUM_OCTEON2:
 #endif
 
+#if defined(CONFIG_SYS_HAS_CPU_BMIPS32_3300) || \
+       defined (CONFIG_SYS_HAS_CPU_MIPS32_R1)
+       case CPU_BMIPS32:
+       case CPU_BMIPS3300:
+#endif
+
+#ifdef CONFIG_SYS_HAS_CPU_BMIPS4350
+       case CPU_BMIPS4350:
+#endif
+
 #ifdef CONFIG_SYS_HAS_CPU_BMIPS4380
        case CPU_BMIPS4380:
 #endif
index d2035e16502a7d98cfe3e015f9855da2617308f2..76411df3d971efee351615d05824cbfa3be72a85 100644 (file)
 #define PRID_IMP_1074K         0x9a00
 #define PRID_IMP_M14KC         0x9c00
 #define PRID_IMP_M14KEC                0x9e00
+#define PRID_IMP_INTERAPTIV_UP 0xa000
+#define PRID_IMP_INTERAPTIV_MP 0xa100
+#define PRID_IMP_PROAPTIV_UP   0xa200
+#define PRID_IMP_PROAPTIV_MP   0xa300
 
 /*
  * These are the PRID's for when 23:16 == PRID_COMP_SIBYTE
 #define PRID_IMP_NETLOGIC_XLP8XX       0x1000
 #define PRID_IMP_NETLOGIC_XLP3XX       0x1100
 #define PRID_IMP_NETLOGIC_XLP2XX       0x1200
+#define PRID_IMP_NETLOGIC_XLP9XX       0x1500
 
 /*
  * Particular Revision values for bits 7:0 of the PRId register.
 
 #define FPIR_IMP_NONE          0x0000
 
+#if !defined(__ASSEMBLY__)
+
 enum cpu_type_enum {
        CPU_UNKNOWN,
 
@@ -289,7 +296,7 @@ enum cpu_type_enum {
        CPU_4KC, CPU_4KEC, CPU_4KSC, CPU_24K, CPU_34K, CPU_1004K, CPU_74K,
        CPU_ALCHEMY, CPU_PR4450, CPU_BMIPS32, CPU_BMIPS3300, CPU_BMIPS4350,
        CPU_BMIPS4380, CPU_BMIPS5000, CPU_JZRISC, CPU_LOONGSON1, CPU_M14KC,
-       CPU_M14KEC,
+       CPU_M14KEC, CPU_INTERAPTIV, CPU_PROAPTIV,
 
        /*
         * MIPS64 class processors
@@ -301,6 +308,7 @@ enum cpu_type_enum {
        CPU_LAST
 };
 
+#endif /* !__ASSEMBLY */
 
 /*
  * ISA Level encodings
@@ -348,6 +356,8 @@ enum cpu_type_enum {
 #define MIPS_CPU_PCI           0x00400000 /* CPU has Perf Ctr Int indicator */
 #define MIPS_CPU_RIXI          0x00800000 /* CPU has TLB Read/eXec Inhibit */
 #define MIPS_CPU_MICROMIPS     0x01000000 /* CPU has microMIPS capability */
+#define MIPS_CPU_TLBINV                0x02000000 /* CPU supports TLBINV/F */
+#define MIPS_CPU_SEGMENTS      0x04000000 /* CPU supports Segmentation Control registers */
 
 /*
  * CPU ASE encodings
index 242cbb3ca5827310f29edbaad2f642f71b33e864..bc5e85d579e607a61420a7c0cd7a1c6b716d8f4c 100644 (file)
@@ -9,7 +9,16 @@
 #ifndef __ASM_DMA_COHERENCE_H
 #define __ASM_DMA_COHERENCE_H
 
+#ifdef CONFIG_DMA_MAYBE_COHERENT
 extern int coherentio;
 extern int hw_coherentio;
+#else
+#ifdef CONFIG_DMA_COHERENT
+#define coherentio     1
+#else
+#define coherentio     0
+#endif
+#define hw_coherentio  0
+#endif /* CONFIG_DMA_MAYBE_COHERENT */
 
 #endif
index a66359ef4ece770e3ed1a6518e96b79e733b4afa..d4144056e9287c2a840450cebb19774380fc404c 100644 (file)
@@ -36,6 +36,7 @@
 #define EF_MIPS_ABI2           0x00000020
 #define EF_MIPS_OPTIONS_FIRST  0x00000080
 #define EF_MIPS_32BITMODE      0x00000100
+#define EF_MIPS_FP64           0x00000200
 #define EF_MIPS_ABI            0x0000f000
 #define EF_MIPS_ARCH           0xf0000000
 
@@ -175,6 +176,18 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
 #ifdef CONFIG_32BIT
 
+/*
+ * In order to be sure that we don't attempt to execute an O32 binary which
+ * requires 64 bit FP (FR=1) on a system which does not support it we refuse
+ * to execute any binary which has bits specified by the following macro set
+ * in its ELF header flags.
+ */
+#ifdef CONFIG_MIPS_O32_FP64_SUPPORT
+# define __MIPS_O32_FP64_MUST_BE_ZERO  0
+#else
+# define __MIPS_O32_FP64_MUST_BE_ZERO  EF_MIPS_FP64
+#endif
+
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
@@ -191,6 +204,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
                __res = 0;                                              \
        if (((__h->e_flags & EF_MIPS_ABI) != 0) &&                      \
            ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32))          \
+               __res = 0;                                              \
+       if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO)                \
                __res = 0;                                              \
                                                                        \
        __res;                                                          \
@@ -249,6 +264,11 @@ extern struct mips_abi mips_abi_n32;
 
 #define SET_PERSONALITY(ex)                                            \
 do {                                                                   \
+       if ((ex).e_flags & EF_MIPS_FP64)                                \
+               clear_thread_flag(TIF_32BIT_FPREGS);                    \
+       else                                                            \
+               set_thread_flag(TIF_32BIT_FPREGS);                      \
+                                                                       \
        if (personality(current->personality) != PER_LINUX)             \
                set_personality(PER_LINUX);                             \
                                                                        \
@@ -271,14 +291,18 @@ do {                                                                      \
 #endif
 
 #ifdef CONFIG_MIPS32_O32
-#define __SET_PERSONALITY32_O32()                                      \
+#define __SET_PERSONALITY32_O32(ex)                                    \
        do {                                                            \
                set_thread_flag(TIF_32BIT_REGS);                        \
                set_thread_flag(TIF_32BIT_ADDR);                        \
+                                                                       \
+               if (!((ex).e_flags & EF_MIPS_FP64))                     \
+                       set_thread_flag(TIF_32BIT_FPREGS);              \
+                                                                       \
                current->thread.abi = &mips_abi_32;                     \
        } while (0)
 #else
-#define __SET_PERSONALITY32_O32()                                      \
+#define __SET_PERSONALITY32_O32(ex)                                    \
        do { } while (0)
 #endif
 
@@ -289,7 +313,7 @@ do {                                                                        \
             ((ex).e_flags & EF_MIPS_ABI) == 0)                         \
                __SET_PERSONALITY32_N32();                              \
        else                                                            \
-               __SET_PERSONALITY32_O32();                              \
+               __SET_PERSONALITY32_O32(ex);                            \
 } while (0)
 #else
 #define __SET_PERSONALITY32(ex) do { } while (0)
@@ -300,6 +324,7 @@ do {                                                                        \
        unsigned int p;                                                 \
                                                                        \
        clear_thread_flag(TIF_32BIT_REGS);                              \
+       clear_thread_flag(TIF_32BIT_FPREGS);                            \
        clear_thread_flag(TIF_32BIT_ADDR);                              \
                                                                        \
        if ((ex).e_ident[EI_CLASS] == ELFCLASS32)                       \
index d088e5db49032bf3d2ed0f050ac49eb889446e8f..cfe092fc720d021ab7636276e2f0ea9eb4a4507c 100644 (file)
@@ -33,11 +33,48 @@ extern void _init_fpu(void);
 extern void _save_fp(struct task_struct *);
 extern void _restore_fp(struct task_struct *);
 
-#define __enable_fpu()                                                 \
-do {                                                                   \
-       set_c0_status(ST0_CU1);                                         \
-       enable_fpu_hazard();                                            \
-} while (0)
+/*
+ * This enum specifies a mode in which we want the FPU to operate, for cores
+ * which implement the Status.FR bit. Note that FPU_32BIT & FPU_64BIT
+ * purposefully have the values 0 & 1 respectively, so that an integer value
+ * of Status.FR can be trivially casted to the corresponding enum fpu_mode.
+ */
+enum fpu_mode {
+       FPU_32BIT = 0,          /* FR = 0 */
+       FPU_64BIT,              /* FR = 1 */
+       FPU_AS_IS,
+};
+
+static inline int __enable_fpu(enum fpu_mode mode)
+{
+       int fr;
+
+       switch (mode) {
+       case FPU_AS_IS:
+               /* just enable the FPU in its current mode */
+               set_c0_status(ST0_CU1);
+               enable_fpu_hazard();
+               return 0;
+
+       case FPU_64BIT:
+#if !(defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_MIPS64))
+               /* we only have a 32-bit FPU */
+               return SIGFPE;
+#endif
+               /* fall through */
+       case FPU_32BIT:
+               /* set CU1 & change FR appropriately */
+               fr = (int)mode;
+               change_c0_status(ST0_CU1 | ST0_FR, ST0_CU1 | (fr ? ST0_FR : 0));
+               enable_fpu_hazard();
+
+               /* check FR has the desired value */
+               return (!!(read_c0_status() & ST0_FR) == !!fr) ? 0 : SIGFPE;
+
+       default:
+               BUG();
+       }
+}
 
 #define __disable_fpu()                                                        \
 do {                                                                   \
@@ -45,19 +82,6 @@ do {                                                                 \
        disable_fpu_hazard();                                           \
 } while (0)
 
-#define enable_fpu()                                                   \
-do {                                                                   \
-       if (cpu_has_fpu)                                                \
-               __enable_fpu();                                         \
-} while (0)
-
-#define disable_fpu()                                                  \
-do {                                                                   \
-       if (cpu_has_fpu)                                                \
-               __disable_fpu();                                        \
-} while (0)
-
-
 #define clear_fpu_owner()      clear_thread_flag(TIF_USEDFPU)
 
 static inline int __is_fpu_owner(void)
@@ -70,27 +94,46 @@ static inline int is_fpu_owner(void)
        return cpu_has_fpu && __is_fpu_owner();
 }
 
-static inline void __own_fpu(void)
+static inline int __own_fpu(void)
 {
-       __enable_fpu();
+       enum fpu_mode mode;
+       int ret;
+
+       mode = !test_thread_flag(TIF_32BIT_FPREGS);
+       ret = __enable_fpu(mode);
+       if (ret)
+               return ret;
+
        KSTK_STATUS(current) |= ST0_CU1;
+       if (mode == FPU_64BIT)
+               KSTK_STATUS(current) |= ST0_FR;
+       else /* mode == FPU_32BIT */
+               KSTK_STATUS(current) &= ~ST0_FR;
+
        set_thread_flag(TIF_USEDFPU);
+       return 0;
 }
 
-static inline void own_fpu_inatomic(int restore)
+static inline int own_fpu_inatomic(int restore)
 {
+       int ret = 0;
+
        if (cpu_has_fpu && !__is_fpu_owner()) {
-               __own_fpu();
-               if (restore)
+               ret = __own_fpu();
+               if (restore && !ret)
                        _restore_fp(current);
        }
+       return ret;
 }
 
-static inline void own_fpu(int restore)
+static inline int own_fpu(int restore)
 {
+       int ret;
+
        preempt_disable();
-       own_fpu_inatomic(restore);
+       ret = own_fpu_inatomic(restore);
        preempt_enable();
+       return ret;
 }
 
 static inline void lose_fpu(int save)
@@ -106,16 +149,21 @@ static inline void lose_fpu(int save)
        preempt_enable();
 }
 
-static inline void init_fpu(void)
+static inline int init_fpu(void)
 {
+       int ret = 0;
+
        preempt_disable();
        if (cpu_has_fpu) {
-               __own_fpu();
-               _init_fpu();
+               ret = __own_fpu();
+               if (!ret)
+                       _init_fpu();
        } else {
                fpu_emulator_init_fpu();
        }
+
        preempt_enable();
+       return ret;
 }
 
 static inline void save_fp(struct task_struct *tsk)
index b0dd0c84df7040dadb1f8d82f5f8b849d2c5a5a4..572e63ec2a38fe8f40faa2555ee7595d8be82cce 100644 (file)
@@ -19,7 +19,6 @@
 
 #ifdef __KERNEL__
 
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/uaccess.h>
 #include <asm/kmap_types.h>
index 32966969f2f975f56bddbf9ea0aa514d8f435d97..a995fce8779103bfea37de1d08cc2b802ee0282c 100644 (file)
@@ -391,9 +391,6 @@ struct kvm_vcpu_arch {
        uint32_t guest_kernel_asid[NR_CPUS];
        struct mm_struct guest_kernel_mm, guest_user_mm;
 
-       struct kvm_mips_tlb shadow_tlb[NR_CPUS][KVM_MIPS_GUEST_TLB_SIZE];
-
-
        struct hrtimer comparecount_timer;
 
        int last_sched_cpu;
@@ -529,7 +526,6 @@ extern enum emulation_result kvm_mips_handle_tlbmod(unsigned long cause,
 
 extern void kvm_mips_dump_host_tlbs(void);
 extern void kvm_mips_dump_guest_tlbs(struct kvm_vcpu *vcpu);
-extern void kvm_mips_dump_shadow_tlbs(struct kvm_vcpu *vcpu);
 extern void kvm_mips_flush_host_tlb(int skip_kseg0);
 extern int kvm_mips_host_tlb_inv(struct kvm_vcpu *vcpu, unsigned long entryhi);
 extern int kvm_mips_host_tlb_inv_index(struct kvm_vcpu *vcpu, int index);
@@ -541,10 +537,7 @@ extern unsigned long kvm_mips_translate_guest_kseg0_to_hpa(struct kvm_vcpu *vcpu
                                                   unsigned long gva);
 extern void kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu,
                                    struct kvm_vcpu *vcpu);
-extern void kvm_shadow_tlb_put(struct kvm_vcpu *vcpu);
-extern void kvm_shadow_tlb_load(struct kvm_vcpu *vcpu);
 extern void kvm_local_flush_tlb_all(void);
-extern void kvm_mips_init_shadow_tlb(struct kvm_vcpu *vcpu);
 extern void kvm_mips_alloc_new_mmu_context(struct kvm_vcpu *vcpu);
 extern void kvm_mips_vcpu_load(struct kvm_vcpu *vcpu, int cpu);
 extern void kvm_mips_vcpu_put(struct kvm_vcpu *vcpu);
index b86a1253a5bf712af01fd988f95e9f8a16b4b582..cd41e93bc1d80170330a26d6219b6fe6260619f7 100644 (file)
@@ -16,7 +16,6 @@
 #define __ASM_MACH_AR71XX_REGS_H
 
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/bitops.h>
 
index cc7563ba1cbf57e7f2893bc4d2b513bb6548614e..7527c1d33d029a11f1558b0d0e94855e5aa6edc5 100644 (file)
@@ -56,4 +56,6 @@ void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo,
                                 const char *prefix);
 #endif
 
+void bcm47xx_set_system_type(u16 chip_id);
+
 #endif /* __ASM_BCM47XX_H */
index 00867dd05a6988a77bf18bb5fcda39366bc571ac..40005fb39618ad4c3b89055e86129c4f83a62cef 100644 (file)
@@ -66,6 +66,7 @@ enum bcm47xx_board {
        BCM47XX_BOARD_LINKSYS_WRT310NV1,
        BCM47XX_BOARD_LINKSYS_WRT310NV2,
        BCM47XX_BOARD_LINKSYS_WRT54G3GV2,
+       BCM47XX_BOARD_LINKSYS_WRT54GSV1,
        BCM47XX_BOARD_LINKSYS_WRT610NV1,
        BCM47XX_BOARD_LINKSYS_WRT610NV2,
        BCM47XX_BOARD_LINKSYS_WRTSL54GS,
diff --git a/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h b/arch/mips/include/asm/mach-bcm47xx/cpu-feature-overrides.h
new file mode 100644 (file)
index 0000000..b7992cd
--- /dev/null
@@ -0,0 +1,82 @@
+#ifndef __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H
+#define __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H
+
+#define cpu_has_tlb                    1
+#define cpu_has_4kex                   1
+#define cpu_has_3k_cache               0
+#define cpu_has_4k_cache               1
+#define cpu_has_tx39_cache             0
+#define cpu_has_fpu                    0
+#define cpu_has_32fpr                  0
+#define cpu_has_counter                        1
+#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB)
+#define cpu_has_watch                  1
+#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA)
+#define cpu_has_watch                  0
+#endif
+#define cpu_has_divec                  1
+#define cpu_has_vce                    0
+#define cpu_has_cache_cdex_p           0
+#define cpu_has_cache_cdex_s           0
+#define cpu_has_prefetch               1
+#define cpu_has_mcheck                 1
+#define cpu_has_ejtag                  1
+#define cpu_has_llsc                   1
+
+/* cpu_has_mips16 */
+#define cpu_has_mdmx                   0
+#define cpu_has_mips3d                 0
+#define cpu_has_rixi                   0
+#define cpu_has_mmips                  0
+#define cpu_has_smartmips              0
+#define cpu_has_vtag_icache            0
+/* cpu_has_dc_aliases */
+#define cpu_has_ic_fills_f_dc          0
+#define cpu_has_pindexed_dcache                0
+#define cpu_icache_snoops_remote_store 0
+
+#define cpu_has_mips_2                 1
+#define cpu_has_mips_3                 0
+#define cpu_has_mips32r1               1
+#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB)
+#define cpu_has_mips32r2               1
+#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA)
+#define cpu_has_mips32r2               0
+#endif
+#define cpu_has_mips64r1               0
+#define cpu_has_mips64r2               0
+
+#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB)
+#define cpu_has_dsp                    1
+#define cpu_has_dsp2                   1
+#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA)
+#define cpu_has_dsp                    0
+#define cpu_has_dsp2                   0
+#endif
+#define cpu_has_mipsmt                 0
+/* cpu_has_userlocal */
+
+#define cpu_has_nofpuex                        0
+#define cpu_has_64bits                 0
+#define cpu_has_64bit_zero_reg         0
+#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB)
+#define cpu_has_vint                   1
+#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA)
+#define cpu_has_vint                   0
+#endif
+#define cpu_has_veic                   0
+#define cpu_has_inclusive_pcaches      0
+
+#if defined(CONFIG_BCM47XX_BCMA) && !defined(CONFIG_BCM47XX_SSB)
+#define cpu_dcache_line_size()         32
+#define cpu_icache_line_size()         32
+#define cpu_has_perf_cntr_intr_bit     1
+#elif defined(CONFIG_BCM47XX_SSB) && !defined(CONFIG_BCM47XX_BCMA)
+#define cpu_dcache_line_size()         16
+#define cpu_icache_line_size()         16
+#define cpu_has_perf_cntr_intr_bit     0
+#endif
+#define cpu_scache_line_size()         0
+#define cpu_has_vz                     0
+
+#endif /* __ASM_MACH_BCM47XX_CPU_FEATURE_OVERRIDES_H */
index 19f9134bfe2fec09031945e3175006fce3ba9da4..3112f08f0c72810fb4747471e902444b705a3526 100644 (file)
@@ -145,6 +145,7 @@ enum bcm63xx_regs_set {
        RSET_UART1,
        RSET_GPIO,
        RSET_SPI,
+       RSET_HSSPI,
        RSET_UDC0,
        RSET_OHCI0,
        RSET_OHCI_PRIV,
@@ -193,6 +194,7 @@ enum bcm63xx_regs_set {
 #define RSET_ENETDMAS_SIZE(chans)      (16 * (chans))
 #define RSET_ENETSW_SIZE               65536
 #define RSET_UART_SIZE                 24
+#define RSET_HSSPI_SIZE                        1536
 #define RSET_UDC_SIZE                  256
 #define RSET_OHCI_SIZE                 256
 #define RSET_EHCI_SIZE                 256
@@ -265,6 +267,7 @@ enum bcm63xx_regs_set {
 #define BCM_6328_UART1_BASE            (0xb0000120)
 #define BCM_6328_GPIO_BASE             (0xb0000080)
 #define BCM_6328_SPI_BASE              (0xdeadbeef)
+#define BCM_6328_HSSPI_BASE            (0xb0001000)
 #define BCM_6328_UDC0_BASE             (0xdeadbeef)
 #define BCM_6328_USBDMA_BASE           (0xb000c000)
 #define BCM_6328_OHCI0_BASE            (0xb0002600)
@@ -313,6 +316,7 @@ enum bcm63xx_regs_set {
 #define BCM_6338_UART1_BASE            (0xdeadbeef)
 #define BCM_6338_GPIO_BASE             (0xfffe0400)
 #define BCM_6338_SPI_BASE              (0xfffe0c00)
+#define BCM_6338_HSSPI_BASE            (0xdeadbeef)
 #define BCM_6338_UDC0_BASE             (0xdeadbeef)
 #define BCM_6338_USBDMA_BASE           (0xfffe2400)
 #define BCM_6338_OHCI0_BASE            (0xdeadbeef)
@@ -360,6 +364,7 @@ enum bcm63xx_regs_set {
 #define BCM_6345_UART1_BASE            (0xdeadbeef)
 #define BCM_6345_GPIO_BASE             (0xfffe0400)
 #define BCM_6345_SPI_BASE              (0xdeadbeef)
+#define BCM_6345_HSSPI_BASE            (0xdeadbeef)
 #define BCM_6345_UDC0_BASE             (0xdeadbeef)
 #define BCM_6345_USBDMA_BASE           (0xfffe2800)
 #define BCM_6345_ENET0_BASE            (0xfffe1800)
@@ -406,6 +411,7 @@ enum bcm63xx_regs_set {
 #define BCM_6348_UART1_BASE            (0xdeadbeef)
 #define BCM_6348_GPIO_BASE             (0xfffe0400)
 #define BCM_6348_SPI_BASE              (0xfffe0c00)
+#define BCM_6348_HSSPI_BASE            (0xdeadbeef)
 #define BCM_6348_UDC0_BASE             (0xfffe1000)
 #define BCM_6348_USBDMA_BASE           (0xdeadbeef)
 #define BCM_6348_OHCI0_BASE            (0xfffe1b00)
@@ -451,6 +457,7 @@ enum bcm63xx_regs_set {
 #define BCM_6358_UART1_BASE            (0xfffe0120)
 #define BCM_6358_GPIO_BASE             (0xfffe0080)
 #define BCM_6358_SPI_BASE              (0xfffe0800)
+#define BCM_6358_HSSPI_BASE            (0xdeadbeef)
 #define BCM_6358_UDC0_BASE             (0xfffe0800)
 #define BCM_6358_USBDMA_BASE           (0xdeadbeef)
 #define BCM_6358_OHCI0_BASE            (0xfffe1400)
@@ -553,6 +560,7 @@ enum bcm63xx_regs_set {
 #define BCM_6368_UART1_BASE            (0xb0000120)
 #define BCM_6368_GPIO_BASE             (0xb0000080)
 #define BCM_6368_SPI_BASE              (0xb0000800)
+#define BCM_6368_HSSPI_BASE            (0xdeadbeef)
 #define BCM_6368_UDC0_BASE             (0xdeadbeef)
 #define BCM_6368_USBDMA_BASE           (0xb0004800)
 #define BCM_6368_OHCI0_BASE            (0xb0001600)
@@ -604,6 +612,7 @@ extern const unsigned long *bcm63xx_regs_base;
        __GEN_RSET_BASE(__cpu, UART1)                                   \
        __GEN_RSET_BASE(__cpu, GPIO)                                    \
        __GEN_RSET_BASE(__cpu, SPI)                                     \
+       __GEN_RSET_BASE(__cpu, HSSPI)                                   \
        __GEN_RSET_BASE(__cpu, UDC0)                                    \
        __GEN_RSET_BASE(__cpu, OHCI0)                                   \
        __GEN_RSET_BASE(__cpu, OHCI_PRIV)                               \
@@ -647,6 +656,7 @@ extern const unsigned long *bcm63xx_regs_base;
        [RSET_UART1]            = BCM_## __cpu ##_UART1_BASE,           \
        [RSET_GPIO]             = BCM_## __cpu ##_GPIO_BASE,            \
        [RSET_SPI]              = BCM_## __cpu ##_SPI_BASE,             \
+       [RSET_HSSPI]            = BCM_## __cpu ##_HSSPI_BASE,           \
        [RSET_UDC0]             = BCM_## __cpu ##_UDC0_BASE,            \
        [RSET_OHCI0]            = BCM_## __cpu ##_OHCI0_BASE,           \
        [RSET_OHCI_PRIV]        = BCM_## __cpu ##_OHCI_PRIV_BASE,       \
@@ -727,6 +737,7 @@ enum bcm63xx_irq {
        IRQ_ENET0,
        IRQ_ENET1,
        IRQ_ENET_PHY,
+       IRQ_HSSPI,
        IRQ_OHCI0,
        IRQ_EHCI0,
        IRQ_USBD,
@@ -815,6 +826,7 @@ enum bcm63xx_irq {
 #define BCM_6328_ENET0_IRQ             0
 #define BCM_6328_ENET1_IRQ             0
 #define BCM_6328_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 12)
+#define BCM_6328_HSSPI_IRQ             (IRQ_INTERNAL_BASE + 29)
 #define BCM_6328_OHCI0_IRQ             (BCM_6328_HIGH_IRQ_BASE + 9)
 #define BCM_6328_EHCI0_IRQ             (BCM_6328_HIGH_IRQ_BASE + 10)
 #define BCM_6328_USBD_IRQ              (IRQ_INTERNAL_BASE + 4)
@@ -860,6 +872,7 @@ enum bcm63xx_irq {
 #define BCM_6338_ENET0_IRQ             (IRQ_INTERNAL_BASE + 8)
 #define BCM_6338_ENET1_IRQ             0
 #define BCM_6338_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 9)
+#define BCM_6338_HSSPI_IRQ             0
 #define BCM_6338_OHCI0_IRQ             0
 #define BCM_6338_EHCI0_IRQ             0
 #define BCM_6338_USBD_IRQ              0
@@ -898,6 +911,7 @@ enum bcm63xx_irq {
 #define BCM_6345_ENET0_IRQ             (IRQ_INTERNAL_BASE + 8)
 #define BCM_6345_ENET1_IRQ             0
 #define BCM_6345_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 12)
+#define BCM_6345_HSSPI_IRQ             0
 #define BCM_6345_OHCI0_IRQ             0
 #define BCM_6345_EHCI0_IRQ             0
 #define BCM_6345_USBD_IRQ              0
@@ -936,6 +950,7 @@ enum bcm63xx_irq {
 #define BCM_6348_ENET0_IRQ             (IRQ_INTERNAL_BASE + 8)
 #define BCM_6348_ENET1_IRQ             (IRQ_INTERNAL_BASE + 7)
 #define BCM_6348_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 9)
+#define BCM_6348_HSSPI_IRQ             0
 #define BCM_6348_OHCI0_IRQ             (IRQ_INTERNAL_BASE + 12)
 #define BCM_6348_EHCI0_IRQ             0
 #define BCM_6348_USBD_IRQ              0
@@ -974,6 +989,7 @@ enum bcm63xx_irq {
 #define BCM_6358_ENET0_IRQ             (IRQ_INTERNAL_BASE + 8)
 #define BCM_6358_ENET1_IRQ             (IRQ_INTERNAL_BASE + 6)
 #define BCM_6358_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 9)
+#define BCM_6358_HSSPI_IRQ             0
 #define BCM_6358_OHCI0_IRQ             (IRQ_INTERNAL_BASE + 5)
 #define BCM_6358_EHCI0_IRQ             (IRQ_INTERNAL_BASE + 10)
 #define BCM_6358_USBD_IRQ              0
@@ -1086,6 +1102,7 @@ enum bcm63xx_irq {
 #define BCM_6368_ENET0_IRQ             0
 #define BCM_6368_ENET1_IRQ             0
 #define BCM_6368_ENET_PHY_IRQ          (IRQ_INTERNAL_BASE + 15)
+#define BCM_6368_HSSPI_IRQ             0
 #define BCM_6368_OHCI0_IRQ             (IRQ_INTERNAL_BASE + 5)
 #define BCM_6368_EHCI0_IRQ             (IRQ_INTERNAL_BASE + 7)
 #define BCM_6368_USBD_IRQ              (IRQ_INTERNAL_BASE + 8)
@@ -1133,6 +1150,7 @@ extern const int *bcm63xx_irqs;
        [IRQ_ENET0]             = BCM_## __cpu ##_ENET0_IRQ,            \
        [IRQ_ENET1]             = BCM_## __cpu ##_ENET1_IRQ,            \
        [IRQ_ENET_PHY]          = BCM_## __cpu ##_ENET_PHY_IRQ,         \
+       [IRQ_HSSPI]             = BCM_## __cpu ##_HSSPI_IRQ,            \
        [IRQ_OHCI0]             = BCM_## __cpu ##_OHCI0_IRQ,            \
        [IRQ_EHCI0]             = BCM_## __cpu ##_EHCI0_IRQ,            \
        [IRQ_USBD]              = BCM_## __cpu ##_USBD_IRQ,             \
diff --git a/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_hsspi.h b/arch/mips/include/asm/mach-bcm63xx/bcm63xx_dev_hsspi.h
new file mode 100644 (file)
index 0000000..1b1acaf
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef BCM63XX_DEV_HSSPI_H
+#define BCM63XX_DEV_HSSPI_H
+
+#include <linux/types.h>
+
+int bcm63xx_hsspi_register(void);
+
+#endif /* BCM63XX_DEV_HSSPI_H */
index 9875db31d883af0df3aa4d4b19ed6b6eb0d183e8..ab427f8814e6b2b3658aada7b5f4e4e882e6ca37 100644 (file)
 /* Watchdog soft reset register (BCM6328 only) */
 #define WDT_SOFTRESET_REG              0xc
 
-/*************************************************************************
- * _REG relative to RSET_UARTx
- *************************************************************************/
-
-/* UART Control Register */
-#define UART_CTL_REG                   0x0
-#define UART_CTL_RXTMOUTCNT_SHIFT      0
-#define UART_CTL_RXTMOUTCNT_MASK       (0x1f << UART_CTL_RXTMOUTCNT_SHIFT)
-#define UART_CTL_RSTTXDN_SHIFT         5
-#define UART_CTL_RSTTXDN_MASK          (1 << UART_CTL_RSTTXDN_SHIFT)
-#define UART_CTL_RSTRXFIFO_SHIFT               6
-#define UART_CTL_RSTRXFIFO_MASK                (1 << UART_CTL_RSTRXFIFO_SHIFT)
-#define UART_CTL_RSTTXFIFO_SHIFT               7
-#define UART_CTL_RSTTXFIFO_MASK                (1 << UART_CTL_RSTTXFIFO_SHIFT)
-#define UART_CTL_STOPBITS_SHIFT                8
-#define UART_CTL_STOPBITS_MASK         (0xf << UART_CTL_STOPBITS_SHIFT)
-#define UART_CTL_STOPBITS_1            (0x7 << UART_CTL_STOPBITS_SHIFT)
-#define UART_CTL_STOPBITS_2            (0xf << UART_CTL_STOPBITS_SHIFT)
-#define UART_CTL_BITSPERSYM_SHIFT      12
-#define UART_CTL_BITSPERSYM_MASK       (0x3 << UART_CTL_BITSPERSYM_SHIFT)
-#define UART_CTL_XMITBRK_SHIFT         14
-#define UART_CTL_XMITBRK_MASK          (1 << UART_CTL_XMITBRK_SHIFT)
-#define UART_CTL_RSVD_SHIFT            15
-#define UART_CTL_RSVD_MASK             (1 << UART_CTL_RSVD_SHIFT)
-#define UART_CTL_RXPAREVEN_SHIFT               16
-#define UART_CTL_RXPAREVEN_MASK                (1 << UART_CTL_RXPAREVEN_SHIFT)
-#define UART_CTL_RXPAREN_SHIFT         17
-#define UART_CTL_RXPAREN_MASK          (1 << UART_CTL_RXPAREN_SHIFT)
-#define UART_CTL_TXPAREVEN_SHIFT               18
-#define UART_CTL_TXPAREVEN_MASK                (1 << UART_CTL_TXPAREVEN_SHIFT)
-#define UART_CTL_TXPAREN_SHIFT         18
-#define UART_CTL_TXPAREN_MASK          (1 << UART_CTL_TXPAREN_SHIFT)
-#define UART_CTL_LOOPBACK_SHIFT                20
-#define UART_CTL_LOOPBACK_MASK         (1 << UART_CTL_LOOPBACK_SHIFT)
-#define UART_CTL_RXEN_SHIFT            21
-#define UART_CTL_RXEN_MASK             (1 << UART_CTL_RXEN_SHIFT)
-#define UART_CTL_TXEN_SHIFT            22
-#define UART_CTL_TXEN_MASK             (1 << UART_CTL_TXEN_SHIFT)
-#define UART_CTL_BRGEN_SHIFT           23
-#define UART_CTL_BRGEN_MASK            (1 << UART_CTL_BRGEN_SHIFT)
-
-/* UART Baudword register */
-#define UART_BAUD_REG                  0x4
-
-/* UART Misc Control register */
-#define UART_MCTL_REG                  0x8
-#define UART_MCTL_DTR_SHIFT            0
-#define UART_MCTL_DTR_MASK             (1 << UART_MCTL_DTR_SHIFT)
-#define UART_MCTL_RTS_SHIFT            1
-#define UART_MCTL_RTS_MASK             (1 << UART_MCTL_RTS_SHIFT)
-#define UART_MCTL_RXFIFOTHRESH_SHIFT   8
-#define UART_MCTL_RXFIFOTHRESH_MASK    (0xf << UART_MCTL_RXFIFOTHRESH_SHIFT)
-#define UART_MCTL_TXFIFOTHRESH_SHIFT   12
-#define UART_MCTL_TXFIFOTHRESH_MASK    (0xf << UART_MCTL_TXFIFOTHRESH_SHIFT)
-#define UART_MCTL_RXFIFOFILL_SHIFT     16
-#define UART_MCTL_RXFIFOFILL_MASK      (0x1f << UART_MCTL_RXFIFOFILL_SHIFT)
-#define UART_MCTL_TXFIFOFILL_SHIFT     24
-#define UART_MCTL_TXFIFOFILL_MASK      (0x1f << UART_MCTL_TXFIFOFILL_SHIFT)
-
-/* UART External Input Configuration register */
-#define UART_EXTINP_REG                        0xc
-#define UART_EXTINP_RI_SHIFT           0
-#define UART_EXTINP_RI_MASK            (1 << UART_EXTINP_RI_SHIFT)
-#define UART_EXTINP_CTS_SHIFT          1
-#define UART_EXTINP_CTS_MASK           (1 << UART_EXTINP_CTS_SHIFT)
-#define UART_EXTINP_DCD_SHIFT          2
-#define UART_EXTINP_DCD_MASK           (1 << UART_EXTINP_DCD_SHIFT)
-#define UART_EXTINP_DSR_SHIFT          3
-#define UART_EXTINP_DSR_MASK           (1 << UART_EXTINP_DSR_SHIFT)
-#define UART_EXTINP_IRSTAT(x)          (1 << (x + 4))
-#define UART_EXTINP_IRMASK(x)          (1 << (x + 8))
-#define UART_EXTINP_IR_RI              0
-#define UART_EXTINP_IR_CTS             1
-#define UART_EXTINP_IR_DCD             2
-#define UART_EXTINP_IR_DSR             3
-#define UART_EXTINP_RI_NOSENSE_SHIFT   16
-#define UART_EXTINP_RI_NOSENSE_MASK    (1 << UART_EXTINP_RI_NOSENSE_SHIFT)
-#define UART_EXTINP_CTS_NOSENSE_SHIFT  17
-#define UART_EXTINP_CTS_NOSENSE_MASK   (1 << UART_EXTINP_CTS_NOSENSE_SHIFT)
-#define UART_EXTINP_DCD_NOSENSE_SHIFT  18
-#define UART_EXTINP_DCD_NOSENSE_MASK   (1 << UART_EXTINP_DCD_NOSENSE_SHIFT)
-#define UART_EXTINP_DSR_NOSENSE_SHIFT  19
-#define UART_EXTINP_DSR_NOSENSE_MASK   (1 << UART_EXTINP_DSR_NOSENSE_SHIFT)
-
-/* UART Interrupt register */
-#define UART_IR_REG                    0x10
-#define UART_IR_MASK(x)                        (1 << (x + 16))
-#define UART_IR_STAT(x)                        (1 << (x))
-#define UART_IR_EXTIP                  0
-#define UART_IR_TXUNDER                        1
-#define UART_IR_TXOVER                 2
-#define UART_IR_TXTRESH                        3
-#define UART_IR_TXRDLATCH              4
-#define UART_IR_TXEMPTY                        5
-#define UART_IR_RXUNDER                        6
-#define UART_IR_RXOVER                 7
-#define UART_IR_RXTIMEOUT              8
-#define UART_IR_RXFULL                 9
-#define UART_IR_RXTHRESH               10
-#define UART_IR_RXNOTEMPTY             11
-#define UART_IR_RXFRAMEERR             12
-#define UART_IR_RXPARERR               13
-#define UART_IR_RXBRK                  14
-#define UART_IR_TXDONE                 15
-
-/* UART Fifo register */
-#define UART_FIFO_REG                  0x14
-#define UART_FIFO_VALID_SHIFT          0
-#define UART_FIFO_VALID_MASK           0xff
-#define UART_FIFO_FRAMEERR_SHIFT       8
-#define UART_FIFO_FRAMEERR_MASK                (1 << UART_FIFO_FRAMEERR_SHIFT)
-#define UART_FIFO_PARERR_SHIFT         9
-#define UART_FIFO_PARERR_MASK          (1 << UART_FIFO_PARERR_SHIFT)
-#define UART_FIFO_BRKDET_SHIFT         10
-#define UART_FIFO_BRKDET_MASK          (1 << UART_FIFO_BRKDET_SHIFT)
-#define UART_FIFO_ANYERR_MASK          (UART_FIFO_FRAMEERR_MASK |      \
-                                       UART_FIFO_PARERR_MASK |         \
-                                       UART_FIFO_BRKDET_MASK)
-
-
 /*************************************************************************
  * _REG relative to RSET_GPIO
  *************************************************************************/
index a9e8f6b62b0b9c9fa2a073f1aeb5c08f1d5a6894..7629c35986f7139c4fe797738d803e892af878e1 100644 (file)
@@ -49,11 +49,7 @@ static inline int plat_dma_supported(struct device *dev, u64 mask)
 
 static inline int plat_device_is_coherent(struct device *dev)
 {
-#ifdef CONFIG_DMA_COHERENT
-       return 1;
-#else
        return coherentio;
-#endif
 }
 
 #ifdef CONFIG_SWIOTLB
index 5b5cd689a2f7a0ef466bff9bcef694698525e529..e2561d99a3feaf12d9d54d948cf2403fc18a8d5c 100644 (file)
@@ -9,7 +9,6 @@
 #define __ASM_MACH_GENERIC_FLOPPY_H
 
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/sched.h>
 #include <linux/linkage.h>
index affa66f5c2dab0c1b616248c4100e1ed02587350..4ae5fbcb15a5a7ad0dd3c75363a28179d0ed71ca 100644 (file)
@@ -23,7 +23,7 @@
 static inline void __ide_flush_prologue(void)
 {
 #ifdef CONFIG_SMP
-       if (cpu_has_dc_aliases)
+       if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
                preempt_disable();
 #endif
 }
@@ -31,14 +31,14 @@ static inline void __ide_flush_prologue(void)
 static inline void __ide_flush_epilogue(void)
 {
 #ifdef CONFIG_SMP
-       if (cpu_has_dc_aliases)
+       if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc)
                preempt_enable();
 #endif
 }
 
 static inline void __ide_flush_dcache_range(unsigned long addr, unsigned long size)
 {
-       if (cpu_has_dc_aliases) {
+       if (cpu_has_dc_aliases || !cpu_has_ic_fills_f_dc) {
                unsigned long end = addr + size;
 
                while (addr < end) {
index 62aa1e287fba1782010e4aed0b31d704e6691990..4b86c88a03b7738ec4ad7370e8ada5d03b934dda 100644 (file)
@@ -9,7 +9,6 @@
 #define __ASM_MACH_JAZZ_FLOPPY_H
 
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/linkage.h>
 #include <linux/types.h>
 #include <linux/mm.h>
index 05988c2d65650970adc3861fd3e31d78a5f43140..069b43a9da6f0e574f96a20054fcada425ad1e71 100644 (file)
@@ -21,6 +21,7 @@
 
 extern struct platform_device jz4740_usb_ohci_device;
 extern struct platform_device jz4740_udc_device;
+extern struct platform_device jz4740_udc_xceiv_device;
 extern struct platform_device jz4740_mmc_device;
 extern struct platform_device jz4740_rtc_device;
 extern struct platform_device jz4740_i2c_device;
index 868ed8a2ed5c025cdf922586b9dfe56e1cd5f29e..c0dbd530cca612cd065f75eec23a096e24dc673e 100644 (file)
@@ -9,7 +9,8 @@
 #define __ASM_NETLOGIC_IRQ_H
 
 #include <asm/mach-netlogic/multi-node.h>
-#define NR_IRQS                        (64 * NLM_NR_NODES)
+#define NLM_IRQS_PER_NODE      1024
+#define NR_IRQS                        (NLM_IRQS_PER_NODE * NLM_NR_NODES)
 
 #define MIPS_CPU_IRQ_BASE      0
 
index d62fc773f4d7a9c0d0f30aa206caa806c143b702..9ed8dacdc37c5aa3bae8bbfc4e31cf5c6b51bed6 100644 (file)
 #endif
 #endif
 
-#define NLM_CORES_PER_NODE     8
 #define NLM_THREADS_PER_CORE   4
-#define NLM_CPUS_PER_NODE      (NLM_CORES_PER_NODE * NLM_THREADS_PER_CORE)
+#ifdef CONFIG_CPU_XLR
+#define nlm_cores_per_node()   8
+#else
+extern unsigned int xlp_cores_per_node;
+#define nlm_cores_per_node()   xlp_cores_per_node
+#endif
+
+#define nlm_threads_per_node() (nlm_cores_per_node() * NLM_THREADS_PER_CORE)
+#define nlm_cpuid_to_node(c)   ((c) / nlm_threads_per_node())
+
+struct nlm_soc_info {
+       unsigned long   coremask;       /* cores enabled on the soc */
+       unsigned long   ebase;          /* not used now */
+       uint64_t        irqmask;        /* EIMR for the node */
+       uint64_t        sysbase;        /* only for XLP - sys block base */
+       uint64_t        picbase;        /* PIC block base */
+       spinlock_t      piclock;        /* lock for PIC access */
+       cpumask_t       cpumask;        /* logical cpu mask for node */
+       unsigned int    socbus;
+};
+
+extern struct nlm_soc_info nlm_nodes[NLM_NR_NODES];
+#define nlm_get_node(i)                (&nlm_nodes[i])
+#define nlm_node_present(n)    ((n) >= 0 && (n) < NLM_NR_NODES && \
+                                       nlm_get_node(n)->coremask != 0)
+#ifdef CONFIG_CPU_XLR
+#define nlm_current_node()     (&nlm_nodes[0])
+#else
+#define nlm_current_node()     (&nlm_nodes[nlm_nodeid()])
+#endif
+void nlm_node_init(int node);
 
 #endif
diff --git a/arch/mips/include/asm/mach-netlogic/topology.h b/arch/mips/include/asm/mach-netlogic/topology.h
new file mode 100644 (file)
index 0000000..0da99fa
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2013 Broadcom Corporation
+ */
+#ifndef _ASM_MACH_NETLOGIC_TOPOLOGY_H
+#define _ASM_MACH_NETLOGIC_TOPOLOGY_H
+
+#include <asm/mach-netlogic/multi-node.h>
+
+#define topology_physical_package_id(cpu)      cpu_to_node(cpu)
+#define topology_core_id(cpu)  (cpu_logical_map(cpu) / NLM_THREADS_PER_CORE)
+#define topology_thread_cpumask(cpu)           (&cpu_sibling_map[cpu])
+#define topology_core_cpumask(cpu)     cpumask_of_node(cpu_to_node(cpu))
+
+#include <asm-generic/topology.h>
+
+#endif /* _ASM_MACH_NETLOGIC_TOPOLOGY_H */
index e33227998713e644a53e21c2e11c3e5fa174c970..836e2ede24de11252a7a4cce4a4008ed7756fee1 100644 (file)
 #define   PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_DISABLE       (1 << 7)
 #define   PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MASK          0xf
 #define   PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX           16
+/* SERIRQ Control */
+#define PIIX4_FUNC0_SERIRQC                    0x64
+#define   PIIX4_FUNC0_SERIRQC_EN                       (1 << 7)
+#define   PIIX4_FUNC0_SERIRQC_CONT                     (1 << 6)
 /* Top Of Memory */
 #define PIIX4_FUNC0_TOM                                0x69
 #define   PIIX4_FUNC0_TOM_TOP_OF_MEMORY_MASK           0xf0
@@ -34,6 +38,9 @@
 #define   PIIX4_FUNC0_DLC_USBPR_EN                     (1 << 2)
 #define   PIIX4_FUNC0_DLC_PASSIVE_RELEASE_EN           (1 << 1)
 #define   PIIX4_FUNC0_DLC_DELAYED_TRANSACTION_EN       (1 << 0)
+/* General Configuration */
+#define PIIX4_FUNC0_GENCFG                     0xb0
+#define   PIIX4_FUNC0_GENCFG_SERIRQ                    (1 << 16)
 
 /* IDE Timing */
 #define PIIX4_FUNC1_IDETIM_PRIMARY_LO          0x40
index e0331414c7d60f05cab6dc1c40788d513d71da23..bbc3dd4294bc31be3908543be66d385932412ae0 100644 (file)
@@ -14,6 +14,7 @@
 #define _ASM_MIPSREGS_H
 
 #include <linux/linkage.h>
+#include <linux/types.h>
 #include <asm/hazards.h>
 #include <asm/war.h>
 
 #define MIPS_CONF1_IA          (_ULCAST_(7) << 16)
 #define MIPS_CONF1_IL          (_ULCAST_(7) << 19)
 #define MIPS_CONF1_IS          (_ULCAST_(7) << 22)
-#define MIPS_CONF1_TLBS                (_ULCAST_(63)<< 25)
+#define MIPS_CONF1_TLBS_SHIFT   (25)
+#define MIPS_CONF1_TLBS_SIZE    (6)
+#define MIPS_CONF1_TLBS         (_ULCAST_(63) << MIPS_CONF1_TLBS_SHIFT)
 
 #define MIPS_CONF2_SA          (_ULCAST_(15)<<  0)
 #define MIPS_CONF2_SL          (_ULCAST_(15)<<  4)
 #define MIPS_CONF3_TL          (_ULCAST_(1) <<  0)
 #define MIPS_CONF3_SM          (_ULCAST_(1) <<  1)
 #define MIPS_CONF3_MT          (_ULCAST_(1) <<  2)
+#define MIPS_CONF3_CDMM                (_ULCAST_(1) <<  3)
 #define MIPS_CONF3_SP          (_ULCAST_(1) <<  4)
 #define MIPS_CONF3_VINT                (_ULCAST_(1) <<  5)
 #define MIPS_CONF3_VEIC                (_ULCAST_(1) <<  6)
 #define MIPS_CONF3_LPA         (_ULCAST_(1) <<  7)
+#define MIPS_CONF3_ITL         (_ULCAST_(1) <<  8)
+#define MIPS_CONF3_CTXTC       (_ULCAST_(1) <<  9)
 #define MIPS_CONF3_DSP         (_ULCAST_(1) << 10)
 #define MIPS_CONF3_DSP2P       (_ULCAST_(1) << 11)
 #define MIPS_CONF3_RXI         (_ULCAST_(1) << 12)
 #define MIPS_CONF3_ULRI                (_ULCAST_(1) << 13)
 #define MIPS_CONF3_ISA         (_ULCAST_(3) << 14)
 #define MIPS_CONF3_ISA_OE      (_ULCAST_(1) << 16)
+#define MIPS_CONF3_MCU         (_ULCAST_(1) << 17)
+#define MIPS_CONF3_MMAR                (_ULCAST_(7) << 18)
+#define MIPS_CONF3_IPLW                (_ULCAST_(3) << 21)
 #define MIPS_CONF3_VZ          (_ULCAST_(1) << 23)
-
+#define MIPS_CONF3_PW          (_ULCAST_(1) << 24)
+#define MIPS_CONF3_SC          (_ULCAST_(1) << 25)
+#define MIPS_CONF3_BI          (_ULCAST_(1) << 26)
+#define MIPS_CONF3_BP          (_ULCAST_(1) << 27)
+#define MIPS_CONF3_MSA         (_ULCAST_(1) << 28)
+#define MIPS_CONF3_CMGCR       (_ULCAST_(1) << 29)
+#define MIPS_CONF3_BPG         (_ULCAST_(1) << 30)
+
+#define MIPS_CONF4_MMUSIZEEXT_SHIFT    (0)
 #define MIPS_CONF4_MMUSIZEEXT  (_ULCAST_(255) << 0)
+#define MIPS_CONF4_FTLBSETS_SHIFT      (0)
+#define MIPS_CONF4_FTLBSETS_SHIFT      (0)
+#define MIPS_CONF4_FTLBSETS    (_ULCAST_(15) << MIPS_CONF4_FTLBSETS_SHIFT)
+#define MIPS_CONF4_FTLBWAYS_SHIFT      (4)
+#define MIPS_CONF4_FTLBWAYS    (_ULCAST_(15) << MIPS_CONF4_FTLBWAYS_SHIFT)
+#define MIPS_CONF4_FTLBPAGESIZE_SHIFT  (8)
+/* bits 10:8 in FTLB-only configurations */
+#define MIPS_CONF4_FTLBPAGESIZE (_ULCAST_(7) << MIPS_CONF4_FTLBPAGESIZE_SHIFT)
+/* bits 12:8 in VTLB-FTLB only configurations */
+#define MIPS_CONF4_VFTLBPAGESIZE (_ULCAST_(31) << MIPS_CONF4_FTLBPAGESIZE_SHIFT)
 #define MIPS_CONF4_MMUEXTDEF   (_ULCAST_(3) << 14)
 #define MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT (_ULCAST_(1) << 14)
+#define MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT       (_ULCAST_(2) << 14)
+#define MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT       (_ULCAST_(3) << 14)
+#define MIPS_CONF4_KSCREXIST   (_ULCAST_(255) << 16)
+#define MIPS_CONF4_VTLBSIZEEXT_SHIFT   (24)
+#define MIPS_CONF4_VTLBSIZEEXT (_ULCAST_(15) << MIPS_CONF4_VTLBSIZEEXT_SHIFT)
+#define MIPS_CONF4_AE          (_ULCAST_(1) << 28)
+#define MIPS_CONF4_IE          (_ULCAST_(3) << 29)
+#define MIPS_CONF4_TLBINV      (_ULCAST_(2) << 29)
 
 #define MIPS_CONF5_NF          (_ULCAST_(1) << 0)
 #define MIPS_CONF5_UFR         (_ULCAST_(1) << 2)
 #define MIPS_CONF5_K           (_ULCAST_(1) << 30)
 
 #define MIPS_CONF6_SYND                (_ULCAST_(1) << 13)
+/* proAptiv FTLB on/off bit */
+#define MIPS_CONF6_FTLBEN      (_ULCAST_(1) << 15)
 
 #define MIPS_CONF7_WII         (_ULCAST_(1) << 31)
 
 #define MIPS_CONF7_RPS         (_ULCAST_(1) << 2)
 
+/*  EntryHI bit definition */
+#define MIPS_ENTRYHI_EHINV     (_ULCAST_(1) << 10)
 
 /*
  * Bits in the MIPS32/64 coprocessor 1 (FPU) revision register.
 #define MIPS_FPIR_L            (_ULCAST_(1) << 21)
 #define MIPS_FPIR_F64          (_ULCAST_(1) << 22)
 
+/*
+ * Bits in the MIPS32 Memory Segmentation registers.
+ */
+#define MIPS_SEGCFG_PA_SHIFT   9
+#define MIPS_SEGCFG_PA         (_ULCAST_(127) << MIPS_SEGCFG_PA_SHIFT)
+#define MIPS_SEGCFG_AM_SHIFT   4
+#define MIPS_SEGCFG_AM         (_ULCAST_(7) << MIPS_SEGCFG_AM_SHIFT)
+#define MIPS_SEGCFG_EU_SHIFT   3
+#define MIPS_SEGCFG_EU         (_ULCAST_(1) << MIPS_SEGCFG_EU_SHIFT)
+#define MIPS_SEGCFG_C_SHIFT    0
+#define MIPS_SEGCFG_C          (_ULCAST_(7) << MIPS_SEGCFG_C_SHIFT)
+
+#define MIPS_SEGCFG_UUSK       _ULCAST_(7)
+#define MIPS_SEGCFG_USK                _ULCAST_(5)
+#define MIPS_SEGCFG_MUSUK      _ULCAST_(4)
+#define MIPS_SEGCFG_MUSK       _ULCAST_(3)
+#define MIPS_SEGCFG_MSK                _ULCAST_(2)
+#define MIPS_SEGCFG_MK         _ULCAST_(1)
+#define MIPS_SEGCFG_UK         _ULCAST_(0)
+
 #ifndef __ASSEMBLY__
 
 /*
@@ -648,6 +707,19 @@ static inline int mm_insn_16bit(u16 insn)
        return (opcode >= 1 && opcode <= 3) ? 1 : 0;
 }
 
+/*
+ * TLB Invalidate Flush
+ */
+static inline void tlbinvf(void)
+{
+       __asm__ __volatile__(
+               ".set push\n\t"
+               ".set noreorder\n\t"
+               ".word 0x42000004\n\t" /* tlbinvf */
+               ".set pop");
+}
+
+
 /*
  * Functions to access the R10000 performance counters.         These are basically
  * mfc0 and mtc0 instructions from and to coprocessor register with a 5-bit
@@ -1102,6 +1174,15 @@ do {                                                                     \
 #define read_c0_ebase()                __read_32bit_c0_register($15, 1)
 #define write_c0_ebase(val)    __write_32bit_c0_register($15, 1, val)
 
+/* MIPSR3 */
+#define read_c0_segctl0()      __read_32bit_c0_register($5, 2)
+#define write_c0_segctl0(val)  __write_32bit_c0_register($5, 2, val)
+
+#define read_c0_segctl1()      __read_32bit_c0_register($5, 3)
+#define write_c0_segctl1(val)  __write_32bit_c0_register($5, 3, val)
+
+#define read_c0_segctl2()      __read_32bit_c0_register($5, 4)
+#define write_c0_segctl2(val)  __write_32bit_c0_register($5, 4, val)
 
 /* Cavium OCTEON (cnMIPS) */
 #define read_c0_cvmcount()     __read_ulong_c0_register($9, 6)
index bb68c3398c8085d74170b4ef9b735a3fa0c30adb..c281f03eb312634c16a0a383e3600a0d3ee8ed50 100644 (file)
@@ -84,7 +84,6 @@ nlm_set_nmi_handler(void *handler)
  */
 void nlm_init_boot_cpu(void);
 unsigned int nlm_get_cpu_frequency(void);
-void nlm_node_init(int node);
 extern struct plat_smp_ops nlm_smp_ops;
 extern char nlm_reset_entry[], nlm_reset_entry_end[];
 
@@ -94,26 +93,16 @@ extern struct dma_map_ops nlm_swiotlb_dma_ops;
 extern unsigned int nlm_threads_per_core;
 extern cpumask_t nlm_cpumask;
 
-struct nlm_soc_info {
-       unsigned long coremask; /* cores enabled on the soc */
-       unsigned long ebase;
-       uint64_t irqmask;
-       uint64_t sysbase;       /* only for XLP */
-       uint64_t picbase;
-       spinlock_t piclock;
-};
-
-#define nlm_get_node(i)                (&nlm_nodes[i])
-#ifdef CONFIG_CPU_XLR
-#define nlm_current_node()     (&nlm_nodes[0])
-#else
-#define nlm_current_node()     (&nlm_nodes[nlm_nodeid()])
-#endif
-
 struct irq_data;
 uint64_t nlm_pci_irqmask(int node);
+void nlm_setup_pic_irq(int node, int picirq, int irq, int irt);
 void nlm_set_pic_extra_ack(int node, int irq,  void (*xack)(struct irq_data *));
 
+#ifdef CONFIG_PCI_MSI
+void nlm_dispatch_msi(int node, int lirq);
+void nlm_dispatch_msix(int node, int msixirq);
+#endif
+
 /*
  * The NR_IRQs is divided between nodes, each of them has a separate irq space
  */
@@ -122,7 +111,6 @@ static inline int nlm_irq_to_xirq(int node, int irq)
        return node * NR_IRQS / NLM_NR_NODES + irq;
 }
 
-extern struct nlm_soc_info nlm_nodes[NLM_NR_NODES];
 extern int nlm_cpu_ready[];
 #endif
 #endif /* _NETLOGIC_COMMON_H_ */
index f299d31d7c1a3faf7eeffd22f7409cce90954cd6..de9aada6f4c1cbd6f0bee1997f7e1744694b04f2 100644 (file)
@@ -146,7 +146,12 @@ static inline int hard_smp_processor_id(void)
 
 static inline int nlm_nodeid(void)
 {
-       return (__read_32bit_c0_register($15, 1) >> 5) & 0x3;
+       uint32_t prid = read_c0_prid();
+
+       if ((prid & 0xff00) == PRID_IMP_NETLOGIC_XLP9XX)
+               return (__read_32bit_c0_register($15, 1) >> 7) & 0x7;
+       else
+               return (__read_32bit_c0_register($15, 1) >> 5) & 0x3;
 }
 
 static inline unsigned int nlm_core_id(void)
index 4e8eacb9588a2b1a69f81d56715c49d719102921..3067f983495d7e74f409bf552e3884ad1b3c75cb 100644 (file)
 #define BRIDGE_FLASH_LIMIT3            0x13
 
 #define BRIDGE_DRAM_BAR(i)             (0x14 + (i))
-#define BRIDGE_DRAM_BAR0               0x14
-#define BRIDGE_DRAM_BAR1               0x15
-#define BRIDGE_DRAM_BAR2               0x16
-#define BRIDGE_DRAM_BAR3               0x17
-#define BRIDGE_DRAM_BAR4               0x18
-#define BRIDGE_DRAM_BAR5               0x19
-#define BRIDGE_DRAM_BAR6               0x1a
-#define BRIDGE_DRAM_BAR7               0x1b
-
 #define BRIDGE_DRAM_LIMIT(i)           (0x1c + (i))
-#define BRIDGE_DRAM_LIMIT0             0x1c
-#define BRIDGE_DRAM_LIMIT1             0x1d
-#define BRIDGE_DRAM_LIMIT2             0x1e
-#define BRIDGE_DRAM_LIMIT3             0x1f
-#define BRIDGE_DRAM_LIMIT4             0x20
-#define BRIDGE_DRAM_LIMIT5             0x21
-#define BRIDGE_DRAM_LIMIT6             0x22
-#define BRIDGE_DRAM_LIMIT7             0x23
-
 #define BRIDGE_DRAM_NODE_TRANSLN(i)    (0x24 + (i))
-#define BRIDGE_DRAM_NODE_TRANSLN0      0x24
-#define BRIDGE_DRAM_NODE_TRANSLN1      0x25
-#define BRIDGE_DRAM_NODE_TRANSLN2      0x26
-#define BRIDGE_DRAM_NODE_TRANSLN3      0x27
-#define BRIDGE_DRAM_NODE_TRANSLN4      0x28
-#define BRIDGE_DRAM_NODE_TRANSLN5      0x29
-#define BRIDGE_DRAM_NODE_TRANSLN6      0x2a
-#define BRIDGE_DRAM_NODE_TRANSLN7      0x2b
-
 #define BRIDGE_DRAM_CHNL_TRANSLN(i)    (0x2c + (i))
-#define BRIDGE_DRAM_CHNL_TRANSLN0      0x2c
-#define BRIDGE_DRAM_CHNL_TRANSLN1      0x2d
-#define BRIDGE_DRAM_CHNL_TRANSLN2      0x2e
-#define BRIDGE_DRAM_CHNL_TRANSLN3      0x2f
-#define BRIDGE_DRAM_CHNL_TRANSLN4      0x30
-#define BRIDGE_DRAM_CHNL_TRANSLN5      0x31
-#define BRIDGE_DRAM_CHNL_TRANSLN6      0x32
-#define BRIDGE_DRAM_CHNL_TRANSLN7      0x33
 
 #define BRIDGE_PCIEMEM_BASE0           0x34
 #define BRIDGE_PCIEMEM_BASE1           0x35
 #define BRIDGE_GIO_WEIGHT              0x2cb
 #define BRIDGE_FLASH_WEIGHT            0x2cc
 
+/* FIXME verify */
+#define BRIDGE_9XX_FLASH_BAR(i)                (0x11 + (i))
+#define BRIDGE_9XX_FLASH_BAR_LIMIT(i)  (0x15 + (i))
+
+#define BRIDGE_9XX_DRAM_BAR(i)         (0x19 + (i))
+#define BRIDGE_9XX_DRAM_LIMIT(i)       (0x29 + (i))
+#define BRIDGE_9XX_DRAM_NODE_TRANSLN(i)        (0x39 + (i))
+#define BRIDGE_9XX_DRAM_CHNL_TRANSLN(i)        (0x49 + (i))
+
+#define BRIDGE_9XX_ADDRESS_ERROR0      0x9d
+#define BRIDGE_9XX_ADDRESS_ERROR1      0x9e
+#define BRIDGE_9XX_ADDRESS_ERROR2      0x9f
+
+#define BRIDGE_9XX_PCIEMEM_BASE0       0x59
+#define BRIDGE_9XX_PCIEMEM_BASE1       0x5a
+#define BRIDGE_9XX_PCIEMEM_BASE2       0x5b
+#define BRIDGE_9XX_PCIEMEM_BASE3       0x5c
+#define BRIDGE_9XX_PCIEMEM_LIMIT0      0x5d
+#define BRIDGE_9XX_PCIEMEM_LIMIT1      0x5e
+#define BRIDGE_9XX_PCIEMEM_LIMIT2      0x5f
+#define BRIDGE_9XX_PCIEMEM_LIMIT3      0x60
+#define BRIDGE_9XX_PCIEIO_BASE0                0x61
+#define BRIDGE_9XX_PCIEIO_BASE1                0x62
+#define BRIDGE_9XX_PCIEIO_BASE2                0x63
+#define BRIDGE_9XX_PCIEIO_BASE3                0x64
+#define BRIDGE_9XX_PCIEIO_LIMIT0       0x65
+#define BRIDGE_9XX_PCIEIO_LIMIT1       0x66
+#define BRIDGE_9XX_PCIEIO_LIMIT2       0x67
+#define BRIDGE_9XX_PCIEIO_LIMIT3       0x68
+
 #ifndef __ASSEMBLY__
 
 #define nlm_read_bridge_reg(b, r)      nlm_read_reg(b, r)
 #define nlm_write_bridge_reg(b, r, v)  nlm_write_reg(b, r, v)
-#define nlm_get_bridge_pcibase(node)   \
-                       nlm_pcicfg_base(XLP_IO_BRIDGE_OFFSET(node))
+#define nlm_get_bridge_pcibase(node)   nlm_pcicfg_base(cpu_is_xlp9xx() ? \
+               XLP9XX_IO_BRIDGE_OFFSET(node) : XLP_IO_BRIDGE_OFFSET(node))
 #define nlm_get_bridge_regbase(node)   \
                        (nlm_get_bridge_pcibase(node) + XLP_IO_PCI_HDRSZ)
 
index 55eee77adaca5d121affce8e3566fc7476ec113e..1f23dfaa7167bc150ca51da72b93030176d829fb 100644 (file)
 #define XLP_IO_SIZE                    (64 << 20)      /* ECFG space size */
 #define XLP_IO_PCI_HDRSZ               0x100
 #define XLP_IO_DEV(node, dev)          ((dev) + (node) * 8)
-#define XLP_HDR_OFFSET(node, bus, dev, fn)     (((bus) << 20) | \
-                               ((XLP_IO_DEV(node, dev)) << 15) | ((fn) << 12))
+#define XLP_IO_PCI_OFFSET(b, d, f)     (((b) << 20) | ((d) << 15) | ((f) << 12))
+
+#define XLP_HDR_OFFSET(node, bus, dev, fn) \
+               XLP_IO_PCI_OFFSET(bus, XLP_IO_DEV(node, dev), fn)
 
 #define XLP_IO_BRIDGE_OFFSET(node)     XLP_HDR_OFFSET(node, 0, 0, 0)
 /* coherent inter chip */
 #define XLP_IO_MMC_OFFSET(node, slot)  \
                ((XLP_IO_SD_OFFSET(node))+(slot*0x100)+XLP_IO_PCI_HDRSZ)
 
+/* Things have changed drastically in XLP 9XX */
+#define XLP9XX_HDR_OFFSET(n, d, f)     \
+                       XLP_IO_PCI_OFFSET(xlp9xx_get_socbus(n), d, f)
+
+#define XLP9XX_IO_BRIDGE_OFFSET(node)  XLP_IO_PCI_OFFSET(0, 0, node)
+#define XLP9XX_IO_PIC_OFFSET(node)     XLP9XX_HDR_OFFSET(node, 2, 0)
+#define XLP9XX_IO_UART_OFFSET(node)    XLP9XX_HDR_OFFSET(node, 2, 2)
+#define XLP9XX_IO_SYS_OFFSET(node)     XLP9XX_HDR_OFFSET(node, 6, 0)
+#define XLP9XX_IO_FUSE_OFFSET(node)    XLP9XX_HDR_OFFSET(node, 6, 1)
+#define XLP9XX_IO_JTAG_OFFSET(node)    XLP9XX_HDR_OFFSET(node, 6, 4)
+
+#define XLP9XX_IO_PCIE_OFFSET(node, i) XLP9XX_HDR_OFFSET(node, 1, i)
+#define XLP9XX_IO_PCIE0_OFFSET(node)   XLP9XX_HDR_OFFSET(node, 1, 0)
+#define XLP9XX_IO_PCIE2_OFFSET(node)   XLP9XX_HDR_OFFSET(node, 1, 2)
+#define XLP9XX_IO_PCIE3_OFFSET(node)   XLP9XX_HDR_OFFSET(node, 1, 3)
+
+/* XLP9xx USB block */
+#define XLP9XX_IO_USB_OFFSET(node, i)          XLP9XX_HDR_OFFSET(node, 4, i)
+#define XLP9XX_IO_USB_XHCI0_OFFSET(node)       XLP9XX_HDR_OFFSET(node, 4, 1)
+#define XLP9XX_IO_USB_XHCI1_OFFSET(node)       XLP9XX_HDR_OFFSET(node, 4, 2)
+
+/* XLP9XX on-chip SATA controller */
+#define XLP9XX_IO_SATA_OFFSET(node)            XLP9XX_HDR_OFFSET(node, 3, 2)
+
+#define XLP9XX_IO_NOR_OFFSET(node)             XLP9XX_HDR_OFFSET(node, 7, 0)
+#define XLP9XX_IO_NAND_OFFSET(node)            XLP9XX_HDR_OFFSET(node, 7, 1)
+#define XLP9XX_IO_SPI_OFFSET(node)             XLP9XX_HDR_OFFSET(node, 7, 2)
+/* SD flash */
+#define XLP9XX_IO_MMCSD_OFFSET(node)           XLP9XX_HDR_OFFSET(node, 7, 3)
+
 /* PCI config header register id's */
 #define XLP_PCI_CFGREG0                        0x00
 #define XLP_PCI_CFGREG1                        0x01
 #define PCI_DEVICE_ID_NLM_MMC          0x1018
 #define PCI_DEVICE_ID_NLM_XHCI         0x101d
 
+#define PCI_DEVICE_ID_XLP9XX_SATA      0x901A
+#define PCI_DEVICE_ID_XLP9XX_XHCI      0x901D
+
 #ifndef __ASSEMBLY__
 
 #define nlm_read_pci_reg(b, r)         nlm_read_reg(b, r)
 #define nlm_write_pci_reg(b, r, v)     nlm_write_reg(b, r, v)
 
+static inline int xlp9xx_get_socbus(int node)
+{
+       uint64_t socbridge;
+
+       if (node == 0)
+               return 1;
+       socbridge = nlm_pcicfg_base(XLP9XX_IO_BRIDGE_OFFSET(node));
+       return (nlm_read_pci_reg(socbridge, 0x6) >> 8) & 0xff;
+}
 #endif /* !__ASSEMBLY */
 
 #endif /* __NLM_HAL_IOMAP_H__ */
index b559cb9f56ea78bd056b92d1faca753189608bb7..d4deb87ad06991bb0e374bad8baa2329c9dcf3a5 100644 (file)
 #define PCIE_BYTE_SWAP_MEM_LIM         0x248
 #define PCIE_BYTE_SWAP_IO_BASE         0x249
 #define PCIE_BYTE_SWAP_IO_LIM          0x24A
+
+#define PCIE_BRIDGE_MSIX_ADDR_BASE     0x24F
+#define PCIE_BRIDGE_MSIX_ADDR_LIMIT    0x250
 #define PCIE_MSI_STATUS                        0x25A
 #define PCIE_MSI_EN                    0x25B
+#define PCIE_MSIX_STATUS               0x25D
+#define PCIE_INT_STATUS0               0x25F
+#define PCIE_INT_STATUS1               0x260
 #define PCIE_INT_EN0                   0x261
+#define PCIE_INT_EN1                   0x262
 
-/* PCIE_MSI_EN */
-#define PCIE_MSI_VECTOR_INT_EN         0xFFFFFFFF
+/* XLP9XX has basic changes */
+#define PCIE_9XX_BYTE_SWAP_MEM_BASE    0x25c
+#define PCIE_9XX_BYTE_SWAP_MEM_LIM     0x25d
+#define PCIE_9XX_BYTE_SWAP_IO_BASE     0x25e
+#define PCIE_9XX_BYTE_SWAP_IO_LIM      0x25f
 
-/* PCIE_INT_EN0 */
-#define PCIE_MSI_INT_EN                        (1 << 9)
+/* other */
+#define PCIE_NLINKS                    4
 
+/* MSI addresses */
+#define MSI_ADDR_BASE                  0xfffee00000ULL
+#define MSI_ADDR_SZ                    0x10000
+#define MSI_LINK_ADDR(n, l)            (MSI_ADDR_BASE + \
+                               (PCIE_NLINKS * (n) + (l)) * MSI_ADDR_SZ)
+#define MSIX_ADDR_BASE                 0xfffef00000ULL
+#define MSIX_LINK_ADDR(n, l)           (MSIX_ADDR_BASE + \
+                               (PCIE_NLINKS * (n) + (l)) * MSI_ADDR_SZ)
 #ifndef __ASSEMBLY__
 
 #define nlm_read_pcie_reg(b, r)                nlm_read_reg(b, r)
 #define nlm_write_pcie_reg(b, r, v)    nlm_write_reg(b, r, v)
-#define nlm_get_pcie_base(node, inst)  \
-                       nlm_pcicfg_base(XLP_IO_PCIE_OFFSET(node, inst))
-#define nlm_get_pcie_regbase(node, inst)       \
-                       (nlm_get_pcie_base(node, inst) + XLP_IO_PCI_HDRSZ)
+#define nlm_get_pcie_base(node, inst)  nlm_pcicfg_base(cpu_is_xlp9xx() ? \
+       XLP9XX_IO_PCIE_OFFSET(node, inst) : XLP_IO_PCIE_OFFSET(node, inst))
+
+#ifdef CONFIG_PCI_MSI
+void xlp_init_node_msi_irqs(int node, int link);
+#else
+static inline void xlp_init_node_msi_irqs(int node, int link) {}
+#endif
+
+struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev);
 
-int xlp_pcie_link_irt(int link);
 #endif
 #endif /* __NLM_HAL_PCIBUS_H__ */
index 105389b79f09392d1d6ebe086adfb4d0ffb9d091..f10bf3bba58fc5f87df74915c6398f1f9b6b0b3b 100644 (file)
 #define PIC_IRT0               0x74
 #define PIC_IRT(i)             (PIC_IRT0 + ((i) * 2))
 
-#define TIMER_CYCLES_MAXVAL    0xffffffffffffffffULL
+#define PIC_9XX_PENDING_0      0x6
+#define PIC_9XX_PENDING_1      0x8
+#define PIC_9XX_PENDING_2      0xa
+#define PIC_9XX_PENDING_3      0xc
+
+#define PIC_9XX_IRT0           0x1c0
+#define PIC_9XX_IRT(i)         (PIC_9XX_IRT0 + ((i) * 2))
 
 /*
  *    IRT Map
  */
 #define PIC_NUM_IRTS           160
+#define PIC_9XX_NUM_IRTS       256
 
 #define PIC_IRT_WD_0_INDEX     0
 #define PIC_IRT_WD_1_INDEX     1
 #define PIC_IRT_PCIE_LINK_INDEX(num)   ((num) + PIC_IRT_PCIE_LINK_0_INDEX)
 
 #define PIC_CLOCK_TIMER                        7
-#define PIC_IRQ_BASE                   8
 
 #if !defined(LOCORE) && !defined(__ASSEMBLY__)
 
-#define PIC_IRT_FIRST_IRQ              (PIC_IRQ_BASE)
-#define PIC_IRT_LAST_IRQ               63
-#define PIC_IRQ_IS_IRT(irq)            ((irq) >= PIC_IRT_FIRST_IRQ)
-
 /*
  *   Misc
  */
 
 #define nlm_read_pic_reg(b, r) nlm_read_reg64(b, r)
 #define nlm_write_pic_reg(b, r, v) nlm_write_reg64(b, r, v)
-#define nlm_get_pic_pcibase(node) nlm_pcicfg_base(XLP_IO_PIC_OFFSET(node))
+#define nlm_get_pic_pcibase(node)      nlm_pcicfg_base(cpu_is_xlp9xx() ? \
+               XLP9XX_IO_PIC_OFFSET(node) : XLP_IO_PIC_OFFSET(node))
 #define nlm_get_pic_regbase(node) (nlm_get_pic_pcibase(node) + XLP_IO_PCI_HDRSZ)
 
 /* We use PIC on node 0 as a timer */
 #define pic_timer_freq()               nlm_get_pic_frequency(0)
 
 /* IRT and h/w interrupt routines */
-static inline int
-nlm_pic_read_irt(uint64_t base, int irt_index)
-{
-       return nlm_read_pic_reg(base, PIC_IRT(irt_index));
-}
-
 static inline void
-nlm_set_irt_to_cpu(uint64_t base, int irt, int cpu)
+nlm_9xx_pic_write_irt(uint64_t base, int irt_num, int en, int nmi,
+       int sch, int vec, int dt, int db, int cpu)
 {
        uint64_t val;
 
-       val = nlm_read_pic_reg(base, PIC_IRT(irt));
-       /* clear cpuset and mask */
-       val &= ~((0x7ull << 16) | 0xffff);
-       /* set DB, cpuset and cpumask */
-       val |= (1 << 19) | ((cpu >> 4) << 16) | (1 << (cpu & 0xf));
-       nlm_write_pic_reg(base, PIC_IRT(irt), val);
+       val = (((uint64_t)en & 0x1) << 22) | ((nmi & 0x1) << 23) |
+                       ((0 /*mc*/) << 20) | ((vec & 0x3f) << 24) |
+                       ((dt & 0x1) << 21) | (0 /*ptr*/ << 16) |
+                       (cpu & 0x3ff);
+
+       nlm_write_pic_reg(base, PIC_9XX_IRT(irt_num), val);
 }
 
 static inline void
@@ -254,9 +252,13 @@ static inline void
 nlm_pic_write_irt_direct(uint64_t base, int irt_num, int en, int nmi,
        int sch, int vec, int cpu)
 {
-       nlm_pic_write_irt(base, irt_num, en, nmi, sch, vec, 1,
-               (cpu >> 4),             /* thread group */
-               1 << (cpu & 0xf));      /* thread mask */
+       if (cpu_is_xlp9xx())
+               nlm_9xx_pic_write_irt(base, irt_num, en, nmi, sch, vec,
+                                                       1, 0, cpu);
+       else
+               nlm_pic_write_irt(base, irt_num, en, nmi, sch, vec, 1,
+                       (cpu >> 4),             /* thread group */
+                       1 << (cpu & 0xf));      /* thread mask */
 }
 
 static inline uint64_t
@@ -298,8 +300,13 @@ nlm_pic_enable_irt(uint64_t base, int irt)
 {
        uint64_t reg;
 
-       reg = nlm_read_pic_reg(base, PIC_IRT(irt));
-       nlm_write_pic_reg(base, PIC_IRT(irt), reg | (1u << 31));
+       if (cpu_is_xlp9xx()) {
+               reg = nlm_read_pic_reg(base, PIC_9XX_IRT(irt));
+               nlm_write_pic_reg(base, PIC_9XX_IRT(irt), reg | (1 << 22));
+       } else {
+               reg = nlm_read_pic_reg(base, PIC_IRT(irt));
+               nlm_write_pic_reg(base, PIC_IRT(irt), reg | (1u << 31));
+       }
 }
 
 static inline void
@@ -307,8 +314,15 @@ nlm_pic_disable_irt(uint64_t base, int irt)
 {
        uint64_t reg;
 
-       reg = nlm_read_pic_reg(base, PIC_IRT(irt));
-       nlm_write_pic_reg(base, PIC_IRT(irt), reg & ~((uint64_t)1 << 31));
+       if (cpu_is_xlp9xx()) {
+               reg = nlm_read_pic_reg(base, PIC_9XX_IRT(irt));
+               reg &= ~((uint64_t)1 << 22);
+               nlm_write_pic_reg(base, PIC_9XX_IRT(irt), reg);
+       } else {
+               reg = nlm_read_pic_reg(base, PIC_IRT(irt));
+               reg &= ~((uint64_t)1 << 31);
+               nlm_write_pic_reg(base, PIC_IRT(irt), reg);
+       }
 }
 
 static inline void
@@ -316,8 +330,13 @@ nlm_pic_send_ipi(uint64_t base, int hwt, int irq, int nmi)
 {
        uint64_t ipi;
 
-       ipi = ((uint64_t)nmi << 31) | (irq << 20);
-       ipi |= ((hwt >> 4) << 16) | (1 << (hwt & 0xf)); /* cpuset and mask */
+       if (cpu_is_xlp9xx())
+               ipi = (nmi << 23) | (irq << 24) |
+                       (0/*mcm*/ << 20) | (0/*ptr*/ << 16) | hwt;
+       else
+               ipi = ((uint64_t)nmi << 31) | (irq << 20) |
+                       ((hwt >> 4) << 16) | (1 << (hwt & 0xf));
+
        nlm_write_pic_reg(base, PIC_IPI_CTL, ipi);
 }
 
index fcf2833c16ca9d42c5119b3250cba8b20452d09e..d9b107ffca933ca525235321200f63f872a1d8c3 100644 (file)
 #define SYS_SYS_PLL_MEM_REQ                    0x2a3
 #define SYS_PLL_MEM_STAT                       0x2a4
 
+/* Registers changed on 9XX */
+#define SYS_9XX_POWER_ON_RESET_CFG             0x00
+#define SYS_9XX_CHIP_RESET                     0x01
+#define SYS_9XX_CPU_RESET                      0x02
+#define SYS_9XX_CPU_NONCOHERENT_MODE           0x03
+
+/* XLP 9XX fuse block registers */
+#define FUSE_9XX_DEVCFG6                       0xc6
+
 #ifndef __ASSEMBLY__
 
 #define nlm_read_sys_reg(b, r)         nlm_read_reg(b, r)
 #define nlm_write_sys_reg(b, r, v)     nlm_write_reg(b, r, v)
-#define nlm_get_sys_pcibase(node) nlm_pcicfg_base(XLP_IO_SYS_OFFSET(node))
+#define nlm_get_sys_pcibase(node)      nlm_pcicfg_base(cpu_is_xlp9xx() ? \
+               XLP9XX_IO_SYS_OFFSET(node) : XLP_IO_SYS_OFFSET(node))
 #define nlm_get_sys_regbase(node) (nlm_get_sys_pcibase(node) + XLP_IO_PCI_HDRSZ)
 
+/* XLP9XX fuse block */
+#define nlm_get_fuse_pcibase(node)     \
+                       nlm_pcicfg_base(XLP9XX_IO_FUSE_OFFSET(node))
+#define nlm_get_fuse_regbase(node)     \
+                       (nlm_get_fuse_pcibase(node) + XLP_IO_PCI_HDRSZ)
+
 unsigned int nlm_get_pic_frequency(int node);
 #endif
 #endif
index 86d16e1e60720caedb6470debf9d0a9654dbcac6..a6c54424dd95cadf51cc2658fb22f9283409b155 100644 (file)
@@ -94,7 +94,8 @@
 #define nlm_read_uart_reg(b, r)                nlm_read_reg(b, r)
 #define nlm_write_uart_reg(b, r, v)    nlm_write_reg(b, r, v)
 #define nlm_get_uart_pcibase(node, inst)       \
-               nlm_pcicfg_base(XLP_IO_UART_OFFSET(node, inst))
+       nlm_pcicfg_base(cpu_is_xlp9xx() ?  XLP9XX_IO_UART_OFFSET(node) : \
+                                               XLP_IO_UART_OFFSET(node, inst))
 #define nlm_get_uart_regbase(node, inst)       \
                        (nlm_get_uart_pcibase(node, inst) + XLP_IO_PCI_HDRSZ)
 
index 470f2095b34613e6ab93851334f560c8421cceff..2b0c9599ebe595701127749b138c823ce9488613 100644 (file)
 
 #define PIC_UART_0_IRQ                 17
 #define PIC_UART_1_IRQ                 18
-#define PIC_PCIE_LINK_0_IRQ            19
-#define PIC_PCIE_LINK_1_IRQ            20
-#define PIC_PCIE_LINK_2_IRQ            21
-#define PIC_PCIE_LINK_3_IRQ            22
+
+#define PIC_PCIE_LINK_LEGACY_IRQ_BASE  19
+#define PIC_PCIE_LINK_LEGACY_IRQ(i)    (19 + (i))
 
 #define PIC_EHCI_0_IRQ                 23
 #define PIC_EHCI_1_IRQ                 24
@@ -51,6 +50,8 @@
 #define PIC_2XX_XHCI_0_IRQ             23
 #define PIC_2XX_XHCI_1_IRQ             24
 #define PIC_2XX_XHCI_2_IRQ             25
+#define PIC_9XX_XHCI_0_IRQ             23
+#define PIC_9XX_XHCI_1_IRQ             24
 
 #define PIC_MMC_IRQ                    29
 #define PIC_I2C_0_IRQ                  30
 #define PIC_I2C_2_IRQ                  32
 #define PIC_I2C_3_IRQ                  33
 
+#define PIC_PCIE_LINK_MSI_IRQ_BASE     44      /* 44 - 47 MSI IRQ */
+#define PIC_PCIE_LINK_MSI_IRQ(i)       (44 + (i))
+
+/* MSI-X with second link-level dispatch */
+#define PIC_PCIE_MSIX_IRQ_BASE         48      /* 48 - 51 MSI-X IRQ */
+#define PIC_PCIE_MSIX_IRQ(i)           (48 + (i))
+
+#define NLM_MSIX_VEC_BASE              96      /* 96 - 127 - MSIX mapped */
+#define NLM_MSI_VEC_BASE               128     /* 128 -255 - MSI mapped */
+
+#define NLM_PIC_INDIRECT_VEC_BASE      512
+#define NLM_GPIO_VEC_BASE              768
+
+#define PIC_IRQ_BASE                   8
+#define PIC_IRT_FIRST_IRQ              PIC_IRQ_BASE
+#define PIC_IRT_LAST_IRQ               63
+
 #ifndef __ASSEMBLY__
 
 /* SMP support functions */
@@ -68,6 +86,9 @@ void xlp_mmu_init(void);
 void nlm_hal_init(void);
 int xlp_get_dram_map(int n, uint64_t *dram_map);
 
+struct pci_dev;
+int xlp_socdev_to_node(const struct pci_dev *dev);
+
 /* Device tree related */
 void xlp_early_init_devtree(void);
 void *xlp_dt_init(void *fdtp);
@@ -76,8 +97,15 @@ static inline int cpu_is_xlpii(void)
 {
        int chip = read_c0_prid() & 0xff00;
 
-       return chip == PRID_IMP_NETLOGIC_XLP2XX;
+       return chip == PRID_IMP_NETLOGIC_XLP2XX ||
+               chip == PRID_IMP_NETLOGIC_XLP9XX;
 }
 
+static inline int cpu_is_xlp9xx(void)
+{
+       int chip = read_c0_prid() & 0xff00;
+
+       return chip == PRID_IMP_NETLOGIC_XLP9XX;
+}
 #endif /* !__ASSEMBLY__ */
 #endif /* _ASM_NLM_XLP_H */
index c1667e0c272a4d7019efe22ff6d638a73d9fb99c..ceb991ca843697546d2dcfde15a0594f348a7392 100644 (file)
 #ifndef _ASM_NLM_XLR_H
 #define _ASM_NLM_XLR_H
 
-/* Platform UART functions */
-struct uart_port;
-unsigned int nlm_xlr_uart_in(struct uart_port *, int);
-void nlm_xlr_uart_out(struct uart_port *, int, int);
-
 /* SMP helpers */
 void xlr_wakeup_secondary_cpus(void);
 
index 41785dd0ddd0a0923583d06b39c8ce84e1fbb347..893320375aefaf44f1779e18889bbec4e2dc2555 100644 (file)
 
 #include <asm/octeon/cvmx-helper.h>
 
+enum cvmx_helper_board_usb_clock_types {
+       USB_CLOCK_TYPE_REF_12,
+       USB_CLOCK_TYPE_REF_24,
+       USB_CLOCK_TYPE_REF_48,
+       USB_CLOCK_TYPE_CRYSTAL_12,
+};
+
 typedef enum {
        set_phy_link_flags_autoneg = 0x1,
        set_phy_link_flags_flow_control_dont_touch = 0x0 << 1,
@@ -154,4 +161,6 @@ extern int __cvmx_helper_board_interface_probe(int interface,
  */
 extern int __cvmx_helper_board_hardware_enable(int interface);
 
+enum cvmx_helper_board_usb_clock_types __cvmx_helper_board_usb_get_clock_type(void);
+
 #endif /* __CVMX_HELPER_BOARD_H__ */
index f6be4741f7e839d30d1c7d6b30ab666db4221350..5e08bcc74897ab35c377c2d3b4cca9e7a9829824 100644 (file)
@@ -11,6 +11,8 @@
 
 #include <spaces.h>
 #include <linux/const.h>
+#include <linux/kernel.h>
+#include <asm/mipsregs.h>
 
 /*
  * PAGE_SHIFT determines the page size
 #define PAGE_SIZE      (_AC(1,UL) << PAGE_SHIFT)
 #define PAGE_MASK      (~((1 << PAGE_SHIFT) - 1))
 
+/*
+ * This is used for calculating the real page sizes
+ * for FTLB or VTLB + FTLB confugrations.
+ */
+static inline unsigned int page_size_ftlb(unsigned int mmuextdef)
+{
+       switch (mmuextdef) {
+       case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
+               if (PAGE_SIZE == (1 << 30))
+                       return 5;
+               if (PAGE_SIZE == (1llu << 32))
+                       return 6;
+               if (PAGE_SIZE > (256 << 10))
+                       return 7; /* reserved */
+                       /* fall through */
+       case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT:
+               return (PAGE_SHIFT - 10) / 2;
+       default:
+               panic("Invalid FTLB configuration with Conf4_mmuextdef=%d value\n",
+                     mmuextdef >> 14);
+       }
+}
+
 #ifdef CONFIG_MIPS_HUGE_TLB_SUPPORT
 #define HPAGE_SHIFT    (PAGE_SHIFT + PAGE_SHIFT - 3)
 #define HPAGE_SIZE     (_AC(1,UL) << HPAGE_SHIFT)
index 90985b61dbd9a2c83cbf7acaa43d253521525c91..c1020654876e82faa7a9197e2dcca78e503b3b7e 100644 (file)
@@ -1,13 +1,18 @@
 /*
- * Copyright (C) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
  *
+ * Copyright (C) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
  */
-
 #ifndef __ASM_RTLX_H_
 #define __ASM_RTLX_H_
 
 #include <irq.h>
 
+#define RTLX_MODULE_NAME "rtlx"
+
 #define LX_NODE_BASE 10
 
 #define MIPS_CPU_RTLX_IRQ 0
 #define RTLX_VERSION 2
 #define RTLX_xID 0x12345600
 #define RTLX_ID (RTLX_xID | RTLX_VERSION)
+#define RTLX_BUFFER_SIZE 2048
 #define RTLX_CHANNELS 8
 
 #define RTLX_CHANNEL_STDIO     0
 #define RTLX_CHANNEL_DBG       1
 #define RTLX_CHANNEL_SYSIO     2
 
-extern int rtlx_open(int index, int can_sleep);
-extern int rtlx_release(int index);
-extern ssize_t rtlx_read(int index, void __user *buff, size_t count);
-extern ssize_t rtlx_write(int index, const void __user *buffer, size_t count);
-extern unsigned int rtlx_read_poll(int index, int can_sleep);
-extern unsigned int rtlx_write_poll(int index);
+void rtlx_starting(int vpe);
+void rtlx_stopping(int vpe);
+
+int rtlx_open(int index, int can_sleep);
+int rtlx_release(int index);
+ssize_t rtlx_read(int index, void __user *buff, size_t count);
+ssize_t rtlx_write(int index, const void __user *buffer, size_t count);
+unsigned int rtlx_read_poll(int index, int can_sleep);
+unsigned int rtlx_write_poll(int index);
+
+int __init rtlx_module_init(void);
+void __exit rtlx_module_exit(void);
+
+void _interrupt_sp(void);
+
+extern struct vpe_notifications rtlx_notify;
+extern const struct file_operations rtlx_fops;
+extern void (*aprp_hook)(void);
 
 enum rtlx_state {
        RTLX_STATE_UNUSED = 0,
@@ -35,10 +53,15 @@ enum rtlx_state {
        RTLX_STATE_OPENED
 };
 
-#define RTLX_BUFFER_SIZE 2048
+extern struct chan_waitqueues {
+       wait_queue_head_t rt_queue;
+       wait_queue_head_t lx_queue;
+       atomic_t in_open;
+       struct mutex mutex;
+} channel_wqs[RTLX_CHANNELS];
 
 /* each channel supports read and write.
-   linux (vpe0) reads lx_buffer         and writes rt_buffer
+   linux (vpe0) reads lx_buffer and writes rt_buffer
    SP (vpe1) reads rt_buffer and writes lx_buffer
 */
 struct rtlx_channel {
@@ -55,11 +78,11 @@ struct rtlx_channel {
        char *lx_buffer;
 };
 
-struct rtlx_info {
+extern struct rtlx_info {
        unsigned long id;
        enum rtlx_state state;
+       int ap_int_pending;     /* Status of 0 or 1 for CONFIG_MIPS_CMP only */
 
        struct rtlx_channel channel[RTLX_CHANNELS];
-};
-
+} *rtlx;
 #endif /* __ASM_RTLX_H_ */
index eb0af15ac656b5757d3250ad38cd800e7ac291f1..278d45a097286034bfba656c9d626b1ff3d810b2 100644 (file)
 
 struct task_struct;
 
-/*
- * switch_to(n) should switch tasks to task nr n, first
- * checking that n isn't the current task, in which case it does nothing.
+/**
+ * resume - resume execution of a task
+ * @prev:      The task previously executed.
+ * @next:      The task to begin executing.
+ * @next_ti:   task_thread_info(next).
+ * @usedfpu:   Non-zero if prev's FP context should be saved.
+ *
+ * This function is used whilst scheduling to save the context of prev & load
+ * the context of next. Returns prev.
  */
-extern asmlinkage void *resume(void *last, void *next, void *next_ti, u32 __usedfpu);
+extern asmlinkage struct task_struct *resume(struct task_struct *prev,
+               struct task_struct *next, struct thread_info *next_ti,
+               u32 usedfpu);
 
 extern unsigned int ll_bit;
 extern struct task_struct *ll_task;
index 81c89132c59d8731643c860d4fb3f1c2179d6f6e..33e8dbfc1b631626b3f52dd9c60d27957ae0f364 100644 (file)
@@ -29,7 +29,7 @@ static inline long syscall_get_nr(struct task_struct *task,
 static inline unsigned long mips_get_syscall_arg(unsigned long *arg,
        struct task_struct *task, struct pt_regs *regs, unsigned int n)
 {
-       unsigned long usp = regs->regs[29];
+       unsigned long usp __maybe_unused = regs->regs[29];
 
        switch (n) {
        case 0: case 1: case 2: case 3:
index 4f58ef6d0eed5c58c9e58595fac36b4b7f747a2e..24846f9053fe9af196996a43e7d77ab929f1d0ef 100644 (file)
@@ -110,11 +110,12 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_NOHZ               19      /* in adaptive nohz mode */
 #define TIF_FIXADE             20      /* Fix address errors in software */
 #define TIF_LOGADE             21      /* Log address errors to syslog */
-#define TIF_32BIT_REGS         22      /* also implies 16/32 fprs */
+#define TIF_32BIT_REGS         22      /* 32-bit general purpose registers */
 #define TIF_32BIT_ADDR         23      /* 32-bit address space (o32/n32) */
 #define TIF_FPUBOUND           24      /* thread bound to FPU-full CPU set */
 #define TIF_LOAD_WATCH         25      /* If set, load watch registers */
 #define TIF_SYSCALL_TRACEPOINT 26      /* syscall tracepoint instrumentation */
+#define TIF_32BIT_FPREGS       27      /* 32-bit floating point registers */
 #define TIF_SYSCALL_TRACE      31      /* syscall trace active */
 
 #define _TIF_SYSCALL_TRACE     (1<<TIF_SYSCALL_TRACE)
@@ -131,6 +132,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_32BIT_ADDR                (1<<TIF_32BIT_ADDR)
 #define _TIF_FPUBOUND          (1<<TIF_FPUBOUND)
 #define _TIF_LOAD_WATCH                (1<<TIF_LOAD_WATCH)
+#define _TIF_32BIT_FPREGS      (1<<TIF_32BIT_FPREGS)
 #define _TIF_SYSCALL_TRACEPOINT        (1<<TIF_SYSCALL_TRACEPOINT)
 
 #define _TIF_WORK_SYSCALL_ENTRY        (_TIF_NOHZ | _TIF_SYSCALL_TRACE |       \
index c67842bc8ef3831c42c59ed42235f5bf999a8ead..4a2349302b552c5a7c4772c235553b4bdbef4695 100644 (file)
  */
 #define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
 
+#define UNIQUE_ENTRYHI(idx)                                            \
+               ((CKSEG0 + ((idx) << (PAGE_SHIFT + 1))) |               \
+                (cpu_has_tlbinv ? MIPS_ENTRYHI_EHINV : 0))
+
 #include <asm-generic/tlb.h>
 
 #endif /* __ASM_TLB_H */
index 0880fe8809b19842a79da37e30aa94997b79c221..7849f3978feafe09cd0d9e712526bcc13d5e6c37 100644 (file)
@@ -1,24 +1,95 @@
 /*
- * Copyright (C) 2005 MIPS Technologies, Inc.  All rights reserved.
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * 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) 2005 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
  */
-
 #ifndef _ASM_VPE_H
 #define _ASM_VPE_H
 
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/smp.h>
+#include <linux/spinlock.h>
+
+#define VPE_MODULE_NAME "vpe"
+#define VPE_MODULE_MINOR 1
+
+/* grab the likely amount of memory we will need. */
+#ifdef CONFIG_MIPS_VPE_LOADER_TOM
+#define P_SIZE (2 * 1024 * 1024)
+#else
+/* add an overhead to the max kmalloc size for non-striped symbols/etc */
+#define P_SIZE (256 * 1024)
+#endif
+
+#define MAX_VPES 16
+#define VPE_PATH_MAX 256
+
+static inline int aprp_cpu_index(void)
+{
+#ifdef CONFIG_MIPS_CMP
+       return setup_max_cpus;
+#else
+       extern int tclimit;
+       return tclimit;
+#endif
+}
+
+enum vpe_state {
+       VPE_STATE_UNUSED = 0,
+       VPE_STATE_INUSE,
+       VPE_STATE_RUNNING
+};
+
+enum tc_state {
+       TC_STATE_UNUSED = 0,
+       TC_STATE_INUSE,
+       TC_STATE_RUNNING,
+       TC_STATE_DYNAMIC
+};
+
+struct vpe {
+       enum vpe_state state;
+
+       /* (device) minor associated with this vpe */
+       int minor;
+
+       /* elfloader stuff */
+       void *load_addr;
+       unsigned long len;
+       char *pbuffer;
+       unsigned long plen;
+       char cwd[VPE_PATH_MAX];
+
+       unsigned long __start;
+
+       /* tc's associated with this vpe */
+       struct list_head tc;
+
+       /* The list of vpe's */
+       struct list_head list;
+
+       /* shared symbol address */
+       void *shared_ptr;
+
+       /* the list of who wants to know when something major happens */
+       struct list_head notify;
+
+       unsigned int ntcs;
+};
+
+struct tc {
+       enum tc_state state;
+       int index;
+
+       struct vpe *pvpe;       /* parent VPE */
+       struct list_head tc;    /* The list of TC's with this VPE */
+       struct list_head list;  /* The global list of tc's */
+};
+
 struct vpe_notifications {
        void (*start)(int vpe);
        void (*stop)(int vpe);
@@ -26,10 +97,34 @@ struct vpe_notifications {
        struct list_head list;
 };
 
+struct vpe_control {
+       spinlock_t vpe_list_lock;
+       struct list_head vpe_list;      /* Virtual processing elements */
+       spinlock_t tc_list_lock;
+       struct list_head tc_list;       /* Thread contexts */
+};
+
+extern unsigned long physical_memsize;
+extern struct vpe_control vpecontrol;
+extern const struct file_operations vpe_fops;
+
+int vpe_notify(int index, struct vpe_notifications *notify);
+
+void *vpe_get_shared(int index);
+char *vpe_getcwd(int index);
+
+struct vpe *get_vpe(int minor);
+struct tc *get_tc(int index);
+struct vpe *alloc_vpe(int minor);
+struct tc *alloc_tc(int index);
+void release_vpe(struct vpe *v);
 
-extern int vpe_notify(int index, struct vpe_notifications *notify);
+void *alloc_progmem(unsigned long len);
+void release_progmem(void *ptr);
 
-extern void *vpe_get_shared(int index);
-extern char *vpe_getcwd(int index);
+int __weak vpe_run(struct vpe *v);
+void cleanup_tc(struct tc *tc);
 
+int __init vpe_module_init(void);
+void __exit vpe_module_exit(void);
 #endif /* _ASM_VPE_H */
index e5a676e3d3c04ce267dc6254652ff48520565823..b39ba25b41ccd2db0ae723ba01c4fab3a82621a6 100644 (file)
@@ -98,8 +98,9 @@ enum rt_op {
  */
 enum cop_op {
        mfc_op        = 0x00, dmfc_op       = 0x01,
-       cfc_op        = 0x02, mtc_op        = 0x04,
-       dmtc_op       = 0x05, ctc_op        = 0x06,
+       cfc_op        = 0x02, mfhc_op       = 0x03,
+       mtc_op        = 0x04, dmtc_op       = 0x05,
+       ctc_op        = 0x06, mthc_op       = 0x07,
        bc_op         = 0x08, cop_op        = 0x10,
        copm_op       = 0x18
 };
@@ -397,8 +398,10 @@ enum mm_32f_73_minor_op {
        mm_movt1_op = 0xa5,
        mm_ftruncw_op = 0xac,
        mm_fneg1_op = 0xad,
+       mm_mfhc1_op = 0xc0,
        mm_froundl_op = 0xcc,
        mm_fcvtd1_op = 0xcd,
+       mm_mthc1_op = 0xe0,
        mm_froundw_op = 0xec,
        mm_fcvts1_op = 0xed,
 };
index 8a5ec0eedeb0649067355907220fe2af395b4878..c01900e5d0788633c44c28558fe3cae80c42dd49 100644 (file)
@@ -427,6 +427,7 @@ static struct platform_device qi_lb60_audio_device = {
 
 static struct platform_device *jz_platform_devices[] __initdata = {
        &jz4740_udc_device,
+       &jz4740_udc_xceiv_device,
        &jz4740_mmc_device,
        &jz4740_nand_device,
        &qi_lb60_keypad,
index df65677f3d0b20ef38c4873607c0c1719c484684..a447101cf9f1143c3972aab257cf33522539fbb3 100644 (file)
  */
 
 #include <linux/device.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/platform_device.h>
 #include <linux/resource.h>
 
 #include <linux/dma-mapping.h>
 
+#include <linux/usb/musb.h>
+
 #include <asm/mach-jz4740/platform.h>
 #include <asm/mach-jz4740/base.h>
 #include <asm/mach-jz4740/irq.h>
@@ -56,29 +57,35 @@ struct platform_device jz4740_usb_ohci_device = {
        .resource       = jz4740_usb_ohci_resources,
 };
 
-/* UDC (USB gadget controller) */
-static struct resource jz4740_usb_gdt_resources[] = {
-       {
-               .start  = JZ4740_UDC_BASE_ADDR,
-               .end    = JZ4740_UDC_BASE_ADDR + 0x1000 - 1,
-               .flags  = IORESOURCE_MEM,
+/* USB Device Controller */
+struct platform_device jz4740_udc_xceiv_device = {
+       .name = "usb_phy_gen_xceiv",
+       .id   = 0,
+};
+
+static struct resource jz4740_udc_resources[] = {
+       [0] = {
+               .start = JZ4740_UDC_BASE_ADDR,
+               .end   = JZ4740_UDC_BASE_ADDR + 0x10000 - 1,
+               .flags = IORESOURCE_MEM,
        },
-       {
-               .start  = JZ4740_IRQ_UDC,
-               .end    = JZ4740_IRQ_UDC,
-               .flags  = IORESOURCE_IRQ,
+       [1] = {
+               .start = JZ4740_IRQ_UDC,
+               .end   = JZ4740_IRQ_UDC,
+               .flags = IORESOURCE_IRQ,
+               .name  = "mc",
        },
 };
 
 struct platform_device jz4740_udc_device = {
-       .name           = "jz-udc",
-       .id             = -1,
-       .dev = {
-               .dma_mask = &jz4740_udc_device.dev.coherent_dma_mask,
+       .name = "musb-jz4740",
+       .id   = -1,
+       .dev  = {
+               .dma_mask          = &jz4740_udc_device.dev.coherent_dma_mask,
                .coherent_dma_mask = DMA_BIT_MASK(32),
        },
-       .num_resources  = ARRAY_SIZE(jz4740_usb_gdt_resources),
-       .resource       = jz4740_usb_gdt_resources,
+       .num_resources = ARRAY_SIZE(jz4740_udc_resources),
+       .resource      = jz4740_udc_resources,
 };
 
 /* MMC/SD controller */
index 1c1b71752c84cbc26dc2c0f81cc778e0a749a495..26c6175e137962545086bf4d11c3119b22c315f4 100644 (file)
@@ -30,6 +30,7 @@ obj-$(CONFIG_CSRC_R4K)                += csrc-r4k.o
 obj-$(CONFIG_CSRC_SB1250)      += csrc-sb1250.o
 obj-$(CONFIG_SYNC_R4K)         += sync-r4k.o
 
+obj-$(CONFIG_DEBUG_FS)         += segment.o
 obj-$(CONFIG_STACKTRACE)       += stacktrace.o
 obj-$(CONFIG_MODULES)          += mips_ksyms.o module.o
 obj-$(CONFIG_MODULES_USE_ELF_RELA) += module-rela.o
@@ -55,7 +56,11 @@ obj-$(CONFIG_MIPS_CMP)               += smp-cmp.o
 obj-$(CONFIG_CPU_MIPSR2)       += spram.o
 
 obj-$(CONFIG_MIPS_VPE_LOADER)  += vpe.o
+obj-$(CONFIG_MIPS_VPE_LOADER_CMP) += vpe-cmp.o
+obj-$(CONFIG_MIPS_VPE_LOADER_MT) += vpe-mt.o
 obj-$(CONFIG_MIPS_VPE_APSP_API) += rtlx.o
+obj-$(CONFIG_MIPS_VPE_APSP_API_CMP) += rtlx-cmp.o
+obj-$(CONFIG_MIPS_VPE_APSP_API_MT) += rtlx-mt.o
 
 obj-$(CONFIG_I8259)            += i8259.o
 obj-$(CONFIG_IRQ_CPU)          += irq_cpu.o
index 202e581e609653ea3f2b651cb2387ba9e04fe65e..7faf5f2bee25d7d9a0ca51e629ce2340161162aa 100644 (file)
@@ -27,6 +27,18 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG];
 typedef double elf_fpreg_t;
 typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
 
+/*
+ * In order to be sure that we don't attempt to execute an O32 binary which
+ * requires 64 bit FP (FR=1) on a system which does not support it we refuse
+ * to execute any binary which has bits specified by the following macro set
+ * in its ELF header flags.
+ */
+#ifdef CONFIG_MIPS_O32_FP64_SUPPORT
+# define __MIPS_O32_FP64_MUST_BE_ZERO  0
+#else
+# define __MIPS_O32_FP64_MUST_BE_ZERO  EF_MIPS_FP64
+#endif
+
 /*
  * This is used to ensure we don't load something for the wrong architecture.
  */
@@ -43,6 +55,8 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG];
                __res = 0;                                              \
        if (((__h->e_flags & EF_MIPS_ABI) != 0) &&                      \
            ((__h->e_flags & EF_MIPS_ABI) != EF_MIPS_ABI_O32))          \
+               __res = 0;                                              \
+       if (__h->e_flags & __MIPS_O32_FP64_MUST_BE_ZERO)                \
                __res = 0;                                              \
                                                                        \
        __res;                                                          \
index bd79c4f9bff403eeb2e320343b83d81d70855852..a5bf73d22fcc378ae9dfa4648cb45ed9249f3c09 100644 (file)
@@ -8,11 +8,11 @@
  * Reset/NMI/re-entry vectors for BMIPS processors
  */
 
-#include <linux/init.h>
 
 #include <asm/asm.h>
 #include <asm/asmmacro.h>
 #include <asm/cacheops.h>
+#include <asm/cpu.h>
 #include <asm/regdef.h>
 #include <asm/mipsregs.h>
 #include <asm/stackframe.h>
@@ -91,12 +91,18 @@ NESTED(bmips_reset_nmi_vec, PT_SIZE, sp)
        beqz    k0, bmips_smp_entry
 
 #if defined(CONFIG_CPU_BMIPS5000)
+       mfc0    k0, CP0_PRID
+       li      k1, PRID_IMP_BMIPS5000
+       andi    k0, 0xff00
+       bne     k0, k1, 1f
+
        /* if we're not on core 0, this must be the SMP boot signal */
        li      k1, (3 << 25)
        mfc0    k0, $22
        and     k0, k1
        bnez    k0, bmips_smp_entry
-#endif
+1:
+#endif /* CONFIG_CPU_BMIPS5000 */
 #endif /* CONFIG_SMP */
 
        /* nope, it's just a regular NMI */
@@ -139,7 +145,12 @@ bmips_smp_entry:
        xori    k0, 0x04
        mtc0    k0, CP0_CONFIG
 
+       mfc0    k0, CP0_PRID
+       andi    k0, 0xff00
 #if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
+       li      k1, PRID_IMP_BMIPS43XX
+       bne     k0, k1, 2f
+
        /* initialize CPU1's local I-cache */
        li      k0, 0x80000000
        li      k1, 0x80010000
@@ -150,14 +161,21 @@ bmips_smp_entry:
 1:     cache   Index_Store_Tag_I, 0(k0)
        addiu   k0, 16
        bne     k0, k1, 1b
-#elif defined(CONFIG_CPU_BMIPS5000)
+
+       b       3f
+2:
+#endif /* CONFIG_CPU_BMIPS4350 || CONFIG_CPU_BMIPS4380 */
+#if defined(CONFIG_CPU_BMIPS5000)
        /* set exception vector base */
+       li      k1, PRID_IMP_BMIPS5000
+       bne     k0, k1, 3f
+
        la      k0, ebase
        lw      k0, 0(k0)
        mtc0    k0, $15, 1
        BARRIER
-#endif
-
+#endif /* CONFIG_CPU_BMIPS5000 */
+3:
        /* jump back to kseg0 in case we need to remap the kseg1 area */
        la      k0, 1f
        jr      k0
@@ -221,8 +239,18 @@ END(bmips_smp_int_vec)
 LEAF(bmips_enable_xks01)
 
 #if defined(CONFIG_XKS01)
-
+       mfc0    t0, CP0_PRID
+       andi    t2, t0, 0xff00
 #if defined(CONFIG_CPU_BMIPS4380)
+       li      t1, PRID_IMP_BMIPS43XX
+       bne     t2, t1, 1f
+
+       andi    t0, 0xff
+       addiu   t1, t0, -PRID_REV_BMIPS4380_HI
+       bgtz    t1, 2f
+       addiu   t0, -PRID_REV_BMIPS4380_LO
+       bltz    t0, 2f
+
        mfc0    t0, $22, 3
        li      t1, 0x1ff0
        li      t2, (1 << 12) | (1 << 9)
@@ -231,7 +259,13 @@ LEAF(bmips_enable_xks01)
        or      t0, t2
        mtc0    t0, $22, 3
        BARRIER
-#elif defined(CONFIG_CPU_BMIPS5000)
+       b       2f
+1:
+#endif /* CONFIG_CPU_BMIPS4380 */
+#if defined(CONFIG_CPU_BMIPS5000)
+       li      t1, PRID_IMP_BMIPS5000
+       bne     t2, t1, 2f
+
        mfc0    t0, $22, 5
        li      t1, 0x01ff
        li      t2, (1 << 8) | (1 << 5)
@@ -240,12 +274,8 @@ LEAF(bmips_enable_xks01)
        or      t0, t2
        mtc0    t0, $22, 5
        BARRIER
-#else
-
-#error Missing XKS01 setup
-
-#endif
-
+#endif /* CONFIG_CPU_BMIPS5000 */
+2:
 #endif /* defined(CONFIG_XKS01) */
 
        jr      ra
index c814287bdf5d10d8a44a9e6a843b3acd5ab30ff8..530f832de02c20165c6d36a6a63f5db8b2603f99 100644 (file)
@@ -112,7 +112,7 @@ static inline unsigned long cpu_get_fpu_id(void)
        unsigned long tmp, fpu_id;
 
        tmp = read_c0_status();
-       __enable_fpu();
+       __enable_fpu(FPU_AS_IS);
        fpu_id = read_32bit_cp1_register(CP1_REVISION);
        write_c0_status(tmp);
        return fpu_id;
@@ -163,6 +163,25 @@ static void set_isa(struct cpuinfo_mips *c, unsigned int isa)
 static char unknown_isa[] = KERN_ERR \
        "Unsupported ISA type, c0.config0: %d.";
 
+static void set_ftlb_enable(struct cpuinfo_mips *c, int enable)
+{
+       unsigned int config6;
+       /*
+        * Config6 is implementation dependent and it's currently only
+        * used by proAptiv
+        */
+       if (c->cputype == CPU_PROAPTIV) {
+               config6 = read_c0_config6();
+               if (enable)
+                       /* Enable FTLB */
+                       write_c0_config6(config6 | MIPS_CONF6_FTLBEN);
+               else
+                       /* Disable FTLB */
+                       write_c0_config6(config6 &  ~MIPS_CONF6_FTLBEN);
+               back_to_back_c0_hazard();
+       }
+}
+
 static inline unsigned int decode_config0(struct cpuinfo_mips *c)
 {
        unsigned int config0;
@@ -170,8 +189,13 @@ static inline unsigned int decode_config0(struct cpuinfo_mips *c)
 
        config0 = read_c0_config();
 
-       if (((config0 & MIPS_CONF_MT) >> 7) == 1)
+       /*
+        * Look for Standard TLB or Dual VTLB and FTLB
+        */
+       if ((((config0 & MIPS_CONF_MT) >> 7) == 1) ||
+           (((config0 & MIPS_CONF_MT) >> 7) == 4))
                c->options |= MIPS_CPU_TLB;
+
        isa = (config0 & MIPS_CONF_AT) >> 13;
        switch (isa) {
        case 0:
@@ -226,8 +250,11 @@ static inline unsigned int decode_config1(struct cpuinfo_mips *c)
                c->options |= MIPS_CPU_FPU;
                c->options |= MIPS_CPU_32FPR;
        }
-       if (cpu_has_tlb)
+       if (cpu_has_tlb) {
                c->tlbsize = ((config1 & MIPS_CONF1_TLBS) >> 25) + 1;
+               c->tlbsizevtlb = c->tlbsize;
+               c->tlbsizeftlbsets = 0;
+       }
 
        return config1 & MIPS_CONF_M;
 }
@@ -272,6 +299,8 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
                c->options |= MIPS_CPU_MICROMIPS;
        if (config3 & MIPS_CONF3_VZ)
                c->ases |= MIPS_ASE_VZ;
+       if (config3 & MIPS_CONF3_SC)
+               c->options |= MIPS_CPU_SEGMENTS;
 
        return config3 & MIPS_CONF_M;
 }
@@ -279,12 +308,51 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
 static inline unsigned int decode_config4(struct cpuinfo_mips *c)
 {
        unsigned int config4;
+       unsigned int newcf4;
+       unsigned int mmuextdef;
+       unsigned int ftlb_page = MIPS_CONF4_FTLBPAGESIZE;
 
        config4 = read_c0_config4();
 
-       if ((config4 & MIPS_CONF4_MMUEXTDEF) == MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT
-           && cpu_has_tlb)
-               c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
+       if (cpu_has_tlb) {
+               if (((config4 & MIPS_CONF4_IE) >> 29) == 2)
+                       c->options |= MIPS_CPU_TLBINV;
+               mmuextdef = config4 & MIPS_CONF4_MMUEXTDEF;
+               switch (mmuextdef) {
+               case MIPS_CONF4_MMUEXTDEF_MMUSIZEEXT:
+                       c->tlbsize += (config4 & MIPS_CONF4_MMUSIZEEXT) * 0x40;
+                       c->tlbsizevtlb = c->tlbsize;
+                       break;
+               case MIPS_CONF4_MMUEXTDEF_VTLBSIZEEXT:
+                       c->tlbsizevtlb +=
+                               ((config4 & MIPS_CONF4_VTLBSIZEEXT) >>
+                                 MIPS_CONF4_VTLBSIZEEXT_SHIFT) * 0x40;
+                       c->tlbsize = c->tlbsizevtlb;
+                       ftlb_page = MIPS_CONF4_VFTLBPAGESIZE;
+                       /* fall through */
+               case MIPS_CONF4_MMUEXTDEF_FTLBSIZEEXT:
+                       newcf4 = (config4 & ~ftlb_page) |
+                               (page_size_ftlb(mmuextdef) <<
+                                MIPS_CONF4_FTLBPAGESIZE_SHIFT);
+                       write_c0_config4(newcf4);
+                       back_to_back_c0_hazard();
+                       config4 = read_c0_config4();
+                       if (config4 != newcf4) {
+                               pr_err("PAGE_SIZE 0x%lx is not supported by FTLB (config4=0x%x)\n",
+                                      PAGE_SIZE, config4);
+                               /* Switch FTLB off */
+                               set_ftlb_enable(c, 0);
+                               break;
+                       }
+                       c->tlbsizeftlbsets = 1 <<
+                               ((config4 & MIPS_CONF4_FTLBSETS) >>
+                                MIPS_CONF4_FTLBSETS_SHIFT);
+                       c->tlbsizeftlbways = ((config4 & MIPS_CONF4_FTLBWAYS) >>
+                                             MIPS_CONF4_FTLBWAYS_SHIFT) + 2;
+                       c->tlbsize += c->tlbsizeftlbways * c->tlbsizeftlbsets;
+                       break;
+               }
+       }
 
        c->kscratch_mask = (config4 >> 16) & 0xff;
 
@@ -312,6 +380,9 @@ static void decode_configs(struct cpuinfo_mips *c)
 
        c->scache.flags = MIPS_CACHE_NOT_PRESENT;
 
+       /* Enable FTLB if present */
+       set_ftlb_enable(c, 1);
+
        ok = decode_config0(c);                 /* Read Config registers.  */
        BUG_ON(!ok);                            /* Arch spec violation!  */
        if (ok)
@@ -675,7 +746,6 @@ static inline void cpu_probe_legacy(struct cpuinfo_mips *c, unsigned int cpu)
 
 static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
 {
-       decode_configs(c);
        switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_4KC:
                c->cputype = CPU_4KC;
@@ -739,8 +809,26 @@ static inline void cpu_probe_mips(struct cpuinfo_mips *c, unsigned int cpu)
                c->cputype = CPU_74K;
                __cpu_name[cpu] = "MIPS 1074Kc";
                break;
+       case PRID_IMP_INTERAPTIV_UP:
+               c->cputype = CPU_INTERAPTIV;
+               __cpu_name[cpu] = "MIPS interAptiv";
+               break;
+       case PRID_IMP_INTERAPTIV_MP:
+               c->cputype = CPU_INTERAPTIV;
+               __cpu_name[cpu] = "MIPS interAptiv (multi)";
+               break;
+       case PRID_IMP_PROAPTIV_UP:
+               c->cputype = CPU_PROAPTIV;
+               __cpu_name[cpu] = "MIPS proAptiv";
+               break;
+       case PRID_IMP_PROAPTIV_MP:
+               c->cputype = CPU_PROAPTIV;
+               __cpu_name[cpu] = "MIPS proAptiv (multi)";
+               break;
        }
 
+       decode_configs(c);
+
        spram_config();
 }
 
@@ -943,6 +1031,7 @@ static inline void cpu_probe_netlogic(struct cpuinfo_mips *c, int cpu)
 
        switch (c->processor_id & PRID_IMP_MASK) {
        case PRID_IMP_NETLOGIC_XLP2XX:
+       case PRID_IMP_NETLOGIC_XLP9XX:
                c->cputype = CPU_XLP;
                __cpu_name[cpu] = "Broadcom XLPII";
                break;
index 93aa302948d7236d70dc9f0b5ae9e96b7b123c8b..d21264681e97d805b6a6ef1defffd8ccfb8fb08b 100644 (file)
@@ -5,7 +5,6 @@
 #include <linux/bootmem.h>
 #include <linux/crash_dump.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/types.h>
 #include <linux/sched.h>
index 47d7583cd67ff7de77d5010c89d8bcbba234c2d0..d84f6a5095023ea5ff1bd052822937b8f87ac5dc 100644 (file)
@@ -476,6 +476,7 @@ NESTED(nmi_handler, PT_SIZE, sp)
        BUILD_HANDLER ov ov sti silent                  /* #12 */
        BUILD_HANDLER tr tr sti silent                  /* #13 */
        BUILD_HANDLER fpe fpe fpe silent                /* #15 */
+       BUILD_HANDLER ftlb ftlb none silent             /* #16 */
        BUILD_HANDLER mdmx mdmx sti silent              /* #22 */
 #ifdef CONFIG_HARDWARE_WATCHPOINTS
        /*
index f7991d95bff9a67374501ee4b3ce5f3c25973742..3553243bf9d660f0f7ec69941462990ac7ee55b7 100644 (file)
@@ -184,6 +184,8 @@ void __init check_wait(void)
        case CPU_24K:
        case CPU_34K:
        case CPU_1004K:
+       case CPU_INTERAPTIV:
+       case CPU_PROAPTIV:
                cpu_wait = r4k_wait;
                if (read_c0_config7() & MIPS_CONF7_WII)
                        cpu_wait = r4k_wait_irqoff;
index 8c58d8a84bf30d6a98e34f973510ebff8be006ac..00d20974b3e7b2bde15969c78402dbea65793edc 100644 (file)
@@ -65,26 +65,25 @@ static int show_cpuinfo(struct seq_file *m, void *v)
                                cpu_data[n].watch_reg_masks[i]);
                seq_printf(m, "]\n");
        }
-       if (cpu_has_mips_r) {
-               seq_printf(m, "isa\t\t\t: mips1");
-               if (cpu_has_mips_2)
-                       seq_printf(m, "%s", " mips2");
-               if (cpu_has_mips_3)
-                       seq_printf(m, "%s", " mips3");
-               if (cpu_has_mips_4)
-                       seq_printf(m, "%s", " mips4");
-               if (cpu_has_mips_5)
-                       seq_printf(m, "%s", " mips5");
-               if (cpu_has_mips32r1)
-                       seq_printf(m, "%s", " mips32r1");
-               if (cpu_has_mips32r2)
-                       seq_printf(m, "%s", " mips32r2");
-               if (cpu_has_mips64r1)
-                       seq_printf(m, "%s", " mips64r1");
-               if (cpu_has_mips64r2)
-                       seq_printf(m, "%s", " mips64r2");
-               seq_printf(m, "\n");
-       }
+
+       seq_printf(m, "isa\t\t\t: mips1");
+       if (cpu_has_mips_2)
+               seq_printf(m, "%s", " mips2");
+       if (cpu_has_mips_3)
+               seq_printf(m, "%s", " mips3");
+       if (cpu_has_mips_4)
+               seq_printf(m, "%s", " mips4");
+       if (cpu_has_mips_5)
+               seq_printf(m, "%s", " mips5");
+       if (cpu_has_mips32r1)
+               seq_printf(m, "%s", " mips32r1");
+       if (cpu_has_mips32r2)
+               seq_printf(m, "%s", " mips32r2");
+       if (cpu_has_mips64r1)
+               seq_printf(m, "%s", " mips64r1");
+       if (cpu_has_mips64r2)
+               seq_printf(m, "%s", " mips64r2");
+       seq_printf(m, "\n");
 
        seq_printf(m, "ASEs implemented\t:");
        if (cpu_has_mips16)     seq_printf(m, "%s", " mips16");
@@ -107,7 +106,14 @@ static int show_cpuinfo(struct seq_file *m, void *v)
        seq_printf(m, "kscratch registers\t: %d\n",
                      hweight8(cpu_data[n].kscratch_mask));
        seq_printf(m, "core\t\t\t: %d\n", cpu_data[n].core);
-
+#if defined(CONFIG_MIPS_MT_SMP) || defined(CONFIG_MIPS_MT_SMTC)
+       if (cpu_has_mipsmt) {
+               seq_printf(m, "VPE\t\t\t: %d\n", cpu_data[n].vpe_id);
+#if defined(CONFIG_MIPS_MT_SMTC)
+               seq_printf(m, "TC\t\t\t: %d\n", cpu_data[n].tc_id);
+#endif
+       }
+#endif
        sprintf(fmt, "VCE%%c exceptions\t\t: %s\n",
                      cpu_has_vce ? "%u" : "not available");
        seq_printf(m, fmt, 'D', vced_count);
index ddc76103e78c1447015ad02ccd83b2ae25c6d420..6ae540e133b2aa592a029a131f541a6619aaaceb 100644 (file)
@@ -60,15 +60,11 @@ void start_thread(struct pt_regs * regs, unsigned long pc, unsigned long sp)
 
        /* New thread loses kernel privileges. */
        status = regs->cp0_status & ~(ST0_CU0|ST0_CU1|ST0_FR|KU_MASK);
-#ifdef CONFIG_64BIT
-       status |= test_thread_flag(TIF_32BIT_REGS) ? 0 : ST0_FR;
-#endif
        status |= KU_USER;
        regs->cp0_status = status;
        clear_used_math();
        clear_fpu_owner();
-       if (cpu_has_dsp)
-               __init_dsp();
+       init_dsp();
        regs->cp0_epc = pc;
        regs->regs[29] = sp;
 }
index b52e1d2b33e03836002b495328124225ebba29db..7da9b76db4d9719157d112044a81a23d44063261 100644 (file)
@@ -137,13 +137,13 @@ int ptrace_getfpregs(struct task_struct *child, __u32 __user *data)
                if (cpu_has_mipsmt) {
                        unsigned int vpflags = dvpe();
                        flags = read_c0_status();
-                       __enable_fpu();
+                       __enable_fpu(FPU_AS_IS);
                        __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
                        write_c0_status(flags);
                        evpe(vpflags);
                } else {
                        flags = read_c0_status();
-                       __enable_fpu();
+                       __enable_fpu(FPU_AS_IS);
                        __asm__ __volatile__("cfc1\t%0,$0" : "=r" (tmp));
                        write_c0_status(flags);
                }
@@ -408,6 +408,7 @@ long arch_ptrace(struct task_struct *child, long request,
        /* Read the word at location addr in the USER area. */
        case PTRACE_PEEKUSR: {
                struct pt_regs *regs;
+               fpureg_t *fregs;
                unsigned long tmp = 0;
 
                regs = task_pt_regs(child);
@@ -418,26 +419,28 @@ long arch_ptrace(struct task_struct *child, long request,
                        tmp = regs->regs[addr];
                        break;
                case FPR_BASE ... FPR_BASE + 31:
-                       if (tsk_used_math(child)) {
-                               fpureg_t *fregs = get_fpu_regs(child);
+                       if (!tsk_used_math(child)) {
+                               /* FP not yet used */
+                               tmp = -1;
+                               break;
+                       }
+                       fregs = get_fpu_regs(child);
 
 #ifdef CONFIG_32BIT
+                       if (test_thread_flag(TIF_32BIT_FPREGS)) {
                                /*
                                 * The odd registers are actually the high
                                 * order bits of the values stored in the even
                                 * registers - unless we're using r2k_switch.S.
                                 */
                                if (addr & 1)
-                                       tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
+                                       tmp = fregs[(addr & ~1) - 32] >> 32;
                                else
-                                       tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
-#endif
-#ifdef CONFIG_64BIT
-                               tmp = fregs[addr - FPR_BASE];
-#endif
-                       } else {
-                               tmp = -1;       /* FP not yet used  */
+                                       tmp = fregs[addr - 32];
+                               break;
                        }
+#endif
+                       tmp = fregs[addr - FPR_BASE];
                        break;
                case PC:
                        tmp = regs->cp0_epc;
@@ -483,13 +486,13 @@ long arch_ptrace(struct task_struct *child, long request,
                        if (cpu_has_mipsmt) {
                                unsigned int vpflags = dvpe();
                                flags = read_c0_status();
-                               __enable_fpu();
+                               __enable_fpu(FPU_AS_IS);
                                __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
                                write_c0_status(flags);
                                evpe(vpflags);
                        } else {
                                flags = read_c0_status();
-                               __enable_fpu();
+                               __enable_fpu(FPU_AS_IS);
                                __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
                                write_c0_status(flags);
                        }
@@ -554,22 +557,25 @@ long arch_ptrace(struct task_struct *child, long request,
                                child->thread.fpu.fcr31 = 0;
                        }
 #ifdef CONFIG_32BIT
-                       /*
-                        * The odd registers are actually the high order bits
-                        * of the values stored in the even registers - unless
-                        * we're using r2k_switch.S.
-                        */
-                       if (addr & 1) {
-                               fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
-                               fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
-                       } else {
-                               fregs[addr - FPR_BASE] &= ~0xffffffffLL;
-                               fregs[addr - FPR_BASE] |= data;
+                       if (test_thread_flag(TIF_32BIT_FPREGS)) {
+                               /*
+                                * The odd registers are actually the high
+                                * order bits of the values stored in the even
+                                * registers - unless we're using r2k_switch.S.
+                                */
+                               if (addr & 1) {
+                                       fregs[(addr & ~1) - FPR_BASE] &=
+                                               0xffffffff;
+                                       fregs[(addr & ~1) - FPR_BASE] |=
+                                               ((u64)data) << 32;
+                               } else {
+                                       fregs[addr - FPR_BASE] &= ~0xffffffffLL;
+                                       fregs[addr - FPR_BASE] |= data;
+                               }
+                               break;
                        }
 #endif
-#ifdef CONFIG_64BIT
                        fregs[addr - FPR_BASE] = data;
-#endif
                        break;
                }
                case PC:
index 9486055ba660319c415b7ec7affdd07b9eff887e..b8aa2dd5b00bc13af9f2b88225718773d7b5732d 100644 (file)
@@ -80,6 +80,7 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
        /* Read the word at location addr in the USER area. */
        case PTRACE_PEEKUSR: {
                struct pt_regs *regs;
+               fpureg_t *fregs;
                unsigned int tmp;
 
                regs = task_pt_regs(child);
@@ -90,21 +91,25 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        tmp = regs->regs[addr];
                        break;
                case FPR_BASE ... FPR_BASE + 31:
-                       if (tsk_used_math(child)) {
-                               fpureg_t *fregs = get_fpu_regs(child);
-
+                       if (!tsk_used_math(child)) {
+                               /* FP not yet used */
+                               tmp = -1;
+                               break;
+                       }
+                       fregs = get_fpu_regs(child);
+                       if (test_thread_flag(TIF_32BIT_FPREGS)) {
                                /*
                                 * The odd registers are actually the high
                                 * order bits of the values stored in the even
                                 * registers - unless we're using r2k_switch.S.
                                 */
                                if (addr & 1)
-                                       tmp = (unsigned long) (fregs[((addr & ~1) - 32)] >> 32);
+                                       tmp = fregs[(addr & ~1) - 32] >> 32;
                                else
-                                       tmp = (unsigned long) (fregs[(addr - 32)] & 0xffffffff);
-                       } else {
-                               tmp = -1;       /* FP not yet used  */
+                                       tmp = fregs[addr - 32];
+                               break;
                        }
+                       tmp = fregs[addr - FPR_BASE];
                        break;
                case PC:
                        tmp = regs->cp0_epc;
@@ -147,13 +152,13 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                        if (cpu_has_mipsmt) {
                                unsigned int vpflags = dvpe();
                                flags = read_c0_status();
-                               __enable_fpu();
+                               __enable_fpu(FPU_AS_IS);
                                __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
                                write_c0_status(flags);
                                evpe(vpflags);
                        } else {
                                flags = read_c0_status();
-                               __enable_fpu();
+                               __enable_fpu(FPU_AS_IS);
                                __asm__ __volatile__("cfc1\t%0,$0": "=r" (tmp));
                                write_c0_status(flags);
                        }
@@ -236,20 +241,24 @@ long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
                                       sizeof(child->thread.fpu));
                                child->thread.fpu.fcr31 = 0;
                        }
-                       /*
-                        * The odd registers are actually the high order bits
-                        * of the values stored in the even registers - unless
-                        * we're using r2k_switch.S.
-                        */
-                       if (addr & 1) {
-                               fregs[(addr & ~1) - FPR_BASE] &= 0xffffffff;
-                               fregs[(addr & ~1) - FPR_BASE] |= ((unsigned long long) data) << 32;
-                       } else {
-                               fregs[addr - FPR_BASE] &= ~0xffffffffLL;
-                               /* Must cast, lest sign extension fill upper
-                                  bits!  */
-                               fregs[addr - FPR_BASE] |= (unsigned int)data;
+                       if (test_thread_flag(TIF_32BIT_FPREGS)) {
+                               /*
+                                * The odd registers are actually the high
+                                * order bits of the values stored in the even
+                                * registers - unless we're using r2k_switch.S.
+                                */
+                               if (addr & 1) {
+                                       fregs[(addr & ~1) - FPR_BASE] &=
+                                               0xffffffff;
+                                       fregs[(addr & ~1) - FPR_BASE] |=
+                                               ((u64)data) << 32;
+                               } else {
+                                       fregs[addr - FPR_BASE] &= ~0xffffffffLL;
+                                       fregs[addr - FPR_BASE] |= data;
+                               }
+                               break;
                        }
+                       fregs[addr - FPR_BASE] = data;
                        break;
                }
                case PC:
index 55ffe149dae90582bd2be2ec1d828639eae79b8d..253b2fb520267fb3536584df6d395a6b860392f1 100644 (file)
 LEAF(_save_fp_context)
        cfc1    t1, fcr31
 
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+       .set    push
+#ifdef CONFIG_MIPS32_R2
+       .set    mips64r2
+       mfc0    t0, CP0_STATUS
+       sll     t0, t0, 5
+       bgez    t0, 1f                  # skip storing odd if FR=0
+        nop
+#endif
        /* Store the 16 odd double precision registers */
        EX      sdc1 $f1, SC_FPREGS+8(a0)
        EX      sdc1 $f3, SC_FPREGS+24(a0)
@@ -53,6 +61,7 @@ LEAF(_save_fp_context)
        EX      sdc1 $f27, SC_FPREGS+216(a0)
        EX      sdc1 $f29, SC_FPREGS+232(a0)
        EX      sdc1 $f31, SC_FPREGS+248(a0)
+1:     .set    pop
 #endif
 
        /* Store the 16 even double precision registers */
@@ -82,7 +91,31 @@ LEAF(_save_fp_context)
 LEAF(_save_fp_context32)
        cfc1    t1, fcr31
 
-       EX      sdc1 $f0, SC32_FPREGS+0(a0)
+       mfc0    t0, CP0_STATUS
+       sll     t0, t0, 5
+       bgez    t0, 1f                  # skip storing odd if FR=0
+        nop
+
+       /* Store the 16 odd double precision registers */
+       EX      sdc1 $f1, SC32_FPREGS+8(a0)
+       EX      sdc1 $f3, SC32_FPREGS+24(a0)
+       EX      sdc1 $f5, SC32_FPREGS+40(a0)
+       EX      sdc1 $f7, SC32_FPREGS+56(a0)
+       EX      sdc1 $f9, SC32_FPREGS+72(a0)
+       EX      sdc1 $f11, SC32_FPREGS+88(a0)
+       EX      sdc1 $f13, SC32_FPREGS+104(a0)
+       EX      sdc1 $f15, SC32_FPREGS+120(a0)
+       EX      sdc1 $f17, SC32_FPREGS+136(a0)
+       EX      sdc1 $f19, SC32_FPREGS+152(a0)
+       EX      sdc1 $f21, SC32_FPREGS+168(a0)
+       EX      sdc1 $f23, SC32_FPREGS+184(a0)
+       EX      sdc1 $f25, SC32_FPREGS+200(a0)
+       EX      sdc1 $f27, SC32_FPREGS+216(a0)
+       EX      sdc1 $f29, SC32_FPREGS+232(a0)
+       EX      sdc1 $f31, SC32_FPREGS+248(a0)
+
+       /* Store the 16 even double precision registers */
+1:     EX      sdc1 $f0, SC32_FPREGS+0(a0)
        EX      sdc1 $f2, SC32_FPREGS+16(a0)
        EX      sdc1 $f4, SC32_FPREGS+32(a0)
        EX      sdc1 $f6, SC32_FPREGS+48(a0)
@@ -114,7 +147,16 @@ LEAF(_save_fp_context32)
  */
 LEAF(_restore_fp_context)
        EX      lw t0, SC_FPC_CSR(a0)
-#ifdef CONFIG_64BIT
+
+#if defined(CONFIG_64BIT) || defined(CONFIG_MIPS32_R2)
+       .set    push
+#ifdef CONFIG_MIPS32_R2
+       .set    mips64r2
+       mfc0    t0, CP0_STATUS
+       sll     t0, t0, 5
+       bgez    t0, 1f                  # skip loading odd if FR=0
+        nop
+#endif
        EX      ldc1 $f1, SC_FPREGS+8(a0)
        EX      ldc1 $f3, SC_FPREGS+24(a0)
        EX      ldc1 $f5, SC_FPREGS+40(a0)
@@ -131,6 +173,7 @@ LEAF(_restore_fp_context)
        EX      ldc1 $f27, SC_FPREGS+216(a0)
        EX      ldc1 $f29, SC_FPREGS+232(a0)
        EX      ldc1 $f31, SC_FPREGS+248(a0)
+1:     .set pop
 #endif
        EX      ldc1 $f0, SC_FPREGS+0(a0)
        EX      ldc1 $f2, SC_FPREGS+16(a0)
@@ -157,7 +200,30 @@ LEAF(_restore_fp_context)
 LEAF(_restore_fp_context32)
        /* Restore an o32 sigcontext.  */
        EX      lw t0, SC32_FPC_CSR(a0)
-       EX      ldc1 $f0, SC32_FPREGS+0(a0)
+
+       mfc0    t0, CP0_STATUS
+       sll     t0, t0, 5
+       bgez    t0, 1f                  # skip loading odd if FR=0
+        nop
+
+       EX      ldc1 $f1, SC32_FPREGS+8(a0)
+       EX      ldc1 $f3, SC32_FPREGS+24(a0)
+       EX      ldc1 $f5, SC32_FPREGS+40(a0)
+       EX      ldc1 $f7, SC32_FPREGS+56(a0)
+       EX      ldc1 $f9, SC32_FPREGS+72(a0)
+       EX      ldc1 $f11, SC32_FPREGS+88(a0)
+       EX      ldc1 $f13, SC32_FPREGS+104(a0)
+       EX      ldc1 $f15, SC32_FPREGS+120(a0)
+       EX      ldc1 $f17, SC32_FPREGS+136(a0)
+       EX      ldc1 $f19, SC32_FPREGS+152(a0)
+       EX      ldc1 $f21, SC32_FPREGS+168(a0)
+       EX      ldc1 $f23, SC32_FPREGS+184(a0)
+       EX      ldc1 $f25, SC32_FPREGS+200(a0)
+       EX      ldc1 $f27, SC32_FPREGS+216(a0)
+       EX      ldc1 $f29, SC32_FPREGS+232(a0)
+       EX      ldc1 $f31, SC32_FPREGS+248(a0)
+
+1:     EX      ldc1 $f0, SC32_FPREGS+0(a0)
        EX      ldc1 $f2, SC32_FPREGS+16(a0)
        EX      ldc1 $f4, SC32_FPREGS+32(a0)
        EX      ldc1 $f6, SC32_FPREGS+48(a0)
index 078de5eaca8fd96d8bcb720491fe3f56901dc03c..cc78dd9a17c788412e2254f0e505aadb789be34b 100644 (file)
  * Save a thread's fp context.
  */
 LEAF(_save_fp)
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        mfc0    t0, CP0_STATUS
 #endif
        fpu_save_double a0 t0 t1                # clobbers t1
@@ -134,7 +134,7 @@ LEAF(_save_fp)
  * Restore a thread's fp context.
  */
 LEAF(_restore_fp)
-#ifdef CONFIG_64BIT
+#if defined(CONFIG_64BIT) || defined(CONFIG_CPU_MIPS32_R2)
        mfc0    t0, CP0_STATUS
 #endif
        fpu_restore_double a0 t0 t1             # clobbers t1
@@ -228,6 +228,47 @@ LEAF(_init_fpu)
        mtc1    t1, $f29
        mtc1    t1, $f30
        mtc1    t1, $f31
+
+#ifdef CONFIG_CPU_MIPS32_R2
+       .set    push
+       .set    mips64r2
+       sll     t0, t0, 5                       # is Status.FR set?
+       bgez    t0, 1f                          # no: skip setting upper 32b
+
+       mthc1   t1, $f0
+       mthc1   t1, $f1
+       mthc1   t1, $f2
+       mthc1   t1, $f3
+       mthc1   t1, $f4
+       mthc1   t1, $f5
+       mthc1   t1, $f6
+       mthc1   t1, $f7
+       mthc1   t1, $f8
+       mthc1   t1, $f9
+       mthc1   t1, $f10
+       mthc1   t1, $f11
+       mthc1   t1, $f12
+       mthc1   t1, $f13
+       mthc1   t1, $f14
+       mthc1   t1, $f15
+       mthc1   t1, $f16
+       mthc1   t1, $f17
+       mthc1   t1, $f18
+       mthc1   t1, $f19
+       mthc1   t1, $f20
+       mthc1   t1, $f21
+       mthc1   t1, $f22
+       mthc1   t1, $f23
+       mthc1   t1, $f24
+       mthc1   t1, $f25
+       mthc1   t1, $f26
+       mthc1   t1, $f27
+       mthc1   t1, $f28
+       mthc1   t1, $f29
+       mthc1   t1, $f30
+       mthc1   t1, $f31
+1:     .set    pop
+#endif /* CONFIG_CPU_MIPS32_R2 */
 #else
        .set    mips3
        dmtc1   t1, $f0
diff --git a/arch/mips/kernel/rtlx-cmp.c b/arch/mips/kernel/rtlx-cmp.c
new file mode 100644 (file)
index 0000000..56dc696
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ * 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) 2005 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ */
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/smp.h>
+
+#include <asm/mips_mt.h>
+#include <asm/vpe.h>
+#include <asm/rtlx.h>
+
+static int major;
+
+static void rtlx_interrupt(void)
+{
+       int i;
+       struct rtlx_info *info;
+       struct rtlx_info **p = vpe_get_shared(aprp_cpu_index());
+
+       if (p == NULL || *p == NULL)
+               return;
+
+       info = *p;
+
+       if (info->ap_int_pending == 1 && smp_processor_id() == 0) {
+               for (i = 0; i < RTLX_CHANNELS; i++) {
+                       wake_up(&channel_wqs[i].lx_queue);
+                       wake_up(&channel_wqs[i].rt_queue);
+               }
+               info->ap_int_pending = 0;
+       }
+}
+
+void _interrupt_sp(void)
+{
+       smp_send_reschedule(aprp_cpu_index());
+}
+
+int __init rtlx_module_init(void)
+{
+       struct device *dev;
+       int i, err;
+
+       if (!cpu_has_mipsmt) {
+               pr_warn("VPE loader: not a MIPS MT capable processor\n");
+               return -ENODEV;
+       }
+
+       if (num_possible_cpus() - aprp_cpu_index() < 1) {
+               pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n"
+                       "Pass maxcpus=<n> argument as kernel argument\n");
+
+               return -ENODEV;
+       }
+
+       major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops);
+       if (major < 0) {
+               pr_err("rtlx_module_init: unable to register device\n");
+               return major;
+       }
+
+       /* initialise the wait queues */
+       for (i = 0; i < RTLX_CHANNELS; i++) {
+               init_waitqueue_head(&channel_wqs[i].rt_queue);
+               init_waitqueue_head(&channel_wqs[i].lx_queue);
+               atomic_set(&channel_wqs[i].in_open, 0);
+               mutex_init(&channel_wqs[i].mutex);
+
+               dev = device_create(mt_class, NULL, MKDEV(major, i), NULL,
+                                   "%s%d", RTLX_MODULE_NAME, i);
+               if (IS_ERR(dev)) {
+                       err = PTR_ERR(dev);
+                       goto out_chrdev;
+               }
+       }
+
+       /* set up notifiers */
+       rtlx_notify.start = rtlx_starting;
+       rtlx_notify.stop = rtlx_stopping;
+       vpe_notify(aprp_cpu_index(), &rtlx_notify);
+
+       if (cpu_has_vint) {
+               aprp_hook = rtlx_interrupt;
+       } else {
+               pr_err("APRP RTLX init on non-vectored-interrupt processor\n");
+               err = -ENODEV;
+               goto out_class;
+       }
+
+       return 0;
+
+out_class:
+       for (i = 0; i < RTLX_CHANNELS; i++)
+               device_destroy(mt_class, MKDEV(major, i));
+out_chrdev:
+       unregister_chrdev(major, RTLX_MODULE_NAME);
+
+       return err;
+}
+
+void __exit rtlx_module_exit(void)
+{
+       int i;
+
+       for (i = 0; i < RTLX_CHANNELS; i++)
+               device_destroy(mt_class, MKDEV(major, i));
+       unregister_chrdev(major, RTLX_MODULE_NAME);
+}
diff --git a/arch/mips/kernel/rtlx-mt.c b/arch/mips/kernel/rtlx-mt.c
new file mode 100644 (file)
index 0000000..91d61ba
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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) 2005 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ */
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/err.h>
+#include <linux/wait.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <asm/mips_mt.h>
+#include <asm/vpe.h>
+#include <asm/rtlx.h>
+
+static int major;
+
+static void rtlx_dispatch(void)
+{
+       if (read_c0_cause() & read_c0_status() & C_SW0)
+               do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ);
+}
+
+/*
+ * Interrupt handler may be called before rtlx_init has otherwise had
+ * a chance to run.
+ */
+static irqreturn_t rtlx_interrupt(int irq, void *dev_id)
+{
+       unsigned int vpeflags;
+       unsigned long flags;
+       int i;
+
+       /* Ought not to be strictly necessary for SMTC builds */
+       local_irq_save(flags);
+       vpeflags = dvpe();
+       set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ);
+       irq_enable_hazard();
+       evpe(vpeflags);
+       local_irq_restore(flags);
+
+       for (i = 0; i < RTLX_CHANNELS; i++) {
+               wake_up(&channel_wqs[i].lx_queue);
+               wake_up(&channel_wqs[i].rt_queue);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static struct irqaction rtlx_irq = {
+       .handler        = rtlx_interrupt,
+       .name           = "RTLX",
+};
+
+static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ;
+
+void _interrupt_sp(void)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+       dvpe();
+       settc(1);
+       write_vpe_c0_cause(read_vpe_c0_cause() | C_SW0);
+       evpe(EVPE_ENABLE);
+       local_irq_restore(flags);
+}
+
+int __init rtlx_module_init(void)
+{
+       struct device *dev;
+       int i, err;
+
+       if (!cpu_has_mipsmt) {
+               pr_warn("VPE loader: not a MIPS MT capable processor\n");
+               return -ENODEV;
+       }
+
+       if (aprp_cpu_index() == 0) {
+               pr_warn("No TCs reserved for AP/SP, not initializing RTLX.\n"
+                       "Pass maxtcs=<n> argument as kernel argument\n");
+
+               return -ENODEV;
+       }
+
+       major = register_chrdev(0, RTLX_MODULE_NAME, &rtlx_fops);
+       if (major < 0) {
+               pr_err("rtlx_module_init: unable to register device\n");
+               return major;
+       }
+
+       /* initialise the wait queues */
+       for (i = 0; i < RTLX_CHANNELS; i++) {
+               init_waitqueue_head(&channel_wqs[i].rt_queue);
+               init_waitqueue_head(&channel_wqs[i].lx_queue);
+               atomic_set(&channel_wqs[i].in_open, 0);
+               mutex_init(&channel_wqs[i].mutex);
+
+               dev = device_create(mt_class, NULL, MKDEV(major, i), NULL,
+                                   "%s%d", RTLX_MODULE_NAME, i);
+               if (IS_ERR(dev)) {
+                       err = PTR_ERR(dev);
+                       goto out_chrdev;
+               }
+       }
+
+       /* set up notifiers */
+       rtlx_notify.start = rtlx_starting;
+       rtlx_notify.stop = rtlx_stopping;
+       vpe_notify(aprp_cpu_index(), &rtlx_notify);
+
+       if (cpu_has_vint) {
+               aprp_hook = rtlx_dispatch;
+       } else {
+               pr_err("APRP RTLX init on non-vectored-interrupt processor\n");
+               err = -ENODEV;
+               goto out_class;
+       }
+
+       rtlx_irq.dev_id = rtlx;
+       err = setup_irq(rtlx_irq_num, &rtlx_irq);
+       if (err)
+               goto out_class;
+
+       return 0;
+
+out_class:
+       for (i = 0; i < RTLX_CHANNELS; i++)
+               device_destroy(mt_class, MKDEV(major, i));
+out_chrdev:
+       unregister_chrdev(major, RTLX_MODULE_NAME);
+
+       return err;
+}
+
+void __exit rtlx_module_exit(void)
+{
+       int i;
+
+       for (i = 0; i < RTLX_CHANNELS; i++)
+               device_destroy(mt_class, MKDEV(major, i));
+       unregister_chrdev(major, RTLX_MODULE_NAME);
+}
index 2c12ea1668d13df21b8908abc7fbc4f80d60678c..31b1b763cb298841eee156c61752687c4056809d 100644 (file)
 /*
+ * 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) 2005 MIPS Technologies, Inc.  All rights reserved.
  * Copyright (C) 2005, 06 Ralf Baechle (ralf@linux-mips.org)
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
  */
-
-#include <linux/device.h>
 #include <linux/kernel.h>
 #include <linux/fs.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <linux/list.h>
-#include <linux/vmalloc.h>
-#include <linux/elf.h>
-#include <linux/seq_file.h>
 #include <linux/syscalls.h>
 #include <linux/moduleloader.h>
-#include <linux/interrupt.h>
-#include <linux/poll.h>
-#include <linux/sched.h>
-#include <linux/wait.h>
+#include <linux/atomic.h>
 #include <asm/mipsmtregs.h>
 #include <asm/mips_mt.h>
-#include <asm/cacheflush.h>
-#include <linux/atomic.h>
-#include <asm/cpu.h>
 #include <asm/processor.h>
-#include <asm/vpe.h>
 #include <asm/rtlx.h>
 #include <asm/setup.h>
+#include <asm/vpe.h>
 
-static struct rtlx_info *rtlx;
-static int major;
-static char module_name[] = "rtlx";
-
-static struct chan_waitqueues {
-       wait_queue_head_t rt_queue;
-       wait_queue_head_t lx_queue;
-       atomic_t in_open;
-       struct mutex mutex;
-} channel_wqs[RTLX_CHANNELS];
-
-static struct vpe_notifications notify;
 static int sp_stopping;
-
-extern void *vpe_get_shared(int index);
-
-static void rtlx_dispatch(void)
-{
-       do_IRQ(MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ);
-}
-
-
-/* Interrupt handler may be called before rtlx_init has otherwise had
-   a chance to run.
-*/
-static irqreturn_t rtlx_interrupt(int irq, void *dev_id)
-{
-       unsigned int vpeflags;
-       unsigned long flags;
-       int i;
-
-       /* Ought not to be strictly necessary for SMTC builds */
-       local_irq_save(flags);
-       vpeflags = dvpe();
-       set_c0_status(0x100 << MIPS_CPU_RTLX_IRQ);
-       irq_enable_hazard();
-       evpe(vpeflags);
-       local_irq_restore(flags);
-
-       for (i = 0; i < RTLX_CHANNELS; i++) {
-                       wake_up(&channel_wqs[i].lx_queue);
-                       wake_up(&channel_wqs[i].rt_queue);
-       }
-
-       return IRQ_HANDLED;
-}
+struct rtlx_info *rtlx;
+struct chan_waitqueues channel_wqs[RTLX_CHANNELS];
+struct vpe_notifications rtlx_notify;
+void (*aprp_hook)(void) = NULL;
+EXPORT_SYMBOL(aprp_hook);
 
 static void __used dump_rtlx(void)
 {
        int i;
 
-       printk("id 0x%lx state %d\n", rtlx->id, rtlx->state);
+       pr_info("id 0x%lx state %d\n", rtlx->id, rtlx->state);
 
        for (i = 0; i < RTLX_CHANNELS; i++) {
                struct rtlx_channel *chan = &rtlx->channel[i];
 
-               printk(" rt_state %d lx_state %d buffer_size %d\n",
-                      chan->rt_state, chan->lx_state, chan->buffer_size);
+               pr_info(" rt_state %d lx_state %d buffer_size %d\n",
+                       chan->rt_state, chan->lx_state, chan->buffer_size);
 
-               printk(" rt_read %d rt_write %d\n",
-                      chan->rt_read, chan->rt_write);
+               pr_info(" rt_read %d rt_write %d\n",
+                       chan->rt_read, chan->rt_write);
 
-               printk(" lx_read %d lx_write %d\n",
-                      chan->lx_read, chan->lx_write);
+               pr_info(" lx_read %d lx_write %d\n",
+                       chan->lx_read, chan->lx_write);
 
-               printk(" rt_buffer <%s>\n", chan->rt_buffer);
-               printk(" lx_buffer <%s>\n", chan->lx_buffer);
+               pr_info(" rt_buffer <%s>\n", chan->rt_buffer);
+               pr_info(" lx_buffer <%s>\n", chan->lx_buffer);
        }
 }
 
@@ -116,8 +53,7 @@ static void __used dump_rtlx(void)
 static int rtlx_init(struct rtlx_info *rtlxi)
 {
        if (rtlxi->id != RTLX_ID) {
-               printk(KERN_ERR "no valid RTLX id at 0x%p 0x%lx\n",
-                       rtlxi, rtlxi->id);
+               pr_err("no valid RTLX id at 0x%p 0x%lx\n", rtlxi, rtlxi->id);
                return -ENOEXEC;
        }
 
@@ -127,20 +63,20 @@ static int rtlx_init(struct rtlx_info *rtlxi)
 }
 
 /* notifications */
-static void starting(int vpe)
+void rtlx_starting(int vpe)
 {
        int i;
        sp_stopping = 0;
 
        /* force a reload of rtlx */
-       rtlx=NULL;
+       rtlx = NULL;
 
        /* wake up any sleeping rtlx_open's */
        for (i = 0; i < RTLX_CHANNELS; i++)
                wake_up_interruptible(&channel_wqs[i].lx_queue);
 }
 
-static void stopping(int vpe)
+void rtlx_stopping(int vpe)
 {
        int i;
 
@@ -158,31 +94,30 @@ int rtlx_open(int index, int can_sleep)
        int ret = 0;
 
        if (index >= RTLX_CHANNELS) {
-               printk(KERN_DEBUG "rtlx_open index out of range\n");
+               pr_debug(KERN_DEBUG "rtlx_open index out of range\n");
                return -ENOSYS;
        }
 
        if (atomic_inc_return(&channel_wqs[index].in_open) > 1) {
-               printk(KERN_DEBUG "rtlx_open channel %d already opened\n",
-                      index);
+               pr_debug(KERN_DEBUG "rtlx_open channel %d already opened\n", index);
                ret = -EBUSY;
                goto out_fail;
        }
 
        if (rtlx == NULL) {
-               if( (p = vpe_get_shared(tclimit)) == NULL) {
-                   if (can_sleep) {
-                       ret = __wait_event_interruptible(
+               p = vpe_get_shared(aprp_cpu_index());
+               if (p == NULL) {
+                       if (can_sleep) {
+                               ret = __wait_event_interruptible(
                                        channel_wqs[index].lx_queue,
-                                       (p = vpe_get_shared(tclimit)));
-                       if (ret)
+                                       (p = vpe_get_shared(aprp_cpu_index())));
+                               if (ret)
+                                       goto out_fail;
+                       } else {
+                               pr_debug("No SP program loaded, and device opened with O_NONBLOCK\n");
+                               ret = -ENOSYS;
                                goto out_fail;
-                   } else {
-                       printk(KERN_DEBUG "No SP program loaded, and device "
-                                       "opened with O_NONBLOCK\n");
-                       ret = -ENOSYS;
-                       goto out_fail;
-                   }
+                       }
                }
 
                smp_rmb();
@@ -204,24 +139,24 @@ int rtlx_open(int index, int can_sleep)
                                        ret = -ERESTARTSYS;
                                        goto out_fail;
                                }
-                               finish_wait(&channel_wqs[index].lx_queue, &wait);
+                               finish_wait(&channel_wqs[index].lx_queue,
+                                           &wait);
                        } else {
-                               pr_err(" *vpe_get_shared is NULL. "
-                                      "Has an SP program been loaded?\n");
+                               pr_err(" *vpe_get_shared is NULL. Has an SP program been loaded?\n");
                                ret = -ENOSYS;
                                goto out_fail;
                        }
                }
 
                if ((unsigned int)*p < KSEG0) {
-                       printk(KERN_WARNING "vpe_get_shared returned an "
-                              "invalid pointer maybe an error code %d\n",
-                              (int)*p);
+                       pr_warn("vpe_get_shared returned an invalid pointer maybe an error code %d\n",
+                               (int)*p);
                        ret = -ENOSYS;
                        goto out_fail;
                }
 
-               if ((ret = rtlx_init(*p)) < 0)
+               ret = rtlx_init(*p);
+               if (ret < 0)
                        goto out_ret;
        }
 
@@ -352,7 +287,7 @@ ssize_t rtlx_write(int index, const void __user *buffer, size_t count)
        size_t fl;
 
        if (rtlx == NULL)
-               return(-ENOSYS);
+               return -ENOSYS;
 
        rt = &rtlx->channel[index];
 
@@ -361,8 +296,8 @@ ssize_t rtlx_write(int index, const void __user *buffer, size_t count)
        rt_read = rt->rt_read;
 
        /* total number of bytes to copy */
-       count = min(count, (size_t)write_spacefree(rt_read, rt->rt_write,
-                                                       rt->buffer_size));
+       count = min_t(size_t, count, write_spacefree(rt_read, rt->rt_write,
+                                                    rt->buffer_size));
 
        /* first bit from write pointer to the end of the buffer, or count */
        fl = min(count, (size_t) rt->buffer_size - rt->rt_write);
@@ -372,9 +307,8 @@ ssize_t rtlx_write(int index, const void __user *buffer, size_t count)
                goto out;
 
        /* if there's any left copy to the beginning of the buffer */
-       if (count - fl) {
+       if (count - fl)
                failed = copy_from_user(rt->rt_buffer, buffer + fl, count - fl);
-       }
 
 out:
        count -= failed;
@@ -384,6 +318,8 @@ out:
        smp_wmb();
        mutex_unlock(&channel_wqs[index].mutex);
 
+       _interrupt_sp();
+
        return count;
 }
 
@@ -398,7 +334,7 @@ static int file_release(struct inode *inode, struct file *filp)
        return rtlx_release(iminor(inode));
 }
 
-static unsigned int file_poll(struct file *file, poll_table * wait)
+static unsigned int file_poll(struct file *file, poll_table *wait)
 {
        int minor = iminor(file_inode(file));
        unsigned int mask = 0;
@@ -420,21 +356,20 @@ static unsigned int file_poll(struct file *file, poll_table * wait)
        return mask;
 }
 
-static ssize_t file_read(struct file *file, char __user * buffer, size_t count,
-                        loff_t * ppos)
+static ssize_t file_read(struct file *file, char __user *buffer, size_t count,
+                        loff_t *ppos)
 {
        int minor = iminor(file_inode(file));
 
        /* data available? */
-       if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1)) {
-               return 0;       // -EAGAIN makes cat whinge
-       }
+       if (!rtlx_read_poll(minor, (file->f_flags & O_NONBLOCK) ? 0 : 1))
+               return 0;       /* -EAGAIN makes 'cat' whine */
 
        return rtlx_read(minor, buffer, count);
 }
 
-static ssize_t file_write(struct file *file, const char __user * buffer,
-                         size_t count, loff_t * ppos)
+static ssize_t file_write(struct file *file, const char __user *buffer,
+                         size_t count, loff_t *ppos)
 {
        int minor = iminor(file_inode(file));
 
@@ -454,100 +389,16 @@ static ssize_t file_write(struct file *file, const char __user * buffer,
        return rtlx_write(minor, buffer, count);
 }
 
-static const struct file_operations rtlx_fops = {
+const struct file_operations rtlx_fops = {
        .owner =   THIS_MODULE,
-       .open =    file_open,
+       .open =    file_open,
        .release = file_release,
        .write =   file_write,
-       .read =    file_read,
-       .poll =    file_poll,
+       .read =    file_read,
+       .poll =    file_poll,
        .llseek =  noop_llseek,
 };
 
-static struct irqaction rtlx_irq = {
-       .handler        = rtlx_interrupt,
-       .name           = "RTLX",
-};
-
-static int rtlx_irq_num = MIPS_CPU_IRQ_BASE + MIPS_CPU_RTLX_IRQ;
-
-static char register_chrdev_failed[] __initdata =
-       KERN_ERR "rtlx_module_init: unable to register device\n";
-
-static int __init rtlx_module_init(void)
-{
-       struct device *dev;
-       int i, err;
-
-       if (!cpu_has_mipsmt) {
-               printk("VPE loader: not a MIPS MT capable processor\n");
-               return -ENODEV;
-       }
-
-       if (tclimit == 0) {
-               printk(KERN_WARNING "No TCs reserved for AP/SP, not "
-                      "initializing RTLX.\nPass maxtcs=<n> argument as kernel "
-                      "argument\n");
-
-               return -ENODEV;
-       }
-
-       major = register_chrdev(0, module_name, &rtlx_fops);
-       if (major < 0) {
-               printk(register_chrdev_failed);
-               return major;
-       }
-
-       /* initialise the wait queues */
-       for (i = 0; i < RTLX_CHANNELS; i++) {
-               init_waitqueue_head(&channel_wqs[i].rt_queue);
-               init_waitqueue_head(&channel_wqs[i].lx_queue);
-               atomic_set(&channel_wqs[i].in_open, 0);
-               mutex_init(&channel_wqs[i].mutex);
-
-               dev = device_create(mt_class, NULL, MKDEV(major, i), NULL,
-                                   "%s%d", module_name, i);
-               if (IS_ERR(dev)) {
-                       err = PTR_ERR(dev);
-                       goto out_chrdev;
-               }
-       }
-
-       /* set up notifiers */
-       notify.start = starting;
-       notify.stop = stopping;
-       vpe_notify(tclimit, &notify);
-
-       if (cpu_has_vint)
-               set_vi_handler(MIPS_CPU_RTLX_IRQ, rtlx_dispatch);
-       else {
-               pr_err("APRP RTLX init on non-vectored-interrupt processor\n");
-               err = -ENODEV;
-               goto out_chrdev;
-       }
-
-       rtlx_irq.dev_id = rtlx;
-       setup_irq(rtlx_irq_num, &rtlx_irq);
-
-       return 0;
-
-out_chrdev:
-       for (i = 0; i < RTLX_CHANNELS; i++)
-               device_destroy(mt_class, MKDEV(major, i));
-
-       return err;
-}
-
-static void __exit rtlx_module_exit(void)
-{
-       int i;
-
-       for (i = 0; i < RTLX_CHANNELS; i++)
-               device_destroy(mt_class, MKDEV(major, i));
-
-       unregister_chrdev(major, module_name);
-}
-
 module_init(rtlx_module_init);
 module_exit(rtlx_module_exit);
 
diff --git a/arch/mips/kernel/segment.c b/arch/mips/kernel/segment.c
new file mode 100644 (file)
index 0000000..076ead2
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ */
+
+#include <linux/kernel.h>
+#include <linux/debugfs.h>
+#include <linux/seq_file.h>
+#include <asm/cpu.h>
+#include <asm/mipsregs.h>
+
+static void build_segment_config(char *str, unsigned int cfg)
+{
+       unsigned int am;
+       static const char * const am_str[] = {
+               "UK", "MK", "MSK", "MUSK", "MUSUK", "USK",
+               "RSRVD", "UUSK"};
+
+       /* Segment access mode. */
+       am = (cfg & MIPS_SEGCFG_AM) >> MIPS_SEGCFG_AM_SHIFT;
+       str += sprintf(str, "%-5s", am_str[am]);
+
+       /*
+        * Access modes MK, MSK and MUSK are mapped segments. Therefore
+        * there is no direct physical address mapping.
+        */
+       if ((am == 0) || (am > 3)) {
+               str += sprintf(str, "         %03lx",
+                       ((cfg & MIPS_SEGCFG_PA) >> MIPS_SEGCFG_PA_SHIFT));
+               str += sprintf(str, "         %01ld",
+                       ((cfg & MIPS_SEGCFG_C) >> MIPS_SEGCFG_C_SHIFT));
+       } else {
+               str += sprintf(str, "         UND");
+               str += sprintf(str, "         U");
+       }
+
+       /* Exception configuration. */
+       str += sprintf(str, "       %01ld\n",
+               ((cfg & MIPS_SEGCFG_EU) >> MIPS_SEGCFG_EU_SHIFT));
+}
+
+static int show_segments(struct seq_file *m, void *v)
+{
+       unsigned int segcfg;
+       char str[42];
+
+       seq_puts(m, "Segment   Virtual    Size   Access Mode   Physical   Caching   EU\n");
+       seq_puts(m, "-------   -------    ----   -----------   --------   -------   --\n");
+
+       segcfg = read_c0_segctl0();
+       build_segment_config(str, segcfg);
+       seq_printf(m, "   0      e0000000   512M      %s", str);
+
+       segcfg >>= 16;
+       build_segment_config(str, segcfg);
+       seq_printf(m, "   1      c0000000   512M      %s", str);
+
+       segcfg = read_c0_segctl1();
+       build_segment_config(str, segcfg);
+       seq_printf(m, "   2      a0000000   512M      %s", str);
+
+       segcfg >>= 16;
+       build_segment_config(str, segcfg);
+       seq_printf(m, "   3      80000000   512M      %s", str);
+
+       segcfg = read_c0_segctl2();
+       build_segment_config(str, segcfg);
+       seq_printf(m, "   4      40000000    1G       %s", str);
+
+       segcfg >>= 16;
+       build_segment_config(str, segcfg);
+       seq_printf(m, "   5      00000000    1G       %s\n", str);
+
+       return 0;
+}
+
+static int segments_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, show_segments, NULL);
+}
+
+static const struct file_operations segments_fops = {
+       .open           = segments_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static int __init segments_info(void)
+{
+       extern struct dentry *mips_debugfs_dir;
+       struct dentry *segments;
+
+       if (cpu_has_segments) {
+               if (!mips_debugfs_dir)
+                       return -ENODEV;
+
+               segments = debugfs_create_file("segments", S_IRUGO,
+                                              mips_debugfs_dir, NULL,
+                                              &segments_fops);
+               if (!segments)
+                       return -ENOMEM;
+       }
+       return 0;
+}
+
+device_initcall(segments_info);
index 2f285abc76d5b9be1e68920bdbe962b5c6c6d11f..5199563c4403a5bb0cebbeaf85bb2aeca8b1b8c2 100644 (file)
@@ -71,8 +71,9 @@ static int protected_save_fp_context(struct sigcontext __user *sc)
        int err;
        while (1) {
                lock_fpu_owner();
-               own_fpu_inatomic(1);
-               err = save_fp_context(sc); /* this might fail */
+               err = own_fpu_inatomic(1);
+               if (!err)
+                       err = save_fp_context(sc); /* this might fail */
                unlock_fpu_owner();
                if (likely(!err))
                        break;
@@ -91,8 +92,9 @@ static int protected_restore_fp_context(struct sigcontext __user *sc)
        int err, tmp __maybe_unused;
        while (1) {
                lock_fpu_owner();
-               own_fpu_inatomic(0);
-               err = restore_fp_context(sc); /* this might fail */
+               err = own_fpu_inatomic(0);
+               if (!err)
+                       err = restore_fp_context(sc); /* this might fail */
                unlock_fpu_owner();
                if (likely(!err))
                        break;
index 1905a419aa46f9e5e0018b9b9c1be8466762aaa3..3d60f7750fa8d873c4651cd362239a0441e24c72 100644 (file)
@@ -85,8 +85,9 @@ static int protected_save_fp_context32(struct sigcontext32 __user *sc)
        int err;
        while (1) {
                lock_fpu_owner();
-               own_fpu_inatomic(1);
-               err = save_fp_context32(sc); /* this might fail */
+               err = own_fpu_inatomic(1);
+               if (!err)
+                       err = save_fp_context32(sc); /* this might fail */
                unlock_fpu_owner();
                if (likely(!err))
                        break;
@@ -105,8 +106,9 @@ static int protected_restore_fp_context32(struct sigcontext32 __user *sc)
        int err, tmp __maybe_unused;
        while (1) {
                lock_fpu_owner();
-               own_fpu_inatomic(0);
-               err = restore_fp_context32(sc); /* this might fail */
+               err = own_fpu_inatomic(0);
+               if (!err)
+                       err = restore_fp_context32(sc); /* this might fail */
                unlock_fpu_owner();
                if (likely(!err))
                        break;
index 2362665ba4965f2b3ff272a34bb5aca6360f8897..ea4c2dc316927476ce6ef86ff461d1ec28299327 100644 (file)
@@ -49,8 +49,10 @@ cpumask_t bmips_booted_mask;
 unsigned long bmips_smp_boot_sp;
 unsigned long bmips_smp_boot_gp;
 
-static void bmips_send_ipi_single(int cpu, unsigned int action);
-static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id);
+static void bmips43xx_send_ipi_single(int cpu, unsigned int action);
+static void bmips5000_send_ipi_single(int cpu, unsigned int action);
+static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id);
+static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id);
 
 /* SW interrupts 0,1 are used for interprocessor signaling */
 #define IPI0_IRQ                       (MIPS_CPU_IRQ_BASE + 0)
@@ -64,49 +66,58 @@ static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id);
 static void __init bmips_smp_setup(void)
 {
        int i, cpu = 1, boot_cpu = 0;
-
-#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
        int cpu_hw_intr;
 
-       /* arbitration priority */
-       clear_c0_brcm_cmt_ctrl(0x30);
-
-       /* NBK and weak order flags */
-       set_c0_brcm_config_0(0x30000);
-
-       /* Find out if we are running on TP0 or TP1 */
-       boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
-
-       /*
-        * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other thread
-        * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output
-        * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output
-        */
-       if (boot_cpu == 0)
-               cpu_hw_intr = 0x02;
-       else
-               cpu_hw_intr = 0x1d;
-
-       change_c0_brcm_cmt_intr(0xf8018000, (cpu_hw_intr << 27) | (0x03 << 15));
-
-       /* single core, 2 threads (2 pipelines) */
-       max_cpus = 2;
-#elif defined(CONFIG_CPU_BMIPS5000)
-       /* enable raceless SW interrupts */
-       set_c0_brcm_config(0x03 << 22);
-
-       /* route HW interrupt 0 to CPU0, HW interrupt 1 to CPU1 */
-       change_c0_brcm_mode(0x1f << 27, 0x02 << 27);
-
-       /* N cores, 2 threads per core */
-       max_cpus = (((read_c0_brcm_config() >> 6) & 0x03) + 1) << 1;
+       switch (current_cpu_type()) {
+       case CPU_BMIPS4350:
+       case CPU_BMIPS4380:
+               /* arbitration priority */
+               clear_c0_brcm_cmt_ctrl(0x30);
+
+               /* NBK and weak order flags */
+               set_c0_brcm_config_0(0x30000);
+
+               /* Find out if we are running on TP0 or TP1 */
+               boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
+
+               /*
+                * MIPS interrupts 0,1 (SW INT 0,1) cross over to the other
+                * thread
+                * MIPS interrupt 2 (HW INT 0) is the CPU0 L1 controller output
+                * MIPS interrupt 3 (HW INT 1) is the CPU1 L1 controller output
+                */
+               if (boot_cpu == 0)
+                       cpu_hw_intr = 0x02;
+               else
+                       cpu_hw_intr = 0x1d;
+
+               change_c0_brcm_cmt_intr(0xf8018000,
+                                       (cpu_hw_intr << 27) | (0x03 << 15));
+
+               /* single core, 2 threads (2 pipelines) */
+               max_cpus = 2;
+
+               break;
+       case CPU_BMIPS5000:
+               /* enable raceless SW interrupts */
+               set_c0_brcm_config(0x03 << 22);
+
+               /* route HW interrupt 0 to CPU0, HW interrupt 1 to CPU1 */
+               change_c0_brcm_mode(0x1f << 27, 0x02 << 27);
+
+               /* N cores, 2 threads per core */
+               max_cpus = (((read_c0_brcm_config() >> 6) & 0x03) + 1) << 1;
+
+               /* clear any pending SW interrupts */
+               for (i = 0; i < max_cpus; i++) {
+                       write_c0_brcm_action(ACTION_CLR_IPI(i, 0));
+                       write_c0_brcm_action(ACTION_CLR_IPI(i, 1));
+               }
 
-       /* clear any pending SW interrupts */
-       for (i = 0; i < max_cpus; i++) {
-               write_c0_brcm_action(ACTION_CLR_IPI(i, 0));
-               write_c0_brcm_action(ACTION_CLR_IPI(i, 1));
+               break;
+       default:
+               max_cpus = 1;
        }
-#endif
 
        if (!bmips_smp_enabled)
                max_cpus = 1;
@@ -134,6 +145,20 @@ static void __init bmips_smp_setup(void)
  */
 static void bmips_prepare_cpus(unsigned int max_cpus)
 {
+       irqreturn_t (*bmips_ipi_interrupt)(int irq, void *dev_id);
+
+       switch (current_cpu_type()) {
+       case CPU_BMIPS4350:
+       case CPU_BMIPS4380:
+               bmips_ipi_interrupt = bmips43xx_ipi_interrupt;
+               break;
+       case CPU_BMIPS5000:
+               bmips_ipi_interrupt = bmips5000_ipi_interrupt;
+               break;
+       default:
+               return;
+       }
+
        if (request_irq(IPI0_IRQ, bmips_ipi_interrupt, IRQF_PERCPU,
                        "smp_ipi0", NULL))
                panic("Can't request IPI0 interrupt");
@@ -168,26 +193,39 @@ static void bmips_boot_secondary(int cpu, struct task_struct *idle)
 
        pr_info("SMP: Booting CPU%d...\n", cpu);
 
-       if (cpumask_test_cpu(cpu, &bmips_booted_mask))
-               bmips_send_ipi_single(cpu, 0);
+       if (cpumask_test_cpu(cpu, &bmips_booted_mask)) {
+               switch (current_cpu_type()) {
+               case CPU_BMIPS4350:
+               case CPU_BMIPS4380:
+                       bmips43xx_send_ipi_single(cpu, 0);
+                       break;
+               case CPU_BMIPS5000:
+                       bmips5000_send_ipi_single(cpu, 0);
+                       break;
+               }
+       }
        else {
-#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
-               /* Reset slave TP1 if booting from TP0 */
-               if (cpu_logical_map(cpu) == 1)
-                       set_c0_brcm_cmt_ctrl(0x01);
-#elif defined(CONFIG_CPU_BMIPS5000)
-               if (cpu & 0x01)
-                       write_c0_brcm_action(ACTION_BOOT_THREAD(cpu));
-               else {
-                       /*
-                        * core N thread 0 was already booted; just
-                        * pulse the NMI line
-                        */
-                       bmips_write_zscm_reg(0x210, 0xc0000000);
-                       udelay(10);
-                       bmips_write_zscm_reg(0x210, 0x00);
+               switch (current_cpu_type()) {
+               case CPU_BMIPS4350:
+               case CPU_BMIPS4380:
+                       /* Reset slave TP1 if booting from TP0 */
+                       if (cpu_logical_map(cpu) == 1)
+                               set_c0_brcm_cmt_ctrl(0x01);
+                       break;
+               case CPU_BMIPS5000:
+                       if (cpu & 0x01)
+                               write_c0_brcm_action(ACTION_BOOT_THREAD(cpu));
+                       else {
+                               /*
+                                * core N thread 0 was already booted; just
+                                * pulse the NMI line
+                                */
+                               bmips_write_zscm_reg(0x210, 0xc0000000);
+                               udelay(10);
+                               bmips_write_zscm_reg(0x210, 0x00);
+                       }
+                       break;
                }
-#endif
                cpumask_set_cpu(cpu, &bmips_booted_mask);
        }
 }
@@ -199,26 +237,32 @@ static void bmips_init_secondary(void)
 {
        /* move NMI vector to kseg0, in case XKS01 is enabled */
 
-#if defined(CONFIG_CPU_BMIPS4350) || defined(CONFIG_CPU_BMIPS4380)
-       void __iomem *cbr = BMIPS_GET_CBR();
+       void __iomem *cbr;
        unsigned long old_vec;
        unsigned long relo_vector;
        int boot_cpu;
 
-       boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
-       relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 :
-                         BMIPS_RELO_VECTOR_CONTROL_1;
+       switch (current_cpu_type()) {
+       case CPU_BMIPS4350:
+       case CPU_BMIPS4380:
+               cbr = BMIPS_GET_CBR();
 
-       old_vec = __raw_readl(cbr + relo_vector);
-       __raw_writel(old_vec & ~0x20000000, cbr + relo_vector);
+               boot_cpu = !!(read_c0_brcm_cmt_local() & (1 << 31));
+               relo_vector = boot_cpu ? BMIPS_RELO_VECTOR_CONTROL_0 :
+                                 BMIPS_RELO_VECTOR_CONTROL_1;
 
-       clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0);
-#elif defined(CONFIG_CPU_BMIPS5000)
-       write_c0_brcm_bootvec(read_c0_brcm_bootvec() &
-               (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000));
+               old_vec = __raw_readl(cbr + relo_vector);
+               __raw_writel(old_vec & ~0x20000000, cbr + relo_vector);
 
-       write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0));
-#endif
+               clear_c0_cause(smp_processor_id() ? C_SW1 : C_SW0);
+               break;
+       case CPU_BMIPS5000:
+               write_c0_brcm_bootvec(read_c0_brcm_bootvec() &
+                       (smp_processor_id() & 0x01 ? ~0x20000000 : ~0x2000));
+
+               write_c0_brcm_action(ACTION_CLR_IPI(smp_processor_id(), 0));
+               break;
+       }
 }
 
 /*
@@ -243,8 +287,6 @@ static void bmips_cpus_done(void)
 {
 }
 
-#if defined(CONFIG_CPU_BMIPS5000)
-
 /*
  * BMIPS5000 raceless IPIs
  *
@@ -253,12 +295,12 @@ static void bmips_cpus_done(void)
  * IPI1 is used for SMP_CALL_FUNCTION
  */
 
-static void bmips_send_ipi_single(int cpu, unsigned int action)
+static void bmips5000_send_ipi_single(int cpu, unsigned int action)
 {
        write_c0_brcm_action(ACTION_SET_IPI(cpu, action == SMP_CALL_FUNCTION));
 }
 
-static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id)
+static irqreturn_t bmips5000_ipi_interrupt(int irq, void *dev_id)
 {
        int action = irq - IPI0_IRQ;
 
@@ -272,7 +314,14 @@ static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#else
+static void bmips5000_send_ipi_mask(const struct cpumask *mask,
+       unsigned int action)
+{
+       unsigned int i;
+
+       for_each_cpu(i, mask)
+               bmips5000_send_ipi_single(i, action);
+}
 
 /*
  * BMIPS43xx racey IPIs
@@ -287,7 +336,7 @@ static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id)
 static DEFINE_SPINLOCK(ipi_lock);
 static DEFINE_PER_CPU(int, ipi_action_mask);
 
-static void bmips_send_ipi_single(int cpu, unsigned int action)
+static void bmips43xx_send_ipi_single(int cpu, unsigned int action)
 {
        unsigned long flags;
 
@@ -298,7 +347,7 @@ static void bmips_send_ipi_single(int cpu, unsigned int action)
        spin_unlock_irqrestore(&ipi_lock, flags);
 }
 
-static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id)
+static irqreturn_t bmips43xx_ipi_interrupt(int irq, void *dev_id)
 {
        unsigned long flags;
        int action, cpu = irq - IPI0_IRQ;
@@ -317,15 +366,13 @@ static irqreturn_t bmips_ipi_interrupt(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#endif /* BMIPS type */
-
-static void bmips_send_ipi_mask(const struct cpumask *mask,
+static void bmips43xx_send_ipi_mask(const struct cpumask *mask,
        unsigned int action)
 {
        unsigned int i;
 
        for_each_cpu(i, mask)
-               bmips_send_ipi_single(i, action);
+               bmips43xx_send_ipi_single(i, action);
 }
 
 #ifdef CONFIG_HOTPLUG_CPU
@@ -381,15 +428,30 @@ void __ref play_dead(void)
 
 #endif /* CONFIG_HOTPLUG_CPU */
 
-struct plat_smp_ops bmips_smp_ops = {
+struct plat_smp_ops bmips43xx_smp_ops = {
+       .smp_setup              = bmips_smp_setup,
+       .prepare_cpus           = bmips_prepare_cpus,
+       .boot_secondary         = bmips_boot_secondary,
+       .smp_finish             = bmips_smp_finish,
+       .init_secondary         = bmips_init_secondary,
+       .cpus_done              = bmips_cpus_done,
+       .send_ipi_single        = bmips43xx_send_ipi_single,
+       .send_ipi_mask          = bmips43xx_send_ipi_mask,
+#ifdef CONFIG_HOTPLUG_CPU
+       .cpu_disable            = bmips_cpu_disable,
+       .cpu_die                = bmips_cpu_die,
+#endif
+};
+
+struct plat_smp_ops bmips5000_smp_ops = {
        .smp_setup              = bmips_smp_setup,
        .prepare_cpus           = bmips_prepare_cpus,
        .boot_secondary         = bmips_boot_secondary,
        .smp_finish             = bmips_smp_finish,
        .init_secondary         = bmips_init_secondary,
        .cpus_done              = bmips_cpus_done,
-       .send_ipi_single        = bmips_send_ipi_single,
-       .send_ipi_mask          = bmips_send_ipi_mask,
+       .send_ipi_single        = bmips5000_send_ipi_single,
+       .send_ipi_mask          = bmips5000_send_ipi_mask,
 #ifdef CONFIG_HOTPLUG_CPU
        .cpu_disable            = bmips_cpu_disable,
        .cpu_die                = bmips_cpu_die,
@@ -427,43 +489,47 @@ void bmips_ebase_setup(void)
 
        BUG_ON(ebase != CKSEG0);
 
-#if defined(CONFIG_CPU_BMIPS4350)
-       /*
-        * BMIPS4350 cannot relocate the normal vectors, but it
-        * can relocate the BEV=1 vectors.  So CPU1 starts up at
-        * the relocated BEV=1, IV=0 general exception vector @
-        * 0xa000_0380.
-        *
-        * set_uncached_handler() is used here because:
-        *  - CPU1 will run this from uncached space
-        *  - None of the cacheflush functions are set up yet
-        */
-       set_uncached_handler(BMIPS_WARM_RESTART_VEC - CKSEG0,
-               &bmips_smp_int_vec, 0x80);
-       __sync();
-       return;
-#elif defined(CONFIG_CPU_BMIPS4380)
-       /*
-        * 0x8000_0000: reset/NMI (initially in kseg1)
-        * 0x8000_0400: normal vectors
-        */
-       new_ebase = 0x80000400;
-       cbr = BMIPS_GET_CBR();
-       __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
-       __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
-#elif defined(CONFIG_CPU_BMIPS5000)
-       /*
-        * 0x8000_0000: reset/NMI (initially in kseg1)
-        * 0x8000_1000: normal vectors
-        */
-       new_ebase = 0x80001000;
-       write_c0_brcm_bootvec(0xa0088008);
-       write_c0_ebase(new_ebase);
-       if (max_cpus > 2)
-               bmips_write_zscm_reg(0xa0, 0xa008a008);
-#else
-       return;
-#endif
+       switch (current_cpu_type()) {
+       case CPU_BMIPS4350:
+               /*
+                * BMIPS4350 cannot relocate the normal vectors, but it
+                * can relocate the BEV=1 vectors.  So CPU1 starts up at
+                * the relocated BEV=1, IV=0 general exception vector @
+                * 0xa000_0380.
+                *
+                * set_uncached_handler() is used here because:
+                *  - CPU1 will run this from uncached space
+                *  - None of the cacheflush functions are set up yet
+                */
+               set_uncached_handler(BMIPS_WARM_RESTART_VEC - CKSEG0,
+                       &bmips_smp_int_vec, 0x80);
+               __sync();
+               return;
+       case CPU_BMIPS4380:
+               /*
+                * 0x8000_0000: reset/NMI (initially in kseg1)
+                * 0x8000_0400: normal vectors
+                */
+               new_ebase = 0x80000400;
+               cbr = BMIPS_GET_CBR();
+               __raw_writel(0x80080800, cbr + BMIPS_RELO_VECTOR_CONTROL_0);
+               __raw_writel(0xa0080800, cbr + BMIPS_RELO_VECTOR_CONTROL_1);
+               break;
+       case CPU_BMIPS5000:
+               /*
+                * 0x8000_0000: reset/NMI (initially in kseg1)
+                * 0x8000_1000: normal vectors
+                */
+               new_ebase = 0x80001000;
+               write_c0_brcm_bootvec(0xa0088008);
+               write_c0_ebase(new_ebase);
+               if (max_cpus > 2)
+                       bmips_write_zscm_reg(0xa0, 0xa008a008);
+               break;
+       default:
+               return;
+       }
+
        board_nmi_handler_setup = &bmips_nmi_handler_setup;
        ebase = new_ebase;
 }
index 5969f1e9b62a5c2b8fa0fc2645de79bc1dfa4aa7..1b925d8a610cdce41f7e0f031943d8afeb678518 100644 (file)
@@ -199,11 +199,14 @@ void __init cmp_prepare_cpus(unsigned int max_cpus)
        pr_debug("SMPCMP: CPU%d: %s max_cpus=%d\n",
                 smp_processor_id(), __func__, max_cpus);
 
+#ifdef CONFIG_MIPS_MT
        /*
         * FIXME: some of these options are per-system, some per-core and
         * some per-cpu
         */
        mips_mt_set_cpuoptions();
+#endif
+
 }
 
 struct plat_smp_ops cmp_smp_ops = {
index 57a3f7a2b370c1af38296b7439b26bf60f387833..0fb8cefc9114b299fd5ed3b73ef3da86abf4da8e 100644 (file)
@@ -71,6 +71,7 @@ static unsigned int __init smvp_vpe_init(unsigned int tc, unsigned int mvpconf0,
 
                /* Record this as available CPU */
                set_cpu_possible(tc, true);
+               set_cpu_present(tc, true);
                __cpu_number_map[tc]    = ++ncpu;
                __cpu_logical_map[ncpu] = tc;
        }
@@ -112,12 +113,39 @@ static void __init smvp_tc_init(unsigned int tc, unsigned int mvpconf0)
        write_tc_c0_tchalt(TCHALT_H);
 }
 
+#ifdef CONFIG_IRQ_GIC
+static void mp_send_ipi_single(int cpu, unsigned int action)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       switch (action) {
+       case SMP_CALL_FUNCTION:
+               gic_send_ipi(plat_ipi_call_int_xlate(cpu));
+               break;
+
+       case SMP_RESCHEDULE_YOURSELF:
+               gic_send_ipi(plat_ipi_resched_int_xlate(cpu));
+               break;
+       }
+
+       local_irq_restore(flags);
+}
+#endif
+
 static void vsmp_send_ipi_single(int cpu, unsigned int action)
 {
        int i;
        unsigned long flags;
        int vpflags;
 
+#ifdef CONFIG_IRQ_GIC
+       if (gic_present) {
+               mp_send_ipi_single(cpu, action);
+               return;
+       }
+#endif
        local_irq_save(flags);
 
        vpflags = dvpe();       /* can't access the other CPU's registers whilst MVPE enabled */
index 93f86817f20a64aae37b136d7fa3f2429e18852b..b242e2c10ea0b6b5c1230579e4a6ad83463fed49 100644 (file)
@@ -8,7 +8,6 @@
  *
  * Copyright (C) 2007, 2008 MIPS Technologies, Inc.
  */
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
 #include <linux/stddef.h>
@@ -206,6 +205,8 @@ void spram_config(void)
        case CPU_34K:
        case CPU_74K:
        case CPU_1004K:
+       case CPU_INTERAPTIV:
+       case CPU_PROAPTIV:
                config0 = read_c0_config();
                /* FIXME: addresses are Malta specific */
                if (config0 & (1<<24)) {
index 84536bf4a15403157296bf0324d144cbb5e87a34..c24ad5f4b324596368391ee1af1fffb1972d7a07 100644 (file)
@@ -11,7 +11,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/irqflags.h>
 #include <linux/cpumask.h>
 
index f9c8746be8d66d78b3ad1fc500d72674d486cdb9..e0b499694d180ae1513153b1acbcfbf031ab240a 100644 (file)
@@ -78,6 +78,7 @@ extern asmlinkage void handle_cpu(void);
 extern asmlinkage void handle_ov(void);
 extern asmlinkage void handle_tr(void);
 extern asmlinkage void handle_fpe(void);
+extern asmlinkage void handle_ftlb(void);
 extern asmlinkage void handle_mdmx(void);
 extern asmlinkage void handle_watch(void);
 extern asmlinkage void handle_mt(void);
@@ -1080,7 +1081,7 @@ asmlinkage void do_cpu(struct pt_regs *regs)
        unsigned long old_epc, old31;
        unsigned int opcode;
        unsigned int cpid;
-       int status;
+       int status, err;
        unsigned long __maybe_unused flags;
 
        prev_state = exception_enter();
@@ -1153,19 +1154,19 @@ asmlinkage void do_cpu(struct pt_regs *regs)
 
        case 1:
                if (used_math())        /* Using the FPU again.  */
-                       own_fpu(1);
+                       err = own_fpu(1);
                else {                  /* First time FPU user.  */
-                       init_fpu();
+                       err = init_fpu();
                        set_used_math();
                }
 
-               if (!raw_cpu_has_fpu) {
+               if (!raw_cpu_has_fpu || err) {
                        int sig;
                        void __user *fault_addr = NULL;
                        sig = fpu_emulator_cop1Handler(regs,
                                                       &current->thread.fpu,
                                                       0, &fault_addr);
-                       if (!process_fpemu_return(sig, fault_addr))
+                       if (!process_fpemu_return(sig, fault_addr) && !err)
                                mt_ase_fp_affinity();
                }
 
@@ -1336,6 +1337,8 @@ static inline void parity_protection_init(void)
        case CPU_34K:
        case CPU_74K:
        case CPU_1004K:
+       case CPU_INTERAPTIV:
+       case CPU_PROAPTIV:
                {
 #define ERRCTL_PE      0x80000000
 #define ERRCTL_L2P     0x00800000
@@ -1425,14 +1428,27 @@ asmlinkage void cache_parity_error(void)
        printk("Decoded c0_cacheerr: %s cache fault in %s reference.\n",
               reg_val & (1<<30) ? "secondary" : "primary",
               reg_val & (1<<31) ? "data" : "insn");
-       printk("Error bits: %s%s%s%s%s%s%s\n",
-              reg_val & (1<<29) ? "ED " : "",
-              reg_val & (1<<28) ? "ET " : "",
-              reg_val & (1<<26) ? "EE " : "",
-              reg_val & (1<<25) ? "EB " : "",
-              reg_val & (1<<24) ? "EI " : "",
-              reg_val & (1<<23) ? "E1 " : "",
-              reg_val & (1<<22) ? "E0 " : "");
+       if (cpu_has_mips_r2 &&
+           ((current_cpu_data.processor_id && 0xff0000) == PRID_COMP_MIPS)) {
+               pr_err("Error bits: %s%s%s%s%s%s%s%s\n",
+                       reg_val & (1<<29) ? "ED " : "",
+                       reg_val & (1<<28) ? "ET " : "",
+                       reg_val & (1<<27) ? "ES " : "",
+                       reg_val & (1<<26) ? "EE " : "",
+                       reg_val & (1<<25) ? "EB " : "",
+                       reg_val & (1<<24) ? "EI " : "",
+                       reg_val & (1<<23) ? "E1 " : "",
+                       reg_val & (1<<22) ? "E0 " : "");
+       } else {
+               pr_err("Error bits: %s%s%s%s%s%s%s\n",
+                       reg_val & (1<<29) ? "ED " : "",
+                       reg_val & (1<<28) ? "ET " : "",
+                       reg_val & (1<<26) ? "EE " : "",
+                       reg_val & (1<<25) ? "EB " : "",
+                       reg_val & (1<<24) ? "EI " : "",
+                       reg_val & (1<<23) ? "E1 " : "",
+                       reg_val & (1<<22) ? "E0 " : "");
+       }
        printk("IDX: 0x%08x\n", reg_val & ((1<<22)-1));
 
 #if defined(CONFIG_CPU_MIPS32) || defined(CONFIG_CPU_MIPS64)
@@ -1446,6 +1462,34 @@ asmlinkage void cache_parity_error(void)
        panic("Can't handle the cache error!");
 }
 
+asmlinkage void do_ftlb(void)
+{
+       const int field = 2 * sizeof(unsigned long);
+       unsigned int reg_val;
+
+       /* For the moment, report the problem and hang. */
+       if (cpu_has_mips_r2 &&
+           ((current_cpu_data.processor_id && 0xff0000) == PRID_COMP_MIPS)) {
+               pr_err("FTLB error exception, cp0_ecc=0x%08x:\n",
+                      read_c0_ecc());
+               pr_err("cp0_errorepc == %0*lx\n", field, read_c0_errorepc());
+               reg_val = read_c0_cacheerr();
+               pr_err("c0_cacheerr == %08x\n", reg_val);
+
+               if ((reg_val & 0xc0000000) == 0xc0000000) {
+                       pr_err("Decoded c0_cacheerr: FTLB parity error\n");
+               } else {
+                       pr_err("Decoded c0_cacheerr: %s cache fault in %s reference.\n",
+                              reg_val & (1<<30) ? "secondary" : "primary",
+                              reg_val & (1<<31) ? "data" : "insn");
+               }
+       } else {
+               pr_err("FTLB error exception\n");
+       }
+       /* Just print the cacheerr bits for now */
+       cache_parity_error();
+}
+
 /*
  * SDBBP EJTAG debug exception handler.
  * We skip the instruction and return to the next instruction.
@@ -1995,6 +2039,7 @@ void __init trap_init(void)
        if (cpu_has_fpu && !cpu_has_nofpuex)
                set_except_vector(15, handle_fpe);
 
+       set_except_vector(16, handle_ftlb);
        set_except_vector(22, handle_mdmx);
 
        if (cpu_has_mcheck)
diff --git a/arch/mips/kernel/vpe-cmp.c b/arch/mips/kernel/vpe-cmp.c
new file mode 100644 (file)
index 0000000..9268ebc
--- /dev/null
@@ -0,0 +1,180 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include <asm/vpe.h>
+
+static int major;
+
+void cleanup_tc(struct tc *tc)
+{
+
+}
+
+static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t len)
+{
+       struct vpe *vpe = get_vpe(aprp_cpu_index());
+       struct vpe_notifications *notifier;
+
+       list_for_each_entry(notifier, &vpe->notify, list)
+               notifier->stop(aprp_cpu_index());
+
+       release_progmem(vpe->load_addr);
+       vpe->state = VPE_STATE_UNUSED;
+
+       return len;
+}
+static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill);
+
+static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr,
+                        char *buf)
+{
+       struct vpe *vpe = get_vpe(aprp_cpu_index());
+
+       return sprintf(buf, "%d\n", vpe->ntcs);
+}
+
+static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t len)
+{
+       struct vpe *vpe = get_vpe(aprp_cpu_index());
+       unsigned long new;
+       int ret;
+
+       ret = kstrtoul(buf, 0, &new);
+       if (ret < 0)
+               return ret;
+
+       /* APRP can only reserve one TC in a VPE and no more. */
+       if (new != 1)
+               return -EINVAL;
+
+       vpe->ntcs = new;
+
+       return len;
+}
+static DEVICE_ATTR_RW(ntcs);
+
+static struct attribute *vpe_attrs[] = {
+       &dev_attr_kill.attr,
+       &dev_attr_ntcs.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(vpe);
+
+static void vpe_device_release(struct device *cd)
+{
+       kfree(cd);
+}
+
+static struct class vpe_class = {
+       .name = "vpe",
+       .owner = THIS_MODULE,
+       .dev_release = vpe_device_release,
+       .dev_groups = vpe_groups,
+};
+
+static struct device vpe_device;
+
+int __init vpe_module_init(void)
+{
+       struct vpe *v = NULL;
+       struct tc *t;
+       int err;
+
+       if (!cpu_has_mipsmt) {
+               pr_warn("VPE loader: not a MIPS MT capable processor\n");
+               return -ENODEV;
+       }
+
+       if (num_possible_cpus() - aprp_cpu_index() < 1) {
+               pr_warn("No VPEs reserved for AP/SP, not initialize VPE loader\n"
+                       "Pass maxcpus=<n> argument as kernel argument\n");
+               return -ENODEV;
+       }
+
+       major = register_chrdev(0, VPE_MODULE_NAME, &vpe_fops);
+       if (major < 0) {
+               pr_warn("VPE loader: unable to register character device\n");
+               return major;
+       }
+
+       err = class_register(&vpe_class);
+       if (err) {
+               pr_err("vpe_class registration failed\n");
+               goto out_chrdev;
+       }
+
+       device_initialize(&vpe_device);
+       vpe_device.class        = &vpe_class,
+       vpe_device.parent       = NULL,
+       dev_set_name(&vpe_device, "vpe_sp");
+       vpe_device.devt = MKDEV(major, VPE_MODULE_MINOR);
+       err = device_add(&vpe_device);
+       if (err) {
+               pr_err("Adding vpe_device failed\n");
+               goto out_class;
+       }
+
+       t = alloc_tc(aprp_cpu_index());
+       if (!t) {
+               pr_warn("VPE: unable to allocate TC\n");
+               err = -ENOMEM;
+               goto out_dev;
+       }
+
+       /* VPE */
+       v = alloc_vpe(aprp_cpu_index());
+       if (v == NULL) {
+               pr_warn("VPE: unable to allocate VPE\n");
+               kfree(t);
+               err = -ENOMEM;
+               goto out_dev;
+       }
+
+       v->ntcs = 1;
+
+       /* add the tc to the list of this vpe's tc's. */
+       list_add(&t->tc, &v->tc);
+
+       /* TC */
+       t->pvpe = v;    /* set the parent vpe */
+
+       return 0;
+
+out_dev:
+       device_del(&vpe_device);
+
+out_class:
+       class_unregister(&vpe_class);
+
+out_chrdev:
+       unregister_chrdev(major, VPE_MODULE_NAME);
+
+       return err;
+}
+
+void __exit vpe_module_exit(void)
+{
+       struct vpe *v, *n;
+
+       device_del(&vpe_device);
+       class_unregister(&vpe_class);
+       unregister_chrdev(major, VPE_MODULE_NAME);
+
+       /* No locking needed here */
+       list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list)
+               if (v->state != VPE_STATE_UNUSED)
+                       release_vpe(v);
+}
diff --git a/arch/mips/kernel/vpe-mt.c b/arch/mips/kernel/vpe-mt.c
new file mode 100644 (file)
index 0000000..949ae0e
--- /dev/null
@@ -0,0 +1,523 @@
+/*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
+ * Copyright (C) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
+ */
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/export.h>
+
+#include <asm/mipsregs.h>
+#include <asm/mipsmtregs.h>
+#include <asm/mips_mt.h>
+#include <asm/vpe.h>
+
+static int major;
+
+/* The number of TCs and VPEs physically available on the core */
+static int hw_tcs, hw_vpes;
+
+/* We are prepared so configure and start the VPE... */
+int vpe_run(struct vpe *v)
+{
+       unsigned long flags, val, dmt_flag;
+       struct vpe_notifications *notifier;
+       unsigned int vpeflags;
+       struct tc *t;
+
+       /* check we are the Master VPE */
+       local_irq_save(flags);
+       val = read_c0_vpeconf0();
+       if (!(val & VPECONF0_MVP)) {
+               pr_warn("VPE loader: only Master VPE's are able to config MT\n");
+               local_irq_restore(flags);
+
+               return -1;
+       }
+
+       dmt_flag = dmt();
+       vpeflags = dvpe();
+
+       if (list_empty(&v->tc)) {
+               evpe(vpeflags);
+               emt(dmt_flag);
+               local_irq_restore(flags);
+
+               pr_warn("VPE loader: No TC's associated with VPE %d\n",
+                       v->minor);
+
+               return -ENOEXEC;
+       }
+
+       t = list_first_entry(&v->tc, struct tc, tc);
+
+       /* Put MVPE's into 'configuration state' */
+       set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+       settc(t->index);
+
+       /* should check it is halted, and not activated */
+       if ((read_tc_c0_tcstatus() & TCSTATUS_A) ||
+          !(read_tc_c0_tchalt() & TCHALT_H)) {
+               evpe(vpeflags);
+               emt(dmt_flag);
+               local_irq_restore(flags);
+
+               pr_warn("VPE loader: TC %d is already active!\n",
+                       t->index);
+
+               return -ENOEXEC;
+       }
+
+       /*
+        * Write the address we want it to start running from in the TCPC
+        * register.
+        */
+       write_tc_c0_tcrestart((unsigned long)v->__start);
+       write_tc_c0_tccontext((unsigned long)0);
+
+       /*
+        * Mark the TC as activated, not interrupt exempt and not dynamically
+        * allocatable
+        */
+       val = read_tc_c0_tcstatus();
+       val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
+       write_tc_c0_tcstatus(val);
+
+       write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
+
+       /*
+        * The sde-kit passes 'memsize' to __start in $a3, so set something
+        * here...  Or set $a3 to zero and define DFLT_STACK_SIZE and
+        * DFLT_HEAP_SIZE when you compile your program
+        */
+       mttgpr(6, v->ntcs);
+       mttgpr(7, physical_memsize);
+
+       /* set up VPE1 */
+       /*
+        * bind the TC to VPE 1 as late as possible so we only have the final
+        * VPE registers to set up, and so an EJTAG probe can trigger on it
+        */
+       write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
+
+       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
+
+       back_to_back_c0_hazard();
+
+       /* Set up the XTC bit in vpeconf0 to point at our tc */
+       write_vpe_c0_vpeconf0((read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
+                             | (t->index << VPECONF0_XTC_SHIFT));
+
+       back_to_back_c0_hazard();
+
+       /* enable this VPE */
+       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
+
+       /* clear out any left overs from a previous program */
+       write_vpe_c0_status(0);
+       write_vpe_c0_cause(0);
+
+       /* take system out of configuration state */
+       clear_c0_mvpcontrol(MVPCONTROL_VPC);
+
+       /*
+        * SMTC/SMVP kernels manage VPE enable independently,
+        * but uniprocessor kernels need to turn it on, even
+        * if that wasn't the pre-dvpe() state.
+        */
+#ifdef CONFIG_SMP
+       evpe(vpeflags);
+#else
+       evpe(EVPE_ENABLE);
+#endif
+       emt(dmt_flag);
+       local_irq_restore(flags);
+
+       list_for_each_entry(notifier, &v->notify, list)
+               notifier->start(VPE_MODULE_MINOR);
+
+       return 0;
+}
+
+void cleanup_tc(struct tc *tc)
+{
+       unsigned long flags;
+       unsigned int mtflags, vpflags;
+       int tmp;
+
+       local_irq_save(flags);
+       mtflags = dmt();
+       vpflags = dvpe();
+       /* Put MVPE's into 'configuration state' */
+       set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+       settc(tc->index);
+       tmp = read_tc_c0_tcstatus();
+
+       /* mark not allocated and not dynamically allocatable */
+       tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
+       tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
+       write_tc_c0_tcstatus(tmp);
+
+       write_tc_c0_tchalt(TCHALT_H);
+       mips_ihb();
+
+       clear_c0_mvpcontrol(MVPCONTROL_VPC);
+       evpe(vpflags);
+       emt(mtflags);
+       local_irq_restore(flags);
+}
+
+/* module wrapper entry points */
+/* give me a vpe */
+void *vpe_alloc(void)
+{
+       int i;
+       struct vpe *v;
+
+       /* find a vpe */
+       for (i = 1; i < MAX_VPES; i++) {
+               v = get_vpe(i);
+               if (v != NULL) {
+                       v->state = VPE_STATE_INUSE;
+                       return v;
+               }
+       }
+       return NULL;
+}
+EXPORT_SYMBOL(vpe_alloc);
+
+/* start running from here */
+int vpe_start(void *vpe, unsigned long start)
+{
+       struct vpe *v = vpe;
+
+       v->__start = start;
+       return vpe_run(v);
+}
+EXPORT_SYMBOL(vpe_start);
+
+/* halt it for now */
+int vpe_stop(void *vpe)
+{
+       struct vpe *v = vpe;
+       struct tc *t;
+       unsigned int evpe_flags;
+
+       evpe_flags = dvpe();
+
+       t = list_entry(v->tc.next, struct tc, tc);
+       if (t != NULL) {
+               settc(t->index);
+               write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
+       }
+
+       evpe(evpe_flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(vpe_stop);
+
+/* I've done with it thank you */
+int vpe_free(void *vpe)
+{
+       struct vpe *v = vpe;
+       struct tc *t;
+       unsigned int evpe_flags;
+
+       t = list_entry(v->tc.next, struct tc, tc);
+       if (t == NULL)
+               return -ENOEXEC;
+
+       evpe_flags = dvpe();
+
+       /* Put MVPE's into 'configuration state' */
+       set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+       settc(t->index);
+       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
+
+       /* halt the TC */
+       write_tc_c0_tchalt(TCHALT_H);
+       mips_ihb();
+
+       /* mark the TC unallocated */
+       write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
+
+       v->state = VPE_STATE_UNUSED;
+
+       clear_c0_mvpcontrol(MVPCONTROL_VPC);
+       evpe(evpe_flags);
+
+       return 0;
+}
+EXPORT_SYMBOL(vpe_free);
+
+static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t len)
+{
+       struct vpe *vpe = get_vpe(aprp_cpu_index());
+       struct vpe_notifications *notifier;
+
+       list_for_each_entry(notifier, &vpe->notify, list)
+               notifier->stop(aprp_cpu_index());
+
+       release_progmem(vpe->load_addr);
+       cleanup_tc(get_tc(aprp_cpu_index()));
+       vpe_stop(vpe);
+       vpe_free(vpe);
+
+       return len;
+}
+static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill);
+
+static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr,
+                        char *buf)
+{
+       struct vpe *vpe = get_vpe(aprp_cpu_index());
+
+       return sprintf(buf, "%d\n", vpe->ntcs);
+}
+
+static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr,
+                         const char *buf, size_t len)
+{
+       struct vpe *vpe = get_vpe(aprp_cpu_index());
+       unsigned long new;
+       int ret;
+
+       ret = kstrtoul(buf, 0, &new);
+       if (ret < 0)
+               return ret;
+
+       if (new == 0 || new > (hw_tcs - aprp_cpu_index()))
+               return -EINVAL;
+
+       vpe->ntcs = new;
+
+       return len;
+}
+static DEVICE_ATTR_RW(ntcs);
+
+static struct attribute *vpe_attrs[] = {
+       &dev_attr_kill.attr,
+       &dev_attr_ntcs.attr,
+       NULL,
+};
+ATTRIBUTE_GROUPS(vpe);
+
+static void vpe_device_release(struct device *cd)
+{
+       kfree(cd);
+}
+
+static struct class vpe_class = {
+       .name = "vpe",
+       .owner = THIS_MODULE,
+       .dev_release = vpe_device_release,
+       .dev_groups = vpe_groups,
+};
+
+static struct device vpe_device;
+
+int __init vpe_module_init(void)
+{
+       unsigned int mtflags, vpflags;
+       unsigned long flags, val;
+       struct vpe *v = NULL;
+       struct tc *t;
+       int tc, err;
+
+       if (!cpu_has_mipsmt) {
+               pr_warn("VPE loader: not a MIPS MT capable processor\n");
+               return -ENODEV;
+       }
+
+       if (vpelimit == 0) {
+               pr_warn("No VPEs reserved for AP/SP, not initialize VPE loader\n"
+                       "Pass maxvpes=<n> argument as kernel argument\n");
+
+               return -ENODEV;
+       }
+
+       if (aprp_cpu_index() == 0) {
+               pr_warn("No TCs reserved for AP/SP, not initialize VPE loader\n"
+                       "Pass maxtcs=<n> argument as kernel argument\n");
+
+               return -ENODEV;
+       }
+
+       major = register_chrdev(0, VPE_MODULE_NAME, &vpe_fops);
+       if (major < 0) {
+               pr_warn("VPE loader: unable to register character device\n");
+               return major;
+       }
+
+       err = class_register(&vpe_class);
+       if (err) {
+               pr_err("vpe_class registration failed\n");
+               goto out_chrdev;
+       }
+
+       device_initialize(&vpe_device);
+       vpe_device.class        = &vpe_class,
+       vpe_device.parent       = NULL,
+       dev_set_name(&vpe_device, "vpe1");
+       vpe_device.devt = MKDEV(major, VPE_MODULE_MINOR);
+       err = device_add(&vpe_device);
+       if (err) {
+               pr_err("Adding vpe_device failed\n");
+               goto out_class;
+       }
+
+       local_irq_save(flags);
+       mtflags = dmt();
+       vpflags = dvpe();
+
+       /* Put MVPE's into 'configuration state' */
+       set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+       val = read_c0_mvpconf0();
+       hw_tcs = (val & MVPCONF0_PTC) + 1;
+       hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
+
+       for (tc = aprp_cpu_index(); tc < hw_tcs; tc++) {
+               /*
+                * Must re-enable multithreading temporarily or in case we
+                * reschedule send IPIs or similar we might hang.
+                */
+               clear_c0_mvpcontrol(MVPCONTROL_VPC);
+               evpe(vpflags);
+               emt(mtflags);
+               local_irq_restore(flags);
+               t = alloc_tc(tc);
+               if (!t) {
+                       err = -ENOMEM;
+                       goto out_dev;
+               }
+
+               local_irq_save(flags);
+               mtflags = dmt();
+               vpflags = dvpe();
+               set_c0_mvpcontrol(MVPCONTROL_VPC);
+
+               /* VPE's */
+               if (tc < hw_tcs) {
+                       settc(tc);
+
+                       v = alloc_vpe(tc);
+                       if (v == NULL) {
+                               pr_warn("VPE: unable to allocate VPE\n");
+                               goto out_reenable;
+                       }
+
+                       v->ntcs = hw_tcs - aprp_cpu_index();
+
+                       /* add the tc to the list of this vpe's tc's. */
+                       list_add(&t->tc, &v->tc);
+
+                       /* deactivate all but vpe0 */
+                       if (tc >= aprp_cpu_index()) {
+                               unsigned long tmp = read_vpe_c0_vpeconf0();
+
+                               tmp &= ~VPECONF0_VPA;
+
+                               /* master VPE */
+                               tmp |= VPECONF0_MVP;
+                               write_vpe_c0_vpeconf0(tmp);
+                       }
+
+                       /* disable multi-threading with TC's */
+                       write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() &
+                                               ~VPECONTROL_TE);
+
+                       if (tc >= vpelimit) {
+                               /*
+                                * Set config to be the same as vpe0,
+                                * particularly kseg0 coherency alg
+                                */
+                               write_vpe_c0_config(read_c0_config());
+                       }
+               }
+
+               /* TC's */
+               t->pvpe = v;    /* set the parent vpe */
+
+               if (tc >= aprp_cpu_index()) {
+                       unsigned long tmp;
+
+                       settc(tc);
+
+                       /* Any TC that is bound to VPE0 gets left as is - in
+                        * case we are running SMTC on VPE0. A TC that is bound
+                        * to any other VPE gets bound to VPE0, ideally I'd like
+                        * to make it homeless but it doesn't appear to let me
+                        * bind a TC to a non-existent VPE. Which is perfectly
+                        * reasonable.
+                        *
+                        * The (un)bound state is visible to an EJTAG probe so
+                        * may notify GDB...
+                        */
+                       tmp = read_tc_c0_tcbind();
+                       if (tmp & TCBIND_CURVPE) {
+                               /* tc is bound >vpe0 */
+                               write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
+
+                               t->pvpe = get_vpe(0);   /* set the parent vpe */
+                       }
+
+                       /* halt the TC */
+                       write_tc_c0_tchalt(TCHALT_H);
+                       mips_ihb();
+
+                       tmp = read_tc_c0_tcstatus();
+
+                       /* mark not activated and not dynamically allocatable */
+                       tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
+                       tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
+                       write_tc_c0_tcstatus(tmp);
+               }
+       }
+
+out_reenable:
+       /* release config state */
+       clear_c0_mvpcontrol(MVPCONTROL_VPC);
+
+       evpe(vpflags);
+       emt(mtflags);
+       local_irq_restore(flags);
+
+       return 0;
+
+out_dev:
+       device_del(&vpe_device);
+
+out_class:
+       class_unregister(&vpe_class);
+
+out_chrdev:
+       unregister_chrdev(major, VPE_MODULE_NAME);
+
+       return err;
+}
+
+void __exit vpe_module_exit(void)
+{
+       struct vpe *v, *n;
+
+       device_del(&vpe_device);
+       class_unregister(&vpe_class);
+       unregister_chrdev(major, VPE_MODULE_NAME);
+
+       /* No locking needed here */
+       list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
+               if (v->state != VPE_STATE_UNUSED)
+                       release_vpe(v);
+       }
+}
index 2d5c142bad67b0b10b20cd3a102559b056eb845b..11da314565cc331a03ad2e5b75b834361842d831 100644 (file)
@@ -1,37 +1,22 @@
 /*
- * Copyright (C) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- */
-
-/*
- * VPE support module
+ * 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.
  *
- * Provides support for loading a MIPS SP program on VPE1.
- * The SP environment is rather simple, no tlb's.  It needs to be relocatable
- * (or partially linked). You should initialise your stack in the startup
- * code. This loader looks for the symbol __start and sets up
- * execution to resume from there. The MIPS SDE kit contains suitable examples.
+ * Copyright (C) 2004, 2005 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
  *
- * To load and run, simply cat a SP 'program file' to /dev/vpe1.
- * i.e cat spapp >/dev/vpe1.
+ * VPE spport module for loading a MIPS SP program into VPE1. The SP
+ * environment is rather simple since there are no TLBs. It needs
+ * to be relocatable (or partiall linked). Initialize your stack in
+ * the startup-code. The loader looks for the symbol __start and sets
+ * up the execution to resume from there. To load and run, simply do
+ * a cat SP 'binary' to the /dev/vpe1 device.
  */
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/fs.h>
 #include <linux/init.h>
-#include <asm/uaccess.h>
 #include <linux/slab.h>
 #include <linux/list.h>
 #include <linux/vmalloc.h>
 #include <asm/mipsmtregs.h>
 #include <asm/cacheflush.h>
 #include <linux/atomic.h>
-#include <asm/cpu.h>
 #include <asm/mips_mt.h>
 #include <asm/processor.h>
 #include <asm/vpe.h>
 
-typedef void *vpe_handle;
-
 #ifndef ARCH_SHF_SMALL
 #define ARCH_SHF_SMALL 0
 #endif
@@ -60,95 +42,15 @@ typedef void *vpe_handle;
 /* If this is set, the section belongs in the init part of the module */
 #define INIT_OFFSET_MASK (1UL << (BITS_PER_LONG-1))
 
-/*
- * The number of TCs and VPEs physically available on the core
- */
-static int hw_tcs, hw_vpes;
-static char module_name[] = "vpe";
-static int major;
-static const int minor = 1;    /* fixed for now  */
-
-/* grab the likely amount of memory we will need. */
-#ifdef CONFIG_MIPS_VPE_LOADER_TOM
-#define P_SIZE (2 * 1024 * 1024)
-#else
-/* add an overhead to the max kmalloc size for non-striped symbols/etc */
-#define P_SIZE (256 * 1024)
-#endif
-
-extern unsigned long physical_memsize;
-
-#define MAX_VPES 16
-#define VPE_PATH_MAX 256
-
-enum vpe_state {
-       VPE_STATE_UNUSED = 0,
-       VPE_STATE_INUSE,
-       VPE_STATE_RUNNING
-};
-
-enum tc_state {
-       TC_STATE_UNUSED = 0,
-       TC_STATE_INUSE,
-       TC_STATE_RUNNING,
-       TC_STATE_DYNAMIC
-};
-
-struct vpe {
-       enum vpe_state state;
-
-       /* (device) minor associated with this vpe */
-       int minor;
-
-       /* elfloader stuff */
-       void *load_addr;
-       unsigned long len;
-       char *pbuffer;
-       unsigned long plen;
-       char cwd[VPE_PATH_MAX];
-
-       unsigned long __start;
-
-       /* tc's associated with this vpe */
-       struct list_head tc;
-
-       /* The list of vpe's */
-       struct list_head list;
-
-       /* shared symbol address */
-       void *shared_ptr;
-
-       /* the list of who wants to know when something major happens */
-       struct list_head notify;
-
-       unsigned int ntcs;
-};
-
-struct tc {
-       enum tc_state state;
-       int index;
-
-       struct vpe *pvpe;       /* parent VPE */
-       struct list_head tc;    /* The list of TC's with this VPE */
-       struct list_head list;  /* The global list of tc's */
-};
-
-struct {
-       spinlock_t vpe_list_lock;
-       struct list_head vpe_list;      /* Virtual processing elements */
-       spinlock_t tc_list_lock;
-       struct list_head tc_list;       /* Thread contexts */
-} vpecontrol = {
+struct vpe_control vpecontrol = {
        .vpe_list_lock  = __SPIN_LOCK_UNLOCKED(vpe_list_lock),
        .vpe_list       = LIST_HEAD_INIT(vpecontrol.vpe_list),
        .tc_list_lock   = __SPIN_LOCK_UNLOCKED(tc_list_lock),
        .tc_list        = LIST_HEAD_INIT(vpecontrol.tc_list)
 };
 
-static void release_progmem(void *ptr);
-
 /* get the vpe associated with this minor */
-static struct vpe *get_vpe(int minor)
+struct vpe *get_vpe(int minor)
 {
        struct vpe *res, *v;
 
@@ -158,7 +60,7 @@ static struct vpe *get_vpe(int minor)
        res = NULL;
        spin_lock(&vpecontrol.vpe_list_lock);
        list_for_each_entry(v, &vpecontrol.vpe_list, list) {
-               if (v->minor == minor) {
+               if (v->minor == VPE_MODULE_MINOR) {
                        res = v;
                        break;
                }
@@ -169,7 +71,7 @@ static struct vpe *get_vpe(int minor)
 }
 
 /* get the vpe associated with this minor */
-static struct tc *get_tc(int index)
+struct tc *get_tc(int index)
 {
        struct tc *res, *t;
 
@@ -187,12 +89,13 @@ static struct tc *get_tc(int index)
 }
 
 /* allocate a vpe and associate it with this minor (or index) */
-static struct vpe *alloc_vpe(int minor)
+struct vpe *alloc_vpe(int minor)
 {
        struct vpe *v;
 
-       if ((v = kzalloc(sizeof(struct vpe), GFP_KERNEL)) == NULL)
-               return NULL;
+       v = kzalloc(sizeof(struct vpe), GFP_KERNEL);
+       if (v == NULL)
+               goto out;
 
        INIT_LIST_HEAD(&v->tc);
        spin_lock(&vpecontrol.vpe_list_lock);
@@ -200,17 +103,19 @@ static struct vpe *alloc_vpe(int minor)
        spin_unlock(&vpecontrol.vpe_list_lock);
 
        INIT_LIST_HEAD(&v->notify);
-       v->minor = minor;
+       v->minor = VPE_MODULE_MINOR;
 
+out:
        return v;
 }
 
 /* allocate a tc. At startup only tc0 is running, all other can be halted. */
-static struct tc *alloc_tc(int index)
+struct tc *alloc_tc(int index)
 {
        struct tc *tc;
 
-       if ((tc = kzalloc(sizeof(struct tc), GFP_KERNEL)) == NULL)
+       tc = kzalloc(sizeof(struct tc), GFP_KERNEL);
+       if (tc == NULL)
                goto out;
 
        INIT_LIST_HEAD(&tc->tc);
@@ -225,7 +130,7 @@ out:
 }
 
 /* clean up and free everything */
-static void release_vpe(struct vpe *v)
+void release_vpe(struct vpe *v)
 {
        list_del(&v->list);
        if (v->load_addr)
@@ -233,28 +138,8 @@ static void release_vpe(struct vpe *v)
        kfree(v);
 }
 
-static void __maybe_unused dump_mtregs(void)
-{
-       unsigned long val;
-
-       val = read_c0_config3();
-       printk("config3 0x%lx MT %ld\n", val,
-              (val & CONFIG3_MT) >> CONFIG3_MT_SHIFT);
-
-       val = read_c0_mvpcontrol();
-       printk("MVPControl 0x%lx, STLB %ld VPC %ld EVP %ld\n", val,
-              (val & MVPCONTROL_STLB) >> MVPCONTROL_STLB_SHIFT,
-              (val & MVPCONTROL_VPC) >> MVPCONTROL_VPC_SHIFT,
-              (val & MVPCONTROL_EVP));
-
-       val = read_c0_mvpconf0();
-       printk("mvpconf0 0x%lx, PVPE %ld PTC %ld M %ld\n", val,
-              (val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT,
-              val & MVPCONF0_PTC, (val & MVPCONF0_M) >> MVPCONF0_M_SHIFT);
-}
-
-/* Find some VPE program space */
-static void *alloc_progmem(unsigned long len)
+/* Find some VPE program space */
+void *alloc_progmem(unsigned long len)
 {
        void *addr;
 
@@ -273,7 +158,7 @@ static void *alloc_progmem(unsigned long len)
        return addr;
 }
 
-static void release_progmem(void *ptr)
+void release_progmem(void *ptr)
 {
 #ifndef CONFIG_MIPS_VPE_LOADER_TOM
        kfree(ptr);
@@ -281,7 +166,7 @@ static void release_progmem(void *ptr)
 }
 
 /* Update size with this section: return offset. */
-static long get_offset(unsigned long *size, Elf_Shdr * sechdr)
+static long get_offset(unsigned long *size, Elf_Shdr *sechdr)
 {
        long ret;
 
@@ -294,8 +179,8 @@ static long get_offset(unsigned long *size, Elf_Shdr * sechdr)
    might -- code, read-only data, read-write data, small data. Tally
    sizes, and place the offsets into sh_entsize fields: high bit means it
    belongs in init. */
-static void layout_sections(struct module *mod, const Elf_Ehdr * hdr,
-                           Elf_Shdr * sechdrs, const char *secstrings)
+static void layout_sections(struct module *mod, const Elf_Ehdr *hdr,
+                           Elf_Shdr *sechdrs, const char *secstrings)
 {
        static unsigned long const masks[][2] = {
                /* NOTE: all executable code must be the first section
@@ -315,7 +200,6 @@ static void layout_sections(struct module *mod, const Elf_Ehdr * hdr,
                for (i = 0; i < hdr->e_shnum; ++i) {
                        Elf_Shdr *s = &sechdrs[i];
 
-                       //  || strncmp(secstrings + s->sh_name, ".init", 5) == 0)
                        if ((s->sh_flags & masks[m][0]) != masks[m][0]
                            || (s->sh_flags & masks[m][1])
                            || s->sh_entsize != ~0UL)
@@ -330,7 +214,6 @@ static void layout_sections(struct module *mod, const Elf_Ehdr * hdr,
        }
 }
 
-
 /* from module-elf32.c, but subverted a little */
 
 struct mips_hi16 {
@@ -353,20 +236,18 @@ static int apply_r_mips_gprel16(struct module *me, uint32_t *location,
 {
        int rel;
 
-       if( !(*location & 0xffff) ) {
+       if (!(*location & 0xffff)) {
                rel = (int)v - gp_addr;
-       }
-       else {
+       } else {
                /* .sbss + gp(relative) + offset */
                /* kludge! */
                rel =  (int)(short)((int)v + gp_offs +
                                    (int)(short)(*location & 0xffff) - gp_addr);
        }
 
-       if( (rel > 32768) || (rel < -32768) ) {
-               printk(KERN_DEBUG "VPE loader: apply_r_mips_gprel16: "
-                      "relative address 0x%x out of range of gp register\n",
-                      rel);
+       if ((rel > 32768) || (rel < -32768)) {
+               pr_debug("VPE loader: apply_r_mips_gprel16: relative address 0x%x out of range of gp register\n",
+                        rel);
                return -ENOEXEC;
        }
 
@@ -380,12 +261,12 @@ static int apply_r_mips_pc16(struct module *me, uint32_t *location,
 {
        int rel;
        rel = (((unsigned int)v - (unsigned int)location));
-       rel >>= 2;              // because the offset is in _instructions_ not bytes.
-       rel -= 1;               // and one instruction less due to the branch delay slot.
+       rel >>= 2; /* because the offset is in _instructions_ not bytes. */
+       rel -= 1;  /* and one instruction less due to the branch delay slot. */
 
-       if( (rel > 32768) || (rel < -32768) ) {
-               printk(KERN_DEBUG "VPE loader: "
-                      "apply_r_mips_pc16: relative address out of range 0x%x\n", rel);
+       if ((rel > 32768) || (rel < -32768)) {
+               pr_debug("VPE loader: apply_r_mips_pc16: relative address out of range 0x%x\n",
+                        rel);
                return -ENOEXEC;
        }
 
@@ -406,8 +287,7 @@ static int apply_r_mips_26(struct module *me, uint32_t *location,
                           Elf32_Addr v)
 {
        if (v % 4) {
-               printk(KERN_DEBUG "VPE loader: apply_r_mips_26 "
-                      " unaligned relocation\n");
+               pr_debug("VPE loader: apply_r_mips_26: unaligned relocation\n");
                return -ENOEXEC;
        }
 
@@ -438,7 +318,7 @@ static int apply_r_mips_hi16(struct module *me, uint32_t *location,
         * the carry we need to add.  Save the information, and let LO16 do the
         * actual relocation.
         */
-       n = kmalloc(sizeof *n, GFP_KERNEL);
+       n = kmalloc(sizeof(*n), GFP_KERNEL);
        if (!n)
                return -ENOMEM;
 
@@ -470,9 +350,7 @@ static int apply_r_mips_lo16(struct module *me, uint32_t *location,
                         * The value for the HI16 had best be the same.
                         */
                        if (v != l->value) {
-                               printk(KERN_DEBUG "VPE loader: "
-                                      "apply_r_mips_lo16/hi16: \t"
-                                      "inconsistent value information\n");
+                               pr_debug("VPE loader: apply_r_mips_lo16/hi16: inconsistent value information\n");
                                goto out_free;
                        }
 
@@ -568,20 +446,19 @@ static int apply_relocations(Elf32_Shdr *sechdrs,
                        + ELF32_R_SYM(r_info);
 
                if (!sym->st_value) {
-                       printk(KERN_DEBUG "%s: undefined weak symbol %s\n",
-                              me->name, strtab + sym->st_name);
+                       pr_debug("%s: undefined weak symbol %s\n",
+                                me->name, strtab + sym->st_name);
                        /* just print the warning, dont barf */
                }
 
                v = sym->st_value;
 
                res = reloc_handlers[ELF32_R_TYPE(r_info)](me, location, v);
-               if( res ) {
+               if (res) {
                        char *r = rstrs[ELF32_R_TYPE(r_info)];
-                       printk(KERN_WARNING "VPE loader: .text+0x%x "
-                              "relocation type %s for symbol \"%s\" failed\n",
-                              rel[i].r_offset, r ? r : "UNKNOWN",
-                              strtab + sym->st_name);
+                       pr_warn("VPE loader: .text+0x%x relocation type %s for symbol \"%s\" failed\n",
+                               rel[i].r_offset, r ? r : "UNKNOWN",
+                               strtab + sym->st_name);
                        return res;
                }
        }
@@ -596,10 +473,8 @@ static inline void save_gp_address(unsigned int secbase, unsigned int rel)
 }
 /* end module-elf32.c */
 
-
-
 /* Change all symbols so that sh_value encodes the pointer directly. */
-static void simplify_symbols(Elf_Shdr * sechdrs,
+static void simplify_symbols(Elf_Shdr *sechdrs,
                            unsigned int symindex,
                            const char *strtab,
                            const char *secstrings,
@@ -640,18 +515,16 @@ static void simplify_symbols(Elf_Shdr * sechdrs,
                        break;
 
                case SHN_MIPS_SCOMMON:
-                       printk(KERN_DEBUG "simplify_symbols: ignoring SHN_MIPS_SCOMMON "
-                              "symbol <%s> st_shndx %d\n", strtab + sym[i].st_name,
-                              sym[i].st_shndx);
-                       // .sbss section
+                       pr_debug("simplify_symbols: ignoring SHN_MIPS_SCOMMON symbol <%s> st_shndx %d\n",
+                                strtab + sym[i].st_name, sym[i].st_shndx);
+                       /* .sbss section */
                        break;
 
                default:
                        secbase = sechdrs[sym[i].st_shndx].sh_addr;
 
-                       if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0) {
+                       if (strncmp(strtab + sym[i].st_name, "_gp", 3) == 0)
                                save_gp_address(secbase, sym[i].st_value);
-                       }
 
                        sym[i].st_value += secbase;
                        break;
@@ -660,142 +533,21 @@ static void simplify_symbols(Elf_Shdr * sechdrs,
 }
 
 #ifdef DEBUG_ELFLOADER
-static void dump_elfsymbols(Elf_Shdr * sechdrs, unsigned int symindex,
+static void dump_elfsymbols(Elf_Shdr *sechdrs, unsigned int symindex,
                            const char *strtab, struct module *mod)
 {
        Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr;
        unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
 
-       printk(KERN_DEBUG "dump_elfsymbols: n %d\n", n);
+       pr_debug("dump_elfsymbols: n %d\n", n);
        for (i = 1; i < n; i++) {
-               printk(KERN_DEBUG " i %d name <%s> 0x%x\n", i,
-                      strtab + sym[i].st_name, sym[i].st_value);
+               pr_debug(" i %d name <%s> 0x%x\n", i, strtab + sym[i].st_name,
+                        sym[i].st_value);
        }
 }
 #endif
 
-/* We are prepared so configure and start the VPE... */
-static int vpe_run(struct vpe * v)
-{
-       unsigned long flags, val, dmt_flag;
-       struct vpe_notifications *n;
-       unsigned int vpeflags;
-       struct tc *t;
-
-       /* check we are the Master VPE */
-       local_irq_save(flags);
-       val = read_c0_vpeconf0();
-       if (!(val & VPECONF0_MVP)) {
-               printk(KERN_WARNING
-                      "VPE loader: only Master VPE's are allowed to configure MT\n");
-               local_irq_restore(flags);
-
-               return -1;
-       }
-
-       dmt_flag = dmt();
-       vpeflags = dvpe();
-
-       if (list_empty(&v->tc)) {
-               evpe(vpeflags);
-               emt(dmt_flag);
-               local_irq_restore(flags);
-
-               printk(KERN_WARNING
-                      "VPE loader: No TC's associated with VPE %d\n",
-                      v->minor);
-
-               return -ENOEXEC;
-       }
-
-       t = list_first_entry(&v->tc, struct tc, tc);
-
-       /* Put MVPE's into 'configuration state' */
-       set_c0_mvpcontrol(MVPCONTROL_VPC);
-
-       settc(t->index);
-
-       /* should check it is halted, and not activated */
-       if ((read_tc_c0_tcstatus() & TCSTATUS_A) || !(read_tc_c0_tchalt() & TCHALT_H)) {
-               evpe(vpeflags);
-               emt(dmt_flag);
-               local_irq_restore(flags);
-
-               printk(KERN_WARNING "VPE loader: TC %d is already active!\n",
-                      t->index);
-
-               return -ENOEXEC;
-       }
-
-       /* Write the address we want it to start running from in the TCPC register. */
-       write_tc_c0_tcrestart((unsigned long)v->__start);
-       write_tc_c0_tccontext((unsigned long)0);
-
-       /*
-        * Mark the TC as activated, not interrupt exempt and not dynamically
-        * allocatable
-        */
-       val = read_tc_c0_tcstatus();
-       val = (val & ~(TCSTATUS_DA | TCSTATUS_IXMT)) | TCSTATUS_A;
-       write_tc_c0_tcstatus(val);
-
-       write_tc_c0_tchalt(read_tc_c0_tchalt() & ~TCHALT_H);
-
-       /*
-        * The sde-kit passes 'memsize' to __start in $a3, so set something
-        * here...  Or set $a3 to zero and define DFLT_STACK_SIZE and
-        * DFLT_HEAP_SIZE when you compile your program
-        */
-       mttgpr(6, v->ntcs);
-       mttgpr(7, physical_memsize);
-
-       /* set up VPE1 */
-       /*
-        * bind the TC to VPE 1 as late as possible so we only have the final
-        * VPE registers to set up, and so an EJTAG probe can trigger on it
-        */
-       write_tc_c0_tcbind((read_tc_c0_tcbind() & ~TCBIND_CURVPE) | 1);
-
-       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~(VPECONF0_VPA));
-
-       back_to_back_c0_hazard();
-
-       /* Set up the XTC bit in vpeconf0 to point at our tc */
-       write_vpe_c0_vpeconf0( (read_vpe_c0_vpeconf0() & ~(VPECONF0_XTC))
-                             | (t->index << VPECONF0_XTC_SHIFT));
-
-       back_to_back_c0_hazard();
-
-       /* enable this VPE */
-       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() | VPECONF0_VPA);
-
-       /* clear out any left overs from a previous program */
-       write_vpe_c0_status(0);
-       write_vpe_c0_cause(0);
-
-       /* take system out of configuration state */
-       clear_c0_mvpcontrol(MVPCONTROL_VPC);
-
-       /*
-        * SMTC/SMVP kernels manage VPE enable independently,
-        * but uniprocessor kernels need to turn it on, even
-        * if that wasn't the pre-dvpe() state.
-        */
-#ifdef CONFIG_SMP
-       evpe(vpeflags);
-#else
-       evpe(EVPE_ENABLE);
-#endif
-       emt(dmt_flag);
-       local_irq_restore(flags);
-
-       list_for_each_entry(n, &v->notify, list)
-               n->start(minor);
-
-       return 0;
-}
-
-static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
+static int find_vpe_symbols(struct vpe *v, Elf_Shdr *sechdrs,
                                      unsigned int symindex, const char *strtab,
                                      struct module *mod)
 {
@@ -803,16 +555,14 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
        unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym);
 
        for (i = 1; i < n; i++) {
-               if (strcmp(strtab + sym[i].st_name, "__start") == 0) {
+               if (strcmp(strtab + sym[i].st_name, "__start") == 0)
                        v->__start = sym[i].st_value;
-               }
 
-               if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0) {
+               if (strcmp(strtab + sym[i].st_name, "vpe_shared") == 0)
                        v->shared_ptr = (void *)sym[i].st_value;
-               }
        }
 
-       if ( (v->__start == 0) || (v->shared_ptr == NULL))
+       if ((v->__start == 0) || (v->shared_ptr == NULL))
                return -1;
 
        return 0;
@@ -823,14 +573,14 @@ static int find_vpe_symbols(struct vpe * v, Elf_Shdr * sechdrs,
  * contents of the program (p)buffer performing relocatations/etc, free's it
  * when finished.
  */
-static int vpe_elfload(struct vpe * v)
+static int vpe_elfload(struct vpe *v)
 {
        Elf_Ehdr *hdr;
        Elf_Shdr *sechdrs;
        long err = 0;
        char *secstrings, *strtab = NULL;
        unsigned int len, i, symindex = 0, strindex = 0, relocate = 0;
-       struct module mod;      // so we can re-use the relocations code
+       struct module mod; /* so we can re-use the relocations code */
 
        memset(&mod, 0, sizeof(struct module));
        strcpy(mod.name, "VPE loader");
@@ -844,8 +594,7 @@ static int vpe_elfload(struct vpe * v)
            || (hdr->e_type != ET_REL && hdr->e_type != ET_EXEC)
            || !elf_check_arch(hdr)
            || hdr->e_shentsize != sizeof(*sechdrs)) {
-               printk(KERN_WARNING
-                      "VPE loader: program wrong arch or weird elf version\n");
+               pr_warn("VPE loader: program wrong arch or weird elf version\n");
 
                return -ENOEXEC;
        }
@@ -854,8 +603,7 @@ static int vpe_elfload(struct vpe * v)
                relocate = 1;
 
        if (len < hdr->e_shoff + hdr->e_shnum * sizeof(Elf_Shdr)) {
-               printk(KERN_ERR "VPE loader: program length %u truncated\n",
-                      len);
+               pr_err("VPE loader: program length %u truncated\n", len);
 
                return -ENOEXEC;
        }
@@ -870,22 +618,24 @@ static int vpe_elfload(struct vpe * v)
 
        if (relocate) {
                for (i = 1; i < hdr->e_shnum; i++) {
-                       if (sechdrs[i].sh_type != SHT_NOBITS
-                           && len < sechdrs[i].sh_offset + sechdrs[i].sh_size) {
-                               printk(KERN_ERR "VPE program length %u truncated\n",
+                       if ((sechdrs[i].sh_type != SHT_NOBITS) &&
+                           (len < sechdrs[i].sh_offset + sechdrs[i].sh_size)) {
+                               pr_err("VPE program length %u truncated\n",
                                       len);
                                return -ENOEXEC;
                        }
 
                        /* Mark all sections sh_addr with their address in the
                           temporary image. */
-                       sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
+                       sechdrs[i].sh_addr = (size_t) hdr +
+                               sechdrs[i].sh_offset;
 
                        /* Internal symbols and strings. */
                        if (sechdrs[i].sh_type == SHT_SYMTAB) {
                                symindex = i;
                                strindex = sechdrs[i].sh_link;
-                               strtab = (char *)hdr + sechdrs[strindex].sh_offset;
+                               strtab = (char *)hdr +
+                                       sechdrs[strindex].sh_offset;
                        }
                }
                layout_sections(&mod, hdr, sechdrs, secstrings);
@@ -912,8 +662,9 @@ static int vpe_elfload(struct vpe * v)
                        /* Update sh_addr to point to copy in image. */
                        sechdrs[i].sh_addr = (unsigned long)dest;
 
-                       printk(KERN_DEBUG " section sh_name %s sh_addr 0x%x\n",
-                              secstrings + sechdrs[i].sh_name, sechdrs[i].sh_addr);
+                       pr_debug(" section sh_name %s sh_addr 0x%x\n",
+                                secstrings + sechdrs[i].sh_name,
+                                sechdrs[i].sh_addr);
                }
 
                /* Fix up syms, so that st_value is a pointer to location. */
@@ -934,17 +685,18 @@ static int vpe_elfload(struct vpe * v)
                                continue;
 
                        if (sechdrs[i].sh_type == SHT_REL)
-                               err = apply_relocations(sechdrs, strtab, symindex, i,
-                                                       &mod);
+                               err = apply_relocations(sechdrs, strtab,
+                                                       symindex, i, &mod);
                        else if (sechdrs[i].sh_type == SHT_RELA)
-                               err = apply_relocate_add(sechdrs, strtab, symindex, i,
-                                                        &mod);
+                               err = apply_relocate_add(sechdrs, strtab,
+                                                        symindex, i, &mod);
                        if (err < 0)
                                return err;
 
                }
        } else {
-               struct elf_phdr *phdr = (struct elf_phdr *) ((char *)hdr + hdr->e_phoff);
+               struct elf_phdr *phdr = (struct elf_phdr *)
+                                               ((char *)hdr + hdr->e_phoff);
 
                for (i = 0; i < hdr->e_phnum; i++) {
                        if (phdr->p_type == PT_LOAD) {
@@ -962,11 +714,15 @@ static int vpe_elfload(struct vpe * v)
                        if (sechdrs[i].sh_type == SHT_SYMTAB) {
                                symindex = i;
                                strindex = sechdrs[i].sh_link;
-                               strtab = (char *)hdr + sechdrs[strindex].sh_offset;
+                               strtab = (char *)hdr +
+                                       sechdrs[strindex].sh_offset;
 
-                               /* mark the symtab's address for when we try to find the
-                                  magic symbols */
-                               sechdrs[i].sh_addr = (size_t) hdr + sechdrs[i].sh_offset;
+                               /*
+                                * mark symtab's address for when we try
+                                * to find the magic symbols
+                                */
+                               sechdrs[i].sh_addr = (size_t) hdr +
+                                       sechdrs[i].sh_offset;
                        }
                }
        }
@@ -977,53 +733,19 @@ static int vpe_elfload(struct vpe * v)
 
        if ((find_vpe_symbols(v, sechdrs, symindex, strtab, &mod)) < 0) {
                if (v->__start == 0) {
-                       printk(KERN_WARNING "VPE loader: program does not contain "
-                              "a __start symbol\n");
+                       pr_warn("VPE loader: program does not contain a __start symbol\n");
                        return -ENOEXEC;
                }
 
                if (v->shared_ptr == NULL)
-                       printk(KERN_WARNING "VPE loader: "
-                              "program does not contain vpe_shared symbol.\n"
-                              " Unable to use AMVP (AP/SP) facilities.\n");
+                       pr_warn("VPE loader: program does not contain vpe_shared symbol.\n"
+                               " Unable to use AMVP (AP/SP) facilities.\n");
        }
 
-       printk(" elf loaded\n");
+       pr_info(" elf loaded\n");
        return 0;
 }
 
-static void cleanup_tc(struct tc *tc)
-{
-       unsigned long flags;
-       unsigned int mtflags, vpflags;
-       int tmp;
-
-       local_irq_save(flags);
-       mtflags = dmt();
-       vpflags = dvpe();
-       /* Put MVPE's into 'configuration state' */
-       set_c0_mvpcontrol(MVPCONTROL_VPC);
-
-       settc(tc->index);
-       tmp = read_tc_c0_tcstatus();
-
-       /* mark not allocated and not dynamically allocatable */
-       tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
-       tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
-       write_tc_c0_tcstatus(tmp);
-
-       write_tc_c0_tchalt(TCHALT_H);
-       mips_ihb();
-
-       /* bind it to anything other than VPE1 */
-//     write_tc_c0_tcbind(read_tc_c0_tcbind() & ~TCBIND_CURVPE); // | TCBIND_CURVPE
-
-       clear_c0_mvpcontrol(MVPCONTROL_VPC);
-       evpe(vpflags);
-       emt(mtflags);
-       local_irq_restore(flags);
-}
-
 static int getcwd(char *buff, int size)
 {
        mm_segment_t old_fs;
@@ -1043,39 +765,39 @@ static int getcwd(char *buff, int size)
 static int vpe_open(struct inode *inode, struct file *filp)
 {
        enum vpe_state state;
-       struct vpe_notifications *not;
+       struct vpe_notifications *notifier;
        struct vpe *v;
        int ret;
 
-       if (minor != iminor(inode)) {
+       if (VPE_MODULE_MINOR != iminor(inode)) {
                /* assume only 1 device at the moment. */
-               pr_warning("VPE loader: only vpe1 is supported\n");
+               pr_warn("VPE loader: only vpe1 is supported\n");
 
                return -ENODEV;
        }
 
-       if ((v = get_vpe(tclimit)) == NULL) {
-               pr_warning("VPE loader: unable to get vpe\n");
+       v = get_vpe(aprp_cpu_index());
+       if (v == NULL) {
+               pr_warn("VPE loader: unable to get vpe\n");
 
                return -ENODEV;
        }
 
        state = xchg(&v->state, VPE_STATE_INUSE);
        if (state != VPE_STATE_UNUSED) {
-               printk(KERN_DEBUG "VPE loader: tc in use dumping regs\n");
+               pr_debug("VPE loader: tc in use dumping regs\n");
 
-               list_for_each_entry(not, &v->notify, list) {
-                       not->stop(tclimit);
-               }
+               list_for_each_entry(notifier, &v->notify, list)
+                       notifier->stop(aprp_cpu_index());
 
                release_progmem(v->load_addr);
-               cleanup_tc(get_tc(tclimit));
+               cleanup_tc(get_tc(aprp_cpu_index()));
        }
 
        /* this of-course trashes what was there before... */
        v->pbuffer = vmalloc(P_SIZE);
        if (!v->pbuffer) {
-               pr_warning("VPE loader: unable to allocate memory\n");
+               pr_warn("VPE loader: unable to allocate memory\n");
                return -ENOMEM;
        }
        v->plen = P_SIZE;
@@ -1085,7 +807,7 @@ static int vpe_open(struct inode *inode, struct file *filp)
        v->cwd[0] = 0;
        ret = getcwd(v->cwd, VPE_PATH_MAX);
        if (ret < 0)
-               printk(KERN_WARNING "VPE loader: open, getcwd returned %d\n", ret);
+               pr_warn("VPE loader: open, getcwd returned %d\n", ret);
 
        v->shared_ptr = NULL;
        v->__start = 0;
@@ -1099,20 +821,20 @@ static int vpe_release(struct inode *inode, struct file *filp)
        Elf_Ehdr *hdr;
        int ret = 0;
 
-       v = get_vpe(tclimit);
+       v = get_vpe(aprp_cpu_index());
        if (v == NULL)
                return -ENODEV;
 
        hdr = (Elf_Ehdr *) v->pbuffer;
        if (memcmp(hdr->e_ident, ELFMAG, SELFMAG) == 0) {
-               if (vpe_elfload(v) >= 0) {
+               if ((vpe_elfload(v) >= 0) && vpe_run) {
                        vpe_run(v);
                } else {
-                       printk(KERN_WARNING "VPE loader: ELF load failed.\n");
+                       pr_warn("VPE loader: ELF load failed.\n");
                        ret = -ENOEXEC;
                }
        } else {
-               printk(KERN_WARNING "VPE loader: only elf files are supported\n");
+               pr_warn("VPE loader: only elf files are supported\n");
                ret = -ENOEXEC;
        }
 
@@ -1130,22 +852,22 @@ static int vpe_release(struct inode *inode, struct file *filp)
        return ret;
 }
 
-static ssize_t vpe_write(struct file *file, const char __user * buffer,
-                        size_t count, loff_t * ppos)
+static ssize_t vpe_write(struct file *file, const char __user *buffer,
+                        size_t count, loff_t *ppos)
 {
        size_t ret = count;
        struct vpe *v;
 
-       if (iminor(file_inode(file)) != minor)
+       if (iminor(file_inode(file)) != VPE_MODULE_MINOR)
                return -ENODEV;
 
-       v = get_vpe(tclimit);
+       v = get_vpe(aprp_cpu_index());
+
        if (v == NULL)
                return -ENODEV;
 
        if ((count + v->len) > v->plen) {
-               printk(KERN_WARNING
-                      "VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
+               pr_warn("VPE loader: elf size too big. Perhaps strip uneeded symbols\n");
                return -ENOMEM;
        }
 
@@ -1157,7 +879,7 @@ static ssize_t vpe_write(struct file *file, const char __user * buffer,
        return ret;
 }
 
-static const struct file_operations vpe_fops = {
+const struct file_operations vpe_fops = {
        .owner = THIS_MODULE,
        .open = vpe_open,
        .release = vpe_release,
@@ -1165,396 +887,40 @@ static const struct file_operations vpe_fops = {
        .llseek = noop_llseek,
 };
 
-/* module wrapper entry points */
-/* give me a vpe */
-vpe_handle vpe_alloc(void)
-{
-       int i;
-       struct vpe *v;
-
-       /* find a vpe */
-       for (i = 1; i < MAX_VPES; i++) {
-               if ((v = get_vpe(i)) != NULL) {
-                       v->state = VPE_STATE_INUSE;
-                       return v;
-               }
-       }
-       return NULL;
-}
-
-EXPORT_SYMBOL(vpe_alloc);
-
-/* start running from here */
-int vpe_start(vpe_handle vpe, unsigned long start)
-{
-       struct vpe *v = vpe;
-
-       v->__start = start;
-       return vpe_run(v);
-}
-
-EXPORT_SYMBOL(vpe_start);
-
-/* halt it for now */
-int vpe_stop(vpe_handle vpe)
-{
-       struct vpe *v = vpe;
-       struct tc *t;
-       unsigned int evpe_flags;
-
-       evpe_flags = dvpe();
-
-       if ((t = list_entry(v->tc.next, struct tc, tc)) != NULL) {
-
-               settc(t->index);
-               write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
-       }
-
-       evpe(evpe_flags);
-
-       return 0;
-}
-
-EXPORT_SYMBOL(vpe_stop);
-
-/* I've done with it thank you */
-int vpe_free(vpe_handle vpe)
-{
-       struct vpe *v = vpe;
-       struct tc *t;
-       unsigned int evpe_flags;
-
-       if ((t = list_entry(v->tc.next, struct tc, tc)) == NULL) {
-               return -ENOEXEC;
-       }
-
-       evpe_flags = dvpe();
-
-       /* Put MVPE's into 'configuration state' */
-       set_c0_mvpcontrol(MVPCONTROL_VPC);
-
-       settc(t->index);
-       write_vpe_c0_vpeconf0(read_vpe_c0_vpeconf0() & ~VPECONF0_VPA);
-
-       /* halt the TC */
-       write_tc_c0_tchalt(TCHALT_H);
-       mips_ihb();
-
-       /* mark the TC unallocated */
-       write_tc_c0_tcstatus(read_tc_c0_tcstatus() & ~TCSTATUS_A);
-
-       v->state = VPE_STATE_UNUSED;
-
-       clear_c0_mvpcontrol(MVPCONTROL_VPC);
-       evpe(evpe_flags);
-
-       return 0;
-}
-
-EXPORT_SYMBOL(vpe_free);
-
 void *vpe_get_shared(int index)
 {
-       struct vpe *v;
+       struct vpe *v = get_vpe(index);
 
-       if ((v = get_vpe(index)) == NULL)
+       if (v == NULL)
                return NULL;
 
        return v->shared_ptr;
 }
-
 EXPORT_SYMBOL(vpe_get_shared);
 
 int vpe_notify(int index, struct vpe_notifications *notify)
 {
-       struct vpe *v;
+       struct vpe *v = get_vpe(index);
 
-       if ((v = get_vpe(index)) == NULL)
+       if (v == NULL)
                return -1;
 
        list_add(&notify->list, &v->notify);
        return 0;
 }
-
 EXPORT_SYMBOL(vpe_notify);
 
 char *vpe_getcwd(int index)
 {
-       struct vpe *v;
+       struct vpe *v = get_vpe(index);
 
-       if ((v = get_vpe(index)) == NULL)
+       if (v == NULL)
                return NULL;
 
        return v->cwd;
 }
-
 EXPORT_SYMBOL(vpe_getcwd);
 
-static ssize_t store_kill(struct device *dev, struct device_attribute *attr,
-                         const char *buf, size_t len)
-{
-       struct vpe *vpe = get_vpe(tclimit);
-       struct vpe_notifications *not;
-
-       list_for_each_entry(not, &vpe->notify, list) {
-               not->stop(tclimit);
-       }
-
-       release_progmem(vpe->load_addr);
-       cleanup_tc(get_tc(tclimit));
-       vpe_stop(vpe);
-       vpe_free(vpe);
-
-       return len;
-}
-static DEVICE_ATTR(kill, S_IWUSR, NULL, store_kill);
-
-static ssize_t ntcs_show(struct device *cd, struct device_attribute *attr,
-                        char *buf)
-{
-       struct vpe *vpe = get_vpe(tclimit);
-
-       return sprintf(buf, "%d\n", vpe->ntcs);
-}
-
-static ssize_t ntcs_store(struct device *dev, struct device_attribute *attr,
-                         const char *buf, size_t len)
-{
-       struct vpe *vpe = get_vpe(tclimit);
-       unsigned long new;
-       char *endp;
-
-       new = simple_strtoul(buf, &endp, 0);
-       if (endp == buf)
-               goto out_einval;
-
-       if (new == 0 || new > (hw_tcs - tclimit))
-               goto out_einval;
-
-       vpe->ntcs = new;
-
-       return len;
-
-out_einval:
-       return -EINVAL;
-}
-static DEVICE_ATTR_RW(ntcs);
-
-static struct attribute *vpe_attrs[] = {
-       &dev_attr_kill.attr,
-       &dev_attr_ntcs.attr,
-       NULL,
-};
-ATTRIBUTE_GROUPS(vpe);
-
-static void vpe_device_release(struct device *cd)
-{
-       kfree(cd);
-}
-
-struct class vpe_class = {
-       .name = "vpe",
-       .owner = THIS_MODULE,
-       .dev_release = vpe_device_release,
-       .dev_groups = vpe_groups,
-};
-
-struct device vpe_device;
-
-static int __init vpe_module_init(void)
-{
-       unsigned int mtflags, vpflags;
-       unsigned long flags, val;
-       struct vpe *v = NULL;
-       struct tc *t;
-       int tc, err;
-
-       if (!cpu_has_mipsmt) {
-               printk("VPE loader: not a MIPS MT capable processor\n");
-               return -ENODEV;
-       }
-
-       if (vpelimit == 0) {
-               printk(KERN_WARNING "No VPEs reserved for AP/SP, not "
-                      "initializing VPE loader.\nPass maxvpes=<n> argument as "
-                      "kernel argument\n");
-
-               return -ENODEV;
-       }
-
-       if (tclimit == 0) {
-               printk(KERN_WARNING "No TCs reserved for AP/SP, not "
-                      "initializing VPE loader.\nPass maxtcs=<n> argument as "
-                      "kernel argument\n");
-
-               return -ENODEV;
-       }
-
-       major = register_chrdev(0, module_name, &vpe_fops);
-       if (major < 0) {
-               printk("VPE loader: unable to register character device\n");
-               return major;
-       }
-
-       err = class_register(&vpe_class);
-       if (err) {
-               printk(KERN_ERR "vpe_class registration failed\n");
-               goto out_chrdev;
-       }
-
-       device_initialize(&vpe_device);
-       vpe_device.class        = &vpe_class,
-       vpe_device.parent       = NULL,
-       dev_set_name(&vpe_device, "vpe1");
-       vpe_device.devt = MKDEV(major, minor);
-       err = device_add(&vpe_device);
-       if (err) {
-               printk(KERN_ERR "Adding vpe_device failed\n");
-               goto out_class;
-       }
-
-       local_irq_save(flags);
-       mtflags = dmt();
-       vpflags = dvpe();
-
-       /* Put MVPE's into 'configuration state' */
-       set_c0_mvpcontrol(MVPCONTROL_VPC);
-
-       /* dump_mtregs(); */
-
-       val = read_c0_mvpconf0();
-       hw_tcs = (val & MVPCONF0_PTC) + 1;
-       hw_vpes = ((val & MVPCONF0_PVPE) >> MVPCONF0_PVPE_SHIFT) + 1;
-
-       for (tc = tclimit; tc < hw_tcs; tc++) {
-               /*
-                * Must re-enable multithreading temporarily or in case we
-                * reschedule send IPIs or similar we might hang.
-                */
-               clear_c0_mvpcontrol(MVPCONTROL_VPC);
-               evpe(vpflags);
-               emt(mtflags);
-               local_irq_restore(flags);
-               t = alloc_tc(tc);
-               if (!t) {
-                       err = -ENOMEM;
-                       goto out;
-               }
-
-               local_irq_save(flags);
-               mtflags = dmt();
-               vpflags = dvpe();
-               set_c0_mvpcontrol(MVPCONTROL_VPC);
-
-               /* VPE's */
-               if (tc < hw_tcs) {
-                       settc(tc);
-
-                       if ((v = alloc_vpe(tc)) == NULL) {
-                               printk(KERN_WARNING "VPE: unable to allocate VPE\n");
-
-                               goto out_reenable;
-                       }
-
-                       v->ntcs = hw_tcs - tclimit;
-
-                       /* add the tc to the list of this vpe's tc's. */
-                       list_add(&t->tc, &v->tc);
-
-                       /* deactivate all but vpe0 */
-                       if (tc >= tclimit) {
-                               unsigned long tmp = read_vpe_c0_vpeconf0();
-
-                               tmp &= ~VPECONF0_VPA;
-
-                               /* master VPE */
-                               tmp |= VPECONF0_MVP;
-                               write_vpe_c0_vpeconf0(tmp);
-                       }
-
-                       /* disable multi-threading with TC's */
-                       write_vpe_c0_vpecontrol(read_vpe_c0_vpecontrol() & ~VPECONTROL_TE);
-
-                       if (tc >= vpelimit) {
-                               /*
-                                * Set config to be the same as vpe0,
-                                * particularly kseg0 coherency alg
-                                */
-                               write_vpe_c0_config(read_c0_config());
-                       }
-               }
-
-               /* TC's */
-               t->pvpe = v;    /* set the parent vpe */
-
-               if (tc >= tclimit) {
-                       unsigned long tmp;
-
-                       settc(tc);
-
-                       /* Any TC that is bound to VPE0 gets left as is - in case
-                          we are running SMTC on VPE0. A TC that is bound to any
-                          other VPE gets bound to VPE0, ideally I'd like to make
-                          it homeless but it doesn't appear to let me bind a TC
-                          to a non-existent VPE. Which is perfectly reasonable.
-
-                          The (un)bound state is visible to an EJTAG probe so may
-                          notify GDB...
-                       */
-
-                       if (((tmp = read_tc_c0_tcbind()) & TCBIND_CURVPE)) {
-                               /* tc is bound >vpe0 */
-                               write_tc_c0_tcbind(tmp & ~TCBIND_CURVPE);
-
-                               t->pvpe = get_vpe(0);   /* set the parent vpe */
-                       }
-
-                       /* halt the TC */
-                       write_tc_c0_tchalt(TCHALT_H);
-                       mips_ihb();
-
-                       tmp = read_tc_c0_tcstatus();
-
-                       /* mark not activated and not dynamically allocatable */
-                       tmp &= ~(TCSTATUS_A | TCSTATUS_DA);
-                       tmp |= TCSTATUS_IXMT;   /* interrupt exempt */
-                       write_tc_c0_tcstatus(tmp);
-               }
-       }
-
-out_reenable:
-       /* release config state */
-       clear_c0_mvpcontrol(MVPCONTROL_VPC);
-
-       evpe(vpflags);
-       emt(mtflags);
-       local_irq_restore(flags);
-
-       return 0;
-
-out_class:
-       class_unregister(&vpe_class);
-out_chrdev:
-       unregister_chrdev(major, module_name);
-
-out:
-       return err;
-}
-
-static void __exit vpe_module_exit(void)
-{
-       struct vpe *v, *n;
-
-       device_del(&vpe_device);
-       unregister_chrdev(major, module_name);
-
-       /* No locking needed here */
-       list_for_each_entry_safe(v, n, &vpecontrol.vpe_list, list) {
-               if (v->state != VPE_STATE_UNUSED)
-                       release_vpe(v);
-       }
-}
-
 module_init(vpe_module_init);
 module_exit(vpe_module_exit);
 MODULE_DESCRIPTION("MIPS VPE Loader");
index 73b34827826c206a0e98c43be862a272395818b7..da5186fbd77a3a6946d7ffd125805f92d407fa65 100644 (file)
@@ -1001,7 +1001,6 @@ int kvm_arch_vcpu_init(struct kvm_vcpu *vcpu)
        hrtimer_init(&vcpu->arch.comparecount_timer, CLOCK_MONOTONIC,
                     HRTIMER_MODE_REL);
        vcpu->arch.comparecount_timer.function = kvm_mips_comparecount_wakeup;
-       kvm_mips_init_shadow_tlb(vcpu);
        return 0;
 }
 
index c777dd36d4a8bf88be1000dc993bc2d8774b6a33..50ab9c4d4a5dc6d2cf1d98270314b8aeb102623b 100644 (file)
@@ -10,7 +10,6 @@
 * Authors: Sanjay Lal <sanjayl@kymasys.com>
 */
 
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
@@ -25,6 +24,7 @@
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
 #include <asm/cacheflush.h>
+#include <asm/tlb.h>
 
 #undef CONFIG_MIPS_MT
 #include <asm/r4kcache.h>
@@ -35,9 +35,6 @@
 
 #define PRIx64 "llx"
 
-/* Use VZ EntryHi.EHINV to invalidate TLB entries */
-#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
-
 atomic_t kvm_mips_instance;
 EXPORT_SYMBOL(kvm_mips_instance);
 
@@ -147,30 +144,6 @@ void kvm_mips_dump_guest_tlbs(struct kvm_vcpu *vcpu)
        }
 }
 
-void kvm_mips_dump_shadow_tlbs(struct kvm_vcpu *vcpu)
-{
-       int i;
-       volatile struct kvm_mips_tlb tlb;
-
-       printk("Shadow TLBs:\n");
-       for (i = 0; i < KVM_MIPS_GUEST_TLB_SIZE; i++) {
-               tlb = vcpu->arch.shadow_tlb[smp_processor_id()][i];
-               printk("TLB%c%3d Hi 0x%08lx ",
-                      (tlb.tlb_lo0 | tlb.tlb_lo1) & MIPS3_PG_V ? ' ' : '*',
-                      i, tlb.tlb_hi);
-               printk("Lo0=0x%09" PRIx64 " %c%c attr %lx ",
-                      (uint64_t) mips3_tlbpfn_to_paddr(tlb.tlb_lo0),
-                      (tlb.tlb_lo0 & MIPS3_PG_D) ? 'D' : ' ',
-                      (tlb.tlb_lo0 & MIPS3_PG_G) ? 'G' : ' ',
-                      (tlb.tlb_lo0 >> 3) & 7);
-               printk("Lo1=0x%09" PRIx64 " %c%c attr %lx sz=%lx\n",
-                      (uint64_t) mips3_tlbpfn_to_paddr(tlb.tlb_lo1),
-                      (tlb.tlb_lo1 & MIPS3_PG_D) ? 'D' : ' ',
-                      (tlb.tlb_lo1 & MIPS3_PG_G) ? 'G' : ' ',
-                      (tlb.tlb_lo1 >> 3) & 7, tlb.tlb_mask);
-       }
-}
-
 static int kvm_mips_map_page(struct kvm *kvm, gfn_t gfn)
 {
        int srcu_idx, err = 0;
@@ -657,70 +630,6 @@ kvm_get_new_mmu_context(struct mm_struct *mm, unsigned long cpu,
        cpu_context(cpu, mm) = asid_cache(cpu) = asid;
 }
 
-void kvm_shadow_tlb_put(struct kvm_vcpu *vcpu)
-{
-       unsigned long flags;
-       unsigned long old_entryhi;
-       unsigned long old_pagemask;
-       int entry = 0;
-       int cpu = smp_processor_id();
-
-       local_irq_save(flags);
-
-       old_entryhi = read_c0_entryhi();
-       old_pagemask = read_c0_pagemask();
-
-       for (entry = 0; entry < current_cpu_data.tlbsize; entry++) {
-               write_c0_index(entry);
-               mtc0_tlbw_hazard();
-               tlb_read();
-               tlbw_use_hazard();
-
-               vcpu->arch.shadow_tlb[cpu][entry].tlb_hi = read_c0_entryhi();
-               vcpu->arch.shadow_tlb[cpu][entry].tlb_lo0 = read_c0_entrylo0();
-               vcpu->arch.shadow_tlb[cpu][entry].tlb_lo1 = read_c0_entrylo1();
-               vcpu->arch.shadow_tlb[cpu][entry].tlb_mask = read_c0_pagemask();
-       }
-
-       write_c0_entryhi(old_entryhi);
-       write_c0_pagemask(old_pagemask);
-       mtc0_tlbw_hazard();
-
-       local_irq_restore(flags);
-
-}
-
-void kvm_shadow_tlb_load(struct kvm_vcpu *vcpu)
-{
-       unsigned long flags;
-       unsigned long old_ctx;
-       int entry;
-       int cpu = smp_processor_id();
-
-       local_irq_save(flags);
-
-       old_ctx = read_c0_entryhi();
-
-       for (entry = 0; entry < current_cpu_data.tlbsize; entry++) {
-               write_c0_entryhi(vcpu->arch.shadow_tlb[cpu][entry].tlb_hi);
-               mtc0_tlbw_hazard();
-               write_c0_entrylo0(vcpu->arch.shadow_tlb[cpu][entry].tlb_lo0);
-               write_c0_entrylo1(vcpu->arch.shadow_tlb[cpu][entry].tlb_lo1);
-
-               write_c0_index(entry);
-               mtc0_tlbw_hazard();
-
-               tlb_write_indexed();
-               tlbw_use_hazard();
-       }
-
-       tlbw_use_hazard();
-       write_c0_entryhi(old_ctx);
-       mtc0_tlbw_hazard();
-       local_irq_restore(flags);
-}
-
-
 void kvm_local_flush_tlb_all(void)
 {
        unsigned long flags;
@@ -749,30 +658,6 @@ void kvm_local_flush_tlb_all(void)
        local_irq_restore(flags);
 }
 
-void kvm_mips_init_shadow_tlb(struct kvm_vcpu *vcpu)
-{
-       int cpu, entry;
-
-       for_each_possible_cpu(cpu) {
-               for (entry = 0; entry < current_cpu_data.tlbsize; entry++) {
-                       vcpu->arch.shadow_tlb[cpu][entry].tlb_hi =
-                           UNIQUE_ENTRYHI(entry);
-                       vcpu->arch.shadow_tlb[cpu][entry].tlb_lo0 = 0x0;
-                       vcpu->arch.shadow_tlb[cpu][entry].tlb_lo1 = 0x0;
-                       vcpu->arch.shadow_tlb[cpu][entry].tlb_mask =
-                           read_c0_pagemask();
-#ifdef DEBUG
-                       kvm_debug
-                           ("shadow_tlb[%d][%d]: tlb_hi: %#lx, lo0: %#lx, lo1: %#lx\n",
-                            cpu, entry,
-                            vcpu->arch.shadow_tlb[cpu][entry].tlb_hi,
-                            vcpu->arch.shadow_tlb[cpu][entry].tlb_lo0,
-                            vcpu->arch.shadow_tlb[cpu][entry].tlb_lo1);
-#endif
-               }
-       }
-}
-
 /* Restore ASID once we are scheduled back after preemption */
 void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
 {
@@ -810,14 +695,6 @@ void kvm_arch_vcpu_load(struct kvm_vcpu *vcpu, int cpu)
                         vcpu->arch.last_sched_cpu, cpu, vcpu->vcpu_id);
        }
 
-       /* Only reload shadow host TLB if new ASIDs haven't been allocated */
-#if 0
-       if ((atomic_read(&kvm_mips_instance) > 1) && !newasid) {
-               kvm_mips_flush_host_tlb(0);
-               kvm_shadow_tlb_load(vcpu);
-       }
-#endif
-
        if (!newasid) {
                /* If we preempted while the guest was executing, then reload the pre-empted ASID */
                if (current->flags & PF_VCPU) {
@@ -863,12 +740,6 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu)
        vcpu->arch.preempt_entryhi = read_c0_entryhi();
        vcpu->arch.last_sched_cpu = cpu;
 
-#if 0
-       if ((atomic_read(&kvm_mips_instance) > 1)) {
-               kvm_shadow_tlb_put(vcpu);
-       }
-#endif
-
        if (((cpu_context(cpu, current->mm) ^ asid_cache(cpu)) &
             ASID_VERSION_MASK)) {
                kvm_debug("%s: Dropping MMU Context:  %#lx\n", __func__,
@@ -930,10 +801,8 @@ uint32_t kvm_get_inst(uint32_t *opc, struct kvm_vcpu *vcpu)
 }
 
 EXPORT_SYMBOL(kvm_local_flush_tlb_all);
-EXPORT_SYMBOL(kvm_shadow_tlb_put);
 EXPORT_SYMBOL(kvm_mips_handle_mapped_seg_tlb_fault);
 EXPORT_SYMBOL(kvm_mips_handle_commpage_tlb_fault);
-EXPORT_SYMBOL(kvm_mips_init_shadow_tlb);
 EXPORT_SYMBOL(kvm_mips_dump_host_tlbs);
 EXPORT_SYMBOL(kvm_mips_handle_kseg0_tlb_fault);
 EXPORT_SYMBOL(kvm_mips_host_tlb_lookup);
@@ -941,8 +810,6 @@ EXPORT_SYMBOL(kvm_mips_flush_host_tlb);
 EXPORT_SYMBOL(kvm_mips_guest_tlb_lookup);
 EXPORT_SYMBOL(kvm_mips_host_tlb_inv);
 EXPORT_SYMBOL(kvm_mips_translate_guest_kseg0_to_hpa);
-EXPORT_SYMBOL(kvm_shadow_tlb_load);
-EXPORT_SYMBOL(kvm_mips_dump_shadow_tlbs);
 EXPORT_SYMBOL(kvm_mips_dump_guest_tlbs);
 EXPORT_SYMBOL(kvm_get_inst);
 EXPORT_SYMBOL(kvm_arch_vcpu_load);
index 1ab576dc9bd1ad75c250e0722fe0a7a1e44305c4..8750dc0a1bf678c5bd8500260816d6070b949aca 100644 (file)
@@ -8,7 +8,6 @@
 
 #include <linux/io.h>
 #include <linux/export.h>
-#include <linux/init.h>
 #include <linux/clk.h>
 
 #include <asm/time.h>
index 08f7ebd9c7746c5643c9335a4e25d3a19603146f..78a91fa41944d3e7daaa67014a307a382bf9ee0c 100644 (file)
@@ -220,10 +220,6 @@ ltq_dma_init(struct platform_device *pdev)
        int i;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               panic("Failed to get dma resource");
-
-       /* remap dma register range */
        ltq_dma_membase = devm_ioremap_resource(&pdev->dev, res);
        if (IS_ERR(ltq_dma_membase))
                panic("Failed to remap dma resource");
index 793e234719a66c1539861e36483a380bbd08310f..942f32b91d12da6a803e4c9da3edea54a29f3f23 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/delay.h>
 #include <asm/lasat/lasat.h>
 #include <linux/module.h>
-#include <linux/init.h>
 
 #include "at93c.h"
 
index 7eb334892693db3fd5d5951f67fd23bd5552ed03..d613b97cd513bedebbb9f09262be7a0e8735a5ec 100644 (file)
@@ -9,7 +9,6 @@
 #include <asm/bootinfo.h>
 #include <asm/lasat/lasat.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 
index d8522f8e842a29d2615af700e449a3dd77ef0da8..09d5deea747f2fc37921c1cdb7d692010e165e4e 100644 (file)
@@ -8,7 +8,6 @@
  *     Author: Maciej W. Rozycki <macro@mips.com>
  */
 
-#include <linux/init.h>
 
 #include <asm/addrspace.h>
 #include <asm/bug.h>
index 4dc2f5fa3f6737f940103216558b2310867f4e7e..aed32b88576cbe1fbd11f4256a5f8b875bf3f809 100644 (file)
@@ -10,7 +10,6 @@
 #include <linux/cpufreq.h>
 #include <linux/errno.h>
 #include <linux/export.h>
-#include <linux/init.h>
 #include <linux/list.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
index efe008846ed056759dd2e66c83a54cfe2d4d789c..506925b2c3f366a12aecfb8ecc3cf6d69274654d 100644 (file)
@@ -417,14 +417,20 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr)
                        case mm_mtc1_op:
                        case mm_cfc1_op:
                        case mm_ctc1_op:
+                       case mm_mfhc1_op:
+                       case mm_mthc1_op:
                                if (insn.mm_fp1_format.op == mm_mfc1_op)
                                        op = mfc_op;
                                else if (insn.mm_fp1_format.op == mm_mtc1_op)
                                        op = mtc_op;
                                else if (insn.mm_fp1_format.op == mm_cfc1_op)
                                        op = cfc_op;
-                               else
+                               else if (insn.mm_fp1_format.op == mm_ctc1_op)
                                        op = ctc_op;
+                               else if (insn.mm_fp1_format.op == mm_mfhc1_op)
+                                       op = mfhc_op;
+                               else
+                                       op = mthc_op;
                                mips32_insn.fp1_format.opcode = cop1_op;
                                mips32_insn.fp1_format.op = op;
                                mips32_insn.fp1_format.rt =
@@ -853,20 +859,20 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn,
  * In the Linux kernel, we support selection of FPR format on the
  * basis of the Status.FR bit. If an FPU is not present, the FR bit
  * is hardwired to zero, which would imply a 32-bit FPU even for
- * 64-bit CPUs so we rather look at TIF_32BIT_REGS.
+ * 64-bit CPUs so we rather look at TIF_32BIT_FPREGS.
  * FPU emu is slow and bulky and optimizing this function offers fairly
  * sizeable benefits so we try to be clever and make this function return
  * a constant whenever possible, that is on 64-bit kernels without O32
- * compatibility enabled and on 32-bit kernels.
+ * compatibility enabled and on 32-bit without 64-bit FPU support.
  */
 static inline int cop1_64bit(struct pt_regs *xcp)
 {
 #if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32)
        return 1;
-#elif defined(CONFIG_64BIT) && defined(CONFIG_MIPS32_O32)
-       return !test_thread_flag(TIF_32BIT_REGS);
-#else
+#elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT)
        return 0;
+#else
+       return !test_thread_flag(TIF_32BIT_FPREGS);
 #endif
 }
 
@@ -878,6 +884,10 @@ static inline int cop1_64bit(struct pt_regs *xcp)
                        ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \
                        ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32)
 
+#define SIFROMHREG(si, x)      ((si) = (int)(ctx->fpr[x] >> 32))
+#define SITOHREG(si, x)                (ctx->fpr[x] = \
+                               ctx->fpr[x] << 32 >> 32 | (u64)(si) << 32)
+
 #define DIFROMREG(di, x) ((di) = ctx->fpr[x & ~(cop1_64bit(xcp) == 0)])
 #define DITOREG(di, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = (di))
 
@@ -1055,6 +1065,25 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                        break;
 #endif
 
+               case mfhc_op:
+                       if (!cpu_has_mips_r2)
+                               goto sigill;
+
+                       /* copregister rd -> gpr[rt] */
+                       if (MIPSInst_RT(ir) != 0) {
+                               SIFROMHREG(xcp->regs[MIPSInst_RT(ir)],
+                                       MIPSInst_RD(ir));
+                       }
+                       break;
+
+               case mthc_op:
+                       if (!cpu_has_mips_r2)
+                               goto sigill;
+
+                       /* copregister rd <- gpr[rt] */
+                       SITOHREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir));
+                       break;
+
                case mfc_op:
                        /* copregister rd -> gpr[rt] */
                        if (MIPSInst_RT(ir) != 0) {
@@ -1263,6 +1292,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
 #endif
 
        default:
+sigill:
                return SIGILL;
        }
 
index 1c586575fe172c2283846da91dc5d9910b52f0c2..3aeae07ed5b8db9eef5f697b93ebcef3e6856cf3 100644 (file)
@@ -89,8 +89,9 @@ int fpu_emulator_save_context32(struct sigcontext32 __user *sc)
 {
        int i;
        int err = 0;
+       int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
 
-       for (i = 0; i < 32; i+=2) {
+       for (i = 0; i < 32; i += inc) {
                err |=
                    __put_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
        }
@@ -103,8 +104,9 @@ int fpu_emulator_restore_context32(struct sigcontext32 __user *sc)
 {
        int i;
        int err = 0;
+       int inc = test_thread_flag(TIF_32BIT_FPREGS) ? 2 : 1;
 
-       for (i = 0; i < 32; i+=2) {
+       for (i = 0; i < 32; i += inc) {
                err |=
                    __get_user(current->thread.fpu.fpr[i], &sc->sc_fpregs[i]);
        }
index c8efdb5b6ee0297df1799fe41a3ca94750688119..f41a5c5b0865ecc4e17a66f47129801ebb8ad2f1 100644 (file)
@@ -6,7 +6,6 @@
  * Copyright (C) 2005-2007 Cavium Networks
  */
 #include <linux/export.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
index 2fcde0c8ea029ccfa48f4a52c4fe19af29099333..135ec313c1f6594b31fbda33a7f8fcfc05735e95 100644 (file)
@@ -9,7 +9,6 @@
  * Copyright (C) 1998 Gleb Raiko & Vladimir Roganov
  * Copyright (C) 2001, 2004, 2007  Maciej W. Rozycki
  */
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
index 49e572d879e1348234bc1413f2e9f25e593d9318..c14259edd53f40539ce41cf73025ddce6cbcb277 100644 (file)
@@ -1020,10 +1020,14 @@ static void probe_pcache(void)
                 */
                config1 = read_c0_config1();
 
-               if ((lsize = ((config1 >> 19) & 7)))
-                       c->icache.linesz = 2 << lsize;
-               else
-                       c->icache.linesz = lsize;
+               lsize = (config1 >> 19) & 7;
+
+               /* IL == 7 is reserved */
+               if (lsize == 7)
+                       panic("Invalid icache line size");
+
+               c->icache.linesz = lsize ? 2 << lsize : 0;
+
                c->icache.sets = 32 << (((config1 >> 22) + 1) & 7);
                c->icache.ways = 1 + ((config1 >> 16) & 7);
 
@@ -1040,10 +1044,14 @@ static void probe_pcache(void)
                 */
                c->dcache.flags = 0;
 
-               if ((lsize = ((config1 >> 10) & 7)))
-                       c->dcache.linesz = 2 << lsize;
-               else
-                       c->dcache.linesz= lsize;
+               lsize = (config1 >> 10) & 7;
+
+               /* DL == 7 is reserved */
+               if (lsize == 7)
+                       panic("Invalid dcache line size");
+
+               c->dcache.linesz = lsize ? 2 << lsize : 0;
+
                c->dcache.sets = 32 << (((config1 >> 13) + 1) & 7);
                c->dcache.ways = 1 + ((config1 >> 7) & 7);
 
@@ -1105,6 +1113,8 @@ static void probe_pcache(void)
        case CPU_34K:
        case CPU_74K:
        case CPU_1004K:
+       case CPU_INTERAPTIV:
+       case CPU_PROAPTIV:
                if (current_cpu_type() == CPU_74K)
                        alias_74k_erratum(c);
                if ((read_c0_config7() & (1 << 16))) {
index 15f813c303b45bcb35f253249bd3571b6f4b8d8c..fde7e56d13fe3c0d6079d8ad76283f0e13a75a8e 100644 (file)
@@ -8,7 +8,6 @@
  */
 #include <linux/fs.h>
 #include <linux/fcntl.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/linkage.h>
 #include <linux/module.h>
index 191cf6e0c7258b16217725084650a5043ec34cdd..5d5f29681a21c0f539626159367b050f34ad5584 100644 (file)
@@ -15,7 +15,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  */
-#include <linux/init.h>
 
 #include <asm/asm.h>
 #include <asm/regdef.h>
index 2e9418562258754dacb511341b499965022760aa..44b6dff5aba2a09e92715aab976c2ac37619e729 100644 (file)
@@ -23,6 +23,7 @@
 
 #include <dma-coherence.h>
 
+#ifdef CONFIG_DMA_MAYBE_COHERENT
 int coherentio = 0;    /* User defined DMA coherency from command line. */
 EXPORT_SYMBOL_GPL(coherentio);
 int hw_coherentio = 0; /* Actual hardware supported DMA coherency setting. */
@@ -42,6 +43,7 @@ static int __init setnocoherentio(char *str)
        return 0;
 }
 early_param("nocoherentio", setnocoherentio);
+#endif
 
 static inline struct page *dma_addr_to_page(struct device *dev,
        dma_addr_t dma_addr)
index 01fda4419ed09de2e5adbfcd0b318023f3cc7664..77e0ae036e7c9edf75e9ffc64369802a54ee3a1e 100644 (file)
@@ -11,7 +11,6 @@
  * Copyright (C) 2008, 2009 Cavium Networks, Inc.
  */
 
-#include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
index 12156176c7caa937ff5abcea16b249b95c748cb1..6b59617760c1933223337581dd0359feef084b37 100644 (file)
@@ -171,8 +171,6 @@ void *kmap_coherent(struct page *page, unsigned long addr)
        return (void*) vaddr;
 }
 
-#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
-
 void kunmap_coherent(void)
 {
 #ifndef CONFIG_MIPS_MT_SMTC
index cbd81d17793a71b617ed28b92a2510d89d08114a..58033c44690d75db10637e757168f96b5bb5dea7 100644 (file)
@@ -8,7 +8,6 @@
  * Copyright (C) 2008  Thiemo Seufer
  * Copyright (C) 2012  MIPS Technologies, Inc.
  */
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
index 08d05aee8788beecdf0a6e3cc8d21ee3901e17da..7a56aee5fce70ebc5c7fb627a262f1e84b2176f2 100644 (file)
@@ -76,6 +76,8 @@ static inline int mips_sc_is_activated(struct cpuinfo_mips *c)
        case CPU_34K:
        case CPU_74K:
        case CPU_1004K:
+       case CPU_INTERAPTIV:
+       case CPU_PROAPTIV:
        case CPU_BMIPS5000:
                if (config2 & (1 << 12))
                        return 0;
index aaffbba33706400c05701f31313d835c7debdbff..9ac1efcfbcc7f735727900bc482fcce28b1622ba 100644 (file)
@@ -6,7 +6,6 @@
 
 #undef DEBUG
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/mm.h>
 #include <linux/bitops.h>
index 9aca10994cd22b4af8c1900ffa5592a0ea42788e..d657493ef561efcc1403ce79f5dbdf1d28845de6 100644 (file)
@@ -10,7 +10,6 @@
  * Copyright (C) 2002  Ralf Baechle
  * Copyright (C) 2002  Maciej W. Rozycki
  */
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
index da3b0b9c9eae0a9800dfbbd20f6717709e72bfed..ae4ca24507072f8cd3a94b02a935442091aae76b 100644 (file)
 #include <asm/bootinfo.h>
 #include <asm/mmu_context.h>
 #include <asm/pgtable.h>
+#include <asm/tlb.h>
 #include <asm/tlbmisc.h>
 
 extern void build_tlb_refill_handler(void);
 
-/*
- * Make sure all entries differ.  If they're not different
- * MIPS32 will take revenge ...
- */
-#define UNIQUE_ENTRYHI(idx) (CKSEG0 + ((idx) << (PAGE_SHIFT + 1)))
-
 /* Atomicity and interruptability */
 #ifdef CONFIG_MIPS_MT_SMTC
 
@@ -77,7 +72,7 @@ void local_flush_tlb_all(void)
 {
        unsigned long flags;
        unsigned long old_ctx;
-       int entry;
+       int entry, ftlbhighset;
 
        ENTER_CRITICAL(flags);
        /* Save old context and create impossible VPN2 value */
@@ -88,13 +83,30 @@ void local_flush_tlb_all(void)
        entry = read_c0_wired();
 
        /* Blast 'em all away. */
-       while (entry < current_cpu_data.tlbsize) {
-               /* Make sure all entries differ. */
-               write_c0_entryhi(UNIQUE_ENTRYHI(entry));
-               write_c0_index(entry);
-               mtc0_tlbw_hazard();
-               tlb_write_indexed();
-               entry++;
+       if (cpu_has_tlbinv) {
+               if (current_cpu_data.tlbsizevtlb) {
+                       write_c0_index(0);
+                       mtc0_tlbw_hazard();
+                       tlbinvf();  /* invalidate VTLB */
+               }
+               ftlbhighset = current_cpu_data.tlbsizevtlb +
+                       current_cpu_data.tlbsizeftlbsets;
+               for (entry = current_cpu_data.tlbsizevtlb;
+                    entry < ftlbhighset;
+                    entry++) {
+                       write_c0_index(entry);
+                       mtc0_tlbw_hazard();
+                       tlbinvf();  /* invalidate one FTLB set */
+               }
+       } else {
+               while (entry < current_cpu_data.tlbsize) {
+                       /* Make sure all entries differ. */
+                       write_c0_entryhi(UNIQUE_ENTRYHI(entry));
+                       write_c0_index(entry);
+                       mtc0_tlbw_hazard();
+                       tlb_write_indexed();
+                       entry++;
+               }
        }
        tlbw_use_hazard();
        write_c0_entryhi(old_ctx);
@@ -133,7 +145,9 @@ void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
                start = round_down(start, PAGE_SIZE << 1);
                end = round_up(end, PAGE_SIZE << 1);
                size = (end - start) >> (PAGE_SHIFT + 1);
-               if (size <= current_cpu_data.tlbsize/2) {
+               if (size <= (current_cpu_data.tlbsizeftlbsets ?
+                            current_cpu_data.tlbsize / 8 :
+                            current_cpu_data.tlbsize / 2)) {
                        int oldpid = read_c0_entryhi();
                        int newpid = cpu_asid(cpu, mm);
 
@@ -172,7 +186,9 @@ void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
        ENTER_CRITICAL(flags);
        size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
        size = (size + 1) >> 1;
-       if (size <= current_cpu_data.tlbsize / 2) {
+       if (size <= (current_cpu_data.tlbsizeftlbsets ?
+                    current_cpu_data.tlbsize / 8 :
+                    current_cpu_data.tlbsize / 2)) {
                int pid = read_c0_entryhi();
 
                start &= (PAGE_MASK << 1);
index 6a99733a44402b71a198c5d18e5d6e1e3eff7b8e..138a2ec7cc6b7785069f64401c39c9b569ff497e 100644 (file)
@@ -8,7 +8,6 @@
  * Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 2002 MIPS Technologies, Inc.  All rights reserved.
  */
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/mm.h>
index 183f2b583e4dbc7798411c4fd8c6c3927bff607f..b234b1b5ccada646b9286d8cc31c531d3b9f2a8a 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/types.h>
 #include <linux/smp.h>
 #include <linux/string.h>
-#include <linux/init.h>
 #include <linux/cache.h>
 
 #include <asm/cacheflush.h>
@@ -510,6 +509,7 @@ static void build_tlb_write_entry(u32 **p, struct uasm_label **l,
                switch (current_cpu_type()) {
                case CPU_M14KC:
                case CPU_74K:
+               case CPU_PROAPTIV:
                        break;
 
                default:
index 060000fa653c3c939835381f45d56c5cf162194a..b8d580ca02e53f43bf38df9ae921e0c589b28582 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/init.h>
 
 #include <asm/inst.h>
 #include <asm/elf.h>
index 0c724589854e7216e470d59d4359b984bd15375a..3abd609518c9701d1cdd1d0165a4e6a4611e6013 100644 (file)
@@ -15,7 +15,6 @@
 
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/init.h>
 
 #include <asm/inst.h>
 #include <asm/elf.h>
index 72fdedbf76db8bd9d1d8dffc803f26fc771d8483..eae0ba3876d92269565d9dad245780699b77388f 100644 (file)
@@ -9,7 +9,5 @@ obj-y                           := malta-amon.o malta-display.o malta-init.o \
                                   malta-int.o malta-memory.o malta-platform.o \
                                   malta-reset.o malta-setup.o malta-time.o
 
-obj-$(CONFIG_EARLY_PRINTK)     += malta-console.o
-
 # FIXME FIXME FIXME
 obj-$(CONFIG_MIPS_MT_SMTC)     += malta-smtc.o
index 1e4784458016eb73a417283777f2b9b9d5117ae4..592ac0427426acd4b83d1272f4e8c43c7716bca1 100644 (file)
@@ -1,30 +1,20 @@
 /*
- * Copyright (C) 2007  MIPS Technologies, Inc.
- *     All rights reserved.
-
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
+ * 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.
  *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * Copyright (C) 2007 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
  *
- * Arbitrary Monitor interface
+ * Arbitrary Monitor Interface
  */
-
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 
 #include <asm/addrspace.h>
-#include <asm/mips-boards/launch.h>
 #include <asm/mipsmtregs.h>
+#include <asm/mips-boards/launch.h>
+#include <asm/vpe.h>
 
 int amon_cpu_avail(int cpu)
 {
@@ -48,7 +38,7 @@ int amon_cpu_avail(int cpu)
        return 1;
 }
 
-void amon_cpu_start(int cpu,
+int amon_cpu_start(int cpu,
                    unsigned long pc, unsigned long sp,
                    unsigned long gp, unsigned long a0)
 {
@@ -56,10 +46,10 @@ void amon_cpu_start(int cpu,
                (struct cpulaunch  *)CKSEG0ADDR(CPULAUNCH);
 
        if (!amon_cpu_avail(cpu))
-               return;
+               return -1;
        if (cpu == smp_processor_id()) {
                pr_debug("launch: I am cpu%d!\n", cpu);
-               return;
+               return -1;
        }
        launch += cpu;
 
@@ -78,4 +68,21 @@ void amon_cpu_start(int cpu,
                ;
        smp_rmb();      /* Target will be updating flags soon */
        pr_debug("launch: cpu%d gone!\n", cpu);
+
+       return 0;
+}
+
+#ifdef CONFIG_MIPS_VPE_LOADER
+int vpe_run(struct vpe *v)
+{
+       struct vpe_notifications *n;
+
+       if (amon_cpu_start(aprp_cpu_index(), v->__start, 0, 0, 0) < 0)
+               return -1;
+
+       list_for_each_entry(n, &v->notify, list)
+               n->start(VPE_MODULE_MINOR);
+
+       return 0;
 }
+#endif
diff --git a/arch/mips/mti-malta/malta-console.c b/arch/mips/mti-malta/malta-console.c
deleted file mode 100644 (file)
index 43bcfb4..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Carsten Langgaard, carstenl@mips.com
- * Copyright (C) 1999,2000 MIPS Technologies, Inc.  All rights reserved.
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
- *
- * Putting things on the screen/serial line using YAMONs facilities.
- */
-#include <linux/console.h>
-#include <linux/init.h>
-#include <linux/serial_reg.h>
-#include <asm/io.h>
-
-
-#define PORT(offset) (0x3f8 + (offset))
-
-
-static inline unsigned int serial_in(int offset)
-{
-       return inb(PORT(offset));
-}
-
-static inline void serial_out(int offset, int value)
-{
-       outb(value, PORT(offset));
-}
-
-int prom_putchar(char c)
-{
-       while ((serial_in(UART_LSR) & UART_LSR_THRE) == 0)
-               ;
-
-       serial_out(UART_TX, c);
-
-       return 1;
-}
index ff8caffd3266ea0a1deaaa1ee1093eac50b600b9..fcebfced26d0c929aed514ca9b310677b3ba3247 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/kernel.h>
+#include <linux/serial_8250.h>
 
 #include <asm/cacheflush.h>
 #include <asm/smp-ops.h>
@@ -44,32 +45,39 @@ static void __init console_config(void)
        char parity = '\0', bits = '\0', flow = '\0';
        char *s;
 
-       if ((strstr(fw_getcmdline(), "console=")) == NULL) {
-               s = fw_getenv("modetty0");
-               if (s) {
-                       while (*s >= '0' && *s <= '9')
-                               baud = baud*10 + *s++ - '0';
-                       if (*s == ',')
-                               s++;
-                       if (*s)
-                               parity = *s++;
-                       if (*s == ',')
-                               s++;
-                       if (*s)
-                               bits = *s++;
-                       if (*s == ',')
-                               s++;
-                       if (*s == 'h')
-                               flow = 'r';
-               }
-               if (baud == 0)
-                       baud = 38400;
-               if (parity != 'n' && parity != 'o' && parity != 'e')
-                       parity = 'n';
-               if (bits != '7' && bits != '8')
-                       bits = '8';
-               if (flow == '\0')
+       s = fw_getenv("modetty0");
+       if (s) {
+               while (*s >= '0' && *s <= '9')
+                       baud = baud*10 + *s++ - '0';
+               if (*s == ',')
+                       s++;
+               if (*s)
+                       parity = *s++;
+               if (*s == ',')
+                       s++;
+               if (*s)
+                       bits = *s++;
+               if (*s == ',')
+                       s++;
+               if (*s == 'h')
                        flow = 'r';
+       }
+       if (baud == 0)
+               baud = 38400;
+       if (parity != 'n' && parity != 'o' && parity != 'e')
+               parity = 'n';
+       if (bits != '7' && bits != '8')
+               bits = '8';
+       if (flow == '\0')
+               flow = 'r';
+
+       if ((strstr(fw_getcmdline(), "earlycon=")) == NULL) {
+               sprintf(console_string, "uart8250,io,0x3f8,%d%c%c", baud,
+                       parity, bits);
+               setup_early_serial8250_console(console_string);
+       }
+
+       if ((strstr(fw_getcmdline(), "console=")) == NULL) {
                sprintf(console_string, " console=ttyS0,%d%c%c%c", baud,
                        parity, bits, flow);
                strcat(fw_getcmdline(), console_string);
index 0892575f829da5a5cb71218265fe81da24d14cfb..ca3e3a46a42f90dedc359c1729d7b3c55365fc92 100644 (file)
@@ -1,25 +1,16 @@
 /*
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License.  See the file "COPYING" in the main directory of this archive
+ * for more details.
+ *
  * Carsten Langgaard, carstenl@mips.com
  * Copyright (C) 2000, 2001, 2004 MIPS Technologies, Inc.
  * Copyright (C) 2001 Ralf Baechle
- *
- *  This program is free software; you can distribute it and/or modify it
- *  under the terms of the GNU General Public License (Version 2) as
- *  published by the Free Software Foundation.
- *
- *  This program is distributed in the hope it will be useful, but WITHOUT
- *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- *  for more details.
- *
- *  You should have received a copy of the GNU General Public License along
- *  with this program; if not, write to the Free Software Foundation, Inc.,
- *  59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
  *
  * Routines for generic manipulation of the interrupts found on the MIPS
- * Malta board.
- * The interrupt controller is located in the South Bridge a PIIX4 device
- * with two internal 82C95 interrupt controllers.
+ * Malta board. The interrupt controller is located in the South Bridge
+ * a PIIX4 device with two internal 82C95 interrupt controllers.
  */
 #include <linux/init.h>
 #include <linux/irq.h>
@@ -44,6 +35,7 @@
 #include <asm/gic.h>
 #include <asm/gcmpregs.h>
 #include <asm/setup.h>
+#include <asm/rtlx.h>
 
 int gcmp_present = -1;
 static unsigned long _msc01_biu_base;
@@ -90,7 +82,7 @@ static inline int mips_pcibios_iack(void)
                BONITO_PCIMAP_CFG = 0;
                break;
        default:
-               printk(KERN_WARNING "Unknown system controller.\n");
+               pr_emerg("Unknown system controller.\n");
                return -1;
        }
        return irq;
@@ -126,6 +118,11 @@ static void malta_hw0_irqdispatch(void)
        }
 
        do_IRQ(MALTA_INT_BASE + irq);
+
+#ifdef MIPS_VPE_APSP_API
+       if (aprp_hook)
+               aprp_hook();
+#endif
 }
 
 static void malta_ipi_irqdispatch(void)
@@ -149,11 +146,11 @@ static void corehi_irqdispatch(void)
        unsigned int intrcause, datalo, datahi;
        struct pt_regs *regs = get_irq_regs();
 
-       printk(KERN_EMERG "CoreHI interrupt, shouldn't happen, we die here!\n");
-       printk(KERN_EMERG "epc   : %08lx\nStatus: %08lx\n"
-                       "Cause : %08lx\nbadVaddr : %08lx\n",
-                       regs->cp0_epc, regs->cp0_status,
-                       regs->cp0_cause, regs->cp0_badvaddr);
+       pr_emerg("CoreHI interrupt, shouldn't happen, we die here!\n");
+       pr_emerg("epc    : %08lx\nStatus: %08lx\n"
+                "Cause : %08lx\nbadVaddr : %08lx\n",
+                regs->cp0_epc, regs->cp0_status,
+                regs->cp0_cause, regs->cp0_badvaddr);
 
        /* Read all the registers and then print them as there is a
           problem with interspersed printk's upsetting the Bonito controller.
@@ -171,8 +168,8 @@ static void corehi_irqdispatch(void)
                intrcause = GT_READ(GT_INTRCAUSE_OFS);
                datalo = GT_READ(GT_CPUERR_ADDRLO_OFS);
                datahi = GT_READ(GT_CPUERR_ADDRHI_OFS);
-               printk(KERN_EMERG "GT_INTRCAUSE = %08x\n", intrcause);
-               printk(KERN_EMERG "GT_CPUERR_ADDR = %02x%08x\n",
+               pr_emerg("GT_INTRCAUSE = %08x\n", intrcause);
+               pr_emerg("GT_CPUERR_ADDR = %02x%08x\n",
                                datahi, datalo);
                break;
        case MIPS_REVISION_SCON_BONITO:
@@ -184,14 +181,14 @@ static void corehi_irqdispatch(void)
                intedge = BONITO_INTEDGE;
                intsteer = BONITO_INTSTEER;
                pcicmd = BONITO_PCICMD;
-               printk(KERN_EMERG "BONITO_INTISR = %08x\n", intisr);
-               printk(KERN_EMERG "BONITO_INTEN = %08x\n", inten);
-               printk(KERN_EMERG "BONITO_INTPOL = %08x\n", intpol);
-               printk(KERN_EMERG "BONITO_INTEDGE = %08x\n", intedge);
-               printk(KERN_EMERG "BONITO_INTSTEER = %08x\n", intsteer);
-               printk(KERN_EMERG "BONITO_PCICMD = %08x\n", pcicmd);
-               printk(KERN_EMERG "BONITO_PCIBADADDR = %08x\n", pcibadaddr);
-               printk(KERN_EMERG "BONITO_PCIMSTAT = %08x\n", pcimstat);
+               pr_emerg("BONITO_INTISR = %08x\n", intisr);
+               pr_emerg("BONITO_INTEN = %08x\n", inten);
+               pr_emerg("BONITO_INTPOL = %08x\n", intpol);
+               pr_emerg("BONITO_INTEDGE = %08x\n", intedge);
+               pr_emerg("BONITO_INTSTEER = %08x\n", intsteer);
+               pr_emerg("BONITO_PCICMD = %08x\n", pcicmd);
+               pr_emerg("BONITO_PCIBADADDR = %08x\n", pcibadaddr);
+               pr_emerg("BONITO_PCIMSTAT = %08x\n", pcimstat);
                break;
        }
 
@@ -313,6 +310,11 @@ static void ipi_call_dispatch(void)
 
 static irqreturn_t ipi_resched_interrupt(int irq, void *dev_id)
 {
+#ifdef MIPS_VPE_APSP_API
+       if (aprp_hook)
+               aprp_hook();
+#endif
+
        scheduler_ipi();
 
        return IRQ_HANDLED;
@@ -365,13 +367,13 @@ static struct irqaction corehi_irqaction = {
        .flags = IRQF_NO_THREAD,
 };
 
-static msc_irqmap_t __initdata msc_irqmap[] = {
+static msc_irqmap_t msc_irqmap[] __initdata = {
        {MSC01C_INT_TMR,                MSC01_IRQ_EDGE, 0},
        {MSC01C_INT_PCI,                MSC01_IRQ_LEVEL, 0},
 };
-static int __initdata msc_nr_irqs = ARRAY_SIZE(msc_irqmap);
+static int msc_nr_irqs __initdata = ARRAY_SIZE(msc_irqmap);
 
-static msc_irqmap_t __initdata msc_eicirqmap[] = {
+static msc_irqmap_t msc_eicirqmap[] __initdata = {
        {MSC01E_INT_SW0,                MSC01_IRQ_LEVEL, 0},
        {MSC01E_INT_SW1,                MSC01_IRQ_LEVEL, 0},
        {MSC01E_INT_I8259A,             MSC01_IRQ_LEVEL, 0},
@@ -384,7 +386,7 @@ static msc_irqmap_t __initdata msc_eicirqmap[] = {
        {MSC01E_INT_CPUCTR,             MSC01_IRQ_LEVEL, 0}
 };
 
-static int __initdata msc_nr_eicirqs = ARRAY_SIZE(msc_eicirqmap);
+static int msc_nr_eicirqs __initdata = ARRAY_SIZE(msc_eicirqmap);
 
 /*
  * This GIC specific tabular array defines the association between External
@@ -431,9 +433,12 @@ int __init gcmp_probe(unsigned long addr, unsigned long size)
        if (gcmp_present >= 0)
                return gcmp_present;
 
-       _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR, GCMP_ADDRSPACE_SZ);
-       _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE, MSC01_BIU_ADDRSPACE_SZ);
-       gcmp_present = (GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) == GCMP_BASE_ADDR;
+       _gcmp_base = (unsigned long) ioremap_nocache(GCMP_BASE_ADDR,
+               GCMP_ADDRSPACE_SZ);
+       _msc01_biu_base = (unsigned long) ioremap_nocache(MSC01_BIU_REG_BASE,
+               MSC01_BIU_ADDRSPACE_SZ);
+       gcmp_present = ((GCMPGCB(GCMPB) & GCMP_GCB_GCMPB_GCMPBASE_MSK) ==
+               GCMP_BASE_ADDR);
 
        if (gcmp_present)
                pr_debug("GCMP present\n");
@@ -443,9 +448,8 @@ int __init gcmp_probe(unsigned long addr, unsigned long size)
 /* Return the number of IOCU's present */
 int __init gcmp_niocu(void)
 {
-  return gcmp_present ?
-    (GCMPGCB(GC) & GCMP_GCB_GC_NUMIOCU_MSK) >> GCMP_GCB_GC_NUMIOCU_SHF :
-    0;
+       return gcmp_present ? ((GCMPGCB(GC) & GCMP_GCB_GC_NUMIOCU_MSK) >>
+               GCMP_GCB_GC_NUMIOCU_SHF) : 0;
 }
 
 /* Set GCMP region attributes */
@@ -594,11 +598,14 @@ void __init arch_init_irq(void)
                        set_vi_handler(MIPSCPU_INT_IPI1, malta_ipi_irqdispatch);
                }
                /* Argh.. this really needs sorting out.. */
-               printk("CPU%d: status register was %08x\n", smp_processor_id(), read_c0_status());
+               pr_info("CPU%d: status register was %08x\n",
+                       smp_processor_id(), read_c0_status());
                write_c0_status(read_c0_status() | STATUSF_IP3 | STATUSF_IP4);
-               printk("CPU%d: status register now %08x\n", smp_processor_id(), read_c0_status());
+               pr_info("CPU%d: status register now %08x\n",
+                       smp_processor_id(), read_c0_status());
                write_c0_status(0x1100dc00);
-               printk("CPU%d: status register frc %08x\n", smp_processor_id(), read_c0_status());
+               pr_info("CPU%d: status register frc %08x\n",
+                       smp_processor_id(), read_c0_status());
                for (i = 0; i < nr_cpu_ids; i++) {
                        arch_init_ipiirq(MIPS_GIC_IRQ_BASE +
                                         GIC_RESCHED_INT(i), &irq_resched);
@@ -616,11 +623,15 @@ void __init arch_init_irq(void)
                        cpu_ipi_call_irq = MSC01E_INT_SW1;
                } else {
                        if (cpu_has_vint) {
-                               set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ, ipi_resched_dispatch);
-                               set_vi_handler (MIPS_CPU_IPI_CALL_IRQ, ipi_call_dispatch);
+                               set_vi_handler (MIPS_CPU_IPI_RESCHED_IRQ,
+                                       ipi_resched_dispatch);
+                               set_vi_handler (MIPS_CPU_IPI_CALL_IRQ,
+                                       ipi_call_dispatch);
                        }
-                       cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_RESCHED_IRQ;
-                       cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE + MIPS_CPU_IPI_CALL_IRQ;
+                       cpu_ipi_resched_irq = MIPS_CPU_IRQ_BASE +
+                               MIPS_CPU_IPI_RESCHED_IRQ;
+                       cpu_ipi_call_irq = MIPS_CPU_IRQ_BASE +
+                               MIPS_CPU_IPI_CALL_IRQ;
                }
                arch_init_ipiirq(cpu_ipi_resched_irq, &irq_resched);
                arch_init_ipiirq(cpu_ipi_call_irq, &irq_call);
@@ -630,9 +641,7 @@ void __init arch_init_irq(void)
 
 void malta_be_init(void)
 {
-       if (gcmp_present) {
-               /* Could change CM error mask register */
-       }
+       /* Could change CM error mask register. */
 }
 
 
@@ -712,14 +721,14 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
                        if (cause < 16) {
                                unsigned long cca_bits = (cm_error >> 15) & 7;
                                unsigned long tr_bits = (cm_error >> 12) & 7;
-                               unsigned long mcmd_bits = (cm_error >> 7) & 0x1f;
+                               unsigned long cmd_bits = (cm_error >> 7) & 0x1f;
                                unsigned long stag_bits = (cm_error >> 3) & 15;
                                unsigned long sport_bits = (cm_error >> 0) & 7;
 
                                snprintf(buf, sizeof(buf),
                                         "CCA=%lu TR=%s MCmd=%s STag=%lu "
                                         "SPort=%lu\n",
-                                        cca_bits, tr[tr_bits], mcmd[mcmd_bits],
+                                        cca_bits, tr[tr_bits], mcmd[cmd_bits],
                                         stag_bits, sport_bits);
                        } else {
                                /* glob state & sresp together */
@@ -728,7 +737,7 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
                                unsigned long c1_bits = (cm_error >> 12) & 7;
                                unsigned long c0_bits = (cm_error >> 9) & 7;
                                unsigned long sc_bit = (cm_error >> 8) & 1;
-                               unsigned long mcmd_bits = (cm_error >> 3) & 0x1f;
+                               unsigned long cmd_bits = (cm_error >> 3) & 0x1f;
                                unsigned long sport_bits = (cm_error >> 0) & 7;
                                snprintf(buf, sizeof(buf),
                                         "C3=%s C2=%s C1=%s C0=%s SC=%s "
@@ -736,16 +745,16 @@ int malta_be_handler(struct pt_regs *regs, int is_fixup)
                                         core[c3_bits], core[c2_bits],
                                         core[c1_bits], core[c0_bits],
                                         sc_bit ? "True" : "False",
-                                        mcmd[mcmd_bits], sport_bits);
+                                        mcmd[cmd_bits], sport_bits);
                        }
 
                        ocause = (cm_other & GCMP_GCB_GMEO_ERROR_2ND_MSK) >>
                                 GCMP_GCB_GMEO_ERROR_2ND_SHF;
 
-                       printk("CM_ERROR=%08lx %s <%s>\n", cm_error,
+                       pr_err("CM_ERROR=%08lx %s <%s>\n", cm_error,
                               causes[cause], buf);
-                       printk("CM_ADDR =%08lx\n", cm_addr);
-                       printk("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]);
+                       pr_err("CM_ADDR =%08lx\n", cm_addr);
+                       pr_err("CM_OTHER=%08lx %s\n", cm_other, causes[ocause]);
 
                        /* reprime cause register */
                        GCMPGCB(GCMEC) = 0;
index 132f8663825e4b29da00e44b48b32407cfba871b..e1dd1c1d3fdeed9f5214dc18ec4cb7f2c5593279 100644 (file)
@@ -47,6 +47,7 @@
 static struct plat_serial8250_port uart8250_data[] = {
        SMC_PORT(0x3F8, 4),
        SMC_PORT(0x2F8, 3),
+#ifndef CONFIG_MIPS_CMP
        {
                .mapbase        = 0x1f000900,   /* The CBUS UART */
                .irq            = MIPS_CPU_IRQ_BASE + MIPSCPU_INT_MB2,
@@ -55,6 +56,7 @@ static struct plat_serial8250_port uart8250_data[] = {
                .flags          = CBUS_UART_FLAGS,
                .regshift       = 3,
        },
+#endif
        { },
 };
 
index a18af5fce67eb704d223742f6f15f7062604ff7b..319009912142414c72862a04adf083136f1cdd45 100644 (file)
@@ -42,8 +42,6 @@
 #include <asm/mips-boards/generic.h>
 #include <asm/mips-boards/maltaint.h>
 
-unsigned long cpu_khz;
-
 static int mips_cpu_timer_irq;
 static int mips_cpu_perf_irq;
 extern int cp0_perfcount_irq;
@@ -168,11 +166,24 @@ unsigned int get_c0_compare_int(void)
        return mips_cpu_timer_irq;
 }
 
+static void __init init_rtc(void)
+{
+       /* stop the clock whilst setting it up */
+       CMOS_WRITE(RTC_SET | RTC_24H, RTC_CONTROL);
+
+       /* 32KHz time base */
+       CMOS_WRITE(RTC_REF_CLCK_32KHZ, RTC_FREQ_SELECT);
+
+       /* start the clock */
+       CMOS_WRITE(RTC_24H, RTC_CONTROL);
+}
+
 void __init plat_time_init(void)
 {
        unsigned int prid = read_c0_prid() & (PRID_COMP_MASK | PRID_IMP_MASK);
        unsigned int freq;
 
+       init_rtc();
        estimate_frequencies();
 
        freq = mips_hpt_frequency;
@@ -182,7 +193,6 @@ void __init plat_time_init(void)
        freq = freqround(freq, 5000);
        printk("CPU frequency %d.%02d MHz\n", freq/1000000,
               (freq%1000000)*100/1000000);
-       cpu_khz = freq / 1000;
 
        mips_scroll_message();
 
index be114209217cc5a13fe8531365ba5454b12c530f..071786fa234ba5652cb290f9254f0e80ecebf6ce 100644 (file)
@@ -21,5 +21,7 @@ obj-$(CONFIG_EARLY_PRINTK)    += sead3-console.o
 obj-$(CONFIG_USB_EHCI_HCD)     += sead3-ehci.o
 obj-$(CONFIG_OF)               += sead3.dtb.o
 
+CFLAGS_sead3-setup.o = -I$(src)/../../../scripts/dtc/libfdt
+
 $(obj)/%.dtb: $(obj)/%.dts
        $(call if_changed,dtc)
index eb2bf936d102b3a410a419bf341493d4177108dc..3b12aa5a7c88f378d3122ff5587e6192c74e22ad 100644 (file)
@@ -8,7 +8,6 @@
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/errno.h>
 
index 928ba84c8a78590ff9839cf8be195532deb8f237..bf7fe48bf2f927dfef969233658968bfdcf79bbc 100644 (file)
@@ -4,13 +4,15 @@
  * for more details.
  *
  * Copyright (C) 2012 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2013 Imagination Technologies Ltd.
  */
 #include <linux/init.h>
+#include <linux/libfdt.h>
 #include <linux/of_platform.h>
 #include <linux/of_fdt.h>
-#include <linux/bootmem.h>
 
 #include <asm/prom.h>
+#include <asm/fw/fw.h>
 
 #include <asm/mips-boards/generic.h>
 
@@ -19,8 +21,73 @@ const char *get_system_type(void)
        return "MIPS SEAD3";
 }
 
+static uint32_t get_memsize_from_cmdline(void)
+{
+       int memsize = 0;
+       char *p = arcs_cmdline;
+       char *s = "memsize=";
+
+       p = strstr(p, s);
+       if (p) {
+               p += strlen(s);
+               memsize = memparse(p, NULL);
+       }
+
+       return memsize;
+}
+
+static uint32_t get_memsize_from_env(void)
+{
+       int memsize = 0;
+       char *p;
+
+       p = fw_getenv("memsize");
+       if (p)
+               memsize = memparse(p, NULL);
+
+       return memsize;
+}
+
+static uint32_t get_memsize(void)
+{
+       uint32_t memsize;
+
+       memsize = get_memsize_from_cmdline();
+       if (memsize)
+               return memsize;
+
+       return get_memsize_from_env();
+}
+
+static void __init parse_memsize_param(void)
+{
+       int offset;
+       const uint64_t *prop_value;
+       int prop_len;
+       uint32_t memsize = get_memsize();
+
+       if (!memsize)
+               return;
+
+       offset = fdt_path_offset(&__dtb_start, "/memory");
+       if (offset > 0) {
+               uint64_t new_value;
+               /*
+                * reg contains 2 32-bits BE values, offset and size. We just
+                * want to replace the size value without affecting the offset
+                */
+               prop_value = fdt_getprop(&__dtb_start, offset, "reg", &prop_len);
+               new_value = be64_to_cpu(*prop_value);
+               new_value =  (new_value & ~0xffffffffllu) | memsize;
+               fdt_setprop_inplace_u64(&__dtb_start, offset, "reg", new_value);
+       }
+}
+
 void __init plat_mem_setup(void)
 {
+       /* allow command line/bootloader env to override memory size in DT */
+       parse_memsize_param();
+
        /*
         * Load the builtin devicetree. This causes the chosen node to be
         * parsed resulting in our memory appearing
@@ -30,16 +97,15 @@ void __init plat_mem_setup(void)
 
 void __init device_tree_init(void)
 {
-       unsigned long base, size;
-
        if (!initial_boot_params)
                return;
 
-       base = virt_to_phys((void *)initial_boot_params);
-       size = be32_to_cpu(initial_boot_params->totalsize);
-
-       /* Before we do anything, lets reserve the dt blob */
-       reserve_bootmem(base, size, BOOTMEM_DEFAULT);
+       unflatten_and_copy_device_tree();
+}
 
-       unflatten_device_tree();
+static int __init customize_machine(void)
+{
+       of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+       return 0;
 }
+arch_initcall(customize_machine);
index 552d26c343869fe6c02778dec476215626a7b356..678d03d53c60cc80e399e1b79a44dfbb4f64ab84 100644 (file)
@@ -13,8 +13,6 @@
 #include <asm/irq.h>
 #include <asm/mips-boards/generic.h>
 
-unsigned long cpu_khz;
-
 static int mips_cpu_timer_irq;
 static int mips_cpu_perf_irq;
 
@@ -109,8 +107,6 @@ void __init plat_time_init(void)
        pr_debug("CPU frequency %d.%02d MHz\n", (est_freq / 1000000),
                (est_freq % 1000000) * 100 / 1000000);
 
-       cpu_khz = est_freq / 1000;
-
        mips_scroll_message();
 
        plat_perf_setup();
index 658f437870562924bf0ad9d93b3aba2873bf9e5f..e4b317d414f112576bbd04012381ab6804dabf86 100644 (file)
                };
        };
 
-       chosen {
-               bootargs = "console=ttyS1,38400 rootdelay=10 root=/dev/sda3";
-       };
-
        memory {
                device_type = "memory";
                reg = <0x0 0x08000000>;
index 852a4ee09954dacd635a2cfe6827b56bcd48acdc..4eb683aef7d7669bf86cae46a45b5c352fbfab39 100644 (file)
@@ -28,6 +28,15 @@ config DT_XLP_FVP
          pointer to the kernel.  The corresponding DTS file is at
          arch/mips/netlogic/dts/xlp_fvp.dts
 
+config DT_XLP_GVP
+       bool "Built-in device tree for XLP GVP boards"
+       default y
+       help
+         Add an FDT blob for XLP GVP board into the kernel.
+         This DTB will be used if the firmware does not pass in a DTB
+         pointer to the kernel.  The corresponding DTS file is at
+         arch/mips/netlogic/dts/xlp_gvp.dts
+
 config NLM_MULTINODE
        bool "Support for multi-chip boards"
        depends on NLM_XLP_BOARD
index 1902fa22d277dc2cdd8ccd1ccad583a71d8cdc7a..769f93032c5331f3628e33b42c621db462e07717 100644 (file)
 
 #include <asm/mipsregs.h>
 #include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
 
 #if defined(CONFIG_CPU_XLP)
 #include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
 #include <asm/netlogic/xlp-hal/uart.h>
 #elif defined(CONFIG_CPU_XLR)
 #include <asm/netlogic/xlr/iomap.h>
index 1c7e3a1b81abd622477997fa6b30f5ef861ba1d3..5afc4b7fce0f12ddb96fd00f54b7a6577b887eb0 100644 (file)
@@ -180,6 +180,7 @@ static void __init nlm_init_percpu_irqs(void)
 #endif
 }
 
+
 void nlm_setup_pic_irq(int node, int picirq, int irq, int irt)
 {
        struct nlm_pic_irq *pic_data;
@@ -207,32 +208,32 @@ void nlm_set_pic_extra_ack(int node, int irq, void (*xack)(struct irq_data *))
 
 static void nlm_init_node_irqs(int node)
 {
-       int i, irt;
-       uint64_t irqmask;
        struct nlm_soc_info *nodep;
+       int i, irt;
 
        pr_info("Init IRQ for node %d\n", node);
        nodep = nlm_get_node(node);
-       irqmask = PERCPU_IRQ_MASK;
+       nodep->irqmask = PERCPU_IRQ_MASK;
        for (i = PIC_IRT_FIRST_IRQ; i <= PIC_IRT_LAST_IRQ; i++) {
                irt = nlm_irq_to_irt(i);
-               if (irt == -1)
+               if (irt == -1)          /* unused irq */
                        continue;
-               nlm_setup_pic_irq(node, i, i, irt);
-               /* set interrupts to first cpu in node */
+               nodep->irqmask |= 1ull << i;
+               if (irt == -2)          /* not a direct PIC irq */
+                       continue;
+
                nlm_pic_init_irt(nodep->picbase, irt, i,
-                                       node * NLM_CPUS_PER_NODE, 0);
-               irqmask |= (1ull << i);
+                               node * nlm_threads_per_node(), 0);
+               nlm_setup_pic_irq(node, i, i, irt);
        }
-       nodep->irqmask = irqmask;
 }
 
 void nlm_smp_irq_init(int hwcpuid)
 {
        int node, cpu;
 
-       node = hwcpuid / NLM_CPUS_PER_NODE;
-       cpu  = hwcpuid % NLM_CPUS_PER_NODE;
+       node = nlm_cpuid_to_node(hwcpuid);
+       cpu  = hwcpuid % nlm_threads_per_node();
 
        if (cpu == 0 && node != 0)
                nlm_init_node_irqs(node);
@@ -256,13 +257,23 @@ asmlinkage void plat_irq_dispatch(void)
                return;
        }
 
+#if defined(CONFIG_PCI_MSI) && defined(CONFIG_CPU_XLP)
+       /* PCI interrupts need a second level dispatch for MSI bits */
+       if (i >= PIC_PCIE_LINK_MSI_IRQ(0) && i <= PIC_PCIE_LINK_MSI_IRQ(3)) {
+               nlm_dispatch_msi(node, i);
+               return;
+       }
+       if (i >= PIC_PCIE_MSIX_IRQ(0) && i <= PIC_PCIE_MSIX_IRQ(3)) {
+               nlm_dispatch_msix(node, i);
+               return;
+       }
+
+#endif
        /* top level irq handling */
        do_IRQ(nlm_irq_to_xirq(node, i));
 }
 
 #ifdef CONFIG_OF
-static struct irq_domain *xlp_pic_domain;
-
 static const struct irq_domain_ops xlp_pic_irq_domain_ops = {
        .xlate = irq_domain_xlate_onetwocell,
 };
@@ -271,8 +282,9 @@ static int __init xlp_of_pic_init(struct device_node *node,
                                        struct device_node *parent)
 {
        const int n_picirqs = PIC_IRT_LAST_IRQ - PIC_IRQ_BASE + 1;
+       struct irq_domain *xlp_pic_domain;
        struct resource res;
-       int socid, ret;
+       int socid, ret, bus;
 
        /* we need a hack to get the PIC's SoC chip id */
        ret = of_address_to_resource(node, 0, &res);
@@ -280,7 +292,34 @@ static int __init xlp_of_pic_init(struct device_node *node,
                pr_err("PIC %s: reg property not found!\n", node->name);
                return -EINVAL;
        }
-       socid = (res.start >> 18) & 0x3;
+
+       if (cpu_is_xlp9xx()) {
+               bus = (res.start >> 20) & 0xf;
+               for (socid = 0; socid < NLM_NR_NODES; socid++) {
+                       if (!nlm_node_present(socid))
+                               continue;
+                       if (nlm_get_node(socid)->socbus == bus)
+                               break;
+               }
+               if (socid == NLM_NR_NODES) {
+                       pr_err("PIC %s: Node mapping for bus %d not found!\n",
+                                       node->name, bus);
+                       return -EINVAL;
+               }
+       } else {
+               socid = (res.start >> 18) & 0x3;
+               if (!nlm_node_present(socid)) {
+                       pr_err("PIC %s: node %d does not exist!\n",
+                                                       node->name, socid);
+                       return -EINVAL;
+               }
+       }
+
+       if (!nlm_node_present(socid)) {
+               pr_err("PIC %s: node %d does not exist!\n", node->name, socid);
+               return -EINVAL;
+       }
+
        xlp_pic_domain = irq_domain_add_legacy(node, n_picirqs,
                nlm_irq_to_xirq(socid, PIC_IRQ_BASE), PIC_IRQ_BASE,
                &xlp_pic_irq_domain_ops, NULL);
@@ -288,8 +327,7 @@ static int __init xlp_of_pic_init(struct device_node *node,
                pr_err("PIC %s: Creating legacy domain failed!\n", node->name);
                return -EINVAL;
        }
-       pr_info("Node %d: IRQ domain created for PIC@%pa\n", socid,
-                                                       &res.start);
+       pr_info("Node %d: IRQ domain created for PIC@%pR\n", socid, &res);
        return 0;
 }
 
index adb18288a6c0d5f3bc8cdb847518b580adbd1795..b231fe1e7a093c0e9a0296f428a18e51e47e4f20 100644 (file)
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <linux/init.h>
 
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
+#include <asm/cacheops.h>
 #include <asm/regdef.h>
 #include <asm/mipsregs.h>
 #include <asm/stackframe.h>
@@ -50,8 +50,8 @@
 #include <asm/netlogic/xlp-hal/cpucontrol.h>
 
 #define CP0_EBASE      $15
-#define SYS_CPU_COHERENT_BASE(node)    CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \
-                       XLP_IO_SYS_OFFSET(node) + XLP_IO_PCI_HDRSZ + \
+#define SYS_CPU_COHERENT_BASE  CKSEG1ADDR(XLP_DEFAULT_IO_BASE) + \
+                       XLP_IO_SYS_OFFSET(0) + XLP_IO_PCI_HDRSZ + \
                        SYS_CPU_NONCOHERENT_MODE * 4
 
 /* Enable XLP features and workarounds in the LSU */
 .endm
 
 /*
- * Low level flush for L1D cache on XLP, the normal cache ops does
- * not do the complete and correct cache flush.
+ * L1D cache has to be flushed before enabling threads in XLP.
+ * On XLP8xx/XLP3xx, we do a low level flush using processor control
+ * registers. On XLPII CPUs, usual cache instructions work.
  */
 .macro xlp_flush_l1_dcache
+       mfc0    t0, CP0_EBASE, 0
+       andi    t0, t0, 0xff00
+       slt     t1, t0, 0x1200
+       beqz    t1, 15f
+       nop
+
+       /* XLP8xx low level cache flush */
        li      t0, LSU_DEBUG_DATA0
        li      t1, LSU_DEBUG_ADDR
        li      t2, 0           /* index */
        li      t3, 0x1000      /* loop count */
-1:
+11:
        sll     v0, t2, 5
        mtcr    zero, t0
        ori     v1, v0, 0x3     /* way0 | write_enable | write_active */
        mtcr    v1, t1
-2:
+12:
        mfcr    v1, t1
        andi    v1, 0x1         /* wait for write_active == 0 */
-       bnez    v1, 2b
+       bnez    v1, 12b
        nop
        mtcr    zero, t0
        ori     v1, v0, 0x7     /* way1 | write_enable | write_active */
        mtcr    v1, t1
-3:
+13:
        mfcr    v1, t1
        andi    v1, 0x1         /* wait for write_active == 0 */
-       bnez    v1, 3b
+       bnez    v1, 13b
        nop
        addi    t2, 1
-       bne     t3, t2, 1b
+       bne     t3, t2, 11b
+       nop
+       b       17f
+       nop
+
+       /* XLPII CPUs, Invalidate all 64k of L1 D-cache */
+15:
+       li      t0, 0x80000000
+       li      t1, 0x80010000
+16:    cache   Index_Writeback_Inv_D, 0(t0)
+       addiu   t0, t0, 32
+       bne     t0, t1, 16b
        nop
+17:
 .endm
 
 /*
@@ -138,6 +158,13 @@ FEXPORT(nlm_reset_entry)
        nop
 
 1:     /* Entry point on core wakeup */
+       mfc0    t0, CP0_EBASE, 0        /* processor ID */
+       andi    t0, 0xff00
+       li      t1, 0x1500              /* XLP 9xx */
+       beq     t0, t1, 2f              /* does not need to set coherent */
+       nop
+
+       /* set bit in SYS coherent register for the core */
        mfc0    t0, CP0_EBASE, 1
        mfc0    t1, CP0_EBASE, 1
        srl     t1, 5
@@ -149,7 +176,7 @@ FEXPORT(nlm_reset_entry)
        li      t1, 0x1
        sll     t0, t1, t0
        nor     t0, t0, zero            /* t0 <- ~(1 << core) */
-       li      t2, SYS_CPU_COHERENT_BASE(0)
+       li      t2, SYS_CPU_COHERENT_BASE
        add     t2, t2, t3              /* t2 <- SYS offset for node */
        lw      t1, 0(t2)
        and     t1, t1, t0
@@ -159,13 +186,13 @@ FEXPORT(nlm_reset_entry)
        lw      t1, 0(t2)
        sync
 
+2:
        /* Configure LSU on Non-0 Cores. */
        xlp_config_lsu
        /* FALL THROUGH */
 
 /*
- * Wake up sibling threads from the initial thread in
- * a core.
+ * Wake up sibling threads from the initial thread in a core.
  */
 EXPORT(nlm_boot_siblings)
        /* core L1D flush before enable threads */
@@ -181,8 +208,10 @@ EXPORT(nlm_boot_siblings)
        /*
         * The new hardware thread starts at the next instruction
         * For all the cases other than core 0 thread 0, we will
-       * jump to the secondary wait function.
-       */
+        * jump to the secondary wait function.
+
+        * NOTE: All GPR contents are lost after the mtcr above!
+        */
        mfc0    v0, CP0_EBASE, 1
        andi    v0, 0x3ff               /* v0 <- node/core */
 
@@ -196,7 +225,7 @@ EXPORT(nlm_boot_siblings)
 #endif
        mtc0    t1, CP0_STATUS
 
-       /* mark CPU ready, careful here, previous mtcr trashed registers */
+       /* mark CPU ready */
        li      t3, CKSEG1ADDR(RESET_DATA_PHYS)
        ADDIU   t1, t3, BOOT_CPU_READY
        sll     v1, v0, 2
index c0eded01fde96ef23676eabc28e72ceb286467ad..6baae15cc7b182e8840e71d58b7a8e3669385ca4 100644 (file)
@@ -63,7 +63,7 @@ void nlm_send_ipi_single(int logical_cpu, unsigned int action)
        uint64_t picbase;
 
        cpu = cpu_logical_map(logical_cpu);
-       node = cpu / NLM_CPUS_PER_NODE;
+       node = nlm_cpuid_to_node(cpu);
        picbase = nlm_get_node(node)->picbase;
 
        if (action & SMP_CALL_FUNCTION)
@@ -152,7 +152,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle)
        int cpu, node;
 
        cpu = cpu_logical_map(logical_cpu);
-       node = cpu / NLM_CPUS_PER_NODE;
+       node = nlm_cpuid_to_node(logical_cpu);
        nlm_next_sp = (unsigned long)__KSTK_TOS(idle);
        nlm_next_gp = (unsigned long)task_thread_info(idle);
 
@@ -164,7 +164,7 @@ void nlm_boot_secondary(int logical_cpu, struct task_struct *idle)
 void __init nlm_smp_setup(void)
 {
        unsigned int boot_cpu;
-       int num_cpus, i, ncore;
+       int num_cpus, i, ncore, node;
        volatile u32 *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY);
        char buf[64];
 
@@ -187,6 +187,8 @@ void __init nlm_smp_setup(void)
                        __cpu_number_map[i] = num_cpus;
                        __cpu_logical_map[num_cpus] = i;
                        set_cpu_possible(num_cpus, true);
+                       node = nlm_cpuid_to_node(i);
+                       cpumask_set_cpu(num_cpus, &nlm_get_node(node)->cpumask);
                        ++num_cpus;
                }
        }
index aa6cff0a229b0c00d2421cdaffc624e47f2b6d8d..8597657c27fcc05d4f84e84b1616c8c412f942ee 100644 (file)
@@ -32,7 +32,6 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <linux/init.h>
 
 #include <asm/asm.h>
 #include <asm/asm-offsets.h>
@@ -98,7 +97,7 @@ END(nlm_boot_secondary_cpus)
  * In case of RMIboot bootloader which is used on XLR boards, the CPUs
  * be already woken up and waiting in bootloader code.
  * This will get them out of the bootloader code and into linux. Needed
- *  because the bootloader area will be taken and initialized by linux.
+ * because the bootloader area will be taken and initialized by linux.
  */
 NESTED(nlm_rmiboot_preboot, 16, sp)
        mfc0    t0, $15, 1      /* read ebase */
@@ -133,6 +132,7 @@ NESTED(nlm_rmiboot_preboot, 16, sp)
        or      t1, t2, v1      /* put in new value */
        mtcr    t1, t0          /* update core control */
 
+       /* wait for NMI to hit */
 1:     wait
        b       1b
        nop
index 0b9be5fd2e466e771ec51ec40a7f1ffeae0a8e47..25c8e873ee2577464f47f2475c1c26704341899f 100644 (file)
@@ -1,3 +1,4 @@
 obj-$(CONFIG_DT_XLP_EVP) := xlp_evp.dtb.o
 obj-$(CONFIG_DT_XLP_SVP) += xlp_svp.dtb.o
 obj-$(CONFIG_DT_XLP_FVP) += xlp_fvp.dtb.o
+obj-$(CONFIG_DT_XLP_GVP) += xlp_gvp.dtb.o
diff --git a/arch/mips/netlogic/dts/xlp_gvp.dts b/arch/mips/netlogic/dts/xlp_gvp.dts
new file mode 100644 (file)
index 0000000..047d27f
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * XLP9XX Device Tree Source for GVP boards
+ */
+
+/dts-v1/;
+/ {
+       model = "netlogic,XLP-GVP";
+       compatible = "netlogic,xlp";
+       #address-cells = <2>;
+       #size-cells = <2>;
+
+       soc {
+               #address-cells = <2>;
+               #size-cells = <1>;
+               compatible = "simple-bus";
+               ranges = <0 0  0 0x18000000  0x04000000   // PCIe CFG
+                         1 0  0 0x16000000  0x02000000>; // GBU chipselects
+
+               serial0: serial@30000 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0 0x112100 0xa00>;
+                       reg-shift = <2>;
+                       reg-io-width = <4>;
+                       clock-frequency = <125000000>;
+                       interrupt-parent = <&pic>;
+                       interrupts = <17>;
+               };
+               pic: pic@4000 {
+                       interrupt-controller;
+                       #address-cells = <0>;
+                       #interrupt-cells = <1>;
+                       reg = <0 0x110000 0x200>;
+               };
+
+               nor_flash@1,0 {
+                       compatible = "cfi-flash";
+                       #address-cells = <1>;
+                       #size-cells = <1>;
+                       bank-width = <2>;
+                       reg = <1 0 0x1000000>;
+
+                       partition@0 {
+                               label = "x-loader";
+                               reg = <0x0 0x100000>; /* 1M */
+                               read-only;
+                       };
+
+                       partition@100000 {
+                               label = "u-boot";
+                               reg = <0x100000 0x100000>; /* 1M */
+                       };
+
+                       partition@200000 {
+                               label = "kernel";
+                               reg = <0x200000 0x500000>; /* 5M */
+                       };
+
+                       partition@700000 {
+                               label = "rootfs";
+                               reg = <0x700000 0x800000>; /* 8M */
+                       };
+
+                       partition@f00000 {
+                               label = "env";
+                               reg = <0xf00000 0x100000>; /* 1M */
+                               read-only;
+                       };
+               };
+
+       };
+
+       chosen {
+               bootargs = "console=ttyS0,115200 rdinit=/sbin/init";
+       };
+};
index 8316d5454b1751d8f65e5f63a1017e198ce0bc31..5754097b9cde83d5a57ab86c67eda7ee0c35e528 100644 (file)
 #include <asm/prom.h>
 
 extern u32 __dtb_xlp_evp_begin[], __dtb_xlp_svp_begin[],
-       __dtb_xlp_fvp_begin[], __dtb_start[];
+       __dtb_xlp_fvp_begin[], __dtb_xlp_gvp_begin[], __dtb_start[];
 static void *xlp_fdt_blob;
 
 void __init *xlp_dt_init(void *fdtp)
 {
        if (!fdtp) {
                switch (current_cpu_data.processor_id & 0xff00) {
+#ifdef CONFIG_DT_XLP_GVP
+               case PRID_IMP_NETLOGIC_XLP9XX:
+                       fdtp = __dtb_xlp_gvp_begin;
+                       break;
+#endif
 #ifdef CONFIG_DT_XLP_FVP
                case PRID_IMP_NETLOGIC_XLP2XX:
                        fdtp = __dtb_xlp_fvp_begin;
index 56c50ba43c9b0bb74cc13e016e92477c6d95c6e3..997cd9ee10de663015e21aa84b88c75617c7b58a 100644 (file)
@@ -57,6 +57,10 @@ void nlm_node_init(int node)
        nodep->sysbase = nlm_get_sys_regbase(node);
        nodep->picbase = nlm_get_pic_regbase(node);
        nodep->ebase = read_c0_ebase() & (~((1 << 12) - 1));
+       if (cpu_is_xlp9xx())
+               nodep->socbus = xlp9xx_get_socbus(node);
+       else
+               nodep->socbus = 0;
        spin_lock_init(&nodep->piclock);
 }
 
@@ -65,6 +69,26 @@ int nlm_irq_to_irt(int irq)
        uint64_t pcibase;
        int devoff, irt;
 
+       /* bypass for 9xx */
+       if (cpu_is_xlp9xx()) {
+               switch (irq) {
+               case PIC_9XX_XHCI_0_IRQ:
+                       return 114;
+               case PIC_9XX_XHCI_1_IRQ:
+                       return 115;
+               case PIC_UART_0_IRQ:
+                       return 133;
+               case PIC_UART_1_IRQ:
+                       return 134;
+               case PIC_PCIE_LINK_LEGACY_IRQ(0):
+               case PIC_PCIE_LINK_LEGACY_IRQ(1):
+               case PIC_PCIE_LINK_LEGACY_IRQ(2):
+               case PIC_PCIE_LINK_LEGACY_IRQ(3):
+                       return 191 + irq - PIC_PCIE_LINK_LEGACY_IRQ_BASE;
+               }
+               return -1;
+       }
+
        devoff = 0;
        switch (irq) {
        case PIC_UART_0_IRQ:
@@ -135,9 +159,17 @@ int nlm_irq_to_irt(int irq)
                case PIC_I2C_3_IRQ:
                        irt = irt + 3; break;
                }
-       } else if (irq >= PIC_PCIE_LINK_0_IRQ && irq <= PIC_PCIE_LINK_3_IRQ) {
+       } else if (irq >= PIC_PCIE_LINK_LEGACY_IRQ(0) &&
+                       irq <= PIC_PCIE_LINK_LEGACY_IRQ(3)) {
                /* HW bug, PCI IRT entries are bad on early silicon, fix */
-               irt = PIC_IRT_PCIE_LINK_INDEX(irq - PIC_PCIE_LINK_0_IRQ);
+               irt = PIC_IRT_PCIE_LINK_INDEX(irq -
+                                       PIC_PCIE_LINK_LEGACY_IRQ_BASE);
+       } else if (irq >= PIC_PCIE_LINK_MSI_IRQ(0) &&
+                       irq <= PIC_PCIE_LINK_MSI_IRQ(3)) {
+               irt = -2;
+       } else if (irq >= PIC_PCIE_MSIX_IRQ(0) &&
+                       irq <= PIC_PCIE_MSIX_IRQ(3)) {
+               irt = -2;
        } else {
                irt = -1;
        }
@@ -151,7 +183,10 @@ unsigned int nlm_get_core_frequency(int node, int core)
        uint64_t num, sysbase;
 
        sysbase = nlm_get_node(node)->sysbase;
-       rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG);
+       if (cpu_is_xlp9xx())
+               rstval = nlm_read_sys_reg(sysbase, SYS_9XX_POWER_ON_RESET_CFG);
+       else
+               rstval = nlm_read_sys_reg(sysbase, SYS_POWER_ON_RESET_CFG);
        if (cpu_is_xlpii()) {
                num = 1000000ULL * (400 * 3 + 100 * (rstval >> 26));
                denom = 3;
@@ -265,6 +300,10 @@ static unsigned int nlm_2xx_get_pic_frequency(int node)
 
 unsigned int nlm_get_pic_frequency(int node)
 {
+       /* TODO Has to calculate freq as like 2xx */
+       if (cpu_is_xlp9xx())
+               return 250000000;
+
        if (cpu_is_xlpii())
                return nlm_2xx_get_pic_frequency(node);
        else
@@ -284,21 +323,33 @@ int xlp_get_dram_map(int n, uint64_t *dram_map)
 {
        uint64_t bridgebase, base, lim;
        uint32_t val;
+       unsigned int barreg, limreg, xlatreg;
        int i, node, rv;
 
        /* Look only at mapping on Node 0, we don't handle crazy configs */
        bridgebase = nlm_get_bridge_regbase(0);
        rv = 0;
        for (i = 0; i < 8; i++) {
-               val = nlm_read_bridge_reg(bridgebase,
-                                       BRIDGE_DRAM_NODE_TRANSLN(i));
-               node = (val >> 1) & 0x3;
-               if (n >= 0 && n != node)
-                       continue;
-               val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_BAR(i));
+               if (cpu_is_xlp9xx()) {
+                       barreg = BRIDGE_9XX_DRAM_BAR(i);
+                       limreg = BRIDGE_9XX_DRAM_LIMIT(i);
+                       xlatreg = BRIDGE_9XX_DRAM_NODE_TRANSLN(i);
+               } else {
+                       barreg = BRIDGE_DRAM_BAR(i);
+                       limreg = BRIDGE_DRAM_LIMIT(i);
+                       xlatreg = BRIDGE_DRAM_NODE_TRANSLN(i);
+               }
+               if (n >= 0) {
+                       /* node specified, get node mapping of BAR */
+                       val = nlm_read_bridge_reg(bridgebase, xlatreg);
+                       node = (val >> 1) & 0x3;
+                       if (n != node)
+                               continue;
+               }
+               val = nlm_read_bridge_reg(bridgebase, barreg);
                val = (val >>  12) & 0xfffff;
                base = (uint64_t) val << 20;
-               val = nlm_read_bridge_reg(bridgebase, BRIDGE_DRAM_LIMIT(i));
+               val = nlm_read_bridge_reg(bridgebase, limreg);
                val = (val >>  12) & 0xfffff;
                if (val == 0)   /* BAR not used */
                        continue;
index 54e75c77184b883fdbec601e1b2e97e49b1aa8c9..8c60a2dd9ef6bd5f2d86cd786b7c8c5e31627fe7 100644 (file)
@@ -51,12 +51,16 @@ uint64_t nlm_io_base;
 struct nlm_soc_info nlm_nodes[NLM_NR_NODES];
 cpumask_t nlm_cpumask = CPU_MASK_CPU0;
 unsigned int nlm_threads_per_core;
+unsigned int xlp_cores_per_node;
 
 static void nlm_linux_exit(void)
 {
        uint64_t sysbase = nlm_get_node(0)->sysbase;
 
-       nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1);
+       if (cpu_is_xlp9xx())
+               nlm_write_sys_reg(sysbase, SYS_9XX_CHIP_RESET, 1);
+       else
+               nlm_write_sys_reg(sysbase, SYS_CHIP_RESET, 1);
        for ( ; ; )
                cpu_wait();
 }
@@ -92,6 +96,14 @@ static void __init xlp_init_mem_from_bars(void)
 
 void __init plat_mem_setup(void)
 {
+#ifdef CONFIG_SMP
+       nlm_wakeup_secondary_cpus();
+
+       /* update TLB size after waking up threads */
+       current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1;
+
+       register_smp_ops(&nlm_smp_ops);
+#endif
        _machine_restart = (void (*)(char *))nlm_linux_exit;
        _machine_halt   = nlm_linux_exit;
        pm_power_off    = nlm_linux_exit;
@@ -110,6 +122,7 @@ void __init plat_mem_setup(void)
 const char *get_system_type(void)
 {
        switch (read_c0_prid() & 0xff00) {
+       case PRID_IMP_NETLOGIC_XLP9XX:
        case PRID_IMP_NETLOGIC_XLP2XX:
                return "Broadcom XLPII Series";
        default:
@@ -149,6 +162,10 @@ void __init prom_init(void)
        void *reset_vec;
 
        nlm_io_base = CKSEG1ADDR(XLP_DEFAULT_IO_BASE);
+       if (cpu_is_xlp9xx())
+               xlp_cores_per_node = 32;
+       else
+               xlp_cores_per_node = 8;
        nlm_init_boot_cpu();
        xlp_mmu_init();
        nlm_node_init(0);
@@ -162,11 +179,5 @@ void __init prom_init(void)
 
 #ifdef CONFIG_SMP
        cpumask_setall(&nlm_cpumask);
-       nlm_wakeup_secondary_cpus();
-
-       /* update TLB size after waking up threads */
-       current_cpu_data.tlbsize = ((read_c0_config6() >> 16) & 0xffff) + 1;
-
-       register_smp_ops(&nlm_smp_ops);
 #endif
 }
index 36e9c22afc467f39bfd2429a654d8bcce3ca8e7c..17ade1ce5dfd87f6692e5dbb44002f3fbca8c2d7 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/pci.h>
+#include <linux/pci_ids.h>
 #include <linux/platform_device.h>
 #include <linux/irq.h>
 
 #define nlm_read_usb_reg(b, r)         nlm_read_reg(b, r)
 #define nlm_write_usb_reg(b, r, v)     nlm_write_reg(b, r, v)
 
-#define nlm_xlpii_get_usb_pcibase(node, inst)          \
-       nlm_pcicfg_base(XLP2XX_IO_USB_OFFSET(node, inst))
+#define nlm_xlpii_get_usb_pcibase(node, inst)                  \
+                       nlm_pcicfg_base(cpu_is_xlp9xx() ?       \
+                       XLP9XX_IO_USB_OFFSET(node, inst) :      \
+                       XLP2XX_IO_USB_OFFSET(node, inst))
 #define nlm_xlpii_get_usb_regbase(node, inst)          \
        (nlm_xlpii_get_usb_pcibase(node, inst) + XLP_IO_PCI_HDRSZ)
 
-static void xlpii_usb_ack(struct irq_data *data)
+static void xlp2xx_usb_ack(struct irq_data *data)
 {
        u64 port_addr;
 
@@ -109,6 +112,29 @@ static void xlpii_usb_ack(struct irq_data *data)
        nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff);
 }
 
+static void xlp9xx_usb_ack(struct irq_data *data)
+{
+       u64 port_addr;
+       int node, irq;
+
+       /* Find the node and irq on the node */
+       irq = data->irq % NLM_IRQS_PER_NODE;
+       node = data->irq / NLM_IRQS_PER_NODE;
+
+       switch (irq) {
+       case PIC_9XX_XHCI_0_IRQ:
+               port_addr = nlm_xlpii_get_usb_regbase(node, 1);
+               break;
+       case PIC_9XX_XHCI_1_IRQ:
+               port_addr = nlm_xlpii_get_usb_regbase(node, 2);
+               break;
+       default:
+               pr_err("No matching USB irq %d node  %d!\n", irq, node);
+               return;
+       }
+       nlm_write_usb_reg(port_addr, XLPII_USB3_INT_REG, 0xffffffff);
+}
+
 static void nlm_xlpii_usb_hw_reset(int node, int port)
 {
        u64 port_addr, xhci_base, pci_base;
@@ -178,17 +204,33 @@ static void nlm_xlpii_usb_hw_reset(int node, int port)
 
 static int __init nlm_platform_xlpii_usb_init(void)
 {
+       int node;
+
        if (!cpu_is_xlpii())
                return 0;
 
-       pr_info("Initializing 2XX USB Interface\n");
-       nlm_xlpii_usb_hw_reset(0, 1);
-       nlm_xlpii_usb_hw_reset(0, 2);
-       nlm_xlpii_usb_hw_reset(0, 3);
-       nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_0_IRQ, xlpii_usb_ack);
-       nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_1_IRQ, xlpii_usb_ack);
-       nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_2_IRQ, xlpii_usb_ack);
+       if (!cpu_is_xlp9xx()) {
+               /* XLP 2XX single node */
+               pr_info("Initializing 2XX USB Interface\n");
+               nlm_xlpii_usb_hw_reset(0, 1);
+               nlm_xlpii_usb_hw_reset(0, 2);
+               nlm_xlpii_usb_hw_reset(0, 3);
+               nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_0_IRQ, xlp2xx_usb_ack);
+               nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_1_IRQ, xlp2xx_usb_ack);
+               nlm_set_pic_extra_ack(0, PIC_2XX_XHCI_2_IRQ, xlp2xx_usb_ack);
+               return 0;
+       }
 
+       /* XLP 9XX, multi-node */
+       pr_info("Initializing 9XX USB Interface\n");
+       for (node = 0; node < NLM_NR_NODES; node++) {
+               if (!nlm_node_present(node))
+                       continue;
+               nlm_xlpii_usb_hw_reset(node, 1);
+               nlm_xlpii_usb_hw_reset(node, 2);
+               nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_0_IRQ, xlp9xx_usb_ack);
+               nlm_set_pic_extra_ack(node, PIC_9XX_XHCI_1_IRQ, xlp9xx_usb_ack);
+       }
        return 0;
 }
 
@@ -196,8 +238,26 @@ arch_initcall(nlm_platform_xlpii_usb_init);
 
 static u64 xlp_usb_dmamask = ~(u32)0;
 
-/* Fixup IRQ for USB devices on XLP the SoC PCIe bus */
-static void nlm_usb_fixup_final(struct pci_dev *dev)
+/* Fixup the IRQ for USB devices which is exist on XLP9XX SOC PCIE bus */
+static void nlm_xlp9xx_usb_fixup_final(struct pci_dev *dev)
+{
+       int node;
+
+       node = xlp_socdev_to_node(dev);
+       dev->dev.dma_mask               = &xlp_usb_dmamask;
+       dev->dev.coherent_dma_mask      = DMA_BIT_MASK(32);
+       switch (dev->devfn) {
+       case 0x21:
+               dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_0_IRQ);
+               break;
+       case 0x22:
+               dev->irq = nlm_irq_to_xirq(node, PIC_9XX_XHCI_1_IRQ);
+               break;
+       }
+}
+
+/* Fixup the IRQ for USB devices which is exist on XLP2XX SOC PCIE bus */
+static void nlm_xlp2xx_usb_fixup_final(struct pci_dev *dev)
 {
        dev->dev.dma_mask               = &xlp_usb_dmamask;
        dev->dev.coherent_dma_mask      = DMA_BIT_MASK(32);
@@ -214,5 +274,7 @@ static void nlm_usb_fixup_final(struct pci_dev *dev)
        }
 }
 
+DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_XLP9XX_XHCI,
+               nlm_xlp9xx_usb_fixup_final);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_NETLOGIC, PCI_DEVICE_ID_NLM_XHCI,
-               nlm_usb_fixup_final);
+               nlm_xlp2xx_usb_fixup_final);
index 682d5638dc01cafcbf72ec5700e802a80116fe8f..9a92617a2af5920917f069b0f9e30b46a42d4471 100644 (file)
@@ -32,7 +32,6 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/threads.h>
 
 #include <asm/netlogic/mips-extns.h>
 
 #include <asm/netlogic/xlp-hal/iomap.h>
-#include <asm/netlogic/xlp-hal/pic.h>
 #include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pic.h>
 #include <asm/netlogic/xlp-hal/sys.h>
 
 static int xlp_wakeup_core(uint64_t sysbase, int node, int core)
 {
        uint32_t coremask, value;
-       int count;
+       int count, resetreg;
 
        coremask = (1 << core);
 
@@ -65,12 +64,24 @@ static int xlp_wakeup_core(uint64_t sysbase, int node, int core)
                nlm_write_sys_reg(sysbase, SYS_CORE_DFS_DIS_CTRL, value);
        }
 
+       /* On 9XX, mark coherent first */
+       if (cpu_is_xlp9xx()) {
+               value = nlm_read_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE);
+               value &= ~coremask;
+               nlm_write_sys_reg(sysbase, SYS_9XX_CPU_NONCOHERENT_MODE, value);
+       }
+
        /* Remove CPU Reset */
-       value = nlm_read_sys_reg(sysbase, SYS_CPU_RESET);
+       resetreg = cpu_is_xlp9xx() ? SYS_9XX_CPU_RESET : SYS_CPU_RESET;
+       value = nlm_read_sys_reg(sysbase, resetreg);
        value &= ~coremask;
-       nlm_write_sys_reg(sysbase, SYS_CPU_RESET, value);
+       nlm_write_sys_reg(sysbase, resetreg, value);
+
+       /* We are done on 9XX */
+       if (cpu_is_xlp9xx())
+               return 1;
 
-       /* Poll for CPU to mark itself coherent */
+       /* Poll for CPU to mark itself coherent on other type of XLP */
        count = 100000;
        do {
                value = nlm_read_sys_reg(sysbase, SYS_CPU_NONCOHERENT_MODE);
@@ -84,7 +95,7 @@ static int wait_for_cpus(int cpu, int bootcpu)
        volatile uint32_t *cpu_ready = nlm_get_boot_data(BOOT_CPU_READY);
        int i, count, notready;
 
-       count = 0x20000000;
+       count = 0x800000;
        do {
                notready = nlm_threads_per_core;
                for (i = 0; i < nlm_threads_per_core; i++)
@@ -98,27 +109,62 @@ static int wait_for_cpus(int cpu, int bootcpu)
 static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)
 {
        struct nlm_soc_info *nodep;
-       uint64_t syspcibase;
-       uint32_t syscoremask;
+       uint64_t syspcibase, fusebase;
+       uint32_t syscoremask, mask, fusemask;
        int core, n, cpu;
 
        for (n = 0; n < NLM_NR_NODES; n++) {
-               syspcibase = nlm_get_sys_pcibase(n);
-               if (nlm_read_reg(syspcibase, 0) == 0xffffffff)
-                       break;
+               if (n != 0) {
+                       /* check if node exists and is online */
+                       if (cpu_is_xlp9xx()) {
+                               int b = xlp9xx_get_socbus(n);
+                               pr_info("Node %d SoC PCI bus %d.\n", n, b);
+                               if (b == 0)
+                                       break;
+                       } else {
+                               syspcibase = nlm_get_sys_pcibase(n);
+                               if (nlm_read_reg(syspcibase, 0) == 0xffffffff)
+                                       break;
+                       }
+                       nlm_node_init(n);
+               }
 
                /* read cores in reset from SYS */
-               if (n != 0)
-                       nlm_node_init(n);
                nodep = nlm_get_node(n);
-               syscoremask = nlm_read_sys_reg(nodep->sysbase, SYS_CPU_RESET);
+
+               if (cpu_is_xlp9xx()) {
+                       fusebase = nlm_get_fuse_regbase(n);
+                       fusemask = nlm_read_reg(fusebase, FUSE_9XX_DEVCFG6);
+                       mask = 0xfffff;
+               } else {
+                       fusemask = nlm_read_sys_reg(nodep->sysbase,
+                                               SYS_EFUSE_DEVICE_CFG_STATUS0);
+                       switch (read_c0_prid() & 0xff00) {
+                       case PRID_IMP_NETLOGIC_XLP3XX:
+                               mask = 0xf;
+                               break;
+                       case PRID_IMP_NETLOGIC_XLP2XX:
+                               mask = 0x3;
+                               break;
+                       case PRID_IMP_NETLOGIC_XLP8XX:
+                       default:
+                               mask = 0xff;
+                               break;
+                       }
+               }
+
+               /*
+                * Fused out cores are set in the fusemask, and the remaining
+                * cores are renumbered to range 0 .. nactive-1
+                */
+               syscoremask = (1 << hweight32(~fusemask & mask)) - 1;
+
                /* The boot cpu */
-               if (n == 0) {
-                       syscoremask |= 1;
+               if (n == 0)
                        nodep->coremask = 1;
-               }
 
-               for (core = 0; core < NLM_CORES_PER_NODE; core++) {
+               pr_info("Node %d - SYS/FUSE coremask %x\n", n, syscoremask);
+               for (core = 0; core < nlm_cores_per_node(); core++) {
                        /* we will be on node 0 core 0 */
                        if (n == 0 && core == 0)
                                continue;
@@ -128,7 +174,7 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)
                                continue;
 
                        /* see if at least the first hw thread is enabled */
-                       cpu = (n * NLM_CORES_PER_NODE + core)
+                       cpu = (n * nlm_cores_per_node() + core)
                                                * NLM_THREADS_PER_CORE;
                        if (!cpumask_test_cpu(cpu, wakeup_mask))
                                continue;
@@ -141,7 +187,8 @@ static void xlp_enable_secondary_cores(const cpumask_t *wakeup_mask)
                        nodep->coremask |= 1u << core;
 
                        /* spin until the hw threads sets their ready */
-                       wait_for_cpus(cpu, 0);
+                       if (!wait_for_cpus(cpu, 0))
+                               pr_err("Node %d : timeout core %d\n", n, core);
                }
        }
 }
@@ -153,7 +200,8 @@ void xlp_wakeup_secondary_cpus()
         * first wakeup core 0 threads
         */
        xlp_boot_core0_siblings();
-       wait_for_cpus(0, 0);
+       if (!wait_for_cpus(0, 0))
+               pr_err("Node 0 : timeout core 0\n");
 
        /* now get other cores out of reset */
        xlp_enable_secondary_cores(&nlm_cpumask);
index 7b96a91f47731ac36f2b6246d831a95c575a763e..4785932af248de4dc4b7d83c563ab9d7d135edbd 100644 (file)
@@ -23,7 +23,7 @@
 #include <asm/netlogic/xlr/pic.h>
 #include <asm/netlogic/xlr/xlr.h>
 
-unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)
+static unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)
 {
        uint64_t uartbase;
        unsigned int value;
@@ -41,7 +41,7 @@ unsigned int nlm_xlr_uart_in(struct uart_port *p, int offset)
        return value;
 }
 
-void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
+static void nlm_xlr_uart_out(struct uart_port *p, int offset, int value)
 {
        uint64_t uartbase;
 
index 921be5f77797706279d61c1c79f897a206546d07..d118b9aa7647408035c64935b7b222d60b6c0cc8 100644 (file)
@@ -60,25 +60,6 @@ unsigned int  nlm_threads_per_core = 1;
 struct nlm_soc_info nlm_nodes[NLM_NR_NODES];
 cpumask_t nlm_cpumask = CPU_MASK_CPU0;
 
-static void __init nlm_early_serial_setup(void)
-{
-       struct uart_port s;
-       unsigned long uart_base;
-
-       uart_base = (unsigned long)nlm_mmio_base(NETLOGIC_IO_UART_0_OFFSET);
-       memset(&s, 0, sizeof(s));
-       s.flags         = ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST;
-       s.iotype        = UPIO_MEM32;
-       s.regshift      = 2;
-       s.irq           = PIC_UART_0_IRQ;
-       s.uartclk       = PIC_CLK_HZ;
-       s.serial_in     = nlm_xlr_uart_in;
-       s.serial_out    = nlm_xlr_uart_out;
-       s.mapbase       = uart_base;
-       s.membase       = (unsigned char __iomem *)uart_base;
-       early_serial_setup(&s);
-}
-
 static void nlm_linux_exit(void)
 {
        uint64_t gpiobase;
@@ -214,7 +195,6 @@ void __init prom_init(void)
        memcpy(reset_vec, (void *)nlm_reset_entry,
                        (nlm_reset_entry_end - nlm_reset_entry));
 
-       nlm_early_serial_setup();
        build_arcs_cmdline(argv);
        prom_add_memory();
 
index 9fb81fa6272a753b805952166dd5e8dc45cb93ee..d61cba1e9c659281369e3a943b95481b8a56f53e 100644 (file)
@@ -32,7 +32,6 @@
  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/threads.h>
 
@@ -70,7 +69,7 @@ int xlr_wakeup_secondary_cpus(void)
 
        /* Fill up the coremask early */
        nodep->coremask = 1;
-       for (i = 1; i < NLM_CORES_PER_NODE; i++) {
+       for (i = 1; i < nlm_cores_per_node(); i++) {
                for (j = 1000000; j > 0; j--) {
                        if (cpu_ready[i * NLM_THREADS_PER_CORE])
                                break;
index 4d1736fc19557b793fd707f2543500a043bf6488..2a86e38872a725a89e31f2a5ad1907eb84a3b854 100644 (file)
@@ -86,6 +86,8 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
        case CPU_34K:
        case CPU_1004K:
        case CPU_74K:
+       case CPU_INTERAPTIV:
+       case CPU_PROAPTIV:
        case CPU_LOONGSON1:
        case CPU_SB1:
        case CPU_SB1A:
index 3a2b6e9f25cfb95ab0f2f5ee1eeccf069bde8f22..4d94d75ec6f98f47351afd695202be986355ba24 100644 (file)
@@ -376,6 +376,14 @@ static int __init mipsxx_init(void)
                op_model_mipsxx_ops.cpu_type = "mips/74K";
                break;
 
+       case CPU_INTERAPTIV:
+               op_model_mipsxx_ops.cpu_type = "mips/interAptiv";
+               break;
+
+       case CPU_PROAPTIV:
+               op_model_mipsxx_ops.cpu_type = "mips/proAptiv";
+               break;
+
        case CPU_5KC:
                op_model_mipsxx_ops.cpu_type = "mips/5K";
                break;
index 719e4557e22e551288d6a84e877a831335b2cd91..137f2a6feb257a5e1164e40000c672adc98f695b 100644 (file)
@@ -60,4 +60,5 @@ obj-$(CONFIG_CPU_XLP)         += pci-xlp.o
 
 ifdef CONFIG_PCI_MSI
 obj-$(CONFIG_CAVIUM_OCTEON_SOC) += msi-octeon.o
+obj-$(CONFIG_CPU_XLP)          += msi-xlp.o
 endif
index df36e2327c54572cca76848547cbbbf030c554ac..7a0eda782e35cf8c51d894c1b832dd9692f41c15 100644 (file)
@@ -54,6 +54,7 @@ int pcibios_plat_dev_init(struct pci_dev *dev)
 static void malta_piix_func0_fixup(struct pci_dev *pdev)
 {
        unsigned char reg_val;
+       u32 reg_val32;
        /* PIIX PIRQC[A:D] irq mappings */
        static int piixirqmap[PIIX4_FUNC0_PIRQRC_IRQ_ROUTING_MAX] = {
                0,  0,  0,  3,
@@ -83,6 +84,16 @@ static void malta_piix_func0_fixup(struct pci_dev *pdev)
                pci_write_config_byte(pdev, PIIX4_FUNC0_TOM, reg_val |
                                PIIX4_FUNC0_TOM_TOP_OF_MEMORY_MASK);
        }
+
+       /* Mux SERIRQ to its pin */
+       pci_read_config_dword(pdev, PIIX4_FUNC0_GENCFG, &reg_val32);
+       pci_write_config_dword(pdev, PIIX4_FUNC0_GENCFG,
+                              reg_val32 | PIIX4_FUNC0_GENCFG_SERIRQ);
+
+       /* Enable SERIRQ */
+       pci_read_config_byte(pdev, PIIX4_FUNC0_SERIRQC, &reg_val);
+       reg_val |= PIIX4_FUNC0_SERIRQC_EN | PIIX4_FUNC0_SERIRQC_CONT;
+       pci_write_config_byte(pdev, PIIX4_FUNC0_SERIRQC, reg_val);
 }
 
 DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82371AB_0,
index d0f6ecbf35f7486c2435dc0375312b51929450b1..7fcafd5da7da65ec4e2e0d90e966d43eff318bd8 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 
 #include <asm/mach-rc32434/rc32434.h>
 #include <asm/mach-rc32434/irq.h>
index 1441becdcb6c1cf32cf19c728f1b58bf8859d31f..8feae9154bafb7d508d8aaa75a16a663c663c09a 100644 (file)
@@ -8,7 +8,6 @@
  *     2 of the License, or (at your option) any later version.
  */
 
-#include <linux/init.h>
 #include <linux/pci.h>
 
 /*
diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c
new file mode 100644 (file)
index 0000000..afd8405
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ * Copyright (c) 2003-2012 Broadcom Corporation
+ * All Rights Reserved
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the Broadcom
+ * license below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BROADCOM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL BROADCOM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <linux/types.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/msi.h>
+#include <linux/mm.h>
+#include <linux/irq.h>
+#include <linux/irqdesc.h>
+#include <linux/console.h>
+
+#include <asm/io.h>
+
+#include <asm/netlogic/interrupt.h>
+#include <asm/netlogic/haldefs.h>
+#include <asm/netlogic/common.h>
+#include <asm/netlogic/mips-extns.h>
+
+#include <asm/netlogic/xlp-hal/iomap.h>
+#include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pic.h>
+#include <asm/netlogic/xlp-hal/pcibus.h>
+#include <asm/netlogic/xlp-hal/bridge.h>
+
+#define XLP_MSIVEC_PER_LINK    32
+#define XLP_MSIXVEC_TOTAL      32
+#define XLP_MSIXVEC_PER_LINK   8
+
+/* 128 MSI irqs per node, mapped starting at NLM_MSI_VEC_BASE */
+static inline int nlm_link_msiirq(int link, int msivec)
+{
+       return NLM_MSI_VEC_BASE + link * XLP_MSIVEC_PER_LINK + msivec;
+}
+
+static inline int nlm_irq_msivec(int irq)
+{
+       return irq % XLP_MSIVEC_PER_LINK;
+}
+
+static inline int nlm_irq_msilink(int irq)
+{
+       return (irq % (XLP_MSIVEC_PER_LINK * PCIE_NLINKS)) /
+                                               XLP_MSIVEC_PER_LINK;
+}
+
+/*
+ * Only 32 MSI-X vectors are possible because there are only 32 PIC
+ * interrupts for MSI. We split them statically and use 8 MSI-X vectors
+ * per link - this keeps the allocation and lookup simple.
+ */
+static inline int nlm_link_msixirq(int link, int bit)
+{
+       return NLM_MSIX_VEC_BASE + link * XLP_MSIXVEC_PER_LINK + bit;
+}
+
+static inline int nlm_irq_msixvec(int irq)
+{
+       return irq % XLP_MSIXVEC_TOTAL;  /* works when given xirq */
+}
+
+static inline int nlm_irq_msixlink(int irq)
+{
+       return nlm_irq_msixvec(irq) / XLP_MSIXVEC_PER_LINK;
+}
+
+/*
+ * Per link MSI and MSI-X information, set as IRQ handler data for
+ * MSI and MSI-X interrupts.
+ */
+struct xlp_msi_data {
+       struct nlm_soc_info *node;
+       uint64_t        lnkbase;
+       uint32_t        msi_enabled_mask;
+       uint32_t        msi_alloc_mask;
+       uint32_t        msix_alloc_mask;
+       spinlock_t      msi_lock;
+};
+
+/*
+ * MSI Chip definitions
+ *
+ * On XLP, there is a PIC interrupt associated with each PCIe link on the
+ * chip (which appears as a PCI bridge to us). This gives us 32 MSI irqa
+ * per link and 128 overall.
+ *
+ * When a device connected to the link raises a MSI interrupt, we get a
+ * link interrupt and we then have to look at PCIE_MSI_STATUS register at
+ * the bridge to map it to the IRQ
+ */
+static void xlp_msi_enable(struct irq_data *d)
+{
+       struct xlp_msi_data *md = irq_data_get_irq_handler_data(d);
+       unsigned long flags;
+       int vec;
+
+       vec = nlm_irq_msivec(d->irq);
+       spin_lock_irqsave(&md->msi_lock, flags);
+       md->msi_enabled_mask |= 1u << vec;
+       nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask);
+       spin_unlock_irqrestore(&md->msi_lock, flags);
+}
+
+static void xlp_msi_disable(struct irq_data *d)
+{
+       struct xlp_msi_data *md = irq_data_get_irq_handler_data(d);
+       unsigned long flags;
+       int vec;
+
+       vec = nlm_irq_msivec(d->irq);
+       spin_lock_irqsave(&md->msi_lock, flags);
+       md->msi_enabled_mask &= ~(1u << vec);
+       nlm_write_reg(md->lnkbase, PCIE_MSI_EN, md->msi_enabled_mask);
+       spin_unlock_irqrestore(&md->msi_lock, flags);
+}
+
+static void xlp_msi_mask_ack(struct irq_data *d)
+{
+       struct xlp_msi_data *md = irq_data_get_irq_handler_data(d);
+       int link, vec;
+
+       link = nlm_irq_msilink(d->irq);
+       vec = nlm_irq_msivec(d->irq);
+       xlp_msi_disable(d);
+
+       /* Ack MSI on bridge */
+       nlm_write_reg(md->lnkbase, PCIE_MSI_STATUS, 1u << vec);
+
+       /* Ack at eirr and PIC */
+       ack_c0_eirr(PIC_PCIE_LINK_MSI_IRQ(link));
+       nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_LINK_INDEX(link));
+}
+
+static struct irq_chip xlp_msi_chip = {
+       .name           = "XLP-MSI",
+       .irq_enable     = xlp_msi_enable,
+       .irq_disable    = xlp_msi_disable,
+       .irq_mask_ack   = xlp_msi_mask_ack,
+       .irq_unmask     = xlp_msi_enable,
+};
+
+/*
+ * The MSI-X interrupt handling is different from MSI, there are 32
+ * MSI-X interrupts generated by the PIC and each of these correspond
+ * to a MSI-X vector (0-31) that can be assigned.
+ *
+ * We divide the MSI-X vectors to 8 per link and do a per-link
+ * allocation
+ *
+ * Enable and disable done using standard MSI functions.
+ */
+static void xlp_msix_mask_ack(struct irq_data *d)
+{
+       struct xlp_msi_data *md = irq_data_get_irq_handler_data(d);
+       int link, msixvec;
+
+       msixvec = nlm_irq_msixvec(d->irq);
+       link = nlm_irq_msixlink(d->irq);
+       mask_msi_irq(d);
+
+       /* Ack MSI on bridge */
+       nlm_write_reg(md->lnkbase, PCIE_MSIX_STATUS, 1u << msixvec);
+
+       /* Ack at eirr and PIC */
+       ack_c0_eirr(PIC_PCIE_MSIX_IRQ(link));
+       nlm_pic_ack(md->node->picbase, PIC_IRT_PCIE_MSIX_INDEX(msixvec));
+}
+
+static struct irq_chip xlp_msix_chip = {
+       .name           = "XLP-MSIX",
+       .irq_enable     = unmask_msi_irq,
+       .irq_disable    = mask_msi_irq,
+       .irq_mask_ack   = xlp_msix_mask_ack,
+       .irq_unmask     = unmask_msi_irq,
+};
+
+void destroy_irq(unsigned int irq)
+{
+           /* nothing to do yet */
+}
+
+void arch_teardown_msi_irq(unsigned int irq)
+{
+       destroy_irq(irq);
+}
+
+/*
+ * Setup a PCIe link for MSI.  By default, the links are in
+ * legacy interrupt mode.  We will switch them to MSI mode
+ * at the first MSI request.
+ */
+static void xlp_config_link_msi(uint64_t lnkbase, int lirq, uint64_t msiaddr)
+{
+       u32 val;
+
+       val = nlm_read_reg(lnkbase, PCIE_INT_EN0);
+       if ((val & 0x200) == 0) {
+               val |= 0x200;           /* MSI Interrupt enable */
+               nlm_write_reg(lnkbase, PCIE_INT_EN0, val);
+       }
+
+       val = nlm_read_reg(lnkbase, 0x1);       /* CMD */
+       if ((val & 0x0400) == 0) {
+               val |= 0x0400;
+               nlm_write_reg(lnkbase, 0x1, val);
+       }
+
+       /* Update IRQ in the PCI irq reg */
+       val = nlm_read_pci_reg(lnkbase, 0xf);
+       val &= ~0x1fu;
+       val |= (1 << 8) | lirq;
+       nlm_write_pci_reg(lnkbase, 0xf, val);
+
+       /* MSI addr */
+       nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRH, msiaddr >> 32);
+       nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_ADDRL, msiaddr & 0xffffffff);
+
+       /* MSI cap for bridge */
+       val = nlm_read_reg(lnkbase, PCIE_BRIDGE_MSI_CAP);
+       if ((val & (1 << 16)) == 0) {
+               val |= 0xb << 16;               /* mmc32, msi enable */
+               nlm_write_reg(lnkbase, PCIE_BRIDGE_MSI_CAP, val);
+       }
+}
+
+/*
+ * Allocate a MSI vector on a link
+ */
+static int xlp_setup_msi(uint64_t lnkbase, int node, int link,
+       struct msi_desc *desc)
+{
+       struct xlp_msi_data *md;
+       struct msi_msg msg;
+       unsigned long flags;
+       int msivec, irt, lirq, xirq, ret;
+       uint64_t msiaddr;
+
+       /* Get MSI data for the link */
+       lirq = PIC_PCIE_LINK_MSI_IRQ(link);
+       xirq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0));
+       md = irq_get_handler_data(xirq);
+       msiaddr = MSI_LINK_ADDR(node, link);
+
+       spin_lock_irqsave(&md->msi_lock, flags);
+       if (md->msi_alloc_mask == 0) {
+               /* switch the link IRQ to MSI range */
+               xlp_config_link_msi(lnkbase, lirq, msiaddr);
+               irt = PIC_IRT_PCIE_LINK_INDEX(link);
+               nlm_setup_pic_irq(node, lirq, lirq, irt);
+               nlm_pic_init_irt(nlm_get_node(node)->picbase, irt, lirq,
+                                node * nlm_threads_per_node(), 1 /*en */);
+       }
+
+       /* allocate a MSI vec, and tell the bridge about it */
+       msivec = fls(md->msi_alloc_mask);
+       if (msivec == XLP_MSIVEC_PER_LINK) {
+               spin_unlock_irqrestore(&md->msi_lock, flags);
+               return -ENOMEM;
+       }
+       md->msi_alloc_mask |= (1u << msivec);
+       spin_unlock_irqrestore(&md->msi_lock, flags);
+
+       msg.address_hi = msiaddr >> 32;
+       msg.address_lo = msiaddr & 0xffffffff;
+       msg.data = 0xc00 | msivec;
+
+       xirq = xirq + msivec;           /* msi mapped to global irq space */
+       ret = irq_set_msi_desc(xirq, desc);
+       if (ret < 0) {
+               destroy_irq(xirq);
+               return ret;
+       }
+
+       write_msi_msg(xirq, &msg);
+       return 0;
+}
+
+/*
+ * Switch a link to MSI-X mode
+ */
+static void xlp_config_link_msix(uint64_t lnkbase, int lirq, uint64_t msixaddr)
+{
+       u32 val;
+
+       val = nlm_read_reg(lnkbase, 0x2C);
+       if ((val & 0x80000000U) == 0) {
+               val |= 0x80000000U;
+               nlm_write_reg(lnkbase, 0x2C, val);
+       }
+       val = nlm_read_reg(lnkbase, PCIE_INT_EN0);
+       if ((val & 0x200) == 0) {
+               val |= 0x200;           /* MSI Interrupt enable */
+               nlm_write_reg(lnkbase, PCIE_INT_EN0, val);
+       }
+
+       val = nlm_read_reg(lnkbase, 0x1);       /* CMD */
+       if ((val & 0x0400) == 0) {
+               val |= 0x0400;
+               nlm_write_reg(lnkbase, 0x1, val);
+       }
+
+       /* Update IRQ in the PCI irq reg */
+       val = nlm_read_pci_reg(lnkbase, 0xf);
+       val &= ~0x1fu;
+       val |= (1 << 8) | lirq;
+       nlm_write_pci_reg(lnkbase, 0xf, val);
+
+       /* MSI-X addresses */
+       nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_BASE, msixaddr >> 8);
+       nlm_write_reg(lnkbase, PCIE_BRIDGE_MSIX_ADDR_LIMIT,
+                                       (msixaddr + MSI_ADDR_SZ) >> 8);
+}
+
+/*
+ *  Allocate a MSI-X vector
+ */
+static int xlp_setup_msix(uint64_t lnkbase, int node, int link,
+       struct msi_desc *desc)
+{
+       struct xlp_msi_data *md;
+       struct msi_msg msg;
+       unsigned long flags;
+       int t, msixvec, lirq, xirq, ret;
+       uint64_t msixaddr;
+
+       /* Get MSI data for the link */
+       lirq = PIC_PCIE_MSIX_IRQ(link);
+       xirq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0));
+       md = irq_get_handler_data(xirq);
+       msixaddr = MSIX_LINK_ADDR(node, link);
+
+       spin_lock_irqsave(&md->msi_lock, flags);
+       /* switch the PCIe link to MSI-X mode at the first alloc */
+       if (md->msix_alloc_mask == 0)
+               xlp_config_link_msix(lnkbase, lirq, msixaddr);
+
+       /* allocate a MSI-X vec, and tell the bridge about it */
+       t = fls(md->msix_alloc_mask);
+       if (t == XLP_MSIXVEC_PER_LINK) {
+               spin_unlock_irqrestore(&md->msi_lock, flags);
+               return -ENOMEM;
+       }
+       md->msix_alloc_mask |= (1u << t);
+       spin_unlock_irqrestore(&md->msi_lock, flags);
+
+       xirq += t;
+       msixvec = nlm_irq_msixvec(xirq);
+       msg.address_hi = msixaddr >> 32;
+       msg.address_lo = msixaddr & 0xffffffff;
+       msg.data = 0xc00 | msixvec;
+
+       ret = irq_set_msi_desc(xirq, desc);
+       if (ret < 0) {
+               destroy_irq(xirq);
+               return ret;
+       }
+
+       write_msi_msg(xirq, &msg);
+       return 0;
+}
+
+int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
+{
+       struct pci_dev *lnkdev;
+       uint64_t lnkbase;
+       int node, link, slot;
+
+       lnkdev = xlp_get_pcie_link(dev);
+       if (lnkdev == NULL) {
+               dev_err(&dev->dev, "Could not find bridge\n");
+               return 1;
+       }
+       slot = PCI_SLOT(lnkdev->devfn);
+       link = PCI_FUNC(lnkdev->devfn);
+       node = slot / 8;
+       lnkbase = nlm_get_pcie_base(node, link);
+
+       if (desc->msi_attrib.is_msix)
+               return xlp_setup_msix(lnkbase, node, link, desc);
+       else
+               return xlp_setup_msi(lnkbase, node, link, desc);
+}
+
+void __init xlp_init_node_msi_irqs(int node, int link)
+{
+       struct nlm_soc_info *nodep;
+       struct xlp_msi_data *md;
+       int irq, i, irt, msixvec;
+
+       pr_info("[%d %d] Init node PCI IRT\n", node, link);
+       nodep = nlm_get_node(node);
+
+       /* Alloc an MSI block for the link */
+       md = kzalloc(sizeof(*md), GFP_KERNEL);
+       spin_lock_init(&md->msi_lock);
+       md->msi_enabled_mask = 0;
+       md->msi_alloc_mask = 0;
+       md->msix_alloc_mask = 0;
+       md->node = nodep;
+       md->lnkbase = nlm_get_pcie_base(node, link);
+
+       /* extended space for MSI interrupts */
+       irq = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0));
+       for (i = irq; i < irq + XLP_MSIVEC_PER_LINK; i++) {
+               irq_set_chip_and_handler(i, &xlp_msi_chip, handle_level_irq);
+               irq_set_handler_data(i, md);
+       }
+
+       for (i = 0; i < XLP_MSIXVEC_PER_LINK; i++) {
+               /* Initialize MSI-X irts to generate one interrupt per link */
+               msixvec = link * XLP_MSIXVEC_PER_LINK + i;
+               irt = PIC_IRT_PCIE_MSIX_INDEX(msixvec);
+               nlm_pic_init_irt(nodep->picbase, irt, PIC_PCIE_MSIX_IRQ(link),
+                       node * nlm_threads_per_node(), 1 /* enable */);
+
+               /* Initialize MSI-X extended irq space for the link  */
+               irq = nlm_irq_to_xirq(node, nlm_link_msixirq(link, i));
+               irq_set_chip_and_handler(irq, &xlp_msix_chip, handle_level_irq);
+               irq_set_handler_data(irq, md);
+       }
+
+}
+
+void nlm_dispatch_msi(int node, int lirq)
+{
+       struct xlp_msi_data *md;
+       int link, i, irqbase;
+       u32 status;
+
+       link = lirq - PIC_PCIE_LINK_MSI_IRQ_BASE;
+       irqbase = nlm_irq_to_xirq(node, nlm_link_msiirq(link, 0));
+       md = irq_get_handler_data(irqbase);
+       status = nlm_read_reg(md->lnkbase, PCIE_MSI_STATUS) &
+                                               md->msi_enabled_mask;
+       while (status) {
+               i = __ffs(status);
+               do_IRQ(irqbase + i);
+               status &= status - 1;
+       }
+}
+
+void nlm_dispatch_msix(int node, int lirq)
+{
+       struct xlp_msi_data *md;
+       int link, i, irqbase;
+       u32 status;
+
+       link = lirq - PIC_PCIE_MSIX_IRQ_BASE;
+       irqbase = nlm_irq_to_xirq(node, nlm_link_msixirq(link, 0));
+       md = irq_get_handler_data(irqbase);
+       status = nlm_read_reg(md->lnkbase, PCIE_MSIX_STATUS);
+
+       /* narrow it down to the MSI-x vectors for our link */
+       status = (status >> (link * XLP_MSIXVEC_PER_LINK)) &
+                       ((1 << XLP_MSIXVEC_PER_LINK) - 1);
+
+       while (status) {
+               i = __ffs(status);
+               do_IRQ(irqbase + i);
+               status &= status - 1;
+       }
+}
index 6144bb337e4466929b0cf9519fbb18c6383f5124..13eea696bbe718b3b31be72dfdb5a706beaf6d83 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 
index 830352e3aeda71174ade994531e51f48a03e0781..c06205a87348d093881867747277bcdbf5149a03 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 
 #include <asm/mips-boards/bonito64.h>
 
index 16e7c2526d7756fd0a47380724d0fd112f44b904..e5738ee26f4f1e21303d932f58f0b2d1bb4dd741 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
 #include <asm/addrspace.h>
index 98254afa0287f6bfcfb0a3bddece6b670a4db5f5..24138bb0cbe150815a284849e213e3729d56ab18 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/export.h>
 
 #include <loongson.h>
index 1cfb5588699fb6764f0793db6f47512167943430..6b5821febc38fbd3abcf787e35748db7a709ebf3 100644 (file)
@@ -6,7 +6,6 @@
  * Copyright (C) 2000, 2001 Keith M Wesolowski
  */
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/types.h>
 #include <asm/pci.h>
index 92a8543361bb867a3d932ddedcbcf2a1d0fc8eba..dbbf3657896c58ae1a034d6da6e6d593a626afc6 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/types.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 
 #include <asm/mips-boards/msc01_pci.h>
 
index 499e35c3eb3575337f9826700ab4b83fc8ad042b..a1a7c9f4096e3fddb45ddd73dc06d1eadbc38bfb 100644 (file)
@@ -1,5 +1,4 @@
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <asm/bootinfo.h>
 
index 7c7182e2350a362371658eaeb20ff6229c2d12bf..874ed6df97683ad1d6dbce7b49c72c091e64488c 100644 (file)
@@ -26,7 +26,6 @@
  *  675 Mass Ave, Cambridge, MA 02139, USA.
  */
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/pci.h>
 #include <linux/types.h>
index 162b4cb29dbaa32d0e09edfd2615abe2f0f4f815..0f09eafa5e3abb068bd920676f6971ce1bf2578b 100644 (file)
@@ -7,7 +7,6 @@
  * Copyright (C) 1999, 2000, 04 Ralf Baechle (ralf@linux-mips.org)
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/export.h>
 #include <linux/pci.h>
index 37134ddfeaa5d43b26ac482e251523a42e404741..f1a73890dd4f104b87f3165ce1796d1be7bda92a 100644 (file)
@@ -241,9 +241,9 @@ void __init mips_pcibios_init(void)
                return;
        }
 
-       /* Change start address to avoid conflicts with ACPI and SMB devices */
-       if (controller->io_resource->start < 0x00002000UL)
-               controller->io_resource->start = 0x00002000UL;
+       /* PIIX4 ACPI starts at 0x1000 */
+       if (controller->io_resource->start < 0x00001000UL)
+               controller->io_resource->start = 0x00001000UL;
 
        iomem_resource.end &= 0xfffffffffULL;                   /* 64 GB */
        ioport_resource.end = controller->io_resource->end;
index adeff2bfe4cdd35ecd00419c4e8fd1338f2b4d51..72919aeef42b314d90c9ec451b149a508a4866a1 100644 (file)
@@ -436,9 +436,6 @@ static int rt3883_pci_probe(struct platform_device *pdev)
                return -ENOMEM;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -EINVAL;
-
        rpc->base = devm_ioremap_resource(dev, res);
        if (IS_ERR(rpc->base))
                return PTR_ERR(rpc->base);
index 653d2db9e0c5187d516cf73e2e6268b375e481fd..7babf01600cb0fd9cbb97d4bb40f079693b2e8ed 100644 (file)
 #include <asm/netlogic/interrupt.h>
 #include <asm/netlogic/haldefs.h>
 #include <asm/netlogic/common.h>
+#include <asm/netlogic/mips-extns.h>
 
 #include <asm/netlogic/xlp-hal/iomap.h>
-#include <asm/netlogic/xlp-hal/pic.h>
 #include <asm/netlogic/xlp-hal/xlp.h>
+#include <asm/netlogic/xlp-hal/pic.h>
 #include <asm/netlogic/xlp-hal/pcibus.h>
 #include <asm/netlogic/xlp-hal/bridge.h>
 
@@ -66,9 +67,22 @@ static inline u32 pci_cfg_read_32bit(struct pci_bus *bus, unsigned int devfn,
        u32 *cfgaddr;
 
        where &= ~3;
-       if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954)
+       if (cpu_is_xlp9xx()) {
+               /* be very careful on SoC buses */
+               if (bus->number == 0) {
+                       /* Scan only existing nodes - uboot bug? */
+                       if (PCI_SLOT(devfn) != 0 ||
+                                          !nlm_node_present(PCI_FUNC(devfn)))
+                               return 0xffffffff;
+               } else if (bus->parent->number == 0) {  /* SoC bus */
+                       if (PCI_SLOT(devfn) == 0)       /* b.0.0 hangs */
+                               return 0xffffffff;
+                       if (devfn == 44)                /* b.5.4 hangs */
+                               return 0xffffffff;
+               }
+       } else if (bus->number == 0 && PCI_SLOT(devfn) == 1 && where == 0x954) {
                return 0xffffffff;
-
+       }
        cfgaddr = (u32 *)(pci_config_base +
                        pci_cfg_addr(bus->number, devfn, where));
        data = *cfgaddr;
@@ -162,27 +176,39 @@ struct pci_controller nlm_pci_controller = {
        .io_offset      = 0x00000000UL,
 };
 
-static struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)
+struct pci_dev *xlp_get_pcie_link(const struct pci_dev *dev)
 {
        struct pci_bus *bus, *p;
 
-       /* Find the bridge on bus 0 */
        bus = dev->bus;
-       for (p = bus->parent; p && p->number != 0; p = p->parent)
-               bus = p;
 
-       return p ? bus->self : NULL;
+       if (cpu_is_xlp9xx()) {
+               /* find bus with grand parent number == 0 */
+               for (p = bus->parent; p && p->parent && p->parent->number != 0;
+                               p = p->parent)
+                       bus = p;
+               return (p && p->parent) ? bus->self : NULL;
+       } else {
+               /* Find the bridge on bus 0 */
+               for (p = bus->parent; p && p->number != 0; p = p->parent)
+                       bus = p;
+
+               return p ? bus->self : NULL;
+       }
 }
 
-static inline int nlm_pci_link_to_irq(int link)
+int xlp_socdev_to_node(const struct pci_dev *lnkdev)
 {
-       return PIC_PCIE_LINK_0_IRQ + link;
+       if (cpu_is_xlp9xx())
+               return PCI_FUNC(lnkdev->bus->self->devfn);
+       else
+               return PCI_SLOT(lnkdev->devfn) / 8;
 }
 
 int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
 {
        struct pci_dev *lnkdev;
-       int lnkslot, lnkfunc;
+       int lnkfunc, node;
 
        /*
         * For XLP PCIe, there is an IRQ per Link, find out which
@@ -191,9 +217,11 @@ int __init pcibios_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
        lnkdev = xlp_get_pcie_link(dev);
        if (lnkdev == NULL)
                return 0;
+
        lnkfunc = PCI_FUNC(lnkdev->devfn);
-       lnkslot = PCI_SLOT(lnkdev->devfn);
-       return nlm_irq_to_xirq(lnkslot / 8, nlm_pci_link_to_irq(lnkfunc));
+       node = xlp_socdev_to_node(lnkdev);
+
+       return nlm_irq_to_xirq(node, PIC_PCIE_LINK_LEGACY_IRQ(lnkfunc));
 }
 
 /* Do platform specific device initialization at pci_enable_device() time */
@@ -220,17 +248,38 @@ static void xlp_config_pci_bswap(int node, int link)
         *  Enable byte swap in hardware. Program each link's PCIe SWAP regions
         * from the link's address ranges.
         */
-       reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link);
-       nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg);
-
-       reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_LIMIT0 + link);
-       nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff);
-
-       reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link);
-       nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg);
-
-       reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link);
-       nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
+       if (cpu_is_xlp9xx()) {
+               reg = nlm_read_bridge_reg(nbubase,
+                               BRIDGE_9XX_PCIEMEM_BASE0 + link);
+               nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_MEM_BASE, reg);
+
+               reg = nlm_read_bridge_reg(nbubase,
+                               BRIDGE_9XX_PCIEMEM_LIMIT0 + link);
+               nlm_write_pci_reg(lnkbase,
+                               PCIE_9XX_BYTE_SWAP_MEM_LIM, reg | 0xfff);
+
+               reg = nlm_read_bridge_reg(nbubase,
+                               BRIDGE_9XX_PCIEIO_BASE0 + link);
+               nlm_write_pci_reg(lnkbase, PCIE_9XX_BYTE_SWAP_IO_BASE, reg);
+
+               reg = nlm_read_bridge_reg(nbubase,
+                               BRIDGE_9XX_PCIEIO_LIMIT0 + link);
+               nlm_write_pci_reg(lnkbase,
+                               PCIE_9XX_BYTE_SWAP_IO_LIM, reg | 0xfff);
+       } else {
+               reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEMEM_BASE0 + link);
+               nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_BASE, reg);
+
+               reg = nlm_read_bridge_reg(nbubase,
+                                       BRIDGE_PCIEMEM_LIMIT0 + link);
+               nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_MEM_LIM, reg | 0xfff);
+
+               reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_BASE0 + link);
+               nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_BASE, reg);
+
+               reg = nlm_read_bridge_reg(nbubase, BRIDGE_PCIEIO_LIMIT0 + link);
+               nlm_write_pci_reg(lnkbase, PCIE_BYTE_SWAP_IO_LIM, reg | 0xfff);
+       }
 }
 #else
 /* Swap configuration not needed in little-endian mode */
@@ -239,7 +288,6 @@ static inline void xlp_config_pci_bswap(int node, int link) {}
 
 static int __init pcibios_init(void)
 {
-       struct nlm_soc_info *nodep;
        uint64_t pciebase;
        int link, n;
        u32 reg;
@@ -253,20 +301,20 @@ static int __init pcibios_init(void)
        ioport_resource.end   = ~0;
 
        for (n = 0; n < NLM_NR_NODES; n++) {
-               nodep = nlm_get_node(n);
-               if (!nodep->coremask)
-                       continue;       /* node does not exist */
+               if (!nlm_node_present(n))
+                       continue;
 
-               for (link = 0; link < 4; link++) {
+               for (link = 0; link < PCIE_NLINKS; link++) {
                        pciebase = nlm_get_pcie_base(n, link);
                        if (nlm_read_pci_reg(pciebase, 0) == 0xffffffff)
                                continue;
                        xlp_config_pci_bswap(n, link);
+                       xlp_init_node_msi_irqs(n, link);
 
                        /* put in intpin and irq - u-boot does not */
                        reg = nlm_read_pci_reg(pciebase, 0xf);
-                       reg &= ~0x1fu;
-                       reg |= (1 << 8) | nlm_pci_link_to_irq(link);
+                       reg &= ~0x1ffu;
+                       reg |= (1 << 8) | PIC_PCIE_LINK_LEGACY_IRQ(link);
                        nlm_write_pci_reg(pciebase, 0xf, reg);
                        pr_info("XLP PCIe: Link %d-%d initialized.\n", n, link);
                }
index 3482b8c8640cfa5f5c7dcd8ef7255ad60e240bcd..6073ca456d110cace96281adf4337f5104c5d22c 100644 (file)
@@ -6,6 +6,7 @@ config PMC_MSP4200_EVAL
        bool "PMC-Sierra MSP4200 Eval Board"
        select IRQ_MSP_SLP
        select HW_HAS_PCI
+       select MIPS_L1_CACHE_SHIFT_4
 
 config PMC_MSP4200_GW
        bool "PMC-Sierra MSP4200 VoIP Gateway"
index 424f03496d14ad6de256329d967083990faf98ca..1bfd1c17b3c22377231466f4402707ab0515b6af 100644 (file)
@@ -15,6 +15,7 @@ choice
 
        config SOC_RT288X
                bool "RT288x"
+               select MIPS_L1_CACHE_SHIFT_4
 
        config SOC_RT305X
                bool "RT305x"
index b952d5b1af862afed1d9fc8006d3f1e9a7ed59d6..45fdfbcbd4c612149353db396eb648860df0a5ef 100644 (file)
@@ -5,7 +5,6 @@
  *
  * Copyright (C) 2001, 2002 Ralf Baechle
  */
-#include <linux/init.h>
 
 #include <asm/page.h>
 #include <asm/sn/addrs.h>
index ec22ec5600f3bfa037fd8c0c299711d7eb1038ba..2a1c40784bd9e3441f970cafe5a534a85271e3d7 100644 (file)
@@ -8,7 +8,6 @@
 
 #undef DEBUG
 
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/errno.h>
 #include <linux/signal.h>
index 7afe14688003a237372bd005f1b9353e688c6a92..c873d62ff083559e53ee038307ff6c8edbe23c96 100644 (file)
@@ -2,7 +2,6 @@
  * Copyright (C) 1999, 2000 Ralf Baechle (ralf@gnu.org)
  * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
  */
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
 #include <linux/interrupt.h>
index d59b820f528d1b5bc5042555a1ede083a0814430..20f582a2137a3fea18c278f79e55ffb7f7e47bfe 100644 (file)
@@ -7,7 +7,6 @@
  * Generic XTALK initialization code
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/smp.h>
 #include <asm/sn/types.h>
index a3d0fef3b126ba859e5fe0459b1e12658cbebe69..3f1ea5ddc40264d4760220b273f1e0b26067e4cd 100644 (file)
@@ -92,14 +92,6 @@ define archhelp
   echo  '* zImage        - Compressed kernel image (arch/$(ARCH)/boot/zImage)'
 endef
 
-# If you make sure the .S files get compiled with debug info,
-# uncomment the following to disable optimisations
-# that are unhelpful whilst debugging.
-ifdef CONFIG_DEBUG_INFO
-#KBUILD_CFLAGS += -O1
-KBUILD_AFLAGS  += -Wa,--gdwarf2
-endif
-
 #
 # include the appropriate processor- and unit-specific headers
 #
index d8a455ede5a751c8dc31604526e425fb50167ee0..fec8bf97d806422ce76a578c83576733633a9bf6 100644 (file)
@@ -853,37 +853,44 @@ UNHANDLED_EXCEPTION(_vector_0x1f00,0x1f00)
 
 /* ========================================================[ return ] === */
 
+_resume_userspace:
+       DISABLE_INTERRUPTS(r3,r4)
+       l.lwz   r4,TI_FLAGS(r10)
+       l.andi  r13,r4,_TIF_WORK_MASK
+       l.sfeqi r13,0
+       l.bf    _restore_all
+        l.nop
+
 _work_pending:
-       /*
-        * if (current_thread_info->flags & _TIF_NEED_RESCHED)
-        *     schedule();
-        */
-       l.lwz   r5,TI_FLAGS(r10)
-       l.andi  r3,r5,_TIF_NEED_RESCHED
-       l.sfnei r3,0
-       l.bnf   _work_notifysig
+       l.lwz   r5,PT_ORIG_GPR11(r1)
+       l.sfltsi r5,0
+       l.bnf   1f
         l.nop
-       l.jal   schedule
+       l.andi  r5,r5,0
+1:
+       l.jal   do_work_pending
+        l.ori  r3,r1,0                 /* pt_regs */
+
+       l.sfeqi r11,0
+       l.bf    _restore_all
         l.nop
-       l.j     _resume_userspace
+       l.sfltsi r11,0
+       l.bnf   1f
         l.nop
-
-/* Handle pending signals and notify-resume requests.
- * do_notify_resume must be passed the latest pushed pt_regs, not
- * necessarily the "userspace" ones.  Also, pt_regs->syscallno
- * must be set so that the syscall restart functionality works.
- */
-_work_notifysig:
-       l.jal   do_notify_resume
-        l.ori  r3,r1,0           /* pt_regs */
-
-_resume_userspace:
-       DISABLE_INTERRUPTS(r3,r4)
-       l.lwz   r3,TI_FLAGS(r10)
-       l.andi  r3,r3,_TIF_WORK_MASK
-       l.sfnei r3,0
-       l.bf    _work_pending
+       l.and   r11,r11,r0
+       l.ori   r11,r11,__NR_restart_syscall
+       l.j     _syscall_check_trace_enter
         l.nop
+1:
+       l.lwz   r11,PT_ORIG_GPR11(r1)
+       /* Restore arg registers */
+       l.lwz   r3,PT_GPR3(r1)
+       l.lwz   r4,PT_GPR4(r1)
+       l.lwz   r5,PT_GPR5(r1)
+       l.lwz   r6,PT_GPR6(r1)
+       l.lwz   r7,PT_GPR7(r1)
+       l.j     _syscall_check_trace_enter
+        l.lwz  r8,PT_GPR8(r1)
 
 _restore_all:
        RESTORE_ALL
index ae167f7e081aa0368cb571093df8f16a9dcf71d9..66775bc07a8eeb780e65a290247b3156f0a44ccd 100644 (file)
 #include <linux/tracehook.h>
 
 #include <asm/processor.h>
+#include <asm/syscall.h>
 #include <asm/ucontext.h>
 #include <asm/uaccess.h>
 
 #define DEBUG_SIG 0
 
 struct rt_sigframe {
-       struct siginfo *pinfo;
-       void *puc;
        struct siginfo info;
        struct ucontext uc;
        unsigned char retcode[16];      /* trampoline code */
 };
 
-static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
+static int restore_sigcontext(struct pt_regs *regs,
+                             struct sigcontext __user *sc)
 {
-       unsigned int err = 0;
+       int err = 0;
 
-       /* Alwys make any pending restarted system call return -EINTR */
+       /* Always make any pending restarted system calls return -EINTR */
        current_thread_info()->restart_block.fn = do_no_restart_syscall;
 
        /*
@@ -53,25 +53,21 @@ static int restore_sigcontext(struct pt_regs *regs, struct sigcontext *sc)
         * (sc is already checked for VERIFY_READ since the sigframe was
         *  checked in sys_sigreturn previously)
         */
-       if (__copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long)))
-               goto badframe;
-       if (__copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long)))
-               goto badframe;
-       if (__copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long)))
-               goto badframe;
+       err |= __copy_from_user(regs, sc->regs.gpr, 32 * sizeof(unsigned long));
+       err |= __copy_from_user(&regs->pc, &sc->regs.pc, sizeof(unsigned long));
+       err |= __copy_from_user(&regs->sr, &sc->regs.sr, sizeof(unsigned long));
 
        /* make sure the SM-bit is cleared so user-mode cannot fool us */
        regs->sr &= ~SPR_SR_SM;
 
+       regs->orig_gpr11 = -1;  /* Avoid syscall restart checks */
+
        /* TODO: the other ports use regs->orig_XX to disable syscall checks
         * after this completes, but we don't use that mechanism. maybe we can
         * use it now ?
         */
 
        return err;
-
-badframe:
-       return 1;
 }
 
 asmlinkage long _sys_rt_sigreturn(struct pt_regs *regs)
@@ -111,21 +107,18 @@ badframe:
  * Set up a signal frame.
  */
 
-static int setup_sigcontext(struct sigcontext *sc, struct pt_regs *regs,
-                           unsigned long mask)
+static int setup_sigcontext(struct pt_regs *regs, struct sigcontext __user *sc)
 {
        int err = 0;
 
        /* copy the regs */
-
+       /* There should be no need to save callee-saved registers here...
+        * ...but we save them anyway.  Revisit this
+        */
        err |= __copy_to_user(sc->regs.gpr, regs, 32 * sizeof(unsigned long));
        err |= __copy_to_user(&sc->regs.pc, &regs->pc, sizeof(unsigned long));
        err |= __copy_to_user(&sc->regs.sr, &regs->sr, sizeof(unsigned long));
 
-       /* then some other stuff */
-
-       err |= __put_user(mask, &sc->oldmask);
-
        return err;
 }
 
@@ -173,55 +166,53 @@ static inline void __user *get_sigframe(struct k_sigaction *ka,
  * trampoline which performs the syscall sigreturn, or a provided
  * user-mode trampoline.
  */
-static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
-                         sigset_t *set, struct pt_regs *regs)
+static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
+                         struct pt_regs *regs)
 {
        struct rt_sigframe *frame;
        unsigned long return_ip;
        int err = 0;
 
-       frame = get_sigframe(ka, regs, sizeof(*frame));
+       frame = get_sigframe(&ksig->ka, regs, sizeof(*frame));
 
        if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
-               goto give_sigsegv;
+               return -EFAULT;
 
-       err |= __put_user(&frame->info, &frame->pinfo);
-       err |= __put_user(&frame->uc, &frame->puc);
+       /* Create siginfo.  */
+       if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+               err |= copy_siginfo_to_user(&frame->info, &ksig->info);
 
-       if (ka->sa.sa_flags & SA_SIGINFO)
-               err |= copy_siginfo_to_user(&frame->info, info);
-       if (err)
-               goto give_sigsegv;
-
-       /* Clear all the bits of the ucontext we don't use.  */
-       err |= __clear_user(&frame->uc, offsetof(struct ucontext, uc_mcontext));
+       /* 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->sp);
-       err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]);
+       err |= setup_sigcontext(regs, &frame->uc.uc_mcontext);
 
        err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
 
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* trampoline - the desired return ip is the retcode itself */
        return_ip = (unsigned long)&frame->retcode;
-       /* This is l.ori r11,r0,__NR_sigreturn, l.sys 1 */
-       err |= __put_user(0xa960, (short *)(frame->retcode + 0));
-       err |= __put_user(__NR_rt_sigreturn, (short *)(frame->retcode + 2));
+       /* This is:
+               l.ori r11,r0,__NR_sigreturn
+               l.sys 1
+        */
+       err |= __put_user(0xa960,             (short *)(frame->retcode + 0));
+       err |= __put_user(__NR_rt_sigreturn,  (short *)(frame->retcode + 2));
        err |= __put_user(0x20000001, (unsigned long *)(frame->retcode + 4));
        err |= __put_user(0x15000000, (unsigned long *)(frame->retcode + 8));
 
        if (err)
-               goto give_sigsegv;
+               return -EFAULT;
 
        /* TODO what is the current->exec_domain stuff and invmap ? */
 
        /* Set up registers for signal handler */
-       regs->pc = (unsigned long)ka->sa.sa_handler; /* what we enter NOW */
+       regs->pc = (unsigned long)ksig->ka.sa.sa_handler; /* what we enter NOW */
        regs->gpr[9] = (unsigned long)return_ip;     /* what we enter LATER */
-       regs->gpr[3] = (unsigned long)sig;           /* arg 1: signo */
+       regs->gpr[3] = (unsigned long)ksig->sig;           /* arg 1: signo */
        regs->gpr[4] = (unsigned long)&frame->info;  /* arg 2: (siginfo_t*) */
        regs->gpr[5] = (unsigned long)&frame->uc;    /* arg 3: ucontext */
 
@@ -229,25 +220,16 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        regs->sp = (unsigned long)frame;
 
        return 0;
-
-give_sigsegv:
-       force_sigsegv(sig, current);
-       return -EFAULT;
 }
 
 static inline void
-handle_signal(unsigned long sig,
-             siginfo_t *info, struct k_sigaction *ka,
-             struct pt_regs *regs)
+handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 {
        int ret;
 
-       ret = setup_rt_frame(sig, ka, info, sigmask_to_save(), regs);
-       if (ret)
-               return;
+       ret = setup_rt_frame(ksig, sigmask_to_save(), regs);
 
-       signal_delivered(sig, info, ka, regs,
-                                test_thread_flag(TIF_SINGLESTEP));
+       signal_setup_done(ret, ksig, test_thread_flag(TIF_SINGLESTEP));
 }
 
 /*
@@ -262,82 +244,99 @@ handle_signal(unsigned long sig,
  * mode below.
  */
 
-void do_signal(struct pt_regs *regs)
+int do_signal(struct pt_regs *regs, int syscall)
 {
-       siginfo_t info;
-       int signr;
-       struct k_sigaction ka;
-
-       /*
-        * We want the common case to go fast, which
-        * is why we may in certain cases get here from
-        * kernel mode. Just return without doing anything
-        * if so.
-        */
-       if (!user_mode(regs))
-               return;
-
-       signr = get_signal_to_deliver(&info, &ka, regs, NULL);
-
-       /* If we are coming out of a syscall then we need
-        * to check if the syscall was interrupted and wants to be
-        * restarted after handling the signal.  If so, the original
-        * syscall number is put back into r11 and the PC rewound to
-        * point at the l.sys instruction that resulted in the
-        * original syscall.  Syscall results other than the four
-        * below mean that the syscall executed to completion and no
-        * restart is necessary.
-        */
-       if (regs->orig_gpr11) {
-               int restart = 0;
-
-               switch (regs->gpr[11]) {
+       struct ksignal ksig;
+       unsigned long continue_addr = 0;
+       unsigned long restart_addr = 0;
+       unsigned long retval = 0;
+       int restart = 0;
+
+       if (syscall) {
+               continue_addr = regs->pc;
+               restart_addr = continue_addr - 4;
+               retval = regs->gpr[11];
+
+               /*
+                * Setup syscall restart here so that a debugger will
+                * see the already changed PC.
+                */
+               switch (retval) {
                case -ERESTART_RESTARTBLOCK:
+                       restart = -2;
+                       /* Fall through */
                case -ERESTARTNOHAND:
-                       /* Restart if there is no signal handler */
-                       restart = (signr <= 0);
-                       break;
                case -ERESTARTSYS:
-                       /* Restart if there no signal handler or
-                        * SA_RESTART flag is set */
-                       restart = (signr <= 0 || (ka.sa.sa_flags & SA_RESTART));
-                       break;
                case -ERESTARTNOINTR:
-                       /* Always restart */
-                       restart = 1;
+                       restart++;
+                       regs->gpr[11] = regs->orig_gpr11;
+                       regs->pc = restart_addr;
                        break;
                }
-
-               if (restart) {
-                       if (regs->gpr[11] == -ERESTART_RESTARTBLOCK)
-                               regs->gpr[11] = __NR_restart_syscall;
-                       else
-                               regs->gpr[11] = regs->orig_gpr11;
-                       regs->pc -= 4;
-               } else {
-                       regs->gpr[11] = -EINTR;
-               }
        }
 
-       if (signr <= 0) {
-               /* no signal to deliver so we just put the saved sigmask
-                * back */
+       /*
+        * Get the signal to deliver.  During the call to get_signal the
+        * debugger may change all our registers so we may need to revert
+        * the decision to restart the syscall; specifically, if the PC is
+        * changed, don't restart the syscall.
+        */
+       if (get_signal(&ksig)) {
+               if (unlikely(restart) && regs->pc == restart_addr) {
+                       if (retval == -ERESTARTNOHAND ||
+                           retval == -ERESTART_RESTARTBLOCK
+                           || (retval == -ERESTARTSYS
+                               && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
+                               /* No automatic restart */
+                               regs->gpr[11] = -EINTR;
+                               regs->pc = continue_addr;
+                       }
+               }
+               handle_signal(&ksig, regs);
+       } else {
+               /* no handler */
                restore_saved_sigmask();
-       } else {                /* signr > 0 */
-               /* Whee!  Actually deliver the signal.  */
-               handle_signal(signr, &info, &ka, regs);
+               /*
+                * Restore pt_regs PC as syscall restart will be handled by
+                * kernel without return to userspace
+                */
+               if (unlikely(restart) && regs->pc == restart_addr) {
+                       regs->pc = continue_addr;
+                       return restart;
+               }
        }
 
-       return;
+       return 0;
 }
 
-asmlinkage void do_notify_resume(struct pt_regs *regs)
+asmlinkage int
+do_work_pending(struct pt_regs *regs, unsigned int thread_flags, int syscall)
 {
-       if (current_thread_info()->flags & _TIF_SIGPENDING)
-               do_signal(regs);
-
-       if (current_thread_info()->flags & _TIF_NOTIFY_RESUME) {
-               clear_thread_flag(TIF_NOTIFY_RESUME);
-               tracehook_notify_resume(regs);
-       }
+       do {
+               if (likely(thread_flags & _TIF_NEED_RESCHED)) {
+                       schedule();
+               } else {
+                       if (unlikely(!user_mode(regs)))
+                               return 0;
+                       local_irq_enable();
+                       if (thread_flags & _TIF_SIGPENDING) {
+                               int restart = do_signal(regs, syscall);
+                               if (unlikely(restart)) {
+                                       /*
+                                        * Restart without handlers.
+                                        * Deal with it without leaving
+                                        * the kernel space.
+                                        */
+                                       return restart;
+                               }
+                               syscall = 0;
+                       } else {
+                               clear_thread_flag(TIF_NOTIFY_RESUME);
+                               tracehook_notify_resume(regs);
+                       }
+               }
+               local_irq_disable();
+               thread_flags = current_thread_info()->flags;
+       } while (thread_flags & _TIF_WORK_MASK);
+       return 0;
 }
index 1695b6ab503d8e1f2763f89e5696bbb9019abfaf..957bf344c0f533e4ebf0c6248b3ba02caf3d8595 100644 (file)
@@ -140,6 +140,7 @@ config PPC
        select OLD_SIGACTION if PPC32
        select HAVE_DEBUG_STACKOVERFLOW
        select HAVE_IRQ_EXIT_ON_IRQ_STACK
+       select ARCH_USE_CMPXCHG_LOCKREF if PPC64
 
 config GENERIC_CSUM
        def_bool CPU_LITTLE_ENDIAN
@@ -214,9 +215,6 @@ config DEFAULT_UIMAGE
          Used to allow a board to specify it wants a uImage built by default
        default n
 
-config REDBOOT
-       bool
-
 config ARCH_HIBERNATION_POSSIBLE
        bool
        default y
@@ -344,6 +342,8 @@ config PPC_TRANSACTIONAL_MEM
        bool "Transactional Memory support for POWERPC"
        depends on PPC_BOOK3S_64
        depends on SMP
+       select ALTIVEC
+       select VSX
        default n
        ---help---
          Support user-mode Transactional Memory on POWERPC.
@@ -384,6 +384,12 @@ config ARCH_HAS_WALK_MEMORY
 config ARCH_ENABLE_MEMORY_HOTREMOVE
        def_bool y
 
+config PPC64_SUPPORTS_MEMORY_FAILURE
+       bool "Add support for memory hwpoison"
+       depends on PPC_BOOK3S_64
+       default "y" if PPC_POWERNV
+       select ARCH_SUPPORTS_MEMORY_FAILURE
+
 config KEXEC
        bool "kexec system call"
        depends on (PPC_BOOK3S || FSL_BOOKE || (44x && !SMP))
@@ -404,8 +410,7 @@ config KEXEC
 config CRASH_DUMP
        bool "Build a kdump crash kernel"
        depends on PPC64 || 6xx || FSL_BOOKE || (44x && !SMP)
-       select RELOCATABLE if PPC64 || 44x
-       select DYNAMIC_MEMSTART if FSL_BOOKE
+       select RELOCATABLE if PPC64 || 44x || FSL_BOOKE
        help
          Build a kernel suitable for use as a kdump capture kernel.
          The same kernel binary can be used as production kernel and dump
@@ -529,6 +534,7 @@ config PPC_16K_PAGES
 
 config PPC_64K_PAGES
        bool "64k page size" if 44x || PPC_STD_MMU_64 || PPC_BOOK3E_64
+       depends on !PPC_FSL_BOOK3E
        select PPC_HAS_HASH_64K if PPC_STD_MMU_64
 
 config PPC_256K_PAGES
@@ -886,7 +892,7 @@ config DYNAMIC_MEMSTART
 
 config RELOCATABLE
        bool "Build a relocatable kernel"
-       depends on ADVANCED_OPTIONS && FLATMEM && 44x
+       depends on ADVANCED_OPTIONS && FLATMEM && (44x || FSL_BOOKE)
        select NONSTATIC_KERNEL
        help
          This builds a kernel image that is capable of running at the
@@ -1042,11 +1048,6 @@ config KEYS_COMPAT
 
 source "crypto/Kconfig"
 
-config PPC_CLOCK
-       bool
-       default n
-       select HAVE_CLK
-
 config PPC_LIB_RHEAP
        bool
 
index 554734ff302e89234c0d3ae51d1f11a840119c57..d61c03525777ce3cdaeab8a294fb6083e64cfe81 100644 (file)
@@ -16,6 +16,7 @@ mktree
 uImage
 cuImage.*
 dtbImage.*
+*.dtb
 treeImage.*
 zImage
 zImage.initrd
index ca7f08cc4afd770b528931bbab92edc55ad5e8db..90e9d95486603281684c9a06bdbb5029e06b0843 100644 (file)
@@ -71,9 +71,9 @@ src-wlib-y := string.S crt0.S crtsavres.S stdio.c main.c \
                uartlite.c mpc52xx-psc.c
 src-wlib-$(CONFIG_40x) += 4xx.c planetcore.c
 src-wlib-$(CONFIG_44x) += 4xx.c ebony.c bamboo.c
-src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c
+src-wlib-$(CONFIG_8xx) += mpc8xx.c planetcore.c fsl-soc.c
 src-wlib-$(CONFIG_PPC_82xx) += pq2.c fsl-soc.c planetcore.c
-src-wlib-$(CONFIG_EMBEDDED6xx) += mv64x60.c mv64x60_i2c.c ugecon.c
+src-wlib-$(CONFIG_EMBEDDED6xx) += mv64x60.c mv64x60_i2c.c ugecon.c fsl-soc.c
 
 src-plat-y := of.c epapr.c
 src-plat-$(CONFIG_40x) += fixed-head.S ep405.c cuboot-hotfoot.c \
@@ -95,7 +95,7 @@ src-plat-$(CONFIG_FSL_SOC_BOOKE) += cuboot-85xx.c cuboot-85xx-cpm2.c
 src-plat-$(CONFIG_EMBEDDED6xx) += cuboot-pq2.c cuboot-mpc7448hpc2.c \
                                        cuboot-c2k.c gamecube-head.S \
                                        gamecube.c wii-head.S wii.c holly.c \
-                                       prpmc2800.c
+                                       prpmc2800.c fixed-head.S mvme5100.c
 src-plat-$(CONFIG_AMIGAONE) += cuboot-amigaone.c
 src-plat-$(CONFIG_PPC_PS3) += ps3-head.S ps3-hvcall.S ps3.c
 src-plat-$(CONFIG_EPAPR_BOOT) += epapr.c epapr-wrapper.c
@@ -286,6 +286,7 @@ image-$(CONFIG_MPC7448HPC2)         += cuImage.mpc7448hpc2
 image-$(CONFIG_PPC_C2K)                        += cuImage.c2k
 image-$(CONFIG_GAMECUBE)               += dtbImage.gamecube
 image-$(CONFIG_WII)                    += dtbImage.wii
+image-$(CONFIG_MVME5100)               += dtbImage.mvme5100
 
 # Board port in arch/powerpc/platform/amigaone/Kconfig
 image-$(CONFIG_AMIGAONE)               += cuImage.amigaone
index a543c4088cba1ea026062a45df2c4ca0c95648ab..a1b883730b3169d8171c06c4fdc2d50cfe874b41 100644 (file)
                };
        };
 
+       clocks {
+               osc {
+                       clock-frequency = <25000000>;
+               };
+       };
+
        soc@80000000 {
+               bus-frequency = <80000000>;     /* 80 MHz ips bus */
 
                clock@f00 {
                        compatible = "fsl,mpc5121rev2-clock", "fsl,mpc5121-clock";
diff --git a/arch/powerpc/boot/dts/fsl/elo3-dma-2.dtsi b/arch/powerpc/boot/dts/fsl/elo3-dma-2.dtsi
new file mode 100644 (file)
index 0000000..d3cc8d0
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * QorIQ Elo3 DMA device tree stub [ controller @ offset 0x102300 ]
+ *
+ * Copyright 2013 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.
+ */
+
+dma2: dma@102300 {
+       #address-cells = <1>;
+       #size-cells = <1>;
+       compatible = "fsl,elo3-dma";
+       reg = <0x102300 0x4>,
+             <0x102600 0x4>;
+       ranges = <0x0 0x102100 0x500>;
+       dma-channel@0 {
+               compatible = "fsl,eloplus-dma-channel";
+               reg = <0x0 0x80>;
+               interrupts = <464 2 0 0>;
+       };
+       dma-channel@80 {
+               compatible = "fsl,eloplus-dma-channel";
+               reg = <0x80 0x80>;
+               interrupts = <465 2 0 0>;
+       };
+       dma-channel@100 {
+               compatible = "fsl,eloplus-dma-channel";
+               reg = <0x100 0x80>;
+               interrupts = <466 2 0 0>;
+       };
+       dma-channel@180 {
+               compatible = "fsl,eloplus-dma-channel";
+               reg = <0x180 0x80>;
+               interrupts = <467 2 0 0>;
+       };
+       dma-channel@300 {
+               compatible = "fsl,eloplus-dma-channel";
+               reg = <0x300 0x80>;
+               interrupts = <468 2 0 0>;
+       };
+       dma-channel@380 {
+               compatible = "fsl,eloplus-dma-channel";
+               reg = <0x380 0x80>;
+               interrupts = <469 2 0 0>;
+       };
+       dma-channel@400 {
+               compatible = "fsl,eloplus-dma-channel";
+               reg = <0x400 0x80>;
+               interrupts = <470 2 0 0>;
+       };
+       dma-channel@480 {
+               compatible = "fsl,eloplus-dma-channel";
+               reg = <0x480 0x80>;
+               interrupts = <471 2 0 0>;
+       };
+};
index 68cc5e7f64777c6a1021494dc5826df4a658c83b..642dc3a83d0e352a46583df09dbecddeb46bc091 100644 (file)
@@ -36,7 +36,8 @@
        #address-cells = <2>;
        #size-cells = <1>;
        compatible = "fsl,p1020-elbc", "fsl,elbc", "simple-bus";
-       interrupts = <19 2 0 0>;
+       interrupts = <19 2 0 0>,
+                    <16 2 0 0>;
 };
 
 /* controller at 0x9000 */
index adb82fd9057f3ddba3861b3a1f5928fd7d5844c9..407cb5fd0f5bad533d31e7afc613f83fd36f3e67 100644 (file)
@@ -36,7 +36,8 @@
        #address-cells = <2>;
        #size-cells = <1>;
        compatible = "fsl,p1021-elbc", "fsl,elbc", "simple-bus";
-       interrupts = <19 2 0 0>;
+       interrupts = <19 2 0 0>,
+                    <16 2 0 0>;
 };
 
 /* controller at 0x9000 */
index e179803a81ef88b6c17feeba36a157bbe3a51dbd..ebf2022345498602fdc3a31487631bfd2e556ed8 100644 (file)
@@ -40,7 +40,8 @@
         * pin muxing when the DIU is enabled.
         */
        compatible = "fsl,p1022-elbc", "fsl,elbc";
-       interrupts = <19 2 0 0>;
+       interrupts = <19 2 0 0>,
+                    <16 2 0 0>;
 };
 
 /* controller at 0x9000 */
index f1105bffa915672c2b8d1d65a362c8c0d64d0626..81437fdf1db4f0ba1198487ce6c0dc452c856885 100644 (file)
@@ -36,7 +36,8 @@
        #address-cells = <2>;
        #size-cells = <1>;
        compatible = "fsl,p1023-elbc", "fsl,elbc", "simple-bus";
-       interrupts = <19 2 0 0>;
+       interrupts = <19 2 0 0>,
+                    <16 2 0 0>;
 };
 
 /* controller at 0xa000 */
index 1613d6e4049eb2ba22aeceef97e8e57110620713..5ba7f01e2a297878251001d427bf498bdd94397c 100644 (file)
 
                MSI: ppc4xx-msi@C10000000 {
                        compatible = "amcc,ppc4xx-msi", "ppc4xx-msi";
-                       reg = < 0x0 0xEF620000 0x100>;
+                       reg = <0xEF620000 0x100>;
                        sdr-base = <0x4B0>;
                        msi-data = <0x00000000>;
                        msi-mask = <0x44440000>;
index 2d7cb04ac962ba3cfed781f408646d7669e50d7d..2c0e1552d20bb9a410ab6c27762d676e6e7f5b9e 100644 (file)
@@ -9,6 +9,8 @@
  * option) any later version.
  */
 
+#include <dt-bindings/clock/mpc512x-clock.h>
+
 /dts-v1/;
 
 / {
                compatible = "fsl,mpc5121-mbx";
                reg = <0x20000000 0x4000>;
                interrupts = <66 0x8>;
+               clocks = <&clks MPC512x_CLK_MBX_BUS>,
+                        <&clks MPC512x_CLK_MBX_3D>,
+                        <&clks MPC512x_CLK_MBX>;
+               clock-names = "mbx-bus", "mbx-3d", "mbx";
        };
 
        sram@30000000 {
@@ -62,6 +68,8 @@
                interrupts = <6 8>;
                #address-cells = <1>;
                #size-cells = <1>;
+               clocks = <&clks MPC512x_CLK_NFC>;
+               clock-names = "ipg";
        };
 
        localbus@80000020 {
                ranges = <0x0 0x0 0xfc000000 0x04000000>;
        };
 
+       clocks {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               osc: osc {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <33000000>;
+               };
+       };
+
        soc@80000000 {
                compatible = "fsl,mpc5121-immr";
                #address-cells = <1>;
                };
 
                /* Clock control */
-               clock@f00 {
+               clks: clock@f00 {
                        compatible = "fsl,mpc5121-clock";
                        reg = <0xf00 0x100>;
+                       #clock-cells = <1>;
+                       clocks = <&osc>;
+                       clock-names = "osc";
                };
 
                /* Power Management Controller */
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x1300 0x80>;
                        interrupts = <12 0x8>;
+                       clocks = <&clks MPC512x_CLK_BDLC>,
+                                <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN0_MCLK>;
+                       clock-names = "ipg", "ips", "sys", "ref", "mclk";
                };
 
                can@1380 {
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x1380 0x80>;
                        interrupts = <13 0x8>;
+                       clocks = <&clks MPC512x_CLK_BDLC>,
+                                <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN1_MCLK>;
+                       clock-names = "ipg", "ips", "sys", "ref", "mclk";
                };
 
                sdhc@1500 {
                        interrupts = <8 0x8>;
                        dmas = <&dma0 30>;
                        dma-names = "rx-tx";
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SDHC>;
+                       clock-names = "ipg", "per";
                };
 
                i2c@1700 {
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1700 0x20>;
                        interrupts = <9 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "ipg";
                };
 
                i2c@1720 {
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1720 0x20>;
                        interrupts = <10 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "ipg";
                };
 
                i2c@1740 {
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1740 0x20>;
                        interrupts = <11 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "ipg";
                };
 
                i2ccontrol@1760 {
                        compatible = "fsl,mpc5121-axe";
                        reg = <0x2000 0x100>;
                        interrupts = <42 0x8>;
+                       clocks = <&clks MPC512x_CLK_AXE>;
+                       clock-names = "ipg";
                };
 
                display@2100 {
                        compatible = "fsl,mpc5121-diu";
                        reg = <0x2100 0x100>;
                        interrupts = <64 0x8>;
+                       clocks = <&clks MPC512x_CLK_DIU>;
+                       clock-names = "ipg";
                };
 
                can@2300 {
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x2300 0x80>;
                        interrupts = <90 0x8>;
+                       clocks = <&clks MPC512x_CLK_BDLC>,
+                                <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN2_MCLK>;
+                       clock-names = "ipg", "ips", "sys", "ref", "mclk";
                };
 
                can@2380 {
                        compatible = "fsl,mpc5121-mscan";
                        reg = <0x2380 0x80>;
                        interrupts = <91 0x8>;
+                       clocks = <&clks MPC512x_CLK_BDLC>,
+                                <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN3_MCLK>;
+                       clock-names = "ipg", "ips", "sys", "ref", "mclk";
                };
 
                viu@2400 {
                        compatible = "fsl,mpc5121-viu";
                        reg = <0x2400 0x400>;
                        interrupts = <67 0x8>;
+                       clocks = <&clks MPC512x_CLK_VIU>;
+                       clock-names = "ipg";
                };
 
                mdio@2800 {
                        reg = <0x2800 0x800>;
                        #address-cells = <1>;
                        #size-cells = <0>;
+                       clocks = <&clks MPC512x_CLK_FEC>;
+                       clock-names = "per";
                };
 
                eth0: ethernet@2800 {
                        reg = <0x2800 0x800>;
                        local-mac-address = [ 00 00 00 00 00 00 ];
                        interrupts = <4 0x8>;
+                       clocks = <&clks MPC512x_CLK_FEC>;
+                       clock-names = "per";
                };
 
                /* USB1 using external ULPI PHY */
                        interrupts = <43 0x8>;
                        dr_mode = "otg";
                        phy_type = "ulpi";
+                       clocks = <&clks MPC512x_CLK_USB1>;
+                       clock-names = "ipg";
                };
 
                /* USB0 using internal UTMI PHY */
                        interrupts = <44 0x8>;
                        dr_mode = "otg";
                        phy_type = "utmi_wide";
+                       clocks = <&clks MPC512x_CLK_USB2>;
+                       clock-names = "ipg";
                };
 
                /* IO control */
                        compatible = "fsl,mpc5121-pata";
                        reg = <0x10200 0x100>;
                        interrupts = <5 0x8>;
+                       clocks = <&clks MPC512x_CLK_PATA>;
+                       clock-names = "ipg";
                };
 
                /* 512x PSCs are not 52xx PSC compatible */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC0>,
+                                <&clks MPC512x_CLK_PSC0_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC1 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC1>,
+                                <&clks MPC512x_CLK_PSC1_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC2 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC2>,
+                                <&clks MPC512x_CLK_PSC2_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC3 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC3>,
+                                <&clks MPC512x_CLK_PSC3_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC4 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC4>,
+                                <&clks MPC512x_CLK_PSC4_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC5 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC5>,
+                                <&clks MPC512x_CLK_PSC5_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC6 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC6>,
+                                <&clks MPC512x_CLK_PSC6_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC7 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC7>,
+                                <&clks MPC512x_CLK_PSC7_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC8 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC8>,
+                                <&clks MPC512x_CLK_PSC8_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC9 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC9>,
+                                <&clks MPC512x_CLK_PSC9_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC10 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC10>,
+                                <&clks MPC512x_CLK_PSC10_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                /* PSC11 */
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC11>,
+                                <&clks MPC512x_CLK_PSC11_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                pscfifo@11f00 {
                        compatible = "fsl,mpc5121-psc-fifo";
                        reg = <0x11f00 0x100>;
                        interrupts = <40 0x8>;
+                       clocks = <&clks MPC512x_CLK_PSC_FIFO>;
+                       clock-names = "ipg";
                };
 
                dma0: dma@14000 {
                #address-cells = <3>;
                #size-cells = <2>;
                #interrupt-cells = <1>;
+               clocks = <&clks MPC512x_CLK_PCI>;
+               clock-names = "ipg";
 
                reg = <0x80008500 0x100 /* internal registers */
                       0x80008300 0x8>; /* config space access registers */
index a618dfc13e4c8f88a5ff70b88325fd39675c9e8a..e4f297471748ecce14a3759a6dd5b77e2e8f3db8 100644 (file)
@@ -12,6 +12,8 @@
  * option) any later version.
  */
 
+#include <dt-bindings/clock/mpc512x-clock.h>
+
 /dts-v1/;
 
 / {
                reg = <0x30000000 0x08000>;             // 32K at 0x30000000
        };
 
+       clocks {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               osc: osc {
+                       compatible = "fixed-clock";
+                       #clock-cells = <0>;
+                       clock-frequency = <33000000>;
+               };
+       };
+
        soc@80000000 {
                compatible = "fsl,mpc5121-immr";
                #address-cells = <1>;
                        reg = <0xe00 0x100>;
                };
 
-               clock@f00 {     // Clock control
+               clks: clock@f00 {       // Clock control
                        compatible = "fsl,mpc5121-clock";
                        reg = <0xf00 0x100>;
+                       #clock-cells = <1>;
+                       clocks = <&osc>;
+                       clock-names = "osc";
                };
 
                pmc@1000{  // Power Management Controller
                        compatible = "fsl,mpc5121-mscan";
                        interrupts = <12 0x8>;
                        reg = <0x1300 0x80>;
+                       clocks = <&clks MPC512x_CLK_BDLC>,
+                                <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN0_MCLK>;
+                       clock-names = "ipg", "ips", "sys", "ref", "mclk";
                };
 
                can@1380 {
                        compatible = "fsl,mpc5121-mscan";
                        interrupts = <13 0x8>;
                        reg = <0x1380 0x80>;
+                       clocks = <&clks MPC512x_CLK_BDLC>,
+                                <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SYS>,
+                                <&clks MPC512x_CLK_REF>,
+                                <&clks MPC512x_CLK_MSCAN1_MCLK>;
+                       clock-names = "ipg", "ips", "sys", "ref", "mclk";
                };
 
                sdhc@1500 {
                        compatible = "fsl,mpc5121-sdhc";
                        interrupts = <8 0x8>;
                        reg = <0x1500 0x100>;
+                       clocks = <&clks MPC512x_CLK_IPS>,
+                                <&clks MPC512x_CLK_SDHC>;
+                       clock-names = "ipg", "per";
                };
 
                i2c@1700 {
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1700 0x20>;
                        interrupts = <0x9 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "ipg";
                };
 
                i2c@1720 {
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1720 0x20>;
                        interrupts = <0xa 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "ipg";
                };
 
                i2c@1740 {
                        compatible = "fsl,mpc5121-i2c", "fsl-i2c";
                        reg = <0x1740 0x20>;
                        interrupts = <0xb 0x8>;
+                       clocks = <&clks MPC512x_CLK_I2C>;
+                       clock-names = "ipg";
                };
 
                i2ccontrol@1760 {
                        compatible = "fsl,mpc5121-diu";
                        reg = <0x2100 0x100>;
                        interrupts = <64 0x8>;
+                       clocks = <&clks MPC512x_CLK_DIU>;
+                       clock-names = "ipg";
                };
 
                mdio@2800 {
                        interrupts = <4 0x8>;
                        phy-handle = < &phy0 >;
                        phy-connection-type = "rmii";
+                       clocks = <&clks MPC512x_CLK_FEC>;
+                       clock-names = "per";
                };
 
                // IO control
                        interrupts = <43 0x8>;
                        dr_mode = "host";
                        phy_type = "ulpi";
+                       clocks = <&clks MPC512x_CLK_USB1>;
+                       clock-names = "ipg";
                        status = "disabled";
                };
 
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC1>,
+                                <&clks MPC512x_CLK_PSC1_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                // PSC9 uart1 aka ttyPSC1
                        interrupts = <40 0x8>;
                        fsl,rx-fifo-size = <16>;
                        fsl,tx-fifo-size = <16>;
+                       clocks = <&clks MPC512x_CLK_PSC9>,
+                                <&clks MPC512x_CLK_PSC9_MCLK>;
+                       clock-names = "ipg", "mclk";
                };
 
                pscfifo@11f00 {
                        compatible = "fsl,mpc5121-psc-fifo";
                        reg = <0x11f00 0x100>;
                        interrupts = <40 0x8>;
+                       clocks = <&clks MPC512x_CLK_PSC_FIFO>;
+                       clock-names = "ipg";
                };
 
                dma@14000 {
diff --git a/arch/powerpc/boot/dts/mvme5100.dts b/arch/powerpc/boot/dts/mvme5100.dts
new file mode 100644 (file)
index 0000000..1ecb341
--- /dev/null
@@ -0,0 +1,185 @@
+/*
+ * Device Tree Source for Motorola/Emerson MVME5100.
+ *
+ * Copyright 2013 CSC Australia Pty. Ltd.
+ *
+ * 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.
+ */
+
+/dts-v1/;
+
+/ {
+       model = "MVME5100";
+       compatible = "MVME5100";
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       aliases {
+               serial0 = &serial0;
+               pci0 = &pci0;
+       };
+
+       cpus {
+               #address-cells = <1>;
+               #size-cells = <0>;
+
+               PowerPC,7410 {
+                       device_type = "cpu";
+                       reg = <0x0>;
+                       /* Following required by dtc but not used */
+                       d-cache-line-size = <32>;
+                       i-cache-line-size = <32>;
+                       i-cache-size = <32768>;
+                       d-cache-size = <32768>;
+                       timebase-frequency = <25000000>;
+                       clock-frequency = <500000000>;
+                       bus-frequency = <100000000>;
+               };
+       };
+
+       memory {
+               device_type = "memory";
+               reg = <0x0 0x20000000>;
+       };
+
+       hawk@fef80000 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "hawk-bridge", "simple-bus";
+               ranges = <0x0 0xfef80000 0x10000>;
+               reg = <0xfef80000 0x10000>;
+
+               serial0: serial@8000 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x8000 0x80>;
+                       reg-shift = <4>;
+                       clock-frequency = <1843200>;
+                       current-speed = <9600>;
+                       interrupts = <1 1>; // IRQ1 Level Active Low.
+                       interrupt-parent = <&mpic>;
+               };
+
+               serial1: serial@8200 {
+                       device_type = "serial";
+                       compatible = "ns16550";
+                       reg = <0x8200 0x80>;
+                       reg-shift = <4>;
+                       clock-frequency = <1843200>;
+                       current-speed = <9600>;
+                       interrupts = <1 1>; // IRQ1 Level Active Low.
+                       interrupt-parent = <&mpic>;
+               };
+
+               mpic: interrupt-controller@f3f80000 {
+                       #interrupt-cells = <2>;
+                       #address-cells = <0>;
+                       device_type = "open-pic";
+                       compatible = "chrp,open-pic";
+                       interrupt-controller;
+                       reg = <0xf3f80000 0x40000>;
+               };
+       };
+
+       pci0: pci@feff0000 {
+               #address-cells = <3>;
+               #size-cells = <2>;
+               #interrupt-cells = <1>;
+               device_type = "pci";
+               compatible = "hawk-pci";
+               reg = <0xfec00000 0x400000>;
+               8259-interrupt-acknowledge = <0xfeff0030>;
+               ranges = <0x1000000 0x0        0x0 0xfe000000 0x0 0x800000
+                         0x2000000 0x0 0x80000000 0x80000000 0x0 0x74000000>;
+               bus-range = <0 255>;
+               clock-frequency = <33333333>;
+               interrupt-parent = <&mpic>;
+               interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+               interrupt-map = <
+
+                       /*
+                        * This definition (IDSEL 11) duplicates the
+                        * interrupts definition in the i8259
+                        * interrupt controller below.
+                        *
+                        * Do not change the interrupt sense/polarity from
+                        * 0x2 to anything else, doing so will cause endless
+                        * "spurious" i8259 interrupts to be fielded.
+                        */
+                       // IDSEL 11 - iPMC712 PCI/ISA Bridge
+                       0x5800 0x0 0x0 0x1 &mpic 0x0 0x2
+                       0x5800 0x0 0x0 0x2 &mpic 0x0 0x2
+                       0x5800 0x0 0x0 0x3 &mpic 0x0 0x2
+                       0x5800 0x0 0x0 0x4 &mpic 0x0 0x2
+
+                       /* IDSEL 12 - Not Used */
+
+                       /* IDSEL 13 - Universe VME Bridge */
+                       0x6800 0x0 0x0 0x1 &mpic 0x5 0x1
+                       0x6800 0x0 0x0 0x2 &mpic 0x6 0x1
+                       0x6800 0x0 0x0 0x3 &mpic 0x7 0x1
+                       0x6800 0x0 0x0 0x4 &mpic 0x8 0x1
+
+                       /* IDSEL 14 - ENET 1 */
+                       0x7000 0x0 0x0 0x1 &mpic 0x2 0x1
+
+                       /* IDSEL 15 - Not Used */
+
+                       /* IDSEL 16 - PMC Slot 1 */
+                       0x8000 0x0 0x0 0x1 &mpic 0x9 0x1
+                       0x8000 0x0 0x0 0x2 &mpic 0xa 0x1
+                       0x8000 0x0 0x0 0x3 &mpic 0xb 0x1
+                       0x8000 0x0 0x0 0x4 &mpic 0xc 0x1
+
+                       /* IDSEL 17 - PMC Slot 2 */
+                       0x8800 0x0 0x0 0x1 &mpic 0xc 0x1
+                       0x8800 0x0 0x0 0x2 &mpic 0x9 0x1
+                       0x8800 0x0 0x0 0x3 &mpic 0xa 0x1
+                       0x8800 0x0 0x0 0x4 &mpic 0xb 0x1
+
+                       /* IDSEL 18 - Not Used */
+
+                       /* IDSEL 19 - ENET 2 */
+                       0x9800 0x0 0x0 0x1 &mpic 0xd 0x1
+
+                       /* IDSEL 20 - PMCSPAN (PCI-X) */
+                       0xa000 0x0 0x0 0x1 &mpic 0x9 0x1
+                       0xa000 0x0 0x0 0x2 &mpic 0xa 0x1
+                       0xa000 0x0 0x0 0x3 &mpic 0xb 0x1
+                       0xa000 0x0 0x0 0x4 &mpic 0xc 0x1
+
+               >;
+
+               isa {
+                       #address-cells = <2>;
+                       #size-cells = <1>;
+                       #interrupt-cells = <2>;
+                       device_type = "isa";
+                       compatible = "isa";
+                       ranges = <0x00000001 0 0x01000000 0 0x00000000 0x00001000>;
+                       interrupt-parent = <&i8259>;
+
+                       i8259: interrupt-controller@20 {
+                               #interrupt-cells = <2>;
+                               #address-cells = <0>;
+                               interrupts = <0 2>;
+                               device_type = "interrupt-controller";
+                               compatible = "chrp,iic";
+                               interrupt-controller;
+                               reg = <1 0x00000020 0x00000002
+                                       1 0x000000a0 0x00000002
+                                       1 0x000004d0 0x00000002>;
+                               interrupt-parent = <&mpic>;
+                       };
+
+               };
+
+       };
+
+       chosen {
+               linux,stdout-path = &serial0;
+        };
+
+};
diff --git a/arch/powerpc/boot/dts/p1010rdb-pa.dts b/arch/powerpc/boot/dts/p1010rdb-pa.dts
new file mode 100644 (file)
index 0000000..767d4c0
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+ * P1010 RDB Device Tree Source
+ *
+ * Copyright 2011 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.
+ */
+
+/include/ "fsl/p1010si-pre.dtsi"
+
+/ {
+       model = "fsl,P1010RDB";
+       compatible = "fsl,P1010RDB";
+
+       /include/ "p1010rdb_32b.dtsi"
+};
+
+/include/ "p1010rdb.dtsi"
+/include/ "p1010rdb-pa.dtsi"
+/include/ "fsl/p1010si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1010rdb-pa.dtsi b/arch/powerpc/boot/dts/p1010rdb-pa.dtsi
new file mode 100644 (file)
index 0000000..434fb2d
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * P1010 RDB Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2013 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_nand {
+       partition@0 {
+               /* This location must not be altered  */
+               /* 1MB for u-boot Bootloader Image */
+               reg = <0x0 0x00100000>;
+               label = "NAND U-Boot Image";
+               read-only;
+       };
+
+       partition@100000 {
+               /* 1MB for DTB Image */
+               reg = <0x00100000 0x00100000>;
+               label = "NAND DTB Image";
+       };
+
+       partition@200000 {
+               /* 4MB for Linux Kernel Image */
+               reg = <0x00200000 0x00400000>;
+               label = "NAND Linux Kernel Image";
+       };
+
+       partition@600000 {
+               /* 4MB for Compressed Root file System Image */
+               reg = <0x00600000 0x00400000>;
+               label = "NAND Compressed RFS Image";
+       };
+
+       partition@a00000 {
+               /* 15MB for JFFS2 based Root file System */
+               reg = <0x00a00000 0x00f00000>;
+               label = "NAND JFFS2 Root File System";
+       };
+
+       partition@1900000 {
+               /* 7MB for User Area */
+               reg = <0x01900000 0x00700000>;
+               label = "NAND User area";
+       };
+};
+
+&phy0 {
+       interrupts = <1 1 0 0>;
+};
+
+&phy1 {
+       interrupts = <2 1 0 0>;
+};
+
+&phy2 {
+       interrupts = <4 1 0 0>;
+};
similarity index 64%
rename from arch/powerpc/boot/dts/p1010rdb_36b.dts
rename to arch/powerpc/boot/dts/p1010rdb-pa_36b.dts
index 64776f4a4651cca6db3a3b5baf1b821a7eeb7638..3033371bc007ec9f6cd7a4c87e608d6422f46e5f 100644 (file)
        model = "fsl,P1010RDB";
        compatible = "fsl,P1010RDB";
 
-       memory {
-               device_type = "memory";
-       };
-
-       board_ifc: ifc: ifc@fffe1e000 {
-               /* NOR, NAND Flashes and CPLD on board */
-               ranges = <0x0 0x0 0xf 0xee000000 0x02000000
-                         0x1 0x0 0xf 0xff800000 0x00010000
-                         0x3 0x0 0xf 0xffb00000 0x00000020>;
-               reg = <0xf 0xffe1e000 0 0x2000>;
-       };
-
-       board_soc: soc: soc@fffe00000 {
-               ranges = <0x0 0xf 0xffe00000 0x100000>;
-       };
-
-       pci0: pcie@fffe09000 {
-               reg = <0xf 0xffe09000 0 0x1000>;
-               ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000
-                         0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
-               pcie@0 {
-                       ranges = <0x2000000 0x0 0xc0000000
-                                 0x2000000 0x0 0xc0000000
-                                 0x0 0x20000000
-
-                                 0x1000000 0x0 0x0
-                                 0x1000000 0x0 0x0
-                                 0x0 0x100000>;
-               };
-       };
-
-       pci1: pcie@fffe0a000 {
-               reg = <0xf 0xffe0a000 0 0x1000>;
-               ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000
-                         0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
-               pcie@0 {
-                       ranges = <0x2000000 0x0 0xc0000000
-                                 0x2000000 0x0 0xc0000000
-                                 0x0 0x20000000
-
-                                 0x1000000 0x0 0x0
-                                 0x1000000 0x0 0x0
-                                 0x0 0x100000>;
-               };
-       };
+       /include/ "p1010rdb_36b.dtsi"
 };
 
 /include/ "p1010rdb.dtsi"
+/include/ "p1010rdb-pa.dtsi"
 /include/ "fsl/p1010si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1010rdb-pb.dts b/arch/powerpc/boot/dts/p1010rdb-pb.dts
new file mode 100644 (file)
index 0000000..6eeb7d3
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * P1010 RDB Device Tree Source
+ *
+ * Copyright 2011 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.
+ */
+
+/include/ "fsl/p1010si-pre.dtsi"
+
+/ {
+       model = "fsl,P1010RDB-PB";
+       compatible = "fsl,P1010RDB-PB";
+
+       /include/ "p1010rdb_32b.dtsi"
+};
+
+/include/ "p1010rdb.dtsi"
+
+&phy0 {
+       interrupts = <0 1 0 0>;
+};
+
+&phy1 {
+       interrupts = <2 1 0 0>;
+};
+
+&phy2 {
+       interrupts = <1 1 0 0>;
+};
+
+/include/ "fsl/p1010si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1010rdb-pb_36b.dts b/arch/powerpc/boot/dts/p1010rdb-pb_36b.dts
new file mode 100644 (file)
index 0000000..7ab3c90
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * P1010 RDB Device Tree Source (36-bit address map)
+ *
+ * Copyright 2011 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/p1010si-pre.dtsi"
+
+/ {
+       model = "fsl,P1010RDB-PB";
+       compatible = "fsl,P1010RDB-PB";
+
+       /include/ "p1010rdb_36b.dtsi"
+};
+
+/include/ "p1010rdb.dtsi"
+
+&phy0 {
+       interrupts = <0 1 0 0>;
+};
+
+&phy1 {
+       interrupts = <2 1 0 0>;
+};
+
+&phy2 {
+       interrupts = <1 1 0 0>;
+};
+
+/include/ "fsl/p1010si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1010rdb.dts b/arch/powerpc/boot/dts/p1010rdb.dts
deleted file mode 100644 (file)
index b868d22..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * P1010 RDB Device Tree Source
- *
- * Copyright 2011 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.
- */
-
-/include/ "fsl/p1010si-pre.dtsi"
-
-/ {
-       model = "fsl,P1010RDB";
-       compatible = "fsl,P1010RDB";
-
-       memory {
-               device_type = "memory";
-       };
-
-       board_ifc: ifc: ifc@ffe1e000 {
-               /* NOR, NAND Flashes and CPLD on board */
-               ranges = <0x0 0x0 0x0 0xee000000 0x02000000
-                         0x1 0x0 0x0 0xff800000 0x00010000
-                         0x3 0x0 0x0 0xffb00000 0x00000020>;
-               reg = <0x0 0xffe1e000 0 0x2000>;
-       };
-
-       board_soc: soc: soc@ffe00000 {
-               ranges = <0x0 0x0 0xffe00000 0x100000>;
-       };
-
-       pci0: pcie@ffe09000 {
-               reg = <0 0xffe09000 0 0x1000>;
-               ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
-                         0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
-               pcie@0 {
-                       ranges = <0x2000000 0x0 0xa0000000
-                                 0x2000000 0x0 0xa0000000
-                                 0x0 0x20000000
-
-                                 0x1000000 0x0 0x0
-                                 0x1000000 0x0 0x0
-                                 0x0 0x100000>;
-               };
-       };
-
-       pci1: pcie@ffe0a000 {
-               reg = <0 0xffe0a000 0 0x1000>;
-               ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
-                         0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
-               pcie@0 {
-                       ranges = <0x2000000 0x0 0x80000000
-                                 0x2000000 0x0 0x80000000
-                                 0x0 0x20000000
-
-                                 0x1000000 0x0 0x0
-                                 0x1000000 0x0 0x0
-                                 0x0 0x100000>;
-               };
-       };
-};
-
-/include/ "p1010rdb.dtsi"
-/include/ "fsl/p1010si-post.dtsi"
index ec7c27a646711c176ba3cd1a51cf5d5e9b9d37b7..ea534efa790d367beade9a27e8a93d27431f208f 100644 (file)
                };
        };
 
-       nand@1,0 {
+       ifc_nand: nand@1,0 {
                #address-cells = <1>;
                #size-cells = <1>;
                compatible = "fsl,ifc-nand";
                reg = <0x1 0x0 0x10000>;
-
-               partition@0 {
-                       /* This location must not be altered  */
-                       /* 1MB for u-boot Bootloader Image */
-                       reg = <0x0 0x00100000>;
-                       label = "NAND U-Boot Image";
-                       read-only;
-               };
-
-               partition@100000 {
-                       /* 1MB for DTB Image */
-                       reg = <0x00100000 0x00100000>;
-                       label = "NAND DTB Image";
-               };
-
-               partition@200000 {
-                       /* 4MB for Linux Kernel Image */
-                       reg = <0x00200000 0x00400000>;
-                       label = "NAND Linux Kernel Image";
-               };
-
-               partition@600000 {
-                       /* 4MB for Compressed Root file System Image */
-                       reg = <0x00600000 0x00400000>;
-                       label = "NAND Compressed RFS Image";
-               };
-
-               partition@a00000 {
-                       /* 15MB for JFFS2 based Root file System */
-                       reg = <0x00a00000 0x00f00000>;
-                       label = "NAND JFFS2 Root File System";
-               };
-
-               partition@1900000 {
-                       /* 7MB for User Area */
-                       reg = <0x01900000 0x00700000>;
-                       label = "NAND User area";
-               };
        };
 
        cpld@3,0 {
 
        mdio@24000 {
                phy0: ethernet-phy@0 {
-                       interrupts = <3 1 0 0>;
                        reg = <0x1>;
                };
 
                phy1: ethernet-phy@1 {
-                       interrupts = <2 1 0 0>;
                        reg = <0x0>;
                };
 
                phy2: ethernet-phy@2 {
-                       interrupts = <2 1 0 0>;
                        reg = <0x2>;
                };
 
diff --git a/arch/powerpc/boot/dts/p1010rdb_32b.dtsi b/arch/powerpc/boot/dts/p1010rdb_32b.dtsi
new file mode 100644 (file)
index 0000000..fdc19aa
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * P1010 RDB Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2013 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.
+ */
+
+memory {
+       device_type = "memory";
+};
+
+board_ifc: ifc: ifc@ffe1e000 {
+       /* NOR, NAND Flashes and CPLD on board */
+       ranges = <0x0 0x0 0x0 0xee000000 0x02000000
+                 0x1 0x0 0x0 0xff800000 0x00010000
+                 0x3 0x0 0x0 0xffb00000 0x00000020>;
+       reg = <0x0 0xffe1e000 0 0x2000>;
+};
+
+board_soc: soc: soc@ffe00000 {
+       ranges = <0x0 0x0 0xffe00000 0x100000>;
+};
+
+pci0: pcie@ffe09000 {
+       reg = <0 0xffe09000 0 0x1000>;
+       ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+                 0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+       pcie@0 {
+               ranges = <0x2000000 0x0 0xa0000000
+                         0x2000000 0x0 0xa0000000
+                         0x0 0x20000000
+
+                         0x1000000 0x0 0x0
+                         0x1000000 0x0 0x0
+                         0x0 0x100000>;
+       };
+};
+
+pci1: pcie@ffe0a000 {
+       reg = <0 0xffe0a000 0 0x1000>;
+       ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+                 0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+       pcie@0 {
+               ranges = <0x2000000 0x0 0x80000000
+                         0x2000000 0x0 0x80000000
+                         0x0 0x20000000
+
+                         0x1000000 0x0 0x0
+                         0x1000000 0x0 0x0
+                         0x0 0x100000>;
+       };
+};
diff --git a/arch/powerpc/boot/dts/p1010rdb_36b.dtsi b/arch/powerpc/boot/dts/p1010rdb_36b.dtsi
new file mode 100644 (file)
index 0000000..de2fcee
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * P1010 RDB Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2013 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.
+ */
+
+memory {
+       device_type = "memory";
+};
+
+board_ifc: ifc: ifc@fffe1e000 {
+       /* NOR, NAND Flashes and CPLD on board */
+       ranges = <0x0 0x0 0xf 0xee000000 0x02000000
+                 0x1 0x0 0xf 0xff800000 0x00010000
+                 0x3 0x0 0xf 0xffb00000 0x00000020>;
+       reg = <0xf 0xffe1e000 0 0x2000>;
+};
+
+board_soc: soc: soc@fffe00000 {
+       ranges = <0x0 0xf 0xffe00000 0x100000>;
+};
+
+pci0: pcie@fffe09000 {
+       reg = <0xf 0xffe09000 0 0x1000>;
+       ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000
+                 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+       pcie@0 {
+               ranges = <0x2000000 0x0 0xc0000000
+                         0x2000000 0x0 0xc0000000
+                         0x0 0x20000000
+
+                         0x1000000 0x0 0x0
+                         0x1000000 0x0 0x0
+                         0x0 0x100000>;
+       };
+};
+
+pci1: pcie@fffe0a000 {
+       reg = <0xf 0xffe0a000 0 0x1000>;
+       ranges = <0x2000000 0x0 0xc0000000 0xc 0x20000000 0x0 0x20000000
+                 0x1000000 0x0 0x00000000 0xf 0xffc10000 0x0 0x10000>;
+       pcie@0 {
+               ranges = <0x2000000 0x0 0xc0000000
+                         0x2000000 0x0 0xc0000000
+                         0x0 0x20000000
+
+                         0x1000000 0x0 0x0
+                         0x1000000 0x0 0x0
+                         0x0 0x100000>;
+       };
+};
index 873da350d01ba6556b136c99a49ffe2569428fb3..957e0dc1dc0f62ceb8507acf115c76f06e8ea8dd 100644 (file)
                         */
                };
                rtc@68 {
-                       compatible = "dallas,ds1339";
+                       compatible = "dallas,ds3232";
                        reg = <0x68>;
+                       interrupts = <0x1 0x1 0 0>;
                };
                adt7461@4c {
                        compatible = "adi,adt7461";
diff --git a/arch/powerpc/boot/dts/p1025twr.dts b/arch/powerpc/boot/dts/p1025twr.dts
new file mode 100644 (file)
index 0000000..9036a49
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * P1025 TWR Device Tree Source (32-bit address map)
+ *
+ * Copyright 2013 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/p1021si-pre.dtsi"
+/ {
+       model = "fsl,P1025";
+       compatible = "fsl,TWR-P1025";
+
+       memory {
+               device_type = "memory";
+       };
+
+       lbc: localbus@ffe05000 {
+               reg = <0 0xffe05000 0 0x1000>;
+
+               /* NOR Flash and SSD1289 */
+               ranges = <0x0 0x0 0x0 0xec000000 0x04000000
+                         0x2 0x0 0x0 0xe0000000 0x00020000>;
+       };
+
+       soc: soc@ffe00000 {
+               ranges = <0x0 0x0 0xffe00000 0x100000>;
+       };
+
+       pci0: pcie@ffe09000 {
+               ranges = <0x2000000 0x0 0xa0000000 0 0xa0000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc10000 0x0 0x10000>;
+               reg = <0 0xffe09000 0 0x1000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0xa0000000
+                                 0x2000000 0x0 0xa0000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       pci1: pcie@ffe0a000 {
+               reg = <0 0xffe0a000 0 0x1000>;
+               ranges = <0x2000000 0x0 0x80000000 0 0x80000000 0x0 0x20000000
+                         0x1000000 0x0 0x00000000 0 0xffc00000 0x0 0x10000>;
+               pcie@0 {
+                       ranges = <0x2000000 0x0 0x80000000
+                                 0x2000000 0x0 0x80000000
+                                 0x0 0x20000000
+
+                                 0x1000000 0x0 0x0
+                                 0x1000000 0x0 0x0
+                                 0x0 0x100000>;
+               };
+       };
+
+       qe: qe@ffe80000 {
+               ranges = <0x0 0x0 0xffe80000 0x40000>;
+               reg = <0 0xffe80000 0 0x480>;
+               brg-frequency = <0>;
+               bus-frequency = <0>;
+       };
+};
+
+/include/ "p1025twr.dtsi"
+/include/ "fsl/p1021si-post.dtsi"
diff --git a/arch/powerpc/boot/dts/p1025twr.dtsi b/arch/powerpc/boot/dts/p1025twr.dtsi
new file mode 100644 (file)
index 0000000..8453501
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * P1025 TWR Device Tree Source stub (no addresses or top-level ranges)
+ *
+ * Copyright 2013 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.
+ */
+
+/{
+       aliases {
+               ethernet3 = &enet3;
+               ethernet4 = &enet4;
+       };
+};
+
+&lbc {
+       nor@0,0 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               compatible = "cfi-flash";
+               reg = <0x0 0x0 0x4000000>;
+               bank-width = <2>;
+               device-width = <1>;
+
+               partition@0 {
+                       /* This location must not be altered  */
+                       /* 256KB for Vitesse 7385 Switch firmware */
+                       reg = <0x0 0x00040000>;
+                       label = "NOR Vitesse-7385 Firmware";
+                       read-only;
+               };
+
+               partition@40000 {
+                       /* 256KB for DTB Image */
+                       reg = <0x00040000 0x00040000>;
+                       label = "NOR DTB Image";
+               };
+
+               partition@80000 {
+                       /* 5.5 MB for Linux Kernel Image */
+                       reg = <0x00080000 0x00580000>;
+                       label = "NOR Linux Kernel Image";
+               };
+
+               partition@400000 {
+                       /* 56.75MB for Root file System */
+                       reg = <0x00600000 0x038c0000>;
+                       label = "NOR Root File System";
+               };
+
+               partition@ec0000 {
+                       /* This location must not be altered  */
+                       /* 256KB for QE ucode firmware*/
+                       reg = <0x03ec0000 0x00040000>;
+                       label = "NOR QE microcode firmware";
+                       read-only;
+               };
+
+               partition@f00000 {
+                       /* This location must not be altered  */
+                       /* 512KB for u-boot Bootloader Image */
+                       /* 512KB for u-boot Environment Variables */
+                       reg = <0x03f00000 0x00100000>;
+                       label = "NOR U-Boot Image";
+                       read-only;
+               };
+       };
+
+       /* CS2 for Display */
+       display@2,0 {
+               compatible = "solomon,ssd1289fb";
+               reg = <0x2 0x0000 0x0004>;
+       };
+
+};
+
+&soc {
+       usb@22000 {
+               phy_type = "ulpi";
+       };
+
+       mdio@24000 {
+               phy0: ethernet-phy@2 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <1 1 0 0>;
+                       reg = <0x2>;
+               };
+
+               phy1: ethernet-phy@1 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <2 1 0 0>;
+                       reg = <0x1>;
+               };
+
+               tbi0: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       mdio@25000 {
+               tbi1: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       mdio@26000 {
+               tbi2: tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       enet0: ethernet@b0000 {
+               phy-handle = <&phy0>;
+               phy-connection-type = "rgmii-id";
+
+       };
+
+       enet1: ethernet@b1000 {
+               status = "disabled";
+       };
+
+       enet2: ethernet@b2000 {
+               phy-handle = <&phy1>;
+               phy-connection-type = "rgmii-id";
+       };
+
+       par_io@e0100 {
+               #address-cells = <1>;
+               #size-cells = <1>;
+               reg = <0xe0100 0x60>;
+               ranges = <0x0 0xe0100 0x60>;
+               device_type = "par_io";
+               num-ports = <3>;
+               pio1: ucc_pin@01 {
+                       pio-map = <
+               /* port  pin  dir  open_drain  assignment  has_irq */
+                               0x1  0x13 0x1  0x0  0x1  0x0    /* QE_MUX_MDC */
+                               0x1  0x14 0x3  0x0  0x1  0x0    /* QE_MUX_MDIO */
+                               0x0  0x17 0x2  0x0  0x2  0x0    /* CLK12 */
+                               0x0  0x18 0x2  0x0  0x1  0x0    /* CLK9 */
+                               0x0  0x7  0x1  0x0  0x2  0x0    /* ENET1_TXD0_SER1_TXD0 */
+                               0x0  0x9  0x1  0x0  0x2  0x0    /* ENET1_TXD1_SER1_TXD1 */
+                               0x0  0xb  0x1  0x0  0x2  0x0    /* ENET1_TXD2_SER1_TXD2 */
+                               0x0  0xc  0x1  0x0  0x2  0x0    /* ENET1_TXD3_SER1_TXD3 */
+                               0x0  0x6  0x2  0x0  0x2  0x0    /* ENET1_RXD0_SER1_RXD0 */
+                               0x0  0xa  0x2  0x0  0x2  0x0    /* ENET1_RXD1_SER1_RXD1 */
+                               0x0  0xe  0x2  0x0  0x2  0x0    /* ENET1_RXD2_SER1_RXD2 */
+                               0x0  0xf  0x2  0x0  0x2  0x0    /* ENET1_RXD3_SER1_RXD3 */
+                               0x0  0x5  0x1  0x0  0x2  0x0    /* ENET1_TX_EN_SER1_RTS_B */
+                               0x0  0xd  0x1  0x0  0x2  0x0    /* ENET1_TX_ER */
+                               0x0  0x4  0x2  0x0  0x2  0x0    /* ENET1_RX_DV_SER1_CTS_B */
+                               0x0  0x8  0x2  0x0  0x2  0x0    /* ENET1_RX_ER_SER1_CD_B */
+                               0x0  0x11 0x2  0x0  0x2  0x0    /* ENET1_CRS */
+                               0x0  0x10 0x2  0x0  0x2  0x0>;    /* ENET1_COL */
+               };
+
+               pio2: ucc_pin@02 {
+                       pio-map = <
+               /* port  pin  dir  open_drain  assignment  has_irq */
+                               0x1  0x13 0x1  0x0  0x1  0x0    /* QE_MUX_MDC */
+                               0x1  0x14 0x3  0x0  0x1  0x0    /* QE_MUX_MDIO */
+                               0x1  0xb  0x2  0x0  0x1  0x0    /* CLK13 */
+                               0x1  0x7  0x1  0x0  0x2  0x0    /* ENET5_TXD0_SER5_TXD0 */
+                               0x1  0xa  0x1  0x0  0x2  0x0    /* ENET5_TXD1_SER5_TXD1 */
+                               0x1  0x6  0x2  0x0  0x2  0x0    /* ENET5_RXD0_SER5_RXD0 */
+                               0x1  0x9  0x2  0x0  0x2  0x0    /* ENET5_RXD1_SER5_RXD1 */
+                               0x1  0x5  0x1  0x0  0x2  0x0    /* ENET5_TX_EN_SER5_RTS_B */
+                               0x1  0x4  0x2  0x0  0x2  0x0    /* ENET5_RX_DV_SER5_CTS_B */
+                               0x1  0x8  0x2  0x0  0x2  0x0>;    /* ENET5_RX_ER_SER5_CD_B */
+               };
+
+               pio3: ucc_pin@03 {
+                       pio-map = <
+               /* port  pin  dir  open_drain  assignment  has_irq */
+                               0x0  0x16 0x2  0x0  0x2  0x0    /* SER7_CD_B*/
+                               0x0  0x12 0x2  0x0  0x2  0x0    /* SER7_CTS_B*/
+                               0x0  0x13 0x1  0x0  0x2  0x0    /* SER7_RTS_B*/
+                               0x0  0x14 0x2  0x0  0x2  0x0    /* SER7_RXD0*/
+                               0x0  0x15 0x1  0x0  0x2  0x0>;    /* SER7_TXD0*/
+               };
+
+               pio4: ucc_pin@04 {
+                       pio-map = <
+               /* port  pin  dir  open_drain  assignment  has_irq */
+                               0x1  0x0  0x2  0x0  0x2  0x0    /* SER3_CD_B*/
+                               0x0  0x1c 0x2  0x0  0x2  0x0    /* SER3_CTS_B*/
+                               0x0  0x1d 0x1  0x0  0x2  0x0    /* SER3_RTS_B*/
+                               0x0  0x1e 0x2  0x0  0x2  0x0    /* SER3_RXD0*/
+                               0x0  0x1f 0x1  0x0  0x2  0x0>;    /* SER3_TXD0*/
+               };
+       };
+};
+
+&qe {
+       enet3: ucc@2000 {
+               device_type = "network";
+               compatible = "ucc_geth";
+               rx-clock-name = "clk12";
+               tx-clock-name = "clk9";
+               pio-handle = <&pio1>;
+               phy-handle = <&qe_phy0>;
+               phy-connection-type = "mii";
+       };
+
+       mdio@2120 {
+               qe_phy0: ethernet-phy@18 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <4 1 0 0>;
+                       reg = <0x18>;
+                       device_type = "ethernet-phy";
+               };
+               qe_phy1: ethernet-phy@19 {
+                       interrupt-parent = <&mpic>;
+                       interrupts = <5 1 0 0>;
+                       reg = <0x19>;
+                       device_type = "ethernet-phy";
+               };
+               tbi-phy@11 {
+                       reg = <0x11>;
+                       device_type = "tbi-phy";
+               };
+       };
+
+       enet4: ucc@2400 {
+               device_type = "network";
+               compatible = "ucc_geth";
+               rx-clock-name = "none";
+               tx-clock-name = "clk13";
+               pio-handle = <&pio2>;
+               phy-handle = <&qe_phy1>;
+               phy-connection-type = "rmii";
+       };
+
+       serial2: ucc@2600 {
+               device_type = "serial";
+               compatible = "ucc_uart";
+               port-number = <0>;
+               rx-clock-name = "brg6";
+               tx-clock-name = "brg6";
+               pio-handle = <&pio3>;
+       };
+
+       serial3: ucc@2200 {
+               device_type = "serial";
+               compatible = "ucc_uart";
+               port-number = <1>;
+               rx-clock-name = "brg2";
+               tx-clock-name = "brg2";
+               pio-handle = <&pio4>;
+       };
+};
index fc7073bc547efaa4e196a80d08be24155fea9695..391a4e299783d84830002c95535bd9a5c6d9c848 100644 (file)
                        #size-cells = <1>;
                        compatible = "xlnx,compound";
                        ethernet@81c00000 {
+                               #address-cells = <1>;
+                               #size-cells = <0>;
                                compatible = "xlnx,xps-ll-temac-1.01.b";
                                device_type = "network";
                                interrupt-parent = <&xps_intc_0>;
diff --git a/arch/powerpc/boot/mvme5100.c b/arch/powerpc/boot/mvme5100.c
new file mode 100644 (file)
index 0000000..cb865f8
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Motorola/Emerson MVME5100 with PPCBug firmware.
+ *
+ * Author: Stephen Chivers <schivers@csc.com>
+ *
+ * Copyright 2013 CSC Australia Pty. Ltd.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ */
+#include "types.h"
+#include "ops.h"
+#include "io.h"
+
+BSS_STACK(4096);
+
+void platform_init(unsigned long r3, unsigned long r4, unsigned long r5)
+{
+       u32                     heapsize;
+
+       heapsize = 0x8000000 - (u32)_end; /* 128M */
+       simple_alloc_init(_end, heapsize, 32, 64);
+       fdt_init(_dtb_start);
+       serial_console_init();
+}
index 2e1af74a64bec5ba3a53ccde16350520ed3f532a..d27a25518b018b03df07110919104ff6811e1b00 100755 (executable)
@@ -265,6 +265,10 @@ epapr)
     link_address='0x20000000'
     pie=-pie
     ;;
+mvme5100)
+    platformo="$object/fixed-head.o $object/mvme5100.o"
+    binary=y
+    ;;
 esac
 
 vmz="$tmpdir/`basename \"$kernel\"`.$ext"
diff --git a/arch/powerpc/configs/85xx/p1023_defconfig b/arch/powerpc/configs/85xx/p1023_defconfig
deleted file mode 100644 (file)
index b06d37d..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-CONFIG_PPC_85xx=y
-CONFIG_SMP=y
-CONFIG_NR_CPUS=2
-CONFIG_SYSVIPC=y
-CONFIG_POSIX_MQUEUE=y
-CONFIG_BSD_PROCESS_ACCT=y
-CONFIG_AUDIT=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_RCU_FANOUT=32
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_KALLSYMS_ALL=y
-CONFIG_EMBEDDED=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-# CONFIG_BLK_DEV_BSG is not set
-CONFIG_PARTITION_ADVANCED=y
-CONFIG_MAC_PARTITION=y
-CONFIG_PHYSICAL_START=0x00000000
-CONFIG_P1023_RDB=y
-CONFIG_P1023_RDS=y
-CONFIG_QUICC_ENGINE=y
-CONFIG_QE_GPIO=y
-CONFIG_CPM2=y
-CONFIG_HIGHMEM=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_BINFMT_MISC=m
-CONFIG_MATH_EMULATION=y
-CONFIG_SWIOTLB=y
-CONFIG_PCI=y
-CONFIG_PCIEPORTBUS=y
-# CONFIG_PCIEAER is not set
-# CONFIG_PCIEASPM is not set
-CONFIG_PCI_MSI=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_XFRM_USER=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_MULTIPLE_TABLES=y
-CONFIG_IP_ROUTE_MULTIPATH=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-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
-CONFIG_IPV6=y
-CONFIG_IP_SCTP=m
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_CFI=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_PHYSMAP_OF=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_FSL_ELBC=y
-CONFIG_PROC_DEVICETREE=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=131072
-CONFIG_EEPROM_AT24=y
-CONFIG_EEPROM_LEGACY=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_CHR_DEV_ST=y
-CONFIG_BLK_DEV_SR=y
-CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
-CONFIG_SCSI_LOGGING=y
-CONFIG_ATA=y
-CONFIG_SATA_FSL=y
-CONFIG_SATA_SIL24=y
-CONFIG_NETDEVICES=y
-CONFIG_DUMMY=y
-CONFIG_FS_ENET=y
-CONFIG_FSL_PQ_MDIO=y
-CONFIG_E1000E=y
-CONFIG_PHYLIB=y
-CONFIG_AT803X_PHY=y
-CONFIG_MARVELL_PHY=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_CICADA_PHY=y
-CONFIG_VITESSE_PHY=y
-CONFIG_FIXED_PHY=y
-CONFIG_INPUT_FF_MEMLESS=m
-# CONFIG_INPUT_MOUSEDEV is not set
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIO_LIBPS2=y
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=2
-CONFIG_SERIAL_8250_RUNTIME_UARTS=2
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
-CONFIG_HW_RANDOM=y
-CONFIG_NVRAM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_CPM=m
-CONFIG_I2C_MPC=y
-CONFIG_GPIO_MPC8XXX=y
-# CONFIG_HWMON is not set
-CONFIG_VIDEO_OUTPUT_CONTROL=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-CONFIG_USB=y
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_MON=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_EHCI_FSL=y
-CONFIG_USB_STORAGE=y
-CONFIG_EDAC=y
-CONFIG_EDAC_MM_EDAC=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_DS1307=y
-CONFIG_RTC_DRV_CMOS=y
-CONFIG_DMADEVICES=y
-CONFIG_FSL_DMA=y
-# CONFIG_NET_DMA is not set
-CONFIG_STAGING=y
-CONFIG_EXT2_FS=y
-CONFIG_EXT3_FS=y
-# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-CONFIG_ZISOFS=y
-CONFIG_UDF_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=y
-CONFIG_NTFS_FS=y
-CONFIG_PROC_KCORE=y
-CONFIG_TMPFS=y
-CONFIG_ADFS_FS=m
-CONFIG_AFFS_FS=m
-CONFIG_HFS_FS=m
-CONFIG_HFSPLUS_FS=m
-CONFIG_BEFS_FS=m
-CONFIG_BFS_FS=m
-CONFIG_EFS_FS=m
-CONFIG_CRAMFS=y
-CONFIG_VXFS_FS=m
-CONFIG_HPFS_FS=m
-CONFIG_QNX4FS_FS=m
-CONFIG_SYSV_FS=m
-CONFIG_UFS_FS=m
-CONFIG_NFS_FS=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_NFSD=y
-CONFIG_CRC_T10DIF=y
-CONFIG_FRAME_WARN=8092
-CONFIG_DEBUG_FS=y
-CONFIG_DETECT_HUNG_TASK=y
-# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
-CONFIG_STRICT_DEVMEM=y
-CONFIG_CRYPTO_PCBC=m
-CONFIG_CRYPTO_SHA256=y
-CONFIG_CRYPTO_SHA512=y
-CONFIG_CRYPTO_AES=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRYPTO_DEV_FSL_CAAM=y
index 69128740c14dcd2c693e2d5d71d713016d15da10..15b1ff5d96e76378bf9e80d93b2e85ecf6f25607 100644 (file)
@@ -70,3 +70,4 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_CRC32_SLICEBY4=y
index 219fd470ed22d402deae87a12ea3ca6333d29384..b8a79d7ee89fae62a28ecad510920bb36916f3f2 100644 (file)
@@ -72,3 +72,4 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_CRC32_SLICEBY4=y
index d2e0fab5ee5b3ec5ac315fe1e9af261cc24ab567..83d3550fdb5400b26f2508ef9e862346e1c004ae 100644 (file)
@@ -31,6 +31,7 @@ CONFIG_C293_PCIE=y
 CONFIG_P1010_RDB=y
 CONFIG_P1022_DS=y
 CONFIG_P1022_RDK=y
+CONFIG_P1023_RDB=y
 CONFIG_P1023_RDS=y
 CONFIG_SOCRATES=y
 CONFIG_KSI8560=y
@@ -113,6 +114,7 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_LEGACY=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
@@ -211,6 +213,7 @@ CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_CMOS=y
+CONFIG_RTC_DRV_DS1307=y
 CONFIG_DMADEVICES=y
 CONFIG_FSL_DMA=y
 # CONFIG_NET_DMA is not set
index 4cb7b59e98bd84259aefb48d8515fd3a4d8da32d..4b686294feb49592594f91c04abaea8377dca52d 100644 (file)
@@ -34,6 +34,7 @@ CONFIG_C293_PCIE=y
 CONFIG_P1010_RDB=y
 CONFIG_P1022_DS=y
 CONFIG_P1022_RDK=y
+CONFIG_P1023_RDB=y
 CONFIG_P1023_RDS=y
 CONFIG_SOCRATES=y
 CONFIG_KSI8560=y
@@ -116,6 +117,7 @@ CONFIG_BLK_DEV_LOOP=y
 CONFIG_BLK_DEV_NBD=y
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_SIZE=131072
+CONFIG_EEPROM_AT24=y
 CONFIG_EEPROM_LEGACY=y
 CONFIG_BLK_DEV_SD=y
 CONFIG_CHR_DEV_ST=y
@@ -212,6 +214,7 @@ CONFIG_EDAC=y
 CONFIG_EDAC_MM_EDAC=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_DRV_CMOS=y
+CONFIG_RTC_DRV_DS1307=y
 CONFIG_DMADEVICES=y
 CONFIG_FSL_DMA=y
 # CONFIG_NET_DMA is not set
index 5c258823e694814a0c7c3e07b0391b919aa29fd9..d954e80c286a92fe1be2b8402fa8f77e114da0ba 100644 (file)
@@ -55,3 +55,4 @@ CONFIG_PARTITION_ADVANCED=y
 CONFIG_CRC_CCITT=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRC32_SLICEBY4=y
index 9e146cdf63ded05591f572fa3b98d1b8400fafa0..3f47d00a10c0d9e8557d26e78f62598f6d629d4d 100644 (file)
@@ -78,3 +78,4 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_CRC32_SLICEBY4=y
diff --git a/arch/powerpc/configs/mvme5100_defconfig b/arch/powerpc/configs/mvme5100_defconfig
new file mode 100644 (file)
index 0000000..93c7752
--- /dev/null
@@ -0,0 +1,144 @@
+CONFIG_SYSVIPC=y
+CONFIG_POSIX_MQUEUE=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_PID_NS is not set
+# CONFIG_NET_NS is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_COMPAT_BRK is not set
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_PPC_CHRP is not set
+# CONFIG_PPC_PMAC is not set
+CONFIG_EMBEDDED6xx=y
+CONFIG_MVME5100=y
+CONFIG_KVM_GUEST=y
+CONFIG_HZ_100=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_COMPACTION is not set
+CONFIG_CMDLINE_BOOL=y
+CONFIG_CMDLINE="console=ttyS0,9600 ip=dhcp root=/dev/nfs"
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+CONFIG_NETFILTER=y
+CONFIG_NF_CONNTRACK=m
+CONFIG_NF_CT_PROTO_SCTP=m
+CONFIG_NF_CONNTRACK_AMANDA=m
+CONFIG_NF_CONNTRACK_FTP=m
+CONFIG_NF_CONNTRACK_H323=m
+CONFIG_NF_CONNTRACK_IRC=m
+CONFIG_NF_CONNTRACK_NETBIOS_NS=m
+CONFIG_NF_CONNTRACK_PPTP=m
+CONFIG_NF_CONNTRACK_SIP=m
+CONFIG_NF_CONNTRACK_TFTP=m
+CONFIG_NETFILTER_XT_MATCH_MAC=m
+CONFIG_NETFILTER_XT_MATCH_PKTTYPE=m
+CONFIG_NETFILTER_XT_MATCH_STATE=m
+CONFIG_NF_CONNTRACK_IPV4=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_FILTER=m
+CONFIG_IP_NF_TARGET_REJECT=m
+CONFIG_IP_NF_MANGLE=m
+CONFIG_IP_NF_TARGET_ECN=m
+CONFIG_IP_NF_TARGET_TTL=m
+CONFIG_IP_NF_RAW=m
+CONFIG_IP_NF_ARPTABLES=m
+CONFIG_IP_NF_ARPFILTER=m
+CONFIG_IP_NF_ARP_MANGLE=m
+CONFIG_LAPB=m
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_PROC_DEVICETREE=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=2
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_EEPROM_LEGACY=m
+CONFIG_NETDEVICES=y
+CONFIG_TUN=m
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_E100=y
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO is not set
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_NR_UARTS=10
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_MANY_PORTS=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_HW_RANDOM=y
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+CONFIG_I2C_MPC=y
+# CONFIG_HWMON is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_HID is not set
+# CONFIG_USB_SUPPORT is not set
+# CONFIG_IOMMU_SUPPORT is not set
+CONFIG_VME_BUS=m
+CONFIG_VME_CA91CX42=m
+CONFIG_EXT2_FS=m
+CONFIG_EXT3_FS=m
+# CONFIG_EXT3_DEFAULTS_TO_ORDERED is not set
+CONFIG_XFS_FS=m
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+CONFIG_ZISOFS=y
+CONFIG_UDF_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_PROC_KCORE=y
+CONFIG_TMPFS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_NFS_V4=y
+CONFIG_ROOT_NFS=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+CONFIG_CIFS=m
+CONFIG_NLS=y
+CONFIG_NLS_CODEPAGE_437=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_ISO8859_1=m
+CONFIG_NLS_UTF8=m
+CONFIG_CRC_CCITT=m
+CONFIG_CRC_T10DIF=y
+CONFIG_XZ_DEC=y
+CONFIG_XZ_DEC_X86=y
+CONFIG_XZ_DEC_IA64=y
+CONFIG_XZ_DEC_ARM=y
+CONFIG_XZ_DEC_ARMTHUMB=y
+CONFIG_XZ_DEC_SPARC=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DETECT_HUNG_TASK=y
+CONFIG_DEFAULT_HUNG_TASK_TIMEOUT=20
+CONFIG_CRYPTO_CBC=y
+CONFIG_CRYPTO_PCBC=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=m
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_DES=y
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
index 581a3bcae7283607bed819cb9d26f7a2b6c6b96f..e015896b7e5cebacaf46bb713ab16e2fe2128747 100644 (file)
@@ -186,6 +186,7 @@ CONFIG_SCSI_DH_RDAC=m
 CONFIG_SCSI_DH_ALUA=m
 CONFIG_ATA=y
 CONFIG_SATA_SIL24=y
+CONFIG_SATA_MV=y
 CONFIG_SATA_SVW=y
 CONFIG_MD=y
 CONFIG_BLK_DEV_MD=y
index 8616fde0896f41ba81eb32b1c5261aed3892cfa6..4b6f8bf104e0687eb331c9c7d383855966ec5143 100644 (file)
@@ -84,3 +84,4 @@ CONFIG_DEBUG_KERNEL=y
 CONFIG_DETECT_HUNG_TASK=y
 CONFIG_DEBUG_INFO=y
 # CONFIG_RCU_CPU_STALL_DETECTOR is not set
+CONFIG_CRC32_SLICEBY4=y
index 910194e9a1e2a2eab5f64d05be6cf9a522cb33a0..a5e9a7d494d8bd685104397bff26d0265dc15e54 100644 (file)
 #include <asm/asm-compat.h>
 #include <asm/synch.h>
 
+/* PPC bit number conversion */
+#define PPC_BITLSHIFT(be)      (BITS_PER_LONG - 1 - (be))
+#define PPC_BIT(bit)           (1UL << PPC_BITLSHIFT(bit))
+#define PPC_BITMASK(bs, be)    ((PPC_BIT(bs) - PPC_BIT(be)) | PPC_BIT(bs))
+
 /*
  * clear_bit doesn't imply a memory barrier
  */
index 9e495c9a6a889d68bca11e1575ee82c3422b7348..ed0afc1e44a43324a31fb59994b42a768ecb8e33 100644 (file)
@@ -41,8 +41,20 @@ struct ppc64_caches {
 extern struct ppc64_caches ppc64_caches;
 #endif /* __powerpc64__ && ! __ASSEMBLY__ */
 
-#if !defined(__ASSEMBLY__)
+#if defined(__ASSEMBLY__)
+/*
+ * For a snooping icache, we still need a dummy icbi to purge all the
+ * prefetched instructions from the ifetch buffers. We also need a sync
+ * before the icbi to order the the actual stores to memory that might
+ * have modified instructions with the icbi.
+ */
+#define PURGE_PREFETCHED_INS   \
+       sync;                   \
+       icbi    0,r3;           \
+       sync;                   \
+       isync
 
+#else
 #define __read_mostly __attribute__((__section__(".data..read_mostly")))
 
 #ifdef CONFIG_6xx
diff --git a/arch/powerpc/include/asm/clk_interface.h b/arch/powerpc/include/asm/clk_interface.h
deleted file mode 100644 (file)
index ab1882c..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __ASM_POWERPC_CLK_INTERFACE_H
-#define __ASM_POWERPC_CLK_INTERFACE_H
-
-#include <linux/clk.h>
-
-struct clk_interface {
-       struct clk*     (*clk_get)      (struct device *dev, const char *id);
-       int             (*clk_enable)   (struct clk *clk);
-       void            (*clk_disable)  (struct clk *clk);
-       unsigned long   (*clk_get_rate) (struct clk *clk);
-       void            (*clk_put)      (struct clk *clk);
-       long            (*clk_round_rate) (struct clk *clk, unsigned long rate);
-       int             (*clk_set_rate) (struct clk *clk, unsigned long rate);
-       int             (*clk_set_parent) (struct clk *clk, struct clk *parent);
-       struct clk*     (*clk_get_parent) (struct clk *clk);
-};
-
-extern struct clk_interface clk_functions;
-
-#endif /* __ASM_POWERPC_CLK_INTERFACE_H */
index e245aab7f191cc98bea0e6f8868fb7fb67d3cffe..d463c68fe7f05fa798a151ea179a5f88a842ddee 100644 (file)
@@ -300,6 +300,7 @@ __cmpxchg_local(volatile void *ptr, unsigned long old, unsigned long new,
        BUILD_BUG_ON(sizeof(*(ptr)) != 8);                              \
        cmpxchg_local((ptr), (o), (n));                                 \
   })
+#define cmpxchg64_relaxed      cmpxchg64_local
 #else
 #include <asm-generic/cmpxchg-local.h>
 #define cmpxchg64_local(ptr, o, n) __cmpxchg64_local_generic((ptr), (o), (n))
index a6f8c7a5cbb74f61925243a1ca42bc183d80361a..97e02f985df8e47946438ecc1b0ba2f040ee7bf5 100644 (file)
@@ -34,6 +34,13 @@ int instr_is_branch_to_addr(const unsigned int *instr, unsigned long addr);
 unsigned long branch_target(const unsigned int *instr);
 unsigned int translate_branch(const unsigned int *dest,
                              const unsigned int *src);
+#ifdef CONFIG_PPC_BOOK3E_64
+void __patch_exception(int exc, unsigned long addr);
+#define patch_exception(exc, name) do { \
+       extern unsigned int name; \
+       __patch_exception((exc), (unsigned long)&name); \
+} while (0)
+#endif
 
 static inline unsigned long ppc_function_entry(void *func)
 {
index 0d4939ba48e72167a9a496f4f10a805d0badd3eb..617cc767c07681b109c5acd54f667cc3274956b5 100644 (file)
@@ -90,6 +90,18 @@ struct cpu_spec {
         * if the error is fatal, 1 if it was fully recovered and 0 to
         * pass up (not CPU originated) */
        int             (*machine_check)(struct pt_regs *regs);
+
+       /*
+        * Processor specific early machine check handler which is
+        * called in real mode to handle SLB and TLB errors.
+        */
+       long            (*machine_check_early)(struct pt_regs *regs);
+
+       /*
+        * Processor specific routine to flush tlbs.
+        */
+       void            (*flush_tlb)(unsigned long inval_selector);
+
 };
 
 extern struct cpu_spec         *cur_cpu_spec;
index d3e5e9bc8f946fa3fd7158a3ecc931561c71c1a3..9e39ceb1d19fd706014794a6918f671ef12a5a58 100644 (file)
@@ -90,7 +90,8 @@ struct eeh_pe {
 #define EEH_DEV_IRQ_DISABLED   (1 << 3)        /* Interrupt disabled   */
 #define EEH_DEV_DISCONNECTED   (1 << 4)        /* Removing from PE     */
 
-#define EEH_DEV_SYSFS          (1 << 8)        /* Sysfs created        */
+#define EEH_DEV_NO_HANDLER     (1 << 8)        /* No error handler     */
+#define EEH_DEV_SYSFS          (1 << 9)        /* Sysfs created        */
 
 struct eeh_dev {
        int mode;                       /* EEH mode                     */
@@ -117,6 +118,16 @@ static inline struct pci_dev *eeh_dev_to_pci_dev(struct eeh_dev *edev)
        return edev ? edev->pdev : NULL;
 }
 
+/* Return values from eeh_ops::next_error */
+enum {
+       EEH_NEXT_ERR_NONE = 0,
+       EEH_NEXT_ERR_INF,
+       EEH_NEXT_ERR_FROZEN_PE,
+       EEH_NEXT_ERR_FENCED_PHB,
+       EEH_NEXT_ERR_DEAD_PHB,
+       EEH_NEXT_ERR_DEAD_IOC
+};
+
 /*
  * The struct is used to trace the registered EEH operation
  * callback functions. Actually, those operation callback
@@ -157,6 +168,7 @@ struct eeh_ops {
        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);
+       int (*restore_config)(struct device_node *dn);
 };
 
 extern struct eeh_ops *eeh_ops;
index 86b0ac79990ca4ebda1ade6d67524d588bb148e9..334459ad145b4e2ad417b4d359507a29f14ac617 100644 (file)
@@ -460,5 +460,116 @@ static inline unsigned int ev_idle(void)
 
        return r3;
 }
+
+#ifdef CONFIG_EPAPR_PARAVIRT
+static inline unsigned long epapr_hypercall(unsigned long *in,
+                           unsigned long *out,
+                           unsigned long nr)
+{
+       unsigned long register r0 asm("r0");
+       unsigned long register r3 asm("r3") = in[0];
+       unsigned long register r4 asm("r4") = in[1];
+       unsigned long register r5 asm("r5") = in[2];
+       unsigned long register r6 asm("r6") = in[3];
+       unsigned long register r7 asm("r7") = in[4];
+       unsigned long register r8 asm("r8") = in[5];
+       unsigned long register r9 asm("r9") = in[6];
+       unsigned long register r10 asm("r10") = in[7];
+       unsigned long register r11 asm("r11") = nr;
+       unsigned long register r12 asm("r12");
+
+       asm volatile("bl        epapr_hypercall_start"
+                    : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6),
+                      "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11),
+                      "=r"(r12)
+                    : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8),
+                      "r"(r9), "r"(r10), "r"(r11)
+                    : "memory", "cc", "xer", "ctr", "lr");
+
+       out[0] = r4;
+       out[1] = r5;
+       out[2] = r6;
+       out[3] = r7;
+       out[4] = r8;
+       out[5] = r9;
+       out[6] = r10;
+       out[7] = r11;
+
+       return r3;
+}
+#else
+static unsigned long epapr_hypercall(unsigned long *in,
+                                  unsigned long *out,
+                                  unsigned long nr)
+{
+       return EV_UNIMPLEMENTED;
+}
+#endif
+
+static inline long epapr_hypercall0_1(unsigned int nr, unsigned long *r2)
+{
+       unsigned long in[8];
+       unsigned long out[8];
+       unsigned long r;
+
+       r = epapr_hypercall(in, out, nr);
+       *r2 = out[0];
+
+       return r;
+}
+
+static inline long epapr_hypercall0(unsigned int nr)
+{
+       unsigned long in[8];
+       unsigned long out[8];
+
+       return epapr_hypercall(in, out, nr);
+}
+
+static inline long epapr_hypercall1(unsigned int nr, unsigned long p1)
+{
+       unsigned long in[8];
+       unsigned long out[8];
+
+       in[0] = p1;
+       return epapr_hypercall(in, out, nr);
+}
+
+static inline long epapr_hypercall2(unsigned int nr, unsigned long p1,
+                                   unsigned long p2)
+{
+       unsigned long in[8];
+       unsigned long out[8];
+
+       in[0] = p1;
+       in[1] = p2;
+       return epapr_hypercall(in, out, nr);
+}
+
+static inline long epapr_hypercall3(unsigned int nr, unsigned long p1,
+                                   unsigned long p2, unsigned long p3)
+{
+       unsigned long in[8];
+       unsigned long out[8];
+
+       in[0] = p1;
+       in[1] = p2;
+       in[2] = p3;
+       return epapr_hypercall(in, out, nr);
+}
+
+static inline long epapr_hypercall4(unsigned int nr, unsigned long p1,
+                                   unsigned long p2, unsigned long p3,
+                                   unsigned long p4)
+{
+       unsigned long in[8];
+       unsigned long out[8];
+
+       in[0] = p1;
+       in[1] = p2;
+       in[2] = p3;
+       in[3] = p4;
+       return epapr_hypercall(in, out, nr);
+}
 #endif /* !__ASSEMBLY__ */
 #endif /* _EPAPR_HCALLS_H */
index 243ce69ad685ffd335041537e6f0b33b0aafe3df..66830618cc19b2f4b12a5b6cefa8d1663425187e 100644 (file)
@@ -301,9 +301,12 @@ do_kvm_##n:                                                                \
        beq     4f;                     /* if from kernel mode          */ \
        ACCOUNT_CPU_USER_ENTRY(r9, r10);                                   \
        SAVE_PPR(area, r9, r10);                                           \
-4:     std     r2,GPR2(r1);            /* save r2 in stackframe        */ \
-       SAVE_4GPRS(3, r1);              /* save r3 - r6 in stackframe   */ \
-       SAVE_2GPRS(7, r1);              /* save r7, r8 in stackframe    */ \
+4:     EXCEPTION_PROLOG_COMMON_2(area)                                    \
+       EXCEPTION_PROLOG_COMMON_3(n)                                       \
+       ACCOUNT_STOLEN_TIME
+
+/* Save original regs values from save area to stack frame. */
+#define EXCEPTION_PROLOG_COMMON_2(area)                                           \
        ld      r9,area+EX_R9(r13);     /* move r9, r10 to stackframe   */ \
        ld      r10,area+EX_R10(r13);                                      \
        std     r9,GPR9(r1);                                               \
@@ -318,11 +321,16 @@ do_kvm_##n:                                                               \
        ld      r10,area+EX_CFAR(r13);                                     \
        std     r10,ORIG_GPR3(r1);                                         \
        END_FTR_SECTION_NESTED(CPU_FTR_CFAR, CPU_FTR_CFAR, 66);            \
+       GET_CTR(r10, area);                                                \
+       std     r10,_CTR(r1);
+
+#define EXCEPTION_PROLOG_COMMON_3(n)                                      \
+       std     r2,GPR2(r1);            /* save r2 in stackframe        */ \
+       SAVE_4GPRS(3, r1);              /* save r3 - r6 in stackframe   */ \
+       SAVE_2GPRS(7, r1);              /* save r7, r8 in stackframe    */ \
        mflr    r9;                     /* Get LR, later save to stack  */ \
        ld      r2,PACATOC(r13);        /* get kernel TOC into r2       */ \
        std     r9,_LINK(r1);                                              \
-       GET_CTR(r10, area);                                                \
-       std     r10,_CTR(r1);                                              \
        lbz     r10,PACASOFTIRQEN(r13);                            \
        mfspr   r11,SPRN_XER;           /* save XER in stackframe       */ \
        std     r10,SOFTE(r1);                                             \
@@ -332,8 +340,7 @@ do_kvm_##n:                                                         \
        li      r10,0;                                                     \
        ld      r11,exception_marker@toc(r2);                              \
        std     r10,RESULT(r1);         /* clear regs->result           */ \
-       std     r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame      */ \
-       ACCOUNT_STOLEN_TIME
+       std     r11,STACK_FRAME_OVERHEAD-16(r1); /* mark the frame      */
 
 /*
  * Exception vectors.
index 420b45368fcff05b5534a3f9bbcb396279bc1cb5..067fb0dca549b86fc4ad02cca3b180718c2a9593 100644 (file)
@@ -285,7 +285,7 @@ struct fsl_lbc_ctrl {
        /* device info */
        struct device                   *dev;
        struct fsl_lbc_regs __iomem     *regs;
-       int                             irq;
+       int                             irq[2];
        wait_queue_head_t               irq_wait;
        spinlock_t                      lock;
        void                            *nand;
index 3bdcfce2c42a926bebc7c2f580ee720f96350818..418fb654370d09c70837943fe399dba75a10cfd2 100644 (file)
@@ -6,7 +6,8 @@
 
 typedef struct {
        unsigned int __softirq_pending;
-       unsigned int timer_irqs;
+       unsigned int timer_irqs_event;
+       unsigned int timer_irqs_others;
        unsigned int pmu_irqs;
        unsigned int mce_exceptions;
        unsigned int spurious_irqs;
index 575fbf81fad02dcd8e946cecfa9c5d5c35e11810..97d3869991ca691ebf0342b496ebe767aee7492a 100644 (file)
@@ -191,8 +191,24 @@ DEF_MMIO_OUT_D(out_le32, 32, stw);
 
 #endif /* __BIG_ENDIAN */
 
+/*
+ * Cache inhibitied accessors for use in real mode, you don't want to use these
+ * unless you know what you're doing.
+ *
+ * NB. These use the cpu byte ordering.
+ */
+DEF_MMIO_OUT_X(out_rm8,   8, stbcix);
+DEF_MMIO_OUT_X(out_rm16, 16, sthcix);
+DEF_MMIO_OUT_X(out_rm32, 32, stwcix);
+DEF_MMIO_IN_X(in_rm8,   8, lbzcix);
+DEF_MMIO_IN_X(in_rm16, 16, lhzcix);
+DEF_MMIO_IN_X(in_rm32, 32, lwzcix);
+
 #ifdef __powerpc64__
 
+DEF_MMIO_OUT_X(out_rm64, 64, stdcix);
+DEF_MMIO_IN_X(in_rm64, 64, ldcix);
+
 #ifdef __BIG_ENDIAN__
 DEF_MMIO_OUT_D(out_be64, 64, std);
 DEF_MMIO_IN_D(in_be64, 64, ld);
index c34656a8925e2f8c3d64d42f7f4efd79dbe36872..f7a8036579b5a43d19ea0730b7e541b61272ab13 100644 (file)
 #include <asm/machdep.h>
 #include <asm/types.h>
 
-#define IOMMU_PAGE_SHIFT      12
-#define IOMMU_PAGE_SIZE       (ASM_CONST(1) << IOMMU_PAGE_SHIFT)
-#define IOMMU_PAGE_MASK       (~((1 << IOMMU_PAGE_SHIFT) - 1))
-#define IOMMU_PAGE_ALIGN(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE)
+#define IOMMU_PAGE_SHIFT_4K      12
+#define IOMMU_PAGE_SIZE_4K       (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K)
+#define IOMMU_PAGE_MASK_4K       (~((1 << IOMMU_PAGE_SHIFT_4K) - 1))
+#define IOMMU_PAGE_ALIGN_4K(addr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE_4K)
+
+#define IOMMU_PAGE_SIZE(tblptr) (ASM_CONST(1) << (tblptr)->it_page_shift)
+#define IOMMU_PAGE_MASK(tblptr) (~((1 << (tblptr)->it_page_shift) - 1))
+#define IOMMU_PAGE_ALIGN(addr, tblptr) _ALIGN_UP(addr, IOMMU_PAGE_SIZE(tblptr))
 
 /* Boot time flags */
 extern int iommu_is_off;
 extern int iommu_force_on;
 
-/* Pure 2^n version of get_order */
-static __inline__ __attribute_const__ int get_iommu_order(unsigned long size)
-{
-       return __ilog2((size - 1) >> IOMMU_PAGE_SHIFT) + 1;
-}
-
-
 /*
  * IOMAP_MAX_ORDER defines the largest contiguous block
  * of dma space we can get.  IOMAP_MAX_ORDER = 13
@@ -76,11 +73,20 @@ struct iommu_table {
        struct iommu_pool large_pool;
        struct iommu_pool pools[IOMMU_NR_POOLS];
        unsigned long *it_map;       /* A simple allocation bitmap for now */
+       unsigned long  it_page_shift;/* table iommu page size */
 #ifdef CONFIG_IOMMU_API
        struct iommu_group *it_group;
 #endif
 };
 
+/* Pure 2^n version of get_order */
+static inline __attribute_const__
+int get_iommu_order(unsigned long size, struct iommu_table *tbl)
+{
+       return __ilog2((size - 1) >> tbl->it_page_shift) + 1;
+}
+
+
 struct scatterlist;
 
 static inline void set_iommu_table_base(struct device *dev, void *base)
@@ -101,8 +107,34 @@ extern void iommu_free_table(struct iommu_table *tbl, const char *node_name);
  */
 extern struct iommu_table *iommu_init_table(struct iommu_table * tbl,
                                            int nid);
+#ifdef CONFIG_IOMMU_API
 extern void iommu_register_group(struct iommu_table *tbl,
                                 int pci_domain_number, unsigned long pe_num);
+extern int iommu_add_device(struct device *dev);
+extern void iommu_del_device(struct device *dev);
+#else
+static inline void iommu_register_group(struct iommu_table *tbl,
+                                       int pci_domain_number,
+                                       unsigned long pe_num)
+{
+}
+
+static inline int iommu_add_device(struct device *dev)
+{
+       return 0;
+}
+
+static inline void iommu_del_device(struct device *dev)
+{
+}
+#endif /* !CONFIG_IOMMU_API */
+
+static inline void set_iommu_table_base_and_group(struct device *dev,
+                                                 void *base)
+{
+       set_iommu_table_base(dev, base);
+       iommu_add_device(dev);
+}
 
 extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
                        struct scatterlist *sglist, int nelems,
index 1bd92fd43cfb7fc8a14f0bfeeaed62f50700f07d..19eb74a95b592f8c41b2562d32244906debe0468 100644 (file)
@@ -74,6 +74,7 @@
 #define BOOKE_INTERRUPT_GUEST_DBELL_CRIT 39
 #define BOOKE_INTERRUPT_HV_SYSCALL 40
 #define BOOKE_INTERRUPT_HV_PRIV 41
+#define BOOKE_INTERRUPT_LRAT_ERROR 42
 
 /* book3s */
 
 #define BOOK3S_INTERRUPT_FP_UNAVAIL    0x800
 #define BOOK3S_INTERRUPT_DECREMENTER   0x900
 #define BOOK3S_INTERRUPT_HV_DECREMENTER        0x980
+#define BOOK3S_INTERRUPT_DOORBELL      0xa00
 #define BOOK3S_INTERRUPT_SYSCALL       0xc00
 #define BOOK3S_INTERRUPT_TRACE         0xd00
 #define BOOK3S_INTERRUPT_H_DATA_STORAGE        0xe00
 #define BOOK3S_INTERRUPT_H_INST_STORAGE        0xe20
 #define BOOK3S_INTERRUPT_H_EMUL_ASSIST 0xe40
+#define BOOK3S_INTERRUPT_H_DOORBELL    0xe80
 #define BOOK3S_INTERRUPT_PERFMON       0xf00
 #define BOOK3S_INTERRUPT_ALTIVEC       0xf20
 #define BOOK3S_INTERRUPT_VSX           0xf40
+#define BOOK3S_INTERRUPT_H_FAC_UNAVAIL 0xf80
 
 #define BOOK3S_IRQPRIO_SYSTEM_RESET            0
 #define BOOK3S_IRQPRIO_DATA_SEGMENT            1
index bc23b1ba798068b1c5a1f21e93da8bd47018ff55..83851aabfdc8694c55a09e4af7686975e44d7cf2 100644 (file)
@@ -186,9 +186,6 @@ extern void kvmppc_update_lpcr(struct kvm *kvm, unsigned long lpcr,
 
 extern void kvmppc_entry_trampoline(void);
 extern void kvmppc_hv_entry_trampoline(void);
-extern void kvmppc_load_up_fpu(void);
-extern void kvmppc_load_up_altivec(void);
-extern void kvmppc_load_up_vsx(void);
 extern u32 kvmppc_alignment_dsisr(struct kvm_vcpu *vcpu, unsigned int inst);
 extern ulong kvmppc_alignment_dar(struct kvm_vcpu *vcpu, unsigned int inst);
 extern int kvmppc_h_pr(struct kvm_vcpu *vcpu, unsigned long cmd);
@@ -271,16 +268,25 @@ static inline ulong kvmppc_get_pc(struct kvm_vcpu *vcpu)
        return vcpu->arch.pc;
 }
 
-static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
+static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
 {
-       ulong pc = kvmppc_get_pc(vcpu);
+       return (vcpu->arch.shared->msr & MSR_LE) != (MSR_KERNEL & MSR_LE);
+}
 
+static inline u32 kvmppc_get_last_inst_internal(struct kvm_vcpu *vcpu, ulong pc)
+{
        /* Load the instruction manually if it failed to do so in the
         * exit path */
        if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED)
                kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false);
 
-       return vcpu->arch.last_inst;
+       return kvmppc_need_byteswap(vcpu) ? swab32(vcpu->arch.last_inst) :
+               vcpu->arch.last_inst;
+}
+
+static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
+{
+       return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu));
 }
 
 /*
@@ -290,14 +296,7 @@ static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
  */
 static inline u32 kvmppc_get_last_sc(struct kvm_vcpu *vcpu)
 {
-       ulong pc = kvmppc_get_pc(vcpu) - 4;
-
-       /* Load the instruction manually if it failed to do so in the
-        * exit path */
-       if (vcpu->arch.last_inst == KVM_INST_FETCH_FAILED)
-               kvmppc_ld(vcpu, &pc, sizeof(u32), &vcpu->arch.last_inst, false);
-
-       return vcpu->arch.last_inst;
+       return kvmppc_get_last_inst_internal(vcpu, kvmppc_get_pc(vcpu) - 4);
 }
 
 static inline ulong kvmppc_get_fault_dar(struct kvm_vcpu *vcpu)
index 192917d2239c4ed5a0eafd36b1206d176f0dddaa..f3a91dc02c981f216cc60b613347c71f988c8a7d 100644 (file)
@@ -88,6 +88,7 @@ struct kvmppc_host_state {
        u8 hwthread_req;
        u8 hwthread_state;
        u8 host_ipi;
+       u8 ptid;
        struct kvm_vcpu *kvm_vcpu;
        struct kvmppc_vcore *kvm_vcore;
        unsigned long xics_phys;
index dd8f61510dfd01151b5d7035dd8cee7c30ac45a7..80d46b5a7efb49cc6de436e45da6b0b5e690d9cf 100644 (file)
@@ -63,6 +63,12 @@ static inline u32 kvmppc_get_xer(struct kvm_vcpu *vcpu)
        return vcpu->arch.xer;
 }
 
+static inline bool kvmppc_need_byteswap(struct kvm_vcpu *vcpu)
+{
+       /* XXX Would need to check TLB entry */
+       return false;
+}
+
 static inline u32 kvmppc_get_last_inst(struct kvm_vcpu *vcpu)
 {
        return vcpu->arch.last_inst;
index 237d1d25b44815d3c65c17465bc3c53bff3e1f5c..1eaea2dea1745e6310eb3918f2a99c0e2d8bd767 100644 (file)
@@ -288,6 +288,7 @@ struct kvmppc_vcore {
        int n_woken;
        int nap_count;
        int napping_threads;
+       int first_vcpuid;
        u16 pcpu;
        u16 last_cpu;
        u8 vcore_state;
@@ -298,10 +299,12 @@ struct kvmppc_vcore {
        u64 stolen_tb;
        u64 preempt_tb;
        struct kvm_vcpu *runner;
+       struct kvm *kvm;
        u64 tb_offset;          /* guest timebase - host timebase */
        ulong lpcr;
        u32 arch_compat;
        ulong pcr;
+       ulong dpdes;            /* doorbell state (POWER8) */
 };
 
 #define VCORE_ENTRY_COUNT(vc)  ((vc)->entry_exit_count & 0xff)
@@ -410,8 +413,7 @@ struct kvm_vcpu_arch {
 
        ulong gpr[32];
 
-       u64 fpr[32];
-       u64 fpscr;
+       struct thread_fp_state fp;
 
 #ifdef CONFIG_SPE
        ulong evr[32];
@@ -420,12 +422,7 @@ struct kvm_vcpu_arch {
        u64 acc;
 #endif
 #ifdef CONFIG_ALTIVEC
-       vector128 vr[32];
-       vector128 vscr;
-#endif
-
-#ifdef CONFIG_VSX
-       u64 vsr[64];
+       struct thread_vr_state vr;
 #endif
 
 #ifdef CONFIG_KVM_BOOKE_HV
@@ -452,6 +449,7 @@ struct kvm_vcpu_arch {
        ulong pc;
        ulong ctr;
        ulong lr;
+       ulong tar;
 
        ulong xer;
        u32 cr;
@@ -461,13 +459,30 @@ struct kvm_vcpu_arch {
        ulong guest_owned_ext;
        ulong purr;
        ulong spurr;
+       ulong ic;
+       ulong vtb;
        ulong dscr;
        ulong amr;
        ulong uamor;
+       ulong iamr;
        u32 ctrl;
+       u32 dabrx;
        ulong dabr;
+       ulong dawr;
+       ulong dawrx;
+       ulong ciabr;
        ulong cfar;
        ulong ppr;
+       ulong pspb;
+       ulong fscr;
+       ulong ebbhr;
+       ulong ebbrr;
+       ulong bescr;
+       ulong csigr;
+       ulong tacr;
+       ulong tcscr;
+       ulong acop;
+       ulong wort;
        ulong shadow_srr1;
 #endif
        u32 vrsave; /* also USPRG0 */
@@ -502,10 +517,33 @@ struct kvm_vcpu_arch {
        u32 ccr1;
        u32 dbsr;
 
-       u64 mmcr[3];
+       u64 mmcr[5];
        u32 pmc[8];
+       u32 spmc[2];
        u64 siar;
        u64 sdar;
+       u64 sier;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       u64 tfhar;
+       u64 texasr;
+       u64 tfiar;
+
+       u32 cr_tm;
+       u64 lr_tm;
+       u64 ctr_tm;
+       u64 amr_tm;
+       u64 ppr_tm;
+       u64 dscr_tm;
+       u64 tar_tm;
+
+       ulong gpr_tm[32];
+
+       struct thread_fp_state fp_tm;
+
+       struct thread_vr_state vr_tm;
+       u32 vrsave_tm; /* also USPRG0 */
+
+#endif
 
 #ifdef CONFIG_KVM_EXIT_TIMING
        struct mutex exit_timing_lock;
@@ -546,6 +584,7 @@ struct kvm_vcpu_arch {
 #endif
        gpa_t paddr_accessed;
        gva_t vaddr_accessed;
+       pgd_t *pgdir;
 
        u8 io_gpr; /* GPR used as IO source/target */
        u8 mmio_is_bigendian;
@@ -603,7 +642,6 @@ struct kvm_vcpu_arch {
        struct list_head run_list;
        struct task_struct *run_task;
        struct kvm_run *kvm_run;
-       pgd_t *pgdir;
 
        spinlock_t vpa_update_lock;
        struct kvmppc_vpa vpa;
@@ -616,9 +654,12 @@ struct kvm_vcpu_arch {
        spinlock_t tbacct_lock;
        u64 busy_stolen;
        u64 busy_preempt;
+       unsigned long intr_msr;
 #endif
 };
 
+#define VCPU_FPR(vcpu, i)      (vcpu)->arch.fp.fpr[i][TS_FPROFFSET]
+
 /* Values for vcpu->arch.state */
 #define KVMPPC_VCPU_NOTREADY           0
 #define KVMPPC_VCPU_RUNNABLE           1
index 2b119654b4c1a5fcd2ce568fd83ad3a64bccdd03..336a91acb8b1f3a98f4bfdd7c0c6488d95b86ae0 100644 (file)
@@ -39,10 +39,6 @@ static inline int kvm_para_available(void)
        return 1;
 }
 
-extern unsigned long kvm_hypercall(unsigned long *in,
-                                  unsigned long *out,
-                                  unsigned long nr);
-
 #else
 
 static inline int kvm_para_available(void)
@@ -50,82 +46,8 @@ static inline int kvm_para_available(void)
        return 0;
 }
 
-static unsigned long kvm_hypercall(unsigned long *in,
-                                  unsigned long *out,
-                                  unsigned long nr)
-{
-       return EV_UNIMPLEMENTED;
-}
-
 #endif
 
-static inline long kvm_hypercall0_1(unsigned int nr, unsigned long *r2)
-{
-       unsigned long in[8];
-       unsigned long out[8];
-       unsigned long r;
-
-       r = kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
-       *r2 = out[0];
-
-       return r;
-}
-
-static inline long kvm_hypercall0(unsigned int nr)
-{
-       unsigned long in[8];
-       unsigned long out[8];
-
-       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
-}
-
-static inline long kvm_hypercall1(unsigned int nr, unsigned long p1)
-{
-       unsigned long in[8];
-       unsigned long out[8];
-
-       in[0] = p1;
-       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
-}
-
-static inline long kvm_hypercall2(unsigned int nr, unsigned long p1,
-                                 unsigned long p2)
-{
-       unsigned long in[8];
-       unsigned long out[8];
-
-       in[0] = p1;
-       in[1] = p2;
-       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
-}
-
-static inline long kvm_hypercall3(unsigned int nr, unsigned long p1,
-                                 unsigned long p2, unsigned long p3)
-{
-       unsigned long in[8];
-       unsigned long out[8];
-
-       in[0] = p1;
-       in[1] = p2;
-       in[2] = p3;
-       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
-}
-
-static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
-                                 unsigned long p2, unsigned long p3,
-                                 unsigned long p4)
-{
-       unsigned long in[8];
-       unsigned long out[8];
-
-       in[0] = p1;
-       in[1] = p2;
-       in[2] = p3;
-       in[3] = p4;
-       return kvm_hypercall(in, out, KVM_HCALL_TOKEN(nr));
-}
-
-
 static inline unsigned int kvm_arch_para_features(void)
 {
        unsigned long r;
@@ -133,7 +55,7 @@ static inline unsigned int kvm_arch_para_features(void)
        if (!kvm_para_available())
                return 0;
 
-       if(kvm_hypercall0_1(KVM_HC_FEATURES, &r))
+       if(epapr_hypercall0_1(KVM_HCALL_TOKEN(KVM_HC_FEATURES), &r))
                return 0;
 
        return r;
index c8317fbf92c470f03842da5cf363efd97aed99b4..fcd53f0d34bad9a26b3b74bc46ecc55b0c673f79 100644 (file)
@@ -54,12 +54,13 @@ extern void kvmppc_handler_highmem(void);
 extern void kvmppc_dump_vcpu(struct kvm_vcpu *vcpu);
 extern int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
                               unsigned int rt, unsigned int bytes,
-                              int is_bigendian);
+                             int is_default_endian);
 extern int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
                                unsigned int rt, unsigned int bytes,
-                               int is_bigendian);
+                              int is_default_endian);
 extern int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
-                               u64 val, unsigned int bytes, int is_bigendian);
+                              u64 val, unsigned int bytes,
+                              int is_default_endian);
 
 extern int kvmppc_emulate_instruction(struct kvm_run *run,
                                       struct kvm_vcpu *vcpu);
@@ -455,6 +456,12 @@ static inline void kvmppc_fix_ee_before_entry(void)
        trace_hardirqs_on();
 
 #ifdef CONFIG_PPC64
+       /*
+        * To avoid races, the caller must have gone directly from having
+        * interrupts fully-enabled to hard-disabled.
+        */
+       WARN_ON(local_paca->irq_happened != PACA_IRQ_HARD_DIS);
+
        /* Only need to enable IRQs by hard enabling them after this */
        local_paca->irq_happened = 0;
        local_paca->soft_enabled = 1;
index 844c28de7ec05e96f4578701a9d46c6dda6d2ecb..d0a2a2f9956471362e13093272955f42c0e4121b 100644 (file)
@@ -132,8 +132,6 @@ struct slb_shadow {
        } save_area[SLB_NUM_BOLTED];
 } ____cacheline_aligned;
 
-extern struct slb_shadow slb_shadow[];
-
 /*
  * Layout of entries in the hypervisor's dispatch trace log buffer.
  */
diff --git a/arch/powerpc/include/asm/mce.h b/arch/powerpc/include/asm/mce.h
new file mode 100644 (file)
index 0000000..8e99edf
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ * Machine check exception header file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2013 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#ifndef __ASM_PPC64_MCE_H__
+#define __ASM_PPC64_MCE_H__
+
+#include <linux/bitops.h>
+
+/*
+ * Machine Check bits on power7 and power8
+ */
+#define P7_SRR1_MC_LOADSTORE(srr1)     ((srr1) & PPC_BIT(42)) /* P8 too */
+
+/* SRR1 bits for machine check (On Power7 and Power8) */
+#define P7_SRR1_MC_IFETCH(srr1)        ((srr1) & PPC_BITMASK(43, 45)) /* P8 too */
+
+#define P7_SRR1_MC_IFETCH_UE           (0x1 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_SLB_PARITY   (0x2 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_SLB_MULTIHIT (0x3 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_SLB_BOTH     (0x4 << PPC_BITLSHIFT(45))
+#define P7_SRR1_MC_IFETCH_TLB_MULTIHIT (0x5 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_UE_TLB_RELOAD        (0x6 << PPC_BITLSHIFT(45)) /* P8 too */
+#define P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL      (0x7 << PPC_BITLSHIFT(45))
+
+/* SRR1 bits for machine check (On Power8) */
+#define P8_SRR1_MC_IFETCH_ERAT_MULTIHIT        (0x4 << PPC_BITLSHIFT(45))
+
+/* DSISR bits for machine check (On Power7 and Power8) */
+#define P7_DSISR_MC_UE                 (PPC_BIT(48))   /* P8 too */
+#define P7_DSISR_MC_UE_TABLEWALK       (PPC_BIT(49))   /* P8 too */
+#define P7_DSISR_MC_ERAT_MULTIHIT      (PPC_BIT(52))   /* P8 too */
+#define P7_DSISR_MC_TLB_MULTIHIT_MFTLB (PPC_BIT(53))   /* P8 too */
+#define P7_DSISR_MC_SLB_PARITY_MFSLB   (PPC_BIT(55))   /* P8 too */
+#define P7_DSISR_MC_SLB_MULTIHIT       (PPC_BIT(56))   /* P8 too */
+#define P7_DSISR_MC_SLB_MULTIHIT_PARITY        (PPC_BIT(57))   /* P8 too */
+
+/*
+ * DSISR bits for machine check (Power8) in addition to above.
+ * Secondary DERAT Multihit
+ */
+#define P8_DSISR_MC_ERAT_MULTIHIT_SEC  (PPC_BIT(54))
+
+/* SLB error bits */
+#define P7_DSISR_MC_SLB_ERRORS         (P7_DSISR_MC_ERAT_MULTIHIT | \
+                                        P7_DSISR_MC_SLB_PARITY_MFSLB | \
+                                        P7_DSISR_MC_SLB_MULTIHIT | \
+                                        P7_DSISR_MC_SLB_MULTIHIT_PARITY)
+
+#define P8_DSISR_MC_SLB_ERRORS         (P7_DSISR_MC_SLB_ERRORS | \
+                                        P8_DSISR_MC_ERAT_MULTIHIT_SEC)
+enum MCE_Version {
+       MCE_V1 = 1,
+};
+
+enum MCE_Severity {
+       MCE_SEV_NO_ERROR = 0,
+       MCE_SEV_WARNING = 1,
+       MCE_SEV_ERROR_SYNC = 2,
+       MCE_SEV_FATAL = 3,
+};
+
+enum MCE_Disposition {
+       MCE_DISPOSITION_RECOVERED = 0,
+       MCE_DISPOSITION_NOT_RECOVERED = 1,
+};
+
+enum MCE_Initiator {
+       MCE_INITIATOR_UNKNOWN = 0,
+       MCE_INITIATOR_CPU = 1,
+};
+
+enum MCE_ErrorType {
+       MCE_ERROR_TYPE_UNKNOWN = 0,
+       MCE_ERROR_TYPE_UE = 1,
+       MCE_ERROR_TYPE_SLB = 2,
+       MCE_ERROR_TYPE_ERAT = 3,
+       MCE_ERROR_TYPE_TLB = 4,
+};
+
+enum MCE_UeErrorType {
+       MCE_UE_ERROR_INDETERMINATE = 0,
+       MCE_UE_ERROR_IFETCH = 1,
+       MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH = 2,
+       MCE_UE_ERROR_LOAD_STORE = 3,
+       MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE = 4,
+};
+
+enum MCE_SlbErrorType {
+       MCE_SLB_ERROR_INDETERMINATE = 0,
+       MCE_SLB_ERROR_PARITY = 1,
+       MCE_SLB_ERROR_MULTIHIT = 2,
+};
+
+enum MCE_EratErrorType {
+       MCE_ERAT_ERROR_INDETERMINATE = 0,
+       MCE_ERAT_ERROR_PARITY = 1,
+       MCE_ERAT_ERROR_MULTIHIT = 2,
+};
+
+enum MCE_TlbErrorType {
+       MCE_TLB_ERROR_INDETERMINATE = 0,
+       MCE_TLB_ERROR_PARITY = 1,
+       MCE_TLB_ERROR_MULTIHIT = 2,
+};
+
+struct machine_check_event {
+       enum MCE_Version        version:8;      /* 0x00 */
+       uint8_t                 in_use;         /* 0x01 */
+       enum MCE_Severity       severity:8;     /* 0x02 */
+       enum MCE_Initiator      initiator:8;    /* 0x03 */
+       enum MCE_ErrorType      error_type:8;   /* 0x04 */
+       enum MCE_Disposition    disposition:8;  /* 0x05 */
+       uint8_t                 reserved_1[2];  /* 0x06 */
+       uint64_t                gpr3;           /* 0x08 */
+       uint64_t                srr0;           /* 0x10 */
+       uint64_t                srr1;           /* 0x18 */
+       union {                                 /* 0x20 */
+               struct {
+                       enum MCE_UeErrorType ue_error_type:8;
+                       uint8_t         effective_address_provided;
+                       uint8_t         physical_address_provided;
+                       uint8_t         reserved_1[5];
+                       uint64_t        effective_address;
+                       uint64_t        physical_address;
+                       uint8_t         reserved_2[8];
+               } ue_error;
+
+               struct {
+                       enum MCE_SlbErrorType slb_error_type:8;
+                       uint8_t         effective_address_provided;
+                       uint8_t         reserved_1[6];
+                       uint64_t        effective_address;
+                       uint8_t         reserved_2[16];
+               } slb_error;
+
+               struct {
+                       enum MCE_EratErrorType erat_error_type:8;
+                       uint8_t         effective_address_provided;
+                       uint8_t         reserved_1[6];
+                       uint64_t        effective_address;
+                       uint8_t         reserved_2[16];
+               } erat_error;
+
+               struct {
+                       enum MCE_TlbErrorType tlb_error_type:8;
+                       uint8_t         effective_address_provided;
+                       uint8_t         reserved_1[6];
+                       uint64_t        effective_address;
+                       uint8_t         reserved_2[16];
+               } tlb_error;
+       } u;
+};
+
+struct mce_error_info {
+       enum MCE_ErrorType error_type:8;
+       union {
+               enum MCE_UeErrorType ue_error_type:8;
+               enum MCE_SlbErrorType slb_error_type:8;
+               enum MCE_EratErrorType erat_error_type:8;
+               enum MCE_TlbErrorType tlb_error_type:8;
+       } u;
+       uint8_t         reserved[2];
+};
+
+#define MAX_MC_EVT     100
+
+/* Release flags for get_mce_event() */
+#define MCE_EVENT_RELEASE      true
+#define MCE_EVENT_DONTRELEASE  false
+
+extern void save_mce_event(struct pt_regs *regs, long handled,
+                          struct mce_error_info *mce_err, uint64_t addr);
+extern int get_mce_event(struct machine_check_event *mce, bool release);
+extern void release_mce_event(void);
+extern void machine_check_queue_event(void);
+extern void machine_check_print_event_info(struct machine_check_event *evt);
+extern uint64_t get_mce_fault_addr(struct machine_check_event *evt);
+
+#endif /* __ASM_PPC64_MCE_H__ */
index 936db360790adcf213e263da9bea0aeb259c4be2..89b785d1684673d0e00b7a75c132a345547f2e33 100644 (file)
@@ -286,8 +286,21 @@ static inline unsigned int mmu_psize_to_shift(unsigned int mmu_psize)
 extern int mmu_linear_psize;
 extern int mmu_vmemmap_psize;
 
+struct tlb_core_data {
+       /* For software way selection, as on Freescale TLB1 */
+       u8 esel_next, esel_max, esel_first;
+
+       /* Per-core spinlock for e6500 TLB handlers (no tlbsrx.) */
+       u8 lock;
+};
+
 #ifdef CONFIG_PPC64
 extern unsigned long linear_map_top;
+extern int book3e_htw_mode;
+
+#define PPC_HTW_NONE   0
+#define PPC_HTW_IBM    1
+#define PPC_HTW_E6500  2
 
 /*
  * 64-bit booke platforms don't load the tlb in the tlb miss handler code.
index 691fd8aca939f8762257de6423a9ea193fb96c8f..f8d1d6dcf7db63c5947aa2be4fa22564187d9953 100644 (file)
@@ -180,16 +180,17 @@ static inline void assert_pte_locked(struct mm_struct *mm, unsigned long addr)
 #define MMU_PAGE_64K_AP        3       /* "Admixed pages" (hash64 only) */
 #define MMU_PAGE_256K  4
 #define MMU_PAGE_1M    5
-#define MMU_PAGE_4M    6
-#define MMU_PAGE_8M    7
-#define MMU_PAGE_16M   8
-#define MMU_PAGE_64M   9
-#define MMU_PAGE_256M  10
-#define MMU_PAGE_1G    11
-#define MMU_PAGE_16G   12
-#define MMU_PAGE_64G   13
-
-#define MMU_PAGE_COUNT 14
+#define MMU_PAGE_2M    6
+#define MMU_PAGE_4M    7
+#define MMU_PAGE_8M    8
+#define MMU_PAGE_16M   9
+#define MMU_PAGE_64M   10
+#define MMU_PAGE_256M  11
+#define MMU_PAGE_1G    12
+#define MMU_PAGE_16G   13
+#define MMU_PAGE_64G   14
+
+#define MMU_PAGE_COUNT 15
 
 #if defined(CONFIG_PPC_STD_MMU_64)
 /* 64-bit classic hash table MMU */
index 887d3d6133e351dcf792ee775f9df15d3d337a80..4a69cd1d50410d29f60b3790e2abd8977bb731c2 100644 (file)
@@ -37,7 +37,12 @@ struct mpc512x_ccm {
        u32     cccr;   /* CFM Clock Control Register */
        u32     dccr;   /* DIU Clock Control Register */
        u32     mscan_ccr[4];   /* MSCAN Clock Control Registers */
-       u8      res[0x98]; /* Reserved */
+       u32     out_ccr[4];     /* OUT CLK Configure Registers */
+       u32     rsv0[2];        /* Reserved */
+       u32     scfr3;          /* System Clock Frequency Register 3 */
+       u32     rsv1[3];        /* Reserved */
+       u32     spll_lock_cnt;  /* System PLL Lock Counter */
+       u8      res[0x6c];      /* Reserved */
 };
 
 /*
index 7bdcf340016c412285df77ac56162aaa94982416..40157e2ca6914467cddae0225070d8582ad0861c 100644 (file)
@@ -33,6 +33,28 @@ struct opal_takeover_args {
        u64     rd_loc;                 /* r11 */
 };
 
+/*
+ * SG entry
+ *
+ * WARNING: The current implementation requires each entry
+ * to represent a block that is 4k aligned *and* each block
+ * size except the last one in the list to be as well.
+ */
+struct opal_sg_entry {
+       void    *data;
+       long    length;
+};
+
+/* sg list */
+struct opal_sg_list {
+       unsigned long num_entries;
+       struct opal_sg_list *next;
+       struct opal_sg_entry entry[];
+};
+
+/* We calculate number of sg entries based on PAGE_SIZE */
+#define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry))
+
 extern long opal_query_takeover(u64 *hal_size, u64 *hal_align);
 
 extern long opal_do_takeover(struct opal_takeover_args *args);
@@ -132,6 +154,9 @@ extern int opal_enter_rtas(struct rtas_args *args,
 #define OPAL_FLASH_VALIDATE                    76
 #define OPAL_FLASH_MANAGE                      77
 #define OPAL_FLASH_UPDATE                      78
+#define OPAL_GET_MSG                           85
+#define OPAL_CHECK_ASYNC_COMPLETION            86
+#define OPAL_SYNC_HOST_REBOOT                  87
 
 #ifndef __ASSEMBLY__
 
@@ -211,7 +236,16 @@ enum OpalPendingState {
        OPAL_EVENT_ERROR_LOG            = 0x40,
        OPAL_EVENT_EPOW                 = 0x80,
        OPAL_EVENT_LED_STATUS           = 0x100,
-       OPAL_EVENT_PCI_ERROR            = 0x200
+       OPAL_EVENT_PCI_ERROR            = 0x200,
+       OPAL_EVENT_MSG_PENDING          = 0x800,
+};
+
+enum OpalMessageType {
+       OPAL_MSG_ASYNC_COMP             = 0,
+       OPAL_MSG_MEM_ERR,
+       OPAL_MSG_EPOW,
+       OPAL_MSG_SHUTDOWN,
+       OPAL_MSG_TYPE_MAX,
 };
 
 /* Machine check related definitions */
@@ -311,12 +345,16 @@ enum OpalMveEnableAction {
        OPAL_ENABLE_MVE = 1
 };
 
-enum OpalPciResetAndReinitScope {
+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,
 };
 
+enum OpalPciReinitScope {
+       OPAL_REINIT_PCI_DEV = 1000
+};
+
 enum OpalPciResetState {
        OPAL_DEASSERT_RESET = 0,
        OPAL_ASSERT_RESET = 1
@@ -356,6 +394,12 @@ enum OpalLPCAddressType {
        OPAL_LPC_FW     = 2,
 };
 
+struct opal_msg {
+       uint32_t msg_type;
+       uint32_t reserved;
+       uint64_t params[8];
+};
+
 struct opal_machine_check_event {
        enum OpalMCE_Version    version:8;      /* 0x00 */
        uint8_t                 in_use;         /* 0x01 */
@@ -404,6 +448,58 @@ struct opal_machine_check_event {
        } u;
 };
 
+/* FSP memory errors handling */
+enum OpalMemErr_Version {
+       OpalMemErr_V1 = 1,
+};
+
+enum OpalMemErrType {
+       OPAL_MEM_ERR_TYPE_RESILIENCE    = 0,
+       OPAL_MEM_ERR_TYPE_DYN_DALLOC,
+       OPAL_MEM_ERR_TYPE_SCRUB,
+};
+
+/* Memory Reilience error type */
+enum OpalMemErr_ResilErrType {
+       OPAL_MEM_RESILIENCE_CE          = 0,
+       OPAL_MEM_RESILIENCE_UE,
+       OPAL_MEM_RESILIENCE_UE_SCRUB,
+};
+
+/* Dynamic Memory Deallocation type */
+enum OpalMemErr_DynErrType {
+       OPAL_MEM_DYNAMIC_DEALLOC        = 0,
+};
+
+/* OpalMemoryErrorData->flags */
+#define OPAL_MEM_CORRECTED_ERROR       0x0001
+#define OPAL_MEM_THRESHOLD_EXCEEDED    0x0002
+#define OPAL_MEM_ACK_REQUIRED          0x8000
+
+struct OpalMemoryErrorData {
+       enum OpalMemErr_Version version:8;      /* 0x00 */
+       enum OpalMemErrType     type:8;         /* 0x01 */
+       uint16_t                flags;          /* 0x02 */
+       uint8_t                 reserved_1[4];  /* 0x04 */
+
+       union {
+               /* Memory Resilience corrected/uncorrected error info */
+               struct {
+                       enum OpalMemErr_ResilErrType resil_err_type:8;
+                       uint8_t         reserved_1[7];
+                       uint64_t        physical_address_start;
+                       uint64_t        physical_address_end;
+               } resilience;
+               /* Dynamic memory deallocation error info */
+               struct {
+                       enum OpalMemErr_DynErrType dyn_err_type:8;
+                       uint8_t         reserved_1[7];
+                       uint64_t        physical_address_start;
+                       uint64_t        physical_address_end;
+               } dyn_dealloc;
+       } u;
+};
+
 enum {
        OPAL_P7IOC_DIAG_TYPE_NONE       = 0,
        OPAL_P7IOC_DIAG_TYPE_RGC        = 1,
@@ -710,7 +806,7 @@ int64_t opal_pci_get_phb_diag_data(uint64_t phb_id, void *diag_buffer,
 int64_t opal_pci_get_phb_diag_data2(uint64_t phb_id, void *diag_buffer,
                                    uint64_t diag_buffer_len);
 int64_t opal_pci_fence_phb(uint64_t phb_id);
-int64_t opal_pci_reinit(uint64_t phb_id, uint8_t reinit_scope);
+int64_t opal_pci_reinit(uint64_t phb_id, uint64_t reinit_scope, uint64_t data);
 int64_t opal_pci_mask_pe_error(uint64_t phb_id, uint16_t pe_number, uint8_t error_type, uint8_t mask_action);
 int64_t opal_set_slot_led_status(uint64_t phb_id, uint64_t slot_id, uint8_t led_type, uint8_t led_action);
 int64_t opal_get_epow_status(__be64 *status);
@@ -731,6 +827,10 @@ int64_t opal_validate_flash(uint64_t buffer, uint32_t *size, uint32_t *result);
 int64_t opal_manage_flash(uint8_t op);
 int64_t opal_update_flash(uint64_t blk_list);
 
+int64_t opal_get_msg(uint64_t buffer, size_t size);
+int64_t opal_check_completion(uint64_t buffer, size_t size, uint64_t token);
+int64_t opal_sync_host_reboot(void);
+
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname, int depth, void *data);
 
@@ -744,6 +844,8 @@ extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
                                   int depth, void *data);
 
 extern int opal_notifier_register(struct notifier_block *nb);
+extern int opal_message_notifier_register(enum OpalMessageType msg_type,
+                                               struct notifier_block *nb);
 extern void opal_notifier_enable(void);
 extern void opal_notifier_disable(void);
 extern void opal_notifier_update_evt(uint64_t evt_mask, uint64_t evt_val);
index b6ea9e068c13dd483033a9f8aea2251d45084cac..9c5dbc3833fbc65976ba17e60eec04f234f8e631 100644 (file)
@@ -16,7 +16,6 @@
 
 #ifdef CONFIG_PPC64
 
-#include <linux/init.h>
 #include <asm/types.h>
 #include <asm/lppaca.h>
 #include <asm/mmu.h>
@@ -113,6 +112,10 @@ struct paca_struct {
        /* Keep pgd in the same cacheline as the start of extlb */
        pgd_t *pgd __attribute__((aligned(0x80))); /* Current PGD */
        pgd_t *kernel_pgd;              /* Kernel PGD */
+
+       /* Shared by all threads of a core -- points to tcd of first thread */
+       struct tlb_core_data *tcd_ptr;
+
        /* We can have up to 3 levels of reentrancy in the TLB miss handler */
        u64 extlb[3][EX_TLB_SIZE / sizeof(u64)];
        u64 exmc[8];            /* used for machine checks */
@@ -123,6 +126,8 @@ struct paca_struct {
        void *mc_kstack;
        void *crit_kstack;
        void *dbg_kstack;
+
+       struct tlb_core_data tcd;
 #endif /* CONFIG_PPC_BOOK3E */
 
        mm_context_t context;
@@ -152,6 +157,15 @@ struct paca_struct {
         */
        struct opal_machine_check_event *opal_mc_evt;
 #endif
+#ifdef CONFIG_PPC_BOOK3S_64
+       /* Exclusive emergency stack pointer for machine check exception. */
+       void *mc_emergency_sp;
+       /*
+        * Flag to check whether we are in machine check early handler
+        * and already using emergency stack.
+        */
+       u16 in_mce;
+#endif
 
        /* Stuff for accurate time accounting */
        u64 user_time;                  /* accumulated usermode TB ticks */
index 4a191c47286748c65cf2e7eb8753239af4c3b5d5..bc141c950b1e6c8128769b786df189eb275f583f 100644 (file)
@@ -558,5 +558,19 @@ extern pgtable_t pgtable_trans_huge_withdraw(struct mm_struct *mm, pmd_t *pmdp);
 #define __HAVE_ARCH_PMDP_INVALIDATE
 extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
                            pmd_t *pmdp);
+
+#define pmd_move_must_withdraw pmd_move_must_withdraw
+struct spinlock;
+static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
+                                        struct spinlock *old_pmd_ptl)
+{
+       /*
+        * Archs like ppc64 use pgtable to store per pmd
+        * specific information. So when we switch the pmd,
+        * we should also withdraw and deposit the pgtable
+        */
+       return true;
+}
+
 #endif /* __ASSEMBLY__ */
 #endif /* _ASM_POWERPC_PGTABLE_PPC64_H_ */
index 7d6eacf249cf420a3e6d0a6f5ef108c76e663e80..f83b6f3e1b39b68c5b25f8df6a107f59bf20ae1b 100644 (file)
@@ -3,6 +3,7 @@
 #ifdef __KERNEL__
 
 #ifndef __ASSEMBLY__
+#include <linux/mmdebug.h>
 #include <asm/processor.h>             /* For TASK_SIZE */
 #include <asm/mmu.h>
 #include <asm/page.h>
@@ -33,10 +34,73 @@ static inline int pte_dirty(pte_t pte)              { return pte_val(pte) & _PAGE_DIRTY; }
 static inline int pte_young(pte_t pte)         { return pte_val(pte) & _PAGE_ACCESSED; }
 static inline int pte_file(pte_t pte)          { return pte_val(pte) & _PAGE_FILE; }
 static inline int pte_special(pte_t pte)       { return pte_val(pte) & _PAGE_SPECIAL; }
-static inline int pte_present(pte_t pte)       { return pte_val(pte) & _PAGE_PRESENT; }
 static inline int pte_none(pte_t pte)          { return (pte_val(pte) & ~_PTE_NONE_MASK) == 0; }
 static inline pgprot_t pte_pgprot(pte_t pte)   { return __pgprot(pte_val(pte) & PAGE_PROT_BITS); }
 
+#ifdef CONFIG_NUMA_BALANCING
+
+static inline int pte_present(pte_t pte)
+{
+       return pte_val(pte) & (_PAGE_PRESENT | _PAGE_NUMA);
+}
+
+#define pte_numa pte_numa
+static inline int pte_numa(pte_t pte)
+{
+       return (pte_val(pte) &
+               (_PAGE_NUMA|_PAGE_PRESENT)) == _PAGE_NUMA;
+}
+
+#define pte_mknonnuma pte_mknonnuma
+static inline pte_t pte_mknonnuma(pte_t pte)
+{
+       pte_val(pte) &= ~_PAGE_NUMA;
+       pte_val(pte) |=  _PAGE_PRESENT | _PAGE_ACCESSED;
+       return pte;
+}
+
+#define pte_mknuma pte_mknuma
+static inline pte_t pte_mknuma(pte_t pte)
+{
+       /*
+        * We should not set _PAGE_NUMA on non present ptes. Also clear the
+        * present bit so that hash_page will return 1 and we collect this
+        * as numa fault.
+        */
+       if (pte_present(pte)) {
+               pte_val(pte) |= _PAGE_NUMA;
+               pte_val(pte) &= ~_PAGE_PRESENT;
+       } else
+               VM_BUG_ON(1);
+       return pte;
+}
+
+#define pmd_numa pmd_numa
+static inline int pmd_numa(pmd_t pmd)
+{
+       return pte_numa(pmd_pte(pmd));
+}
+
+#define pmd_mknonnuma pmd_mknonnuma
+static inline pmd_t pmd_mknonnuma(pmd_t pmd)
+{
+       return pte_pmd(pte_mknonnuma(pmd_pte(pmd)));
+}
+
+#define pmd_mknuma pmd_mknuma
+static inline pmd_t pmd_mknuma(pmd_t pmd)
+{
+       return pte_pmd(pte_mknuma(pmd_pte(pmd)));
+}
+
+# else
+
+static inline int pte_present(pte_t pte)
+{
+       return pte_val(pte) & _PAGE_PRESENT;
+}
+#endif /* CONFIG_NUMA_BALANCING */
+
 /* Conversion functions: convert a page and protection to a page entry,
  * and a page entry and page directory to the page they refer to.
  *
@@ -223,6 +287,27 @@ extern int gup_hugepte(pte_t *ptep, unsigned long sz, unsigned long addr,
 #endif
 pte_t *find_linux_pte_or_hugepte(pgd_t *pgdir, unsigned long ea,
                                 unsigned *shift);
+
+static inline pte_t *lookup_linux_ptep(pgd_t *pgdir, unsigned long hva,
+                                    unsigned long *pte_sizep)
+{
+       pte_t *ptep;
+       unsigned long ps = *pte_sizep;
+       unsigned int shift;
+
+       ptep = find_linux_pte_or_hugepte(pgdir, hva, &shift);
+       if (!ptep)
+               return NULL;
+       if (shift)
+               *pte_sizep = 1ul << shift;
+       else
+               *pte_sizep = PAGE_SIZE;
+
+       if (ps > *pte_sizep)
+               return NULL;
+
+       return ptep;
+}
 #endif /* __ASSEMBLY__ */
 
 #endif /* __KERNEL__ */
index f595b98079ee1ec75064640001998a407524ad59..6586a40a46ce161f9f654a57d0222db3bc06d611 100644 (file)
@@ -4,7 +4,6 @@
 #ifndef _ASM_POWERPC_PPC_ASM_H
 #define _ASM_POWERPC_PPC_ASM_H
 
-#include <linux/init.h>
 #include <linux/stringify.h>
 #include <asm/asm-compat.h>
 #include <asm/processor.h>
@@ -295,6 +294,11 @@ n:
  *   you want to access various offsets within it).  On ppc32 this is
  *   identical to LOAD_REG_IMMEDIATE.
  *
+ * LOAD_REG_ADDR_PIC(rn, name)
+ *   Loads the address of label 'name' into register 'run'. Use this when
+ *   the kernel doesn't run at the linked or relocated address. Please
+ *   note that this macro will clobber the lr register.
+ *
  * LOAD_REG_ADDRBASE(rn, name)
  * ADDROFF(name)
  *   LOAD_REG_ADDRBASE loads part of the address of label 'name' into
@@ -305,6 +309,14 @@ n:
  *      LOAD_REG_ADDRBASE(rX, name)
  *      ld     rY,ADDROFF(name)(rX)
  */
+
+/* Be careful, this will clobber the lr register. */
+#define LOAD_REG_ADDR_PIC(reg, name)           \
+       bl      0f;                             \
+0:     mflr    reg;                            \
+       addis   reg,reg,(name - 0b)@ha;         \
+       addi    reg,reg,(name - 0b)@l;
+
 #ifdef __powerpc64__
 #define LOAD_REG_IMMEDIATE(reg,expr)           \
        lis     reg,(expr)@highest;             \
index fc14a38c7ccffae6c8f7c233e2710462ef621e7d..b62de43ae5f344a02d6096af7842c3799c192b93 100644 (file)
@@ -256,6 +256,8 @@ struct thread_struct {
        unsigned long   evr[32];        /* upper 32-bits of SPE regs */
        u64             acc;            /* Accumulator */
        unsigned long   spefscr;        /* SPE & eFP status */
+       unsigned long   spefscr_last;   /* SPEFSCR value on last prctl
+                                          call or trap return */
        int             used_spe;       /* set if process has used spe */
 #endif /* CONFIG_SPE */
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
@@ -317,7 +319,9 @@ struct thread_struct {
        (_ALIGN_UP(sizeof(init_thread_info), 16) + (unsigned long) &init_stack)
 
 #ifdef CONFIG_SPE
-#define SPEFSCR_INIT .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE,
+#define SPEFSCR_INIT \
+       .spefscr = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE, \
+       .spefscr_last = SPEFSCR_FINVE | SPEFSCR_FDBZE | SPEFSCR_FUNFE | SPEFSCR_FOVFE,
 #else
 #define SPEFSCR_INIT
 #endif
@@ -373,6 +377,8 @@ extern int set_endian(struct task_struct *tsk, unsigned int val);
 extern int get_unalign_ctl(struct task_struct *tsk, unsigned long adr);
 extern int set_unalign_ctl(struct task_struct *tsk, unsigned int val);
 
+extern void fp_enable(void);
+extern void vec_enable(void);
 extern void load_fp_state(struct thread_fp_state *fp);
 extern void store_fp_state(struct thread_fp_state *fp);
 extern void load_vr_state(struct thread_vr_state *vr);
@@ -444,13 +450,6 @@ enum idle_boot_override {IDLE_NO_OVERRIDE = 0, IDLE_POWERSAVE_OFF};
 
 extern int powersave_nap;      /* set if nap mode can be used in idle loop */
 extern void power7_nap(void);
-
-#ifdef CONFIG_PSERIES_IDLE
-extern void update_smt_snooze_delay(int cpu, int residency);
-#else
-static inline void update_smt_snooze_delay(int cpu, int residency) {}
-#endif
-
 extern void flush_instruction_cache(void);
 extern void hard_reset_now(void);
 extern void poweroff_now(void);
index 678a7c1d9cb8ef32ea4da754fb72ac9f6d7f7f47..a1bc7e7584228a9e02215aeb2ee96e21194752c5 100644 (file)
@@ -21,7 +21,6 @@
 #if !defined(_ASM_POWERPC_PS3_H)
 #define _ASM_POWERPC_PS3_H
 
-#include <linux/init.h>
 #include <linux/types.h>
 #include <linux/device.h>
 #include <asm/cell-pmu.h>
index 0419eeb53274c64891c87f1c573e712e6167d62b..2505d8eab15cb94da40aea90b9986aa853c0aecb 100644 (file)
@@ -19,7 +19,7 @@
 #define _PAGE_FILE             0x0002 /* (!present only) software: pte holds file offset */
 #define _PAGE_EXEC             0x0004 /* No execute on POWER4 and newer (we invert) */
 #define _PAGE_GUARDED          0x0008
-#define _PAGE_COHERENT         0x0010 /* M: enforce memory coherence (SMP systems) */
+/* We can derive Memory coherence from _PAGE_NO_CACHE */
 #define _PAGE_NO_CACHE         0x0020 /* I: cache inhibit */
 #define _PAGE_WRITETHRU                0x0040 /* W: cache write-through */
 #define _PAGE_DIRTY            0x0080 /* C: page changed */
 #define _PAGE_RW               0x0200 /* software: user write access allowed */
 #define _PAGE_BUSY             0x0800 /* software: PTE & hash are busy */
 
+/*
+ * Used for tracking numa faults
+ */
+#define _PAGE_NUMA     0x00000010 /* Gather numa placement stats */
+
+
 /* No separate kernel read-only */
 #define _PAGE_KERNEL_RW                (_PAGE_RW | _PAGE_DIRTY) /* user access blocked by key */
 #define _PAGE_KERNEL_RO                 _PAGE_KERNEL_RW
index fa8388ed94c52e6086110bc382c7196ea32f1ad0..90c06ec6eff51d9863db7be38ea3c748f2c98e38 100644 (file)
 #define   CTRL_TE      0x00c00000      /* thread enable */
 #define   CTRL_RUNLATCH        0x1
 #define SPRN_DAWR      0xB4
+#define SPRN_CIABR     0xBB
+#define   CIABR_PRIV           0x3
+#define   CIABR_PRIV_USER      1
+#define   CIABR_PRIV_SUPER     2
+#define   CIABR_PRIV_HYPER     3
 #define SPRN_DAWRX     0xBC
-#define   DAWRX_USER   (1UL << 0)
-#define   DAWRX_KERNEL (1UL << 1)
-#define   DAWRX_HYP    (1UL << 2)
+#define   DAWRX_USER   __MASK(0)
+#define   DAWRX_KERNEL __MASK(1)
+#define   DAWRX_HYP    __MASK(2)
+#define   DAWRX_WTI    __MASK(3)
+#define   DAWRX_WT     __MASK(4)
+#define   DAWRX_DR     __MASK(5)
+#define   DAWRX_DW     __MASK(6)
 #define SPRN_DABR      0x3F5   /* Data Address Breakpoint Register */
 #define SPRN_DABR2     0x13D   /* e300 */
 #define SPRN_DABRX     0x3F7   /* Data Address Breakpoint Register Extension */
-#define   DABRX_USER   (1UL << 0)
-#define   DABRX_KERNEL (1UL << 1)
-#define   DABRX_HYP    (1UL << 2)
-#define   DABRX_BTI    (1UL << 3)
+#define   DABRX_USER   __MASK(0)
+#define   DABRX_KERNEL __MASK(1)
+#define   DABRX_HYP    __MASK(2)
+#define   DABRX_BTI    __MASK(3)
 #define   DABRX_ALL     (DABRX_BTI | DABRX_HYP | DABRX_KERNEL | DABRX_USER)
 #define SPRN_DAR       0x013   /* Data Address Register */
 #define SPRN_DBCR      0x136   /* e300 Data Breakpoint Control Reg */
 #define SPRN_HRMOR     0x139   /* Real mode offset register */
 #define SPRN_HSRR0     0x13A   /* Hypervisor Save/Restore 0 */
 #define SPRN_HSRR1     0x13B   /* Hypervisor Save/Restore 1 */
+#define SPRN_IC                0x350   /* Virtual Instruction Count */
+#define SPRN_VTB       0x351   /* Virtual Time Base */
 /* HFSCR and FSCR bit numbers are the same */
 #define FSCR_TAR_LG    8       /* Enable Target Address Register */
 #define FSCR_EBB_LG    7       /* Enable Event Based Branching */
 #define   LPCR_RMLS    0x1C000000      /* impl dependent rmo limit sel */
 #define          LPCR_RMLS_SH  (63-37)
 #define   LPCR_ILE     0x02000000      /* !HV irqs set MSR:LE */
+#define   LPCR_AIL     0x01800000      /* Alternate interrupt location */
 #define   LPCR_AIL_0   0x00000000      /* MMU off exception offset 0x0 */
 #define   LPCR_AIL_3   0x01800000      /* MMU on exception offset 0xc00...4xxx */
-#define   LPCR_PECE    0x00007000      /* powersave exit cause enable */
+#define   LPCR_ONL     0x00040000      /* online - PURR/SPURR count */
+#define   LPCR_PECE    0x0001f000      /* powersave exit cause enable */
+#define     LPCR_PECEDP        0x00010000      /* directed priv dbells cause exit */
+#define     LPCR_PECEDH        0x00008000      /* directed hyp dbells cause exit */
 #define     LPCR_PECE0 0x00004000      /* ext. exceptions can cause exit */
 #define     LPCR_PECE1 0x00002000      /* decrementer can cause exit */
 #define     LPCR_PECE2 0x00001000      /* machine check etc can cause exit */
 #define SPRN_PCR       0x152   /* Processor compatibility register */
 #define   PCR_VEC_DIS  (1ul << (63-0)) /* Vec. disable (bit NA since POWER8) */
 #define   PCR_VSX_DIS  (1ul << (63-1)) /* VSX disable (bit NA since POWER8) */
+#define   PCR_TM_DIS   (1ul << (63-2)) /* Trans. memory disable (POWER8) */
+#define   PCR_ARCH_206 0x4             /* Architecture 2.06 */
 #define   PCR_ARCH_205 0x2             /* Architecture 2.05 */
 #define        SPRN_HEIR       0x153   /* Hypervisor Emulated Instruction Register */
 #define SPRN_TLBINDEXR 0x154   /* P7 TLB control register */
 #define DER_EBRKE      0x00000002      /* External Breakpoint Interrupt */
 #define DER_DPIE       0x00000001      /* Dev. Port Nonmaskable Request */
 #define SPRN_DMISS     0x3D0           /* Data TLB Miss Register */
+#define SPRN_DHDES     0x0B1           /* Directed Hyp. Doorbell Exc. State */
+#define SPRN_DPDES     0x0B0           /* Directed Priv. Doorbell Exc. State */
 #define SPRN_EAR       0x11A           /* External Address Register */
 #define SPRN_HASH1     0x3D2           /* Primary Hash Address Register */
 #define SPRN_HASH2     0x3D3           /* Secondary Hash Address Resgister */
 #define SPRN_IABR      0x3F2   /* Instruction Address Breakpoint Register */
 #define SPRN_IABR2     0x3FA           /* 83xx */
 #define SPRN_IBCR      0x135           /* 83xx Insn Breakpoint Control Reg */
+#define SPRN_IAMR      0x03D           /* Instr. Authority Mask Reg */
 #define SPRN_HID4      0x3F4           /* 970 HID4 */
 #define  HID4_LPES0     (1ul << (63-0)) /* LPAR env. sel. bit 0 */
 #define         HID4_RMLS2_SH   (63 - 2)       /* Real mode limit bottom 2 bits */
 #define SPRN_PIR       0x3FF   /* Processor Identification Register */
 #endif
 #define SPRN_TIR       0x1BE   /* Thread Identification Register */
+#define SPRN_PSPB      0x09F   /* Problem State Priority Boost reg */
 #define SPRN_PTEHI     0x3D5   /* 981 7450 PTE HI word (S/W TLB load) */
 #define SPRN_PTELO     0x3D6   /* 982 7450 PTE LO word (S/W TLB load) */
 #define SPRN_PURR      0x135   /* Processor Utilization of Resources Reg */
 #define SPRN_EBBHR     804     /* Event based branch handler register */
 #define SPRN_EBBRR     805     /* Event based branch return register */
 #define SPRN_BESCR     806     /* Branch event status and control register */
+#define SPRN_WORT      895     /* Workload optimization register - thread */
 
 #define SPRN_PMC1      787
 #define SPRN_PMC2      788
 #define   SIER_SIHV            0x1000000       /* Sampled MSR_HV */
 #define   SIER_SIAR_VALID      0x0400000       /* SIAR contents valid */
 #define   SIER_SDAR_VALID      0x0200000       /* SDAR contents valid */
+#define SPRN_TACR      888
+#define SPRN_TCSCR     889
+#define SPRN_CSIGR     890
+#define SPRN_SPMC1     892
+#define SPRN_SPMC2     893
 
 /* When EBB is enabled, some of MMCR0/MMCR2/SIER are user accessible */
 #define MMCR0_USER_MASK        (MMCR0_FC | MMCR0_PMXE | MMCR0_PMAO)
 #define PVR_8560       0x80200000
 #define PVR_VER_E500V1 0x8020
 #define PVR_VER_E500V2 0x8021
+#define PVR_VER_E6500  0x8040
+
 /*
  * For the 8xx processors, all of them report the same PVR family for
  * the PowerPC core. The various versions of these processors must be
index 2e31aacd8accaf4bf7742d7a708766a63e1f07d8..163c3b05a76e9d42f1a2067f510fd44cc7232dde 100644 (file)
 #define SPRN_IVOR39    0x1B1   /* Interrupt Vector Offset Register 39 */
 #define SPRN_IVOR40    0x1B2   /* Interrupt Vector Offset Register 40 */
 #define SPRN_IVOR41    0x1B3   /* Interrupt Vector Offset Register 41 */
+#define SPRN_IVOR42    0x1B4   /* Interrupt Vector Offset Register 42 */
 #define SPRN_GIVOR2    0x1B8   /* Guest IVOR2 */
 #define SPRN_GIVOR3    0x1B9   /* Guest IVOR3 */
 #define SPRN_GIVOR4    0x1BA   /* Guest IVOR4 */
 #define SPRN_L2CSR1    0x3FA   /* L2 Data Cache Control and Status Register 1 */
 #define SPRN_DCCR      0x3FA   /* Data Cache Cacheability Register */
 #define SPRN_ICCR      0x3FB   /* Instruction Cache Cacheability Register */
+#define SPRN_PWRMGTCR0 0x3FB   /* Power management control register 0 */
 #define SPRN_SVR       0x3FF   /* System Version Register */
 
 /*
 #define        CCR1_DPC        0x00000100 /* Disable L1 I-Cache/D-Cache parity checking */
 #define        CCR1_TCS        0x00000080 /* Timer Clock Select */
 
+/* Bit definitions for PWRMGTCR0. */
+#define PWRMGTCR0_PW20_WAIT            (1 << 14) /* PW20 state enable bit */
+#define PWRMGTCR0_PW20_ENT_SHIFT       8
+#define PWRMGTCR0_PW20_ENT             0x3F00
+#define PWRMGTCR0_AV_IDLE_PD_EN                (1 << 22) /* Altivec idle enable */
+#define PWRMGTCR0_AV_IDLE_CNT_SHIFT    16
+#define PWRMGTCR0_AV_IDLE_CNT          0x3F0000
+
 /* Bit definitions for the MCSR. */
 #define MCSR_MCS       0x80000000 /* Machine Check Summary */
 #define MCSR_IB                0x40000000 /* Instruction PLB Error */
index f6e78d63fb6accd584e71cd5ebe7b26c5dae2916..35aa339410bdaef7d50decc76bda487677323e78 100644 (file)
@@ -30,8 +30,6 @@
 
 #define smp_mb__after_unlock_lock()    smp_mb()  /* Full ordering for lock. */
 
-#define arch_spin_is_locked(x)         ((x)->slock != 0)
-
 #ifdef CONFIG_PPC64
 /* use 0x800000yy when locked, where yy == CPU number */
 #ifdef __BIG_ENDIAN__
 #define SYNC_IO
 #endif
 
+static __always_inline int arch_spin_value_unlocked(arch_spinlock_t lock)
+{
+       return lock.slock == 0;
+}
+
+static inline int arch_spin_is_locked(arch_spinlock_t *lock)
+{
+       return !arch_spin_value_unlocked(*lock);
+}
+
 /*
  * This returns the old value in the lock, so we succeeded
  * in getting the lock if the return value is 0.
index aace90547614db30ea638945d30d143fbdfb336e..0e83e7d8c73f5d0845690928ce24f179f69e22b8 100644 (file)
@@ -25,10 +25,8 @@ static inline void save_tar(struct thread_struct *prev)
 static inline void save_tar(struct thread_struct *prev) {}
 #endif
 
-extern void load_up_fpu(void);
 extern void enable_kernel_fp(void);
 extern void enable_kernel_altivec(void);
-extern void load_up_altivec(struct task_struct *);
 extern int emulate_altivec(struct pt_regs *);
 extern void __giveup_vsx(struct task_struct *);
 extern void giveup_vsx(struct task_struct *);
index 43523fe0d8b4c4e1f8711645445b93899860272c..3ddf70276706421532066e89261ea3f0d0c8c9ab 100644 (file)
@@ -359,3 +359,5 @@ COMPAT_SYS(process_vm_readv)
 COMPAT_SYS(process_vm_writev)
 SYSCALL(finit_module)
 SYSCALL(ni_syscall) /* sys_kcmp */
+SYSCALL_SPU(sched_setattr)
+SYSCALL_SPU(sched_getattr)
index 9854c564ac525b02b9f81c363a1cd4477cd76d4b..b034ecdb7c74f219b311ac4ad1d58f1c56f3f929 100644 (file)
@@ -91,8 +91,7 @@ static inline struct thread_info *current_thread_info(void)
 #define TIF_POLLING_NRFLAG     3       /* true if poll_idle() is polling
                                           TIF_NEED_RESCHED */
 #define TIF_32BIT              4       /* 32 bit binary */
-#define TIF_PERFMON_WORK       5       /* work for pfm_handle_work() */
-#define TIF_PERFMON_CTXSW      6       /* perfmon needs ctxsw calls */
+#define TIF_RESTORE_TM         5       /* need to restore TM FP/VEC/VSX */
 #define TIF_SYSCALL_AUDIT      7       /* syscall auditing active */
 #define TIF_SINGLESTEP         8       /* singlestepping active */
 #define TIF_NOHZ               9       /* in adaptive nohz mode */
@@ -115,8 +114,7 @@ static inline struct thread_info *current_thread_info(void)
 #define _TIF_NEED_RESCHED      (1<<TIF_NEED_RESCHED)
 #define _TIF_POLLING_NRFLAG    (1<<TIF_POLLING_NRFLAG)
 #define _TIF_32BIT             (1<<TIF_32BIT)
-#define _TIF_PERFMON_WORK      (1<<TIF_PERFMON_WORK)
-#define _TIF_PERFMON_CTXSW     (1<<TIF_PERFMON_CTXSW)
+#define _TIF_RESTORE_TM                (1<<TIF_RESTORE_TM)
 #define _TIF_SYSCALL_AUDIT     (1<<TIF_SYSCALL_AUDIT)
 #define _TIF_SINGLESTEP                (1<<TIF_SINGLESTEP)
 #define _TIF_SECCOMP           (1<<TIF_SECCOMP)
@@ -132,7 +130,8 @@ static inline struct thread_info *current_thread_info(void)
                                 _TIF_NOHZ)
 
 #define _TIF_USER_WORK_MASK    (_TIF_SIGPENDING | _TIF_NEED_RESCHED | \
-                                _TIF_NOTIFY_RESUME | _TIF_UPROBE)
+                                _TIF_NOTIFY_RESUME | _TIF_UPROBE | \
+                                _TIF_RESTORE_TM)
 #define _TIF_PERSYSCALL_MASK   (_TIF_RESTOREALL|_TIF_NOERROR)
 
 /* Bits in local_flags */
index 9dfbc34bdbf5e7e86eda005d4e974f5fe3ebd12a..0c9f8b74dd9743ecd1977281c9365d6d1381fdf2 100644 (file)
@@ -15,6 +15,7 @@ extern void do_load_up_transact_altivec(struct thread_struct *thread);
 extern void tm_enable(void);
 extern void tm_reclaim(struct thread_struct *thread,
                       unsigned long orig_msr, uint8_t cause);
+extern void tm_reclaim_current(uint8_t cause);
 extern void tm_recheckpoint(struct thread_struct *thread,
                            unsigned long orig_msr);
 extern void tm_abort(uint8_t cause);
index 89e3ef2496ac72c4e03d17657833930de22f6b8e..d0b5fca6b0776fc8ef220483b91b1557c73a0835 100644 (file)
@@ -22,7 +22,15 @@ struct device_node;
 
 static inline int cpu_to_node(int cpu)
 {
-       return numa_cpu_lookup_table[cpu];
+       int nid;
+
+       nid = numa_cpu_lookup_table[cpu];
+
+       /*
+        * During early boot, the numa-cpu lookup table might not have been
+        * setup for all CPUs yet. In such cases, default to node 0.
+        */
+       return (nid < 0) ? 0 : nid;
 }
 
 #define parent_node(node)      (node)
index 3ca819f541bfb317bc40f1cfd952d3f6cb8555a9..4494f029b632e50babb7d1d08c8535da144a43b1 100644 (file)
@@ -12,7 +12,7 @@
 #include <uapi/asm/unistd.h>
 
 
-#define __NR_syscalls          355
+#define __NR_syscalls          357
 
 #define __NR__exit __NR_exit
 #define NR_syscalls    __NR_syscalls
index 68d0cc998b1baa5cee49b2a735f394354819492c..4f9b7ca0710fc5935de9d7963aeeedbb33159f90 100644 (file)
@@ -15,7 +15,6 @@
 #define _ASM_POWERPC_VIO_H
 #ifdef __KERNEL__
 
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/device.h>
 #include <linux/dma-mapping.h>
index 6836ec79a8305a33005b8ca4ab17e3688307c6aa..a6665be4f3ab81dfd35ab1f08b8f6a3cce6a8493 100644 (file)
@@ -545,6 +545,7 @@ struct kvm_get_htab_header {
 #define KVM_REG_PPC_TCSCR      (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb1)
 #define KVM_REG_PPC_PID                (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb2)
 #define KVM_REG_PPC_ACOP       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb3)
+#define KVM_REG_PPC_WORT       (KVM_REG_PPC | KVM_REG_SIZE_U64 | 0xb4)
 
 #define KVM_REG_PPC_VRSAVE     (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb4)
 #define KVM_REG_PPC_LPCR       (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb5)
@@ -553,6 +554,8 @@ struct kvm_get_htab_header {
 /* Architecture compatibility level */
 #define KVM_REG_PPC_ARCH_COMPAT        (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb7)
 
+#define KVM_REG_PPC_DABRX      (KVM_REG_PPC | KVM_REG_SIZE_U32 | 0xb8)
+
 /* Transactional Memory checkpointed state:
  * This is all GPRs, all VSX regs and a subset of SPRs
  */
index 85059a00f560b18bf514f0c582ad0ffe8d83ca95..5d836b7c1176242ae2c943c0bcc81cf6bcb031cf 100644 (file)
@@ -6,6 +6,8 @@
  * the failure is persistent.  PAPR saves 0xff-0xe0 for the hypervisor.
  */
 #define TM_CAUSE_PERSISTENT    0x01
+#define TM_CAUSE_KVM_RESCHED   0xe0  /* From PAPR */
+#define TM_CAUSE_KVM_FAC_UNAV  0xe2  /* From PAPR */
 #define TM_CAUSE_RESCHED       0xde
 #define TM_CAUSE_TLBI          0xdc
 #define TM_CAUSE_FAC_UNAV      0xda
index 74cb4d72d6739baafba86eeb4fe1d591f5dd99fd..881bf2e2560d40c05723d262da69402dcdfed262 100644 (file)
 #define __NR_process_vm_writev 352
 #define __NR_finit_module      353
 #define __NR_kcmp              354
-
+#define __NR_sched_setattr     355
+#define __NR_sched_getattr     356
 
 #endif /* _UAPI_ASM_POWERPC_UNISTD_H_ */
index 445cb6e39d5b0bb3058caaefe6af61f3f5ba2618..fcc9a89a46950867c81aaec671f9ac6d782c0a77 100644 (file)
@@ -39,6 +39,7 @@ obj-$(CONFIG_PPC64)           += setup_64.o sys_ppc32.o \
 obj-$(CONFIG_HAVE_HW_BREAKPOINT)       += hw_breakpoint.o
 obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_ppc970.o cpu_setup_pa6t.o
 obj-$(CONFIG_PPC_BOOK3S_64)    += cpu_setup_power.o
+obj-$(CONFIG_PPC_BOOK3S_64)    += mce.o mce_power.o
 obj64-$(CONFIG_RELOCATABLE)    += reloc_64.o
 obj-$(CONFIG_PPC_BOOK3E_64)    += exceptions-64e.o idle_book3e.o
 obj-$(CONFIG_PPC_A2)           += cpu_setup_a2.o
@@ -47,7 +48,6 @@ obj-$(CONFIG_ALTIVEC)         += vecemu.o
 obj-$(CONFIG_PPC_970_NAP)      += idle_power4.o
 obj-$(CONFIG_PPC_P7_NAP)       += idle_power7.o
 obj-$(CONFIG_PPC_OF)           += of_platform.o prom_parse.o
-obj-$(CONFIG_PPC_CLOCK)                += clock.o
 procfs-y                       := proc_powerpc.o
 obj-$(CONFIG_PROC_FS)          += $(procfs-y)
 rtaspci-$(CONFIG_PPC64)-$(CONFIG_PCI)  := rtas_pci.o
index d3de01066f7dd786cd531614046b801ff7ebb18f..b5aacf72ae6f5db492a374c93ad2b505558e81c5 100644 (file)
@@ -203,6 +203,15 @@ int main(void)
        DEFINE(PACA_MC_STACK, offsetof(struct paca_struct, mc_kstack));
        DEFINE(PACA_CRIT_STACK, offsetof(struct paca_struct, crit_kstack));
        DEFINE(PACA_DBG_STACK, offsetof(struct paca_struct, dbg_kstack));
+       DEFINE(PACA_TCD_PTR, offsetof(struct paca_struct, tcd_ptr));
+
+       DEFINE(TCD_ESEL_NEXT,
+               offsetof(struct tlb_core_data, esel_next));
+       DEFINE(TCD_ESEL_MAX,
+               offsetof(struct tlb_core_data, esel_max));
+       DEFINE(TCD_ESEL_FIRST,
+               offsetof(struct tlb_core_data, esel_first));
+       DEFINE(TCD_LOCK, offsetof(struct tlb_core_data, lock));
 #endif /* CONFIG_PPC_BOOK3E */
 
 #ifdef CONFIG_PPC_STD_MMU_64
@@ -232,6 +241,10 @@ int main(void)
        DEFINE(PACA_DTL_RIDX, offsetof(struct paca_struct, dtl_ridx));
 #endif /* CONFIG_PPC_STD_MMU_64 */
        DEFINE(PACAEMERGSP, offsetof(struct paca_struct, emergency_sp));
+#ifdef CONFIG_PPC_BOOK3S_64
+       DEFINE(PACAMCEMERGSP, offsetof(struct paca_struct, mc_emergency_sp));
+       DEFINE(PACA_IN_MCE, offsetof(struct paca_struct, in_mce));
+#endif
        DEFINE(PACAHWCPUID, offsetof(struct paca_struct, hw_cpu_id));
        DEFINE(PACAKEXECSTATE, offsetof(struct paca_struct, kexec_state));
        DEFINE(PACA_STARTTIME, offsetof(struct paca_struct, starttime));
@@ -425,18 +438,14 @@ int main(void)
        DEFINE(VCPU_GUEST_PID, offsetof(struct kvm_vcpu, arch.pid));
        DEFINE(VCPU_GPRS, offsetof(struct kvm_vcpu, arch.gpr));
        DEFINE(VCPU_VRSAVE, offsetof(struct kvm_vcpu, arch.vrsave));
-       DEFINE(VCPU_FPRS, offsetof(struct kvm_vcpu, arch.fpr));
-       DEFINE(VCPU_FPSCR, offsetof(struct kvm_vcpu, arch.fpscr));
+       DEFINE(VCPU_FPRS, offsetof(struct kvm_vcpu, arch.fp.fpr));
 #ifdef CONFIG_ALTIVEC
-       DEFINE(VCPU_VRS, offsetof(struct kvm_vcpu, arch.vr));
-       DEFINE(VCPU_VSCR, offsetof(struct kvm_vcpu, arch.vscr));
-#endif
-#ifdef CONFIG_VSX
-       DEFINE(VCPU_VSRS, offsetof(struct kvm_vcpu, arch.vsr));
+       DEFINE(VCPU_VRS, offsetof(struct kvm_vcpu, arch.vr.vr));
 #endif
        DEFINE(VCPU_XER, offsetof(struct kvm_vcpu, arch.xer));
        DEFINE(VCPU_CTR, offsetof(struct kvm_vcpu, arch.ctr));
        DEFINE(VCPU_LR, offsetof(struct kvm_vcpu, arch.lr));
+       DEFINE(VCPU_TAR, offsetof(struct kvm_vcpu, arch.tar));
        DEFINE(VCPU_CR, offsetof(struct kvm_vcpu, arch.cr));
        DEFINE(VCPU_PC, offsetof(struct kvm_vcpu, arch.pc));
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
@@ -484,16 +493,24 @@ int main(void)
        DEFINE(VCPU_DAR, offsetof(struct kvm_vcpu, arch.shregs.dar));
        DEFINE(VCPU_VPA, offsetof(struct kvm_vcpu, arch.vpa.pinned_addr));
        DEFINE(VCPU_VPA_DIRTY, offsetof(struct kvm_vcpu, arch.vpa.dirty));
+       DEFINE(VCPU_INTR_MSR, offsetof(struct kvm_vcpu, arch.intr_msr));
 #endif
 #ifdef CONFIG_PPC_BOOK3S
        DEFINE(VCPU_VCPUID, offsetof(struct kvm_vcpu, vcpu_id));
        DEFINE(VCPU_PURR, offsetof(struct kvm_vcpu, arch.purr));
        DEFINE(VCPU_SPURR, offsetof(struct kvm_vcpu, arch.spurr));
+       DEFINE(VCPU_IC, offsetof(struct kvm_vcpu, arch.ic));
+       DEFINE(VCPU_VTB, offsetof(struct kvm_vcpu, arch.vtb));
        DEFINE(VCPU_DSCR, offsetof(struct kvm_vcpu, arch.dscr));
        DEFINE(VCPU_AMR, offsetof(struct kvm_vcpu, arch.amr));
        DEFINE(VCPU_UAMOR, offsetof(struct kvm_vcpu, arch.uamor));
+       DEFINE(VCPU_IAMR, offsetof(struct kvm_vcpu, arch.iamr));
        DEFINE(VCPU_CTRL, offsetof(struct kvm_vcpu, arch.ctrl));
        DEFINE(VCPU_DABR, offsetof(struct kvm_vcpu, arch.dabr));
+       DEFINE(VCPU_DABRX, offsetof(struct kvm_vcpu, arch.dabrx));
+       DEFINE(VCPU_DAWR, offsetof(struct kvm_vcpu, arch.dawr));
+       DEFINE(VCPU_DAWRX, offsetof(struct kvm_vcpu, arch.dawrx));
+       DEFINE(VCPU_CIABR, offsetof(struct kvm_vcpu, arch.ciabr));
        DEFINE(VCPU_HFLAGS, offsetof(struct kvm_vcpu, arch.hflags));
        DEFINE(VCPU_DEC, offsetof(struct kvm_vcpu, arch.dec));
        DEFINE(VCPU_DEC_EXPIRES, offsetof(struct kvm_vcpu, arch.dec_expires));
@@ -502,8 +519,10 @@ int main(void)
        DEFINE(VCPU_PRODDED, offsetof(struct kvm_vcpu, arch.prodded));
        DEFINE(VCPU_MMCR, offsetof(struct kvm_vcpu, arch.mmcr));
        DEFINE(VCPU_PMC, offsetof(struct kvm_vcpu, arch.pmc));
+       DEFINE(VCPU_SPMC, offsetof(struct kvm_vcpu, arch.spmc));
        DEFINE(VCPU_SIAR, offsetof(struct kvm_vcpu, arch.siar));
        DEFINE(VCPU_SDAR, offsetof(struct kvm_vcpu, arch.sdar));
+       DEFINE(VCPU_SIER, offsetof(struct kvm_vcpu, arch.sier));
        DEFINE(VCPU_SLB, offsetof(struct kvm_vcpu, arch.slb));
        DEFINE(VCPU_SLB_MAX, offsetof(struct kvm_vcpu, arch.slb_max));
        DEFINE(VCPU_SLB_NR, offsetof(struct kvm_vcpu, arch.slb_nr));
@@ -511,20 +530,47 @@ int main(void)
        DEFINE(VCPU_FAULT_DAR, offsetof(struct kvm_vcpu, arch.fault_dar));
        DEFINE(VCPU_LAST_INST, offsetof(struct kvm_vcpu, arch.last_inst));
        DEFINE(VCPU_TRAP, offsetof(struct kvm_vcpu, arch.trap));
-       DEFINE(VCPU_PTID, offsetof(struct kvm_vcpu, arch.ptid));
        DEFINE(VCPU_CFAR, offsetof(struct kvm_vcpu, arch.cfar));
        DEFINE(VCPU_PPR, offsetof(struct kvm_vcpu, arch.ppr));
+       DEFINE(VCPU_FSCR, offsetof(struct kvm_vcpu, arch.fscr));
+       DEFINE(VCPU_PSPB, offsetof(struct kvm_vcpu, arch.pspb));
+       DEFINE(VCPU_EBBHR, offsetof(struct kvm_vcpu, arch.ebbhr));
+       DEFINE(VCPU_EBBRR, offsetof(struct kvm_vcpu, arch.ebbrr));
+       DEFINE(VCPU_BESCR, offsetof(struct kvm_vcpu, arch.bescr));
+       DEFINE(VCPU_CSIGR, offsetof(struct kvm_vcpu, arch.csigr));
+       DEFINE(VCPU_TACR, offsetof(struct kvm_vcpu, arch.tacr));
+       DEFINE(VCPU_TCSCR, offsetof(struct kvm_vcpu, arch.tcscr));
+       DEFINE(VCPU_ACOP, offsetof(struct kvm_vcpu, arch.acop));
+       DEFINE(VCPU_WORT, offsetof(struct kvm_vcpu, arch.wort));
        DEFINE(VCPU_SHADOW_SRR1, offsetof(struct kvm_vcpu, arch.shadow_srr1));
        DEFINE(VCORE_ENTRY_EXIT, offsetof(struct kvmppc_vcore, entry_exit_count));
        DEFINE(VCORE_NAP_COUNT, offsetof(struct kvmppc_vcore, nap_count));
        DEFINE(VCORE_IN_GUEST, offsetof(struct kvmppc_vcore, in_guest));
        DEFINE(VCORE_NAPPING_THREADS, offsetof(struct kvmppc_vcore, napping_threads));
+       DEFINE(VCORE_KVM, offsetof(struct kvmppc_vcore, kvm));
        DEFINE(VCORE_TB_OFFSET, offsetof(struct kvmppc_vcore, tb_offset));
        DEFINE(VCORE_LPCR, offsetof(struct kvmppc_vcore, lpcr));
        DEFINE(VCORE_PCR, offsetof(struct kvmppc_vcore, pcr));
+       DEFINE(VCORE_DPDES, offsetof(struct kvmppc_vcore, dpdes));
        DEFINE(VCPU_SLB_E, offsetof(struct kvmppc_slb, orige));
        DEFINE(VCPU_SLB_V, offsetof(struct kvmppc_slb, origv));
        DEFINE(VCPU_SLB_SIZE, sizeof(struct kvmppc_slb));
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       DEFINE(VCPU_TFHAR, offsetof(struct kvm_vcpu, arch.tfhar));
+       DEFINE(VCPU_TFIAR, offsetof(struct kvm_vcpu, arch.tfiar));
+       DEFINE(VCPU_TEXASR, offsetof(struct kvm_vcpu, arch.texasr));
+       DEFINE(VCPU_GPR_TM, offsetof(struct kvm_vcpu, arch.gpr_tm));
+       DEFINE(VCPU_FPRS_TM, offsetof(struct kvm_vcpu, arch.fp_tm.fpr));
+       DEFINE(VCPU_VRS_TM, offsetof(struct kvm_vcpu, arch.vr_tm.vr));
+       DEFINE(VCPU_VRSAVE_TM, offsetof(struct kvm_vcpu, arch.vrsave_tm));
+       DEFINE(VCPU_CR_TM, offsetof(struct kvm_vcpu, arch.cr_tm));
+       DEFINE(VCPU_LR_TM, offsetof(struct kvm_vcpu, arch.lr_tm));
+       DEFINE(VCPU_CTR_TM, offsetof(struct kvm_vcpu, arch.ctr_tm));
+       DEFINE(VCPU_AMR_TM, offsetof(struct kvm_vcpu, arch.amr_tm));
+       DEFINE(VCPU_PPR_TM, offsetof(struct kvm_vcpu, arch.ppr_tm));
+       DEFINE(VCPU_DSCR_TM, offsetof(struct kvm_vcpu, arch.dscr_tm));
+       DEFINE(VCPU_TAR_TM, offsetof(struct kvm_vcpu, arch.tar_tm));
+#endif
 
 #ifdef CONFIG_PPC_BOOK3S_64
 #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
@@ -589,6 +635,7 @@ int main(void)
        HSTATE_FIELD(HSTATE_XICS_PHYS, xics_phys);
        HSTATE_FIELD(HSTATE_SAVED_XIRR, saved_xirr);
        HSTATE_FIELD(HSTATE_HOST_IPI, host_ipi);
+       HSTATE_FIELD(HSTATE_PTID, ptid);
        HSTATE_FIELD(HSTATE_MMCR, host_mmcr);
        HSTATE_FIELD(HSTATE_PMC, host_pmc);
        HSTATE_FIELD(HSTATE_PURR, host_purr);
index 654932727873da2ed0073d70d77efb271713a28a..2912b8787aa46b4b28b0e84a2e5c068afc2f5ea2 100644 (file)
@@ -12,7 +12,6 @@
 
 #include <linux/cpu.h>
 #include <linux/cpumask.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/kobject.h>
 #include <linux/list.h>
@@ -794,6 +793,9 @@ static void remove_cache_dir(struct cache_dir *cache_dir)
 {
        remove_index_dirs(cache_dir);
 
+       /* Remove cache dir from sysfs */
+       kobject_del(cache_dir->kobj);
+
        kobject_put(cache_dir->kobj);
 
        kfree(cache_dir);
diff --git a/arch/powerpc/kernel/clock.c b/arch/powerpc/kernel/clock.c
deleted file mode 100644 (file)
index a764b47..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Dummy clk implementations for powerpc.
- * These need to be overridden in platform code.
- */
-
-#include <linux/clk.h>
-#include <linux/err.h>
-#include <linux/errno.h>
-#include <linux/export.h>
-#include <asm/clk_interface.h>
-
-struct clk_interface clk_functions;
-
-struct clk *clk_get(struct device *dev, const char *id)
-{
-       if (clk_functions.clk_get)
-               return clk_functions.clk_get(dev, id);
-       return ERR_PTR(-ENOSYS);
-}
-EXPORT_SYMBOL(clk_get);
-
-void clk_put(struct clk *clk)
-{
-       if (clk_functions.clk_put)
-               clk_functions.clk_put(clk);
-}
-EXPORT_SYMBOL(clk_put);
-
-int clk_enable(struct clk *clk)
-{
-       if (clk_functions.clk_enable)
-               return clk_functions.clk_enable(clk);
-       return -ENOSYS;
-}
-EXPORT_SYMBOL(clk_enable);
-
-void clk_disable(struct clk *clk)
-{
-       if (clk_functions.clk_disable)
-               clk_functions.clk_disable(clk);
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
-       if (clk_functions.clk_get_rate)
-               return clk_functions.clk_get_rate(clk);
-       return 0;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
-       if (clk_functions.clk_round_rate)
-               return clk_functions.clk_round_rate(clk, rate);
-       return -ENOSYS;
-}
-EXPORT_SYMBOL(clk_round_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       if (clk_functions.clk_set_rate)
-               return clk_functions.clk_set_rate(clk, rate);
-       return -ENOSYS;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-struct clk *clk_get_parent(struct clk *clk)
-{
-       if (clk_functions.clk_get_parent)
-               return clk_functions.clk_get_parent(clk);
-       return ERR_PTR(-ENOSYS);
-}
-EXPORT_SYMBOL(clk_get_parent);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
-       if (clk_functions.clk_set_parent)
-               return clk_functions.clk_set_parent(clk, parent);
-       return -ENOSYS;
-}
-EXPORT_SYMBOL(clk_set_parent);
index bfb18c7290b7a13fccd520f064228b876430d807..cc2d8962e0906b78b4fe9f0c6e18a6991b66b60e 100644 (file)
@@ -53,11 +53,57 @@ _GLOBAL(__e500_dcache_setup)
        isync
        blr
 
+/*
+ * FIXME - we haven't yet done testing to determine a reasonable default
+ * value for PW20_WAIT_IDLE_BIT.
+ */
+#define PW20_WAIT_IDLE_BIT             50 /* 1ms, TB frequency is 41.66MHZ */
+_GLOBAL(setup_pw20_idle)
+       mfspr   r3, SPRN_PWRMGTCR0
+
+       /* Set PW20_WAIT bit, enable pw20 state*/
+       ori     r3, r3, PWRMGTCR0_PW20_WAIT
+       li      r11, PW20_WAIT_IDLE_BIT
+
+       /* Set Automatic PW20 Core Idle Count */
+       rlwimi  r3, r11, PWRMGTCR0_PW20_ENT_SHIFT, PWRMGTCR0_PW20_ENT
+
+       mtspr   SPRN_PWRMGTCR0, r3
+
+       blr
+
+/*
+ * FIXME - we haven't yet done testing to determine a reasonable default
+ * value for AV_WAIT_IDLE_BIT.
+ */
+#define AV_WAIT_IDLE_BIT               50 /* 1ms, TB frequency is 41.66MHZ */
+_GLOBAL(setup_altivec_idle)
+       mfspr   r3, SPRN_PWRMGTCR0
+
+       /* Enable Altivec Idle */
+       oris    r3, r3, PWRMGTCR0_AV_IDLE_PD_EN@h
+       li      r11, AV_WAIT_IDLE_BIT
+
+       /* Set Automatic AltiVec Idle Count */
+       rlwimi  r3, r11, PWRMGTCR0_AV_IDLE_CNT_SHIFT, PWRMGTCR0_AV_IDLE_CNT
+
+       mtspr   SPRN_PWRMGTCR0, r3
+
+       blr
+
 _GLOBAL(__setup_cpu_e6500)
        mflr    r6
 #ifdef CONFIG_PPC64
        bl      .setup_altivec_ivors
+       /* Touch IVOR42 only if the CPU supports E.HV category */
+       mfspr   r10,SPRN_MMUCFG
+       rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
+       beq     1f
+       bl      .setup_lrat_ivor
+1:
 #endif
+       bl      setup_pw20_idle
+       bl      setup_altivec_idle
        bl      __setup_cpu_e5500
        mtlr    r6
        blr
@@ -119,6 +165,14 @@ _GLOBAL(__setup_cpu_e5500)
 _GLOBAL(__restore_cpu_e6500)
        mflr    r5
        bl      .setup_altivec_ivors
+       /* Touch IVOR42 only if the CPU supports E.HV category */
+       mfspr   r10,SPRN_MMUCFG
+       rlwinm. r10,r10,0,MMUCFG_LPIDSIZE
+       beq     1f
+       bl      .setup_lrat_ivor
+1:
+       bl      .setup_pw20_idle
+       bl      .setup_altivec_idle
        bl      __restore_cpu_e5500
        mtlr    r5
        blr
index 18b5b9cf8e3730f4608ca6ff997810d5cc47df9a..37d1bb002aa97bbd3ea52b19304f746521e30bff 100644 (file)
@@ -29,7 +29,7 @@ _GLOBAL(__setup_cpu_power7)
        mtspr   SPRN_LPID,r0
        mfspr   r3,SPRN_LPCR
        bl      __init_LPCR
-       bl      __init_TLB
+       bl      __init_tlb_power7
        mtlr    r11
        blr
 
@@ -42,7 +42,7 @@ _GLOBAL(__restore_cpu_power7)
        mtspr   SPRN_LPID,r0
        mfspr   r3,SPRN_LPCR
        bl      __init_LPCR
-       bl      __init_TLB
+       bl      __init_tlb_power7
        mtlr    r11
        blr
 
@@ -59,7 +59,7 @@ _GLOBAL(__setup_cpu_power8)
        oris    r3, r3, LPCR_AIL_3@h
        bl      __init_LPCR
        bl      __init_HFSCR
-       bl      __init_TLB
+       bl      __init_tlb_power8
        bl      __init_PMU_HV
        mtlr    r11
        blr
@@ -78,7 +78,7 @@ _GLOBAL(__restore_cpu_power8)
        oris    r3, r3, LPCR_AIL_3@h
        bl      __init_LPCR
        bl      __init_HFSCR
-       bl      __init_TLB
+       bl      __init_tlb_power8
        bl      __init_PMU_HV
        mtlr    r11
        blr
@@ -134,15 +134,31 @@ __init_HFSCR:
        mtspr   SPRN_HFSCR,r3
        blr
 
-__init_TLB:
-       /*
-        * Clear the TLB using the "IS 3" form of tlbiel instruction
-        * (invalidate by congruence class). P7 has 128 CCs, P8 has 512
-        * so we just always do 512
-        */
+/*
+ * Clear the TLB using the specified IS form of tlbiel instruction
+ * (invalidate by congruence class). P7 has 128 CCs., P8 has 512.
+ *
+ * r3 = IS field
+ */
+__init_tlb_power7:
+       li      r3,0xc00        /* IS field = 0b11 */
+_GLOBAL(__flush_tlb_power7)
+       li      r6,128
+       mtctr   r6
+       mr      r7,r3           /* IS field */
+       ptesync
+2:     tlbiel  r7
+       addi    r7,r7,0x1000
+       bdnz    2b
+       ptesync
+1:     blr
+
+__init_tlb_power8:
+       li      r3,0xc00        /* IS field = 0b11 */
+_GLOBAL(__flush_tlb_power8)
        li      r6,512
        mtctr   r6
-       li      r7,0xc00        /* IS field = 0b11 */
+       mr      r7,r3           /* IS field */
        ptesync
 2:     tlbiel  r7
        addi    r7,r7,0x1000
index 597d954e58601b36f376953898faf9178b818239..6c8dd5da4de5ea0b8b88196b773d2e39fca1c732 100644 (file)
@@ -71,6 +71,10 @@ extern void __restore_cpu_power7(void);
 extern void __setup_cpu_power8(unsigned long offset, struct cpu_spec* spec);
 extern void __restore_cpu_power8(void);
 extern void __restore_cpu_a2(void);
+extern void __flush_tlb_power7(unsigned long inval_selector);
+extern void __flush_tlb_power8(unsigned long inval_selector);
+extern long __machine_check_early_realmode_p7(struct pt_regs *regs);
+extern long __machine_check_early_realmode_p8(struct pt_regs *regs);
 #endif /* CONFIG_PPC64 */
 #if defined(CONFIG_E500)
 extern void __setup_cpu_e5500(unsigned long offset, struct cpu_spec* spec);
@@ -440,6 +444,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_cpu_type      = "ppc64/ibm-compat-v1",
                .cpu_setup              = __setup_cpu_power7,
                .cpu_restore            = __restore_cpu_power7,
+               .flush_tlb              = __flush_tlb_power7,
+               .machine_check_early    = __machine_check_early_realmode_p7,
                .platform               = "power7",
        },
        {       /* 2.07-compliant processor, i.e. Power8 "architected" mode */
@@ -456,6 +462,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_cpu_type      = "ppc64/ibm-compat-v1",
                .cpu_setup              = __setup_cpu_power8,
                .cpu_restore            = __restore_cpu_power8,
+               .flush_tlb              = __flush_tlb_power8,
+               .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
        {       /* Power7 */
@@ -474,6 +482,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_type          = PPC_OPROFILE_POWER4,
                .cpu_setup              = __setup_cpu_power7,
                .cpu_restore            = __restore_cpu_power7,
+               .flush_tlb              = __flush_tlb_power7,
+               .machine_check_early    = __machine_check_early_realmode_p7,
                .platform               = "power7",
        },
        {       /* Power7+ */
@@ -492,6 +502,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_type          = PPC_OPROFILE_POWER4,
                .cpu_setup              = __setup_cpu_power7,
                .cpu_restore            = __restore_cpu_power7,
+               .flush_tlb              = __flush_tlb_power7,
+               .machine_check_early    = __machine_check_early_realmode_p7,
                .platform               = "power7+",
        },
        {       /* Power8E */
@@ -510,6 +522,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_type          = PPC_OPROFILE_INVALID,
                .cpu_setup              = __setup_cpu_power8,
                .cpu_restore            = __restore_cpu_power8,
+               .flush_tlb              = __flush_tlb_power8,
+               .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
        {       /* Power8 */
@@ -528,6 +542,8 @@ static struct cpu_spec __initdata cpu_specs[] = {
                .oprofile_type          = PPC_OPROFILE_INVALID,
                .cpu_setup              = __setup_cpu_power8,
                .cpu_restore            = __restore_cpu_power8,
+               .flush_tlb              = __flush_tlb_power8,
+               .machine_check_early    = __machine_check_early_realmode_p8,
                .platform               = "power8",
        },
        {       /* Cell Broadband Engine */
index fdcd8f551affe3225f8f7da271a4b630c99bd5f5..18d7c80ddeb98c0b9569ca039a630ac5bd5ba7c2 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/export.h>
 #include <linux/crash_dump.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/types.h>
 
index e4897523de41e45476bf002a64a3ab68d3e85e22..54d0116256f752247abd63d6619068c4d619d24d 100644 (file)
@@ -83,10 +83,10 @@ static int dma_iommu_dma_supported(struct device *dev, u64 mask)
                return 0;
        }
 
-       if (tbl->it_offset > (mask >> IOMMU_PAGE_SHIFT)) {
+       if (tbl->it_offset > (mask >> tbl->it_page_shift)) {
                dev_info(dev, "Warning: IOMMU offset too big for device mask\n");
                dev_info(dev, "mask: 0x%08llx, table offset: 0x%08lx\n",
-                               mask, tbl->it_offset << IOMMU_PAGE_SHIFT);
+                               mask, tbl->it_offset << tbl->it_page_shift);
                return 0;
        } else
                return 1;
index 4bd687d5e7aa3f80e1b33912b5451bd34a3187b1..148db72a8c4371e69f79009683eb8b3baf12c3d6 100644 (file)
@@ -84,7 +84,7 @@
 #define EEH_MAX_FAILS  2100000
 
 /* Time to wait for a PCI slot to report status, in milliseconds */
-#define PCI_BUS_RESET_WAIT_MSEC (60*1000)
+#define PCI_BUS_RESET_WAIT_MSEC (5*60*1000)
 
 /* Platform dependent EEH operations */
 struct eeh_ops *eeh_ops = NULL;
@@ -921,6 +921,13 @@ void eeh_add_device_late(struct pci_dev *dev)
                eeh_sysfs_remove_device(edev->pdev);
                edev->mode &= ~EEH_DEV_SYSFS;
 
+               /*
+                * We definitely should have the PCI device removed
+                * though it wasn't correctly. So we needn't call
+                * into error handler afterwards.
+                */
+               edev->mode |= EEH_DEV_NO_HANDLER;
+
                edev->pdev = NULL;
                dev->dev.archdata.edev = NULL;
        }
@@ -1023,6 +1030,14 @@ void eeh_remove_device(struct pci_dev *dev)
        else
                edev->mode |= EEH_DEV_DISCONNECTED;
 
+       /*
+        * We're removing from the PCI subsystem, that means
+        * the PCI device driver can't support EEH or not
+        * well. So we rely on hotplug completely to do recovery
+        * for the specific PCI device.
+        */
+       edev->mode |= EEH_DEV_NO_HANDLER;
+
        eeh_addr_cache_rmv_dev(dev);
        eeh_sysfs_remove_device(dev);
        edev->mode &= ~EEH_DEV_SYSFS;
index c17f90d0f73c62a2bcb12bd5445ab53a2ee935f3..7bb30dca4e192f55ca689319eefdc2a50646ff3a 100644 (file)
@@ -217,7 +217,8 @@ static void *eeh_report_mmio_enabled(void *data, void *userdata)
        if (!driver) return NULL;
 
        if (!driver->err_handler ||
-           !driver->err_handler->mmio_enabled) {
+           !driver->err_handler->mmio_enabled ||
+           (edev->mode & EEH_DEV_NO_HANDLER)) {
                eeh_pcid_put(dev);
                return NULL;
        }
@@ -258,7 +259,8 @@ static void *eeh_report_reset(void *data, void *userdata)
        eeh_enable_irq(dev);
 
        if (!driver->err_handler ||
-           !driver->err_handler->slot_reset) {
+           !driver->err_handler->slot_reset ||
+           (edev->mode & EEH_DEV_NO_HANDLER)) {
                eeh_pcid_put(dev);
                return NULL;
        }
@@ -297,7 +299,9 @@ static void *eeh_report_resume(void *data, void *userdata)
        eeh_enable_irq(dev);
 
        if (!driver->err_handler ||
-           !driver->err_handler->resume) {
+           !driver->err_handler->resume ||
+           (edev->mode & EEH_DEV_NO_HANDLER)) {
+               edev->mode &= ~EEH_DEV_NO_HANDLER;
                eeh_pcid_put(dev);
                return NULL;
        }
@@ -476,7 +480,7 @@ static int eeh_reset_device(struct eeh_pe *pe, struct pci_bus *bus)
 /* The longest amount of time to wait for a pci device
  * to come back on line, in seconds.
  */
-#define MAX_WAIT_FOR_RECOVERY 150
+#define MAX_WAIT_FOR_RECOVERY 300
 
 static void eeh_handle_normal_event(struct eeh_pe *pe)
 {
@@ -637,86 +641,92 @@ static void eeh_handle_special_event(void)
 {
        struct eeh_pe *pe, *phb_pe;
        struct pci_bus *bus;
-       struct pci_controller *hose, *tmp;
+       struct pci_controller *hose;
        unsigned long flags;
-       int rc = 0;
+       int rc;
 
-       /*
-        * The return value from next_error() has been classified as follows.
-        * It might be good to enumerate them. However, next_error() is only
-        * supported by PowerNV platform for now. So it would be fine to use
-        * integer directly:
-        *
-        * 4 - Dead IOC           3 - Dead PHB
-        * 2 - Fenced PHB         1 - Frozen PE
-        * 0 - No error found
-        *
-        */
-       rc = eeh_ops->next_error(&pe);
-       if (rc <= 0)
-               return;
 
-       switch (rc) {
-       case 4:
-               /* Mark all PHBs in dead state */
-               eeh_serialize_lock(&flags);
-               list_for_each_entry_safe(hose, tmp,
-                               &hose_list, list_node) {
-                       phb_pe = eeh_phb_pe_get(hose);
-                       if (!phb_pe) continue;
-
-                       eeh_pe_state_mark(phb_pe,
-                               EEH_PE_ISOLATED | EEH_PE_PHB_DEAD);
+       do {
+               rc = eeh_ops->next_error(&pe);
+
+               switch (rc) {
+               case EEH_NEXT_ERR_DEAD_IOC:
+                       /* Mark all PHBs in dead state */
+                       eeh_serialize_lock(&flags);
+
+                       /* Purge all events */
+                       eeh_remove_event(NULL);
+
+                       list_for_each_entry(hose, &hose_list, list_node) {
+                               phb_pe = eeh_phb_pe_get(hose);
+                               if (!phb_pe) continue;
+
+                               eeh_pe_state_mark(phb_pe,
+                                       EEH_PE_ISOLATED | EEH_PE_PHB_DEAD);
+                       }
+
+                       eeh_serialize_unlock(flags);
+
+                       break;
+               case EEH_NEXT_ERR_FROZEN_PE:
+               case EEH_NEXT_ERR_FENCED_PHB:
+               case EEH_NEXT_ERR_DEAD_PHB:
+                       /* Mark the PE in fenced state */
+                       eeh_serialize_lock(&flags);
+
+                       /* Purge all events of the PHB */
+                       eeh_remove_event(pe);
+
+                       if (rc == EEH_NEXT_ERR_DEAD_PHB)
+                               eeh_pe_state_mark(pe,
+                                       EEH_PE_ISOLATED | EEH_PE_PHB_DEAD);
+                       else
+                               eeh_pe_state_mark(pe,
+                                       EEH_PE_ISOLATED | EEH_PE_RECOVERING);
+
+                       eeh_serialize_unlock(flags);
+
+                       break;
+               case EEH_NEXT_ERR_NONE:
+                       return;
+               default:
+                       pr_warn("%s: Invalid value %d from next_error()\n",
+                               __func__, rc);
+                       return;
                }
-               eeh_serialize_unlock(flags);
-
-               /* Purge all events */
-               eeh_remove_event(NULL);
-               break;
-       case 3:
-       case 2:
-       case 1:
-               /* Mark the PE in fenced state */
-               eeh_serialize_lock(&flags);
-               if (rc == 3)
-                       eeh_pe_state_mark(pe,
-                               EEH_PE_ISOLATED | EEH_PE_PHB_DEAD);
-               else
-                       eeh_pe_state_mark(pe,
-                               EEH_PE_ISOLATED | EEH_PE_RECOVERING);
-               eeh_serialize_unlock(flags);
-
-               /* Purge all events of the PHB */
-               eeh_remove_event(pe);
-               break;
-       default:
-               pr_err("%s: Invalid value %d from next_error()\n",
-                      __func__, rc);
-               return;
-       }
 
-       /*
-        * For fenced PHB and frozen PE, it's handled as normal
-        * event. We have to remove the affected PHBs for dead
-        * PHB and IOC
-        */
-       if (rc == 2 || rc == 1)
-               eeh_handle_normal_event(pe);
-       else {
-               pci_lock_rescan_remove();
-               list_for_each_entry_safe(hose, tmp,
-                       &hose_list, list_node) {
-                       phb_pe = eeh_phb_pe_get(hose);
-                       if (!phb_pe || !(phb_pe->state & EEH_PE_PHB_DEAD))
-                               continue;
-
-                       bus = eeh_pe_bus_get(phb_pe);
-                       /* Notify all devices that they're about to go down. */
-                       eeh_pe_dev_traverse(pe, eeh_report_failure, NULL);
-                       pcibios_remove_pci_devices(bus);
+               /*
+                * For fenced PHB and frozen PE, it's handled as normal
+                * event. We have to remove the affected PHBs for dead
+                * PHB and IOC
+                */
+               if (rc == EEH_NEXT_ERR_FROZEN_PE ||
+                   rc == EEH_NEXT_ERR_FENCED_PHB) {
+                       eeh_handle_normal_event(pe);
+               } else {
+                       pci_lock_rescan_remove();
+                       list_for_each_entry(hose, &hose_list, list_node) {
+                               phb_pe = eeh_phb_pe_get(hose);
+                               if (!phb_pe ||
+                                   !(phb_pe->state & EEH_PE_PHB_DEAD))
+                                       continue;
+
+                               /* Notify all devices to be down */
+                               bus = eeh_pe_bus_get(phb_pe);
+                               eeh_pe_dev_traverse(pe,
+                                       eeh_report_failure, NULL);
+                               pcibios_remove_pci_devices(bus);
+                       }
+                       pci_unlock_rescan_remove();
                }
-               pci_unlock_rescan_remove();
-       }
+
+               /*
+                * If we have detected dead IOC, we needn't proceed
+                * any more since all PHBs would have been removed
+                */
+               if (rc == EEH_NEXT_ERR_DEAD_IOC)
+                       break;
+       } while (rc != EEH_NEXT_ERR_NONE);
 }
 
 /**
index f9450537e335a350354dec35ff5fdf15876ef0a6..f0c353fa655a3a5a742e2de674851ab3ca88006a 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/delay.h>
 #include <linux/export.h>
 #include <linux/gfp.h>
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
 #include <linux/string.h>
@@ -737,6 +736,9 @@ static void *eeh_restore_one_device_bars(void *data, void *flag)
        else
                eeh_restore_device_bars(edev, dn);
 
+       if (eeh_ops->restore_config)
+               eeh_ops->restore_config(dn);
+
        return NULL;
 }
 
index bbfb0294b3544072ac22b2fcfee486620ae1479e..662c6dd98072e72beabcb1e894cc05999324da81 100644 (file)
@@ -664,8 +664,16 @@ _GLOBAL(ret_from_except_lite)
        bl      .restore_interrupts
        SCHEDULE_USER
        b       .ret_from_except_lite
-
-2:     bl      .save_nvgprs
+2:
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       andi.   r0,r4,_TIF_USER_WORK_MASK & ~_TIF_RESTORE_TM
+       bne     3f              /* only restore TM if nothing else to do */
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .restore_tm_state
+       b       restore
+3:
+#endif
+       bl      .save_nvgprs
        bl      .restore_interrupts
        addi    r3,r1,STACK_FRAME_OVERHEAD
        bl      .do_notify_resume
index e7751561fd1d6cb75f88a703edfb3581a0146d3a..063b65dd4f27a256106d34da4fda70c17859752f 100644 (file)
@@ -308,6 +308,7 @@ interrupt_base_book3e:                                      /* fake trap */
        EXCEPTION_STUB(0x2e0, guest_doorbell_crit)
        EXCEPTION_STUB(0x300, hypercall)
        EXCEPTION_STUB(0x320, ehpriv)
+       EXCEPTION_STUB(0x340, lrat_error)
 
        .globl interrupt_end_book3e
 interrupt_end_book3e:
@@ -677,6 +678,17 @@ kernel_dbg_exc:
        bl      .unknown_exception
        b       .ret_from_except
 
+/* LRAT Error interrupt */
+       START_EXCEPTION(lrat_error);
+       NORMAL_EXCEPTION_PROLOG(0x340, BOOKE_INTERRUPT_LRAT_ERROR,
+                               PROLOG_ADDITION_NONE)
+       EXCEPTION_COMMON(0x340, PACA_EXGEN, INTS_KEEP)
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .save_nvgprs
+       INTS_RESTORE_HARD
+       bl      .unknown_exception
+       b       .ret_from_except
+
 /*
  * An interrupt came in while soft-disabled; We mark paca->irq_happened
  * accordingly and if the interrupt is level sensitive, we hard disable
@@ -859,6 +871,7 @@ BAD_STACK_TRAMPOLINE(0x2e0)
 BAD_STACK_TRAMPOLINE(0x300)
 BAD_STACK_TRAMPOLINE(0x310)
 BAD_STACK_TRAMPOLINE(0x320)
+BAD_STACK_TRAMPOLINE(0x340)
 BAD_STACK_TRAMPOLINE(0x400)
 BAD_STACK_TRAMPOLINE(0x500)
 BAD_STACK_TRAMPOLINE(0x600)
@@ -1055,12 +1068,9 @@ skpinv:  addi    r6,r6,1                         /* Increment */
        mtspr   SPRN_MAS0,r3
        tlbre
        mfspr   r6,SPRN_MAS1
-       rlwinm  r6,r6,0,2,0     /* clear IPROT */
+       rlwinm  r6,r6,0,2,31    /* clear IPROT and VALID */
        mtspr   SPRN_MAS1,r6
        tlbwe
-
-       /* Invalidate TLB1 */
-       PPC_TLBILX_ALL(0,R0)
        sync
        isync
 
@@ -1114,12 +1124,9 @@ skpinv:  addi    r6,r6,1                         /* Increment */
        mtspr   SPRN_MAS0,r4
        tlbre
        mfspr   r5,SPRN_MAS1
-       rlwinm  r5,r5,0,2,0     /* clear IPROT */
+       rlwinm  r5,r5,0,2,31    /* clear IPROT and VALID */
        mtspr   SPRN_MAS1,r5
        tlbwe
-
-       /* Invalidate TLB1 */
-       PPC_TLBILX_ALL(0,R0)
        sync
        isync
 
@@ -1414,3 +1421,7 @@ _GLOBAL(setup_ehv_ivors)
        SET_IVOR(38, 0x2c0) /* Guest Processor Doorbell */
        SET_IVOR(39, 0x2e0) /* Guest Processor Doorbell Crit/MC */
        blr
+
+_GLOBAL(setup_lrat_ivor)
+       SET_IVOR(42, 0x340) /* LRAT Error */
+       blr
index 9f905e40922e41de4eb6f43421290944c5d08567..38d507306a111dc40f06028c90d5014e2fedd817 100644 (file)
@@ -155,8 +155,30 @@ machine_check_pSeries_1:
         */
        HMT_MEDIUM_PPR_DISCARD
        SET_SCRATCH0(r13)               /* save r13 */
+#ifdef CONFIG_PPC_P7_NAP
+BEGIN_FTR_SECTION
+       /* Running native on arch 2.06 or later, check if we are
+        * waking up from nap. We only handle no state loss and
+        * supervisor state loss. We do -not- handle hypervisor
+        * state loss at this time.
+        */
+       mfspr   r13,SPRN_SRR1
+       rlwinm. r13,r13,47-31,30,31
+       beq     9f
+
+       /* waking up from powersave (nap) state */
+       cmpwi   cr1,r13,2
+       /* Total loss of HV state is fatal. let's just stay stuck here */
+       bgt     cr1,.
+9:
+END_FTR_SECTION_IFSET(CPU_FTR_HVMODE | CPU_FTR_ARCH_206)
+#endif /* CONFIG_PPC_P7_NAP */
        EXCEPTION_PROLOG_0(PACA_EXMC)
+BEGIN_FTR_SECTION
+       b       machine_check_pSeries_early
+FTR_SECTION_ELSE
        b       machine_check_pSeries_0
+ALT_FTR_SECTION_END_IFSET(CPU_FTR_HVMODE)
 
        . = 0x300
        .globl data_access_pSeries
@@ -405,6 +427,64 @@ denorm_exception_hv:
 
        .align  7
        /* moved from 0x200 */
+machine_check_pSeries_early:
+BEGIN_FTR_SECTION
+       EXCEPTION_PROLOG_1(PACA_EXMC, NOTEST, 0x200)
+       /*
+        * Register contents:
+        * R13          = PACA
+        * R9           = CR
+        * Original R9 to R13 is saved on PACA_EXMC
+        *
+        * Switch to mc_emergency stack and handle re-entrancy (though we
+        * currently don't test for overflow). Save MCE registers srr1,
+        * srr0, dar and dsisr and then set ME=1
+        *
+        * We use paca->in_mce to check whether this is the first entry or
+        * nested machine check. We increment paca->in_mce to track nested
+        * machine checks.
+        *
+        * If this is the first entry then set stack pointer to
+        * paca->mc_emergency_sp, otherwise r1 is already pointing to
+        * stack frame on mc_emergency stack.
+        *
+        * NOTE: We are here with MSR_ME=0 (off), which means we risk a
+        * checkstop if we get another machine check exception before we do
+        * rfid with MSR_ME=1.
+        */
+       mr      r11,r1                  /* Save r1 */
+       lhz     r10,PACA_IN_MCE(r13)
+       cmpwi   r10,0                   /* Are we in nested machine check */
+       bne     0f                      /* Yes, we are. */
+       /* First machine check entry */
+       ld      r1,PACAMCEMERGSP(r13)   /* Use MC emergency stack */
+0:     subi    r1,r1,INT_FRAME_SIZE    /* alloc stack frame */
+       addi    r10,r10,1               /* increment paca->in_mce */
+       sth     r10,PACA_IN_MCE(r13)
+       std     r11,GPR1(r1)            /* Save r1 on the stack. */
+       std     r11,0(r1)               /* make stack chain pointer */
+       mfspr   r11,SPRN_SRR0           /* Save SRR0 */
+       std     r11,_NIP(r1)
+       mfspr   r11,SPRN_SRR1           /* Save SRR1 */
+       std     r11,_MSR(r1)
+       mfspr   r11,SPRN_DAR            /* Save DAR */
+       std     r11,_DAR(r1)
+       mfspr   r11,SPRN_DSISR          /* Save DSISR */
+       std     r11,_DSISR(r1)
+       std     r9,_CCR(r1)             /* Save CR in stackframe */
+       /* Save r9 through r13 from EXMC save area to stack frame. */
+       EXCEPTION_PROLOG_COMMON_2(PACA_EXMC)
+       mfmsr   r11                     /* get MSR value */
+       ori     r11,r11,MSR_ME          /* turn on ME bit */
+       ori     r11,r11,MSR_RI          /* turn on RI bit */
+       ld      r12,PACAKBASE(r13)      /* get high part of &label */
+       LOAD_HANDLER(r12, machine_check_handle_early)
+       mtspr   SPRN_SRR0,r12
+       mtspr   SPRN_SRR1,r11
+       rfid
+       b       .       /* prevent speculative execution */
+END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
+
 machine_check_pSeries:
        .globl machine_check_fwnmi
 machine_check_fwnmi:
@@ -688,30 +768,6 @@ kvmppc_skip_Hinterrupt:
 
        STD_EXCEPTION_COMMON(0x100, system_reset, .system_reset_exception)
 
-       /*
-        * Machine check is different because we use a different
-        * save area: PACA_EXMC instead of PACA_EXGEN.
-        */
-       .align  7
-       .globl machine_check_common
-machine_check_common:
-
-       mfspr   r10,SPRN_DAR
-       std     r10,PACA_EXGEN+EX_DAR(r13)
-       mfspr   r10,SPRN_DSISR
-       stw     r10,PACA_EXGEN+EX_DSISR(r13)
-       EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC)
-       FINISH_NAP
-       DISABLE_INTS
-       ld      r3,PACA_EXGEN+EX_DAR(r13)
-       lwz     r4,PACA_EXGEN+EX_DSISR(r13)
-       std     r3,_DAR(r1)
-       std     r4,_DSISR(r1)
-       bl      .save_nvgprs
-       addi    r3,r1,STACK_FRAME_OVERHEAD
-       bl      .machine_check_exception
-       b       .ret_from_except
-
        STD_EXCEPTION_COMMON_ASYNC(0x500, hardware_interrupt, do_IRQ)
        STD_EXCEPTION_COMMON_ASYNC(0x900, decrementer, .timer_interrupt)
        STD_EXCEPTION_COMMON(0x980, hdecrementer, .hdec_interrupt)
@@ -1080,6 +1136,30 @@ unrecov_user_slb:
 #endif /* __DISABLED__ */
 
 
+       /*
+        * Machine check is different because we use a different
+        * save area: PACA_EXMC instead of PACA_EXGEN.
+        */
+       .align  7
+       .globl machine_check_common
+machine_check_common:
+
+       mfspr   r10,SPRN_DAR
+       std     r10,PACA_EXGEN+EX_DAR(r13)
+       mfspr   r10,SPRN_DSISR
+       stw     r10,PACA_EXGEN+EX_DSISR(r13)
+       EXCEPTION_PROLOG_COMMON(0x200, PACA_EXMC)
+       FINISH_NAP
+       DISABLE_INTS
+       ld      r3,PACA_EXGEN+EX_DAR(r13)
+       lwz     r4,PACA_EXGEN+EX_DSISR(r13)
+       std     r3,_DAR(r1)
+       std     r4,_DSISR(r1)
+       bl      .save_nvgprs
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .machine_check_exception
+       b       .ret_from_except
+
        .align  7
        .globl alignment_common
 alignment_common:
@@ -1263,6 +1343,120 @@ _GLOBAL(opal_mc_secondary_handler)
 #endif /* CONFIG_PPC_POWERNV */
 
 
+#define MACHINE_CHECK_HANDLER_WINDUP                   \
+       /* Clear MSR_RI before setting SRR0 and SRR1. */\
+       li      r0,MSR_RI;                              \
+       mfmsr   r9;             /* get MSR value */     \
+       andc    r9,r9,r0;                               \
+       mtmsrd  r9,1;           /* Clear MSR_RI */      \
+       /* Move original SRR0 and SRR1 into the respective regs */      \
+       ld      r9,_MSR(r1);                            \
+       mtspr   SPRN_SRR1,r9;                           \
+       ld      r3,_NIP(r1);                            \
+       mtspr   SPRN_SRR0,r3;                           \
+       ld      r9,_CTR(r1);                            \
+       mtctr   r9;                                     \
+       ld      r9,_XER(r1);                            \
+       mtxer   r9;                                     \
+       ld      r9,_LINK(r1);                           \
+       mtlr    r9;                                     \
+       REST_GPR(0, r1);                                \
+       REST_8GPRS(2, r1);                              \
+       REST_GPR(10, r1);                               \
+       ld      r11,_CCR(r1);                           \
+       mtcr    r11;                                    \
+       /* Decrement paca->in_mce. */                   \
+       lhz     r12,PACA_IN_MCE(r13);                   \
+       subi    r12,r12,1;                              \
+       sth     r12,PACA_IN_MCE(r13);                   \
+       REST_GPR(11, r1);                               \
+       REST_2GPRS(12, r1);                             \
+       /* restore original r1. */                      \
+       ld      r1,GPR1(r1)
+
+       /*
+        * Handle machine check early in real mode. We come here with
+        * ME=1, MMU (IR=0 and DR=0) off and using MC emergency stack.
+        */
+       .align  7
+       .globl machine_check_handle_early
+machine_check_handle_early:
+       std     r0,GPR0(r1)     /* Save r0 */
+       EXCEPTION_PROLOG_COMMON_3(0x200)
+       bl      .save_nvgprs
+       addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .machine_check_early
+       ld      r12,_MSR(r1)
+#ifdef CONFIG_PPC_P7_NAP
+       /*
+        * Check if thread was in power saving mode. We come here when any
+        * of the following is true:
+        * a. thread wasn't in power saving mode
+        * b. thread was in power saving mode with no state loss or
+        *    supervisor state loss
+        *
+        * Go back to nap again if (b) is true.
+        */
+       rlwinm. r11,r12,47-31,30,31     /* Was it in power saving mode? */
+       beq     4f                      /* No, it wasn;t */
+       /* Thread was in power saving mode. Go back to nap again. */
+       cmpwi   r11,2
+       bne     3f
+       /* Supervisor state loss */
+       li      r0,1
+       stb     r0,PACA_NAPSTATELOST(r13)
+3:     bl      .machine_check_queue_event
+       MACHINE_CHECK_HANDLER_WINDUP
+       GET_PACA(r13)
+       ld      r1,PACAR1(r13)
+       b       .power7_enter_nap_mode
+4:
+#endif
+       /*
+        * Check if we are coming from hypervisor userspace. If yes then we
+        * continue in host kernel in V mode to deliver the MC event.
+        */
+       rldicl. r11,r12,4,63            /* See if MC hit while in HV mode. */
+       beq     5f
+       andi.   r11,r12,MSR_PR          /* See if coming from user. */
+       bne     9f                      /* continue in V mode if we are. */
+
+5:
+#ifdef CONFIG_KVM_BOOK3S_64_HV
+       /*
+        * We are coming from kernel context. Check if we are coming from
+        * guest. if yes, then we can continue. We will fall through
+        * do_kvm_200->kvmppc_interrupt to deliver the MC event to guest.
+        */
+       lbz     r11,HSTATE_IN_GUEST(r13)
+       cmpwi   r11,0                   /* Check if coming from guest */
+       bne     9f                      /* continue if we are. */
+#endif
+       /*
+        * At this point we are not sure about what context we come from.
+        * Queue up the MCE event and return from the interrupt.
+        * But before that, check if this is an un-recoverable exception.
+        * If yes, then stay on emergency stack and panic.
+        */
+       andi.   r11,r12,MSR_RI
+       bne     2f
+1:     addi    r3,r1,STACK_FRAME_OVERHEAD
+       bl      .unrecoverable_exception
+       b       1b
+2:
+       /*
+        * Return from MC interrupt.
+        * Queue up the MCE event so that we can log it later, while
+        * returning from kernel or opal call.
+        */
+       bl      .machine_check_queue_event
+       MACHINE_CHECK_HANDLER_WINDUP
+       rfid
+9:
+       /* Deliver the machine check to host kernel in V mode. */
+       MACHINE_CHECK_HANDLER_WINDUP
+       b       machine_check_pSeries
+
 /*
  * r13 points to the PACA, r9 contains the saved CR,
  * r12 contain the saved SRR1, SRR0 is still ready for return
index f7f5b8bed68f59500964f75ff9f7d9b2aa211d0c..9ad236e5d2c9d072540f1167107076e883af9ac3 100644 (file)
@@ -80,6 +80,22 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
        blr
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 
+/*
+ * Enable use of the FPU, and VSX if possible, for the caller.
+ */
+_GLOBAL(fp_enable)
+       mfmsr   r3
+       ori     r3,r3,MSR_FP
+#ifdef CONFIG_VSX
+BEGIN_FTR_SECTION
+       oris    r3,r3,MSR_VSX@h
+END_FTR_SECTION_IFSET(CPU_FTR_VSX)
+#endif
+       SYNC
+       MTMSRD(r3)
+       isync                   /* (not necessary for arch 2.02 and later) */
+       blr
+
 /*
  * Load state from memory into FP registers including FPSCR.
  * Assumes the caller has enabled FP in the MSR.
index a92c79be2728e97bb54433e6c7d49b5917a2dcde..f22e7e44fbf321e9df8140ef55cb73e0b72142b0 100644 (file)
@@ -176,6 +176,8 @@ skpinv:     addi    r6,r6,1                         /* Increment */
 /* 7. Jump to KERNELBASE mapping */
        lis     r6,(KERNELBASE & ~0xfff)@h
        ori     r6,r6,(KERNELBASE & ~0xfff)@l
+       rlwinm  r7,r25,0,0x03ffffff
+       add     r6,r7,r6
 
 #elif defined(ENTRY_MAPPING_KEXEC_SETUP)
 /*
index 4f0946de2d5c917540f6f51a50c13640011fea8c..b7363bd42452848169e3fa5bc58721c1aeb3b08a 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/threads.h>
+#include <linux/init.h>
 #include <asm/reg.h>
 #include <asm/page.h>
 #include <asm/mmu.h>
index f45726a1d963ddae9591fa1210736f124ac6a5b4..b497188a94a1e2f67b71460189f9f225f7f5e1a3 100644 (file)
@@ -65,29 +65,78 @@ _ENTRY(_start);
        nop
 
        /* Translate device tree address to physical, save in r30/r31 */
-       mfmsr   r16
-       mfspr   r17,SPRN_PID
-       rlwinm  r17,r17,16,0x3fff0000   /* turn PID into MAS6[SPID] */
-       rlwimi  r17,r16,28,0x00000001   /* turn MSR[DS] into MAS6[SAS] */
-       mtspr   SPRN_MAS6,r17
-
-       tlbsx   0,r3                    /* must succeed */
-
-       mfspr   r16,SPRN_MAS1
-       mfspr   r20,SPRN_MAS3
-       rlwinm  r17,r16,25,0x1f         /* r17 = log2(page size) */
-       li      r18,1024
-       slw     r18,r18,r17             /* r18 = page size */
-       addi    r18,r18,-1
-       and     r19,r3,r18              /* r19 = page offset */
-       andc    r31,r20,r18             /* r31 = page base */
-       or      r31,r31,r19             /* r31 = devtree phys addr */
-       mfspr   r30,SPRN_MAS7
+       bl      get_phys_addr
+       mr      r30,r3
+       mr      r31,r4
 
        li      r25,0                   /* phys kernel start (low) */
        li      r24,0                   /* CPU number */
        li      r23,0                   /* phys kernel start (high) */
 
+#ifdef CONFIG_RELOCATABLE
+       LOAD_REG_ADDR_PIC(r3, _stext)   /* Get our current runtime base */
+
+       /* Translate _stext address to physical, save in r23/r25 */
+       bl      get_phys_addr
+       mr      r23,r3
+       mr      r25,r4
+
+       bl      0f
+0:     mflr    r8
+       addis   r3,r8,(is_second_reloc - 0b)@ha
+       lwz     r19,(is_second_reloc - 0b)@l(r3)
+
+       /* Check if this is the second relocation. */
+       cmpwi   r19,1
+       bne     1f
+
+       /*
+        * For the second relocation, we already get the real memstart_addr
+        * from device tree. So we will map PAGE_OFFSET to memstart_addr,
+        * then the virtual address of start kernel should be:
+        *          PAGE_OFFSET + (kernstart_addr - memstart_addr)
+        * Since the offset between kernstart_addr and memstart_addr should
+        * never be beyond 1G, so we can just use the lower 32bit of them
+        * for the calculation.
+        */
+       lis     r3,PAGE_OFFSET@h
+
+       addis   r4,r8,(kernstart_addr - 0b)@ha
+       addi    r4,r4,(kernstart_addr - 0b)@l
+       lwz     r5,4(r4)
+
+       addis   r6,r8,(memstart_addr - 0b)@ha
+       addi    r6,r6,(memstart_addr - 0b)@l
+       lwz     r7,4(r6)
+
+       subf    r5,r7,r5
+       add     r3,r3,r5
+       b       2f
+
+1:
+       /*
+        * We have the runtime (virutal) address of our base.
+        * We calculate our shift of offset from a 64M page.
+        * We could map the 64M page we belong to at PAGE_OFFSET and
+        * get going from there.
+        */
+       lis     r4,KERNELBASE@h
+       ori     r4,r4,KERNELBASE@l
+       rlwinm  r6,r25,0,0x3ffffff              /* r6 = PHYS_START % 64M */
+       rlwinm  r5,r4,0,0x3ffffff               /* r5 = KERNELBASE % 64M */
+       subf    r3,r5,r6                        /* r3 = r6 - r5 */
+       add     r3,r4,r3                        /* Required Virtual Address */
+
+2:     bl      relocate
+
+       /*
+        * For the second relocation, we already set the right tlb entries
+        * for the kernel space, so skip the code in fsl_booke_entry_mapping.S
+       */
+       cmpwi   r19,1
+       beq     set_ivor
+#endif
+
 /* We try to not make any assumptions about how the boot loader
  * setup or used the TLBs.  We invalidate all mappings from the
  * boot loader and load a single entry in TLB1[0] to map the
@@ -113,6 +162,7 @@ _ENTRY(__early_start)
 #include "fsl_booke_entry_mapping.S"
 #undef ENTRY_MAPPING_BOOT_SETUP
 
+set_ivor:
        /* Establish the interrupt vector offsets */
        SET_IVOR(0,  CriticalInput);
        SET_IVOR(1,  MachineCheck);
@@ -166,8 +216,7 @@ _ENTRY(__early_start)
        /* Check to see if we're the second processor, and jump
         * to the secondary_start code if so
         */
-       lis     r24, boot_cpuid@h
-       ori     r24, r24, boot_cpuid@l
+       LOAD_REG_ADDR_PIC(r24, boot_cpuid)
        lwz     r24, 0(r24)
        cmpwi   r24, -1
        mfspr   r24,SPRN_PIR
@@ -197,6 +246,18 @@ _ENTRY(__early_start)
 
        bl      early_init
 
+#ifdef CONFIG_RELOCATABLE
+       mr      r3,r30
+       mr      r4,r31
+#ifdef CONFIG_PHYS_64BIT
+       mr      r5,r23
+       mr      r6,r25
+#else
+       mr      r5,r25
+#endif
+       bl      relocate_init
+#endif
+
 #ifdef CONFIG_DYNAMIC_MEMSTART
        lis     r3,kernstart_addr@ha
        la      r3,kernstart_addr@l(r3)
@@ -855,6 +916,33 @@ KernelSPE:
 
 #endif /* CONFIG_SPE */
 
+/*
+ * Translate the effec addr in r3 to phys addr. The phys addr will be put
+ * into r3(higher 32bit) and r4(lower 32bit)
+ */
+get_phys_addr:
+       mfmsr   r8
+       mfspr   r9,SPRN_PID
+       rlwinm  r9,r9,16,0x3fff0000     /* turn PID into MAS6[SPID] */
+       rlwimi  r9,r8,28,0x00000001     /* turn MSR[DS] into MAS6[SAS] */
+       mtspr   SPRN_MAS6,r9
+
+       tlbsx   0,r3                    /* must succeed */
+
+       mfspr   r8,SPRN_MAS1
+       mfspr   r12,SPRN_MAS3
+       rlwinm  r9,r8,25,0x1f           /* r9 = log2(page size) */
+       li      r10,1024
+       slw     r10,r10,r9              /* r10 = page size */
+       addi    r10,r10,-1
+       and     r11,r3,r10              /* r11 = page offset */
+       andc    r4,r12,r10              /* r4 = page base */
+       or      r4,r4,r11               /* r4 = devtree phys addr */
+#ifdef CONFIG_PHYS_64BIT
+       mfspr   r3,SPRN_MAS7
+#endif
+       blr
+
 /*
  * Global functions
  */
@@ -1057,24 +1145,36 @@ _GLOBAL(__flush_disable_L1)
 /* When we get here, r24 needs to hold the CPU # */
        .globl __secondary_start
 __secondary_start:
-       lis     r3,__secondary_hold_acknowledge@h
-       ori     r3,r3,__secondary_hold_acknowledge@l
-       stw     r24,0(r3)
-
-       li      r3,0
-       mr      r4,r24          /* Why? */
-       bl      call_setup_cpu
-
-       lis     r3,tlbcam_index@ha
-       lwz     r3,tlbcam_index@l(r3)
+       LOAD_REG_ADDR_PIC(r3, tlbcam_index)
+       lwz     r3,0(r3)
        mtctr   r3
        li      r26,0           /* r26 safe? */
 
+       bl      switch_to_as1
+       mr      r27,r3          /* tlb entry */
        /* Load each CAM entry */
 1:     mr      r3,r26
        bl      loadcam_entry
        addi    r26,r26,1
        bdnz    1b
+       mr      r3,r27          /* tlb entry */
+       LOAD_REG_ADDR_PIC(r4, memstart_addr)
+       lwz     r4,0(r4)
+       mr      r5,r25          /* phys kernel start */
+       rlwinm  r5,r5,0,~0x3ffffff      /* aligned 64M */
+       subf    r4,r5,r4        /* memstart_addr - phys kernel start */
+       li      r5,0            /* no device tree */
+       li      r6,0            /* not boot cpu */
+       bl      restore_to_as0
+
+
+       lis     r3,__secondary_hold_acknowledge@h
+       ori     r3,r3,__secondary_hold_acknowledge@l
+       stw     r24,0(r3)
+
+       li      r3,0
+       mr      r4,r24          /* Why? */
+       bl      call_setup_cpu
 
        /* get current_thread_info and current */
        lis     r1,secondary_ti@ha
@@ -1110,6 +1210,112 @@ __secondary_hold_acknowledge:
        .long   -1
 #endif
 
+/*
+ * Create a tlb entry with the same effective and physical address as
+ * the tlb entry used by the current running code. But set the TS to 1.
+ * Then switch to the address space 1. It will return with the r3 set to
+ * the ESEL of the new created tlb.
+ */
+_GLOBAL(switch_to_as1)
+       mflr    r5
+
+       /* Find a entry not used */
+       mfspr   r3,SPRN_TLB1CFG
+       andi.   r3,r3,0xfff
+       mfspr   r4,SPRN_PID
+       rlwinm  r4,r4,16,0x3fff0000     /* turn PID into MAS6[SPID] */
+       mtspr   SPRN_MAS6,r4
+1:     lis     r4,0x1000               /* Set MAS0(TLBSEL) = 1 */
+       addi    r3,r3,-1
+       rlwimi  r4,r3,16,4,15           /* Setup MAS0 = TLBSEL | ESEL(r3) */
+       mtspr   SPRN_MAS0,r4
+       tlbre
+       mfspr   r4,SPRN_MAS1
+       andis.  r4,r4,MAS1_VALID@h
+       bne     1b
+
+       /* Get the tlb entry used by the current running code */
+       bl      0f
+0:     mflr    r4
+       tlbsx   0,r4
+
+       mfspr   r4,SPRN_MAS1
+       ori     r4,r4,MAS1_TS           /* Set the TS = 1 */
+       mtspr   SPRN_MAS1,r4
+
+       mfspr   r4,SPRN_MAS0
+       rlwinm  r4,r4,0,~MAS0_ESEL_MASK
+       rlwimi  r4,r3,16,4,15           /* Setup MAS0 = TLBSEL | ESEL(r3) */
+       mtspr   SPRN_MAS0,r4
+       tlbwe
+       isync
+       sync
+
+       mfmsr   r4
+       ori     r4,r4,MSR_IS | MSR_DS
+       mtspr   SPRN_SRR0,r5
+       mtspr   SPRN_SRR1,r4
+       sync
+       rfi
+
+/*
+ * Restore to the address space 0 and also invalidate the tlb entry created
+ * by switch_to_as1.
+ * r3 - the tlb entry which should be invalidated
+ * r4 - __pa(PAGE_OFFSET in AS1) - __pa(PAGE_OFFSET in AS0)
+ * r5 - device tree virtual address. If r4 is 0, r5 is ignored.
+ * r6 - boot cpu
+*/
+_GLOBAL(restore_to_as0)
+       mflr    r0
+
+       bl      0f
+0:     mflr    r9
+       addi    r9,r9,1f - 0b
+
+       /*
+        * We may map the PAGE_OFFSET in AS0 to a different physical address,
+        * so we need calculate the right jump and device tree address based
+        * on the offset passed by r4.
+        */
+       add     r9,r9,r4
+       add     r5,r5,r4
+       add     r0,r0,r4
+
+2:     mfmsr   r7
+       li      r8,(MSR_IS | MSR_DS)
+       andc    r7,r7,r8
+
+       mtspr   SPRN_SRR0,r9
+       mtspr   SPRN_SRR1,r7
+       sync
+       rfi
+
+       /* Invalidate the temporary tlb entry for AS1 */
+1:     lis     r9,0x1000               /* Set MAS0(TLBSEL) = 1 */
+       rlwimi  r9,r3,16,4,15           /* Setup MAS0 = TLBSEL | ESEL(r3) */
+       mtspr   SPRN_MAS0,r9
+       tlbre
+       mfspr   r9,SPRN_MAS1
+       rlwinm  r9,r9,0,2,31            /* Clear MAS1 Valid and IPPROT */
+       mtspr   SPRN_MAS1,r9
+       tlbwe
+       isync
+
+       cmpwi   r4,0
+       cmpwi   cr1,r6,0
+       cror    eq,4*cr1+eq,eq
+       bne     3f                      /* offset != 0 && is_boot_cpu */
+       mtlr    r0
+       blr
+
+       /*
+        * The PAGE_OFFSET will map to a different physical address,
+        * jump to _start to do another relocation again.
+       */
+3:     mr      r3,r5
+       bl      _start
+
 /*
  * We put a few things here that have to be page-aligned. This stuff
  * goes at the beginning of the data segment, which is page-aligned.
index f0b47d1a6b0ebd92dddd3ed49275e40a361c72ea..b0a1792279bbf38e1726a86b6d8cd504c11e15ca 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/percpu.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 
 #include <asm/hw_breakpoint.h>
index 847e40e62fcee8420046e153e5da9354bc80a40e..3fdef0f0c67fa959e631a4ccee2d3a330001fa44 100644 (file)
@@ -84,6 +84,7 @@ _GLOBAL(power7_nap)
        std     r9,_MSR(r1)
        std     r1,PACAR1(r13)
 
+_GLOBAL(power7_enter_nap_mode)
 #ifdef CONFIG_KVM_BOOK3S_HV_POSSIBLE
        /* Tell KVM we're napping */
        li      r4,KVM_HWTHREAD_IN_NAP
index 97a3715ac8bd83dadfb23555a398260de144ab9e..b82227e7e21bbba3cb22456c0c9248bb65bbd462 100644 (file)
@@ -3,7 +3,6 @@
  *
  * (C) Copyright 2004 Linus Torvalds
  */
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/mm.h>
 #include <linux/export.h>
index 572bb5b95f35d815f6f24fe7b59a67bf420fbe2b..d773dd440a45a32560fed0176120709ff5ea860d 100644 (file)
@@ -251,14 +251,13 @@ again:
 
        if (dev)
                boundary_size = ALIGN(dma_get_seg_boundary(dev) + 1,
-                                     1 << IOMMU_PAGE_SHIFT);
+                                     1 << tbl->it_page_shift);
        else
-               boundary_size = ALIGN(1UL << 32, 1 << IOMMU_PAGE_SHIFT);
+               boundary_size = ALIGN(1UL << 32, 1 << tbl->it_page_shift);
        /* 4GB boundary for iseries_hv_alloc and iseries_hv_map */
 
-       n = iommu_area_alloc(tbl->it_map, limit, start, npages,
-                            tbl->it_offset, boundary_size >> IOMMU_PAGE_SHIFT,
-                            align_mask);
+       n = iommu_area_alloc(tbl->it_map, limit, start, npages, tbl->it_offset,
+                            boundary_size >> tbl->it_page_shift, align_mask);
        if (n == -1) {
                if (likely(pass == 0)) {
                        /* First try the pool from the start */
@@ -320,12 +319,12 @@ static dma_addr_t iommu_alloc(struct device *dev, struct iommu_table *tbl,
                return DMA_ERROR_CODE;
 
        entry += tbl->it_offset;        /* Offset into real TCE table */
-       ret = entry << IOMMU_PAGE_SHIFT;        /* Set the return dma address */
+       ret = entry << tbl->it_page_shift;      /* Set the return dma address */
 
        /* Put the TCEs in the HW table */
        build_fail = ppc_md.tce_build(tbl, entry, npages,
-                                     (unsigned long)page & IOMMU_PAGE_MASK,
-                                     direction, attrs);
+                                     (unsigned long)page &
+                                     IOMMU_PAGE_MASK(tbl), direction, attrs);
 
        /* ppc_md.tce_build() only returns non-zero for transient errors.
         * Clean up the table bitmap in this case and return
@@ -352,7 +351,7 @@ static bool iommu_free_check(struct iommu_table *tbl, dma_addr_t dma_addr,
 {
        unsigned long entry, free_entry;
 
-       entry = dma_addr >> IOMMU_PAGE_SHIFT;
+       entry = dma_addr >> tbl->it_page_shift;
        free_entry = entry - tbl->it_offset;
 
        if (((free_entry + npages) > tbl->it_size) ||
@@ -401,7 +400,7 @@ static void __iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
        unsigned long flags;
        struct iommu_pool *pool;
 
-       entry = dma_addr >> IOMMU_PAGE_SHIFT;
+       entry = dma_addr >> tbl->it_page_shift;
        free_entry = entry - tbl->it_offset;
 
        pool = get_pool(tbl, free_entry);
@@ -468,13 +467,13 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
                }
                /* Allocate iommu entries for that segment */
                vaddr = (unsigned long) sg_virt(s);
-               npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE);
+               npages = iommu_num_pages(vaddr, slen, IOMMU_PAGE_SIZE(tbl));
                align = 0;
-               if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && slen >= PAGE_SIZE &&
+               if (tbl->it_page_shift < PAGE_SHIFT && slen >= PAGE_SIZE &&
                    (vaddr & ~PAGE_MASK) == 0)
-                       align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
+                       align = PAGE_SHIFT - tbl->it_page_shift;
                entry = iommu_range_alloc(dev, tbl, npages, &handle,
-                                         mask >> IOMMU_PAGE_SHIFT, align);
+                                         mask >> tbl->it_page_shift, align);
 
                DBG("  - vaddr: %lx, size: %lx\n", vaddr, slen);
 
@@ -489,16 +488,16 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
 
                /* Convert entry to a dma_addr_t */
                entry += tbl->it_offset;
-               dma_addr = entry << IOMMU_PAGE_SHIFT;
-               dma_addr |= (s->offset & ~IOMMU_PAGE_MASK);
+               dma_addr = entry << tbl->it_page_shift;
+               dma_addr |= (s->offset & ~IOMMU_PAGE_MASK(tbl));
 
                DBG("  - %lu pages, entry: %lx, dma_addr: %lx\n",
                            npages, entry, dma_addr);
 
                /* Insert into HW table */
                build_fail = ppc_md.tce_build(tbl, entry, npages,
-                                             vaddr & IOMMU_PAGE_MASK,
-                                             direction, attrs);
+                                             vaddr & IOMMU_PAGE_MASK(tbl),
+                                             direction, attrs);
                if(unlikely(build_fail))
                        goto failure;
 
@@ -559,9 +558,9 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
                if (s->dma_length != 0) {
                        unsigned long vaddr, npages;
 
-                       vaddr = s->dma_address & IOMMU_PAGE_MASK;
+                       vaddr = s->dma_address & IOMMU_PAGE_MASK(tbl);
                        npages = iommu_num_pages(s->dma_address, s->dma_length,
-                                                IOMMU_PAGE_SIZE);
+                                                IOMMU_PAGE_SIZE(tbl));
                        __iommu_free(tbl, vaddr, npages);
                        s->dma_address = DMA_ERROR_CODE;
                        s->dma_length = 0;
@@ -592,7 +591,7 @@ void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
                if (sg->dma_length == 0)
                        break;
                npages = iommu_num_pages(dma_handle, sg->dma_length,
-                                        IOMMU_PAGE_SIZE);
+                                        IOMMU_PAGE_SIZE(tbl));
                __iommu_free(tbl, dma_handle, npages);
                sg = sg_next(sg);
        }
@@ -676,7 +675,7 @@ struct iommu_table *iommu_init_table(struct iommu_table *tbl, int nid)
                set_bit(0, tbl->it_map);
 
        /* We only split the IOMMU table if we have 1GB or more of space */
-       if ((tbl->it_size << IOMMU_PAGE_SHIFT) >= (1UL * 1024 * 1024 * 1024))
+       if ((tbl->it_size << tbl->it_page_shift) >= (1UL * 1024 * 1024 * 1024))
                tbl->nr_pools = IOMMU_NR_POOLS;
        else
                tbl->nr_pools = 1;
@@ -768,16 +767,16 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
 
        vaddr = page_address(page) + offset;
        uaddr = (unsigned long)vaddr;
-       npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE);
+       npages = iommu_num_pages(uaddr, size, IOMMU_PAGE_SIZE(tbl));
 
        if (tbl) {
                align = 0;
-               if (IOMMU_PAGE_SHIFT < PAGE_SHIFT && size >= PAGE_SIZE &&
+               if (tbl->it_page_shift < PAGE_SHIFT && size >= PAGE_SIZE &&
                    ((unsigned long)vaddr & ~PAGE_MASK) == 0)
-                       align = PAGE_SHIFT - IOMMU_PAGE_SHIFT;
+                       align = PAGE_SHIFT - tbl->it_page_shift;
 
                dma_handle = iommu_alloc(dev, tbl, vaddr, npages, direction,
-                                        mask >> IOMMU_PAGE_SHIFT, align,
+                                        mask >> tbl->it_page_shift, align,
                                         attrs);
                if (dma_handle == DMA_ERROR_CODE) {
                        if (printk_ratelimit())  {
@@ -786,7 +785,7 @@ dma_addr_t iommu_map_page(struct device *dev, struct iommu_table *tbl,
                                         npages);
                        }
                } else
-                       dma_handle |= (uaddr & ~IOMMU_PAGE_MASK);
+                       dma_handle |= (uaddr & ~IOMMU_PAGE_MASK(tbl));
        }
 
        return dma_handle;
@@ -801,7 +800,8 @@ void iommu_unmap_page(struct iommu_table *tbl, dma_addr_t dma_handle,
        BUG_ON(direction == DMA_NONE);
 
        if (tbl) {
-               npages = iommu_num_pages(dma_handle, size, IOMMU_PAGE_SIZE);
+               npages = iommu_num_pages(dma_handle, size,
+                                        IOMMU_PAGE_SIZE(tbl));
                iommu_free(tbl, dma_handle, npages);
        }
 }
@@ -845,10 +845,10 @@ void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
        memset(ret, 0, size);
 
        /* Set up tces to cover the allocated range */
-       nio_pages = size >> IOMMU_PAGE_SHIFT;
-       io_order = get_iommu_order(size);
+       nio_pages = size >> tbl->it_page_shift;
+       io_order = get_iommu_order(size, tbl);
        mapping = iommu_alloc(dev, tbl, ret, nio_pages, DMA_BIDIRECTIONAL,
-                             mask >> IOMMU_PAGE_SHIFT, io_order, NULL);
+                             mask >> tbl->it_page_shift, io_order, NULL);
        if (mapping == DMA_ERROR_CODE) {
                free_pages((unsigned long)ret, order);
                return NULL;
@@ -864,7 +864,7 @@ void iommu_free_coherent(struct iommu_table *tbl, size_t size,
                unsigned int nio_pages;
 
                size = PAGE_ALIGN(size);
-               nio_pages = size >> IOMMU_PAGE_SHIFT;
+               nio_pages = size >> tbl->it_page_shift;
                iommu_free(tbl, dma_handle, nio_pages);
                size = PAGE_ALIGN(size);
                free_pages((unsigned long)vaddr, get_order(size));
@@ -935,10 +935,10 @@ int iommu_tce_clear_param_check(struct iommu_table *tbl,
        if (tce_value)
                return -EINVAL;
 
-       if (ioba & ~IOMMU_PAGE_MASK)
+       if (ioba & ~IOMMU_PAGE_MASK(tbl))
                return -EINVAL;
 
-       ioba >>= IOMMU_PAGE_SHIFT;
+       ioba >>= tbl->it_page_shift;
        if (ioba < tbl->it_offset)
                return -EINVAL;
 
@@ -955,13 +955,13 @@ int iommu_tce_put_param_check(struct iommu_table *tbl,
        if (!(tce & (TCE_PCI_WRITE | TCE_PCI_READ)))
                return -EINVAL;
 
-       if (tce & ~(IOMMU_PAGE_MASK | TCE_PCI_WRITE | TCE_PCI_READ))
+       if (tce & ~(IOMMU_PAGE_MASK(tbl) | TCE_PCI_WRITE | TCE_PCI_READ))
                return -EINVAL;
 
-       if (ioba & ~IOMMU_PAGE_MASK)
+       if (ioba & ~IOMMU_PAGE_MASK(tbl))
                return -EINVAL;
 
-       ioba >>= IOMMU_PAGE_SHIFT;
+       ioba >>= tbl->it_page_shift;
        if (ioba < tbl->it_offset)
                return -EINVAL;
 
@@ -1037,7 +1037,7 @@ int iommu_tce_build(struct iommu_table *tbl, unsigned long entry,
 
        /* if (unlikely(ret))
                pr_err("iommu_tce: %s failed on hwaddr=%lx ioba=%lx kva=%lx ret=%d\n",
-                               __func__, hwaddr, entry << IOMMU_PAGE_SHIFT,
+                       __func__, hwaddr, entry << IOMMU_PAGE_SHIFT(tbl),
                                hwaddr, ret); */
 
        return ret;
@@ -1049,14 +1049,14 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry,
 {
        int ret;
        struct page *page = NULL;
-       unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK & ~PAGE_MASK;
+       unsigned long hwaddr, offset = tce & IOMMU_PAGE_MASK(tbl) & ~PAGE_MASK;
        enum dma_data_direction direction = iommu_tce_direction(tce);
 
        ret = get_user_pages_fast(tce & PAGE_MASK, 1,
                        direction != DMA_TO_DEVICE, &page);
        if (unlikely(ret != 1)) {
                /* pr_err("iommu_tce: get_user_pages_fast failed tce=%lx ioba=%lx ret=%d\n",
-                               tce, entry << IOMMU_PAGE_SHIFT, ret); */
+                               tce, entry << IOMMU_PAGE_SHIFT(tbl), ret); */
                return -EFAULT;
        }
        hwaddr = (unsigned long) page_address(page) + offset;
@@ -1067,7 +1067,7 @@ int iommu_put_tce_user_mode(struct iommu_table *tbl, unsigned long entry,
 
        if (ret < 0)
                pr_err("iommu_tce: %s failed ioba=%lx, tce=%lx, ret=%d\n",
-                               __func__, entry << IOMMU_PAGE_SHIFT, tce, ret);
+                       __func__, entry << tbl->it_page_shift, tce, ret);
 
        return ret;
 }
@@ -1105,7 +1105,7 @@ void iommu_release_ownership(struct iommu_table *tbl)
 }
 EXPORT_SYMBOL_GPL(iommu_release_ownership);
 
-static int iommu_add_device(struct device *dev)
+int iommu_add_device(struct device *dev)
 {
        struct iommu_table *tbl;
        int ret = 0;
@@ -1127,6 +1127,12 @@ static int iommu_add_device(struct device *dev)
        pr_debug("iommu_tce: adding %s to iommu group %d\n",
                        dev_name(dev), iommu_group_id(tbl->it_group));
 
+       if (PAGE_SIZE < IOMMU_PAGE_SIZE(tbl)) {
+               pr_err("iommu_tce: unsupported iommu page size.");
+               pr_err("%s has not been added\n", dev_name(dev));
+               return -EINVAL;
+       }
+
        ret = iommu_group_add_device(tbl->it_group, dev);
        if (ret < 0)
                pr_err("iommu_tce: %s has not been added, ret=%d\n",
@@ -1134,52 +1140,23 @@ static int iommu_add_device(struct device *dev)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(iommu_add_device);
 
-static void iommu_del_device(struct device *dev)
-{
-       iommu_group_remove_device(dev);
-}
-
-static int iommu_bus_notifier(struct notifier_block *nb,
-                             unsigned long action, void *data)
+void iommu_del_device(struct device *dev)
 {
-       struct device *dev = data;
-
-       switch (action) {
-       case BUS_NOTIFY_ADD_DEVICE:
-               return iommu_add_device(dev);
-       case BUS_NOTIFY_DEL_DEVICE:
-               iommu_del_device(dev);
-               return 0;
-       default:
-               return 0;
+       /*
+        * Some devices might not have IOMMU table and group
+        * and we needn't detach them from the associated
+        * IOMMU groups
+        */
+       if (!dev->iommu_group) {
+               pr_debug("iommu_tce: skipping device %s with no tbl\n",
+                        dev_name(dev));
+               return;
        }
-}
 
-static struct notifier_block tce_iommu_bus_nb = {
-       .notifier_call = iommu_bus_notifier,
-};
-
-static int __init tce_iommu_init(void)
-{
-       struct pci_dev *pdev = NULL;
-
-       BUILD_BUG_ON(PAGE_SIZE < IOMMU_PAGE_SIZE);
-
-       for_each_pci_dev(pdev)
-               iommu_add_device(&pdev->dev);
-
-       bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
-       return 0;
-}
-
-subsys_initcall_sync(tce_iommu_init);
-
-#else
-
-void iommu_register_group(struct iommu_table *tbl,
-               int pci_domain_number, unsigned long pe_num)
-{
+       iommu_group_remove_device(dev);
 }
+EXPORT_SYMBOL_GPL(iommu_del_device);
 
 #endif /* CONFIG_IOMMU_API */
index ba0165615215577be84a8a576283a5fd6df12e51..9729b23bfb0a2deebf0e5157accb2d68541b6bf0 100644 (file)
@@ -354,8 +354,13 @@ int arch_show_interrupts(struct seq_file *p, int prec)
 
        seq_printf(p, "%*s: ", prec, "LOC");
        for_each_online_cpu(j)
-               seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs);
-        seq_printf(p, "  Local timer interrupts\n");
+               seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_event);
+        seq_printf(p, "  Local timer interrupts for timer event device\n");
+
+       seq_printf(p, "%*s: ", prec, "LOC");
+       for_each_online_cpu(j)
+               seq_printf(p, "%10u ", per_cpu(irq_stat, j).timer_irqs_others);
+        seq_printf(p, "  Local timer interrupts for others\n");
 
        seq_printf(p, "%*s: ", prec, "SPU");
        for_each_online_cpu(j)
@@ -389,11 +394,12 @@ int arch_show_interrupts(struct seq_file *p, int prec)
  */
 u64 arch_irq_stat_cpu(unsigned int cpu)
 {
-       u64 sum = per_cpu(irq_stat, cpu).timer_irqs;
+       u64 sum = per_cpu(irq_stat, cpu).timer_irqs_event;
 
        sum += per_cpu(irq_stat, cpu).pmu_irqs;
        sum += per_cpu(irq_stat, cpu).mce_exceptions;
        sum += per_cpu(irq_stat, cpu).spurious_irqs;
+       sum += per_cpu(irq_stat, cpu).timer_irqs_others;
 #ifdef CONFIG_PPC_DOORBELL
        sum += per_cpu(irq_stat, cpu).doorbell_irqs;
 #endif
index 83e89d310734f676274f819f2897777ce9ad3f72..8504657379f13fe7858f08b9f4f61ea4e23ecb92 100644 (file)
@@ -15,7 +15,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/kgdb.h>
 #include <linux/smp.h>
 #include <linux/signal.h>
index db28032e320e3e5332b6e60d77d1b56d29cea7d9..6a0175297b0d8e92495ce97e7274ecba72fcb790 100644 (file)
@@ -413,13 +413,13 @@ static void kvm_map_magic_page(void *data)
 {
        u32 *features = data;
 
-       ulong in[8];
+       ulong in[8] = {0};
        ulong out[8];
 
        in[0] = KVM_MAGIC_PAGE;
        in[1] = KVM_MAGIC_PAGE;
 
-       kvm_hypercall(in, out, KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE));
+       epapr_hypercall(in, out, KVM_HCALL_TOKEN(KVM_HC_PPC_MAP_MAGIC_PAGE));
 
        *features = out[0];
 }
@@ -711,43 +711,6 @@ static void kvm_use_magic_page(void)
                         kvm_patching_worked ? "worked" : "failed");
 }
 
-unsigned long kvm_hypercall(unsigned long *in,
-                           unsigned long *out,
-                           unsigned long nr)
-{
-       unsigned long register r0 asm("r0");
-       unsigned long register r3 asm("r3") = in[0];
-       unsigned long register r4 asm("r4") = in[1];
-       unsigned long register r5 asm("r5") = in[2];
-       unsigned long register r6 asm("r6") = in[3];
-       unsigned long register r7 asm("r7") = in[4];
-       unsigned long register r8 asm("r8") = in[5];
-       unsigned long register r9 asm("r9") = in[6];
-       unsigned long register r10 asm("r10") = in[7];
-       unsigned long register r11 asm("r11") = nr;
-       unsigned long register r12 asm("r12");
-
-       asm volatile("bl        epapr_hypercall_start"
-                    : "=r"(r0), "=r"(r3), "=r"(r4), "=r"(r5), "=r"(r6),
-                      "=r"(r7), "=r"(r8), "=r"(r9), "=r"(r10), "=r"(r11),
-                      "=r"(r12)
-                    : "r"(r3), "r"(r4), "r"(r5), "r"(r6), "r"(r7), "r"(r8),
-                      "r"(r9), "r"(r10), "r"(r11)
-                    : "memory", "cc", "xer", "ctr", "lr");
-
-       out[0] = r4;
-       out[1] = r5;
-       out[2] = r6;
-       out[3] = r7;
-       out[4] = r8;
-       out[5] = r9;
-       out[6] = r10;
-       out[7] = r11;
-
-       return r3;
-}
-EXPORT_SYMBOL_GPL(kvm_hypercall);
-
 static __init void kvm_free_tmp(void)
 {
        free_reserved_area(&kvm_tmp[kvm_tmp_index],
diff --git a/arch/powerpc/kernel/mce.c b/arch/powerpc/kernel/mce.c
new file mode 100644 (file)
index 0000000..cadef7e
--- /dev/null
@@ -0,0 +1,352 @@
+/*
+ * Machine check exception handling.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2013 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "mce: " fmt
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/percpu.h>
+#include <linux/export.h>
+#include <linux/irq_work.h>
+#include <asm/mce.h>
+
+static DEFINE_PER_CPU(int, mce_nest_count);
+static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event);
+
+/* Queue for delayed MCE events. */
+static DEFINE_PER_CPU(int, mce_queue_count);
+static DEFINE_PER_CPU(struct machine_check_event[MAX_MC_EVT], mce_event_queue);
+
+static void machine_check_process_queued_event(struct irq_work *work);
+struct irq_work mce_event_process_work = {
+        .func = machine_check_process_queued_event,
+};
+
+static void mce_set_error_info(struct machine_check_event *mce,
+                              struct mce_error_info *mce_err)
+{
+       mce->error_type = mce_err->error_type;
+       switch (mce_err->error_type) {
+       case MCE_ERROR_TYPE_UE:
+               mce->u.ue_error.ue_error_type = mce_err->u.ue_error_type;
+               break;
+       case MCE_ERROR_TYPE_SLB:
+               mce->u.slb_error.slb_error_type = mce_err->u.slb_error_type;
+               break;
+       case MCE_ERROR_TYPE_ERAT:
+               mce->u.erat_error.erat_error_type = mce_err->u.erat_error_type;
+               break;
+       case MCE_ERROR_TYPE_TLB:
+               mce->u.tlb_error.tlb_error_type = mce_err->u.tlb_error_type;
+               break;
+       case MCE_ERROR_TYPE_UNKNOWN:
+       default:
+               break;
+       }
+}
+
+/*
+ * Decode and save high level MCE information into per cpu buffer which
+ * is an array of machine_check_event structure.
+ */
+void save_mce_event(struct pt_regs *regs, long handled,
+                   struct mce_error_info *mce_err,
+                   uint64_t addr)
+{
+       uint64_t srr1;
+       int index = __get_cpu_var(mce_nest_count)++;
+       struct machine_check_event *mce = &__get_cpu_var(mce_event[index]);
+
+       /*
+        * Return if we don't have enough space to log mce event.
+        * mce_nest_count may go beyond MAX_MC_EVT but that's ok,
+        * the check below will stop buffer overrun.
+        */
+       if (index >= MAX_MC_EVT)
+               return;
+
+       /* Populate generic machine check info */
+       mce->version = MCE_V1;
+       mce->srr0 = regs->nip;
+       mce->srr1 = regs->msr;
+       mce->gpr3 = regs->gpr[3];
+       mce->in_use = 1;
+
+       mce->initiator = MCE_INITIATOR_CPU;
+       if (handled)
+               mce->disposition = MCE_DISPOSITION_RECOVERED;
+       else
+               mce->disposition = MCE_DISPOSITION_NOT_RECOVERED;
+       mce->severity = MCE_SEV_ERROR_SYNC;
+
+       srr1 = regs->msr;
+
+       /*
+        * Populate the mce error_type and type-specific error_type.
+        */
+       mce_set_error_info(mce, mce_err);
+
+       if (!addr)
+               return;
+
+       if (mce->error_type == MCE_ERROR_TYPE_TLB) {
+               mce->u.tlb_error.effective_address_provided = true;
+               mce->u.tlb_error.effective_address = addr;
+       } else if (mce->error_type == MCE_ERROR_TYPE_SLB) {
+               mce->u.slb_error.effective_address_provided = true;
+               mce->u.slb_error.effective_address = addr;
+       } else if (mce->error_type == MCE_ERROR_TYPE_ERAT) {
+               mce->u.erat_error.effective_address_provided = true;
+               mce->u.erat_error.effective_address = addr;
+       } else if (mce->error_type == MCE_ERROR_TYPE_UE) {
+               mce->u.ue_error.effective_address_provided = true;
+               mce->u.ue_error.effective_address = addr;
+       }
+       return;
+}
+
+/*
+ * get_mce_event:
+ *     mce     Pointer to machine_check_event structure to be filled.
+ *     release Flag to indicate whether to free the event slot or not.
+ *             0 <= do not release the mce event. Caller will invoke
+ *                  release_mce_event() once event has been consumed.
+ *             1 <= release the slot.
+ *
+ *     return  1 = success
+ *             0 = failure
+ *
+ * get_mce_event() will be called by platform specific machine check
+ * handle routine and in KVM.
+ * When we call get_mce_event(), we are still in interrupt context and
+ * preemption will not be scheduled until ret_from_expect() routine
+ * is called.
+ */
+int get_mce_event(struct machine_check_event *mce, bool release)
+{
+       int index = __get_cpu_var(mce_nest_count) - 1;
+       struct machine_check_event *mc_evt;
+       int ret = 0;
+
+       /* Sanity check */
+       if (index < 0)
+               return ret;
+
+       /* Check if we have MCE info to process. */
+       if (index < MAX_MC_EVT) {
+               mc_evt = &__get_cpu_var(mce_event[index]);
+               /* Copy the event structure and release the original */
+               if (mce)
+                       *mce = *mc_evt;
+               if (release)
+                       mc_evt->in_use = 0;
+               ret = 1;
+       }
+       /* Decrement the count to free the slot. */
+       if (release)
+               __get_cpu_var(mce_nest_count)--;
+
+       return ret;
+}
+
+void release_mce_event(void)
+{
+       get_mce_event(NULL, true);
+}
+
+/*
+ * Queue up the MCE event which then can be handled later.
+ */
+void machine_check_queue_event(void)
+{
+       int index;
+       struct machine_check_event evt;
+
+       if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
+               return;
+
+       index = __get_cpu_var(mce_queue_count)++;
+       /* If queue is full, just return for now. */
+       if (index >= MAX_MC_EVT) {
+               __get_cpu_var(mce_queue_count)--;
+               return;
+       }
+       __get_cpu_var(mce_event_queue[index]) = evt;
+
+       /* Queue irq work to process this event later. */
+       irq_work_queue(&mce_event_process_work);
+}
+
+/*
+ * process pending MCE event from the mce event queue. This function will be
+ * called during syscall exit.
+ */
+static void machine_check_process_queued_event(struct irq_work *work)
+{
+       int index;
+
+       /*
+        * For now just print it to console.
+        * TODO: log this error event to FSP or nvram.
+        */
+       while (__get_cpu_var(mce_queue_count) > 0) {
+               index = __get_cpu_var(mce_queue_count) - 1;
+               machine_check_print_event_info(
+                               &__get_cpu_var(mce_event_queue[index]));
+               __get_cpu_var(mce_queue_count)--;
+       }
+}
+
+void machine_check_print_event_info(struct machine_check_event *evt)
+{
+       const char *level, *sevstr, *subtype;
+       static const char *mc_ue_types[] = {
+               "Indeterminate",
+               "Instruction fetch",
+               "Page table walk ifetch",
+               "Load/Store",
+               "Page table walk Load/Store",
+       };
+       static const char *mc_slb_types[] = {
+               "Indeterminate",
+               "Parity",
+               "Multihit",
+       };
+       static const char *mc_erat_types[] = {
+               "Indeterminate",
+               "Parity",
+               "Multihit",
+       };
+       static const char *mc_tlb_types[] = {
+               "Indeterminate",
+               "Parity",
+               "Multihit",
+       };
+
+       /* Print things out */
+       if (evt->version != MCE_V1) {
+               pr_err("Machine Check Exception, Unknown event version %d !\n",
+                      evt->version);
+               return;
+       }
+       switch (evt->severity) {
+       case MCE_SEV_NO_ERROR:
+               level = KERN_INFO;
+               sevstr = "Harmless";
+               break;
+       case MCE_SEV_WARNING:
+               level = KERN_WARNING;
+               sevstr = "";
+               break;
+       case MCE_SEV_ERROR_SYNC:
+               level = KERN_ERR;
+               sevstr = "Severe";
+               break;
+       case MCE_SEV_FATAL:
+       default:
+               level = KERN_ERR;
+               sevstr = "Fatal";
+               break;
+       }
+
+       printk("%s%s Machine check interrupt [%s]\n", level, sevstr,
+              evt->disposition == MCE_DISPOSITION_RECOVERED ?
+              "Recovered" : "[Not recovered");
+       printk("%s  Initiator: %s\n", level,
+              evt->initiator == MCE_INITIATOR_CPU ? "CPU" : "Unknown");
+       switch (evt->error_type) {
+       case MCE_ERROR_TYPE_UE:
+               subtype = evt->u.ue_error.ue_error_type <
+                       ARRAY_SIZE(mc_ue_types) ?
+                       mc_ue_types[evt->u.ue_error.ue_error_type]
+                       : "Unknown";
+               printk("%s  Error type: UE [%s]\n", level, subtype);
+               if (evt->u.ue_error.effective_address_provided)
+                       printk("%s    Effective address: %016llx\n",
+                              level, evt->u.ue_error.effective_address);
+               if (evt->u.ue_error.physical_address_provided)
+                       printk("%s      Physial address: %016llx\n",
+                              level, evt->u.ue_error.physical_address);
+               break;
+       case MCE_ERROR_TYPE_SLB:
+               subtype = evt->u.slb_error.slb_error_type <
+                       ARRAY_SIZE(mc_slb_types) ?
+                       mc_slb_types[evt->u.slb_error.slb_error_type]
+                       : "Unknown";
+               printk("%s  Error type: SLB [%s]\n", level, subtype);
+               if (evt->u.slb_error.effective_address_provided)
+                       printk("%s    Effective address: %016llx\n",
+                              level, evt->u.slb_error.effective_address);
+               break;
+       case MCE_ERROR_TYPE_ERAT:
+               subtype = evt->u.erat_error.erat_error_type <
+                       ARRAY_SIZE(mc_erat_types) ?
+                       mc_erat_types[evt->u.erat_error.erat_error_type]
+                       : "Unknown";
+               printk("%s  Error type: ERAT [%s]\n", level, subtype);
+               if (evt->u.erat_error.effective_address_provided)
+                       printk("%s    Effective address: %016llx\n",
+                              level, evt->u.erat_error.effective_address);
+               break;
+       case MCE_ERROR_TYPE_TLB:
+               subtype = evt->u.tlb_error.tlb_error_type <
+                       ARRAY_SIZE(mc_tlb_types) ?
+                       mc_tlb_types[evt->u.tlb_error.tlb_error_type]
+                       : "Unknown";
+               printk("%s  Error type: TLB [%s]\n", level, subtype);
+               if (evt->u.tlb_error.effective_address_provided)
+                       printk("%s    Effective address: %016llx\n",
+                              level, evt->u.tlb_error.effective_address);
+               break;
+       default:
+       case MCE_ERROR_TYPE_UNKNOWN:
+               printk("%s  Error type: Unknown\n", level);
+               break;
+       }
+}
+
+uint64_t get_mce_fault_addr(struct machine_check_event *evt)
+{
+       switch (evt->error_type) {
+       case MCE_ERROR_TYPE_UE:
+               if (evt->u.ue_error.effective_address_provided)
+                       return evt->u.ue_error.effective_address;
+               break;
+       case MCE_ERROR_TYPE_SLB:
+               if (evt->u.slb_error.effective_address_provided)
+                       return evt->u.slb_error.effective_address;
+               break;
+       case MCE_ERROR_TYPE_ERAT:
+               if (evt->u.erat_error.effective_address_provided)
+                       return evt->u.erat_error.effective_address;
+               break;
+       case MCE_ERROR_TYPE_TLB:
+               if (evt->u.tlb_error.effective_address_provided)
+                       return evt->u.tlb_error.effective_address;
+               break;
+       default:
+       case MCE_ERROR_TYPE_UNKNOWN:
+               break;
+       }
+       return 0;
+}
+EXPORT_SYMBOL(get_mce_fault_addr);
diff --git a/arch/powerpc/kernel/mce_power.c b/arch/powerpc/kernel/mce_power.c
new file mode 100644 (file)
index 0000000..27c93f4
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ * Machine check exception handling CPU-side for power7 and power8
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2013 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+#define pr_fmt(fmt) "mce_power: " fmt
+
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <asm/mmu.h>
+#include <asm/mce.h>
+
+/* flush SLBs and reload */
+static void flush_and_reload_slb(void)
+{
+       struct slb_shadow *slb;
+       unsigned long i, n;
+
+       /* Invalidate all SLBs */
+       asm volatile("slbmte %0,%0; slbia" : : "r" (0));
+
+#ifdef CONFIG_KVM_BOOK3S_HANDLER
+       /*
+        * If machine check is hit when in guest or in transition, we will
+        * only flush the SLBs and continue.
+        */
+       if (get_paca()->kvm_hstate.in_guest)
+               return;
+#endif
+
+       /* For host kernel, reload the SLBs from shadow SLB buffer. */
+       slb = get_slb_shadow();
+       if (!slb)
+               return;
+
+       n = min_t(u32, be32_to_cpu(slb->persistent), SLB_MIN_SIZE);
+
+       /* Load up the SLB entries from shadow SLB */
+       for (i = 0; i < n; i++) {
+               unsigned long rb = be64_to_cpu(slb->save_area[i].esid);
+               unsigned long rs = be64_to_cpu(slb->save_area[i].vsid);
+
+               rb = (rb & ~0xFFFul) | i;
+               asm volatile("slbmte %0,%1" : : "r" (rs), "r" (rb));
+       }
+}
+
+static long mce_handle_derror(uint64_t dsisr, uint64_t slb_error_bits)
+{
+       long handled = 1;
+
+       /*
+        * flush and reload SLBs for SLB errors and flush TLBs for TLB errors.
+        * reset the error bits whenever we handle them so that at the end
+        * we can check whether we handled all of them or not.
+        * */
+       if (dsisr & slb_error_bits) {
+               flush_and_reload_slb();
+               /* reset error bits */
+               dsisr &= ~(slb_error_bits);
+       }
+       if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) {
+               if (cur_cpu_spec && cur_cpu_spec->flush_tlb)
+                       cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE);
+               /* reset error bits */
+               dsisr &= ~P7_DSISR_MC_TLB_MULTIHIT_MFTLB;
+       }
+       /* Any other errors we don't understand? */
+       if (dsisr & 0xffffffffUL)
+               handled = 0;
+
+       return handled;
+}
+
+static long mce_handle_derror_p7(uint64_t dsisr)
+{
+       return mce_handle_derror(dsisr, P7_DSISR_MC_SLB_ERRORS);
+}
+
+static long mce_handle_common_ierror(uint64_t srr1)
+{
+       long handled = 0;
+
+       switch (P7_SRR1_MC_IFETCH(srr1)) {
+       case 0:
+               break;
+       case P7_SRR1_MC_IFETCH_SLB_PARITY:
+       case P7_SRR1_MC_IFETCH_SLB_MULTIHIT:
+               /* flush and reload SLBs for SLB errors. */
+               flush_and_reload_slb();
+               handled = 1;
+               break;
+       case P7_SRR1_MC_IFETCH_TLB_MULTIHIT:
+               if (cur_cpu_spec && cur_cpu_spec->flush_tlb) {
+                       cur_cpu_spec->flush_tlb(TLBIEL_INVAL_PAGE);
+                       handled = 1;
+               }
+               break;
+       default:
+               break;
+       }
+
+       return handled;
+}
+
+static long mce_handle_ierror_p7(uint64_t srr1)
+{
+       long handled = 0;
+
+       handled = mce_handle_common_ierror(srr1);
+
+       if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) {
+               flush_and_reload_slb();
+               handled = 1;
+       }
+       return handled;
+}
+
+static void mce_get_common_ierror(struct mce_error_info *mce_err, uint64_t srr1)
+{
+       switch (P7_SRR1_MC_IFETCH(srr1)) {
+       case P7_SRR1_MC_IFETCH_SLB_PARITY:
+               mce_err->error_type = MCE_ERROR_TYPE_SLB;
+               mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY;
+               break;
+       case P7_SRR1_MC_IFETCH_SLB_MULTIHIT:
+               mce_err->error_type = MCE_ERROR_TYPE_SLB;
+               mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
+               break;
+       case P7_SRR1_MC_IFETCH_TLB_MULTIHIT:
+               mce_err->error_type = MCE_ERROR_TYPE_TLB;
+               mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
+               break;
+       case P7_SRR1_MC_IFETCH_UE:
+       case P7_SRR1_MC_IFETCH_UE_IFU_INTERNAL:
+               mce_err->error_type = MCE_ERROR_TYPE_UE;
+               mce_err->u.ue_error_type = MCE_UE_ERROR_IFETCH;
+               break;
+       case P7_SRR1_MC_IFETCH_UE_TLB_RELOAD:
+               mce_err->error_type = MCE_ERROR_TYPE_UE;
+               mce_err->u.ue_error_type =
+                               MCE_UE_ERROR_PAGE_TABLE_WALK_IFETCH;
+               break;
+       }
+}
+
+static void mce_get_ierror_p7(struct mce_error_info *mce_err, uint64_t srr1)
+{
+       mce_get_common_ierror(mce_err, srr1);
+       if (P7_SRR1_MC_IFETCH(srr1) == P7_SRR1_MC_IFETCH_SLB_BOTH) {
+               mce_err->error_type = MCE_ERROR_TYPE_SLB;
+               mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE;
+       }
+}
+
+static void mce_get_derror_p7(struct mce_error_info *mce_err, uint64_t dsisr)
+{
+       if (dsisr & P7_DSISR_MC_UE) {
+               mce_err->error_type = MCE_ERROR_TYPE_UE;
+               mce_err->u.ue_error_type = MCE_UE_ERROR_LOAD_STORE;
+       } else if (dsisr & P7_DSISR_MC_UE_TABLEWALK) {
+               mce_err->error_type = MCE_ERROR_TYPE_UE;
+               mce_err->u.ue_error_type =
+                               MCE_UE_ERROR_PAGE_TABLE_WALK_LOAD_STORE;
+       } else if (dsisr & P7_DSISR_MC_ERAT_MULTIHIT) {
+               mce_err->error_type = MCE_ERROR_TYPE_ERAT;
+               mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
+       } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT) {
+               mce_err->error_type = MCE_ERROR_TYPE_SLB;
+               mce_err->u.slb_error_type = MCE_SLB_ERROR_MULTIHIT;
+       } else if (dsisr & P7_DSISR_MC_SLB_PARITY_MFSLB) {
+               mce_err->error_type = MCE_ERROR_TYPE_SLB;
+               mce_err->u.slb_error_type = MCE_SLB_ERROR_PARITY;
+       } else if (dsisr & P7_DSISR_MC_TLB_MULTIHIT_MFTLB) {
+               mce_err->error_type = MCE_ERROR_TYPE_TLB;
+               mce_err->u.tlb_error_type = MCE_TLB_ERROR_MULTIHIT;
+       } else if (dsisr & P7_DSISR_MC_SLB_MULTIHIT_PARITY) {
+               mce_err->error_type = MCE_ERROR_TYPE_SLB;
+               mce_err->u.slb_error_type = MCE_SLB_ERROR_INDETERMINATE;
+       }
+}
+
+long __machine_check_early_realmode_p7(struct pt_regs *regs)
+{
+       uint64_t srr1, addr;
+       long handled = 1;
+       struct mce_error_info mce_error_info = { 0 };
+
+       srr1 = regs->msr;
+
+       /*
+        * Handle memory errors depending whether this was a load/store or
+        * ifetch exception. Also, populate the mce error_type and
+        * type-specific error_type from either SRR1 or DSISR, depending
+        * whether this was a load/store or ifetch exception
+        */
+       if (P7_SRR1_MC_LOADSTORE(srr1)) {
+               handled = mce_handle_derror_p7(regs->dsisr);
+               mce_get_derror_p7(&mce_error_info, regs->dsisr);
+               addr = regs->dar;
+       } else {
+               handled = mce_handle_ierror_p7(srr1);
+               mce_get_ierror_p7(&mce_error_info, srr1);
+               addr = regs->nip;
+       }
+
+       save_mce_event(regs, handled, &mce_error_info, addr);
+       return handled;
+}
+
+static void mce_get_ierror_p8(struct mce_error_info *mce_err, uint64_t srr1)
+{
+       mce_get_common_ierror(mce_err, srr1);
+       if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) {
+               mce_err->error_type = MCE_ERROR_TYPE_ERAT;
+               mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
+       }
+}
+
+static void mce_get_derror_p8(struct mce_error_info *mce_err, uint64_t dsisr)
+{
+       mce_get_derror_p7(mce_err, dsisr);
+       if (dsisr & P8_DSISR_MC_ERAT_MULTIHIT_SEC) {
+               mce_err->error_type = MCE_ERROR_TYPE_ERAT;
+               mce_err->u.erat_error_type = MCE_ERAT_ERROR_MULTIHIT;
+       }
+}
+
+static long mce_handle_ierror_p8(uint64_t srr1)
+{
+       long handled = 0;
+
+       handled = mce_handle_common_ierror(srr1);
+
+       if (P7_SRR1_MC_IFETCH(srr1) == P8_SRR1_MC_IFETCH_ERAT_MULTIHIT) {
+               flush_and_reload_slb();
+               handled = 1;
+       }
+       return handled;
+}
+
+static long mce_handle_derror_p8(uint64_t dsisr)
+{
+       return mce_handle_derror(dsisr, P8_DSISR_MC_SLB_ERRORS);
+}
+
+long __machine_check_early_realmode_p8(struct pt_regs *regs)
+{
+       uint64_t srr1, addr;
+       long handled = 1;
+       struct mce_error_info mce_error_info = { 0 };
+
+       srr1 = regs->msr;
+
+       if (P7_SRR1_MC_LOADSTORE(srr1)) {
+               handled = mce_handle_derror_p8(regs->dsisr);
+               mce_get_derror_p8(&mce_error_info, regs->dsisr);
+               addr = regs->dar;
+       } else {
+               handled = mce_handle_ierror_p8(srr1);
+               mce_get_ierror_p8(&mce_error_info, srr1);
+               addr = regs->nip;
+       }
+
+       save_mce_event(regs, handled, &mce_error_info, addr);
+       return handled;
+}
index e47d268727a4a8ed87948a4d3ab5f87ad00793b1..879f09620f8341e27dbfd1ed6be47fe242eab812 100644 (file)
@@ -344,7 +344,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_UNIFIED_ID_CACHE)
  */
 _KPROBE(flush_icache_range)
 BEGIN_FTR_SECTION
-       isync
+       PURGE_PREFETCHED_INS
        blr                             /* for 601, do nothing */
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
        li      r5,L1_CACHE_BYTES-1
@@ -448,6 +448,7 @@ _GLOBAL(invalidate_dcache_range)
  */
 _GLOBAL(__flush_dcache_icache)
 BEGIN_FTR_SECTION
+       PURGE_PREFETCHED_INS
        blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
        rlwinm  r3,r3,0,0,31-PAGE_SHIFT         /* Get page base address */
@@ -489,6 +490,7 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_TYPE_44x)
  */
 _GLOBAL(__flush_dcache_icache_phys)
 BEGIN_FTR_SECTION
+       PURGE_PREFETCHED_INS
        blr                                     /* for 601, do nothing */
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
        mfmsr   r10
index 64bf8db12b15be3e8dbc903b6c8bb27173940fc1..3d0249599d524af2a8883cacc4df5d44716273b8 100644 (file)
@@ -67,6 +67,7 @@ PPC64_CACHES:
 
 _KPROBE(flush_icache_range)
 BEGIN_FTR_SECTION
+       PURGE_PREFETCHED_INS
        blr
 END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
 /*
@@ -211,6 +212,11 @@ _GLOBAL(__flush_dcache_icache)
  * Different systems have different cache line sizes
  */
 
+BEGIN_FTR_SECTION
+       PURGE_PREFETCHED_INS
+       blr
+END_FTR_SECTION_IFSET(CPU_FTR_COHERENT_ICACHE)
+
 /* Flush the dcache */
        ld      r7,PPC64_CACHES@toc(r2)
        clrrdi  r3,r3,PAGE_SHIFT                    /* Page align */
index 0620eaaaad45b419c70475485a9d052c0ddbe246..bf0aada02fe4798c39e60d84653bef3a51ee4f83 100644 (file)
@@ -99,12 +99,28 @@ static inline void free_lppacas(void) { }
  * 3 persistent SLBs are registered here.  The buffer will be zero
  * initially, hence will all be invaild until we actually write them.
  */
-struct slb_shadow slb_shadow[] __cacheline_aligned = {
-       [0 ... (NR_CPUS-1)] = {
-               .persistent = cpu_to_be32(SLB_NUM_BOLTED),
-               .buffer_length = cpu_to_be32(sizeof(struct slb_shadow)),
-       },
-};
+static struct slb_shadow *slb_shadow;
+
+static void __init allocate_slb_shadows(int nr_cpus, int limit)
+{
+       int size = PAGE_ALIGN(sizeof(struct slb_shadow) * nr_cpus);
+       slb_shadow = __va(memblock_alloc_base(size, PAGE_SIZE, limit));
+       memset(slb_shadow, 0, size);
+}
+
+static struct slb_shadow * __init init_slb_shadow(int cpu)
+{
+       struct slb_shadow *s = &slb_shadow[cpu];
+
+       s->persistent = cpu_to_be32(SLB_NUM_BOLTED);
+       s->buffer_length = cpu_to_be32(sizeof(*s));
+
+       return s;
+}
+
+#else /* CONFIG_PPC_STD_MMU_64 */
+
+static void __init allocate_slb_shadows(int nr_cpus, int limit) { }
 
 #endif /* CONFIG_PPC_STD_MMU_64 */
 
@@ -142,8 +158,13 @@ void __init initialise_paca(struct paca_struct *new_paca, int cpu)
        new_paca->__current = &init_task;
        new_paca->data_offset = 0xfeeeeeeeeeeeeeeeULL;
 #ifdef CONFIG_PPC_STD_MMU_64
-       new_paca->slb_shadow_ptr = &slb_shadow[cpu];
+       new_paca->slb_shadow_ptr = init_slb_shadow(cpu);
 #endif /* CONFIG_PPC_STD_MMU_64 */
+
+#ifdef CONFIG_PPC_BOOK3E
+       /* For now -- if we have threads this will be adjusted later */
+       new_paca->tcd_ptr = &new_paca->tcd;
+#endif
 }
 
 /* Put the paca pointer into r13 and SPRG_PACA */
@@ -190,6 +211,8 @@ void __init allocate_pacas(void)
 
        allocate_lppacas(nr_cpu_ids, limit);
 
+       allocate_slb_shadows(nr_cpu_ids, limit);
+
        /* Can't use for_each_*_cpu, as they aren't functional yet */
        for (cpu = 0; cpu < nr_cpu_ids; cpu++)
                initialise_paca(&paca[cpu], cpu);
index 4a96556fd2d49e484c143ed3643db6c8a24962df..8d4c247f17389f283d02bc48dba044ff077e3ffe 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/slab.h>
 #include <linux/user.h>
 #include <linux/elf.h>
-#include <linux/init.h>
 #include <linux/prctl.h>
 #include <linux/init_task.h>
 #include <linux/export.h>
@@ -74,6 +73,48 @@ struct task_struct *last_task_used_vsx = NULL;
 struct task_struct *last_task_used_spe = NULL;
 #endif
 
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+void giveup_fpu_maybe_transactional(struct task_struct *tsk)
+{
+       /*
+        * If we are saving the current thread's registers, and the
+        * thread is in a transactional state, set the TIF_RESTORE_TM
+        * bit so that we know to restore the registers before
+        * returning to userspace.
+        */
+       if (tsk == current && tsk->thread.regs &&
+           MSR_TM_ACTIVE(tsk->thread.regs->msr) &&
+           !test_thread_flag(TIF_RESTORE_TM)) {
+               tsk->thread.tm_orig_msr = tsk->thread.regs->msr;
+               set_thread_flag(TIF_RESTORE_TM);
+       }
+
+       giveup_fpu(tsk);
+}
+
+void giveup_altivec_maybe_transactional(struct task_struct *tsk)
+{
+       /*
+        * If we are saving the current thread's registers, and the
+        * thread is in a transactional state, set the TIF_RESTORE_TM
+        * bit so that we know to restore the registers before
+        * returning to userspace.
+        */
+       if (tsk == current && tsk->thread.regs &&
+           MSR_TM_ACTIVE(tsk->thread.regs->msr) &&
+           !test_thread_flag(TIF_RESTORE_TM)) {
+               tsk->thread.tm_orig_msr = tsk->thread.regs->msr;
+               set_thread_flag(TIF_RESTORE_TM);
+       }
+
+       giveup_altivec(tsk);
+}
+
+#else
+#define giveup_fpu_maybe_transactional(tsk)    giveup_fpu(tsk)
+#define giveup_altivec_maybe_transactional(tsk)        giveup_altivec(tsk)
+#endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
+
 #ifdef CONFIG_PPC_FPU
 /*
  * Make sure the floating-point register state in the
@@ -102,13 +143,13 @@ void flush_fp_to_thread(struct task_struct *tsk)
                         */
                        BUG_ON(tsk != current);
 #endif
-                       giveup_fpu(tsk);
+                       giveup_fpu_maybe_transactional(tsk);
                }
                preempt_enable();
        }
 }
 EXPORT_SYMBOL_GPL(flush_fp_to_thread);
-#endif
+#endif /* CONFIG_PPC_FPU */
 
 void enable_kernel_fp(void)
 {
@@ -116,11 +157,11 @@ void enable_kernel_fp(void)
 
 #ifdef CONFIG_SMP
        if (current->thread.regs && (current->thread.regs->msr & MSR_FP))
-               giveup_fpu(current);
+               giveup_fpu_maybe_transactional(current);
        else
                giveup_fpu(NULL);       /* just enables FP for kernel */
 #else
-       giveup_fpu(last_task_used_math);
+       giveup_fpu_maybe_transactional(last_task_used_math);
 #endif /* CONFIG_SMP */
 }
 EXPORT_SYMBOL(enable_kernel_fp);
@@ -132,11 +173,11 @@ void enable_kernel_altivec(void)
 
 #ifdef CONFIG_SMP
        if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
-               giveup_altivec(current);
+               giveup_altivec_maybe_transactional(current);
        else
                giveup_altivec_notask();
 #else
-       giveup_altivec(last_task_used_altivec);
+       giveup_altivec_maybe_transactional(last_task_used_altivec);
 #endif /* CONFIG_SMP */
 }
 EXPORT_SYMBOL(enable_kernel_altivec);
@@ -153,7 +194,7 @@ void flush_altivec_to_thread(struct task_struct *tsk)
 #ifdef CONFIG_SMP
                        BUG_ON(tsk != current);
 #endif
-                       giveup_altivec(tsk);
+                       giveup_altivec_maybe_transactional(tsk);
                }
                preempt_enable();
        }
@@ -182,8 +223,8 @@ EXPORT_SYMBOL(enable_kernel_vsx);
 
 void giveup_vsx(struct task_struct *tsk)
 {
-       giveup_fpu(tsk);
-       giveup_altivec(tsk);
+       giveup_fpu_maybe_transactional(tsk);
+       giveup_altivec_maybe_transactional(tsk);
        __giveup_vsx(tsk);
 }
 
@@ -479,7 +520,48 @@ static inline bool hw_brk_match(struct arch_hw_breakpoint *a,
                return false;
        return true;
 }
+
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+static void tm_reclaim_thread(struct thread_struct *thr,
+                             struct thread_info *ti, uint8_t cause)
+{
+       unsigned long msr_diff = 0;
+
+       /*
+        * If FP/VSX registers have been already saved to the
+        * thread_struct, move them to the transact_fp array.
+        * We clear the TIF_RESTORE_TM bit since after the reclaim
+        * the thread will no longer be transactional.
+        */
+       if (test_ti_thread_flag(ti, TIF_RESTORE_TM)) {
+               msr_diff = thr->tm_orig_msr & ~thr->regs->msr;
+               if (msr_diff & MSR_FP)
+                       memcpy(&thr->transact_fp, &thr->fp_state,
+                              sizeof(struct thread_fp_state));
+               if (msr_diff & MSR_VEC)
+                       memcpy(&thr->transact_vr, &thr->vr_state,
+                              sizeof(struct thread_vr_state));
+               clear_ti_thread_flag(ti, TIF_RESTORE_TM);
+               msr_diff &= MSR_FP | MSR_VEC | MSR_VSX | MSR_FE0 | MSR_FE1;
+       }
+
+       tm_reclaim(thr, thr->regs->msr, cause);
+
+       /* Having done the reclaim, we now have the checkpointed
+        * FP/VSX values in the registers.  These might be valid
+        * even if we have previously called enable_kernel_fp() or
+        * flush_fp_to_thread(), so update thr->regs->msr to
+        * indicate their current validity.
+        */
+       thr->regs->msr |= msr_diff;
+}
+
+void tm_reclaim_current(uint8_t cause)
+{
+       tm_enable();
+       tm_reclaim_thread(&current->thread, current_thread_info(), cause);
+}
+
 static inline void tm_reclaim_task(struct task_struct *tsk)
 {
        /* We have to work out if we're switching from/to a task that's in the
@@ -502,9 +584,11 @@ static inline void tm_reclaim_task(struct task_struct *tsk)
 
        /* Stash the original thread MSR, as giveup_fpu et al will
         * modify it.  We hold onto it to see whether the task used
-        * FP & vector regs.
+        * FP & vector regs.  If the TIF_RESTORE_TM flag is set,
+        * tm_orig_msr is already set.
         */
-       thr->tm_orig_msr = thr->regs->msr;
+       if (!test_ti_thread_flag(task_thread_info(tsk), TIF_RESTORE_TM))
+               thr->tm_orig_msr = thr->regs->msr;
 
        TM_DEBUG("--- tm_reclaim on pid %d (NIP=%lx, "
                 "ccr=%lx, msr=%lx, trap=%lx)\n",
@@ -512,7 +596,7 @@ static inline void tm_reclaim_task(struct task_struct *tsk)
                 thr->regs->ccr, thr->regs->msr,
                 thr->regs->trap);
 
-       tm_reclaim(thr, thr->regs->msr, TM_CAUSE_RESCHED);
+       tm_reclaim_thread(thr, task_thread_info(tsk), TM_CAUSE_RESCHED);
 
        TM_DEBUG("--- tm_reclaim on pid %d complete\n",
                 tsk->pid);
@@ -588,6 +672,43 @@ static inline void __switch_to_tm(struct task_struct *prev)
                tm_reclaim_task(prev);
        }
 }
+
+/*
+ * This is called if we are on the way out to userspace and the
+ * TIF_RESTORE_TM flag is set.  It checks if we need to reload
+ * FP and/or vector state and does so if necessary.
+ * If userspace is inside a transaction (whether active or
+ * suspended) and FP/VMX/VSX instructions have ever been enabled
+ * inside that transaction, then we have to keep them enabled
+ * and keep the FP/VMX/VSX state loaded while ever the transaction
+ * continues.  The reason is that if we didn't, and subsequently
+ * got a FP/VMX/VSX unavailable interrupt inside a transaction,
+ * we don't know whether it's the same transaction, and thus we
+ * don't know which of the checkpointed state and the transactional
+ * state to use.
+ */
+void restore_tm_state(struct pt_regs *regs)
+{
+       unsigned long msr_diff;
+
+       clear_thread_flag(TIF_RESTORE_TM);
+       if (!MSR_TM_ACTIVE(regs->msr))
+               return;
+
+       msr_diff = current->thread.tm_orig_msr & ~regs->msr;
+       msr_diff &= MSR_FP | MSR_VEC | MSR_VSX;
+       if (msr_diff & MSR_FP) {
+               fp_enable();
+               load_fp_state(&current->thread.fp_state);
+               regs->msr |= current->thread.fpexc_mode;
+       }
+       if (msr_diff & MSR_VEC) {
+               vec_enable();
+               load_vr_state(&current->thread.vr_state);
+       }
+       regs->msr |= msr_diff;
+}
+
 #else
 #define tm_recheckpoint_new_task(new)
 #define __switch_to_tm(prev)
@@ -690,7 +811,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
  * schedule DABR
  */
 #ifndef CONFIG_HAVE_HW_BREAKPOINT
-       if (unlikely(hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk)))
+       if (unlikely(!hw_brk_match(&__get_cpu_var(current_brk), &new->thread.hw_brk)))
                set_breakpoint(&new->thread.hw_brk);
 #endif /* CONFIG_HAVE_HW_BREAKPOINT */
 #endif
@@ -1175,6 +1296,19 @@ int set_fpexc_mode(struct task_struct *tsk, unsigned int val)
        if (val & PR_FP_EXC_SW_ENABLE) {
 #ifdef CONFIG_SPE
                if (cpu_has_feature(CPU_FTR_SPE)) {
+                       /*
+                        * When the sticky exception bits are set
+                        * directly by userspace, it must call prctl
+                        * with PR_GET_FPEXC (with PR_FP_EXC_SW_ENABLE
+                        * in the existing prctl settings) or
+                        * PR_SET_FPEXC (with PR_FP_EXC_SW_ENABLE in
+                        * the bits being set).  <fenv.h> functions
+                        * saving and restoring the whole
+                        * floating-point environment need to do so
+                        * anyway to restore the prctl settings from
+                        * the saved environment.
+                        */
+                       tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR);
                        tsk->thread.fpexc_mode = val &
                                (PR_FP_EXC_SW_ENABLE | PR_FP_ALL_EXCEPT);
                        return 0;
@@ -1206,9 +1340,22 @@ int get_fpexc_mode(struct task_struct *tsk, unsigned long adr)
 
        if (tsk->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE)
 #ifdef CONFIG_SPE
-               if (cpu_has_feature(CPU_FTR_SPE))
+               if (cpu_has_feature(CPU_FTR_SPE)) {
+                       /*
+                        * When the sticky exception bits are set
+                        * directly by userspace, it must call prctl
+                        * with PR_GET_FPEXC (with PR_FP_EXC_SW_ENABLE
+                        * in the existing prctl settings) or
+                        * PR_SET_FPEXC (with PR_FP_EXC_SW_ENABLE in
+                        * the bits being set).  <fenv.h> functions
+                        * saving and restoring the whole
+                        * floating-point environment need to do so
+                        * anyway to restore the prctl settings from
+                        * the saved environment.
+                        */
+                       tsk->thread.spefscr_last = mfspr(SPRN_SPEFSCR);
                        val = tsk->thread.fpexc_mode;
-               else
+               else
                        return -EINVAL;
 #else
                return -EINVAL;
index fa0ad8aafbccf3950506a96a64f75bc2141f1bd7..f58c0d3aaeb497697aaa7ed75874ddee33146652 100644 (file)
@@ -523,6 +523,20 @@ static int __init early_init_dt_scan_memory_ppc(unsigned long node,
        return early_init_dt_scan_memory(node, uname, depth, data);
 }
 
+/*
+ * For a relocatable kernel, we need to get the memstart_addr first,
+ * then use it to calculate the virtual kernel start address. This has
+ * to happen at a very early stage (before machine_init). In this case,
+ * we just want to get the memstart_address and would not like to mess the
+ * memblock at this stage. So introduce a variable to skip the memblock_add()
+ * for this reason.
+ */
+#ifdef CONFIG_RELOCATABLE
+static int add_mem_to_memblock = 1;
+#else
+#define add_mem_to_memblock 1
+#endif
+
 void __init early_init_dt_add_memory_arch(u64 base, u64 size)
 {
 #ifdef CONFIG_PPC64
@@ -543,7 +557,8 @@ void __init early_init_dt_add_memory_arch(u64 base, u64 size)
        }
 
        /* Add the chunk to the MEMBLOCK list */
-       memblock_add(base, size);
+       if (add_mem_to_memblock)
+               memblock_add(base, size);
 }
 
 static void __init early_reserve_mem_dt(void)
@@ -740,6 +755,30 @@ void __init early_init_devtree(void *params)
        DBG(" <- early_init_devtree()\n");
 }
 
+#ifdef CONFIG_RELOCATABLE
+/*
+ * This function run before early_init_devtree, so we have to init
+ * initial_boot_params.
+ */
+void __init early_get_first_memblock_info(void *params, phys_addr_t *size)
+{
+       /* Setup flat device-tree pointer */
+       initial_boot_params = params;
+
+       /*
+        * Scan the memory nodes and set add_mem_to_memblock to 0 to avoid
+        * mess the memblock.
+        */
+       add_mem_to_memblock = 0;
+       of_scan_flat_dt(early_init_dt_scan_root, NULL);
+       of_scan_flat_dt(early_init_dt_scan_memory_ppc, NULL);
+       add_mem_to_memblock = 1;
+
+       if (size)
+               *size = first_memblock_size;
+}
+#endif
+
 /*******
  *
  * New implementation of the OF "find" APIs, return a refcounted
index 856dd4e99bfe459cdb430f5cba6fbc0b3229be89..f5f11a7d30e5502637d58656b7c587b37001ea81 100644 (file)
@@ -97,6 +97,36 @@ int dcache_bsize;
 int icache_bsize;
 int ucache_bsize;
 
+#if defined(CONFIG_PPC_BOOK3E) && defined(CONFIG_SMP)
+static void setup_tlb_core_data(void)
+{
+       int cpu;
+
+       for_each_possible_cpu(cpu) {
+               int first = cpu_first_thread_sibling(cpu);
+
+               paca[cpu].tcd_ptr = &paca[first].tcd;
+
+               /*
+                * If we have threads, we need either tlbsrx.
+                * or e6500 tablewalk mode, or else TLB handlers
+                * will be racy and could produce duplicate entries.
+                */
+               if (smt_enabled_at_boot >= 2 &&
+                   !mmu_has_feature(MMU_FTR_USE_TLBRSRV) &&
+                   book3e_htw_mode != PPC_HTW_E6500) {
+                       /* Should we panic instead? */
+                       WARN_ONCE("%s: unsupported MMU configuration -- expect problems\n",
+                                 __func__);
+               }
+       }
+}
+#else
+static void setup_tlb_core_data(void)
+{
+}
+#endif
+
 #ifdef CONFIG_SMP
 
 static char *smt_enabled_cmdline;
@@ -445,6 +475,7 @@ void __init setup_system(void)
 
        smp_setup_cpu_maps();
        check_smt_enabled();
+       setup_tlb_core_data();
 
 #ifdef CONFIG_SMP
        /* Release secondary cpus out of their spinloops at 0x60 now that
@@ -520,9 +551,6 @@ static void __init irqstack_early_init(void)
 #ifdef CONFIG_PPC_BOOK3E
 static void __init exc_lvl_early_init(void)
 {
-       extern unsigned int interrupt_base_book3e;
-       extern unsigned int exc_debug_debug_book3e;
-
        unsigned int i;
 
        for_each_possible_cpu(i) {
@@ -535,8 +563,7 @@ static void __init exc_lvl_early_init(void)
        }
 
        if (cpu_has_feature(CPU_FTR_DEBUG_LVL_EXC))
-               patch_branch(&interrupt_base_book3e + (0x040 / 4) + 1,
-                            (unsigned long)&exc_debug_debug_book3e, 0);
+               patch_exception(0x040, exc_debug_debug_book3e);
 }
 #else
 #define exc_lvl_early_init()
@@ -544,7 +571,8 @@ static void __init exc_lvl_early_init(void)
 
 /*
  * Stack space used when we detect a bad kernel stack pointer, and
- * early in SMP boots before relocation is enabled.
+ * early in SMP boots before relocation is enabled. Exclusive emergency
+ * stack for machine checks.
  */
 static void __init emergency_stack_init(void)
 {
@@ -567,6 +595,13 @@ static void __init emergency_stack_init(void)
                sp  = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit);
                sp += THREAD_SIZE;
                paca[i].emergency_sp = __va(sp);
+
+#ifdef CONFIG_PPC_BOOK3S_64
+               /* emergency stack for machine check exception handling. */
+               sp  = memblock_alloc_base(THREAD_SIZE, THREAD_SIZE, limit);
+               sp += THREAD_SIZE;
+               paca[i].mc_emergency_sp = __va(sp);
+#endif
        }
 }
 
index 457e97aa29455e6894257f443f1a223583483685..8fc4177ed65acb6e9b1873f3614fc0457125c783 100644 (file)
@@ -203,8 +203,7 @@ unsigned long get_tm_stackpointer(struct pt_regs *regs)
 
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
        if (MSR_TM_ACTIVE(regs->msr)) {
-               tm_enable();
-               tm_reclaim(&current->thread, regs->msr, TM_CAUSE_SIGNAL);
+               tm_reclaim_current(TM_CAUSE_SIGNAL);
                if (MSR_TM_TRANSACTIONAL(regs->msr))
                        return current->thread.ckpt_regs.gpr[1];
        }
index 68027bfa5f8e3c4a958deeb13db1b6a9fcf89325..a67e00aa3caad1353630f4477a8cec38fb8461e4 100644 (file)
@@ -519,6 +519,13 @@ static int save_tm_user_regs(struct pt_regs *regs,
 {
        unsigned long msr = regs->msr;
 
+       /* Remove TM bits from thread's MSR.  The MSR in the sigcontext
+        * just indicates to userland that we were doing a transaction, but we
+        * don't want to return in transactional state.  This also ensures
+        * that flush_fp_to_thread won't set TIF_RESTORE_TM again.
+        */
+       regs->msr &= ~MSR_TS_MASK;
+
        /* Make sure floating point registers are stored in regs */
        flush_fp_to_thread(current);
 
@@ -1015,29 +1022,24 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
 #ifdef CONFIG_PPC_TRANSACTIONAL_MEM
        tm_frame = &rt_sf->uc_transact.uc_mcontext;
        if (MSR_TM_ACTIVE(regs->msr)) {
+               if (__put_user((unsigned long)&rt_sf->uc_transact,
+                              &rt_sf->uc.uc_link) ||
+                   __put_user((unsigned long)tm_frame,
+                              &rt_sf->uc_transact.uc_regs))
+                       goto badframe;
                if (save_tm_user_regs(regs, frame, tm_frame, sigret))
                        goto badframe;
        }
        else
 #endif
        {
+               if (__put_user(0, &rt_sf->uc.uc_link))
+                       goto badframe;
                if (save_user_regs(regs, frame, tm_frame, sigret, 1))
                        goto badframe;
        }
        regs->link = tramp;
 
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-       if (MSR_TM_ACTIVE(regs->msr)) {
-               if (__put_user((unsigned long)&rt_sf->uc_transact,
-                              &rt_sf->uc.uc_link)
-                   || __put_user((unsigned long)tm_frame, &rt_sf->uc_transact.uc_regs))
-                       goto badframe;
-       }
-       else
-#endif
-               if (__put_user(0, &rt_sf->uc.uc_link))
-                       goto badframe;
-
        current->thread.fp_state.fpscr = 0;     /* turn off all fp exceptions */
 
        /* create a stack frame for the caller of the handler */
@@ -1056,13 +1058,6 @@ int handle_rt_signal32(unsigned long sig, struct k_sigaction *ka,
        /* enter the signal handler in native-endian mode */
        regs->msr &= ~MSR_LE;
        regs->msr |= (MSR_KERNEL & MSR_LE);
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-       /* Remove TM bits from thread's MSR.  The MSR in the sigcontext
-        * just indicates to userland that we were doing a transaction, but we
-        * don't want to return in transactional state:
-        */
-       regs->msr &= ~MSR_TS_MASK;
-#endif
        return 1;
 
 badframe:
@@ -1484,13 +1479,6 @@ int handle_signal32(unsigned long sig, struct k_sigaction *ka,
        regs->nip = (unsigned long) ka->sa.sa_handler;
        /* enter the signal handler in big-endian mode */
        regs->msr &= ~MSR_LE;
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-       /* Remove TM bits from thread's MSR.  The MSR in the sigcontext
-        * just indicates to userland that we were doing a transaction, but we
-        * don't want to return in transactional state:
-        */
-       regs->msr &= ~MSR_TS_MASK;
-#endif
        return 1;
 
 badframe:
index 42991045349f815e124e18dba78c9a914c8b8b84..e35bf773df7a8d972990374cbb1507db261ccea2 100644 (file)
@@ -192,6 +192,13 @@ static long setup_tm_sigcontexts(struct sigcontext __user *sc,
 
        BUG_ON(!MSR_TM_ACTIVE(regs->msr));
 
+       /* Remove TM bits from thread's MSR.  The MSR in the sigcontext
+        * just indicates to userland that we were doing a transaction, but we
+        * don't want to return in transactional state.  This also ensures
+        * that flush_fp_to_thread won't set TIF_RESTORE_TM again.
+        */
+       regs->msr &= ~MSR_TS_MASK;
+
        flush_fp_to_thread(current);
 
 #ifdef CONFIG_ALTIVEC
@@ -749,13 +756,6 @@ int handle_rt_signal64(int signr, struct k_sigaction *ka, siginfo_t *info,
 
        /* Make sure signal handler doesn't get spurious FP exceptions */
        current->thread.fp_state.fpscr = 0;
-#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
-       /* Remove TM bits from thread's MSR.  The MSR in the sigcontext
-        * just indicates to userland that we were doing a transaction, but we
-        * don't want to return in transactional state:
-        */
-       regs->msr &= ~MSR_TS_MASK;
-#endif
 
        /* Set up to return from userspace. */
        if (vdso64_rt_sigtramp && current->mm->context.vdso_base) {
index e68fd1ae727a56c2edd9f79a21fcf9dd467b4f04..7a37ecd3afa3b211202ddcfbdfe382f6ce5d4995 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/unistd.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/atomic.h>
 #include <asm/smp.h>
index c1cf4a1522d9940bf3bb97a3e995a2642dee41ca..ac2621af31545b4aa3a4a434f7119c2c3aac222e 100644 (file)
@@ -369,13 +369,8 @@ void __init smp_prepare_cpus(unsigned int max_cpus)
        cpumask_set_cpu(boot_cpuid, cpu_sibling_mask(boot_cpuid));
        cpumask_set_cpu(boot_cpuid, cpu_core_mask(boot_cpuid));
 
-       if (smp_ops)
-               if (smp_ops->probe)
-                       max_cpus = smp_ops->probe();
-               else
-                       max_cpus = NR_CPUS;
-       else
-               max_cpus = 1;
+       if (smp_ops && smp_ops->probe)
+               smp_ops->probe();
 }
 
 void smp_prepare_boot_cpu(void)
index 0f204053e5b5a49e29df9d2f4113d208cb65417e..553c1405ee05774b49f355a7c3bfcedc1e7a69f9 100644 (file)
@@ -74,21 +74,21 @@ _GLOBAL(swsusp_arch_suspend)
        bne     1b
 
        /* Save SPRGs */
-       mfsprg  r4,0
+       mfspr   r4,SPRN_SPRG0
        stw     r4,SL_SPRG0(r11)
-       mfsprg  r4,1
+       mfspr   r4,SPRN_SPRG1
        stw     r4,SL_SPRG1(r11)
-       mfsprg  r4,2
+       mfspr   r4,SPRN_SPRG2
        stw     r4,SL_SPRG2(r11)
-       mfsprg  r4,3
+       mfspr   r4,SPRN_SPRG3
        stw     r4,SL_SPRG3(r11)
-       mfsprg  r4,4
+       mfspr   r4,SPRN_SPRG4
        stw     r4,SL_SPRG4(r11)
-       mfsprg  r4,5
+       mfspr   r4,SPRN_SPRG5
        stw     r4,SL_SPRG5(r11)
-       mfsprg  r4,6
+       mfspr   r4,SPRN_SPRG6
        stw     r4,SL_SPRG6(r11)
-       mfsprg  r4,7
+       mfspr   r4,SPRN_SPRG7
        stw     r4,SL_SPRG7(r11)
 
        /* Call the low level suspend stuff (we should probably have made
@@ -150,21 +150,21 @@ _GLOBAL(swsusp_arch_resume)
        bl      _tlbil_all
 
        lwz     r4,SL_SPRG0(r11)
-       mtsprg  0,r4
+       mtspr   SPRN_SPRG0,r4
        lwz     r4,SL_SPRG1(r11)
-       mtsprg  1,r4
+       mtspr   SPRN_SPRG1,r4
        lwz     r4,SL_SPRG2(r11)
-       mtsprg  2,r4
+       mtspr   SPRN_SPRG2,r4
        lwz     r4,SL_SPRG3(r11)
-       mtsprg  3,r4
+       mtspr   SPRN_SPRG3,r4
        lwz     r4,SL_SPRG4(r11)
-       mtsprg  4,r4
+       mtspr   SPRN_SPRG4,r4
        lwz     r4,SL_SPRG5(r11)
-       mtsprg  5,r4
+       mtspr   SPRN_SPRG5,r4
        lwz     r4,SL_SPRG6(r11)
-       mtsprg  6,r4
+       mtspr   SPRN_SPRG6,r4
        lwz     r4,SL_SPRG7(r11)
-       mtsprg  7,r4
+       mtspr   SPRN_SPRG7,r4
 
        /* restore the MSR */
        lwz     r3,SL_MSR(r11)
index 4e3cc47f26b90e157ebb5c2a1cd156918e655930..cd9be9aa016d184da98d24cd5dbb2f04c48dce50 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/ipc.h>
 #include <linux/utsname.h>
 #include <linux/file.h>
-#include <linux/init.h>
 #include <linux/personality.h>
 
 #include <asm/uaccess.h>
index b4e667663d9bfc2e9954435790b0ebc5b6fc94ca..97e1dc91768374e7a7c5b56eb6752b7df5ae05ea 100644 (file)
@@ -51,8 +51,6 @@ static ssize_t store_smt_snooze_delay(struct device *dev,
                return -EINVAL;
 
        per_cpu(smt_snooze_delay, cpu->dev.id) = snooze;
-       update_smt_snooze_delay(cpu->dev.id, snooze);
-
        return count;
 }
 
@@ -86,6 +84,304 @@ __setup("smt-snooze-delay=", setup_smt_snooze_delay);
 
 #endif /* CONFIG_PPC64 */
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+#define MAX_BIT                                63
+
+static u64 pw20_wt;
+static u64 altivec_idle_wt;
+
+static unsigned int get_idle_ticks_bit(u64 ns)
+{
+       u64 cycle;
+
+       if (ns >= 10000)
+               cycle = div_u64(ns + 500, 1000) * tb_ticks_per_usec;
+       else
+               cycle = div_u64(ns * tb_ticks_per_usec, 1000);
+
+       if (!cycle)
+               return 0;
+
+       return ilog2(cycle);
+}
+
+static void do_show_pwrmgtcr0(void *val)
+{
+       u32 *value = val;
+
+       *value = mfspr(SPRN_PWRMGTCR0);
+}
+
+static ssize_t show_pw20_state(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       u32 value;
+       unsigned int cpu = dev->id;
+
+       smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1);
+
+       value &= PWRMGTCR0_PW20_WAIT;
+
+       return sprintf(buf, "%u\n", value ? 1 : 0);
+}
+
+static void do_store_pw20_state(void *val)
+{
+       u32 *value = val;
+       u32 pw20_state;
+
+       pw20_state = mfspr(SPRN_PWRMGTCR0);
+
+       if (*value)
+               pw20_state |= PWRMGTCR0_PW20_WAIT;
+       else
+               pw20_state &= ~PWRMGTCR0_PW20_WAIT;
+
+       mtspr(SPRN_PWRMGTCR0, pw20_state);
+}
+
+static ssize_t store_pw20_state(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       u32 value;
+       unsigned int cpu = dev->id;
+
+       if (kstrtou32(buf, 0, &value))
+               return -EINVAL;
+
+       if (value > 1)
+               return -EINVAL;
+
+       smp_call_function_single(cpu, do_store_pw20_state, &value, 1);
+
+       return count;
+}
+
+static ssize_t show_pw20_wait_time(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       u32 value;
+       u64 tb_cycle = 1;
+       u64 time;
+
+       unsigned int cpu = dev->id;
+
+       if (!pw20_wt) {
+               smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1);
+               value = (value & PWRMGTCR0_PW20_ENT) >>
+                                       PWRMGTCR0_PW20_ENT_SHIFT;
+
+               tb_cycle = (tb_cycle << (MAX_BIT - value + 1));
+               /* convert ms to ns */
+               if (tb_ticks_per_usec > 1000) {
+                       time = div_u64(tb_cycle, tb_ticks_per_usec / 1000);
+               } else {
+                       u32 rem_us;
+
+                       time = div_u64_rem(tb_cycle, tb_ticks_per_usec,
+                                               &rem_us);
+                       time = time * 1000 + rem_us * 1000 / tb_ticks_per_usec;
+               }
+       } else {
+               time = pw20_wt;
+       }
+
+       return sprintf(buf, "%llu\n", time > 0 ? time : 0);
+}
+
+static void set_pw20_wait_entry_bit(void *val)
+{
+       u32 *value = val;
+       u32 pw20_idle;
+
+       pw20_idle = mfspr(SPRN_PWRMGTCR0);
+
+       /* Set Automatic PW20 Core Idle Count */
+       /* clear count */
+       pw20_idle &= ~PWRMGTCR0_PW20_ENT;
+
+       /* set count */
+       pw20_idle |= ((MAX_BIT - *value) << PWRMGTCR0_PW20_ENT_SHIFT);
+
+       mtspr(SPRN_PWRMGTCR0, pw20_idle);
+}
+
+static ssize_t store_pw20_wait_time(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       u32 entry_bit;
+       u64 value;
+
+       unsigned int cpu = dev->id;
+
+       if (kstrtou64(buf, 0, &value))
+               return -EINVAL;
+
+       if (!value)
+               return -EINVAL;
+
+       entry_bit = get_idle_ticks_bit(value);
+       if (entry_bit > MAX_BIT)
+               return -EINVAL;
+
+       pw20_wt = value;
+
+       smp_call_function_single(cpu, set_pw20_wait_entry_bit,
+                               &entry_bit, 1);
+
+       return count;
+}
+
+static ssize_t show_altivec_idle(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       u32 value;
+       unsigned int cpu = dev->id;
+
+       smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1);
+
+       value &= PWRMGTCR0_AV_IDLE_PD_EN;
+
+       return sprintf(buf, "%u\n", value ? 1 : 0);
+}
+
+static void do_store_altivec_idle(void *val)
+{
+       u32 *value = val;
+       u32 altivec_idle;
+
+       altivec_idle = mfspr(SPRN_PWRMGTCR0);
+
+       if (*value)
+               altivec_idle |= PWRMGTCR0_AV_IDLE_PD_EN;
+       else
+               altivec_idle &= ~PWRMGTCR0_AV_IDLE_PD_EN;
+
+       mtspr(SPRN_PWRMGTCR0, altivec_idle);
+}
+
+static ssize_t store_altivec_idle(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       u32 value;
+       unsigned int cpu = dev->id;
+
+       if (kstrtou32(buf, 0, &value))
+               return -EINVAL;
+
+       if (value > 1)
+               return -EINVAL;
+
+       smp_call_function_single(cpu, do_store_altivec_idle, &value, 1);
+
+       return count;
+}
+
+static ssize_t show_altivec_idle_wait_time(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       u32 value;
+       u64 tb_cycle = 1;
+       u64 time;
+
+       unsigned int cpu = dev->id;
+
+       if (!altivec_idle_wt) {
+               smp_call_function_single(cpu, do_show_pwrmgtcr0, &value, 1);
+               value = (value & PWRMGTCR0_AV_IDLE_CNT) >>
+                                       PWRMGTCR0_AV_IDLE_CNT_SHIFT;
+
+               tb_cycle = (tb_cycle << (MAX_BIT - value + 1));
+               /* convert ms to ns */
+               if (tb_ticks_per_usec > 1000) {
+                       time = div_u64(tb_cycle, tb_ticks_per_usec / 1000);
+               } else {
+                       u32 rem_us;
+
+                       time = div_u64_rem(tb_cycle, tb_ticks_per_usec,
+                                               &rem_us);
+                       time = time * 1000 + rem_us * 1000 / tb_ticks_per_usec;
+               }
+       } else {
+               time = altivec_idle_wt;
+       }
+
+       return sprintf(buf, "%llu\n", time > 0 ? time : 0);
+}
+
+static void set_altivec_idle_wait_entry_bit(void *val)
+{
+       u32 *value = val;
+       u32 altivec_idle;
+
+       altivec_idle = mfspr(SPRN_PWRMGTCR0);
+
+       /* Set Automatic AltiVec Idle Count */
+       /* clear count */
+       altivec_idle &= ~PWRMGTCR0_AV_IDLE_CNT;
+
+       /* set count */
+       altivec_idle |= ((MAX_BIT - *value) << PWRMGTCR0_AV_IDLE_CNT_SHIFT);
+
+       mtspr(SPRN_PWRMGTCR0, altivec_idle);
+}
+
+static ssize_t store_altivec_idle_wait_time(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       u32 entry_bit;
+       u64 value;
+
+       unsigned int cpu = dev->id;
+
+       if (kstrtou64(buf, 0, &value))
+               return -EINVAL;
+
+       if (!value)
+               return -EINVAL;
+
+       entry_bit = get_idle_ticks_bit(value);
+       if (entry_bit > MAX_BIT)
+               return -EINVAL;
+
+       altivec_idle_wt = value;
+
+       smp_call_function_single(cpu, set_altivec_idle_wait_entry_bit,
+                               &entry_bit, 1);
+
+       return count;
+}
+
+/*
+ * Enable/Disable interface:
+ * 0, disable. 1, enable.
+ */
+static DEVICE_ATTR(pw20_state, 0600, show_pw20_state, store_pw20_state);
+static DEVICE_ATTR(altivec_idle, 0600, show_altivec_idle, store_altivec_idle);
+
+/*
+ * Set wait time interface:(Nanosecond)
+ * Example: Base on TBfreq is 41MHZ.
+ * 1~48(ns): TB[63]
+ * 49~97(ns): TB[62]
+ * 98~195(ns): TB[61]
+ * 196~390(ns): TB[60]
+ * 391~780(ns): TB[59]
+ * 781~1560(ns): TB[58]
+ * ...
+ */
+static DEVICE_ATTR(pw20_wait_time, 0600,
+                       show_pw20_wait_time,
+                       store_pw20_wait_time);
+static DEVICE_ATTR(altivec_idle_wait_time, 0600,
+                       show_altivec_idle_wait_time,
+                       store_altivec_idle_wait_time);
+#endif
+
 /*
  * Enabling PMCs will slow partition context switch times so we only do
  * it the first time we write to the PMCs.
@@ -108,14 +404,14 @@ void ppc_enable_pmcs(void)
 }
 EXPORT_SYMBOL(ppc_enable_pmcs);
 
-#define SYSFS_PMCSETUP(NAME, ADDRESS) \
+#define __SYSFS_SPRSETUP(NAME, ADDRESS, EXTRA) \
 static void read_##NAME(void *val) \
 { \
        *(unsigned long *)val = mfspr(ADDRESS); \
 } \
 static void write_##NAME(void *val) \
 { \
-       ppc_enable_pmcs(); \
+       EXTRA; \
        mtspr(ADDRESS, *(unsigned long *)val);  \
 } \
 static ssize_t show_##NAME(struct device *dev, \
@@ -140,6 +436,10 @@ static ssize_t __used \
        return count; \
 }
 
+#define SYSFS_PMCSETUP(NAME, ADDRESS)  \
+       __SYSFS_SPRSETUP(NAME, ADDRESS, ppc_enable_pmcs())
+#define SYSFS_SPRSETUP(NAME, ADDRESS)  \
+       __SYSFS_SPRSETUP(NAME, ADDRESS, )
 
 /* Let's define all possible registers, we'll only hook up the ones
  * that are implemented on the current processor
@@ -175,10 +475,10 @@ SYSFS_PMCSETUP(pmc7, SPRN_PMC7);
 SYSFS_PMCSETUP(pmc8, SPRN_PMC8);
 
 SYSFS_PMCSETUP(mmcra, SPRN_MMCRA);
-SYSFS_PMCSETUP(purr, SPRN_PURR);
-SYSFS_PMCSETUP(spurr, SPRN_SPURR);
-SYSFS_PMCSETUP(dscr, SPRN_DSCR);
-SYSFS_PMCSETUP(pir, SPRN_PIR);
+SYSFS_SPRSETUP(purr, SPRN_PURR);
+SYSFS_SPRSETUP(spurr, SPRN_SPURR);
+SYSFS_SPRSETUP(dscr, SPRN_DSCR);
+SYSFS_SPRSETUP(pir, SPRN_PIR);
 
 /*
   Lets only enable read for phyp resources and
@@ -249,34 +549,34 @@ SYSFS_PMCSETUP(pa6t_pmc3, SPRN_PA6T_PMC3);
 SYSFS_PMCSETUP(pa6t_pmc4, SPRN_PA6T_PMC4);
 SYSFS_PMCSETUP(pa6t_pmc5, SPRN_PA6T_PMC5);
 #ifdef CONFIG_DEBUG_KERNEL
-SYSFS_PMCSETUP(hid0, SPRN_HID0);
-SYSFS_PMCSETUP(hid1, SPRN_HID1);
-SYSFS_PMCSETUP(hid4, SPRN_HID4);
-SYSFS_PMCSETUP(hid5, SPRN_HID5);
-SYSFS_PMCSETUP(ima0, SPRN_PA6T_IMA0);
-SYSFS_PMCSETUP(ima1, SPRN_PA6T_IMA1);
-SYSFS_PMCSETUP(ima2, SPRN_PA6T_IMA2);
-SYSFS_PMCSETUP(ima3, SPRN_PA6T_IMA3);
-SYSFS_PMCSETUP(ima4, SPRN_PA6T_IMA4);
-SYSFS_PMCSETUP(ima5, SPRN_PA6T_IMA5);
-SYSFS_PMCSETUP(ima6, SPRN_PA6T_IMA6);
-SYSFS_PMCSETUP(ima7, SPRN_PA6T_IMA7);
-SYSFS_PMCSETUP(ima8, SPRN_PA6T_IMA8);
-SYSFS_PMCSETUP(ima9, SPRN_PA6T_IMA9);
-SYSFS_PMCSETUP(imaat, SPRN_PA6T_IMAAT);
-SYSFS_PMCSETUP(btcr, SPRN_PA6T_BTCR);
-SYSFS_PMCSETUP(pccr, SPRN_PA6T_PCCR);
-SYSFS_PMCSETUP(rpccr, SPRN_PA6T_RPCCR);
-SYSFS_PMCSETUP(der, SPRN_PA6T_DER);
-SYSFS_PMCSETUP(mer, SPRN_PA6T_MER);
-SYSFS_PMCSETUP(ber, SPRN_PA6T_BER);
-SYSFS_PMCSETUP(ier, SPRN_PA6T_IER);
-SYSFS_PMCSETUP(sier, SPRN_PA6T_SIER);
-SYSFS_PMCSETUP(siar, SPRN_PA6T_SIAR);
-SYSFS_PMCSETUP(tsr0, SPRN_PA6T_TSR0);
-SYSFS_PMCSETUP(tsr1, SPRN_PA6T_TSR1);
-SYSFS_PMCSETUP(tsr2, SPRN_PA6T_TSR2);
-SYSFS_PMCSETUP(tsr3, SPRN_PA6T_TSR3);
+SYSFS_SPRSETUP(hid0, SPRN_HID0);
+SYSFS_SPRSETUP(hid1, SPRN_HID1);
+SYSFS_SPRSETUP(hid4, SPRN_HID4);
+SYSFS_SPRSETUP(hid5, SPRN_HID5);
+SYSFS_SPRSETUP(ima0, SPRN_PA6T_IMA0);
+SYSFS_SPRSETUP(ima1, SPRN_PA6T_IMA1);
+SYSFS_SPRSETUP(ima2, SPRN_PA6T_IMA2);
+SYSFS_SPRSETUP(ima3, SPRN_PA6T_IMA3);
+SYSFS_SPRSETUP(ima4, SPRN_PA6T_IMA4);
+SYSFS_SPRSETUP(ima5, SPRN_PA6T_IMA5);
+SYSFS_SPRSETUP(ima6, SPRN_PA6T_IMA6);
+SYSFS_SPRSETUP(ima7, SPRN_PA6T_IMA7);
+SYSFS_SPRSETUP(ima8, SPRN_PA6T_IMA8);
+SYSFS_SPRSETUP(ima9, SPRN_PA6T_IMA9);
+SYSFS_SPRSETUP(imaat, SPRN_PA6T_IMAAT);
+SYSFS_SPRSETUP(btcr, SPRN_PA6T_BTCR);
+SYSFS_SPRSETUP(pccr, SPRN_PA6T_PCCR);
+SYSFS_SPRSETUP(rpccr, SPRN_PA6T_RPCCR);
+SYSFS_SPRSETUP(der, SPRN_PA6T_DER);
+SYSFS_SPRSETUP(mer, SPRN_PA6T_MER);
+SYSFS_SPRSETUP(ber, SPRN_PA6T_BER);
+SYSFS_SPRSETUP(ier, SPRN_PA6T_IER);
+SYSFS_SPRSETUP(sier, SPRN_PA6T_SIER);
+SYSFS_SPRSETUP(siar, SPRN_PA6T_SIAR);
+SYSFS_SPRSETUP(tsr0, SPRN_PA6T_TSR0);
+SYSFS_SPRSETUP(tsr1, SPRN_PA6T_TSR1);
+SYSFS_SPRSETUP(tsr2, SPRN_PA6T_TSR2);
+SYSFS_SPRSETUP(tsr3, SPRN_PA6T_TSR3);
 #endif /* CONFIG_DEBUG_KERNEL */
 #endif /* HAS_PPC_PMC_PA6T */
 
@@ -421,6 +721,15 @@ static void register_cpu_online(unsigned int cpu)
                device_create_file(s, &dev_attr_pir);
 #endif /* CONFIG_PPC64 */
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+       if (PVR_VER(cur_cpu_spec->pvr_value) == PVR_VER_E6500) {
+               device_create_file(s, &dev_attr_pw20_state);
+               device_create_file(s, &dev_attr_pw20_wait_time);
+
+               device_create_file(s, &dev_attr_altivec_idle);
+               device_create_file(s, &dev_attr_altivec_idle_wait_time);
+       }
+#endif
        cacheinfo_cpu_online(cpu);
 }
 
@@ -493,6 +802,15 @@ static void unregister_cpu_online(unsigned int cpu)
                device_remove_file(s, &dev_attr_pir);
 #endif /* CONFIG_PPC64 */
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+       if (PVR_VER(cur_cpu_spec->pvr_value) == PVR_VER_E6500) {
+               device_remove_file(s, &dev_attr_pw20_state);
+               device_remove_file(s, &dev_attr_pw20_wait_time);
+
+               device_remove_file(s, &dev_attr_altivec_idle);
+               device_remove_file(s, &dev_attr_altivec_idle_wait_time);
+       }
+#endif
        cacheinfo_cpu_offline(cpu);
 }
 
index b3b144121cc99d64df0c409b0773259770ddf0af..b3dab20acf34abe126e244d34a7dee39021457de 100644 (file)
@@ -510,7 +510,6 @@ void timer_interrupt(struct pt_regs * regs)
         */
        may_hard_irq_enable();
 
-       __get_cpu_var(irq_stat).timer_irqs++;
 
 #if defined(CONFIG_PPC32) && defined(CONFIG_PMAC)
        if (atomic_read(&ppc_n_lost_interrupts) != 0)
@@ -532,10 +531,15 @@ void timer_interrupt(struct pt_regs * regs)
                *next_tb = ~(u64)0;
                if (evt->event_handler)
                        evt->event_handler(evt);
+               __get_cpu_var(irq_stat).timer_irqs_event++;
        } else {
                now = *next_tb - now;
                if (now <= DECREMENTER_MAX)
                        set_dec((int)now);
+               /* We may have raced with new irq work */
+               if (test_irq_work_pending())
+                       set_dec(1);
+               __get_cpu_var(irq_stat).timer_irqs_others++;
        }
 
 #ifdef CONFIG_PPC64
@@ -801,8 +805,16 @@ static void __init clocksource_init(void)
 static int decrementer_set_next_event(unsigned long evt,
                                      struct clock_event_device *dev)
 {
+       /* Don't adjust the decrementer if some irq work is pending */
+       if (test_irq_work_pending())
+               return 0;
        __get_cpu_var(decrementers_next_tb) = get_tb_or_rtc() + evt;
        set_dec(evt);
+
+       /* We may have raced with new irq work */
+       if (test_irq_work_pending())
+               set_dec(1);
+
        return 0;
 }
 
index 907a472f9a9e4c1db3747a8d4ff22cc1bb133ee8..33cd7a0b8e730b1d22583ab304821a2d1d203cc2 100644 (file)
@@ -285,6 +285,21 @@ void system_reset_exception(struct pt_regs *regs)
 
        /* What should we do here? We could issue a shutdown or hard reset. */
 }
+
+/*
+ * This function is called in real mode. Strictly no printk's please.
+ *
+ * regs->nip and regs->msr contains srr0 and ssr1.
+ */
+long machine_check_early(struct pt_regs *regs)
+{
+       long handled = 0;
+
+       if (cur_cpu_spec && cur_cpu_spec->machine_check_early)
+               handled = cur_cpu_spec->machine_check_early(regs);
+       return handled;
+}
+
 #endif
 
 /*
@@ -1384,7 +1399,6 @@ void fp_unavailable_tm(struct pt_regs *regs)
 
        TM_DEBUG("FP Unavailable trap whilst transactional at 0x%lx, MSR=%lx\n",
                 regs->nip, regs->msr);
-       tm_enable();
 
         /* We can only have got here if the task started using FP after
          * beginning the transaction.  So, the transactional regs are just a
@@ -1393,8 +1407,7 @@ void fp_unavailable_tm(struct pt_regs *regs)
          * transaction, and probably retry but now with FP enabled.  So the
          * checkpointed FP registers need to be loaded.
         */
-       tm_reclaim(&current->thread, current->thread.regs->msr,
-                  TM_CAUSE_FAC_UNAV);
+       tm_reclaim_current(TM_CAUSE_FAC_UNAV);
        /* Reclaim didn't save out any FPRs to transact_fprs. */
 
        /* Enable FP for the task: */
@@ -1403,11 +1416,19 @@ void fp_unavailable_tm(struct pt_regs *regs)
        /* This loads and recheckpoints the FP registers from
         * thread.fpr[].  They will remain in registers after the
         * checkpoint so we don't need to reload them after.
+        * If VMX is in use, the VRs now hold checkpointed values,
+        * so we don't want to load the VRs from the thread_struct.
         */
-       tm_recheckpoint(&current->thread, regs->msr);
+       tm_recheckpoint(&current->thread, MSR_FP);
+
+       /* If VMX is in use, get the transactional values back */
+       if (regs->msr & MSR_VEC) {
+               do_load_up_transact_altivec(&current->thread);
+               /* At this point all the VSX state is loaded, so enable it */
+               regs->msr |= MSR_VSX;
+       }
 }
 
-#ifdef CONFIG_ALTIVEC
 void altivec_unavailable_tm(struct pt_regs *regs)
 {
        /* See the comments in fp_unavailable_tm().  This function operates
@@ -1417,18 +1438,21 @@ void altivec_unavailable_tm(struct pt_regs *regs)
        TM_DEBUG("Vector Unavailable trap whilst transactional at 0x%lx,"
                 "MSR=%lx\n",
                 regs->nip, regs->msr);
-       tm_enable();
-       tm_reclaim(&current->thread, current->thread.regs->msr,
-                  TM_CAUSE_FAC_UNAV);
+       tm_reclaim_current(TM_CAUSE_FAC_UNAV);
        regs->msr |= MSR_VEC;
-       tm_recheckpoint(&current->thread, regs->msr);
+       tm_recheckpoint(&current->thread, MSR_VEC);
        current->thread.used_vr = 1;
+
+       if (regs->msr & MSR_FP) {
+               do_load_up_transact_fpu(&current->thread);
+               regs->msr |= MSR_VSX;
+       }
 }
-#endif
 
-#ifdef CONFIG_VSX
 void vsx_unavailable_tm(struct pt_regs *regs)
 {
+       unsigned long orig_msr = regs->msr;
+
        /* See the comments in fp_unavailable_tm().  This works similarly,
         * though we're loading both FP and VEC registers in here.
         *
@@ -1440,18 +1464,30 @@ void vsx_unavailable_tm(struct pt_regs *regs)
                 "MSR=%lx\n",
                 regs->nip, regs->msr);
 
-       tm_enable();
+       current->thread.used_vsr = 1;
+
+       /* If FP and VMX are already loaded, we have all the state we need */
+       if ((orig_msr & (MSR_FP | MSR_VEC)) == (MSR_FP | MSR_VEC)) {
+               regs->msr |= MSR_VSX;
+               return;
+       }
+
        /* This reclaims FP and/or VR regs if they're already enabled */
-       tm_reclaim(&current->thread, current->thread.regs->msr,
-                  TM_CAUSE_FAC_UNAV);
+       tm_reclaim_current(TM_CAUSE_FAC_UNAV);
 
        regs->msr |= MSR_VEC | MSR_FP | current->thread.fpexc_mode |
                MSR_VSX;
-       /* This loads & recheckpoints FP and VRs. */
-       tm_recheckpoint(&current->thread, regs->msr);
-       current->thread.used_vsr = 1;
+
+       /* This loads & recheckpoints FP and VRs; but we have
+        * to be sure not to overwrite previously-valid state.
+        */
+       tm_recheckpoint(&current->thread, regs->msr & ~orig_msr);
+
+       if (orig_msr & MSR_FP)
+               do_load_up_transact_fpu(&current->thread);
+       if (orig_msr & MSR_VEC)
+               do_load_up_transact_altivec(&current->thread);
 }
-#endif
 #endif /* CONFIG_PPC_TRANSACTIONAL_MEM */
 
 void performance_monitor_exception(struct pt_regs *regs)
index 6e8f507ed32bb5f74f9d9f5574f09636ae15f9a3..79683d0393f5d01577503b02d7d298018647a758 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/init.h>
 #include <linux/linkage.h>
 #include <asm/page.h>
 
index b8553d62b792ffb2953a400fabdf8fc746c62501..8df9e2463007c1601012aae7062c6a8896ebf9ef 100644 (file)
@@ -1,4 +1,3 @@
-#include <linux/init.h>
 #include <linux/linkage.h>
 #include <asm/page.h>
 
index 0458a9aaba9d135867d6a4263404a8264148a7cd..74f8050518d69034984eaf50c8e34e131842f22c 100644 (file)
@@ -36,6 +36,16 @@ _GLOBAL(do_load_up_transact_altivec)
        blr
 #endif
 
+/*
+ * Enable use of VMX/Altivec for the caller.
+ */
+_GLOBAL(vec_enable)
+       mfmsr   r3
+       oris    r3,r3,MSR_VEC@h
+       MTMSRD(r3)
+       isync
+       blr
+
 /*
  * Load state from memory into VMX registers including VSCR.
  * Assumes the caller has enabled VMX in the MSR.
index 76a64821f4a23653b64cc6ba0e32daec509ee5b5..826d8bd9e5223d94eccfe3639d980e323c78b189 100644 (file)
@@ -518,16 +518,18 @@ static dma_addr_t vio_dma_iommu_map_page(struct device *dev, struct page *page,
                                          struct dma_attrs *attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
+       struct iommu_table *tbl;
        dma_addr_t ret = DMA_ERROR_CODE;
 
-       if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE))) {
+       tbl = get_iommu_table_base(dev);
+       if (vio_cmo_alloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)))) {
                atomic_inc(&viodev->cmo.allocs_failed);
                return ret;
        }
 
        ret = dma_iommu_ops.map_page(dev, page, offset, size, direction, attrs);
        if (unlikely(dma_mapping_error(dev, ret))) {
-               vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE));
+               vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)));
                atomic_inc(&viodev->cmo.allocs_failed);
        }
 
@@ -540,10 +542,12 @@ static void vio_dma_iommu_unmap_page(struct device *dev, dma_addr_t dma_handle,
                                     struct dma_attrs *attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
+       struct iommu_table *tbl;
 
+       tbl = get_iommu_table_base(dev);
        dma_iommu_ops.unmap_page(dev, dma_handle, size, direction, attrs);
 
-       vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE));
+       vio_cmo_dealloc(viodev, roundup(size, IOMMU_PAGE_SIZE(tbl)));
 }
 
 static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
@@ -551,12 +555,14 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
                                 struct dma_attrs *attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
+       struct iommu_table *tbl;
        struct scatterlist *sgl;
        int ret, count = 0;
        size_t alloc_size = 0;
 
+       tbl = get_iommu_table_base(dev);
        for (sgl = sglist; count < nelems; count++, sgl++)
-               alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE);
+               alloc_size += roundup(sgl->length, IOMMU_PAGE_SIZE(tbl));
 
        if (vio_cmo_alloc(viodev, alloc_size)) {
                atomic_inc(&viodev->cmo.allocs_failed);
@@ -572,7 +578,7 @@ static int vio_dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
        }
 
        for (sgl = sglist, count = 0; count < ret; count++, sgl++)
-               alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE);
+               alloc_size -= roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl));
        if (alloc_size)
                vio_cmo_dealloc(viodev, alloc_size);
 
@@ -585,12 +591,14 @@ static void vio_dma_iommu_unmap_sg(struct device *dev,
                struct dma_attrs *attrs)
 {
        struct vio_dev *viodev = to_vio_dev(dev);
+       struct iommu_table *tbl;
        struct scatterlist *sgl;
        size_t alloc_size = 0;
        int count = 0;
 
+       tbl = get_iommu_table_base(dev);
        for (sgl = sglist; count < nelems; count++, sgl++)
-               alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE);
+               alloc_size += roundup(sgl->dma_length, IOMMU_PAGE_SIZE(tbl));
 
        dma_iommu_ops.unmap_sg(dev, sglist, nelems, direction, attrs);
 
@@ -706,11 +714,14 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev)
 {
        struct vio_cmo_dev_entry *dev_ent;
        struct device *dev = &viodev->dev;
+       struct iommu_table *tbl;
        struct vio_driver *viodrv = to_vio_driver(dev->driver);
        unsigned long flags;
        size_t size;
        bool dma_capable = false;
 
+       tbl = get_iommu_table_base(dev);
+
        /* A device requires entitlement if it has a DMA window property */
        switch (viodev->family) {
        case VDEVICE:
@@ -736,7 +747,8 @@ static int vio_cmo_bus_probe(struct vio_dev *viodev)
                        return -EINVAL;
                }
 
-               viodev->cmo.desired = IOMMU_PAGE_ALIGN(viodrv->get_desired_dma(viodev));
+               viodev->cmo.desired =
+                       IOMMU_PAGE_ALIGN(viodrv->get_desired_dma(viodev), tbl);
                if (viodev->cmo.desired < VIO_CMO_MIN_ENT)
                        viodev->cmo.desired = VIO_CMO_MIN_ENT;
                size = VIO_CMO_MIN_ENT;
@@ -1176,9 +1188,10 @@ static struct iommu_table *vio_build_iommu_table(struct vio_dev *dev)
                            &tbl->it_index, &offset, &size);
 
        /* TCE table size - measured in tce entries */
-       tbl->it_size = size >> IOMMU_PAGE_SHIFT;
+       tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K;
+       tbl->it_size = size >> tbl->it_page_shift;
        /* offset for VIO should always be 0 */
-       tbl->it_offset = offset >> IOMMU_PAGE_SHIFT;
+       tbl->it_offset = offset >> tbl->it_page_shift;
        tbl->it_busno = 0;
        tbl->it_type = TCE_VB;
        tbl->it_blocksize = 16;
index 93221e87b911963f890bc7e3a111359ead5054a5..9cb4b0a3603183fe71818a0e28869de12d78071d 100644 (file)
@@ -21,6 +21,8 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/export.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
 
 #include <asm/reg.h>
 #include <asm/cputable.h>
@@ -231,3 +233,5 @@ static void __exit kvmppc_44x_exit(void)
 
 module_init(kvmppc_44x_init);
 module_exit(kvmppc_44x_exit);
+MODULE_ALIAS_MISCDEV(KVM_MINOR);
+MODULE_ALIAS("devname:kvm");
index 8912608b7e1b34908b2e86870366a4cee500a313..94e597e6f15cd08f3f4f7deb5bab73d2d3ff1f27 100644 (file)
@@ -18,6 +18,8 @@
 #include <linux/err.h>
 #include <linux/export.h>
 #include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
 
 #include <asm/reg.h>
 #include <asm/cputable.h>
@@ -575,10 +577,10 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
                        break;
                case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
                        i = reg->id - KVM_REG_PPC_FPR0;
-                       val = get_reg_val(reg->id, vcpu->arch.fpr[i]);
+                       val = get_reg_val(reg->id, VCPU_FPR(vcpu, i));
                        break;
                case KVM_REG_PPC_FPSCR:
-                       val = get_reg_val(reg->id, vcpu->arch.fpscr);
+                       val = get_reg_val(reg->id, vcpu->arch.fp.fpscr);
                        break;
 #ifdef CONFIG_ALTIVEC
                case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
@@ -586,19 +588,30 @@ int kvm_vcpu_ioctl_get_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
                                r = -ENXIO;
                                break;
                        }
-                       val.vval = vcpu->arch.vr[reg->id - KVM_REG_PPC_VR0];
+                       val.vval = vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0];
                        break;
                case KVM_REG_PPC_VSCR:
                        if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
                                r = -ENXIO;
                                break;
                        }
-                       val = get_reg_val(reg->id, vcpu->arch.vscr.u[3]);
+                       val = get_reg_val(reg->id, vcpu->arch.vr.vscr.u[3]);
                        break;
                case KVM_REG_PPC_VRSAVE:
                        val = get_reg_val(reg->id, vcpu->arch.vrsave);
                        break;
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_VSX
+               case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
+                       if (cpu_has_feature(CPU_FTR_VSX)) {
+                               long int i = reg->id - KVM_REG_PPC_VSR0;
+                               val.vsxval[0] = vcpu->arch.fp.fpr[i][0];
+                               val.vsxval[1] = vcpu->arch.fp.fpr[i][1];
+                       } else {
+                               r = -ENXIO;
+                       }
+                       break;
+#endif /* CONFIG_VSX */
                case KVM_REG_PPC_DEBUG_INST: {
                        u32 opcode = INS_TW;
                        r = copy_to_user((u32 __user *)(long)reg->addr,
@@ -654,10 +667,10 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
                        break;
                case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
                        i = reg->id - KVM_REG_PPC_FPR0;
-                       vcpu->arch.fpr[i] = set_reg_val(reg->id, val);
+                       VCPU_FPR(vcpu, i) = set_reg_val(reg->id, val);
                        break;
                case KVM_REG_PPC_FPSCR:
-                       vcpu->arch.fpscr = set_reg_val(reg->id, val);
+                       vcpu->arch.fp.fpscr = set_reg_val(reg->id, val);
                        break;
 #ifdef CONFIG_ALTIVEC
                case KVM_REG_PPC_VR0 ... KVM_REG_PPC_VR31:
@@ -665,14 +678,14 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
                                r = -ENXIO;
                                break;
                        }
-                       vcpu->arch.vr[reg->id - KVM_REG_PPC_VR0] = val.vval;
+                       vcpu->arch.vr.vr[reg->id - KVM_REG_PPC_VR0] = val.vval;
                        break;
                case KVM_REG_PPC_VSCR:
                        if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
                                r = -ENXIO;
                                break;
                        }
-                       vcpu->arch.vscr.u[3] = set_reg_val(reg->id, val);
+                       vcpu->arch.vr.vscr.u[3] = set_reg_val(reg->id, val);
                        break;
                case KVM_REG_PPC_VRSAVE:
                        if (!cpu_has_feature(CPU_FTR_ALTIVEC)) {
@@ -682,6 +695,17 @@ int kvm_vcpu_ioctl_set_one_reg(struct kvm_vcpu *vcpu, struct kvm_one_reg *reg)
                        vcpu->arch.vrsave = set_reg_val(reg->id, val);
                        break;
 #endif /* CONFIG_ALTIVEC */
+#ifdef CONFIG_VSX
+               case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
+                       if (cpu_has_feature(CPU_FTR_VSX)) {
+                               long int i = reg->id - KVM_REG_PPC_VSR0;
+                               vcpu->arch.fp.fpr[i][0] = val.vsxval[0];
+                               vcpu->arch.fp.fpr[i][1] = val.vsxval[1];
+                       } else {
+                               r = -ENXIO;
+                       }
+                       break;
+#endif /* CONFIG_VSX */
 #ifdef CONFIG_KVM_XICS
                case KVM_REG_PPC_ICP_STATE:
                        if (!vcpu->arch.icp) {
@@ -879,3 +903,9 @@ static void kvmppc_book3s_exit(void)
 
 module_init(kvmppc_book3s_init);
 module_exit(kvmppc_book3s_exit);
+
+/* On 32bit this is our one and only kernel module */
+#ifdef CONFIG_KVM_BOOK3S_32
+MODULE_ALIAS_MISCDEV(KVM_MINOR);
+MODULE_ALIAS("devname:kvm");
+#endif
index 3a0abd2e5a15a2b4b3e3c3305408790193358b24..5fac89dfe4cdf2dd1673753d703dbf32c8b26b03 100644 (file)
@@ -243,6 +243,11 @@ next_pteg:
        /* Now tell our Shadow PTE code about the new page */
 
        pte = kvmppc_mmu_hpte_cache_next(vcpu);
+       if (!pte) {
+               kvm_release_pfn_clean(hpaddr >> PAGE_SHIFT);
+               r = -EAGAIN;
+               goto out;
+       }
 
        dprintk_mmu("KVM: %c%c Map 0x%llx: [%lx] 0x%llx (0x%llx) -> %lx\n",
                    orig_pte->may_write ? 'w' : '-',
index c5d148434c08197034eba8ababd951176adb6a1f..303ece75b8e4aa5b798381b4cf782a3dde8b79f6 100644 (file)
@@ -262,7 +262,7 @@ int kvmppc_mmu_hv_init(void)
 
 static void kvmppc_mmu_book3s_64_hv_reset_msr(struct kvm_vcpu *vcpu)
 {
-       kvmppc_set_msr(vcpu, MSR_SF | MSR_ME);
+       kvmppc_set_msr(vcpu, vcpu->arch.intr_msr);
 }
 
 /*
@@ -562,7 +562,7 @@ static int kvmppc_hv_emulate_mmio(struct kvm_run *run, struct kvm_vcpu *vcpu,
         * we just return and retry the instruction.
         */
 
-       if (instruction_is_store(vcpu->arch.last_inst) != !!is_store)
+       if (instruction_is_store(kvmppc_get_last_inst(vcpu)) != !!is_store)
                return RESUME_GUEST;
 
        /*
index 852989a9bad3040751d39a32c81b28bf28d864e4..20d4ea8e656d3eacf3202ef42f806168d44841f4 100644 (file)
@@ -25,9 +25,5 @@ EXPORT_SYMBOL_GPL(kvmppc_hv_entry_trampoline);
 #endif
 #ifdef CONFIG_KVM_BOOK3S_PR_POSSIBLE
 EXPORT_SYMBOL_GPL(kvmppc_entry_trampoline);
-EXPORT_SYMBOL_GPL(kvmppc_load_up_fpu);
-#ifdef CONFIG_ALTIVEC
-EXPORT_SYMBOL_GPL(kvmppc_load_up_altivec);
-#endif
 #endif
 
index 3818bd95327c5f1cf14e200d04a468bb46da6c59..17fc9496b6aca0d088bf6d6b13d38dca19121a13 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/spinlock.h>
 #include <linux/page-flags.h>
 #include <linux/srcu.h>
+#include <linux/miscdevice.h>
 
 #include <asm/reg.h>
 #include <asm/cputable.h>
@@ -85,10 +86,13 @@ static void kvmppc_fast_vcpu_kick_hv(struct kvm_vcpu *vcpu)
 
        /* CPU points to the first thread of the core */
        if (cpu != me && cpu >= 0 && cpu < nr_cpu_ids) {
+#ifdef CONFIG_KVM_XICS
                int real_cpu = cpu + vcpu->arch.ptid;
                if (paca[real_cpu].kvm_hstate.xics_phys)
                        xics_wake_cpu(real_cpu);
-               else if (cpu_online(cpu))
+               else
+#endif
+               if (cpu_online(cpu))
                        smp_send_reschedule(cpu);
        }
        put_cpu();
@@ -182,14 +186,28 @@ int kvmppc_set_arch_compat(struct kvm_vcpu *vcpu, u32 arch_compat)
 
                switch (arch_compat) {
                case PVR_ARCH_205:
-                       pcr = PCR_ARCH_205;
+                       /*
+                        * If an arch bit is set in PCR, all the defined
+                        * higher-order arch bits also have to be set.
+                        */
+                       pcr = PCR_ARCH_206 | PCR_ARCH_205;
                        break;
                case PVR_ARCH_206:
                case PVR_ARCH_206p:
+                       pcr = PCR_ARCH_206;
+                       break;
+               case PVR_ARCH_207:
                        break;
                default:
                        return -EINVAL;
                }
+
+               if (!cpu_has_feature(CPU_FTR_ARCH_207S)) {
+                       /* POWER7 can't emulate POWER8 */
+                       if (!(pcr & PCR_ARCH_206))
+                               return -EINVAL;
+                       pcr &= ~PCR_ARCH_206;
+               }
        }
 
        spin_lock(&vc->lock);
@@ -637,6 +655,7 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
                r = RESUME_GUEST;
                break;
        case BOOK3S_INTERRUPT_EXTERNAL:
+       case BOOK3S_INTERRUPT_H_DOORBELL:
                vcpu->stat.ext_intr_exits++;
                r = RESUME_GUEST;
                break;
@@ -673,12 +692,10 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
                /* hcall - punt to userspace */
                int i;
 
-               if (vcpu->arch.shregs.msr & MSR_PR) {
-                       /* sc 1 from userspace - reflect to guest syscall */
-                       kvmppc_book3s_queue_irqprio(vcpu, BOOK3S_INTERRUPT_SYSCALL);
-                       r = RESUME_GUEST;
-                       break;
-               }
+               /* hypercall with MSR_PR has already been handled in rmode,
+                * and never reaches here.
+                */
+
                run->papr_hcall.nr = kvmppc_get_gpr(vcpu, 3);
                for (i = 0; i < 9; ++i)
                        run->papr_hcall.args[i] = kvmppc_get_gpr(vcpu, 4 + i);
@@ -708,7 +725,16 @@ static int kvmppc_handle_exit_hv(struct kvm_run *run, struct kvm_vcpu *vcpu,
         * we don't emulate any guest instructions at this stage.
         */
        case BOOK3S_INTERRUPT_H_EMUL_ASSIST:
-               kvmppc_core_queue_program(vcpu, 0x80000);
+               kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
+               r = RESUME_GUEST;
+               break;
+       /*
+        * This occurs if the guest (kernel or userspace), does something that
+        * is prohibited by HFSCR.  We just generate a program interrupt to
+        * the guest.
+        */
+       case BOOK3S_INTERRUPT_H_FAC_UNAVAIL:
+               kvmppc_core_queue_program(vcpu, SRR1_PROGILL);
                r = RESUME_GUEST;
                break;
        default:
@@ -765,11 +791,35 @@ static void kvmppc_set_lpcr(struct kvm_vcpu *vcpu, u64 new_lpcr)
        u64 mask;
 
        spin_lock(&vc->lock);
+       /*
+        * If ILE (interrupt little-endian) has changed, update the
+        * MSR_LE bit in the intr_msr for each vcpu in this vcore.
+        */
+       if ((new_lpcr & LPCR_ILE) != (vc->lpcr & LPCR_ILE)) {
+               struct kvm *kvm = vcpu->kvm;
+               struct kvm_vcpu *vcpu;
+               int i;
+
+               mutex_lock(&kvm->lock);
+               kvm_for_each_vcpu(i, vcpu, kvm) {
+                       if (vcpu->arch.vcore != vc)
+                               continue;
+                       if (new_lpcr & LPCR_ILE)
+                               vcpu->arch.intr_msr |= MSR_LE;
+                       else
+                               vcpu->arch.intr_msr &= ~MSR_LE;
+               }
+               mutex_unlock(&kvm->lock);
+       }
+
        /*
         * Userspace can only modify DPFD (default prefetch depth),
         * ILE (interrupt little-endian) and TC (translation control).
+        * On POWER8 userspace can also modify AIL (alt. interrupt loc.)
         */
        mask = LPCR_DPFD | LPCR_ILE | LPCR_TC;
+       if (cpu_has_feature(CPU_FTR_ARCH_207S))
+               mask |= LPCR_AIL;
        vc->lpcr = (vc->lpcr & ~mask) | (new_lpcr & mask);
        spin_unlock(&vc->lock);
 }
@@ -787,6 +837,9 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_DABR:
                *val = get_reg_val(id, vcpu->arch.dabr);
                break;
+       case KVM_REG_PPC_DABRX:
+               *val = get_reg_val(id, vcpu->arch.dabrx);
+               break;
        case KVM_REG_PPC_DSCR:
                *val = get_reg_val(id, vcpu->arch.dscr);
                break;
@@ -802,7 +855,7 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_UAMOR:
                *val = get_reg_val(id, vcpu->arch.uamor);
                break;
-       case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRA:
+       case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRS:
                i = id - KVM_REG_PPC_MMCR0;
                *val = get_reg_val(id, vcpu->arch.mmcr[i]);
                break;
@@ -810,33 +863,87 @@ static int kvmppc_get_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
                i = id - KVM_REG_PPC_PMC1;
                *val = get_reg_val(id, vcpu->arch.pmc[i]);
                break;
+       case KVM_REG_PPC_SPMC1 ... KVM_REG_PPC_SPMC2:
+               i = id - KVM_REG_PPC_SPMC1;
+               *val = get_reg_val(id, vcpu->arch.spmc[i]);
+               break;
        case KVM_REG_PPC_SIAR:
                *val = get_reg_val(id, vcpu->arch.siar);
                break;
        case KVM_REG_PPC_SDAR:
                *val = get_reg_val(id, vcpu->arch.sdar);
                break;
-#ifdef CONFIG_VSX
-       case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
-               if (cpu_has_feature(CPU_FTR_VSX)) {
-                       /* VSX => FP reg i is stored in arch.vsr[2*i] */
-                       long int i = id - KVM_REG_PPC_FPR0;
-                       *val = get_reg_val(id, vcpu->arch.vsr[2 * i]);
-               } else {
-                       /* let generic code handle it */
-                       r = -EINVAL;
-               }
+       case KVM_REG_PPC_SIER:
+               *val = get_reg_val(id, vcpu->arch.sier);
                break;
-       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
-               if (cpu_has_feature(CPU_FTR_VSX)) {
-                       long int i = id - KVM_REG_PPC_VSR0;
-                       val->vsxval[0] = vcpu->arch.vsr[2 * i];
-                       val->vsxval[1] = vcpu->arch.vsr[2 * i + 1];
-               } else {
-                       r = -ENXIO;
-               }
+       case KVM_REG_PPC_IAMR:
+               *val = get_reg_val(id, vcpu->arch.iamr);
+               break;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       case KVM_REG_PPC_TFHAR:
+               *val = get_reg_val(id, vcpu->arch.tfhar);
+               break;
+       case KVM_REG_PPC_TFIAR:
+               *val = get_reg_val(id, vcpu->arch.tfiar);
+               break;
+       case KVM_REG_PPC_TEXASR:
+               *val = get_reg_val(id, vcpu->arch.texasr);
+               break;
+#endif
+       case KVM_REG_PPC_FSCR:
+               *val = get_reg_val(id, vcpu->arch.fscr);
+               break;
+       case KVM_REG_PPC_PSPB:
+               *val = get_reg_val(id, vcpu->arch.pspb);
+               break;
+       case KVM_REG_PPC_EBBHR:
+               *val = get_reg_val(id, vcpu->arch.ebbhr);
+               break;
+       case KVM_REG_PPC_EBBRR:
+               *val = get_reg_val(id, vcpu->arch.ebbrr);
+               break;
+       case KVM_REG_PPC_BESCR:
+               *val = get_reg_val(id, vcpu->arch.bescr);
+               break;
+       case KVM_REG_PPC_TAR:
+               *val = get_reg_val(id, vcpu->arch.tar);
+               break;
+       case KVM_REG_PPC_DPDES:
+               *val = get_reg_val(id, vcpu->arch.vcore->dpdes);
+               break;
+       case KVM_REG_PPC_DAWR:
+               *val = get_reg_val(id, vcpu->arch.dawr);
+               break;
+       case KVM_REG_PPC_DAWRX:
+               *val = get_reg_val(id, vcpu->arch.dawrx);
+               break;
+       case KVM_REG_PPC_CIABR:
+               *val = get_reg_val(id, vcpu->arch.ciabr);
+               break;
+       case KVM_REG_PPC_IC:
+               *val = get_reg_val(id, vcpu->arch.ic);
+               break;
+       case KVM_REG_PPC_VTB:
+               *val = get_reg_val(id, vcpu->arch.vtb);
+               break;
+       case KVM_REG_PPC_CSIGR:
+               *val = get_reg_val(id, vcpu->arch.csigr);
+               break;
+       case KVM_REG_PPC_TACR:
+               *val = get_reg_val(id, vcpu->arch.tacr);
+               break;
+       case KVM_REG_PPC_TCSCR:
+               *val = get_reg_val(id, vcpu->arch.tcscr);
+               break;
+       case KVM_REG_PPC_PID:
+               *val = get_reg_val(id, vcpu->arch.pid);
+               break;
+       case KVM_REG_PPC_ACOP:
+               *val = get_reg_val(id, vcpu->arch.acop);
+               break;
+       case KVM_REG_PPC_WORT:
+               *val = get_reg_val(id, vcpu->arch.wort);
                break;
-#endif /* CONFIG_VSX */
        case KVM_REG_PPC_VPA_ADDR:
                spin_lock(&vcpu->arch.vpa_update_lock);
                *val = get_reg_val(id, vcpu->arch.vpa.next_gpa);
@@ -890,6 +997,9 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_DABR:
                vcpu->arch.dabr = set_reg_val(id, *val);
                break;
+       case KVM_REG_PPC_DABRX:
+               vcpu->arch.dabrx = set_reg_val(id, *val) & ~DABRX_HYP;
+               break;
        case KVM_REG_PPC_DSCR:
                vcpu->arch.dscr = set_reg_val(id, *val);
                break;
@@ -905,7 +1015,7 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_UAMOR:
                vcpu->arch.uamor = set_reg_val(id, *val);
                break;
-       case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRA:
+       case KVM_REG_PPC_MMCR0 ... KVM_REG_PPC_MMCRS:
                i = id - KVM_REG_PPC_MMCR0;
                vcpu->arch.mmcr[i] = set_reg_val(id, *val);
                break;
@@ -913,33 +1023,90 @@ static int kvmppc_set_one_reg_hv(struct kvm_vcpu *vcpu, u64 id,
                i = id - KVM_REG_PPC_PMC1;
                vcpu->arch.pmc[i] = set_reg_val(id, *val);
                break;
+       case KVM_REG_PPC_SPMC1 ... KVM_REG_PPC_SPMC2:
+               i = id - KVM_REG_PPC_SPMC1;
+               vcpu->arch.spmc[i] = set_reg_val(id, *val);
+               break;
        case KVM_REG_PPC_SIAR:
                vcpu->arch.siar = set_reg_val(id, *val);
                break;
        case KVM_REG_PPC_SDAR:
                vcpu->arch.sdar = set_reg_val(id, *val);
                break;
-#ifdef CONFIG_VSX
-       case KVM_REG_PPC_FPR0 ... KVM_REG_PPC_FPR31:
-               if (cpu_has_feature(CPU_FTR_VSX)) {
-                       /* VSX => FP reg i is stored in arch.vsr[2*i] */
-                       long int i = id - KVM_REG_PPC_FPR0;
-                       vcpu->arch.vsr[2 * i] = set_reg_val(id, *val);
-               } else {
-                       /* let generic code handle it */
-                       r = -EINVAL;
-               }
+       case KVM_REG_PPC_SIER:
+               vcpu->arch.sier = set_reg_val(id, *val);
                break;
-       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31:
-               if (cpu_has_feature(CPU_FTR_VSX)) {
-                       long int i = id - KVM_REG_PPC_VSR0;
-                       vcpu->arch.vsr[2 * i] = val->vsxval[0];
-                       vcpu->arch.vsr[2 * i + 1] = val->vsxval[1];
-               } else {
-                       r = -ENXIO;
-               }
+       case KVM_REG_PPC_IAMR:
+               vcpu->arch.iamr = set_reg_val(id, *val);
+               break;
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       case KVM_REG_PPC_TFHAR:
+               vcpu->arch.tfhar = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TFIAR:
+               vcpu->arch.tfiar = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TEXASR:
+               vcpu->arch.texasr = set_reg_val(id, *val);
+               break;
+#endif
+       case KVM_REG_PPC_FSCR:
+               vcpu->arch.fscr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_PSPB:
+               vcpu->arch.pspb = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_EBBHR:
+               vcpu->arch.ebbhr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_EBBRR:
+               vcpu->arch.ebbrr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_BESCR:
+               vcpu->arch.bescr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TAR:
+               vcpu->arch.tar = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_DPDES:
+               vcpu->arch.vcore->dpdes = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_DAWR:
+               vcpu->arch.dawr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_DAWRX:
+               vcpu->arch.dawrx = set_reg_val(id, *val) & ~DAWRX_HYP;
+               break;
+       case KVM_REG_PPC_CIABR:
+               vcpu->arch.ciabr = set_reg_val(id, *val);
+               /* Don't allow setting breakpoints in hypervisor code */
+               if ((vcpu->arch.ciabr & CIABR_PRIV) == CIABR_PRIV_HYPER)
+                       vcpu->arch.ciabr &= ~CIABR_PRIV;        /* disable */
+               break;
+       case KVM_REG_PPC_IC:
+               vcpu->arch.ic = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_VTB:
+               vcpu->arch.vtb = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_CSIGR:
+               vcpu->arch.csigr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TACR:
+               vcpu->arch.tacr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_TCSCR:
+               vcpu->arch.tcscr = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_PID:
+               vcpu->arch.pid = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_ACOP:
+               vcpu->arch.acop = set_reg_val(id, *val);
+               break;
+       case KVM_REG_PPC_WORT:
+               vcpu->arch.wort = set_reg_val(id, *val);
                break;
-#endif /* CONFIG_VSX */
        case KVM_REG_PPC_VPA_ADDR:
                addr = set_reg_val(id, *val);
                r = -EINVAL;
@@ -1017,6 +1184,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
        spin_lock_init(&vcpu->arch.vpa_update_lock);
        spin_lock_init(&vcpu->arch.tbacct_lock);
        vcpu->arch.busy_preempt = TB_NIL;
+       vcpu->arch.intr_msr = MSR_SF | MSR_ME;
 
        kvmppc_mmu_book3s_hv_init(vcpu);
 
@@ -1034,6 +1202,8 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
                        init_waitqueue_head(&vcore->wq);
                        vcore->preempt_tb = TB_NIL;
                        vcore->lpcr = kvm->arch.lpcr;
+                       vcore->first_vcpuid = core * threads_per_core;
+                       vcore->kvm = kvm;
                }
                kvm->arch.vcores[core] = vcore;
                kvm->arch.online_vcores++;
@@ -1047,6 +1217,7 @@ static struct kvm_vcpu *kvmppc_core_vcpu_create_hv(struct kvm *kvm,
        ++vcore->num_threads;
        spin_unlock(&vcore->lock);
        vcpu->arch.vcore = vcore;
+       vcpu->arch.ptid = vcpu->vcpu_id - vcore->first_vcpuid;
 
        vcpu->arch.cpu_type = KVM_CPU_3S_64;
        kvmppc_sanity_check(vcpu);
@@ -1110,7 +1281,7 @@ static void kvmppc_end_cede(struct kvm_vcpu *vcpu)
        }
 }
 
-extern int __kvmppc_vcore_entry(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu);
+extern void __kvmppc_vcore_entry(void);
 
 static void kvmppc_remove_runnable(struct kvmppc_vcore *vc,
                                   struct kvm_vcpu *vcpu)
@@ -1184,13 +1355,16 @@ static void kvmppc_start_thread(struct kvm_vcpu *vcpu)
        tpaca = &paca[cpu];
        tpaca->kvm_hstate.kvm_vcpu = vcpu;
        tpaca->kvm_hstate.kvm_vcore = vc;
-       tpaca->kvm_hstate.napping = 0;
+       tpaca->kvm_hstate.ptid = vcpu->arch.ptid;
        vcpu->cpu = vc->pcpu;
        smp_wmb();
 #if defined(CONFIG_PPC_ICP_NATIVE) && defined(CONFIG_SMP)
-       if (vcpu->arch.ptid) {
+       if (cpu != smp_processor_id()) {
+#ifdef CONFIG_KVM_XICS
                xics_wake_cpu(cpu);
-               ++vc->n_woken;
+#endif
+               if (vcpu->arch.ptid)
+                       ++vc->n_woken;
        }
 #endif
 }
@@ -1247,10 +1421,10 @@ static int on_primary_thread(void)
  */
 static void kvmppc_run_core(struct kvmppc_vcore *vc)
 {
-       struct kvm_vcpu *vcpu, *vcpu0, *vnext;
+       struct kvm_vcpu *vcpu, *vnext;
        long ret;
        u64 now;
-       int ptid, i, need_vpa_update;
+       int i, need_vpa_update;
        int srcu_idx;
        struct kvm_vcpu *vcpus_to_update[threads_per_core];
 
@@ -1287,25 +1461,6 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
                spin_lock(&vc->lock);
        }
 
-       /*
-        * Assign physical thread IDs, first to non-ceded vcpus
-        * and then to ceded ones.
-        */
-       ptid = 0;
-       vcpu0 = NULL;
-       list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list) {
-               if (!vcpu->arch.ceded) {
-                       if (!ptid)
-                               vcpu0 = vcpu;
-                       vcpu->arch.ptid = ptid++;
-               }
-       }
-       if (!vcpu0)
-               goto out;       /* nothing to run; should never happen */
-       list_for_each_entry(vcpu, &vc->runnable_threads, arch.run_list)
-               if (vcpu->arch.ceded)
-                       vcpu->arch.ptid = ptid++;
-
        /*
         * Make sure we are running on thread 0, and that
         * secondary threads are offline.
@@ -1322,15 +1477,19 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
                kvmppc_create_dtl_entry(vcpu, vc);
        }
 
+       /* Set this explicitly in case thread 0 doesn't have a vcpu */
+       get_paca()->kvm_hstate.kvm_vcore = vc;
+       get_paca()->kvm_hstate.ptid = 0;
+
        vc->vcore_state = VCORE_RUNNING;
        preempt_disable();
        spin_unlock(&vc->lock);
 
        kvm_guest_enter();
 
-       srcu_idx = srcu_read_lock(&vcpu0->kvm->srcu);
+       srcu_idx = srcu_read_lock(&vc->kvm->srcu);
 
-       __kvmppc_vcore_entry(NULL, vcpu0);
+       __kvmppc_vcore_entry();
 
        spin_lock(&vc->lock);
        /* disable sending of IPIs on virtual external irqs */
@@ -1345,7 +1504,7 @@ static void kvmppc_run_core(struct kvmppc_vcore *vc)
        vc->vcore_state = VCORE_EXITING;
        spin_unlock(&vc->lock);
 
-       srcu_read_unlock(&vcpu0->kvm->srcu, srcu_idx);
+       srcu_read_unlock(&vc->kvm->srcu, srcu_idx);
 
        /* make sure updates to secondary vcpu structs are visible now */
        smp_mb();
@@ -1453,7 +1612,6 @@ static int kvmppc_run_vcpu(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        if (!signal_pending(current)) {
                if (vc->vcore_state == VCORE_RUNNING &&
                    VCORE_EXIT_COUNT(vc) == 0) {
-                       vcpu->arch.ptid = vc->n_runnable - 1;
                        kvmppc_create_dtl_entry(vcpu, vc);
                        kvmppc_start_thread(vcpu);
                } else if (vc->vcore_state == VCORE_SLEEPING) {
@@ -2048,6 +2206,9 @@ static int kvmppc_core_init_vm_hv(struct kvm *kvm)
                        LPCR_VPM0 | LPCR_VPM1;
                kvm->arch.vrma_slb_v = SLB_VSID_B_1T |
                        (VRMA_VSID << SLB_VSID_SHIFT_1T);
+               /* On POWER8 turn on online bit to enable PURR/SPURR */
+               if (cpu_has_feature(CPU_FTR_ARCH_207S))
+                       lpcr |= LPCR_ONL;
        }
        kvm->arch.lpcr = lpcr;
 
@@ -2222,3 +2383,5 @@ static void kvmppc_book3s_exit_hv(void)
 module_init(kvmppc_book3s_init_hv);
 module_exit(kvmppc_book3s_exit_hv);
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(KVM_MINOR);
+MODULE_ALIAS("devname:kvm");
index 928142c64cb00ed2ce0d30081222b66abc45ddc0..e873796b1a2931eabd3c9ecb716a2c415eaba7f2 100644 (file)
@@ -35,7 +35,7 @@
  ****************************************************************************/
 
 /* Registers:
- *  r4: vcpu pointer
+ *  none
  */
 _GLOBAL(__kvmppc_vcore_entry)
 
@@ -57,9 +57,11 @@ BEGIN_FTR_SECTION
        std     r3, HSTATE_DSCR(r13)
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
+BEGIN_FTR_SECTION
        /* Save host DABR */
        mfspr   r3, SPRN_DABR
        std     r3, HSTATE_DABR(r13)
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
 
        /* Hard-disable interrupts */
        mfmsr   r10
@@ -69,7 +71,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
        mtmsrd  r10,1
 
        /* Save host PMU registers */
-       /* R4 is live here (vcpu pointer) but not r3 or r5 */
        li      r3, 1
        sldi    r3, r3, 31              /* MMCR0_FC (freeze counters) bit */
        mfspr   r7, SPRN_MMCR0          /* save MMCR0 */
@@ -134,16 +135,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
         * enters the guest with interrupts enabled.
         */
 BEGIN_FTR_SECTION
+       ld      r4, HSTATE_KVM_VCPU(r13)
        ld      r0, VCPU_PENDING_EXC(r4)
        li      r7, (1 << BOOK3S_IRQPRIO_EXTERNAL)
        oris    r7, r7, (1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h
        and.    r0, r0, r7
        beq     32f
-       mr      r31, r4
        lhz     r3, PACAPACAINDEX(r13)
        bl      smp_send_reschedule
        nop
-       mr      r4, r31
 32:
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
 #endif /* CONFIG_SMP */
index a353c485808c6ea203eac428106b5fdf41943b36..768a9f977c001ee73e6d5aa2f0b8ee44ea3b35f5 100644 (file)
@@ -12,6 +12,7 @@
 #include <linux/kvm_host.h>
 #include <linux/kernel.h>
 #include <asm/opal.h>
+#include <asm/mce.h>
 
 /* SRR1 bits for machine check on POWER7 */
 #define SRR1_MC_LDSTERR                (1ul << (63-42))
@@ -58,18 +59,6 @@ static void reload_slb(struct kvm_vcpu *vcpu)
        }
 }
 
-/* POWER7 TLB flush */
-static void flush_tlb_power7(struct kvm_vcpu *vcpu)
-{
-       unsigned long i, rb;
-
-       rb = TLBIEL_INVAL_SET_LPID;
-       for (i = 0; i < POWER7_TLB_SETS; ++i) {
-               asm volatile("tlbiel %0" : : "r" (rb));
-               rb += 1 << TLBIEL_INVAL_SET_SHIFT;
-       }
-}
-
 /*
  * On POWER7, see if we can handle a machine check that occurred inside
  * the guest in real mode, without switching to the host partition.
@@ -79,9 +68,7 @@ static void flush_tlb_power7(struct kvm_vcpu *vcpu)
 static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
 {
        unsigned long srr1 = vcpu->arch.shregs.msr;
-#ifdef CONFIG_PPC_POWERNV
-       struct opal_machine_check_event *opal_evt;
-#endif
+       struct machine_check_event mce_evt;
        long handled = 1;
 
        if (srr1 & SRR1_MC_LDSTERR) {
@@ -96,7 +83,8 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
                                   DSISR_MC_SLB_PARITY | DSISR_MC_DERAT_MULTI);
                }
                if (dsisr & DSISR_MC_TLB_MULTI) {
-                       flush_tlb_power7(vcpu);
+                       if (cur_cpu_spec && cur_cpu_spec->flush_tlb)
+                               cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID);
                        dsisr &= ~DSISR_MC_TLB_MULTI;
                }
                /* Any other errors we don't understand? */
@@ -113,28 +101,38 @@ static long kvmppc_realmode_mc_power7(struct kvm_vcpu *vcpu)
                reload_slb(vcpu);
                break;
        case SRR1_MC_IFETCH_TLBMULTI:
-               flush_tlb_power7(vcpu);
+               if (cur_cpu_spec && cur_cpu_spec->flush_tlb)
+                       cur_cpu_spec->flush_tlb(TLBIEL_INVAL_SET_LPID);
                break;
        default:
                handled = 0;
        }
 
-#ifdef CONFIG_PPC_POWERNV
        /*
-        * See if OPAL has already handled the condition.
-        * We assume that if the condition is recovered then OPAL
+        * See if we have already handled the condition in the linux host.
+        * We assume that if the condition is recovered then linux host
         * will have generated an error log event that we will pick
         * up and log later.
+        * Don't release mce event now. In case if condition is not
+        * recovered we do guest exit and go back to linux host machine
+        * check handler. Hence we need make sure that current mce event
+        * is available for linux host to consume.
         */
-       opal_evt = local_paca->opal_mc_evt;
-       if (opal_evt->version == OpalMCE_V1 &&
-           (opal_evt->severity == OpalMCE_SEV_NO_ERROR ||
-            opal_evt->disposition == OpalMCE_DISPOSITION_RECOVERED))
+       if (!get_mce_event(&mce_evt, MCE_EVENT_DONTRELEASE))
+               goto out;
+
+       if (mce_evt.version == MCE_V1 &&
+           (mce_evt.severity == MCE_SEV_NO_ERROR ||
+            mce_evt.disposition == MCE_DISPOSITION_RECOVERED))
                handled = 1;
 
+out:
+       /*
+        * If we have handled the error, then release the mce event because
+        * we will be delivering machine check to guest.
+        */
        if (handled)
-               opal_evt->in_use = 0;
-#endif
+               release_mce_event();
 
        return handled;
 }
index 8689e2e308573b0df26996e2ebfed77e235df59c..37fb3caa4c80a59c5162b92943e1d7878991b8f1 100644 (file)
@@ -134,7 +134,7 @@ static void remove_revmap_chain(struct kvm *kvm, long pte_index,
        unlock_rmap(rmap);
 }
 
-static pte_t lookup_linux_pte(pgd_t *pgdir, unsigned long hva,
+static pte_t lookup_linux_pte_and_update(pgd_t *pgdir, unsigned long hva,
                              int writing, unsigned long *pte_sizep)
 {
        pte_t *ptep;
@@ -232,7 +232,8 @@ long kvmppc_do_h_enter(struct kvm *kvm, unsigned long flags,
 
                /* Look up the Linux PTE for the backing page */
                pte_size = psize;
-               pte = lookup_linux_pte(pgdir, hva, writing, &pte_size);
+               pte = lookup_linux_pte_and_update(pgdir, hva, writing,
+                                                 &pte_size);
                if (pte_present(pte)) {
                        if (writing && !pte_write(pte))
                                /* make the actual HPTE be read-only */
@@ -672,7 +673,8 @@ long kvmppc_h_protect(struct kvm_vcpu *vcpu, unsigned long flags,
                        memslot = __gfn_to_memslot(kvm_memslots(kvm), gfn);
                        if (memslot) {
                                hva = __gfn_to_hva_memslot(memslot, gfn);
-                               pte = lookup_linux_pte(pgdir, hva, 1, &psize);
+                               pte = lookup_linux_pte_and_update(pgdir, hva,
+                                                                 1, &psize);
                                if (pte_present(pte) && !pte_write(pte))
                                        r = hpte_make_readonly(r);
                        }
index be4fa04a37c96d56d5f07d241395afe22e1627dd..e66d4ec04d953a78a314b43a3a07f47ca27f5ae7 100644 (file)
 #error Need to fix lppaca and SLB shadow accesses in little endian mode
 #endif
 
+/* Values in HSTATE_NAPPING(r13) */
+#define NAPPING_CEDE   1
+#define NAPPING_NOVCPU 2
+
 /*
  * Call kvmppc_hv_entry in real mode.
  * Must be called with interrupts hard-disabled.
@@ -57,29 +61,23 @@ _GLOBAL(kvmppc_hv_entry_trampoline)
        RFI
 
 kvmppc_call_hv_entry:
+       ld      r4, HSTATE_KVM_VCPU(r13)
        bl      kvmppc_hv_entry
 
        /* Back from guest - restore host state and return to caller */
 
+BEGIN_FTR_SECTION
        /* Restore host DABR and DABRX */
        ld      r5,HSTATE_DABR(r13)
        li      r6,7
        mtspr   SPRN_DABR,r5
        mtspr   SPRN_DABRX,r6
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
 
        /* Restore SPRG3 */
        ld      r3,PACA_SPRG3(r13)
        mtspr   SPRN_SPRG3,r3
 
-       /*
-        * Reload DEC.  HDEC interrupts were disabled when
-        * we reloaded the host's LPCR value.
-        */
-       ld      r3, HSTATE_DECEXP(r13)
-       mftb    r4
-       subf    r4, r4, r3
-       mtspr   SPRN_DEC, r4
-
        /* Reload the host's PMU registers */
        ld      r3, PACALPPACAPTR(r13)  /* is the host using the PMU? */
        lbz     r4, LPPACA_PMCINUSE(r3)
@@ -114,6 +112,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        isync
 23:
 
+       /*
+        * Reload DEC.  HDEC interrupts were disabled when
+        * we reloaded the host's LPCR value.
+        */
+       ld      r3, HSTATE_DECEXP(r13)
+       mftb    r4
+       subf    r4, r4, r3
+       mtspr   SPRN_DEC, r4
+
        /*
         * For external and machine check interrupts, we need
         * to call the Linux handler to process the interrupt.
@@ -153,15 +160,75 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
 13:    b       machine_check_fwnmi
 
+kvmppc_primary_no_guest:
+       /* We handle this much like a ceded vcpu */
+       /* set our bit in napping_threads */
+       ld      r5, HSTATE_KVM_VCORE(r13)
+       lbz     r7, HSTATE_PTID(r13)
+       li      r0, 1
+       sld     r0, r0, r7
+       addi    r6, r5, VCORE_NAPPING_THREADS
+1:     lwarx   r3, 0, r6
+       or      r3, r3, r0
+       stwcx.  r3, 0, r6
+       bne     1b
+       /* order napping_threads update vs testing entry_exit_count */
+       isync
+       li      r12, 0
+       lwz     r7, VCORE_ENTRY_EXIT(r5)
+       cmpwi   r7, 0x100
+       bge     kvm_novcpu_exit /* another thread already exiting */
+       li      r3, NAPPING_NOVCPU
+       stb     r3, HSTATE_NAPPING(r13)
+       li      r3, 1
+       stb     r3, HSTATE_HWTHREAD_REQ(r13)
+
+       b       kvm_do_nap
+
+kvm_novcpu_wakeup:
+       ld      r1, HSTATE_HOST_R1(r13)
+       ld      r5, HSTATE_KVM_VCORE(r13)
+       li      r0, 0
+       stb     r0, HSTATE_NAPPING(r13)
+       stb     r0, HSTATE_HWTHREAD_REQ(r13)
+
+       /* check the wake reason */
+       bl      kvmppc_check_wake_reason
+       
+       /* see if any other thread is already exiting */
+       lwz     r0, VCORE_ENTRY_EXIT(r5)
+       cmpwi   r0, 0x100
+       bge     kvm_novcpu_exit
+
+       /* clear our bit in napping_threads */
+       lbz     r7, HSTATE_PTID(r13)
+       li      r0, 1
+       sld     r0, r0, r7
+       addi    r6, r5, VCORE_NAPPING_THREADS
+4:     lwarx   r7, 0, r6
+       andc    r7, r7, r0
+       stwcx.  r7, 0, r6
+       bne     4b
+
+       /* See if the wake reason means we need to exit */
+       cmpdi   r3, 0
+       bge     kvm_novcpu_exit
+
+       /* Got an IPI but other vcpus aren't yet exiting, must be a latecomer */
+       ld      r4, HSTATE_KVM_VCPU(r13)
+       cmpdi   r4, 0
+       bne     kvmppc_got_guest
+
+kvm_novcpu_exit:
+       b       hdec_soon
+
 /*
- * We come in here when wakened from nap mode on a secondary hw thread.
+ * We come in here when wakened from nap mode.
  * Relocation is off and most register values are lost.
  * r13 points to the PACA.
  */
        .globl  kvm_start_guest
 kvm_start_guest:
-       ld      r1,PACAEMERGSP(r13)
-       subi    r1,r1,STACK_FRAME_OVERHEAD
        ld      r2,PACATOC(r13)
 
        li      r0,KVM_HWTHREAD_IN_KVM
@@ -173,8 +240,13 @@ kvm_start_guest:
 
        /* were we napping due to cede? */
        lbz     r0,HSTATE_NAPPING(r13)
-       cmpwi   r0,0
-       bne     kvm_end_cede
+       cmpwi   r0,NAPPING_CEDE
+       beq     kvm_end_cede
+       cmpwi   r0,NAPPING_NOVCPU
+       beq     kvm_novcpu_wakeup
+
+       ld      r1,PACAEMERGSP(r13)
+       subi    r1,r1,STACK_FRAME_OVERHEAD
 
        /*
         * We weren't napping due to cede, so this must be a secondary
@@ -184,40 +256,22 @@ kvm_start_guest:
         */
 
        /* Check the wake reason in SRR1 to see why we got here */
-       mfspr   r3,SPRN_SRR1
-       rlwinm  r3,r3,44-31,0x7         /* extract wake reason field */
-       cmpwi   r3,4                    /* was it an external interrupt? */
-       bne     27f                     /* if not */
-       ld      r5,HSTATE_XICS_PHYS(r13)
-       li      r7,XICS_XIRR            /* if it was an external interrupt, */
-       lwzcix  r8,r5,r7                /* get and ack the interrupt */
-       sync
-       clrldi. r9,r8,40                /* get interrupt source ID. */
-       beq     28f                     /* none there? */
-       cmpwi   r9,XICS_IPI             /* was it an IPI? */
-       bne     29f
-       li      r0,0xff
-       li      r6,XICS_MFRR
-       stbcix  r0,r5,r6                /* clear IPI */
-       stwcix  r8,r5,r7                /* EOI the interrupt */
-       sync                            /* order loading of vcpu after that */
+       bl      kvmppc_check_wake_reason
+       cmpdi   r3, 0
+       bge     kvm_no_guest
 
        /* get vcpu pointer, NULL if we have no vcpu to run */
        ld      r4,HSTATE_KVM_VCPU(r13)
        cmpdi   r4,0
        /* if we have no vcpu to run, go back to sleep */
        beq     kvm_no_guest
-       b       30f
 
-27:    /* XXX should handle hypervisor maintenance interrupts etc. here */
-       b       kvm_no_guest
-28:    /* SRR1 said external but ICP said nope?? */
-       b       kvm_no_guest
-29:    /* External non-IPI interrupt to offline secondary thread? help?? */
-       stw     r8,HSTATE_SAVED_XIRR(r13)
-       b       kvm_no_guest
+       /* Set HSTATE_DSCR(r13) to something sensible */
+       LOAD_REG_ADDR(r6, dscr_default)
+       ld      r6, 0(r6)
+       std     r6, HSTATE_DSCR(r13)
 
-30:    bl      kvmppc_hv_entry
+       bl      kvmppc_hv_entry
 
        /* Back from the guest, go back to nap */
        /* Clear our vcpu pointer so we don't come back in early */
@@ -229,18 +283,6 @@ kvm_start_guest:
         * visible we could be given another vcpu.
         */
        lwsync
-       /* Clear any pending IPI - we're an offline thread */
-       ld      r5, HSTATE_XICS_PHYS(r13)
-       li      r7, XICS_XIRR
-       lwzcix  r3, r5, r7              /* ack any pending interrupt */
-       rlwinm. r0, r3, 0, 0xffffff     /* any pending? */
-       beq     37f
-       sync
-       li      r0, 0xff
-       li      r6, XICS_MFRR
-       stbcix  r0, r5, r6              /* clear the IPI */
-       stwcix  r3, r5, r7              /* EOI it */
-37:    sync
 
        /* increment the nap count and then go to nap mode */
        ld      r4, HSTATE_KVM_VCORE(r13)
@@ -253,6 +295,7 @@ kvm_start_guest:
 kvm_no_guest:
        li      r0, KVM_HWTHREAD_IN_NAP
        stb     r0, HSTATE_HWTHREAD_STATE(r13)
+kvm_do_nap:
        li      r3, LPCR_PECE0
        mfspr   r4, SPRN_LPCR
        rlwimi  r4, r3, 0, LPCR_PECE0 | LPCR_PECE1
@@ -277,7 +320,7 @@ kvmppc_hv_entry:
 
        /* Required state:
         *
-        * R4 = vcpu pointer
+        * R4 = vcpu pointer (or NULL)
         * MSR = ~IR|DR
         * R13 = PACA
         * R1 = host R1
@@ -287,122 +330,12 @@ kvmppc_hv_entry:
        std     r0, PPC_LR_STKOFF(r1)
        stdu    r1, -112(r1)
 
-       /* Set partition DABR */
-       /* Do this before re-enabling PMU to avoid P7 DABR corruption bug */
-       li      r5,3
-       ld      r6,VCPU_DABR(r4)
-       mtspr   SPRN_DABRX,r5
-       mtspr   SPRN_DABR,r6
-BEGIN_FTR_SECTION
-       isync
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-
-       /* Load guest PMU registers */
-       /* R4 is live here (vcpu pointer) */
-       li      r3, 1
-       sldi    r3, r3, 31              /* MMCR0_FC (freeze counters) bit */
-       mtspr   SPRN_MMCR0, r3          /* freeze all counters, disable ints */
-       isync
-       lwz     r3, VCPU_PMC(r4)        /* always load up guest PMU registers */
-       lwz     r5, VCPU_PMC + 4(r4)    /* to prevent information leak */
-       lwz     r6, VCPU_PMC + 8(r4)
-       lwz     r7, VCPU_PMC + 12(r4)
-       lwz     r8, VCPU_PMC + 16(r4)
-       lwz     r9, VCPU_PMC + 20(r4)
-BEGIN_FTR_SECTION
-       lwz     r10, VCPU_PMC + 24(r4)
-       lwz     r11, VCPU_PMC + 28(r4)
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
-       mtspr   SPRN_PMC1, r3
-       mtspr   SPRN_PMC2, r5
-       mtspr   SPRN_PMC3, r6
-       mtspr   SPRN_PMC4, r7
-       mtspr   SPRN_PMC5, r8
-       mtspr   SPRN_PMC6, r9
-BEGIN_FTR_SECTION
-       mtspr   SPRN_PMC7, r10
-       mtspr   SPRN_PMC8, r11
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
-       ld      r3, VCPU_MMCR(r4)
-       ld      r5, VCPU_MMCR + 8(r4)
-       ld      r6, VCPU_MMCR + 16(r4)
-       ld      r7, VCPU_SIAR(r4)
-       ld      r8, VCPU_SDAR(r4)
-       mtspr   SPRN_MMCR1, r5
-       mtspr   SPRN_MMCRA, r6
-       mtspr   SPRN_SIAR, r7
-       mtspr   SPRN_SDAR, r8
-       mtspr   SPRN_MMCR0, r3
-       isync
-
-       /* Load up FP, VMX and VSX registers */
-       bl      kvmppc_load_fp
-
-       ld      r14, VCPU_GPR(R14)(r4)
-       ld      r15, VCPU_GPR(R15)(r4)
-       ld      r16, VCPU_GPR(R16)(r4)
-       ld      r17, VCPU_GPR(R17)(r4)
-       ld      r18, VCPU_GPR(R18)(r4)
-       ld      r19, VCPU_GPR(R19)(r4)
-       ld      r20, VCPU_GPR(R20)(r4)
-       ld      r21, VCPU_GPR(R21)(r4)
-       ld      r22, VCPU_GPR(R22)(r4)
-       ld      r23, VCPU_GPR(R23)(r4)
-       ld      r24, VCPU_GPR(R24)(r4)
-       ld      r25, VCPU_GPR(R25)(r4)
-       ld      r26, VCPU_GPR(R26)(r4)
-       ld      r27, VCPU_GPR(R27)(r4)
-       ld      r28, VCPU_GPR(R28)(r4)
-       ld      r29, VCPU_GPR(R29)(r4)
-       ld      r30, VCPU_GPR(R30)(r4)
-       ld      r31, VCPU_GPR(R31)(r4)
-
-BEGIN_FTR_SECTION
-       /* Switch DSCR to guest value */
-       ld      r5, VCPU_DSCR(r4)
-       mtspr   SPRN_DSCR, r5
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-
-       /*
-        * Set the decrementer to the guest decrementer.
-        */
-       ld      r8,VCPU_DEC_EXPIRES(r4)
-       mftb    r7
-       subf    r3,r7,r8
-       mtspr   SPRN_DEC,r3
-       stw     r3,VCPU_DEC(r4)
-
-       ld      r5, VCPU_SPRG0(r4)
-       ld      r6, VCPU_SPRG1(r4)
-       ld      r7, VCPU_SPRG2(r4)
-       ld      r8, VCPU_SPRG3(r4)
-       mtspr   SPRN_SPRG0, r5
-       mtspr   SPRN_SPRG1, r6
-       mtspr   SPRN_SPRG2, r7
-       mtspr   SPRN_SPRG3, r8
-
        /* Save R1 in the PACA */
        std     r1, HSTATE_HOST_R1(r13)
 
-       /* Load up DAR and DSISR */
-       ld      r5, VCPU_DAR(r4)
-       lwz     r6, VCPU_DSISR(r4)
-       mtspr   SPRN_DAR, r5
-       mtspr   SPRN_DSISR, r6
-
        li      r6, KVM_GUEST_MODE_HOST_HV
        stb     r6, HSTATE_IN_GUEST(r13)
 
-BEGIN_FTR_SECTION
-       /* Restore AMR and UAMOR, set AMOR to all 1s */
-       ld      r5,VCPU_AMR(r4)
-       ld      r6,VCPU_UAMOR(r4)
-       li      r7,-1
-       mtspr   SPRN_AMR,r5
-       mtspr   SPRN_UAMOR,r6
-       mtspr   SPRN_AMOR,r7
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-
        /* Clear out SLB */
        li      r6,0
        slbmte  r6,r6
@@ -428,8 +361,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        bne     21b
 
        /* Primary thread switches to guest partition. */
-       ld      r9,VCPU_KVM(r4)         /* pointer to struct kvm */
-       lwz     r6,VCPU_PTID(r4)
+       ld      r9,VCORE_KVM(r5)        /* pointer to struct kvm */
+       lbz     r6,HSTATE_PTID(r13)
        cmpwi   r6,0
        bne     20f
        ld      r6,KVM_SDR1(r9)
@@ -457,7 +390,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        andc    r7,r7,r0
        stdcx.  r7,0,r6
        bne     23b
-       li      r6,128                  /* and flush the TLB */
+       /* Flush the TLB of any entries for this LPID */
+       /* use arch 2.07S as a proxy for POWER8 */
+BEGIN_FTR_SECTION
+       li      r6,512                  /* POWER8 has 512 sets */
+FTR_SECTION_ELSE
+       li      r6,128                  /* POWER7 has 128 sets */
+ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_207S)
        mtctr   r6
        li      r7,0x800                /* IS field = 0b10 */
        ptesync
@@ -487,6 +426,13 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        beq     38f
        mtspr   SPRN_PCR, r7
 38:
+
+BEGIN_FTR_SECTION
+       /* DPDES is shared between threads */
+       ld      r8, VCORE_DPDES(r5)
+       mtspr   SPRN_DPDES, r8
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+
        li      r0,1
        stb     r0,VCORE_IN_GUEST(r5)   /* signal secondaries to continue */
        b       10f
@@ -503,32 +449,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        mtspr   SPRN_RMOR,r8
        isync
 
-       /* Increment yield count if they have a VPA */
-       ld      r3, VCPU_VPA(r4)
-       cmpdi   r3, 0
-       beq     25f
-       lwz     r5, LPPACA_YIELDCOUNT(r3)
-       addi    r5, r5, 1
-       stw     r5, LPPACA_YIELDCOUNT(r3)
-       li      r6, 1
-       stb     r6, VCPU_VPA_DIRTY(r4)
-25:
        /* Check if HDEC expires soon */
        mfspr   r3,SPRN_HDEC
-       cmpwi   r3,10
+       cmpwi   r3,512          /* 1 microsecond */
        li      r12,BOOK3S_INTERRUPT_HV_DECREMENTER
-       mr      r9,r4
        blt     hdec_soon
-
-       /* Save purr/spurr */
-       mfspr   r5,SPRN_PURR
-       mfspr   r6,SPRN_SPURR
-       std     r5,HSTATE_PURR(r13)
-       std     r6,HSTATE_SPURR(r13)
-       ld      r7,VCPU_PURR(r4)
-       ld      r8,VCPU_SPURR(r4)
-       mtspr   SPRN_PURR,r7
-       mtspr   SPRN_SPURR,r8
        b       31f
 
        /*
@@ -539,7 +464,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
         * We also have to invalidate the TLB since its
         * entries aren't tagged with the LPID.
         */
-30:    ld      r9,VCPU_KVM(r4)         /* pointer to struct kvm */
+30:    ld      r5,HSTATE_KVM_VCORE(r13)
+       ld      r9,VCORE_KVM(r5)        /* pointer to struct kvm */
 
        /* first take native_tlbie_lock */
        .section ".toc","aw"
@@ -604,7 +530,6 @@ toc_tlbie_lock:
        mfspr   r3,SPRN_HDEC
        cmpwi   r3,10
        li      r12,BOOK3S_INTERRUPT_HV_DECREMENTER
-       mr      r9,r4
        blt     hdec_soon
 
        /* Enable HDEC interrupts */
@@ -619,9 +544,14 @@ toc_tlbie_lock:
        mfspr   r0,SPRN_HID0
        mfspr   r0,SPRN_HID0
        mfspr   r0,SPRN_HID0
+31:
+       /* Do we have a guest vcpu to run? */
+       cmpdi   r4, 0
+       beq     kvmppc_primary_no_guest
+kvmppc_got_guest:
 
        /* Load up guest SLB entries */
-31:    lwz     r5,VCPU_SLB_MAX(r4)
+       lwz     r5,VCPU_SLB_MAX(r4)
        cmpwi   r5,0
        beq     9f
        mtctr   r5
@@ -632,6 +562,209 @@ toc_tlbie_lock:
        addi    r6,r6,VCPU_SLB_SIZE
        bdnz    1b
 9:
+       /* Increment yield count if they have a VPA */
+       ld      r3, VCPU_VPA(r4)
+       cmpdi   r3, 0
+       beq     25f
+       lwz     r5, LPPACA_YIELDCOUNT(r3)
+       addi    r5, r5, 1
+       stw     r5, LPPACA_YIELDCOUNT(r3)
+       li      r6, 1
+       stb     r6, VCPU_VPA_DIRTY(r4)
+25:
+
+BEGIN_FTR_SECTION
+       /* Save purr/spurr */
+       mfspr   r5,SPRN_PURR
+       mfspr   r6,SPRN_SPURR
+       std     r5,HSTATE_PURR(r13)
+       std     r6,HSTATE_SPURR(r13)
+       ld      r7,VCPU_PURR(r4)
+       ld      r8,VCPU_SPURR(r4)
+       mtspr   SPRN_PURR,r7
+       mtspr   SPRN_SPURR,r8
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+
+BEGIN_FTR_SECTION
+       /* Set partition DABR */
+       /* Do this before re-enabling PMU to avoid P7 DABR corruption bug */
+       lwz     r5,VCPU_DABRX(r4)
+       ld      r6,VCPU_DABR(r4)
+       mtspr   SPRN_DABRX,r5
+       mtspr   SPRN_DABR,r6
+ BEGIN_FTR_SECTION_NESTED(89)
+       isync
+ END_FTR_SECTION_NESTED(CPU_FTR_ARCH_206, CPU_FTR_ARCH_206, 89)
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
+
+       /* Load guest PMU registers */
+       /* R4 is live here (vcpu pointer) */
+       li      r3, 1
+       sldi    r3, r3, 31              /* MMCR0_FC (freeze counters) bit */
+       mtspr   SPRN_MMCR0, r3          /* freeze all counters, disable ints */
+       isync
+       lwz     r3, VCPU_PMC(r4)        /* always load up guest PMU registers */
+       lwz     r5, VCPU_PMC + 4(r4)    /* to prevent information leak */
+       lwz     r6, VCPU_PMC + 8(r4)
+       lwz     r7, VCPU_PMC + 12(r4)
+       lwz     r8, VCPU_PMC + 16(r4)
+       lwz     r9, VCPU_PMC + 20(r4)
+BEGIN_FTR_SECTION
+       lwz     r10, VCPU_PMC + 24(r4)
+       lwz     r11, VCPU_PMC + 28(r4)
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
+       mtspr   SPRN_PMC1, r3
+       mtspr   SPRN_PMC2, r5
+       mtspr   SPRN_PMC3, r6
+       mtspr   SPRN_PMC4, r7
+       mtspr   SPRN_PMC5, r8
+       mtspr   SPRN_PMC6, r9
+BEGIN_FTR_SECTION
+       mtspr   SPRN_PMC7, r10
+       mtspr   SPRN_PMC8, r11
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
+       ld      r3, VCPU_MMCR(r4)
+       ld      r5, VCPU_MMCR + 8(r4)
+       ld      r6, VCPU_MMCR + 16(r4)
+       ld      r7, VCPU_SIAR(r4)
+       ld      r8, VCPU_SDAR(r4)
+       mtspr   SPRN_MMCR1, r5
+       mtspr   SPRN_MMCRA, r6
+       mtspr   SPRN_SIAR, r7
+       mtspr   SPRN_SDAR, r8
+BEGIN_FTR_SECTION
+       ld      r5, VCPU_MMCR + 24(r4)
+       ld      r6, VCPU_SIER(r4)
+       lwz     r7, VCPU_PMC + 24(r4)
+       lwz     r8, VCPU_PMC + 28(r4)
+       ld      r9, VCPU_MMCR + 32(r4)
+       mtspr   SPRN_MMCR2, r5
+       mtspr   SPRN_SIER, r6
+       mtspr   SPRN_SPMC1, r7
+       mtspr   SPRN_SPMC2, r8
+       mtspr   SPRN_MMCRS, r9
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+       mtspr   SPRN_MMCR0, r3
+       isync
+
+       /* Load up FP, VMX and VSX registers */
+       bl      kvmppc_load_fp
+
+       ld      r14, VCPU_GPR(R14)(r4)
+       ld      r15, VCPU_GPR(R15)(r4)
+       ld      r16, VCPU_GPR(R16)(r4)
+       ld      r17, VCPU_GPR(R17)(r4)
+       ld      r18, VCPU_GPR(R18)(r4)
+       ld      r19, VCPU_GPR(R19)(r4)
+       ld      r20, VCPU_GPR(R20)(r4)
+       ld      r21, VCPU_GPR(R21)(r4)
+       ld      r22, VCPU_GPR(R22)(r4)
+       ld      r23, VCPU_GPR(R23)(r4)
+       ld      r24, VCPU_GPR(R24)(r4)
+       ld      r25, VCPU_GPR(R25)(r4)
+       ld      r26, VCPU_GPR(R26)(r4)
+       ld      r27, VCPU_GPR(R27)(r4)
+       ld      r28, VCPU_GPR(R28)(r4)
+       ld      r29, VCPU_GPR(R29)(r4)
+       ld      r30, VCPU_GPR(R30)(r4)
+       ld      r31, VCPU_GPR(R31)(r4)
+
+BEGIN_FTR_SECTION
+       /* Switch DSCR to guest value */
+       ld      r5, VCPU_DSCR(r4)
+       mtspr   SPRN_DSCR, r5
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+
+BEGIN_FTR_SECTION
+       /* Skip next section on POWER7 or PPC970 */
+       b       8f
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
+       /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
+       mfmsr   r8
+       li      r0, 1
+       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
+       mtmsrd  r8
+
+       /* Load up POWER8-specific registers */
+       ld      r5, VCPU_IAMR(r4)
+       lwz     r6, VCPU_PSPB(r4)
+       ld      r7, VCPU_FSCR(r4)
+       mtspr   SPRN_IAMR, r5
+       mtspr   SPRN_PSPB, r6
+       mtspr   SPRN_FSCR, r7
+       ld      r5, VCPU_DAWR(r4)
+       ld      r6, VCPU_DAWRX(r4)
+       ld      r7, VCPU_CIABR(r4)
+       ld      r8, VCPU_TAR(r4)
+       mtspr   SPRN_DAWR, r5
+       mtspr   SPRN_DAWRX, r6
+       mtspr   SPRN_CIABR, r7
+       mtspr   SPRN_TAR, r8
+       ld      r5, VCPU_IC(r4)
+       ld      r6, VCPU_VTB(r4)
+       mtspr   SPRN_IC, r5
+       mtspr   SPRN_VTB, r6
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       ld      r5, VCPU_TFHAR(r4)
+       ld      r6, VCPU_TFIAR(r4)
+       ld      r7, VCPU_TEXASR(r4)
+       mtspr   SPRN_TFHAR, r5
+       mtspr   SPRN_TFIAR, r6
+       mtspr   SPRN_TEXASR, r7
+#endif
+       ld      r8, VCPU_EBBHR(r4)
+       mtspr   SPRN_EBBHR, r8
+       ld      r5, VCPU_EBBRR(r4)
+       ld      r6, VCPU_BESCR(r4)
+       ld      r7, VCPU_CSIGR(r4)
+       ld      r8, VCPU_TACR(r4)
+       mtspr   SPRN_EBBRR, r5
+       mtspr   SPRN_BESCR, r6
+       mtspr   SPRN_CSIGR, r7
+       mtspr   SPRN_TACR, r8
+       ld      r5, VCPU_TCSCR(r4)
+       ld      r6, VCPU_ACOP(r4)
+       lwz     r7, VCPU_GUEST_PID(r4)
+       ld      r8, VCPU_WORT(r4)
+       mtspr   SPRN_TCSCR, r5
+       mtspr   SPRN_ACOP, r6
+       mtspr   SPRN_PID, r7
+       mtspr   SPRN_WORT, r8
+8:
+
+       /*
+        * Set the decrementer to the guest decrementer.
+        */
+       ld      r8,VCPU_DEC_EXPIRES(r4)
+       mftb    r7
+       subf    r3,r7,r8
+       mtspr   SPRN_DEC,r3
+       stw     r3,VCPU_DEC(r4)
+
+       ld      r5, VCPU_SPRG0(r4)
+       ld      r6, VCPU_SPRG1(r4)
+       ld      r7, VCPU_SPRG2(r4)
+       ld      r8, VCPU_SPRG3(r4)
+       mtspr   SPRN_SPRG0, r5
+       mtspr   SPRN_SPRG1, r6
+       mtspr   SPRN_SPRG2, r7
+       mtspr   SPRN_SPRG3, r8
+
+       /* Load up DAR and DSISR */
+       ld      r5, VCPU_DAR(r4)
+       lwz     r6, VCPU_DSISR(r4)
+       mtspr   SPRN_DAR, r5
+       mtspr   SPRN_DSISR, r6
+
+BEGIN_FTR_SECTION
+       /* Restore AMR and UAMOR, set AMOR to all 1s */
+       ld      r5,VCPU_AMR(r4)
+       ld      r6,VCPU_UAMOR(r4)
+       li      r7,-1
+       mtspr   SPRN_AMR,r5
+       mtspr   SPRN_UAMOR,r6
+       mtspr   SPRN_AMOR,r7
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
 
        /* Restore state of CTRL run bit; assume 1 on entry */
        lwz     r5,VCPU_CTRL(r4)
@@ -647,48 +780,53 @@ toc_tlbie_lock:
        mtctr   r6
        mtxer   r7
 
+kvmppc_cede_reentry:           /* r4 = vcpu, r13 = paca */
        ld      r10, VCPU_PC(r4)
        ld      r11, VCPU_MSR(r4)
-kvmppc_cede_reentry:           /* r4 = vcpu, r13 = paca */
        ld      r6, VCPU_SRR0(r4)
        ld      r7, VCPU_SRR1(r4)
+       mtspr   SPRN_SRR0, r6
+       mtspr   SPRN_SRR1, r7
 
+deliver_guest_interrupt:
        /* r11 = vcpu->arch.msr & ~MSR_HV */
        rldicl  r11, r11, 63 - MSR_HV_LG, 1
        rotldi  r11, r11, 1 + MSR_HV_LG
        ori     r11, r11, MSR_ME
 
        /* Check if we can deliver an external or decrementer interrupt now */
-       ld      r0,VCPU_PENDING_EXC(r4)
-       lis     r8,(1 << BOOK3S_IRQPRIO_EXTERNAL_LEVEL)@h
-       and     r0,r0,r8
-       cmpdi   cr1,r0,0
-       andi.   r0,r11,MSR_EE
-       beq     cr1,11f
+       ld      r0, VCPU_PENDING_EXC(r4)
+       rldicl  r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63
+       cmpdi   cr1, r0, 0
+       andi.   r8, r11, MSR_EE
 BEGIN_FTR_SECTION
-       mfspr   r8,SPRN_LPCR
-       ori     r8,r8,LPCR_MER
-       mtspr   SPRN_LPCR,r8
+       mfspr   r8, SPRN_LPCR
+       /* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */
+       rldimi  r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH
+       mtspr   SPRN_LPCR, r8
        isync
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
        beq     5f
-       li      r0,BOOK3S_INTERRUPT_EXTERNAL
-12:    mr      r6,r10
-       mr      r10,r0
-       mr      r7,r11
-       li      r11,(MSR_ME << 1) | 1   /* synthesize MSR_SF | MSR_ME */
-       rotldi  r11,r11,63
-       b       5f
-11:    beq     5f
-       mfspr   r0,SPRN_DEC
-       cmpwi   r0,0
-       li      r0,BOOK3S_INTERRUPT_DECREMENTER
-       blt     12b
+       li      r0, BOOK3S_INTERRUPT_EXTERNAL
+       bne     cr1, 12f
+       mfspr   r0, SPRN_DEC
+       cmpwi   r0, 0
+       li      r0, BOOK3S_INTERRUPT_DECREMENTER
+       bge     5f
 
-       /* Move SRR0 and SRR1 into the respective regs */
-5:     mtspr   SPRN_SRR0, r6
-       mtspr   SPRN_SRR1, r7
+12:    mtspr   SPRN_SRR0, r10
+       mr      r10,r0
+       mtspr   SPRN_SRR1, r11
+       ld      r11, VCPU_INTR_MSR(r4)
+5:
 
+/*
+ * Required state:
+ * R4 = vcpu
+ * R10: value for HSRR0
+ * R11: value for HSRR1
+ * R13 = PACA
+ */
 fast_guest_return:
        li      r0,0
        stb     r0,VCPU_CEDED(r4)       /* cancel cede */
@@ -868,39 +1006,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
        /* External interrupt, first check for host_ipi. If this is
         * set, we know the host wants us out so let's do it now
         */
-do_ext_interrupt:
        bl      kvmppc_read_intr
        cmpdi   r3, 0
        bgt     ext_interrupt_to_host
 
-       /* Allright, looks like an IPI for the guest, we need to set MER */
        /* Check if any CPU is heading out to the host, if so head out too */
        ld      r5, HSTATE_KVM_VCORE(r13)
        lwz     r0, VCORE_ENTRY_EXIT(r5)
        cmpwi   r0, 0x100
        bge     ext_interrupt_to_host
 
-       /* See if there is a pending interrupt for the guest */
-       mfspr   r8, SPRN_LPCR
-       ld      r0, VCPU_PENDING_EXC(r9)
-       /* Insert EXTERNAL_LEVEL bit into LPCR at the MER bit position */
-       rldicl. r0, r0, 64 - BOOK3S_IRQPRIO_EXTERNAL_LEVEL, 63
-       rldimi  r8, r0, LPCR_MER_SH, 63 - LPCR_MER_SH
-       beq     2f
-
-       /* And if the guest EE is set, we can deliver immediately, else
-        * we return to the guest with MER set
-        */
-       andi.   r0, r11, MSR_EE
-       beq     2f
-       mtspr   SPRN_SRR0, r10
-       mtspr   SPRN_SRR1, r11
-       li      r10, BOOK3S_INTERRUPT_EXTERNAL
-       li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
-       rotldi  r11, r11, 63
-2:     mr      r4, r9
-       mtspr   SPRN_LPCR, r8
-       b       fast_guest_return
+       /* Return to guest after delivering any pending interrupt */
+       mr      r4, r9
+       b       deliver_guest_interrupt
 
 ext_interrupt_to_host:
 
@@ -963,25 +1081,206 @@ BEGIN_FTR_SECTION
        subf    r5,r7,r5
        subf    r6,r8,r6
 
-       /*
-        * Restore host PURR/SPURR and add guest times
-        * so that the time in the guest gets accounted.
-        */
-       ld      r3,HSTATE_PURR(r13)
-       ld      r4,HSTATE_SPURR(r13)
-       add     r3,r3,r5
-       add     r4,r4,r6
-       mtspr   SPRN_PURR,r3
-       mtspr   SPRN_SPURR,r4
-END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_201)
+       /*
+        * Restore host PURR/SPURR and add guest times
+        * so that the time in the guest gets accounted.
+        */
+       ld      r3,HSTATE_PURR(r13)
+       ld      r4,HSTATE_SPURR(r13)
+       add     r3,r3,r5
+       add     r4,r4,r6
+       mtspr   SPRN_PURR,r3
+       mtspr   SPRN_SPURR,r4
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_201)
+
+       /* Save DEC */
+       mfspr   r5,SPRN_DEC
+       mftb    r6
+       extsw   r5,r5
+       add     r5,r5,r6
+       std     r5,VCPU_DEC_EXPIRES(r9)
+
+BEGIN_FTR_SECTION
+       b       8f
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
+       /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
+       mfmsr   r8
+       li      r0, 1
+       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
+       mtmsrd  r8
+
+       /* Save POWER8-specific registers */
+       mfspr   r5, SPRN_IAMR
+       mfspr   r6, SPRN_PSPB
+       mfspr   r7, SPRN_FSCR
+       std     r5, VCPU_IAMR(r9)
+       stw     r6, VCPU_PSPB(r9)
+       std     r7, VCPU_FSCR(r9)
+       mfspr   r5, SPRN_IC
+       mfspr   r6, SPRN_VTB
+       mfspr   r7, SPRN_TAR
+       std     r5, VCPU_IC(r9)
+       std     r6, VCPU_VTB(r9)
+       std     r7, VCPU_TAR(r9)
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       mfspr   r5, SPRN_TFHAR
+       mfspr   r6, SPRN_TFIAR
+       mfspr   r7, SPRN_TEXASR
+       std     r5, VCPU_TFHAR(r9)
+       std     r6, VCPU_TFIAR(r9)
+       std     r7, VCPU_TEXASR(r9)
+#endif
+       mfspr   r8, SPRN_EBBHR
+       std     r8, VCPU_EBBHR(r9)
+       mfspr   r5, SPRN_EBBRR
+       mfspr   r6, SPRN_BESCR
+       mfspr   r7, SPRN_CSIGR
+       mfspr   r8, SPRN_TACR
+       std     r5, VCPU_EBBRR(r9)
+       std     r6, VCPU_BESCR(r9)
+       std     r7, VCPU_CSIGR(r9)
+       std     r8, VCPU_TACR(r9)
+       mfspr   r5, SPRN_TCSCR
+       mfspr   r6, SPRN_ACOP
+       mfspr   r7, SPRN_PID
+       mfspr   r8, SPRN_WORT
+       std     r5, VCPU_TCSCR(r9)
+       std     r6, VCPU_ACOP(r9)
+       stw     r7, VCPU_GUEST_PID(r9)
+       std     r8, VCPU_WORT(r9)
+8:
+
+       /* Save and reset AMR and UAMOR before turning on the MMU */
+BEGIN_FTR_SECTION
+       mfspr   r5,SPRN_AMR
+       mfspr   r6,SPRN_UAMOR
+       std     r5,VCPU_AMR(r9)
+       std     r6,VCPU_UAMOR(r9)
+       li      r6,0
+       mtspr   SPRN_AMR,r6
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+
+       /* Switch DSCR back to host value */
+BEGIN_FTR_SECTION
+       mfspr   r8, SPRN_DSCR
+       ld      r7, HSTATE_DSCR(r13)
+       std     r8, VCPU_DSCR(r9)
+       mtspr   SPRN_DSCR, r7
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+
+       /* Save non-volatile GPRs */
+       std     r14, VCPU_GPR(R14)(r9)
+       std     r15, VCPU_GPR(R15)(r9)
+       std     r16, VCPU_GPR(R16)(r9)
+       std     r17, VCPU_GPR(R17)(r9)
+       std     r18, VCPU_GPR(R18)(r9)
+       std     r19, VCPU_GPR(R19)(r9)
+       std     r20, VCPU_GPR(R20)(r9)
+       std     r21, VCPU_GPR(R21)(r9)
+       std     r22, VCPU_GPR(R22)(r9)
+       std     r23, VCPU_GPR(R23)(r9)
+       std     r24, VCPU_GPR(R24)(r9)
+       std     r25, VCPU_GPR(R25)(r9)
+       std     r26, VCPU_GPR(R26)(r9)
+       std     r27, VCPU_GPR(R27)(r9)
+       std     r28, VCPU_GPR(R28)(r9)
+       std     r29, VCPU_GPR(R29)(r9)
+       std     r30, VCPU_GPR(R30)(r9)
+       std     r31, VCPU_GPR(R31)(r9)
+
+       /* Save SPRGs */
+       mfspr   r3, SPRN_SPRG0
+       mfspr   r4, SPRN_SPRG1
+       mfspr   r5, SPRN_SPRG2
+       mfspr   r6, SPRN_SPRG3
+       std     r3, VCPU_SPRG0(r9)
+       std     r4, VCPU_SPRG1(r9)
+       std     r5, VCPU_SPRG2(r9)
+       std     r6, VCPU_SPRG3(r9)
+
+       /* save FP state */
+       mr      r3, r9
+       bl      kvmppc_save_fp
 
+       /* Increment yield count if they have a VPA */
+       ld      r8, VCPU_VPA(r9)        /* do they have a VPA? */
+       cmpdi   r8, 0
+       beq     25f
+       lwz     r3, LPPACA_YIELDCOUNT(r8)
+       addi    r3, r3, 1
+       stw     r3, LPPACA_YIELDCOUNT(r8)
+       li      r3, 1
+       stb     r3, VCPU_VPA_DIRTY(r9)
+25:
+       /* Save PMU registers if requested */
+       /* r8 and cr0.eq are live here */
+       li      r3, 1
+       sldi    r3, r3, 31              /* MMCR0_FC (freeze counters) bit */
+       mfspr   r4, SPRN_MMCR0          /* save MMCR0 */
+       mtspr   SPRN_MMCR0, r3          /* freeze all counters, disable ints */
+       mfspr   r6, SPRN_MMCRA
+BEGIN_FTR_SECTION
+       /* On P7, clear MMCRA in order to disable SDAR updates */
+       li      r7, 0
+       mtspr   SPRN_MMCRA, r7
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
+       isync
+       beq     21f                     /* if no VPA, save PMU stuff anyway */
+       lbz     r7, LPPACA_PMCINUSE(r8)
+       cmpwi   r7, 0                   /* did they ask for PMU stuff to be saved? */
+       bne     21f
+       std     r3, VCPU_MMCR(r9)       /* if not, set saved MMCR0 to FC */
+       b       22f
+21:    mfspr   r5, SPRN_MMCR1
+       mfspr   r7, SPRN_SIAR
+       mfspr   r8, SPRN_SDAR
+       std     r4, VCPU_MMCR(r9)
+       std     r5, VCPU_MMCR + 8(r9)
+       std     r6, VCPU_MMCR + 16(r9)
+       std     r7, VCPU_SIAR(r9)
+       std     r8, VCPU_SDAR(r9)
+       mfspr   r3, SPRN_PMC1
+       mfspr   r4, SPRN_PMC2
+       mfspr   r5, SPRN_PMC3
+       mfspr   r6, SPRN_PMC4
+       mfspr   r7, SPRN_PMC5
+       mfspr   r8, SPRN_PMC6
+BEGIN_FTR_SECTION
+       mfspr   r10, SPRN_PMC7
+       mfspr   r11, SPRN_PMC8
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
+       stw     r3, VCPU_PMC(r9)
+       stw     r4, VCPU_PMC + 4(r9)
+       stw     r5, VCPU_PMC + 8(r9)
+       stw     r6, VCPU_PMC + 12(r9)
+       stw     r7, VCPU_PMC + 16(r9)
+       stw     r8, VCPU_PMC + 20(r9)
+BEGIN_FTR_SECTION
+       stw     r10, VCPU_PMC + 24(r9)
+       stw     r11, VCPU_PMC + 28(r9)
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
+BEGIN_FTR_SECTION
+       mfspr   r4, SPRN_MMCR2
+       mfspr   r5, SPRN_SIER
+       mfspr   r6, SPRN_SPMC1
+       mfspr   r7, SPRN_SPMC2
+       mfspr   r8, SPRN_MMCRS
+       std     r4, VCPU_MMCR + 24(r9)
+       std     r5, VCPU_SIER(r9)
+       stw     r6, VCPU_PMC + 24(r9)
+       stw     r7, VCPU_PMC + 28(r9)
+       std     r8, VCPU_MMCR + 32(r9)
+       lis     r4, 0x8000
+       mtspr   SPRN_MMCRS, r4
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+22:
        /* Clear out SLB */
        li      r5,0
        slbmte  r5,r5
        slbia
        ptesync
 
-hdec_soon:                     /* r9 = vcpu, r12 = trap, r13 = paca */
+hdec_soon:                     /* r12 = trap, r13 = paca */
 BEGIN_FTR_SECTION
        b       32f
 END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
@@ -1014,8 +1313,6 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
         */
        cmpwi   r3,0x100        /* Are we the first here? */
        bge     43f
-       cmpwi   r3,1            /* Are any other threads in the guest? */
-       ble     43f
        cmpwi   r12,BOOK3S_INTERRUPT_HV_DECREMENTER
        beq     40f
        li      r0,0
@@ -1026,7 +1323,7 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
         * doesn't wake CPUs up from nap.
         */
        lwz     r3,VCORE_NAPPING_THREADS(r5)
-       lwz     r4,VCPU_PTID(r9)
+       lbz     r4,HSTATE_PTID(r13)
        li      r0,1
        sld     r0,r0,r4
        andc.   r3,r3,r0                /* no sense IPI'ing ourselves */
@@ -1045,10 +1342,11 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        addi    r6,r6,PACA_SIZE
        bne     42b
 
+secondary_too_late:
        /* Secondary threads wait for primary to do partition switch */
-43:    ld      r4,VCPU_KVM(r9)         /* pointer to struct kvm */
-       ld      r5,HSTATE_KVM_VCORE(r13)
-       lwz     r3,VCPU_PTID(r9)
+43:    ld      r5,HSTATE_KVM_VCORE(r13)
+       ld      r4,VCORE_KVM(r5)        /* pointer to struct kvm */
+       lbz     r3,HSTATE_PTID(r13)
        cmpwi   r3,0
        beq     15f
        HMT_LOW
@@ -1076,6 +1374,15 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        mtspr   SPRN_LPID,r7
        isync
 
+BEGIN_FTR_SECTION
+       /* DPDES is shared between threads */
+       mfspr   r7, SPRN_DPDES
+       std     r7, VCORE_DPDES(r5)
+       /* clear DPDES so we don't get guest doorbells in the host */
+       li      r8, 0
+       mtspr   SPRN_DPDES, r8
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+
        /* Subtract timebase offset from timebase */
        ld      r8,VCORE_TB_OFFSET(r5)
        cmpdi   r8,0
@@ -1113,7 +1420,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
         * We have to lock against concurrent tlbies, and
         * we have to flush the whole TLB.
         */
-32:    ld      r4,VCPU_KVM(r9)         /* pointer to struct kvm */
+32:    ld      r5,HSTATE_KVM_VCORE(r13)
+       ld      r4,VCORE_KVM(r5)        /* pointer to struct kvm */
 
        /* Take the guest's tlbie_lock */
 #ifdef __BIG_ENDIAN__
@@ -1203,6 +1511,56 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
        add     r5,r5,r6
        std     r5,VCPU_DEC_EXPIRES(r9)
 
+BEGIN_FTR_SECTION
+       b       8f
+END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_207S)
+       /* Turn on TM so we can access TFHAR/TFIAR/TEXASR */
+       mfmsr   r8
+       li      r0, 1
+       rldimi  r8, r0, MSR_TM_LG, 63-MSR_TM_LG
+       mtmsrd  r8
+
+       /* Save POWER8-specific registers */
+       mfspr   r5, SPRN_IAMR
+       mfspr   r6, SPRN_PSPB
+       mfspr   r7, SPRN_FSCR
+       std     r5, VCPU_IAMR(r9)
+       stw     r6, VCPU_PSPB(r9)
+       std     r7, VCPU_FSCR(r9)
+       mfspr   r5, SPRN_IC
+       mfspr   r6, SPRN_VTB
+       mfspr   r7, SPRN_TAR
+       std     r5, VCPU_IC(r9)
+       std     r6, VCPU_VTB(r9)
+       std     r7, VCPU_TAR(r9)
+#ifdef CONFIG_PPC_TRANSACTIONAL_MEM
+       mfspr   r5, SPRN_TFHAR
+       mfspr   r6, SPRN_TFIAR
+       mfspr   r7, SPRN_TEXASR
+       std     r5, VCPU_TFHAR(r9)
+       std     r6, VCPU_TFIAR(r9)
+       std     r7, VCPU_TEXASR(r9)
+#endif
+       mfspr   r8, SPRN_EBBHR
+       std     r8, VCPU_EBBHR(r9)
+       mfspr   r5, SPRN_EBBRR
+       mfspr   r6, SPRN_BESCR
+       mfspr   r7, SPRN_CSIGR
+       mfspr   r8, SPRN_TACR
+       std     r5, VCPU_EBBRR(r9)
+       std     r6, VCPU_BESCR(r9)
+       std     r7, VCPU_CSIGR(r9)
+       std     r8, VCPU_TACR(r9)
+       mfspr   r5, SPRN_TCSCR
+       mfspr   r6, SPRN_ACOP
+       mfspr   r7, SPRN_PID
+       mfspr   r8, SPRN_WORT
+       std     r5, VCPU_TCSCR(r9)
+       std     r6, VCPU_ACOP(r9)
+       stw     r7, VCPU_GUEST_PID(r9)
+       std     r8, VCPU_WORT(r9)
+8:
+
        /* Save and reset AMR and UAMOR before turning on the MMU */
 BEGIN_FTR_SECTION
        mfspr   r5,SPRN_AMR
@@ -1217,130 +1575,10 @@ END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
        li      r0, KVM_GUEST_MODE_NONE
        stb     r0, HSTATE_IN_GUEST(r13)
 
-       /* Switch DSCR back to host value */
-BEGIN_FTR_SECTION
-       mfspr   r8, SPRN_DSCR
-       ld      r7, HSTATE_DSCR(r13)
-       std     r8, VCPU_DSCR(r9)
-       mtspr   SPRN_DSCR, r7
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-
-       /* Save non-volatile GPRs */
-       std     r14, VCPU_GPR(R14)(r9)
-       std     r15, VCPU_GPR(R15)(r9)
-       std     r16, VCPU_GPR(R16)(r9)
-       std     r17, VCPU_GPR(R17)(r9)
-       std     r18, VCPU_GPR(R18)(r9)
-       std     r19, VCPU_GPR(R19)(r9)
-       std     r20, VCPU_GPR(R20)(r9)
-       std     r21, VCPU_GPR(R21)(r9)
-       std     r22, VCPU_GPR(R22)(r9)
-       std     r23, VCPU_GPR(R23)(r9)
-       std     r24, VCPU_GPR(R24)(r9)
-       std     r25, VCPU_GPR(R25)(r9)
-       std     r26, VCPU_GPR(R26)(r9)
-       std     r27, VCPU_GPR(R27)(r9)
-       std     r28, VCPU_GPR(R28)(r9)
-       std     r29, VCPU_GPR(R29)(r9)
-       std     r30, VCPU_GPR(R30)(r9)
-       std     r31, VCPU_GPR(R31)(r9)
-
-       /* Save SPRGs */
-       mfspr   r3, SPRN_SPRG0
-       mfspr   r4, SPRN_SPRG1
-       mfspr   r5, SPRN_SPRG2
-       mfspr   r6, SPRN_SPRG3
-       std     r3, VCPU_SPRG0(r9)
-       std     r4, VCPU_SPRG1(r9)
-       std     r5, VCPU_SPRG2(r9)
-       std     r6, VCPU_SPRG3(r9)
-
-       /* save FP state */
-       mr      r3, r9
-       bl      .kvmppc_save_fp
-
-       /* Increment yield count if they have a VPA */
-       ld      r8, VCPU_VPA(r9)        /* do they have a VPA? */
-       cmpdi   r8, 0
-       beq     25f
-       lwz     r3, LPPACA_YIELDCOUNT(r8)
-       addi    r3, r3, 1
-       stw     r3, LPPACA_YIELDCOUNT(r8)
-       li      r3, 1
-       stb     r3, VCPU_VPA_DIRTY(r9)
-25:
-       /* Save PMU registers if requested */
-       /* r8 and cr0.eq are live here */
-       li      r3, 1
-       sldi    r3, r3, 31              /* MMCR0_FC (freeze counters) bit */
-       mfspr   r4, SPRN_MMCR0          /* save MMCR0 */
-       mtspr   SPRN_MMCR0, r3          /* freeze all counters, disable ints */
-       mfspr   r6, SPRN_MMCRA
-BEGIN_FTR_SECTION
-       /* On P7, clear MMCRA in order to disable SDAR updates */
-       li      r7, 0
-       mtspr   SPRN_MMCRA, r7
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_206)
-       isync
-       beq     21f                     /* if no VPA, save PMU stuff anyway */
-       lbz     r7, LPPACA_PMCINUSE(r8)
-       cmpwi   r7, 0                   /* did they ask for PMU stuff to be saved? */
-       bne     21f
-       std     r3, VCPU_MMCR(r9)       /* if not, set saved MMCR0 to FC */
-       b       22f
-21:    mfspr   r5, SPRN_MMCR1
-       mfspr   r7, SPRN_SIAR
-       mfspr   r8, SPRN_SDAR
-       std     r4, VCPU_MMCR(r9)
-       std     r5, VCPU_MMCR + 8(r9)
-       std     r6, VCPU_MMCR + 16(r9)
-       std     r7, VCPU_SIAR(r9)
-       std     r8, VCPU_SDAR(r9)
-       mfspr   r3, SPRN_PMC1
-       mfspr   r4, SPRN_PMC2
-       mfspr   r5, SPRN_PMC3
-       mfspr   r6, SPRN_PMC4
-       mfspr   r7, SPRN_PMC5
-       mfspr   r8, SPRN_PMC6
-BEGIN_FTR_SECTION
-       mfspr   r10, SPRN_PMC7
-       mfspr   r11, SPRN_PMC8
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
-       stw     r3, VCPU_PMC(r9)
-       stw     r4, VCPU_PMC + 4(r9)
-       stw     r5, VCPU_PMC + 8(r9)
-       stw     r6, VCPU_PMC + 12(r9)
-       stw     r7, VCPU_PMC + 16(r9)
-       stw     r8, VCPU_PMC + 20(r9)
-BEGIN_FTR_SECTION
-       stw     r10, VCPU_PMC + 24(r9)
-       stw     r11, VCPU_PMC + 28(r9)
-END_FTR_SECTION_IFSET(CPU_FTR_ARCH_201)
-22:
        ld      r0, 112+PPC_LR_STKOFF(r1)
        addi    r1, r1, 112
        mtlr    r0
        blr
-secondary_too_late:
-       ld      r5,HSTATE_KVM_VCORE(r13)
-       HMT_LOW
-13:    lbz     r3,VCORE_IN_GUEST(r5)
-       cmpwi   r3,0
-       bne     13b
-       HMT_MEDIUM
-       li      r0, KVM_GUEST_MODE_NONE
-       stb     r0, HSTATE_IN_GUEST(r13)
-       ld      r11,PACA_SLBSHADOWPTR(r13)
-
-       .rept   SLB_NUM_BOLTED
-       ld      r5,SLBSHADOW_SAVEAREA(r11)
-       ld      r6,SLBSHADOW_SAVEAREA+8(r11)
-       andis.  r7,r5,SLB_ESID_V@h
-       beq     1f
-       slbmte  r6,r5
-1:     addi    r11,r11,16
-       .endr
-       b       22b
 
 /*
  * Check whether an HDSI is an HPTE not found fault or something else.
@@ -1386,8 +1624,7 @@ kvmppc_hdsi:
        mtspr   SPRN_SRR0, r10
        mtspr   SPRN_SRR1, r11
        li      r10, BOOK3S_INTERRUPT_DATA_STORAGE
-       li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
-       rotldi  r11, r11, 63
+       ld      r11, VCPU_INTR_MSR(r9)
 fast_interrupt_c_return:
 6:     ld      r7, VCPU_CTR(r9)
        lwz     r8, VCPU_XER(r9)
@@ -1456,8 +1693,7 @@ kvmppc_hisi:
 1:     mtspr   SPRN_SRR0, r10
        mtspr   SPRN_SRR1, r11
        li      r10, BOOK3S_INTERRUPT_INST_STORAGE
-       li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
-       rotldi  r11, r11, 63
+       ld      r11, VCPU_INTR_MSR(r9)
        b       fast_interrupt_c_return
 
 3:     ld      r6, VCPU_KVM(r9)        /* not relocated, use VRMA */
@@ -1474,7 +1710,8 @@ kvmppc_hisi:
 hcall_try_real_mode:
        ld      r3,VCPU_GPR(R3)(r9)
        andi.   r0,r11,MSR_PR
-       bne     guest_exit_cont
+       /* sc 1 from userspace - reflect to guest syscall */
+       bne     sc_1_fast_return
        clrrdi  r3,r3,2
        cmpldi  r3,hcall_real_table_end - hcall_real_table
        bge     guest_exit_cont
@@ -1495,6 +1732,14 @@ hcall_try_real_mode:
        ld      r11,VCPU_MSR(r4)
        b       fast_guest_return
 
+sc_1_fast_return:
+       mtspr   SPRN_SRR0,r10
+       mtspr   SPRN_SRR1,r11
+       li      r10, BOOK3S_INTERRUPT_SYSCALL
+       ld      r11, VCPU_INTR_MSR(r9)
+       mr      r4,r9
+       b       fast_guest_return
+
        /* We've attempted a real mode hcall, but it's punted it back
         * to userspace.  We need to restore some clobbered volatiles
         * before resuming the pass-it-to-qemu path */
@@ -1588,14 +1833,34 @@ hcall_real_table:
        .long   0               /* 0x11c */
        .long   0               /* 0x120 */
        .long   .kvmppc_h_bulk_remove - hcall_real_table
+       .long   0               /* 0x128 */
+       .long   0               /* 0x12c */
+       .long   0               /* 0x130 */
+       .long   .kvmppc_h_set_xdabr - hcall_real_table
 hcall_real_table_end:
 
 ignore_hdec:
        mr      r4,r9
        b       fast_guest_return
 
+_GLOBAL(kvmppc_h_set_xdabr)
+       andi.   r0, r5, DABRX_USER | DABRX_KERNEL
+       beq     6f
+       li      r0, DABRX_USER | DABRX_KERNEL | DABRX_BTI
+       andc.   r0, r5, r0
+       beq     3f
+6:     li      r3, H_PARAMETER
+       blr
+
 _GLOBAL(kvmppc_h_set_dabr)
+       li      r5, DABRX_USER | DABRX_KERNEL
+3:
+BEGIN_FTR_SECTION
+       b       2f
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        std     r4,VCPU_DABR(r3)
+       stw     r5, VCPU_DABRX(r3)
+       mtspr   SPRN_DABRX, r5
        /* Work around P7 bug where DABR can get corrupted on mtspr */
 1:     mtspr   SPRN_DABR,r4
        mfspr   r5, SPRN_DABR
@@ -1605,6 +1870,17 @@ _GLOBAL(kvmppc_h_set_dabr)
        li      r3,0
        blr
 
+       /* Emulate H_SET_DABR/X on P8 for the sake of compat mode guests */
+2:     rlwimi  r5, r4, 5, DAWRX_DR | DAWRX_DW
+       rlwimi  r5, r4, 1, DAWRX_WT
+       clrrdi  r4, r4, 3
+       std     r4, VCPU_DAWR(r3)
+       std     r5, VCPU_DAWRX(r3)
+       mtspr   SPRN_DAWR, r4
+       mtspr   SPRN_DAWRX, r5
+       li      r3, 0
+       blr
+
 _GLOBAL(kvmppc_h_cede)
        ori     r11,r11,MSR_EE
        std     r11,VCPU_MSR(r3)
@@ -1628,7 +1904,7 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
         * up to the host.
         */
        ld      r5,HSTATE_KVM_VCORE(r13)
-       lwz     r6,VCPU_PTID(r3)
+       lbz     r6,HSTATE_PTID(r13)
        lwz     r8,VCORE_ENTRY_EXIT(r5)
        clrldi  r8,r8,56
        li      r0,1
@@ -1643,9 +1919,8 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
        bne     31b
        /* order napping_threads update vs testing entry_exit_count */
        isync
-       li      r0,1
+       li      r0,NAPPING_CEDE
        stb     r0,HSTATE_NAPPING(r13)
-       mr      r4,r3
        lwz     r7,VCORE_ENTRY_EXIT(r5)
        cmpwi   r7,0x100
        bge     33f             /* another thread already exiting */
@@ -1677,16 +1952,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
        std     r31, VCPU_GPR(R31)(r3)
 
        /* save FP state */
-       bl      .kvmppc_save_fp
+       bl      kvmppc_save_fp
 
        /*
-        * Take a nap until a decrementer or external interrupt occurs,
-        * with PECE1 (wake on decr) and PECE0 (wake on external) set in LPCR
+        * Take a nap until a decrementer or external or doobell interrupt
+        * occurs, with PECE1, PECE0 and PECEDP set in LPCR
         */
        li      r0,1
        stb     r0,HSTATE_HWTHREAD_REQ(r13)
        mfspr   r5,SPRN_LPCR
        ori     r5,r5,LPCR_PECE0 | LPCR_PECE1
+BEGIN_FTR_SECTION
+       oris    r5,r5,LPCR_PECEDP@h
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
        mtspr   SPRN_LPCR,r5
        isync
        li      r0, 0
@@ -1698,6 +1976,11 @@ END_FTR_SECTION_IFCLR(CPU_FTR_ARCH_206)
        nap
        b       .
 
+33:    mr      r4, r3
+       li      r3, 0
+       li      r12, 0
+       b       34f
+
 kvm_end_cede:
        /* get vcpu pointer */
        ld      r4, HSTATE_KVM_VCPU(r13)
@@ -1727,12 +2010,15 @@ kvm_end_cede:
        ld      r29, VCPU_GPR(R29)(r4)
        ld      r30, VCPU_GPR(R30)(r4)
        ld      r31, VCPU_GPR(R31)(r4)
+       /* Check the wake reason in SRR1 to see why we got here */
+       bl      kvmppc_check_wake_reason
 
        /* clear our bit in vcore->napping_threads */
-33:    ld      r5,HSTATE_KVM_VCORE(r13)
-       lwz     r3,VCPU_PTID(r4)
+34:    ld      r5,HSTATE_KVM_VCORE(r13)
+       lbz     r7,HSTATE_PTID(r13)
        li      r0,1
-       sld     r0,r0,r3
+       sld     r0,r0,r7
        addi    r6,r5,VCORE_NAPPING_THREADS
 32:    lwarx   r7,0,r6
        andc    r7,r7,r0
@@ -1741,23 +2027,18 @@ kvm_end_cede:
        li      r0,0
        stb     r0,HSTATE_NAPPING(r13)
 
-       /* Check the wake reason in SRR1 to see why we got here */
-       mfspr   r3, SPRN_SRR1
-       rlwinm  r3, r3, 44-31, 0x7      /* extract wake reason field */
-       cmpwi   r3, 4                   /* was it an external interrupt? */
-       li      r12, BOOK3S_INTERRUPT_EXTERNAL
+       /* See if the wake reason means we need to exit */
+       stw     r12, VCPU_TRAP(r4)
        mr      r9, r4
-       ld      r10, VCPU_PC(r9)
-       ld      r11, VCPU_MSR(r9)
-       beq     do_ext_interrupt        /* if so */
+       cmpdi   r3, 0
+       bgt     guest_exit_cont
 
        /* see if any other thread is already exiting */
        lwz     r0,VCORE_ENTRY_EXIT(r5)
        cmpwi   r0,0x100
-       blt     kvmppc_cede_reentry     /* if not go back to guest */
+       bge     guest_exit_cont
 
-       /* some threads are exiting, so go to the guest exit path */
-       b       hcall_real_fallback
+       b       kvmppc_cede_reentry     /* if not go back to guest */
 
        /* cede when already previously prodded case */
 kvm_cede_prodded:
@@ -1783,10 +2064,47 @@ machine_check_realmode:
        beq     mc_cont
        /* If not, deliver a machine check.  SRR0/1 are already set */
        li      r10, BOOK3S_INTERRUPT_MACHINE_CHECK
-       li      r11, (MSR_ME << 1) | 1  /* synthesize MSR_SF | MSR_ME */
-       rotldi  r11, r11, 63
+       ld      r11, VCPU_INTR_MSR(r9)
        b       fast_interrupt_c_return
 
+/*
+ * Check the reason we woke from nap, and take appropriate action.
+ * Returns:
+ *     0 if nothing needs to be done
+ *     1 if something happened that needs to be handled by the host
+ *     -1 if there was a guest wakeup (IPI)
+ *
+ * Also sets r12 to the interrupt vector for any interrupt that needs
+ * to be handled now by the host (0x500 for external interrupt), or zero.
+ */
+kvmppc_check_wake_reason:
+       mfspr   r6, SPRN_SRR1
+BEGIN_FTR_SECTION
+       rlwinm  r6, r6, 45-31, 0xf      /* extract wake reason field (P8) */
+FTR_SECTION_ELSE
+       rlwinm  r6, r6, 45-31, 0xe      /* P7 wake reason field is 3 bits */
+ALT_FTR_SECTION_END_IFSET(CPU_FTR_ARCH_207S)
+       cmpwi   r6, 8                   /* was it an external interrupt? */
+       li      r12, BOOK3S_INTERRUPT_EXTERNAL
+       beq     kvmppc_read_intr        /* if so, see what it was */
+       li      r3, 0
+       li      r12, 0
+       cmpwi   r6, 6                   /* was it the decrementer? */
+       beq     0f
+BEGIN_FTR_SECTION
+       cmpwi   r6, 5                   /* privileged doorbell? */
+       beq     0f
+       cmpwi   r6, 3                   /* hypervisor doorbell? */
+       beq     3f
+END_FTR_SECTION_IFSET(CPU_FTR_ARCH_207S)
+       li      r3, 1                   /* anything else, return 1 */
+0:     blr
+
+       /* hypervisor doorbell */
+3:     li      r12, BOOK3S_INTERRUPT_H_DOORBELL
+       li      r3, 1
+       blr
+
 /*
  * Determine what sort of external interrupt is pending (if any).
  * Returns:
@@ -1818,7 +2136,6 @@ kvmppc_read_intr:
         * interrupts directly to the guest
         */
        cmpwi   r3, XICS_IPI            /* if there is, is it an IPI? */
-       li      r3, 1
        bne     42f
 
        /* It's an IPI, clear the MFRR and EOI it */
@@ -1844,19 +2161,25 @@ kvmppc_read_intr:
         * before exit, it will be picked up by the host ICP driver
         */
        stw     r0, HSTATE_SAVED_XIRR(r13)
+       li      r3, 1
        b       1b
 
 43:    /* We raced with the host, we need to resend that IPI, bummer */
        li      r0, IPI_PRIORITY
        stbcix  r0, r6, r8              /* set the IPI */
        sync
+       li      r3, 1
        b       1b
 
 /*
  * Save away FP, VMX and VSX registers.
  * r3 = vcpu pointer
+ * N.B. r30 and r31 are volatile across this function,
+ * thus it is not callable from C.
  */
-_GLOBAL(kvmppc_save_fp)
+kvmppc_save_fp:
+       mflr    r30
+       mr      r31,r3
        mfmsr   r5
        ori     r8,r5,MSR_FP
 #ifdef CONFIG_ALTIVEC
@@ -1871,42 +2194,17 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
 #endif
        mtmsrd  r8
        isync
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
-       reg = 0
-       .rept   32
-       li      r6,reg*16+VCPU_VSRS
-       STXVD2X(reg,R6,R3)
-       reg = reg + 1
-       .endr
-FTR_SECTION_ELSE
-#endif
-       reg = 0
-       .rept   32
-       stfd    reg,reg*8+VCPU_FPRS(r3)
-       reg = reg + 1
-       .endr
-#ifdef CONFIG_VSX
-ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX)
-#endif
-       mffs    fr0
-       stfd    fr0,VCPU_FPSCR(r3)
-
+       addi    r3,r3,VCPU_FPRS
+       bl      .store_fp_state
 #ifdef CONFIG_ALTIVEC
 BEGIN_FTR_SECTION
-       reg = 0
-       .rept   32
-       li      r6,reg*16+VCPU_VRS
-       stvx    reg,r6,r3
-       reg = reg + 1
-       .endr
-       mfvscr  vr0
-       li      r6,VCPU_VSCR
-       stvx    vr0,r6,r3
+       addi    r3,r31,VCPU_VRS
+       bl      .store_vr_state
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
        mfspr   r6,SPRN_VRSAVE
        stw     r6,VCPU_VRSAVE(r3)
+       mtlr    r30
        mtmsrd  r5
        isync
        blr
@@ -1914,9 +2212,12 @@ END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 /*
  * Load up FP, VMX and VSX registers
  * r4 = vcpu pointer
+ * N.B. r30 and r31 are volatile across this function,
+ * thus it is not callable from C.
  */
-       .globl  kvmppc_load_fp
 kvmppc_load_fp:
+       mflr    r30
+       mr      r31,r4
        mfmsr   r9
        ori     r8,r9,MSR_FP
 #ifdef CONFIG_ALTIVEC
@@ -1931,42 +2232,18 @@ END_FTR_SECTION_IFSET(CPU_FTR_VSX)
 #endif
        mtmsrd  r8
        isync
-       lfd     fr0,VCPU_FPSCR(r4)
-       MTFSF_L(fr0)
-#ifdef CONFIG_VSX
-BEGIN_FTR_SECTION
-       reg = 0
-       .rept   32
-       li      r7,reg*16+VCPU_VSRS
-       LXVD2X(reg,R7,R4)
-       reg = reg + 1
-       .endr
-FTR_SECTION_ELSE
-#endif
-       reg = 0
-       .rept   32
-       lfd     reg,reg*8+VCPU_FPRS(r4)
-       reg = reg + 1
-       .endr
-#ifdef CONFIG_VSX
-ALT_FTR_SECTION_END_IFSET(CPU_FTR_VSX)
-#endif
-
+       addi    r3,r4,VCPU_FPRS
+       bl      .load_fp_state
 #ifdef CONFIG_ALTIVEC
 BEGIN_FTR_SECTION
-       li      r7,VCPU_VSCR
-       lvx     vr0,r7,r4
-       mtvscr  vr0
-       reg = 0
-       .rept   32
-       li      r7,reg*16+VCPU_VRS
-       lvx     reg,r7,r4
-       reg = reg + 1
-       .endr
+       addi    r3,r31,VCPU_VRS
+       bl      .load_vr_state
 END_FTR_SECTION_IFSET(CPU_FTR_ALTIVEC)
 #endif
        lwz     r7,VCPU_VRSAVE(r4)
        mtspr   SPRN_VRSAVE,r7
+       mtlr    r30
+       mr      r4,r31
        blr
 
 /*
index a59a25a1321843ff5fe72caf385b80aba0302f95..c1abd95063f47d56a2092c57352bc0fff7ff9632 100644 (file)
 
 static inline void kvmppc_sync_qpr(struct kvm_vcpu *vcpu, int rt)
 {
-       kvm_cvt_df(&vcpu->arch.fpr[rt], &vcpu->arch.qpr[rt]);
+       kvm_cvt_df(&VCPU_FPR(vcpu, rt), &vcpu->arch.qpr[rt]);
 }
 
 static void kvmppc_inject_pf(struct kvm_vcpu *vcpu, ulong eaddr, bool is_store)
@@ -207,11 +207,11 @@ static int kvmppc_emulate_fpr_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
        /* put in registers */
        switch (ls_type) {
        case FPU_LS_SINGLE:
-               kvm_cvt_fd((u32*)tmp, &vcpu->arch.fpr[rs]);
+               kvm_cvt_fd((u32*)tmp, &VCPU_FPR(vcpu, rs));
                vcpu->arch.qpr[rs] = *((u32*)tmp);
                break;
        case FPU_LS_DOUBLE:
-               vcpu->arch.fpr[rs] = *((u64*)tmp);
+               VCPU_FPR(vcpu, rs) = *((u64*)tmp);
                break;
        }
 
@@ -233,18 +233,18 @@ static int kvmppc_emulate_fpr_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
 
        switch (ls_type) {
        case FPU_LS_SINGLE:
-               kvm_cvt_df(&vcpu->arch.fpr[rs], (u32*)tmp);
+               kvm_cvt_df(&VCPU_FPR(vcpu, rs), (u32*)tmp);
                val = *((u32*)tmp);
                len = sizeof(u32);
                break;
        case FPU_LS_SINGLE_LOW:
-               *((u32*)tmp) = vcpu->arch.fpr[rs];
-               val = vcpu->arch.fpr[rs] & 0xffffffff;
+               *((u32*)tmp) = VCPU_FPR(vcpu, rs);
+               val = VCPU_FPR(vcpu, rs) & 0xffffffff;
                len = sizeof(u32);
                break;
        case FPU_LS_DOUBLE:
-               *((u64*)tmp) = vcpu->arch.fpr[rs];
-               val = vcpu->arch.fpr[rs];
+               *((u64*)tmp) = VCPU_FPR(vcpu, rs);
+               val = VCPU_FPR(vcpu, rs);
                len = sizeof(u64);
                break;
        default:
@@ -301,7 +301,7 @@ static int kvmppc_emulate_psq_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
        emulated = EMULATE_DONE;
 
        /* put in registers */
-       kvm_cvt_fd(&tmp[0], &vcpu->arch.fpr[rs]);
+       kvm_cvt_fd(&tmp[0], &VCPU_FPR(vcpu, rs));
        vcpu->arch.qpr[rs] = tmp[1];
 
        dprintk(KERN_INFO "KVM: PSQ_LD [0x%x, 0x%x] at 0x%lx (%d)\n", tmp[0],
@@ -319,7 +319,7 @@ static int kvmppc_emulate_psq_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
        u32 tmp[2];
        int len = w ? sizeof(u32) : sizeof(u64);
 
-       kvm_cvt_df(&vcpu->arch.fpr[rs], &tmp[0]);
+       kvm_cvt_df(&VCPU_FPR(vcpu, rs), &tmp[0]);
        tmp[1] = vcpu->arch.qpr[rs];
 
        r = kvmppc_st(vcpu, &addr, len, tmp, true);
@@ -512,7 +512,6 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
                                                 u32 *src2, u32 *src3))
 {
        u32 *qpr = vcpu->arch.qpr;
-       u64 *fpr = vcpu->arch.fpr;
        u32 ps0_out;
        u32 ps0_in1, ps0_in2, ps0_in3;
        u32 ps1_in1, ps1_in2, ps1_in3;
@@ -521,20 +520,20 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
        WARN_ON(rc);
 
        /* PS0 */
-       kvm_cvt_df(&fpr[reg_in1], &ps0_in1);
-       kvm_cvt_df(&fpr[reg_in2], &ps0_in2);
-       kvm_cvt_df(&fpr[reg_in3], &ps0_in3);
+       kvm_cvt_df(&VCPU_FPR(vcpu, reg_in1), &ps0_in1);
+       kvm_cvt_df(&VCPU_FPR(vcpu, reg_in2), &ps0_in2);
+       kvm_cvt_df(&VCPU_FPR(vcpu, reg_in3), &ps0_in3);
 
        if (scalar & SCALAR_LOW)
                ps0_in2 = qpr[reg_in2];
 
-       func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3);
+       func(&vcpu->arch.fp.fpscr, &ps0_out, &ps0_in1, &ps0_in2, &ps0_in3);
 
        dprintk(KERN_INFO "PS3 ps0 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
                          ps0_in1, ps0_in2, ps0_in3, ps0_out);
 
        if (!(scalar & SCALAR_NO_PS0))
-               kvm_cvt_fd(&ps0_out, &fpr[reg_out]);
+               kvm_cvt_fd(&ps0_out, &VCPU_FPR(vcpu, reg_out));
 
        /* PS1 */
        ps1_in1 = qpr[reg_in1];
@@ -545,7 +544,7 @@ static int kvmppc_ps_three_in(struct kvm_vcpu *vcpu, bool rc,
                ps1_in2 = ps0_in2;
 
        if (!(scalar & SCALAR_NO_PS1))
-               func(&vcpu->arch.fpscr, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3);
+               func(&vcpu->arch.fp.fpscr, &qpr[reg_out], &ps1_in1, &ps1_in2, &ps1_in3);
 
        dprintk(KERN_INFO "PS3 ps1 -> f(0x%x, 0x%x, 0x%x) = 0x%x\n",
                          ps1_in1, ps1_in2, ps1_in3, qpr[reg_out]);
@@ -561,7 +560,6 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
                                                 u32 *src2))
 {
        u32 *qpr = vcpu->arch.qpr;
-       u64 *fpr = vcpu->arch.fpr;
        u32 ps0_out;
        u32 ps0_in1, ps0_in2;
        u32 ps1_out;
@@ -571,20 +569,20 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
        WARN_ON(rc);
 
        /* PS0 */
-       kvm_cvt_df(&fpr[reg_in1], &ps0_in1);
+       kvm_cvt_df(&VCPU_FPR(vcpu, reg_in1), &ps0_in1);
 
        if (scalar & SCALAR_LOW)
                ps0_in2 = qpr[reg_in2];
        else
-               kvm_cvt_df(&fpr[reg_in2], &ps0_in2);
+               kvm_cvt_df(&VCPU_FPR(vcpu, reg_in2), &ps0_in2);
 
-       func(&vcpu->arch.fpscr, &ps0_out, &ps0_in1, &ps0_in2);
+       func(&vcpu->arch.fp.fpscr, &ps0_out, &ps0_in1, &ps0_in2);
 
        if (!(scalar & SCALAR_NO_PS0)) {
                dprintk(KERN_INFO "PS2 ps0 -> f(0x%x, 0x%x) = 0x%x\n",
                                  ps0_in1, ps0_in2, ps0_out);
 
-               kvm_cvt_fd(&ps0_out, &fpr[reg_out]);
+               kvm_cvt_fd(&ps0_out, &VCPU_FPR(vcpu, reg_out));
        }
 
        /* PS1 */
@@ -594,7 +592,7 @@ static int kvmppc_ps_two_in(struct kvm_vcpu *vcpu, bool rc,
        if (scalar & SCALAR_HIGH)
                ps1_in2 = ps0_in2;
 
-       func(&vcpu->arch.fpscr, &ps1_out, &ps1_in1, &ps1_in2);
+       func(&vcpu->arch.fp.fpscr, &ps1_out, &ps1_in1, &ps1_in2);
 
        if (!(scalar & SCALAR_NO_PS1)) {
                qpr[reg_out] = ps1_out;
@@ -612,7 +610,6 @@ static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc,
                                                 u32 *dst, u32 *src1))
 {
        u32 *qpr = vcpu->arch.qpr;
-       u64 *fpr = vcpu->arch.fpr;
        u32 ps0_out, ps0_in;
        u32 ps1_in;
 
@@ -620,17 +617,17 @@ static int kvmppc_ps_one_in(struct kvm_vcpu *vcpu, bool rc,
        WARN_ON(rc);
 
        /* PS0 */
-       kvm_cvt_df(&fpr[reg_in], &ps0_in);
-       func(&vcpu->arch.fpscr, &ps0_out, &ps0_in);
+       kvm_cvt_df(&VCPU_FPR(vcpu, reg_in), &ps0_in);
+       func(&vcpu->arch.fp.fpscr, &ps0_out, &ps0_in);
 
        dprintk(KERN_INFO "PS1 ps0 -> f(0x%x) = 0x%x\n",
                          ps0_in, ps0_out);
 
-       kvm_cvt_fd(&ps0_out, &fpr[reg_out]);
+       kvm_cvt_fd(&ps0_out, &VCPU_FPR(vcpu, reg_out));
 
        /* PS1 */
        ps1_in = qpr[reg_in];
-       func(&vcpu->arch.fpscr, &qpr[reg_out], &ps1_in);
+       func(&vcpu->arch.fp.fpscr, &qpr[reg_out], &ps1_in);
 
        dprintk(KERN_INFO "PS1 ps1 -> f(0x%x) = 0x%x\n",
                          ps1_in, qpr[reg_out]);
@@ -649,10 +646,10 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
        int ax_rc = inst_get_field(inst, 21, 25);
        short full_d = inst_get_field(inst, 16, 31);
 
-       u64 *fpr_d = &vcpu->arch.fpr[ax_rd];
-       u64 *fpr_a = &vcpu->arch.fpr[ax_ra];
-       u64 *fpr_b = &vcpu->arch.fpr[ax_rb];
-       u64 *fpr_c = &vcpu->arch.fpr[ax_rc];
+       u64 *fpr_d = &VCPU_FPR(vcpu, ax_rd);
+       u64 *fpr_a = &VCPU_FPR(vcpu, ax_ra);
+       u64 *fpr_b = &VCPU_FPR(vcpu, ax_rb);
+       u64 *fpr_c = &VCPU_FPR(vcpu, ax_rc);
 
        bool rcomp = (inst & 1) ? true : false;
        u32 cr = kvmppc_get_cr(vcpu);
@@ -674,11 +671,11 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
        /* Do we need to clear FE0 / FE1 here? Don't think so. */
 
 #ifdef DEBUG
-       for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
+       for (i = 0; i < ARRAY_SIZE(vcpu->arch.fp.fpr); i++) {
                u32 f;
-               kvm_cvt_df(&vcpu->arch.fpr[i], &f);
+               kvm_cvt_df(&VCPU_FPR(vcpu, i), &f);
                dprintk(KERN_INFO "FPR[%d] = 0x%x / 0x%llx    QPR[%d] = 0x%x\n",
-                       i, f, vcpu->arch.fpr[i], i, vcpu->arch.qpr[i]);
+                       i, f, VCPU_FPR(vcpu, i), i, vcpu->arch.qpr[i]);
        }
 #endif
 
@@ -764,8 +761,8 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        break;
                }
                case OP_4X_PS_NEG:
-                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb];
-                       vcpu->arch.fpr[ax_rd] ^= 0x8000000000000000ULL;
+                       VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb);
+                       VCPU_FPR(vcpu, ax_rd) ^= 0x8000000000000000ULL;
                        vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
                        vcpu->arch.qpr[ax_rd] ^= 0x80000000;
                        break;
@@ -775,7 +772,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        break;
                case OP_4X_PS_MR:
                        WARN_ON(rcomp);
-                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb];
+                       VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb);
                        vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
                        break;
                case OP_4X_PS_CMPO1:
@@ -784,44 +781,44 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        break;
                case OP_4X_PS_NABS:
                        WARN_ON(rcomp);
-                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb];
-                       vcpu->arch.fpr[ax_rd] |= 0x8000000000000000ULL;
+                       VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb);
+                       VCPU_FPR(vcpu, ax_rd) |= 0x8000000000000000ULL;
                        vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
                        vcpu->arch.qpr[ax_rd] |= 0x80000000;
                        break;
                case OP_4X_PS_ABS:
                        WARN_ON(rcomp);
-                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rb];
-                       vcpu->arch.fpr[ax_rd] &= ~0x8000000000000000ULL;
+                       VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rb);
+                       VCPU_FPR(vcpu, ax_rd) &= ~0x8000000000000000ULL;
                        vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
                        vcpu->arch.qpr[ax_rd] &= ~0x80000000;
                        break;
                case OP_4X_PS_MERGE00:
                        WARN_ON(rcomp);
-                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra];
-                       /* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
-                       kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
+                       VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_ra);
+                       /* vcpu->arch.qpr[ax_rd] = VCPU_FPR(vcpu, ax_rb); */
+                       kvm_cvt_df(&VCPU_FPR(vcpu, ax_rb),
                                   &vcpu->arch.qpr[ax_rd]);
                        break;
                case OP_4X_PS_MERGE01:
                        WARN_ON(rcomp);
-                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_ra];
+                       VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_ra);
                        vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
                        break;
                case OP_4X_PS_MERGE10:
                        WARN_ON(rcomp);
-                       /* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
+                       /* VCPU_FPR(vcpu, ax_rd) = vcpu->arch.qpr[ax_ra]; */
                        kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
-                                  &vcpu->arch.fpr[ax_rd]);
-                       /* vcpu->arch.qpr[ax_rd] = vcpu->arch.fpr[ax_rb]; */
-                       kvm_cvt_df(&vcpu->arch.fpr[ax_rb],
+                                  &VCPU_FPR(vcpu, ax_rd));
+                       /* vcpu->arch.qpr[ax_rd] = VCPU_FPR(vcpu, ax_rb); */
+                       kvm_cvt_df(&VCPU_FPR(vcpu, ax_rb),
                                   &vcpu->arch.qpr[ax_rd]);
                        break;
                case OP_4X_PS_MERGE11:
                        WARN_ON(rcomp);
-                       /* vcpu->arch.fpr[ax_rd] = vcpu->arch.qpr[ax_ra]; */
+                       /* VCPU_FPR(vcpu, ax_rd) = vcpu->arch.qpr[ax_ra]; */
                        kvm_cvt_fd(&vcpu->arch.qpr[ax_ra],
-                                  &vcpu->arch.fpr[ax_rd]);
+                                  &VCPU_FPR(vcpu, ax_rd));
                        vcpu->arch.qpr[ax_rd] = vcpu->arch.qpr[ax_rb];
                        break;
                }
@@ -856,7 +853,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                case OP_4A_PS_SUM1:
                        emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
                                        ax_rb, ax_ra, SCALAR_NO_PS0 | SCALAR_HIGH, fps_fadds);
-                       vcpu->arch.fpr[ax_rd] = vcpu->arch.fpr[ax_rc];
+                       VCPU_FPR(vcpu, ax_rd) = VCPU_FPR(vcpu, ax_rc);
                        break;
                case OP_4A_PS_SUM0:
                        emulated = kvmppc_ps_two_in(vcpu, rcomp, ax_rd,
@@ -1106,45 +1103,45 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
        case 59:
                switch (inst_get_field(inst, 21, 30)) {
                case OP_59_FADDS:
-                       fpd_fadds(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       fpd_fadds(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                case OP_59_FSUBS:
-                       fpd_fsubs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       fpd_fsubs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                case OP_59_FDIVS:
-                       fpd_fdivs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       fpd_fdivs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                case OP_59_FRES:
-                       fpd_fres(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       fpd_fres(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                case OP_59_FRSQRTES:
-                       fpd_frsqrtes(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       fpd_frsqrtes(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                }
                switch (inst_get_field(inst, 26, 30)) {
                case OP_59_FMULS:
-                       fpd_fmuls(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c);
+                       fpd_fmuls(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                case OP_59_FMSUBS:
-                       fpd_fmsubs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       fpd_fmsubs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                case OP_59_FMADDS:
-                       fpd_fmadds(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       fpd_fmadds(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                case OP_59_FNMSUBS:
-                       fpd_fnmsubs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       fpd_fnmsubs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                case OP_59_FNMADDS:
-                       fpd_fnmadds(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       fpd_fnmadds(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                }
@@ -1159,12 +1156,12 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        break;
                case OP_63_MFFS:
                        /* XXX missing CR */
-                       *fpr_d = vcpu->arch.fpscr;
+                       *fpr_d = vcpu->arch.fp.fpscr;
                        break;
                case OP_63_MTFSF:
                        /* XXX missing fm bits */
                        /* XXX missing CR */
-                       vcpu->arch.fpscr = *fpr_b;
+                       vcpu->arch.fp.fpscr = *fpr_b;
                        break;
                case OP_63_FCMPU:
                {
@@ -1172,7 +1169,7 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        u32 cr0_mask = 0xf0000000;
                        u32 cr_shift = inst_get_field(inst, 6, 8) * 4;
 
-                       fpd_fcmpu(&vcpu->arch.fpscr, &tmp_cr, fpr_a, fpr_b);
+                       fpd_fcmpu(&vcpu->arch.fp.fpscr, &tmp_cr, fpr_a, fpr_b);
                        cr &= ~(cr0_mask >> cr_shift);
                        cr |= (cr & cr0_mask) >> cr_shift;
                        break;
@@ -1183,40 +1180,40 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        u32 cr0_mask = 0xf0000000;
                        u32 cr_shift = inst_get_field(inst, 6, 8) * 4;
 
-                       fpd_fcmpo(&vcpu->arch.fpscr, &tmp_cr, fpr_a, fpr_b);
+                       fpd_fcmpo(&vcpu->arch.fp.fpscr, &tmp_cr, fpr_a, fpr_b);
                        cr &= ~(cr0_mask >> cr_shift);
                        cr |= (cr & cr0_mask) >> cr_shift;
                        break;
                }
                case OP_63_FNEG:
-                       fpd_fneg(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       fpd_fneg(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
                        break;
                case OP_63_FMR:
                        *fpr_d = *fpr_b;
                        break;
                case OP_63_FABS:
-                       fpd_fabs(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       fpd_fabs(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
                        break;
                case OP_63_FCPSGN:
-                       fpd_fcpsgn(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       fpd_fcpsgn(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
                        break;
                case OP_63_FDIV:
-                       fpd_fdiv(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       fpd_fdiv(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
                        break;
                case OP_63_FADD:
-                       fpd_fadd(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       fpd_fadd(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
                        break;
                case OP_63_FSUB:
-                       fpd_fsub(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_b);
+                       fpd_fsub(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_b);
                        break;
                case OP_63_FCTIW:
-                       fpd_fctiw(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       fpd_fctiw(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
                        break;
                case OP_63_FCTIWZ:
-                       fpd_fctiwz(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       fpd_fctiwz(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
                        break;
                case OP_63_FRSP:
-                       fpd_frsp(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       fpd_frsp(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
                        kvmppc_sync_qpr(vcpu, ax_rd);
                        break;
                case OP_63_FRSQRTE:
@@ -1224,39 +1221,39 @@ int kvmppc_emulate_paired_single(struct kvm_run *run, struct kvm_vcpu *vcpu)
                        double one = 1.0f;
 
                        /* fD = sqrt(fB) */
-                       fpd_fsqrt(&vcpu->arch.fpscr, &cr, fpr_d, fpr_b);
+                       fpd_fsqrt(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_b);
                        /* fD = 1.0f / fD */
-                       fpd_fdiv(&vcpu->arch.fpscr, &cr, fpr_d, (u64*)&one, fpr_d);
+                       fpd_fdiv(&vcpu->arch.fp.fpscr, &cr, fpr_d, (u64*)&one, fpr_d);
                        break;
                }
                }
                switch (inst_get_field(inst, 26, 30)) {
                case OP_63_FMUL:
-                       fpd_fmul(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c);
+                       fpd_fmul(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c);
                        break;
                case OP_63_FSEL:
-                       fpd_fsel(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       fpd_fsel(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
                        break;
                case OP_63_FMSUB:
-                       fpd_fmsub(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       fpd_fmsub(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
                        break;
                case OP_63_FMADD:
-                       fpd_fmadd(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       fpd_fmadd(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
                        break;
                case OP_63_FNMSUB:
-                       fpd_fnmsub(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       fpd_fnmsub(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
                        break;
                case OP_63_FNMADD:
-                       fpd_fnmadd(&vcpu->arch.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
+                       fpd_fnmadd(&vcpu->arch.fp.fpscr, &cr, fpr_d, fpr_a, fpr_c, fpr_b);
                        break;
                }
                break;
        }
 
 #ifdef DEBUG
-       for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++) {
+       for (i = 0; i < ARRAY_SIZE(vcpu->arch.fp.fpr); i++) {
                u32 f;
-               kvm_cvt_df(&vcpu->arch.fpr[i], &f);
+               kvm_cvt_df(&VCPU_FPR(vcpu, i), &f);
                dprintk(KERN_INFO "FPR[%d] = 0x%x\n", i, f);
        }
 #endif
index 5b9e9063cfaf0c407be267a67ab26d35fcc84a93..c5c052a9729c95d14591087fe71b20168237dc5d 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/vmalloc.h>
 #include <linux/highmem.h>
 #include <linux/module.h>
+#include <linux/miscdevice.h>
 
 #include "book3s.h"
 
@@ -566,12 +567,6 @@ static inline int get_fpr_index(int i)
 void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
 {
        struct thread_struct *t = &current->thread;
-       u64 *vcpu_fpr = vcpu->arch.fpr;
-#ifdef CONFIG_VSX
-       u64 *vcpu_vsx = vcpu->arch.vsr;
-#endif
-       u64 *thread_fpr = &t->fp_state.fpr[0][0];
-       int i;
 
        /*
         * VSX instructions can access FP and vector registers, so if
@@ -594,26 +589,16 @@ void kvmppc_giveup_ext(struct kvm_vcpu *vcpu, ulong msr)
                 * both the traditional FP registers and the added VSX
                 * registers into thread.fp_state.fpr[].
                 */
-               if (current->thread.regs->msr & MSR_FP)
+               if (t->regs->msr & MSR_FP)
                        giveup_fpu(current);
-               for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
-                       vcpu_fpr[i] = thread_fpr[get_fpr_index(i)];
-
-               vcpu->arch.fpscr = t->fp_state.fpscr;
-
-#ifdef CONFIG_VSX
-               if (cpu_has_feature(CPU_FTR_VSX))
-                       for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr) / 2; i++)
-                               vcpu_vsx[i] = thread_fpr[get_fpr_index(i) + 1];
-#endif
+               t->fp_save_area = NULL;
        }
 
 #ifdef CONFIG_ALTIVEC
        if (msr & MSR_VEC) {
                if (current->thread.regs->msr & MSR_VEC)
                        giveup_altivec(current);
-               memcpy(vcpu->arch.vr, t->vr_state.vr, sizeof(vcpu->arch.vr));
-               vcpu->arch.vscr = t->vr_state.vscr;
+               t->vr_save_area = NULL;
        }
 #endif
 
@@ -661,12 +646,6 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
                             ulong msr)
 {
        struct thread_struct *t = &current->thread;
-       u64 *vcpu_fpr = vcpu->arch.fpr;
-#ifdef CONFIG_VSX
-       u64 *vcpu_vsx = vcpu->arch.vsr;
-#endif
-       u64 *thread_fpr = &t->fp_state.fpr[0][0];
-       int i;
 
        /* When we have paired singles, we emulate in software */
        if (vcpu->arch.hflags & BOOK3S_HFLAG_PAIRED_SINGLE)
@@ -704,27 +683,20 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr,
 #endif
 
        if (msr & MSR_FP) {
-               for (i = 0; i < ARRAY_SIZE(vcpu->arch.fpr); i++)
-                       thread_fpr[get_fpr_index(i)] = vcpu_fpr[i];
-#ifdef CONFIG_VSX
-               for (i = 0; i < ARRAY_SIZE(vcpu->arch.vsr) / 2; i++)
-                       thread_fpr[get_fpr_index(i) + 1] = vcpu_vsx[i];
-#endif
-               t->fp_state.fpscr = vcpu->arch.fpscr;
-               t->fpexc_mode = 0;
-               kvmppc_load_up_fpu();
+               enable_kernel_fp();
+               load_fp_state(&vcpu->arch.fp);
+               t->fp_save_area = &vcpu->arch.fp;
        }
 
        if (msr & MSR_VEC) {
 #ifdef CONFIG_ALTIVEC
-               memcpy(t->vr_state.vr, vcpu->arch.vr, sizeof(vcpu->arch.vr));
-               t->vr_state.vscr = vcpu->arch.vscr;
-               t->vrsave = -1;
-               kvmppc_load_up_altivec();
+               enable_kernel_altivec();
+               load_vr_state(&vcpu->arch.vr);
+               t->vr_save_area = &vcpu->arch.vr;
 #endif
        }
 
-       current->thread.regs->msr |= msr;
+       t->regs->msr |= msr;
        vcpu->arch.guest_owned_ext |= msr;
        kvmppc_recalc_shadow_msr(vcpu);
 
@@ -743,11 +715,15 @@ static void kvmppc_handle_lost_ext(struct kvm_vcpu *vcpu)
        if (!lost_ext)
                return;
 
-       if (lost_ext & MSR_FP)
-               kvmppc_load_up_fpu();
+       if (lost_ext & MSR_FP) {
+               enable_kernel_fp();
+               load_fp_state(&vcpu->arch.fp);
+       }
 #ifdef CONFIG_ALTIVEC
-       if (lost_ext & MSR_VEC)
-               kvmppc_load_up_altivec();
+       if (lost_ext & MSR_VEC) {
+               enable_kernel_altivec();
+               load_vr_state(&vcpu->arch.vr);
+       }
 #endif
        current->thread.regs->msr |= lost_ext;
 }
@@ -873,6 +849,7 @@ int kvmppc_handle_exit_pr(struct kvm_run *run, struct kvm_vcpu *vcpu,
        /* We're good on these - the host merely wanted to get our attention */
        case BOOK3S_INTERRUPT_DECREMENTER:
        case BOOK3S_INTERRUPT_HV_DECREMENTER:
+       case BOOK3S_INTERRUPT_DOORBELL:
                vcpu->stat.dec_exits++;
                r = RESUME_GUEST;
                break;
@@ -1045,14 +1022,14 @@ program_interrupt:
                 * and if we really did time things so badly, then we just exit
                 * again due to a host external interrupt.
                 */
-               local_irq_disable();
                s = kvmppc_prepare_to_enter(vcpu);
-               if (s <= 0) {
-                       local_irq_enable();
+               if (s <= 0)
                        r = s;
-               } else {
+               else {
+                       /* interrupts now hard-disabled */
                        kvmppc_fix_ee_before_entry();
                }
+
                kvmppc_handle_lost_ext(vcpu);
        }
 
@@ -1133,19 +1110,6 @@ static int kvmppc_get_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
        case KVM_REG_PPC_HIOR:
                *val = get_reg_val(id, to_book3s(vcpu)->hior);
                break;
-#ifdef CONFIG_VSX
-       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: {
-               long int i = id - KVM_REG_PPC_VSR0;
-
-               if (!cpu_has_feature(CPU_FTR_VSX)) {
-                       r = -ENXIO;
-                       break;
-               }
-               val->vsxval[0] = vcpu->arch.fpr[i];
-               val->vsxval[1] = vcpu->arch.vsr[i];
-               break;
-       }
-#endif /* CONFIG_VSX */
        default:
                r = -EINVAL;
                break;
@@ -1164,19 +1128,6 @@ static int kvmppc_set_one_reg_pr(struct kvm_vcpu *vcpu, u64 id,
                to_book3s(vcpu)->hior = set_reg_val(id, *val);
                to_book3s(vcpu)->hior_explicit = true;
                break;
-#ifdef CONFIG_VSX
-       case KVM_REG_PPC_VSR0 ... KVM_REG_PPC_VSR31: {
-               long int i = id - KVM_REG_PPC_VSR0;
-
-               if (!cpu_has_feature(CPU_FTR_VSX)) {
-                       r = -ENXIO;
-                       break;
-               }
-               vcpu->arch.fpr[i] = val->vsxval[0];
-               vcpu->arch.vsr[i] = val->vsxval[1];
-               break;
-       }
-#endif /* CONFIG_VSX */
        default:
                r = -EINVAL;
                break;
@@ -1274,17 +1225,9 @@ static void kvmppc_core_vcpu_free_pr(struct kvm_vcpu *vcpu)
 static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
        int ret;
-       struct thread_fp_state fp;
-       int fpexc_mode;
 #ifdef CONFIG_ALTIVEC
-       struct thread_vr_state vr;
        unsigned long uninitialized_var(vrsave);
-       int used_vr;
 #endif
-#ifdef CONFIG_VSX
-       int used_vsr;
-#endif
-       ulong ext_msr;
 
        /* Check if we can run the vcpu at all */
        if (!vcpu->arch.sane) {
@@ -1299,40 +1242,27 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
         * really did time things so badly, then we just exit again due to
         * a host external interrupt.
         */
-       local_irq_disable();
        ret = kvmppc_prepare_to_enter(vcpu);
-       if (ret <= 0) {
-               local_irq_enable();
+       if (ret <= 0)
                goto out;
-       }
+       /* interrupts now hard-disabled */
 
-       /* Save FPU state in stack */
+       /* Save FPU state in thread_struct */
        if (current->thread.regs->msr & MSR_FP)
                giveup_fpu(current);
-       fp = current->thread.fp_state;
-       fpexc_mode = current->thread.fpexc_mode;
 
 #ifdef CONFIG_ALTIVEC
-       /* Save Altivec state in stack */
-       used_vr = current->thread.used_vr;
-       if (used_vr) {
-               if (current->thread.regs->msr & MSR_VEC)
-                       giveup_altivec(current);
-               vr = current->thread.vr_state;
-               vrsave = current->thread.vrsave;
-       }
+       /* Save Altivec state in thread_struct */
+       if (current->thread.regs->msr & MSR_VEC)
+               giveup_altivec(current);
 #endif
 
 #ifdef CONFIG_VSX
-       /* Save VSX state in stack */
-       used_vsr = current->thread.used_vsr;
-       if (used_vsr && (current->thread.regs->msr & MSR_VSX))
+       /* Save VSX state in thread_struct */
+       if (current->thread.regs->msr & MSR_VSX)
                __giveup_vsx(current);
 #endif
 
-       /* Remember the MSR with disabled extensions */
-       ext_msr = current->thread.regs->msr;
-
        /* Preload FPU if it's enabled */
        if (vcpu->arch.shared->msr & MSR_FP)
                kvmppc_handle_ext(vcpu, BOOK3S_INTERRUPT_FP_UNAVAIL, MSR_FP);
@@ -1347,25 +1277,6 @@ static int kvmppc_vcpu_run_pr(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        /* Make sure we save the guest FPU/Altivec/VSX state */
        kvmppc_giveup_ext(vcpu, MSR_FP | MSR_VEC | MSR_VSX);
 
-       current->thread.regs->msr = ext_msr;
-
-       /* Restore FPU/VSX state from stack */
-       current->thread.fp_state = fp;
-       current->thread.fpexc_mode = fpexc_mode;
-
-#ifdef CONFIG_ALTIVEC
-       /* Restore Altivec state from stack */
-       if (used_vr && current->thread.used_vr) {
-               current->thread.vr_state = vr;
-               current->thread.vrsave = vrsave;
-       }
-       current->thread.used_vr = used_vr;
-#endif
-
-#ifdef CONFIG_VSX
-       current->thread.used_vsr = used_vsr;
-#endif
-
 out:
        vcpu->mode = OUTSIDE_GUEST_MODE;
        return ret;
@@ -1606,4 +1517,6 @@ module_init(kvmppc_book3s_init_pr);
 module_exit(kvmppc_book3s_exit_pr);
 
 MODULE_LICENSE("GPL");
+MODULE_ALIAS_MISCDEV(KVM_MINOR);
+MODULE_ALIAS("devname:kvm");
 #endif
index c3c5231adade6f3871709a318fed1abc752040fe..9eec675220e621e029eac8ecf2a5dabfff17df5a 100644 (file)
@@ -162,51 +162,4 @@ _GLOBAL(kvmppc_entry_trampoline)
        mtsrr1  r6
        RFI
 
-#if defined(CONFIG_PPC_BOOK3S_32)
-#define STACK_LR       INT_FRAME_SIZE+4
-
-/* load_up_xxx have to run with MSR_DR=0 on Book3S_32 */
-#define MSR_EXT_START                                          \
-       PPC_STL r20, _NIP(r1);                                  \
-       mfmsr   r20;                                            \
-       LOAD_REG_IMMEDIATE(r3, MSR_DR|MSR_EE);                  \
-       andc    r3,r20,r3;              /* Disable DR,EE */     \
-       mtmsr   r3;                                             \
-       sync
-
-#define MSR_EXT_END                                            \
-       mtmsr   r20;                    /* Enable DR,EE */      \
-       sync;                                                   \
-       PPC_LL  r20, _NIP(r1)
-
-#elif defined(CONFIG_PPC_BOOK3S_64)
-#define STACK_LR       _LINK
-#define MSR_EXT_START
-#define MSR_EXT_END
-#endif
-
-/*
- * Activate current's external feature (FPU/Altivec/VSX)
- */
-#define define_load_up(what)                                   \
-                                                               \
-_GLOBAL(kvmppc_load_up_ ## what);                              \
-       PPC_STLU r1, -INT_FRAME_SIZE(r1);                       \
-       mflr    r3;                                             \
-       PPC_STL r3, STACK_LR(r1);                               \
-       MSR_EXT_START;                                          \
-                                                               \
-       bl      FUNC(load_up_ ## what);                         \
-                                                               \
-       MSR_EXT_END;                                            \
-       PPC_LL  r3, STACK_LR(r1);                               \
-       mtlr    r3;                                             \
-       addi    r1, r1, INT_FRAME_SIZE;                         \
-       blr
-
-define_load_up(fpu)
-#ifdef CONFIG_ALTIVEC
-define_load_up(altivec)
-#endif
-
 #include "book3s_segment.S"
index bc50c97751d368b3f0b837030312dfc038890695..1e0cc2adfd40d9aaee3ee93662d6f4ee48d8d659 100644 (file)
@@ -361,6 +361,8 @@ END_FTR_SECTION_IFSET(CPU_FTR_HVMODE)
        beqa    BOOK3S_INTERRUPT_DECREMENTER
        cmpwi   r12, BOOK3S_INTERRUPT_PERFMON
        beqa    BOOK3S_INTERRUPT_PERFMON
+       cmpwi   r12, BOOK3S_INTERRUPT_DOORBELL
+       beqa    BOOK3S_INTERRUPT_DOORBELL
 
        RFI
 kvmppc_handler_trampoline_exit_end:
index 02a17dcf16107adbe1309185bf464d0fda4b8772..d1acd32a64c034649447413fcde90b15826c86cd 100644 (file)
@@ -1246,8 +1246,10 @@ static int kvmppc_xics_create(struct kvm_device *dev, u32 type)
                kvm->arch.xics = xics;
        mutex_unlock(&kvm->lock);
 
-       if (ret)
+       if (ret) {
+               kfree(xics);
                return ret;
+       }
 
        xics_debugfs_init(xics);
 
index 0591e05db74b1a1a1f906af6a2a67cf9770320fa..ab62109fdfa3f71a43701c7d08220db2cb826066 100644 (file)
@@ -643,7 +643,7 @@ int kvmppc_core_prepare_to_enter(struct kvm_vcpu *vcpu)
                local_irq_enable();
                kvm_vcpu_block(vcpu);
                clear_bit(KVM_REQ_UNHALT, &vcpu->requests);
-               local_irq_disable();
+               hard_irq_disable();
 
                kvmppc_set_exit_type(vcpu, EMULATED_MTMSRWE_EXITS);
                r = 1;
@@ -682,34 +682,22 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
 {
        int ret, s;
        struct debug_reg debug;
-#ifdef CONFIG_PPC_FPU
-       struct thread_fp_state fp;
-       int fpexc_mode;
-#endif
 
        if (!vcpu->arch.sane) {
                kvm_run->exit_reason = KVM_EXIT_INTERNAL_ERROR;
                return -EINVAL;
        }
 
-       local_irq_disable();
        s = kvmppc_prepare_to_enter(vcpu);
        if (s <= 0) {
-               local_irq_enable();
                ret = s;
                goto out;
        }
+       /* interrupts now hard-disabled */
 
 #ifdef CONFIG_PPC_FPU
        /* Save userspace FPU state in stack */
        enable_kernel_fp();
-       fp = current->thread.fp_state;
-       fpexc_mode = current->thread.fpexc_mode;
-
-       /* Restore guest FPU state to thread */
-       memcpy(current->thread.fp_state.fpr, vcpu->arch.fpr,
-              sizeof(vcpu->arch.fpr));
-       current->thread.fp_state.fpscr = vcpu->arch.fpscr;
 
        /*
         * Since we can't trap on MSR_FP in GS-mode, we consider the guest
@@ -728,6 +716,7 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        debug = current->thread.debug;
        current->thread.debug = vcpu->arch.shadow_dbg_reg;
 
+       vcpu->arch.pgdir = current->mm->pgd;
        kvmppc_fix_ee_before_entry();
 
        ret = __kvmppc_vcpu_run(kvm_run, vcpu);
@@ -743,15 +732,6 @@ int kvmppc_vcpu_run(struct kvm_run *kvm_run, struct kvm_vcpu *vcpu)
        kvmppc_save_guest_fp(vcpu);
 
        vcpu->fpu_active = 0;
-
-       /* Save guest FPU state from thread */
-       memcpy(vcpu->arch.fpr, current->thread.fp_state.fpr,
-              sizeof(vcpu->arch.fpr));
-       vcpu->arch.fpscr = current->thread.fp_state.fpscr;
-
-       /* Restore userspace FPU state from stack */
-       current->thread.fp_state = fp;
-       current->thread.fpexc_mode = fpexc_mode;
 #endif
 
 out:
@@ -898,17 +878,6 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
        int s;
        int idx;
 
-#ifdef CONFIG_PPC64
-       WARN_ON(local_paca->irq_happened != 0);
-#endif
-
-       /*
-        * We enter with interrupts disabled in hardware, but
-        * we need to call hard_irq_disable anyway to ensure that
-        * the software state is kept in sync.
-        */
-       hard_irq_disable();
-
        /* update before a new last_exit_type is rewritten */
        kvmppc_update_timing_stats(vcpu);
 
@@ -1217,12 +1186,11 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu,
         * aren't already exiting to userspace for some other reason.
         */
        if (!(r & RESUME_HOST)) {
-               local_irq_disable();
                s = kvmppc_prepare_to_enter(vcpu);
-               if (s <= 0) {
-                       local_irq_enable();
+               if (s <= 0)
                        r = (s << 2) | RESUME_HOST | (r & RESUME_FLAG_NV);
-               } else {
+               else {
+                       /* interrupts now hard-disabled */
                        kvmppc_fix_ee_before_entry();
                }
        }
index 09bfd9bc7cf8d9b1db12a9afc1956ec2fa9fc5e3..b632cd35919b1b32460abd2d4f6c4d9c579627b7 100644 (file)
@@ -136,7 +136,9 @@ static inline void kvmppc_load_guest_fp(struct kvm_vcpu *vcpu)
 {
 #ifdef CONFIG_PPC_FPU
        if (vcpu->fpu_active && !(current->thread.regs->msr & MSR_FP)) {
-               load_up_fpu();
+               enable_kernel_fp();
+               load_fp_state(&vcpu->arch.fp);
+               current->thread.fp_save_area = &vcpu->arch.fp;
                current->thread.regs->msr |= MSR_FP;
        }
 #endif
@@ -151,6 +153,7 @@ static inline void kvmppc_save_guest_fp(struct kvm_vcpu *vcpu)
 #ifdef CONFIG_PPC_FPU
        if (vcpu->fpu_active && (current->thread.regs->msr & MSR_FP))
                giveup_fpu(current);
+       current->thread.fp_save_area = NULL;
 #endif
 }
 
index e8ed7d659c55f8cbcdc341c07ea58a8bc26b744d..e4185f6b3309af4cf51d5990f766647c88e9a5a2 100644 (file)
@@ -33,6 +33,8 @@
 
 #ifdef CONFIG_64BIT
 #include <asm/exception-64e.h>
+#include <asm/hw_irq.h>
+#include <asm/irqflags.h>
 #else
 #include "../kernel/head_booke.h" /* for THREAD_NORMSAVE() */
 #endif
@@ -319,6 +321,8 @@ kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(DBG), \
        SPRN_DSRR0, SPRN_DSRR1, 0
 kvm_handler BOOKE_INTERRUPT_DEBUG, EX_PARAMS(CRIT), \
        SPRN_CSRR0, SPRN_CSRR1, 0
+kvm_handler BOOKE_INTERRUPT_LRAT_ERROR, EX_PARAMS(GEN), \
+       SPRN_SRR0, SPRN_SRR1, (NEED_EMU | NEED_DEAR | NEED_ESR)
 #else
 /*
  * For input register values, see arch/powerpc/include/asm/kvm_booke_hv_asm.h
@@ -465,6 +469,15 @@ _GLOBAL(kvmppc_resume_host)
        mtspr   SPRN_EPCR, r3
        isync
 
+#ifdef CONFIG_64BIT
+       /*
+        * We enter with interrupts disabled in hardware, but
+        * we need to call RECONCILE_IRQ_STATE to ensure
+        * that the software state is kept in sync.
+        */
+       RECONCILE_IRQ_STATE(r3,r5)
+#endif
+
        /* Switch to kernel stack and jump to handler. */
        PPC_LL  r3, HOST_RUN(r1)
        mr      r5, r14 /* intno */
index 497b142f651c835f10c8395ec4f70297b18442c3..2e02ed849f36d1a5724a48557e08d8e3bea69ce0 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/export.h>
+#include <linux/module.h>
+#include <linux/miscdevice.h>
 
 #include <asm/reg.h>
 #include <asm/cputable.h>
@@ -573,3 +575,5 @@ static void __exit kvmppc_e500_exit(void)
 
 module_init(kvmppc_e500_init);
 module_exit(kvmppc_e500_exit);
+MODULE_ALIAS_MISCDEV(KVM_MINOR);
+MODULE_ALIAS("devname:kvm");
index 4fd9650eb0185374bfd567291dd16ce5f397b688..a326178bdea5163935a48f23c2d545dd3d2e3863 100644 (file)
@@ -31,11 +31,13 @@ enum vcpu_ftr {
 #define E500_TLB_NUM   2
 
 /* entry is mapped somewhere in host TLB */
-#define E500_TLB_VALID         (1 << 0)
+#define E500_TLB_VALID         (1 << 31)
 /* TLB1 entry is mapped by host TLB1, tracked by bitmaps */
-#define E500_TLB_BITMAP                (1 << 1)
+#define E500_TLB_BITMAP                (1 << 30)
 /* TLB1 entry is mapped by host TLB0 */
-#define E500_TLB_TLB0          (1 << 2)
+#define E500_TLB_TLB0          (1 << 29)
+/* bits [6-5] MAS2_X1 and MAS2_X0 and [4-0] bits for WIMGE */
+#define E500_TLB_MAS2_ATTR     (0x7f)
 
 struct tlbe_ref {
        pfn_t pfn;              /* valid only for TLB0, except briefly */
index ebca6b88ea5e7d545840dc4f7b9c3efd2447d69f..50860e919cb81777a0ef4015e48f9bfda2b3e810 100644 (file)
@@ -127,7 +127,7 @@ static int kvmppc_e500_tlb_index(struct kvmppc_vcpu_e500 *vcpu_e500,
 }
 
 static inline void kvmppc_e500_deliver_tlb_miss(struct kvm_vcpu *vcpu,
-               unsigned int eaddr, int as)
+               gva_t eaddr, int as)
 {
        struct kvmppc_vcpu_e500 *vcpu_e500 = to_e500(vcpu);
        unsigned int victim, tsized;
index ecf2247b13be771a0b1442a6d447fd5c881e89c1..dd2cc03f406f9a0e1f844473ca92c5560eca6c67 100644 (file)
@@ -65,15 +65,6 @@ static inline u32 e500_shadow_mas3_attrib(u32 mas3, int usermode)
        return mas3;
 }
 
-static inline u32 e500_shadow_mas2_attrib(u32 mas2, int usermode)
-{
-#ifdef CONFIG_SMP
-       return (mas2 & MAS2_ATTRIB_MASK) | MAS2_M;
-#else
-       return mas2 & MAS2_ATTRIB_MASK;
-#endif
-}
-
 /*
  * writing shadow tlb entry to host TLB
  */
@@ -231,15 +222,15 @@ void inval_gtlbe_on_host(struct kvmppc_vcpu_e500 *vcpu_e500, int tlbsel,
                ref->flags &= ~(E500_TLB_TLB0 | E500_TLB_VALID);
        }
 
-       /* Already invalidated in between */
-       if (!(ref->flags & E500_TLB_VALID))
-               return;
-
-       /* Guest tlbe is backed by at most one host tlbe per shadow pid. */
-       kvmppc_e500_tlbil_one(vcpu_e500, gtlbe);
+       /*
+        * If TLB entry is still valid then it's a TLB0 entry, and thus
+        * backed by at most one host tlbe per shadow pid
+        */
+       if (ref->flags & E500_TLB_VALID)
+               kvmppc_e500_tlbil_one(vcpu_e500, gtlbe);
 
        /* Mark the TLB as not backed by the host anymore */
-       ref->flags &= ~E500_TLB_VALID;
+       ref->flags = 0;
 }
 
 static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
@@ -249,10 +240,13 @@ static inline int tlbe_is_writable(struct kvm_book3e_206_tlb_entry *tlbe)
 
 static inline void kvmppc_e500_ref_setup(struct tlbe_ref *ref,
                                         struct kvm_book3e_206_tlb_entry *gtlbe,
-                                        pfn_t pfn)
+                                        pfn_t pfn, unsigned int wimg)
 {
        ref->pfn = pfn;
-       ref->flags |= E500_TLB_VALID;
+       ref->flags = E500_TLB_VALID;
+
+       /* Use guest supplied MAS2_G and MAS2_E */
+       ref->flags |= (gtlbe->mas2 & MAS2_ATTRIB_MASK) | wimg;
 
        /* Mark the page accessed */
        kvm_set_pfn_accessed(pfn);
@@ -316,8 +310,7 @@ static void kvmppc_e500_setup_stlbe(
 
        /* Force IPROT=0 for all guest mappings. */
        stlbe->mas1 = MAS1_TSIZE(tsize) | get_tlb_sts(gtlbe) | MAS1_VALID;
-       stlbe->mas2 = (gvaddr & MAS2_EPN) |
-                     e500_shadow_mas2_attrib(gtlbe->mas2, pr);
+       stlbe->mas2 = (gvaddr & MAS2_EPN) | (ref->flags & E500_TLB_MAS2_ATTR);
        stlbe->mas7_3 = ((u64)pfn << PAGE_SHIFT) |
                        e500_shadow_mas3_attrib(gtlbe->mas7_3, pr);
 
@@ -339,6 +332,10 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        int ret = 0;
        unsigned long mmu_seq;
        struct kvm *kvm = vcpu_e500->vcpu.kvm;
+       unsigned long tsize_pages = 0;
+       pte_t *ptep;
+       unsigned int wimg = 0;
+       pgd_t *pgdir;
 
        /* used to check for invalidations in progress */
        mmu_seq = kvm->mmu_notifier_seq;
@@ -405,7 +402,7 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                         */
 
                        for (; tsize > BOOK3E_PAGESZ_4K; tsize -= 2) {
-                               unsigned long gfn_start, gfn_end, tsize_pages;
+                               unsigned long gfn_start, gfn_end;
                                tsize_pages = 1 << (tsize - 2);
 
                                gfn_start = gfn & ~(tsize_pages - 1);
@@ -447,11 +444,12 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
        }
 
        if (likely(!pfnmap)) {
-               unsigned long tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT);
+               tsize_pages = 1 << (tsize + 10 - PAGE_SHIFT);
                pfn = gfn_to_pfn_memslot(slot, gfn);
                if (is_error_noslot_pfn(pfn)) {
-                       printk(KERN_ERR "Couldn't get real page for gfn %lx!\n",
-                                       (long)gfn);
+                       if (printk_ratelimit())
+                               pr_err("%s: real page not found for gfn %lx\n",
+                                      __func__, (long)gfn);
                        return -EINVAL;
                }
 
@@ -466,7 +464,18 @@ static inline int kvmppc_e500_shadow_map(struct kvmppc_vcpu_e500 *vcpu_e500,
                goto out;
        }
 
-       kvmppc_e500_ref_setup(ref, gtlbe, pfn);
+
+       pgdir = vcpu_e500->vcpu.arch.pgdir;
+       ptep = lookup_linux_ptep(pgdir, hva, &tsize_pages);
+       if (pte_present(*ptep))
+               wimg = (*ptep >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK;
+       else {
+               if (printk_ratelimit())
+                       pr_err("%s: pte not present: gfn %lx, pfn %lx\n",
+                               __func__, (long)gfn, pfn);
+               return -EINVAL;
+       }
+       kvmppc_e500_ref_setup(ref, gtlbe, pfn, wimg);
 
        kvmppc_e500_setup_stlbe(&vcpu_e500->vcpu, gtlbe, tsize,
                                ref, gvaddr, stlbe);
index 4132cd2fc1715c4a838be1c6fcee53018e6e2215..17e456279224652ce86c5c404130bdc45a702fe7 100644 (file)
@@ -16,6 +16,8 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/export.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
 
 #include <asm/reg.h>
 #include <asm/cputable.h>
@@ -391,3 +393,5 @@ static void __exit kvmppc_e500mc_exit(void)
 
 module_init(kvmppc_e500mc_init);
 module_exit(kvmppc_e500mc_exit);
+MODULE_ALIAS_MISCDEV(KVM_MINOR);
+MODULE_ALIAS("devname:kvm");
index 2f9a0873b44fe21d106988004d2c48ae40ce210e..c2b887be2c2922bebf772cedbba0ab14cc74c52f 100644 (file)
@@ -219,7 +219,6 @@ static int kvmppc_emulate_mfspr(struct kvm_vcpu *vcpu, int sprn, int rt)
  * lmw
  * stmw
  *
- * XXX is_bigendian should depend on MMU mapping or MSR[LE]
  */
 /* XXX Should probably auto-generate instruction decoding for a particular core
  * from opcode tables in the future. */
index 2861ae9eaae6e2f841af45bc928cec309303d66c..efbd9962a209c999ff9ab8ff4959d9e4522d296b 100644 (file)
@@ -1635,6 +1635,7 @@ static void mpic_destroy(struct kvm_device *dev)
 
        dev->kvm->arch.mpic = NULL;
        kfree(opp);
+       kfree(dev);
 }
 
 static int mpic_set_default_irq_routing(struct openpic *opp)
index 9ae97686e9f444ded5700bd7621fd0a7207d08e4..3cf541a53e2aef14a00e467e0c4daec16c255e7a 100644 (file)
@@ -68,14 +68,16 @@ int kvm_arch_vcpu_should_kick(struct kvm_vcpu *vcpu)
  */
 int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
 {
-       int r = 1;
+       int r;
+
+       WARN_ON(irqs_disabled());
+       hard_irq_disable();
 
-       WARN_ON_ONCE(!irqs_disabled());
        while (true) {
                if (need_resched()) {
                        local_irq_enable();
                        cond_resched();
-                       local_irq_disable();
+                       hard_irq_disable();
                        continue;
                }
 
@@ -101,7 +103,7 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
                        local_irq_enable();
                        trace_kvm_check_requests(vcpu);
                        r = kvmppc_core_check_requests(vcpu);
-                       local_irq_disable();
+                       hard_irq_disable();
                        if (r > 0)
                                continue;
                        break;
@@ -113,22 +115,12 @@ int kvmppc_prepare_to_enter(struct kvm_vcpu *vcpu)
                        continue;
                }
 
-#ifdef CONFIG_PPC64
-               /* lazy EE magic */
-               hard_irq_disable();
-               if (lazy_irq_pending()) {
-                       /* Got an interrupt in between, try again */
-                       local_irq_enable();
-                       local_irq_disable();
-                       kvm_guest_exit();
-                       continue;
-               }
-#endif
-
                kvm_guest_enter();
-               break;
+               return 1;
        }
 
+       /* return to host */
+       local_irq_enable();
        return r;
 }
 EXPORT_SYMBOL_GPL(kvmppc_prepare_to_enter);
@@ -656,14 +648,14 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
                kvmppc_set_gpr(vcpu, vcpu->arch.io_gpr, gpr);
                break;
        case KVM_MMIO_REG_FPR:
-               vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
+               VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;
                break;
 #ifdef CONFIG_PPC_BOOK3S
        case KVM_MMIO_REG_QPR:
                vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
                break;
        case KVM_MMIO_REG_FQPR:
-               vcpu->arch.fpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
+               VCPU_FPR(vcpu, vcpu->arch.io_gpr & KVM_MMIO_REG_MASK) = gpr;
                vcpu->arch.qpr[vcpu->arch.io_gpr & KVM_MMIO_REG_MASK] = gpr;
                break;
 #endif
@@ -673,9 +665,19 @@ static void kvmppc_complete_mmio_load(struct kvm_vcpu *vcpu,
 }
 
 int kvmppc_handle_load(struct kvm_run *run, struct kvm_vcpu *vcpu,
-                       unsigned int rt, unsigned int bytes, int is_bigendian)
+                      unsigned int rt, unsigned int bytes,
+                      int is_default_endian)
 {
        int idx, ret;
+       int is_bigendian;
+
+       if (kvmppc_need_byteswap(vcpu)) {
+               /* Default endianness is "little endian". */
+               is_bigendian = !is_default_endian;
+       } else {
+               /* Default endianness is "big endian". */
+               is_bigendian = is_default_endian;
+       }
 
        if (bytes > sizeof(run->mmio.data)) {
                printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,
@@ -711,21 +713,31 @@ EXPORT_SYMBOL_GPL(kvmppc_handle_load);
 
 /* Same as above, but sign extends */
 int kvmppc_handle_loads(struct kvm_run *run, struct kvm_vcpu *vcpu,
-                        unsigned int rt, unsigned int bytes, int is_bigendian)
+                       unsigned int rt, unsigned int bytes,
+                       int is_default_endian)
 {
        int r;
 
        vcpu->arch.mmio_sign_extend = 1;
-       r = kvmppc_handle_load(run, vcpu, rt, bytes, is_bigendian);
+       r = kvmppc_handle_load(run, vcpu, rt, bytes, is_default_endian);
 
        return r;
 }
 
 int kvmppc_handle_store(struct kvm_run *run, struct kvm_vcpu *vcpu,
-                        u64 val, unsigned int bytes, int is_bigendian)
+                       u64 val, unsigned int bytes, int is_default_endian)
 {
        void *data = run->mmio.data;
        int idx, ret;
+       int is_bigendian;
+
+       if (kvmppc_need_byteswap(vcpu)) {
+               /* Default endianness is "little endian". */
+               is_bigendian = !is_default_endian;
+       } else {
+               /* Default endianness is "big endian". */
+               is_bigendian = is_default_endian;
+       }
 
        if (bytes > sizeof(run->mmio.data)) {
                printk(KERN_ERR "%s: bad MMIO length: %d\n", __func__,
index 17e5b23643124347febe56a05f5deb7e1a2e361e..d5edbeb8eb8209e61a9d6524acfa565e3f30782f 100644 (file)
@@ -159,6 +159,21 @@ unsigned int translate_branch(const unsigned int *dest, const unsigned int *src)
        return 0;
 }
 
+#ifdef CONFIG_PPC_BOOK3E_64
+void __patch_exception(int exc, unsigned long addr)
+{
+       extern unsigned int interrupt_base_book3e;
+       unsigned int *ibase = &interrupt_base_book3e;
+
+       /* Our exceptions vectors start with a NOP and -then- a branch
+        * to deal with single stepping from userspace which stops on
+        * the second instruction. Thus we need to patch the second
+        * instruction of the exception, not the first one
+        */
+
+       patch_branch(ibase + (exc / 4) + 1, addr, 0);
+}
+#endif
 
 #ifdef CONFIG_CODE_PATCHING_SELFTEST
 
index b2c68ce139aecbc6819ff8f6493dde59c749fa7e..a5b30c71a8d3f863d6717d0cf51503dbb8387df9 100644 (file)
@@ -231,6 +231,87 @@ _GLOBAL(_rest32gpr_31_x)
        mr      1,11
        blr
 
+#ifdef CONFIG_ALTIVEC
+/* Called with r0 pointing just beyond the end of the vector save area.  */
+
+_GLOBAL(_savevr_20)
+       li      r11,-192
+       stvx    vr20,r11,r0
+_GLOBAL(_savevr_21)
+       li      r11,-176
+       stvx    vr21,r11,r0
+_GLOBAL(_savevr_22)
+       li      r11,-160
+       stvx    vr22,r11,r0
+_GLOBAL(_savevr_23)
+       li      r11,-144
+       stvx    vr23,r11,r0
+_GLOBAL(_savevr_24)
+       li      r11,-128
+       stvx    vr24,r11,r0
+_GLOBAL(_savevr_25)
+       li      r11,-112
+       stvx    vr25,r11,r0
+_GLOBAL(_savevr_26)
+       li      r11,-96
+       stvx    vr26,r11,r0
+_GLOBAL(_savevr_27)
+       li      r11,-80
+       stvx    vr27,r11,r0
+_GLOBAL(_savevr_28)
+       li      r11,-64
+       stvx    vr28,r11,r0
+_GLOBAL(_savevr_29)
+       li      r11,-48
+       stvx    vr29,r11,r0
+_GLOBAL(_savevr_30)
+       li      r11,-32
+       stvx    vr30,r11,r0
+_GLOBAL(_savevr_31)
+       li      r11,-16
+       stvx    vr31,r11,r0
+       blr
+
+_GLOBAL(_restvr_20)
+       li      r11,-192
+       lvx     vr20,r11,r0
+_GLOBAL(_restvr_21)
+       li      r11,-176
+       lvx     vr21,r11,r0
+_GLOBAL(_restvr_22)
+       li      r11,-160
+       lvx     vr22,r11,r0
+_GLOBAL(_restvr_23)
+       li      r11,-144
+       lvx     vr23,r11,r0
+_GLOBAL(_restvr_24)
+       li      r11,-128
+       lvx     vr24,r11,r0
+_GLOBAL(_restvr_25)
+       li      r11,-112
+       lvx     vr25,r11,r0
+_GLOBAL(_restvr_26)
+       li      r11,-96
+       lvx     vr26,r11,r0
+_GLOBAL(_restvr_27)
+       li      r11,-80
+       lvx     vr27,r11,r0
+_GLOBAL(_restvr_28)
+       li      r11,-64
+       lvx     vr28,r11,r0
+_GLOBAL(_restvr_29)
+       li      r11,-48
+       lvx     vr29,r11,r0
+_GLOBAL(_restvr_30)
+       li      r11,-32
+       lvx     vr30,r11,r0
+_GLOBAL(_restvr_31)
+       li      r11,-16
+       lvx     vr31,r11,r0
+       blr
+
+#endif /* CONFIG_ALTIVEC */
+
 #else /* CONFIG_PPC64 */
 
        .section ".text.save.restore","ax",@progbits
@@ -356,6 +437,111 @@ _restgpr0_31:
        mtlr    r0
        blr
 
+#ifdef CONFIG_ALTIVEC
+/* Called with r0 pointing just beyond the end of the vector save area.  */
+
+.globl _savevr_20
+_savevr_20:
+       li      r12,-192
+       stvx    vr20,r12,r0
+.globl _savevr_21
+_savevr_21:
+       li      r12,-176
+       stvx    vr21,r12,r0
+.globl _savevr_22
+_savevr_22:
+       li      r12,-160
+       stvx    vr22,r12,r0
+.globl _savevr_23
+_savevr_23:
+       li      r12,-144
+       stvx    vr23,r12,r0
+.globl _savevr_24
+_savevr_24:
+       li      r12,-128
+       stvx    vr24,r12,r0
+.globl _savevr_25
+_savevr_25:
+       li      r12,-112
+       stvx    vr25,r12,r0
+.globl _savevr_26
+_savevr_26:
+       li      r12,-96
+       stvx    vr26,r12,r0
+.globl _savevr_27
+_savevr_27:
+       li      r12,-80
+       stvx    vr27,r12,r0
+.globl _savevr_28
+_savevr_28:
+       li      r12,-64
+       stvx    vr28,r12,r0
+.globl _savevr_29
+_savevr_29:
+       li      r12,-48
+       stvx    vr29,r12,r0
+.globl _savevr_30
+_savevr_30:
+       li      r12,-32
+       stvx    vr30,r12,r0
+.globl _savevr_31
+_savevr_31:
+       li      r12,-16
+       stvx    vr31,r12,r0
+       blr
+
+.globl _restvr_20
+_restvr_20:
+       li      r12,-192
+       lvx     vr20,r12,r0
+.globl _restvr_21
+_restvr_21:
+       li      r12,-176
+       lvx     vr21,r12,r0
+.globl _restvr_22
+_restvr_22:
+       li      r12,-160
+       lvx     vr22,r12,r0
+.globl _restvr_23
+_restvr_23:
+       li      r12,-144
+       lvx     vr23,r12,r0
+.globl _restvr_24
+_restvr_24:
+       li      r12,-128
+       lvx     vr24,r12,r0
+.globl _restvr_25
+_restvr_25:
+       li      r12,-112
+       lvx     vr25,r12,r0
+.globl _restvr_26
+_restvr_26:
+       li      r12,-96
+       lvx     vr26,r12,r0
+.globl _restvr_27
+_restvr_27:
+       li      r12,-80
+       lvx     vr27,r12,r0
+.globl _restvr_28
+_restvr_28:
+       li      r12,-64
+       lvx     vr28,r12,r0
+.globl _restvr_29
+_restvr_29:
+       li      r12,-48
+       lvx     vr29,r12,r0
+.globl _restvr_30
+_restvr_30:
+       li      r12,-32
+       lvx     vr30,r12,r0
+.globl _restvr_31
+_restvr_31:
+       li      r12,-16
+       lvx     vr31,r12,r0
+       blr
+
+#endif /* CONFIG_ALTIVEC */
+
 #endif /* CONFIG_PPC64 */
 
 #endif
index a73f0884d358d0d9095c992d6c532929f853044c..28337c9709ae60c326bbe9e67364b9fe3c19796e 100644 (file)
@@ -20,6 +20,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/prctl.h>
 
 #include <asm/uaccess.h>
 #include <asm/reg.h>
@@ -275,21 +276,13 @@ int do_spe_mathemu(struct pt_regs *regs)
 
                case EFSCTSF:
                case EFSCTUF:
-                       if (!((vb.wp[1] >> 23) == 0xff && ((vb.wp[1] & 0x7fffff) > 0))) {
-                               /* NaN */
-                               if (((vb.wp[1] >> 23) & 0xff) == 0) {
-                                       /* denorm */
-                                       vc.wp[1] = 0x0;
-                               } else if ((vb.wp[1] >> 31) == 0) {
-                                       /* positive normal */
-                                       vc.wp[1] = (func == EFSCTSF) ?
-                                               0x7fffffff : 0xffffffff;
-                               } else { /* negative normal */
-                                       vc.wp[1] = (func == EFSCTSF) ?
-                                               0x80000000 : 0x0;
-                               }
-                       } else { /* rB is NaN */
-                               vc.wp[1] = 0x0;
+                       if (SB_c == FP_CLS_NAN) {
+                               vc.wp[1] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               SB_e += (func == EFSCTSF ? 31 : 32);
+                               FP_TO_INT_ROUND_S(vc.wp[1], SB, 32,
+                                               (func == EFSCTSF));
                        }
                        goto update_regs;
 
@@ -306,16 +299,25 @@ int do_spe_mathemu(struct pt_regs *regs)
                }
 
                case EFSCTSI:
-               case EFSCTSIZ:
                case EFSCTUI:
+                       if (SB_c == FP_CLS_NAN) {
+                               vc.wp[1] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               FP_TO_INT_ROUND_S(vc.wp[1], SB, 32,
+                                               ((func & 0x3) != 0));
+                       }
+                       goto update_regs;
+
+               case EFSCTSIZ:
                case EFSCTUIZ:
-                       if (func & 0x4) {
-                               _FP_ROUND(1, SB);
+                       if (SB_c == FP_CLS_NAN) {
+                               vc.wp[1] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
                        } else {
-                               _FP_ROUND_ZERO(1, SB);
+                               FP_TO_INT_S(vc.wp[1], SB, 32,
+                                               ((func & 0x3) != 0));
                        }
-                       FP_TO_INT_S(vc.wp[1], SB, 32,
-                                       (((func & 0x3) != 0) || SB_s));
                        goto update_regs;
 
                default:
@@ -404,22 +406,13 @@ cmp_s:
 
                case EFDCTSF:
                case EFDCTUF:
-                       if (!((vb.wp[0] >> 20) == 0x7ff &&
-                          ((vb.wp[0] & 0xfffff) > 0 || (vb.wp[1] > 0)))) {
-                               /* not a NaN */
-                               if (((vb.wp[0] >> 20) & 0x7ff) == 0) {
-                                       /* denorm */
-                                       vc.wp[1] = 0x0;
-                               } else if ((vb.wp[0] >> 31) == 0) {
-                                       /* positive normal */
-                                       vc.wp[1] = (func == EFDCTSF) ?
-                                               0x7fffffff : 0xffffffff;
-                               } else { /* negative normal */
-                                       vc.wp[1] = (func == EFDCTSF) ?
-                                               0x80000000 : 0x0;
-                               }
-                       } else { /* NaN */
-                               vc.wp[1] = 0x0;
+                       if (DB_c == FP_CLS_NAN) {
+                               vc.wp[1] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               DB_e += (func == EFDCTSF ? 31 : 32);
+                               FP_TO_INT_ROUND_D(vc.wp[1], DB, 32,
+                                               (func == EFDCTSF));
                        }
                        goto update_regs;
 
@@ -437,21 +430,35 @@ cmp_s:
 
                case EFDCTUIDZ:
                case EFDCTSIDZ:
-                       _FP_ROUND_ZERO(2, DB);
-                       FP_TO_INT_D(vc.dp[0], DB, 64, ((func & 0x1) == 0));
+                       if (DB_c == FP_CLS_NAN) {
+                               vc.dp[0] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               FP_TO_INT_D(vc.dp[0], DB, 64,
+                                               ((func & 0x1) == 0));
+                       }
                        goto update_regs;
 
                case EFDCTUI:
                case EFDCTSI:
+                       if (DB_c == FP_CLS_NAN) {
+                               vc.wp[1] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               FP_TO_INT_ROUND_D(vc.wp[1], DB, 32,
+                                               ((func & 0x3) != 0));
+                       }
+                       goto update_regs;
+
                case EFDCTUIZ:
                case EFDCTSIZ:
-                       if (func & 0x4) {
-                               _FP_ROUND(2, DB);
+                       if (DB_c == FP_CLS_NAN) {
+                               vc.wp[1] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
                        } else {
-                               _FP_ROUND_ZERO(2, DB);
+                               FP_TO_INT_D(vc.wp[1], DB, 32,
+                                               ((func & 0x3) != 0));
                        }
-                       FP_TO_INT_D(vc.wp[1], DB, 32,
-                                       (((func & 0x3) != 0) || DB_s));
                        goto update_regs;
 
                default:
@@ -556,37 +563,60 @@ cmp_d:
                        cmp = -1;
                        goto cmp_vs;
 
-               case EVFSCTSF:
-                       __asm__ __volatile__ ("mtspr 512, %4\n"
-                               "efsctsf %0, %2\n"
-                               "efsctsf %1, %3\n"
-                               : "=r" (vc.wp[0]), "=r" (vc.wp[1])
-                               : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));
-                       goto update_regs;
-
                case EVFSCTUF:
-                       __asm__ __volatile__ ("mtspr 512, %4\n"
-                               "efsctuf %0, %2\n"
-                               "efsctuf %1, %3\n"
-                               : "=r" (vc.wp[0]), "=r" (vc.wp[1])
-                               : "r" (vb.wp[0]), "r" (vb.wp[1]), "r" (0));
+               case EVFSCTSF:
+                       if (SB0_c == FP_CLS_NAN) {
+                               vc.wp[0] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               SB0_e += (func == EVFSCTSF ? 31 : 32);
+                               FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32,
+                                               (func == EVFSCTSF));
+                       }
+                       if (SB1_c == FP_CLS_NAN) {
+                               vc.wp[1] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               SB1_e += (func == EVFSCTSF ? 31 : 32);
+                               FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32,
+                                               (func == EVFSCTSF));
+                       }
                        goto update_regs;
 
                case EVFSCTUI:
                case EVFSCTSI:
+                       if (SB0_c == FP_CLS_NAN) {
+                               vc.wp[0] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               FP_TO_INT_ROUND_S(vc.wp[0], SB0, 32,
+                                               ((func & 0x3) != 0));
+                       }
+                       if (SB1_c == FP_CLS_NAN) {
+                               vc.wp[1] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               FP_TO_INT_ROUND_S(vc.wp[1], SB1, 32,
+                                               ((func & 0x3) != 0));
+                       }
+                       goto update_regs;
+
                case EVFSCTUIZ:
                case EVFSCTSIZ:
-                       if (func & 0x4) {
-                               _FP_ROUND(1, SB0);
-                               _FP_ROUND(1, SB1);
+                       if (SB0_c == FP_CLS_NAN) {
+                               vc.wp[0] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
                        } else {
-                               _FP_ROUND_ZERO(1, SB0);
-                               _FP_ROUND_ZERO(1, SB1);
+                               FP_TO_INT_S(vc.wp[0], SB0, 32,
+                                               ((func & 0x3) != 0));
+                       }
+                       if (SB1_c == FP_CLS_NAN) {
+                               vc.wp[1] = 0;
+                               FP_SET_EXCEPTION(FP_EX_INVALID);
+                       } else {
+                               FP_TO_INT_S(vc.wp[1], SB1, 32,
+                                               ((func & 0x3) != 0));
                        }
-                       FP_TO_INT_S(vc.wp[0], SB0, 32,
-                                       (((func & 0x3) != 0) || SB0_s));
-                       FP_TO_INT_S(vc.wp[1], SB1, 32,
-                                       (((func & 0x3) != 0) || SB1_s));
                        goto update_regs;
 
                default:
@@ -630,9 +660,27 @@ update_ccr:
        regs->ccr |= (IR << ((7 - ((speinsn >> 23) & 0x7)) << 2));
 
 update_regs:
-       __FPU_FPSCR &= ~FP_EX_MASK;
+       /*
+        * If the "invalid" exception sticky bit was set by the
+        * processor for non-finite input, but was not set before the
+        * instruction being emulated, clear it.  Likewise for the
+        * "underflow" bit, which may have been set by the processor
+        * for exact underflow, not just inexact underflow when the
+        * flag should be set for IEEE 754 semantics.  Other sticky
+        * exceptions will only be set by the processor when they are
+        * correct according to IEEE 754 semantics, and we must not
+        * clear sticky bits that were already set before the emulated
+        * instruction as they represent the user-visible sticky
+        * exception status.  "inexact" traps to kernel are not
+        * required for IEEE semantics and are not enabled by default,
+        * so the "inexact" sticky bit may have been set by a previous
+        * instruction without the kernel being aware of it.
+        */
+       __FPU_FPSCR
+         &= ~(FP_EX_INVALID | FP_EX_UNDERFLOW) | current->thread.spefscr_last;
        __FPU_FPSCR |= (FP_CUR_EXCEPTIONS & FP_EX_MASK);
        mtspr(SPRN_SPEFSCR, __FPU_FPSCR);
+       current->thread.spefscr_last = __FPU_FPSCR;
 
        current->thread.evr[fc] = vc.wp[0];
        regs->gpr[fc] = vc.wp[1];
@@ -644,6 +692,23 @@ update_regs:
        pr_debug("va: %08x  %08x\n", va.wp[0], va.wp[1]);
        pr_debug("vb: %08x  %08x\n", vb.wp[0], vb.wp[1]);
 
+       if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE) {
+               if ((FP_CUR_EXCEPTIONS & FP_EX_DIVZERO)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_DIV))
+                       return 1;
+               if ((FP_CUR_EXCEPTIONS & FP_EX_OVERFLOW)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_OVF))
+                       return 1;
+               if ((FP_CUR_EXCEPTIONS & FP_EX_UNDERFLOW)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_UND))
+                       return 1;
+               if ((FP_CUR_EXCEPTIONS & FP_EX_INEXACT)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_RES))
+                       return 1;
+               if ((FP_CUR_EXCEPTIONS & FP_EX_INVALID)
+                   && (current->thread.fpexc_mode & PR_FP_EXC_INV))
+                       return 1;
+       }
        return 0;
 
 illegal:
@@ -662,21 +727,28 @@ int speround_handler(struct pt_regs *regs)
 {
        union dw_union fgpr;
        int s_lo, s_hi;
-       unsigned long speinsn, type, fc;
+       int lo_inexact, hi_inexact;
+       int fp_result;
+       unsigned long speinsn, type, fb, fc, fptype, func;
 
        if (get_user(speinsn, (unsigned int __user *) regs->nip))
                return -EFAULT;
        if ((speinsn >> 26) != 4)
                return -EINVAL;         /* not an spe instruction */
 
-       type = insn_type(speinsn & 0x7ff);
+       func = speinsn & 0x7ff;
+       type = insn_type(func);
        if (type == XCR) return -ENOSYS;
 
        __FPU_FPSCR = mfspr(SPRN_SPEFSCR);
        pr_debug("speinsn:%08lx spefscr:%08lx\n", speinsn, __FPU_FPSCR);
 
+       fptype = (speinsn >> 5) & 0x7;
+
        /* No need to round if the result is exact */
-       if (!(__FPU_FPSCR & FP_EX_INEXACT))
+       lo_inexact = __FPU_FPSCR & (SPEFSCR_FG | SPEFSCR_FX);
+       hi_inexact = __FPU_FPSCR & (SPEFSCR_FGH | SPEFSCR_FXH);
+       if (!(lo_inexact || (hi_inexact && fptype == VCT)))
                return 0;
 
        fc = (speinsn >> 21) & 0x1f;
@@ -685,9 +757,68 @@ int speround_handler(struct pt_regs *regs)
        fgpr.wp[0] = current->thread.evr[fc];
        fgpr.wp[1] = regs->gpr[fc];
 
+       fb = (speinsn >> 11) & 0x1f;
+       switch (func) {
+       case EFSCTUIZ:
+       case EFSCTSIZ:
+       case EVFSCTUIZ:
+       case EVFSCTSIZ:
+       case EFDCTUIDZ:
+       case EFDCTSIDZ:
+       case EFDCTUIZ:
+       case EFDCTSIZ:
+               /*
+                * These instructions always round to zero,
+                * independent of the rounding mode.
+                */
+               return 0;
+
+       case EFSCTUI:
+       case EFSCTUF:
+       case EVFSCTUI:
+       case EVFSCTUF:
+       case EFDCTUI:
+       case EFDCTUF:
+               fp_result = 0;
+               s_lo = 0;
+               s_hi = 0;
+               break;
+
+       case EFSCTSI:
+       case EFSCTSF:
+               fp_result = 0;
+               /* Recover the sign of a zero result if possible.  */
+               if (fgpr.wp[1] == 0)
+                       s_lo = regs->gpr[fb] & SIGN_BIT_S;
+               break;
+
+       case EVFSCTSI:
+       case EVFSCTSF:
+               fp_result = 0;
+               /* Recover the sign of a zero result if possible.  */
+               if (fgpr.wp[1] == 0)
+                       s_lo = regs->gpr[fb] & SIGN_BIT_S;
+               if (fgpr.wp[0] == 0)
+                       s_hi = current->thread.evr[fb] & SIGN_BIT_S;
+               break;
+
+       case EFDCTSI:
+       case EFDCTSF:
+               fp_result = 0;
+               s_hi = s_lo;
+               /* Recover the sign of a zero result if possible.  */
+               if (fgpr.wp[1] == 0)
+                       s_hi = current->thread.evr[fb] & SIGN_BIT_S;
+               break;
+
+       default:
+               fp_result = 1;
+               break;
+       }
+
        pr_debug("round fgpr: %08x  %08x\n", fgpr.wp[0], fgpr.wp[1]);
 
-       switch ((speinsn >> 5) & 0x7) {
+       switch (fptype) {
        /* Since SPE instructions on E500 core can handle round to nearest
         * and round toward zero with IEEE-754 complied, we just need
         * to handle round toward +Inf and round toward -Inf by software.
@@ -696,25 +827,52 @@ int speround_handler(struct pt_regs *regs)
                if ((FP_ROUNDMODE) == FP_RND_PINF) {
                        if (!s_lo) fgpr.wp[1]++; /* Z > 0, choose Z1 */
                } else { /* round to -Inf */
-                       if (s_lo) fgpr.wp[1]++; /* Z < 0, choose Z2 */
+                       if (s_lo) {
+                               if (fp_result)
+                                       fgpr.wp[1]++; /* Z < 0, choose Z2 */
+                               else
+                                       fgpr.wp[1]--; /* Z < 0, choose Z2 */
+                       }
                }
                break;
 
        case DPFP:
                if (FP_ROUNDMODE == FP_RND_PINF) {
-                       if (!s_hi) fgpr.dp[0]++; /* Z > 0, choose Z1 */
+                       if (!s_hi) {
+                               if (fp_result)
+                                       fgpr.dp[0]++; /* Z > 0, choose Z1 */
+                               else
+                                       fgpr.wp[1]++; /* Z > 0, choose Z1 */
+                       }
                } else { /* round to -Inf */
-                       if (s_hi) fgpr.dp[0]++; /* Z < 0, choose Z2 */
+                       if (s_hi) {
+                               if (fp_result)
+                                       fgpr.dp[0]++; /* Z < 0, choose Z2 */
+                               else
+                                       fgpr.wp[1]--; /* Z < 0, choose Z2 */
+                       }
                }
                break;
 
        case VCT:
                if (FP_ROUNDMODE == FP_RND_PINF) {
-                       if (!s_lo) fgpr.wp[1]++; /* Z_low > 0, choose Z1 */
-                       if (!s_hi) fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */
+                       if (lo_inexact && !s_lo)
+                               fgpr.wp[1]++; /* Z_low > 0, choose Z1 */
+                       if (hi_inexact && !s_hi)
+                               fgpr.wp[0]++; /* Z_high word > 0, choose Z1 */
                } else { /* round to -Inf */
-                       if (s_lo) fgpr.wp[1]++; /* Z_low < 0, choose Z2 */
-                       if (s_hi) fgpr.wp[0]++; /* Z_high < 0, choose Z2 */
+                       if (lo_inexact && s_lo) {
+                               if (fp_result)
+                                       fgpr.wp[1]++; /* Z_low < 0, choose Z2 */
+                               else
+                                       fgpr.wp[1]--; /* Z_low < 0, choose Z2 */
+                       }
+                       if (hi_inexact && s_hi) {
+                               if (fp_result)
+                                       fgpr.wp[0]++; /* Z_high < 0, choose Z2 */
+                               else
+                                       fgpr.wp[0]--; /* Z_high < 0, choose Z2 */
+                       }
                }
                break;
 
@@ -727,6 +885,8 @@ int speround_handler(struct pt_regs *regs)
 
        pr_debug("  to fgpr: %08x  %08x\n", fgpr.wp[0], fgpr.wp[1]);
 
+       if (current->thread.fpexc_mode & PR_FP_EXC_SW_ENABLE)
+               return (current->thread.fpexc_mode & PR_FP_EXC_RES) ? 1 : 0;
        return 0;
 }
 
index 07ba45b0f07c8ed311313c14fdf4422613639e0e..94cd728166d37a1be14a8867ec1ea2f059249d96 100644 (file)
@@ -52,6 +52,7 @@
 #include <asm/smp.h>
 #include <asm/machdep.h>
 #include <asm/setup.h>
+#include <asm/paca.h>
 
 #include "mmu_decl.h"
 
@@ -171,11 +172,10 @@ unsigned long calc_cam_sz(unsigned long ram, unsigned long virt,
        return 1UL << camsize;
 }
 
-unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx)
+static unsigned long map_mem_in_cams_addr(phys_addr_t phys, unsigned long virt,
+                                       unsigned long ram, int max_cam_idx)
 {
        int i;
-       unsigned long virt = PAGE_OFFSET;
-       phys_addr_t phys = memstart_addr;
        unsigned long amount_mapped = 0;
 
        /* Calculate CAM values */
@@ -192,9 +192,23 @@ unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx)
        }
        tlbcam_index = i;
 
+#ifdef CONFIG_PPC64
+       get_paca()->tcd.esel_next = i;
+       get_paca()->tcd.esel_max = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
+       get_paca()->tcd.esel_first = i;
+#endif
+
        return amount_mapped;
 }
 
+unsigned long map_mem_in_cams(unsigned long ram, int max_cam_idx)
+{
+       unsigned long virt = PAGE_OFFSET;
+       phys_addr_t phys = memstart_addr;
+
+       return map_mem_in_cams_addr(phys, virt, ram, max_cam_idx);
+}
+
 #ifdef CONFIG_PPC32
 
 #if defined(CONFIG_LOWMEM_CAM_NUM_BOOL) && (CONFIG_LOWMEM_CAM_NUM >= NUM_TLBCAMS)
@@ -222,7 +236,9 @@ void __init adjust_total_lowmem(void)
        /* adjust lowmem size to __max_low_memory */
        ram = min((phys_addr_t)__max_low_memory, (phys_addr_t)total_lowmem);
 
+       i = switch_to_as1();
        __max_low_memory = map_mem_in_cams(ram, CONFIG_LOWMEM_CAM_NUM);
+       restore_to_as0(i, 0, 0, 1);
 
        pr_info("Memory CAM mapping: ");
        for (i = 0; i < tlbcam_index - 1; i++)
@@ -241,4 +257,62 @@ void setup_initial_memory_limit(phys_addr_t first_memblock_base,
        /* 64M mapped initially according to head_fsl_booke.S */
        memblock_set_current_limit(min_t(u64, limit, 0x04000000));
 }
+
+#ifdef CONFIG_RELOCATABLE
+int __initdata is_second_reloc;
+notrace void __init relocate_init(u64 dt_ptr, phys_addr_t start)
+{
+       unsigned long base = KERNELBASE;
+
+       kernstart_addr = start;
+       if (is_second_reloc) {
+               virt_phys_offset = PAGE_OFFSET - memstart_addr;
+               return;
+       }
+
+       /*
+        * Relocatable kernel support based on processing of dynamic
+        * relocation entries. Before we get the real memstart_addr,
+        * We will compute the virt_phys_offset like this:
+        * virt_phys_offset = stext.run - kernstart_addr
+        *
+        * stext.run = (KERNELBASE & ~0x3ffffff) +
+        *                              (kernstart_addr & 0x3ffffff)
+        * When we relocate, we have :
+        *
+        *      (kernstart_addr & 0x3ffffff) = (stext.run & 0x3ffffff)
+        *
+        * hence:
+        *  virt_phys_offset = (KERNELBASE & ~0x3ffffff) -
+        *                              (kernstart_addr & ~0x3ffffff)
+        *
+        */
+       start &= ~0x3ffffff;
+       base &= ~0x3ffffff;
+       virt_phys_offset = base - start;
+       early_get_first_memblock_info(__va(dt_ptr), NULL);
+       /*
+        * We now get the memstart_addr, then we should check if this
+        * address is the same as what the PAGE_OFFSET map to now. If
+        * not we have to change the map of PAGE_OFFSET to memstart_addr
+        * and do a second relocation.
+        */
+       if (start != memstart_addr) {
+               int n;
+               long offset = start - memstart_addr;
+
+               is_second_reloc = 1;
+               n = switch_to_as1();
+               /* map a 64M area for the second relocation */
+               if (memstart_addr > start)
+                       map_mem_in_cams(0x4000000, CONFIG_LOWMEM_CAM_NUM);
+               else
+                       map_mem_in_cams_addr(start, PAGE_OFFSET + offset,
+                                       0x4000000, CONFIG_LOWMEM_CAM_NUM);
+               restore_to_as0(n, offset, __va(dt_ptr), 1);
+               /* We should never reach here */
+               panic("Relocation error");
+       }
+}
+#endif
 #endif
index d3cbda62857b92ffb0867c4fe0ab1deeb0979313..1136d26a95ae02ac075914e13f54720864b71fea 100644 (file)
@@ -148,7 +148,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
        and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
        andc    r0,r30,r0               /* r0 = pte & ~r0 */
        rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
-       ori     r3,r3,HPTE_R_C          /* Always add "C" bit for perf. */
+       /*
+        * Always add "C" bit for perf. Memory coherence is always enabled
+        */
+       ori     r3,r3,HPTE_R_C | HPTE_R_M
 
        /* We eventually do the icache sync here (maybe inline that
         * code rather than call a C function...) 
@@ -457,7 +460,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
        and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
        andc    r0,r3,r0                /* r0 = pte & ~r0 */
        rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
-       ori     r3,r3,HPTE_R_C          /* Always add "C" bit for perf. */
+       /*
+        * Always add "C" bit for perf. Memory coherence is always enabled
+        */
+       ori     r3,r3,HPTE_R_C | HPTE_R_M
 
        /* We eventually do the icache sync here (maybe inline that
         * code rather than call a C function...)
@@ -795,7 +801,10 @@ END_MMU_FTR_SECTION_IFSET(MMU_FTR_1T_SEGMENT)
        and     r0,r0,r4                /* _PAGE_RW & _PAGE_DIRTY ->r0 bit 30*/
        andc    r0,r30,r0               /* r0 = pte & ~r0 */
        rlwimi  r3,r0,32-1,31,31        /* Insert result into PP lsb */
-       ori     r3,r3,HPTE_R_C          /* Always add "C" bit for perf. */
+       /*
+        * Always add "C" bit for perf. Memory coherence is always enabled
+        */
+       ori     r3,r3,HPTE_R_C | HPTE_R_M
 
        /* We eventually do the icache sync here (maybe inline that
         * code rather than call a C function...)
index 6176b3cdf57991590df2b26f42f27eed593096bb..de6881259aef3bd552c53ea77751093336e2e5be 100644 (file)
@@ -169,9 +169,10 @@ static unsigned long htab_convert_pte_flags(unsigned long pteflags)
        if ((pteflags & _PAGE_USER) && !((pteflags & _PAGE_RW) &&
                                         (pteflags & _PAGE_DIRTY)))
                rflags |= 1;
-
-       /* Always add C */
-       return rflags | HPTE_R_C;
+       /*
+        * Always add "C" bit for perf. Memory coherence is always enabled
+        */
+       return rflags | HPTE_R_C | HPTE_R_M;
 }
 
 int htab_bolt_mapping(unsigned long vstart, unsigned long vend,
index 34de9e0cdc3466313eea62bbdd7079df409547c8..826893fcb3a78b0198d5fa4b0b047428d8852802 100644 (file)
@@ -127,7 +127,11 @@ repeat:
 
                /* Add in WIMG bits */
                rflags |= (new_pmd & (_PAGE_WRITETHRU | _PAGE_NO_CACHE |
-                                     _PAGE_COHERENT | _PAGE_GUARDED));
+                                     _PAGE_GUARDED));
+               /*
+                * enable the memory coherence always
+                */
+               rflags |= HPTE_R_M;
 
                /* Insert into the hash table, primary slot */
                slot = ppc_md.hpte_insert(hpte_group, vpn, pa, rflags, 0,
index 74551b5e41e5156b0720c65ec9cdd1adf988260a..5e4ee2573903eb1af940ac1927c6be61c78fc8a9 100644 (file)
@@ -8,6 +8,44 @@
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+#ifdef CONFIG_PPC64
+static inline int tlb1_next(void)
+{
+       struct paca_struct *paca = get_paca();
+       struct tlb_core_data *tcd;
+       int this, next;
+
+       tcd = paca->tcd_ptr;
+       this = tcd->esel_next;
+
+       next = this + 1;
+       if (next >= tcd->esel_max)
+               next = tcd->esel_first;
+
+       tcd->esel_next = next;
+       return this;
+}
+#else
+static inline int tlb1_next(void)
+{
+       int index, ncams;
+
+       ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
+
+       index = __get_cpu_var(next_tlbcam_idx);
+
+       /* Just round-robin the entries and wrap when we hit the end */
+       if (unlikely(index == ncams - 1))
+               __get_cpu_var(next_tlbcam_idx) = tlbcam_index;
+       else
+               __get_cpu_var(next_tlbcam_idx)++;
+
+       return index;
+}
+#endif /* !PPC64 */
+#endif /* FSL */
+
 static inline int mmu_get_tsize(int psize)
 {
        return mmu_psize_defs[psize].enc;
@@ -47,7 +85,7 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea,
        struct mm_struct *mm;
 
 #ifdef CONFIG_PPC_FSL_BOOK3E
-       int index, ncams;
+       int index;
 #endif
 
        if (unlikely(is_kernel_addr(ea)))
@@ -77,18 +115,11 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea,
        }
 
 #ifdef CONFIG_PPC_FSL_BOOK3E
-       ncams = mfspr(SPRN_TLB1CFG) & TLBnCFG_N_ENTRY;
-
        /* We have to use the CAM(TLB1) on FSL parts for hugepages */
-       index = __get_cpu_var(next_tlbcam_idx);
+       index = tlb1_next();
        mtspr(SPRN_MAS0, MAS0_ESEL(index) | MAS0_TLBSEL(1));
-
-       /* Just round-robin the entries and wrap when we hit the end */
-       if (unlikely(index == ncams - 1))
-               __get_cpu_var(next_tlbcam_idx) = tlbcam_index;
-       else
-               __get_cpu_var(next_tlbcam_idx)++;
 #endif
+
        mas1 = MAS1_VALID | MAS1_TID(mm->context.id) | MAS1_TSIZE(tsize);
        mas2 = ea & ~((1UL << shift) - 1);
        mas2 |= (pte_val(pte) >> PTE_WIMGE_SHIFT) & MAS2_WIMGE_MASK;
@@ -103,7 +134,8 @@ void book3e_hugetlb_preload(struct vm_area_struct *vma, unsigned long ea,
        if (mmu_has_feature(MMU_FTR_USE_PAIRED_MAS)) {
                mtspr(SPRN_MAS7_MAS3, mas7_3);
        } else {
-               mtspr(SPRN_MAS7, upper_32_bits(mas7_3));
+               if (mmu_has_feature(MMU_FTR_BIG_PHYS))
+                       mtspr(SPRN_MAS7, upper_32_bits(mas7_3));
                mtspr(SPRN_MAS3, lower_32_bits(mas7_3));
        }
 
index 0b7fb6761015526a38be8dac7ee51d0ca4d9f161..a5bcf930119691ad01c4116faaece823292669aa 100644 (file)
@@ -99,6 +99,10 @@ int __hash_page_huge(unsigned long ea, unsigned long access, unsigned long vsid,
                /* Add in WIMG bits */
                rflags |= (new_pte & (_PAGE_WRITETHRU | _PAGE_NO_CACHE |
                                      _PAGE_COHERENT | _PAGE_GUARDED));
+               /*
+                * enable the memory coherence always
+                */
+               rflags |= HPTE_R_M;
 
                slot = hpte_insert_repeating(hash, vpn, pa, rflags, 0,
                                             mmu_psize, ssize);
index 90bb6d9409bfd77b84eb62cd5b2cb594238780b1..eb923654ba80e7412760ce67e6429486576fb044 100644 (file)
@@ -472,12 +472,13 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte)
 {
        struct hugepd_freelist **batchp;
 
-       batchp = &__get_cpu_var(hugepd_freelist_cur);
+       batchp = &get_cpu_var(hugepd_freelist_cur);
 
        if (atomic_read(&tlb->mm->mm_users) < 2 ||
            cpumask_equal(mm_cpumask(tlb->mm),
                          cpumask_of(smp_processor_id()))) {
                kmem_cache_free(hugepte_cache, hugepte);
+        put_cpu_var(hugepd_freelist_cur);
                return;
        }
 
@@ -491,6 +492,7 @@ static void hugepd_free(struct mmu_gather *tlb, void *hugepte)
                call_rcu_sched(&(*batchp)->rcu, hugepd_free_rcu_callback);
                *batchp = NULL;
        }
+       put_cpu_var(hugepd_freelist_cur);
 }
 #endif
 
index 8c1dd23652a13e32f0818772e62b9b2ec24539b1..4b5cd5c2594d9b5ca507bc80751f6d1003fde4d6 100644 (file)
@@ -307,6 +307,12 @@ static void __init register_page_bootmem_info(void)
 
 void __init mem_init(void)
 {
+       /*
+        * book3s is limited to 16 page sizes due to encoding this in
+        * a 4-bit field for slices.
+        */
+       BUILD_BUG_ON(MMU_PAGE_COUNT > 16);
+
 #ifdef CONFIG_SWIOTLB
        swiotlb_init(0);
 #endif
@@ -507,7 +513,7 @@ void update_mmu_cache(struct vm_area_struct *vma, unsigned long address,
  * System memory should not be in /proc/iomem but various tools expect it
  * (eg kdump).
  */
-static int add_system_ram_resources(void)
+static int __init add_system_ram_resources(void)
 {
        struct memblock_region *reg;
 
index 83eb5d5f53d52f51c278db4ff0f0d2d75a0f7c54..9615d82919b8b47075794acbf1dc44038aaf8ea8 100644 (file)
@@ -148,6 +148,8 @@ extern unsigned long calc_cam_sz(unsigned long ram, unsigned long virt,
 extern void MMU_init_hw(void);
 extern unsigned long mmu_mapin_ram(unsigned long top);
 extern void adjust_total_lowmem(void);
+extern int switch_to_as1(void);
+extern void restore_to_as0(int esel, int offset, void *dt_ptr, int bootcpu);
 #endif
 extern void loadcam_entry(unsigned int index);
 
index 5a944f25e94ff4618661cd6efaea6ca3140157c8..30a42e24bf14f467c3e5cc25eb7fdef4ebd98203 100644 (file)
@@ -31,6 +31,8 @@
 #include <asm/sparsemem.h>
 #include <asm/prom.h>
 #include <asm/smp.h>
+#include <asm/cputhreads.h>
+#include <asm/topology.h>
 #include <asm/firmware.h>
 #include <asm/paca.h>
 #include <asm/hvcall.h>
@@ -152,9 +154,22 @@ static void __init get_node_active_region(unsigned long pfn,
        }
 }
 
-static void map_cpu_to_node(int cpu, int node)
+static void reset_numa_cpu_lookup_table(void)
+{
+       unsigned int cpu;
+
+       for_each_possible_cpu(cpu)
+               numa_cpu_lookup_table[cpu] = -1;
+}
+
+static void update_numa_cpu_lookup_table(unsigned int cpu, int node)
 {
        numa_cpu_lookup_table[cpu] = node;
+}
+
+static void map_cpu_to_node(int cpu, int node)
+{
+       update_numa_cpu_lookup_table(cpu, node);
 
        dbg("adding cpu %d to node %d\n", cpu, node);
 
@@ -522,11 +537,24 @@ static int of_drconf_to_nid_single(struct of_drconf_cell *drmem,
  */
 static int numa_setup_cpu(unsigned long lcpu)
 {
-       int nid = 0;
-       struct device_node *cpu = of_get_cpu_node(lcpu, NULL);
+       int nid;
+       struct device_node *cpu;
+
+       /*
+        * If a valid cpu-to-node mapping is already available, use it
+        * directly instead of querying the firmware, since it represents
+        * the most recent mapping notified to us by the platform (eg: VPHN).
+        */
+       if ((nid = numa_cpu_lookup_table[lcpu]) >= 0) {
+               map_cpu_to_node(lcpu, nid);
+               return nid;
+       }
+
+       cpu = of_get_cpu_node(lcpu, NULL);
 
        if (!cpu) {
                WARN_ON(1);
+               nid = 0;
                goto out;
        }
 
@@ -542,16 +570,38 @@ out:
        return nid;
 }
 
+static void verify_cpu_node_mapping(int cpu, int node)
+{
+       int base, sibling, i;
+
+       /* Verify that all the threads in the core belong to the same node */
+       base = cpu_first_thread_sibling(cpu);
+
+       for (i = 0; i < threads_per_core; i++) {
+               sibling = base + i;
+
+               if (sibling == cpu || cpu_is_offline(sibling))
+                       continue;
+
+               if (cpu_to_node(sibling) != node) {
+                       WARN(1, "CPU thread siblings %d and %d don't belong"
+                               " to the same node!\n", cpu, sibling);
+                       break;
+               }
+       }
+}
+
 static int cpu_numa_callback(struct notifier_block *nfb, unsigned long action,
                             void *hcpu)
 {
        unsigned long lcpu = (unsigned long)hcpu;
-       int ret = NOTIFY_DONE;
+       int ret = NOTIFY_DONE, nid;
 
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               numa_setup_cpu(lcpu);
+               nid = numa_setup_cpu(lcpu);
+               verify_cpu_node_mapping((int)lcpu, nid);
                ret = NOTIFY_OK;
                break;
 #ifdef CONFIG_HOTPLUG_CPU
@@ -1069,6 +1119,7 @@ void __init do_init_bootmem(void)
         */
        setup_node_to_cpumask_map();
 
+       reset_numa_cpu_lookup_table();
        register_cpu_notifier(&ppc64_numa_nb);
        cpu_numa_callback(&ppc64_numa_nb, CPU_UP_PREPARE,
                          (void *)(unsigned long)boot_cpuid);
@@ -1447,6 +1498,33 @@ static int update_cpu_topology(void *data)
        return 0;
 }
 
+static int update_lookup_table(void *data)
+{
+       struct topology_update_data *update;
+
+       if (!data)
+               return -EINVAL;
+
+       /*
+        * Upon topology update, the numa-cpu lookup table needs to be updated
+        * for all threads in the core, including offline CPUs, to ensure that
+        * future hotplug operations respect the cpu-to-node associativity
+        * properly.
+        */
+       for (update = data; update; update = update->next) {
+               int nid, base, j;
+
+               nid = update->new_nid;
+               base = cpu_first_thread_sibling(update->cpu);
+
+               for (j = 0; j < threads_per_core; j++) {
+                       update_numa_cpu_lookup_table(base + j, nid);
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Update the node maps and sysfs entries for each cpu whose home node
  * has changed. Returns 1 when the topology has changed, and 0 otherwise.
@@ -1515,6 +1593,14 @@ int arch_update_cpu_topology(void)
 
        stop_machine(update_cpu_topology, &updates[0], &updated_cpus);
 
+       /*
+        * Update the numa-cpu lookup table with the new mappings, even for
+        * offline CPUs. It is best to perform this update from the stop-
+        * machine context.
+        */
+       stop_machine(update_lookup_table, &updates[0],
+                                       cpumask_of(raw_smp_processor_id()));
+
        for (ud = &updates[0]; ud; ud = ud->next) {
                unregister_cpu_under_node(ud->cpu, ud->old_nid);
                register_cpu_under_node(ud->cpu, ud->new_nid);
@@ -1699,7 +1785,7 @@ static const struct file_operations topology_ops = {
 static int topology_update_init(void)
 {
        start_topology_update();
-       proc_create("powerpc/topology_updates", 644, NULL, &topology_ops);
+       proc_create("powerpc/topology_updates", 0644, NULL, &topology_ops);
 
        return 0;
 }
index 841e0d00863c94d99cac5c139b887dc97c21cfe1..c695943a513cc638621c830f537ea903ccfa3b86 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/kernel.h>
 #include <linux/gfp.h>
 #include <linux/mm.h>
-#include <linux/init.h>
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
 #include <linux/hugetlb.h>
@@ -174,7 +173,7 @@ void set_pte_at(struct mm_struct *mm, unsigned long addr, pte_t *ptep,
                pte_t pte)
 {
 #ifdef CONFIG_DEBUG_VM
-       WARN_ON(pte_present(*ptep));
+       WARN_ON(pte_val(*ptep) & _PAGE_PRESENT);
 #endif
        /* Note: mm->context.id might not yet have been assigned as
         * this context might not have been activated yet when this
index 5b9601715289c450a23e41b7ffc62d428496b8c9..343a87fa78b5eb3ea403c7a4dcf18ef5da7e2b63 100644 (file)
@@ -299,6 +299,7 @@ int map_page(unsigned long va, phys_addr_t pa, int flags)
                set_pte_at(&init_mm, va, pg, pfn_pte(pa >> PAGE_SHIFT,
                                                     __pgprot(flags)));
        }
+       smp_wmb();
        return err;
 }
 
index 9d95786aa80ffbdcb8601379d774fc1f158006d0..65b7b65e8708bd1867861f4b519d207b25beb5a7 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/swap.h>
 #include <linux/stddef.h>
 #include <linux/vmalloc.h>
-#include <linux/init.h>
 #include <linux/bootmem.h>
 #include <linux/memblock.h>
 #include <linux/slab.h>
@@ -153,6 +152,18 @@ int map_kernel_page(unsigned long ea, unsigned long pa, int flags)
                }
 #endif /* !CONFIG_PPC_MMU_NOHASH */
        }
+
+#ifdef CONFIG_PPC_BOOK3E_64
+       /*
+        * With hardware tablewalk, a sync is needed to ensure that
+        * subsequent accesses see the PTE we just wrote.  Unlike userspace
+        * mappings, we can't tolerate spurious faults, so make sure
+        * the new PTE will be seen the first time.
+        */
+       mb();
+#else
+       smp_wmb();
+#endif
        return 0;
 }
 
@@ -687,7 +698,7 @@ void set_pmd_at(struct mm_struct *mm, unsigned long addr,
                pmd_t *pmdp, pmd_t pmd)
 {
 #ifdef CONFIG_DEBUG_VM
-       WARN_ON(!pmd_none(*pmdp));
+       WARN_ON(pmd_val(*pmdp) & _PAGE_PRESENT);
        assert_spin_locked(&mm->page_table_lock);
        WARN_ON(!pmd_trans_huge(pmd));
 #endif
index 7ce9cf3b698835c0dd2b2644d137ff7549c68e72..b0c75cc15efc673a0ff8f22e0c0e6ef8dc18a038 100644 (file)
@@ -408,7 +408,7 @@ unsigned long slice_get_unmapped_area(unsigned long addr, unsigned long len,
        if (fixed && (addr & ((1ul << pshift) - 1)))
                return -EINVAL;
        if (fixed && addr > (mm->task_size - len))
-               return -EINVAL;
+               return -ENOMEM;
 
        /* If hint, make sure it matches our alignment restrictions */
        if (!fixed && addr) {
index 36e44b4260ebd25ea5fa34660d7cbd81f71bf760..c99f6510a0b267220253249ed836e3dee4327ba7 100644 (file)
@@ -23,7 +23,6 @@
 
 #include <linux/kernel.h>
 #include <linux/mm.h>
-#include <linux/init.h>
 #include <linux/percpu.h>
 #include <linux/hardirq.h>
 #include <asm/pgalloc.h>
index b4113bf863538adbf6d0bffdaa3aabe090270064..c95eb323e9ae5ac8e07feb28c024127266e405a8 100644 (file)
@@ -136,7 +136,7 @@ BEGIN_MMU_FTR_SECTION
         */
        PPC_TLBSRX_DOT(0,R16)
        ldx     r14,r14,r15             /* grab pgd entry */
-       beq     normal_tlb_miss_done    /* tlb exists already, bail */
+       beq     tlb_miss_done_bolted    /* tlb exists already, bail */
 MMU_FTR_SECTION_ELSE
        ldx     r14,r14,r15             /* grab pgd entry */
 ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBRSRV)
@@ -192,6 +192,7 @@ ALT_MMU_FTR_SECTION_END_IFSET(MMU_FTR_USE_TLBRSRV)
        mtspr   SPRN_MAS7_MAS3,r15
        tlbwe
 
+tlb_miss_done_bolted:
        TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK)
        tlb_epilog_bolted
        rfi
@@ -239,6 +240,178 @@ itlb_miss_fault_bolted:
        beq     tlb_miss_common_bolted
        b       itlb_miss_kernel_bolted
 
+#ifdef CONFIG_PPC_FSL_BOOK3E
+/*
+ * TLB miss handling for e6500 and derivatives, using hardware tablewalk.
+ *
+ * Linear mapping is bolted: no virtual page table or nested TLB misses
+ * Indirect entries in TLB1, hardware loads resulting direct entries
+ *    into TLB0
+ * No HES or NV hint on TLB1, so we need to do software round-robin
+ * No tlbsrx. so we need a spinlock, and we have to deal
+ *    with MAS-damage caused by tlbsx
+ * 4K pages only
+ */
+
+       START_EXCEPTION(instruction_tlb_miss_e6500)
+       tlb_prolog_bolted BOOKE_INTERRUPT_ITLB_MISS SPRN_SRR0
+
+       ld      r11,PACA_TCD_PTR(r13)
+       srdi.   r15,r16,60              /* get region */
+       ori     r16,r16,1
+
+       TLB_MISS_STATS_SAVE_INFO_BOLTED
+       bne     tlb_miss_kernel_e6500   /* user/kernel test */
+
+       b       tlb_miss_common_e6500
+
+       START_EXCEPTION(data_tlb_miss_e6500)
+       tlb_prolog_bolted BOOKE_INTERRUPT_DTLB_MISS SPRN_DEAR
+
+       ld      r11,PACA_TCD_PTR(r13)
+       srdi.   r15,r16,60              /* get region */
+       rldicr  r16,r16,0,62
+
+       TLB_MISS_STATS_SAVE_INFO_BOLTED
+       bne     tlb_miss_kernel_e6500   /* user vs kernel check */
+
+/*
+ * This is the guts of the TLB miss handler for e6500 and derivatives.
+ * We are entered with:
+ *
+ * r16 = page of faulting address (low bit 0 if data, 1 if instruction)
+ * r15 = crap (free to use)
+ * r14 = page table base
+ * r13 = PACA
+ * r11 = tlb_per_core ptr
+ * r10 = crap (free to use)
+ */
+tlb_miss_common_e6500:
+       /*
+        * Search if we already have an indirect entry for that virtual
+        * address, and if we do, bail out.
+        *
+        * MAS6:IND should be already set based on MAS4
+        */
+       addi    r10,r11,TCD_LOCK
+1:     lbarx   r15,0,r10
+       cmpdi   r15,0
+       bne     2f
+       li      r15,1
+       stbcx.  r15,0,r10
+       bne     1b
+       .subsection 1
+2:     lbz     r15,0(r10)
+       cmpdi   r15,0
+       bne     2b
+       b       1b
+       .previous
+
+       mfspr   r15,SPRN_MAS2
+
+       tlbsx   0,r16
+       mfspr   r10,SPRN_MAS1
+       andis.  r10,r10,MAS1_VALID@h
+       bne     tlb_miss_done_e6500
+
+       /* Undo MAS-damage from the tlbsx */
+       mfspr   r10,SPRN_MAS1
+       oris    r10,r10,MAS1_VALID@h
+       mtspr   SPRN_MAS1,r10
+       mtspr   SPRN_MAS2,r15
+
+       /* Now, we need to walk the page tables. First check if we are in
+        * range.
+        */
+       rldicl. r10,r16,64-PGTABLE_EADDR_SIZE,PGTABLE_EADDR_SIZE+4
+       bne-    tlb_miss_fault_e6500
+
+       rldicl  r15,r16,64-PGDIR_SHIFT+3,64-PGD_INDEX_SIZE-3
+       cmpldi  cr0,r14,0
+       clrrdi  r15,r15,3
+       beq-    tlb_miss_fault_e6500 /* No PGDIR, bail */
+       ldx     r14,r14,r15             /* grab pgd entry */
+
+       rldicl  r15,r16,64-PUD_SHIFT+3,64-PUD_INDEX_SIZE-3
+       clrrdi  r15,r15,3
+       cmpdi   cr0,r14,0
+       bge     tlb_miss_fault_e6500    /* Bad pgd entry or hugepage; bail */
+       ldx     r14,r14,r15             /* grab pud entry */
+
+       rldicl  r15,r16,64-PMD_SHIFT+3,64-PMD_INDEX_SIZE-3
+       clrrdi  r15,r15,3
+       cmpdi   cr0,r14,0
+       bge     tlb_miss_fault_e6500
+       ldx     r14,r14,r15             /* Grab pmd entry */
+
+       mfspr   r10,SPRN_MAS0
+       cmpdi   cr0,r14,0
+       bge     tlb_miss_fault_e6500
+
+       /* Now we build the MAS for a 2M indirect page:
+        *
+        * MAS 0   :    ESEL needs to be filled by software round-robin
+        * MAS 1   :    Fully set up
+        *               - PID already updated by caller if necessary
+        *               - TSIZE for now is base ind page size always
+        *               - TID already cleared if necessary
+        * MAS 2   :    Default not 2M-aligned, need to be redone
+        * MAS 3+7 :    Needs to be done
+        */
+
+       ori     r14,r14,(BOOK3E_PAGESZ_4K << MAS3_SPSIZE_SHIFT)
+       mtspr   SPRN_MAS7_MAS3,r14
+
+       clrrdi  r15,r16,21              /* make EA 2M-aligned */
+       mtspr   SPRN_MAS2,r15
+
+       lbz     r15,TCD_ESEL_NEXT(r11)
+       lbz     r16,TCD_ESEL_MAX(r11)
+       lbz     r14,TCD_ESEL_FIRST(r11)
+       rlwimi  r10,r15,16,0x00ff0000   /* insert esel_next into MAS0 */
+       addi    r15,r15,1               /* increment esel_next */
+       mtspr   SPRN_MAS0,r10
+       cmpw    r15,r16
+       iseleq  r15,r14,r15             /* if next == last use first */
+       stb     r15,TCD_ESEL_NEXT(r11)
+
+       tlbwe
+
+tlb_miss_done_e6500:
+       .macro  tlb_unlock_e6500
+       li      r15,0
+       isync
+       stb     r15,TCD_LOCK(r11)
+       .endm
+
+       tlb_unlock_e6500
+       TLB_MISS_STATS_X(MMSTAT_TLB_MISS_NORM_OK)
+       tlb_epilog_bolted
+       rfi
+
+tlb_miss_kernel_e6500:
+       mfspr   r10,SPRN_MAS1
+       ld      r14,PACA_KERNELPGD(r13)
+       cmpldi  cr0,r15,8               /* Check for vmalloc region */
+       rlwinm  r10,r10,0,16,1          /* Clear TID */
+       mtspr   SPRN_MAS1,r10
+       beq+    tlb_miss_common_e6500
+
+tlb_miss_fault_e6500:
+       tlb_unlock_e6500
+       /* We need to check if it was an instruction miss */
+       andi.   r16,r16,1
+       bne     itlb_miss_fault_e6500
+dtlb_miss_fault_e6500:
+       TLB_MISS_STATS_D(MMSTAT_TLB_MISS_NORM_FAULT)
+       tlb_epilog_bolted
+       b       exc_data_storage_book3e
+itlb_miss_fault_e6500:
+       TLB_MISS_STATS_I(MMSTAT_TLB_MISS_NORM_FAULT)
+       tlb_epilog_bolted
+       b       exc_instruction_storage_book3e
+#endif /* CONFIG_PPC_FSL_BOOK3E */
+
 /**********************************************************************
  *                                                                    *
  * TLB miss handling for Book3E with TLB reservation and HES support  *
index 358d743031385ae7a269ba65200483227126d372..b37a58e1c92da8bfa9092828f6d3a92126da29d9 100644 (file)
@@ -43,6 +43,7 @@
 #include <asm/tlb.h>
 #include <asm/code-patching.h>
 #include <asm/hugetlb.h>
+#include <asm/paca.h>
 
 #include "mmu_decl.h"
 
@@ -58,6 +59,10 @@ struct mmu_psize_def mmu_psize_defs[MMU_PAGE_COUNT] = {
                .shift  = 12,
                .enc    = BOOK3E_PAGESZ_4K,
        },
+       [MMU_PAGE_2M] = {
+               .shift  = 21,
+               .enc    = BOOK3E_PAGESZ_2M,
+       },
        [MMU_PAGE_4M] = {
                .shift  = 22,
                .enc    = BOOK3E_PAGESZ_4M,
@@ -136,7 +141,7 @@ static inline int mmu_get_tsize(int psize)
 int mmu_linear_psize;          /* Page size used for the linear mapping */
 int mmu_pte_psize;             /* Page size used for PTE pages */
 int mmu_vmemmap_psize;         /* Page size used for the virtual mem map */
-int book3e_htw_enabled;                /* Is HW tablewalk enabled ? */
+int book3e_htw_mode;           /* HW tablewalk?  Value is PPC_HTW_* */
 unsigned long linear_map_top;  /* Top of linear mapping */
 
 #endif /* CONFIG_PPC64 */
@@ -377,7 +382,7 @@ void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address)
 {
        int tsize = mmu_psize_defs[mmu_pte_psize].enc;
 
-       if (book3e_htw_enabled) {
+       if (book3e_htw_mode != PPC_HTW_NONE) {
                unsigned long start = address & PMD_MASK;
                unsigned long end = address + PMD_SIZE;
                unsigned long size = 1UL << mmu_psize_defs[mmu_pte_psize].shift;
@@ -430,7 +435,7 @@ static void setup_page_sizes(void)
                        def = &mmu_psize_defs[psize];
                        shift = def->shift;
 
-                       if (shift == 0)
+                       if (shift == 0 || shift & 1)
                                continue;
 
                        /* adjust to be in terms of 4^shift Kb */
@@ -440,21 +445,40 @@ static void setup_page_sizes(void)
                                def->flags |= MMU_PAGE_SIZE_DIRECT;
                }
 
-               goto no_indirect;
+               goto out;
        }
 
        if (fsl_mmu && (mmucfg & MMUCFG_MAVN) == MMUCFG_MAVN_V2) {
-               u32 tlb1ps = mfspr(SPRN_TLB1PS);
+               u32 tlb1cfg, tlb1ps;
+
+               tlb0cfg = mfspr(SPRN_TLB0CFG);
+               tlb1cfg = mfspr(SPRN_TLB1CFG);
+               tlb1ps = mfspr(SPRN_TLB1PS);
+               eptcfg = mfspr(SPRN_EPTCFG);
+
+               if ((tlb1cfg & TLBnCFG_IND) && (tlb0cfg & TLBnCFG_PT))
+                       book3e_htw_mode = PPC_HTW_E6500;
+
+               /*
+                * We expect 4K subpage size and unrestricted indirect size.
+                * The lack of a restriction on indirect size is a Freescale
+                * extension, indicated by PSn = 0 but SPSn != 0.
+                */
+               if (eptcfg != 2)
+                       book3e_htw_mode = PPC_HTW_NONE;
 
                for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
                        struct mmu_psize_def *def = &mmu_psize_defs[psize];
 
                        if (tlb1ps & (1U << (def->shift - 10))) {
                                def->flags |= MMU_PAGE_SIZE_DIRECT;
+
+                               if (book3e_htw_mode && psize == MMU_PAGE_2M)
+                                       def->flags |= MMU_PAGE_SIZE_INDIRECT;
                        }
                }
 
-               goto no_indirect;
+               goto out;
        }
 #endif
 
@@ -471,8 +495,11 @@ static void setup_page_sizes(void)
        }
 
        /* Indirect page sizes supported ? */
-       if ((tlb0cfg & TLBnCFG_IND) == 0)
-               goto no_indirect;
+       if ((tlb0cfg & TLBnCFG_IND) == 0 ||
+           (tlb0cfg & TLBnCFG_PT) == 0)
+               goto out;
+
+       book3e_htw_mode = PPC_HTW_IBM;
 
        /* Now, we only deal with one IND page size for each
         * direct size. Hopefully all implementations today are
@@ -497,8 +524,8 @@ static void setup_page_sizes(void)
                                def->ind = ps + 10;
                }
        }
- no_indirect:
 
+out:
        /* Cleanup array and print summary */
        pr_info("MMU: Supported page sizes\n");
        for (psize = 0; psize < MMU_PAGE_COUNT; ++psize) {
@@ -518,44 +545,27 @@ static void setup_page_sizes(void)
        }
 }
 
-static void __patch_exception(int exc, unsigned long addr)
-{
-       extern unsigned int interrupt_base_book3e;
-       unsigned int *ibase = &interrupt_base_book3e;
-       /* Our exceptions vectors start with a NOP and -then- a branch
-        * to deal with single stepping from userspace which stops on
-        * the second instruction. Thus we need to patch the second
-        * instruction of the exception, not the first one
-        */
-
-       patch_branch(ibase + (exc / 4) + 1, addr, 0);
-}
-
-#define patch_exception(exc, name) do { \
-       extern unsigned int name; \
-       __patch_exception((exc), (unsigned long)&name); \
-} while (0)
-
 static void setup_mmu_htw(void)
 {
-       /* Check if HW tablewalk is present, and if yes, enable it by:
-        *
-        * - patching the TLB miss handlers to branch to the
-        *   one dedicates to it
-        *
-        * - setting the global book3e_htw_enabled
-                */
-       unsigned int tlb0cfg = mfspr(SPRN_TLB0CFG);
+       /*
+        * If we want to use HW tablewalk, enable it by patching the TLB miss
+        * handlers to branch to the one dedicated to it.
+        */
 
-       if ((tlb0cfg & TLBnCFG_IND) &&
-           (tlb0cfg & TLBnCFG_PT)) {
+       switch (book3e_htw_mode) {
+       case PPC_HTW_IBM:
                patch_exception(0x1c0, exc_data_tlb_miss_htw_book3e);
                patch_exception(0x1e0, exc_instruction_tlb_miss_htw_book3e);
-               book3e_htw_enabled = 1;
+               break;
+#ifdef CONFIG_PPC_FSL_BOOK3E
+       case PPC_HTW_E6500:
+               patch_exception(0x1c0, exc_data_tlb_miss_e6500_book3e);
+               patch_exception(0x1e0, exc_instruction_tlb_miss_e6500_book3e);
+               break;
+#endif
        }
        pr_info("MMU: Book3E HW tablewalk %s\n",
-               book3e_htw_enabled ? "enabled" : "not supported");
+               book3e_htw_mode != PPC_HTW_NONE ? "enabled" : "not supported");
 }
 
 /*
@@ -595,8 +605,16 @@ static void __early_init_mmu(int boot_cpu)
        /* Set MAS4 based on page table setting */
 
        mas4 = 0x4 << MAS4_WIMGED_SHIFT;
-       if (book3e_htw_enabled) {
-               mas4 |= mas4 | MAS4_INDD;
+       switch (book3e_htw_mode) {
+       case PPC_HTW_E6500:
+               mas4 |= MAS4_INDD;
+               mas4 |= BOOK3E_PAGESZ_2M << MAS4_TSIZED_SHIFT;
+               mas4 |= MAS4_TLBSELD(1);
+               mmu_pte_psize = MMU_PAGE_2M;
+               break;
+
+       case PPC_HTW_IBM:
+               mas4 |= MAS4_INDD;
 #ifdef CONFIG_PPC_64K_PAGES
                mas4 |= BOOK3E_PAGESZ_256M << MAS4_TSIZED_SHIFT;
                mmu_pte_psize = MMU_PAGE_256M;
@@ -604,13 +622,16 @@ static void __early_init_mmu(int boot_cpu)
                mas4 |= BOOK3E_PAGESZ_1M << MAS4_TSIZED_SHIFT;
                mmu_pte_psize = MMU_PAGE_1M;
 #endif
-       } else {
+               break;
+
+       case PPC_HTW_NONE:
 #ifdef CONFIG_PPC_64K_PAGES
                mas4 |= BOOK3E_PAGESZ_64K << MAS4_TSIZED_SHIFT;
 #else
                mas4 |= BOOK3E_PAGESZ_4K << MAS4_TSIZED_SHIFT;
 #endif
                mmu_pte_psize = mmu_virtual_psize;
+               break;
        }
        mtspr(SPRN_MAS4, mas4);
 
@@ -630,8 +651,11 @@ static void __early_init_mmu(int boot_cpu)
                /* limit memory so we dont have linear faults */
                memblock_enforce_memory_limit(linear_map_top);
 
-               patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
-               patch_exception(0x1e0, exc_instruction_tlb_miss_bolted_book3e);
+               if (book3e_htw_mode == PPC_HTW_NONE) {
+                       patch_exception(0x1c0, exc_data_tlb_miss_bolted_book3e);
+                       patch_exception(0x1e0,
+                               exc_instruction_tlb_miss_bolted_book3e);
+               }
        }
 #endif
 
index 626ad081639f0e25e910bd3207082d097a684c6c..43ff3c797fbfed1eb3191470ce57813107b10619 100644 (file)
@@ -402,7 +402,9 @@ _GLOBAL(set_context)
  * Load TLBCAM[index] entry in to the L2 CAM MMU
  */
 _GLOBAL(loadcam_entry)
-       LOAD_REG_ADDR(r4, TLBCAM)
+       mflr    r5
+       LOAD_REG_ADDR_PIC(r4, TLBCAM)
+       mtlr    r5
        mulli   r5,r3,TLBCAM_SIZE
        add     r3,r5,r4
        lwz     r4,TLBCAM_MAS0(r3)
index ff617246d128b7a9c5555c42f2b22f4bf9cfa000..d29b6e4e5e721f1509417a0eef829dcaf58dd80b 100644 (file)
@@ -16,7 +16,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
index b9589c19ccdabff66348caae82bf49ec2ed1d243..1f0ebdeea5f77cdd63a844680912242d8b0a7574 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <linux/cpufreq.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/jiffies.h>
 #include <linux/kthread.h>
 #include <linux/oprofile.h>
index 2a82d3ed464d09123db06c59c429014176611272..14cf86fdddab4373f76594509e0cc5789b33a371 100644 (file)
@@ -14,7 +14,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
index 42f778dff919b3c75977a2dd118217259647de7a..a114a7c22d40a9cbce59550a973c0f784552c6ca 100644 (file)
@@ -22,7 +22,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <linux/percpu.h>
 #include <asm/processor.h>
index f444b94935f560f6a7abf1a1de46d88cd32e71d5..962fe7b3e3fb1924543634b10593914257e30b39 100644 (file)
@@ -10,7 +10,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/firmware.h>
 #include <asm/ptrace.h>
index 9b801b8c8c5adb63c8b9bc908c700ad214411c65..7e5b8ed3a1b772609bdd44de8136bd80035006d3 100644 (file)
@@ -8,7 +8,6 @@
  */
 
 #include <linux/oprofile.h>
-#include <linux/init.h>
 #include <linux/smp.h>
 #include <asm/ptrace.h>
 #include <asm/processor.h>
index fc9c1cbfcb1d5ff7719d75f7db46d36a8e93d1b9..5aa3f4b5332c575b6de4963e5d0ade67f6f63855 100644 (file)
@@ -1,9 +1,9 @@
 config PPC_MPC512x
        bool "512x-based boards"
        depends on 6xx
+       select COMMON_CLK
        select FSL_SOC
        select IPIC
-       select PPC_CLOCK
        select PPC_PCI_CHOICE
        select FSL_PCI if PCI
        select ARCH_WANT_OPTIONAL_GPIOLIB
index 72fb9340e09fa7bd2c8e4921a4e57bfdda3d760b..01693121a2b1a54feedcaac3489a4ea96f0ad64b 100644 (file)
@@ -1,7 +1,8 @@
 #
 # Makefile for the Freescale PowerPC 512x linux kernel.
 #
-obj-y                          += clock.o mpc512x_shared.o
+obj-$(CONFIG_COMMON_CLK)       += clock-commonclk.o
+obj-y                          += mpc512x_shared.o
 obj-$(CONFIG_MPC5121_ADS)      += mpc5121_ads.o mpc5121_ads_cpld.o
 obj-$(CONFIG_MPC512x_GENERIC)  += mpc512x_generic.o
 obj-$(CONFIG_PDM360NG)         += pdm360ng.o
diff --git a/arch/powerpc/platforms/512x/clock-commonclk.c b/arch/powerpc/platforms/512x/clock-commonclk.c
new file mode 100644 (file)
index 0000000..6eb614a
--- /dev/null
@@ -0,0 +1,1221 @@
+/*
+ * Copyright (C) 2013 DENX Software Engineering
+ *
+ * Gerhard Sittig, <gsi@denx.de>
+ *
+ * common clock driver support for the MPC512x platform
+ *
+ * This 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/bitops.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+
+#include <asm/mpc5121.h>
+#include <dt-bindings/clock/mpc512x-clock.h>
+
+#include "mpc512x.h"           /* our public mpc5121_clk_init() API */
+
+/* helpers to keep the MCLK intermediates "somewhere" in our table */
+enum {
+       MCLK_IDX_MUX0,
+       MCLK_IDX_EN0,
+       MCLK_IDX_DIV0,
+       MCLK_MAX_IDX,
+};
+
+#define NR_PSCS                        12
+#define NR_MSCANS              4
+#define NR_SPDIFS              1
+#define NR_OUTCLK              4
+#define NR_MCLKS               (NR_PSCS + NR_MSCANS + NR_SPDIFS + NR_OUTCLK)
+
+/* extend the public set of clocks by adding internal slots for management */
+enum {
+       /* arrange for adjacent numbers after the public set */
+       MPC512x_CLK_START_PRIVATE = MPC512x_CLK_LAST_PUBLIC,
+       /* clocks which aren't announced to the public */
+       MPC512x_CLK_DDR,
+       MPC512x_CLK_MEM,
+       MPC512x_CLK_IIM,
+       /* intermediates in div+gate combos or fractional dividers */
+       MPC512x_CLK_DDR_UG,
+       MPC512x_CLK_SDHC_x4,
+       MPC512x_CLK_SDHC_UG,
+       MPC512x_CLK_SDHC2_UG,
+       MPC512x_CLK_DIU_x4,
+       MPC512x_CLK_DIU_UG,
+       MPC512x_CLK_MBX_BUS_UG,
+       MPC512x_CLK_MBX_UG,
+       MPC512x_CLK_MBX_3D_UG,
+       MPC512x_CLK_PCI_UG,
+       MPC512x_CLK_NFC_UG,
+       MPC512x_CLK_LPC_UG,
+       MPC512x_CLK_SPDIF_TX_IN,
+       /* intermediates for the mux+gate+div+mux MCLK generation */
+       MPC512x_CLK_MCLKS_FIRST,
+       MPC512x_CLK_MCLKS_LAST = MPC512x_CLK_MCLKS_FIRST
+                               + NR_MCLKS * MCLK_MAX_IDX,
+       /* internal, symbolic spec for the number of slots */
+       MPC512x_CLK_LAST_PRIVATE,
+};
+
+/* data required for the OF clock provider registration */
+static struct clk *clks[MPC512x_CLK_LAST_PRIVATE];
+static struct clk_onecell_data clk_data;
+
+/* CCM register access */
+static struct mpc512x_ccm __iomem *clkregs;
+static DEFINE_SPINLOCK(clklock);
+
+/* SoC variants {{{ */
+
+/*
+ * tell SoC variants apart as they are rather similar yet not identical,
+ * cache the result in an enum to not repeatedly run the expensive OF test
+ *
+ * MPC5123 is an MPC5121 without the MBX graphics accelerator
+ *
+ * MPC5125 has many more differences: no MBX, no AXE, no VIU, no SPDIF,
+ * no PATA, no SATA, no PCI, two FECs (of different compatibility name),
+ * only 10 PSCs (of different compatibility name), two SDHCs, different
+ * NFC IP block, output clocks, system PLL status query, different CPMF
+ * interpretation, no CFM, different fourth PSC/CAN mux0 input -- yet
+ * those differences can get folded into this clock provider support
+ * code and don't warrant a separate highly redundant implementation
+ */
+
+static enum soc_type {
+       MPC512x_SOC_MPC5121,
+       MPC512x_SOC_MPC5123,
+       MPC512x_SOC_MPC5125,
+} soc;
+
+static void mpc512x_clk_determine_soc(void)
+{
+       if (of_machine_is_compatible("fsl,mpc5121")) {
+               soc = MPC512x_SOC_MPC5121;
+               return;
+       }
+       if (of_machine_is_compatible("fsl,mpc5123")) {
+               soc = MPC512x_SOC_MPC5123;
+               return;
+       }
+       if (of_machine_is_compatible("fsl,mpc5125")) {
+               soc = MPC512x_SOC_MPC5125;
+               return;
+       }
+}
+
+static bool soc_has_mbx(void)
+{
+       if (soc == MPC512x_SOC_MPC5121)
+               return true;
+       return false;
+}
+
+static bool soc_has_axe(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return false;
+       return true;
+}
+
+static bool soc_has_viu(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return false;
+       return true;
+}
+
+static bool soc_has_spdif(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return false;
+       return true;
+}
+
+static bool soc_has_pata(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return false;
+       return true;
+}
+
+static bool soc_has_sata(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return false;
+       return true;
+}
+
+static bool soc_has_pci(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return false;
+       return true;
+}
+
+static bool soc_has_fec2(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return true;
+       return false;
+}
+
+static int soc_max_pscnum(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return 10;
+       return 12;
+}
+
+static bool soc_has_sdhc2(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return true;
+       return false;
+}
+
+static bool soc_has_nfc_5125(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return true;
+       return false;
+}
+
+static bool soc_has_outclk(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return true;
+       return false;
+}
+
+static bool soc_has_cpmf_0_bypass(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return true;
+       return false;
+}
+
+static bool soc_has_mclk_mux0_canin(void)
+{
+       if (soc == MPC512x_SOC_MPC5125)
+               return true;
+       return false;
+}
+
+/* }}} SoC variants */
+/* common clk API wrappers {{{ */
+
+/* convenience wrappers around the common clk API */
+static inline struct clk *mpc512x_clk_fixed(const char *name, int rate)
+{
+       return clk_register_fixed_rate(NULL, name, NULL, CLK_IS_ROOT, rate);
+}
+
+static inline struct clk *mpc512x_clk_factor(
+       const char *name, const char *parent_name,
+       int mul, int div)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       return clk_register_fixed_factor(NULL, name, parent_name, clkflags,
+                                        mul, div);
+}
+
+static inline struct clk *mpc512x_clk_divider(
+       const char *name, const char *parent_name, u8 clkflags,
+       u32 __iomem *reg, u8 pos, u8 len, int divflags)
+{
+       return clk_register_divider(NULL, name, parent_name, clkflags,
+                                   reg, pos, len, divflags, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_divtable(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos, u8 len,
+       const struct clk_div_table *divtab)
+{
+       u8 divflags;
+
+       divflags = 0;
+       return clk_register_divider_table(NULL, name, parent_name, 0,
+                                         reg, pos, len, divflags,
+                                         divtab, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_gated(
+       const char *name, const char *parent_name,
+       u32 __iomem *reg, u8 pos)
+{
+       int clkflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       return clk_register_gate(NULL, name, parent_name, clkflags,
+                                reg, pos, 0, &clklock);
+}
+
+static inline struct clk *mpc512x_clk_muxed(const char *name,
+       const char **parent_names, int parent_count,
+       u32 __iomem *reg, u8 pos, u8 len)
+{
+       int clkflags;
+       u8 muxflags;
+
+       clkflags = CLK_SET_RATE_PARENT;
+       muxflags = 0;
+       return clk_register_mux(NULL, name,
+                               parent_names, parent_count, clkflags,
+                               reg, pos, len, muxflags, &clklock);
+}
+
+/* }}} common clk API wrappers */
+
+/* helper to isolate a bit field from a register */
+static inline int get_bit_field(uint32_t __iomem *reg, uint8_t pos, uint8_t len)
+{
+       uint32_t val;
+
+       val = in_be32(reg);
+       val >>= pos;
+       val &= (1 << len) - 1;
+       return val;
+}
+
+/* get the SPMF and translate it into the "sys pll" multiplier */
+static int get_spmf_mult(void)
+{
+       static int spmf_to_mult[] = {
+               68, 1, 12, 16, 20, 24, 28, 32,
+               36, 40, 44, 48, 52, 56, 60, 64,
+       };
+       int spmf;
+
+       spmf = get_bit_field(&clkregs->spmr, 24, 4);
+       return spmf_to_mult[spmf];
+}
+
+/*
+ * get the SYS_DIV value and translate it into a divide factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * divide ratio is fractional
+ */
+static int get_sys_div_x2(void)
+{
+       static int sysdiv_code_to_x2[] = {
+               4, 5, 6, 7, 8, 9, 10, 14,
+               12, 16, 18, 22, 20, 24, 26, 30,
+               28, 32, 34, 38, 36, 40, 42, 46,
+               44, 48, 50, 54, 52, 56, 58, 62,
+               60, 64, 66,
+       };
+       int divcode;
+
+       divcode = get_bit_field(&clkregs->scfr2, 26, 6);
+       return sysdiv_code_to_x2[divcode];
+}
+
+/*
+ * get the CPMF value and translate it into a multiplier factor
+ *
+ * values returned from here are a multiple of the real factor since the
+ * multiplier ratio is fractional
+ */
+static int get_cpmf_mult_x2(void)
+{
+       static int cpmf_to_mult_x36[] = {
+               /* 0b000 is "times 36" */
+               72, 2, 2, 3, 4, 5, 6, 7,
+       };
+       static int cpmf_to_mult_0by[] = {
+               /* 0b000 is "bypass" */
+               2, 2, 2, 3, 4, 5, 6, 7,
+       };
+
+       int *cpmf_to_mult;
+       int cpmf;
+
+       cpmf = get_bit_field(&clkregs->spmr, 16, 4);
+       if (soc_has_cpmf_0_bypass())
+               cpmf_to_mult = cpmf_to_mult_0by;
+       else
+               cpmf_to_mult = cpmf_to_mult_x36;
+       return cpmf_to_mult[cpmf];
+}
+
+/*
+ * some of the clock dividers do scale in a linear way, yet not all of
+ * their bit combinations are legal; use a divider table to get a
+ * resulting set of applicable divider values
+ */
+
+/* applies to the IPS_DIV, and PCI_DIV values */
+static struct clk_div_table divtab_2346[] = {
+       { .val = 2, .div = 2, },
+       { .val = 3, .div = 3, },
+       { .val = 4, .div = 4, },
+       { .val = 6, .div = 6, },
+       { .div = 0, },
+};
+
+/* applies to the MBX_DIV, LPC_DIV, and NFC_DIV values */
+static struct clk_div_table divtab_1234[] = {
+       { .val = 1, .div = 1, },
+       { .val = 2, .div = 2, },
+       { .val = 3, .div = 3, },
+       { .val = 4, .div = 4, },
+       { .div = 0, },
+};
+
+static int get_freq_from_dt(char *propname)
+{
+       struct device_node *np;
+       const unsigned int *prop;
+       int val;
+
+       val = 0;
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
+       if (np) {
+               prop = of_get_property(np, propname, NULL);
+               if (prop)
+                       val = *prop;
+           of_node_put(np);
+       }
+       return val;
+}
+
+static void mpc512x_clk_preset_data(void)
+{
+       size_t i;
+
+       for (i = 0; i < ARRAY_SIZE(clks); i++)
+               clks[i] = ERR_PTR(-ENODEV);
+}
+
+/*
+ * - receives the "bus frequency" from the caller (that's the IPS clock
+ *   rate, the historical source of clock information)
+ * - fetches the system PLL multiplier and divider values as well as the
+ *   IPS divider value from hardware
+ * - determines the REF clock rate either from the XTAL/OSC spec (if
+ *   there is a device tree node describing the oscillator) or from the
+ *   IPS bus clock (supported for backwards compatibility, such that
+ *   setups without XTAL/OSC specs keep working)
+ * - creates the "ref" clock item in the clock tree, such that
+ *   subsequent code can create the remainder of the hierarchy (REF ->
+ *   SYS -> CSB -> IPS) from the REF clock rate and the returned mul/div
+ *   values
+ */
+static void mpc512x_clk_setup_ref_clock(struct device_node *np, int bus_freq,
+                                       int *sys_mul, int *sys_div,
+                                       int *ips_div)
+{
+       struct clk *osc_clk;
+       int calc_freq;
+
+       /* fetch mul/div factors from the hardware */
+       *sys_mul = get_spmf_mult();
+       *sys_mul *= 2;          /* compensate for the fractional divider */
+       *sys_div = get_sys_div_x2();
+       *ips_div = get_bit_field(&clkregs->scfr1, 23, 3);
+
+       /* lookup the oscillator clock for its rate */
+       osc_clk = of_clk_get_by_name(np, "osc");
+
+       /*
+        * either descend from OSC to REF (and in bypassing verify the
+        * IPS rate), or backtrack from IPS and multiplier values that
+        * were fetched from hardware to REF and thus to the OSC value
+        *
+        * in either case the REF clock gets created here and the
+        * remainder of the clock tree can get spanned from there
+        */
+       if (!IS_ERR(osc_clk)) {
+               clks[MPC512x_CLK_REF] = mpc512x_clk_factor("ref", "osc", 1, 1);
+               calc_freq = clk_get_rate(clks[MPC512x_CLK_REF]);
+               calc_freq *= *sys_mul;
+               calc_freq /= *sys_div;
+               calc_freq /= 2;
+               calc_freq /= *ips_div;
+               if (bus_freq && calc_freq != bus_freq)
+                       pr_warn("calc rate %d != OF spec %d\n",
+                               calc_freq, bus_freq);
+       } else {
+               calc_freq = bus_freq;   /* start with IPS */
+               calc_freq *= *ips_div;  /* IPS -> CSB */
+               calc_freq *= 2;         /* CSB -> SYS */
+               calc_freq *= *sys_div;  /* SYS -> PLL out */
+               calc_freq /= *sys_mul;  /* PLL out -> REF == OSC */
+               clks[MPC512x_CLK_REF] = mpc512x_clk_fixed("ref", calc_freq);
+       }
+}
+
+/* MCLK helpers {{{ */
+
+/*
+ * helper code for the MCLK subtree setup
+ *
+ * the overview in section 5.2.4 of the MPC5121e Reference Manual rev4
+ * suggests that all instances of the "PSC clock generation" are equal,
+ * and that one might re-use the PSC setup for MSCAN clock generation
+ * (section 5.2.5) as well, at least the logic if not the data for
+ * description
+ *
+ * the details (starting at page 5-20) show differences in the specific
+ * inputs of the first mux stage ("can clk in", "spdif tx"), and the
+ * factual non-availability of the second mux stage (it's present yet
+ * only one input is valid)
+ *
+ * the MSCAN clock related registers (starting at page 5-35) all
+ * reference "spdif clk" at the first mux stage and don't mention any
+ * "can clk" at all, which somehow is unexpected
+ *
+ * TODO re-check the document, and clarify whether the RM is correct in
+ * the overview or in the details, and whether the difference is a
+ * clipboard induced error or results from chip revisions
+ *
+ * it turns out that the RM rev4 as of 2012-06 talks about "can" for the
+ * PSCs while RM rev3 as of 2008-10 talks about "spdif", so I guess that
+ * first a doc update is required which better reflects reality in the
+ * SoC before the implementation should follow while no questions remain
+ */
+
+/*
+ * note that this declaration raises a checkpatch warning, but
+ * it's the very data type dictated by <linux/clk-provider.h>,
+ * "fixing" this warning will break compilation
+ */
+static const char *parent_names_mux0_spdif[] = {
+       "sys", "ref", "psc-mclk-in", "spdif-tx",
+};
+
+static const char *parent_names_mux0_canin[] = {
+       "sys", "ref", "psc-mclk-in", "can-clk-in",
+};
+
+enum mclk_type {
+       MCLK_TYPE_PSC,
+       MCLK_TYPE_MSCAN,
+       MCLK_TYPE_SPDIF,
+       MCLK_TYPE_OUTCLK,
+};
+
+struct mclk_setup_data {
+       enum mclk_type type;
+       bool has_mclk1;
+       const char *name_mux0;
+       const char *name_en0;
+       const char *name_div0;
+       const char *parent_names_mux1[2];
+       const char *name_mclk;
+};
+
+#define MCLK_SETUP_DATA_PSC(id) { \
+       MCLK_TYPE_PSC, 0, \
+       "psc" #id "-mux0", \
+       "psc" #id "-en0", \
+       "psc" #id "_mclk_div", \
+       { "psc" #id "_mclk_div", "dummy", }, \
+       "psc" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_MSCAN(id) { \
+       MCLK_TYPE_MSCAN, 0, \
+       "mscan" #id "-mux0", \
+       "mscan" #id "-en0", \
+       "mscan" #id "_mclk_div", \
+       { "mscan" #id "_mclk_div", "dummy", }, \
+       "mscan" #id "_mclk", \
+}
+
+#define MCLK_SETUP_DATA_SPDIF { \
+       MCLK_TYPE_SPDIF, 1, \
+       "spdif-mux0", \
+       "spdif-en0", \
+       "spdif_mclk_div", \
+       { "spdif_mclk_div", "spdif-rx", }, \
+       "spdif_mclk", \
+}
+
+#define MCLK_SETUP_DATA_OUTCLK(id) { \
+       MCLK_TYPE_OUTCLK, 0, \
+       "out" #id "-mux0", \
+       "out" #id "-en0", \
+       "out" #id "_mclk_div", \
+       { "out" #id "_mclk_div", "dummy", }, \
+       "out" #id "_clk", \
+}
+
+static struct mclk_setup_data mclk_psc_data[] = {
+       MCLK_SETUP_DATA_PSC(0),
+       MCLK_SETUP_DATA_PSC(1),
+       MCLK_SETUP_DATA_PSC(2),
+       MCLK_SETUP_DATA_PSC(3),
+       MCLK_SETUP_DATA_PSC(4),
+       MCLK_SETUP_DATA_PSC(5),
+       MCLK_SETUP_DATA_PSC(6),
+       MCLK_SETUP_DATA_PSC(7),
+       MCLK_SETUP_DATA_PSC(8),
+       MCLK_SETUP_DATA_PSC(9),
+       MCLK_SETUP_DATA_PSC(10),
+       MCLK_SETUP_DATA_PSC(11),
+};
+
+static struct mclk_setup_data mclk_mscan_data[] = {
+       MCLK_SETUP_DATA_MSCAN(0),
+       MCLK_SETUP_DATA_MSCAN(1),
+       MCLK_SETUP_DATA_MSCAN(2),
+       MCLK_SETUP_DATA_MSCAN(3),
+};
+
+static struct mclk_setup_data mclk_spdif_data[] = {
+       MCLK_SETUP_DATA_SPDIF,
+};
+
+static struct mclk_setup_data mclk_outclk_data[] = {
+       MCLK_SETUP_DATA_OUTCLK(0),
+       MCLK_SETUP_DATA_OUTCLK(1),
+       MCLK_SETUP_DATA_OUTCLK(2),
+       MCLK_SETUP_DATA_OUTCLK(3),
+};
+
+/* setup the MCLK clock subtree of an individual PSC/MSCAN/SPDIF */
+static void mpc512x_clk_setup_mclk(struct mclk_setup_data *entry, size_t idx)
+{
+       size_t clks_idx_pub, clks_idx_int;
+       u32 __iomem *mccr_reg;  /* MCLK control register (mux, en, div) */
+       int div;
+
+       /* derive a few parameters from the component type and index */
+       switch (entry->type) {
+       case MCLK_TYPE_PSC:
+               clks_idx_pub = MPC512x_CLK_PSC0_MCLK + idx;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (idx) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->psc_ccr[idx];
+               break;
+       case MCLK_TYPE_MSCAN:
+               clks_idx_pub = MPC512x_CLK_MSCAN0_MCLK + idx;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + idx) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->mscan_ccr[idx];
+               break;
+       case MCLK_TYPE_SPDIF:
+               clks_idx_pub = MPC512x_CLK_SPDIF_MCLK;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + NR_MSCANS) * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->spccr;
+               break;
+       case MCLK_TYPE_OUTCLK:
+               clks_idx_pub = MPC512x_CLK_OUT0_CLK + idx;
+               clks_idx_int = MPC512x_CLK_MCLKS_FIRST
+                            + (NR_PSCS + NR_MSCANS + NR_SPDIFS + idx)
+                            * MCLK_MAX_IDX;
+               mccr_reg = &clkregs->out_ccr[idx];
+               break;
+       default:
+               return;
+       }
+
+       /*
+        * this was grabbed from the PPC_CLOCK implementation, which
+        * enforced a specific MCLK divider while the clock was gated
+        * during setup (that's a documented hardware requirement)
+        *
+        * the PPC_CLOCK implementation might even have violated the
+        * "MCLK <= IPS" constraint, the fixed divider value of 1
+        * results in a divider of 2 and thus MCLK = SYS/2 which equals
+        * CSB which is greater than IPS; the serial port setup may have
+        * adjusted the divider which the clock setup might have left in
+        * an undesirable state
+        *
+        * initial setup is:
+        * - MCLK 0 from SYS
+        * - MCLK DIV such to not exceed the IPS clock
+        * - MCLK 0 enabled
+        * - MCLK 1 from MCLK DIV
+        */
+       div = clk_get_rate(clks[MPC512x_CLK_SYS]);
+       div /= clk_get_rate(clks[MPC512x_CLK_IPS]);
+       out_be32(mccr_reg, (0 << 16));
+       out_be32(mccr_reg, (0 << 16) | ((div - 1) << 17));
+       out_be32(mccr_reg, (1 << 16) | ((div - 1) << 17));
+
+       /*
+        * create the 'struct clk' items of the MCLK's clock subtree
+        *
+        * note that by design we always create all nodes and won't take
+        * shortcuts here, because
+        * - the "internal" MCLK_DIV and MCLK_OUT signal in turn are
+        *   selectable inputs to the CFM while those who "actually use"
+        *   the PSC/MSCAN/SPDIF (serial drivers et al) need the MCLK
+        *   for their bitrate
+        * - in the absence of "aliases" for clocks we need to create
+        *   individial 'struct clk' items for whatever might get
+        *   referenced or looked up, even if several of those items are
+        *   identical from the logical POV (their rate value)
+        * - for easier future maintenance and for better reflection of
+        *   the SoC's documentation, it appears appropriate to generate
+        *   clock items even for those muxers which actually are NOPs
+        *   (those with two inputs of which one is reserved)
+        */
+       clks[clks_idx_int + MCLK_IDX_MUX0] = mpc512x_clk_muxed(
+                       entry->name_mux0,
+                       soc_has_mclk_mux0_canin()
+                               ? &parent_names_mux0_canin[0]
+                               : &parent_names_mux0_spdif[0],
+                       ARRAY_SIZE(parent_names_mux0_spdif),
+                       mccr_reg, 14, 2);
+       clks[clks_idx_int + MCLK_IDX_EN0] = mpc512x_clk_gated(
+                       entry->name_en0, entry->name_mux0,
+                       mccr_reg, 16);
+       clks[clks_idx_int + MCLK_IDX_DIV0] = mpc512x_clk_divider(
+                       entry->name_div0,
+                       entry->name_en0, CLK_SET_RATE_GATE,
+                       mccr_reg, 17, 15, 0);
+       if (entry->has_mclk1) {
+               clks[clks_idx_pub] = mpc512x_clk_muxed(
+                               entry->name_mclk,
+                               &entry->parent_names_mux1[0],
+                               ARRAY_SIZE(entry->parent_names_mux1),
+                               mccr_reg, 7, 1);
+       } else {
+               clks[clks_idx_pub] = mpc512x_clk_factor(
+                               entry->name_mclk,
+                               entry->parent_names_mux1[0],
+                               1, 1);
+       }
+}
+
+/* }}} MCLK helpers */
+
+static void mpc512x_clk_setup_clock_tree(struct device_node *np, int busfreq)
+{
+       int sys_mul, sys_div, ips_div;
+       int mul, div;
+       size_t mclk_idx;
+       int freq;
+
+       /*
+        * developer's notes:
+        * - consider whether to handle clocks which have both gates and
+        *   dividers via intermediates or by means of composites
+        * - fractional dividers appear to not map well to composites
+        *   since they can be seen as a fixed multiplier and an
+        *   adjustable divider, while composites can only combine at
+        *   most one of a mux, div, and gate each into one 'struct clk'
+        *   item
+        * - PSC/MSCAN/SPDIF clock generation OTOH already is very
+        *   specific and cannot get mapped to componsites (at least not
+        *   a single one, maybe two of them, but then some of these
+        *   intermediate clock signals get referenced elsewhere (e.g.
+        *   in the clock frequency measurement, CFM) and thus need
+        *   publicly available names
+        * - the current source layout appropriately reflects the
+        *   hardware setup, and it works, so it's questionable whether
+        *   further changes will result in big enough a benefit
+        */
+
+       /* regardless of whether XTAL/OSC exists, have REF created */
+       mpc512x_clk_setup_ref_clock(np, busfreq, &sys_mul, &sys_div, &ips_div);
+
+       /* now setup the REF -> SYS -> CSB -> IPS hierarchy */
+       clks[MPC512x_CLK_SYS] = mpc512x_clk_factor("sys", "ref",
+                                                  sys_mul, sys_div);
+       clks[MPC512x_CLK_CSB] = mpc512x_clk_factor("csb", "sys", 1, 2);
+       clks[MPC512x_CLK_IPS] = mpc512x_clk_divtable("ips", "csb",
+                                                    &clkregs->scfr1, 23, 3,
+                                                    divtab_2346);
+       /* now setup anything below SYS and CSB and IPS */
+
+       clks[MPC512x_CLK_DDR_UG] = mpc512x_clk_factor("ddr-ug", "sys", 1, 2);
+
+       /*
+        * the Reference Manual discusses that for SDHC only even divide
+        * ratios are supported because clock domain synchronization
+        * between 'per' and 'ipg' is broken;
+        * keep the divider's bit 0 cleared (per reset value), and only
+        * allow to setup the divider's bits 7:1, which results in that
+        * only even divide ratios can get configured upon rate changes;
+        * keep the "x4" name because this bit shift hack is an internal
+        * implementation detail, the "fractional divider with quarters"
+        * semantics remains
+        */
+       clks[MPC512x_CLK_SDHC_x4] = mpc512x_clk_factor("sdhc-x4", "csb", 2, 1);
+       clks[MPC512x_CLK_SDHC_UG] = mpc512x_clk_divider("sdhc-ug", "sdhc-x4", 0,
+                                                       &clkregs->scfr2, 1, 7,
+                                                       CLK_DIVIDER_ONE_BASED);
+       if (soc_has_sdhc2()) {
+               clks[MPC512x_CLK_SDHC2_UG] = mpc512x_clk_divider(
+                               "sdhc2-ug", "sdhc-x4", 0, &clkregs->scfr2,
+                               9, 7, CLK_DIVIDER_ONE_BASED);
+       }
+
+       clks[MPC512x_CLK_DIU_x4] = mpc512x_clk_factor("diu-x4", "csb", 4, 1);
+       clks[MPC512x_CLK_DIU_UG] = mpc512x_clk_divider("diu-ug", "diu-x4", 0,
+                                                      &clkregs->scfr1, 0, 8,
+                                                      CLK_DIVIDER_ONE_BASED);
+
+       /*
+        * the "power architecture PLL" was setup from data which was
+        * sampled from the reset config word, at this point in time the
+        * configuration can be considered fixed and read only (i.e. no
+        * longer adjustable, or no longer in need of adjustment), which
+        * is why we don't register a PLL here but assume fixed factors
+        */
+       mul = get_cpmf_mult_x2();
+       div = 2;        /* compensate for the fractional factor */
+       clks[MPC512x_CLK_E300] = mpc512x_clk_factor("e300", "csb", mul, div);
+
+       if (soc_has_mbx()) {
+               clks[MPC512x_CLK_MBX_BUS_UG] = mpc512x_clk_factor(
+                               "mbx-bus-ug", "csb", 1, 2);
+               clks[MPC512x_CLK_MBX_UG] = mpc512x_clk_divtable(
+                               "mbx-ug", "mbx-bus-ug", &clkregs->scfr1,
+                               14, 3, divtab_1234);
+               clks[MPC512x_CLK_MBX_3D_UG] = mpc512x_clk_factor(
+                               "mbx-3d-ug", "mbx-ug", 1, 1);
+       }
+       if (soc_has_pci()) {
+               clks[MPC512x_CLK_PCI_UG] = mpc512x_clk_divtable(
+                               "pci-ug", "csb", &clkregs->scfr1,
+                               20, 3, divtab_2346);
+       }
+       if (soc_has_nfc_5125()) {
+               /*
+                * XXX TODO implement 5125 NFC clock setup logic,
+                * with high/low period counters in clkregs->scfr3,
+                * currently there are no users so it's ENOIMPL
+                */
+               clks[MPC512x_CLK_NFC_UG] = ERR_PTR(-ENOTSUPP);
+       } else {
+               clks[MPC512x_CLK_NFC_UG] = mpc512x_clk_divtable(
+                               "nfc-ug", "ips", &clkregs->scfr1,
+                               8, 3, divtab_1234);
+       }
+       clks[MPC512x_CLK_LPC_UG] = mpc512x_clk_divtable("lpc-ug", "ips",
+                                                       &clkregs->scfr1, 11, 3,
+                                                       divtab_1234);
+
+       clks[MPC512x_CLK_LPC] = mpc512x_clk_gated("lpc", "lpc-ug",
+                                                 &clkregs->sccr1, 30);
+       clks[MPC512x_CLK_NFC] = mpc512x_clk_gated("nfc", "nfc-ug",
+                                                 &clkregs->sccr1, 29);
+       if (soc_has_pata()) {
+               clks[MPC512x_CLK_PATA] = mpc512x_clk_gated(
+                               "pata", "ips", &clkregs->sccr1, 28);
+       }
+       /* for PSCs there is a "registers" gate and a bitrate MCLK subtree */
+       for (mclk_idx = 0; mclk_idx < soc_max_pscnum(); mclk_idx++) {
+               char name[12];
+               snprintf(name, sizeof(name), "psc%d", mclk_idx);
+               clks[MPC512x_CLK_PSC0 + mclk_idx] = mpc512x_clk_gated(
+                               name, "ips", &clkregs->sccr1, 27 - mclk_idx);
+               mpc512x_clk_setup_mclk(&mclk_psc_data[mclk_idx], mclk_idx);
+       }
+       clks[MPC512x_CLK_PSC_FIFO] = mpc512x_clk_gated("psc-fifo", "ips",
+                                                      &clkregs->sccr1, 15);
+       if (soc_has_sata()) {
+               clks[MPC512x_CLK_SATA] = mpc512x_clk_gated(
+                               "sata", "ips", &clkregs->sccr1, 14);
+       }
+       clks[MPC512x_CLK_FEC] = mpc512x_clk_gated("fec", "ips",
+                                                 &clkregs->sccr1, 13);
+       if (soc_has_pci()) {
+               clks[MPC512x_CLK_PCI] = mpc512x_clk_gated(
+                               "pci", "pci-ug", &clkregs->sccr1, 11);
+       }
+       clks[MPC512x_CLK_DDR] = mpc512x_clk_gated("ddr", "ddr-ug",
+                                                 &clkregs->sccr1, 10);
+       if (soc_has_fec2()) {
+               clks[MPC512x_CLK_FEC2] = mpc512x_clk_gated(
+                               "fec2", "ips", &clkregs->sccr1, 9);
+       }
+
+       clks[MPC512x_CLK_DIU] = mpc512x_clk_gated("diu", "diu-ug",
+                                                 &clkregs->sccr2, 31);
+       if (soc_has_axe()) {
+               clks[MPC512x_CLK_AXE] = mpc512x_clk_gated(
+                               "axe", "csb", &clkregs->sccr2, 30);
+       }
+       clks[MPC512x_CLK_MEM] = mpc512x_clk_gated("mem", "ips",
+                                                 &clkregs->sccr2, 29);
+       clks[MPC512x_CLK_USB1] = mpc512x_clk_gated("usb1", "csb",
+                                                  &clkregs->sccr2, 28);
+       clks[MPC512x_CLK_USB2] = mpc512x_clk_gated("usb2", "csb",
+                                                  &clkregs->sccr2, 27);
+       clks[MPC512x_CLK_I2C] = mpc512x_clk_gated("i2c", "ips",
+                                                 &clkregs->sccr2, 26);
+       /* MSCAN differs from PSC with just one gate for multiple components */
+       clks[MPC512x_CLK_BDLC] = mpc512x_clk_gated("bdlc", "ips",
+                                                  &clkregs->sccr2, 25);
+       for (mclk_idx = 0; mclk_idx < ARRAY_SIZE(mclk_mscan_data); mclk_idx++)
+               mpc512x_clk_setup_mclk(&mclk_mscan_data[mclk_idx], mclk_idx);
+       clks[MPC512x_CLK_SDHC] = mpc512x_clk_gated("sdhc", "sdhc-ug",
+                                                  &clkregs->sccr2, 24);
+       /* there is only one SPDIF component, which shares MCLK support code */
+       if (soc_has_spdif()) {
+               clks[MPC512x_CLK_SPDIF] = mpc512x_clk_gated(
+                               "spdif", "ips", &clkregs->sccr2, 23);
+               mpc512x_clk_setup_mclk(&mclk_spdif_data[0], 0);
+       }
+       if (soc_has_mbx()) {
+               clks[MPC512x_CLK_MBX_BUS] = mpc512x_clk_gated(
+                               "mbx-bus", "mbx-bus-ug", &clkregs->sccr2, 22);
+               clks[MPC512x_CLK_MBX] = mpc512x_clk_gated(
+                               "mbx", "mbx-ug", &clkregs->sccr2, 21);
+               clks[MPC512x_CLK_MBX_3D] = mpc512x_clk_gated(
+                               "mbx-3d", "mbx-3d-ug", &clkregs->sccr2, 20);
+       }
+       clks[MPC512x_CLK_IIM] = mpc512x_clk_gated("iim", "csb",
+                                                 &clkregs->sccr2, 19);
+       if (soc_has_viu()) {
+               clks[MPC512x_CLK_VIU] = mpc512x_clk_gated(
+                               "viu", "csb", &clkregs->sccr2, 18);
+       }
+       if (soc_has_sdhc2()) {
+               clks[MPC512x_CLK_SDHC2] = mpc512x_clk_gated(
+                               "sdhc-2", "sdhc2-ug", &clkregs->sccr2, 17);
+       }
+
+       if (soc_has_outclk()) {
+               size_t idx;     /* used as mclk_idx, just to trim line length */
+               for (idx = 0; idx < ARRAY_SIZE(mclk_outclk_data); idx++)
+                       mpc512x_clk_setup_mclk(&mclk_outclk_data[idx], idx);
+       }
+
+       /*
+        * externally provided clocks (when implemented in hardware,
+        * device tree may specify values which otherwise were unknown)
+        */
+       freq = get_freq_from_dt("psc_mclk_in");
+       if (!freq)
+               freq = 25000000;
+       clks[MPC512x_CLK_PSC_MCLK_IN] = mpc512x_clk_fixed("psc_mclk_in", freq);
+       if (soc_has_mclk_mux0_canin()) {
+               freq = get_freq_from_dt("can_clk_in");
+               clks[MPC512x_CLK_CAN_CLK_IN] = mpc512x_clk_fixed(
+                               "can_clk_in", freq);
+       } else {
+               freq = get_freq_from_dt("spdif_tx_in");
+               clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed(
+                               "spdif_tx_in", freq);
+               freq = get_freq_from_dt("spdif_rx_in");
+               clks[MPC512x_CLK_SPDIF_TX_IN] = mpc512x_clk_fixed(
+                               "spdif_rx_in", freq);
+       }
+
+       /* fixed frequency for AC97, always 24.567MHz */
+       clks[MPC512x_CLK_AC97] = mpc512x_clk_fixed("ac97", 24567000);
+
+       /*
+        * pre-enable those "internal" clock items which never get
+        * claimed by any peripheral driver, to not have the clock
+        * subsystem disable them late at startup
+        */
+       clk_prepare_enable(clks[MPC512x_CLK_DUMMY]);
+       clk_prepare_enable(clks[MPC512x_CLK_E300]);     /* PowerPC CPU */
+       clk_prepare_enable(clks[MPC512x_CLK_DDR]);      /* DRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_MEM]);      /* SRAM */
+       clk_prepare_enable(clks[MPC512x_CLK_IPS]);      /* SoC periph */
+       clk_prepare_enable(clks[MPC512x_CLK_LPC]);      /* boot media */
+}
+
+/*
+ * registers the set of public clocks (those listed in the dt-bindings/
+ * header file) for OF lookups, keeps the intermediates private to us
+ */
+static void mpc5121_clk_register_of_provider(struct device_node *np)
+{
+       clk_data.clks = clks;
+       clk_data.clk_num = MPC512x_CLK_LAST_PUBLIC + 1; /* _not_ ARRAY_SIZE() */
+       of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+}
+
+/*
+ * temporary support for the period of time between introduction of CCF
+ * support and the adjustment of peripheral drivers to OF based lookups
+ */
+static void mpc5121_clk_provide_migration_support(void)
+{
+
+       /*
+        * pre-enable those clock items which are not yet appropriately
+        * acquired by their peripheral driver
+        *
+        * the PCI clock cannot get acquired by its peripheral driver,
+        * because for this platform the driver won't probe(), instead
+        * initialization is done from within the .setup_arch() routine
+        * at a point in time where the clock provider has not been
+        * setup yet and thus isn't available yet
+        *
+        * so we "pre-enable" the clock here, to not have the clock
+        * subsystem automatically disable this item in a late init call
+        *
+        * this PCI clock pre-enable workaround only applies when there
+        * are device tree nodes for PCI and thus the peripheral driver
+        * has attached to bridges, otherwise the PCI clock remains
+        * unused and so it gets disabled
+        */
+       clk_prepare_enable(clks[MPC512x_CLK_PSC3_MCLK]);/* serial console */
+       if (of_find_compatible_node(NULL, "pci", "fsl,mpc5121-pci"))
+               clk_prepare_enable(clks[MPC512x_CLK_PCI]);
+}
+
+/*
+ * those macros are not exactly pretty, but they encapsulate a lot
+ * of copy'n'paste heavy code which is even more ugly, and reduce
+ * the potential for inconsistencies in those many code copies
+ */
+#define FOR_NODES(compatname) \
+       for_each_compatible_node(np, NULL, compatname)
+
+#define NODE_PREP do { \
+       of_address_to_resource(np, 0, &res); \
+       snprintf(devname, sizeof(devname), "%08x.%s", res.start, np->name); \
+} while (0)
+
+#define NODE_CHK(clkname, clkitem, regnode, regflag) do { \
+       struct clk *clk; \
+       clk = of_clk_get_by_name(np, clkname); \
+       if (IS_ERR(clk)) { \
+               clk = clkitem; \
+               clk_register_clkdev(clk, clkname, devname); \
+               if (regnode) \
+                       clk_register_clkdev(clk, clkname, np->name); \
+               did_register |= DID_REG_ ## regflag; \
+               pr_debug("clock alias name '%s' for dev '%s' pointer %p\n", \
+                        clkname, devname, clk); \
+       } else { \
+               clk_put(clk); \
+       } \
+} while (0)
+
+/*
+ * register source code provided fallback results for clock lookups,
+ * these get consulted when OF based clock lookup fails (that is in the
+ * case of not yet adjusted device tree data, where clock related specs
+ * are missing)
+ */
+static void mpc5121_clk_provide_backwards_compat(void)
+{
+       enum did_reg_flags {
+               DID_REG_PSC     = BIT(0),
+               DID_REG_PSCFIFO = BIT(1),
+               DID_REG_NFC     = BIT(2),
+               DID_REG_CAN     = BIT(3),
+               DID_REG_I2C     = BIT(4),
+               DID_REG_DIU     = BIT(5),
+               DID_REG_VIU     = BIT(6),
+               DID_REG_FEC     = BIT(7),
+               DID_REG_USB     = BIT(8),
+               DID_REG_PATA    = BIT(9),
+       };
+
+       int did_register;
+       struct device_node *np;
+       struct resource res;
+       int idx;
+       char devname[32];
+
+       did_register = 0;
+
+       FOR_NODES(mpc512x_select_psc_compat()) {
+               NODE_PREP;
+               idx = (res.start >> 8) & 0xf;
+               NODE_CHK("ipg", clks[MPC512x_CLK_PSC0 + idx], 0, PSC);
+               NODE_CHK("mclk", clks[MPC512x_CLK_PSC0_MCLK + idx], 0, PSC);
+       }
+
+       FOR_NODES("fsl,mpc5121-psc-fifo") {
+               NODE_PREP;
+               NODE_CHK("ipg", clks[MPC512x_CLK_PSC_FIFO], 1, PSCFIFO);
+       }
+
+       FOR_NODES("fsl,mpc5121-nfc") {
+               NODE_PREP;
+               NODE_CHK("ipg", clks[MPC512x_CLK_NFC], 0, NFC);
+       }
+
+       FOR_NODES("fsl,mpc5121-mscan") {
+               NODE_PREP;
+               idx = 0;
+               idx += (res.start & 0x2000) ? 2 : 0;
+               idx += (res.start & 0x0080) ? 1 : 0;
+               NODE_CHK("ipg", clks[MPC512x_CLK_BDLC], 0, CAN);
+               NODE_CHK("mclk", clks[MPC512x_CLK_MSCAN0_MCLK + idx], 0, CAN);
+       }
+
+       /*
+        * do register the 'ips', 'sys', and 'ref' names globally
+        * instead of inside each individual CAN node, as there is no
+        * potential for a name conflict (in contrast to 'ipg' and 'mclk')
+        */
+       if (did_register & DID_REG_CAN) {
+               clk_register_clkdev(clks[MPC512x_CLK_IPS], "ips", NULL);
+               clk_register_clkdev(clks[MPC512x_CLK_SYS], "sys", NULL);
+               clk_register_clkdev(clks[MPC512x_CLK_REF], "ref", NULL);
+       }
+
+       FOR_NODES("fsl,mpc5121-i2c") {
+               NODE_PREP;
+               NODE_CHK("ipg", clks[MPC512x_CLK_I2C], 0, I2C);
+       }
+
+       /*
+        * workaround for the fact that the I2C driver does an "anonymous"
+        * lookup (NULL name spec, which yields the first clock spec) for
+        * which we cannot register an alias -- a _global_ 'ipg' alias that
+        * is not bound to any device name and returns the I2C clock item
+        * is not a good idea
+        *
+        * so we have the lookup in the peripheral driver fail, which is
+        * silent and non-fatal, and pre-enable the clock item here such
+        * that register access is possible
+        *
+        * see commit b3bfce2b "i2c: mpc: cleanup clock API use" for
+        * details, adjusting s/NULL/"ipg"/ in i2c-mpc.c would make this
+        * workaround obsolete
+        */
+       if (did_register & DID_REG_I2C)
+               clk_prepare_enable(clks[MPC512x_CLK_I2C]);
+
+       FOR_NODES("fsl,mpc5121-diu") {
+               NODE_PREP;
+               NODE_CHK("ipg", clks[MPC512x_CLK_DIU], 1, DIU);
+       }
+
+       FOR_NODES("fsl,mpc5121-viu") {
+               NODE_PREP;
+               NODE_CHK("ipg", clks[MPC512x_CLK_VIU], 0, VIU);
+       }
+
+       /*
+        * note that 2771399a "fs_enet: cleanup clock API use" did use the
+        * "per" string for the clock lookup in contrast to the "ipg" name
+        * which most other nodes are using -- this is not a fatal thing
+        * but just something to keep in mind when doing compatibility
+        * registration, it's a non-issue with up-to-date device tree data
+        */
+       FOR_NODES("fsl,mpc5121-fec") {
+               NODE_PREP;
+               NODE_CHK("per", clks[MPC512x_CLK_FEC], 0, FEC);
+       }
+       FOR_NODES("fsl,mpc5121-fec-mdio") {
+               NODE_PREP;
+               NODE_CHK("per", clks[MPC512x_CLK_FEC], 0, FEC);
+       }
+       /*
+        * MPC5125 has two FECs: FEC1 at 0x2800, FEC2 at 0x4800;
+        * the clock items don't "form an array" since FEC2 was
+        * added only later and was not allowed to shift all other
+        * clock item indices, so the numbers aren't adjacent
+        */
+       FOR_NODES("fsl,mpc5125-fec") {
+               NODE_PREP;
+               if (res.start & 0x4000)
+                       idx = MPC512x_CLK_FEC2;
+               else
+                       idx = MPC512x_CLK_FEC;
+               NODE_CHK("per", clks[idx], 0, FEC);
+       }
+
+       FOR_NODES("fsl,mpc5121-usb2-dr") {
+               NODE_PREP;
+               idx = (res.start & 0x4000) ? 1 : 0;
+               NODE_CHK("ipg", clks[MPC512x_CLK_USB1 + idx], 0, USB);
+       }
+
+       FOR_NODES("fsl,mpc5121-pata") {
+               NODE_PREP;
+               NODE_CHK("ipg", clks[MPC512x_CLK_PATA], 0, PATA);
+       }
+
+       /*
+        * try to collapse diagnostics into a single line of output yet
+        * provide a full list of what is missing, to avoid noise in the
+        * absence of up-to-date device tree data -- backwards
+        * compatibility to old DTBs is a requirement, updates may be
+        * desirable or preferrable but are not at all mandatory
+        */
+       if (did_register) {
+               pr_notice("device tree lacks clock specs, adding fallbacks (0x%x,%s%s%s%s%s%s%s%s%s%s)\n",
+                         did_register,
+                         (did_register & DID_REG_PSC) ? " PSC" : "",
+                         (did_register & DID_REG_PSCFIFO) ? " PSCFIFO" : "",
+                         (did_register & DID_REG_NFC) ? " NFC" : "",
+                         (did_register & DID_REG_CAN) ? " CAN" : "",
+                         (did_register & DID_REG_I2C) ? " I2C" : "",
+                         (did_register & DID_REG_DIU) ? " DIU" : "",
+                         (did_register & DID_REG_VIU) ? " VIU" : "",
+                         (did_register & DID_REG_FEC) ? " FEC" : "",
+                         (did_register & DID_REG_USB) ? " USB" : "",
+                         (did_register & DID_REG_PATA) ? " PATA" : "");
+       } else {
+               pr_debug("device tree has clock specs, no fallbacks added\n");
+       }
+}
+
+int __init mpc5121_clk_init(void)
+{
+       struct device_node *clk_np;
+       int busfreq;
+
+       /* map the clock control registers */
+       clk_np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+       if (!clk_np)
+               return -ENODEV;
+       clkregs = of_iomap(clk_np, 0);
+       WARN_ON(!clkregs);
+
+       /* determine the SoC variant we run on */
+       mpc512x_clk_determine_soc();
+
+       /* invalidate all not yet registered clock slots */
+       mpc512x_clk_preset_data();
+
+       /*
+        * have the device tree scanned for "fixed-clock" nodes (which
+        * includes the oscillator node if the board's DT provides one)
+        */
+       of_clk_init(NULL);
+
+       /*
+        * add a dummy clock for those situations where a clock spec is
+        * required yet no real clock is involved
+        */
+       clks[MPC512x_CLK_DUMMY] = mpc512x_clk_fixed("dummy", 0);
+
+       /*
+        * have all the real nodes in the clock tree populated from REF
+        * down to all leaves, either starting from the OSC node or from
+        * a REF root that was created from the IPS bus clock input
+        */
+       busfreq = get_freq_from_dt("bus-frequency");
+       mpc512x_clk_setup_clock_tree(clk_np, busfreq);
+
+       /* register as an OF clock provider */
+       mpc5121_clk_register_of_provider(clk_np);
+
+       /*
+        * unbreak not yet adjusted peripheral drivers during migration
+        * towards fully operational common clock support, and allow
+        * operation in the absence of clock related device tree specs
+        */
+       mpc5121_clk_provide_migration_support();
+       mpc5121_clk_provide_backwards_compat();
+
+       return 0;
+}
diff --git a/arch/powerpc/platforms/512x/clock.c b/arch/powerpc/platforms/512x/clock.c
deleted file mode 100644 (file)
index fd8a376..0000000
+++ /dev/null
@@ -1,754 +0,0 @@
-/*
- * Copyright (C) 2007,2008 Freescale Semiconductor, Inc. All rights reserved.
- *
- * Author: John Rigby <jrigby@freescale.com>
- *
- * Implements the clk api defined in include/linux/clk.h
- *
- *    Original based on linux/arch/arm/mach-integrator/clock.c
- *
- *    Copyright (C) 2004 ARM Limited.
- *    Written by Deep Blue Solutions 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.
- */
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/clk.h>
-#include <linux/mutex.h>
-#include <linux/io.h>
-
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <asm/mpc5xxx.h>
-#include <asm/mpc5121.h>
-#include <asm/clk_interface.h>
-
-#include "mpc512x.h"
-
-#undef CLK_DEBUG
-
-static int clocks_initialized;
-
-#define CLK_HAS_RATE   0x1     /* has rate in MHz */
-#define CLK_HAS_CTRL   0x2     /* has control reg and bit */
-
-struct clk {
-       struct list_head node;
-       char name[32];
-       int flags;
-       struct device *dev;
-       unsigned long rate;
-       struct module *owner;
-       void (*calc) (struct clk *);
-       struct clk *parent;
-       int reg, bit;           /* CLK_HAS_CTRL */
-       int div_shift;          /* only used by generic_div_clk_calc */
-};
-
-static LIST_HEAD(clocks);
-static DEFINE_MUTEX(clocks_mutex);
-
-static struct clk *mpc5121_clk_get(struct device *dev, const char *id)
-{
-       struct clk *p, *clk = ERR_PTR(-ENOENT);
-       int dev_match;
-       int id_match;
-
-       if (dev == NULL || id == NULL)
-               return clk;
-
-       mutex_lock(&clocks_mutex);
-       list_for_each_entry(p, &clocks, node) {
-               dev_match = id_match = 0;
-
-               if (dev == p->dev)
-                       dev_match++;
-               if (strcmp(id, p->name) == 0)
-                       id_match++;
-               if ((dev_match || id_match) && try_module_get(p->owner)) {
-                       clk = p;
-                       break;
-               }
-       }
-       mutex_unlock(&clocks_mutex);
-
-       return clk;
-}
-
-#ifdef CLK_DEBUG
-static void dump_clocks(void)
-{
-       struct clk *p;
-
-       mutex_lock(&clocks_mutex);
-       printk(KERN_INFO "CLOCKS:\n");
-       list_for_each_entry(p, &clocks, node) {
-               pr_info("  %s=%ld", p->name, p->rate);
-               if (p->parent)
-                       pr_cont(" %s=%ld", p->parent->name,
-                              p->parent->rate);
-               if (p->flags & CLK_HAS_CTRL)
-                       pr_cont(" reg/bit=%d/%d", p->reg, p->bit);
-               pr_cont("\n");
-       }
-       mutex_unlock(&clocks_mutex);
-}
-#define        DEBUG_CLK_DUMP() dump_clocks()
-#else
-#define        DEBUG_CLK_DUMP()
-#endif
-
-
-static void mpc5121_clk_put(struct clk *clk)
-{
-       module_put(clk->owner);
-}
-
-#define NRPSC 12
-
-struct mpc512x_clockctl {
-       u32 spmr;               /* System PLL Mode Reg */
-       u32 sccr[2];            /* System Clk Ctrl Reg 1 & 2 */
-       u32 scfr1;              /* System Clk Freq Reg 1 */
-       u32 scfr2;              /* System Clk Freq Reg 2 */
-       u32 reserved;
-       u32 bcr;                /* Bread Crumb Reg */
-       u32 pccr[NRPSC];        /* PSC Clk Ctrl Reg 0-11 */
-       u32 spccr;              /* SPDIF Clk Ctrl Reg */
-       u32 cccr;               /* CFM Clk Ctrl Reg */
-       u32 dccr;               /* DIU Clk Cnfg Reg */
-};
-
-static struct mpc512x_clockctl __iomem *clockctl;
-
-static int mpc5121_clk_enable(struct clk *clk)
-{
-       unsigned int mask;
-
-       if (clk->flags & CLK_HAS_CTRL) {
-               mask = in_be32(&clockctl->sccr[clk->reg]);
-               mask |= 1 << clk->bit;
-               out_be32(&clockctl->sccr[clk->reg], mask);
-       }
-       return 0;
-}
-
-static void mpc5121_clk_disable(struct clk *clk)
-{
-       unsigned int mask;
-
-       if (clk->flags & CLK_HAS_CTRL) {
-               mask = in_be32(&clockctl->sccr[clk->reg]);
-               mask &= ~(1 << clk->bit);
-               out_be32(&clockctl->sccr[clk->reg], mask);
-       }
-}
-
-static unsigned long mpc5121_clk_get_rate(struct clk *clk)
-{
-       if (clk->flags & CLK_HAS_RATE)
-               return clk->rate;
-       else
-               return 0;
-}
-
-static long mpc5121_clk_round_rate(struct clk *clk, unsigned long rate)
-{
-       return rate;
-}
-
-static int mpc5121_clk_set_rate(struct clk *clk, unsigned long rate)
-{
-       return 0;
-}
-
-static int clk_register(struct clk *clk)
-{
-       mutex_lock(&clocks_mutex);
-       list_add(&clk->node, &clocks);
-       mutex_unlock(&clocks_mutex);
-       return 0;
-}
-
-static unsigned long spmf_mult(void)
-{
-       /*
-        * Convert spmf to multiplier
-        */
-       static int spmf_to_mult[] = {
-               68, 1, 12, 16,
-               20, 24, 28, 32,
-               36, 40, 44, 48,
-               52, 56, 60, 64
-       };
-       int spmf = (in_be32(&clockctl->spmr) >> 24) & 0xf;
-       return spmf_to_mult[spmf];
-}
-
-static unsigned long sysdiv_div_x_2(void)
-{
-       /*
-        * Convert sysdiv to divisor x 2
-        * Some divisors have fractional parts so
-        * multiply by 2 then divide by this value
-        */
-       static int sysdiv_to_div_x_2[] = {
-               4, 5, 6, 7,
-               8, 9, 10, 14,
-               12, 16, 18, 22,
-               20, 24, 26, 30,
-               28, 32, 34, 38,
-               36, 40, 42, 46,
-               44, 48, 50, 54,
-               52, 56, 58, 62,
-               60, 64, 66,
-       };
-       int sysdiv = (in_be32(&clockctl->scfr2) >> 26) & 0x3f;
-       return sysdiv_to_div_x_2[sysdiv];
-}
-
-static unsigned long ref_to_sys(unsigned long rate)
-{
-       rate *= spmf_mult();
-       rate *= 2;
-       rate /= sysdiv_div_x_2();
-
-       return rate;
-}
-
-static unsigned long sys_to_ref(unsigned long rate)
-{
-       rate *= sysdiv_div_x_2();
-       rate /= 2;
-       rate /= spmf_mult();
-
-       return rate;
-}
-
-static long ips_to_ref(unsigned long rate)
-{
-       int ips_div = (in_be32(&clockctl->scfr1) >> 23) & 0x7;
-
-       rate *= ips_div;        /* csb_clk = ips_clk * ips_div */
-       rate *= 2;              /* sys_clk = csb_clk * 2 */
-       return sys_to_ref(rate);
-}
-
-static unsigned long devtree_getfreq(char *clockname)
-{
-       struct device_node *np;
-       const unsigned int *prop;
-       unsigned int val = 0;
-
-       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-immr");
-       if (np) {
-               prop = of_get_property(np, clockname, NULL);
-               if (prop)
-                       val = *prop;
-           of_node_put(np);
-       }
-       return val;
-}
-
-static void ref_clk_calc(struct clk *clk)
-{
-       unsigned long rate;
-
-       rate = devtree_getfreq("bus-frequency");
-       if (rate == 0) {
-               printk(KERN_ERR "No bus-frequency in dev tree\n");
-               clk->rate = 0;
-               return;
-       }
-       clk->rate = ips_to_ref(rate);
-}
-
-static struct clk ref_clk = {
-       .name = "ref_clk",
-       .calc = ref_clk_calc,
-};
-
-
-static void sys_clk_calc(struct clk *clk)
-{
-       clk->rate = ref_to_sys(ref_clk.rate);
-}
-
-static struct clk sys_clk = {
-       .name = "sys_clk",
-       .calc = sys_clk_calc,
-};
-
-static void diu_clk_calc(struct clk *clk)
-{
-       int diudiv_x_2 = in_be32(&clockctl->scfr1) & 0xff;
-       unsigned long rate;
-
-       rate = sys_clk.rate;
-
-       rate *= 2;
-       rate /= diudiv_x_2;
-
-       clk->rate = rate;
-}
-
-static void viu_clk_calc(struct clk *clk)
-{
-       unsigned long rate;
-
-       rate = sys_clk.rate;
-       rate /= 2;
-       clk->rate = rate;
-}
-
-static void half_clk_calc(struct clk *clk)
-{
-       clk->rate = clk->parent->rate / 2;
-}
-
-static void generic_div_clk_calc(struct clk *clk)
-{
-       int div = (in_be32(&clockctl->scfr1) >> clk->div_shift) & 0x7;
-
-       clk->rate = clk->parent->rate / div;
-}
-
-static void unity_clk_calc(struct clk *clk)
-{
-       clk->rate = clk->parent->rate;
-}
-
-static struct clk csb_clk = {
-       .name = "csb_clk",
-       .calc = half_clk_calc,
-       .parent = &sys_clk,
-};
-
-static void e300_clk_calc(struct clk *clk)
-{
-       int spmf = (in_be32(&clockctl->spmr) >> 16) & 0xf;
-       int ratex2 = clk->parent->rate * spmf;
-
-       clk->rate = ratex2 / 2;
-}
-
-static struct clk e300_clk = {
-       .name = "e300_clk",
-       .calc = e300_clk_calc,
-       .parent = &csb_clk,
-};
-
-static struct clk ips_clk = {
-       .name = "ips_clk",
-       .calc = generic_div_clk_calc,
-       .parent = &csb_clk,
-       .div_shift = 23,
-};
-
-/*
- * Clocks controlled by SCCR1 (.reg = 0)
- */
-static struct clk lpc_clk = {
-       .name = "lpc_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 0,
-       .bit = 30,
-       .calc = generic_div_clk_calc,
-       .parent = &ips_clk,
-       .div_shift = 11,
-};
-
-static struct clk nfc_clk = {
-       .name = "nfc_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 0,
-       .bit = 29,
-       .calc = generic_div_clk_calc,
-       .parent = &ips_clk,
-       .div_shift = 8,
-};
-
-static struct clk pata_clk = {
-       .name = "pata_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 0,
-       .bit = 28,
-       .calc = unity_clk_calc,
-       .parent = &ips_clk,
-};
-
-/*
- * PSC clocks (bits 27 - 16)
- * are setup elsewhere
- */
-
-static struct clk sata_clk = {
-       .name = "sata_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 0,
-       .bit = 14,
-       .calc = unity_clk_calc,
-       .parent = &ips_clk,
-};
-
-static struct clk fec_clk = {
-       .name = "fec_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 0,
-       .bit = 13,
-       .calc = unity_clk_calc,
-       .parent = &ips_clk,
-};
-
-static struct clk pci_clk = {
-       .name = "pci_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 0,
-       .bit = 11,
-       .calc = generic_div_clk_calc,
-       .parent = &csb_clk,
-       .div_shift = 20,
-};
-
-/*
- * Clocks controlled by SCCR2 (.reg = 1)
- */
-static struct clk diu_clk = {
-       .name = "diu_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 31,
-       .calc = diu_clk_calc,
-};
-
-static struct clk viu_clk = {
-       .name = "viu_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 18,
-       .calc = viu_clk_calc,
-};
-
-static struct clk axe_clk = {
-       .name = "axe_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 30,
-       .calc = unity_clk_calc,
-       .parent = &csb_clk,
-};
-
-static struct clk usb1_clk = {
-       .name = "usb1_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 28,
-       .calc = unity_clk_calc,
-       .parent = &csb_clk,
-};
-
-static struct clk usb2_clk = {
-       .name = "usb2_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 27,
-       .calc = unity_clk_calc,
-       .parent = &csb_clk,
-};
-
-static struct clk i2c_clk = {
-       .name = "i2c_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 26,
-       .calc = unity_clk_calc,
-       .parent = &ips_clk,
-};
-
-static struct clk mscan_clk = {
-       .name = "mscan_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 25,
-       .calc = unity_clk_calc,
-       .parent = &ips_clk,
-};
-
-static struct clk sdhc_clk = {
-       .name = "sdhc_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 24,
-       .calc = unity_clk_calc,
-       .parent = &ips_clk,
-};
-
-static struct clk mbx_bus_clk = {
-       .name = "mbx_bus_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 22,
-       .calc = half_clk_calc,
-       .parent = &csb_clk,
-};
-
-static struct clk mbx_clk = {
-       .name = "mbx_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 21,
-       .calc = unity_clk_calc,
-       .parent = &csb_clk,
-};
-
-static struct clk mbx_3d_clk = {
-       .name = "mbx_3d_clk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 20,
-       .calc = generic_div_clk_calc,
-       .parent = &mbx_bus_clk,
-       .div_shift = 14,
-};
-
-static void psc_mclk_in_calc(struct clk *clk)
-{
-       clk->rate = devtree_getfreq("psc_mclk_in");
-       if (!clk->rate)
-               clk->rate = 25000000;
-}
-
-static struct clk psc_mclk_in = {
-       .name = "psc_mclk_in",
-       .calc = psc_mclk_in_calc,
-};
-
-static struct clk spdif_txclk = {
-       .name = "spdif_txclk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 23,
-};
-
-static struct clk spdif_rxclk = {
-       .name = "spdif_rxclk",
-       .flags = CLK_HAS_CTRL,
-       .reg = 1,
-       .bit = 23,
-};
-
-static void ac97_clk_calc(struct clk *clk)
-{
-       /* ac97 bit clock is always 24.567 MHz */
-       clk->rate = 24567000;
-}
-
-static struct clk ac97_clk = {
-       .name = "ac97_clk_in",
-       .calc = ac97_clk_calc,
-};
-
-static struct clk *rate_clks[] = {
-       &ref_clk,
-       &sys_clk,
-       &diu_clk,
-       &viu_clk,
-       &csb_clk,
-       &e300_clk,
-       &ips_clk,
-       &fec_clk,
-       &sata_clk,
-       &pata_clk,
-       &nfc_clk,
-       &lpc_clk,
-       &mbx_bus_clk,
-       &mbx_clk,
-       &mbx_3d_clk,
-       &axe_clk,
-       &usb1_clk,
-       &usb2_clk,
-       &i2c_clk,
-       &mscan_clk,
-       &sdhc_clk,
-       &pci_clk,
-       &psc_mclk_in,
-       &spdif_txclk,
-       &spdif_rxclk,
-       &ac97_clk,
-       NULL
-};
-
-static void rate_clk_init(struct clk *clk)
-{
-       if (clk->calc) {
-               clk->calc(clk);
-               clk->flags |= CLK_HAS_RATE;
-               clk_register(clk);
-       } else {
-               printk(KERN_WARNING
-                      "Could not initialize clk %s without a calc routine\n",
-                      clk->name);
-       }
-}
-
-static void rate_clks_init(void)
-{
-       struct clk **cpp, *clk;
-
-       cpp = rate_clks;
-       while ((clk = *cpp++))
-               rate_clk_init(clk);
-}
-
-/*
- * There are two clk enable registers with 32 enable bits each
- * psc clocks and device clocks are all stored in dev_clks
- */
-static struct clk dev_clks[2][32];
-
-/*
- * Given a psc number return the dev_clk
- * associated with it
- */
-static struct clk *psc_dev_clk(int pscnum)
-{
-       int reg, bit;
-       struct clk *clk;
-
-       reg = 0;
-       bit = 27 - pscnum;
-
-       clk = &dev_clks[reg][bit];
-       clk->reg = 0;
-       clk->bit = bit;
-       return clk;
-}
-
-/*
- * PSC clock rate calculation
- */
-static void psc_calc_rate(struct clk *clk, int pscnum, struct device_node *np)
-{
-       unsigned long mclk_src = sys_clk.rate;
-       unsigned long mclk_div;
-
-       /*
-        * Can only change value of mclk divider
-        * when the divider is disabled.
-        *
-        * Zero is not a valid divider so minimum
-        * divider is 1
-        *
-        * disable/set divider/enable
-        */
-       out_be32(&clockctl->pccr[pscnum], 0);
-       out_be32(&clockctl->pccr[pscnum], 0x00020000);
-       out_be32(&clockctl->pccr[pscnum], 0x00030000);
-
-       if (in_be32(&clockctl->pccr[pscnum]) & 0x80) {
-               clk->rate = spdif_rxclk.rate;
-               return;
-       }
-
-       switch ((in_be32(&clockctl->pccr[pscnum]) >> 14) & 0x3) {
-       case 0:
-               mclk_src = sys_clk.rate;
-               break;
-       case 1:
-               mclk_src = ref_clk.rate;
-               break;
-       case 2:
-               mclk_src = psc_mclk_in.rate;
-               break;
-       case 3:
-               mclk_src = spdif_txclk.rate;
-               break;
-       }
-
-       mclk_div = ((in_be32(&clockctl->pccr[pscnum]) >> 17) & 0x7fff) + 1;
-       clk->rate = mclk_src / mclk_div;
-}
-
-/*
- * Find all psc nodes in device tree and assign a clock
- * with name "psc%d_mclk" and dev pointing at the device
- * returned from of_find_device_by_node
- */
-static void psc_clks_init(void)
-{
-       struct device_node *np;
-       struct platform_device *ofdev;
-       u32 reg;
-       const char *psc_compat;
-
-       psc_compat = mpc512x_select_psc_compat();
-       if (!psc_compat)
-               return;
-
-       for_each_compatible_node(np, NULL, psc_compat) {
-               if (!of_property_read_u32(np, "reg", &reg)) {
-                       int pscnum = (reg & 0xf00) >> 8;
-                       struct clk *clk = psc_dev_clk(pscnum);
-
-                       clk->flags = CLK_HAS_RATE | CLK_HAS_CTRL;
-                       ofdev = of_find_device_by_node(np);
-                       clk->dev = &ofdev->dev;
-                       /*
-                        * AC97 is special rate clock does
-                        * not go through normal path
-                        */
-                       if (of_device_is_compatible(np, "fsl,mpc5121-psc-ac97"))
-                               clk->rate = ac97_clk.rate;
-                       else
-                               psc_calc_rate(clk, pscnum, np);
-                       sprintf(clk->name, "psc%d_mclk", pscnum);
-                       clk_register(clk);
-                       clk_enable(clk);
-               }
-       }
-}
-
-static struct clk_interface mpc5121_clk_functions = {
-       .clk_get                = mpc5121_clk_get,
-       .clk_enable             = mpc5121_clk_enable,
-       .clk_disable            = mpc5121_clk_disable,
-       .clk_get_rate           = mpc5121_clk_get_rate,
-       .clk_put                = mpc5121_clk_put,
-       .clk_round_rate         = mpc5121_clk_round_rate,
-       .clk_set_rate           = mpc5121_clk_set_rate,
-       .clk_set_parent         = NULL,
-       .clk_get_parent         = NULL,
-};
-
-int __init mpc5121_clk_init(void)
-{
-       struct device_node *np;
-
-       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
-       if (np) {
-               clockctl = of_iomap(np, 0);
-               of_node_put(np);
-       }
-
-       if (!clockctl) {
-               printk(KERN_ERR "Could not map clock control registers\n");
-               return 0;
-       }
-
-       rate_clks_init();
-       psc_clks_init();
-
-       /* leave clockctl mapped forever */
-       /*iounmap(clockctl); */
-       DEBUG_CLK_DUMP();
-       clocks_initialized++;
-       clk_functions = mpc5121_clk_functions;
-       return 0;
-}
index 36b5652aada200cc05fe7e12a99e84b989a9d434..adb95f03d4d4b20002992977120bd8a27073dc88 100644 (file)
@@ -12,6 +12,7 @@
  * (at your option) any later version.
  */
 
+#include <linux/clk.h>
 #include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/irq.h>
@@ -68,98 +69,112 @@ struct fsl_diu_shared_fb {
        bool            in_use;
 };
 
-#define DIU_DIV_MASK   0x000000ff
+/* receives a pixel clock spec in pico seconds, adjusts the DIU clock rate */
 static void mpc512x_set_pixel_clock(unsigned int pixclock)
 {
-       unsigned long bestval, bestfreq, speed, busfreq;
-       unsigned long minpixclock, maxpixclock, pixval;
-       struct mpc512x_ccm __iomem *ccm;
        struct device_node *np;
-       u32 temp;
-       long err;
-       int i;
+       struct clk *clk_diu;
+       unsigned long epsilon, minpixclock, maxpixclock;
+       unsigned long offset, want, got, delta;
 
-       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-clock");
+       /* lookup and enable the DIU clock */
+       np = of_find_compatible_node(NULL, NULL, "fsl,mpc5121-diu");
        if (!np) {
-               pr_err("Can't find clock control module.\n");
+               pr_err("Could not find DIU device tree node.\n");
                return;
        }
-
-       ccm = of_iomap(np, 0);
+       clk_diu = of_clk_get(np, 0);
+       if (IS_ERR(clk_diu)) {
+               /* backwards compat with device trees that lack clock specs */
+               clk_diu = clk_get_sys(np->name, "ipg");
+       }
        of_node_put(np);
-       if (!ccm) {
-               pr_err("Can't map clock control module reg.\n");
+       if (IS_ERR(clk_diu)) {
+               pr_err("Could not lookup DIU clock.\n");
                return;
        }
-
-       np = of_find_node_by_type(NULL, "cpu");
-       if (np) {
-               const unsigned int *prop =
-                       of_get_property(np, "bus-frequency", NULL);
-
-               of_node_put(np);
-               if (prop) {
-                       busfreq = *prop;
-               } else {
-                       pr_err("Can't get bus-frequency property\n");
-                       return;
-               }
-       } else {
-               pr_err("Can't find 'cpu' node.\n");
+       if (clk_prepare_enable(clk_diu)) {
+               pr_err("Could not enable DIU clock.\n");
                return;
        }
 
-       /* Pixel Clock configuration */
-       pr_debug("DIU: Bus Frequency = %lu\n", busfreq);
-       speed = busfreq * 4; /* DIU_DIV ratio is 4 * CSB_CLK / DIU_CLK */
-
-       /* Calculate the pixel clock with the smallest error */
-       /* calculate the following in steps to avoid overflow */
-       pr_debug("DIU pixclock in ps - %d\n", pixclock);
-       temp = (1000000000 / pixclock) * 1000;
-       pixclock = temp;
-       pr_debug("DIU pixclock freq - %u\n", pixclock);
-
-       temp = temp / 20; /* pixclock * 0.05 */
-       pr_debug("deviation = %d\n", temp);
-       minpixclock = pixclock - temp;
-       maxpixclock = pixclock + temp;
-       pr_debug("DIU minpixclock - %lu\n", minpixclock);
-       pr_debug("DIU maxpixclock - %lu\n", maxpixclock);
-       pixval = speed/pixclock;
-       pr_debug("DIU pixval = %lu\n", pixval);
-
-       err = LONG_MAX;
-       bestval = pixval;
-       pr_debug("DIU bestval = %lu\n", bestval);
-
-       bestfreq = 0;
-       for (i = -1; i <= 1; i++) {
-               temp = speed / (pixval+i);
-               pr_debug("DIU test pixval i=%d, pixval=%lu, temp freq. = %u\n",
-                       i, pixval, temp);
-               if ((temp < minpixclock) || (temp > maxpixclock))
-                       pr_debug("DIU exceeds monitor range (%lu to %lu)\n",
-                               minpixclock, maxpixclock);
-               else if (abs(temp - pixclock) < err) {
-                       pr_debug("Entered the else if block %d\n", i);
-                       err = abs(temp - pixclock);
-                       bestval = pixval + i;
-                       bestfreq = temp;
-               }
+       /*
+        * convert the picoseconds spec into the desired clock rate,
+        * determine the acceptable clock range for the monitor (+/- 5%),
+        * do the calculation in steps to avoid integer overflow
+        */
+       pr_debug("DIU pixclock in ps - %u\n", pixclock);
+       pixclock = (1000000000 / pixclock) * 1000;
+       pr_debug("DIU pixclock freq  - %u\n", pixclock);
+       epsilon = pixclock / 20; /* pixclock * 0.05 */
+       pr_debug("DIU deviation      - %lu\n", epsilon);
+       minpixclock = pixclock - epsilon;
+       maxpixclock = pixclock + epsilon;
+       pr_debug("DIU minpixclock    - %lu\n", minpixclock);
+       pr_debug("DIU maxpixclock    - %lu\n", maxpixclock);
+
+       /*
+        * check whether the DIU supports the desired pixel clock
+        *
+        * - simply request the desired clock and see what the
+        *   platform's clock driver will make of it, assuming that it
+        *   will setup the best approximation of the requested value
+        * - try other candidate frequencies in the order of decreasing
+        *   preference (i.e. with increasing distance from the desired
+        *   pixel clock, and checking the lower frequency before the
+        *   higher frequency to not overload the hardware) until the
+        *   first match is found -- any potential subsequent match
+        *   would only be as good as the former match or typically
+        *   would be less preferrable
+        *
+        * the offset increment of pixelclock divided by 64 is an
+        * arbitrary choice -- it's simple to calculate, in the typical
+        * case we expect the first check to succeed already, in the
+        * worst case seven frequencies get tested (the exact center and
+        * three more values each to the left and to the right) before
+        * the 5% tolerance window is exceeded, resulting in fast enough
+        * execution yet high enough probability of finding a suitable
+        * value, while the error rate will be in the order of single
+        * percents
+        */
+       for (offset = 0; offset <= epsilon; offset += pixclock / 64) {
+               want = pixclock - offset;
+               pr_debug("DIU checking clock - %lu\n", want);
+               clk_set_rate(clk_diu, want);
+               got = clk_get_rate(clk_diu);
+               delta = abs(pixclock - got);
+               if (delta < epsilon)
+                       break;
+               if (!offset)
+                       continue;
+               want = pixclock + offset;
+               pr_debug("DIU checking clock - %lu\n", want);
+               clk_set_rate(clk_diu, want);
+               got = clk_get_rate(clk_diu);
+               delta = abs(pixclock - got);
+               if (delta < epsilon)
+                       break;
        }
+       if (offset <= epsilon) {
+               pr_debug("DIU clock accepted - %lu\n", want);
+               pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n",
+                        pixclock, got, delta, epsilon);
+               return;
+       }
+       pr_warn("DIU pixclock auto search unsuccessful\n");
 
-       pr_debug("DIU chose = %lx\n", bestval);
-       pr_debug("DIU error = %ld\n NomPixClk ", err);
-       pr_debug("DIU: Best Freq = %lx\n", bestfreq);
-       /* Modify DIU_DIV in CCM SCFR1 */
-       temp = in_be32(&ccm->scfr1);
-       pr_debug("DIU: Current value of SCFR1: 0x%08x\n", temp);
-       temp &= ~DIU_DIV_MASK;
-       temp |= (bestval & DIU_DIV_MASK);
-       out_be32(&ccm->scfr1, temp);
-       pr_debug("DIU: Modified value of SCFR1: 0x%08x\n", temp);
-       iounmap(ccm);
+       /*
+        * what is the most appropriate action to take when the search
+        * for an available pixel clock which is acceptable to the
+        * monitor has failed?  disable the DIU (clock) or just provide
+        * a "best effort"?  we go with the latter
+        */
+       pr_warn("DIU pixclock best effort fallback (backend's choice)\n");
+       clk_set_rate(clk_diu, pixclock);
+       got = clk_get_rate(clk_diu);
+       delta = abs(pixclock - got);
+       pr_debug("DIU pixclock want %u, got %lu, delta %lu, eps %lu\n",
+                pixclock, got, delta, epsilon);
 }
 
 static enum fsl_diu_monitor_port
index af54174801f7aa9042f12487e5fe94530f8d089a..b625a2c6f4f27b5ba77dfd9e9c8ccf1a9cf66c23 100644 (file)
@@ -1,7 +1,7 @@
 config PPC_MPC52xx
        bool "52xx-based boards"
        depends on 6xx
-       select PPC_CLOCK
+       select COMMON_CLK
        select PPC_PCI_CHOICE
 
 config PPC_MPC5200_SIMPLE
index 670a033264c0f1626af64f79b7b4fd23da797ec4..2bdc8c862c46c1af3c9ca38f4c116923d254fad6 100644 (file)
@@ -99,7 +99,6 @@ config SBC834x
 config ASP834x
        bool "Analogue & Micro ASP 834x"
        select PPC_MPC834x
-       select REDBOOT
        help
          This enables support for the Analogue & Micro ASP 83xx
          board.
index fd71cfdf23802e56f121d6c5dbc6144d3dcbd11f..e238b6a55b1593e08f43e029bf6b4f9af1a7836f 100644 (file)
@@ -11,7 +11,6 @@
  * (at your option) any later version.
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/device.h>
index 3d9716ccd3274b2fa162e2137ced47883c9a27cd..4b4c081df94db168e480e10bff1d427debb1c6bb 100644 (file)
@@ -10,7 +10,6 @@
  * by the Free Software Foundation.
  */
 
-#include <linux/init.h>
 #include <linux/pm.h>
 #include <linux/types.h>
 #include <linux/ioport.h>
index 4d4634958cfb09107a37829dc19ee65b427a6bab..c17aae80e7ffd73d4860a64a42bee8b686fb4b62 100644 (file)
@@ -123,6 +123,12 @@ config P1023_RDS
        help
          This option enables support for the P1023 RDS and RDB boards
 
+config TWR_P102x
+       bool "Freescale TWR-P102x"
+       select DEFAULT_UIMAGE
+       help
+         This option enables support for the TWR-P1025 board.
+
 config SOCRATES
        bool "Socrates"
        select DEFAULT_UIMAGE
index dd4c0b59577bb98f0574f5eca765f46a5a5b287c..25cebe74ac463365b7d5a4d7e89aea8088a818a4 100644 (file)
@@ -18,6 +18,7 @@ obj-$(CONFIG_P1010_RDB)   += p1010rdb.o
 obj-$(CONFIG_P1022_DS)    += p1022_ds.o
 obj-$(CONFIG_P1022_RDK)   += p1022_rdk.o
 obj-$(CONFIG_P1023_RDS)   += p1023_rds.o
+obj-$(CONFIG_TWR_P102x)   += twr_p102x.o
 obj-$(CONFIG_CORENET_GENERIC)   += corenet_generic.o
 obj-$(CONFIG_STX_GP3)    += stx_gp3.o
 obj-$(CONFIG_TQM85xx)    += tqm85xx.o
index eba78c85303f9f6ee27eb8d1d0c2f4221e056d65..3b085c7ee539bc23fbcaf0e38ebaa7752a8e05d3 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
 
+#include <asm/qe.h>
 #include <sysdev/cpm2_pic.h>
 
 #include "mpc85xx.h"
@@ -82,3 +83,40 @@ void __init mpc85xx_cpm2_pic_init(void)
        irq_set_chained_handler(irq, cpm2_cascade);
 }
 #endif
+
+#ifdef CONFIG_QUICC_ENGINE
+void __init mpc85xx_qe_init(void)
+{
+       struct device_node *np;
+
+       np = of_find_compatible_node(NULL, NULL, "fsl,qe");
+       if (!np) {
+               np = of_find_node_by_name(NULL, "qe");
+               if (!np) {
+                       pr_err("%s: Could not find Quicc Engine node\n",
+                                       __func__);
+                       return;
+               }
+       }
+
+       if (!of_device_is_available(np)) {
+               of_node_put(np);
+               return;
+       }
+
+       qe_reset();
+       of_node_put(np);
+
+       np = of_find_node_by_name(NULL, "par_io");
+       if (np) {
+               struct device_node *ucc;
+
+               par_io_init(np);
+               of_node_put(np);
+
+               for_each_node_by_name(ucc, "ucc")
+                       par_io_of_config(ucc);
+
+       }
+}
+#endif
index 2aa7c5dc2c7f6d1131e482a27d58ff2931fdf709..fc51dd4092e5d10d88620f10c07434072e612b63 100644 (file)
@@ -8,4 +8,10 @@ extern void mpc85xx_cpm2_pic_init(void);
 static inline void __init mpc85xx_cpm2_pic_init(void) {}
 #endif /* CONFIG_CPM2 */
 
+#ifdef CONFIG_QUICC_ENGINE
+extern void mpc85xx_qe_init(void);
+#else
+static inline void __init mpc85xx_qe_init(void) {}
+#endif
+
 #endif
index a7b3621a8df5dc019c4ec63102ec71ef9a5d947f..34f3c5eb3bee77dcf584b9742a241ee9d99cc310 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006-2010, 2012 Freescale Semiconductor, Inc.
+ * Copyright (C) 2006-2010, 2012-2013 Freescale Semiconductor, Inc.
  * All rights reserved.
  *
  * Author: Andy Fleming <afleming@freescale.com>
@@ -238,32 +238,7 @@ static void __init mpc85xx_mds_qe_init(void)
 {
        struct device_node *np;
 
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!np) {
-               np = of_find_node_by_name(NULL, "qe");
-               if (!np)
-                       return;
-       }
-
-       if (!of_device_is_available(np)) {
-               of_node_put(np);
-               return;
-       }
-
-       qe_reset();
-       of_node_put(np);
-
-       np = of_find_node_by_name(NULL, "par_io");
-       if (np) {
-               struct device_node *ucc;
-
-               par_io_init(np);
-               of_node_put(np);
-
-               for_each_node_by_name(ucc, "ucc")
-                       par_io_of_config(ucc);
-       }
-
+       mpc85xx_qe_init();
        mpc85xx_mds_reset_ucc_phys();
 
        if (machine_is(p1021_mds)) {
index 53b6fb0a3d560a5be2e2aa0dd186075d34ff794b..e15bdd18fdb2f2571312a6cfad74ee5ee741bbd9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * MPC85xx RDB Board Setup
  *
- * Copyright 2009,2012 Freescale Semiconductor Inc.
+ * Copyright 2009,2012-2013 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
@@ -98,26 +98,7 @@ static void __init mpc85xx_rdb_setup_arch(void)
        fsl_pci_assign_primary();
 
 #ifdef CONFIG_QUICC_ENGINE
-       np = of_find_compatible_node(NULL, NULL, "fsl,qe");
-       if (!np) {
-               pr_err("%s: Could not find Quicc Engine node\n", __func__);
-               goto qe_fail;
-       }
-
-       qe_reset();
-       of_node_put(np);
-
-       np = of_find_node_by_name(NULL, "par_io");
-       if (np) {
-               struct device_node *ucc;
-
-               par_io_init(np);
-               of_node_put(np);
-
-               for_each_node_by_name(ucc, "ucc")
-                       par_io_of_config(ucc);
-
-       }
+       mpc85xx_qe_init();
 #if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
        if (machine_is(p1025_rdb)) {
 
@@ -148,8 +129,6 @@ static void __init mpc85xx_rdb_setup_arch(void)
 
        }
 #endif
-
-qe_fail:
 #endif /* CONFIG_QUICC_ENGINE */
 
        printk(KERN_INFO "MPC85xx RDB board from Freescale Semiconductor\n");
index b9197cea1854da9e9934b302c45045868efc8c83..bb75add670844e3f2e990d0a21e1c48a0ac42c20 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/platform_device.h>
 #include <linux/device.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/of_gpio.h>
 #include <linux/of_irq.h>
 #include <linux/workqueue.h>
index 393f975ab397c1dd32919b77f9f0cfe8351fc397..6382098d6f8d884aeea1fbbef387df8572f0b5b9 100644 (file)
@@ -389,15 +389,18 @@ static void mpc85xx_smp_machine_kexec(struct kimage *image)
 }
 #endif /* CONFIG_KEXEC */
 
-static void smp_85xx_setup_cpu(int cpu_nr)
+static void smp_85xx_basic_setup(int cpu_nr)
 {
-       if (smp_85xx_ops.probe == smp_mpic_probe)
-               mpic_setup_this_cpu();
-
        if (cpu_has_feature(CPU_FTR_DBELL))
                doorbell_setup_this_cpu();
 }
 
+static void smp_85xx_setup_cpu(int cpu_nr)
+{
+       mpic_setup_this_cpu();
+       smp_85xx_basic_setup(cpu_nr);
+}
+
 static const struct of_device_id mpc85xx_smp_guts_ids[] = {
        { .compatible = "fsl,mpc8572-guts", },
        { .compatible = "fsl,p1020-guts", },
@@ -412,13 +415,14 @@ void __init mpc85xx_smp_init(void)
 {
        struct device_node *np;
 
-       smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu;
 
        np = of_find_node_by_type(NULL, "open-pic");
        if (np) {
                smp_85xx_ops.probe = smp_mpic_probe;
+               smp_85xx_ops.setup_cpu = smp_85xx_setup_cpu;
                smp_85xx_ops.message_pass = smp_mpic_message_pass;
-       }
+       } else
+               smp_85xx_ops.setup_cpu = smp_85xx_basic_setup;
 
        if (cpu_has_feature(CPU_FTR_DBELL)) {
                /*
@@ -427,6 +431,7 @@ void __init mpc85xx_smp_init(void)
                 */
                smp_85xx_ops.message_pass = NULL;
                smp_85xx_ops.cause_ipi = doorbell_cause_ipi;
+               smp_85xx_ops.probe = NULL;
        }
 
        np = of_find_matching_node(NULL, mpc85xx_smp_guts_ids);
diff --git a/arch/powerpc/platforms/85xx/twr_p102x.c b/arch/powerpc/platforms/85xx/twr_p102x.c
new file mode 100644 (file)
index 0000000..c25ff10
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2010-2011, 2013 Freescale Semiconductor, Inc.
+ *
+ * Author: Michael Johnston <michael.johnston@freescale.com>
+ *
+ * Description:
+ * TWR-P102x Board Setup
+ *
+ * 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/init.h>
+#include <linux/errno.h>
+#include <linux/pci.h>
+#include <linux/of_platform.h>
+
+#include <asm/pci-bridge.h>
+#include <asm/udbg.h>
+#include <asm/mpic.h>
+#include <asm/qe.h>
+#include <asm/qe_ic.h>
+#include <asm/fsl_guts.h>
+
+#include <sysdev/fsl_soc.h>
+#include <sysdev/fsl_pci.h>
+#include "smp.h"
+
+#include "mpc85xx.h"
+
+static void __init twr_p1025_pic_init(void)
+{
+       struct mpic *mpic;
+
+#ifdef CONFIG_QUICC_ENGINE
+       struct device_node *np;
+#endif
+
+       mpic = mpic_alloc(NULL, 0, MPIC_BIG_ENDIAN |
+                       MPIC_SINGLE_DEST_CPU,
+                       0, 256, " OpenPIC  ");
+
+       BUG_ON(mpic == NULL);
+       mpic_init(mpic);
+
+#ifdef CONFIG_QUICC_ENGINE
+       np = of_find_compatible_node(NULL, NULL, "fsl,qe-ic");
+       if (np) {
+               qe_ic_init(np, 0, qe_ic_cascade_low_mpic,
+                               qe_ic_cascade_high_mpic);
+               of_node_put(np);
+       } else
+               pr_err("Could not find qe-ic node\n");
+#endif
+}
+
+/* ************************************************************************
+ *
+ * Setup the architecture
+ *
+ */
+static void __init twr_p1025_setup_arch(void)
+{
+#ifdef CONFIG_QUICC_ENGINE
+       struct device_node *np;
+#endif
+
+       if (ppc_md.progress)
+               ppc_md.progress("twr_p1025_setup_arch()", 0);
+
+       mpc85xx_smp_init();
+
+       fsl_pci_assign_primary();
+
+#ifdef CONFIG_QUICC_ENGINE
+       mpc85xx_qe_init();
+
+#if defined(CONFIG_UCC_GETH) || defined(CONFIG_SERIAL_QE)
+       if (machine_is(twr_p1025)) {
+               struct ccsr_guts __iomem *guts;
+
+               np = of_find_compatible_node(NULL, NULL, "fsl,p1021-guts");
+               if (np) {
+                       guts = of_iomap(np, 0);
+                       if (!guts)
+                               pr_err("twr_p1025: could not map global utilities register\n");
+                       else {
+                       /* P1025 has pins muxed for QE and other functions. To
+                        * enable QE UEC mode, we need to set bit QE0 for UCC1
+                        * in Eth mode, QE0 and QE3 for UCC5 in Eth mode, QE9
+                        * and QE12 for QE MII management signals in PMUXCR
+                        * register.
+                        * Set QE mux bits in PMUXCR */
+                       setbits32(&guts->pmuxcr, MPC85xx_PMUXCR_QE(0) |
+                                       MPC85xx_PMUXCR_QE(3) |
+                                       MPC85xx_PMUXCR_QE(9) |
+                                       MPC85xx_PMUXCR_QE(12));
+                       iounmap(guts);
+
+#if defined(CONFIG_SERIAL_QE)
+                       /* On P1025TWR board, the UCC7 acted as UART port.
+                        * However, The UCC7's CTS pin is low level in default,
+                        * it will impact the transmission in full duplex
+                        * communication. So disable the Flow control pin PA18.
+                        * The UCC7 UART just can use RXD and TXD pins.
+                        */
+                       par_io_config_pin(0, 18, 0, 0, 0, 0);
+#endif
+                       /* Drive PB29 to CPLD low - CPLD will then change
+                        * muxing from LBC to QE */
+                       par_io_config_pin(1, 29, 1, 0, 0, 0);
+                       par_io_data_set(1, 29, 0);
+                       }
+                       of_node_put(np);
+               }
+       }
+#endif
+#endif /* CONFIG_QUICC_ENGINE */
+
+       pr_info("TWR-P1025 board from Freescale Semiconductor\n");
+}
+
+machine_arch_initcall(twr_p1025, mpc85xx_common_publish_devices);
+
+static int __init twr_p1025_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "fsl,TWR-P1025");
+}
+
+define_machine(twr_p1025) {
+       .name                   = "TWR-P1025",
+       .probe                  = twr_p1025_probe,
+       .setup_arch             = twr_p1025_setup_arch,
+       .init_IRQ               = twr_p1025_pic_init,
+#ifdef CONFIG_PCI
+       .pcibios_fixup_bus      = fsl_pcibios_fixup_bus,
+#endif
+       .get_irq                = mpic_get_irq,
+       .restart                = fsl_rstcr_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
index 8dec3c0911ad0f4ad047b6d68ce8a34b95452cfe..bd6f1a1cf922bc60bf15ed1e659c6ecb06d96312 100644 (file)
@@ -45,7 +45,6 @@ config PPC_EP88XC
 config PPC_ADDER875
        bool "Analogue & Micro Adder 875"
        select CPM1
-       select REDBOOT
        help
          This enables support for the Analogue & Micro Adder 875
          board.
index bca2465a9c347ad65f3617a7a51f2e4f2a73034a..434fda39bf8b51f219098f207ce9cf35760fd484 100644 (file)
@@ -72,6 +72,7 @@ config PPC_BOOK3S_64
        select PPC_HAVE_PMU_SUPPORT
        select SYS_SUPPORTS_HUGETLBFS
        select HAVE_ARCH_TRANSPARENT_HUGEPAGE if PPC_64K_PAGES
+       select ARCH_SUPPORTS_NUMA_BALANCING
 
 config PPC_BOOK3E_64
        bool "Embedded processors"
index c34ee4e608734f387a0e43ed87abc1ba27e6dd27..d4d245c0d78799a6f48e65aae52560b75daac6e7 100644 (file)
@@ -111,7 +111,7 @@ static long beat_lpar_hpte_insert(unsigned long hpte_group,
                DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
 
        if (rflags & _PAGE_NO_CACHE)
-               hpte_r &= ~_PAGE_COHERENT;
+               hpte_r &= ~HPTE_R_M;
 
        raw_spin_lock(&beat_htab_lock);
        lpar_rc = beat_read_mask(hpte_group);
@@ -337,7 +337,7 @@ static long beat_lpar_hpte_insert_v3(unsigned long hpte_group,
                DBG_LOW(" hpte_v=%016lx, hpte_r=%016lx\n", hpte_v, hpte_r);
 
        if (rflags & _PAGE_NO_CACHE)
-               hpte_r &= ~_PAGE_COHERENT;
+               hpte_r &= ~HPTE_R_M;
 
        /* insert into not-volted entry */
        lpar_rc = beat_insert_htab_entry3(0, hpte_group, hpte_v, hpte_r,
index b53560660b72e72030a6235d295be8ab1fd9c722..2b90ff8a93bea7542fee7d89f99d3439bf9e0d13 100644 (file)
@@ -197,7 +197,7 @@ static int tce_build_cell(struct iommu_table *tbl, long index, long npages,
 
        io_pte = (unsigned long *)tbl->it_base + (index - tbl->it_offset);
 
-       for (i = 0; i < npages; i++, uaddr += IOMMU_PAGE_SIZE)
+       for (i = 0; i < npages; i++, uaddr += tbl->it_page_shift)
                io_pte[i] = base_pte | (__pa(uaddr) & CBE_IOPTE_RPN_Mask);
 
        mb();
@@ -430,7 +430,7 @@ static void cell_iommu_setup_hardware(struct cbe_iommu *iommu,
 {
        cell_iommu_setup_stab(iommu, base, size, 0, 0);
        iommu->ptab = cell_iommu_alloc_ptab(iommu, base, size, 0, 0,
-                                           IOMMU_PAGE_SHIFT);
+                                           IOMMU_PAGE_SHIFT_4K);
        cell_iommu_enable_hardware(iommu);
 }
 
@@ -487,8 +487,10 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct device_node *np,
        window->table.it_blocksize = 16;
        window->table.it_base = (unsigned long)iommu->ptab;
        window->table.it_index = iommu->nid;
-       window->table.it_offset = (offset >> IOMMU_PAGE_SHIFT) + pte_offset;
-       window->table.it_size = size >> IOMMU_PAGE_SHIFT;
+       window->table.it_page_shift = IOMMU_PAGE_SHIFT_4K;
+       window->table.it_offset =
+               (offset >> window->table.it_page_shift) + pte_offset;
+       window->table.it_size = size >> window->table.it_page_shift;
 
        iommu_init_table(&window->table, iommu->nid);
 
@@ -773,7 +775,7 @@ static void __init cell_iommu_init_one(struct device_node *np,
 
        /* Setup the iommu_table */
        cell_iommu_setup_window(iommu, np, base, size,
-                               offset >> IOMMU_PAGE_SHIFT);
+                               offset >> IOMMU_PAGE_SHIFT_4K);
 }
 
 static void __init cell_disable_iommus(void)
@@ -1122,7 +1124,7 @@ static int __init cell_iommu_fixed_mapping_init(void)
 
                cell_iommu_setup_stab(iommu, dbase, dsize, fbase, fsize);
                iommu->ptab = cell_iommu_alloc_ptab(iommu, dbase, dsize, 0, 0,
-                                                   IOMMU_PAGE_SHIFT);
+                                                   IOMMU_PAGE_SHIFT_4K);
                cell_iommu_setup_fixed_ptab(iommu, np, dbase, dsize,
                                             fbase, fsize);
                cell_iommu_enable_hardware(iommu);
index dead91b177b9df702e236d9abba5a379a5aa793d..b6c9a0dcc92485b6dbf07e1934d80a6a16d7264c 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/interrupt.h>
 #include <linux/kernel_stat.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/spinlock.h>
 
 #include <asm/ptrace.h>
index 302ba43d73a168df77e53d20f5203513c2c03695..6d3c7a9fd047a5de571a733d11aa31bd48cd82bd 100644 (file)
@@ -67,6 +67,18 @@ config PPC_C2K
          This option enables support for the GE Fanuc C2K board (formerly
          an SBS board).
 
+config MVME5100
+       bool "Motorola/Emerson MVME5100"
+       depends on EMBEDDED6xx
+       select MPIC
+       select PCI
+       select PPC_INDIRECT_PCI
+       select PPC_I8259
+       select PPC_NATIVE
+       help
+         This option enables support for the Motorola (now Emerson) MVME5100
+         board.
+
 config TSI108_BRIDGE
        bool
        select PCI
@@ -113,4 +125,3 @@ config WII
        help
          Select WII if configuring for the Nintendo Wii.
          More information at: <http://gc-linux.sourceforge.net/>
-
index 66c23e423f40784ae85affb14bd5d7e95f8d68c2..cdd48d402b93eba2633ff5854eb4bf8723e47cbb 100644 (file)
@@ -11,3 +11,4 @@ obj-$(CONFIG_USBGECKO_UDBG)   += usbgecko_udbg.o
 obj-$(CONFIG_GAMECUBE_COMMON)  += flipper-pic.o
 obj-$(CONFIG_GAMECUBE)         += gamecube.o
 obj-$(CONFIG_WII)              += wii.o hlwd-pic.o
+obj-$(CONFIG_MVME5100)         += mvme5100.o
index 6c03034dbbd31b4aba9f0faf06579bdf9e8fab21..c269caee58f9486f6e260cf67367cb501820642c 100644 (file)
@@ -15,7 +15,6 @@
 #define pr_fmt(fmt) DRV_MODULE_NAME ": " fmt
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/irq.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
diff --git a/arch/powerpc/platforms/embedded6xx/mvme5100.c b/arch/powerpc/platforms/embedded6xx/mvme5100.c
new file mode 100644 (file)
index 0000000..25e3bfb
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Board setup routines for the Motorola/Emerson MVME5100.
+ *
+ * Copyright 2013 CSC Australia Pty. Ltd.
+ *
+ * Based on earlier code by:
+ *
+ *    Matt Porter, MontaVista Software Inc.
+ *    Copyright 2001 MontaVista Software 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.
+ *
+ * Author: Stephen Chivers <schivers@csc.com>
+ *
+ */
+
+#include <linux/of_platform.h>
+
+#include <asm/i8259.h>
+#include <asm/pci-bridge.h>
+#include <asm/mpic.h>
+#include <asm/prom.h>
+#include <mm/mmu_decl.h>
+#include <asm/udbg.h>
+
+#define HAWK_MPIC_SIZE         0x00040000U
+#define MVME5100_PCI_MEM_OFFSET 0x00000000
+
+/* Board register addresses. */
+#define BOARD_STATUS_REG       0xfef88080
+#define BOARD_MODFAIL_REG      0xfef88090
+#define BOARD_MODRST_REG       0xfef880a0
+#define BOARD_TBEN_REG         0xfef880c0
+#define BOARD_SW_READ_REG      0xfef880e0
+#define BOARD_GEO_ADDR_REG     0xfef880e8
+#define BOARD_EXT_FEATURE1_REG 0xfef880f0
+#define BOARD_EXT_FEATURE2_REG 0xfef88100
+
+static phys_addr_t pci_membase;
+static u_char *restart;
+
+static void mvme5100_8259_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       unsigned int cascade_irq = i8259_irq();
+
+       if (cascade_irq != NO_IRQ)
+               generic_handle_irq(cascade_irq);
+
+       chip->irq_eoi(&desc->irq_data);
+}
+
+static void __init mvme5100_pic_init(void)
+{
+       struct mpic *mpic;
+       struct device_node *np;
+       struct device_node *cp = NULL;
+       unsigned int cirq;
+       unsigned long intack = 0;
+       const u32 *prop = NULL;
+
+       np = of_find_node_by_type(NULL, "open-pic");
+       if (!np) {
+               pr_err("Could not find open-pic node\n");
+               return;
+       }
+
+       mpic = mpic_alloc(np, pci_membase, 0, 16, 256, " OpenPIC  ");
+
+       BUG_ON(mpic == NULL);
+       of_node_put(np);
+
+       mpic_assign_isu(mpic, 0, pci_membase + 0x10000);
+
+       mpic_init(mpic);
+
+       cp = of_find_compatible_node(NULL, NULL, "chrp,iic");
+       if (cp == NULL) {
+               pr_warn("mvme5100_pic_init: couldn't find i8259\n");
+               return;
+       }
+
+       cirq = irq_of_parse_and_map(cp, 0);
+       if (cirq == NO_IRQ) {
+               pr_warn("mvme5100_pic_init: no cascade interrupt?\n");
+               return;
+       }
+
+       np = of_find_compatible_node(NULL, "pci", "mpc10x-pci");
+       if (np) {
+               prop = of_get_property(np, "8259-interrupt-acknowledge", NULL);
+
+               if (prop)
+                       intack = prop[0];
+
+               of_node_put(np);
+       }
+
+       if (intack)
+               pr_debug("mvme5100_pic_init: PCI 8259 intack at 0x%016lx\n",
+                  intack);
+
+       i8259_init(cp, intack);
+       of_node_put(cp);
+       irq_set_chained_handler(cirq, mvme5100_8259_cascade);
+}
+
+static int __init mvme5100_add_bridge(struct device_node *dev)
+{
+       const int               *bus_range;
+       int                     len;
+       struct pci_controller   *hose;
+       unsigned short          devid;
+
+       pr_info("Adding PCI host bridge %s\n", dev->full_name);
+
+       bus_range = of_get_property(dev, "bus-range", &len);
+
+       hose = pcibios_alloc_controller(dev);
+       if (hose == NULL)
+               return -ENOMEM;
+
+       hose->first_busno = bus_range ? bus_range[0] : 0;
+       hose->last_busno = bus_range ? bus_range[1] : 0xff;
+
+       setup_indirect_pci(hose, 0xfe000cf8, 0xfe000cfc, 0);
+
+       pci_process_bridge_OF_ranges(hose, dev, 1);
+
+       early_read_config_word(hose, 0, 0, PCI_DEVICE_ID, &devid);
+
+       if (devid != PCI_DEVICE_ID_MOTOROLA_HAWK) {
+               pr_err("HAWK PHB not present?\n");
+               return 0;
+       }
+
+       early_read_config_dword(hose, 0, 0, PCI_BASE_ADDRESS_1, &pci_membase);
+
+       if (pci_membase == 0) {
+               pr_err("HAWK PHB mibar not correctly set?\n");
+               return 0;
+       }
+
+       pr_info("mvme5100_pic_init: pci_membase: %x\n", pci_membase);
+
+       return 0;
+}
+
+static struct of_device_id mvme5100_of_bus_ids[] __initdata = {
+       { .compatible = "hawk-bridge", },
+       {},
+};
+
+/*
+ * Setup the architecture
+ */
+static void __init mvme5100_setup_arch(void)
+{
+       struct device_node *np;
+
+       if (ppc_md.progress)
+               ppc_md.progress("mvme5100_setup_arch()", 0);
+
+       for_each_compatible_node(np, "pci", "hawk-pci")
+               mvme5100_add_bridge(np);
+
+       restart = ioremap(BOARD_MODRST_REG, 4);
+}
+
+
+static void mvme5100_show_cpuinfo(struct seq_file *m)
+{
+       seq_puts(m, "Vendor\t\t: Motorola/Emerson\n");
+       seq_puts(m, "Machine\t\t: MVME5100\n");
+}
+
+static void mvme5100_restart(char *cmd)
+{
+
+       local_irq_disable();
+       mtmsr(mfmsr() | MSR_IP);
+
+       out_8((u_char *) restart, 0x01);
+
+       while (1)
+               ;
+}
+
+/*
+ * Called very early, device-tree isn't unflattened
+ */
+static int __init mvme5100_probe(void)
+{
+       unsigned long root = of_get_flat_dt_root();
+
+       return of_flat_dt_is_compatible(root, "MVME5100");
+}
+
+static int __init probe_of_platform_devices(void)
+{
+
+       of_platform_bus_probe(NULL, mvme5100_of_bus_ids, NULL);
+       return 0;
+}
+
+machine_device_initcall(mvme5100, probe_of_platform_devices);
+
+define_machine(mvme5100) {
+       .name                   = "MVME5100",
+       .probe                  = mvme5100_probe,
+       .setup_arch             = mvme5100_setup_arch,
+       .init_IRQ               = mvme5100_pic_init,
+       .show_cpuinfo           = mvme5100_show_cpuinfo,
+       .get_irq                = mpic_get_irq,
+       .restart                = mvme5100_restart,
+       .calibrate_decr         = generic_calibrate_decr,
+       .progress               = udbg_progress,
+};
index f3defd8a28069af474718e40017ac3a8359e79e7..aafa01ba062f80f904a44fa8e7fd7db93763aed0 100644 (file)
@@ -18,7 +18,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/export.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
index 7d2d036754b5b56ecf5df1ddeb6367d2cc6b223c..2e576f2ae44256301fbcdb149ea47fdeef241fe7 100644 (file)
@@ -138,8 +138,11 @@ static void iommu_table_iobmap_setup(void)
        pr_debug(" -> %s\n", __func__);
        iommu_table_iobmap.it_busno = 0;
        iommu_table_iobmap.it_offset = 0;
+       iommu_table_iobmap.it_page_shift = IOBMAP_PAGE_SHIFT;
+
        /* it_size is in number of entries */
-       iommu_table_iobmap.it_size = 0x80000000 >> IOBMAP_PAGE_SHIFT;
+       iommu_table_iobmap.it_size =
+               0x80000000 >> iommu_table_iobmap.it_page_shift;
 
        /* Initialize the common IOMMU code */
        iommu_table_iobmap.it_base = (unsigned long)iob_l2_base;
index d588e48dff74cd9d1469e4dfafce5627ec09b4f2..43075081721f7ea93c51240bc92a5b73573e4759 100644 (file)
@@ -5,7 +5,6 @@
  * FIXME: LOCKING !!!
  */
 
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
index 9fced3f6d2dcfadbf0f26c71d57693d79b1c78ba..895e8a20a3fc064069d49d4b4cc1280b05df4e87 100644 (file)
@@ -13,11 +13,6 @@ config PPC_POWERNV
        select ARCH_RANDOM
        default y
 
-config POWERNV_MSI
-       bool "Support PCI MSI on PowerNV platform"
-       depends on PCI_MSI
-       default y
-
 config PPC_POWERNV_RTAS
        depends on PPC_POWERNV
        bool "Support for RTAS based PowerNV platforms such as BML"
index 873fa1370dc44c1b0b3994e7555c4fac450adcbd..8d767fde5a6ac32484bf106698d8c43e1292cd73 100644 (file)
@@ -6,3 +6,4 @@ obj-$(CONFIG_SMP)       += smp.o
 obj-$(CONFIG_PCI)      += pci.o pci-p5ioc2.o pci-ioda.o
 obj-$(CONFIG_EEH)      += eeh-ioda.o eeh-powernv.o
 obj-$(CONFIG_PPC_SCOM) += opal-xscom.o
+obj-$(CONFIG_MEMORY_FAILURE)   += opal-memory-errors.o
index d7ddcee7feb8bc8084d18be32f348263c8de6e0e..e1e71618b70cfe5d4caa7d15e30bc42a37361c56 100644 (file)
@@ -14,7 +14,6 @@
 #include <linux/bootmem.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/kernel.h>
@@ -578,11 +577,8 @@ static int ioda_eeh_get_log(struct eeh_pe *pe, int severity,
                return -EIO;
        }
 
-       /*
-        * FIXME: We probably need log the error in somewhere.
-        * Lets make it up in future.
-        */
-       /* pr_info("%s", phb->diag.blob); */
+       /* The PHB diag-data is always indicative */
+       pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
 
        spin_unlock_irqrestore(&phb->lock, flags);
 
@@ -670,143 +666,9 @@ static void ioda_eeh_hub_diag(struct pci_controller *hose)
        }
 }
 
-static void ioda_eeh_p7ioc_phb_diag(struct pci_controller *hose,
-                                   struct OpalIoPhbErrorCommon *common)
-{
-       struct OpalIoP7IOCPhbErrorData *data;
-       int i;
-
-       data = (struct OpalIoP7IOCPhbErrorData *)common;
-
-       pr_info("P7IOC PHB#%x Diag-data (Version: %d)\n\n",
-               hose->global_number, common->version);
-
-       pr_info("  brdgCtl:              %08x\n", data->brdgCtl);
-
-       pr_info("  portStatusReg:        %08x\n", data->portStatusReg);
-       pr_info("  rootCmplxStatus:      %08x\n", data->rootCmplxStatus);
-       pr_info("  busAgentStatus:       %08x\n", data->busAgentStatus);
-
-       pr_info("  deviceStatus:         %08x\n", data->deviceStatus);
-       pr_info("  slotStatus:           %08x\n", data->slotStatus);
-       pr_info("  linkStatus:           %08x\n", data->linkStatus);
-       pr_info("  devCmdStatus:         %08x\n", data->devCmdStatus);
-       pr_info("  devSecStatus:         %08x\n", data->devSecStatus);
-
-       pr_info("  rootErrorStatus:      %08x\n", data->rootErrorStatus);
-       pr_info("  uncorrErrorStatus:    %08x\n", data->uncorrErrorStatus);
-       pr_info("  corrErrorStatus:      %08x\n", data->corrErrorStatus);
-       pr_info("  tlpHdr1:              %08x\n", data->tlpHdr1);
-       pr_info("  tlpHdr2:              %08x\n", data->tlpHdr2);
-       pr_info("  tlpHdr3:              %08x\n", data->tlpHdr3);
-       pr_info("  tlpHdr4:              %08x\n", data->tlpHdr4);
-       pr_info("  sourceId:             %08x\n", data->sourceId);
-
-       pr_info("  errorClass:           %016llx\n", data->errorClass);
-       pr_info("  correlator:           %016llx\n", data->correlator);
-       pr_info("  p7iocPlssr:           %016llx\n", data->p7iocPlssr);
-       pr_info("  p7iocCsr:             %016llx\n", data->p7iocCsr);
-       pr_info("  lemFir:               %016llx\n", data->lemFir);
-       pr_info("  lemErrorMask:         %016llx\n", data->lemErrorMask);
-       pr_info("  lemWOF:               %016llx\n", data->lemWOF);
-       pr_info("  phbErrorStatus:       %016llx\n", data->phbErrorStatus);
-       pr_info("  phbFirstErrorStatus:  %016llx\n", data->phbFirstErrorStatus);
-       pr_info("  phbErrorLog0:         %016llx\n", data->phbErrorLog0);
-       pr_info("  phbErrorLog1:         %016llx\n", data->phbErrorLog1);
-       pr_info("  mmioErrorStatus:      %016llx\n", data->mmioErrorStatus);
-       pr_info("  mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
-       pr_info("  mmioErrorLog0:        %016llx\n", data->mmioErrorLog0);
-       pr_info("  mmioErrorLog1:        %016llx\n", data->mmioErrorLog1);
-       pr_info("  dma0ErrorStatus:      %016llx\n", data->dma0ErrorStatus);
-       pr_info("  dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
-       pr_info("  dma0ErrorLog0:        %016llx\n", data->dma0ErrorLog0);
-       pr_info("  dma0ErrorLog1:        %016llx\n", data->dma0ErrorLog1);
-       pr_info("  dma1ErrorStatus:      %016llx\n", data->dma1ErrorStatus);
-       pr_info("  dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
-       pr_info("  dma1ErrorLog0:        %016llx\n", data->dma1ErrorLog0);
-       pr_info("  dma1ErrorLog1:        %016llx\n", data->dma1ErrorLog1);
-
-       for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
-               if ((data->pestA[i] >> 63) == 0 &&
-                   (data->pestB[i] >> 63) == 0)
-                       continue;
-
-               pr_info("  PE[%3d] PESTA:        %016llx\n", i, data->pestA[i]);
-               pr_info("          PESTB:        %016llx\n", data->pestB[i]);
-       }
-}
-
-static void ioda_eeh_phb3_phb_diag(struct pci_controller *hose,
-                                   struct OpalIoPhbErrorCommon *common)
-{
-       struct OpalIoPhb3ErrorData *data;
-       int i;
-
-       data = (struct OpalIoPhb3ErrorData*)common;
-       pr_info("PHB3 PHB#%x Diag-data (Version: %d)\n\n",
-               hose->global_number, common->version);
-
-       pr_info("  brdgCtl:              %08x\n", data->brdgCtl);
-
-       pr_info("  portStatusReg:        %08x\n", data->portStatusReg);
-       pr_info("  rootCmplxStatus:      %08x\n", data->rootCmplxStatus);
-       pr_info("  busAgentStatus:       %08x\n", data->busAgentStatus);
-
-       pr_info("  deviceStatus:         %08x\n", data->deviceStatus);
-       pr_info("  slotStatus:           %08x\n", data->slotStatus);
-       pr_info("  linkStatus:           %08x\n", data->linkStatus);
-       pr_info("  devCmdStatus:         %08x\n", data->devCmdStatus);
-       pr_info("  devSecStatus:         %08x\n", data->devSecStatus);
-
-       pr_info("  rootErrorStatus:      %08x\n", data->rootErrorStatus);
-       pr_info("  uncorrErrorStatus:    %08x\n", data->uncorrErrorStatus);
-       pr_info("  corrErrorStatus:      %08x\n", data->corrErrorStatus);
-       pr_info("  tlpHdr1:              %08x\n", data->tlpHdr1);
-       pr_info("  tlpHdr2:              %08x\n", data->tlpHdr2);
-       pr_info("  tlpHdr3:              %08x\n", data->tlpHdr3);
-       pr_info("  tlpHdr4:              %08x\n", data->tlpHdr4);
-       pr_info("  sourceId:             %08x\n", data->sourceId);
-       pr_info("  errorClass:           %016llx\n", data->errorClass);
-       pr_info("  correlator:           %016llx\n", data->correlator);
-       pr_info("  nFir:                 %016llx\n", data->nFir);
-       pr_info("  nFirMask:             %016llx\n", data->nFirMask);
-       pr_info("  nFirWOF:              %016llx\n", data->nFirWOF);
-       pr_info("  PhbPlssr:             %016llx\n", data->phbPlssr);
-       pr_info("  PhbCsr:               %016llx\n", data->phbCsr);
-       pr_info("  lemFir:               %016llx\n", data->lemFir);
-       pr_info("  lemErrorMask:         %016llx\n", data->lemErrorMask);
-       pr_info("  lemWOF:               %016llx\n", data->lemWOF);
-       pr_info("  phbErrorStatus:       %016llx\n", data->phbErrorStatus);
-       pr_info("  phbFirstErrorStatus:  %016llx\n", data->phbFirstErrorStatus);
-       pr_info("  phbErrorLog0:         %016llx\n", data->phbErrorLog0);
-       pr_info("  phbErrorLog1:         %016llx\n", data->phbErrorLog1);
-       pr_info("  mmioErrorStatus:      %016llx\n", data->mmioErrorStatus);
-       pr_info("  mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
-       pr_info("  mmioErrorLog0:        %016llx\n", data->mmioErrorLog0);
-       pr_info("  mmioErrorLog1:        %016llx\n", data->mmioErrorLog1);
-       pr_info("  dma0ErrorStatus:      %016llx\n", data->dma0ErrorStatus);
-       pr_info("  dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
-       pr_info("  dma0ErrorLog0:        %016llx\n", data->dma0ErrorLog0);
-       pr_info("  dma0ErrorLog1:        %016llx\n", data->dma0ErrorLog1);
-       pr_info("  dma1ErrorStatus:      %016llx\n", data->dma1ErrorStatus);
-       pr_info("  dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
-       pr_info("  dma1ErrorLog0:        %016llx\n", data->dma1ErrorLog0);
-       pr_info("  dma1ErrorLog1:        %016llx\n", data->dma1ErrorLog1);
-
-       for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) {
-               if ((data->pestA[i] >> 63) == 0 &&
-                   (data->pestB[i] >> 63) == 0)
-                       continue;
-
-               pr_info("  PE[%3d] PESTA:        %016llx\n", i, data->pestA[i]);
-               pr_info("          PESTB:        %016llx\n", data->pestB[i]);
-       }
-}
-
 static void ioda_eeh_phb_diag(struct pci_controller *hose)
 {
        struct pnv_phb *phb = hose->private_data;
-       struct OpalIoPhbErrorCommon *common;
        long rc;
 
        rc = opal_pci_get_phb_diag_data2(phb->opal_id, phb->diag.blob,
@@ -817,18 +679,7 @@ static void ioda_eeh_phb_diag(struct pci_controller *hose)
                return;
        }
 
-       common = (struct OpalIoPhbErrorCommon *)phb->diag.blob;
-       switch (common->ioType) {
-       case OPAL_PHB_ERROR_DATA_TYPE_P7IOC:
-               ioda_eeh_p7ioc_phb_diag(hose, common);
-               break;
-       case OPAL_PHB_ERROR_DATA_TYPE_PHB3:
-               ioda_eeh_phb3_phb_diag(hose, common);
-               break;
-       default:
-               pr_warning("%s: Unrecognized I/O chip %d\n",
-                          __func__, common->ioType);
-       }
+       pnv_pci_dump_phb_diag_data(hose, phb->diag.blob);
 }
 
 static int ioda_eeh_get_phb_pe(struct pci_controller *hose,
@@ -862,11 +713,7 @@ static int ioda_eeh_get_pe(struct pci_controller *hose,
        dev.phb = hose;
        dev.pe_config_addr = pe_no;
        dev_pe = eeh_pe_get(&dev);
-       if (!dev_pe) {
-               pr_warning("%s: Can't find PE for PHB#%x - PE#%x\n",
-                          __func__, hose->global_number, pe_no);
-               return -EEXIST;
-       }
+       if (!dev_pe) return -EEXIST;
 
        *pe = dev_pe;
        return 0;
@@ -884,12 +731,12 @@ static int ioda_eeh_get_pe(struct pci_controller *hose,
  */
 static int ioda_eeh_next_error(struct eeh_pe **pe)
 {
-       struct pci_controller *hose, *tmp;
+       struct pci_controller *hose;
        struct pnv_phb *phb;
        u64 frozen_pe_no;
        u16 err_type, severity;
        long rc;
-       int ret = 1;
+       int ret = EEH_NEXT_ERR_NONE;
 
        /*
         * While running here, it's safe to purge the event queue.
@@ -899,7 +746,7 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
        eeh_remove_event(NULL);
        opal_notifier_update_evt(OPAL_EVENT_PCI_ERROR, 0x0ul);
 
-       list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
+       list_for_each_entry(hose, &hose_list, list_node) {
                /*
                 * If the subordinate PCI buses of the PHB has been
                 * removed, we needn't take care of it any more.
@@ -938,19 +785,19 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
                switch (err_type) {
                case OPAL_EEH_IOC_ERROR:
                        if (severity == OPAL_EEH_SEV_IOC_DEAD) {
-                               list_for_each_entry_safe(hose, tmp,
-                                               &hose_list, list_node) {
+                               list_for_each_entry(hose, &hose_list,
+                                                   list_node) {
                                        phb = hose->private_data;
                                        phb->eeh_state |= PNV_EEH_STATE_REMOVED;
                                }
 
                                pr_err("EEH: dead IOC detected\n");
-                               ret = 4;
-                               goto out;
+                               ret = EEH_NEXT_ERR_DEAD_IOC;
                        } else if (severity == OPAL_EEH_SEV_INF) {
                                pr_info("EEH: IOC informative error "
                                        "detected\n");
                                ioda_eeh_hub_diag(hose);
+                               ret = EEH_NEXT_ERR_NONE;
                        }
 
                        break;
@@ -962,37 +809,61 @@ static int ioda_eeh_next_error(struct eeh_pe **pe)
                                pr_err("EEH: dead PHB#%x detected\n",
                                        hose->global_number);
                                phb->eeh_state |= PNV_EEH_STATE_REMOVED;
-                               ret = 3;
-                               goto out;
+                               ret = EEH_NEXT_ERR_DEAD_PHB;
                        } else if (severity == OPAL_EEH_SEV_PHB_FENCED) {
                                if (ioda_eeh_get_phb_pe(hose, pe))
                                        break;
 
                                pr_err("EEH: fenced PHB#%x detected\n",
                                        hose->global_number);
-                               ret = 2;
-                               goto out;
+                               ret = EEH_NEXT_ERR_FENCED_PHB;
                        } else if (severity == OPAL_EEH_SEV_INF) {
                                pr_info("EEH: PHB#%x informative error "
                                        "detected\n",
                                        hose->global_number);
                                ioda_eeh_phb_diag(hose);
+                               ret = EEH_NEXT_ERR_NONE;
                        }
 
                        break;
                case OPAL_EEH_PE_ERROR:
-                       if (ioda_eeh_get_pe(hose, frozen_pe_no, pe))
-                               break;
+                       /*
+                        * If we can't find the corresponding PE, the
+                        * PEEV / PEST would be messy. So we force an
+                        * fenced PHB so that it can be recovered.
+                        */
+                       if (ioda_eeh_get_pe(hose, frozen_pe_no, pe)) {
+                               if (!ioda_eeh_get_phb_pe(hose, pe)) {
+                                       pr_err("EEH: Escalated fenced PHB#%x "
+                                              "detected for PE#%llx\n",
+                                               hose->global_number,
+                                               frozen_pe_no);
+                                       ret = EEH_NEXT_ERR_FENCED_PHB;
+                               } else {
+                                       ret = EEH_NEXT_ERR_NONE;
+                               }
+                       } else {
+                               pr_err("EEH: Frozen PE#%x on PHB#%x detected\n",
+                                       (*pe)->addr, (*pe)->phb->global_number);
+                               ret = EEH_NEXT_ERR_FROZEN_PE;
+                       }
 
-                       pr_err("EEH: Frozen PE#%x on PHB#%x detected\n",
-                               (*pe)->addr, (*pe)->phb->global_number);
-                       ret = 1;
-                       goto out;
+                       break;
+               default:
+                       pr_warn("%s: Unexpected error type %d\n",
+                               __func__, err_type);
                }
+
+               /*
+                * If we have no errors on the specific PHB or only
+                * informative error there, we continue poking it.
+                * Otherwise, we need actions to be taken by upper
+                * layer.
+                */
+               if (ret > EEH_NEXT_ERR_INF)
+                       break;
        }
 
-       ret = 0;
-out:
        return ret;
 }
 
index 73b981438cc583e0ba4345129046d56b72a8b9c1..a79fddc5e74e58ac0a0b18fc1b7cb5db607095b2 100644 (file)
@@ -344,6 +344,27 @@ static int powernv_eeh_next_error(struct eeh_pe **pe)
        return -EEXIST;
 }
 
+static int powernv_eeh_restore_config(struct device_node *dn)
+{
+       struct eeh_dev *edev = of_node_to_eeh_dev(dn);
+       struct pnv_phb *phb;
+       s64 ret;
+
+       if (!edev)
+               return -EEXIST;
+
+       phb = edev->phb->private_data;
+       ret = opal_pci_reinit(phb->opal_id,
+                             OPAL_REINIT_PCI_DEV, edev->config_addr);
+       if (ret) {
+               pr_warn("%s: Can't reinit PCI dev 0x%x (%lld)\n",
+                       __func__, edev->config_addr, ret);
+               return -EIO;
+       }
+
+       return 0;
+}
+
 static struct eeh_ops powernv_eeh_ops = {
        .name                   = "powernv",
        .init                   = powernv_eeh_init,
@@ -359,7 +380,8 @@ static struct eeh_ops powernv_eeh_ops = {
        .configure_bridge       = powernv_eeh_configure_bridge,
        .read_config            = pnv_pci_cfg_read,
        .write_config           = pnv_pci_cfg_write,
-       .next_error             = powernv_eeh_next_error
+       .next_error             = powernv_eeh_next_error,
+       .restore_config         = powernv_eeh_restore_config
 };
 
 /**
index d8773079ce195afd380a6fa97c5fc5809a976a78..714ef972406bcacf66a4a896283c6fb25963ca16 100644 (file)
@@ -76,8 +76,8 @@
 /* Validate buffer size */
 #define VALIDATE_BUF_SIZE      4096
 
-/* XXX: Assume candidate image size is <= 256MB */
-#define MAX_IMAGE_SIZE 0x10000000
+/* XXX: Assume candidate image size is <= 1GB */
+#define MAX_IMAGE_SIZE 0x40000000
 
 /* Flash sg list version */
 #define SG_LIST_VERSION (1UL)
@@ -103,27 +103,6 @@ struct image_header_t {
        uint32_t        size;
 };
 
-/* Scatter/gather entry */
-struct opal_sg_entry {
-       void    *data;
-       long    length;
-};
-
-/* We calculate number of entries based on PAGE_SIZE */
-#define SG_ENTRIES_PER_NODE ((PAGE_SIZE - 16) / sizeof(struct opal_sg_entry))
-
-/*
- * This struct is very similar but not identical to that
- * needed by the opal flash update. All we need to do for
- * opal is rewrite num_entries into a version/length and
- * translate the pointers to absolute.
- */
-struct opal_sg_list {
-       unsigned long num_entries;
-       struct opal_sg_list *next;
-       struct opal_sg_entry entry[SG_ENTRIES_PER_NODE];
-};
-
 struct validate_flash_t {
        int             status;         /* Return status */
        void            *buf;           /* Candidate image buffer */
@@ -333,7 +312,7 @@ static struct opal_sg_list *image_data_to_sglist(void)
        addr = image_data.data;
        size = image_data.size;
 
-       sg1 = kzalloc((sizeof(struct opal_sg_list)), GFP_KERNEL);
+       sg1 = kzalloc(PAGE_SIZE, GFP_KERNEL);
        if (!sg1)
                return NULL;
 
@@ -351,8 +330,7 @@ static struct opal_sg_list *image_data_to_sglist(void)
 
                sg1->num_entries++;
                if (sg1->num_entries >= SG_ENTRIES_PER_NODE) {
-                       sg1->next = kzalloc((sizeof(struct opal_sg_list)),
-                                           GFP_KERNEL);
+                       sg1->next = kzalloc(PAGE_SIZE, GFP_KERNEL);
                        if (!sg1->next) {
                                pr_err("%s : Failed to allocate memory\n",
                                       __func__);
@@ -402,7 +380,10 @@ static int opal_flash_update(int op)
                else
                        sg->next = NULL;
 
-               /* Make num_entries into the version/length field */
+               /*
+                * Convert num_entries to version/length format
+                * to satisfy OPAL.
+                */
                sg->num_entries = (SG_LIST_VERSION << 56) |
                        (sg->num_entries * sizeof(struct opal_sg_entry) + 16);
        }
diff --git a/arch/powerpc/platforms/powernv/opal-memory-errors.c b/arch/powerpc/platforms/powernv/opal-memory-errors.c
new file mode 100644 (file)
index 0000000..ec41322
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * OPAL asynchronus Memory error handling support in PowreNV.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * Copyright 2013 IBM Corporation
+ * Author: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>
+ */
+
+#undef DEBUG
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+
+#include <asm/opal.h>
+#include <asm/cputable.h>
+
+static int opal_mem_err_nb_init;
+static LIST_HEAD(opal_memory_err_list);
+static DEFINE_SPINLOCK(opal_mem_err_lock);
+
+struct OpalMsgNode {
+       struct list_head list;
+       struct opal_msg msg;
+};
+
+static void handle_memory_error_event(struct OpalMemoryErrorData *merr_evt)
+{
+       uint64_t paddr_start, paddr_end;
+
+       pr_debug("%s: Retrived memory error event, type: 0x%x\n",
+                 __func__, merr_evt->type);
+       switch (merr_evt->type) {
+       case OPAL_MEM_ERR_TYPE_RESILIENCE:
+               paddr_start = merr_evt->u.resilience.physical_address_start;
+               paddr_end = merr_evt->u.resilience.physical_address_end;
+               break;
+       case OPAL_MEM_ERR_TYPE_DYN_DALLOC:
+               paddr_start = merr_evt->u.dyn_dealloc.physical_address_start;
+               paddr_end = merr_evt->u.dyn_dealloc.physical_address_end;
+               break;
+       default:
+               return;
+       }
+
+       for (; paddr_start < paddr_end; paddr_start += PAGE_SIZE) {
+               memory_failure(paddr_start >> PAGE_SHIFT, 0, 0);
+       }
+}
+
+static void handle_memory_error(void)
+{
+       unsigned long flags;
+       struct OpalMemoryErrorData *merr_evt;
+       struct OpalMsgNode *msg_node;
+
+       spin_lock_irqsave(&opal_mem_err_lock, flags);
+       while (!list_empty(&opal_memory_err_list)) {
+                msg_node = list_entry(opal_memory_err_list.next,
+                                          struct OpalMsgNode, list);
+               list_del(&msg_node->list);
+               spin_unlock_irqrestore(&opal_mem_err_lock, flags);
+
+               merr_evt = (struct OpalMemoryErrorData *)
+                                       &msg_node->msg.params[0];
+               handle_memory_error_event(merr_evt);
+               kfree(msg_node);
+               spin_lock_irqsave(&opal_mem_err_lock, flags);
+       }
+       spin_unlock_irqrestore(&opal_mem_err_lock, flags);
+}
+
+static void mem_error_handler(struct work_struct *work)
+{
+       handle_memory_error();
+}
+
+static DECLARE_WORK(mem_error_work, mem_error_handler);
+
+/*
+ * opal_memory_err_event - notifier handler that queues up the opal message
+ * to be preocessed later.
+ */
+static int opal_memory_err_event(struct notifier_block *nb,
+                         unsigned long msg_type, void *msg)
+{
+       unsigned long flags;
+       struct OpalMsgNode *msg_node;
+
+       if (msg_type != OPAL_MSG_MEM_ERR)
+               return 0;
+
+       msg_node = kzalloc(sizeof(*msg_node), GFP_ATOMIC);
+       if (!msg_node) {
+               pr_err("MEMORY_ERROR: out of memory, Opal message event not"
+                      "handled\n");
+               return -ENOMEM;
+       }
+       memcpy(&msg_node->msg, msg, sizeof(struct opal_msg));
+
+       spin_lock_irqsave(&opal_mem_err_lock, flags);
+       list_add(&msg_node->list, &opal_memory_err_list);
+       spin_unlock_irqrestore(&opal_mem_err_lock, flags);
+
+       schedule_work(&mem_error_work);
+       return 0;
+}
+
+static struct notifier_block opal_mem_err_nb = {
+       .notifier_call  = opal_memory_err_event,
+       .next           = NULL,
+       .priority       = 0,
+};
+
+static int __init opal_mem_err_init(void)
+{
+       int ret;
+
+       if (!opal_mem_err_nb_init) {
+               ret = opal_message_notifier_register(
+                                       OPAL_MSG_MEM_ERR, &opal_mem_err_nb);
+               if (ret) {
+                       pr_err("%s: Can't register OPAL event notifier (%d)\n",
+                              __func__, ret);
+                       return ret;
+               }
+               opal_mem_err_nb_init = 1;
+       }
+       return 0;
+}
+subsys_initcall(opal_mem_err_init);
index 7d07c7e80ec09e9232b3cafd9c41a104992b5331..b1885db8fdf34bfe068f1712d486f6884dc50d0e 100644 (file)
@@ -18,6 +18,7 @@
 
 #include <asm/opal.h>
 #include <asm/firmware.h>
+#include <asm/machdep.h>
 
 static void opal_to_tm(u32 y_m_d, u64 h_m_s_ms, struct rtc_time *tm)
 {
@@ -48,8 +49,11 @@ unsigned long __init opal_get_boot_time(void)
                else
                        mdelay(10);
        }
-       if (rc != OPAL_SUCCESS)
+       if (rc != OPAL_SUCCESS) {
+               ppc_md.get_rtc_time = NULL;
+               ppc_md.set_rtc_time = NULL;
                return 0;
+       }
        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);
index e7806504e9769162f921e704cf55d0b3e210cf6c..3e8829c40fbbfc436adb206fb297b82ea7385e89 100644 (file)
@@ -126,3 +126,6 @@ OPAL_CALL(opal_return_cpu,                  OPAL_RETURN_CPU);
 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_get_msg,                                OPAL_GET_MSG);
+OPAL_CALL(opal_check_completion,               OPAL_CHECK_ASYNC_COMPLETION);
+OPAL_CALL(opal_sync_host_reboot,               OPAL_SYNC_HOST_REBOOT);
index 1c798cd553722f6f043a066c299100be89c10f96..65499adaecff2a1e2367612ece5e051028e38634 100644 (file)
 #include <linux/interrupt.h>
 #include <linux/notifier.h>
 #include <linux/slab.h>
+#include <linux/sched.h>
 #include <linux/kobject.h>
+#include <linux/delay.h>
 #include <asm/opal.h>
 #include <asm/firmware.h>
+#include <asm/mce.h>
 
 #include "powernv.h"
 
@@ -38,6 +41,7 @@ extern u64 opal_mc_secondary_handler[];
 static unsigned int *opal_irqs;
 static unsigned int opal_irq_count;
 static ATOMIC_NOTIFIER_HEAD(opal_notifier_head);
+static struct atomic_notifier_head opal_msg_notifier_head[OPAL_MSG_TYPE_MAX];
 static DEFINE_SPINLOCK(opal_notifier_lock);
 static uint64_t last_notified_mask = 0x0ul;
 static atomic_t opal_notifier_hold = ATOMIC_INIT(0);
@@ -88,14 +92,10 @@ static int __init opal_register_exception_handlers(void)
        if (!(powerpc_firmware_features & FW_FEATURE_OPAL))
                return -ENODEV;
 
-       /* Hookup some exception handlers. We use the fwnmi area at 0x7000
-        * to provide the glue space to OPAL
+       /* Hookup some exception handlers except machine check. We use the
+        * fwnmi area at 0x7000 to provide the glue space to OPAL
         */
        glue = 0x7000;
-       opal_register_exception_handler(OPAL_MACHINE_CHECK_HANDLER,
-                                       __pa(opal_mc_secondary_handler[0]),
-                                       glue);
-       glue += 128;
        opal_register_exception_handler(OPAL_HYPERVISOR_MAINTENANCE_HANDLER,
                                        0, glue);
        glue += 128;
@@ -169,6 +169,95 @@ void opal_notifier_disable(void)
        atomic_set(&opal_notifier_hold, 1);
 }
 
+/*
+ * Opal message notifier based on message type. Allow subscribers to get
+ * notified for specific messgae type.
+ */
+int opal_message_notifier_register(enum OpalMessageType msg_type,
+                                       struct notifier_block *nb)
+{
+       if (!nb) {
+               pr_warning("%s: Invalid argument (%p)\n",
+                          __func__, nb);
+               return -EINVAL;
+       }
+       if (msg_type > OPAL_MSG_TYPE_MAX) {
+               pr_warning("%s: Invalid message type argument (%d)\n",
+                          __func__, msg_type);
+               return -EINVAL;
+       }
+       return atomic_notifier_chain_register(
+                               &opal_msg_notifier_head[msg_type], nb);
+}
+
+static void opal_message_do_notify(uint32_t msg_type, void *msg)
+{
+       /* notify subscribers */
+       atomic_notifier_call_chain(&opal_msg_notifier_head[msg_type],
+                                       msg_type, msg);
+}
+
+static void opal_handle_message(void)
+{
+       s64 ret;
+       /*
+        * TODO: pre-allocate a message buffer depending on opal-msg-size
+        * value in /proc/device-tree.
+        */
+       static struct opal_msg msg;
+
+       ret = opal_get_msg(__pa(&msg), sizeof(msg));
+       /* No opal message pending. */
+       if (ret == OPAL_RESOURCE)
+               return;
+
+       /* check for errors. */
+       if (ret) {
+               pr_warning("%s: Failed to retrive opal message, err=%lld\n",
+                               __func__, ret);
+               return;
+       }
+
+       /* Sanity check */
+       if (msg.msg_type > OPAL_MSG_TYPE_MAX) {
+               pr_warning("%s: Unknown message type: %u\n",
+                               __func__, msg.msg_type);
+               return;
+       }
+       opal_message_do_notify(msg.msg_type, (void *)&msg);
+}
+
+static int opal_message_notify(struct notifier_block *nb,
+                         unsigned long events, void *change)
+{
+       if (events & OPAL_EVENT_MSG_PENDING)
+               opal_handle_message();
+       return 0;
+}
+
+static struct notifier_block opal_message_nb = {
+       .notifier_call  = opal_message_notify,
+       .next           = NULL,
+       .priority       = 0,
+};
+
+static int __init opal_message_init(void)
+{
+       int ret, i;
+
+       for (i = 0; i < OPAL_MSG_TYPE_MAX; i++)
+               ATOMIC_INIT_NOTIFIER_HEAD(&opal_msg_notifier_head[i]);
+
+       ret = opal_notifier_register(&opal_message_nb);
+       if (ret) {
+               pr_err("%s: Can't register OPAL event notifier (%d)\n",
+                      __func__, ret);
+               return ret;
+       }
+       return 0;
+}
+early_initcall(opal_message_init);
+
 int opal_get_chars(uint32_t vtermno, char *buf, int count)
 {
        s64 rc;
@@ -254,119 +343,62 @@ int opal_put_chars(uint32_t vtermno, const char *data, int total_len)
        return written;
 }
 
+static int opal_recover_mce(struct pt_regs *regs,
+                                       struct machine_check_event *evt)
+{
+       int recovered = 0;
+       uint64_t ea = get_mce_fault_addr(evt);
+
+       if (!(regs->msr & MSR_RI)) {
+               /* If MSR_RI isn't set, we cannot recover */
+               recovered = 0;
+       } else if (evt->disposition == MCE_DISPOSITION_RECOVERED) {
+               /* Platform corrected itself */
+               recovered = 1;
+       } else if (ea && !is_kernel_addr(ea)) {
+               /*
+                * Faulting address is not in kernel text. We should be fine.
+                * We need to find which process uses this address.
+                * For now, kill the task if we have received exception when
+                * in userspace.
+                *
+                * TODO: Queue up this address for hwpoisioning later.
+                */
+               if (user_mode(regs) && !is_global_init(current)) {
+                       _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
+                       recovered = 1;
+               } else
+                       recovered = 0;
+       } else if (user_mode(regs) && !is_global_init(current) &&
+               evt->severity == MCE_SEV_ERROR_SYNC) {
+               /*
+                * If we have received a synchronous error when in userspace
+                * kill the task.
+                */
+               _exception(SIGBUS, regs, BUS_MCEERR_AR, regs->nip);
+               recovered = 1;
+       }
+       return recovered;
+}
+
 int opal_machine_check(struct pt_regs *regs)
 {
-       struct opal_machine_check_event *opal_evt = get_paca()->opal_mc_evt;
-       struct opal_machine_check_event evt;
-       const char *level, *sevstr, *subtype;
-       static const char *opal_mc_ue_types[] = {
-               "Indeterminate",
-               "Instruction fetch",
-               "Page table walk ifetch",
-               "Load/Store",
-               "Page table walk Load/Store",
-       };
-       static const char *opal_mc_slb_types[] = {
-               "Indeterminate",
-               "Parity",
-               "Multihit",
-       };
-       static const char *opal_mc_erat_types[] = {
-               "Indeterminate",
-               "Parity",
-               "Multihit",
-       };
-       static const char *opal_mc_tlb_types[] = {
-               "Indeterminate",
-               "Parity",
-               "Multihit",
-       };
-
-       /* Copy the event structure and release the original */
-       evt = *opal_evt;
-       opal_evt->in_use = 0;
+       struct machine_check_event evt;
+
+       if (!get_mce_event(&evt, MCE_EVENT_RELEASE))
+               return 0;
 
        /* Print things out */
-       if (evt.version != OpalMCE_V1) {
+       if (evt.version != MCE_V1) {
                pr_err("Machine Check Exception, Unknown event version %d !\n",
                       evt.version);
                return 0;
        }
-       switch(evt.severity) {
-       case OpalMCE_SEV_NO_ERROR:
-               level = KERN_INFO;
-               sevstr = "Harmless";
-               break;
-       case OpalMCE_SEV_WARNING:
-               level = KERN_WARNING;
-               sevstr = "";
-               break;
-       case OpalMCE_SEV_ERROR_SYNC:
-               level = KERN_ERR;
-               sevstr = "Severe";
-               break;
-       case OpalMCE_SEV_FATAL:
-       default:
-               level = KERN_ERR;
-               sevstr = "Fatal";
-               break;
-       }
+       machine_check_print_event_info(&evt);
 
-       printk("%s%s Machine check interrupt [%s]\n", level, sevstr,
-              evt.disposition == OpalMCE_DISPOSITION_RECOVERED ?
-              "Recovered" : "[Not recovered");
-       printk("%s  Initiator: %s\n", level,
-              evt.initiator == OpalMCE_INITIATOR_CPU ? "CPU" : "Unknown");
-       switch(evt.error_type) {
-       case OpalMCE_ERROR_TYPE_UE:
-               subtype = evt.u.ue_error.ue_error_type <
-                       ARRAY_SIZE(opal_mc_ue_types) ?
-                       opal_mc_ue_types[evt.u.ue_error.ue_error_type]
-                       : "Unknown";
-               printk("%s  Error type: UE [%s]\n", level, subtype);
-               if (evt.u.ue_error.effective_address_provided)
-                       printk("%s    Effective address: %016llx\n",
-                              level, evt.u.ue_error.effective_address);
-               if (evt.u.ue_error.physical_address_provided)
-                       printk("%s      Physial address: %016llx\n",
-                              level, evt.u.ue_error.physical_address);
-               break;
-       case OpalMCE_ERROR_TYPE_SLB:
-               subtype = evt.u.slb_error.slb_error_type <
-                       ARRAY_SIZE(opal_mc_slb_types) ?
-                       opal_mc_slb_types[evt.u.slb_error.slb_error_type]
-                       : "Unknown";
-               printk("%s  Error type: SLB [%s]\n", level, subtype);
-               if (evt.u.slb_error.effective_address_provided)
-                       printk("%s    Effective address: %016llx\n",
-                              level, evt.u.slb_error.effective_address);
-               break;
-       case OpalMCE_ERROR_TYPE_ERAT:
-               subtype = evt.u.erat_error.erat_error_type <
-                       ARRAY_SIZE(opal_mc_erat_types) ?
-                       opal_mc_erat_types[evt.u.erat_error.erat_error_type]
-                       : "Unknown";
-               printk("%s  Error type: ERAT [%s]\n", level, subtype);
-               if (evt.u.erat_error.effective_address_provided)
-                       printk("%s    Effective address: %016llx\n",
-                              level, evt.u.erat_error.effective_address);
-               break;
-       case OpalMCE_ERROR_TYPE_TLB:
-               subtype = evt.u.tlb_error.tlb_error_type <
-                       ARRAY_SIZE(opal_mc_tlb_types) ?
-                       opal_mc_tlb_types[evt.u.tlb_error.tlb_error_type]
-                       : "Unknown";
-               printk("%s  Error type: TLB [%s]\n", level, subtype);
-               if (evt.u.tlb_error.effective_address_provided)
-                       printk("%s    Effective address: %016llx\n",
-                              level, evt.u.tlb_error.effective_address);
-               break;
-       default:
-       case OpalMCE_ERROR_TYPE_UNKNOWN:
-               printk("%s  Error type: Unknown\n", level);
-               break;
-       }
-       return evt.severity == OpalMCE_SEV_FATAL ? 0 : 1;
+       if (opal_recover_mce(regs, &evt))
+               return 1;
+       return 0;
 }
 
 static irqreturn_t opal_interrupt(int irq, void *data)
@@ -451,10 +483,25 @@ subsys_initcall(opal_init);
 void opal_shutdown(void)
 {
        unsigned int i;
+       long rc = OPAL_BUSY;
 
+       /* First free interrupts, which will also mask them */
        for (i = 0; i < opal_irq_count; i++) {
                if (opal_irqs[i])
                        free_irq(opal_irqs[i], NULL);
                opal_irqs[i] = 0;
        }
+
+       /*
+        * Then sync with OPAL which ensure anything that can
+        * potentially write to our memory has completed such
+        * as an ongoing dump retrieval
+        */
+       while (rc == OPAL_BUSY || rc == OPAL_BUSY_EVENT) {
+               rc = opal_sync_host_reboot();
+               if (rc == OPAL_BUSY)
+                       opal_poll_events(NULL);
+               else
+                       mdelay(10);
+       }
 }
index 2c6d173842b2f1056d3702826b3c2a1d84d614ad..7d6dcc6d5fa9a6551c2465285cc1886242cc0125 100644 (file)
@@ -460,7 +460,7 @@ static void pnv_pci_ioda_dma_dev_setup(struct pnv_phb *phb, struct pci_dev *pdev
                return;
 
        pe = &phb->ioda.pe_array[pdn->pe_number];
-       set_iommu_table_base(&pdev->dev, &pe->tce32_table);
+       set_iommu_table_base_and_group(&pdev->dev, &pe->tce32_table);
 }
 
 static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
@@ -468,7 +468,7 @@ static void pnv_ioda_setup_bus_dma(struct pnv_ioda_pe *pe, struct pci_bus *bus)
        struct pci_dev *dev;
 
        list_for_each_entry(dev, &bus->devices, bus_list) {
-               set_iommu_table_base(&dev->dev, &pe->tce32_table);
+               set_iommu_table_base_and_group(&dev->dev, &pe->tce32_table);
                if (dev->subordinate)
                        pnv_ioda_setup_bus_dma(pe, dev->subordinate);
        }
@@ -644,7 +644,7 @@ static void pnv_pci_ioda_setup_dma_pe(struct pnv_phb *phb,
        iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number);
 
        if (pe->pdev)
-               set_iommu_table_base(&pe->pdev->dev, tbl);
+               set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
        else
                pnv_ioda_setup_bus_dma(pe, pe->pbus);
 
@@ -723,7 +723,7 @@ static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
        iommu_register_group(tbl, pci_domain_nr(pe->pbus), pe->pe_number);
 
        if (pe->pdev)
-               set_iommu_table_base(&pe->pdev->dev, tbl);
+               set_iommu_table_base_and_group(&pe->pdev->dev, tbl);
        else
                pnv_ioda_setup_bus_dma(pe, pe->pbus);
 
@@ -1144,7 +1144,7 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
 {
        struct pci_controller *hose;
        struct pnv_phb *phb;
-       unsigned long size, m32map_off, iomap_off, pemap_off;
+       unsigned long size, m32map_off, pemap_off, iomap_off = 0;
        const __be64 *prop64;
        const __be32 *prop32;
        int len;
@@ -1231,7 +1231,6 @@ void __init pnv_pci_init_ioda_phb(struct device_node *np,
        size = _ALIGN_UP(phb->ioda.total_pe / 8, sizeof(unsigned long));
        m32map_off = size;
        size += phb->ioda.total_pe * sizeof(phb->ioda.m32_segmap[0]);
-       iomap_off = size;
        if (phb->type == PNV_PHB_IODA1) {
                iomap_off = size;
                size += phb->ioda.total_pe * sizeof(phb->ioda.io_segmap[0]);
index f8b4bd8afb2e5da39cd8632c7a6a8eae54448aeb..e3807d69393e02c753e1777cffb03c5d6ae0db74 100644 (file)
@@ -92,7 +92,7 @@ static void pnv_pci_p5ioc2_dma_dev_setup(struct pnv_phb *phb,
                                pci_domain_nr(phb->hose->bus), phb->opal_id);
        }
 
-       set_iommu_table_base(&pdev->dev, &phb->p5ioc2.iommu_table);
+       set_iommu_table_base_and_group(&pdev->dev, &phb->p5ioc2.iommu_table);
 }
 
 static void __init pnv_pci_init_p5ioc2_phb(struct device_node *np, u64 hub_id,
index 4eb33a9ed5325a3e84b2a7f1d4d58d5dc7fa7b22..b555ebc57ef5a33010ea4becbf992d3deb2dcbad 100644 (file)
@@ -124,77 +124,157 @@ static void pnv_teardown_msi_irqs(struct pci_dev *pdev)
 }
 #endif /* CONFIG_PCI_MSI */
 
-static void pnv_pci_dump_p7ioc_diag_data(struct pnv_phb *phb)
+static void pnv_pci_dump_p7ioc_diag_data(struct pci_controller *hose,
+                                        struct OpalIoPhbErrorCommon *common)
 {
-       struct OpalIoP7IOCPhbErrorData *data = &phb->diag.p7ioc;
+       struct OpalIoP7IOCPhbErrorData *data;
        int i;
 
-       pr_info("PHB %d diagnostic data:\n", phb->hose->global_number);
-
-       pr_info("  brdgCtl              = 0x%08x\n", data->brdgCtl);
-
-       pr_info("  portStatusReg        = 0x%08x\n", data->portStatusReg);
-       pr_info("  rootCmplxStatus      = 0x%08x\n", data->rootCmplxStatus);
-       pr_info("  busAgentStatus       = 0x%08x\n", data->busAgentStatus);
-
-       pr_info("  deviceStatus         = 0x%08x\n", data->deviceStatus);
-       pr_info("  slotStatus           = 0x%08x\n", data->slotStatus);
-       pr_info("  linkStatus           = 0x%08x\n", data->linkStatus);
-       pr_info("  devCmdStatus         = 0x%08x\n", data->devCmdStatus);
-       pr_info("  devSecStatus         = 0x%08x\n", data->devSecStatus);
-
-       pr_info("  rootErrorStatus      = 0x%08x\n", data->rootErrorStatus);
-       pr_info("  uncorrErrorStatus    = 0x%08x\n", data->uncorrErrorStatus);
-       pr_info("  corrErrorStatus      = 0x%08x\n", data->corrErrorStatus);
-       pr_info("  tlpHdr1              = 0x%08x\n", data->tlpHdr1);
-       pr_info("  tlpHdr2              = 0x%08x\n", data->tlpHdr2);
-       pr_info("  tlpHdr3              = 0x%08x\n", data->tlpHdr3);
-       pr_info("  tlpHdr4              = 0x%08x\n", data->tlpHdr4);
-       pr_info("  sourceId             = 0x%08x\n", data->sourceId);
-
-       pr_info("  errorClass           = 0x%016llx\n", data->errorClass);
-       pr_info("  correlator           = 0x%016llx\n", data->correlator);
-
-       pr_info("  p7iocPlssr           = 0x%016llx\n", data->p7iocPlssr);
-       pr_info("  p7iocCsr             = 0x%016llx\n", data->p7iocCsr);
-       pr_info("  lemFir               = 0x%016llx\n", data->lemFir);
-       pr_info("  lemErrorMask         = 0x%016llx\n", data->lemErrorMask);
-       pr_info("  lemWOF               = 0x%016llx\n", data->lemWOF);
-       pr_info("  phbErrorStatus       = 0x%016llx\n", data->phbErrorStatus);
-       pr_info("  phbFirstErrorStatus  = 0x%016llx\n", data->phbFirstErrorStatus);
-       pr_info("  phbErrorLog0         = 0x%016llx\n", data->phbErrorLog0);
-       pr_info("  phbErrorLog1         = 0x%016llx\n", data->phbErrorLog1);
-       pr_info("  mmioErrorStatus      = 0x%016llx\n", data->mmioErrorStatus);
-       pr_info("  mmioFirstErrorStatus = 0x%016llx\n", data->mmioFirstErrorStatus);
-       pr_info("  mmioErrorLog0        = 0x%016llx\n", data->mmioErrorLog0);
-       pr_info("  mmioErrorLog1        = 0x%016llx\n", data->mmioErrorLog1);
-       pr_info("  dma0ErrorStatus      = 0x%016llx\n", data->dma0ErrorStatus);
-       pr_info("  dma0FirstErrorStatus = 0x%016llx\n", data->dma0FirstErrorStatus);
-       pr_info("  dma0ErrorLog0        = 0x%016llx\n", data->dma0ErrorLog0);
-       pr_info("  dma0ErrorLog1        = 0x%016llx\n", data->dma0ErrorLog1);
-       pr_info("  dma1ErrorStatus      = 0x%016llx\n", data->dma1ErrorStatus);
-       pr_info("  dma1FirstErrorStatus = 0x%016llx\n", data->dma1FirstErrorStatus);
-       pr_info("  dma1ErrorLog0        = 0x%016llx\n", data->dma1ErrorLog0);
-       pr_info("  dma1ErrorLog1        = 0x%016llx\n", data->dma1ErrorLog1);
+       data = (struct OpalIoP7IOCPhbErrorData *)common;
+       pr_info("P7IOC PHB#%d Diag-data (Version: %d)\n\n",
+               hose->global_number, common->version);
+
+       pr_info("  brdgCtl:              %08x\n", data->brdgCtl);
+
+       pr_info("  portStatusReg:        %08x\n", data->portStatusReg);
+       pr_info("  rootCmplxStatus:      %08x\n", data->rootCmplxStatus);
+       pr_info("  busAgentStatus:       %08x\n", data->busAgentStatus);
+
+       pr_info("  deviceStatus:         %08x\n", data->deviceStatus);
+       pr_info("  slotStatus:           %08x\n", data->slotStatus);
+       pr_info("  linkStatus:           %08x\n", data->linkStatus);
+       pr_info("  devCmdStatus:         %08x\n", data->devCmdStatus);
+       pr_info("  devSecStatus:         %08x\n", data->devSecStatus);
+
+       pr_info("  rootErrorStatus:      %08x\n", data->rootErrorStatus);
+       pr_info("  uncorrErrorStatus:    %08x\n", data->uncorrErrorStatus);
+       pr_info("  corrErrorStatus:      %08x\n", data->corrErrorStatus);
+       pr_info("  tlpHdr1:              %08x\n", data->tlpHdr1);
+       pr_info("  tlpHdr2:              %08x\n", data->tlpHdr2);
+       pr_info("  tlpHdr3:              %08x\n", data->tlpHdr3);
+       pr_info("  tlpHdr4:              %08x\n", data->tlpHdr4);
+       pr_info("  sourceId:             %08x\n", data->sourceId);
+       pr_info("  errorClass:           %016llx\n", data->errorClass);
+       pr_info("  correlator:           %016llx\n", data->correlator);
+       pr_info("  p7iocPlssr:           %016llx\n", data->p7iocPlssr);
+       pr_info("  p7iocCsr:             %016llx\n", data->p7iocCsr);
+       pr_info("  lemFir:               %016llx\n", data->lemFir);
+       pr_info("  lemErrorMask:         %016llx\n", data->lemErrorMask);
+       pr_info("  lemWOF:               %016llx\n", data->lemWOF);
+       pr_info("  phbErrorStatus:       %016llx\n", data->phbErrorStatus);
+       pr_info("  phbFirstErrorStatus:  %016llx\n", data->phbFirstErrorStatus);
+       pr_info("  phbErrorLog0:         %016llx\n", data->phbErrorLog0);
+       pr_info("  phbErrorLog1:         %016llx\n", data->phbErrorLog1);
+       pr_info("  mmioErrorStatus:      %016llx\n", data->mmioErrorStatus);
+       pr_info("  mmioFirstErrorStatus%016llx\n", data->mmioFirstErrorStatus);
+       pr_info("  mmioErrorLog0:        %016llx\n", data->mmioErrorLog0);
+       pr_info("  mmioErrorLog1:        %016llx\n", data->mmioErrorLog1);
+       pr_info("  dma0ErrorStatus:      %016llx\n", data->dma0ErrorStatus);
+       pr_info("  dma0FirstErrorStatus%016llx\n", data->dma0FirstErrorStatus);
+       pr_info("  dma0ErrorLog0:        %016llx\n", data->dma0ErrorLog0);
+       pr_info("  dma0ErrorLog1:        %016llx\n", data->dma0ErrorLog1);
+       pr_info("  dma1ErrorStatus:      %016llx\n", data->dma1ErrorStatus);
+       pr_info("  dma1FirstErrorStatus%016llx\n", data->dma1FirstErrorStatus);
+       pr_info("  dma1ErrorLog0:        %016llx\n", data->dma1ErrorLog0);
+       pr_info("  dma1ErrorLog1:        %016llx\n", data->dma1ErrorLog1);
 
        for (i = 0; i < OPAL_P7IOC_NUM_PEST_REGS; i++) {
                if ((data->pestA[i] >> 63) == 0 &&
                    (data->pestB[i] >> 63) == 0)
                        continue;
-               pr_info("  PE[%3d] PESTA        = 0x%016llx\n", i, data->pestA[i]);
-               pr_info("          PESTB        = 0x%016llx\n", data->pestB[i]);
+
+               pr_info("  PE[%3d] PESTA:        %016llx\n", i, data->pestA[i]);
+               pr_info("          PESTB:        %016llx\n", data->pestB[i]);
+       }
+}
+
+static void pnv_pci_dump_phb3_diag_data(struct pci_controller *hose,
+                                       struct OpalIoPhbErrorCommon *common)
+{
+       struct OpalIoPhb3ErrorData *data;
+       int i;
+
+       data = (struct OpalIoPhb3ErrorData*)common;
+       pr_info("PHB3 PHB#%d Diag-data (Version: %d)\n\n",
+               hose->global_number, common->version);
+
+       pr_info("  brdgCtl:              %08x\n", data->brdgCtl);
+
+       pr_info("  portStatusReg:        %08x\n", data->portStatusReg);
+       pr_info("  rootCmplxStatus:      %08x\n", data->rootCmplxStatus);
+       pr_info("  busAgentStatus:       %08x\n", data->busAgentStatus);
+
+       pr_info("  deviceStatus:         %08x\n", data->deviceStatus);
+       pr_info("  slotStatus:           %08x\n", data->slotStatus);
+       pr_info("  linkStatus:           %08x\n", data->linkStatus);
+       pr_info("  devCmdStatus:         %08x\n", data->devCmdStatus);
+       pr_info("  devSecStatus:         %08x\n", data->devSecStatus);
+
+       pr_info("  rootErrorStatus:      %08x\n", data->rootErrorStatus);
+       pr_info("  uncorrErrorStatus:    %08x\n", data->uncorrErrorStatus);
+       pr_info("  corrErrorStatus:      %08x\n", data->corrErrorStatus);
+       pr_info("  tlpHdr1:              %08x\n", data->tlpHdr1);
+       pr_info("  tlpHdr2:              %08x\n", data->tlpHdr2);
+       pr_info("  tlpHdr3:              %08x\n", data->tlpHdr3);
+       pr_info("  tlpHdr4:              %08x\n", data->tlpHdr4);
+       pr_info("  sourceId:             %08x\n", data->sourceId);
+       pr_info("  errorClass:           %016llx\n", data->errorClass);
+       pr_info("  correlator:           %016llx\n", data->correlator);
+
+       pr_info("  nFir:                 %016llx\n", data->nFir);
+       pr_info("  nFirMask:             %016llx\n", data->nFirMask);
+       pr_info("  nFirWOF:              %016llx\n", data->nFirWOF);
+       pr_info("  PhbPlssr:             %016llx\n", data->phbPlssr);
+       pr_info("  PhbCsr:               %016llx\n", data->phbCsr);
+       pr_info("  lemFir:               %016llx\n", data->lemFir);
+       pr_info("  lemErrorMask:         %016llx\n", data->lemErrorMask);
+       pr_info("  lemWOF:               %016llx\n", data->lemWOF);
+       pr_info("  phbErrorStatus:       %016llx\n", data->phbErrorStatus);
+       pr_info("  phbFirstErrorStatus:  %016llx\n", data->phbFirstErrorStatus);
+       pr_info("  phbErrorLog0:         %016llx\n", data->phbErrorLog0);
+       pr_info("  phbErrorLog1:         %016llx\n", data->phbErrorLog1);
+       pr_info("  mmioErrorStatus:      %016llx\n", data->mmioErrorStatus);
+       pr_info("  mmioFirstErrorStatus: %016llx\n", data->mmioFirstErrorStatus);
+       pr_info("  mmioErrorLog0:        %016llx\n", data->mmioErrorLog0);
+       pr_info("  mmioErrorLog1:        %016llx\n", data->mmioErrorLog1);
+       pr_info("  dma0ErrorStatus:      %016llx\n", data->dma0ErrorStatus);
+       pr_info("  dma0FirstErrorStatus: %016llx\n", data->dma0FirstErrorStatus);
+       pr_info("  dma0ErrorLog0:        %016llx\n", data->dma0ErrorLog0);
+       pr_info("  dma0ErrorLog1:        %016llx\n", data->dma0ErrorLog1);
+       pr_info("  dma1ErrorStatus:      %016llx\n", data->dma1ErrorStatus);
+       pr_info("  dma1FirstErrorStatus: %016llx\n", data->dma1FirstErrorStatus);
+       pr_info("  dma1ErrorLog0:        %016llx\n", data->dma1ErrorLog0);
+       pr_info("  dma1ErrorLog1:        %016llx\n", data->dma1ErrorLog1);
+
+       for (i = 0; i < OPAL_PHB3_NUM_PEST_REGS; i++) {
+               if ((data->pestA[i] >> 63) == 0 &&
+                   (data->pestB[i] >> 63) == 0)
+                       continue;
+
+               pr_info("  PE[%3d] PESTA:        %016llx\n", i, data->pestA[i]);
+               pr_info("          PESTB:        %016llx\n", data->pestB[i]);
        }
 }
 
-static void pnv_pci_dump_phb_diag_data(struct pnv_phb *phb)
+void pnv_pci_dump_phb_diag_data(struct pci_controller *hose,
+                               unsigned char *log_buff)
 {
-       switch(phb->model) {
-       case PNV_PHB_MODEL_P7IOC:
-               pnv_pci_dump_p7ioc_diag_data(phb);
+       struct OpalIoPhbErrorCommon *common;
+
+       if (!hose || !log_buff)
+               return;
+
+       common = (struct OpalIoPhbErrorCommon *)log_buff;
+       switch (common->ioType) {
+       case OPAL_PHB_ERROR_DATA_TYPE_P7IOC:
+               pnv_pci_dump_p7ioc_diag_data(hose, common);
+               break;
+       case OPAL_PHB_ERROR_DATA_TYPE_PHB3:
+               pnv_pci_dump_phb3_diag_data(hose, common);
                break;
        default:
-               pr_warning("PCI %d: Can't decode this PHB diag data\n",
-                          phb->hose->global_number);
+               pr_warn("%s: Unrecognized ioType %d\n",
+                       __func__, common->ioType);
        }
 }
 
@@ -222,7 +302,7 @@ static void pnv_pci_handle_eeh_config(struct pnv_phb *phb, u32 pe_no)
                 * with the normal errors generated when probing empty slots
                 */
                if (has_diag)
-                       pnv_pci_dump_phb_diag_data(phb);
+                       pnv_pci_dump_phb_diag_data(phb->hose, phb->diag.blob);
                else
                        pr_warning("PCI %d: No diag data available\n",
                                   phb->hose->global_number);
@@ -484,7 +564,8 @@ void pnv_pci_setup_iommu_table(struct iommu_table *tbl,
 {
        tbl->it_blocksize = 16;
        tbl->it_base = (unsigned long)tce_mem;
-       tbl->it_offset = dma_offset >> IOMMU_PAGE_SHIFT;
+       tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K;
+       tbl->it_offset = dma_offset >> tbl->it_page_shift;
        tbl->it_index = 0;
        tbl->it_size = tce_size >> 3;
        tbl->it_busno = 0;
@@ -536,7 +617,7 @@ static void pnv_pci_dma_fallback_setup(struct pci_controller *hose,
                pdn->iommu_table = pnv_pci_setup_bml_iommu(hose);
        if (!pdn->iommu_table)
                return;
-       set_iommu_table_base(&pdev->dev, pdn->iommu_table);
+       set_iommu_table_base_and_group(&pdev->dev, pdn->iommu_table);
 }
 
 static void pnv_pci_dma_dev_setup(struct pci_dev *pdev)
@@ -657,3 +738,32 @@ void __init pnv_pci_init(void)
        ppc_md.teardown_msi_irqs = pnv_teardown_msi_irqs;
 #endif
 }
+
+static int tce_iommu_bus_notifier(struct notifier_block *nb,
+               unsigned long action, void *data)
+{
+       struct device *dev = data;
+
+       switch (action) {
+       case BUS_NOTIFY_ADD_DEVICE:
+               return iommu_add_device(dev);
+       case BUS_NOTIFY_DEL_DEVICE:
+               if (dev->iommu_group)
+                       iommu_del_device(dev);
+               return 0;
+       default:
+               return 0;
+       }
+}
+
+static struct notifier_block tce_iommu_bus_nb = {
+       .notifier_call = tce_iommu_bus_notifier,
+};
+
+static int __init tce_iommu_bus_notifier_init(void)
+{
+       bus_register_notifier(&pci_bus_type, &tce_iommu_bus_nb);
+       return 0;
+}
+
+subsys_initcall_sync(tce_iommu_bus_notifier_init);
index 1ed8d5f40f5ad1423f78c9ae7fdac42abac4376d..13f1942a9a5f98708038808a2d816f2bec0d6e1a 100644 (file)
@@ -176,6 +176,7 @@ struct pnv_phb {
        union {
                unsigned char                   blob[PNV_PCI_DIAG_BUF_SIZE];
                struct OpalIoP7IOCPhbErrorData  p7ioc;
+               struct OpalIoPhb3ErrorData      phb3;
                struct OpalIoP7IOCErrorData     hub_diag;
        } diag;
 
@@ -186,6 +187,8 @@ extern struct pci_ops pnv_pci_ops;
 extern struct pnv_eeh_ops ioda_eeh_ops;
 #endif
 
+void pnv_pci_dump_phb_diag_data(struct pci_controller *hose,
+                               unsigned char *log_buff);
 int pnv_pci_cfg_read(struct device_node *dn,
                     int where, int size, u32 *val);
 int pnv_pci_cfg_write(struct device_node *dn,
index 19884b2a51b4743f78a9389f22e8588e228616d7..21166f65c97c37df19e48a938c33c49d5bad845e 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of_fdt.h>
 #include <linux/interrupt.h>
 #include <linux/bug.h>
+#include <linux/cpuidle.h>
 
 #include <asm/machdep.h>
 #include <asm/firmware.h>
@@ -145,8 +146,10 @@ static void pnv_shutdown(void)
        /* Let the PCI code clear up IODA tables */
        pnv_pci_shutdown();
 
-       /* And unregister all OPAL interrupts so they don't fire
-        * up while we kexec
+       /*
+        * Stop OPAL activity: Unregister all OPAL interrupts so they
+        * don't fire up while we kexec and make sure all potentially
+        * DMA'ing ops are complete (such as dump retrieval).
         */
        opal_shutdown();
 }
@@ -214,6 +217,16 @@ static int __init pnv_probe(void)
        return 1;
 }
 
+void powernv_idle(void)
+{
+       /* Hook to cpuidle framework if available, else
+        * call on default platform idle code
+        */
+       if (cpuidle_idle_call()) {
+               power7_idle();
+       }
+}
+
 define_machine(powernv) {
        .name                   = "PowerNV",
        .probe                  = pnv_probe,
@@ -223,7 +236,7 @@ define_machine(powernv) {
        .show_cpuinfo           = pnv_show_cpuinfo,
        .progress               = pnv_progress,
        .machine_shutdown       = pnv_shutdown,
-       .power_save             = power7_idle,
+       .power_save             = powernv_idle,
        .calibrate_decr         = generic_calibrate_decr,
 #ifdef CONFIG_KEXEC
        .kexec_cpu_down         = pnv_kexec_cpu_down,
index e17fa1432d80706ad9b5fa2682ea88751027c38a..a0bca05e26b0c7478c7483c43b2437fa0f6a61d7 100644 (file)
@@ -143,7 +143,7 @@ static void _dump_areas(unsigned int spe_id, unsigned long priv2,
        pr_debug("%s:%d: shadow:  %lxh\n", func, line, shadow);
 }
 
-inline u64 ps3_get_spe_id(void *arg)
+u64 ps3_get_spe_id(void *arg)
 {
        return spu_pdata(arg)->spe_id;
 }
index 62b4f8025de005ad77bdbfcd42024d25614eb79c..37300f6ee244edeb96f7ebbf86c2b476d3dfbb23 100644 (file)
@@ -34,7 +34,7 @@ config PPC_SPLPAR
 
 config PSERIES_MSI
        bool
-       depends on PCI_MSI && EEH
+       depends on PCI_MSI && PPC_PSERIES && EEH
        default y
 
 config PSERIES_ENERGY
@@ -119,12 +119,3 @@ config DTL
          which are accessible through a debugfs file.
 
          Say N if you are unsure.
-
-config PSERIES_IDLE
-       bool "Cpuidle driver for pSeries platforms"
-       depends on CPU_IDLE
-       depends on PPC_PSERIES
-       default y
-       help
-         Select this option to enable processor idle state management
-         through cpuidle subsystem.
index fbccac9cd2dc393c2828ccacfd70e8018efcfb10..03480796af9a55cad0b024aaf23223a8b51d8175 100644 (file)
@@ -21,7 +21,6 @@ obj-$(CONFIG_HCALL_STATS)     += hvCall_inst.o
 obj-$(CONFIG_CMM)              += cmm.o
 obj-$(CONFIG_DTL)              += dtl.o
 obj-$(CONFIG_IO_EVENT_IRQ)     += io_event_irq.o
-obj-$(CONFIG_PSERIES_IDLE)     += processor_idle.o
 obj-$(CONFIG_LPARCFG)          += lparcfg.o
 
 ifeq ($(CONFIG_PPC_PSERIES),y)
index 1e561bef459b4261d4e06f8ee2c563edc04e7e9d..2d8bf15879fdd3e14da6c8c46f6bbeaf7ab3f138 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/gfp.h>
-#include <linux/init.h>
 #include <linux/kthread.h>
 #include <linux/module.h>
 #include <linux/oom.h>
index 5db66f1fbc2648f41244b15ca07fdc8bfad7ad5d..7d61498e45c082fee52f370be623dd8f97114f62 100644 (file)
@@ -20,7 +20,6 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/debugfs.h>
 #include <linux/spinlock.h>
index ccb633e077b16d6c7a57bb6cfd4372ca87ceeb6a..9ef3cc8ebc11c7f533a3bc966d90bd6c085d891d 100644 (file)
@@ -689,7 +689,9 @@ static struct eeh_ops pseries_eeh_ops = {
        .get_log                = pseries_eeh_get_log,
        .configure_bridge       = pseries_eeh_configure_bridge,
        .read_config            = pseries_eeh_read_config,
-       .write_config           = pseries_eeh_write_config
+       .write_config           = pseries_eeh_write_config,
+       .next_error             = NULL,
+       .restore_config         = NULL
 };
 
 /**
index f253361552aee3fbc3c98f077790f89551b4ea74..33b552ffbe576d4b452f31aa22af5b6a16a9cd0c 100644 (file)
@@ -486,9 +486,10 @@ static void iommu_table_setparms(struct pci_controller *phb,
                memset((void *)tbl->it_base, 0, *sizep);
 
        tbl->it_busno = phb->bus->number;
+       tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K;
 
        /* Units of tce entries */
-       tbl->it_offset = phb->dma_window_base_cur >> IOMMU_PAGE_SHIFT;
+       tbl->it_offset = phb->dma_window_base_cur >> tbl->it_page_shift;
 
        /* Test if we are going over 2GB of DMA space */
        if (phb->dma_window_base_cur + phb->dma_window_size > 0x80000000ul) {
@@ -499,7 +500,7 @@ static void iommu_table_setparms(struct pci_controller *phb,
        phb->dma_window_base_cur += phb->dma_window_size;
 
        /* Set the tce table size - measured in entries */
-       tbl->it_size = phb->dma_window_size >> IOMMU_PAGE_SHIFT;
+       tbl->it_size = phb->dma_window_size >> tbl->it_page_shift;
 
        tbl->it_index = 0;
        tbl->it_blocksize = 16;
@@ -537,11 +538,12 @@ static void iommu_table_setparms_lpar(struct pci_controller *phb,
        of_parse_dma_window(dn, dma_window, &tbl->it_index, &offset, &size);
 
        tbl->it_busno = phb->bus->number;
+       tbl->it_page_shift = IOMMU_PAGE_SHIFT_4K;
        tbl->it_base   = 0;
        tbl->it_blocksize  = 16;
        tbl->it_type = TCE_PCI;
-       tbl->it_offset = offset >> IOMMU_PAGE_SHIFT;
-       tbl->it_size = size >> IOMMU_PAGE_SHIFT;
+       tbl->it_offset = offset >> tbl->it_page_shift;
+       tbl->it_size = size >> tbl->it_page_shift;
 }
 
 static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
@@ -687,7 +689,8 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
                iommu_table_setparms(phb, dn, tbl);
                PCI_DN(dn)->iommu_table = iommu_init_table(tbl, phb->node);
                iommu_register_group(tbl, pci_domain_nr(phb->bus), 0);
-               set_iommu_table_base(&dev->dev, PCI_DN(dn)->iommu_table);
+               set_iommu_table_base_and_group(&dev->dev,
+                                              PCI_DN(dn)->iommu_table);
                return;
        }
 
@@ -699,7 +702,8 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
                dn = dn->parent;
 
        if (dn && PCI_DN(dn))
-               set_iommu_table_base(&dev->dev, PCI_DN(dn)->iommu_table);
+               set_iommu_table_base_and_group(&dev->dev,
+                                              PCI_DN(dn)->iommu_table);
        else
                printk(KERN_WARNING "iommu: Device %s has no iommu table\n",
                       pci_name(dev));
@@ -717,21 +721,6 @@ static int __init disable_ddw_setup(char *str)
 
 early_param("disable_ddw", disable_ddw_setup);
 
-static inline void __remove_ddw(struct device_node *np, const u32 *ddw_avail, u64 liobn)
-{
-       int ret;
-
-       ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn);
-       if (ret)
-               pr_warning("%s: failed to remove DMA window: rtas returned "
-                       "%d to ibm,remove-pe-dma-window(%x) %llx\n",
-                       np->full_name, ret, ddw_avail[2], liobn);
-       else
-               pr_debug("%s: successfully removed DMA window: rtas returned "
-                       "%d to ibm,remove-pe-dma-window(%x) %llx\n",
-                       np->full_name, ret, ddw_avail[2], liobn);
-}
-
 static void remove_ddw(struct device_node *np)
 {
        struct dynamic_dma_window_prop *dwp;
@@ -761,7 +750,15 @@ static void remove_ddw(struct device_node *np)
                pr_debug("%s successfully cleared tces in window.\n",
                         np->full_name);
 
-       __remove_ddw(np, ddw_avail, liobn);
+       ret = rtas_call(ddw_avail[2], 1, 1, NULL, liobn);
+       if (ret)
+               pr_warning("%s: failed to remove direct window: rtas returned "
+                       "%d to ibm,remove-pe-dma-window(%x) %llx\n",
+                       np->full_name, ret, ddw_avail[2], liobn);
+       else
+               pr_debug("%s: successfully removed direct window: rtas returned "
+                       "%d to ibm,remove-pe-dma-window(%x) %llx\n",
+                       np->full_name, ret, ddw_avail[2], liobn);
 
 delprop:
        ret = of_remove_property(np, win64);
@@ -790,68 +787,33 @@ static u64 find_existing_ddw(struct device_node *pdn)
        return dma_addr;
 }
 
-static void __restore_default_window(struct eeh_dev *edev,
-                                               u32 ddw_restore_token)
-{
-       u32 cfg_addr;
-       u64 buid;
-       int ret;
-
-       /*
-        * Get the config address and phb buid of the PE window.
-        * Rely on eeh to retrieve this for us.
-        * Retrieve them from the pci device, not the node with the
-        * dma-window property
-        */
-       cfg_addr = edev->config_addr;
-       if (edev->pe_config_addr)
-               cfg_addr = edev->pe_config_addr;
-       buid = edev->phb->buid;
-
-       do {
-               ret = rtas_call(ddw_restore_token, 3, 1, NULL, cfg_addr,
-                                       BUID_HI(buid), BUID_LO(buid));
-       } while (rtas_busy_delay(ret));
-       pr_info("ibm,reset-pe-dma-windows(%x) %x %x %x returned %d\n",
-                ddw_restore_token, cfg_addr, BUID_HI(buid), BUID_LO(buid), ret);
-}
-
 static int find_existing_ddw_windows(void)
 {
+       int len;
        struct device_node *pdn;
+       struct direct_window *window;
        const struct dynamic_dma_window_prop *direct64;
-       const u32 *ddw_extensions;
 
        if (!firmware_has_feature(FW_FEATURE_LPAR))
                return 0;
 
        for_each_node_with_property(pdn, DIRECT64_PROPNAME) {
-               direct64 = of_get_property(pdn, DIRECT64_PROPNAME, NULL);
+               direct64 = of_get_property(pdn, DIRECT64_PROPNAME, &len);
                if (!direct64)
                        continue;
 
-               /*
-                * We need to ensure the IOMMU table is active when we
-                * return from the IOMMU setup so that the common code
-                * can clear the table or find the holes. To that end,
-                * first, remove any existing DDW configuration.
-                */
-               remove_ddw(pdn);
+               window = kzalloc(sizeof(*window), GFP_KERNEL);
+               if (!window || len < sizeof(struct dynamic_dma_window_prop)) {
+                       kfree(window);
+                       remove_ddw(pdn);
+                       continue;
+               }
 
-               /*
-                * Second, if we are running on a new enough level of
-                * firmware where the restore API is present, use it to
-                * restore the 32-bit window, which was removed in
-                * create_ddw.
-                * If the API is not present, then create_ddw couldn't
-                * have removed the 32-bit window in the first place, so
-                * removing the DDW configuration should be sufficient.
-                */
-               ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions",
-                                                                       NULL);
-               if (ddw_extensions && ddw_extensions[0] > 0)
-                       __restore_default_window(of_node_to_eeh_dev(pdn),
-                                                       ddw_extensions[1]);
+               window->device = pdn;
+               window->prop = direct64;
+               spin_lock(&direct_window_list_lock);
+               list_add(&window->list, &direct_window_list);
+               spin_unlock(&direct_window_list_lock);
        }
 
        return 0;
@@ -921,12 +883,6 @@ static int create_ddw(struct pci_dev *dev, const u32 *ddw_avail,
        return ret;
 }
 
-static void restore_default_window(struct pci_dev *dev,
-                                       u32 ddw_restore_token)
-{
-       __restore_default_window(pci_dev_to_eeh_dev(dev), ddw_restore_token);
-}
-
 struct failed_ddw_pdn {
        struct device_node *pdn;
        struct list_head list;
@@ -954,13 +910,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
        u64 dma_addr, max_addr;
        struct device_node *dn;
        const u32 *uninitialized_var(ddw_avail);
-       const u32 *uninitialized_var(ddw_extensions);
-       u32 ddw_restore_token = 0;
        struct direct_window *window;
        struct property *win64;
        struct dynamic_dma_window_prop *ddwprop;
-       const void *dma_window = NULL;
-       unsigned long liobn, offset, size;
        struct failed_ddw_pdn *fpdn;
 
        mutex_lock(&direct_window_init_mutex);
@@ -991,42 +943,9 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
         */
        ddw_avail = of_get_property(pdn, "ibm,ddw-applicable", &len);
        if (!ddw_avail || len < 3 * sizeof(u32))
-               goto out_unlock;
-
-       /*
-        * the extensions property is only required to exist in certain
-        * levels of firmware and later
-        * the ibm,ddw-extensions property is a list with the first
-        * element containing the number of extensions and each
-        * subsequent entry is a value corresponding to that extension
-        */
-       ddw_extensions = of_get_property(pdn, "ibm,ddw-extensions", &len);
-       if (ddw_extensions) {
-               /*
-                * each new defined extension length should be added to
-                * the top of the switch so the "earlier" entries also
-                * get picked up
-                */
-               switch (ddw_extensions[0]) {
-                       /* ibm,reset-pe-dma-windows */
-                       case 1:
-                               ddw_restore_token = ddw_extensions[1];
-                               break;
-               }
-       }
-
-       /*
-        * Only remove the existing DMA window if we can restore back to
-        * the default state. Removing the existing window maximizes the
-        * resources available to firmware for dynamic window creation.
-        */
-       if (ddw_restore_token) {
-               dma_window = of_get_property(pdn, "ibm,dma-window", NULL);
-               of_parse_dma_window(pdn, dma_window, &liobn, &offset, &size);
-               __remove_ddw(pdn, ddw_avail, liobn);
-       }
+               goto out_failed;
 
-       /*
+       /*
         * Query if there is a second window of size to map the
         * whole partition.  Query returns number of windows, largest
         * block assigned to PE (partition endpoint), and two bitmasks
@@ -1035,7 +954,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
        dn = pci_device_to_OF_node(dev);
        ret = query_ddw(dev, ddw_avail, &query);
        if (ret != 0)
-               goto out_restore_window;
+               goto out_failed;
 
        if (query.windows_available == 0) {
                /*
@@ -1044,7 +963,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
                 * trading in for a larger page size.
                 */
                dev_dbg(&dev->dev, "no free dynamic windows");
-               goto out_restore_window;
+               goto out_failed;
        }
        if (be32_to_cpu(query.page_size) & 4) {
                page_shift = 24; /* 16MB */
@@ -1055,7 +974,7 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
        } else {
                dev_dbg(&dev->dev, "no supported direct page size in mask %x",
                          query.page_size);
-               goto out_restore_window;
+               goto out_failed;
        }
        /* verify the window * number of ptes will map the partition */
        /* check largest block * page size > max memory hotplug addr */
@@ -1064,14 +983,14 @@ static u64 enable_ddw(struct pci_dev *dev, struct device_node *pdn)
                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);
-               goto out_restore_window;
+               goto out_failed;
        }
        len = order_base_2(max_addr);
        win64 = kzalloc(sizeof(struct property), GFP_KERNEL);
        if (!win64) {
                dev_info(&dev->dev,
                        "couldn't allocate property for 64bit dma window\n");
-               goto out_restore_window;
+               goto out_failed;
        }
        win64->name = kstrdup(DIRECT64_PROPNAME, GFP_KERNEL);
        win64->value = ddwprop = kmalloc(sizeof(*ddwprop), GFP_KERNEL);
@@ -1133,9 +1052,7 @@ out_free_prop:
        kfree(win64->value);
        kfree(win64);
 
-out_restore_window:
-       if (ddw_restore_token)
-               restore_default_window(dev, ddw_restore_token);
+out_failed:
 
        fpdn = kzalloc(sizeof(*fpdn), GFP_KERNEL);
        if (!fpdn)
@@ -1193,7 +1110,7 @@ static void pci_dma_dev_setup_pSeriesLP(struct pci_dev *dev)
                pr_debug("  found DMA window, table: %p\n", pci->iommu_table);
        }
 
-       set_iommu_table_base(&dev->dev, pci->iommu_table);
+       set_iommu_table_base_and_group(&dev->dev, pci->iommu_table);
 }
 
 static int dma_set_mask_pSeriesLP(struct device *dev, u64 dma_mask)
index 4fca3def9db951896864d0b716d7dea8a2364ba2..b02af9ef3ff61ab45fb2ae86f2b49cdc6b5cc7ff 100644 (file)
@@ -92,7 +92,7 @@ void vpa_init(int cpu)
         * PAPR says this feature is SLB-Buffer but firmware never
         * reports that.  All SPLPAR support SLB shadow buffer.
         */
-       addr = __pa(&slb_shadow[cpu]);
+       addr = __pa(paca[cpu].slb_shadow_ptr);
        if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
                ret = register_slb_shadow(hwcpu, addr);
                if (ret)
@@ -153,7 +153,8 @@ static long pSeries_lpar_hpte_insert(unsigned long hpte_group,
 
        /* Make pHyp happy */
        if ((rflags & _PAGE_NO_CACHE) && !(rflags & _PAGE_WRITETHRU))
-               hpte_r &= ~_PAGE_COHERENT;
+               hpte_r &= ~HPTE_R_M;
+
        if (firmware_has_feature(FW_FEATURE_XCMO) && !(hpte_r & HPTE_R_N))
                flags |= H_COALESCE_CAND;
 
index 6f76ae417f47e561bbf7e8b01c588a8e73f6374d..8e639d7cbda72e057ab535083e29ef03f8d7f369 100644 (file)
@@ -72,7 +72,7 @@
 
 int CMO_PrPSP = -1;
 int CMO_SecPSP = -1;
-unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT);
+unsigned long CMO_PageSize = (ASM_CONST(1) << IOMMU_PAGE_SHIFT_4K);
 EXPORT_SYMBOL(CMO_PageSize);
 
 int fwnmi_active;  /* TRUE if an FWNMI handler is present */
@@ -569,7 +569,7 @@ void pSeries_cmo_feature_init(void)
 {
        char *ptr, *key, *value, *end;
        int call_status;
-       int page_order = IOMMU_PAGE_SHIFT;
+       int page_order = IOMMU_PAGE_SHIFT_4K;
 
        pr_debug(" -> fw_cmo_feature_init()\n");
        spin_lock(&rtas_data_buf_lock);
index 62cb527493e774969ec4dbf709e28f2bb41bf144..9a15e5b39bb8516c39f9da9e678534a8167f74ac 100644 (file)
@@ -260,7 +260,7 @@ static int tce_build_wsp(struct iommu_table *tbl, long index, long npages,
                *tcep = proto_tce | (rpn & TCE_RPN_MASK) << TCE_RPN_SHIFT;
 
                dma_debug("[DMA] TCE %p set to 0x%016llx (dma addr: 0x%lx)\n",
-                         tcep, *tcep, (tbl->it_offset + index) << IOMMU_PAGE_SHIFT);
+                         tcep, *tcep, (tbl->it_offset + index) << IOMMU_PAGE_SHIFT_4K);
 
                uaddr += TCE_PAGE_SIZE;
                index++;
@@ -381,8 +381,9 @@ static struct wsp_dma_table *wsp_pci_create_dma32_table(struct wsp_phb *phb,
 
        /* Init bits and pieces */
        tbl->table.it_blocksize = 16;
-       tbl->table.it_offset = addr >> IOMMU_PAGE_SHIFT;
-       tbl->table.it_size = size >> IOMMU_PAGE_SHIFT;
+       tbl->table.it_page_shift = IOMMU_PAGE_SHIFT_4K;
+       tbl->table.it_offset = addr >> tbl->table.it_page_shift;
+       tbl->table.it_size = size >> tbl->table.it_page_shift;
 
        /*
         * It's already blank but we clear it anyway.
@@ -449,8 +450,8 @@ static void wsp_pci_dma_dev_setup(struct pci_dev *pdev)
        if (table) {
                pr_info("%s: Setup iommu: 32-bit DMA region 0x%08lx..0x%08lx\n",
                        pci_name(pdev),
-                       table->table.it_offset << IOMMU_PAGE_SHIFT,
-                       (table->table.it_offset << IOMMU_PAGE_SHIFT)
+                       table->table.it_offset << IOMMU_PAGE_SHIFT_4K,
+                       (table->table.it_offset << IOMMU_PAGE_SHIFT_4K)
                        + phb->dma32_region_size - 1);
                archdata->dma_data.iommu_table_base = &table->table;
                return;
index 13ec968be4c7a25ca79fc480a7aab26e514b3bb8..7baa70d6dc016c85b8e4874f7618dbf9145d30ac 100644 (file)
@@ -19,7 +19,7 @@ config PPC_MSI_BITMAP
        default y if MPIC
        default y if FSL_PCI
        default y if PPC4xx_MSI
-       default y if POWERNV_MSI
+       default y if PPC_POWERNV
 
 source "arch/powerpc/sysdev/xics/Kconfig"
 
index 1c16141c031c9e2d2512b0d308a8456c15fd1ae1..47b6b9f81d4305537b7d0e6290e178efb4253f4c 100644 (file)
@@ -109,27 +109,28 @@ axon_ram_make_request(struct request_queue *queue, struct bio *bio)
        struct axon_ram_bank *bank = bio->bi_bdev->bd_disk->private_data;
        unsigned long phys_mem, phys_end;
        void *user_mem;
-       struct bio_vec *vec;
+       struct bio_vec vec;
        unsigned int transfered;
-       unsigned short idx;
+       struct bvec_iter iter;
 
-       phys_mem = bank->io_addr + (bio->bi_sector << AXON_RAM_SECTOR_SHIFT);
+       phys_mem = bank->io_addr + (bio->bi_iter.bi_sector <<
+                                   AXON_RAM_SECTOR_SHIFT);
        phys_end = bank->io_addr + bank->size;
        transfered = 0;
-       bio_for_each_segment(vec, bio, idx) {
-               if (unlikely(phys_mem + vec->bv_len > phys_end)) {
+       bio_for_each_segment(vec, bio, iter) {
+               if (unlikely(phys_mem + vec.bv_len > phys_end)) {
                        bio_io_error(bio);
                        return;
                }
 
-               user_mem = page_address(vec->bv_page) + vec->bv_offset;
+               user_mem = page_address(vec.bv_page) + vec.bv_offset;
                if (bio_data_dir(bio) == READ)
-                       memcpy(user_mem, (void *) phys_mem, vec->bv_len);
+                       memcpy(user_mem, (void *) phys_mem, vec.bv_len);
                else
-                       memcpy((void *) phys_mem, user_mem, vec->bv_len);
+                       memcpy((void *) phys_mem, user_mem, vec.bv_len);
 
-               phys_mem += vec->bv_len;
-               transfered += vec->bv_len;
+               phys_mem += vec.bv_len;
+               transfered += vec.bv_len;
        }
        bio_endio(bio, 0);
 }
index 10386b676d8758b7f52bb8348f7cf321cc8db89a..a11bd1d433adf7e749ad7e3008f7327bdff29110 100644 (file)
@@ -27,7 +27,6 @@
  */
 
 #include <linux/stddef.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/irq.h>
index bd968a43a48b29047fa5f2d9d8cd1fe9ceb66b69..62c47bb765178a10fe3aa371ef0c7d5d0c0c6364 100644 (file)
@@ -292,6 +292,7 @@ static void iommu_table_dart_setup(void)
        iommu_table_dart.it_offset = 0;
        /* it_size is in number of entries */
        iommu_table_dart.it_size = dart_tablesize / sizeof(u32);
+       iommu_table_dart.it_page_shift = IOMMU_PAGE_SHIFT_4K;
 
        /* Initialize the common IOMMU code */
        iommu_table_dart.it_base = (unsigned long)dart_vbase;
index d7fc7223914487bdcabac51a6beba8fa68036474..fbc885b3194690fd8762f1f8b03e78e5bc712c93 100644 (file)
@@ -19,7 +19,6 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/compiler.h>
index 6bc5a546d49fad87ccde51786371a8d5ca9dbf63..d631022ffb4b3c77a4fe057c3c6da91457a20c64 100644 (file)
@@ -214,10 +214,14 @@ static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
        struct fsl_lbc_ctrl *ctrl = data;
        struct fsl_lbc_regs __iomem *lbc = ctrl->regs;
        u32 status;
+       unsigned long flags;
 
+       spin_lock_irqsave(&fsl_lbc_lock, flags);
        status = in_be32(&lbc->ltesr);
-       if (!status)
+       if (!status) {
+               spin_unlock_irqrestore(&fsl_lbc_lock, flags);
                return IRQ_NONE;
+       }
 
        out_be32(&lbc->ltesr, LTESR_CLEAR);
        out_be32(&lbc->lteatr, 0);
@@ -260,6 +264,7 @@ static irqreturn_t fsl_lbc_ctrl_irq(int irqno, void *data)
        if (status & ~LTESR_MASK)
                dev_err(ctrl->dev, "Unknown error: "
                        "LTESR 0x%08X\n", status);
+       spin_unlock_irqrestore(&fsl_lbc_lock, flags);
        return IRQ_HANDLED;
 }
 
@@ -298,8 +303,8 @@ static int fsl_lbc_ctrl_probe(struct platform_device *dev)
                goto err;
        }
 
-       fsl_lbc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0);
-       if (fsl_lbc_ctrl_dev->irq == NO_IRQ) {
+       fsl_lbc_ctrl_dev->irq[0] = irq_of_parse_and_map(dev->dev.of_node, 0);
+       if (!fsl_lbc_ctrl_dev->irq[0]) {
                dev_err(&dev->dev, "failed to get irq resource\n");
                ret = -ENODEV;
                goto err;
@@ -311,20 +316,34 @@ static int fsl_lbc_ctrl_probe(struct platform_device *dev)
        if (ret < 0)
                goto err;
 
-       ret = request_irq(fsl_lbc_ctrl_dev->irq, fsl_lbc_ctrl_irq, 0,
+       ret = request_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_irq, 0,
                                "fsl-lbc", fsl_lbc_ctrl_dev);
        if (ret != 0) {
                dev_err(&dev->dev, "failed to install irq (%d)\n",
-                       fsl_lbc_ctrl_dev->irq);
-               ret = fsl_lbc_ctrl_dev->irq;
+                       fsl_lbc_ctrl_dev->irq[0]);
+               ret = fsl_lbc_ctrl_dev->irq[0];
                goto err;
        }
 
+       fsl_lbc_ctrl_dev->irq[1] = irq_of_parse_and_map(dev->dev.of_node, 1);
+       if (fsl_lbc_ctrl_dev->irq[1]) {
+               ret = request_irq(fsl_lbc_ctrl_dev->irq[1], fsl_lbc_ctrl_irq,
+                               IRQF_SHARED, "fsl-lbc-err", fsl_lbc_ctrl_dev);
+               if (ret) {
+                       dev_err(&dev->dev, "failed to install irq (%d)\n",
+                                       fsl_lbc_ctrl_dev->irq[1]);
+                       ret = fsl_lbc_ctrl_dev->irq[1];
+                       goto err1;
+               }
+       }
+
        /* Enable interrupts for any detected events */
        out_be32(&fsl_lbc_ctrl_dev->regs->lteir, LTEIR_ENABLE);
 
        return 0;
 
+err1:
+       free_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_dev);
 err:
        iounmap(fsl_lbc_ctrl_dev->regs);
        kfree(fsl_lbc_ctrl_dev);
index 4dfd61df8aba99a01fb0d3d141d1544aeea3b341..a625dcf26b2b7c53374883980d9f45e1881098ff 100644 (file)
@@ -122,7 +122,7 @@ static int fsl_pci_dma_set_mask(struct device *dev, u64 dma_mask)
         * address width of the SoC such that we can address any internal
         * SoC address from across PCI if needed
         */
-       if ((dev->bus == &pci_bus_type) &&
+       if ((dev_is_pci(dev)) &&
            dma_mask >= DMA_BIT_MASK(MAX_PHYS_ADDR_BITS)) {
                set_dma_ops(dev, &dma_direct_ops);
                set_dma_offset(dev, pci64_dma_offset);
@@ -454,7 +454,7 @@ void fsl_pcibios_fixup_bus(struct pci_bus *bus)
        }
 }
 
-int __init fsl_add_bridge(struct platform_device *pdev, int is_primary)
+int fsl_add_bridge(struct platform_device *pdev, int is_primary)
 {
        int len;
        struct pci_controller *hose;
@@ -1035,6 +1035,7 @@ static const struct of_device_id pci_ids[] = {
        { .compatible = "fsl,mpc8548-pcie", },
        { .compatible = "fsl,mpc8610-pci", },
        { .compatible = "fsl,mpc8641-pcie", },
+       { .compatible = "fsl,qoriq-pcie", },
        { .compatible = "fsl,qoriq-pcie-v2.1", },
        { .compatible = "fsl,qoriq-pcie-v2.2", },
        { .compatible = "fsl,qoriq-pcie-v2.3", },
index 6149916da3f48c50c0e42c73e5dd7a1099fd0568..908dbd9826b6e15bf0fa8e916116ea0c568a44c7 100644 (file)
@@ -1,7 +1,6 @@
 #ifndef __GEF_PIC_H__
 #define __GEF_PIC_H__
 
-#include <linux/init.h>
 
 void gef_pic_cascade(unsigned int, struct irq_desc *);
 unsigned int gef_pic_get_irq(void);
index 997df6a7ab5d19fd1aeac65d020f51d2d17ba482..45598da0b3214221feb8b8d66200fe8146b3ef2f 100644 (file)
@@ -8,7 +8,6 @@
  */
 #undef DEBUG
 
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/interrupt.h>
 #include <linux/kernel.h>
index c6c8b526a4f6e5e68b569dd6451ad339d39cb78c..1f6c570d66d45ee88e1114b790d600f06c0bc4ec 100644 (file)
@@ -152,10 +152,8 @@ static struct pci_ops indirect_pci_ops =
        .write = indirect_write_config,
 };
 
-void __init
-setup_indirect_pci(struct pci_controller* hose,
-                  resource_size_t cfg_addr,
-                  resource_size_t cfg_data, u32 flags)
+void setup_indirect_pci(struct pci_controller *hose, resource_size_t cfg_addr,
+                       resource_size_t cfg_data, u32 flags)
 {
        resource_size_t base = cfg_addr & PAGE_MASK;
        void __iomem *mbase;
index b724622c3a0b74ab5eddfa3b0cfc10dc6eab2c34..c4828c0be5bd861e734577dc982071a305e8fbea 100644 (file)
@@ -1,6 +1,5 @@
 #include <linux/kernel.h>
 #include <linux/stddef.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/signal.h>
 #include <linux/irq.h>
index 22d7d57eead9d88fca57629de658a5629fd2d6bf..9d9b06217f8b9dff2a994ad5d357436e9986553e 100644 (file)
@@ -41,6 +41,7 @@
 #define MPIC_TIMER_TCR_ROVR_OFFSET     24
 
 #define TIMER_STOP                     0x80000000
+#define GTCCR_TOG                      0x80000000
 #define TIMERS_PER_GROUP               4
 #define MAX_TICKS                      (~0U >> 1)
 #define MAX_TICKS_CASCADE              (~0U)
@@ -96,8 +97,11 @@ static void convert_ticks_to_time(struct timer_group_priv *priv,
        time->tv_sec = (__kernel_time_t)div_u64(ticks, priv->timerfreq);
        tmp_sec = (u64)time->tv_sec * (u64)priv->timerfreq;
 
-       time->tv_usec = (__kernel_suseconds_t)
-               div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq);
+       time->tv_usec = 0;
+
+       if (tmp_sec <= ticks)
+               time->tv_usec = (__kernel_suseconds_t)
+                       div_u64((ticks - tmp_sec) * 1000000, priv->timerfreq);
 
        return;
 }
@@ -327,11 +331,13 @@ void mpic_get_remain_time(struct mpic_timer *handle, struct timeval *time)
        casc_priv = priv->timer[handle->num].cascade_handle;
        if (casc_priv) {
                tmp_ticks = in_be32(&priv->regs[handle->num].gtccr);
+               tmp_ticks &= ~GTCCR_TOG;
                ticks = ((u64)tmp_ticks & UINT_MAX) * (u64)MAX_TICKS_CASCADE;
                tmp_ticks = in_be32(&priv->regs[handle->num - 1].gtccr);
                ticks += tmp_ticks;
        } else {
                ticks = in_be32(&priv->regs[handle->num].gtccr);
+               ticks &= ~GTCCR_TOG;
        }
 
        convert_ticks_to_time(priv, ticks, time);
index a88807b3dd578b7b4e2ed423d5305ef41dad00e3..d09994164dafd315027bd381209128e76fc79e15 100644 (file)
@@ -16,7 +16,6 @@
 
 #include <linux/stddef.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
index 134b07d2943564ee3e7244fee932366680c744d2..621575b7e84aa3b2c5932b1768f909b56d593587 100644 (file)
@@ -14,7 +14,6 @@
  * option) any later version.
  */
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
index cceb2e366738f90b7b9570c9dab1b1a14c37830d..65aaf15032aee221f313e844248749cb8029baee 100644 (file)
@@ -13,7 +13,6 @@
  * option) any later version.
  */
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/stddef.h>
index 1c062f48f1ac8711e8975b3cf601cb595ce494fd..befaf1123f7f0c72e3c45bbf3807ec3fd0362e27 100644 (file)
@@ -13,7 +13,6 @@
  * option) any later version.
  */
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/stddef.h>
index ce5a7b489e4b4282b7b0ac4d5f75ffd66c00ff36..9998c0de12d056739cf891e318ddb08b0f7cfc27 100644 (file)
@@ -18,7 +18,6 @@
  *      2 of the License, or (at your option) any later version.
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <asm/barrier.h>
 #include <asm/page.h>
index df0fc58214697623b429f55555d494e8ccf56c52..c1917cf67c3ded26aee9e48b50340ff51d5048ac 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/irq.h>
 #include <linux/smp.h>
 #include <linux/interrupt.h>
-#include <linux/init.h>
 #include <linux/cpu.h>
 #include <linux/of.h>
 
index af9d3469fb9933e4f3d424f01e3230ddeb580c67..a90731b3d44a3ea41052690975aefcd8b3ce2db7 100644 (file)
@@ -2051,6 +2051,10 @@ static void dump_one_paca(int cpu)
        DUMP(p, stab_addr, "lx");
 #endif
        DUMP(p, emergency_sp, "p");
+#ifdef CONFIG_PPC_BOOK3S_64
+       DUMP(p, mc_emergency_sp, "p");
+       DUMP(p, in_mce, "x");
+#endif
        DUMP(p, data_offset, "lx");
        DUMP(p, hw_cpu_id, "x");
        DUMP(p, cpu_start, "x");
index 4f858f77d870d842fa99fdc26e00b13521ae35e3..65a07750f4f946f038bb2e2a4e13f9f6d05dce83 100644 (file)
@@ -596,7 +596,7 @@ config CRASH_DUMP
 config ZFCPDUMP
        def_bool n
        prompt "zfcpdump support"
-       depends on SMP
+       depends on 64BIT && SMP
        help
          Select this option if you want to build an zfcpdump enabled kernel.
          Refer to <file:Documentation/s390/zfcpdump.txt> for more details on this.
index 2e671d5004ca56651a0f246d91a5a65b81889603..06f8d95a16cdc9767d4538ea1798c32bfac73187 100644 (file)
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_S390_HYPFS_FS) += s390_hypfs.o
 
-s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o
+s390_hypfs-objs := inode.o hypfs_diag.o hypfs_vm.o hypfs_dbfs.o hypfs_sprp.o
index 79f2ac55253f9289c3864f2ee7b286d67aca58bd..b34b5ab90a313b77bd0561503d882af311a50c7d 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/debugfs.h>
 #include <linux/workqueue.h>
 #include <linux/kref.h>
+#include <asm/hypfs.h>
 
 #define REG_FILE_MODE    0440
 #define UPDATE_FILE_MODE 0220
@@ -36,6 +37,10 @@ extern int hypfs_vm_init(void);
 extern void hypfs_vm_exit(void);
 extern int hypfs_vm_create_files(struct dentry *root);
 
+/* Set Partition-Resource Parameter */
+int hypfs_sprp_init(void);
+void hypfs_sprp_exit(void);
+
 /* debugfs interface */
 struct hypfs_dbfs_file;
 
@@ -52,6 +57,8 @@ struct hypfs_dbfs_file {
        int             (*data_create)(void **data, void **data_free_ptr,
                                       size_t *size);
        void            (*data_free)(const void *buf_free_ptr);
+       long            (*unlocked_ioctl) (struct file *, unsigned int,
+                                          unsigned long);
 
        /* Private data for hypfs_dbfs.c */
        struct hypfs_dbfs_data  *data;
index 17ab8b7b53cc58074fce7c214caa1e543164d991..2badf2bf9cd74217806129bb5a578ac1fd8e1131 100644 (file)
@@ -81,9 +81,25 @@ static ssize_t dbfs_read(struct file *file, char __user *buf,
        return rc;
 }
 
+static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+       struct hypfs_dbfs_file *df;
+       long rc;
+
+       df = file->f_path.dentry->d_inode->i_private;
+       mutex_lock(&df->lock);
+       if (df->unlocked_ioctl)
+               rc = df->unlocked_ioctl(file, cmd, arg);
+       else
+               rc = -ENOTTY;
+       mutex_unlock(&df->lock);
+       return rc;
+}
+
 static const struct file_operations dbfs_ops = {
        .read           = dbfs_read,
        .llseek         = no_llseek,
+       .unlocked_ioctl = dbfs_ioctl,
 };
 
 int hypfs_dbfs_create_file(struct hypfs_dbfs_file *df)
diff --git a/arch/s390/hypfs/hypfs_sprp.c b/arch/s390/hypfs/hypfs_sprp.c
new file mode 100644 (file)
index 0000000..f043c3c
--- /dev/null
@@ -0,0 +1,141 @@
+/*
+ *    Hypervisor filesystem for Linux on s390.
+ *    Set Partition-Resource Parameter interface.
+ *
+ *    Copyright IBM Corp. 2013
+ *    Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#include <linux/compat.h>
+#include <linux/errno.h>
+#include <linux/gfp.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/uaccess.h>
+#include <asm/compat.h>
+#include <asm/sclp.h>
+#include "hypfs.h"
+
+#define DIAG304_SET_WEIGHTS    0
+#define DIAG304_QUERY_PRP      1
+#define DIAG304_SET_CAPPING    2
+
+#define DIAG304_CMD_MAX                2
+
+static unsigned long hypfs_sprp_diag304(void *data, unsigned long cmd)
+{
+       register unsigned long _data asm("2") = (unsigned long) data;
+       register unsigned long _rc asm("3");
+       register unsigned long _cmd asm("4") = cmd;
+
+       asm volatile("diag %1,%2,0x304\n"
+                    : "=d" (_rc) : "d" (_data), "d" (_cmd) : "memory");
+
+       return _rc;
+}
+
+static void hypfs_sprp_free(const void *data)
+{
+       free_page((unsigned long) data);
+}
+
+static int hypfs_sprp_create(void **data_ptr, void **free_ptr, size_t *size)
+{
+       unsigned long rc;
+       void *data;
+
+       data = (void *) get_zeroed_page(GFP_KERNEL);
+       if (!data)
+               return -ENOMEM;
+       rc = hypfs_sprp_diag304(data, DIAG304_QUERY_PRP);
+       if (rc != 1) {
+               *data_ptr = *free_ptr = NULL;
+               *size = 0;
+               free_page((unsigned long) data);
+               return -EIO;
+       }
+       *data_ptr = *free_ptr = data;
+       *size = PAGE_SIZE;
+       return 0;
+}
+
+static int __hypfs_sprp_ioctl(void __user *user_area)
+{
+       struct hypfs_diag304 diag304;
+       unsigned long cmd;
+       void __user *udata;
+       void *data;
+       int rc;
+
+       if (copy_from_user(&diag304, user_area, sizeof(diag304)))
+               return -EFAULT;
+       if ((diag304.args[0] >> 8) != 0 || diag304.args[1] > DIAG304_CMD_MAX)
+               return -EINVAL;
+
+       data = (void *) get_zeroed_page(GFP_KERNEL | GFP_DMA);
+       if (!data)
+               return -ENOMEM;
+
+       udata = (void __user *)(unsigned long) diag304.data;
+       if (diag304.args[1] == DIAG304_SET_WEIGHTS ||
+           diag304.args[1] == DIAG304_SET_CAPPING)
+               if (copy_from_user(data, udata, PAGE_SIZE)) {
+                       rc = -EFAULT;
+                       goto out;
+               }
+
+       cmd = *(unsigned long *) &diag304.args[0];
+       diag304.rc = hypfs_sprp_diag304(data, cmd);
+
+       if (diag304.args[1] == DIAG304_QUERY_PRP)
+               if (copy_to_user(udata, data, PAGE_SIZE)) {
+                       rc = -EFAULT;
+                       goto out;
+               }
+
+       rc = copy_to_user(user_area, &diag304, sizeof(diag304)) ? -EFAULT : 0;
+out:
+       free_page((unsigned long) data);
+       return rc;
+}
+
+static long hypfs_sprp_ioctl(struct file *file, unsigned int cmd,
+                              unsigned long arg)
+{
+       void __user *argp;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EACCES;
+       if (is_compat_task())
+               argp = compat_ptr(arg);
+       else
+               argp = (void __user *) arg;
+       switch (cmd) {
+       case HYPFS_DIAG304:
+               return __hypfs_sprp_ioctl(argp);
+       default: /* unknown ioctl number */
+               return -ENOTTY;
+       }
+       return 0;
+}
+
+static struct hypfs_dbfs_file hypfs_sprp_file = {
+       .name           = "diag_304",
+       .data_create    = hypfs_sprp_create,
+       .data_free      = hypfs_sprp_free,
+       .unlocked_ioctl = hypfs_sprp_ioctl,
+};
+
+int hypfs_sprp_init(void)
+{
+       if (!sclp_has_sprp())
+               return 0;
+       return hypfs_dbfs_create_file(&hypfs_sprp_file);
+}
+
+void hypfs_sprp_exit(void)
+{
+       if (!sclp_has_sprp())
+               return;
+       hypfs_dbfs_remove_file(&hypfs_sprp_file);
+}
index ddfe09b4513492cd2700d691e61d70ad38f8379b..c952b981e4f28885223c7f77b51ada2299f03c6a 100644 (file)
@@ -478,10 +478,14 @@ static int __init hypfs_init(void)
                rc = -ENODATA;
                goto fail_hypfs_diag_exit;
        }
+       if (hypfs_sprp_init()) {
+               rc = -ENODATA;
+               goto fail_hypfs_vm_exit;
+       }
        s390_kobj = kobject_create_and_add("s390", hypervisor_kobj);
        if (!s390_kobj) {
                rc = -ENOMEM;
-               goto fail_hypfs_vm_exit;
+               goto fail_hypfs_sprp_exit;
        }
        rc = register_filesystem(&hypfs_type);
        if (rc)
@@ -490,6 +494,8 @@ static int __init hypfs_init(void)
 
 fail_filesystem:
        kobject_put(s390_kobj);
+fail_hypfs_sprp_exit:
+       hypfs_sprp_exit();
 fail_hypfs_vm_exit:
        hypfs_vm_exit();
 fail_hypfs_diag_exit:
@@ -502,11 +508,12 @@ fail_dbfs_exit:
 
 static void __exit hypfs_exit(void)
 {
-       hypfs_diag_exit();
-       hypfs_vm_exit();
-       hypfs_dbfs_exit();
        unregister_filesystem(&hypfs_type);
        kobject_put(s390_kobj);
+       hypfs_sprp_exit();
+       hypfs_vm_exit();
+       hypfs_diag_exit();
+       hypfs_dbfs_exit();
 }
 
 module_init(hypfs_init)
index 0f636cbdf3420973f169a591d03614b5f173ca11..4236408070e5f7cb163e1be623627ffc398e677f 100644 (file)
@@ -185,11 +185,12 @@ static inline unsigned long long __cmpxchg64(void *ptr,
 {
        register_pair rp_old = {.pair = old};
        register_pair rp_new = {.pair = new};
+       unsigned long long *ullptr = ptr;
 
        asm volatile(
                "       cds     %0,%2,%1"
-               : "+&d" (rp_old), "=Q" (ptr)
-               : "d" (rp_new), "Q" (ptr)
+               : "+d" (rp_old), "+Q" (*ullptr)
+               : "d" (rp_new)
                : "memory", "cc");
        return rp_old.pair;
 }
index d5bc3750616ebae0c2fedac6be4587238577b3ca..eef3dd3fd9a9f76d105b2c92d266dc5079c7833f 100644 (file)
@@ -106,9 +106,22 @@ struct kvm_s390_sie_block {
        __u64   gbea;                   /* 0x0180 */
        __u8    reserved188[24];        /* 0x0188 */
        __u32   fac;                    /* 0x01a0 */
-       __u8    reserved1a4[92];        /* 0x01a4 */
+       __u8    reserved1a4[68];        /* 0x01a4 */
+       __u64   itdba;                  /* 0x01e8 */
+       __u8    reserved1f0[16];        /* 0x01f0 */
 } __attribute__((packed));
 
+struct kvm_s390_itdb {
+       __u8    data[256];
+} __packed;
+
+struct sie_page {
+       struct kvm_s390_sie_block sie_block;
+       __u8 reserved200[1024];         /* 0x0200 */
+       struct kvm_s390_itdb itdb;      /* 0x0600 */
+       __u8 reserved700[2304];         /* 0x0700 */
+} __packed;
+
 struct kvm_vcpu_stat {
        u32 exit_userspace;
        u32 exit_null;
index 220e171413f857210012d7a09f07dfb904c21a10..abaca2275c7a5acb3f0f730539e4d8d5fd6cd19f 100644 (file)
@@ -54,6 +54,7 @@ int sclp_chp_read_info(struct sclp_chp_info *info);
 void sclp_get_ipl_info(struct sclp_ipl_info *info);
 bool __init sclp_has_linemode(void);
 bool __init sclp_has_vt220(void);
+bool sclp_has_sprp(void);
 int sclp_pci_configure(u32 fid);
 int sclp_pci_deconfigure(u32 fid);
 int memcpy_hsa(void *dest, unsigned long src, size_t count, int mode);
diff --git a/arch/s390/include/uapi/asm/hypfs.h b/arch/s390/include/uapi/asm/hypfs.h
new file mode 100644 (file)
index 0000000..37998b4
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * IOCTL interface for hypfs
+ *
+ * Copyright IBM Corp. 2013
+ *
+ * Author: Martin Schwidefsky <schwidefsky@de.ibm.com>
+ */
+
+#ifndef _ASM_HYPFS_CTL_H
+#define _ASM_HYPFS_CTL_H
+
+#include <linux/types.h>
+
+struct hypfs_diag304 {
+       __u32   args[2];
+       __u64   data;
+       __u64   rc;
+} __attribute__((packed));
+
+#define HYPFS_IOCTL_MAGIC 0x10
+
+#define HYPFS_DIAG304 \
+       _IOWR(HYPFS_IOCTL_MAGIC, 0x20, struct hypfs_diag304)
+
+#endif
index a61d538756f29c9ec6f932aec471c2f74de93e8a..471eb09184d4558ae59963adac953443bc055fbe 100644 (file)
@@ -35,11 +35,11 @@ struct statfs {
 struct statfs64 {
        unsigned int    f_type;
        unsigned int    f_bsize;
-       unsigned long   f_blocks;
-       unsigned long   f_bfree;
-       unsigned long   f_bavail;
-       unsigned long   f_files;
-       unsigned long   f_ffree;
+       unsigned long long f_blocks;
+       unsigned long long f_bfree;
+       unsigned long long f_bavail;
+       unsigned long long f_files;
+       unsigned long long f_ffree;
        __kernel_fsid_t f_fsid;
        unsigned int    f_namelen;
        unsigned int    f_frsize;
index 864f693c237fe440cd02125e588c4b5867b6edb8..5eb5c9ddb120027df003990329a0b7ede4cbfa59 100644 (file)
 #define __NR_s390_runtime_instr 342
 #define __NR_kcmp              343
 #define __NR_finit_module      344
+#define __NR_sched_setattr     345
+#define __NR_sched_getattr     346
 #define NR_syscalls 345
 
 /* 
index e030d2bdec1b6aa2b9f29288b28c6600710ecfd1..db02052bd137254c1c6d46314005ed4fce1a6204 100644 (file)
@@ -286,8 +286,8 @@ asmlinkage long sys32_getegid16(void)
 }
 
 #ifdef CONFIG_SYSVIPC
-COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, unsigned long, second,
-               unsigned long, third, compat_uptr_t, ptr)
+COMPAT_SYSCALL_DEFINE5(s390_ipc, uint, call, int, first, compat_ulong_t, second,
+               compat_ulong_t, third, compat_uptr_t, ptr)
 {
        if (call >> 16)         /* hack for backward compatibility */
                return -EINVAL;
index 9cb1b975b3532f3cc6237ab1cd168146f99a9904..59c8efce1b99b52964950f0933b4934a12b6a9db 100644 (file)
@@ -1412,3 +1412,14 @@ ENTRY(sys_finit_module_wrapper)
        llgtr   %r3,%r3                 # const char __user *
        lgfr    %r4,%r4                 # int
        jg      sys_finit_module
+
+ENTRY(sys_sched_setattr_wrapper)
+       lgfr    %r2,%r2                 # pid_t
+       llgtr   %r3,%r3                 # struct sched_attr __user *
+       jg      sys_sched_setattr
+
+ENTRY(sys_sched_getattr_wrapper)
+       lgfr    %r2,%r2                 # pid_t
+       llgtr   %r3,%r3                 # const char __user *
+       llgfr   %r3,%r3                 # unsigned int
+       jg      sys_sched_getattr
index 913410bd74a335c0693637ccb69e49cb89fd63c1..143992152ec95d7c2b96c1978d1bae78da480efb 100644 (file)
@@ -353,3 +353,5 @@ SYSCALL(sys_process_vm_writev,sys_process_vm_writev,compat_sys_process_vm_writev
 SYSCALL(sys_ni_syscall,sys_s390_runtime_instr,sys_s390_runtime_instr_wrapper)
 SYSCALL(sys_kcmp,sys_kcmp,sys_kcmp_wrapper)
 SYSCALL(sys_finit_module,sys_finit_module,sys_finit_module_wrapper)
+SYSCALL(sys_sched_setattr,sys_sched_setattr,sys_sched_setattr_wrapper) /* 345 */
+SYSCALL(sys_sched_getattr,sys_sched_getattr,sys_sched_getattr_wrapper)
index 5ddbbde6f65c32fde299b9b34adbddfb02c5886d..eeb1ac7d8fa48798a79c18a5015aae5aa372c455 100644 (file)
@@ -112,6 +112,17 @@ static int handle_instruction(struct kvm_vcpu *vcpu)
 static int handle_prog(struct kvm_vcpu *vcpu)
 {
        vcpu->stat.exit_program_interruption++;
+
+       /* Restore ITDB to Program-Interruption TDB in guest memory */
+       if (IS_TE_ENABLED(vcpu) &&
+           !(current->thread.per_flags & PER_FLAG_NO_TE) &&
+           IS_ITDB_VALID(vcpu)) {
+               copy_to_guest(vcpu, TDB_ADDR, vcpu->arch.sie_block->itdba,
+                             sizeof(struct kvm_s390_itdb));
+               memset((void *) vcpu->arch.sie_block->itdba, 0,
+                      sizeof(struct kvm_s390_itdb));
+       }
+
        trace_kvm_s390_intercept_prog(vcpu, vcpu->arch.sie_block->iprcc);
        return kvm_s390_inject_program_int(vcpu, vcpu->arch.sie_block->iprcc);
 }
index 7635c00a1479428b295e044d57e514abdce86b3d..e0676f390d57d22aeaf991a95c0a7d0e3458d369 100644 (file)
@@ -395,6 +395,9 @@ int kvm_arch_vcpu_setup(struct kvm_vcpu *vcpu)
                                                    CPUSTAT_STOPPED |
                                                    CPUSTAT_GED);
        vcpu->arch.sie_block->ecb   = 6;
+       if (test_vfacility(50) && test_vfacility(73))
+               vcpu->arch.sie_block->ecb |= 0x10;
+
        vcpu->arch.sie_block->ecb2  = 8;
        vcpu->arch.sie_block->eca   = 0xC1002001U;
        vcpu->arch.sie_block->fac   = (int) (long) vfacilities;
@@ -411,6 +414,7 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
                                      unsigned int id)
 {
        struct kvm_vcpu *vcpu;
+       struct sie_page *sie_page;
        int rc = -EINVAL;
 
        if (id >= KVM_MAX_VCPUS)
@@ -422,12 +426,13 @@ struct kvm_vcpu *kvm_arch_vcpu_create(struct kvm *kvm,
        if (!vcpu)
                goto out;
 
-       vcpu->arch.sie_block = (struct kvm_s390_sie_block *)
-                                       get_zeroed_page(GFP_KERNEL);
-
-       if (!vcpu->arch.sie_block)
+       sie_page = (struct sie_page *) get_zeroed_page(GFP_KERNEL);
+       if (!sie_page)
                goto out_free_cpu;
 
+       vcpu->arch.sie_block = &sie_page->sie_block;
+       vcpu->arch.sie_block->itdba = (unsigned long) &sie_page->itdb;
+
        vcpu->arch.sie_block->icpua = id;
        if (!kvm_is_ucontrol(kvm)) {
                if (!kvm->arch.sca) {
@@ -1182,8 +1187,8 @@ static int __init kvm_s390_init(void)
                return -ENOMEM;
        }
        memcpy(vfacilities, S390_lowcore.stfle_fac_list, 16);
-       vfacilities[0] &= 0xff82fff3f47c0000UL;
-       vfacilities[1] &= 0x001c000000000000UL;
+       vfacilities[0] &= 0xff82fff3f4fc2000UL;
+       vfacilities[1] &= 0x005c000000000000UL;
        return 0;
 }
 
index 095cf51b16ec5965feb06c08aba33becafa7fae2..f9559b0bd620962d095851fc5c884a759b49996c 100644 (file)
@@ -26,6 +26,12 @@ extern unsigned long *vfacilities;
 
 int kvm_handle_sie_intercept(struct kvm_vcpu *vcpu);
 
+/* Transactional Memory Execution related macros */
+#define IS_TE_ENABLED(vcpu)    ((vcpu->arch.sie_block->ecb & 0x10))
+#define TDB_ADDR               0x1800UL
+#define TDB_FORMAT1            1
+#define IS_ITDB_VALID(vcpu)    ((*(char *)vcpu->arch.sie_block->itdba == TDB_FORMAT1))
+
 #define VM_EVENT(d_kvm, d_loglevel, d_string, d_args...)\
 do { \
        debug_sprintf_event(d_kvm->arch.dbf, d_loglevel, d_string "\n", \
index 315dbe09983e518b06326b2f730c45a176a57aa5..b1a22173d027b9bde6774194631d635932bc42ff 100644 (file)
@@ -6,15 +6,6 @@
 #ifndef __ARCH_S390_LIB_UACCESS_H
 #define __ARCH_S390_LIB_UACCESS_H
 
-extern size_t copy_from_user_std(size_t, const void __user *, void *);
-extern size_t copy_to_user_std(size_t, void __user *, const void *);
-extern size_t strnlen_user_std(size_t, const char __user *);
-extern size_t strncpy_from_user_std(size_t, const char __user *, char *);
-extern int futex_atomic_cmpxchg_std(u32 *, u32 __user *, u32, u32);
-extern int futex_atomic_op_std(int, u32 __user *, int, int *);
-
-extern size_t copy_from_user_pt(size_t, const void __user *, void *);
-extern size_t copy_to_user_pt(size_t, void __user *, const void *);
 extern int futex_atomic_op_pt(int, u32 __user *, int, int *);
 extern int futex_atomic_cmpxchg_pt(u32 *, u32 __user *, u32, u32);
 
index 0632dc50da78b88557ca61c766b29bccbb30a64d..61ebcc9ccb3472abe320fd8ed4939b4cc5074ebe 100644 (file)
@@ -153,6 +153,8 @@ static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr,
        unsigned long offset, done, size, kaddr;
        void *from, *to;
 
+       if (!mm)
+               return n;
        done = 0;
 retry:
        spin_lock(&mm->page_table_lock);
@@ -209,7 +211,7 @@ fault:
        return 0;
 }
 
-size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
+static size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
 {
        size_t rc;
 
@@ -221,7 +223,7 @@ size_t copy_from_user_pt(size_t n, const void __user *from, void *to)
        return rc;
 }
 
-size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
+static size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
 {
        if (segment_eq(get_fs(), KERNEL_DS))
                return copy_in_kernel(n, to, (void __user *) from);
@@ -262,6 +264,8 @@ static size_t strnlen_user_pt(size_t count, const char __user *src)
                return 0;
        if (segment_eq(get_fs(), KERNEL_DS))
                return strnlen_kernel(count, src);
+       if (!mm)
+               return 0;
        done = 0;
 retry:
        spin_lock(&mm->page_table_lock);
@@ -323,6 +327,8 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
 
        if (segment_eq(get_fs(), KERNEL_DS))
                return copy_in_kernel(n, to, from);
+       if (!mm)
+               return n;
        done = 0;
 retry:
        spin_lock(&mm->page_table_lock);
@@ -411,6 +417,8 @@ int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old)
 
        if (segment_eq(get_fs(), KERNEL_DS))
                return __futex_atomic_op_pt(op, uaddr, oparg, old);
+       if (unlikely(!current->mm))
+               return -EFAULT;
        spin_lock(&current->mm->page_table_lock);
        uaddr = (u32 __force __user *)
                __dat_user_addr((__force unsigned long) uaddr, 1);
@@ -448,6 +456,8 @@ int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr,
 
        if (segment_eq(get_fs(), KERNEL_DS))
                return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval);
+       if (unlikely(!current->mm))
+               return -EFAULT;
        spin_lock(&current->mm->page_table_lock);
        uaddr = (u32 __force __user *)
                __dat_user_addr((__force unsigned long) uaddr, 1);
index 706157edc7d54698ee7cd8748c2389f773edf512..1141f2b4a50186858f6889c74ae3b88867ec2020 100644 (file)
@@ -137,7 +137,7 @@ ENTRY(csum_partial)
        ldi r25, 0
        mv r10, r5
        cmpi.c  r5, 0x8
-       blt     small_csumcpy           /* < 8(singed) bytes to copy */
+       blt     small_csumcpy           /* < 8(signed) bytes to copy */
        cmpi.c  r5, 0x0
        beq     out
        andri.c r25, src, 0x1           /* odd buffer? */
index 62ced589bcf78f1554bcadd4f420fad19c7ebcc1..b73274fb961a27a9b54eb5fd1719650762fef305 100644 (file)
 #define __NR_kern_features     340
 #define __NR_kcmp              341
 #define __NR_finit_module      342
+#define __NR_sched_setattr     343
+#define __NR_sched_getattr     344
 
-#define NR_syscalls            343
+#define NR_syscalls            345
 
 /* Bitmask values returned from kern_features system call.  */
 #define KERN_FEATURE_MIXED_MODE_STACK  0x00000001
index cb5d272d658acce52fc85a77b1e730a40c5d885a..de1c844dfabc02569cfe71c91b3e52a9ea705ef4 100644 (file)
@@ -6,7 +6,6 @@
 #include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/cpumask.h>
 #include <linux/spinlock.h>
 #include <asm/cpudata.h>
index e306fb08ee5e1fab217823321460d94deac5cb75..acf8314cec489d1beec128ce5d3d422f53554231 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/export.h>
 #include <linux/kernel.h>
 #include <linux/types.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
index 4eb1a5a1d5440642aefbef171c527767cc722063..b7ddcdd1dea943a9f5e768c006547a3e7737d4f7 100644 (file)
@@ -3,7 +3,6 @@
  * Copyright (C) 2007, 2008 David S. Miller <davem@davemloft.net>
  */
 
-#include <linux/init.h>
 
 #include <asm/thread_info.h>
 #include <asm/hypervisor.h>
index de199bf0cb051c6e695296d8b8ab392efd00c7c6..3241f56331c2aced51e918aa9dde9ef936e54e7c 100644 (file)
@@ -1,7 +1,6 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/of.h>
-#include <linux/init.h>
 #include <linux/export.h>
 #include <linux/mod_devicetable.h>
 #include <linux/errno.h>
index 7de8d1f590b7fbb7023c6d455b2a079714051bc7..1555bbcae1eee617fecd7cbecaa78eb5d6ab2ca8 100644 (file)
@@ -1005,6 +1005,5 @@ static int __init of_pci_slot_init(void)
 
        return 0;
 }
-
-module_init(of_pci_slot_init);
+device_initcall(of_pci_slot_init);
 #endif
index a6895987fb70254b7db258c2eff6fd65262aba46..944a06536ecc129ab81c9e758a6f89b92d3091fe 100644 (file)
@@ -5,7 +5,6 @@
 
 #include <linux/string.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/device.h>
 #include <linux/of_device.h>
index fdd819dfdacf2057474d6e09f590d7617eaf9cb2..510baec1b69b2ca79d3f9e8687520e1b0b541b91 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/reboot.h>
 #include <linux/delay.h>
 #include <linux/pm.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 
 #include <asm/auxio.h>
index e521c54560f9dffa74e1057dc9480ead73aea2df..bf4ccb10a78c600ac48cba552cb1794836b094bf 100644 (file)
@@ -6,7 +6,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 
 #include <asm/pgtable.h>
 #include <asm/uaccess.h>
index 9f5e24ddcc70b0b10240f2a476b34610e011023b..a92d5d2c46a3a6553bf13a57f95f65c6d61c334c 100644 (file)
@@ -7,7 +7,6 @@
 
 #include <linux/export.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/bitops.h>
 
 #include <asm/cpudata.h>
index 7b87171ecf1e91803ce0a3908c629118d205c020..151ace8766cc2d99d5be3552a4b2014eb74fdaa6 100644 (file)
@@ -85,4 +85,4 @@ sys_call_table:
 /*325*/        .long sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .long sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
 /*335*/        .long sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
-/*340*/        .long sys_ni_syscall, sys_kcmp, sys_finit_module
+/*340*/        .long sys_ni_syscall, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
index 6d81597064b6b5c7efa0861fc6c5c230e3c4984f..4bd4e2bb26cf4d35a8980f1a9040cdd88a645a4a 100644 (file)
@@ -86,7 +86,7 @@ sys_call_table32:
        .word compat_sys_pwritev, compat_sys_rt_tgsigqueueinfo, sys_perf_event_open, compat_sys_recvmmsg, sys_fanotify_init
 /*330*/        .word compat_sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, compat_sys_open_by_handle_at, compat_sys_clock_adjtime
        .word sys_syncfs, compat_sys_sendmmsg, sys_setns, compat_sys_process_vm_readv, compat_sys_process_vm_writev
-/*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module
+/*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
 
 #endif /* CONFIG_COMPAT */
 
@@ -164,4 +164,4 @@ sys_call_table:
        .word sys_pwritev, sys_rt_tgsigqueueinfo, sys_perf_event_open, sys_recvmmsg, sys_fanotify_init
 /*330*/        .word sys_fanotify_mark, sys_prlimit64, sys_name_to_handle_at, sys_open_by_handle_at, sys_clock_adjtime
        .word sys_syncfs, sys_sendmmsg, sys_setns, sys_process_vm_readv, sys_process_vm_writev
-/*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module
+/*340*/        .word sys_kern_features, sys_kcmp, sys_finit_module, sys_sched_setattr, sys_sched_getattr
index 76dcbd3c988aed9445de17442e8cb1076ef5cc49..3eed99fc69892f40c34e2865895928c35b78067f 100644 (file)
@@ -5,7 +5,6 @@
  * Copyright (C) 1998 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
-#include <linux/init.h>
 #include <asm/head.h>
 #include <asm/psr.h>
 #include <asm/page.h>
index ad4bde3bb61e6763df6baf6c44b9b0f7be921f7b..737f8cbc7d56cda4e4afbdb1c7166c4fcaad3ece 100644 (file)
@@ -4,7 +4,6 @@
  * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu)
  */
 
-#include <linux/init.h>
 
 #include <asm/head.h>
 #include <asm/asi.h>
index 30963178d7e940f4afe02ed86bc936020dd1ec8a..9bd9ce80bf77eb46605942278dd4c1fe72fa4da0 100644 (file)
@@ -4,7 +4,6 @@
  * Copyright (C) 2002, 2003, 2006 David S. Miller (davem@davemloft.net)
  */
 
-#include <linux/init.h>
 #include <linux/fs.h>
 #include <linux/mm.h>
 #include <linux/hugetlb.h>
index ad3bf4b4324d94f10504947bd88b2dea93a44b2e..b12cb5e72812140688d771ed0788b6a2cf2cfc16 100644 (file)
@@ -4,7 +4,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/percpu.h>
 #include <linux/mm.h>
 #include <linux/swap.h>
index 04a4540509dd87d5c533938810eaebeb55a21edf..e58b817263199f9d45d28aed5f735b38eb94904b 100644 (file)
@@ -5,7 +5,6 @@
  */
 
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/smp.h>
 #include <linux/string.h>
index 9be0d5d02a9a7681ab00cd21aa2272449336d8fa..f2f6323c8d64e4bdec2b9864a152244e5b33a8d3 100644 (file)
@@ -35,17 +35,11 @@ static struct console early_ocd_console = {
 
 static int __init setup_early_printk(char *buf)
 {
-       int keep_early;
-
        if (!buf || early_console)
                return 0;
 
-       if (strstr(buf, "keep"))
-               keep_early = 1;
-
        early_console = &early_ocd_console;
-
-       if (keep_early)
+       if (strstr(buf, "keep"))
                early_console->flags &= ~CON_BOOT;
        else
                early_console->flags |= CON_BOOT;
index 13b22e0f681dbeff951dde5055e7f594778a98a1..eeda43abed6ec8d48837abaa5f6c18a40c38785a 100644 (file)
@@ -11,6 +11,28 @@ else
         KBUILD_DEFCONFIG := $(ARCH)_defconfig
 endif
 
+# How to compile the 16-bit code.  Note we always compile for -march=i386;
+# that way we can complain to the user if the CPU is insufficient.
+#
+# The -m16 option is supported by GCC >= 4.9 and clang >= 3.5. For
+# older versions of GCC, we need to play evil and unreliable tricks to
+# attempt to ensure that our asm(".code16gcc") is first in the asm
+# output.
+CODE16GCC_CFLAGS := -m32 -include $(srctree)/arch/x86/boot/code16gcc.h \
+                   $(call cc-option, -fno-toplevel-reorder,\
+                     $(call cc-option, -fno-unit-at-a-time))
+M16_CFLAGS      := $(call cc-option, -m16, $(CODE16GCC_CFLAGS))
+
+REALMODE_CFLAGS        := $(M16_CFLAGS) -g -Os -D__KERNEL__ \
+                  -DDISABLE_BRANCH_PROFILING \
+                  -Wall -Wstrict-prototypes -march=i386 -mregparm=3 \
+                  -fno-strict-aliasing -fomit-frame-pointer -fno-pic \
+                  -mno-mmx -mno-sse \
+                  $(call cc-option, -ffreestanding) \
+                  $(call cc-option, -fno-stack-protector) \
+                  $(call cc-option, -mpreferred-stack-boundary=2)
+export REALMODE_CFLAGS
+
 # BITS is used as extension for files which are available in a 32 bit
 # and a 64 bit version to simplify shared Makefiles.
 # e.g.: obj-y += foo_$(BITS).o
index de70669180052163de7a34a21e92302b4c50128e..878df7e88cd4d9c4293d9540432fdd3d7c78fc6e 100644 (file)
@@ -51,20 +51,7 @@ $(obj)/cpustr.h: $(obj)/mkcpustr FORCE
 
 # ---------------------------------------------------------------------------
 
-# How to compile the 16-bit code.  Note we always compile for -march=i386,
-# that way we can complain to the user if the CPU is insufficient.
-KBUILD_CFLAGS  := $(USERINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ \
-                  -DDISABLE_BRANCH_PROFILING \
-                  -Wall -Wstrict-prototypes \
-                  -march=i386 -mregparm=3 \
-                  -include $(srctree)/$(src)/code16gcc.h \
-                  -fno-strict-aliasing -fomit-frame-pointer -fno-pic \
-                  -mno-mmx -mno-sse \
-                  $(call cc-option, -ffreestanding) \
-                  $(call cc-option, -fno-toplevel-reorder,\
-                  $(call cc-option, -fno-unit-at-a-time)) \
-                  $(call cc-option, -fno-stack-protector) \
-                  $(call cc-option, -mpreferred-stack-boundary=2)
+KBUILD_CFLAGS  := $(USERINCLUDE) $(REALMODE_CFLAGS) -D_SETUP
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 GCOV_PROFILE := n
 
index a9fcb7cfb2411fb64034f14dd1185b3b263eac2a..431fa5f84537d1f8019ac2f23c4c01e0573ab955 100644 (file)
@@ -28,20 +28,35 @@ static int has_fpu(void)
        return fsw == 0 && (fcw & 0x103f) == 0x003f;
 }
 
+/*
+ * For building the 16-bit code we want to explicitly specify 32-bit
+ * push/pop operations, rather than just saying 'pushf' or 'popf' and
+ * letting the compiler choose. But this is also included from the
+ * compressed/ directory where it may be 64-bit code, and thus needs
+ * to be 'pushfq' or 'popfq' in that case.
+ */
+#ifdef __x86_64__
+#define PUSHF "pushfq"
+#define POPF "popfq"
+#else
+#define PUSHF "pushfl"
+#define POPF "popfl"
+#endif
+
 int has_eflag(unsigned long mask)
 {
        unsigned long f0, f1;
 
-       asm volatile("pushf     \n\t"
-                    "pushf     \n\t"
+       asm volatile(PUSHF "    \n\t"
+                    PUSHF "    \n\t"
                     "pop %0    \n\t"
                     "mov %0,%1 \n\t"
                     "xor %2,%1 \n\t"
                     "push %1   \n\t"
-                    "popf      \n\t"
-                    "pushf     \n\t"
+                    POPF "     \n\t"
+                    PUSHF "    \n\t"
                     "pop %1    \n\t"
-                    "popf"
+                    POPF
                     : "=&r" (f0), "=&r" (f1)
                     : "ri" (mask));
 
index ff339c5db31127c7db4e27d9e16c32d1d3d0753d..0bb25491262d00f941001d3f7f7b2fc800212250 100644 (file)
@@ -80,7 +80,7 @@ struct card_info {
        u16 xmode_n;            /* Size of unprobed mode range */
 };
 
-#define __videocard struct card_info __attribute__((section(".videocards")))
+#define __videocard struct card_info __attribute__((used,section(".videocards")))
 extern struct card_info video_cards[], video_cards_end[];
 
 int mode_defined(u16 mode);    /* video.c */
index 1df115909758862d8e664d86594a4d02e2c72f8c..c7678e43465bd64a3750bb912b9abc7984ac54cd 100644 (file)
@@ -85,28 +85,9 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
        return ret;
 }
 
-static inline uint32_t kvm_cpuid_base(void)
-{
-       if (boot_cpu_data.cpuid_level < 0)
-               return 0;       /* So we don't blow up on old processors */
-
-       if (cpu_has_hypervisor)
-               return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0);
-
-       return 0;
-}
-
-static inline bool kvm_para_available(void)
-{
-       return kvm_cpuid_base() != 0;
-}
-
-static inline unsigned int kvm_arch_para_features(void)
-{
-       return cpuid_eax(KVM_CPUID_FEATURES);
-}
-
 #ifdef CONFIG_KVM_GUEST
+bool kvm_para_available(void);
+unsigned int kvm_arch_para_features(void);
 void __init kvm_guest_init(void);
 void kvm_async_pf_task_wait(u32 token);
 void kvm_async_pf_task_wake(u32 token);
@@ -126,6 +107,16 @@ static inline void kvm_spinlock_init(void)
 #define kvm_async_pf_task_wait(T) do {} while(0)
 #define kvm_async_pf_task_wake(T) do {} while(0)
 
+static inline bool kvm_para_available(void)
+{
+       return 0;
+}
+
+static inline unsigned int kvm_arch_para_features(void)
+{
+       return 0;
+}
+
 static inline u32 kvm_read_and_reset_pf_reason(void)
 {
        return 0;
index 2f59cce3b38aaabb83efe9c528ffbfc7ea9ae8d8..f97fbe3abb67f5059d4e6f0a37261d6113df19de 100644 (file)
@@ -51,9 +51,9 @@ extern int devmem_is_allowed(unsigned long pagenr);
 extern unsigned long max_low_pfn_mapped;
 extern unsigned long max_pfn_mapped;
 
-static inline phys_addr_t get_max_low_mapped(void)
+static inline phys_addr_t get_max_mapped(void)
 {
-       return (phys_addr_t)max_low_pfn_mapped << PAGE_SHIFT;
+       return (phys_addr_t)max_pfn_mapped << PAGE_SHIFT;
 }
 
 bool pfn_range_is_mapped(unsigned long start_pfn, unsigned long end_pfn);
index 401f350ef71b90b41c2f6d1916659612aa89c950..cd6e1610e29ee0410afd1159829db85d30ac26a3 100644 (file)
@@ -781,9 +781,9 @@ static __always_inline void __ticket_unlock_kick(struct arch_spinlock *lock,
  */
 #define PV_CALLEE_SAVE_REGS_THUNK(func)                                        \
        extern typeof(func) __raw_callee_save_##func;                   \
-       static void *__##func##__ __used = func;                        \
                                                                        \
        asm(".pushsection .text;"                                       \
+           ".globl __raw_callee_save_" #func " ; "                     \
            "__raw_callee_save_" #func ": "                             \
            PV_SAVE_ALL_CALLER_REGS                                     \
            "call " #func ";"                                           \
index aab8f671b523f7801608c880225558d425889061..7549b8b369e47cf540d5dbb747b870ab42eb5b6a 100644 (file)
@@ -388,10 +388,11 @@ extern struct pv_lock_ops pv_lock_ops;
        _paravirt_alt(insn_string, "%c[paravirt_typenum]", "%c[paravirt_clobber]")
 
 /* Simple instruction patching code. */
-#define DEF_NATIVE(ops, name, code)                                    \
-       extern const char start_##ops##_##name[] __visible,             \
-                         end_##ops##_##name[] __visible;               \
-       asm("start_" #ops "_" #name ": " code "; end_" #ops "_" #name ":")
+#define NATIVE_LABEL(a,x,b) "\n\t.globl " a #x "_" #b "\n" a #x "_" #b ":\n\t"
+
+#define DEF_NATIVE(ops, name, code)                                    \
+       __visible extern const char start_##ops##_##name[], end_##ops##_##name[];       \
+       asm(NATIVE_LABEL("start_", ops, name) code NATIVE_LABEL("end_", ops, name))
 
 unsigned paravirt_patch_nop(void);
 unsigned paravirt_patch_ident_32(void *insnbuf, unsigned len);
index a83aa44bb1fb831cac7cda82a590c05ea0e47235..1aa9ccd432236af7d5667657e4267c3a8ba218f6 100644 (file)
 
 /* Set of bits not changed in pte_modify */
 #define _PAGE_CHG_MASK (PTE_PFN_MASK | _PAGE_PCD | _PAGE_PWT |         \
-                        _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY)
+                        _PAGE_SPECIAL | _PAGE_ACCESSED | _PAGE_DIRTY | \
+                        _PAGE_SOFT_DIRTY)
 #define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE)
 
 #define _PAGE_CACHE_MASK       (_PAGE_PCD | _PAGE_PWT)
index 3ba3de457d053e77eb36d7d6fe78f7769a1df470..e1940c06ed022d8b9ad7988aaf76970afc92c4b5 100644 (file)
@@ -163,9 +163,11 @@ struct thread_info {
  */
 #ifndef __ASSEMBLY__
 
-
-/* how to get the current stack pointer from C */
-register unsigned long current_stack_pointer asm("esp") __used;
+#define current_stack_pointer ({               \
+       unsigned long sp;                       \
+       asm("mov %%esp,%0" : "=g" (sp));        \
+       sp;                                     \
+})
 
 /* how to get the thread information struct from C */
 static inline struct thread_info *current_thread_info(void)
index 6b964a0b86d1bb5581e830fef85678a71d837837..062921ef34e9136100d3b4820826642dd45f223b 100644 (file)
@@ -12,7 +12,6 @@ extern enum uv_system_type get_uv_system_type(void);
 extern int is_uv_system(void);
 extern void uv_cpu_init(void);
 extern void uv_nmi_init(void);
-extern void uv_register_nmi_notifier(void);
 extern void uv_system_init(void);
 extern const struct cpumask *uv_flush_tlb_others(const struct cpumask *cpumask,
                                                 struct mm_struct *mm,
@@ -26,7 +25,6 @@ static inline enum uv_system_type get_uv_system_type(void) { return UV_NONE; }
 static inline int is_uv_system(void)   { return 0; }
 static inline void uv_cpu_init(void)   { }
 static inline void uv_system_init(void)        { }
-static inline void uv_register_nmi_notifier(void) { }
 static inline const struct cpumask *
 uv_flush_tlb_others(const struct cpumask *cpumask, struct mm_struct *mm,
                    unsigned long start, unsigned long end, unsigned int cpu)
index 3e276eb23d1bd7c315f055ecfcb551b0cd5ed1b8..787e1bb5aafcfb27b6579eeb56ba62cd2c3f1abe 100644 (file)
@@ -52,7 +52,8 @@ extern unsigned long set_phys_range_identity(unsigned long pfn_s,
 extern int m2p_add_override(unsigned long mfn, struct page *page,
                            struct gnttab_map_grant_ref *kmap_op);
 extern int m2p_remove_override(struct page *page,
-                               struct gnttab_map_grant_ref *kmap_op);
+                              struct gnttab_map_grant_ref *kmap_op,
+                              unsigned long mfn);
 extern struct page *m2p_find_override(unsigned long mfn);
 extern unsigned long m2p_find_override_pfn(unsigned long mfn, unsigned long pfn);
 
@@ -121,7 +122,7 @@ static inline unsigned long mfn_to_pfn(unsigned long mfn)
                pfn = m2p_find_override_pfn(mfn, ~0);
        }
 
-       /* 
+       /*
         * pfn is ~0 if there are no entries in the m2p for mfn or if the
         * entry doesn't map back to the mfn and m2p_override doesn't have a
         * valid entry for it.
index ee50c801f7b7eda1d4ea2aeea1f99cfaf1b03ccd..cc2d6a3aeae7ed24e9fd1d7e8e69204f1a0bc4e4 100644 (file)
 struct semid64_ds {
        struct ipc64_perm sem_perm;     /* permissions .. see ipc.h */
        __kernel_time_t sem_otime;      /* last semop time */
-       unsigned long   __unused1;
+       __kernel_ulong_t __unused1;
        __kernel_time_t sem_ctime;      /* last change time */
-       unsigned long   __unused2;
-       unsigned long   sem_nsems;      /* no. of semaphores in array */
-       unsigned long   __unused3;
-       unsigned long   __unused4;
+       __kernel_ulong_t __unused2;
+       __kernel_ulong_t sem_nsems;     /* no. of semaphores in array */
+       __kernel_ulong_t __unused3;
+       __kernel_ulong_t __unused4;
 };
 
 #endif /* _ASM_X86_SEMBUF_H */
index ad0dc0428baf8cc4550f339f78e4552ef40020fb..d263b1307de1e5b30a114cc0f37c017197d5728f 100644 (file)
@@ -980,7 +980,6 @@ void __init uv_system_init(void)
        uv_nmi_setup();
        uv_cpu_init();
        uv_scir_register_cpu_notifier();
-       uv_register_nmi_notifier();
        proc_mkdir("sgi_uv", NULL);
 
        /* register Legacy VGA I/O redirection handler */
index 6dd802c6d7806c68741b73534029b85a6e1c5cb7..713f1b3bad52a6478d65a153e986b4b533dff801 100644 (file)
@@ -500,6 +500,38 @@ void __init kvm_guest_init(void)
 #endif
 }
 
+static noinline uint32_t __kvm_cpuid_base(void)
+{
+       if (boot_cpu_data.cpuid_level < 0)
+               return 0;       /* So we don't blow up on old processors */
+
+       if (cpu_has_hypervisor)
+               return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0);
+
+       return 0;
+}
+
+static inline uint32_t kvm_cpuid_base(void)
+{
+       static int kvm_cpuid_base = -1;
+
+       if (kvm_cpuid_base == -1)
+               kvm_cpuid_base = __kvm_cpuid_base();
+
+       return kvm_cpuid_base;
+}
+
+bool kvm_para_available(void)
+{
+       return kvm_cpuid_base() != 0;
+}
+EXPORT_SYMBOL_GPL(kvm_para_available);
+
+unsigned int kvm_arch_para_features(void)
+{
+       return cpuid_eax(kvm_cpuid_base() | KVM_CPUID_FEATURES);
+}
+
 static uint32_t __init kvm_detect(void)
 {
        return kvm_cpuid_base();
@@ -673,7 +705,7 @@ static cpumask_t waiting_cpus;
 /* Track spinlock on which a cpu is waiting */
 static DEFINE_PER_CPU(struct kvm_lock_waiting, klock_waiting);
 
-static void kvm_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
+__visible void kvm_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
 {
        struct kvm_lock_waiting *w;
        int cpu;
index c9675594d7caee907fd6fd78559fe14bf1aea036..06853e6703541f8349106e17330f86621fa984db 100644 (file)
@@ -1119,7 +1119,7 @@ void __init setup_arch(char **cmdline_p)
 
        setup_real_mode();
 
-       memblock_set_current_limit(get_max_low_mapped());
+       memblock_set_current_limit(get_max_mapped());
        dma_contiguous_reserve(0);
 
        /*
index 992f890283e9260980349ff128f33446f339810a..f6584a90aba346566d38b6df763a9b0669fd733f 100644 (file)
@@ -33,7 +33,7 @@
  * and vice versa.
  */
 
-static unsigned long vsmp_save_fl(void)
+asmlinkage unsigned long vsmp_save_fl(void)
 {
        unsigned long flags = native_save_fl();
 
@@ -43,7 +43,7 @@ static unsigned long vsmp_save_fl(void)
 }
 PV_CALLEE_SAVE_REGS_THUNK(vsmp_save_fl);
 
-static void vsmp_restore_fl(unsigned long flags)
+__visible void vsmp_restore_fl(unsigned long flags)
 {
        if (flags & X86_EFLAGS_IF)
                flags &= ~X86_EFLAGS_AC;
@@ -53,7 +53,7 @@ static void vsmp_restore_fl(unsigned long flags)
 }
 PV_CALLEE_SAVE_REGS_THUNK(vsmp_restore_fl);
 
-static void vsmp_irq_disable(void)
+asmlinkage void vsmp_irq_disable(void)
 {
        unsigned long flags = native_save_fl();
 
@@ -61,7 +61,7 @@ static void vsmp_irq_disable(void)
 }
 PV_CALLEE_SAVE_REGS_THUNK(vsmp_irq_disable);
 
-static void vsmp_irq_enable(void)
+asmlinkage void vsmp_irq_enable(void)
 {
        unsigned long flags = native_save_fl();
 
index f1e4895174b2472da123b8b74cbee2460b239ccf..a2a1bb7ed8c1b32677db62d4f5bf4303cd1cb9b2 100644 (file)
@@ -72,4 +72,12 @@ static inline bool guest_cpuid_has_pcid(struct kvm_vcpu *vcpu)
        return best && (best->ecx & bit(X86_FEATURE_PCID));
 }
 
+static inline bool guest_cpuid_has_x2apic(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpuid_entry2 *best;
+
+       best = kvm_find_cpuid_entry(vcpu, 1, 0);
+       return best && (best->ecx & bit(X86_FEATURE_X2APIC));
+}
+
 #endif
index c8b0d0d2da5ce2d67f9342fba000e60e1aec84eb..6a11845fd8b94435a383823a1e559ba153dbaaca 100644 (file)
@@ -65,7 +65,7 @@ bool kvm_irq_delivery_to_apic_fast(struct kvm *kvm, struct kvm_lapic *src,
                struct kvm_lapic_irq *irq, int *r, unsigned long *dest_map);
 
 u64 kvm_get_apic_base(struct kvm_vcpu *vcpu);
-void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
+int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info);
 void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu,
                struct kvm_lapic_state *s);
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
index 5c8879127cfa8dbd0327768b9068680d75657285..a06f101ef64b4ae43e954319bbaa81a5c24c326b 100644 (file)
@@ -4392,7 +4392,7 @@ static int vmx_vcpu_setup(struct vcpu_vmx *vmx)
 static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
 {
        struct vcpu_vmx *vmx = to_vmx(vcpu);
-       u64 msr;
+       struct msr_data apic_base_msr;
 
        vmx->rmode.vm86_active = 0;
 
@@ -4400,10 +4400,11 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu)
 
        vmx->vcpu.arch.regs[VCPU_REGS_RDX] = get_rdx_init_val();
        kvm_set_cr8(&vmx->vcpu, 0);
-       msr = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
+       apic_base_msr.data = 0xfee00000 | MSR_IA32_APICBASE_ENABLE;
        if (kvm_vcpu_is_bsp(&vmx->vcpu))
-               msr |= MSR_IA32_APICBASE_BSP;
-       kvm_set_apic_base(&vmx->vcpu, msr);
+               apic_base_msr.data |= MSR_IA32_APICBASE_BSP;
+       apic_base_msr.host_initiated = true;
+       kvm_set_apic_base(&vmx->vcpu, &apic_base_msr);
 
        vmx_segment_cache_clear(vmx);
 
index 0c76f7cfdb32c0f9161ea08427f9144d332eaca5..39c28f09dfd5f03ca064be4bb5cfa01eb0d673a4 100644 (file)
@@ -257,10 +257,26 @@ u64 kvm_get_apic_base(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_get_apic_base);
 
-void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data)
-{
-       /* TODO: reserve bits check */
-       kvm_lapic_set_base(vcpu, data);
+int kvm_set_apic_base(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
+{
+       u64 old_state = vcpu->arch.apic_base &
+               (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE);
+       u64 new_state = msr_info->data &
+               (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE);
+       u64 reserved_bits = ((~0ULL) << cpuid_maxphyaddr(vcpu)) |
+               0x2ff | (guest_cpuid_has_x2apic(vcpu) ? 0 : X2APIC_ENABLE);
+
+       if (!msr_info->host_initiated &&
+           ((msr_info->data & reserved_bits) != 0 ||
+            new_state == X2APIC_ENABLE ||
+            (new_state == MSR_IA32_APICBASE_ENABLE &&
+             old_state == (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)) ||
+            (new_state == (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE) &&
+             old_state == 0)))
+               return 1;
+
+       kvm_lapic_set_base(vcpu, msr_info->data);
+       return 0;
 }
 EXPORT_SYMBOL_GPL(kvm_set_apic_base);
 
@@ -1840,6 +1856,7 @@ static int set_msr_hyperv_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data)
                if (__copy_to_user((void __user *)addr, instructions, 4))
                        return 1;
                kvm->arch.hv_hypercall = data;
+               mark_page_dirty(kvm, gfn);
                break;
        }
        case HV_X64_MSR_REFERENCE_TSC: {
@@ -1868,19 +1885,21 @@ static int set_msr_hyperv(struct kvm_vcpu *vcpu, u32 msr, u64 data)
 {
        switch (msr) {
        case HV_X64_MSR_APIC_ASSIST_PAGE: {
+               u64 gfn;
                unsigned long addr;
 
                if (!(data & HV_X64_MSR_APIC_ASSIST_PAGE_ENABLE)) {
                        vcpu->arch.hv_vapic = data;
                        break;
                }
-               addr = gfn_to_hva(vcpu->kvm, data >>
-                                 HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT);
+               gfn = data >> HV_X64_MSR_APIC_ASSIST_PAGE_ADDRESS_SHIFT;
+               addr = gfn_to_hva(vcpu->kvm, gfn);
                if (kvm_is_error_hva(addr))
                        return 1;
                if (__clear_user((void __user *)addr, PAGE_SIZE))
                        return 1;
                vcpu->arch.hv_vapic = data;
+               mark_page_dirty(vcpu->kvm, gfn);
                break;
        }
        case HV_X64_MSR_EOI:
@@ -2006,8 +2025,7 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
        case 0x200 ... 0x2ff:
                return set_msr_mtrr(vcpu, msr, data);
        case MSR_IA32_APICBASE:
-               kvm_set_apic_base(vcpu, data);
-               break;
+               return kvm_set_apic_base(vcpu, msr_info);
        case APIC_BASE_MSR ... APIC_BASE_MSR + 0x3ff:
                return kvm_x2apic_msr_write(vcpu, msr, data);
        case MSR_IA32_TSCDEADLINE:
@@ -2598,10 +2616,10 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_GET_TSC_KHZ:
        case KVM_CAP_KVMCLOCK_CTRL:
        case KVM_CAP_READONLY_MEM:
+       case KVM_CAP_HYPERV_TIME:
 #ifdef CONFIG_KVM_DEVICE_ASSIGNMENT
        case KVM_CAP_ASSIGN_DEV_IRQ:
        case KVM_CAP_PCI_2_3:
-       case KVM_CAP_HYPERV_TIME:
 #endif
                r = 1;
                break;
@@ -6409,6 +6427,7 @@ EXPORT_SYMBOL_GPL(kvm_task_switch);
 int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
                                  struct kvm_sregs *sregs)
 {
+       struct msr_data apic_base_msr;
        int mmu_reset_needed = 0;
        int pending_vec, max_bits, idx;
        struct desc_ptr dt;
@@ -6432,7 +6451,9 @@ int kvm_arch_vcpu_ioctl_set_sregs(struct kvm_vcpu *vcpu,
 
        mmu_reset_needed |= vcpu->arch.efer != sregs->efer;
        kvm_x86_ops->set_efer(vcpu, sregs->efer);
-       kvm_set_apic_base(vcpu, sregs->apic_base);
+       apic_base_msr.data = sregs->apic_base;
+       apic_base_msr.host_initiated = true;
+       kvm_set_apic_base(vcpu, &apic_base_msr);
 
        mmu_reset_needed |= kvm_read_cr0(vcpu) != sregs->cr0;
        kvm_x86_ops->set_cr0(vcpu, sregs->cr0);
index bdf8532494fed0cc459ba46e19b9cc26e4d6366f..ad1fb5f53925e8634fac38da497128fed1904c55 100644 (file)
@@ -233,13 +233,13 @@ static void lguest_end_context_switch(struct task_struct *next)
  * flags word contains all kind of stuff, but in practice Linux only cares
  * about the interrupt flag.  Our "save_flags()" just returns that.
  */
-static unsigned long save_fl(void)
+asmlinkage unsigned long lguest_save_fl(void)
 {
        return lguest_data.irq_enabled;
 }
 
 /* Interrupts go off... */
-static void irq_disable(void)
+asmlinkage void lguest_irq_disable(void)
 {
        lguest_data.irq_enabled = 0;
 }
@@ -253,8 +253,8 @@ static void irq_disable(void)
  * PV_CALLEE_SAVE_REGS_THUNK(), which pushes %eax onto the stack, calls the
  * C function, then restores it.
  */
-PV_CALLEE_SAVE_REGS_THUNK(save_fl);
-PV_CALLEE_SAVE_REGS_THUNK(irq_disable);
+PV_CALLEE_SAVE_REGS_THUNK(lguest_save_fl);
+PV_CALLEE_SAVE_REGS_THUNK(lguest_irq_disable);
 /*:*/
 
 /* These are in i386_head.S */
@@ -1291,9 +1291,9 @@ __init void lguest_init(void)
         */
 
        /* Interrupt-related operations */
-       pv_irq_ops.save_fl = PV_CALLEE_SAVE(save_fl);
+       pv_irq_ops.save_fl = PV_CALLEE_SAVE(lguest_save_fl);
        pv_irq_ops.restore_fl = __PV_IS_CALLEE_SAVE(lg_restore_fl);
-       pv_irq_ops.irq_disable = PV_CALLEE_SAVE(irq_disable);
+       pv_irq_ops.irq_disable = PV_CALLEE_SAVE(lguest_irq_disable);
        pv_irq_ops.irq_enable = __PV_IS_CALLEE_SAVE(lg_irq_enable);
        pv_irq_ops.safe_halt = lguest_safe_halt;
 
index 59d353d2c599ec26d21a9ab65ea2641e121b25a5..a5449089cd9fef6e58a03174c5fe5a34cd48983a 100644 (file)
@@ -330,11 +330,6 @@ asmlinkage void FPU_exception(int n)
 
        RE_ENTRANT_CHECK_OFF;
        if ((~control_word & n & CW_Exceptions) || (n == EX_INTERNAL)) {
-#ifdef PRINT_MESSAGES
-               /* My message from the sponsor */
-               printk(FPU_VERSION " " __DATE__ " (C) W. Metzenthen.\n");
-#endif /* PRINT_MESSAGES */
-
                /* Get a name string for error reporting */
                for (i = 0; exception_names[i].type; i++)
                        if ((exception_names[i].type & n) ==
index 8f568dd79605058f0d9537e6aeb5c6010d7d1e46..79bb09d4f718f0a99f4ed4f3be8a2b38fd6fd0ae 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef _PLATFORM_IPC_H_
 #define _PLATFORM_IPC_H_
 
-extern void __init ipc_device_handler(struct sfi_device_table_entry *pentry,
-                       struct devs_id *dev) __attribute__((weak));
+void __init
+ipc_device_handler(struct sfi_device_table_entry *pentry, struct devs_id *dev);
+
 #endif
index 917eb56d77dab1aa9ae6b520262b7121c378d181..b7be1d041da233e400203522db151f7d7f703423 100644 (file)
@@ -14,6 +14,6 @@
 
 extern struct intel_msic_platform_data msic_pdata;
 
-extern void *msic_generic_platform_data(void *info,
-                       enum intel_msic_block block) __attribute__((weak));
+void *msic_generic_platform_data(void *info, enum intel_msic_block block);
+
 #endif
index a537ffc16299bf95d567c1fcf8ba7ba13cd00309..46aa25c8ce06c3366b15357d110111de2bd004fc 100644 (file)
@@ -14,6 +14,6 @@
 /* For every CPU addition a new get_<cpuname>_ops interface needs
  * to be added.
  */
-extern void * __cpuinit get_penwell_ops(void) __attribute__((weak));
-extern void * __cpuinit get_cloverview_ops(void) __attribute__((weak));
-extern void * __init get_tangier_ops(void) __attribute__((weak));
+extern void *get_penwell_ops(void) __attribute__((weak));
+extern void *get_cloverview_ops(void) __attribute__((weak));
+extern void *get_tangier_ops(void) __attribute__((weak));
index 4f7884eebc149a5b0c57645df7b3e471e4edc7f9..23381d2174ae1d4d2795ebf9a568ff7e43cf8876 100644 (file)
@@ -58,18 +58,18 @@ static unsigned long __init mfld_calibrate_tsc(void)
        return 0;
 }
 
-static void __init penwell_arch_setup()
+static void __init penwell_arch_setup(void)
 {
        x86_platform.calibrate_tsc = mfld_calibrate_tsc;
        pm_power_off = mfld_power_off;
 }
 
-void * __cpuinit get_penwell_ops()
+void *get_penwell_ops(void)
 {
        return &penwell_ops;
 }
 
-void * __cpuinit get_cloverview_ops()
+void *get_cloverview_ops(void)
 {
        return &penwell_ops;
 }
index 09d10159e7b7f982dea436f28e0d7628cade8ead..aaca91753d3267b94a98af40f7b66f8b5cbbb21c 100644 (file)
@@ -97,7 +97,7 @@ static struct intel_mid_ops tangier_ops = {
        .arch_setup = tangier_arch_setup,
 };
 
-void * __cpuinit get_tangier_ops()
+void *get_tangier_ops(void)
 {
        return &tangier_ops;
 }
index 8eeccba731304bb36d6a297e5d1ed1f4bf7158fd..be27da60dc8f8d2613e4b003239ef4c3b05bbd32 100644 (file)
@@ -74,7 +74,6 @@ static atomic_t       uv_in_nmi;
 static atomic_t uv_nmi_cpu = ATOMIC_INIT(-1);
 static atomic_t uv_nmi_cpus_in_nmi = ATOMIC_INIT(-1);
 static atomic_t uv_nmi_slave_continue;
-static atomic_t uv_nmi_kexec_failed;
 static cpumask_var_t uv_nmi_cpu_mask;
 
 /* Values for uv_nmi_slave_continue */
@@ -149,7 +148,8 @@ module_param_named(retry_count, uv_nmi_retry_count, int, 0644);
  *  "dump"     - dump process stack for each cpu
  *  "ips"      - dump IP info for each cpu
  *  "kdump"    - do crash dump
- *  "kdb"      - enter KDB/KGDB (default)
+ *  "kdb"      - enter KDB (default)
+ *  "kgdb"     - enter KGDB
  */
 static char uv_nmi_action[8] = "kdb";
 module_param_string(action, uv_nmi_action, sizeof(uv_nmi_action), 0644);
@@ -504,6 +504,7 @@ static void uv_nmi_touch_watchdogs(void)
 }
 
 #if defined(CONFIG_KEXEC)
+static atomic_t uv_nmi_kexec_failed;
 static void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs)
 {
        /* Call crash to dump system state */
@@ -537,18 +538,45 @@ static inline void uv_nmi_kdump(int cpu, int master, struct pt_regs *regs)
 }
 #endif /* !CONFIG_KEXEC */
 
+#ifdef CONFIG_KGDB
 #ifdef CONFIG_KGDB_KDB
-/* Call KDB from NMI handler */
-static void uv_call_kdb(int cpu, struct pt_regs *regs, int master)
+static inline int uv_nmi_kdb_reason(void)
 {
-       int ret;
+       return KDB_REASON_SYSTEM_NMI;
+}
+#else /* !CONFIG_KGDB_KDB */
+static inline int uv_nmi_kdb_reason(void)
+{
+       /* Insure user is expecting to attach gdb remote */
+       if (uv_nmi_action_is("kgdb"))
+               return 0;
+
+       pr_err("UV: NMI error: KDB is not enabled in this kernel\n");
+       return -1;
+}
+#endif /* CONFIG_KGDB_KDB */
 
+/*
+ * Call KGDB/KDB from NMI handler
+ *
+ * Note that if both KGDB and KDB are configured, then the action of 'kgdb' or
+ * 'kdb' has no affect on which is used.  See the KGDB documention for further
+ * information.
+ */
+static void uv_call_kgdb_kdb(int cpu, struct pt_regs *regs, int master)
+{
        if (master) {
+               int reason = uv_nmi_kdb_reason();
+               int ret;
+
+               if (reason < 0)
+                       return;
+
                /* call KGDB NMI handler as MASTER */
-               ret = kgdb_nmicallin(cpu, X86_TRAP_NMI, regs,
-                                       &uv_nmi_slave_continue);
+               ret = kgdb_nmicallin(cpu, X86_TRAP_NMI, regs, reason,
+                               &uv_nmi_slave_continue);
                if (ret) {
-                       pr_alert("KDB returned error, is kgdboc set?\n");
+                       pr_alert("KGDB returned error, is kgdboc set?\n");
                        atomic_set(&uv_nmi_slave_continue, SLAVE_EXIT);
                }
        } else {
@@ -567,12 +595,12 @@ static void uv_call_kdb(int cpu, struct pt_regs *regs, int master)
        uv_nmi_sync_exit(master);
 }
 
-#else /* !CONFIG_KGDB_KDB */
-static inline void uv_call_kdb(int cpu, struct pt_regs *regs, int master)
+#else /* !CONFIG_KGDB */
+static inline void uv_call_kgdb_kdb(int cpu, struct pt_regs *regs, int master)
 {
-       pr_err("UV: NMI error: KGDB/KDB is not enabled in this kernel\n");
+       pr_err("UV: NMI error: KGDB is not enabled in this kernel\n");
 }
-#endif /* !CONFIG_KGDB_KDB */
+#endif /* !CONFIG_KGDB */
 
 /*
  * UV NMI handler
@@ -606,9 +634,9 @@ int uv_handle_nmi(unsigned int reason, struct pt_regs *regs)
        if (uv_nmi_action_is("ips") || uv_nmi_action_is("dump"))
                uv_nmi_dump_state(cpu, regs, master);
 
-       /* Call KDB if enabled */
-       else if (uv_nmi_action_is("kdb"))
-               uv_call_kdb(cpu, regs, master);
+       /* Call KGDB/KDB if enabled */
+       else if (uv_nmi_action_is("kdb") || uv_nmi_action_is("kgdb"))
+               uv_call_kgdb_kdb(cpu, regs, master);
 
        /* Clear per_cpu "in nmi" flag */
        atomic_set(&uv_cpu_nmi.state, UV_NMI_STATE_OUT);
@@ -634,7 +662,7 @@ int uv_handle_nmi(unsigned int reason, struct pt_regs *regs)
 /*
  * NMI handler for pulling in CPUs when perf events are grabbing our NMI
  */
-int uv_handle_nmi_ping(unsigned int reason, struct pt_regs *regs)
+static int uv_handle_nmi_ping(unsigned int reason, struct pt_regs *regs)
 {
        int ret;
 
@@ -651,7 +679,7 @@ int uv_handle_nmi_ping(unsigned int reason, struct pt_regs *regs)
        return ret;
 }
 
-void uv_register_nmi_notifier(void)
+static void uv_register_nmi_notifier(void)
 {
        if (register_nmi_handler(NMI_UNKNOWN, uv_handle_nmi, 0, "uv"))
                pr_warn("UV: NMI handler failed to register\n");
@@ -695,6 +723,5 @@ void uv_nmi_setup(void)
                uv_hub_nmi_per(cpu) = uv_hub_nmi_list[nid];
        }
        BUG_ON(!alloc_cpumask_var(&uv_nmi_cpu_mask, GFP_KERNEL));
+       uv_register_nmi_notifier();
 }
-
-
index 9cac82588cbc49d86bc9457586941c69763d7749..3497f14e4dea8acd074ae0c1d6e03836de2623a1 100644 (file)
@@ -64,20 +64,7 @@ $(obj)/realmode.relocs: $(obj)/realmode.elf FORCE
 
 # ---------------------------------------------------------------------------
 
-# How to compile the 16-bit code.  Note we always compile for -march=i386,
-# that way we can complain to the user if the CPU is insufficient.
-KBUILD_CFLAGS  := $(LINUXINCLUDE) -m32 -g -Os -D_SETUP -D__KERNEL__ -D_WAKEUP \
-                  -I$(srctree)/arch/x86/boot \
-                  -DDISABLE_BRANCH_PROFILING \
-                  -Wall -Wstrict-prototypes \
-                  -march=i386 -mregparm=3 \
-                  -include $(srctree)/$(src)/../../boot/code16gcc.h \
-                  -fno-strict-aliasing -fomit-frame-pointer -fno-pic \
-                  -mno-mmx -mno-sse \
-                  $(call cc-option, -ffreestanding) \
-                  $(call cc-option, -fno-toplevel-reorder,\
-                  $(call cc-option, -fno-unit-at-a-time)) \
-                  $(call cc-option, -fno-stack-protector) \
-                  $(call cc-option, -mpreferred-stack-boundary=2)
+KBUILD_CFLAGS  := $(LINUXINCLUDE) $(REALMODE_CFLAGS) -D_SETUP -D_WAKEUP \
+                  -I$(srctree)/arch/x86/boot
 KBUILD_AFLAGS  := $(KBUILD_CFLAGS) -D__ASSEMBLY__
 GCOV_PROFILE := n
index 11f9285a2ff66726b6c62c7eb608e03f516dcc27..cfbdbdb4e1737c3b2461456e48573c75fb4ec6ef 100644 (file)
@@ -1025,6 +1025,29 @@ static void emit_relocs(int as_text, int use_real_mode)
        }
 }
 
+/*
+ * As an aid to debugging problems with different linkers
+ * print summary information about the relocs.
+ * Since different linkers tend to emit the sections in
+ * different orders we use the section names in the output.
+ */
+static int do_reloc_info(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
+                               const char *symname)
+{
+       printf("%s\t%s\t%s\t%s\n",
+               sec_name(sec->shdr.sh_info),
+               rel_type(ELF_R_TYPE(rel->r_info)),
+               symname,
+               sec_name(sym->st_shndx));
+       return 0;
+}
+
+static void print_reloc_info(void)
+{
+       printf("reloc section\treloc type\tsymbol\tsymbol section\n");
+       walk_relocs(do_reloc_info);
+}
+
 #if ELF_BITS == 64
 # define process process_64
 #else
@@ -1032,7 +1055,8 @@ static void emit_relocs(int as_text, int use_real_mode)
 #endif
 
 void process(FILE *fp, int use_real_mode, int as_text,
-            int show_absolute_syms, int show_absolute_relocs)
+            int show_absolute_syms, int show_absolute_relocs,
+            int show_reloc_info)
 {
        regex_init(use_real_mode);
        read_ehdr(fp);
@@ -1050,5 +1074,9 @@ void process(FILE *fp, int use_real_mode, int as_text,
                print_absolute_relocs();
                return;
        }
+       if (show_reloc_info) {
+               print_reloc_info();
+               return;
+       }
        emit_relocs(as_text, use_real_mode);
 }
index 07cdb1eca4fa60dcd80a06b5f032c97f786d4b36..f59590645b68641e4de9da7278b6f1c07f2e3b82 100644 (file)
@@ -29,8 +29,9 @@ enum symtype {
 };
 
 void process_32(FILE *fp, int use_real_mode, int as_text,
-               int show_absolute_syms, int show_absolute_relocs);
+               int show_absolute_syms, int show_absolute_relocs,
+               int show_reloc_info);
 void process_64(FILE *fp, int use_real_mode, int as_text,
-               int show_absolute_syms, int show_absolute_relocs);
-
+               int show_absolute_syms, int show_absolute_relocs,
+               int show_reloc_info);
 #endif /* RELOCS_H */
index 44d396823a53095ace215c49815cdb9cfa3614ed..acab636bcb348191794e0b8a4343c1874daa45a1 100644 (file)
@@ -11,12 +11,13 @@ void die(char *fmt, ...)
 
 static void usage(void)
 {
-       die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n");
+       die("relocs [--abs-syms|--abs-relocs|--reloc-info|--text|--realmode]" \
+           " vmlinux\n");
 }
 
 int main(int argc, char **argv)
 {
-       int show_absolute_syms, show_absolute_relocs;
+       int show_absolute_syms, show_absolute_relocs, show_reloc_info;
        int as_text, use_real_mode;
        const char *fname;
        FILE *fp;
@@ -25,6 +26,7 @@ int main(int argc, char **argv)
 
        show_absolute_syms = 0;
        show_absolute_relocs = 0;
+       show_reloc_info = 0;
        as_text = 0;
        use_real_mode = 0;
        fname = NULL;
@@ -39,6 +41,10 @@ int main(int argc, char **argv)
                                show_absolute_relocs = 1;
                                continue;
                        }
+                       if (strcmp(arg, "--reloc-info") == 0) {
+                               show_reloc_info = 1;
+                               continue;
+                       }
                        if (strcmp(arg, "--text") == 0) {
                                as_text = 1;
                                continue;
@@ -67,10 +73,12 @@ int main(int argc, char **argv)
        rewind(fp);
        if (e_ident[EI_CLASS] == ELFCLASS64)
                process_64(fp, use_real_mode, as_text,
-                          show_absolute_syms, show_absolute_relocs);
+                          show_absolute_syms, show_absolute_relocs,
+                          show_reloc_info);
        else
                process_32(fp, use_real_mode, as_text,
-                          show_absolute_syms, show_absolute_relocs);
+                          show_absolute_syms, show_absolute_relocs,
+                          show_reloc_info);
        fclose(fp);
        return 0;
 }
index 103c93f874b27c8656dde51d1ce7f02463d558e3..c985835885802a69ef0b255e36c81484026ab227 100644 (file)
@@ -162,14 +162,15 @@ static int __init xlated_setup_gnttab_pages(void)
        rc = arch_gnttab_map_shared(pfns, nr_grant_frames, nr_grant_frames,
                                    &xen_auto_xlat_grant_frames.vaddr);
 
-       kfree(pages);
        if (rc) {
                pr_warn("%s Couldn't map %ld pfns rc:%d\n", __func__,
                        nr_grant_frames, rc);
                free_xenballooned_pages(nr_grant_frames, pages);
+               kfree(pages);
                kfree(pfns);
                return rc;
        }
+       kfree(pages);
 
        xen_auto_xlat_grant_frames.pfn = pfns;
        xen_auto_xlat_grant_frames.count = nr_grant_frames;
index 76ca326105f71d9a53fd93e2b68e393dadba9bd8..08f763de26fe4132d7e6dcf0a7b50a660af76319 100644 (file)
@@ -23,7 +23,7 @@ void xen_force_evtchn_callback(void)
        (void)HYPERVISOR_xen_version(0, NULL);
 }
 
-static unsigned long xen_save_fl(void)
+asmlinkage unsigned long xen_save_fl(void)
 {
        struct vcpu_info *vcpu;
        unsigned long flags;
@@ -41,7 +41,7 @@ static unsigned long xen_save_fl(void)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_save_fl);
 
-static void xen_restore_fl(unsigned long flags)
+__visible void xen_restore_fl(unsigned long flags)
 {
        struct vcpu_info *vcpu;
 
@@ -63,7 +63,7 @@ static void xen_restore_fl(unsigned long flags)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_restore_fl);
 
-static void xen_irq_disable(void)
+asmlinkage void xen_irq_disable(void)
 {
        /* There's a one instruction preempt window here.  We need to
           make sure we're don't switch CPUs between getting the vcpu
@@ -74,7 +74,7 @@ static void xen_irq_disable(void)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_irq_disable);
 
-static void xen_irq_enable(void)
+asmlinkage void xen_irq_enable(void)
 {
        struct vcpu_info *vcpu;
 
index c1d406f35523143f7fc21f41a71dc0658c5e1823..2423ef04ffea596fd43eeb918f290003277fbb21 100644 (file)
@@ -431,7 +431,7 @@ static pteval_t iomap_pte(pteval_t val)
        return val;
 }
 
-static pteval_t xen_pte_val(pte_t pte)
+__visible pteval_t xen_pte_val(pte_t pte)
 {
        pteval_t pteval = pte.pte;
 #if 0
@@ -448,7 +448,7 @@ static pteval_t xen_pte_val(pte_t pte)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
 
-static pgdval_t xen_pgd_val(pgd_t pgd)
+__visible pgdval_t xen_pgd_val(pgd_t pgd)
 {
        return pte_mfn_to_pfn(pgd.pgd);
 }
@@ -479,7 +479,7 @@ void xen_set_pat(u64 pat)
        WARN_ON(pat != 0x0007010600070106ull);
 }
 
-static pte_t xen_make_pte(pteval_t pte)
+__visible pte_t xen_make_pte(pteval_t pte)
 {
        phys_addr_t addr = (pte & PTE_PFN_MASK);
 #if 0
@@ -514,14 +514,14 @@ static pte_t xen_make_pte(pteval_t pte)
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pte);
 
-static pgd_t xen_make_pgd(pgdval_t pgd)
+__visible pgd_t xen_make_pgd(pgdval_t pgd)
 {
        pgd = pte_pfn_to_mfn(pgd);
        return native_make_pgd(pgd);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pgd);
 
-static pmdval_t xen_pmd_val(pmd_t pmd)
+__visible pmdval_t xen_pmd_val(pmd_t pmd)
 {
        return pte_mfn_to_pfn(pmd.pmd);
 }
@@ -580,7 +580,7 @@ static void xen_pmd_clear(pmd_t *pmdp)
 }
 #endif /* CONFIG_X86_PAE */
 
-static pmd_t xen_make_pmd(pmdval_t pmd)
+__visible pmd_t xen_make_pmd(pmdval_t pmd)
 {
        pmd = pte_pfn_to_mfn(pmd);
        return native_make_pmd(pmd);
@@ -588,13 +588,13 @@ static pmd_t xen_make_pmd(pmdval_t pmd)
 PV_CALLEE_SAVE_REGS_THUNK(xen_make_pmd);
 
 #if PAGETABLE_LEVELS == 4
-static pudval_t xen_pud_val(pud_t pud)
+__visible pudval_t xen_pud_val(pud_t pud)
 {
        return pte_mfn_to_pfn(pud.pud);
 }
 PV_CALLEE_SAVE_REGS_THUNK(xen_pud_val);
 
-static pud_t xen_make_pud(pudval_t pud)
+__visible pud_t xen_make_pud(pudval_t pud)
 {
        pud = pte_pfn_to_mfn(pud);
 
index 696c694986d0ab6aa967f3db7c6a345ef9c1ab59..8009acbe41e4ca954470796b3ad4e1befd679fe2 100644 (file)
@@ -899,13 +899,6 @@ int m2p_add_override(unsigned long mfn, struct page *page,
                                        "m2p_add_override: pfn %lx not mapped", pfn))
                        return -EINVAL;
        }
-       WARN_ON(PagePrivate(page));
-       SetPagePrivate(page);
-       set_page_private(page, mfn);
-       page->index = pfn_to_mfn(pfn);
-
-       if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn))))
-               return -ENOMEM;
 
        if (kmap_op != NULL) {
                if (!PageHighMem(page)) {
@@ -944,19 +937,16 @@ int m2p_add_override(unsigned long mfn, struct page *page,
 }
 EXPORT_SYMBOL_GPL(m2p_add_override);
 int m2p_remove_override(struct page *page,
-               struct gnttab_map_grant_ref *kmap_op)
+                       struct gnttab_map_grant_ref *kmap_op,
+                       unsigned long mfn)
 {
        unsigned long flags;
-       unsigned long mfn;
        unsigned long pfn;
        unsigned long uninitialized_var(address);
        unsigned level;
        pte_t *ptep = NULL;
 
        pfn = page_to_pfn(page);
-       mfn = get_phys_to_machine(pfn);
-       if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT))
-               return -EINVAL;
 
        if (!PageHighMem(page)) {
                address = (unsigned long)__va(pfn << PAGE_SHIFT);
@@ -970,10 +960,7 @@ int m2p_remove_override(struct page *page,
        spin_lock_irqsave(&m2p_override_lock, flags);
        list_del(&page->lru);
        spin_unlock_irqrestore(&m2p_override_lock, flags);
-       WARN_ON(!PagePrivate(page));
-       ClearPagePrivate(page);
 
-       set_phys_to_machine(pfn, page->index);
        if (kmap_op != NULL) {
                if (!PageHighMem(page)) {
                        struct multicall_space mcs;
index dd5f905e33d5e187d9713d65ddaf3b721f6ad0d6..0982233b9b8433a97d6905de4aad3369c6f4c0a5 100644 (file)
@@ -35,7 +35,7 @@
 extern const char xen_hypervisor_callback[];
 extern const char xen_failsafe_callback[];
 #ifdef CONFIG_X86_64
-extern const char nmi[];
+extern asmlinkage void nmi(void);
 #endif
 extern void xen_sysenter_target(void);
 extern void xen_syscall_target(void);
@@ -577,7 +577,7 @@ void xen_enable_syscall(void)
 void xen_enable_nmi(void)
 {
 #ifdef CONFIG_X86_64
-       if (register_callback(CALLBACKTYPE_nmi, nmi))
+       if (register_callback(CALLBACKTYPE_nmi, (char *)nmi))
                BUG();
 #endif
 }
index 0e36cde12f7e7de605d676055897f04bb231d654..581521c843a576d4264567e90c11dfaf645d6238 100644 (file)
@@ -106,7 +106,7 @@ static DEFINE_PER_CPU(struct xen_lock_waiting, lock_waiting);
 static cpumask_t waiting_cpus;
 
 static bool xen_pvspin = true;
-static void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
+__visible void xen_lock_spinning(struct arch_spinlock *lock, __ticket_t want)
 {
        int irq = __this_cpu_read(lock_kicker_irq);
        struct xen_lock_waiting *w = &__get_cpu_var(lock_waiting);
index 8c6e819cd8edcc26049348a9ca2e4a6d59c677b3..48eebacdf5fe089c0ff8591ddbaf07dc576a2729 100644 (file)
@@ -103,18 +103,18 @@ static void simdisk_transfer(struct simdisk *dev, unsigned long sector,
 
 static int simdisk_xfer_bio(struct simdisk *dev, struct bio *bio)
 {
-       int i;
-       struct bio_vec *bvec;
-       sector_t sector = bio->bi_sector;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
+       sector_t sector = bio->bi_iter.bi_sector;
 
-       bio_for_each_segment(bvec, bio, i) {
-               char *buffer = __bio_kmap_atomic(bio, i);
-               unsigned len = bvec->bv_len >> SECTOR_SHIFT;
+       bio_for_each_segment(bvec, bio, iter) {
+               char *buffer = __bio_kmap_atomic(bio, iter);
+               unsigned len = bvec.bv_len >> SECTOR_SHIFT;
 
                simdisk_transfer(dev, sector, len, buffer,
                                bio_data_dir(bio) == WRITE);
                sector += len;
-               __bio_kunmap_atomic(bio);
+               __bio_kunmap_atomic(buffer);
        }
        return 0;
 }
index 8bdd0121212a51a1dba3c568c5a6a3e070447318..c00e0bdeab4ab4724c42b379717200d405d9c584 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "blk.h"
 #include "blk-cgroup.h"
+#include "blk-mq.h"
 
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_bio_remap);
 EXPORT_TRACEPOINT_SYMBOL_GPL(block_rq_remap);
@@ -130,7 +131,7 @@ static void req_bio_endio(struct request *rq, struct bio *bio,
        bio_advance(bio, nbytes);
 
        /* don't actually finish bio if it's part of flush sequence */
-       if (bio->bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ))
+       if (bio->bi_iter.bi_size == 0 && !(rq->cmd_flags & REQ_FLUSH_SEQ))
                bio_endio(bio, error);
 }
 
@@ -245,7 +246,16 @@ EXPORT_SYMBOL(blk_stop_queue);
 void blk_sync_queue(struct request_queue *q)
 {
        del_timer_sync(&q->timeout);
-       cancel_delayed_work_sync(&q->delay_work);
+
+       if (q->mq_ops) {
+               struct blk_mq_hw_ctx *hctx;
+               int i;
+
+               queue_for_each_hw_ctx(q, hctx, i)
+                       cancel_delayed_work_sync(&hctx->delayed_work);
+       } else {
+               cancel_delayed_work_sync(&q->delay_work);
+       }
 }
 EXPORT_SYMBOL(blk_sync_queue);
 
@@ -497,8 +507,13 @@ void blk_cleanup_queue(struct request_queue *q)
         * Drain all requests queued before DYING marking. Set DEAD flag to
         * prevent that q->request_fn() gets invoked after draining finished.
         */
-       spin_lock_irq(lock);
-       __blk_drain_queue(q, true);
+       if (q->mq_ops) {
+               blk_mq_drain_queue(q);
+               spin_lock_irq(lock);
+       } else {
+               spin_lock_irq(lock);
+               __blk_drain_queue(q, true);
+       }
        queue_flag_set(QUEUE_FLAG_DEAD, q);
        spin_unlock_irq(lock);
 
@@ -1326,7 +1341,7 @@ void blk_add_request_payload(struct request *rq, struct page *page,
        bio->bi_io_vec->bv_offset = 0;
        bio->bi_io_vec->bv_len = len;
 
-       bio->bi_size = len;
+       bio->bi_iter.bi_size = len;
        bio->bi_vcnt = 1;
        bio->bi_phys_segments = 1;
 
@@ -1351,7 +1366,7 @@ bool bio_attempt_back_merge(struct request_queue *q, struct request *req,
 
        req->biotail->bi_next = bio;
        req->biotail = bio;
-       req->__data_len += bio->bi_size;
+       req->__data_len += bio->bi_iter.bi_size;
        req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
 
        blk_account_io_start(req, false);
@@ -1380,8 +1395,8 @@ bool bio_attempt_front_merge(struct request_queue *q, struct request *req,
         * not touch req->buffer either...
         */
        req->buffer = bio_data(bio);
-       req->__sector = bio->bi_sector;
-       req->__data_len += bio->bi_size;
+       req->__sector = bio->bi_iter.bi_sector;
+       req->__data_len += bio->bi_iter.bi_size;
        req->ioprio = ioprio_best(req->ioprio, bio_prio(bio));
 
        blk_account_io_start(req, false);
@@ -1459,7 +1474,7 @@ void init_request_from_bio(struct request *req, struct bio *bio)
                req->cmd_flags |= REQ_FAILFAST_MASK;
 
        req->errors = 0;
-       req->__sector = bio->bi_sector;
+       req->__sector = bio->bi_iter.bi_sector;
        req->ioprio = bio_prio(bio);
        blk_rq_bio_prep(req->q, req, bio);
 }
@@ -1583,12 +1598,12 @@ static inline void blk_partition_remap(struct bio *bio)
        if (bio_sectors(bio) && bdev != bdev->bd_contains) {
                struct hd_struct *p = bdev->bd_part;
 
-               bio->bi_sector += p->start_sect;
+               bio->bi_iter.bi_sector += p->start_sect;
                bio->bi_bdev = bdev->bd_contains;
 
                trace_block_bio_remap(bdev_get_queue(bio->bi_bdev), bio,
                                      bdev->bd_dev,
-                                     bio->bi_sector - p->start_sect);
+                                     bio->bi_iter.bi_sector - p->start_sect);
        }
 }
 
@@ -1654,7 +1669,7 @@ static inline int bio_check_eod(struct bio *bio, unsigned int nr_sectors)
        /* Test device or partition size, when known. */
        maxsector = i_size_read(bio->bi_bdev->bd_inode) >> 9;
        if (maxsector) {
-               sector_t sector = bio->bi_sector;
+               sector_t sector = bio->bi_iter.bi_sector;
 
                if (maxsector < nr_sectors || maxsector - nr_sectors < sector) {
                        /*
@@ -1690,7 +1705,7 @@ generic_make_request_checks(struct bio *bio)
                       "generic_make_request: Trying to access "
                        "nonexistent block-device %s (%Lu)\n",
                        bdevname(bio->bi_bdev, b),
-                       (long long) bio->bi_sector);
+                       (long long) bio->bi_iter.bi_sector);
                goto end_io;
        }
 
@@ -1704,9 +1719,9 @@ generic_make_request_checks(struct bio *bio)
        }
 
        part = bio->bi_bdev->bd_part;
-       if (should_fail_request(part, bio->bi_size) ||
+       if (should_fail_request(part, bio->bi_iter.bi_size) ||
            should_fail_request(&part_to_disk(part)->part0,
-                               bio->bi_size))
+                               bio->bi_iter.bi_size))
                goto end_io;
 
        /*
@@ -1865,7 +1880,7 @@ void submit_bio(int rw, struct bio *bio)
                if (rw & WRITE) {
                        count_vm_events(PGPGOUT, count);
                } else {
-                       task_io_account_read(bio->bi_size);
+                       task_io_account_read(bio->bi_iter.bi_size);
                        count_vm_events(PGPGIN, count);
                }
 
@@ -1874,7 +1889,7 @@ void submit_bio(int rw, struct bio *bio)
                        printk(KERN_DEBUG "%s(%d): %s block %Lu on %s (%u sectors)\n",
                        current->comm, task_pid_nr(current),
                                (rw & WRITE) ? "WRITE" : "READ",
-                               (unsigned long long)bio->bi_sector,
+                               (unsigned long long)bio->bi_iter.bi_sector,
                                bdevname(bio->bi_bdev, b),
                                count);
                }
@@ -2007,7 +2022,7 @@ unsigned int blk_rq_err_bytes(const struct request *rq)
        for (bio = rq->bio; bio; bio = bio->bi_next) {
                if ((bio->bi_rw & ff) != ff)
                        break;
-               bytes += bio->bi_size;
+               bytes += bio->bi_iter.bi_size;
        }
 
        /* this could lead to infinite loop */
@@ -2378,9 +2393,9 @@ bool blk_update_request(struct request *req, int error, unsigned int nr_bytes)
        total_bytes = 0;
        while (req->bio) {
                struct bio *bio = req->bio;
-               unsigned bio_bytes = min(bio->bi_size, nr_bytes);
+               unsigned bio_bytes = min(bio->bi_iter.bi_size, nr_bytes);
 
-               if (bio_bytes == bio->bi_size)
+               if (bio_bytes == bio->bi_iter.bi_size)
                        req->bio = bio->bi_next;
 
                req_bio_endio(req, bio, bio_bytes, error);
@@ -2728,7 +2743,7 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
                rq->nr_phys_segments = bio_phys_segments(q, bio);
                rq->buffer = bio_data(bio);
        }
-       rq->__data_len = bio->bi_size;
+       rq->__data_len = bio->bi_iter.bi_size;
        rq->bio = rq->biotail = bio;
 
        if (bio->bi_bdev)
@@ -2746,10 +2761,10 @@ void blk_rq_bio_prep(struct request_queue *q, struct request *rq,
 void rq_flush_dcache_pages(struct request *rq)
 {
        struct req_iterator iter;
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
 
        rq_for_each_segment(bvec, rq, iter)
-               flush_dcache_page(bvec->bv_page);
+               flush_dcache_page(bvec.bv_page);
 }
 EXPORT_SYMBOL_GPL(rq_flush_dcache_pages);
 #endif
index c3edf9dff566f47883f3fac946b72e1e208c5286..bbfc072a79c2b5d0921ee84d322e4391d85c529b 100644 (file)
@@ -60,6 +60,10 @@ void blk_execute_rq_nowait(struct request_queue *q, struct gendisk *bd_disk,
        rq->rq_disk = bd_disk;
        rq->end_io = done;
 
+       /*
+        * don't check dying flag for MQ because the request won't
+        * be resued after dying flag is set
+        */
        if (q->mq_ops) {
                blk_mq_insert_request(q, rq, true);
                return;
index fb6f3c0ffa494f4f2adcce6fc35c95ecf383c9a8..9288aaf35c21fc8c0f579fa001f316e697a4dfbb 100644 (file)
@@ -548,7 +548,7 @@ int blkdev_issue_flush(struct block_device *bdev, gfp_t gfp_mask,
         * copied from blk_rq_pos(rq).
         */
        if (error_sector)
-               *error_sector = bio->bi_sector;
+               *error_sector = bio->bi_iter.bi_sector;
 
        bio_put(bio);
        return ret;
index 03cf7179e8ef1aac2f1698eae57377e65a94f275..7fbab84399e6c9c602c52c8157596535a2ce2e05 100644 (file)
@@ -43,30 +43,32 @@ static const char *bi_unsupported_name = "unsupported";
  */
 int blk_rq_count_integrity_sg(struct request_queue *q, struct bio *bio)
 {
-       struct bio_vec *iv, *ivprv = NULL;
+       struct bio_vec iv, ivprv = { NULL };
        unsigned int segments = 0;
        unsigned int seg_size = 0;
-       unsigned int i = 0;
+       struct bvec_iter iter;
+       int prev = 0;
 
-       bio_for_each_integrity_vec(iv, bio, i) {
+       bio_for_each_integrity_vec(iv, bio, iter) {
 
-               if (ivprv) {
-                       if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv))
+               if (prev) {
+                       if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv))
                                goto new_segment;
 
-                       if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv))
+                       if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv))
                                goto new_segment;
 
-                       if (seg_size + iv->bv_len > queue_max_segment_size(q))
+                       if (seg_size + iv.bv_len > queue_max_segment_size(q))
                                goto new_segment;
 
-                       seg_size += iv->bv_len;
+                       seg_size += iv.bv_len;
                } else {
 new_segment:
                        segments++;
-                       seg_size = iv->bv_len;
+                       seg_size = iv.bv_len;
                }
 
+               prev = 1;
                ivprv = iv;
        }
 
@@ -87,24 +89,25 @@ EXPORT_SYMBOL(blk_rq_count_integrity_sg);
 int blk_rq_map_integrity_sg(struct request_queue *q, struct bio *bio,
                            struct scatterlist *sglist)
 {
-       struct bio_vec *iv, *ivprv = NULL;
+       struct bio_vec iv, ivprv = { NULL };
        struct scatterlist *sg = NULL;
        unsigned int segments = 0;
-       unsigned int i = 0;
+       struct bvec_iter iter;
+       int prev = 0;
 
-       bio_for_each_integrity_vec(iv, bio, i) {
+       bio_for_each_integrity_vec(iv, bio, iter) {
 
-               if (ivprv) {
-                       if (!BIOVEC_PHYS_MERGEABLE(ivprv, iv))
+               if (prev) {
+                       if (!BIOVEC_PHYS_MERGEABLE(&ivprv, &iv))
                                goto new_segment;
 
-                       if (!BIOVEC_SEG_BOUNDARY(q, ivprv, iv))
+                       if (!BIOVEC_SEG_BOUNDARY(q, &ivprv, &iv))
                                goto new_segment;
 
-                       if (sg->length + iv->bv_len > queue_max_segment_size(q))
+                       if (sg->length + iv.bv_len > queue_max_segment_size(q))
                                goto new_segment;
 
-                       sg->length += iv->bv_len;
+                       sg->length += iv.bv_len;
                } else {
 new_segment:
                        if (!sg)
@@ -114,10 +117,11 @@ new_segment:
                                sg = sg_next(sg);
                        }
 
-                       sg_set_page(sg, iv->bv_page, iv->bv_len, iv->bv_offset);
+                       sg_set_page(sg, iv.bv_page, iv.bv_len, iv.bv_offset);
                        segments++;
                }
 
+               prev = 1;
                ivprv = iv;
        }
 
index 9b5b561cb92812fba2562b3bdb6c5bd8be012905..2da76c999ef3f37bd965f9d91b48dac43196a208 100644 (file)
@@ -108,12 +108,12 @@ int blkdev_issue_discard(struct block_device *bdev, sector_t sector,
                        req_sects = end_sect - sector;
                }
 
-               bio->bi_sector = sector;
+               bio->bi_iter.bi_sector = sector;
                bio->bi_end_io = bio_batch_end_io;
                bio->bi_bdev = bdev;
                bio->bi_private = &bb;
 
-               bio->bi_size = req_sects << 9;
+               bio->bi_iter.bi_size = req_sects << 9;
                nr_sects -= req_sects;
                sector = end_sect;
 
@@ -174,7 +174,7 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector,
                        break;
                }
 
-               bio->bi_sector = sector;
+               bio->bi_iter.bi_sector = sector;
                bio->bi_end_io = bio_batch_end_io;
                bio->bi_bdev = bdev;
                bio->bi_private = &bb;
@@ -184,11 +184,11 @@ int blkdev_issue_write_same(struct block_device *bdev, sector_t sector,
                bio->bi_io_vec->bv_len = bdev_logical_block_size(bdev);
 
                if (nr_sects > max_write_same_sectors) {
-                       bio->bi_size = max_write_same_sectors << 9;
+                       bio->bi_iter.bi_size = max_write_same_sectors << 9;
                        nr_sects -= max_write_same_sectors;
                        sector += max_write_same_sectors;
                } else {
-                       bio->bi_size = nr_sects << 9;
+                       bio->bi_iter.bi_size = nr_sects << 9;
                        nr_sects = 0;
                }
 
@@ -240,7 +240,7 @@ int __blkdev_issue_zeroout(struct block_device *bdev, sector_t sector,
                        break;
                }
 
-               bio->bi_sector = sector;
+               bio->bi_iter.bi_sector = sector;
                bio->bi_bdev   = bdev;
                bio->bi_end_io = bio_batch_end_io;
                bio->bi_private = &bb;
index 623e1cd4cffe997e71fbb54577bd42f220af64b3..ae4ae1047fd99575473a8b251dff562a151f0719 100644 (file)
@@ -20,7 +20,7 @@ int blk_rq_append_bio(struct request_queue *q, struct request *rq,
                rq->biotail->bi_next = bio;
                rq->biotail = bio;
 
-               rq->__data_len += bio->bi_size;
+               rq->__data_len += bio->bi_iter.bi_size;
        }
        return 0;
 }
@@ -76,7 +76,7 @@ static int __blk_rq_map_user(struct request_queue *q, struct request *rq,
 
        ret = blk_rq_append_bio(q, rq, bio);
        if (!ret)
-               return bio->bi_size;
+               return bio->bi_iter.bi_size;
 
        /* if it was boucned we must call the end io function */
        bio_endio(bio, 0);
@@ -220,7 +220,7 @@ int blk_rq_map_user_iov(struct request_queue *q, struct request *rq,
        if (IS_ERR(bio))
                return PTR_ERR(bio);
 
-       if (bio->bi_size != len) {
+       if (bio->bi_iter.bi_size != len) {
                /*
                 * Grab an extra reference to this bio, as bio_unmap_user()
                 * expects to be able to drop it twice as it happens on the
index 1ffc58977835ff2e581c97faa35ee85ebc9a5095..8f8adaa95466ccc8335cde7e313b551b375ed9b9 100644 (file)
 static unsigned int __blk_recalc_rq_segments(struct request_queue *q,
                                             struct bio *bio)
 {
-       struct bio_vec *bv, *bvprv = NULL;
-       int cluster, i, high, highprv = 1;
+       struct bio_vec bv, bvprv = { NULL };
+       int cluster, high, highprv = 1;
        unsigned int seg_size, nr_phys_segs;
        struct bio *fbio, *bbio;
+       struct bvec_iter iter;
 
        if (!bio)
                return 0;
@@ -25,25 +26,23 @@ static unsigned int __blk_recalc_rq_segments(struct request_queue *q,
        seg_size = 0;
        nr_phys_segs = 0;
        for_each_bio(bio) {
-               bio_for_each_segment(bv, bio, i) {
+               bio_for_each_segment(bv, bio, iter) {
                        /*
                         * the trick here is making sure that a high page is
                         * never considered part of another segment, since that
                         * might change with the bounce page.
                         */
-                       high = page_to_pfn(bv->bv_page) > queue_bounce_pfn(q);
-                       if (high || highprv)
-                               goto new_segment;
-                       if (cluster) {
-                               if (seg_size + bv->bv_len
+                       high = page_to_pfn(bv.bv_page) > queue_bounce_pfn(q);
+                       if (!high && !highprv && cluster) {
+                               if (seg_size + bv.bv_len
                                    > queue_max_segment_size(q))
                                        goto new_segment;
-                               if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv))
+                               if (!BIOVEC_PHYS_MERGEABLE(&bvprv, &bv))
                                        goto new_segment;
-                               if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv))
+                               if (!BIOVEC_SEG_BOUNDARY(q, &bvprv, &bv))
                                        goto new_segment;
 
-                               seg_size += bv->bv_len;
+                               seg_size += bv.bv_len;
                                bvprv = bv;
                                continue;
                        }
@@ -54,7 +53,7 @@ new_segment:
 
                        nr_phys_segs++;
                        bvprv = bv;
-                       seg_size = bv->bv_len;
+                       seg_size = bv.bv_len;
                        highprv = high;
                }
                bbio = bio;
@@ -87,6 +86,9 @@ EXPORT_SYMBOL(blk_recount_segments);
 static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
                                   struct bio *nxt)
 {
+       struct bio_vec end_bv = { NULL }, nxt_bv;
+       struct bvec_iter iter;
+
        if (!blk_queue_cluster(q))
                return 0;
 
@@ -97,34 +99,40 @@ static int blk_phys_contig_segment(struct request_queue *q, struct bio *bio,
        if (!bio_has_data(bio))
                return 1;
 
-       if (!BIOVEC_PHYS_MERGEABLE(__BVEC_END(bio), __BVEC_START(nxt)))
+       bio_for_each_segment(end_bv, bio, iter)
+               if (end_bv.bv_len == iter.bi_size)
+                       break;
+
+       nxt_bv = bio_iovec(nxt);
+
+       if (!BIOVEC_PHYS_MERGEABLE(&end_bv, &nxt_bv))
                return 0;
 
        /*
         * bio and nxt are contiguous in memory; check if the queue allows
         * these two to be merged into one
         */
-       if (BIO_SEG_BOUNDARY(q, bio, nxt))
+       if (BIOVEC_SEG_BOUNDARY(q, &end_bv, &nxt_bv))
                return 1;
 
        return 0;
 }
 
-static void
+static inline void
 __blk_segment_map_sg(struct request_queue *q, struct bio_vec *bvec,
-                    struct scatterlist *sglist, struct bio_vec **bvprv,
+                    struct scatterlist *sglist, struct bio_vec *bvprv,
                     struct scatterlist **sg, int *nsegs, int *cluster)
 {
 
        int nbytes = bvec->bv_len;
 
-       if (*bvprv && *cluster) {
+       if (*sg && *cluster) {
                if ((*sg)->length + nbytes > queue_max_segment_size(q))
                        goto new_segment;
 
-               if (!BIOVEC_PHYS_MERGEABLE(*bvprv, bvec))
+               if (!BIOVEC_PHYS_MERGEABLE(bvprv, bvec))
                        goto new_segment;
-               if (!BIOVEC_SEG_BOUNDARY(q, *bvprv, bvec))
+               if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bvec))
                        goto new_segment;
 
                (*sg)->length += nbytes;
@@ -150,7 +158,7 @@ new_segment:
                sg_set_page(*sg, bvec->bv_page, nbytes, bvec->bv_offset);
                (*nsegs)++;
        }
-       *bvprv = bvec;
+       *bvprv = *bvec;
 }
 
 /*
@@ -160,7 +168,7 @@ new_segment:
 int blk_rq_map_sg(struct request_queue *q, struct request *rq,
                  struct scatterlist *sglist)
 {
-       struct bio_vec *bvec, *bvprv;
+       struct bio_vec bvec, bvprv = { NULL };
        struct req_iterator iter;
        struct scatterlist *sg;
        int nsegs, cluster;
@@ -171,10 +179,9 @@ int blk_rq_map_sg(struct request_queue *q, struct request *rq,
        /*
         * for each bio in rq
         */
-       bvprv = NULL;
        sg = NULL;
        rq_for_each_segment(bvec, rq, iter) {
-               __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg,
+               __blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg,
                                     &nsegs, &cluster);
        } /* segments in rq */
 
@@ -223,18 +230,17 @@ EXPORT_SYMBOL(blk_rq_map_sg);
 int blk_bio_map_sg(struct request_queue *q, struct bio *bio,
                   struct scatterlist *sglist)
 {
-       struct bio_vec *bvec, *bvprv;
+       struct bio_vec bvec, bvprv = { NULL };
        struct scatterlist *sg;
        int nsegs, cluster;
-       unsigned long i;
+       struct bvec_iter iter;
 
        nsegs = 0;
        cluster = blk_queue_cluster(q);
 
-       bvprv = NULL;
        sg = NULL;
-       bio_for_each_segment(bvec, bio, i) {
-               __blk_segment_map_sg(q, bvec, sglist, &bvprv, &sg,
+       bio_for_each_segment(bvec, bio, iter) {
+               __blk_segment_map_sg(q, &bvec, sglist, &bvprv, &sg,
                                     &nsegs, &cluster);
        } /* segments in bio */
 
@@ -543,9 +549,9 @@ bool blk_rq_merge_ok(struct request *rq, struct bio *bio)
 
 int blk_try_merge(struct request *rq, struct bio *bio)
 {
-       if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_sector)
+       if (blk_rq_pos(rq) + blk_rq_sectors(rq) == bio->bi_iter.bi_sector)
                return ELEVATOR_BACK_MERGE;
-       else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_sector)
+       else if (blk_rq_pos(rq) - bio_sectors(bio) == bio->bi_iter.bi_sector)
                return ELEVATOR_FRONT_MERGE;
        return ELEVATOR_NO_MERGE;
 }
index 0045ace9bdf0301f724463c2e37ae8b62e9902cb..3146befb56aaac7b925428d0afee89c9e083094a 100644 (file)
@@ -28,36 +28,6 @@ static int blk_mq_main_cpu_notify(struct notifier_block *self,
        return NOTIFY_OK;
 }
 
-static void blk_mq_cpu_notify(void *data, unsigned long action,
-                             unsigned int cpu)
-{
-       if (action == CPU_DEAD || action == CPU_DEAD_FROZEN) {
-               /*
-                * If the CPU goes away, ensure that we run any pending
-                * completions.
-                */
-               struct llist_node *node;
-               struct request *rq;
-
-               local_irq_disable();
-
-               node = llist_del_all(&per_cpu(ipi_lists, cpu));
-               while (node) {
-                       struct llist_node *next = node->next;
-
-                       rq = llist_entry(node, struct request, ll_list);
-                       __blk_mq_end_io(rq, rq->errors);
-                       node = next;
-               }
-
-               local_irq_enable();
-       }
-}
-
-static struct notifier_block __cpuinitdata blk_mq_main_cpu_notifier = {
-       .notifier_call  = blk_mq_main_cpu_notify,
-};
-
 void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier)
 {
        BUG_ON(!notifier->notify);
@@ -82,12 +52,7 @@ void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
        notifier->data = data;
 }
 
-static struct blk_mq_cpu_notifier __cpuinitdata cpu_notifier = {
-       .notify = blk_mq_cpu_notify,
-};
-
 void __init blk_mq_cpu_init(void)
 {
-       register_hotcpu_notifier(&blk_mq_main_cpu_notifier);
-       blk_mq_register_cpu_notifier(&cpu_notifier);
+       hotcpu_notifier(blk_mq_main_cpu_notify, 0);
 }
index d64a02fb1f7307e75bc64410104d22087b04965c..5d70edc9855f7febabb4ebcb7f37ef23585d4b91 100644 (file)
@@ -36,7 +36,8 @@ static unsigned int __blk_mq_get_tag(struct blk_mq_tags *tags, gfp_t gfp)
 {
        int tag;
 
-       tag = percpu_ida_alloc(&tags->free_tags, gfp);
+       tag = percpu_ida_alloc(&tags->free_tags, (gfp & __GFP_WAIT) ?
+                              TASK_UNINTERRUPTIBLE : TASK_RUNNING);
        if (tag < 0)
                return BLK_MQ_TAG_FAIL;
        return tag + tags->nr_reserved_tags;
@@ -52,7 +53,8 @@ static unsigned int __blk_mq_get_reserved_tag(struct blk_mq_tags *tags,
                return BLK_MQ_TAG_FAIL;
        }
 
-       tag = percpu_ida_alloc(&tags->reserved_tags, gfp);
+       tag = percpu_ida_alloc(&tags->reserved_tags, (gfp & __GFP_WAIT) ?
+                              TASK_UNINTERRUPTIBLE : TASK_RUNNING);
        if (tag < 0)
                return BLK_MQ_TAG_FAIL;
        return tag;
index c79126e110308e8b1ea4b322506a425ceeb3085c..57039fcd9c93e7c3e014842fbbcaf2fc6550edd1 100644 (file)
@@ -27,8 +27,6 @@ static LIST_HEAD(all_q_list);
 
 static void __blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx);
 
-DEFINE_PER_CPU(struct llist_head, ipi_lists);
-
 static struct blk_mq_ctx *__blk_mq_get_ctx(struct request_queue *q,
                                           unsigned int cpu)
 {
@@ -106,10 +104,13 @@ static int blk_mq_queue_enter(struct request_queue *q)
 
        spin_lock_irq(q->queue_lock);
        ret = wait_event_interruptible_lock_irq(q->mq_freeze_wq,
-               !blk_queue_bypass(q), *q->queue_lock);
+               !blk_queue_bypass(q) || blk_queue_dying(q),
+               *q->queue_lock);
        /* inc usage with lock hold to avoid freeze_queue runs here */
-       if (!ret)
+       if (!ret && !blk_queue_dying(q))
                __percpu_counter_add(&q->mq_usage_counter, 1, 1000000);
+       else if (blk_queue_dying(q))
+               ret = -ENODEV;
        spin_unlock_irq(q->queue_lock);
 
        return ret;
@@ -120,6 +121,22 @@ static void blk_mq_queue_exit(struct request_queue *q)
        __percpu_counter_add(&q->mq_usage_counter, -1, 1000000);
 }
 
+static void __blk_mq_drain_queue(struct request_queue *q)
+{
+       while (true) {
+               s64 count;
+
+               spin_lock_irq(q->queue_lock);
+               count = percpu_counter_sum(&q->mq_usage_counter);
+               spin_unlock_irq(q->queue_lock);
+
+               if (count == 0)
+                       break;
+               blk_mq_run_queues(q, false);
+               msleep(10);
+       }
+}
+
 /*
  * Guarantee no request is in use, so we can change any data structure of
  * the queue afterward.
@@ -133,21 +150,13 @@ static void blk_mq_freeze_queue(struct request_queue *q)
        queue_flag_set(QUEUE_FLAG_BYPASS, q);
        spin_unlock_irq(q->queue_lock);
 
-       if (!drain)
-               return;
-
-       while (true) {
-               s64 count;
-
-               spin_lock_irq(q->queue_lock);
-               count = percpu_counter_sum(&q->mq_usage_counter);
-               spin_unlock_irq(q->queue_lock);
+       if (drain)
+               __blk_mq_drain_queue(q);
+}
 
-               if (count == 0)
-                       break;
-               blk_mq_run_queues(q, false);
-               msleep(10);
-       }
+void blk_mq_drain_queue(struct request_queue *q)
+{
+       __blk_mq_drain_queue(q);
 }
 
 static void blk_mq_unfreeze_queue(struct request_queue *q)
@@ -179,6 +188,8 @@ static void blk_mq_rq_ctx_init(struct request_queue *q, struct blk_mq_ctx *ctx,
 
        rq->mq_ctx = ctx;
        rq->cmd_flags = rw_flags;
+       rq->start_time = jiffies;
+       set_start_time_ns(rq);
        ctx->rq_dispatched[rw_is_sync(rw_flags)]++;
 }
 
@@ -305,7 +316,7 @@ void blk_mq_complete_request(struct request *rq, int error)
                struct bio *next = bio->bi_next;
 
                bio->bi_next = NULL;
-               bytes += bio->bi_size;
+               bytes += bio->bi_iter.bi_size;
                blk_mq_bio_endio(rq, bio, error);
                bio = next;
        }
@@ -326,55 +337,12 @@ void __blk_mq_end_io(struct request *rq, int error)
                blk_mq_complete_request(rq, error);
 }
 
-#if defined(CONFIG_SMP)
-
-/*
- * Called with interrupts disabled.
- */
-static void ipi_end_io(void *data)
-{
-       struct llist_head *list = &per_cpu(ipi_lists, smp_processor_id());
-       struct llist_node *entry, *next;
-       struct request *rq;
-
-       entry = llist_del_all(list);
-
-       while (entry) {
-               next = entry->next;
-               rq = llist_entry(entry, struct request, ll_list);
-               __blk_mq_end_io(rq, rq->errors);
-               entry = next;
-       }
-}
-
-static int ipi_remote_cpu(struct blk_mq_ctx *ctx, const int cpu,
-                         struct request *rq, const int error)
+static void blk_mq_end_io_remote(void *data)
 {
-       struct call_single_data *data = &rq->csd;
-
-       rq->errors = error;
-       rq->ll_list.next = NULL;
+       struct request *rq = data;
 
-       /*
-        * If the list is non-empty, an existing IPI must already
-        * be "in flight". If that is the case, we need not schedule
-        * a new one.
-        */
-       if (llist_add(&rq->ll_list, &per_cpu(ipi_lists, ctx->cpu))) {
-               data->func = ipi_end_io;
-               data->flags = 0;
-               __smp_call_function_single(ctx->cpu, data, 0);
-       }
-
-       return true;
-}
-#else /* CONFIG_SMP */
-static int ipi_remote_cpu(struct blk_mq_ctx *ctx, const int cpu,
-                         struct request *rq, const int error)
-{
-       return false;
+       __blk_mq_end_io(rq, rq->errors);
 }
-#endif
 
 /*
  * End IO on this request on a multiqueue enabled driver. We'll either do
@@ -390,11 +358,15 @@ void blk_mq_end_io(struct request *rq, int error)
                return __blk_mq_end_io(rq, error);
 
        cpu = get_cpu();
-
-       if (cpu == ctx->cpu || !cpu_online(ctx->cpu) ||
-           !ipi_remote_cpu(ctx, cpu, rq, error))
+       if (cpu != ctx->cpu && cpu_online(ctx->cpu)) {
+               rq->errors = error;
+               rq->csd.func = blk_mq_end_io_remote;
+               rq->csd.info = rq;
+               rq->csd.flags = 0;
+               __smp_call_function_single(ctx->cpu, &rq->csd, 0);
+       } else {
                __blk_mq_end_io(rq, error);
-
+       }
        put_cpu();
 }
 EXPORT_SYMBOL(blk_mq_end_io);
@@ -1091,8 +1063,8 @@ static void blk_mq_free_rq_map(struct blk_mq_hw_ctx *hctx)
        struct page *page;
 
        while (!list_empty(&hctx->page_list)) {
-               page = list_first_entry(&hctx->page_list, struct page, list);
-               list_del_init(&page->list);
+               page = list_first_entry(&hctx->page_list, struct page, lru);
+               list_del_init(&page->lru);
                __free_pages(page, page->private);
        }
 
@@ -1156,7 +1128,7 @@ static int blk_mq_init_rq_map(struct blk_mq_hw_ctx *hctx,
                        break;
 
                page->private = this_order;
-               list_add_tail(&page->list, &hctx->page_list);
+               list_add_tail(&page->lru, &hctx->page_list);
 
                p = page_address(page);
                entries_per_page = order_to_size(this_order) / rq_size;
@@ -1429,7 +1401,6 @@ void blk_mq_free_queue(struct request_queue *q)
        int i;
 
        queue_for_each_hw_ctx(q, hctx, i) {
-               cancel_delayed_work_sync(&hctx->delayed_work);
                kfree(hctx->ctx_map);
                kfree(hctx->ctxs);
                blk_mq_free_rq_map(hctx);
@@ -1451,7 +1422,6 @@ void blk_mq_free_queue(struct request_queue *q)
        list_del_init(&q->all_q_node);
        mutex_unlock(&all_q_mutex);
 }
-EXPORT_SYMBOL(blk_mq_free_queue);
 
 /* Basically redo blk_mq_init_queue with queue frozen */
 static void blk_mq_queue_reinit(struct request_queue *q)
@@ -1495,11 +1465,6 @@ static int blk_mq_queue_reinit_notify(struct notifier_block *nb,
 
 static int __init blk_mq_init(void)
 {
-       unsigned int i;
-
-       for_each_possible_cpu(i)
-               init_llist_head(&per_cpu(ipi_lists, i));
-
        blk_mq_cpu_init();
 
        /* Must be called after percpu_counter_hotcpu_callback() */
index 52bf1f96a2c239195e564fb5bdb19164709770f4..5c3917984b005f13ea35254074744ec91f2e5bd3 100644 (file)
@@ -27,6 +27,8 @@ void blk_mq_complete_request(struct request *rq, int error);
 void blk_mq_run_request(struct request *rq, bool run_queue, bool async);
 void blk_mq_run_hw_queue(struct blk_mq_hw_ctx *hctx, bool async);
 void blk_mq_init_flush(struct request_queue *q);
+void blk_mq_drain_queue(struct request_queue *q);
+void blk_mq_free_queue(struct request_queue *q);
 
 /*
  * CPU hotplug helpers
@@ -38,7 +40,6 @@ void blk_mq_init_cpu_notifier(struct blk_mq_cpu_notifier *notifier,
 void blk_mq_register_cpu_notifier(struct blk_mq_cpu_notifier *notifier);
 void blk_mq_unregister_cpu_notifier(struct blk_mq_cpu_notifier *notifier);
 void blk_mq_cpu_init(void);
-DECLARE_PER_CPU(struct llist_head, ipi_lists);
 
 /*
  * CPU -> queue mappings
index 05e826793e4e36b2e6c8de29802674767e3bd4d8..5d21239bc8599feb3fa12fa4906ba57aaf1c553f 100644 (file)
@@ -592,6 +592,10 @@ int blk_stack_limits(struct queue_limits *t, struct queue_limits *b,
                ret = -1;
        }
 
+       t->raid_partial_stripes_expensive =
+               max(t->raid_partial_stripes_expensive,
+                   b->raid_partial_stripes_expensive);
+
        /* Find lowest common alignment_offset */
        t->alignment_offset = lcm(t->alignment_offset, alignment)
                & (max(t->physical_block_size, t->io_min) - 1);
index 97779522472f8356d5b09e91a33b1b310293d230..8095c4a21fc0f53e6e46ff191de283500dcc97de 100644 (file)
@@ -11,6 +11,7 @@
 
 #include "blk.h"
 #include "blk-cgroup.h"
+#include "blk-mq.h"
 
 struct queue_sysfs_entry {
        struct attribute attr;
index a760857e6b62609dde239ad74aebe2b5ac2ebaac..1474c3ab7e72cb85698ffe8bb3687df66729281b 100644 (file)
@@ -877,14 +877,14 @@ static bool tg_with_in_bps_limit(struct throtl_grp *tg, struct bio *bio,
        do_div(tmp, HZ);
        bytes_allowed = tmp;
 
-       if (tg->bytes_disp[rw] + bio->bi_size <= bytes_allowed) {
+       if (tg->bytes_disp[rw] + bio->bi_iter.bi_size <= bytes_allowed) {
                if (wait)
                        *wait = 0;
                return 1;
        }
 
        /* Calc approx time to dispatch */
-       extra_bytes = tg->bytes_disp[rw] + bio->bi_size - bytes_allowed;
+       extra_bytes = tg->bytes_disp[rw] + bio->bi_iter.bi_size - bytes_allowed;
        jiffy_wait = div64_u64(extra_bytes * HZ, tg->bps[rw]);
 
        if (!jiffy_wait)
@@ -987,7 +987,7 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
        bool rw = bio_data_dir(bio);
 
        /* Charge the bio to the group */
-       tg->bytes_disp[rw] += bio->bi_size;
+       tg->bytes_disp[rw] += bio->bi_iter.bi_size;
        tg->io_disp[rw]++;
 
        /*
@@ -1003,8 +1003,8 @@ static void throtl_charge_bio(struct throtl_grp *tg, struct bio *bio)
         */
        if (!(bio->bi_rw & REQ_THROTTLED)) {
                bio->bi_rw |= REQ_THROTTLED;
-               throtl_update_dispatch_stats(tg_to_blkg(tg), bio->bi_size,
-                                            bio->bi_rw);
+               throtl_update_dispatch_stats(tg_to_blkg(tg),
+                                            bio->bi_iter.bi_size, bio->bi_rw);
        }
 }
 
@@ -1503,7 +1503,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
        if (tg) {
                if (!tg->has_rules[rw]) {
                        throtl_update_dispatch_stats(tg_to_blkg(tg),
-                                                    bio->bi_size, bio->bi_rw);
+                                       bio->bi_iter.bi_size, bio->bi_rw);
                        goto out_unlock_rcu;
                }
        }
@@ -1559,7 +1559,7 @@ bool blk_throtl_bio(struct request_queue *q, struct bio *bio)
        /* out-of-limit, queue to @tg */
        throtl_log(sq, "[%c] bio. bdisp=%llu sz=%u bps=%llu iodisp=%u iops=%u queued=%d/%d",
                   rw == READ ? 'R' : 'W',
-                  tg->bytes_disp[rw], bio->bi_size, tg->bps[rw],
+                  tg->bytes_disp[rw], bio->bi_iter.bi_size, tg->bps[rw],
                   tg->io_disp[rw], tg->iops[rw],
                   sq->nr_queued[READ], sq->nr_queued[WRITE]);
 
index cc2637f8674ed61df149fb3bf51da4cc3a04f7cf..9dbc67e42a993193fb56d169cab00ecf4b825ef0 100644 (file)
@@ -4,8 +4,7 @@
  * Written by Cai Zhiyong <caizhiyong@huawei.com>
  *
  */
-#include <linux/buffer_head.h>
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/cmdline-parser.h>
 
 static int parse_subpart(struct cmdline_subpart **subpart, char *partdef)
@@ -159,6 +158,7 @@ void cmdline_parts_free(struct cmdline_parts **parts)
                *parts = next_parts;
        }
 }
+EXPORT_SYMBOL(cmdline_parts_free);
 
 int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline)
 {
@@ -206,6 +206,7 @@ fail:
        cmdline_parts_free(parts);
        goto done;
 }
+EXPORT_SYMBOL(cmdline_parts_parse);
 
 struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
                                         const char *bdev)
@@ -214,17 +215,17 @@ struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
                parts = parts->next_parts;
        return parts;
 }
+EXPORT_SYMBOL(cmdline_parts_find);
 
 /*
  *  add_part()
  *    0 success.
  *    1 can not add so many partitions.
  */
-void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
-                      int slot,
-                      int (*add_part)(int, struct cmdline_subpart *, void *),
-                      void *param)
-
+int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
+                     int slot,
+                     int (*add_part)(int, struct cmdline_subpart *, void *),
+                     void *param)
 {
        sector_t from = 0;
        struct cmdline_subpart *subpart;
@@ -247,4 +248,7 @@ void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
                if (add_part(slot, subpart, param))
                        break;
        }
+
+       return slot;
 }
+EXPORT_SYMBOL(cmdline_parts_set);
index b7ff2861b6bdc0bd8e57528ac776fc9b923b5c70..42c45a7d67144a5598f5d7b2242a63eb9d58e292 100644 (file)
@@ -440,7 +440,7 @@ int elv_merge(struct request_queue *q, struct request **req, struct bio *bio)
        /*
         * See if our hash lookup can find a potential backmerge.
         */
-       __rq = elv_rqhash_find(q, bio->bi_sector);
+       __rq = elv_rqhash_find(q, bio->bi_iter.bi_sector);
        if (__rq && elv_rq_merge_ok(__rq, bio)) {
                *req = __rq;
                return ELEVATOR_BACK_MERGE;
index 625e3e471d65f55495bd639b0418e8ad85d53d62..26487972ac549ba899a723201125e5b3c59934ff 100644 (file)
@@ -323,12 +323,14 @@ static int sg_io(struct request_queue *q, struct gendisk *bd_disk,
 
        if (hdr->iovec_count) {
                size_t iov_data_len;
-               struct iovec *iov;
+               struct iovec *iov = NULL;
 
                ret = rw_copy_check_uvector(-1, hdr->dxferp, hdr->iovec_count,
                                            0, NULL, &iov);
-               if (ret < 0)
+               if (ret < 0) {
+                       kfree(iov);
                        goto out;
+               }
 
                iov_data_len = ret;
                ret = 0;
index c9311be29a64991ee56563c5c2262e541302ebd7..c29c2c3ec0ad8ffc2c6427393593dbf147899d1b 100644 (file)
@@ -261,7 +261,7 @@ static int acpi_processor_get_info(struct acpi_device *device)
 
        apic_id = acpi_get_apicid(pr->handle, device_declaration, pr->acpi_id);
        if (apic_id < 0) {
-               acpi_handle_err(pr->handle, "failed to get CPU APIC ID.\n");
+               acpi_handle_debug(pr->handle, "failed to get CPU APIC ID.\n");
                return -ENODEV;
        }
        pr->apic_id = apic_id;
index 24db8e153bf0e83770573ccc70608b51ea90ddaa..4ed1aa384df2fd7680268c569a0388434b76d7d4 100644 (file)
@@ -108,7 +108,7 @@ u8 ACPI_INIT_GLOBAL(acpi_gbl_use_default_register_widths, TRUE);
 /*
  * Optionally enable output from the AML Debug Object.
  */
-bool ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
+u8 ACPI_INIT_GLOBAL(acpi_gbl_enable_aml_debug_object, FALSE);
 
 /*
  * Optionally copy the entire DSDT to local memory (instead of simply
index 384da5ab595573a0daf9faf22fa3815889fadcb8..fcb59c21c68d5c53696a29749d88792f58bc4a64 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/proc_fs.h>
 #include <linux/acpi.h>
 #include <linux/slab.h>
+#include <linux/regulator/machine.h>
 #ifdef CONFIG_X86
 #include <asm/mpspec.h>
 #endif
@@ -509,6 +510,14 @@ void __init acpi_early_init(void)
                goto error0;
        }
 
+       /*
+        * If the system is using ACPI then we can be reasonably
+        * confident that any regulators are managed by the firmware
+        * so tell the regulator core it has everything it needs to
+        * know.
+        */
+       regulator_has_full_constraints();
+
        return;
 
       error0:
index d49f1e46470370908d72b6efb7677d70f80ded98..c14a00d3dca61e5d943c41d5fe11fb90669550a6 100644 (file)
@@ -726,18 +726,6 @@ int acpi_pm_device_sleep_wake(struct device *dev, bool enable)
 }
 #endif /* CONFIG_PM_SLEEP */
 
-/**
- * acpi_dev_pm_get_node - Get ACPI device node for the given physical device.
- * @dev: Device to get the ACPI node for.
- */
-struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
-{
-       acpi_handle handle = ACPI_HANDLE(dev);
-       struct acpi_device *adev;
-
-       return handle && !acpi_bus_get_device(handle, &adev) ? adev : NULL;
-}
-
 /**
  * acpi_dev_pm_low_power - Put ACPI device into a low-power state.
  * @dev: Device to put into a low-power state.
@@ -778,7 +766,7 @@ static int acpi_dev_pm_full_power(struct acpi_device *adev)
  */
 int acpi_dev_runtime_suspend(struct device *dev)
 {
-       struct acpi_device *adev = acpi_dev_pm_get_node(dev);
+       struct acpi_device *adev = ACPI_COMPANION(dev);
        bool remote_wakeup;
        int error;
 
@@ -809,7 +797,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_runtime_suspend);
  */
 int acpi_dev_runtime_resume(struct device *dev)
 {
-       struct acpi_device *adev = acpi_dev_pm_get_node(dev);
+       struct acpi_device *adev = ACPI_COMPANION(dev);
        int error;
 
        if (!adev)
@@ -862,7 +850,7 @@ EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume);
  */
 int acpi_dev_suspend_late(struct device *dev)
 {
-       struct acpi_device *adev = acpi_dev_pm_get_node(dev);
+       struct acpi_device *adev = ACPI_COMPANION(dev);
        u32 target_state;
        bool wakeup;
        int error;
@@ -894,7 +882,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_suspend_late);
  */
 int acpi_dev_resume_early(struct device *dev)
 {
-       struct acpi_device *adev = acpi_dev_pm_get_node(dev);
+       struct acpi_device *adev = ACPI_COMPANION(dev);
        int error;
 
        if (!adev)
@@ -985,7 +973,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
  */
 int acpi_dev_pm_attach(struct device *dev, bool power_on)
 {
-       struct acpi_device *adev = acpi_dev_pm_get_node(dev);
+       struct acpi_device *adev = ACPI_COMPANION(dev);
 
        if (!adev)
                return -ENODEV;
@@ -1017,7 +1005,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_pm_attach);
  */
 void acpi_dev_pm_detach(struct device *dev, bool power_off)
 {
-       struct acpi_device *adev = acpi_dev_pm_get_node(dev);
+       struct acpi_device *adev = ACPI_COMPANION(dev);
 
        if (adev && dev->pm_domain == &acpi_general_pm_domain) {
                dev->pm_domain = NULL;
index 34e7b3c6a08de157c6c962bd0643ddb67176bd5e..a4eea9a508d3efd977fe97563b967b776a49a084 100644 (file)
@@ -44,13 +44,13 @@ static int map_lapic_id(struct acpi_subtable_header *entry,
                (struct acpi_madt_local_apic *)entry;
 
        if (!(lapic->lapic_flags & ACPI_MADT_ENABLED))
-               return 0;
+               return -ENODEV;
 
        if (lapic->processor_id != acpi_id)
-               return 0;
+               return -EINVAL;
 
        *apic_id = lapic->id;
-       return 1;
+       return 0;
 }
 
 static int map_x2apic_id(struct acpi_subtable_header *entry,
@@ -60,14 +60,14 @@ static int map_x2apic_id(struct acpi_subtable_header *entry,
                (struct acpi_madt_local_x2apic *)entry;
 
        if (!(apic->lapic_flags & ACPI_MADT_ENABLED))
-               return 0;
+               return -ENODEV;
 
        if (device_declaration && (apic->uid == acpi_id)) {
                *apic_id = apic->local_apic_id;
-               return 1;
+               return 0;
        }
 
-       return 0;
+       return -EINVAL;
 }
 
 static int map_lsapic_id(struct acpi_subtable_header *entry,
@@ -77,16 +77,16 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,
                (struct acpi_madt_local_sapic *)entry;
 
        if (!(lsapic->lapic_flags & ACPI_MADT_ENABLED))
-               return 0;
+               return -ENODEV;
 
        if (device_declaration) {
                if ((entry->length < 16) || (lsapic->uid != acpi_id))
-                       return 0;
+                       return -EINVAL;
        } else if (lsapic->processor_id != acpi_id)
-               return 0;
+               return -EINVAL;
 
        *apic_id = (lsapic->id << 8) | lsapic->eid;
-       return 1;
+       return 0;
 }
 
 static int map_madt_entry(int type, u32 acpi_id)
@@ -116,13 +116,13 @@ static int map_madt_entry(int type, u32 acpi_id)
                struct acpi_subtable_header *header =
                        (struct acpi_subtable_header *)entry;
                if (header->type == ACPI_MADT_TYPE_LOCAL_APIC) {
-                       if (map_lapic_id(header, acpi_id, &apic_id))
+                       if (!map_lapic_id(header, acpi_id, &apic_id))
                                break;
                } else if (header->type == ACPI_MADT_TYPE_LOCAL_X2APIC) {
-                       if (map_x2apic_id(header, type, acpi_id, &apic_id))
+                       if (!map_x2apic_id(header, type, acpi_id, &apic_id))
                                break;
                } else if (header->type == ACPI_MADT_TYPE_LOCAL_SAPIC) {
-                       if (map_lsapic_id(header, type, acpi_id, &apic_id))
+                       if (!map_lsapic_id(header, type, acpi_id, &apic_id))
                                break;
                }
                entry += header->length;
index e00365ccb89750e8e1dcd1987ad800de65f9bbed..7384158c7f8770ddc4cd78d1570171a4cce9aae9 100644 (file)
@@ -2105,6 +2105,7 @@ void acpi_bus_trim(struct acpi_device *adev)
        list_for_each_entry_reverse(child, &adev->children, node)
                acpi_bus_trim(child);
 
+       adev->flags.match_driver = false;
        if (handler) {
                if (handler->detach)
                        handler->detach(adev);
index 443dc9366052f623b14b6ce278a2bafff81e15ac..91a32cefb11f6098fbea62d9744ed61ed864c4a9 100644 (file)
@@ -226,7 +226,7 @@ module_param_call(trace_state, param_set_trace_state, param_get_trace_state,
 /* /sys/modules/acpi/parameters/aml_debug_output */
 
 module_param_named(aml_debug_output, acpi_gbl_enable_aml_debug_object,
-                  bool, 0644);
+                  byte, 0644);
 MODULE_PARM_DESC(aml_debug_output,
                 "To enable/disable the ACPI Debug Object output.");
 
index 7c081b38ef3e840ed37248e2110e012e7ebb2191..0ee48be23837e2e6655f137d047a27dc7c3df60d 100644 (file)
@@ -75,6 +75,7 @@ config BCMA_DRIVER_GMAC_CMN
 config BCMA_DRIVER_GPIO
        bool "BCMA GPIO driver"
        depends on BCMA && GPIOLIB
+       select IRQ_DOMAIN if BCMA_HOST_SOC
        help
          Driver to provide access to the GPIO pins of the bcma bus.
 
index 45f0996a375231be24109df39f89d1ee707e1f21..25f9887a35d08e89600e8aca86fc8c72062600f6 100644 (file)
@@ -9,6 +9,9 @@
  */
 
 #include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/export.h>
 #include <linux/bcma/bcma.h>
 
@@ -73,19 +76,136 @@ static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio)
        bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
 }
 
+#if IS_BUILTIN(CONFIG_BCMA_HOST_SOC)
 static int bcma_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
 {
        struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
 
        if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
-               return bcma_core_irq(cc->core);
+               return irq_find_mapping(cc->irq_domain, gpio);
        else
                return -EINVAL;
 }
 
+static void bcma_gpio_irq_unmask(struct irq_data *d)
+{
+       struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d);
+       int gpio = irqd_to_hwirq(d);
+       u32 val = bcma_chipco_gpio_in(cc, BIT(gpio));
+
+       bcma_chipco_gpio_polarity(cc, BIT(gpio), val);
+       bcma_chipco_gpio_intmask(cc, BIT(gpio), BIT(gpio));
+}
+
+static void bcma_gpio_irq_mask(struct irq_data *d)
+{
+       struct bcma_drv_cc *cc = irq_data_get_irq_chip_data(d);
+       int gpio = irqd_to_hwirq(d);
+
+       bcma_chipco_gpio_intmask(cc, BIT(gpio), 0);
+}
+
+static struct irq_chip bcma_gpio_irq_chip = {
+       .name           = "BCMA-GPIO",
+       .irq_mask       = bcma_gpio_irq_mask,
+       .irq_unmask     = bcma_gpio_irq_unmask,
+};
+
+static irqreturn_t bcma_gpio_irq_handler(int irq, void *dev_id)
+{
+       struct bcma_drv_cc *cc = dev_id;
+       u32 val = bcma_cc_read32(cc, BCMA_CC_GPIOIN);
+       u32 mask = bcma_cc_read32(cc, BCMA_CC_GPIOIRQ);
+       u32 pol = bcma_cc_read32(cc, BCMA_CC_GPIOPOL);
+       unsigned long irqs = (val ^ pol) & mask;
+       int gpio;
+
+       if (!irqs)
+               return IRQ_NONE;
+
+       for_each_set_bit(gpio, &irqs, cc->gpio.ngpio)
+               generic_handle_irq(bcma_gpio_to_irq(&cc->gpio, gpio));
+       bcma_chipco_gpio_polarity(cc, irqs, val & irqs);
+
+       return IRQ_HANDLED;
+}
+
+static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc)
+{
+       struct gpio_chip *chip = &cc->gpio;
+       int gpio, hwirq, err;
+
+       if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC)
+               return 0;
+
+       cc->irq_domain = irq_domain_add_linear(NULL, chip->ngpio,
+                                              &irq_domain_simple_ops, cc);
+       if (!cc->irq_domain) {
+               err = -ENODEV;
+               goto err_irq_domain;
+       }
+       for (gpio = 0; gpio < chip->ngpio; gpio++) {
+               int irq = irq_create_mapping(cc->irq_domain, gpio);
+
+               irq_set_chip_data(irq, cc);
+               irq_set_chip_and_handler(irq, &bcma_gpio_irq_chip,
+                                        handle_simple_irq);
+       }
+
+       hwirq = bcma_core_irq(cc->core);
+       err = request_irq(hwirq, bcma_gpio_irq_handler, IRQF_SHARED, "gpio",
+                         cc);
+       if (err)
+               goto err_req_irq;
+
+       bcma_chipco_gpio_intmask(cc, ~0, 0);
+       bcma_cc_set32(cc, BCMA_CC_IRQMASK, BCMA_CC_IRQ_GPIO);
+
+       return 0;
+
+err_req_irq:
+       for (gpio = 0; gpio < chip->ngpio; gpio++) {
+               int irq = irq_find_mapping(cc->irq_domain, gpio);
+
+               irq_dispose_mapping(irq);
+       }
+       irq_domain_remove(cc->irq_domain);
+err_irq_domain:
+       return err;
+}
+
+static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc)
+{
+       struct gpio_chip *chip = &cc->gpio;
+       int gpio;
+
+       if (cc->core->bus->hosttype != BCMA_HOSTTYPE_SOC)
+               return;
+
+       bcma_cc_mask32(cc, BCMA_CC_IRQMASK, ~BCMA_CC_IRQ_GPIO);
+       free_irq(bcma_core_irq(cc->core), cc);
+       for (gpio = 0; gpio < chip->ngpio; gpio++) {
+               int irq = irq_find_mapping(cc->irq_domain, gpio);
+
+               irq_dispose_mapping(irq);
+       }
+       irq_domain_remove(cc->irq_domain);
+}
+#else
+static int bcma_gpio_irq_domain_init(struct bcma_drv_cc *cc)
+{
+       return 0;
+}
+
+static void bcma_gpio_irq_domain_exit(struct bcma_drv_cc *cc)
+{
+}
+#endif
+
 int bcma_gpio_init(struct bcma_drv_cc *cc)
 {
        struct gpio_chip *chip = &cc->gpio;
+       int err;
 
        chip->label             = "bcma_gpio";
        chip->owner             = THIS_MODULE;
@@ -95,7 +215,9 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
        chip->set               = bcma_gpio_set_value;
        chip->direction_input   = bcma_gpio_direction_input;
        chip->direction_output  = bcma_gpio_direction_output;
+#if IS_BUILTIN(CONFIG_BCMA_HOST_SOC)
        chip->to_irq            = bcma_gpio_to_irq;
+#endif
        chip->ngpio             = 16;
        /* There is just one SoC in one device and its GPIO addresses should be
         * deterministic to address them more easily. The other buses could get
@@ -105,10 +227,21 @@ int bcma_gpio_init(struct bcma_drv_cc *cc)
        else
                chip->base              = -1;
 
-       return gpiochip_add(chip);
+       err = bcma_gpio_irq_domain_init(cc);
+       if (err)
+               return err;
+
+       err = gpiochip_add(chip);
+       if (err) {
+               bcma_gpio_irq_domain_exit(cc);
+               return err;
+       }
+
+       return 0;
 }
 
 int bcma_gpio_unregister(struct bcma_drv_cc *cc)
 {
+       bcma_gpio_irq_domain_exit(cc);
        return gpiochip_remove(&cc->gpio);
 }
index 9ffa90c6201c3860779f4a3e7e162a368b766874..014a1cfc41c51fe5d69f0d76a31607d1834ba953 100644 (file)
@@ -108,6 +108,8 @@ source "drivers/block/paride/Kconfig"
 
 source "drivers/block/mtip32xx/Kconfig"
 
+source "drivers/block/zram/Kconfig"
+
 config BLK_CPQ_DA
        tristate "Compaq SMART2 support"
        depends on PCI && VIRT_TO_BUS && 0
index 816d979c32667f9549b7ef313f38f386b8790705..02b688d1438d95b6ad4f64cac713dacf77023c40 100644 (file)
@@ -42,6 +42,7 @@ obj-$(CONFIG_BLK_DEV_PCIESSD_MTIP32XX)        += mtip32xx/
 
 obj-$(CONFIG_BLK_DEV_RSXX) += rsxx/
 obj-$(CONFIG_BLK_DEV_NULL_BLK) += null_blk.o
+obj-$(CONFIG_ZRAM) += zram/
 
 nvme-y         := nvme-core.o nvme-scsi.o
 skd-y          := skd_main.o
index 14a9d1912318b99fe764108420b143159c2bca32..9220f8e833d08228297373d116c308176c8d44a8 100644 (file)
@@ -100,11 +100,8 @@ enum {
 
 struct buf {
        ulong nframesout;
-       ulong resid;
-       ulong bv_resid;
-       sector_t sector;
        struct bio *bio;
-       struct bio_vec *bv;
+       struct bvec_iter iter;
        struct request *rq;
 };
 
@@ -120,13 +117,10 @@ struct frame {
        ulong waited;
        ulong waited_total;
        struct aoetgt *t;               /* parent target I belong to */
-       sector_t lba;
        struct sk_buff *skb;            /* command skb freed on module exit */
        struct sk_buff *r_skb;          /* response skb for async processing */
        struct buf *buf;
-       struct bio_vec *bv;
-       ulong bcnt;
-       ulong bv_off;
+       struct bvec_iter iter;
        char flags;
 };
 
index d2515435e23f2f87215558ec703f5a625ab8ac80..8184451b57c04999bd23c286080e14ca7f069031 100644 (file)
@@ -196,8 +196,7 @@ aoe_freetframe(struct frame *f)
 
        t = f->t;
        f->buf = NULL;
-       f->lba = 0;
-       f->bv = NULL;
+       memset(&f->iter, 0, sizeof(f->iter));
        f->r_skb = NULL;
        f->flags = 0;
        list_add(&f->head, &t->ffree);
@@ -295,21 +294,14 @@ newframe(struct aoedev *d)
 }
 
 static void
-skb_fillup(struct sk_buff *skb, struct bio_vec *bv, ulong off, ulong cnt)
+skb_fillup(struct sk_buff *skb, struct bio *bio, struct bvec_iter iter)
 {
        int frag = 0;
-       ulong fcnt;
-loop:
-       fcnt = bv->bv_len - (off - bv->bv_offset);
-       if (fcnt > cnt)
-               fcnt = cnt;
-       skb_fill_page_desc(skb, frag++, bv->bv_page, off, fcnt);
-       cnt -= fcnt;
-       if (cnt <= 0)
-               return;
-       bv++;
-       off = bv->bv_offset;
-       goto loop;
+       struct bio_vec bv;
+
+       __bio_for_each_segment(bv, bio, iter, iter)
+               skb_fill_page_desc(skb, frag++, bv.bv_page,
+                                  bv.bv_offset, bv.bv_len);
 }
 
 static void
@@ -346,12 +338,10 @@ ata_rw_frameinit(struct frame *f)
        t->nout++;
        f->waited = 0;
        f->waited_total = 0;
-       if (f->buf)
-               f->lba = f->buf->sector;
 
        /* set up ata header */
-       ah->scnt = f->bcnt >> 9;
-       put_lba(ah, f->lba);
+       ah->scnt = f->iter.bi_size >> 9;
+       put_lba(ah, f->iter.bi_sector);
        if (t->d->flags & DEVFL_EXT) {
                ah->aflags |= AOEAFL_EXT;
        } else {
@@ -360,11 +350,11 @@ ata_rw_frameinit(struct frame *f)
                ah->lba3 |= 0xe0;       /* LBA bit + obsolete 0xa0 */
        }
        if (f->buf && bio_data_dir(f->buf->bio) == WRITE) {
-               skb_fillup(skb, f->bv, f->bv_off, f->bcnt);
+               skb_fillup(skb, f->buf->bio, f->iter);
                ah->aflags |= AOEAFL_WRITE;
-               skb->len += f->bcnt;
-               skb->data_len = f->bcnt;
-               skb->truesize += f->bcnt;
+               skb->len += f->iter.bi_size;
+               skb->data_len = f->iter.bi_size;
+               skb->truesize += f->iter.bi_size;
                t->wpkts++;
        } else {
                t->rpkts++;
@@ -382,7 +372,6 @@ aoecmd_ata_rw(struct aoedev *d)
        struct buf *buf;
        struct sk_buff *skb;
        struct sk_buff_head queue;
-       ulong bcnt, fbcnt;
 
        buf = nextbuf(d);
        if (buf == NULL)
@@ -390,39 +379,22 @@ aoecmd_ata_rw(struct aoedev *d)
        f = newframe(d);
        if (f == NULL)
                return 0;
-       bcnt = d->maxbcnt;
-       if (bcnt == 0)
-               bcnt = DEFAULTBCNT;
-       if (bcnt > buf->resid)
-               bcnt = buf->resid;
-       fbcnt = bcnt;
-       f->bv = buf->bv;
-       f->bv_off = f->bv->bv_offset + (f->bv->bv_len - buf->bv_resid);
-       do {
-               if (fbcnt < buf->bv_resid) {
-                       buf->bv_resid -= fbcnt;
-                       buf->resid -= fbcnt;
-                       break;
-               }
-               fbcnt -= buf->bv_resid;
-               buf->resid -= buf->bv_resid;
-               if (buf->resid == 0) {
-                       d->ip.buf = NULL;
-                       break;
-               }
-               buf->bv++;
-               buf->bv_resid = buf->bv->bv_len;
-               WARN_ON(buf->bv_resid == 0);
-       } while (fbcnt);
 
        /* initialize the headers & frame */
        f->buf = buf;
-       f->bcnt = bcnt;
-       ata_rw_frameinit(f);
+       f->iter = buf->iter;
+       f->iter.bi_size = min_t(unsigned long,
+                               d->maxbcnt ?: DEFAULTBCNT,
+                               f->iter.bi_size);
+       bio_advance_iter(buf->bio, &buf->iter, f->iter.bi_size);
+
+       if (!buf->iter.bi_size)
+               d->ip.buf = NULL;
 
        /* mark all tracking fields and load out */
        buf->nframesout += 1;
-       buf->sector += bcnt >> 9;
+
+       ata_rw_frameinit(f);
 
        skb = skb_clone(f->skb, GFP_ATOMIC);
        if (skb) {
@@ -613,10 +585,7 @@ reassign_frame(struct frame *f)
        skb = nf->skb;
        nf->skb = f->skb;
        nf->buf = f->buf;
-       nf->bcnt = f->bcnt;
-       nf->lba = f->lba;
-       nf->bv = f->bv;
-       nf->bv_off = f->bv_off;
+       nf->iter = f->iter;
        nf->waited = 0;
        nf->waited_total = f->waited_total;
        nf->sent = f->sent;
@@ -648,19 +617,19 @@ probe(struct aoetgt *t)
        }
        f->flags |= FFL_PROBE;
        ifrotate(t);
-       f->bcnt = t->d->maxbcnt ? t->d->maxbcnt : DEFAULTBCNT;
+       f->iter.bi_size = t->d->maxbcnt ? t->d->maxbcnt : DEFAULTBCNT;
        ata_rw_frameinit(f);
        skb = f->skb;
-       for (frag = 0, n = f->bcnt; n > 0; ++frag, n -= m) {
+       for (frag = 0, n = f->iter.bi_size; n > 0; ++frag, n -= m) {
                if (n < PAGE_SIZE)
                        m = n;
                else
                        m = PAGE_SIZE;
                skb_fill_page_desc(skb, frag, empty_page, 0, m);
        }
-       skb->len += f->bcnt;
-       skb->data_len = f->bcnt;
-       skb->truesize += f->bcnt;
+       skb->len += f->iter.bi_size;
+       skb->data_len = f->iter.bi_size;
+       skb->truesize += f->iter.bi_size;
 
        skb = skb_clone(f->skb, GFP_ATOMIC);
        if (skb) {
@@ -897,15 +866,15 @@ rqbiocnt(struct request *r)
 static void
 bio_pageinc(struct bio *bio)
 {
-       struct bio_vec *bv;
+       struct bio_vec bv;
        struct page *page;
-       int i;
+       struct bvec_iter iter;
 
-       bio_for_each_segment(bv, bio, i) {
+       bio_for_each_segment(bv, bio, iter) {
                /* Non-zero page count for non-head members of
                 * compound pages is no longer allowed by the kernel.
                 */
-               page = compound_trans_head(bv->bv_page);
+               page = compound_trans_head(bv.bv_page);
                atomic_inc(&page->_count);
        }
 }
@@ -913,12 +882,12 @@ bio_pageinc(struct bio *bio)
 static void
 bio_pagedec(struct bio *bio)
 {
-       struct bio_vec *bv;
        struct page *page;
-       int i;
+       struct bio_vec bv;
+       struct bvec_iter iter;
 
-       bio_for_each_segment(bv, bio, i) {
-               page = compound_trans_head(bv->bv_page);
+       bio_for_each_segment(bv, bio, iter) {
+               page = compound_trans_head(bv.bv_page);
                atomic_dec(&page->_count);
        }
 }
@@ -929,12 +898,8 @@ bufinit(struct buf *buf, struct request *rq, struct bio *bio)
        memset(buf, 0, sizeof(*buf));
        buf->rq = rq;
        buf->bio = bio;
-       buf->resid = bio->bi_size;
-       buf->sector = bio->bi_sector;
+       buf->iter = bio->bi_iter;
        bio_pageinc(bio);
-       buf->bv = bio_iovec(bio);
-       buf->bv_resid = buf->bv->bv_len;
-       WARN_ON(buf->bv_resid == 0);
 }
 
 static struct buf *
@@ -1119,24 +1084,18 @@ gettgt(struct aoedev *d, char *addr)
 }
 
 static void
-bvcpy(struct bio_vec *bv, ulong off, struct sk_buff *skb, long cnt)
+bvcpy(struct sk_buff *skb, struct bio *bio, struct bvec_iter iter, long cnt)
 {
-       ulong fcnt;
-       char *p;
        int soff = 0;
-loop:
-       fcnt = bv->bv_len - (off - bv->bv_offset);
-       if (fcnt > cnt)
-               fcnt = cnt;
-       p = page_address(bv->bv_page) + off;
-       skb_copy_bits(skb, soff, p, fcnt);
-       soff += fcnt;
-       cnt -= fcnt;
-       if (cnt <= 0)
-               return;
-       bv++;
-       off = bv->bv_offset;
-       goto loop;
+       struct bio_vec bv;
+
+       iter.bi_size = cnt;
+
+       __bio_for_each_segment(bv, bio, iter, iter) {
+               char *p = page_address(bv.bv_page) + bv.bv_offset;
+               skb_copy_bits(skb, soff, p, bv.bv_len);
+               soff += bv.bv_len;
+       }
 }
 
 void
@@ -1152,7 +1111,7 @@ aoe_end_request(struct aoedev *d, struct request *rq, int fastfail)
        do {
                bio = rq->bio;
                bok = !fastfail && test_bit(BIO_UPTODATE, &bio->bi_flags);
-       } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_size));
+       } while (__blk_end_request(rq, bok ? 0 : -EIO, bio->bi_iter.bi_size));
 
        /* cf. http://lkml.org/lkml/2006/10/31/28 */
        if (!fastfail)
@@ -1229,7 +1188,15 @@ noskb:           if (buf)
                        clear_bit(BIO_UPTODATE, &buf->bio->bi_flags);
                        break;
                }
-               bvcpy(f->bv, f->bv_off, skb, n);
+               if (n > f->iter.bi_size) {
+                       pr_err_ratelimited("%s e%ld.%d.  bytes=%ld need=%u\n",
+                               "aoe: too-large data size in read from",
+                               (long) d->aoemajor, d->aoeminor,
+                               n, f->iter.bi_size);
+                       clear_bit(BIO_UPTODATE, &buf->bio->bi_flags);
+                       break;
+               }
+               bvcpy(skb, f->buf->bio, f->iter, n);
        case ATA_CMD_PIO_WRITE:
        case ATA_CMD_PIO_WRITE_EXT:
                spin_lock_irq(&d->lock);
@@ -1272,7 +1239,7 @@ out:
 
        aoe_freetframe(f);
 
-       if (buf && --buf->nframesout == 0 && buf->resid == 0)
+       if (buf && --buf->nframesout == 0 && buf->iter.bi_size == 0)
                aoe_end_buf(d, buf);
 
        spin_unlock_irq(&d->lock);
@@ -1727,7 +1694,7 @@ aoe_failbuf(struct aoedev *d, struct buf *buf)
 {
        if (buf == NULL)
                return;
-       buf->resid = 0;
+       buf->iter.bi_size = 0;
        clear_bit(BIO_UPTODATE, &buf->bio->bi_flags);
        if (buf->nframesout == 0)
                aoe_end_buf(d, buf);
index d91f1a56e8617f56c019bfb6389bb79f71fa8ad2..e73b85cf0756876adbf4ad9b8220fc466bcdb412 100644 (file)
@@ -328,18 +328,18 @@ static void brd_make_request(struct request_queue *q, struct bio *bio)
        struct block_device *bdev = bio->bi_bdev;
        struct brd_device *brd = bdev->bd_disk->private_data;
        int rw;
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
        sector_t sector;
-       int i;
+       struct bvec_iter iter;
        int err = -EIO;
 
-       sector = bio->bi_sector;
+       sector = bio->bi_iter.bi_sector;
        if (bio_end_sector(bio) > get_capacity(bdev->bd_disk))
                goto out;
 
        if (unlikely(bio->bi_rw & REQ_DISCARD)) {
                err = 0;
-               discard_from_brd(brd, sector, bio->bi_size);
+               discard_from_brd(brd, sector, bio->bi_iter.bi_size);
                goto out;
        }
 
@@ -347,10 +347,10 @@ static void brd_make_request(struct request_queue *q, struct bio *bio)
        if (rw == READA)
                rw = READ;
 
-       bio_for_each_segment(bvec, bio, i) {
-               unsigned int len = bvec->bv_len;
-               err = brd_do_bvec(brd, bvec->bv_page, len,
-                                       bvec->bv_offset, rw, sector);
+       bio_for_each_segment(bvec, bio, iter) {
+               unsigned int len = bvec.bv_len;
+               err = brd_do_bvec(brd, bvec.bv_page, len,
+                                       bvec.bv_offset, rw, sector);
                if (err)
                        break;
                sector += len >> SECTOR_SHIFT;
index b35fc4f5237c3b44c7c51aaa0517e58a42a2ab81..036e8ab86c718057ae01c9f6bf3ba6c403a6b942 100644 (file)
@@ -5004,7 +5004,7 @@ reinit_after_soft_reset:
 
        i = alloc_cciss_hba(pdev);
        if (i < 0)
-               return -1;
+               return -ENOMEM;
 
        h = hba[i];
        h->pdev = pdev;
@@ -5205,7 +5205,7 @@ clean_no_release_regions:
         */
        pci_set_drvdata(pdev, NULL);
        free_hba(h);
-       return -1;
+       return -ENODEV;
 }
 
 static void cciss_shutdown(struct pci_dev *pdev)
index 28c73ca320a8f7f9b1741492785fa2f18e042d8c..a9b13f2cc420b055b8089fde687d601a23b8e635 100644 (file)
@@ -159,7 +159,7 @@ static int _drbd_md_sync_page_io(struct drbd_conf *mdev,
 
        bio = bio_alloc_drbd(GFP_NOIO);
        bio->bi_bdev = bdev->md_bdev;
-       bio->bi_sector = sector;
+       bio->bi_iter.bi_sector = sector;
        err = -EIO;
        if (bio_add_page(bio, page, size, 0) != size)
                goto out;
index b12c11ec4bd21e405fe75276d656e3519c8ad873..597f111df67b3597987eb816f8ff2ca2ec17c285 100644 (file)
@@ -1028,7 +1028,7 @@ static void bm_page_io_async(struct bm_aio_ctx *ctx, int page_nr, int rw) __must
        } else
                page = b->bm_pages[page_nr];
        bio->bi_bdev = mdev->ldev->md_bdev;
-       bio->bi_sector = on_disk_sector;
+       bio->bi_iter.bi_sector = on_disk_sector;
        /* bio_add_page of a single page to an empty bio will always succeed,
         * according to api.  Do we want to assert that? */
        bio_add_page(bio, page, len, 0);
index 9e3818b1bc8321e5883a1ef1b3dfe9542e7ea619..929468e1512a687d44bb310b8e3cc94a6b15161d 100644 (file)
@@ -1537,15 +1537,17 @@ static int _drbd_send_page(struct drbd_conf *mdev, struct page *page,
 
 static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
 {
-       struct bio_vec *bvec;
-       int i;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
+
        /* hint all but last page with MSG_MORE */
-       bio_for_each_segment(bvec, bio, i) {
+       bio_for_each_segment(bvec, bio, iter) {
                int err;
 
-               err = _drbd_no_send_page(mdev, bvec->bv_page,
-                                        bvec->bv_offset, bvec->bv_len,
-                                        i == bio->bi_vcnt - 1 ? 0 : MSG_MORE);
+               err = _drbd_no_send_page(mdev, bvec.bv_page,
+                                        bvec.bv_offset, bvec.bv_len,
+                                        bio_iter_last(bvec, iter)
+                                        ? 0 : MSG_MORE);
                if (err)
                        return err;
        }
@@ -1554,15 +1556,16 @@ static int _drbd_send_bio(struct drbd_conf *mdev, struct bio *bio)
 
 static int _drbd_send_zc_bio(struct drbd_conf *mdev, struct bio *bio)
 {
-       struct bio_vec *bvec;
-       int i;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
+
        /* hint all but last page with MSG_MORE */
-       bio_for_each_segment(bvec, bio, i) {
+       bio_for_each_segment(bvec, bio, iter) {
                int err;
 
-               err = _drbd_send_page(mdev, bvec->bv_page,
-                                     bvec->bv_offset, bvec->bv_len,
-                                     i == bio->bi_vcnt - 1 ? 0 : MSG_MORE);
+               err = _drbd_send_page(mdev, bvec.bv_page,
+                                     bvec.bv_offset, bvec.bv_len,
+                                     bio_iter_last(bvec, iter) ? 0 : MSG_MORE);
                if (err)
                        return err;
        }
index 6fa6673b36b396765b58142e8e8abcdc4beaae05..d073305ffd5e76e17a7d0804ad92be1ad82bba67 100644 (file)
@@ -1333,7 +1333,7 @@ next_bio:
                goto fail;
        }
        /* > peer_req->i.sector, unless this is the first bio */
-       bio->bi_sector = sector;
+       bio->bi_iter.bi_sector = sector;
        bio->bi_bdev = mdev->ldev->backing_bdev;
        bio->bi_rw = rw;
        bio->bi_private = peer_req;
@@ -1353,7 +1353,7 @@ next_bio:
                                dev_err(DEV,
                                        "bio_add_page failed for len=%u, "
                                        "bi_vcnt=0 (bi_sector=%llu)\n",
-                                       len, (unsigned long long)bio->bi_sector);
+                                       len, (uint64_t)bio->bi_iter.bi_sector);
                                err = -ENOSPC;
                                goto fail;
                        }
@@ -1595,9 +1595,10 @@ static int drbd_drain_block(struct drbd_conf *mdev, int data_size)
 static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
                           sector_t sector, int data_size)
 {
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
        struct bio *bio;
-       int dgs, err, i, expect;
+       int dgs, err, expect;
        void *dig_in = mdev->tconn->int_dig_in;
        void *dig_vv = mdev->tconn->int_dig_vv;
 
@@ -1615,13 +1616,13 @@ static int recv_dless_read(struct drbd_conf *mdev, struct drbd_request *req,
        mdev->recv_cnt += data_size>>9;
 
        bio = req->master_bio;
-       D_ASSERT(sector == bio->bi_sector);
+       D_ASSERT(sector == bio->bi_iter.bi_sector);
 
-       bio_for_each_segment(bvec, bio, i) {
-               void *mapped = kmap(bvec->bv_page) + bvec->bv_offset;
-               expect = min_t(int, data_size, bvec->bv_len);
+       bio_for_each_segment(bvec, bio, iter) {
+               void *mapped = kmap(bvec.bv_page) + bvec.bv_offset;
+               expect = min_t(int, data_size, bvec.bv_len);
                err = drbd_recv_all_warn(mdev->tconn, mapped, expect);
-               kunmap(bvec->bv_page);
+               kunmap(bvec.bv_page);
                if (err)
                        return err;
                data_size -= expect;
index fec7bef44994cf8b76e595f69b5e34b42cdaf230..104a040f24de74141274b364ee625aa49eefbb94 100644 (file)
@@ -77,8 +77,8 @@ static struct drbd_request *drbd_req_new(struct drbd_conf *mdev,
        req->epoch       = 0;
 
        drbd_clear_interval(&req->i);
-       req->i.sector     = bio_src->bi_sector;
-       req->i.size      = bio_src->bi_size;
+       req->i.sector     = bio_src->bi_iter.bi_sector;
+       req->i.size      = bio_src->bi_iter.bi_size;
        req->i.local = true;
        req->i.waiting = false;
 
@@ -1280,7 +1280,7 @@ void drbd_make_request(struct request_queue *q, struct bio *bio)
        /*
         * what we "blindly" assume:
         */
-       D_ASSERT(IS_ALIGNED(bio->bi_size, 512));
+       D_ASSERT(IS_ALIGNED(bio->bi_iter.bi_size, 512));
 
        inc_ap_bio(mdev);
        __drbd_make_request(mdev, bio, start_time);
index 978cb1addc98845fb8ca49838cfb5ec2478170f7..28e15d91197af1b234e43136740709adc090bcde 100644 (file)
@@ -269,7 +269,7 @@ static inline void drbd_req_make_private_bio(struct drbd_request *req, struct bi
 
 /* Short lived temporary struct on the stack.
  * We could squirrel the error to be returned into
- * bio->bi_size, or similar. But that would be too ugly. */
+ * bio->bi_iter.bi_size, or similar. But that would be too ugly. */
 struct bio_and_error {
        struct bio *bio;
        int error;
index 891c0ecaa292c84998f7357b82e3a80cdc0f6484..84d3175d493aaef91edabd97297238a717f6973c 100644 (file)
@@ -313,8 +313,8 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *
 {
        struct hash_desc desc;
        struct scatterlist sg;
-       struct bio_vec *bvec;
-       int i;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
 
        desc.tfm = tfm;
        desc.flags = 0;
@@ -322,8 +322,8 @@ void drbd_csum_bio(struct drbd_conf *mdev, struct crypto_hash *tfm, struct bio *
        sg_init_table(&sg, 1);
        crypto_hash_init(&desc);
 
-       bio_for_each_segment(bvec, bio, i) {
-               sg_set_page(&sg, bvec->bv_page, bvec->bv_len, bvec->bv_offset);
+       bio_for_each_segment(bvec, bio, iter) {
+               sg_set_page(&sg, bvec.bv_page, bvec.bv_len, bvec.bv_offset);
                crypto_hash_update(&desc, &sg, sg.length);
        }
        crypto_hash_final(&desc, digest);
index 000abe2f105c60f06d5fac31a2a4889cddd22b15..2023043ce7c0e94b0e3c3618eb0787a9ad5ddb73 100644 (file)
@@ -2351,7 +2351,7 @@ static void rw_interrupt(void)
 /* Compute maximal contiguous buffer size. */
 static int buffer_chain_size(void)
 {
-       struct bio_vec *bv;
+       struct bio_vec bv;
        int size;
        struct req_iterator iter;
        char *base;
@@ -2360,10 +2360,10 @@ static int buffer_chain_size(void)
        size = 0;
 
        rq_for_each_segment(bv, current_req, iter) {
-               if (page_address(bv->bv_page) + bv->bv_offset != base + size)
+               if (page_address(bv.bv_page) + bv.bv_offset != base + size)
                        break;
 
-               size += bv->bv_len;
+               size += bv.bv_len;
        }
 
        return size >> 9;
@@ -2389,7 +2389,7 @@ static int transfer_size(int ssize, int max_sector, int max_size)
 static void copy_buffer(int ssize, int max_sector, int max_sector_2)
 {
        int remaining;          /* number of transferred 512-byte sectors */
-       struct bio_vec *bv;
+       struct bio_vec bv;
        char *buffer;
        char *dma_buffer;
        int size;
@@ -2427,10 +2427,10 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
                if (!remaining)
                        break;
 
-               size = bv->bv_len;
+               size = bv.bv_len;
                SUPBOUND(size, remaining);
 
-               buffer = page_address(bv->bv_page) + bv->bv_offset;
+               buffer = page_address(bv.bv_page) + bv.bv_offset;
                if (dma_buffer + size >
                    floppy_track_buffer + (max_buffer_sectors << 10) ||
                    dma_buffer < floppy_track_buffer) {
@@ -3691,9 +3691,12 @@ static int floppy_open(struct block_device *bdev, fmode_t mode)
        if (!(mode & FMODE_NDELAY)) {
                if (mode & (FMODE_READ|FMODE_WRITE)) {
                        UDRS->last_checked = 0;
+                       clear_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
                        check_disk_change(bdev);
                        if (test_bit(FD_DISK_CHANGED_BIT, &UDRS->flags))
                                goto out;
+                       if (test_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags))
+                               goto out;
                }
                res = -EROFS;
                if ((mode & FMODE_WRITE) &&
@@ -3746,17 +3749,29 @@ static unsigned int floppy_check_events(struct gendisk *disk,
  * a disk in the drive, and whether that disk is writable.
  */
 
-static void floppy_rb0_complete(struct bio *bio, int err)
+struct rb0_cbdata {
+       int drive;
+       struct completion complete;
+};
+
+static void floppy_rb0_cb(struct bio *bio, int err)
 {
-       complete((struct completion *)bio->bi_private);
+       struct rb0_cbdata *cbdata = (struct rb0_cbdata *)bio->bi_private;
+       int drive = cbdata->drive;
+
+       if (err) {
+               pr_info("floppy: error %d while reading block 0", err);
+               set_bit(FD_OPEN_SHOULD_FAIL_BIT, &UDRS->flags);
+       }
+       complete(&cbdata->complete);
 }
 
-static int __floppy_read_block_0(struct block_device *bdev)
+static int __floppy_read_block_0(struct block_device *bdev, int drive)
 {
        struct bio bio;
        struct bio_vec bio_vec;
-       struct completion complete;
        struct page *page;
+       struct rb0_cbdata cbdata;
        size_t size;
 
        page = alloc_page(GFP_NOIO);
@@ -3769,23 +3784,26 @@ static int __floppy_read_block_0(struct block_device *bdev)
        if (!size)
                size = 1024;
 
+       cbdata.drive = drive;
+
        bio_init(&bio);
        bio.bi_io_vec = &bio_vec;
        bio_vec.bv_page = page;
        bio_vec.bv_len = size;
        bio_vec.bv_offset = 0;
        bio.bi_vcnt = 1;
-       bio.bi_size = size;
+       bio.bi_iter.bi_size = size;
        bio.bi_bdev = bdev;
-       bio.bi_sector = 0;
+       bio.bi_iter.bi_sector = 0;
        bio.bi_flags = (1 << BIO_QUIET);
-       init_completion(&complete);
-       bio.bi_private = &complete;
-       bio.bi_end_io = floppy_rb0_complete;
+       bio.bi_private = &cbdata;
+       bio.bi_end_io = floppy_rb0_cb;
 
        submit_bio(READ, &bio);
        process_fd_request();
-       wait_for_completion(&complete);
+
+       init_completion(&cbdata.complete);
+       wait_for_completion(&cbdata.complete);
 
        __free_page(page);
 
@@ -3827,7 +3845,7 @@ static int floppy_revalidate(struct gendisk *disk)
                        UDRS->generation++;
                if (drive_no_geom(drive)) {
                        /* auto-sensing */
-                       res = __floppy_read_block_0(opened_bdev[drive]);
+                       res = __floppy_read_block_0(opened_bdev[drive], drive);
                } else {
                        if (cf)
                                poll_drive(false, FD_RAW_NEED_DISK);
index c8dac730524408f63e78cb9acdae8294aaf8dafa..66e8c3b94ef35443f46bf67ea3065023da8b808d 100644 (file)
@@ -288,9 +288,10 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos)
 {
        int (*do_lo_send)(struct loop_device *, struct bio_vec *, loff_t,
                        struct page *page);
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
        struct page *page = NULL;
-       int i, ret = 0;
+       int ret = 0;
 
        if (lo->transfer != transfer_none) {
                page = alloc_page(GFP_NOIO | __GFP_HIGHMEM);
@@ -302,11 +303,11 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos)
                do_lo_send = do_lo_send_direct_write;
        }
 
-       bio_for_each_segment(bvec, bio, i) {
-               ret = do_lo_send(lo, bvec, pos, page);
+       bio_for_each_segment(bvec, bio, iter) {
+               ret = do_lo_send(lo, &bvec, pos, page);
                if (ret < 0)
                        break;
-               pos += bvec->bv_len;
+               pos += bvec.bv_len;
        }
        if (page) {
                kunmap(page);
@@ -392,20 +393,20 @@ do_lo_receive(struct loop_device *lo,
 static int
 lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
 {
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
        ssize_t s;
-       int i;
 
-       bio_for_each_segment(bvec, bio, i) {
-               s = do_lo_receive(lo, bvec, bsize, pos);
+       bio_for_each_segment(bvec, bio, iter) {
+               s = do_lo_receive(lo, &bvec, bsize, pos);
                if (s < 0)
                        return s;
 
-               if (s != bvec->bv_len) {
+               if (s != bvec.bv_len) {
                        zero_fill_bio(bio);
                        break;
                }
-               pos += bvec->bv_len;
+               pos += bvec.bv_len;
        }
        return 0;
 }
@@ -415,7 +416,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
        loff_t pos;
        int ret;
 
-       pos = ((loff_t) bio->bi_sector << 9) + lo->lo_offset;
+       pos = ((loff_t) bio->bi_iter.bi_sector << 9) + lo->lo_offset;
 
        if (bio_rw(bio) == WRITE) {
                struct file *file = lo->lo_backing_file;
@@ -444,7 +445,7 @@ static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
                                goto out;
                        }
                        ret = file->f_op->fallocate(file, mode, pos,
-                                                   bio->bi_size);
+                                                   bio->bi_iter.bi_size);
                        if (unlikely(ret && ret != -EINVAL &&
                                     ret != -EOPNOTSUPP))
                                ret = -EIO;
@@ -798,7 +799,7 @@ static void loop_config_discard(struct loop_device *lo)
 
        /*
         * We use punch hole to reclaim the free space used by the
-        * image a.k.a. discard. However we do support discard if
+        * image a.k.a. discard. However we do not support discard if
         * encryption is enabled, because it may give an attacker
         * useful information.
         */
index 7bc363f1ee82241227452594a78a1e7c5c2d3eca..eb59b124136690e217897dd6003473e09e5bd64a 100644 (file)
@@ -915,7 +915,7 @@ static int mg_probe(struct platform_device *plat_dev)
 
        /* disk reset */
        if (prv_data->dev_attr == MG_STORAGE_DEV) {
-               /* If POR seq. not yet finised, wait */
+               /* If POR seq. not yet finished, wait */
                err = mg_wait_rstout(host->rstout, MG_TMAX_RSTOUT);
                if (err)
                        goto probe_err_3b;
index 050c71267f146340281992e341ab86c93d79c33d..516026954be62d325a9e9d7c5541e5fbf51c7569 100644 (file)
 #include "mtip32xx.h"
 
 #define HW_CMD_SLOT_SZ         (MTIP_MAX_COMMAND_SLOTS * 32)
-#define HW_CMD_TBL_SZ          (AHCI_CMD_TBL_HDR_SZ + (MTIP_MAX_SG * 16))
-#define HW_CMD_TBL_AR_SZ       (HW_CMD_TBL_SZ * MTIP_MAX_COMMAND_SLOTS)
-#define HW_PORT_PRIV_DMA_SZ \
-               (HW_CMD_SLOT_SZ + HW_CMD_TBL_AR_SZ + AHCI_RX_FIS_SZ)
+
+/* DMA region containing RX Fis, Identify, RLE10, and SMART buffers */
+#define AHCI_RX_FIS_SZ          0x100
+#define AHCI_RX_FIS_OFFSET      0x0
+#define AHCI_IDFY_SZ            ATA_SECT_SIZE
+#define AHCI_IDFY_OFFSET        0x400
+#define AHCI_SECTBUF_SZ         ATA_SECT_SIZE
+#define AHCI_SECTBUF_OFFSET     0x800
+#define AHCI_SMARTBUF_SZ        ATA_SECT_SIZE
+#define AHCI_SMARTBUF_OFFSET    0xC00
+/* 0x100 + 0x200 + 0x200 + 0x200 is smaller than 4k but we pad it out */
+#define BLOCK_DMA_ALLOC_SZ      4096
+
+/* DMA region containing command table (should be 8192 bytes) */
+#define AHCI_CMD_SLOT_SZ        sizeof(struct mtip_cmd_hdr)
+#define AHCI_CMD_TBL_SZ         (MTIP_MAX_COMMAND_SLOTS * AHCI_CMD_SLOT_SZ)
+#define AHCI_CMD_TBL_OFFSET     0x0
+
+/* DMA region per command (contains header and SGL) */
+#define AHCI_CMD_TBL_HDR_SZ     0x80
+#define AHCI_CMD_TBL_HDR_OFFSET 0x0
+#define AHCI_CMD_TBL_SGL_SZ     (MTIP_MAX_SG * sizeof(struct mtip_cmd_sg))
+#define AHCI_CMD_TBL_SGL_OFFSET AHCI_CMD_TBL_HDR_SZ
+#define CMD_DMA_ALLOC_SZ        (AHCI_CMD_TBL_SGL_SZ + AHCI_CMD_TBL_HDR_SZ)
+
 
 #define HOST_CAP_NZDMA         (1 << 19)
 #define HOST_HSORG             0xFC
@@ -899,8 +920,9 @@ static void mtip_handle_tfe(struct driver_data *dd)
                        fail_reason = "thermal shutdown";
                }
                if (buf[288] == 0xBF) {
+                       set_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag);
                        dev_info(&dd->pdev->dev,
-                               "Drive indicates rebuild has failed.\n");
+                               "Drive indicates rebuild has failed. Secure erase required.\n");
                        fail_all_ncq_cmds = 1;
                        fail_reason = "rebuild failed";
                }
@@ -1566,6 +1588,12 @@ static int mtip_get_identify(struct mtip_port *port, void __user *user_buffer)
        }
 #endif
 
+       /* Check security locked state */
+       if (port->identify[128] & 0x4)
+               set_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
+       else
+               clear_bit(MTIP_DDF_SEC_LOCK_BIT, &port->dd->dd_flag);
+
 #ifdef MTIP_TRIM /* Disabling TRIM support temporarily */
        /* Demux ID.DRAT & ID.RZAT to determine trim support */
        if (port->identify[69] & (1 << 14) && port->identify[69] & (1 << 5))
@@ -1887,6 +1915,10 @@ static void mtip_dump_identify(struct mtip_port *port)
        strlcpy(cbuf, (char *)(port->identify+27), 41);
        dev_info(&port->dd->pdev->dev, "Model: %s\n", cbuf);
 
+       dev_info(&port->dd->pdev->dev, "Security: %04x %s\n",
+               port->identify[128],
+               port->identify[128] & 0x4 ? "(LOCKED)" : "");
+
        if (mtip_hw_get_capacity(port->dd, &sectors))
                dev_info(&port->dd->pdev->dev,
                        "Capacity: %llu sectors (%llu MB)\n",
@@ -3312,6 +3344,118 @@ st_out:
        return 0;
 }
 
+/*
+ * DMA region teardown
+ *
+ * @dd Pointer to driver_data structure
+ *
+ * return value
+ *      None
+ */
+static void mtip_dma_free(struct driver_data *dd)
+{
+       int i;
+       struct mtip_port *port = dd->port;
+
+       if (port->block1)
+               dmam_free_coherent(&dd->pdev->dev, BLOCK_DMA_ALLOC_SZ,
+                                       port->block1, port->block1_dma);
+
+       if (port->command_list) {
+               dmam_free_coherent(&dd->pdev->dev, AHCI_CMD_TBL_SZ,
+                               port->command_list, port->command_list_dma);
+       }
+
+       for (i = 0; i < MTIP_MAX_COMMAND_SLOTS; i++) {
+               if (port->commands[i].command)
+                       dmam_free_coherent(&dd->pdev->dev, CMD_DMA_ALLOC_SZ,
+                               port->commands[i].command,
+                               port->commands[i].command_dma);
+       }
+}
+
+/*
+ * DMA region setup
+ *
+ * @dd Pointer to driver_data structure
+ *
+ * return value
+ *      -ENOMEM Not enough free DMA region space to initialize driver
+ */
+static int mtip_dma_alloc(struct driver_data *dd)
+{
+       struct mtip_port *port = dd->port;
+       int i, rv = 0;
+       u32 host_cap_64 = readl(dd->mmio + HOST_CAP) & HOST_CAP_64;
+
+       /* Allocate dma memory for RX Fis, Identify, and Sector Bufffer */
+       port->block1 =
+               dmam_alloc_coherent(&dd->pdev->dev, BLOCK_DMA_ALLOC_SZ,
+                                       &port->block1_dma, GFP_KERNEL);
+       if (!port->block1)
+               return -ENOMEM;
+       memset(port->block1, 0, BLOCK_DMA_ALLOC_SZ);
+
+       /* Allocate dma memory for command list */
+       port->command_list =
+               dmam_alloc_coherent(&dd->pdev->dev, AHCI_CMD_TBL_SZ,
+                                       &port->command_list_dma, GFP_KERNEL);
+       if (!port->command_list) {
+               dmam_free_coherent(&dd->pdev->dev, BLOCK_DMA_ALLOC_SZ,
+                                       port->block1, port->block1_dma);
+               port->block1 = NULL;
+               port->block1_dma = 0;
+               return -ENOMEM;
+       }
+       memset(port->command_list, 0, AHCI_CMD_TBL_SZ);
+
+       /* Setup all pointers into first DMA region */
+       port->rxfis         = port->block1 + AHCI_RX_FIS_OFFSET;
+       port->rxfis_dma     = port->block1_dma + AHCI_RX_FIS_OFFSET;
+       port->identify      = port->block1 + AHCI_IDFY_OFFSET;
+       port->identify_dma  = port->block1_dma + AHCI_IDFY_OFFSET;
+       port->log_buf       = port->block1 + AHCI_SECTBUF_OFFSET;
+       port->log_buf_dma   = port->block1_dma + AHCI_SECTBUF_OFFSET;
+       port->smart_buf     = port->block1 + AHCI_SMARTBUF_OFFSET;
+       port->smart_buf_dma = port->block1_dma + AHCI_SMARTBUF_OFFSET;
+
+       /* Setup per command SGL DMA region */
+
+       /* Point the command headers at the command tables */
+       for (i = 0; i < MTIP_MAX_COMMAND_SLOTS; i++) {
+               port->commands[i].command =
+                       dmam_alloc_coherent(&dd->pdev->dev, CMD_DMA_ALLOC_SZ,
+                               &port->commands[i].command_dma, GFP_KERNEL);
+               if (!port->commands[i].command) {
+                       rv = -ENOMEM;
+                       mtip_dma_free(dd);
+                       return rv;
+               }
+               memset(port->commands[i].command, 0, CMD_DMA_ALLOC_SZ);
+
+               port->commands[i].command_header = port->command_list +
+                                       (sizeof(struct mtip_cmd_hdr) * i);
+               port->commands[i].command_header_dma =
+                                       dd->port->command_list_dma +
+                                       (sizeof(struct mtip_cmd_hdr) * i);
+
+               if (host_cap_64)
+                       port->commands[i].command_header->ctbau =
+                               __force_bit2int cpu_to_le32(
+                               (port->commands[i].command_dma >> 16) >> 16);
+
+               port->commands[i].command_header->ctba =
+                               __force_bit2int cpu_to_le32(
+                               port->commands[i].command_dma & 0xFFFFFFFF);
+
+               sg_init_table(port->commands[i].sg, MTIP_MAX_SG);
+
+               /* Mark command as currently inactive */
+               atomic_set(&dd->port->commands[i].active, 0);
+       }
+       return 0;
+}
+
 /*
  * Called once for each card.
  *
@@ -3370,83 +3514,10 @@ static int mtip_hw_init(struct driver_data *dd)
        dd->port->mmio  = dd->mmio + PORT_OFFSET;
        dd->port->dd    = dd;
 
-       /* Allocate memory for the command list. */
-       dd->port->command_list =
-               dmam_alloc_coherent(&dd->pdev->dev,
-                       HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4),
-                       &dd->port->command_list_dma,
-                       GFP_KERNEL);
-       if (!dd->port->command_list) {
-               dev_err(&dd->pdev->dev,
-                       "Memory allocation: command list\n");
-               rv = -ENOMEM;
+       /* DMA allocations */
+       rv = mtip_dma_alloc(dd);
+       if (rv < 0)
                goto out1;
-       }
-
-       /* Clear the memory we have allocated. */
-       memset(dd->port->command_list,
-               0,
-               HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4));
-
-       /* Setup the addresse of the RX FIS. */
-       dd->port->rxfis     = dd->port->command_list + HW_CMD_SLOT_SZ;
-       dd->port->rxfis_dma = dd->port->command_list_dma + HW_CMD_SLOT_SZ;
-
-       /* Setup the address of the command tables. */
-       dd->port->command_table   = dd->port->rxfis + AHCI_RX_FIS_SZ;
-       dd->port->command_tbl_dma = dd->port->rxfis_dma + AHCI_RX_FIS_SZ;
-
-       /* Setup the address of the identify data. */
-       dd->port->identify     = dd->port->command_table +
-                                       HW_CMD_TBL_AR_SZ;
-       dd->port->identify_dma = dd->port->command_tbl_dma +
-                                       HW_CMD_TBL_AR_SZ;
-
-       /* Setup the address of the sector buffer - for some non-ncq cmds */
-       dd->port->sector_buffer = (void *) dd->port->identify + ATA_SECT_SIZE;
-       dd->port->sector_buffer_dma = dd->port->identify_dma + ATA_SECT_SIZE;
-
-       /* Setup the address of the log buf - for read log command */
-       dd->port->log_buf = (void *)dd->port->sector_buffer  + ATA_SECT_SIZE;
-       dd->port->log_buf_dma = dd->port->sector_buffer_dma + ATA_SECT_SIZE;
-
-       /* Setup the address of the smart buf - for smart read data command */
-       dd->port->smart_buf = (void *)dd->port->log_buf  + ATA_SECT_SIZE;
-       dd->port->smart_buf_dma = dd->port->log_buf_dma + ATA_SECT_SIZE;
-
-
-       /* Point the command headers at the command tables. */
-       for (i = 0; i < num_command_slots; i++) {
-               dd->port->commands[i].command_header =
-                                       dd->port->command_list +
-                                       (sizeof(struct mtip_cmd_hdr) * i);
-               dd->port->commands[i].command_header_dma =
-                                       dd->port->command_list_dma +
-                                       (sizeof(struct mtip_cmd_hdr) * i);
-
-               dd->port->commands[i].command =
-                       dd->port->command_table + (HW_CMD_TBL_SZ * i);
-               dd->port->commands[i].command_dma =
-                       dd->port->command_tbl_dma + (HW_CMD_TBL_SZ * i);
-
-               if (readl(dd->mmio + HOST_CAP) & HOST_CAP_64)
-                       dd->port->commands[i].command_header->ctbau =
-                       __force_bit2int cpu_to_le32(
-                       (dd->port->commands[i].command_dma >> 16) >> 16);
-               dd->port->commands[i].command_header->ctba =
-                       __force_bit2int cpu_to_le32(
-                       dd->port->commands[i].command_dma & 0xFFFFFFFF);
-
-               /*
-                * If this is not done, a bug is reported by the stock
-                * FC11 i386. Due to the fact that it has lots of kernel
-                * debugging enabled.
-                */
-               sg_init_table(dd->port->commands[i].sg, MTIP_MAX_SG);
-
-               /* Mark all commands as currently inactive.*/
-               atomic_set(&dd->port->commands[i].active, 0);
-       }
 
        /* Setup the pointers to the extended s_active and CI registers. */
        for (i = 0; i < dd->slot_groups; i++) {
@@ -3594,12 +3665,8 @@ out3:
 
 out2:
        mtip_deinit_port(dd->port);
+       mtip_dma_free(dd);
 
-       /* Free the command/command header memory. */
-       dmam_free_coherent(&dd->pdev->dev,
-                               HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4),
-                               dd->port->command_list,
-                               dd->port->command_list_dma);
 out1:
        /* Free the memory allocated for the for structure. */
        kfree(dd->port);
@@ -3622,7 +3689,8 @@ static int mtip_hw_exit(struct driver_data *dd)
         * saves its state.
         */
        if (!dd->sr) {
-               if (!test_bit(MTIP_DDF_REBUILD_FAILED_BIT, &dd->dd_flag))
+               if (!test_bit(MTIP_PF_REBUILD_BIT, &dd->port->flags) &&
+                   !test_bit(MTIP_DDF_SEC_LOCK_BIT, &dd->dd_flag))
                        if (mtip_standby_immediate(dd->port))
                                dev_warn(&dd->pdev->dev,
                                        "STANDBY IMMEDIATE failed\n");
@@ -3641,11 +3709,9 @@ static int mtip_hw_exit(struct driver_data *dd)
        irq_set_affinity_hint(dd->pdev->irq, NULL);
        devm_free_irq(&dd->pdev->dev, dd->pdev->irq, dd);
 
-       /* Free the command/command header memory. */
-       dmam_free_coherent(&dd->pdev->dev,
-                       HW_PORT_PRIV_DMA_SZ + (ATA_SECT_SIZE * 4),
-                       dd->port->command_list,
-                       dd->port->command_list_dma);
+       /* Free dma regions */
+       mtip_dma_free(dd);
+
        /* Free the memory allocated for the for structure. */
        kfree(dd->port);
        dd->port = NULL;
@@ -3962,8 +4028,9 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
 {
        struct driver_data *dd = queue->queuedata;
        struct scatterlist *sg;
-       struct bio_vec *bvec;
-       int i, nents = 0;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
+       int nents = 0;
        int tag = 0, unaligned = 0;
 
        if (unlikely(dd->dd_flag & MTIP_DDF_STOP_IO)) {
@@ -3993,7 +4060,7 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
        }
 
        if (unlikely(bio->bi_rw & REQ_DISCARD)) {
-               bio_endio(bio, mtip_send_trim(dd, bio->bi_sector,
+               bio_endio(bio, mtip_send_trim(dd, bio->bi_iter.bi_sector,
                                                bio_sectors(bio)));
                return;
        }
@@ -4006,7 +4073,8 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
 
        if (bio_data_dir(bio) == WRITE && bio_sectors(bio) <= 64 &&
                                                        dd->unal_qdepth) {
-               if (bio->bi_sector % 8 != 0) /* Unaligned on 4k boundaries */
+               if (bio->bi_iter.bi_sector % 8 != 0)
+                       /* Unaligned on 4k boundaries */
                        unaligned = 1;
                else if (bio_sectors(bio) % 8 != 0) /* Aligned but not 4k/8k */
                        unaligned = 1;
@@ -4025,17 +4093,17 @@ static void mtip_make_request(struct request_queue *queue, struct bio *bio)
                }
 
                /* Create the scatter list for this bio. */
-               bio_for_each_segment(bvec, bio, i) {
+               bio_for_each_segment(bvec, bio, iter) {
                        sg_set_page(&sg[nents],
-                                       bvec->bv_page,
-                                       bvec->bv_len,
-                                       bvec->bv_offset);
+                                       bvec.bv_page,
+                                       bvec.bv_len,
+                                       bvec.bv_offset);
                        nents++;
                }
 
                /* Issue the read/write. */
                mtip_hw_submit_io(dd,
-                               bio->bi_sector,
+                               bio->bi_iter.bi_sector,
                                bio_sectors(bio),
                                nents,
                                tag,
index 9be7a1582ad3471a5400237b7db57b6a976cb2d9..b52e9a6d6aad6d602bf3a9d6f73c9b4c277c7e17 100644 (file)
@@ -69,7 +69,7 @@
  * Maximum number of scatter gather entries
  * a single command may have.
  */
-#define MTIP_MAX_SG            128
+#define MTIP_MAX_SG            504
 
 /*
  * Maximum number of slot groups (Command Issue & s_active registers)
@@ -92,7 +92,7 @@
 
 /* Driver name and version strings */
 #define MTIP_DRV_NAME          "mtip32xx"
-#define MTIP_DRV_VERSION       "1.2.6os3"
+#define MTIP_DRV_VERSION       "1.3.0"
 
 /* Maximum number of minor device numbers per device. */
 #define MTIP_MAX_MINORS                16
@@ -391,15 +391,13 @@ struct mtip_port {
         */
        dma_addr_t rxfis_dma;
        /*
-        * Pointer to the beginning of the command table memory as used
-        * by the driver.
+        * Pointer to the DMA region for RX Fis, Identify, RLE10, and SMART
         */
-       void *command_table;
+       void *block1;
        /*
-        * Pointer to the beginning of the command table memory as used
-        * by the DMA.
+        * DMA address of region for RX Fis, Identify, RLE10, and SMART
         */
-       dma_addr_t command_tbl_dma;
+       dma_addr_t block1_dma;
        /*
         * Pointer to the beginning of the identify data memory as used
         * by the driver.
index 2dc3b5153f0d82b42cfab720464e17bd963223f8..55298db36b2d61a113f25c22905fffb0f22ddd32 100644 (file)
@@ -271,18 +271,18 @@ static int nbd_send_req(struct nbd_device *nbd, struct request *req)
 
        if (nbd_cmd(req) == NBD_CMD_WRITE) {
                struct req_iterator iter;
-               struct bio_vec *bvec;
+               struct bio_vec bvec;
                /*
                 * we are really probing at internals to determine
                 * whether to set MSG_MORE or not...
                 */
                rq_for_each_segment(bvec, req, iter) {
                        flags = 0;
-                       if (!rq_iter_last(req, iter))
+                       if (!rq_iter_last(bvec, iter))
                                flags = MSG_MORE;
                        dprintk(DBG_TX, "%s: request %p: sending %d bytes data\n",
-                                       nbd->disk->disk_name, req, bvec->bv_len);
-                       result = sock_send_bvec(nbd, bvec, flags);
+                                       nbd->disk->disk_name, req, bvec.bv_len);
+                       result = sock_send_bvec(nbd, &bvec, flags);
                        if (result <= 0) {
                                dev_err(disk_to_dev(nbd->disk),
                                        "Send data failed (result %d)\n",
@@ -378,10 +378,10 @@ static struct request *nbd_read_stat(struct nbd_device *nbd)
                        nbd->disk->disk_name, req);
        if (nbd_cmd(req) == NBD_CMD_READ) {
                struct req_iterator iter;
-               struct bio_vec *bvec;
+               struct bio_vec bvec;
 
                rq_for_each_segment(bvec, req, iter) {
-                       result = sock_recv_bvec(nbd, bvec);
+                       result = sock_recv_bvec(nbd, &bvec);
                        if (result <= 0) {
                                dev_err(disk_to_dev(nbd->disk), "Receive data failed (result %d)\n",
                                        result);
@@ -389,7 +389,7 @@ static struct request *nbd_read_stat(struct nbd_device *nbd)
                                return req;
                        }
                        dprintk(DBG_RX, "%s: request %p: got %d bytes data\n",
-                               nbd->disk->disk_name, req, bvec->bv_len);
+                               nbd->disk->disk_name, req, bvec.bv_len);
                }
        }
        return req;
index 83a598ebb65a4ab7699d1dcebe1b44b42ea8ae5a..3107282a9741f96665a2805b08217d3209c27bf7 100644 (file)
@@ -616,6 +616,11 @@ static int __init null_init(void)
                irqmode = NULL_IRQ_NONE;
        }
 #endif
+       if (bs > PAGE_SIZE) {
+               pr_warn("null_blk: invalid block size\n");
+               pr_warn("null_blk: defaults block size to %lu\n", PAGE_SIZE);
+               bs = PAGE_SIZE;
+       }
 
        if (queue_mode == NULL_Q_MQ && use_per_node_hctx) {
                if (submit_queues < nr_online_nodes) {
index 26d03fa0bf26696d9e004b3983a580d409d3d006..1f14ac4039450e84137b4eab0dacf043aa46d16e 100644 (file)
@@ -441,104 +441,19 @@ int nvme_setup_prps(struct nvme_dev *dev, struct nvme_common_command *cmd,
        return total_len;
 }
 
-struct nvme_bio_pair {
-       struct bio b1, b2, *parent;
-       struct bio_vec *bv1, *bv2;
-       int err;
-       atomic_t cnt;
-};
-
-static void nvme_bio_pair_endio(struct bio *bio, int err)
-{
-       struct nvme_bio_pair *bp = bio->bi_private;
-
-       if (err)
-               bp->err = err;
-
-       if (atomic_dec_and_test(&bp->cnt)) {
-               bio_endio(bp->parent, bp->err);
-               kfree(bp->bv1);
-               kfree(bp->bv2);
-               kfree(bp);
-       }
-}
-
-static struct nvme_bio_pair *nvme_bio_split(struct bio *bio, int idx,
-                                                       int len, int offset)
-{
-       struct nvme_bio_pair *bp;
-
-       BUG_ON(len > bio->bi_size);
-       BUG_ON(idx > bio->bi_vcnt);
-
-       bp = kmalloc(sizeof(*bp), GFP_ATOMIC);
-       if (!bp)
-               return NULL;
-       bp->err = 0;
-
-       bp->b1 = *bio;
-       bp->b2 = *bio;
-
-       bp->b1.bi_size = len;
-       bp->b2.bi_size -= len;
-       bp->b1.bi_vcnt = idx;
-       bp->b2.bi_idx = idx;
-       bp->b2.bi_sector += len >> 9;
-
-       if (offset) {
-               bp->bv1 = kmalloc(bio->bi_max_vecs * sizeof(struct bio_vec),
-                                                               GFP_ATOMIC);
-               if (!bp->bv1)
-                       goto split_fail_1;
-
-               bp->bv2 = kmalloc(bio->bi_max_vecs * sizeof(struct bio_vec),
-                                                               GFP_ATOMIC);
-               if (!bp->bv2)
-                       goto split_fail_2;
-
-               memcpy(bp->bv1, bio->bi_io_vec,
-                       bio->bi_max_vecs * sizeof(struct bio_vec));
-               memcpy(bp->bv2, bio->bi_io_vec,
-                       bio->bi_max_vecs * sizeof(struct bio_vec));
-
-               bp->b1.bi_io_vec = bp->bv1;
-               bp->b2.bi_io_vec = bp->bv2;
-               bp->b2.bi_io_vec[idx].bv_offset += offset;
-               bp->b2.bi_io_vec[idx].bv_len -= offset;
-               bp->b1.bi_io_vec[idx].bv_len = offset;
-               bp->b1.bi_vcnt++;
-       } else
-               bp->bv1 = bp->bv2 = NULL;
-
-       bp->b1.bi_private = bp;
-       bp->b2.bi_private = bp;
-
-       bp->b1.bi_end_io = nvme_bio_pair_endio;
-       bp->b2.bi_end_io = nvme_bio_pair_endio;
-
-       bp->parent = bio;
-       atomic_set(&bp->cnt, 2);
-
-       return bp;
-
- split_fail_2:
-       kfree(bp->bv1);
- split_fail_1:
-       kfree(bp);
-       return NULL;
-}
-
 static int nvme_split_and_submit(struct bio *bio, struct nvme_queue *nvmeq,
-                                               int idx, int len, int offset)
+                                int len)
 {
-       struct nvme_bio_pair *bp = nvme_bio_split(bio, idx, len, offset);
-       if (!bp)
+       struct bio *split = bio_split(bio, len >> 9, GFP_ATOMIC, NULL);
+       if (!split)
                return -ENOMEM;
 
+       bio_chain(split, bio);
+
        if (bio_list_empty(&nvmeq->sq_cong))
                add_wait_queue(&nvmeq->sq_full, &nvmeq->sq_cong_wait);
-       bio_list_add(&nvmeq->sq_cong, &bp->b1);
-       bio_list_add(&nvmeq->sq_cong, &bp->b2);
+       bio_list_add(&nvmeq->sq_cong, split);
+       bio_list_add(&nvmeq->sq_cong, bio);
 
        return 0;
 }
@@ -550,41 +465,44 @@ static int nvme_split_and_submit(struct bio *bio, struct nvme_queue *nvmeq,
 static int nvme_map_bio(struct nvme_queue *nvmeq, struct nvme_iod *iod,
                struct bio *bio, enum dma_data_direction dma_dir, int psegs)
 {
-       struct bio_vec *bvec, *bvprv = NULL;
+       struct bio_vec bvec, bvprv;
+       struct bvec_iter iter;
        struct scatterlist *sg = NULL;
-       int i, length = 0, nsegs = 0, split_len = bio->bi_size;
+       int length = 0, nsegs = 0, split_len = bio->bi_iter.bi_size;
+       int first = 1;
 
        if (nvmeq->dev->stripe_size)
                split_len = nvmeq->dev->stripe_size -
-                       ((bio->bi_sector << 9) & (nvmeq->dev->stripe_size - 1));
+                       ((bio->bi_iter.bi_sector << 9) &
+                        (nvmeq->dev->stripe_size - 1));
 
        sg_init_table(iod->sg, psegs);
-       bio_for_each_segment(bvec, bio, i) {
-               if (bvprv && BIOVEC_PHYS_MERGEABLE(bvprv, bvec)) {
-                       sg->length += bvec->bv_len;
+       bio_for_each_segment(bvec, bio, iter) {
+               if (!first && BIOVEC_PHYS_MERGEABLE(&bvprv, &bvec)) {
+                       sg->length += bvec.bv_len;
                } else {
-                       if (bvprv && BIOVEC_NOT_VIRT_MERGEABLE(bvprv, bvec))
-                               return nvme_split_and_submit(bio, nvmeq, i,
-                                                               length, 0);
+                       if (!first && BIOVEC_NOT_VIRT_MERGEABLE(&bvprv, &bvec))
+                               return nvme_split_and_submit(bio, nvmeq,
+                                                            length);
 
                        sg = sg ? sg + 1 : iod->sg;
-                       sg_set_page(sg, bvec->bv_page, bvec->bv_len,
-                                                       bvec->bv_offset);
+                       sg_set_page(sg, bvec.bv_page,
+                                   bvec.bv_len, bvec.bv_offset);
                        nsegs++;
                }
 
-               if (split_len - length < bvec->bv_len)
-                       return nvme_split_and_submit(bio, nvmeq, i, split_len,
-                                                       split_len - length);
-               length += bvec->bv_len;
+               if (split_len - length < bvec.bv_len)
+                       return nvme_split_and_submit(bio, nvmeq, split_len);
+               length += bvec.bv_len;
                bvprv = bvec;
+               first = 0;
        }
        iod->nents = nsegs;
        sg_mark_end(sg);
        if (dma_map_sg(nvmeq->q_dmadev, iod->sg, iod->nents, dma_dir) == 0)
                return -ENOMEM;
 
-       BUG_ON(length != bio->bi_size);
+       BUG_ON(length != bio->bi_iter.bi_size);
        return length;
 }
 
@@ -608,8 +526,8 @@ static int nvme_submit_discard(struct nvme_queue *nvmeq, struct nvme_ns *ns,
        iod->npages = 0;
 
        range->cattr = cpu_to_le32(0);
-       range->nlb = cpu_to_le32(bio->bi_size >> ns->lba_shift);
-       range->slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector));
+       range->nlb = cpu_to_le32(bio->bi_iter.bi_size >> ns->lba_shift);
+       range->slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_iter.bi_sector));
 
        memset(cmnd, 0, sizeof(*cmnd));
        cmnd->dsm.opcode = nvme_cmd_dsm;
@@ -674,7 +592,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns,
        }
 
        result = -ENOMEM;
-       iod = nvme_alloc_iod(psegs, bio->bi_size, GFP_ATOMIC);
+       iod = nvme_alloc_iod(psegs, bio->bi_iter.bi_size, GFP_ATOMIC);
        if (!iod)
                goto nomem;
        iod->private = bio;
@@ -723,7 +641,7 @@ static int nvme_submit_bio_queue(struct nvme_queue *nvmeq, struct nvme_ns *ns,
        cmnd->rw.nsid = cpu_to_le32(ns->ns_id);
        length = nvme_setup_prps(nvmeq->dev, &cmnd->common, iod, length,
                                                                GFP_ATOMIC);
-       cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_sector));
+       cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, bio->bi_iter.bi_sector));
        cmnd->rw.length = cpu_to_le16((length >> ns->lba_shift) - 1);
        cmnd->rw.control = cpu_to_le16(control);
        cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt);
index 4a27b1de5fcb9fb0fef805fb51d0d2f1bc418a29..2ce3dfd7e6b9bafd65c670aa45bf3a8660578360 100644 (file)
@@ -581,7 +581,7 @@ static ssize_t pg_write(struct file *filp, const char __user *buf, size_t count,
 
        if (hdr.magic != PG_MAGIC)
                return -EINVAL;
-       if (hdr.dlen > PG_MAX_DATA)
+       if (hdr.dlen < 0 || hdr.dlen > PG_MAX_DATA)
                return -EINVAL;
        if ((count - hs) > PG_MAX_DATA)
                return -EINVAL;
index ff8668c5efb10eebc1a02736d306cce1f43ad7ff..a2af73db187b694c3112bf1c6d08e4070596cd10 100644 (file)
@@ -651,7 +651,7 @@ static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s
 
        for (;;) {
                tmp = rb_entry(n, struct pkt_rb_node, rb_node);
-               if (s <= tmp->bio->bi_sector)
+               if (s <= tmp->bio->bi_iter.bi_sector)
                        next = n->rb_left;
                else
                        next = n->rb_right;
@@ -660,12 +660,12 @@ static struct pkt_rb_node *pkt_rbtree_find(struct pktcdvd_device *pd, sector_t s
                n = next;
        }
 
-       if (s > tmp->bio->bi_sector) {
+       if (s > tmp->bio->bi_iter.bi_sector) {
                tmp = pkt_rbtree_next(tmp);
                if (!tmp)
                        return NULL;
        }
-       BUG_ON(s > tmp->bio->bi_sector);
+       BUG_ON(s > tmp->bio->bi_iter.bi_sector);
        return tmp;
 }
 
@@ -676,13 +676,13 @@ static void pkt_rbtree_insert(struct pktcdvd_device *pd, struct pkt_rb_node *nod
 {
        struct rb_node **p = &pd->bio_queue.rb_node;
        struct rb_node *parent = NULL;
-       sector_t s = node->bio->bi_sector;
+       sector_t s = node->bio->bi_iter.bi_sector;
        struct pkt_rb_node *tmp;
 
        while (*p) {
                parent = *p;
                tmp = rb_entry(parent, struct pkt_rb_node, rb_node);
-               if (s < tmp->bio->bi_sector)
+               if (s < tmp->bio->bi_iter.bi_sector)
                        p = &(*p)->rb_left;
                else
                        p = &(*p)->rb_right;
@@ -706,7 +706,9 @@ static int pkt_generic_packet(struct pktcdvd_device *pd, struct packet_command *
                             WRITE : READ, __GFP_WAIT);
 
        if (cgc->buflen) {
-               if (blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen, __GFP_WAIT))
+               ret = blk_rq_map_kern(q, rq, cgc->buffer, cgc->buflen,
+                                     __GFP_WAIT);
+               if (ret)
                        goto out;
        }
 
@@ -857,7 +859,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
                        spin_lock(&pd->iosched.lock);
                        bio = bio_list_peek(&pd->iosched.write_queue);
                        spin_unlock(&pd->iosched.lock);
-                       if (bio && (bio->bi_sector == pd->iosched.last_write))
+                       if (bio && (bio->bi_iter.bi_sector ==
+                                   pd->iosched.last_write))
                                need_write_seek = 0;
                        if (need_write_seek && reads_queued) {
                                if (atomic_read(&pd->cdrw.pending_bios) > 0) {
@@ -888,7 +891,8 @@ static void pkt_iosched_process_queue(struct pktcdvd_device *pd)
                        continue;
 
                if (bio_data_dir(bio) == READ)
-                       pd->iosched.successive_reads += bio->bi_size >> 10;
+                       pd->iosched.successive_reads +=
+                               bio->bi_iter.bi_size >> 10;
                else {
                        pd->iosched.successive_reads = 0;
                        pd->iosched.last_write = bio_end_sector(bio);
@@ -978,7 +982,7 @@ static void pkt_end_io_read(struct bio *bio, int err)
 
        pkt_dbg(2, pd, "bio=%p sec0=%llx sec=%llx err=%d\n",
                bio, (unsigned long long)pkt->sector,
-               (unsigned long long)bio->bi_sector, err);
+               (unsigned long long)bio->bi_iter.bi_sector, err);
 
        if (err)
                atomic_inc(&pkt->io_errors);
@@ -1026,8 +1030,9 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
        memset(written, 0, sizeof(written));
        spin_lock(&pkt->lock);
        bio_list_for_each(bio, &pkt->orig_bios) {
-               int first_frame = (bio->bi_sector - pkt->sector) / (CD_FRAMESIZE >> 9);
-               int num_frames = bio->bi_size / CD_FRAMESIZE;
+               int first_frame = (bio->bi_iter.bi_sector - pkt->sector) /
+                       (CD_FRAMESIZE >> 9);
+               int num_frames = bio->bi_iter.bi_size / CD_FRAMESIZE;
                pd->stats.secs_w += num_frames * (CD_FRAMESIZE >> 9);
                BUG_ON(first_frame < 0);
                BUG_ON(first_frame + num_frames > pkt->frames);
@@ -1053,7 +1058,7 @@ static void pkt_gather_data(struct pktcdvd_device *pd, struct packet_data *pkt)
 
                bio = pkt->r_bios[f];
                bio_reset(bio);
-               bio->bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9);
+               bio->bi_iter.bi_sector = pkt->sector + f * (CD_FRAMESIZE >> 9);
                bio->bi_bdev = pd->bdev;
                bio->bi_end_io = pkt_end_io_read;
                bio->bi_private = pkt;
@@ -1150,8 +1155,8 @@ static int pkt_start_recovery(struct packet_data *pkt)
        bio_reset(pkt->bio);
        pkt->bio->bi_bdev = pd->bdev;
        pkt->bio->bi_rw = REQ_WRITE;
-       pkt->bio->bi_sector = new_sector;
-       pkt->bio->bi_size = pkt->frames * CD_FRAMESIZE;
+       pkt->bio->bi_iter.bi_sector = new_sector;
+       pkt->bio->bi_iter.bi_size = pkt->frames * CD_FRAMESIZE;
        pkt->bio->bi_vcnt = pkt->frames;
 
        pkt->bio->bi_end_io = pkt_end_io_packet_write;
@@ -1213,7 +1218,7 @@ static int pkt_handle_queue(struct pktcdvd_device *pd)
        node = first_node;
        while (node) {
                bio = node->bio;
-               zone = get_zone(bio->bi_sector, pd);
+               zone = get_zone(bio->bi_iter.bi_sector, pd);
                list_for_each_entry(p, &pd->cdrw.pkt_active_list, list) {
                        if (p->sector == zone) {
                                bio = NULL;
@@ -1252,14 +1257,14 @@ try_next_bio:
        pkt_dbg(2, pd, "looking for zone %llx\n", (unsigned long long)zone);
        while ((node = pkt_rbtree_find(pd, zone)) != NULL) {
                bio = node->bio;
-               pkt_dbg(2, pd, "found zone=%llx\n",
-                       (unsigned long long)get_zone(bio->bi_sector, pd));
-               if (get_zone(bio->bi_sector, pd) != zone)
+               pkt_dbg(2, pd, "found zone=%llx\n", (unsigned long long)
+                       get_zone(bio->bi_iter.bi_sector, pd));
+               if (get_zone(bio->bi_iter.bi_sector, pd) != zone)
                        break;
                pkt_rbtree_erase(pd, node);
                spin_lock(&pkt->lock);
                bio_list_add(&pkt->orig_bios, bio);
-               pkt->write_size += bio->bi_size / CD_FRAMESIZE;
+               pkt->write_size += bio->bi_iter.bi_size / CD_FRAMESIZE;
                spin_unlock(&pkt->lock);
        }
        /* check write congestion marks, and if bio_queue_size is
@@ -1293,7 +1298,7 @@ static void pkt_start_write(struct pktcdvd_device *pd, struct packet_data *pkt)
        struct bio_vec *bvec = pkt->w_bio->bi_io_vec;
 
        bio_reset(pkt->w_bio);
-       pkt->w_bio->bi_sector = pkt->sector;
+       pkt->w_bio->bi_iter.bi_sector = pkt->sector;
        pkt->w_bio->bi_bdev = pd->bdev;
        pkt->w_bio->bi_end_io = pkt_end_io_packet_write;
        pkt->w_bio->bi_private = pkt;
@@ -2335,75 +2340,29 @@ static void pkt_end_io_read_cloned(struct bio *bio, int err)
        pkt_bio_finished(pd);
 }
 
-static void pkt_make_request(struct request_queue *q, struct bio *bio)
+static void pkt_make_request_read(struct pktcdvd_device *pd, struct bio *bio)
 {
-       struct pktcdvd_device *pd;
-       char b[BDEVNAME_SIZE];
+       struct bio *cloned_bio = bio_clone(bio, GFP_NOIO);
+       struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO);
+
+       psd->pd = pd;
+       psd->bio = bio;
+       cloned_bio->bi_bdev = pd->bdev;
+       cloned_bio->bi_private = psd;
+       cloned_bio->bi_end_io = pkt_end_io_read_cloned;
+       pd->stats.secs_r += bio_sectors(bio);
+       pkt_queue_bio(pd, cloned_bio);
+}
+
+static void pkt_make_request_write(struct request_queue *q, struct bio *bio)
+{
+       struct pktcdvd_device *pd = q->queuedata;
        sector_t zone;
        struct packet_data *pkt;
        int was_empty, blocked_bio;
        struct pkt_rb_node *node;
 
-       pd = q->queuedata;
-       if (!pd) {
-               pr_err("%s incorrect request queue\n",
-                      bdevname(bio->bi_bdev, b));
-               goto end_io;
-       }
-
-       /*
-        * Clone READ bios so we can have our own bi_end_io callback.
-        */
-       if (bio_data_dir(bio) == READ) {
-               struct bio *cloned_bio = bio_clone(bio, GFP_NOIO);
-               struct packet_stacked_data *psd = mempool_alloc(psd_pool, GFP_NOIO);
-
-               psd->pd = pd;
-               psd->bio = bio;
-               cloned_bio->bi_bdev = pd->bdev;
-               cloned_bio->bi_private = psd;
-               cloned_bio->bi_end_io = pkt_end_io_read_cloned;
-               pd->stats.secs_r += bio_sectors(bio);
-               pkt_queue_bio(pd, cloned_bio);
-               return;
-       }
-
-       if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
-               pkt_notice(pd, "WRITE for ro device (%llu)\n",
-                          (unsigned long long)bio->bi_sector);
-               goto end_io;
-       }
-
-       if (!bio->bi_size || (bio->bi_size % CD_FRAMESIZE)) {
-               pkt_err(pd, "wrong bio size\n");
-               goto end_io;
-       }
-
-       blk_queue_bounce(q, &bio);
-
-       zone = get_zone(bio->bi_sector, pd);
-       pkt_dbg(2, pd, "start = %6llx stop = %6llx\n",
-               (unsigned long long)bio->bi_sector,
-               (unsigned long long)bio_end_sector(bio));
-
-       /* Check if we have to split the bio */
-       {
-               struct bio_pair *bp;
-               sector_t last_zone;
-               int first_sectors;
-
-               last_zone = get_zone(bio_end_sector(bio) - 1, pd);
-               if (last_zone != zone) {
-                       BUG_ON(last_zone != zone + pd->settings.size);
-                       first_sectors = last_zone - bio->bi_sector;
-                       bp = bio_split(bio, first_sectors);
-                       BUG_ON(!bp);
-                       pkt_make_request(q, &bp->bio1);
-                       pkt_make_request(q, &bp->bio2);
-                       bio_pair_release(bp);
-                       return;
-               }
-       }
+       zone = get_zone(bio->bi_iter.bi_sector, pd);
 
        /*
         * If we find a matching packet in state WAITING or READ_WAIT, we can
@@ -2417,7 +2376,8 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio)
                        if ((pkt->state == PACKET_WAITING_STATE) ||
                            (pkt->state == PACKET_READ_WAIT_STATE)) {
                                bio_list_add(&pkt->orig_bios, bio);
-                               pkt->write_size += bio->bi_size / CD_FRAMESIZE;
+                               pkt->write_size +=
+                                       bio->bi_iter.bi_size / CD_FRAMESIZE;
                                if ((pkt->write_size >= pkt->frames) &&
                                    (pkt->state == PACKET_WAITING_STATE)) {
                                        atomic_inc(&pkt->run_sm);
@@ -2476,6 +2436,64 @@ static void pkt_make_request(struct request_queue *q, struct bio *bio)
                 */
                wake_up(&pd->wqueue);
        }
+}
+
+static void pkt_make_request(struct request_queue *q, struct bio *bio)
+{
+       struct pktcdvd_device *pd;
+       char b[BDEVNAME_SIZE];
+       struct bio *split;
+
+       pd = q->queuedata;
+       if (!pd) {
+               pr_err("%s incorrect request queue\n",
+                      bdevname(bio->bi_bdev, b));
+               goto end_io;
+       }
+
+       pkt_dbg(2, pd, "start = %6llx stop = %6llx\n",
+               (unsigned long long)bio->bi_iter.bi_sector,
+               (unsigned long long)bio_end_sector(bio));
+
+       /*
+        * Clone READ bios so we can have our own bi_end_io callback.
+        */
+       if (bio_data_dir(bio) == READ) {
+               pkt_make_request_read(pd, bio);
+               return;
+       }
+
+       if (!test_bit(PACKET_WRITABLE, &pd->flags)) {
+               pkt_notice(pd, "WRITE for ro device (%llu)\n",
+                          (unsigned long long)bio->bi_iter.bi_sector);
+               goto end_io;
+       }
+
+       if (!bio->bi_iter.bi_size || (bio->bi_iter.bi_size % CD_FRAMESIZE)) {
+               pkt_err(pd, "wrong bio size\n");
+               goto end_io;
+       }
+
+       blk_queue_bounce(q, &bio);
+
+       do {
+               sector_t zone = get_zone(bio->bi_iter.bi_sector, pd);
+               sector_t last_zone = get_zone(bio_end_sector(bio) - 1, pd);
+
+               if (last_zone != zone) {
+                       BUG_ON(last_zone != zone + pd->settings.size);
+
+                       split = bio_split(bio, last_zone -
+                                         bio->bi_iter.bi_sector,
+                                         GFP_NOIO, fs_bio_set);
+                       bio_chain(split, bio);
+               } else {
+                       split = bio;
+               }
+
+               pkt_make_request_write(q, split);
+       } while (split != bio);
+
        return;
 end_io:
        bio_io_error(bio);
index d754a88d75858ef46f8553ac54b0163ff7b60d8a..c120d70d3fb3b31fdfb584859a8cdd5bf0849dab 100644 (file)
@@ -94,26 +94,25 @@ static void ps3disk_scatter_gather(struct ps3_storage_device *dev,
 {
        unsigned int offset = 0;
        struct req_iterator iter;
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
        unsigned int i = 0;
        size_t size;
        void *buf;
 
        rq_for_each_segment(bvec, req, iter) {
                unsigned long flags;
-               dev_dbg(&dev->sbd.core,
-                       "%s:%u: bio %u: %u segs %u sectors from %lu\n",
-                       __func__, __LINE__, i, bio_segments(iter.bio),
-                       bio_sectors(iter.bio), iter.bio->bi_sector);
+               dev_dbg(&dev->sbd.core, "%s:%u: bio %u: %u sectors from %lu\n",
+                       __func__, __LINE__, i, bio_sectors(iter.bio),
+                       iter.bio->bi_iter.bi_sector);
 
-               size = bvec->bv_len;
-               buf = bvec_kmap_irq(bvec, &flags);
+               size = bvec.bv_len;
+               buf = bvec_kmap_irq(&bvec, &flags);
                if (gather)
                        memcpy(dev->bounce_buf+offset, buf, size);
                else
                        memcpy(buf, dev->bounce_buf+offset, size);
                offset += size;
-               flush_kernel_dcache_page(bvec->bv_page);
+               flush_kernel_dcache_page(bvec.bv_page);
                bvec_kunmap_irq(buf, &flags);
                i++;
        }
@@ -130,7 +129,7 @@ static int ps3disk_submit_request_sg(struct ps3_storage_device *dev,
 
 #ifdef DEBUG
        unsigned int n = 0;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        struct req_iterator iter;
 
        rq_for_each_segment(bv, req, iter)
index 06a2e53e5f37299191b1d9c7fe5e2caf036461a6..ef45cfb98fd2f12278d9f9caa6d044c1336e7baa 100644 (file)
@@ -553,16 +553,16 @@ static struct bio *ps3vram_do_bio(struct ps3_system_bus_device *dev,
        struct ps3vram_priv *priv = ps3_system_bus_get_drvdata(dev);
        int write = bio_data_dir(bio) == WRITE;
        const char *op = write ? "write" : "read";
-       loff_t offset = bio->bi_sector << 9;
+       loff_t offset = bio->bi_iter.bi_sector << 9;
        int error = 0;
-       struct bio_vec *bvec;
-       unsigned int i;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
        struct bio *next;
 
-       bio_for_each_segment(bvec, bio, i) {
+       bio_for_each_segment(bvec, bio, iter) {
                /* PS3 is ppc64, so we don't handle highmem */
-               char *ptr = page_address(bvec->bv_page) + bvec->bv_offset;
-               size_t len = bvec->bv_len, retlen;
+               char *ptr = page_address(bvec.bv_page) + bvec.bv_offset;
+               size_t len = bvec.bv_len, retlen;
 
                dev_dbg(&dev->core, "    %s %zu bytes at offset %llu\n", op,
                        len, offset);
index cb1db2979d3d7b5417a8a4b131e09c5c5f6767c0..b365e0dfccb66f7c256a9d07d7fd976fba17ae95 100644 (file)
@@ -41,6 +41,7 @@
 #include <linux/fs.h>
 #include <linux/blkdev.h>
 #include <linux/slab.h>
+#include <linux/idr.h>
 
 #include "rbd_types.h"
 
@@ -89,9 +90,9 @@ static int atomic_dec_return_safe(atomic_t *v)
 }
 
 #define RBD_DRV_NAME "rbd"
-#define RBD_DRV_NAME_LONG "rbd (rados block device)"
 
-#define RBD_MINORS_PER_MAJOR   256             /* max minors per blkdev */
+#define RBD_MINORS_PER_MAJOR           256
+#define RBD_SINGLE_MAJOR_PART_SHIFT    4
 
 #define RBD_SNAP_DEV_NAME_PREFIX       "snap_"
 #define RBD_MAX_SNAP_NAME_LEN  \
@@ -323,6 +324,7 @@ struct rbd_device {
        int                     dev_id;         /* blkdev unique id */
 
        int                     major;          /* blkdev assigned major */
+       int                     minor;
        struct gendisk          *disk;          /* blkdev's gendisk and rq */
 
        u32                     image_format;   /* Either 1 or 2 */
@@ -386,6 +388,17 @@ static struct kmem_cache   *rbd_img_request_cache;
 static struct kmem_cache       *rbd_obj_request_cache;
 static struct kmem_cache       *rbd_segment_name_cache;
 
+static int rbd_major;
+static DEFINE_IDA(rbd_dev_id_ida);
+
+/*
+ * Default to false for now, as single-major requires >= 0.75 version of
+ * userspace rbd utility.
+ */
+static bool single_major = false;
+module_param(single_major, bool, S_IRUGO);
+MODULE_PARM_DESC(single_major, "Use a single major number for all rbd devices (default: false)");
+
 static int rbd_img_request_submit(struct rbd_img_request *img_request);
 
 static void rbd_dev_device_release(struct device *dev);
@@ -394,18 +407,52 @@ static ssize_t rbd_add(struct bus_type *bus, const char *buf,
                       size_t count);
 static ssize_t rbd_remove(struct bus_type *bus, const char *buf,
                          size_t count);
+static ssize_t rbd_add_single_major(struct bus_type *bus, const char *buf,
+                                   size_t count);
+static ssize_t rbd_remove_single_major(struct bus_type *bus, const char *buf,
+                                      size_t count);
 static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping);
 static void rbd_spec_put(struct rbd_spec *spec);
 
+static int rbd_dev_id_to_minor(int dev_id)
+{
+       return dev_id << RBD_SINGLE_MAJOR_PART_SHIFT;
+}
+
+static int minor_to_rbd_dev_id(int minor)
+{
+       return minor >> RBD_SINGLE_MAJOR_PART_SHIFT;
+}
+
 static BUS_ATTR(add, S_IWUSR, NULL, rbd_add);
 static BUS_ATTR(remove, S_IWUSR, NULL, rbd_remove);
+static BUS_ATTR(add_single_major, S_IWUSR, NULL, rbd_add_single_major);
+static BUS_ATTR(remove_single_major, S_IWUSR, NULL, rbd_remove_single_major);
 
 static struct attribute *rbd_bus_attrs[] = {
        &bus_attr_add.attr,
        &bus_attr_remove.attr,
+       &bus_attr_add_single_major.attr,
+       &bus_attr_remove_single_major.attr,
        NULL,
 };
-ATTRIBUTE_GROUPS(rbd_bus);
+
+static umode_t rbd_bus_is_visible(struct kobject *kobj,
+                                 struct attribute *attr, int index)
+{
+       if (!single_major &&
+           (attr == &bus_attr_add_single_major.attr ||
+            attr == &bus_attr_remove_single_major.attr))
+               return 0;
+
+       return attr->mode;
+}
+
+static const struct attribute_group rbd_bus_group = {
+       .attrs = rbd_bus_attrs,
+       .is_visible = rbd_bus_is_visible,
+};
+__ATTRIBUTE_GROUPS(rbd_bus);
 
 static struct bus_type rbd_bus_type = {
        .name           = "rbd",
@@ -1041,9 +1088,9 @@ static const char *rbd_segment_name(struct rbd_device *rbd_dev, u64 offset)
        name_format = "%s.%012llx";
        if (rbd_dev->image_format == 2)
                name_format = "%s.%016llx";
-       ret = snprintf(name, MAX_OBJ_NAME_SIZE + 1, name_format,
+       ret = snprintf(name, CEPH_MAX_OID_NAME_LEN + 1, name_format,
                        rbd_dev->header.object_prefix, segment);
-       if (ret < 0 || ret > MAX_OBJ_NAME_SIZE) {
+       if (ret < 0 || ret > CEPH_MAX_OID_NAME_LEN) {
                pr_err("error formatting segment name for #%llu (%d)\n",
                        segment, ret);
                kfree(name);
@@ -1109,23 +1156,23 @@ static void bio_chain_put(struct bio *chain)
  */
 static void zero_bio_chain(struct bio *chain, int start_ofs)
 {
-       struct bio_vec *bv;
+       struct bio_vec bv;
+       struct bvec_iter iter;
        unsigned long flags;
        void *buf;
-       int i;
        int pos = 0;
 
        while (chain) {
-               bio_for_each_segment(bv, chain, i) {
-                       if (pos + bv->bv_len > start_ofs) {
+               bio_for_each_segment(bv, chain, iter) {
+                       if (pos + bv.bv_len > start_ofs) {
                                int remainder = max(start_ofs - pos, 0);
-                               buf = bvec_kmap_irq(bv, &flags);
+                               buf = bvec_kmap_irq(&bv, &flags);
                                memset(buf + remainder, 0,
-                                      bv->bv_len - remainder);
-                               flush_dcache_page(bv->bv_page);
+                                      bv.bv_len - remainder);
+                               flush_dcache_page(bv.bv_page);
                                bvec_kunmap_irq(buf, &flags);
                        }
-                       pos += bv->bv_len;
+                       pos += bv.bv_len;
                }
 
                chain = chain->bi_next;
@@ -1173,74 +1220,14 @@ static struct bio *bio_clone_range(struct bio *bio_src,
                                        unsigned int len,
                                        gfp_t gfpmask)
 {
-       struct bio_vec *bv;
-       unsigned int resid;
-       unsigned short idx;
-       unsigned int voff;
-       unsigned short end_idx;
-       unsigned short vcnt;
        struct bio *bio;
 
-       /* Handle the easy case for the caller */
-
-       if (!offset && len == bio_src->bi_size)
-               return bio_clone(bio_src, gfpmask);
-
-       if (WARN_ON_ONCE(!len))
-               return NULL;
-       if (WARN_ON_ONCE(len > bio_src->bi_size))
-               return NULL;
-       if (WARN_ON_ONCE(offset > bio_src->bi_size - len))
-               return NULL;
-
-       /* Find first affected segment... */
-
-       resid = offset;
-       bio_for_each_segment(bv, bio_src, idx) {
-               if (resid < bv->bv_len)
-                       break;
-               resid -= bv->bv_len;
-       }
-       voff = resid;
-
-       /* ...and the last affected segment */
-
-       resid += len;
-       __bio_for_each_segment(bv, bio_src, end_idx, idx) {
-               if (resid <= bv->bv_len)
-                       break;
-               resid -= bv->bv_len;
-       }
-       vcnt = end_idx - idx + 1;
-
-       /* Build the clone */
-
-       bio = bio_alloc(gfpmask, (unsigned int) vcnt);
+       bio = bio_clone(bio_src, gfpmask);
        if (!bio)
                return NULL;    /* ENOMEM */
 
-       bio->bi_bdev = bio_src->bi_bdev;
-       bio->bi_sector = bio_src->bi_sector + (offset >> SECTOR_SHIFT);
-       bio->bi_rw = bio_src->bi_rw;
-       bio->bi_flags |= 1 << BIO_CLONED;
-
-       /*
-        * Copy over our part of the bio_vec, then update the first
-        * and last (or only) entries.
-        */
-       memcpy(&bio->bi_io_vec[0], &bio_src->bi_io_vec[idx],
-                       vcnt * sizeof (struct bio_vec));
-       bio->bi_io_vec[0].bv_offset += voff;
-       if (vcnt > 1) {
-               bio->bi_io_vec[0].bv_len -= voff;
-               bio->bi_io_vec[vcnt - 1].bv_len = resid;
-       } else {
-               bio->bi_io_vec[0].bv_len = len;
-       }
-
-       bio->bi_vcnt = vcnt;
-       bio->bi_size = len;
-       bio->bi_idx = 0;
+       bio_advance(bio, offset);
+       bio->bi_iter.bi_size = len;
 
        return bio;
 }
@@ -1271,7 +1258,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src,
 
        /* Build up a chain of clone bios up to the limit */
 
-       if (!bi || off >= bi->bi_size || !len)
+       if (!bi || off >= bi->bi_iter.bi_size || !len)
                return NULL;            /* Nothing to clone */
 
        end = &chain;
@@ -1283,7 +1270,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src,
                        rbd_warn(NULL, "bio_chain exhausted with %u left", len);
                        goto out_err;   /* EINVAL; ran out of bio's */
                }
-               bi_size = min_t(unsigned int, bi->bi_size - off, len);
+               bi_size = min_t(unsigned int, bi->bi_iter.bi_size - off, len);
                bio = bio_clone_range(bi, off, bi_size, gfpmask);
                if (!bio)
                        goto out_err;   /* ENOMEM */
@@ -1292,7 +1279,7 @@ static struct bio *bio_chain_clone_range(struct bio **bio_src,
                end = &bio->bi_next;
 
                off += bi_size;
-               if (off == bi->bi_size) {
+               if (off == bi->bi_iter.bi_size) {
                        bi = bi->bi_next;
                        off = 0;
                }
@@ -1761,11 +1748,8 @@ static struct ceph_osd_request *rbd_osd_req_create(
        osd_req->r_callback = rbd_osd_req_callback;
        osd_req->r_priv = obj_request;
 
-       osd_req->r_oid_len = strlen(obj_request->object_name);
-       rbd_assert(osd_req->r_oid_len < sizeof (osd_req->r_oid));
-       memcpy(osd_req->r_oid, obj_request->object_name, osd_req->r_oid_len);
-
-       osd_req->r_file_layout = rbd_dev->layout;       /* struct */
+       osd_req->r_base_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout);
+       ceph_oid_set_name(&osd_req->r_base_oid, obj_request->object_name);
 
        return osd_req;
 }
@@ -1802,11 +1786,8 @@ rbd_osd_req_create_copyup(struct rbd_obj_request *obj_request)
        osd_req->r_callback = rbd_osd_req_callback;
        osd_req->r_priv = obj_request;
 
-       osd_req->r_oid_len = strlen(obj_request->object_name);
-       rbd_assert(osd_req->r_oid_len < sizeof (osd_req->r_oid));
-       memcpy(osd_req->r_oid, obj_request->object_name, osd_req->r_oid_len);
-
-       osd_req->r_file_layout = rbd_dev->layout;       /* struct */
+       osd_req->r_base_oloc.pool = ceph_file_layout_pg_pool(rbd_dev->layout);
+       ceph_oid_set_name(&osd_req->r_base_oid, obj_request->object_name);
 
        return osd_req;
 }
@@ -2186,7 +2167,8 @@ static int rbd_img_request_fill(struct rbd_img_request *img_request,
 
        if (type == OBJ_REQUEST_BIO) {
                bio_list = data_desc;
-               rbd_assert(img_offset == bio_list->bi_sector << SECTOR_SHIFT);
+               rbd_assert(img_offset ==
+                          bio_list->bi_iter.bi_sector << SECTOR_SHIFT);
        } else {
                rbd_assert(type == OBJ_REQUEST_PAGES);
                pages = data_desc;
@@ -2866,7 +2848,7 @@ static void rbd_watch_cb(u64 ver, u64 notify_id, u8 opcode, void *data)
  * Request sync osd watch/unwatch.  The value of "start" determines
  * whether a watch request is being initiated or torn down.
  */
-static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start)
+static int __rbd_dev_header_watch_sync(struct rbd_device *rbd_dev, bool start)
 {
        struct ceph_osd_client *osdc = &rbd_dev->rbd_client->client->osdc;
        struct rbd_obj_request *obj_request;
@@ -2941,6 +2923,22 @@ out_cancel:
        return ret;
 }
 
+static int rbd_dev_header_watch_sync(struct rbd_device *rbd_dev)
+{
+       return __rbd_dev_header_watch_sync(rbd_dev, true);
+}
+
+static void rbd_dev_header_unwatch_sync(struct rbd_device *rbd_dev)
+{
+       int ret;
+
+       ret = __rbd_dev_header_watch_sync(rbd_dev, false);
+       if (ret) {
+               rbd_warn(rbd_dev, "unable to tear down watch request: %d\n",
+                        ret);
+       }
+}
+
 /*
  * Synchronous osd object method call.  Returns the number of bytes
  * returned in the outbound buffer, or a negative error code.
@@ -3388,14 +3386,18 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
        u64 segment_size;
 
        /* create gendisk info */
-       disk = alloc_disk(RBD_MINORS_PER_MAJOR);
+       disk = alloc_disk(single_major ?
+                         (1 << RBD_SINGLE_MAJOR_PART_SHIFT) :
+                         RBD_MINORS_PER_MAJOR);
        if (!disk)
                return -ENOMEM;
 
        snprintf(disk->disk_name, sizeof(disk->disk_name), RBD_DRV_NAME "%d",
                 rbd_dev->dev_id);
        disk->major = rbd_dev->major;
-       disk->first_minor = 0;
+       disk->first_minor = rbd_dev->minor;
+       if (single_major)
+               disk->flags |= GENHD_FL_EXT_DEVT;
        disk->fops = &rbd_bd_ops;
        disk->private_data = rbd_dev;
 
@@ -3467,7 +3469,14 @@ static ssize_t rbd_major_show(struct device *dev,
                return sprintf(buf, "%d\n", rbd_dev->major);
 
        return sprintf(buf, "(none)\n");
+}
+
+static ssize_t rbd_minor_show(struct device *dev,
+                             struct device_attribute *attr, char *buf)
+{
+       struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
 
+       return sprintf(buf, "%d\n", rbd_dev->minor);
 }
 
 static ssize_t rbd_client_id_show(struct device *dev,
@@ -3589,6 +3598,7 @@ static ssize_t rbd_image_refresh(struct device *dev,
 static DEVICE_ATTR(size, S_IRUGO, rbd_size_show, NULL);
 static DEVICE_ATTR(features, S_IRUGO, rbd_features_show, NULL);
 static DEVICE_ATTR(major, S_IRUGO, rbd_major_show, NULL);
+static DEVICE_ATTR(minor, S_IRUGO, rbd_minor_show, NULL);
 static DEVICE_ATTR(client_id, S_IRUGO, rbd_client_id_show, NULL);
 static DEVICE_ATTR(pool, S_IRUGO, rbd_pool_show, NULL);
 static DEVICE_ATTR(pool_id, S_IRUGO, rbd_pool_id_show, NULL);
@@ -3602,6 +3612,7 @@ static struct attribute *rbd_attrs[] = {
        &dev_attr_size.attr,
        &dev_attr_features.attr,
        &dev_attr_major.attr,
+       &dev_attr_minor.attr,
        &dev_attr_client_id.attr,
        &dev_attr_pool.attr,
        &dev_attr_pool_id.attr,
@@ -4372,21 +4383,29 @@ static void rbd_bus_del_dev(struct rbd_device *rbd_dev)
        device_unregister(&rbd_dev->dev);
 }
 
-static atomic64_t rbd_dev_id_max = ATOMIC64_INIT(0);
-
 /*
  * Get a unique rbd identifier for the given new rbd_dev, and add
- * the rbd_dev to the global list.  The minimum rbd id is 1.
+ * the rbd_dev to the global list.
  */
-static void rbd_dev_id_get(struct rbd_device *rbd_dev)
+static int rbd_dev_id_get(struct rbd_device *rbd_dev)
 {
-       rbd_dev->dev_id = atomic64_inc_return(&rbd_dev_id_max);
+       int new_dev_id;
+
+       new_dev_id = ida_simple_get(&rbd_dev_id_ida,
+                                   0, minor_to_rbd_dev_id(1 << MINORBITS),
+                                   GFP_KERNEL);
+       if (new_dev_id < 0)
+               return new_dev_id;
+
+       rbd_dev->dev_id = new_dev_id;
 
        spin_lock(&rbd_dev_list_lock);
        list_add_tail(&rbd_dev->node, &rbd_dev_list);
        spin_unlock(&rbd_dev_list_lock);
-       dout("rbd_dev %p given dev id %llu\n", rbd_dev,
-               (unsigned long long) rbd_dev->dev_id);
+
+       dout("rbd_dev %p given dev id %d\n", rbd_dev, rbd_dev->dev_id);
+
+       return 0;
 }
 
 /*
@@ -4395,49 +4414,13 @@ static void rbd_dev_id_get(struct rbd_device *rbd_dev)
  */
 static void rbd_dev_id_put(struct rbd_device *rbd_dev)
 {
-       struct list_head *tmp;
-       int rbd_id = rbd_dev->dev_id;
-       int max_id;
-
-       rbd_assert(rbd_id > 0);
-
-       dout("rbd_dev %p released dev id %llu\n", rbd_dev,
-               (unsigned long long) rbd_dev->dev_id);
        spin_lock(&rbd_dev_list_lock);
        list_del_init(&rbd_dev->node);
-
-       /*
-        * If the id being "put" is not the current maximum, there
-        * is nothing special we need to do.
-        */
-       if (rbd_id != atomic64_read(&rbd_dev_id_max)) {
-               spin_unlock(&rbd_dev_list_lock);
-               return;
-       }
-
-       /*
-        * We need to update the current maximum id.  Search the
-        * list to find out what it is.  We're more likely to find
-        * the maximum at the end, so search the list backward.
-        */
-       max_id = 0;
-       list_for_each_prev(tmp, &rbd_dev_list) {
-               struct rbd_device *rbd_dev;
-
-               rbd_dev = list_entry(tmp, struct rbd_device, node);
-               if (rbd_dev->dev_id > max_id)
-                       max_id = rbd_dev->dev_id;
-       }
        spin_unlock(&rbd_dev_list_lock);
 
-       /*
-        * The max id could have been updated by rbd_dev_id_get(), in
-        * which case it now accurately reflects the new maximum.
-        * Be careful not to overwrite the maximum value in that
-        * case.
-        */
-       atomic64_cmpxchg(&rbd_dev_id_max, rbd_id, max_id);
-       dout("  max dev id has been reset\n");
+       ida_simple_remove(&rbd_dev_id_ida, rbd_dev->dev_id);
+
+       dout("rbd_dev %p released dev id %d\n", rbd_dev, rbd_dev->dev_id);
 }
 
 /*
@@ -4860,20 +4843,29 @@ static int rbd_dev_device_setup(struct rbd_device *rbd_dev)
 {
        int ret;
 
-       /* generate unique id: find highest unique id, add one */
-       rbd_dev_id_get(rbd_dev);
+       /* Get an id and fill in device name. */
+
+       ret = rbd_dev_id_get(rbd_dev);
+       if (ret)
+               return ret;
 
-       /* Fill in the device name, now that we have its id. */
        BUILD_BUG_ON(DEV_NAME_LEN
                        < sizeof (RBD_DRV_NAME) + MAX_INT_FORMAT_WIDTH);
        sprintf(rbd_dev->name, "%s%d", RBD_DRV_NAME, rbd_dev->dev_id);
 
-       /* Get our block major device number. */
+       /* Record our major and minor device numbers. */
 
-       ret = register_blkdev(0, rbd_dev->name);
-       if (ret < 0)
-               goto err_out_id;
-       rbd_dev->major = ret;
+       if (!single_major) {
+               ret = register_blkdev(0, rbd_dev->name);
+               if (ret < 0)
+                       goto err_out_id;
+
+               rbd_dev->major = ret;
+               rbd_dev->minor = 0;
+       } else {
+               rbd_dev->major = rbd_major;
+               rbd_dev->minor = rbd_dev_id_to_minor(rbd_dev->dev_id);
+       }
 
        /* Set up the blkdev mapping. */
 
@@ -4905,7 +4897,8 @@ err_out_mapping:
 err_out_disk:
        rbd_free_disk(rbd_dev);
 err_out_blkdev:
-       unregister_blkdev(rbd_dev->major, rbd_dev->name);
+       if (!single_major)
+               unregister_blkdev(rbd_dev->major, rbd_dev->name);
 err_out_id:
        rbd_dev_id_put(rbd_dev);
        rbd_dev_mapping_clear(rbd_dev);
@@ -4961,7 +4954,6 @@ static void rbd_dev_image_release(struct rbd_device *rbd_dev)
 static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping)
 {
        int ret;
-       int tmp;
 
        /*
         * Get the id from the image id object.  Unless there's an
@@ -4980,7 +4972,7 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping)
                goto err_out_format;
 
        if (mapping) {
-               ret = rbd_dev_header_watch_sync(rbd_dev, true);
+               ret = rbd_dev_header_watch_sync(rbd_dev);
                if (ret)
                        goto out_header_name;
        }
@@ -5007,12 +4999,8 @@ static int rbd_dev_image_probe(struct rbd_device *rbd_dev, bool mapping)
 err_out_probe:
        rbd_dev_unprobe(rbd_dev);
 err_out_watch:
-       if (mapping) {
-               tmp = rbd_dev_header_watch_sync(rbd_dev, false);
-               if (tmp)
-                       rbd_warn(rbd_dev, "unable to tear down "
-                                       "watch request (%d)\n", tmp);
-       }
+       if (mapping)
+               rbd_dev_header_unwatch_sync(rbd_dev);
 out_header_name:
        kfree(rbd_dev->header_name);
        rbd_dev->header_name = NULL;
@@ -5026,9 +5014,9 @@ err_out_format:
        return ret;
 }
 
-static ssize_t rbd_add(struct bus_type *bus,
-                      const char *buf,
-                      size_t count)
+static ssize_t do_rbd_add(struct bus_type *bus,
+                         const char *buf,
+                         size_t count)
 {
        struct rbd_device *rbd_dev = NULL;
        struct ceph_options *ceph_opts = NULL;
@@ -5090,6 +5078,12 @@ static ssize_t rbd_add(struct bus_type *bus,
 
        rc = rbd_dev_device_setup(rbd_dev);
        if (rc) {
+               /*
+                * rbd_dev_header_unwatch_sync() can't be moved into
+                * rbd_dev_image_release() without refactoring, see
+                * commit 1f3ef78861ac.
+                */
+               rbd_dev_header_unwatch_sync(rbd_dev);
                rbd_dev_image_release(rbd_dev);
                goto err_out_module;
        }
@@ -5110,6 +5104,23 @@ err_out_module:
        return (ssize_t)rc;
 }
 
+static ssize_t rbd_add(struct bus_type *bus,
+                      const char *buf,
+                      size_t count)
+{
+       if (single_major)
+               return -EINVAL;
+
+       return do_rbd_add(bus, buf, count);
+}
+
+static ssize_t rbd_add_single_major(struct bus_type *bus,
+                                   const char *buf,
+                                   size_t count)
+{
+       return do_rbd_add(bus, buf, count);
+}
+
 static void rbd_dev_device_release(struct device *dev)
 {
        struct rbd_device *rbd_dev = dev_to_rbd_dev(dev);
@@ -5117,8 +5128,8 @@ static void rbd_dev_device_release(struct device *dev)
        rbd_free_disk(rbd_dev);
        clear_bit(RBD_DEV_FLAG_EXISTS, &rbd_dev->flags);
        rbd_dev_mapping_clear(rbd_dev);
-       unregister_blkdev(rbd_dev->major, rbd_dev->name);
-       rbd_dev->major = 0;
+       if (!single_major)
+               unregister_blkdev(rbd_dev->major, rbd_dev->name);
        rbd_dev_id_put(rbd_dev);
        rbd_dev_mapping_clear(rbd_dev);
 }
@@ -5149,9 +5160,9 @@ static void rbd_dev_remove_parent(struct rbd_device *rbd_dev)
        }
 }
 
-static ssize_t rbd_remove(struct bus_type *bus,
-                         const char *buf,
-                         size_t count)
+static ssize_t do_rbd_remove(struct bus_type *bus,
+                            const char *buf,
+                            size_t count)
 {
        struct rbd_device *rbd_dev = NULL;
        struct list_head *tmp;
@@ -5191,16 +5202,14 @@ static ssize_t rbd_remove(struct bus_type *bus,
        if (ret < 0 || already)
                return ret;
 
-       ret = rbd_dev_header_watch_sync(rbd_dev, false);
-       if (ret)
-               rbd_warn(rbd_dev, "failed to cancel watch event (%d)\n", ret);
-
+       rbd_dev_header_unwatch_sync(rbd_dev);
        /*
         * flush remaining watch callbacks - these must be complete
         * before the osd_client is shutdown
         */
        dout("%s: flushing notifies", __func__);
        ceph_osdc_flush_notifies(&rbd_dev->rbd_client->client->osdc);
+
        /*
         * Don't free anything from rbd_dev->disk until after all
         * notifies are completely processed. Otherwise
@@ -5214,6 +5223,23 @@ static ssize_t rbd_remove(struct bus_type *bus,
        return count;
 }
 
+static ssize_t rbd_remove(struct bus_type *bus,
+                         const char *buf,
+                         size_t count)
+{
+       if (single_major)
+               return -EINVAL;
+
+       return do_rbd_remove(bus, buf, count);
+}
+
+static ssize_t rbd_remove_single_major(struct bus_type *bus,
+                                      const char *buf,
+                                      size_t count)
+{
+       return do_rbd_remove(bus, buf, count);
+}
+
 /*
  * create control files in sysfs
  * /sys/bus/rbd/...
@@ -5259,7 +5285,7 @@ static int rbd_slab_init(void)
 
        rbd_assert(!rbd_segment_name_cache);
        rbd_segment_name_cache = kmem_cache_create("rbd_segment_name",
-                                       MAX_OBJ_NAME_SIZE + 1, 1, 0, NULL);
+                                       CEPH_MAX_OID_NAME_LEN + 1, 1, 0, NULL);
        if (rbd_segment_name_cache)
                return 0;
 out_err:
@@ -5295,24 +5321,45 @@ static int __init rbd_init(void)
 
        if (!libceph_compatible(NULL)) {
                rbd_warn(NULL, "libceph incompatibility (quitting)");
-
                return -EINVAL;
        }
+
        rc = rbd_slab_init();
        if (rc)
                return rc;
+
+       if (single_major) {
+               rbd_major = register_blkdev(0, RBD_DRV_NAME);
+               if (rbd_major < 0) {
+                       rc = rbd_major;
+                       goto err_out_slab;
+               }
+       }
+
        rc = rbd_sysfs_init();
        if (rc)
-               rbd_slab_exit();
+               goto err_out_blkdev;
+
+       if (single_major)
+               pr_info("loaded (major %d)\n", rbd_major);
        else
-               pr_info("loaded " RBD_DRV_NAME_LONG "\n");
+               pr_info("loaded\n");
+
+       return 0;
 
+err_out_blkdev:
+       if (single_major)
+               unregister_blkdev(rbd_major, RBD_DRV_NAME);
+err_out_slab:
+       rbd_slab_exit();
        return rc;
 }
 
 static void __exit rbd_exit(void)
 {
        rbd_sysfs_cleanup();
+       if (single_major)
+               unregister_blkdev(rbd_major, RBD_DRV_NAME);
        rbd_slab_exit();
 }
 
@@ -5322,9 +5369,8 @@ module_exit(rbd_exit);
 MODULE_AUTHOR("Alex Elder <elder@inktank.com>");
 MODULE_AUTHOR("Sage Weil <sage@newdream.net>");
 MODULE_AUTHOR("Yehuda Sadeh <yehuda@hq.newdream.net>");
-MODULE_DESCRIPTION("rados block device");
-
 /* following authorship retained from original osdblk.c */
 MODULE_AUTHOR("Jeff Garzik <jeff@garzik.org>");
 
+MODULE_DESCRIPTION("RADOS Block Device (RBD) driver");
 MODULE_LICENSE("GPL");
index 2284f5d3a54ad00dd05c512b30b7bfed30411482..2839d37e5af77922051cb1d48561602ea3a3c2b7 100644 (file)
@@ -174,7 +174,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio)
        if (!card)
                goto req_err;
 
-       if (bio->bi_sector + (bio->bi_size >> 9) > get_capacity(card->gendisk))
+       if (bio_end_sector(bio) > get_capacity(card->gendisk))
                goto req_err;
 
        if (unlikely(card->halt)) {
@@ -187,7 +187,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio)
                goto req_err;
        }
 
-       if (bio->bi_size == 0) {
+       if (bio->bi_iter.bi_size == 0) {
                dev_err(CARD_TO_DEV(card), "size zero BIO!\n");
                goto req_err;
        }
@@ -208,7 +208,7 @@ static void rsxx_make_request(struct request_queue *q, struct bio *bio)
 
        dev_dbg(CARD_TO_DEV(card), "BIO[%c]: meta: %p addr8: x%llx size: %d\n",
                 bio_data_dir(bio) ? 'W' : 'R', bio_meta,
-                (u64)bio->bi_sector << 9, bio->bi_size);
+                (u64)bio->bi_iter.bi_sector << 9, bio->bi_iter.bi_size);
 
        st = rsxx_dma_queue_bio(card, bio, &bio_meta->pending_dmas,
                                    bio_dma_done_cb, bio_meta);
index fc88ba3e1bd27835ecf170d5ba321cf8313a6cea..cf8cd293abb51d338cd6d0ae7762070c80be99a2 100644 (file)
@@ -684,7 +684,8 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
                           void *cb_data)
 {
        struct list_head dma_list[RSXX_MAX_TARGETS];
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
        unsigned long long addr8;
        unsigned int laddr;
        unsigned int bv_len;
@@ -696,7 +697,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
        int st;
        int i;
 
-       addr8 = bio->bi_sector << 9; /* sectors are 512 bytes */
+       addr8 = bio->bi_iter.bi_sector << 9; /* sectors are 512 bytes */
        atomic_set(n_dmas, 0);
 
        for (i = 0; i < card->n_targets; i++) {
@@ -705,7 +706,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
        }
 
        if (bio->bi_rw & REQ_DISCARD) {
-               bv_len = bio->bi_size;
+               bv_len = bio->bi_iter.bi_size;
 
                while (bv_len > 0) {
                        tgt   = rsxx_get_dma_tgt(card, addr8);
@@ -722,9 +723,9 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
                        bv_len -= RSXX_HW_BLK_SIZE;
                }
        } else {
-               bio_for_each_segment(bvec, bio, i) {
-                       bv_len = bvec->bv_len;
-                       bv_off = bvec->bv_offset;
+               bio_for_each_segment(bvec, bio, iter) {
+                       bv_len = bvec.bv_len;
+                       bv_off = bvec.bv_offset;
 
                        while (bv_len > 0) {
                                tgt   = rsxx_get_dma_tgt(card, addr8);
@@ -736,7 +737,7 @@ int rsxx_dma_queue_bio(struct rsxx_cardinfo *card,
                                st = rsxx_queue_dma(card, &dma_list[tgt],
                                                        bio_data_dir(bio),
                                                        dma_off, dma_len,
-                                                       laddr, bvec->bv_page,
+                                                       laddr, bvec.bv_page,
                                                        bv_off, cb, cb_data);
                                if (st)
                                        goto bvec_err;
index 3fb6ab4c8b4e9e96f9ba487cf801fdcd776f0c73..d5e2d12b9d9e329d77fb21560b8f21e5e98a11f4 100644 (file)
@@ -1744,20 +1744,6 @@ static void carm_remove_one (struct pci_dev *pdev)
        kfree(host);
        pci_release_regions(pdev);
        pci_disable_device(pdev);
-       pci_set_drvdata(pdev, NULL);
 }
 
-static int __init carm_init(void)
-{
-       return pci_register_driver(&carm_driver);
-}
-
-static void __exit carm_exit(void)
-{
-       pci_unregister_driver(&carm_driver);
-}
-
-module_init(carm_init);
-module_exit(carm_exit);
-
-
+module_pci_driver(carm_driver);
index ad70868f8a967b40bc866bc5430387b55f4601ac..4cf81b5bf0f7fba42a243a7e717ead98b2144759 100644 (file)
@@ -108,8 +108,7 @@ struct cardinfo {
                                    * have been written
                                    */
        struct bio      *bio, *currentbio, **biotail;
-       int             current_idx;
-       sector_t        current_sector;
+       struct bvec_iter current_iter;
 
        struct request_queue *queue;
 
@@ -118,7 +117,7 @@ struct cardinfo {
                struct mm_dma_desc      *desc;
                int                     cnt, headcnt;
                struct bio              *bio, **biotail;
-               int                     idx;
+               struct bvec_iter        iter;
        } mm_pages[2];
 #define DESC_PER_PAGE ((PAGE_SIZE*2)/sizeof(struct mm_dma_desc))
 
@@ -344,16 +343,13 @@ static int add_bio(struct cardinfo *card)
        dma_addr_t dma_handle;
        int offset;
        struct bio *bio;
-       struct bio_vec *vec;
-       int idx;
+       struct bio_vec vec;
        int rw;
-       int len;
 
        bio = card->currentbio;
        if (!bio && card->bio) {
                card->currentbio = card->bio;
-               card->current_idx = card->bio->bi_idx;
-               card->current_sector = card->bio->bi_sector;
+               card->current_iter = card->bio->bi_iter;
                card->bio = card->bio->bi_next;
                if (card->bio == NULL)
                        card->biotail = &card->bio;
@@ -362,18 +358,17 @@ static int add_bio(struct cardinfo *card)
        }
        if (!bio)
                return 0;
-       idx = card->current_idx;
 
        rw = bio_rw(bio);
        if (card->mm_pages[card->Ready].cnt >= DESC_PER_PAGE)
                return 0;
 
-       vec = bio_iovec_idx(bio, idx);
-       len = vec->bv_len;
+       vec = bio_iter_iovec(bio, card->current_iter);
+
        dma_handle = pci_map_page(card->dev,
-                                 vec->bv_page,
-                                 vec->bv_offset,
-                                 len,
+                                 vec.bv_page,
+                                 vec.bv_offset,
+                                 vec.bv_len,
                                  (rw == READ) ?
                                  PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
 
@@ -381,7 +376,7 @@ static int add_bio(struct cardinfo *card)
        desc = &p->desc[p->cnt];
        p->cnt++;
        if (p->bio == NULL)
-               p->idx = idx;
+               p->iter = card->current_iter;
        if ((p->biotail) != &bio->bi_next) {
                *(p->biotail) = bio;
                p->biotail = &(bio->bi_next);
@@ -391,8 +386,8 @@ static int add_bio(struct cardinfo *card)
        desc->data_dma_handle = dma_handle;
 
        desc->pci_addr = cpu_to_le64((u64)desc->data_dma_handle);
-       desc->local_addr = cpu_to_le64(card->current_sector << 9);
-       desc->transfer_size = cpu_to_le32(len);
+       desc->local_addr = cpu_to_le64(card->current_iter.bi_sector << 9);
+       desc->transfer_size = cpu_to_le32(vec.bv_len);
        offset = (((char *)&desc->sem_control_bits) - ((char *)p->desc));
        desc->sem_addr = cpu_to_le64((u64)(p->page_dma+offset));
        desc->zero1 = desc->zero2 = 0;
@@ -407,10 +402,9 @@ static int add_bio(struct cardinfo *card)
                desc->control_bits |= cpu_to_le32(DMASCR_TRANSFER_READ);
        desc->sem_control_bits = desc->control_bits;
 
-       card->current_sector += (len >> 9);
-       idx++;
-       card->current_idx = idx;
-       if (idx >= bio->bi_vcnt)
+
+       bio_advance_iter(bio, &card->current_iter, vec.bv_len);
+       if (!card->current_iter.bi_size)
                card->currentbio = NULL;
 
        return 1;
@@ -439,23 +433,25 @@ static void process_page(unsigned long data)
                struct mm_dma_desc *desc = &page->desc[page->headcnt];
                int control = le32_to_cpu(desc->sem_control_bits);
                int last = 0;
-               int idx;
+               struct bio_vec vec;
 
                if (!(control & DMASCR_DMA_COMPLETE)) {
                        control = dma_status;
                        last = 1;
                }
+
                page->headcnt++;
-               idx = page->idx;
-               page->idx++;
-               if (page->idx >= bio->bi_vcnt) {
+               vec = bio_iter_iovec(bio, page->iter);
+               bio_advance_iter(bio, &page->iter, vec.bv_len);
+
+               if (!page->iter.bi_size) {
                        page->bio = bio->bi_next;
                        if (page->bio)
-                               page->idx = page->bio->bi_idx;
+                               page->iter = page->bio->bi_iter;
                }
 
                pci_unmap_page(card->dev, desc->data_dma_handle,
-                              bio_iovec_idx(bio, idx)->bv_len,
+                              vec.bv_len,
                                 (control & DMASCR_TRANSFER_READ) ?
                                PCI_DMA_TODEVICE : PCI_DMA_FROMDEVICE);
                if (control & DMASCR_HARD_ERROR) {
@@ -532,7 +528,8 @@ static void mm_make_request(struct request_queue *q, struct bio *bio)
 {
        struct cardinfo *card = q->queuedata;
        pr_debug("mm_make_request %llu %u\n",
-                (unsigned long long)bio->bi_sector, bio->bi_size);
+                (unsigned long long)bio->bi_iter.bi_sector,
+                bio->bi_iter.bi_size);
 
        spin_lock_irq(&card->lock);
        *card->biotail = bio;
index 6620b73d04906191132d771dade31f9e00043e07..da18046d0e0773bf0986d1ef4510d3b0349e59d3 100644 (file)
@@ -285,8 +285,7 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
 
                if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST ||
                        !rb_next(&persistent_gnt->node)) {
-                       ret = gnttab_unmap_refs(unmap, NULL, pages,
-                               segs_to_unmap);
+                       ret = gnttab_unmap_refs(unmap, pages, segs_to_unmap);
                        BUG_ON(ret);
                        put_free_pages(blkif, pages, segs_to_unmap);
                        segs_to_unmap = 0;
@@ -321,8 +320,7 @@ static void unmap_purged_grants(struct work_struct *work)
                pages[segs_to_unmap] = persistent_gnt->page;
 
                if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
-                       ret = gnttab_unmap_refs(unmap, NULL, pages,
-                               segs_to_unmap);
+                       ret = gnttab_unmap_refs(unmap, pages, segs_to_unmap);
                        BUG_ON(ret);
                        put_free_pages(blkif, pages, segs_to_unmap);
                        segs_to_unmap = 0;
@@ -330,7 +328,7 @@ static void unmap_purged_grants(struct work_struct *work)
                kfree(persistent_gnt);
        }
        if (segs_to_unmap > 0) {
-               ret = gnttab_unmap_refs(unmap, NULL, pages, segs_to_unmap);
+               ret = gnttab_unmap_refs(unmap, pages, segs_to_unmap);
                BUG_ON(ret);
                put_free_pages(blkif, pages, segs_to_unmap);
        }
@@ -670,15 +668,14 @@ static void xen_blkbk_unmap(struct xen_blkif *blkif,
                                    GNTMAP_host_map, pages[i]->handle);
                pages[i]->handle = BLKBACK_INVALID_HANDLE;
                if (++invcount == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
-                       ret = gnttab_unmap_refs(unmap, NULL, unmap_pages,
-                                               invcount);
+                       ret = gnttab_unmap_refs(unmap, unmap_pages, invcount);
                        BUG_ON(ret);
                        put_free_pages(blkif, unmap_pages, invcount);
                        invcount = 0;
                }
        }
        if (invcount) {
-               ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount);
+               ret = gnttab_unmap_refs(unmap, unmap_pages, invcount);
                BUG_ON(ret);
                put_free_pages(blkif, unmap_pages, invcount);
        }
@@ -740,7 +737,7 @@ again:
        }
 
        if (segs_to_map) {
-               ret = gnttab_map_refs(map, NULL, pages_to_gnt, segs_to_map);
+               ret = gnttab_map_refs(map, pages_to_gnt, segs_to_map);
                BUG_ON(ret);
        }
 
@@ -1257,7 +1254,7 @@ static int dispatch_rw_block_io(struct xen_blkif *blkif,
                        bio->bi_bdev    = preq.bdev;
                        bio->bi_private = pending_req;
                        bio->bi_end_io  = end_block_io_op;
-                       bio->bi_sector  = preq.sector_number;
+                       bio->bi_iter.bi_sector  = preq.sector_number;
                }
 
                preq.sector_number += seg[i].nsec;
index f9c43f91f03e5de68bff030b663f094e56fc1f9f..8dcfb54f160302e0e1d91c232387f758b2f8e0f6 100644 (file)
@@ -1547,7 +1547,7 @@ static int blkif_recover(struct blkfront_info *info)
                        for (i = 0; i < pending; i++) {
                                offset = (i * segs * PAGE_SIZE) >> 9;
                                size = min((unsigned int)(segs * PAGE_SIZE) >> 9,
-                                          (unsigned int)(bio->bi_size >> 9) - offset);
+                                          (unsigned int)bio_sectors(bio) - offset);
                                cloned_bio = bio_clone(bio, GFP_NOIO);
                                BUG_ON(cloned_bio == NULL);
                                bio_trim(cloned_bio, offset, size);
similarity index 93%
rename from drivers/staging/zram/Kconfig
rename to drivers/block/zram/Kconfig
index 983314c41349666c08213fe6f0dbd0e1509d4d9e..3450be85039943c649a3a96ff54376b39113f542 100644 (file)
@@ -14,7 +14,6 @@ config ZRAM
          disks and maybe many more.
 
          See zram.txt for more information.
-         Project home: <https://compcache.googlecode.com/>
 
 config ZRAM_DEBUG
        bool "Compressed RAM block device debug support"
similarity index 87%
rename from drivers/staging/zram/zram_drv.c
rename to drivers/block/zram/zram_drv.c
index 3277d9838f4e928ab3555720a186e476e826a720..011e55d820b1811a3379a65a4ef754fcc785f3ef 100644 (file)
@@ -2,6 +2,7 @@
  * Compressed RAM block device
  *
  * Copyright (C) 2008, 2009, 2010  Nitin Gupta
+ *               2012, 2013 Minchan Kim
  *
  * This code is released using a dual license strategy: BSD/GPL
  * You can choose the licence that better fits your requirements.
@@ -9,7 +10,6 @@
  * Released under the terms of 3-clause BSD License
  * Released under the terms of GNU General Public License Version 2.0
  *
- * Project home: http://compcache.googlecode.com
  */
 
 #define KMSG_COMPONENT "zram"
@@ -104,7 +104,7 @@ static ssize_t zero_pages_show(struct device *dev,
 {
        struct zram *zram = dev_to_zram(dev);
 
-       return sprintf(buf, "%u\n", zram->stats.pages_zero);
+       return sprintf(buf, "%u\n", atomic_read(&zram->stats.pages_zero));
 }
 
 static ssize_t orig_data_size_show(struct device *dev,
@@ -113,7 +113,7 @@ static ssize_t orig_data_size_show(struct device *dev,
        struct zram *zram = dev_to_zram(dev);
 
        return sprintf(buf, "%llu\n",
-               (u64)(zram->stats.pages_stored) << PAGE_SHIFT);
+               (u64)(atomic_read(&zram->stats.pages_stored)) << PAGE_SHIFT);
 }
 
 static ssize_t compr_data_size_show(struct device *dev,
@@ -140,6 +140,7 @@ static ssize_t mem_used_total_show(struct device *dev,
        return sprintf(buf, "%llu\n", val);
 }
 
+/* flag operations needs meta->tb_lock */
 static int zram_test_flag(struct zram_meta *meta, u32 index,
                        enum zram_pageflags flag)
 {
@@ -171,13 +172,14 @@ static inline int valid_io_request(struct zram *zram, struct bio *bio)
        u64 start, end, bound;
 
        /* unaligned request */
-       if (unlikely(bio->bi_sector & (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
+       if (unlikely(bio->bi_iter.bi_sector &
+                    (ZRAM_SECTOR_PER_LOGICAL_BLOCK - 1)))
                return 0;
-       if (unlikely(bio->bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))
+       if (unlikely(bio->bi_iter.bi_size & (ZRAM_LOGICAL_BLOCK_SIZE - 1)))
                return 0;
 
-       start = bio->bi_sector;
-       end = start + (bio->bi_size >> SECTOR_SHIFT);
+       start = bio->bi_iter.bi_sector;
+       end = start + (bio->bi_iter.bi_size >> SECTOR_SHIFT);
        bound = zram->disksize >> SECTOR_SHIFT;
        /* out of range range */
        if (unlikely(start >= bound || end > bound || start > end))
@@ -227,6 +229,8 @@ static struct zram_meta *zram_meta_alloc(u64 disksize)
                goto free_table;
        }
 
+       rwlock_init(&meta->tb_lock);
+       mutex_init(&meta->buffer_lock);
        return meta;
 
 free_table:
@@ -279,6 +283,7 @@ static void handle_zero_page(struct bio_vec *bvec)
        flush_dcache_page(page);
 }
 
+/* NOTE: caller should hold meta->tb_lock with write-side */
 static void zram_free_page(struct zram *zram, size_t index)
 {
        struct zram_meta *meta = zram->meta;
@@ -292,21 +297,21 @@ static void zram_free_page(struct zram *zram, size_t index)
                 */
                if (zram_test_flag(meta, index, ZRAM_ZERO)) {
                        zram_clear_flag(meta, index, ZRAM_ZERO);
-                       zram->stats.pages_zero--;
+                       atomic_dec(&zram->stats.pages_zero);
                }
                return;
        }
 
        if (unlikely(size > max_zpage_size))
-               zram->stats.bad_compress--;
+               atomic_dec(&zram->stats.bad_compress);
 
        zs_free(meta->mem_pool, handle);
 
        if (size <= PAGE_SIZE / 2)
-               zram->stats.good_compress--;
+               atomic_dec(&zram->stats.good_compress);
 
        atomic64_sub(meta->table[index].size, &zram->stats.compr_size);
-       zram->stats.pages_stored--;
+       atomic_dec(&zram->stats.pages_stored);
 
        meta->table[index].handle = 0;
        meta->table[index].size = 0;
@@ -318,20 +323,26 @@ static int zram_decompress_page(struct zram *zram, char *mem, u32 index)
        size_t clen = PAGE_SIZE;
        unsigned char *cmem;
        struct zram_meta *meta = zram->meta;
-       unsigned long handle = meta->table[index].handle;
+       unsigned long handle;
+       u16 size;
+
+       read_lock(&meta->tb_lock);
+       handle = meta->table[index].handle;
+       size = meta->table[index].size;
 
        if (!handle || zram_test_flag(meta, index, ZRAM_ZERO)) {
+               read_unlock(&meta->tb_lock);
                clear_page(mem);
                return 0;
        }
 
        cmem = zs_map_object(meta->mem_pool, handle, ZS_MM_RO);
-       if (meta->table[index].size == PAGE_SIZE)
+       if (size == PAGE_SIZE)
                copy_page(mem, cmem);
        else
-               ret = lzo1x_decompress_safe(cmem, meta->table[index].size,
-                                               mem, &clen);
+               ret = lzo1x_decompress_safe(cmem, size, mem, &clen);
        zs_unmap_object(meta->mem_pool, handle);
+       read_unlock(&meta->tb_lock);
 
        /* Should NEVER happen. Return bio error if it does. */
        if (unlikely(ret != LZO_E_OK)) {
@@ -352,11 +363,14 @@ static int zram_bvec_read(struct zram *zram, struct bio_vec *bvec,
        struct zram_meta *meta = zram->meta;
        page = bvec->bv_page;
 
+       read_lock(&meta->tb_lock);
        if (unlikely(!meta->table[index].handle) ||
                        zram_test_flag(meta, index, ZRAM_ZERO)) {
+               read_unlock(&meta->tb_lock);
                handle_zero_page(bvec);
                return 0;
        }
+       read_unlock(&meta->tb_lock);
 
        if (is_partial_io(bvec))
                /* Use  a temporary buffer to decompress the page */
@@ -399,6 +413,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
        struct page *page;
        unsigned char *user_mem, *cmem, *src, *uncmem = NULL;
        struct zram_meta *meta = zram->meta;
+       bool locked = false;
 
        page = bvec->bv_page;
        src = meta->compress_buffer;
@@ -418,6 +433,8 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
                        goto out;
        }
 
+       mutex_lock(&meta->buffer_lock);
+       locked = true;
        user_mem = kmap_atomic(page);
 
        if (is_partial_io(bvec)) {
@@ -432,25 +449,18 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
        if (page_zero_filled(uncmem)) {
                kunmap_atomic(user_mem);
                /* Free memory associated with this sector now. */
+               write_lock(&zram->meta->tb_lock);
                zram_free_page(zram, index);
-
-               zram->stats.pages_zero++;
                zram_set_flag(meta, index, ZRAM_ZERO);
+               write_unlock(&zram->meta->tb_lock);
+
+               atomic_inc(&zram->stats.pages_zero);
                ret = 0;
                goto out;
        }
 
-       /*
-        * zram_slot_free_notify could miss free so that let's
-        * double check.
-        */
-       if (unlikely(meta->table[index].handle ||
-                       zram_test_flag(meta, index, ZRAM_ZERO)))
-               zram_free_page(zram, index);
-
        ret = lzo1x_1_compress(uncmem, PAGE_SIZE, src, &clen,
                               meta->compress_workmem);
-
        if (!is_partial_io(bvec)) {
                kunmap_atomic(user_mem);
                user_mem = NULL;
@@ -463,7 +473,7 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
        }
 
        if (unlikely(clen > max_zpage_size)) {
-               zram->stats.bad_compress++;
+               atomic_inc(&zram->stats.bad_compress);
                clen = PAGE_SIZE;
                src = NULL;
                if (is_partial_io(bvec))
@@ -493,18 +503,22 @@ static int zram_bvec_write(struct zram *zram, struct bio_vec *bvec, u32 index,
         * Free memory associated with this sector
         * before overwriting unused sectors.
         */
+       write_lock(&zram->meta->tb_lock);
        zram_free_page(zram, index);
 
        meta->table[index].handle = handle;
        meta->table[index].size = clen;
+       write_unlock(&zram->meta->tb_lock);
 
        /* Update stats */
        atomic64_add(clen, &zram->stats.compr_size);
-       zram->stats.pages_stored++;
+       atomic_inc(&zram->stats.pages_stored);
        if (clen <= PAGE_SIZE / 2)
-               zram->stats.good_compress++;
+               atomic_inc(&zram->stats.good_compress);
 
 out:
+       if (locked)
+               mutex_unlock(&meta->buffer_lock);
        if (is_partial_io(bvec))
                kfree(uncmem);
 
@@ -513,36 +527,15 @@ out:
        return ret;
 }
 
-static void handle_pending_slot_free(struct zram *zram)
-{
-       struct zram_slot_free *free_rq;
-
-       spin_lock(&zram->slot_free_lock);
-       while (zram->slot_free_rq) {
-               free_rq = zram->slot_free_rq;
-               zram->slot_free_rq = free_rq->next;
-               zram_free_page(zram, free_rq->index);
-               kfree(free_rq);
-       }
-       spin_unlock(&zram->slot_free_lock);
-}
-
 static int zram_bvec_rw(struct zram *zram, struct bio_vec *bvec, u32 index,
                        int offset, struct bio *bio, int rw)
 {
        int ret;
 
-       if (rw == READ) {
-               down_read(&zram->lock);
-               handle_pending_slot_free(zram);
+       if (rw == READ)
                ret = zram_bvec_read(zram, bvec, index, offset, bio);
-               up_read(&zram->lock);
-       } else {
-               down_write(&zram->lock);
-               handle_pending_slot_free(zram);
+       else
                ret = zram_bvec_write(zram, bvec, index, offset);
-               up_write(&zram->lock);
-       }
 
        return ret;
 }
@@ -552,8 +545,6 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity)
        size_t index;
        struct zram_meta *meta;
 
-       flush_work(&zram->free_work);
-
        down_write(&zram->init_lock);
        if (!zram->init_done) {
                up_write(&zram->init_lock);
@@ -680,9 +671,10 @@ out:
 
 static void __zram_make_request(struct zram *zram, struct bio *bio, int rw)
 {
-       int i, offset;
+       int offset;
        u32 index;
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
 
        switch (rw) {
        case READ:
@@ -693,36 +685,37 @@ static void __zram_make_request(struct zram *zram, struct bio *bio, int rw)
                break;
        }
 
-       index = bio->bi_sector >> SECTORS_PER_PAGE_SHIFT;
-       offset = (bio->bi_sector & (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT;
+       index = bio->bi_iter.bi_sector >> SECTORS_PER_PAGE_SHIFT;
+       offset = (bio->bi_iter.bi_sector &
+                 (SECTORS_PER_PAGE - 1)) << SECTOR_SHIFT;
 
-       bio_for_each_segment(bvec, bio, i) {
+       bio_for_each_segment(bvec, bio, iter) {
                int max_transfer_size = PAGE_SIZE - offset;
 
-               if (bvec->bv_len > max_transfer_size) {
+               if (bvec.bv_len > max_transfer_size) {
                        /*
                         * zram_bvec_rw() can only make operation on a single
                         * zram page. Split the bio vector.
                         */
                        struct bio_vec bv;
 
-                       bv.bv_page = bvec->bv_page;
+                       bv.bv_page = bvec.bv_page;
                        bv.bv_len = max_transfer_size;
-                       bv.bv_offset = bvec->bv_offset;
+                       bv.bv_offset = bvec.bv_offset;
 
                        if (zram_bvec_rw(zram, &bv, index, offset, bio, rw) < 0)
                                goto out;
 
-                       bv.bv_len = bvec->bv_len - max_transfer_size;
+                       bv.bv_len = bvec.bv_len - max_transfer_size;
                        bv.bv_offset += max_transfer_size;
                        if (zram_bvec_rw(zram, &bv, index+1, 0, bio, rw) < 0)
                                goto out;
                } else
-                       if (zram_bvec_rw(zram, bvec, index, offset, bio, rw)
+                       if (zram_bvec_rw(zram, &bvec, index, offset, bio, rw)
                            < 0)
                                goto out;
 
-               update_position(&index, &offset, bvec);
+               update_position(&index, &offset, &bvec);
        }
 
        set_bit(BIO_UPTODATE, &bio->bi_flags);
@@ -759,40 +752,19 @@ error:
        bio_io_error(bio);
 }
 
-static void zram_slot_free(struct work_struct *work)
-{
-       struct zram *zram;
-
-       zram = container_of(work, struct zram, free_work);
-       down_write(&zram->lock);
-       handle_pending_slot_free(zram);
-       up_write(&zram->lock);
-}
-
-static void add_slot_free(struct zram *zram, struct zram_slot_free *free_rq)
-{
-       spin_lock(&zram->slot_free_lock);
-       free_rq->next = zram->slot_free_rq;
-       zram->slot_free_rq = free_rq;
-       spin_unlock(&zram->slot_free_lock);
-}
-
 static void zram_slot_free_notify(struct block_device *bdev,
                                unsigned long index)
 {
        struct zram *zram;
-       struct zram_slot_free *free_rq;
+       struct zram_meta *meta;
 
        zram = bdev->bd_disk->private_data;
-       atomic64_inc(&zram->stats.notify_free);
-
-       free_rq = kmalloc(sizeof(struct zram_slot_free), GFP_ATOMIC);
-       if (!free_rq)
-               return;
+       meta = zram->meta;
 
-       free_rq->index = index;
-       add_slot_free(zram, free_rq);
-       schedule_work(&zram->free_work);
+       write_lock(&meta->tb_lock);
+       zram_free_page(zram, index);
+       write_unlock(&meta->tb_lock);
+       atomic64_inc(&zram->stats.notify_free);
 }
 
 static const struct block_device_operations zram_devops = {
@@ -836,13 +808,8 @@ static int create_device(struct zram *zram, int device_id)
 {
        int ret = -ENOMEM;
 
-       init_rwsem(&zram->lock);
        init_rwsem(&zram->init_lock);
 
-       INIT_WORK(&zram->free_work, zram_slot_free);
-       spin_lock_init(&zram->slot_free_lock);
-       zram->slot_free_rq = NULL;
-
        zram->queue = blk_alloc_queue(GFP_KERNEL);
        if (!zram->queue) {
                pr_err("Error allocating disk queue for device %d\n",
similarity index 74%
rename from drivers/staging/zram/zram_drv.h
rename to drivers/block/zram/zram_drv.h
index 97a3acf6ab7613ebf4cee59710511162a9719fa0..ad8aa35bae00e9836bcb96f0efbd3f8b781b2705 100644 (file)
@@ -2,6 +2,7 @@
  * Compressed RAM block device
  *
  * Copyright (C) 2008, 2009, 2010  Nitin Gupta
+ *               2012, 2013 Minchan Kim
  *
  * This code is released using a dual license strategy: BSD/GPL
  * You can choose the licence that better fits your requirements.
@@ -9,7 +10,6 @@
  * Released under the terms of 3-clause BSD License
  * Released under the terms of GNU General Public License Version 2.0
  *
- * Project home: http://compcache.googlecode.com
  */
 
 #ifndef _ZRAM_DRV_H_
@@ -17,8 +17,7 @@
 
 #include <linux/spinlock.h>
 #include <linux/mutex.h>
-
-#include "../zsmalloc/zsmalloc.h"
+#include <linux/zsmalloc.h>
 
 /*
  * Some arbitrary value. This is just to catch
@@ -69,10 +68,6 @@ struct table {
        u8 flags;
 } __aligned(4);
 
-/*
- * All 64bit fields should only be manipulated by 64bit atomic accessors.
- * All modifications to 32bit counter should be protected by zram->lock.
- */
 struct zram_stats {
        atomic64_t compr_size;  /* compressed size of pages stored */
        atomic64_t num_reads;   /* failed + successful */
@@ -81,33 +76,23 @@ struct zram_stats {
        atomic64_t failed_writes;       /* can happen when memory is too low */
        atomic64_t invalid_io;  /* non-page-aligned I/O requests */
        atomic64_t notify_free; /* no. of swap slot free notifications */
-       u32 pages_zero;         /* no. of zero filled pages */
-       u32 pages_stored;       /* no. of pages currently stored */
-       u32 good_compress;      /* % of pages with compression ratio<=50% */
-       u32 bad_compress;       /* % of pages with compression ratio>=75% */
+       atomic_t pages_zero;            /* no. of zero filled pages */
+       atomic_t pages_stored;  /* no. of pages currently stored */
+       atomic_t good_compress; /* % of pages with compression ratio<=50% */
+       atomic_t bad_compress;  /* % of pages with compression ratio>=75% */
 };
 
 struct zram_meta {
+       rwlock_t tb_lock;       /* protect table */
        void *compress_workmem;
        void *compress_buffer;
        struct table *table;
        struct zs_pool *mem_pool;
-};
-
-struct zram_slot_free {
-       unsigned long index;
-       struct zram_slot_free *next;
+       struct mutex buffer_lock; /* protect compress buffers */
 };
 
 struct zram {
        struct zram_meta *meta;
-       struct rw_semaphore lock; /* protect compression buffers, table,
-                                  * 32bit stat counters against concurrent
-                                  * notifications, reads and writes */
-
-       struct work_struct free_work;  /* handle pending free request */
-       struct zram_slot_free *slot_free_rq; /* list head of free request */
-
        struct request_queue *queue;
        struct gendisk *disk;
        int init_done;
@@ -118,7 +103,6 @@ struct zram {
         * we can store in a disk.
         */
        u64 disksize;   /* bytes */
-       spinlock_t slot_free_lock;
 
        struct zram_stats stats;
 };
index 5980cb9af857891491baee6026efe16cb84694de..51e75ad964223e07268e0781caa5fa9230f43824 100644 (file)
@@ -561,11 +561,11 @@ static int gdrom_set_interrupt_handlers(void)
        int err;
 
        err = request_irq(HW_EVENT_GDROM_CMD, gdrom_command_interrupt,
-               IRQF_DISABLED, "gdrom_command", &gd);
+               0, "gdrom_command", &gd);
        if (err)
                return err;
        err = request_irq(HW_EVENT_GDROM_DMA, gdrom_dma_interrupt,
-               IRQF_DISABLED, "gdrom_dma", &gd);
+               0, "gdrom_dma", &gd);
        if (err)
                free_irq(HW_EVENT_GDROM_CMD, &gd);
        return err;
index 290fe5b7fd327f48f9a9b8f7091a6f43b83c1745..a324f9303e36da8e9c63c423f3405d777f05cdbb 100644 (file)
@@ -49,7 +49,7 @@ obj-$(CONFIG_GPIO_TB0219)     += tb0219.o
 obj-$(CONFIG_TELCLOCK)         += tlclk.o
 
 obj-$(CONFIG_MWAVE)            += mwave/
-obj-$(CONFIG_AGP)              += agp/
+obj-y                          += agp/
 obj-$(CONFIG_PCMCIA)           += pcmcia/
 
 obj-$(CONFIG_HANGCHECK_TIMER)  += hangcheck-timer.o
index d8b1b576556cf8eba8c2fa398c6c9bc8d6960803..c528f96ee204fb3f480e29d96992e1e0c1870272 100644 (file)
@@ -68,6 +68,7 @@ config AGP_AMD64
 config AGP_INTEL
        tristate "Intel 440LX/BX/GX, I8xx and E7x05 chipset support"
        depends on AGP && X86
+       select INTEL_GTT
        help
          This option gives you AGP support for the GLX component of X
          on Intel 440LX/BX/GX, 815, 820, 830, 840, 845, 850, 860, 875,
@@ -155,3 +156,7 @@ config AGP_SGI_TIOCA
           This option gives you AGP GART support for the SGI TIO chipset
           for IA64 processors.
 
+config INTEL_GTT
+       tristate
+       depends on X86 && PCI
+
index 8eb56e273e75719f51d617fe3a2ed5c4b9cc06f2..604489bcdbf9b6c70b51e89f093accfdb34f4d25 100644 (file)
@@ -13,7 +13,7 @@ obj-$(CONFIG_AGP_HP_ZX1)      += hp-agp.o
 obj-$(CONFIG_AGP_PARISC)       += parisc-agp.o
 obj-$(CONFIG_AGP_I460)         += i460-agp.o
 obj-$(CONFIG_AGP_INTEL)                += intel-agp.o
-obj-$(CONFIG_AGP_INTEL)                += intel-gtt.o
+obj-$(CONFIG_INTEL_GTT)                += intel-gtt.o
 obj-$(CONFIG_AGP_NVIDIA)       += nvidia-agp.o
 obj-$(CONFIG_AGP_SGI_TIOCA)    += sgi-agp.o
 obj-$(CONFIG_AGP_SIS)          += sis-agp.o
index a7c276585a9f4f38b8dc510ea0c2fc6742f5b296..f9b9ca5d31b7946c3b1407ef692db1c2c149c628 100644 (file)
@@ -14,9 +14,6 @@
 #include "intel-agp.h"
 #include <drm/intel-gtt.h>
 
-int intel_agp_enabled;
-EXPORT_SYMBOL(intel_agp_enabled);
-
 static int intel_fetch_size(void)
 {
        int i;
@@ -806,8 +803,6 @@ static int agp_intel_probe(struct pci_dev *pdev,
 found_gmch:
        pci_set_drvdata(pdev, bridge);
        err = agp_add_bridge(bridge);
-       if (!err)
-               intel_agp_enabled = 1;
        return err;
 }
 
index ad5da1ffcbe9a87ca82c78c17ce8aab46d1fb811..5c85350f4c3d065e9c9bdf9ba762667604b7c0f3 100644 (file)
@@ -94,6 +94,7 @@ static struct _intel_private {
 #define IS_IRONLAKE    intel_private.driver->is_ironlake
 #define HAS_PGTBL_EN   intel_private.driver->has_pgtbl_enable
 
+#if IS_ENABLED(CONFIG_AGP_INTEL)
 static int intel_gtt_map_memory(struct page **pages,
                                unsigned int num_entries,
                                struct sg_table *st)
@@ -168,6 +169,7 @@ static void i8xx_destroy_pages(struct page *page)
        __free_pages(page, 2);
        atomic_dec(&agp_bridge->current_memory_agp);
 }
+#endif
 
 #define I810_GTT_ORDER 4
 static int i810_setup(void)
@@ -208,6 +210,7 @@ static void i810_cleanup(void)
        free_gatt_pages(intel_private.i81x_gtt_table, I810_GTT_ORDER);
 }
 
+#if IS_ENABLED(CONFIG_AGP_INTEL)
 static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start,
                                      int type)
 {
@@ -288,6 +291,7 @@ static void intel_i810_free_by_type(struct agp_memory *curr)
        }
        kfree(curr);
 }
+#endif
 
 static int intel_gtt_setup_scratch_page(void)
 {
@@ -645,7 +649,9 @@ static int intel_gtt_init(void)
                return -ENOMEM;
        }
 
+#if IS_ENABLED(CONFIG_AGP_INTEL)
        global_cache_flush();   /* FIXME: ? */
+#endif
 
        intel_private.stolen_size = intel_gtt_stolen_size();
 
@@ -666,6 +672,7 @@ static int intel_gtt_init(void)
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_AGP_INTEL)
 static int intel_fake_agp_fetch_size(void)
 {
        int num_sizes = ARRAY_SIZE(intel_fake_agp_sizes);
@@ -684,6 +691,7 @@ static int intel_fake_agp_fetch_size(void)
 
        return 0;
 }
+#endif
 
 static void i830_cleanup(void)
 {
@@ -795,6 +803,7 @@ static int i830_setup(void)
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_AGP_INTEL)
 static int intel_fake_agp_create_gatt_table(struct agp_bridge_data *bridge)
 {
        agp_bridge->gatt_table_real = NULL;
@@ -819,6 +828,7 @@ static int intel_fake_agp_configure(void)
 
        return 0;
 }
+#endif
 
 static bool i830_check_flags(unsigned int flags)
 {
@@ -857,6 +867,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st,
 }
 EXPORT_SYMBOL(intel_gtt_insert_sg_entries);
 
+#if IS_ENABLED(CONFIG_AGP_INTEL)
 static void intel_gtt_insert_pages(unsigned int first_entry,
                                   unsigned int num_entries,
                                   struct page **pages,
@@ -922,6 +933,7 @@ out_err:
        mem->is_flushed = true;
        return ret;
 }
+#endif
 
 void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
 {
@@ -935,6 +947,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
 }
 EXPORT_SYMBOL(intel_gtt_clear_range);
 
+#if IS_ENABLED(CONFIG_AGP_INTEL)
 static int intel_fake_agp_remove_entries(struct agp_memory *mem,
                                         off_t pg_start, int type)
 {
@@ -976,6 +989,7 @@ static struct agp_memory *intel_fake_agp_alloc_by_type(size_t pg_count,
        /* always return NULL for other allocation types for now */
        return NULL;
 }
+#endif
 
 static int intel_alloc_chipset_flush_resource(void)
 {
@@ -1129,6 +1143,7 @@ static int i9xx_setup(void)
        return 0;
 }
 
+#if IS_ENABLED(CONFIG_AGP_INTEL)
 static const struct agp_bridge_driver intel_fake_agp_driver = {
        .owner                  = THIS_MODULE,
        .size_type              = FIXED_APER_SIZE,
@@ -1150,6 +1165,7 @@ static const struct agp_bridge_driver intel_fake_agp_driver = {
        .agp_destroy_page       = agp_generic_destroy_page,
        .agp_destroy_pages      = agp_generic_destroy_pages,
 };
+#endif
 
 static const struct intel_gtt_driver i81x_gtt_driver = {
        .gen = 1,
@@ -1367,11 +1383,13 @@ int intel_gmch_probe(struct pci_dev *bridge_pdev, struct pci_dev *gpu_pdev,
 
        intel_private.refcount++;
 
+#if IS_ENABLED(CONFIG_AGP_INTEL)
        if (bridge) {
                bridge->driver = &intel_fake_agp_driver;
                bridge->dev_private_data = &intel_private;
                bridge->dev = bridge_pdev;
        }
+#endif
 
        intel_private.bridge_dev = pci_dev_get(bridge_pdev);
 
index e210f858d3cbf854130e0c149703c0642710bf7e..d915707d2ba1d3eae5b3ade411dd5226a5f3296d 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2001  Massimo Dal Zotto <dz@debian.org>
  *
  * Hwmon integration:
- * Copyright (C) 2011  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2011  Jean Delvare <jdelvare@suse.de>
  * Copyright (C) 2013  Guenter Roeck <linux@roeck-us.net>
  *
  * This program is free software; you can redistribute it and/or modify it
index 671c3852d35921852a0570c1636196d38e177599..03f41896d09050ff391ad55ef263faa1430de19a 100644 (file)
@@ -2724,6 +2724,7 @@ static struct platform_driver ipmi_driver = {
 static int ipmi_parisc_probe(struct parisc_device *dev)
 {
        struct smi_info *info;
+       int rv;
 
        info = smi_info_alloc();
 
index 0c16e9cdfb87857c3fd528eebefa72f4af28f629..a367a98317175f59745e5b61e6fdf175f29342bc 100644 (file)
@@ -9,45 +9,44 @@ obj-$(CONFIG_COMMON_CLK)      += clk-gate.o
 obj-$(CONFIG_COMMON_CLK)       += clk-mux.o
 obj-$(CONFIG_COMMON_CLK)       += clk-composite.o
 
-# SoCs specific
-obj-$(CONFIG_ARCH_BCM2835)     += clk-bcm2835.o
-obj-$(CONFIG_ARCH_EFM32)       += clk-efm32gg.o
-obj-$(CONFIG_ARCH_NOMADIK)     += clk-nomadik.o
-obj-$(CONFIG_ARCH_HIGHBANK)    += clk-highbank.o
-obj-$(CONFIG_ARCH_HI3xxx)      += hisilicon/
-obj-$(CONFIG_ARCH_NSPIRE)      += clk-nspire.o
-obj-$(CONFIG_ARCH_MXS)         += mxs/
-obj-$(CONFIG_ARCH_SOCFPGA)     += socfpga/
-obj-$(CONFIG_PLAT_SPEAR)       += spear/
-obj-$(CONFIG_ARCH_U300)                += clk-u300.o
-obj-$(CONFIG_COMMON_CLK_VERSATILE) += versatile/
-obj-$(CONFIG_COMMON_CLK_QCOM)  += qcom/
-obj-$(CONFIG_PLAT_ORION)       += mvebu/
+# hardware specific clock types
+# please keep this section sorted lexicographically by file/directory path name
+obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN)    += clk-axi-clkgen.o
+obj-$(CONFIG_ARCH_BCM2835)             += clk-bcm2835.o
+obj-$(CONFIG_ARCH_EFM32)               += clk-efm32gg.o
+obj-$(CONFIG_ARCH_HIGHBANK)            += clk-highbank.o
+obj-$(CONFIG_MACH_LOONGSON1)           += clk-ls1x.o
+obj-$(CONFIG_COMMON_CLK_MAX77686)      += clk-max77686.o
+obj-$(CONFIG_ARCH_NOMADIK)             += clk-nomadik.o
+obj-$(CONFIG_ARCH_NSPIRE)              += clk-nspire.o
+obj-$(CONFIG_CLK_PPC_CORENET)          += clk-ppc-corenet.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
+obj-$(CONFIG_CLK_TWL6040)              += clk-twl6040.o
+obj-$(CONFIG_ARCH_U300)                        += clk-u300.o
+obj-$(CONFIG_ARCH_VT8500)              += clk-vt8500.o
+obj-$(CONFIG_COMMON_CLK_WM831X)                += clk-wm831x.o
+obj-$(CONFIG_COMMON_CLK_XGENE)         += clk-xgene.o
+obj-$(CONFIG_COMMON_CLK_AT91)          += at91/
+obj-$(CONFIG_ARCH_HI3xxx)              += hisilicon/
+obj-$(CONFIG_COMMON_CLK_KEYSTONE)      += keystone/
 ifeq ($(CONFIG_COMMON_CLK), y)
-obj-$(CONFIG_ARCH_MMP)         += mmp/
+obj-$(CONFIG_ARCH_MMP)                 += mmp/
 endif
-obj-$(CONFIG_MACH_LOONGSON1)   += clk-ls1x.o
-obj-$(CONFIG_ARCH_ROCKCHIP)    += rockchip/
-obj-$(CONFIG_ARCH_SUNXI)       += sunxi/
-obj-$(CONFIG_ARCH_U8500)       += ux500/
-obj-$(CONFIG_ARCH_VT8500)      += clk-vt8500.o
-obj-$(CONFIG_ARCH_SIRF)                += sirf/
-obj-$(CONFIG_ARCH_ZYNQ)                += zynq/
-obj-$(CONFIG_ARCH_TEGRA)       += tegra/
-obj-$(CONFIG_PLAT_SAMSUNG)     += samsung/
-obj-$(CONFIG_COMMON_CLK_XGENE)  += clk-xgene.o
-obj-$(CONFIG_COMMON_CLK_KEYSTONE)      += keystone/
-obj-$(CONFIG_COMMON_CLK_AT91)  += at91/
+obj-$(CONFIG_PLAT_ORION)               += mvebu/
+obj-$(CONFIG_ARCH_MXS)                 += mxs/
+obj-$(CONFIG_COMMON_CLK_QCOM)          += qcom/
+obj-$(CONFIG_ARCH_ROCKCHIP)            += rockchip/
+obj-$(CONFIG_PLAT_SAMSUNG)             += samsung/
 obj-$(CONFIG_ARCH_SHMOBILE_MULTI)      += shmobile/
-
-obj-$(CONFIG_X86)              += x86/
-
-# Chip specific
-obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
-obj-$(CONFIG_COMMON_CLK_WM831X) += clk-wm831x.o
-obj-$(CONFIG_COMMON_CLK_MAX77686) += clk-max77686.o
-obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
-obj-$(CONFIG_COMMON_CLK_SI570) += clk-si570.o
-obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
-obj-$(CONFIG_CLK_TWL6040)      += clk-twl6040.o
-obj-$(CONFIG_CLK_PPC_CORENET)  += clk-ppc-corenet.o
+obj-$(CONFIG_ARCH_SIRF)                        += sirf/
+obj-$(CONFIG_ARCH_SOCFPGA)             += socfpga/
+obj-$(CONFIG_PLAT_SPEAR)               += spear/
+obj-$(CONFIG_ARCH_SUNXI)               += sunxi/
+obj-$(CONFIG_ARCH_TEGRA)               += tegra/
+obj-$(CONFIG_ARCH_OMAP2PLUS)           += ti/
+obj-$(CONFIG_ARCH_U8500)               += ux500/
+obj-$(CONFIG_COMMON_CLK_VERSATILE)     += versatile/
+obj-$(CONFIG_X86)                      += x86/
+obj-$(CONFIG_ARCH_ZYNQ)                        += zynq/
index c50e83744b0aec3a0a8841f068bbbe05adc5ef8d..3b2a66f78755113fe9afde8f9caaa4d4e801260b 100644 (file)
@@ -1111,11 +1111,11 @@ static const struct of_device_id si5351_dt_ids[] = {
 };
 MODULE_DEVICE_TABLE(of, si5351_dt_ids);
 
-static int si5351_dt_parse(struct i2c_client *client)
+static int si5351_dt_parse(struct i2c_client *client,
+                          enum si5351_variant variant)
 {
        struct device_node *child, *np = client->dev.of_node;
        struct si5351_platform_data *pdata;
-       const struct of_device_id *match;
        struct property *prop;
        const __be32 *p;
        int num = 0;
@@ -1124,15 +1124,10 @@ static int si5351_dt_parse(struct i2c_client *client)
        if (np == NULL)
                return 0;
 
-       match = of_match_node(si5351_dt_ids, np);
-       if (match == NULL)
-               return -EINVAL;
-
        pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
        if (!pdata)
                return -ENOMEM;
 
-       pdata->variant = (enum si5351_variant)match->data;
        pdata->clk_xtal = of_clk_get(np, 0);
        if (!IS_ERR(pdata->clk_xtal))
                clk_put(pdata->clk_xtal);
@@ -1163,7 +1158,7 @@ static int si5351_dt_parse(struct i2c_client *client)
                        pdata->pll_src[num] = SI5351_PLL_SRC_XTAL;
                        break;
                case 1:
-                       if (pdata->variant != SI5351_VARIANT_C) {
+                       if (variant != SI5351_VARIANT_C) {
                                dev_err(&client->dev,
                                        "invalid parent %d for pll %d\n",
                                        val, num);
@@ -1187,7 +1182,7 @@ static int si5351_dt_parse(struct i2c_client *client)
                }
 
                if (num >= 8 ||
-                   (pdata->variant == SI5351_VARIANT_A3 && num >= 3)) {
+                   (variant == SI5351_VARIANT_A3 && num >= 3)) {
                        dev_err(&client->dev, "invalid clkout %d\n", num);
                        return -EINVAL;
                }
@@ -1226,7 +1221,7 @@ static int si5351_dt_parse(struct i2c_client *client)
                                        SI5351_CLKOUT_SRC_XTAL;
                                break;
                        case 3:
-                               if (pdata->variant != SI5351_VARIANT_C) {
+                               if (variant != SI5351_VARIANT_C) {
                                        dev_err(&client->dev,
                                                "invalid parent %d for clkout %d\n",
                                                val, num);
@@ -1298,7 +1293,7 @@ static int si5351_dt_parse(struct i2c_client *client)
        return 0;
 }
 #else
-static int si5351_dt_parse(struct i2c_client *client)
+static int si5351_dt_parse(struct i2c_client *client, enum si5351_variant variant)
 {
        return 0;
 }
@@ -1307,6 +1302,7 @@ static int si5351_dt_parse(struct i2c_client *client)
 static int si5351_i2c_probe(struct i2c_client *client,
                            const struct i2c_device_id *id)
 {
+       enum si5351_variant variant = (enum si5351_variant)id->driver_data;
        struct si5351_platform_data *pdata;
        struct si5351_driver_data *drvdata;
        struct clk_init_data init;
@@ -1315,7 +1311,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
        u8 num_parents, num_clocks;
        int ret, n;
 
-       ret = si5351_dt_parse(client);
+       ret = si5351_dt_parse(client, variant);
        if (ret)
                return ret;
 
@@ -1331,7 +1327,7 @@ static int si5351_i2c_probe(struct i2c_client *client,
 
        i2c_set_clientdata(client, drvdata);
        drvdata->client = client;
-       drvdata->variant = pdata->variant;
+       drvdata->variant = variant;
        drvdata->pxtal = pdata->clk_xtal;
        drvdata->pclkin = pdata->clk_clkin;
 
@@ -1568,10 +1564,10 @@ static int si5351_i2c_probe(struct i2c_client *client,
 }
 
 static const struct i2c_device_id si5351_i2c_ids[] = {
-       { "si5351a", 0 },
-       { "si5351a-msop", 0 },
-       { "si5351b", 0 },
-       { "si5351c", 0 },
+       { "si5351a", SI5351_VARIANT_A },
+       { "si5351a-msop", SI5351_VARIANT_A3 },
+       { "si5351b", SI5351_VARIANT_B },
+       { "si5351c", SI5351_VARIANT_C },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, si5351_i2c_ids);
index c0dbf2676872995c1ff698cefe37719f43f1236a..4d0746b50c32e8a6265fb5a410371daebfb5ba85 100644 (file)
 #define  SI5351_XTAL_ENABLE                    (1<<6)
 #define  SI5351_MULTISYNTH_ENABLE              (1<<4)
 
+/**
+ * enum si5351_variant - SiLabs Si5351 chip variant
+ * @SI5351_VARIANT_A: Si5351A (8 output clocks, XTAL input)
+ * @SI5351_VARIANT_A3: Si5351A MSOP10 (3 output clocks, XTAL input)
+ * @SI5351_VARIANT_B: Si5351B (8 output clocks, XTAL/VXCO input)
+ * @SI5351_VARIANT_C: Si5351C (8 output clocks, XTAL/CLKIN input)
+ */
+enum si5351_variant {
+       SI5351_VARIANT_A = 1,
+       SI5351_VARIANT_A3 = 2,
+       SI5351_VARIANT_B = 3,
+       SI5351_VARIANT_C = 4,
+};
+
 #endif
index 2b38dc99063f1b6574df031ccea84af5df9cb9e6..5517944495d893cc3c8dd60569b58e67e9289765 100644 (file)
@@ -575,16 +575,19 @@ struct clk_hw *__clk_get_hw(struct clk *clk)
 {
        return !clk ? NULL : clk->hw;
 }
+EXPORT_SYMBOL_GPL(__clk_get_hw);
 
 u8 __clk_get_num_parents(struct clk *clk)
 {
        return !clk ? 0 : clk->num_parents;
 }
+EXPORT_SYMBOL_GPL(__clk_get_num_parents);
 
 struct clk *__clk_get_parent(struct clk *clk)
 {
        return !clk ? NULL : clk->parent;
 }
+EXPORT_SYMBOL_GPL(__clk_get_parent);
 
 struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
 {
@@ -598,6 +601,7 @@ struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
        else
                return clk->parents[index];
 }
+EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
 
 unsigned int __clk_get_enable_count(struct clk *clk)
 {
@@ -629,6 +633,7 @@ unsigned long __clk_get_rate(struct clk *clk)
 out:
        return ret;
 }
+EXPORT_SYMBOL_GPL(__clk_get_rate);
 
 unsigned long __clk_get_accuracy(struct clk *clk)
 {
@@ -685,6 +690,7 @@ bool __clk_is_enabled(struct clk *clk)
 out:
        return !!ret;
 }
+EXPORT_SYMBOL_GPL(__clk_is_enabled);
 
 static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
 {
@@ -776,6 +782,7 @@ out:
 
        return best;
 }
+EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
 
 /***        clk api        ***/
 
@@ -2373,8 +2380,6 @@ struct of_clk_provider {
        void *data;
 };
 
-extern struct of_device_id __clk_of_table[];
-
 static const struct of_device_id __clk_of_table_sentinel
        __used __section(__clk_of_table_end);
 
@@ -2534,7 +2539,7 @@ void __init of_clk_init(const struct of_device_id *matches)
        struct device_node *np;
 
        if (!matches)
-               matches = __clk_of_table;
+               matches = &__clk_of_table;
 
        for_each_matching_node_and_match(np, matches, &match) {
                of_clk_init_cb_t clk_init_cb = match->data;
index 190d38433202dbe43e0714a72471df03a243c7e6..f60db2ef1aee6a8d9150ec6c896827921a8e803f 100644 (file)
@@ -1,11 +1,11 @@
 obj-$(CONFIG_COMMON_CLK_QCOM) += clk-qcom.o
 
-clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-regmap.o
-clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-pll.o
-clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-rcg.o
-clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-rcg2.o
-clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += clk-branch.o
-clk-qcom-$(CONFIG_COMMON_CLK_QCOM) += reset.o
+clk-qcom-y += clk-regmap.o
+clk-qcom-y += clk-pll.o
+clk-qcom-y += clk-rcg.o
+clk-qcom-y += clk-rcg2.o
+clk-qcom-y += clk-branch.o
+clk-qcom-y += reset.o
 
 obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
 obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
index 529e11dc2c6b0e8af21506211a7756f04b324123..81e6d2f49aa001a9587b33e848c0b4692d5d82e0 100644 (file)
@@ -375,7 +375,7 @@ static int samsung_pll45xx_set_rate(struct clk_hw *hw, unsigned long drate,
                break;
        default:
                break;
-       };
+       }
 
        /* Set new configuration. */
        __raw_writel(con1, pll->con_reg + 0x4);
index 659e4ea31893a42bee5fb701d54fcbb34776ed67..abb6c5ac8a10297505a8a7f1cb1cb0d5f8eccf16 100644 (file)
@@ -875,7 +875,7 @@ static void __init sunxi_divs_clk_setup(struct device_node *node,
        if (!clk_data)
                return;
 
-       clks = kzalloc(SUNXI_DIVS_MAX_QTY * sizeof(struct clk *), GFP_KERNEL);
+       clks = kzalloc((SUNXI_DIVS_MAX_QTY+1) * sizeof(*clks), GFP_KERNEL);
        if (!clks)
                goto free_clkdata;
 
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
new file mode 100644 (file)
index 0000000..4319d40
--- /dev/null
@@ -0,0 +1,11 @@
+ifneq ($(CONFIG_OF),)
+obj-y                                  += clk.o autoidle.o clockdomain.o
+clk-common                             = dpll.o composite.o divider.o gate.o \
+                                         fixed-factor.o mux.o apll.o
+obj-$(CONFIG_SOC_AM33XX)               += $(clk-common) clk-33xx.o
+obj-$(CONFIG_ARCH_OMAP3)               += $(clk-common) interface.o clk-3xxx.o
+obj-$(CONFIG_ARCH_OMAP4)               += $(clk-common) clk-44xx.o
+obj-$(CONFIG_SOC_OMAP5)                        += $(clk-common) clk-54xx.o
+obj-$(CONFIG_SOC_DRA7XX)               += $(clk-common) clk-7xx.o
+obj-$(CONFIG_SOC_AM43XX)               += $(clk-common) clk-43xx.o
+endif
diff --git a/drivers/clk/ti/apll.c b/drivers/clk/ti/apll.c
new file mode 100644 (file)
index 0000000..b986f61
--- /dev/null
@@ -0,0 +1,223 @@
+/*
+ * OMAP APLL clock support
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * J Keerthy <j-keerthy@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/log2.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+#include <linux/delay.h>
+
+#define APLL_FORCE_LOCK 0x1
+#define APLL_AUTO_IDLE 0x2
+#define MAX_APLL_WAIT_TRIES            1000000
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+static int dra7_apll_enable(struct clk_hw *hw)
+{
+       struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+       int r = 0, i = 0;
+       struct dpll_data *ad;
+       const char *clk_name;
+       u8 state = 1;
+       u32 v;
+
+       ad = clk->dpll_data;
+       if (!ad)
+               return -EINVAL;
+
+       clk_name = __clk_get_name(clk->hw.clk);
+
+       state <<= __ffs(ad->idlest_mask);
+
+       /* Check is already locked */
+       v = ti_clk_ll_ops->clk_readl(ad->idlest_reg);
+
+       if ((v & ad->idlest_mask) == state)
+               return r;
+
+       v = ti_clk_ll_ops->clk_readl(ad->control_reg);
+       v &= ~ad->enable_mask;
+       v |= APLL_FORCE_LOCK << __ffs(ad->enable_mask);
+       ti_clk_ll_ops->clk_writel(v, ad->control_reg);
+
+       state <<= __ffs(ad->idlest_mask);
+
+       while (1) {
+               v = ti_clk_ll_ops->clk_readl(ad->idlest_reg);
+               if ((v & ad->idlest_mask) == state)
+                       break;
+               if (i > MAX_APLL_WAIT_TRIES)
+                       break;
+               i++;
+               udelay(1);
+       }
+
+       if (i == MAX_APLL_WAIT_TRIES) {
+               pr_warn("clock: %s failed transition to '%s'\n",
+                       clk_name, (state) ? "locked" : "bypassed");
+       } else {
+               pr_debug("clock: %s transition to '%s' in %d loops\n",
+                        clk_name, (state) ? "locked" : "bypassed", i);
+
+               r = 0;
+       }
+
+       return r;
+}
+
+static void dra7_apll_disable(struct clk_hw *hw)
+{
+       struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+       struct dpll_data *ad;
+       u8 state = 1;
+       u32 v;
+
+       ad = clk->dpll_data;
+
+       state <<= __ffs(ad->idlest_mask);
+
+       v = ti_clk_ll_ops->clk_readl(ad->control_reg);
+       v &= ~ad->enable_mask;
+       v |= APLL_AUTO_IDLE << __ffs(ad->enable_mask);
+       ti_clk_ll_ops->clk_writel(v, ad->control_reg);
+}
+
+static int dra7_apll_is_enabled(struct clk_hw *hw)
+{
+       struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+       struct dpll_data *ad;
+       u32 v;
+
+       ad = clk->dpll_data;
+
+       v = ti_clk_ll_ops->clk_readl(ad->control_reg);
+       v &= ad->enable_mask;
+
+       v >>= __ffs(ad->enable_mask);
+
+       return v == APLL_AUTO_IDLE ? 0 : 1;
+}
+
+static u8 dra7_init_apll_parent(struct clk_hw *hw)
+{
+       return 0;
+}
+
+static const struct clk_ops apll_ck_ops = {
+       .enable         = &dra7_apll_enable,
+       .disable        = &dra7_apll_disable,
+       .is_enabled     = &dra7_apll_is_enabled,
+       .get_parent     = &dra7_init_apll_parent,
+};
+
+static void __init omap_clk_register_apll(struct clk_hw *hw,
+                                         struct device_node *node)
+{
+       struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw);
+       struct dpll_data *ad = clk_hw->dpll_data;
+       struct clk *clk;
+
+       ad->clk_ref = of_clk_get(node, 0);
+       ad->clk_bypass = of_clk_get(node, 1);
+
+       if (IS_ERR(ad->clk_ref) || IS_ERR(ad->clk_bypass)) {
+               pr_debug("clk-ref or clk-bypass for %s not ready, retry\n",
+                        node->name);
+               if (!ti_clk_retry_init(node, hw, omap_clk_register_apll))
+                       return;
+
+               goto cleanup;
+       }
+
+       clk = clk_register(NULL, &clk_hw->hw);
+       if (!IS_ERR(clk)) {
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+               kfree(clk_hw->hw.init->parent_names);
+               kfree(clk_hw->hw.init);
+               return;
+       }
+
+cleanup:
+       kfree(clk_hw->dpll_data);
+       kfree(clk_hw->hw.init->parent_names);
+       kfree(clk_hw->hw.init);
+       kfree(clk_hw);
+}
+
+static void __init of_dra7_apll_setup(struct device_node *node)
+{
+       struct dpll_data *ad = NULL;
+       struct clk_hw_omap *clk_hw = NULL;
+       struct clk_init_data *init = NULL;
+       const char **parent_names = NULL;
+       int i;
+
+       ad = kzalloc(sizeof(*ad), GFP_KERNEL);
+       clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+       init = kzalloc(sizeof(*init), GFP_KERNEL);
+       if (!ad || !clk_hw || !init)
+               goto cleanup;
+
+       clk_hw->dpll_data = ad;
+       clk_hw->hw.init = init;
+       clk_hw->flags = MEMMAP_ADDRESSING;
+
+       init->name = node->name;
+       init->ops = &apll_ck_ops;
+
+       init->num_parents = of_clk_get_parent_count(node);
+       if (init->num_parents < 1) {
+               pr_err("dra7 apll %s must have parent(s)\n", node->name);
+               goto cleanup;
+       }
+
+       parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL);
+       if (!parent_names)
+               goto cleanup;
+
+       for (i = 0; i < init->num_parents; i++)
+               parent_names[i] = of_clk_get_parent_name(node, i);
+
+       init->parent_names = parent_names;
+
+       ad->control_reg = ti_clk_get_reg_addr(node, 0);
+       ad->idlest_reg = ti_clk_get_reg_addr(node, 1);
+
+       if (!ad->control_reg || !ad->idlest_reg)
+               goto cleanup;
+
+       ad->idlest_mask = 0x1;
+       ad->enable_mask = 0x3;
+
+       omap_clk_register_apll(&clk_hw->hw, node);
+       return;
+
+cleanup:
+       kfree(parent_names);
+       kfree(ad);
+       kfree(clk_hw);
+       kfree(init);
+}
+CLK_OF_DECLARE(dra7_apll_clock, "ti,dra7-apll-clock", of_dra7_apll_setup);
diff --git a/drivers/clk/ti/autoidle.c b/drivers/clk/ti/autoidle.c
new file mode 100644 (file)
index 0000000..8912ff8
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * TI clock autoidle support
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+
+struct clk_ti_autoidle {
+       void __iomem            *reg;
+       u8                      shift;
+       u8                      flags;
+       const char              *name;
+       struct list_head        node;
+};
+
+#define AUTOIDLE_LOW           0x1
+
+static LIST_HEAD(autoidle_clks);
+
+static void ti_allow_autoidle(struct clk_ti_autoidle *clk)
+{
+       u32 val;
+
+       val = ti_clk_ll_ops->clk_readl(clk->reg);
+
+       if (clk->flags & AUTOIDLE_LOW)
+               val &= ~(1 << clk->shift);
+       else
+               val |= (1 << clk->shift);
+
+       ti_clk_ll_ops->clk_writel(val, clk->reg);
+}
+
+static void ti_deny_autoidle(struct clk_ti_autoidle *clk)
+{
+       u32 val;
+
+       val = ti_clk_ll_ops->clk_readl(clk->reg);
+
+       if (clk->flags & AUTOIDLE_LOW)
+               val |= (1 << clk->shift);
+       else
+               val &= ~(1 << clk->shift);
+
+       ti_clk_ll_ops->clk_writel(val, clk->reg);
+}
+
+/**
+ * of_ti_clk_allow_autoidle_all - enable autoidle for all clocks
+ *
+ * Enables hardware autoidle for all registered DT clocks, which have
+ * the feature.
+ */
+void of_ti_clk_allow_autoidle_all(void)
+{
+       struct clk_ti_autoidle *c;
+
+       list_for_each_entry(c, &autoidle_clks, node)
+               ti_allow_autoidle(c);
+}
+
+/**
+ * of_ti_clk_deny_autoidle_all - disable autoidle for all clocks
+ *
+ * Disables hardware autoidle for all registered DT clocks, which have
+ * the feature.
+ */
+void of_ti_clk_deny_autoidle_all(void)
+{
+       struct clk_ti_autoidle *c;
+
+       list_for_each_entry(c, &autoidle_clks, node)
+               ti_deny_autoidle(c);
+}
+
+/**
+ * of_ti_clk_autoidle_setup - sets up hardware autoidle for a clock
+ * @node: pointer to the clock device node
+ *
+ * Checks if a clock has hardware autoidle support or not (check
+ * for presence of 'ti,autoidle-shift' property in the device tree
+ * node) and sets up the hardware autoidle feature for the clock
+ * if available. If autoidle is available, the clock is also added
+ * to the autoidle list for later processing. Returns 0 on success,
+ * negative error value on failure.
+ */
+int __init of_ti_clk_autoidle_setup(struct device_node *node)
+{
+       u32 shift;
+       struct clk_ti_autoidle *clk;
+
+       /* Check if this clock has autoidle support or not */
+       if (of_property_read_u32(node, "ti,autoidle-shift", &shift))
+               return 0;
+
+       clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+
+       if (!clk)
+               return -ENOMEM;
+
+       clk->shift = shift;
+       clk->name = node->name;
+       clk->reg = ti_clk_get_reg_addr(node, 0);
+
+       if (!clk->reg) {
+               kfree(clk);
+               return -EINVAL;
+       }
+
+       if (of_property_read_bool(node, "ti,invert-autoidle-bit"))
+               clk->flags |= AUTOIDLE_LOW;
+
+       list_add(&clk->node, &autoidle_clks);
+
+       return 0;
+}
diff --git a/drivers/clk/ti/clk-33xx.c b/drivers/clk/ti/clk-33xx.c
new file mode 100644 (file)
index 0000000..776ee45
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * AM33XX Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc
+ *     Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+static struct ti_dt_clk am33xx_clks[] = {
+       DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"),
+       DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"),
+       DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"),
+       DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"),
+       DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"),
+       DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"),
+       DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"),
+       DT_CLK(NULL, "tclkin_ck", "tclkin_ck"),
+       DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"),
+       DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"),
+       DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"),
+       DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"),
+       DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"),
+       DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"),
+       DT_CLK("cpu0", NULL, "dpll_mpu_ck"),
+       DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"),
+       DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"),
+       DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"),
+       DT_CLK(NULL, "dpll_ddr_m2_div2_ck", "dpll_ddr_m2_div2_ck"),
+       DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"),
+       DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"),
+       DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"),
+       DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"),
+       DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"),
+       DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"),
+       DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"),
+       DT_CLK(NULL, "cefuse_fck", "cefuse_fck"),
+       DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"),
+       DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"),
+       DT_CLK(NULL, "dcan0_fck", "dcan0_fck"),
+       DT_CLK("481cc000.d_can", NULL, "dcan0_fck"),
+       DT_CLK(NULL, "dcan1_fck", "dcan1_fck"),
+       DT_CLK("481d0000.d_can", NULL, "dcan1_fck"),
+       DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"),
+       DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"),
+       DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"),
+       DT_CLK(NULL, "mmu_fck", "mmu_fck"),
+       DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"),
+       DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"),
+       DT_CLK(NULL, "sha0_fck", "sha0_fck"),
+       DT_CLK(NULL, "aes0_fck", "aes0_fck"),
+       DT_CLK(NULL, "rng_fck", "rng_fck"),
+       DT_CLK(NULL, "timer1_fck", "timer1_fck"),
+       DT_CLK(NULL, "timer2_fck", "timer2_fck"),
+       DT_CLK(NULL, "timer3_fck", "timer3_fck"),
+       DT_CLK(NULL, "timer4_fck", "timer4_fck"),
+       DT_CLK(NULL, "timer5_fck", "timer5_fck"),
+       DT_CLK(NULL, "timer6_fck", "timer6_fck"),
+       DT_CLK(NULL, "timer7_fck", "timer7_fck"),
+       DT_CLK(NULL, "usbotg_fck", "usbotg_fck"),
+       DT_CLK(NULL, "ieee5000_fck", "ieee5000_fck"),
+       DT_CLK(NULL, "wdt1_fck", "wdt1_fck"),
+       DT_CLK(NULL, "l4_rtc_gclk", "l4_rtc_gclk"),
+       DT_CLK(NULL, "l3_gclk", "l3_gclk"),
+       DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"),
+       DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"),
+       DT_CLK(NULL, "l3s_gclk", "l3s_gclk"),
+       DT_CLK(NULL, "l4fw_gclk", "l4fw_gclk"),
+       DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"),
+       DT_CLK(NULL, "clk_24mhz", "clk_24mhz"),
+       DT_CLK(NULL, "sysclk_div_ck", "sysclk_div_ck"),
+       DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"),
+       DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"),
+       DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"),
+       DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"),
+       DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"),
+       DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"),
+       DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"),
+       DT_CLK(NULL, "lcd_gclk", "lcd_gclk"),
+       DT_CLK(NULL, "mmc_clk", "mmc_clk"),
+       DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"),
+       DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"),
+       DT_CLK(NULL, "sysclkout_pre_ck", "sysclkout_pre_ck"),
+       DT_CLK(NULL, "clkout2_div_ck", "clkout2_div_ck"),
+       DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"),
+       DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK(NULL, "dbg_sysclk_ck", "dbg_sysclk_ck"),
+       DT_CLK(NULL, "dbg_clka_ck", "dbg_clka_ck"),
+       DT_CLK(NULL, "stm_pmd_clock_mux_ck", "stm_pmd_clock_mux_ck"),
+       DT_CLK(NULL, "trace_pmd_clk_mux_ck", "trace_pmd_clk_mux_ck"),
+       DT_CLK(NULL, "stm_clk_div_ck", "stm_clk_div_ck"),
+       DT_CLK(NULL, "trace_clk_div_ck", "trace_clk_div_ck"),
+       DT_CLK(NULL, "clkout2_ck", "clkout2_ck"),
+       DT_CLK("48300200.ehrpwm", "tbclk", "ehrpwm0_tbclk"),
+       DT_CLK("48302200.ehrpwm", "tbclk", "ehrpwm1_tbclk"),
+       DT_CLK("48304200.ehrpwm", "tbclk", "ehrpwm2_tbclk"),
+       { .node_name = NULL },
+};
+
+static const char *enable_init_clks[] = {
+       "dpll_ddr_m2_ck",
+       "dpll_mpu_m2_ck",
+       "l3_gclk",
+       "l4hs_gclk",
+       "l4fw_gclk",
+       "l4ls_gclk",
+       /* Required for external peripherals like, Audio codecs */
+       "clkout2_ck",
+};
+
+int __init am33xx_dt_clk_init(void)
+{
+       struct clk *clk1, *clk2;
+
+       ti_dt_clocks_register(am33xx_clks);
+
+       omap2_clk_disable_autoidle_all();
+
+       omap2_clk_enable_init_clocks(enable_init_clks,
+                                    ARRAY_SIZE(enable_init_clks));
+
+       /* TRM ERRATA: Timer 3 & 6 default parent (TCLKIN) may not be always
+        *    physically present, in such a case HWMOD enabling of
+        *    clock would be failure with default parent. And timer
+        *    probe thinks clock is already enabled, this leads to
+        *    crash upon accessing timer 3 & 6 registers in probe.
+        *    Fix by setting parent of both these timers to master
+        *    oscillator clock.
+        */
+
+       clk1 = clk_get_sys(NULL, "sys_clkin_ck");
+       clk2 = clk_get_sys(NULL, "timer3_fck");
+       clk_set_parent(clk2, clk1);
+
+       clk2 = clk_get_sys(NULL, "timer6_fck");
+       clk_set_parent(clk2, clk1);
+       /*
+        * The On-Chip 32K RC Osc clock is not an accurate clock-source as per
+        * the design/spec, so as a result, for example, timer which supposed
+        * to get expired @60Sec, but will expire somewhere ~@40Sec, which is
+        * not expected by any use-case, so change WDT1 clock source to PRCM
+        * 32KHz clock.
+        */
+       clk1 = clk_get_sys(NULL, "wdt1_fck");
+       clk2 = clk_get_sys(NULL, "clkdiv32k_ick");
+       clk_set_parent(clk1, clk2);
+
+       return 0;
+}
diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c
new file mode 100644 (file)
index 0000000..d323023
--- /dev/null
@@ -0,0 +1,401 @@
+/*
+ * OMAP3 Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc
+ *     Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+
+static struct ti_dt_clk omap3xxx_clks[] = {
+       DT_CLK(NULL, "apb_pclk", "dummy_apb_pclk"),
+       DT_CLK(NULL, "omap_32k_fck", "omap_32k_fck"),
+       DT_CLK(NULL, "virt_12m_ck", "virt_12m_ck"),
+       DT_CLK(NULL, "virt_13m_ck", "virt_13m_ck"),
+       DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"),
+       DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"),
+       DT_CLK(NULL, "virt_38_4m_ck", "virt_38_4m_ck"),
+       DT_CLK(NULL, "osc_sys_ck", "osc_sys_ck"),
+       DT_CLK("twl", "fck", "osc_sys_ck"),
+       DT_CLK(NULL, "sys_ck", "sys_ck"),
+       DT_CLK(NULL, "omap_96m_alwon_fck", "omap_96m_alwon_fck"),
+       DT_CLK("etb", "emu_core_alwon_ck", "emu_core_alwon_ck"),
+       DT_CLK(NULL, "sys_altclk", "sys_altclk"),
+       DT_CLK(NULL, "mcbsp_clks", "mcbsp_clks"),
+       DT_CLK(NULL, "sys_clkout1", "sys_clkout1"),
+       DT_CLK(NULL, "dpll1_ck", "dpll1_ck"),
+       DT_CLK(NULL, "dpll1_x2_ck", "dpll1_x2_ck"),
+       DT_CLK(NULL, "dpll1_x2m2_ck", "dpll1_x2m2_ck"),
+       DT_CLK(NULL, "dpll3_ck", "dpll3_ck"),
+       DT_CLK(NULL, "core_ck", "core_ck"),
+       DT_CLK(NULL, "dpll3_x2_ck", "dpll3_x2_ck"),
+       DT_CLK(NULL, "dpll3_m2_ck", "dpll3_m2_ck"),
+       DT_CLK(NULL, "dpll3_m2x2_ck", "dpll3_m2x2_ck"),
+       DT_CLK(NULL, "dpll3_m3_ck", "dpll3_m3_ck"),
+       DT_CLK(NULL, "dpll3_m3x2_ck", "dpll3_m3x2_ck"),
+       DT_CLK(NULL, "dpll4_ck", "dpll4_ck"),
+       DT_CLK(NULL, "dpll4_x2_ck", "dpll4_x2_ck"),
+       DT_CLK(NULL, "omap_96m_fck", "omap_96m_fck"),
+       DT_CLK(NULL, "cm_96m_fck", "cm_96m_fck"),
+       DT_CLK(NULL, "omap_54m_fck", "omap_54m_fck"),
+       DT_CLK(NULL, "omap_48m_fck", "omap_48m_fck"),
+       DT_CLK(NULL, "omap_12m_fck", "omap_12m_fck"),
+       DT_CLK(NULL, "dpll4_m2_ck", "dpll4_m2_ck"),
+       DT_CLK(NULL, "dpll4_m2x2_ck", "dpll4_m2x2_ck"),
+       DT_CLK(NULL, "dpll4_m3_ck", "dpll4_m3_ck"),
+       DT_CLK(NULL, "dpll4_m3x2_ck", "dpll4_m3x2_ck"),
+       DT_CLK(NULL, "dpll4_m4_ck", "dpll4_m4_ck"),
+       DT_CLK(NULL, "dpll4_m4x2_ck", "dpll4_m4x2_ck"),
+       DT_CLK(NULL, "dpll4_m5_ck", "dpll4_m5_ck"),
+       DT_CLK(NULL, "dpll4_m5x2_ck", "dpll4_m5x2_ck"),
+       DT_CLK(NULL, "dpll4_m6_ck", "dpll4_m6_ck"),
+       DT_CLK(NULL, "dpll4_m6x2_ck", "dpll4_m6x2_ck"),
+       DT_CLK("etb", "emu_per_alwon_ck", "emu_per_alwon_ck"),
+       DT_CLK(NULL, "clkout2_src_ck", "clkout2_src_ck"),
+       DT_CLK(NULL, "sys_clkout2", "sys_clkout2"),
+       DT_CLK(NULL, "corex2_fck", "corex2_fck"),
+       DT_CLK(NULL, "dpll1_fck", "dpll1_fck"),
+       DT_CLK(NULL, "mpu_ck", "mpu_ck"),
+       DT_CLK(NULL, "arm_fck", "arm_fck"),
+       DT_CLK("etb", "emu_mpu_alwon_ck", "emu_mpu_alwon_ck"),
+       DT_CLK(NULL, "l3_ick", "l3_ick"),
+       DT_CLK(NULL, "l4_ick", "l4_ick"),
+       DT_CLK(NULL, "rm_ick", "rm_ick"),
+       DT_CLK(NULL, "gpt10_fck", "gpt10_fck"),
+       DT_CLK(NULL, "gpt11_fck", "gpt11_fck"),
+       DT_CLK(NULL, "core_96m_fck", "core_96m_fck"),
+       DT_CLK(NULL, "mmchs2_fck", "mmchs2_fck"),
+       DT_CLK(NULL, "mmchs1_fck", "mmchs1_fck"),
+       DT_CLK(NULL, "i2c3_fck", "i2c3_fck"),
+       DT_CLK(NULL, "i2c2_fck", "i2c2_fck"),
+       DT_CLK(NULL, "i2c1_fck", "i2c1_fck"),
+       DT_CLK(NULL, "mcbsp5_fck", "mcbsp5_fck"),
+       DT_CLK(NULL, "mcbsp1_fck", "mcbsp1_fck"),
+       DT_CLK(NULL, "core_48m_fck", "core_48m_fck"),
+       DT_CLK(NULL, "mcspi4_fck", "mcspi4_fck"),
+       DT_CLK(NULL, "mcspi3_fck", "mcspi3_fck"),
+       DT_CLK(NULL, "mcspi2_fck", "mcspi2_fck"),
+       DT_CLK(NULL, "mcspi1_fck", "mcspi1_fck"),
+       DT_CLK(NULL, "uart2_fck", "uart2_fck"),
+       DT_CLK(NULL, "uart1_fck", "uart1_fck"),
+       DT_CLK(NULL, "core_12m_fck", "core_12m_fck"),
+       DT_CLK("omap_hdq.0", "fck", "hdq_fck"),
+       DT_CLK(NULL, "hdq_fck", "hdq_fck"),
+       DT_CLK(NULL, "core_l3_ick", "core_l3_ick"),
+       DT_CLK(NULL, "sdrc_ick", "sdrc_ick"),
+       DT_CLK(NULL, "gpmc_fck", "gpmc_fck"),
+       DT_CLK(NULL, "core_l4_ick", "core_l4_ick"),
+       DT_CLK("omap_hsmmc.1", "ick", "mmchs2_ick"),
+       DT_CLK("omap_hsmmc.0", "ick", "mmchs1_ick"),
+       DT_CLK(NULL, "mmchs2_ick", "mmchs2_ick"),
+       DT_CLK(NULL, "mmchs1_ick", "mmchs1_ick"),
+       DT_CLK("omap_hdq.0", "ick", "hdq_ick"),
+       DT_CLK(NULL, "hdq_ick", "hdq_ick"),
+       DT_CLK("omap2_mcspi.4", "ick", "mcspi4_ick"),
+       DT_CLK("omap2_mcspi.3", "ick", "mcspi3_ick"),
+       DT_CLK("omap2_mcspi.2", "ick", "mcspi2_ick"),
+       DT_CLK("omap2_mcspi.1", "ick", "mcspi1_ick"),
+       DT_CLK(NULL, "mcspi4_ick", "mcspi4_ick"),
+       DT_CLK(NULL, "mcspi3_ick", "mcspi3_ick"),
+       DT_CLK(NULL, "mcspi2_ick", "mcspi2_ick"),
+       DT_CLK(NULL, "mcspi1_ick", "mcspi1_ick"),
+       DT_CLK("omap_i2c.3", "ick", "i2c3_ick"),
+       DT_CLK("omap_i2c.2", "ick", "i2c2_ick"),
+       DT_CLK("omap_i2c.1", "ick", "i2c1_ick"),
+       DT_CLK(NULL, "i2c3_ick", "i2c3_ick"),
+       DT_CLK(NULL, "i2c2_ick", "i2c2_ick"),
+       DT_CLK(NULL, "i2c1_ick", "i2c1_ick"),
+       DT_CLK(NULL, "uart2_ick", "uart2_ick"),
+       DT_CLK(NULL, "uart1_ick", "uart1_ick"),
+       DT_CLK(NULL, "gpt11_ick", "gpt11_ick"),
+       DT_CLK(NULL, "gpt10_ick", "gpt10_ick"),
+       DT_CLK("omap-mcbsp.5", "ick", "mcbsp5_ick"),
+       DT_CLK("omap-mcbsp.1", "ick", "mcbsp1_ick"),
+       DT_CLK(NULL, "mcbsp5_ick", "mcbsp5_ick"),
+       DT_CLK(NULL, "mcbsp1_ick", "mcbsp1_ick"),
+       DT_CLK(NULL, "omapctrl_ick", "omapctrl_ick"),
+       DT_CLK(NULL, "dss_tv_fck", "dss_tv_fck"),
+       DT_CLK(NULL, "dss_96m_fck", "dss_96m_fck"),
+       DT_CLK(NULL, "dss2_alwon_fck", "dss2_alwon_fck"),
+       DT_CLK(NULL, "utmi_p1_gfclk", "dummy_ck"),
+       DT_CLK(NULL, "utmi_p2_gfclk", "dummy_ck"),
+       DT_CLK(NULL, "xclk60mhsp1_ck", "dummy_ck"),
+       DT_CLK(NULL, "xclk60mhsp2_ck", "dummy_ck"),
+       DT_CLK(NULL, "init_60m_fclk", "dummy_ck"),
+       DT_CLK(NULL, "gpt1_fck", "gpt1_fck"),
+       DT_CLK(NULL, "aes2_ick", "aes2_ick"),
+       DT_CLK(NULL, "wkup_32k_fck", "wkup_32k_fck"),
+       DT_CLK(NULL, "gpio1_dbck", "gpio1_dbck"),
+       DT_CLK(NULL, "sha12_ick", "sha12_ick"),
+       DT_CLK(NULL, "wdt2_fck", "wdt2_fck"),
+       DT_CLK("omap_wdt", "ick", "wdt2_ick"),
+       DT_CLK(NULL, "wdt2_ick", "wdt2_ick"),
+       DT_CLK(NULL, "wdt1_ick", "wdt1_ick"),
+       DT_CLK(NULL, "gpio1_ick", "gpio1_ick"),
+       DT_CLK(NULL, "omap_32ksync_ick", "omap_32ksync_ick"),
+       DT_CLK(NULL, "gpt12_ick", "gpt12_ick"),
+       DT_CLK(NULL, "gpt1_ick", "gpt1_ick"),
+       DT_CLK(NULL, "per_96m_fck", "per_96m_fck"),
+       DT_CLK(NULL, "per_48m_fck", "per_48m_fck"),
+       DT_CLK(NULL, "uart3_fck", "uart3_fck"),
+       DT_CLK(NULL, "gpt2_fck", "gpt2_fck"),
+       DT_CLK(NULL, "gpt3_fck", "gpt3_fck"),
+       DT_CLK(NULL, "gpt4_fck", "gpt4_fck"),
+       DT_CLK(NULL, "gpt5_fck", "gpt5_fck"),
+       DT_CLK(NULL, "gpt6_fck", "gpt6_fck"),
+       DT_CLK(NULL, "gpt7_fck", "gpt7_fck"),
+       DT_CLK(NULL, "gpt8_fck", "gpt8_fck"),
+       DT_CLK(NULL, "gpt9_fck", "gpt9_fck"),
+       DT_CLK(NULL, "per_32k_alwon_fck", "per_32k_alwon_fck"),
+       DT_CLK(NULL, "gpio6_dbck", "gpio6_dbck"),
+       DT_CLK(NULL, "gpio5_dbck", "gpio5_dbck"),
+       DT_CLK(NULL, "gpio4_dbck", "gpio4_dbck"),
+       DT_CLK(NULL, "gpio3_dbck", "gpio3_dbck"),
+       DT_CLK(NULL, "gpio2_dbck", "gpio2_dbck"),
+       DT_CLK(NULL, "wdt3_fck", "wdt3_fck"),
+       DT_CLK(NULL, "per_l4_ick", "per_l4_ick"),
+       DT_CLK(NULL, "gpio6_ick", "gpio6_ick"),
+       DT_CLK(NULL, "gpio5_ick", "gpio5_ick"),
+       DT_CLK(NULL, "gpio4_ick", "gpio4_ick"),
+       DT_CLK(NULL, "gpio3_ick", "gpio3_ick"),
+       DT_CLK(NULL, "gpio2_ick", "gpio2_ick"),
+       DT_CLK(NULL, "wdt3_ick", "wdt3_ick"),
+       DT_CLK(NULL, "uart3_ick", "uart3_ick"),
+       DT_CLK(NULL, "uart4_ick", "uart4_ick"),
+       DT_CLK(NULL, "gpt9_ick", "gpt9_ick"),
+       DT_CLK(NULL, "gpt8_ick", "gpt8_ick"),
+       DT_CLK(NULL, "gpt7_ick", "gpt7_ick"),
+       DT_CLK(NULL, "gpt6_ick", "gpt6_ick"),
+       DT_CLK(NULL, "gpt5_ick", "gpt5_ick"),
+       DT_CLK(NULL, "gpt4_ick", "gpt4_ick"),
+       DT_CLK(NULL, "gpt3_ick", "gpt3_ick"),
+       DT_CLK(NULL, "gpt2_ick", "gpt2_ick"),
+       DT_CLK("omap-mcbsp.2", "ick", "mcbsp2_ick"),
+       DT_CLK("omap-mcbsp.3", "ick", "mcbsp3_ick"),
+       DT_CLK("omap-mcbsp.4", "ick", "mcbsp4_ick"),
+       DT_CLK(NULL, "mcbsp4_ick", "mcbsp2_ick"),
+       DT_CLK(NULL, "mcbsp3_ick", "mcbsp3_ick"),
+       DT_CLK(NULL, "mcbsp2_ick", "mcbsp4_ick"),
+       DT_CLK(NULL, "mcbsp2_fck", "mcbsp2_fck"),
+       DT_CLK(NULL, "mcbsp3_fck", "mcbsp3_fck"),
+       DT_CLK(NULL, "mcbsp4_fck", "mcbsp4_fck"),
+       DT_CLK("etb", "emu_src_ck", "emu_src_ck"),
+       DT_CLK(NULL, "emu_src_ck", "emu_src_ck"),
+       DT_CLK(NULL, "pclk_fck", "pclk_fck"),
+       DT_CLK(NULL, "pclkx2_fck", "pclkx2_fck"),
+       DT_CLK(NULL, "atclk_fck", "atclk_fck"),
+       DT_CLK(NULL, "traceclk_src_fck", "traceclk_src_fck"),
+       DT_CLK(NULL, "traceclk_fck", "traceclk_fck"),
+       DT_CLK(NULL, "secure_32k_fck", "secure_32k_fck"),
+       DT_CLK(NULL, "gpt12_fck", "gpt12_fck"),
+       DT_CLK(NULL, "wdt1_fck", "wdt1_fck"),
+       DT_CLK(NULL, "timer_32k_ck", "omap_32k_fck"),
+       DT_CLK(NULL, "timer_sys_ck", "sys_ck"),
+       DT_CLK(NULL, "cpufreq_ck", "dpll1_ck"),
+       { .node_name = NULL },
+};
+
+static struct ti_dt_clk omap34xx_omap36xx_clks[] = {
+       DT_CLK(NULL, "aes1_ick", "aes1_ick"),
+       DT_CLK("omap_rng", "ick", "rng_ick"),
+       DT_CLK("omap3-rom-rng", "ick", "rng_ick"),
+       DT_CLK(NULL, "sha11_ick", "sha11_ick"),
+       DT_CLK(NULL, "des1_ick", "des1_ick"),
+       DT_CLK(NULL, "cam_mclk", "cam_mclk"),
+       DT_CLK(NULL, "cam_ick", "cam_ick"),
+       DT_CLK(NULL, "csi2_96m_fck", "csi2_96m_fck"),
+       DT_CLK(NULL, "security_l3_ick", "security_l3_ick"),
+       DT_CLK(NULL, "pka_ick", "pka_ick"),
+       DT_CLK(NULL, "icr_ick", "icr_ick"),
+       DT_CLK("omap-aes", "ick", "aes2_ick"),
+       DT_CLK("omap-sham", "ick", "sha12_ick"),
+       DT_CLK(NULL, "des2_ick", "des2_ick"),
+       DT_CLK(NULL, "mspro_ick", "mspro_ick"),
+       DT_CLK(NULL, "mailboxes_ick", "mailboxes_ick"),
+       DT_CLK(NULL, "ssi_l4_ick", "ssi_l4_ick"),
+       DT_CLK(NULL, "sr1_fck", "sr1_fck"),
+       DT_CLK(NULL, "sr2_fck", "sr2_fck"),
+       DT_CLK(NULL, "sr_l4_ick", "sr_l4_ick"),
+       DT_CLK(NULL, "security_l4_ick2", "security_l4_ick2"),
+       DT_CLK(NULL, "wkup_l4_ick", "wkup_l4_ick"),
+       DT_CLK(NULL, "dpll2_fck", "dpll2_fck"),
+       DT_CLK(NULL, "iva2_ck", "iva2_ck"),
+       DT_CLK(NULL, "modem_fck", "modem_fck"),
+       DT_CLK(NULL, "sad2d_ick", "sad2d_ick"),
+       DT_CLK(NULL, "mad2d_ick", "mad2d_ick"),
+       DT_CLK(NULL, "mspro_fck", "mspro_fck"),
+       DT_CLK(NULL, "dpll2_ck", "dpll2_ck"),
+       DT_CLK(NULL, "dpll2_m2_ck", "dpll2_m2_ck"),
+       { .node_name = NULL },
+};
+
+static struct ti_dt_clk omap36xx_omap3430es2plus_clks[] = {
+       DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es2"),
+       DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es2"),
+       DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es2"),
+       DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es2"),
+       DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es2"),
+       DT_CLK(NULL, "usim_fck", "usim_fck"),
+       DT_CLK(NULL, "usim_ick", "usim_ick"),
+       { .node_name = NULL },
+};
+
+static struct ti_dt_clk omap3430es1_clks[] = {
+       DT_CLK(NULL, "gfx_l3_ck", "gfx_l3_ck"),
+       DT_CLK(NULL, "gfx_l3_fck", "gfx_l3_fck"),
+       DT_CLK(NULL, "gfx_l3_ick", "gfx_l3_ick"),
+       DT_CLK(NULL, "gfx_cg1_ck", "gfx_cg1_ck"),
+       DT_CLK(NULL, "gfx_cg2_ck", "gfx_cg2_ck"),
+       DT_CLK(NULL, "d2d_26m_fck", "d2d_26m_fck"),
+       DT_CLK(NULL, "fshostusb_fck", "fshostusb_fck"),
+       DT_CLK(NULL, "ssi_ssr_fck", "ssi_ssr_fck_3430es1"),
+       DT_CLK(NULL, "ssi_sst_fck", "ssi_sst_fck_3430es1"),
+       DT_CLK("musb-omap2430", "ick", "hsotgusb_ick_3430es1"),
+       DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_3430es1"),
+       DT_CLK(NULL, "fac_ick", "fac_ick"),
+       DT_CLK(NULL, "ssi_ick", "ssi_ick_3430es1"),
+       DT_CLK(NULL, "usb_l4_ick", "usb_l4_ick"),
+       DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es1"),
+       DT_CLK("omapdss_dss", "ick", "dss_ick_3430es1"),
+       DT_CLK(NULL, "dss_ick", "dss_ick_3430es1"),
+       { .node_name = NULL },
+};
+
+static struct ti_dt_clk omap36xx_am35xx_omap3430es2plus_clks[] = {
+       DT_CLK(NULL, "virt_16_8m_ck", "virt_16_8m_ck"),
+       DT_CLK(NULL, "dpll5_ck", "dpll5_ck"),
+       DT_CLK(NULL, "dpll5_m2_ck", "dpll5_m2_ck"),
+       DT_CLK(NULL, "sgx_fck", "sgx_fck"),
+       DT_CLK(NULL, "sgx_ick", "sgx_ick"),
+       DT_CLK(NULL, "cpefuse_fck", "cpefuse_fck"),
+       DT_CLK(NULL, "ts_fck", "ts_fck"),
+       DT_CLK(NULL, "usbtll_fck", "usbtll_fck"),
+       DT_CLK(NULL, "usbtll_ick", "usbtll_ick"),
+       DT_CLK("omap_hsmmc.2", "ick", "mmchs3_ick"),
+       DT_CLK(NULL, "mmchs3_ick", "mmchs3_ick"),
+       DT_CLK(NULL, "mmchs3_fck", "mmchs3_fck"),
+       DT_CLK(NULL, "dss1_alwon_fck", "dss1_alwon_fck_3430es2"),
+       DT_CLK("omapdss_dss", "ick", "dss_ick_3430es2"),
+       DT_CLK(NULL, "dss_ick", "dss_ick_3430es2"),
+       DT_CLK(NULL, "usbhost_120m_fck", "usbhost_120m_fck"),
+       DT_CLK(NULL, "usbhost_48m_fck", "usbhost_48m_fck"),
+       DT_CLK(NULL, "usbhost_ick", "usbhost_ick"),
+       { .node_name = NULL },
+};
+
+static struct ti_dt_clk am35xx_clks[] = {
+       DT_CLK(NULL, "ipss_ick", "ipss_ick"),
+       DT_CLK(NULL, "rmii_ck", "rmii_ck"),
+       DT_CLK(NULL, "pclk_ck", "pclk_ck"),
+       DT_CLK(NULL, "emac_ick", "emac_ick"),
+       DT_CLK(NULL, "emac_fck", "emac_fck"),
+       DT_CLK("davinci_emac.0", NULL, "emac_ick"),
+       DT_CLK("davinci_mdio.0", NULL, "emac_fck"),
+       DT_CLK("vpfe-capture", "master", "vpfe_ick"),
+       DT_CLK("vpfe-capture", "slave", "vpfe_fck"),
+       DT_CLK(NULL, "hsotgusb_ick", "hsotgusb_ick_am35xx"),
+       DT_CLK(NULL, "hsotgusb_fck", "hsotgusb_fck_am35xx"),
+       DT_CLK(NULL, "hecc_ck", "hecc_ck"),
+       DT_CLK(NULL, "uart4_ick", "uart4_ick_am35xx"),
+       DT_CLK(NULL, "uart4_fck", "uart4_fck_am35xx"),
+       { .node_name = NULL },
+};
+
+static struct ti_dt_clk omap36xx_clks[] = {
+       DT_CLK(NULL, "omap_192m_alwon_fck", "omap_192m_alwon_fck"),
+       DT_CLK(NULL, "uart4_fck", "uart4_fck"),
+       { .node_name = NULL },
+};
+
+static const char *enable_init_clks[] = {
+       "sdrc_ick",
+       "gpmc_fck",
+       "omapctrl_ick",
+};
+
+enum {
+       OMAP3_SOC_AM35XX,
+       OMAP3_SOC_OMAP3430_ES1,
+       OMAP3_SOC_OMAP3430_ES2_PLUS,
+       OMAP3_SOC_OMAP3630,
+       OMAP3_SOC_TI81XX,
+};
+
+static int __init omap3xxx_dt_clk_init(int soc_type)
+{
+       if (soc_type == OMAP3_SOC_AM35XX || soc_type == OMAP3_SOC_OMAP3630 ||
+           soc_type == OMAP3_SOC_OMAP3430_ES1 ||
+           soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS)
+               ti_dt_clocks_register(omap3xxx_clks);
+
+       if (soc_type == OMAP3_SOC_AM35XX)
+               ti_dt_clocks_register(am35xx_clks);
+
+       if (soc_type == OMAP3_SOC_OMAP3630 || soc_type == OMAP3_SOC_AM35XX ||
+           soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS)
+               ti_dt_clocks_register(omap36xx_am35xx_omap3430es2plus_clks);
+
+       if (soc_type == OMAP3_SOC_OMAP3430_ES1)
+               ti_dt_clocks_register(omap3430es1_clks);
+
+       if (soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS ||
+           soc_type == OMAP3_SOC_OMAP3630)
+               ti_dt_clocks_register(omap36xx_omap3430es2plus_clks);
+
+       if (soc_type == OMAP3_SOC_OMAP3430_ES1 ||
+           soc_type == OMAP3_SOC_OMAP3430_ES2_PLUS ||
+           soc_type == OMAP3_SOC_OMAP3630)
+               ti_dt_clocks_register(omap34xx_omap36xx_clks);
+
+       if (soc_type == OMAP3_SOC_OMAP3630)
+               ti_dt_clocks_register(omap36xx_clks);
+
+       omap2_clk_disable_autoidle_all();
+
+       omap2_clk_enable_init_clocks(enable_init_clks,
+                                    ARRAY_SIZE(enable_init_clks));
+
+       pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n",
+               (clk_get_rate(clk_get_sys(NULL, "osc_sys_ck")) / 1000000),
+               (clk_get_rate(clk_get_sys(NULL, "osc_sys_ck")) / 100000) % 10,
+               (clk_get_rate(clk_get_sys(NULL, "core_ck")) / 1000000),
+               (clk_get_rate(clk_get_sys(NULL, "arm_fck")) / 1000000));
+
+       if (soc_type != OMAP3_SOC_TI81XX && soc_type != OMAP3_SOC_OMAP3430_ES1)
+               omap3_clk_lock_dpll5();
+
+       return 0;
+}
+
+int __init omap3430_dt_clk_init(void)
+{
+       return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3430_ES2_PLUS);
+}
+
+int __init omap3630_dt_clk_init(void)
+{
+       return omap3xxx_dt_clk_init(OMAP3_SOC_OMAP3630);
+}
+
+int __init am35xx_dt_clk_init(void)
+{
+       return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX);
+}
+
+int __init ti81xx_dt_clk_init(void)
+{
+       return omap3xxx_dt_clk_init(OMAP3_SOC_TI81XX);
+}
diff --git a/drivers/clk/ti/clk-43xx.c b/drivers/clk/ti/clk-43xx.c
new file mode 100644 (file)
index 0000000..67c8de5
--- /dev/null
@@ -0,0 +1,118 @@
+/*
+ * AM43XX Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc
+ *     Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+static struct ti_dt_clk am43xx_clks[] = {
+       DT_CLK(NULL, "clk_32768_ck", "clk_32768_ck"),
+       DT_CLK(NULL, "clk_rc32k_ck", "clk_rc32k_ck"),
+       DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"),
+       DT_CLK(NULL, "virt_24000000_ck", "virt_24000000_ck"),
+       DT_CLK(NULL, "virt_25000000_ck", "virt_25000000_ck"),
+       DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"),
+       DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"),
+       DT_CLK(NULL, "tclkin_ck", "tclkin_ck"),
+       DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"),
+       DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"),
+       DT_CLK(NULL, "dpll_core_m4_ck", "dpll_core_m4_ck"),
+       DT_CLK(NULL, "dpll_core_m5_ck", "dpll_core_m5_ck"),
+       DT_CLK(NULL, "dpll_core_m6_ck", "dpll_core_m6_ck"),
+       DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"),
+       DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"),
+       DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"),
+       DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"),
+       DT_CLK(NULL, "dpll_disp_ck", "dpll_disp_ck"),
+       DT_CLK(NULL, "dpll_disp_m2_ck", "dpll_disp_m2_ck"),
+       DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"),
+       DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"),
+       DT_CLK(NULL, "dpll_per_m2_div4_wkupdm_ck", "dpll_per_m2_div4_wkupdm_ck"),
+       DT_CLK(NULL, "dpll_per_m2_div4_ck", "dpll_per_m2_div4_ck"),
+       DT_CLK(NULL, "adc_tsc_fck", "adc_tsc_fck"),
+       DT_CLK(NULL, "clkdiv32k_ck", "clkdiv32k_ck"),
+       DT_CLK(NULL, "clkdiv32k_ick", "clkdiv32k_ick"),
+       DT_CLK(NULL, "dcan0_fck", "dcan0_fck"),
+       DT_CLK(NULL, "dcan1_fck", "dcan1_fck"),
+       DT_CLK(NULL, "pruss_ocp_gclk", "pruss_ocp_gclk"),
+       DT_CLK(NULL, "mcasp0_fck", "mcasp0_fck"),
+       DT_CLK(NULL, "mcasp1_fck", "mcasp1_fck"),
+       DT_CLK(NULL, "smartreflex0_fck", "smartreflex0_fck"),
+       DT_CLK(NULL, "smartreflex1_fck", "smartreflex1_fck"),
+       DT_CLK(NULL, "sha0_fck", "sha0_fck"),
+       DT_CLK(NULL, "aes0_fck", "aes0_fck"),
+       DT_CLK(NULL, "timer1_fck", "timer1_fck"),
+       DT_CLK(NULL, "timer2_fck", "timer2_fck"),
+       DT_CLK(NULL, "timer3_fck", "timer3_fck"),
+       DT_CLK(NULL, "timer4_fck", "timer4_fck"),
+       DT_CLK(NULL, "timer5_fck", "timer5_fck"),
+       DT_CLK(NULL, "timer6_fck", "timer6_fck"),
+       DT_CLK(NULL, "timer7_fck", "timer7_fck"),
+       DT_CLK(NULL, "wdt1_fck", "wdt1_fck"),
+       DT_CLK(NULL, "l3_gclk", "l3_gclk"),
+       DT_CLK(NULL, "dpll_core_m4_div2_ck", "dpll_core_m4_div2_ck"),
+       DT_CLK(NULL, "l4hs_gclk", "l4hs_gclk"),
+       DT_CLK(NULL, "l3s_gclk", "l3s_gclk"),
+       DT_CLK(NULL, "l4ls_gclk", "l4ls_gclk"),
+       DT_CLK(NULL, "clk_24mhz", "clk_24mhz"),
+       DT_CLK(NULL, "cpsw_125mhz_gclk", "cpsw_125mhz_gclk"),
+       DT_CLK(NULL, "cpsw_cpts_rft_clk", "cpsw_cpts_rft_clk"),
+       DT_CLK(NULL, "gpio0_dbclk_mux_ck", "gpio0_dbclk_mux_ck"),
+       DT_CLK(NULL, "gpio0_dbclk", "gpio0_dbclk"),
+       DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"),
+       DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"),
+       DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"),
+       DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"),
+       DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"),
+       DT_CLK(NULL, "mmc_clk", "mmc_clk"),
+       DT_CLK(NULL, "gfx_fclk_clksel_ck", "gfx_fclk_clksel_ck"),
+       DT_CLK(NULL, "gfx_fck_div_ck", "gfx_fck_div_ck"),
+       DT_CLK(NULL, "timer_32k_ck", "clkdiv32k_ick"),
+       DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK(NULL, "sysclk_div", "sysclk_div"),
+       DT_CLK(NULL, "disp_clk", "disp_clk"),
+       DT_CLK(NULL, "clk_32k_mosc_ck", "clk_32k_mosc_ck"),
+       DT_CLK(NULL, "clk_32k_tpm_ck", "clk_32k_tpm_ck"),
+       DT_CLK(NULL, "dpll_extdev_ck", "dpll_extdev_ck"),
+       DT_CLK(NULL, "dpll_extdev_m2_ck", "dpll_extdev_m2_ck"),
+       DT_CLK(NULL, "mux_synctimer32k_ck", "mux_synctimer32k_ck"),
+       DT_CLK(NULL, "synctimer_32kclk", "synctimer_32kclk"),
+       DT_CLK(NULL, "timer8_fck", "timer8_fck"),
+       DT_CLK(NULL, "timer9_fck", "timer9_fck"),
+       DT_CLK(NULL, "timer10_fck", "timer10_fck"),
+       DT_CLK(NULL, "timer11_fck", "timer11_fck"),
+       DT_CLK(NULL, "cpsw_50m_clkdiv", "cpsw_50m_clkdiv"),
+       DT_CLK(NULL, "cpsw_5m_clkdiv", "cpsw_5m_clkdiv"),
+       DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"),
+       DT_CLK(NULL, "dpll_ddr_m4_ck", "dpll_ddr_m4_ck"),
+       DT_CLK(NULL, "dpll_per_clkdcoldo", "dpll_per_clkdcoldo"),
+       DT_CLK(NULL, "dll_aging_clk_div", "dll_aging_clk_div"),
+       DT_CLK(NULL, "div_core_25m_ck", "div_core_25m_ck"),
+       DT_CLK(NULL, "func_12m_clk", "func_12m_clk"),
+       DT_CLK(NULL, "vtp_clk_div", "vtp_clk_div"),
+       DT_CLK(NULL, "usbphy_32khz_clkmux", "usbphy_32khz_clkmux"),
+       { .node_name = NULL },
+};
+
+int __init am43xx_dt_clk_init(void)
+{
+       ti_dt_clocks_register(am43xx_clks);
+
+       omap2_clk_disable_autoidle_all();
+
+       return 0;
+}
diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c
new file mode 100644 (file)
index 0000000..ae00218
--- /dev/null
@@ -0,0 +1,316 @@
+/*
+ * OMAP4 Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk-private.h>
+#include <linux/clkdev.h>
+#include <linux/clk/ti.h>
+
+/*
+ * OMAP4 ABE DPLL default frequency. In OMAP4460 TRM version V, section
+ * "3.6.3.2.3 CM1_ABE Clock Generator" states that the "DPLL_ABE_X2_CLK
+ * must be set to 196.608 MHz" and hence, the DPLL locked frequency is
+ * half of this value.
+ */
+#define OMAP4_DPLL_ABE_DEFFREQ                         98304000
+
+/*
+ * OMAP4 USB DPLL default frequency. In OMAP4430 TRM version V, section
+ * "3.6.3.9.5 DPLL_USB Preferred Settings" shows that the preferred
+ * locked frequency for the USB DPLL is 960MHz.
+ */
+#define OMAP4_DPLL_USB_DEFFREQ                         960000000
+
+static struct ti_dt_clk omap44xx_clks[] = {
+       DT_CLK(NULL, "extalt_clkin_ck", "extalt_clkin_ck"),
+       DT_CLK(NULL, "pad_clks_src_ck", "pad_clks_src_ck"),
+       DT_CLK(NULL, "pad_clks_ck", "pad_clks_ck"),
+       DT_CLK(NULL, "pad_slimbus_core_clks_ck", "pad_slimbus_core_clks_ck"),
+       DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"),
+       DT_CLK(NULL, "slimbus_src_clk", "slimbus_src_clk"),
+       DT_CLK(NULL, "slimbus_clk", "slimbus_clk"),
+       DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
+       DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"),
+       DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"),
+       DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"),
+       DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"),
+       DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"),
+       DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"),
+       DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"),
+       DT_CLK(NULL, "sys_clkin_ck", "sys_clkin_ck"),
+       DT_CLK(NULL, "tie_low_clock_ck", "tie_low_clock_ck"),
+       DT_CLK(NULL, "utmi_phy_clkout_ck", "utmi_phy_clkout_ck"),
+       DT_CLK(NULL, "xclk60mhsp1_ck", "xclk60mhsp1_ck"),
+       DT_CLK(NULL, "xclk60mhsp2_ck", "xclk60mhsp2_ck"),
+       DT_CLK(NULL, "xclk60motg_ck", "xclk60motg_ck"),
+       DT_CLK(NULL, "abe_dpll_bypass_clk_mux_ck", "abe_dpll_bypass_clk_mux_ck"),
+       DT_CLK(NULL, "abe_dpll_refclk_mux_ck", "abe_dpll_refclk_mux_ck"),
+       DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"),
+       DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"),
+       DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"),
+       DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"),
+       DT_CLK(NULL, "abe_clk", "abe_clk"),
+       DT_CLK(NULL, "aess_fclk", "aess_fclk"),
+       DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"),
+       DT_CLK(NULL, "core_hsd_byp_clk_mux_ck", "core_hsd_byp_clk_mux_ck"),
+       DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"),
+       DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"),
+       DT_CLK(NULL, "dpll_core_m6x2_ck", "dpll_core_m6x2_ck"),
+       DT_CLK(NULL, "dbgclk_mux_ck", "dbgclk_mux_ck"),
+       DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"),
+       DT_CLK(NULL, "ddrphy_ck", "ddrphy_ck"),
+       DT_CLK(NULL, "dpll_core_m5x2_ck", "dpll_core_m5x2_ck"),
+       DT_CLK(NULL, "div_core_ck", "div_core_ck"),
+       DT_CLK(NULL, "div_iva_hs_clk", "div_iva_hs_clk"),
+       DT_CLK(NULL, "div_mpu_hs_clk", "div_mpu_hs_clk"),
+       DT_CLK(NULL, "dpll_core_m4x2_ck", "dpll_core_m4x2_ck"),
+       DT_CLK(NULL, "dll_clk_div_ck", "dll_clk_div_ck"),
+       DT_CLK(NULL, "dpll_abe_m2_ck", "dpll_abe_m2_ck"),
+       DT_CLK(NULL, "dpll_core_m3x2_ck", "dpll_core_m3x2_ck"),
+       DT_CLK(NULL, "dpll_core_m7x2_ck", "dpll_core_m7x2_ck"),
+       DT_CLK(NULL, "iva_hsd_byp_clk_mux_ck", "iva_hsd_byp_clk_mux_ck"),
+       DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"),
+       DT_CLK(NULL, "dpll_iva_x2_ck", "dpll_iva_x2_ck"),
+       DT_CLK(NULL, "dpll_iva_m4x2_ck", "dpll_iva_m4x2_ck"),
+       DT_CLK(NULL, "dpll_iva_m5x2_ck", "dpll_iva_m5x2_ck"),
+       DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"),
+       DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"),
+       DT_CLK(NULL, "per_hs_clk_div_ck", "per_hs_clk_div_ck"),
+       DT_CLK(NULL, "per_hsd_byp_clk_mux_ck", "per_hsd_byp_clk_mux_ck"),
+       DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"),
+       DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"),
+       DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"),
+       DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"),
+       DT_CLK(NULL, "dpll_per_m3x2_ck", "dpll_per_m3x2_ck"),
+       DT_CLK(NULL, "dpll_per_m4x2_ck", "dpll_per_m4x2_ck"),
+       DT_CLK(NULL, "dpll_per_m5x2_ck", "dpll_per_m5x2_ck"),
+       DT_CLK(NULL, "dpll_per_m6x2_ck", "dpll_per_m6x2_ck"),
+       DT_CLK(NULL, "dpll_per_m7x2_ck", "dpll_per_m7x2_ck"),
+       DT_CLK(NULL, "usb_hs_clk_div_ck", "usb_hs_clk_div_ck"),
+       DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"),
+       DT_CLK(NULL, "dpll_usb_clkdcoldo_ck", "dpll_usb_clkdcoldo_ck"),
+       DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"),
+       DT_CLK(NULL, "ducati_clk_mux_ck", "ducati_clk_mux_ck"),
+       DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"),
+       DT_CLK(NULL, "func_24m_clk", "func_24m_clk"),
+       DT_CLK(NULL, "func_24mc_fclk", "func_24mc_fclk"),
+       DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"),
+       DT_CLK(NULL, "func_48mc_fclk", "func_48mc_fclk"),
+       DT_CLK(NULL, "func_64m_fclk", "func_64m_fclk"),
+       DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"),
+       DT_CLK(NULL, "init_60m_fclk", "init_60m_fclk"),
+       DT_CLK(NULL, "l3_div_ck", "l3_div_ck"),
+       DT_CLK(NULL, "l4_div_ck", "l4_div_ck"),
+       DT_CLK(NULL, "lp_clk_div_ck", "lp_clk_div_ck"),
+       DT_CLK(NULL, "l4_wkup_clk_mux_ck", "l4_wkup_clk_mux_ck"),
+       DT_CLK("smp_twd", NULL, "mpu_periphclk"),
+       DT_CLK(NULL, "ocp_abe_iclk", "ocp_abe_iclk"),
+       DT_CLK(NULL, "per_abe_24m_fclk", "per_abe_24m_fclk"),
+       DT_CLK(NULL, "per_abe_nc_fclk", "per_abe_nc_fclk"),
+       DT_CLK(NULL, "syc_clk_div_ck", "syc_clk_div_ck"),
+       DT_CLK(NULL, "aes1_fck", "aes1_fck"),
+       DT_CLK(NULL, "aes2_fck", "aes2_fck"),
+       DT_CLK(NULL, "dmic_sync_mux_ck", "dmic_sync_mux_ck"),
+       DT_CLK(NULL, "func_dmic_abe_gfclk", "func_dmic_abe_gfclk"),
+       DT_CLK(NULL, "dss_sys_clk", "dss_sys_clk"),
+       DT_CLK(NULL, "dss_tv_clk", "dss_tv_clk"),
+       DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"),
+       DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"),
+       DT_CLK(NULL, "dss_fck", "dss_fck"),
+       DT_CLK("omapdss_dss", "ick", "dss_fck"),
+       DT_CLK(NULL, "fdif_fck", "fdif_fck"),
+       DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"),
+       DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"),
+       DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"),
+       DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"),
+       DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"),
+       DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"),
+       DT_CLK(NULL, "sgx_clk_mux", "sgx_clk_mux"),
+       DT_CLK(NULL, "hsi_fck", "hsi_fck"),
+       DT_CLK(NULL, "iss_ctrlclk", "iss_ctrlclk"),
+       DT_CLK(NULL, "mcasp_sync_mux_ck", "mcasp_sync_mux_ck"),
+       DT_CLK(NULL, "func_mcasp_abe_gfclk", "func_mcasp_abe_gfclk"),
+       DT_CLK(NULL, "mcbsp1_sync_mux_ck", "mcbsp1_sync_mux_ck"),
+       DT_CLK(NULL, "func_mcbsp1_gfclk", "func_mcbsp1_gfclk"),
+       DT_CLK(NULL, "mcbsp2_sync_mux_ck", "mcbsp2_sync_mux_ck"),
+       DT_CLK(NULL, "func_mcbsp2_gfclk", "func_mcbsp2_gfclk"),
+       DT_CLK(NULL, "mcbsp3_sync_mux_ck", "mcbsp3_sync_mux_ck"),
+       DT_CLK(NULL, "func_mcbsp3_gfclk", "func_mcbsp3_gfclk"),
+       DT_CLK(NULL, "mcbsp4_sync_mux_ck", "mcbsp4_sync_mux_ck"),
+       DT_CLK(NULL, "per_mcbsp4_gfclk", "per_mcbsp4_gfclk"),
+       DT_CLK(NULL, "hsmmc1_fclk", "hsmmc1_fclk"),
+       DT_CLK(NULL, "hsmmc2_fclk", "hsmmc2_fclk"),
+       DT_CLK(NULL, "ocp2scp_usb_phy_phy_48m", "ocp2scp_usb_phy_phy_48m"),
+       DT_CLK(NULL, "sha2md5_fck", "sha2md5_fck"),
+       DT_CLK(NULL, "slimbus1_fclk_1", "slimbus1_fclk_1"),
+       DT_CLK(NULL, "slimbus1_fclk_0", "slimbus1_fclk_0"),
+       DT_CLK(NULL, "slimbus1_fclk_2", "slimbus1_fclk_2"),
+       DT_CLK(NULL, "slimbus1_slimbus_clk", "slimbus1_slimbus_clk"),
+       DT_CLK(NULL, "slimbus2_fclk_1", "slimbus2_fclk_1"),
+       DT_CLK(NULL, "slimbus2_fclk_0", "slimbus2_fclk_0"),
+       DT_CLK(NULL, "slimbus2_slimbus_clk", "slimbus2_slimbus_clk"),
+       DT_CLK(NULL, "smartreflex_core_fck", "smartreflex_core_fck"),
+       DT_CLK(NULL, "smartreflex_iva_fck", "smartreflex_iva_fck"),
+       DT_CLK(NULL, "smartreflex_mpu_fck", "smartreflex_mpu_fck"),
+       DT_CLK(NULL, "dmt1_clk_mux", "dmt1_clk_mux"),
+       DT_CLK(NULL, "cm2_dm10_mux", "cm2_dm10_mux"),
+       DT_CLK(NULL, "cm2_dm11_mux", "cm2_dm11_mux"),
+       DT_CLK(NULL, "cm2_dm2_mux", "cm2_dm2_mux"),
+       DT_CLK(NULL, "cm2_dm3_mux", "cm2_dm3_mux"),
+       DT_CLK(NULL, "cm2_dm4_mux", "cm2_dm4_mux"),
+       DT_CLK(NULL, "timer5_sync_mux", "timer5_sync_mux"),
+       DT_CLK(NULL, "timer6_sync_mux", "timer6_sync_mux"),
+       DT_CLK(NULL, "timer7_sync_mux", "timer7_sync_mux"),
+       DT_CLK(NULL, "timer8_sync_mux", "timer8_sync_mux"),
+       DT_CLK(NULL, "cm2_dm9_mux", "cm2_dm9_mux"),
+       DT_CLK(NULL, "usb_host_fs_fck", "usb_host_fs_fck"),
+       DT_CLK("usbhs_omap", "fs_fck", "usb_host_fs_fck"),
+       DT_CLK(NULL, "utmi_p1_gfclk", "utmi_p1_gfclk"),
+       DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "usb_host_hs_utmi_p1_clk"),
+       DT_CLK(NULL, "utmi_p2_gfclk", "utmi_p2_gfclk"),
+       DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "usb_host_hs_utmi_p2_clk"),
+       DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "usb_host_hs_utmi_p3_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "usb_host_hs_hsic480m_p1_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "usb_host_hs_hsic60m_p1_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "usb_host_hs_hsic60m_p2_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "usb_host_hs_hsic480m_p2_clk"),
+       DT_CLK(NULL, "usb_host_hs_func48mclk", "usb_host_hs_func48mclk"),
+       DT_CLK(NULL, "usb_host_hs_fck", "usb_host_hs_fck"),
+       DT_CLK("usbhs_omap", "hs_fck", "usb_host_hs_fck"),
+       DT_CLK(NULL, "otg_60m_gfclk", "otg_60m_gfclk"),
+       DT_CLK(NULL, "usb_otg_hs_xclk", "usb_otg_hs_xclk"),
+       DT_CLK(NULL, "usb_otg_hs_ick", "usb_otg_hs_ick"),
+       DT_CLK("musb-omap2430", "ick", "usb_otg_hs_ick"),
+       DT_CLK(NULL, "usb_phy_cm_clk32k", "usb_phy_cm_clk32k"),
+       DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "usb_tll_hs_usb_ch2_clk"),
+       DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "usb_tll_hs_usb_ch0_clk"),
+       DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "usb_tll_hs_usb_ch1_clk"),
+       DT_CLK(NULL, "usb_tll_hs_ick", "usb_tll_hs_ick"),
+       DT_CLK("usbhs_omap", "usbtll_ick", "usb_tll_hs_ick"),
+       DT_CLK("usbhs_tll", "usbtll_ick", "usb_tll_hs_ick"),
+       DT_CLK(NULL, "usim_ck", "usim_ck"),
+       DT_CLK(NULL, "usim_fclk", "usim_fclk"),
+       DT_CLK(NULL, "pmd_stm_clock_mux_ck", "pmd_stm_clock_mux_ck"),
+       DT_CLK(NULL, "pmd_trace_clk_mux_ck", "pmd_trace_clk_mux_ck"),
+       DT_CLK(NULL, "stm_clk_div_ck", "stm_clk_div_ck"),
+       DT_CLK(NULL, "trace_clk_div_ck", "trace_clk_div_ck"),
+       DT_CLK(NULL, "auxclk0_src_ck", "auxclk0_src_ck"),
+       DT_CLK(NULL, "auxclk0_ck", "auxclk0_ck"),
+       DT_CLK(NULL, "auxclkreq0_ck", "auxclkreq0_ck"),
+       DT_CLK(NULL, "auxclk1_src_ck", "auxclk1_src_ck"),
+       DT_CLK(NULL, "auxclk1_ck", "auxclk1_ck"),
+       DT_CLK(NULL, "auxclkreq1_ck", "auxclkreq1_ck"),
+       DT_CLK(NULL, "auxclk2_src_ck", "auxclk2_src_ck"),
+       DT_CLK(NULL, "auxclk2_ck", "auxclk2_ck"),
+       DT_CLK(NULL, "auxclkreq2_ck", "auxclkreq2_ck"),
+       DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"),
+       DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"),
+       DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"),
+       DT_CLK(NULL, "auxclk4_src_ck", "auxclk4_src_ck"),
+       DT_CLK(NULL, "auxclk4_ck", "auxclk4_ck"),
+       DT_CLK(NULL, "auxclkreq4_ck", "auxclkreq4_ck"),
+       DT_CLK(NULL, "auxclk5_src_ck", "auxclk5_src_ck"),
+       DT_CLK(NULL, "auxclk5_ck", "auxclk5_ck"),
+       DT_CLK(NULL, "auxclkreq5_ck", "auxclkreq5_ck"),
+       DT_CLK("50000000.gpmc", "fck", "dummy_ck"),
+       DT_CLK("omap_i2c.1", "ick", "dummy_ck"),
+       DT_CLK("omap_i2c.2", "ick", "dummy_ck"),
+       DT_CLK("omap_i2c.3", "ick", "dummy_ck"),
+       DT_CLK("omap_i2c.4", "ick", "dummy_ck"),
+       DT_CLK(NULL, "mailboxes_ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"),
+       DT_CLK(NULL, "uart1_ick", "dummy_ck"),
+       DT_CLK(NULL, "uart2_ick", "dummy_ck"),
+       DT_CLK(NULL, "uart3_ick", "dummy_ck"),
+       DT_CLK(NULL, "uart4_ick", "dummy_ck"),
+       DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"),
+       DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"),
+       DT_CLK("usbhs_tll", "usbtll_fck", "dummy_ck"),
+       DT_CLK("omap_wdt", "ick", "dummy_ck"),
+       DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
+       DT_CLK("omap_timer.1", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("omap_timer.2", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("omap_timer.3", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("omap_timer.4", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("omap_timer.9", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("omap_timer.10", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("omap_timer.11", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("omap_timer.5", "timer_sys_ck", "syc_clk_div_ck"),
+       DT_CLK("omap_timer.6", "timer_sys_ck", "syc_clk_div_ck"),
+       DT_CLK("omap_timer.7", "timer_sys_ck", "syc_clk_div_ck"),
+       DT_CLK("omap_timer.8", "timer_sys_ck", "syc_clk_div_ck"),
+       DT_CLK("4a318000.timer", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin_ck"),
+       DT_CLK("40138000.timer", "timer_sys_ck", "syc_clk_div_ck"),
+       DT_CLK("4013a000.timer", "timer_sys_ck", "syc_clk_div_ck"),
+       DT_CLK("4013c000.timer", "timer_sys_ck", "syc_clk_div_ck"),
+       DT_CLK("4013e000.timer", "timer_sys_ck", "syc_clk_div_ck"),
+       DT_CLK(NULL, "cpufreq_ck", "dpll_mpu_ck"),
+       DT_CLK(NULL, "bandgap_fclk", "bandgap_fclk"),
+       DT_CLK(NULL, "div_ts_ck", "div_ts_ck"),
+       DT_CLK(NULL, "bandgap_ts_fclk", "bandgap_ts_fclk"),
+       { .node_name = NULL },
+};
+
+int __init omap4xxx_dt_clk_init(void)
+{
+       int rc;
+       struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll;
+
+       ti_dt_clocks_register(omap44xx_clks);
+
+       omap2_clk_disable_autoidle_all();
+
+       /*
+        * Lock USB DPLL on OMAP4 devices so that the L3INIT power
+        * domain can transition to retention state when not in use.
+        */
+       usb_dpll = clk_get_sys(NULL, "dpll_usb_ck");
+       rc = clk_set_rate(usb_dpll, OMAP4_DPLL_USB_DEFFREQ);
+       if (rc)
+               pr_err("%s: failed to configure USB DPLL!\n", __func__);
+
+       /*
+        * On OMAP4460 the ABE DPLL fails to turn on if in idle low-power
+        * state when turning the ABE clock domain. Workaround this by
+        * locking the ABE DPLL on boot.
+        * Lock the ABE DPLL in any case to avoid issues with audio.
+        */
+       abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_refclk_mux_ck");
+       sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck");
+       rc = clk_set_parent(abe_dpll_ref, sys_32k_ck);
+       abe_dpll = clk_get_sys(NULL, "dpll_abe_ck");
+       if (!rc)
+               rc = clk_set_rate(abe_dpll, OMAP4_DPLL_ABE_DEFFREQ);
+       if (rc)
+               pr_err("%s: failed to configure ABE DPLL!\n", __func__);
+
+       return 0;
+}
diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c
new file mode 100644 (file)
index 0000000..0ef9f58
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ * OMAP5 Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk-private.h>
+#include <linux/clkdev.h>
+#include <linux/io.h>
+#include <linux/clk/ti.h>
+
+#define OMAP5_DPLL_ABE_DEFFREQ                         98304000
+
+/*
+ * OMAP543x TRM, section "3.6.3.9.5 DPLL_USB Preferred Settings"
+ * states it must be at 960MHz
+ */
+#define OMAP5_DPLL_USB_DEFFREQ                         960000000
+
+static struct ti_dt_clk omap54xx_clks[] = {
+       DT_CLK(NULL, "pad_clks_src_ck", "pad_clks_src_ck"),
+       DT_CLK(NULL, "pad_clks_ck", "pad_clks_ck"),
+       DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"),
+       DT_CLK(NULL, "slimbus_src_clk", "slimbus_src_clk"),
+       DT_CLK(NULL, "slimbus_clk", "slimbus_clk"),
+       DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
+       DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"),
+       DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"),
+       DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"),
+       DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"),
+       DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"),
+       DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"),
+       DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"),
+       DT_CLK(NULL, "sys_clkin", "sys_clkin"),
+       DT_CLK(NULL, "xclk60mhsp1_ck", "xclk60mhsp1_ck"),
+       DT_CLK(NULL, "xclk60mhsp2_ck", "xclk60mhsp2_ck"),
+       DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"),
+       DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"),
+       DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"),
+       DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"),
+       DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"),
+       DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"),
+       DT_CLK(NULL, "abe_clk", "abe_clk"),
+       DT_CLK(NULL, "abe_iclk", "abe_iclk"),
+       DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"),
+       DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"),
+       DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"),
+       DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"),
+       DT_CLK(NULL, "dpll_core_h21x2_ck", "dpll_core_h21x2_ck"),
+       DT_CLK(NULL, "c2c_fclk", "c2c_fclk"),
+       DT_CLK(NULL, "c2c_iclk", "c2c_iclk"),
+       DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"),
+       DT_CLK(NULL, "dpll_core_h11x2_ck", "dpll_core_h11x2_ck"),
+       DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"),
+       DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"),
+       DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"),
+       DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"),
+       DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"),
+       DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"),
+       DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"),
+       DT_CLK(NULL, "dpll_core_m3x2_ck", "dpll_core_m3x2_ck"),
+       DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"),
+       DT_CLK(NULL, "dpll_iva_x2_ck", "dpll_iva_x2_ck"),
+       DT_CLK(NULL, "dpll_iva_h11x2_ck", "dpll_iva_h11x2_ck"),
+       DT_CLK(NULL, "dpll_iva_h12x2_ck", "dpll_iva_h12x2_ck"),
+       DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"),
+       DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"),
+       DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"),
+       DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"),
+       DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"),
+       DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"),
+       DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"),
+       DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"),
+       DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"),
+       DT_CLK(NULL, "dpll_per_m3x2_ck", "dpll_per_m3x2_ck"),
+       DT_CLK(NULL, "dpll_unipro1_ck", "dpll_unipro1_ck"),
+       DT_CLK(NULL, "dpll_unipro1_clkdcoldo", "dpll_unipro1_clkdcoldo"),
+       DT_CLK(NULL, "dpll_unipro1_m2_ck", "dpll_unipro1_m2_ck"),
+       DT_CLK(NULL, "dpll_unipro2_ck", "dpll_unipro2_ck"),
+       DT_CLK(NULL, "dpll_unipro2_clkdcoldo", "dpll_unipro2_clkdcoldo"),
+       DT_CLK(NULL, "dpll_unipro2_m2_ck", "dpll_unipro2_m2_ck"),
+       DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"),
+       DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"),
+       DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"),
+       DT_CLK(NULL, "dss_syc_gfclk_div", "dss_syc_gfclk_div"),
+       DT_CLK(NULL, "func_128m_clk", "func_128m_clk"),
+       DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"),
+       DT_CLK(NULL, "func_24m_clk", "func_24m_clk"),
+       DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"),
+       DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"),
+       DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"),
+       DT_CLK(NULL, "gpu_l3_iclk", "gpu_l3_iclk"),
+       DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"),
+       DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"),
+       DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"),
+       DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"),
+       DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"),
+       DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"),
+       DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"),
+       DT_CLK(NULL, "dss_sys_clk", "dss_sys_clk"),
+       DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"),
+       DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"),
+       DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"),
+       DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"),
+       DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"),
+       DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"),
+       DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"),
+       DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"),
+       DT_CLK(NULL, "iss_ctrlclk", "iss_ctrlclk"),
+       DT_CLK(NULL, "lli_txphy_clk", "lli_txphy_clk"),
+       DT_CLK(NULL, "lli_txphy_ls_clk", "lli_txphy_ls_clk"),
+       DT_CLK(NULL, "mmc1_32khz_clk", "mmc1_32khz_clk"),
+       DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"),
+       DT_CLK(NULL, "slimbus1_slimbus_clk", "slimbus1_slimbus_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic480m_p1_clk", "usb_host_hs_hsic480m_p1_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic480m_p2_clk", "usb_host_hs_hsic480m_p2_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic480m_p3_clk", "usb_host_hs_hsic480m_p3_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic60m_p1_clk", "usb_host_hs_hsic60m_p1_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic60m_p2_clk", "usb_host_hs_hsic60m_p2_clk"),
+       DT_CLK(NULL, "usb_host_hs_hsic60m_p3_clk", "usb_host_hs_hsic60m_p3_clk"),
+       DT_CLK(NULL, "usb_host_hs_utmi_p1_clk", "usb_host_hs_utmi_p1_clk"),
+       DT_CLK(NULL, "usb_host_hs_utmi_p2_clk", "usb_host_hs_utmi_p2_clk"),
+       DT_CLK(NULL, "usb_host_hs_utmi_p3_clk", "usb_host_hs_utmi_p3_clk"),
+       DT_CLK(NULL, "usb_otg_ss_refclk960m", "usb_otg_ss_refclk960m"),
+       DT_CLK(NULL, "usb_phy_cm_clk32k", "usb_phy_cm_clk32k"),
+       DT_CLK(NULL, "usb_tll_hs_usb_ch0_clk", "usb_tll_hs_usb_ch0_clk"),
+       DT_CLK(NULL, "usb_tll_hs_usb_ch1_clk", "usb_tll_hs_usb_ch1_clk"),
+       DT_CLK(NULL, "usb_tll_hs_usb_ch2_clk", "usb_tll_hs_usb_ch2_clk"),
+       DT_CLK(NULL, "aess_fclk", "aess_fclk"),
+       DT_CLK(NULL, "dmic_sync_mux_ck", "dmic_sync_mux_ck"),
+       DT_CLK(NULL, "dmic_gfclk", "dmic_gfclk"),
+       DT_CLK(NULL, "fdif_fclk", "fdif_fclk"),
+       DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"),
+       DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"),
+       DT_CLK(NULL, "hsi_fclk", "hsi_fclk"),
+       DT_CLK(NULL, "mcasp_sync_mux_ck", "mcasp_sync_mux_ck"),
+       DT_CLK(NULL, "mcasp_gfclk", "mcasp_gfclk"),
+       DT_CLK(NULL, "mcbsp1_sync_mux_ck", "mcbsp1_sync_mux_ck"),
+       DT_CLK(NULL, "mcbsp1_gfclk", "mcbsp1_gfclk"),
+       DT_CLK(NULL, "mcbsp2_sync_mux_ck", "mcbsp2_sync_mux_ck"),
+       DT_CLK(NULL, "mcbsp2_gfclk", "mcbsp2_gfclk"),
+       DT_CLK(NULL, "mcbsp3_sync_mux_ck", "mcbsp3_sync_mux_ck"),
+       DT_CLK(NULL, "mcbsp3_gfclk", "mcbsp3_gfclk"),
+       DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"),
+       DT_CLK(NULL, "mmc1_fclk", "mmc1_fclk"),
+       DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"),
+       DT_CLK(NULL, "mmc2_fclk", "mmc2_fclk"),
+       DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"),
+       DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"),
+       DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"),
+       DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"),
+       DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"),
+       DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"),
+       DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"),
+       DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"),
+       DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"),
+       DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"),
+       DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"),
+       DT_CLK(NULL, "utmi_p1_gfclk", "utmi_p1_gfclk"),
+       DT_CLK(NULL, "utmi_p2_gfclk", "utmi_p2_gfclk"),
+       DT_CLK(NULL, "auxclk0_src_ck", "auxclk0_src_ck"),
+       DT_CLK(NULL, "auxclk0_ck", "auxclk0_ck"),
+       DT_CLK(NULL, "auxclkreq0_ck", "auxclkreq0_ck"),
+       DT_CLK(NULL, "auxclk1_src_ck", "auxclk1_src_ck"),
+       DT_CLK(NULL, "auxclk1_ck", "auxclk1_ck"),
+       DT_CLK(NULL, "auxclkreq1_ck", "auxclkreq1_ck"),
+       DT_CLK(NULL, "auxclk2_src_ck", "auxclk2_src_ck"),
+       DT_CLK(NULL, "auxclk2_ck", "auxclk2_ck"),
+       DT_CLK(NULL, "auxclkreq2_ck", "auxclkreq2_ck"),
+       DT_CLK(NULL, "auxclk3_src_ck", "auxclk3_src_ck"),
+       DT_CLK(NULL, "auxclk3_ck", "auxclk3_ck"),
+       DT_CLK(NULL, "auxclkreq3_ck", "auxclkreq3_ck"),
+       DT_CLK(NULL, "gpmc_ck", "dummy_ck"),
+       DT_CLK("omap_i2c.1", "ick", "dummy_ck"),
+       DT_CLK("omap_i2c.2", "ick", "dummy_ck"),
+       DT_CLK("omap_i2c.3", "ick", "dummy_ck"),
+       DT_CLK("omap_i2c.4", "ick", "dummy_ck"),
+       DT_CLK(NULL, "mailboxes_ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"),
+       DT_CLK(NULL, "uart1_ick", "dummy_ck"),
+       DT_CLK(NULL, "uart2_ick", "dummy_ck"),
+       DT_CLK(NULL, "uart3_ick", "dummy_ck"),
+       DT_CLK(NULL, "uart4_ick", "dummy_ck"),
+       DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"),
+       DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"),
+       DT_CLK("omap_wdt", "ick", "dummy_ck"),
+       DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
+       DT_CLK("omap_timer.1", "sys_ck", "sys_clkin"),
+       DT_CLK("omap_timer.2", "sys_ck", "sys_clkin"),
+       DT_CLK("omap_timer.3", "sys_ck", "sys_clkin"),
+       DT_CLK("omap_timer.4", "sys_ck", "sys_clkin"),
+       DT_CLK("omap_timer.9", "sys_ck", "sys_clkin"),
+       DT_CLK("omap_timer.10", "sys_ck", "sys_clkin"),
+       DT_CLK("omap_timer.11", "sys_ck", "sys_clkin"),
+       DT_CLK("omap_timer.5", "sys_ck", "dss_syc_gfclk_div"),
+       DT_CLK("omap_timer.6", "sys_ck", "dss_syc_gfclk_div"),
+       DT_CLK("omap_timer.7", "sys_ck", "dss_syc_gfclk_div"),
+       DT_CLK("omap_timer.8", "sys_ck", "dss_syc_gfclk_div"),
+       { .node_name = NULL },
+};
+
+int __init omap5xxx_dt_clk_init(void)
+{
+       int rc;
+       struct clk *abe_dpll_ref, *abe_dpll, *sys_32k_ck, *usb_dpll;
+
+       ti_dt_clocks_register(omap54xx_clks);
+
+       omap2_clk_disable_autoidle_all();
+
+       abe_dpll_ref = clk_get_sys(NULL, "abe_dpll_clk_mux");
+       sys_32k_ck = clk_get_sys(NULL, "sys_32k_ck");
+       rc = clk_set_parent(abe_dpll_ref, sys_32k_ck);
+       abe_dpll = clk_get_sys(NULL, "dpll_abe_ck");
+       if (!rc)
+               rc = clk_set_rate(abe_dpll, OMAP5_DPLL_ABE_DEFFREQ);
+       if (rc)
+               pr_err("%s: failed to configure ABE DPLL!\n", __func__);
+
+       usb_dpll = clk_get_sys(NULL, "dpll_usb_ck");
+       rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ);
+       if (rc)
+               pr_err("%s: failed to configure USB DPLL!\n", __func__);
+
+       usb_dpll = clk_get_sys(NULL, "dpll_usb_m2_ck");
+       rc = clk_set_rate(usb_dpll, OMAP5_DPLL_USB_DEFFREQ/2);
+       if (rc)
+               pr_err("%s: failed to set USB_DPLL M2 OUT\n", __func__);
+
+       return 0;
+}
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
new file mode 100644 (file)
index 0000000..9977653
--- /dev/null
@@ -0,0 +1,332 @@
+/*
+ * DRA7 Clock init
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/clk-private.h>
+#include <linux/clkdev.h>
+#include <linux/clk/ti.h>
+
+#define DRA7_DPLL_ABE_DEFFREQ                          361267200
+#define DRA7_DPLL_GMAC_DEFFREQ                         1000000000
+
+
+static struct ti_dt_clk dra7xx_clks[] = {
+       DT_CLK(NULL, "atl_clkin0_ck", "atl_clkin0_ck"),
+       DT_CLK(NULL, "atl_clkin1_ck", "atl_clkin1_ck"),
+       DT_CLK(NULL, "atl_clkin2_ck", "atl_clkin2_ck"),
+       DT_CLK(NULL, "atlclkin3_ck", "atlclkin3_ck"),
+       DT_CLK(NULL, "hdmi_clkin_ck", "hdmi_clkin_ck"),
+       DT_CLK(NULL, "mlb_clkin_ck", "mlb_clkin_ck"),
+       DT_CLK(NULL, "mlbp_clkin_ck", "mlbp_clkin_ck"),
+       DT_CLK(NULL, "pciesref_acs_clk_ck", "pciesref_acs_clk_ck"),
+       DT_CLK(NULL, "ref_clkin0_ck", "ref_clkin0_ck"),
+       DT_CLK(NULL, "ref_clkin1_ck", "ref_clkin1_ck"),
+       DT_CLK(NULL, "ref_clkin2_ck", "ref_clkin2_ck"),
+       DT_CLK(NULL, "ref_clkin3_ck", "ref_clkin3_ck"),
+       DT_CLK(NULL, "rmii_clk_ck", "rmii_clk_ck"),
+       DT_CLK(NULL, "sdvenc_clkin_ck", "sdvenc_clkin_ck"),
+       DT_CLK(NULL, "secure_32k_clk_src_ck", "secure_32k_clk_src_ck"),
+       DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
+       DT_CLK(NULL, "virt_12000000_ck", "virt_12000000_ck"),
+       DT_CLK(NULL, "virt_13000000_ck", "virt_13000000_ck"),
+       DT_CLK(NULL, "virt_16800000_ck", "virt_16800000_ck"),
+       DT_CLK(NULL, "virt_19200000_ck", "virt_19200000_ck"),
+       DT_CLK(NULL, "virt_20000000_ck", "virt_20000000_ck"),
+       DT_CLK(NULL, "virt_26000000_ck", "virt_26000000_ck"),
+       DT_CLK(NULL, "virt_27000000_ck", "virt_27000000_ck"),
+       DT_CLK(NULL, "virt_38400000_ck", "virt_38400000_ck"),
+       DT_CLK(NULL, "sys_clkin1", "sys_clkin1"),
+       DT_CLK(NULL, "sys_clkin2", "sys_clkin2"),
+       DT_CLK(NULL, "usb_otg_clkin_ck", "usb_otg_clkin_ck"),
+       DT_CLK(NULL, "video1_clkin_ck", "video1_clkin_ck"),
+       DT_CLK(NULL, "video1_m2_clkin_ck", "video1_m2_clkin_ck"),
+       DT_CLK(NULL, "video2_clkin_ck", "video2_clkin_ck"),
+       DT_CLK(NULL, "video2_m2_clkin_ck", "video2_m2_clkin_ck"),
+       DT_CLK(NULL, "abe_dpll_sys_clk_mux", "abe_dpll_sys_clk_mux"),
+       DT_CLK(NULL, "abe_dpll_bypass_clk_mux", "abe_dpll_bypass_clk_mux"),
+       DT_CLK(NULL, "abe_dpll_clk_mux", "abe_dpll_clk_mux"),
+       DT_CLK(NULL, "dpll_abe_ck", "dpll_abe_ck"),
+       DT_CLK(NULL, "dpll_abe_x2_ck", "dpll_abe_x2_ck"),
+       DT_CLK(NULL, "dpll_abe_m2x2_ck", "dpll_abe_m2x2_ck"),
+       DT_CLK(NULL, "abe_24m_fclk", "abe_24m_fclk"),
+       DT_CLK(NULL, "abe_clk", "abe_clk"),
+       DT_CLK(NULL, "aess_fclk", "aess_fclk"),
+       DT_CLK(NULL, "abe_giclk_div", "abe_giclk_div"),
+       DT_CLK(NULL, "abe_lp_clk_div", "abe_lp_clk_div"),
+       DT_CLK(NULL, "abe_sys_clk_div", "abe_sys_clk_div"),
+       DT_CLK(NULL, "adc_gfclk_mux", "adc_gfclk_mux"),
+       DT_CLK(NULL, "dpll_pcie_ref_ck", "dpll_pcie_ref_ck"),
+       DT_CLK(NULL, "dpll_pcie_ref_m2ldo_ck", "dpll_pcie_ref_m2ldo_ck"),
+       DT_CLK(NULL, "apll_pcie_ck", "apll_pcie_ck"),
+       DT_CLK(NULL, "apll_pcie_clkvcoldo", "apll_pcie_clkvcoldo"),
+       DT_CLK(NULL, "apll_pcie_clkvcoldo_div", "apll_pcie_clkvcoldo_div"),
+       DT_CLK(NULL, "apll_pcie_m2_ck", "apll_pcie_m2_ck"),
+       DT_CLK(NULL, "sys_clk1_dclk_div", "sys_clk1_dclk_div"),
+       DT_CLK(NULL, "sys_clk2_dclk_div", "sys_clk2_dclk_div"),
+       DT_CLK(NULL, "dpll_abe_m2_ck", "dpll_abe_m2_ck"),
+       DT_CLK(NULL, "per_abe_x1_dclk_div", "per_abe_x1_dclk_div"),
+       DT_CLK(NULL, "dpll_abe_m3x2_ck", "dpll_abe_m3x2_ck"),
+       DT_CLK(NULL, "dpll_core_ck", "dpll_core_ck"),
+       DT_CLK(NULL, "dpll_core_x2_ck", "dpll_core_x2_ck"),
+       DT_CLK(NULL, "dpll_core_h12x2_ck", "dpll_core_h12x2_ck"),
+       DT_CLK(NULL, "mpu_dpll_hs_clk_div", "mpu_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_mpu_ck", "dpll_mpu_ck"),
+       DT_CLK(NULL, "dpll_mpu_m2_ck", "dpll_mpu_m2_ck"),
+       DT_CLK(NULL, "mpu_dclk_div", "mpu_dclk_div"),
+       DT_CLK(NULL, "dsp_dpll_hs_clk_div", "dsp_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_dsp_ck", "dpll_dsp_ck"),
+       DT_CLK(NULL, "dpll_dsp_m2_ck", "dpll_dsp_m2_ck"),
+       DT_CLK(NULL, "dsp_gclk_div", "dsp_gclk_div"),
+       DT_CLK(NULL, "iva_dpll_hs_clk_div", "iva_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_iva_ck", "dpll_iva_ck"),
+       DT_CLK(NULL, "dpll_iva_m2_ck", "dpll_iva_m2_ck"),
+       DT_CLK(NULL, "iva_dclk", "iva_dclk"),
+       DT_CLK(NULL, "dpll_gpu_ck", "dpll_gpu_ck"),
+       DT_CLK(NULL, "dpll_gpu_m2_ck", "dpll_gpu_m2_ck"),
+       DT_CLK(NULL, "gpu_dclk", "gpu_dclk"),
+       DT_CLK(NULL, "dpll_core_m2_ck", "dpll_core_m2_ck"),
+       DT_CLK(NULL, "core_dpll_out_dclk_div", "core_dpll_out_dclk_div"),
+       DT_CLK(NULL, "dpll_ddr_ck", "dpll_ddr_ck"),
+       DT_CLK(NULL, "dpll_ddr_m2_ck", "dpll_ddr_m2_ck"),
+       DT_CLK(NULL, "emif_phy_dclk_div", "emif_phy_dclk_div"),
+       DT_CLK(NULL, "dpll_gmac_ck", "dpll_gmac_ck"),
+       DT_CLK(NULL, "dpll_gmac_m2_ck", "dpll_gmac_m2_ck"),
+       DT_CLK(NULL, "gmac_250m_dclk_div", "gmac_250m_dclk_div"),
+       DT_CLK(NULL, "video2_dclk_div", "video2_dclk_div"),
+       DT_CLK(NULL, "video1_dclk_div", "video1_dclk_div"),
+       DT_CLK(NULL, "hdmi_dclk_div", "hdmi_dclk_div"),
+       DT_CLK(NULL, "per_dpll_hs_clk_div", "per_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_per_ck", "dpll_per_ck"),
+       DT_CLK(NULL, "dpll_per_m2_ck", "dpll_per_m2_ck"),
+       DT_CLK(NULL, "func_96m_aon_dclk_div", "func_96m_aon_dclk_div"),
+       DT_CLK(NULL, "usb_dpll_hs_clk_div", "usb_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_usb_ck", "dpll_usb_ck"),
+       DT_CLK(NULL, "dpll_usb_m2_ck", "dpll_usb_m2_ck"),
+       DT_CLK(NULL, "l3init_480m_dclk_div", "l3init_480m_dclk_div"),
+       DT_CLK(NULL, "usb_otg_dclk_div", "usb_otg_dclk_div"),
+       DT_CLK(NULL, "sata_dclk_div", "sata_dclk_div"),
+       DT_CLK(NULL, "dpll_pcie_ref_m2_ck", "dpll_pcie_ref_m2_ck"),
+       DT_CLK(NULL, "pcie2_dclk_div", "pcie2_dclk_div"),
+       DT_CLK(NULL, "pcie_dclk_div", "pcie_dclk_div"),
+       DT_CLK(NULL, "emu_dclk_div", "emu_dclk_div"),
+       DT_CLK(NULL, "secure_32k_dclk_div", "secure_32k_dclk_div"),
+       DT_CLK(NULL, "eve_dpll_hs_clk_div", "eve_dpll_hs_clk_div"),
+       DT_CLK(NULL, "dpll_eve_ck", "dpll_eve_ck"),
+       DT_CLK(NULL, "dpll_eve_m2_ck", "dpll_eve_m2_ck"),
+       DT_CLK(NULL, "eve_dclk_div", "eve_dclk_div"),
+       DT_CLK(NULL, "clkoutmux0_clk_mux", "clkoutmux0_clk_mux"),
+       DT_CLK(NULL, "clkoutmux1_clk_mux", "clkoutmux1_clk_mux"),
+       DT_CLK(NULL, "clkoutmux2_clk_mux", "clkoutmux2_clk_mux"),
+       DT_CLK(NULL, "custefuse_sys_gfclk_div", "custefuse_sys_gfclk_div"),
+       DT_CLK(NULL, "dpll_core_h13x2_ck", "dpll_core_h13x2_ck"),
+       DT_CLK(NULL, "dpll_core_h14x2_ck", "dpll_core_h14x2_ck"),
+       DT_CLK(NULL, "dpll_core_h22x2_ck", "dpll_core_h22x2_ck"),
+       DT_CLK(NULL, "dpll_core_h23x2_ck", "dpll_core_h23x2_ck"),
+       DT_CLK(NULL, "dpll_core_h24x2_ck", "dpll_core_h24x2_ck"),
+       DT_CLK(NULL, "dpll_ddr_x2_ck", "dpll_ddr_x2_ck"),
+       DT_CLK(NULL, "dpll_ddr_h11x2_ck", "dpll_ddr_h11x2_ck"),
+       DT_CLK(NULL, "dpll_dsp_x2_ck", "dpll_dsp_x2_ck"),
+       DT_CLK(NULL, "dpll_dsp_m3x2_ck", "dpll_dsp_m3x2_ck"),
+       DT_CLK(NULL, "dpll_gmac_x2_ck", "dpll_gmac_x2_ck"),
+       DT_CLK(NULL, "dpll_gmac_h11x2_ck", "dpll_gmac_h11x2_ck"),
+       DT_CLK(NULL, "dpll_gmac_h12x2_ck", "dpll_gmac_h12x2_ck"),
+       DT_CLK(NULL, "dpll_gmac_h13x2_ck", "dpll_gmac_h13x2_ck"),
+       DT_CLK(NULL, "dpll_gmac_m3x2_ck", "dpll_gmac_m3x2_ck"),
+       DT_CLK(NULL, "dpll_per_x2_ck", "dpll_per_x2_ck"),
+       DT_CLK(NULL, "dpll_per_h11x2_ck", "dpll_per_h11x2_ck"),
+       DT_CLK(NULL, "dpll_per_h12x2_ck", "dpll_per_h12x2_ck"),
+       DT_CLK(NULL, "dpll_per_h13x2_ck", "dpll_per_h13x2_ck"),
+       DT_CLK(NULL, "dpll_per_h14x2_ck", "dpll_per_h14x2_ck"),
+       DT_CLK(NULL, "dpll_per_m2x2_ck", "dpll_per_m2x2_ck"),
+       DT_CLK(NULL, "dpll_usb_clkdcoldo", "dpll_usb_clkdcoldo"),
+       DT_CLK(NULL, "eve_clk", "eve_clk"),
+       DT_CLK(NULL, "func_128m_clk", "func_128m_clk"),
+       DT_CLK(NULL, "func_12m_fclk", "func_12m_fclk"),
+       DT_CLK(NULL, "func_24m_clk", "func_24m_clk"),
+       DT_CLK(NULL, "func_48m_fclk", "func_48m_fclk"),
+       DT_CLK(NULL, "func_96m_fclk", "func_96m_fclk"),
+       DT_CLK(NULL, "gmii_m_clk_div", "gmii_m_clk_div"),
+       DT_CLK(NULL, "hdmi_clk2_div", "hdmi_clk2_div"),
+       DT_CLK(NULL, "hdmi_div_clk", "hdmi_div_clk"),
+       DT_CLK(NULL, "hdmi_dpll_clk_mux", "hdmi_dpll_clk_mux"),
+       DT_CLK(NULL, "l3_iclk_div", "l3_iclk_div"),
+       DT_CLK(NULL, "l3init_60m_fclk", "l3init_60m_fclk"),
+       DT_CLK(NULL, "l4_root_clk_div", "l4_root_clk_div"),
+       DT_CLK(NULL, "mlb_clk", "mlb_clk"),
+       DT_CLK(NULL, "mlbp_clk", "mlbp_clk"),
+       DT_CLK(NULL, "per_abe_x1_gfclk2_div", "per_abe_x1_gfclk2_div"),
+       DT_CLK(NULL, "timer_sys_clk_div", "timer_sys_clk_div"),
+       DT_CLK(NULL, "video1_clk2_div", "video1_clk2_div"),
+       DT_CLK(NULL, "video1_div_clk", "video1_div_clk"),
+       DT_CLK(NULL, "video1_dpll_clk_mux", "video1_dpll_clk_mux"),
+       DT_CLK(NULL, "video2_clk2_div", "video2_clk2_div"),
+       DT_CLK(NULL, "video2_div_clk", "video2_div_clk"),
+       DT_CLK(NULL, "video2_dpll_clk_mux", "video2_dpll_clk_mux"),
+       DT_CLK(NULL, "wkupaon_iclk_mux", "wkupaon_iclk_mux"),
+       DT_CLK(NULL, "dss_32khz_clk", "dss_32khz_clk"),
+       DT_CLK(NULL, "dss_48mhz_clk", "dss_48mhz_clk"),
+       DT_CLK(NULL, "dss_dss_clk", "dss_dss_clk"),
+       DT_CLK(NULL, "dss_hdmi_clk", "dss_hdmi_clk"),
+       DT_CLK(NULL, "dss_video1_clk", "dss_video1_clk"),
+       DT_CLK(NULL, "dss_video2_clk", "dss_video2_clk"),
+       DT_CLK(NULL, "gpio1_dbclk", "gpio1_dbclk"),
+       DT_CLK(NULL, "gpio2_dbclk", "gpio2_dbclk"),
+       DT_CLK(NULL, "gpio3_dbclk", "gpio3_dbclk"),
+       DT_CLK(NULL, "gpio4_dbclk", "gpio4_dbclk"),
+       DT_CLK(NULL, "gpio5_dbclk", "gpio5_dbclk"),
+       DT_CLK(NULL, "gpio6_dbclk", "gpio6_dbclk"),
+       DT_CLK(NULL, "gpio7_dbclk", "gpio7_dbclk"),
+       DT_CLK(NULL, "gpio8_dbclk", "gpio8_dbclk"),
+       DT_CLK(NULL, "mmc1_clk32k", "mmc1_clk32k"),
+       DT_CLK(NULL, "mmc2_clk32k", "mmc2_clk32k"),
+       DT_CLK(NULL, "mmc3_clk32k", "mmc3_clk32k"),
+       DT_CLK(NULL, "mmc4_clk32k", "mmc4_clk32k"),
+       DT_CLK(NULL, "sata_ref_clk", "sata_ref_clk"),
+       DT_CLK(NULL, "usb_otg_ss1_refclk960m", "usb_otg_ss1_refclk960m"),
+       DT_CLK(NULL, "usb_otg_ss2_refclk960m", "usb_otg_ss2_refclk960m"),
+       DT_CLK(NULL, "usb_phy1_always_on_clk32k", "usb_phy1_always_on_clk32k"),
+       DT_CLK(NULL, "usb_phy2_always_on_clk32k", "usb_phy2_always_on_clk32k"),
+       DT_CLK(NULL, "usb_phy3_always_on_clk32k", "usb_phy3_always_on_clk32k"),
+       DT_CLK(NULL, "atl_dpll_clk_mux", "atl_dpll_clk_mux"),
+       DT_CLK(NULL, "atl_gfclk_mux", "atl_gfclk_mux"),
+       DT_CLK(NULL, "dcan1_sys_clk_mux", "dcan1_sys_clk_mux"),
+       DT_CLK(NULL, "gmac_gmii_ref_clk_div", "gmac_gmii_ref_clk_div"),
+       DT_CLK(NULL, "gmac_rft_clk_mux", "gmac_rft_clk_mux"),
+       DT_CLK(NULL, "gpu_core_gclk_mux", "gpu_core_gclk_mux"),
+       DT_CLK(NULL, "gpu_hyd_gclk_mux", "gpu_hyd_gclk_mux"),
+       DT_CLK(NULL, "ipu1_gfclk_mux", "ipu1_gfclk_mux"),
+       DT_CLK(NULL, "l3instr_ts_gclk_div", "l3instr_ts_gclk_div"),
+       DT_CLK(NULL, "mcasp1_ahclkr_mux", "mcasp1_ahclkr_mux"),
+       DT_CLK(NULL, "mcasp1_ahclkx_mux", "mcasp1_ahclkx_mux"),
+       DT_CLK(NULL, "mcasp1_aux_gfclk_mux", "mcasp1_aux_gfclk_mux"),
+       DT_CLK(NULL, "mcasp2_ahclkr_mux", "mcasp2_ahclkr_mux"),
+       DT_CLK(NULL, "mcasp2_ahclkx_mux", "mcasp2_ahclkx_mux"),
+       DT_CLK(NULL, "mcasp2_aux_gfclk_mux", "mcasp2_aux_gfclk_mux"),
+       DT_CLK(NULL, "mcasp3_ahclkx_mux", "mcasp3_ahclkx_mux"),
+       DT_CLK(NULL, "mcasp3_aux_gfclk_mux", "mcasp3_aux_gfclk_mux"),
+       DT_CLK(NULL, "mcasp4_ahclkx_mux", "mcasp4_ahclkx_mux"),
+       DT_CLK(NULL, "mcasp4_aux_gfclk_mux", "mcasp4_aux_gfclk_mux"),
+       DT_CLK(NULL, "mcasp5_ahclkx_mux", "mcasp5_ahclkx_mux"),
+       DT_CLK(NULL, "mcasp5_aux_gfclk_mux", "mcasp5_aux_gfclk_mux"),
+       DT_CLK(NULL, "mcasp6_ahclkx_mux", "mcasp6_ahclkx_mux"),
+       DT_CLK(NULL, "mcasp6_aux_gfclk_mux", "mcasp6_aux_gfclk_mux"),
+       DT_CLK(NULL, "mcasp7_ahclkx_mux", "mcasp7_ahclkx_mux"),
+       DT_CLK(NULL, "mcasp7_aux_gfclk_mux", "mcasp7_aux_gfclk_mux"),
+       DT_CLK(NULL, "mcasp8_ahclk_mux", "mcasp8_ahclk_mux"),
+       DT_CLK(NULL, "mcasp8_aux_gfclk_mux", "mcasp8_aux_gfclk_mux"),
+       DT_CLK(NULL, "mmc1_fclk_mux", "mmc1_fclk_mux"),
+       DT_CLK(NULL, "mmc1_fclk_div", "mmc1_fclk_div"),
+       DT_CLK(NULL, "mmc2_fclk_mux", "mmc2_fclk_mux"),
+       DT_CLK(NULL, "mmc2_fclk_div", "mmc2_fclk_div"),
+       DT_CLK(NULL, "mmc3_gfclk_mux", "mmc3_gfclk_mux"),
+       DT_CLK(NULL, "mmc3_gfclk_div", "mmc3_gfclk_div"),
+       DT_CLK(NULL, "mmc4_gfclk_mux", "mmc4_gfclk_mux"),
+       DT_CLK(NULL, "mmc4_gfclk_div", "mmc4_gfclk_div"),
+       DT_CLK(NULL, "qspi_gfclk_mux", "qspi_gfclk_mux"),
+       DT_CLK(NULL, "qspi_gfclk_div", "qspi_gfclk_div"),
+       DT_CLK(NULL, "timer10_gfclk_mux", "timer10_gfclk_mux"),
+       DT_CLK(NULL, "timer11_gfclk_mux", "timer11_gfclk_mux"),
+       DT_CLK(NULL, "timer13_gfclk_mux", "timer13_gfclk_mux"),
+       DT_CLK(NULL, "timer14_gfclk_mux", "timer14_gfclk_mux"),
+       DT_CLK(NULL, "timer15_gfclk_mux", "timer15_gfclk_mux"),
+       DT_CLK(NULL, "timer16_gfclk_mux", "timer16_gfclk_mux"),
+       DT_CLK(NULL, "timer1_gfclk_mux", "timer1_gfclk_mux"),
+       DT_CLK(NULL, "timer2_gfclk_mux", "timer2_gfclk_mux"),
+       DT_CLK(NULL, "timer3_gfclk_mux", "timer3_gfclk_mux"),
+       DT_CLK(NULL, "timer4_gfclk_mux", "timer4_gfclk_mux"),
+       DT_CLK(NULL, "timer5_gfclk_mux", "timer5_gfclk_mux"),
+       DT_CLK(NULL, "timer6_gfclk_mux", "timer6_gfclk_mux"),
+       DT_CLK(NULL, "timer7_gfclk_mux", "timer7_gfclk_mux"),
+       DT_CLK(NULL, "timer8_gfclk_mux", "timer8_gfclk_mux"),
+       DT_CLK(NULL, "timer9_gfclk_mux", "timer9_gfclk_mux"),
+       DT_CLK(NULL, "uart10_gfclk_mux", "uart10_gfclk_mux"),
+       DT_CLK(NULL, "uart1_gfclk_mux", "uart1_gfclk_mux"),
+       DT_CLK(NULL, "uart2_gfclk_mux", "uart2_gfclk_mux"),
+       DT_CLK(NULL, "uart3_gfclk_mux", "uart3_gfclk_mux"),
+       DT_CLK(NULL, "uart4_gfclk_mux", "uart4_gfclk_mux"),
+       DT_CLK(NULL, "uart5_gfclk_mux", "uart5_gfclk_mux"),
+       DT_CLK(NULL, "uart6_gfclk_mux", "uart6_gfclk_mux"),
+       DT_CLK(NULL, "uart7_gfclk_mux", "uart7_gfclk_mux"),
+       DT_CLK(NULL, "uart8_gfclk_mux", "uart8_gfclk_mux"),
+       DT_CLK(NULL, "uart9_gfclk_mux", "uart9_gfclk_mux"),
+       DT_CLK(NULL, "vip1_gclk_mux", "vip1_gclk_mux"),
+       DT_CLK(NULL, "vip2_gclk_mux", "vip2_gclk_mux"),
+       DT_CLK(NULL, "vip3_gclk_mux", "vip3_gclk_mux"),
+       DT_CLK(NULL, "gpmc_ck", "dummy_ck"),
+       DT_CLK("omap_i2c.1", "ick", "dummy_ck"),
+       DT_CLK("omap_i2c.2", "ick", "dummy_ck"),
+       DT_CLK("omap_i2c.3", "ick", "dummy_ck"),
+       DT_CLK("omap_i2c.4", "ick", "dummy_ck"),
+       DT_CLK(NULL, "mailboxes_ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.0", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.1", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.2", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.3", "ick", "dummy_ck"),
+       DT_CLK("omap_hsmmc.4", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.1", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.2", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.3", "ick", "dummy_ck"),
+       DT_CLK("omap-mcbsp.4", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.1", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.2", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.3", "ick", "dummy_ck"),
+       DT_CLK("omap2_mcspi.4", "ick", "dummy_ck"),
+       DT_CLK(NULL, "uart1_ick", "dummy_ck"),
+       DT_CLK(NULL, "uart2_ick", "dummy_ck"),
+       DT_CLK(NULL, "uart3_ick", "dummy_ck"),
+       DT_CLK(NULL, "uart4_ick", "dummy_ck"),
+       DT_CLK("usbhs_omap", "usbhost_ick", "dummy_ck"),
+       DT_CLK("usbhs_omap", "usbtll_fck", "dummy_ck"),
+       DT_CLK("omap_wdt", "ick", "dummy_ck"),
+       DT_CLK(NULL, "timer_32k_ck", "sys_32k_ck"),
+       DT_CLK("4ae18000.timer", "timer_sys_ck", "sys_clkin2"),
+       DT_CLK("48032000.timer", "timer_sys_ck", "sys_clkin2"),
+       DT_CLK("48034000.timer", "timer_sys_ck", "sys_clkin2"),
+       DT_CLK("48036000.timer", "timer_sys_ck", "sys_clkin2"),
+       DT_CLK("4803e000.timer", "timer_sys_ck", "sys_clkin2"),
+       DT_CLK("48086000.timer", "timer_sys_ck", "sys_clkin2"),
+       DT_CLK("48088000.timer", "timer_sys_ck", "sys_clkin2"),
+       DT_CLK("48820000.timer", "timer_sys_ck", "timer_sys_clk_div"),
+       DT_CLK("48822000.timer", "timer_sys_ck", "timer_sys_clk_div"),
+       DT_CLK("48824000.timer", "timer_sys_ck", "timer_sys_clk_div"),
+       DT_CLK("48826000.timer", "timer_sys_ck", "timer_sys_clk_div"),
+       DT_CLK(NULL, "sys_clkin", "sys_clkin1"),
+       { .node_name = NULL },
+};
+
+int __init dra7xx_dt_clk_init(void)
+{
+       int rc;
+       struct clk *abe_dpll_mux, *sys_clkin2, *dpll_ck;
+
+       ti_dt_clocks_register(dra7xx_clks);
+
+       omap2_clk_disable_autoidle_all();
+
+       abe_dpll_mux = clk_get_sys(NULL, "abe_dpll_sys_clk_mux");
+       sys_clkin2 = clk_get_sys(NULL, "sys_clkin2");
+       dpll_ck = clk_get_sys(NULL, "dpll_abe_ck");
+
+       rc = clk_set_parent(abe_dpll_mux, sys_clkin2);
+       if (!rc)
+               rc = clk_set_rate(dpll_ck, DRA7_DPLL_ABE_DEFFREQ);
+       if (rc)
+               pr_err("%s: failed to configure ABE DPLL!\n", __func__);
+
+       dpll_ck = clk_get_sys(NULL, "dpll_gmac_ck");
+       rc = clk_set_rate(dpll_ck, DRA7_DPLL_GMAC_DEFFREQ);
+       if (rc)
+               pr_err("%s: failed to configure GMAC DPLL!\n", __func__);
+
+       return rc;
+}
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c
new file mode 100644 (file)
index 0000000..b1a6f71
--- /dev/null
@@ -0,0 +1,167 @@
+/*
+ * TI clock support
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/ti.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/list.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+static int ti_dt_clk_memmap_index;
+struct ti_clk_ll_ops *ti_clk_ll_ops;
+
+/**
+ * ti_dt_clocks_register - register DT alias clocks during boot
+ * @oclks: list of clocks to register
+ *
+ * Register alias or non-standard DT clock entries during boot. By
+ * default, DT clocks are found based on their node name. If any
+ * additional con-id / dev-id -> clock mapping is required, use this
+ * function to list these.
+ */
+void __init ti_dt_clocks_register(struct ti_dt_clk oclks[])
+{
+       struct ti_dt_clk *c;
+       struct device_node *node;
+       struct clk *clk;
+       struct of_phandle_args clkspec;
+
+       for (c = oclks; c->node_name != NULL; c++) {
+               node = of_find_node_by_name(NULL, c->node_name);
+               clkspec.np = node;
+               clk = of_clk_get_from_provider(&clkspec);
+
+               if (!IS_ERR(clk)) {
+                       c->lk.clk = clk;
+                       clkdev_add(&c->lk);
+               } else {
+                       pr_warn("failed to lookup clock node %s\n",
+                               c->node_name);
+               }
+       }
+}
+
+struct clk_init_item {
+       struct device_node *node;
+       struct clk_hw *hw;
+       ti_of_clk_init_cb_t func;
+       struct list_head link;
+};
+
+static LIST_HEAD(retry_list);
+
+/**
+ * ti_clk_retry_init - retries a failed clock init at later phase
+ * @node: device not for the clock
+ * @hw: partially initialized clk_hw struct for the clock
+ * @func: init function to be called for the clock
+ *
+ * Adds a failed clock init to the retry list. The retry list is parsed
+ * once all the other clocks have been initialized.
+ */
+int __init ti_clk_retry_init(struct device_node *node, struct clk_hw *hw,
+                             ti_of_clk_init_cb_t func)
+{
+       struct clk_init_item *retry;
+
+       pr_debug("%s: adding to retry list...\n", node->name);
+       retry = kzalloc(sizeof(*retry), GFP_KERNEL);
+       if (!retry)
+               return -ENOMEM;
+
+       retry->node = node;
+       retry->func = func;
+       retry->hw = hw;
+       list_add(&retry->link, &retry_list);
+
+       return 0;
+}
+
+/**
+ * ti_clk_get_reg_addr - get register address for a clock register
+ * @node: device node for the clock
+ * @index: register index from the clock node
+ *
+ * Builds clock register address from device tree information. This
+ * is a struct of type clk_omap_reg.
+ */
+void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index)
+{
+       struct clk_omap_reg *reg;
+       u32 val;
+       u32 tmp;
+
+       reg = (struct clk_omap_reg *)&tmp;
+       reg->index = ti_dt_clk_memmap_index;
+
+       if (of_property_read_u32_index(node, "reg", index, &val)) {
+               pr_err("%s must have reg[%d]!\n", node->name, index);
+               return NULL;
+       }
+
+       reg->offset = val;
+
+       return (void __iomem *)tmp;
+}
+
+/**
+ * ti_dt_clk_init_provider - init master clock provider
+ * @parent: master node
+ * @index: internal index for clk_reg_ops
+ *
+ * Initializes a master clock IP block and its child clock nodes.
+ * Regmap is provided for accessing the register space for the
+ * IP block and all the clocks under it.
+ */
+void ti_dt_clk_init_provider(struct device_node *parent, int index)
+{
+       const struct of_device_id *match;
+       struct device_node *np;
+       struct device_node *clocks;
+       of_clk_init_cb_t clk_init_cb;
+       struct clk_init_item *retry;
+       struct clk_init_item *tmp;
+
+       ti_dt_clk_memmap_index = index;
+
+       /* get clocks for this parent */
+       clocks = of_get_child_by_name(parent, "clocks");
+       if (!clocks) {
+               pr_err("%s missing 'clocks' child node.\n", parent->name);
+               return;
+       }
+
+       for_each_child_of_node(clocks, np) {
+               match = of_match_node(&__clk_of_table, np);
+               if (!match)
+                       continue;
+               clk_init_cb = (of_clk_init_cb_t)match->data;
+               pr_debug("%s: initializing: %s\n", __func__, np->name);
+               clk_init_cb(np);
+       }
+
+       list_for_each_entry_safe(retry, tmp, &retry_list, link) {
+               pr_debug("retry-init: %s\n", retry->node->name);
+               retry->func(retry->hw, retry->node);
+               list_del(&retry->link);
+               kfree(retry);
+       }
+}
diff --git a/drivers/clk/ti/clockdomain.c b/drivers/clk/ti/clockdomain.c
new file mode 100644 (file)
index 0000000..f1e0038
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * OMAP clockdomain support
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+static void __init of_ti_clockdomain_setup(struct device_node *node)
+{
+       struct clk *clk;
+       struct clk_hw *clk_hw;
+       const char *clkdm_name = node->name;
+       int i;
+       int num_clks;
+
+       num_clks = of_count_phandle_with_args(node, "clocks", "#clock-cells");
+
+       for (i = 0; i < num_clks; i++) {
+               clk = of_clk_get(node, i);
+               if (__clk_get_flags(clk) & CLK_IS_BASIC) {
+                       pr_warn("can't setup clkdm for basic clk %s\n",
+                               __clk_get_name(clk));
+                       continue;
+               }
+               clk_hw = __clk_get_hw(clk);
+               to_clk_hw_omap(clk_hw)->clkdm_name = clkdm_name;
+               omap2_init_clk_clkdm(clk_hw);
+       }
+}
+
+static struct of_device_id ti_clkdm_match_table[] __initdata = {
+       { .compatible = "ti,clockdomain" },
+       { }
+};
+
+/**
+ * ti_dt_clockdomains_setup - setup device tree clockdomains
+ *
+ * Initializes clockdomain nodes for a SoC. This parses through all the
+ * nodes with compatible = "ti,clockdomain", and add the clockdomain
+ * info for all the clocks listed under these. This function shall be
+ * called after rest of the DT clock init has completed and all
+ * clock nodes have been registered.
+ */
+void __init ti_dt_clockdomains_setup(void)
+{
+       struct device_node *np;
+       for_each_matching_node(np, ti_clkdm_match_table) {
+               of_ti_clockdomain_setup(np);
+       }
+}
diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c
new file mode 100644 (file)
index 0000000..19d8980
--- /dev/null
@@ -0,0 +1,269 @@
+/*
+ * TI composite clock support
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+#include <linux/list.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+
+static unsigned long ti_composite_recalc_rate(struct clk_hw *hw,
+                                             unsigned long parent_rate)
+{
+       return ti_clk_divider_ops.recalc_rate(hw, parent_rate);
+}
+
+static long ti_composite_round_rate(struct clk_hw *hw, unsigned long rate,
+                                   unsigned long *prate)
+{
+       return -EINVAL;
+}
+
+static int ti_composite_set_rate(struct clk_hw *hw, unsigned long rate,
+                                unsigned long parent_rate)
+{
+       return -EINVAL;
+}
+
+static const struct clk_ops ti_composite_divider_ops = {
+       .recalc_rate    = &ti_composite_recalc_rate,
+       .round_rate     = &ti_composite_round_rate,
+       .set_rate       = &ti_composite_set_rate,
+};
+
+static const struct clk_ops ti_composite_gate_ops = {
+       .enable         = &omap2_dflt_clk_enable,
+       .disable        = &omap2_dflt_clk_disable,
+       .is_enabled     = &omap2_dflt_clk_is_enabled,
+};
+
+struct component_clk {
+       int num_parents;
+       const char **parent_names;
+       struct device_node *node;
+       int type;
+       struct clk_hw *hw;
+       struct list_head link;
+};
+
+static const char * __initconst component_clk_types[] = {
+       "gate", "divider", "mux"
+};
+
+static LIST_HEAD(component_clks);
+
+static struct device_node *_get_component_node(struct device_node *node, int i)
+{
+       int rc;
+       struct of_phandle_args clkspec;
+
+       rc = of_parse_phandle_with_args(node, "clocks", "#clock-cells", i,
+                                       &clkspec);
+       if (rc)
+               return NULL;
+
+       return clkspec.np;
+}
+
+static struct component_clk *_lookup_component(struct device_node *node)
+{
+       struct component_clk *comp;
+
+       list_for_each_entry(comp, &component_clks, link) {
+               if (comp->node == node)
+                       return comp;
+       }
+       return NULL;
+}
+
+struct clk_hw_omap_comp {
+       struct clk_hw hw;
+       struct device_node *comp_nodes[CLK_COMPONENT_TYPE_MAX];
+       struct component_clk *comp_clks[CLK_COMPONENT_TYPE_MAX];
+};
+
+static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx)
+{
+       if (!clk)
+               return NULL;
+
+       if (!clk->comp_clks[idx])
+               return NULL;
+
+       return clk->comp_clks[idx]->hw;
+}
+
+#define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw)
+
+static void __init ti_clk_register_composite(struct clk_hw *hw,
+                                            struct device_node *node)
+{
+       struct clk *clk;
+       struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw);
+       struct component_clk *comp;
+       int num_parents = 0;
+       const char **parent_names = NULL;
+       int i;
+
+       /* Check for presence of each component clock */
+       for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {
+               if (!cclk->comp_nodes[i])
+                       continue;
+
+               comp = _lookup_component(cclk->comp_nodes[i]);
+               if (!comp) {
+                       pr_debug("component %s not ready for %s, retry\n",
+                                cclk->comp_nodes[i]->name, node->name);
+                       if (!ti_clk_retry_init(node, hw,
+                                              ti_clk_register_composite))
+                               return;
+
+                       goto cleanup;
+               }
+               if (cclk->comp_clks[comp->type] != NULL) {
+                       pr_err("duplicate component types for %s (%s)!\n",
+                              node->name, component_clk_types[comp->type]);
+                       goto cleanup;
+               }
+
+               cclk->comp_clks[comp->type] = comp;
+
+               /* Mark this node as found */
+               cclk->comp_nodes[i] = NULL;
+       }
+
+       /* All components exists, proceed with registration */
+       for (i = CLK_COMPONENT_TYPE_MAX - 1; i >= 0; i--) {
+               comp = cclk->comp_clks[i];
+               if (!comp)
+                       continue;
+               if (comp->num_parents) {
+                       num_parents = comp->num_parents;
+                       parent_names = comp->parent_names;
+                       break;
+               }
+       }
+
+       if (!num_parents) {
+               pr_err("%s: no parents found for %s!\n", __func__, node->name);
+               goto cleanup;
+       }
+
+       clk = clk_register_composite(NULL, node->name,
+                                    parent_names, num_parents,
+                                    _get_hw(cclk, CLK_COMPONENT_TYPE_MUX),
+                                    &ti_clk_mux_ops,
+                                    _get_hw(cclk, CLK_COMPONENT_TYPE_DIVIDER),
+                                    &ti_composite_divider_ops,
+                                    _get_hw(cclk, CLK_COMPONENT_TYPE_GATE),
+                                    &ti_composite_gate_ops, 0);
+
+       if (!IS_ERR(clk))
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+cleanup:
+       /* Free component clock list entries */
+       for (i = 0; i < CLK_COMPONENT_TYPE_MAX; i++) {
+               if (!cclk->comp_clks[i])
+                       continue;
+               list_del(&cclk->comp_clks[i]->link);
+               kfree(cclk->comp_clks[i]);
+       }
+
+       kfree(cclk);
+}
+
+static void __init of_ti_composite_clk_setup(struct device_node *node)
+{
+       int num_clks;
+       int i;
+       struct clk_hw_omap_comp *cclk;
+
+       /* Number of component clocks to be put inside this clock */
+       num_clks = of_clk_get_parent_count(node);
+
+       if (num_clks < 1) {
+               pr_err("composite clk %s must have component(s)\n", node->name);
+               return;
+       }
+
+       cclk = kzalloc(sizeof(*cclk), GFP_KERNEL);
+       if (!cclk)
+               return;
+
+       /* Get device node pointers for each component clock */
+       for (i = 0; i < num_clks; i++)
+               cclk->comp_nodes[i] = _get_component_node(node, i);
+
+       ti_clk_register_composite(&cclk->hw, node);
+}
+CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock",
+              of_ti_composite_clk_setup);
+
+/**
+ * ti_clk_add_component - add a component clock to the pool
+ * @node: device node of the component clock
+ * @hw: hardware clock definition for the component clock
+ * @type: type of the component clock
+ *
+ * Adds a component clock to the list of available components, so that
+ * it can be registered by a composite clock.
+ */
+int __init ti_clk_add_component(struct device_node *node, struct clk_hw *hw,
+                               int type)
+{
+       int num_parents;
+       const char **parent_names;
+       struct component_clk *clk;
+       int i;
+
+       num_parents = of_clk_get_parent_count(node);
+
+       if (num_parents < 1) {
+               pr_err("component-clock %s must have parent(s)\n", node->name);
+               return -EINVAL;
+       }
+
+       parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
+       if (!parent_names)
+               return -ENOMEM;
+
+       for (i = 0; i < num_parents; i++)
+               parent_names[i] = of_clk_get_parent_name(node, i);
+
+       clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+       if (!clk) {
+               kfree(parent_names);
+               return -ENOMEM;
+       }
+
+       clk->num_parents = num_parents;
+       clk->parent_names = parent_names;
+       clk->hw = hw;
+       clk->node = node;
+       clk->type = type;
+       list_add(&clk->link, &component_clks);
+
+       return 0;
+}
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
new file mode 100644 (file)
index 0000000..a15e445
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * TI Divider Clock
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+
+#define div_mask(d)    ((1 << ((d)->width)) - 1)
+
+static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
+{
+       unsigned int maxdiv = 0;
+       const struct clk_div_table *clkt;
+
+       for (clkt = table; clkt->div; clkt++)
+               if (clkt->div > maxdiv)
+                       maxdiv = clkt->div;
+       return maxdiv;
+}
+
+static unsigned int _get_maxdiv(struct clk_divider *divider)
+{
+       if (divider->flags & CLK_DIVIDER_ONE_BASED)
+               return div_mask(divider);
+       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+               return 1 << div_mask(divider);
+       if (divider->table)
+               return _get_table_maxdiv(divider->table);
+       return div_mask(divider) + 1;
+}
+
+static unsigned int _get_table_div(const struct clk_div_table *table,
+                                  unsigned int val)
+{
+       const struct clk_div_table *clkt;
+
+       for (clkt = table; clkt->div; clkt++)
+               if (clkt->val == val)
+                       return clkt->div;
+       return 0;
+}
+
+static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
+{
+       if (divider->flags & CLK_DIVIDER_ONE_BASED)
+               return val;
+       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+               return 1 << val;
+       if (divider->table)
+               return _get_table_div(divider->table, val);
+       return val + 1;
+}
+
+static unsigned int _get_table_val(const struct clk_div_table *table,
+                                  unsigned int div)
+{
+       const struct clk_div_table *clkt;
+
+       for (clkt = table; clkt->div; clkt++)
+               if (clkt->div == div)
+                       return clkt->val;
+       return 0;
+}
+
+static unsigned int _get_val(struct clk_divider *divider, u8 div)
+{
+       if (divider->flags & CLK_DIVIDER_ONE_BASED)
+               return div;
+       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+               return __ffs(div);
+       if (divider->table)
+               return  _get_table_val(divider->table, div);
+       return div - 1;
+}
+
+static unsigned long ti_clk_divider_recalc_rate(struct clk_hw *hw,
+                                               unsigned long parent_rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       unsigned int div, val;
+
+       val = ti_clk_ll_ops->clk_readl(divider->reg) >> divider->shift;
+       val &= div_mask(divider);
+
+       div = _get_div(divider, val);
+       if (!div) {
+               WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
+                    "%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
+                    __clk_get_name(hw->clk));
+               return parent_rate;
+       }
+
+       return parent_rate / div;
+}
+
+/*
+ * The reverse of DIV_ROUND_UP: The maximum number which
+ * divided by m is r
+ */
+#define MULT_ROUND_UP(r, m) ((r) * (m) + (m) - 1)
+
+static bool _is_valid_table_div(const struct clk_div_table *table,
+                               unsigned int div)
+{
+       const struct clk_div_table *clkt;
+
+       for (clkt = table; clkt->div; clkt++)
+               if (clkt->div == div)
+                       return true;
+       return false;
+}
+
+static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
+{
+       if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+               return is_power_of_2(div);
+       if (divider->table)
+               return _is_valid_table_div(divider->table, div);
+       return true;
+}
+
+static int ti_clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
+                                 unsigned long *best_parent_rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       int i, bestdiv = 0;
+       unsigned long parent_rate, best = 0, now, maxdiv;
+       unsigned long parent_rate_saved = *best_parent_rate;
+
+       if (!rate)
+               rate = 1;
+
+       maxdiv = _get_maxdiv(divider);
+
+       if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
+               parent_rate = *best_parent_rate;
+               bestdiv = DIV_ROUND_UP(parent_rate, rate);
+               bestdiv = bestdiv == 0 ? 1 : bestdiv;
+               bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
+               return bestdiv;
+       }
+
+       /*
+        * The maximum divider we can use without overflowing
+        * unsigned long in rate * i below
+        */
+       maxdiv = min(ULONG_MAX / rate, maxdiv);
+
+       for (i = 1; i <= maxdiv; i++) {
+               if (!_is_valid_div(divider, i))
+                       continue;
+               if (rate * i == parent_rate_saved) {
+                       /*
+                        * It's the most ideal case if the requested rate can be
+                        * divided from parent clock without needing to change
+                        * parent rate, so return the divider immediately.
+                        */
+                       *best_parent_rate = parent_rate_saved;
+                       return i;
+               }
+               parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
+                               MULT_ROUND_UP(rate, i));
+               now = parent_rate / i;
+               if (now <= rate && now > best) {
+                       bestdiv = i;
+                       best = now;
+                       *best_parent_rate = parent_rate;
+               }
+       }
+
+       if (!bestdiv) {
+               bestdiv = _get_maxdiv(divider);
+               *best_parent_rate =
+                       __clk_round_rate(__clk_get_parent(hw->clk), 1);
+       }
+
+       return bestdiv;
+}
+
+static long ti_clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+                                     unsigned long *prate)
+{
+       int div;
+       div = ti_clk_divider_bestdiv(hw, rate, prate);
+
+       return *prate / div;
+}
+
+static int ti_clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+                                  unsigned long parent_rate)
+{
+       struct clk_divider *divider = to_clk_divider(hw);
+       unsigned int div, value;
+       unsigned long flags = 0;
+       u32 val;
+
+       div = parent_rate / rate;
+       value = _get_val(divider, div);
+
+       if (value > div_mask(divider))
+               value = div_mask(divider);
+
+       if (divider->lock)
+               spin_lock_irqsave(divider->lock, flags);
+
+       if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
+               val = div_mask(divider) << (divider->shift + 16);
+       } else {
+               val = ti_clk_ll_ops->clk_readl(divider->reg);
+               val &= ~(div_mask(divider) << divider->shift);
+       }
+       val |= value << divider->shift;
+       ti_clk_ll_ops->clk_writel(val, divider->reg);
+
+       if (divider->lock)
+               spin_unlock_irqrestore(divider->lock, flags);
+
+       return 0;
+}
+
+const struct clk_ops ti_clk_divider_ops = {
+       .recalc_rate = ti_clk_divider_recalc_rate,
+       .round_rate = ti_clk_divider_round_rate,
+       .set_rate = ti_clk_divider_set_rate,
+};
+
+static struct clk *_register_divider(struct device *dev, const char *name,
+                                    const char *parent_name,
+                                    unsigned long flags, void __iomem *reg,
+                                    u8 shift, u8 width, u8 clk_divider_flags,
+                                    const struct clk_div_table *table,
+                                    spinlock_t *lock)
+{
+       struct clk_divider *div;
+       struct clk *clk;
+       struct clk_init_data init;
+
+       if (clk_divider_flags & CLK_DIVIDER_HIWORD_MASK) {
+               if (width + shift > 16) {
+                       pr_warn("divider value exceeds LOWORD field\n");
+                       return ERR_PTR(-EINVAL);
+               }
+       }
+
+       /* allocate the divider */
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+       if (!div) {
+               pr_err("%s: could not allocate divider clk\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       init.name = name;
+       init.ops = &ti_clk_divider_ops;
+       init.flags = flags | CLK_IS_BASIC;
+       init.parent_names = (parent_name ? &parent_name : NULL);
+       init.num_parents = (parent_name ? 1 : 0);
+
+       /* struct clk_divider assignments */
+       div->reg = reg;
+       div->shift = shift;
+       div->width = width;
+       div->flags = clk_divider_flags;
+       div->lock = lock;
+       div->hw.init = &init;
+       div->table = table;
+
+       /* register the clock */
+       clk = clk_register(dev, &div->hw);
+
+       if (IS_ERR(clk))
+               kfree(div);
+
+       return clk;
+}
+
+static struct clk_div_table
+__init *ti_clk_get_div_table(struct device_node *node)
+{
+       struct clk_div_table *table;
+       const __be32 *divspec;
+       u32 val;
+       u32 num_div;
+       u32 valid_div;
+       int i;
+
+       divspec = of_get_property(node, "ti,dividers", &num_div);
+
+       if (!divspec)
+               return NULL;
+
+       num_div /= 4;
+
+       valid_div = 0;
+
+       /* Determine required size for divider table */
+       for (i = 0; i < num_div; i++) {
+               of_property_read_u32_index(node, "ti,dividers", i, &val);
+               if (val)
+                       valid_div++;
+       }
+
+       if (!valid_div) {
+               pr_err("no valid dividers for %s table\n", node->name);
+               return ERR_PTR(-EINVAL);
+       }
+
+       table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL);
+
+       if (!table)
+               return ERR_PTR(-ENOMEM);
+
+       valid_div = 0;
+
+       for (i = 0; i < num_div; i++) {
+               of_property_read_u32_index(node, "ti,dividers", i, &val);
+               if (val) {
+                       table[valid_div].div = val;
+                       table[valid_div].val = i;
+                       valid_div++;
+               }
+       }
+
+       return table;
+}
+
+static int _get_divider_width(struct device_node *node,
+                             const struct clk_div_table *table,
+                             u8 flags)
+{
+       u32 min_div;
+       u32 max_div;
+       u32 val = 0;
+       u32 div;
+
+       if (!table) {
+               /* Clk divider table not provided, determine min/max divs */
+               if (of_property_read_u32(node, "ti,min-div", &min_div))
+                       min_div = 1;
+
+               if (of_property_read_u32(node, "ti,max-div", &max_div)) {
+                       pr_err("no max-div for %s!\n", node->name);
+                       return -EINVAL;
+               }
+
+               /* Determine bit width for the field */
+               if (flags & CLK_DIVIDER_ONE_BASED)
+                       val = 1;
+
+               div = min_div;
+
+               while (div < max_div) {
+                       if (flags & CLK_DIVIDER_POWER_OF_TWO)
+                               div <<= 1;
+                       else
+                               div++;
+                       val++;
+               }
+       } else {
+               div = 0;
+
+               while (table[div].div) {
+                       val = table[div].val;
+                       div++;
+               }
+       }
+
+       return fls(val);
+}
+
+static int __init ti_clk_divider_populate(struct device_node *node,
+       void __iomem **reg, const struct clk_div_table **table,
+       u32 *flags, u8 *div_flags, u8 *width, u8 *shift)
+{
+       u32 val;
+
+       *reg = ti_clk_get_reg_addr(node, 0);
+       if (!*reg)
+               return -EINVAL;
+
+       if (!of_property_read_u32(node, "ti,bit-shift", &val))
+               *shift = val;
+       else
+               *shift = 0;
+
+       *flags = 0;
+       *div_flags = 0;
+
+       if (of_property_read_bool(node, "ti,index-starts-at-one"))
+               *div_flags |= CLK_DIVIDER_ONE_BASED;
+
+       if (of_property_read_bool(node, "ti,index-power-of-two"))
+               *div_flags |= CLK_DIVIDER_POWER_OF_TWO;
+
+       if (of_property_read_bool(node, "ti,set-rate-parent"))
+               *flags |= CLK_SET_RATE_PARENT;
+
+       *table = ti_clk_get_div_table(node);
+
+       if (IS_ERR(*table))
+               return PTR_ERR(*table);
+
+       *width = _get_divider_width(node, *table, *div_flags);
+
+       return 0;
+}
+
+/**
+ * of_ti_divider_clk_setup - Setup function for simple div rate clock
+ * @node: device node for this clock
+ *
+ * Sets up a basic divider clock.
+ */
+static void __init of_ti_divider_clk_setup(struct device_node *node)
+{
+       struct clk *clk;
+       const char *parent_name;
+       void __iomem *reg;
+       u8 clk_divider_flags = 0;
+       u8 width = 0;
+       u8 shift = 0;
+       const struct clk_div_table *table = NULL;
+       u32 flags = 0;
+
+       parent_name = of_clk_get_parent_name(node, 0);
+
+       if (ti_clk_divider_populate(node, &reg, &table, &flags,
+                                   &clk_divider_flags, &width, &shift))
+               goto cleanup;
+
+       clk = _register_divider(NULL, node->name, parent_name, flags, reg,
+                               shift, width, clk_divider_flags, table, NULL);
+
+       if (!IS_ERR(clk)) {
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+               of_ti_clk_autoidle_setup(node);
+               return;
+       }
+
+cleanup:
+       kfree(table);
+}
+CLK_OF_DECLARE(divider_clk, "ti,divider-clock", of_ti_divider_clk_setup);
+
+static void __init of_ti_composite_divider_clk_setup(struct device_node *node)
+{
+       struct clk_divider *div;
+       u32 val;
+
+       div = kzalloc(sizeof(*div), GFP_KERNEL);
+       if (!div)
+               return;
+
+       if (ti_clk_divider_populate(node, &div->reg, &div->table, &val,
+                                   &div->flags, &div->width, &div->shift) < 0)
+               goto cleanup;
+
+       if (!ti_clk_add_component(node, &div->hw, CLK_COMPONENT_TYPE_DIVIDER))
+               return;
+
+cleanup:
+       kfree(div->table);
+       kfree(div);
+}
+CLK_OF_DECLARE(ti_composite_divider_clk, "ti,composite-divider-clock",
+              of_ti_composite_divider_clk_setup);
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
new file mode 100644 (file)
index 0000000..7e498a4
--- /dev/null
@@ -0,0 +1,558 @@
+/*
+ * OMAP DPLL clock support
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#define DPLL_HAS_AUTOIDLE      0x1
+
+#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
+       defined(CONFIG_SOC_DRA7XX)
+static const struct clk_ops dpll_m4xen_ck_ops = {
+       .enable         = &omap3_noncore_dpll_enable,
+       .disable        = &omap3_noncore_dpll_disable,
+       .recalc_rate    = &omap4_dpll_regm4xen_recalc,
+       .round_rate     = &omap4_dpll_regm4xen_round_rate,
+       .set_rate       = &omap3_noncore_dpll_set_rate,
+       .get_parent     = &omap2_init_dpll_parent,
+};
+#endif
+
+static const struct clk_ops dpll_core_ck_ops = {
+       .recalc_rate    = &omap3_dpll_recalc,
+       .get_parent     = &omap2_init_dpll_parent,
+};
+
+#ifdef CONFIG_ARCH_OMAP3
+static const struct clk_ops omap3_dpll_core_ck_ops = {
+       .get_parent     = &omap2_init_dpll_parent,
+       .recalc_rate    = &omap3_dpll_recalc,
+       .round_rate     = &omap2_dpll_round_rate,
+};
+#endif
+
+static const struct clk_ops dpll_ck_ops = {
+       .enable         = &omap3_noncore_dpll_enable,
+       .disable        = &omap3_noncore_dpll_disable,
+       .recalc_rate    = &omap3_dpll_recalc,
+       .round_rate     = &omap2_dpll_round_rate,
+       .set_rate       = &omap3_noncore_dpll_set_rate,
+       .get_parent     = &omap2_init_dpll_parent,
+};
+
+static const struct clk_ops dpll_no_gate_ck_ops = {
+       .recalc_rate    = &omap3_dpll_recalc,
+       .get_parent     = &omap2_init_dpll_parent,
+       .round_rate     = &omap2_dpll_round_rate,
+       .set_rate       = &omap3_noncore_dpll_set_rate,
+};
+
+#ifdef CONFIG_ARCH_OMAP3
+static const struct clk_ops omap3_dpll_ck_ops = {
+       .enable         = &omap3_noncore_dpll_enable,
+       .disable        = &omap3_noncore_dpll_disable,
+       .get_parent     = &omap2_init_dpll_parent,
+       .recalc_rate    = &omap3_dpll_recalc,
+       .set_rate       = &omap3_noncore_dpll_set_rate,
+       .round_rate     = &omap2_dpll_round_rate,
+};
+
+static const struct clk_ops omap3_dpll_per_ck_ops = {
+       .enable         = &omap3_noncore_dpll_enable,
+       .disable        = &omap3_noncore_dpll_disable,
+       .get_parent     = &omap2_init_dpll_parent,
+       .recalc_rate    = &omap3_dpll_recalc,
+       .set_rate       = &omap3_dpll4_set_rate,
+       .round_rate     = &omap2_dpll_round_rate,
+};
+#endif
+
+static const struct clk_ops dpll_x2_ck_ops = {
+       .recalc_rate    = &omap3_clkoutx2_recalc,
+};
+
+/**
+ * ti_clk_register_dpll - low level registration of a DPLL clock
+ * @hw: hardware clock definition for the clock
+ * @node: device node for the clock
+ *
+ * Finalizes DPLL registration process. In case a failure (clk-ref or
+ * clk-bypass is missing), the clock is added to retry list and
+ * the initialization is retried on later stage.
+ */
+static void __init ti_clk_register_dpll(struct clk_hw *hw,
+                                       struct device_node *node)
+{
+       struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw);
+       struct dpll_data *dd = clk_hw->dpll_data;
+       struct clk *clk;
+
+       dd->clk_ref = of_clk_get(node, 0);
+       dd->clk_bypass = of_clk_get(node, 1);
+
+       if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) {
+               pr_debug("clk-ref or clk-bypass missing for %s, retry later\n",
+                        node->name);
+               if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll))
+                       return;
+
+               goto cleanup;
+       }
+
+       /* register the clock */
+       clk = clk_register(NULL, &clk_hw->hw);
+
+       if (!IS_ERR(clk)) {
+               omap2_init_clk_hw_omap_clocks(clk);
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+               kfree(clk_hw->hw.init->parent_names);
+               kfree(clk_hw->hw.init);
+               return;
+       }
+
+cleanup:
+       kfree(clk_hw->dpll_data);
+       kfree(clk_hw->hw.init->parent_names);
+       kfree(clk_hw->hw.init);
+       kfree(clk_hw);
+}
+
+#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
+       defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX)
+/**
+ * ti_clk_register_dpll_x2 - Registers a DPLLx2 clock
+ * @node: device node for this clock
+ * @ops: clk_ops for this clock
+ * @hw_ops: clk_hw_ops for this clock
+ *
+ * Initializes a DPLL x 2 clock from device tree data.
+ */
+static void ti_clk_register_dpll_x2(struct device_node *node,
+                                   const struct clk_ops *ops,
+                                   const struct clk_hw_omap_ops *hw_ops)
+{
+       struct clk *clk;
+       struct clk_init_data init = { NULL };
+       struct clk_hw_omap *clk_hw;
+       const char *name = node->name;
+       const char *parent_name;
+
+       parent_name = of_clk_get_parent_name(node, 0);
+       if (!parent_name) {
+               pr_err("%s must have parent\n", node->name);
+               return;
+       }
+
+       clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+       if (!clk_hw)
+               return;
+
+       clk_hw->ops = hw_ops;
+       clk_hw->hw.init = &init;
+
+       init.name = name;
+       init.ops = ops;
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       /* register the clock */
+       clk = clk_register(NULL, &clk_hw->hw);
+
+       if (IS_ERR(clk)) {
+               kfree(clk_hw);
+       } else {
+               omap2_init_clk_hw_omap_clocks(clk);
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+       }
+}
+#endif
+
+/**
+ * of_ti_dpll_setup - Setup function for OMAP DPLL clocks
+ * @node: device node containing the DPLL info
+ * @ops: ops for the DPLL
+ * @ddt: DPLL data template to use
+ * @init_flags: flags for controlling init types
+ *
+ * Initializes a DPLL clock from device tree data.
+ */
+static void __init of_ti_dpll_setup(struct device_node *node,
+                                   const struct clk_ops *ops,
+                                   const struct dpll_data *ddt,
+                                   u8 init_flags)
+{
+       struct clk_hw_omap *clk_hw = NULL;
+       struct clk_init_data *init = NULL;
+       const char **parent_names = NULL;
+       struct dpll_data *dd = NULL;
+       int i;
+       u8 dpll_mode = 0;
+
+       dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+       clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+       init = kzalloc(sizeof(*init), GFP_KERNEL);
+       if (!dd || !clk_hw || !init)
+               goto cleanup;
+
+       memcpy(dd, ddt, sizeof(*dd));
+
+       clk_hw->dpll_data = dd;
+       clk_hw->ops = &clkhwops_omap3_dpll;
+       clk_hw->hw.init = init;
+       clk_hw->flags = MEMMAP_ADDRESSING;
+
+       init->name = node->name;
+       init->ops = ops;
+
+       init->num_parents = of_clk_get_parent_count(node);
+       if (init->num_parents < 1) {
+               pr_err("%s must have parent(s)\n", node->name);
+               goto cleanup;
+       }
+
+       parent_names = kzalloc(sizeof(char *) * init->num_parents, GFP_KERNEL);
+       if (!parent_names)
+               goto cleanup;
+
+       for (i = 0; i < init->num_parents; i++)
+               parent_names[i] = of_clk_get_parent_name(node, i);
+
+       init->parent_names = parent_names;
+
+       dd->control_reg = ti_clk_get_reg_addr(node, 0);
+       dd->idlest_reg = ti_clk_get_reg_addr(node, 1);
+       dd->mult_div1_reg = ti_clk_get_reg_addr(node, 2);
+
+       if (!dd->control_reg || !dd->idlest_reg || !dd->mult_div1_reg)
+               goto cleanup;
+
+       if (init_flags & DPLL_HAS_AUTOIDLE) {
+               dd->autoidle_reg = ti_clk_get_reg_addr(node, 3);
+               if (!dd->autoidle_reg)
+                       goto cleanup;
+       }
+
+       if (of_property_read_bool(node, "ti,low-power-stop"))
+               dpll_mode |= 1 << DPLL_LOW_POWER_STOP;
+
+       if (of_property_read_bool(node, "ti,low-power-bypass"))
+               dpll_mode |= 1 << DPLL_LOW_POWER_BYPASS;
+
+       if (of_property_read_bool(node, "ti,lock"))
+               dpll_mode |= 1 << DPLL_LOCKED;
+
+       if (dpll_mode)
+               dd->modes = dpll_mode;
+
+       ti_clk_register_dpll(&clk_hw->hw, node);
+       return;
+
+cleanup:
+       kfree(dd);
+       kfree(parent_names);
+       kfree(init);
+       kfree(clk_hw);
+}
+
+#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
+       defined(CONFIG_SOC_DRA7XX)
+static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node)
+{
+       ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx);
+}
+CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock",
+              of_ti_omap4_dpll_x2_setup);
+#endif
+
+#ifdef CONFIG_SOC_AM33XX
+static void __init of_ti_am3_dpll_x2_setup(struct device_node *node)
+{
+       ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
+}
+CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock",
+              of_ti_am3_dpll_x2_setup);
+#endif
+
+#ifdef CONFIG_ARCH_OMAP3
+static void __init of_ti_omap3_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .freqsel_mask = 0xf0,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &omap3_dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+}
+CLK_OF_DECLARE(ti_omap3_dpll_clock, "ti,omap3-dpll-clock",
+              of_ti_omap3_dpll_setup);
+
+static void __init of_ti_omap3_core_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 16,
+               .div1_mask = 0x7f << 8,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .freqsel_mask = 0xf0,
+       };
+
+       of_ti_dpll_setup(node, &omap3_dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+}
+CLK_OF_DECLARE(ti_omap3_core_dpll_clock, "ti,omap3-dpll-core-clock",
+              of_ti_omap3_core_dpll_setup);
+
+static void __init of_ti_omap3_per_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1 << 1,
+               .enable_mask = 0x7 << 16,
+               .autoidle_mask = 0x7 << 3,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .freqsel_mask = 0xf00000,
+               .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+}
+CLK_OF_DECLARE(ti_omap3_per_dpll_clock, "ti,omap3-dpll-per-clock",
+              of_ti_omap3_per_dpll_setup);
+
+static void __init of_ti_omap3_per_jtype_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1 << 1,
+               .enable_mask = 0x7 << 16,
+               .autoidle_mask = 0x7 << 3,
+               .mult_mask = 0xfff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 4095,
+               .max_divider = 128,
+               .min_divider = 1,
+               .sddiv_mask = 0xff << 24,
+               .dco_mask = 0xe << 20,
+               .flags = DPLL_J_TYPE,
+               .modes = (1 << DPLL_LOW_POWER_STOP) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &omap3_dpll_per_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+}
+CLK_OF_DECLARE(ti_omap3_per_jtype_dpll_clock, "ti,omap3-dpll-per-j-type-clock",
+              of_ti_omap3_per_jtype_dpll_setup);
+#endif
+
+static void __init of_ti_omap4_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &dpll_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+}
+CLK_OF_DECLARE(ti_omap4_dpll_clock, "ti,omap4-dpll-clock",
+              of_ti_omap4_dpll_setup);
+
+static void __init of_ti_omap4_core_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+}
+CLK_OF_DECLARE(ti_omap4_core_dpll_clock, "ti,omap4-dpll-core-clock",
+              of_ti_omap4_core_dpll_setup);
+
+#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
+       defined(CONFIG_SOC_DRA7XX)
+static void __init of_ti_omap4_m4xen_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .m4xen_mask = 0x800,
+               .lpmode_mask = 1 << 10,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+}
+CLK_OF_DECLARE(ti_omap4_m4xen_dpll_clock, "ti,omap4-dpll-m4xen-clock",
+              of_ti_omap4_m4xen_dpll_setup);
+
+static void __init of_ti_omap4_jtype_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0xfff << 8,
+               .div1_mask = 0xff,
+               .max_multiplier = 4095,
+               .max_divider = 256,
+               .min_divider = 1,
+               .sddiv_mask = 0xff << 24,
+               .flags = DPLL_J_TYPE,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &dpll_m4xen_ck_ops, &dd, DPLL_HAS_AUTOIDLE);
+}
+CLK_OF_DECLARE(ti_omap4_jtype_dpll_clock, "ti,omap4-dpll-j-type-clock",
+              of_ti_omap4_jtype_dpll_setup);
+#endif
+
+static void __init of_ti_am3_no_gate_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0);
+}
+CLK_OF_DECLARE(ti_am3_no_gate_dpll_clock, "ti,am3-dpll-no-gate-clock",
+              of_ti_am3_no_gate_dpll_setup);
+
+static void __init of_ti_am3_jtype_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 4095,
+               .max_divider = 256,
+               .min_divider = 2,
+               .flags = DPLL_J_TYPE,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0);
+}
+CLK_OF_DECLARE(ti_am3_jtype_dpll_clock, "ti,am3-dpll-j-type-clock",
+              of_ti_am3_jtype_dpll_setup);
+
+static void __init of_ti_am3_no_gate_jtype_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .flags = DPLL_J_TYPE,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &dpll_no_gate_ck_ops, &dd, 0);
+}
+CLK_OF_DECLARE(ti_am3_no_gate_jtype_dpll_clock,
+              "ti,am3-dpll-no-gate-j-type-clock",
+              of_ti_am3_no_gate_jtype_dpll_setup);
+
+static void __init of_ti_am3_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &dpll_ck_ops, &dd, 0);
+}
+CLK_OF_DECLARE(ti_am3_dpll_clock, "ti,am3-dpll-clock", of_ti_am3_dpll_setup);
+
+static void __init of_ti_am3_core_dpll_setup(struct device_node *node)
+{
+       const struct dpll_data dd = {
+               .idlest_mask = 0x1,
+               .enable_mask = 0x7,
+               .autoidle_mask = 0x7,
+               .mult_mask = 0x7ff << 8,
+               .div1_mask = 0x7f,
+               .max_multiplier = 2047,
+               .max_divider = 128,
+               .min_divider = 1,
+               .modes = (1 << DPLL_LOW_POWER_BYPASS) | (1 << DPLL_LOCKED),
+       };
+
+       of_ti_dpll_setup(node, &dpll_core_ck_ops, &dd, 0);
+}
+CLK_OF_DECLARE(ti_am3_core_dpll_clock, "ti,am3-dpll-core-clock",
+              of_ti_am3_core_dpll_setup);
diff --git a/drivers/clk/ti/fixed-factor.c b/drivers/clk/ti/fixed-factor.c
new file mode 100644 (file)
index 0000000..c2c8a28
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * TI Fixed Factor Clock
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+/**
+ * of_ti_fixed_factor_clk_setup - Setup function for TI fixed factor clock
+ * @node: device node for this clock
+ *
+ * Sets up a simple fixed factor clock based on device tree info.
+ */
+static void __init of_ti_fixed_factor_clk_setup(struct device_node *node)
+{
+       struct clk *clk;
+       const char *clk_name = node->name;
+       const char *parent_name;
+       u32 div, mult;
+       u32 flags = 0;
+
+       if (of_property_read_u32(node, "ti,clock-div", &div)) {
+               pr_err("%s must have a clock-div property\n", node->name);
+               return;
+       }
+
+       if (of_property_read_u32(node, "ti,clock-mult", &mult)) {
+               pr_err("%s must have a clock-mult property\n", node->name);
+               return;
+       }
+
+       if (of_property_read_bool(node, "ti,set-rate-parent"))
+               flags |= CLK_SET_RATE_PARENT;
+
+       parent_name = of_clk_get_parent_name(node, 0);
+
+       clk = clk_register_fixed_factor(NULL, clk_name, parent_name, flags,
+                                       mult, div);
+
+       if (!IS_ERR(clk)) {
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+               of_ti_clk_autoidle_setup(node);
+       }
+}
+CLK_OF_DECLARE(ti_fixed_factor_clk, "ti,fixed-factor-clock",
+              of_ti_fixed_factor_clk_setup);
diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c
new file mode 100644 (file)
index 0000000..3e2999d
--- /dev/null
@@ -0,0 +1,249 @@
+/*
+ * OMAP gate clock support
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+
+#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk);
+
+static const struct clk_ops omap_gate_clkdm_clk_ops = {
+       .init           = &omap2_init_clk_clkdm,
+       .enable         = &omap2_clkops_enable_clkdm,
+       .disable        = &omap2_clkops_disable_clkdm,
+};
+
+static const struct clk_ops omap_gate_clk_ops = {
+       .init           = &omap2_init_clk_clkdm,
+       .enable         = &omap2_dflt_clk_enable,
+       .disable        = &omap2_dflt_clk_disable,
+       .is_enabled     = &omap2_dflt_clk_is_enabled,
+};
+
+static const struct clk_ops omap_gate_clk_hsdiv_restore_ops = {
+       .init           = &omap2_init_clk_clkdm,
+       .enable         = &omap36xx_gate_clk_enable_with_hsdiv_restore,
+       .disable        = &omap2_dflt_clk_disable,
+       .is_enabled     = &omap2_dflt_clk_is_enabled,
+};
+
+/**
+ * omap36xx_gate_clk_enable_with_hsdiv_restore - enable clocks suffering
+ *         from HSDivider PWRDN problem Implements Errata ID: i556.
+ * @clk: DPLL output struct clk
+ *
+ * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck,
+ * dpll4_m5_ck & dpll4_m6_ck dividers gets loaded with reset
+ * valueafter their respective PWRDN bits are set.  Any dummy write
+ * (Any other value different from the Read value) to the
+ * corresponding CM_CLKSEL register will refresh the dividers.
+ */
+static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
+{
+       struct clk_divider *parent;
+       struct clk_hw *parent_hw;
+       u32 dummy_v, orig_v;
+       int ret;
+
+       /* Clear PWRDN bit of HSDIVIDER */
+       ret = omap2_dflt_clk_enable(clk);
+
+       /* Parent is the x2 node, get parent of parent for the m2 div */
+       parent_hw = __clk_get_hw(__clk_get_parent(__clk_get_parent(clk->clk)));
+       parent = to_clk_divider(parent_hw);
+
+       /* Restore the dividers */
+       if (!ret) {
+               orig_v = ti_clk_ll_ops->clk_readl(parent->reg);
+               dummy_v = orig_v;
+
+               /* Write any other value different from the Read value */
+               dummy_v ^= (1 << parent->shift);
+               ti_clk_ll_ops->clk_writel(dummy_v, parent->reg);
+
+               /* Write the original divider */
+               ti_clk_ll_ops->clk_writel(orig_v, parent->reg);
+       }
+
+       return ret;
+}
+
+static void __init _of_ti_gate_clk_setup(struct device_node *node,
+                                        const struct clk_ops *ops,
+                                        const struct clk_hw_omap_ops *hw_ops)
+{
+       struct clk *clk;
+       struct clk_init_data init = { NULL };
+       struct clk_hw_omap *clk_hw;
+       const char *clk_name = node->name;
+       const char *parent_name;
+       u32 val;
+
+       clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+       if (!clk_hw)
+               return;
+
+       clk_hw->hw.init = &init;
+
+       init.name = clk_name;
+       init.ops = ops;
+
+       if (ops != &omap_gate_clkdm_clk_ops) {
+               clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
+               if (!clk_hw->enable_reg)
+                       goto cleanup;
+
+               if (!of_property_read_u32(node, "ti,bit-shift", &val))
+                       clk_hw->enable_bit = val;
+       }
+
+       clk_hw->ops = hw_ops;
+
+       clk_hw->flags = MEMMAP_ADDRESSING;
+
+       if (of_clk_get_parent_count(node) != 1) {
+               pr_err("%s must have 1 parent\n", clk_name);
+               goto cleanup;
+       }
+
+       parent_name = of_clk_get_parent_name(node, 0);
+       init.parent_names = &parent_name;
+       init.num_parents = 1;
+
+       if (of_property_read_bool(node, "ti,set-rate-parent"))
+               init.flags |= CLK_SET_RATE_PARENT;
+
+       if (of_property_read_bool(node, "ti,set-bit-to-disable"))
+               clk_hw->flags |= INVERT_ENABLE;
+
+       clk = clk_register(NULL, &clk_hw->hw);
+
+       if (!IS_ERR(clk)) {
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+               return;
+       }
+
+cleanup:
+       kfree(clk_hw);
+}
+
+static void __init
+_of_ti_composite_gate_clk_setup(struct device_node *node,
+                               const struct clk_hw_omap_ops *hw_ops)
+{
+       struct clk_hw_omap *gate;
+       u32 val = 0;
+
+       gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+       if (!gate)
+               return;
+
+       gate->enable_reg = ti_clk_get_reg_addr(node, 0);
+       if (!gate->enable_reg)
+               goto cleanup;
+
+       of_property_read_u32(node, "ti,bit-shift", &val);
+
+       gate->enable_bit = val;
+       gate->ops = hw_ops;
+       gate->flags = MEMMAP_ADDRESSING;
+
+       if (!ti_clk_add_component(node, &gate->hw, CLK_COMPONENT_TYPE_GATE))
+               return;
+
+cleanup:
+       kfree(gate);
+}
+
+static void __init
+of_ti_composite_no_wait_gate_clk_setup(struct device_node *node)
+{
+       _of_ti_composite_gate_clk_setup(node, NULL);
+}
+CLK_OF_DECLARE(ti_composite_no_wait_gate_clk, "ti,composite-no-wait-gate-clock",
+              of_ti_composite_no_wait_gate_clk_setup);
+
+#ifdef CONFIG_ARCH_OMAP3
+static void __init of_ti_composite_interface_clk_setup(struct device_node *node)
+{
+       _of_ti_composite_gate_clk_setup(node, &clkhwops_iclk_wait);
+}
+CLK_OF_DECLARE(ti_composite_interface_clk, "ti,composite-interface-clock",
+              of_ti_composite_interface_clk_setup);
+#endif
+
+static void __init of_ti_composite_gate_clk_setup(struct device_node *node)
+{
+       _of_ti_composite_gate_clk_setup(node, &clkhwops_wait);
+}
+CLK_OF_DECLARE(ti_composite_gate_clk, "ti,composite-gate-clock",
+              of_ti_composite_gate_clk_setup);
+
+
+static void __init of_ti_clkdm_gate_clk_setup(struct device_node *node)
+{
+       _of_ti_gate_clk_setup(node, &omap_gate_clkdm_clk_ops, NULL);
+}
+CLK_OF_DECLARE(ti_clkdm_gate_clk, "ti,clkdm-gate-clock",
+              of_ti_clkdm_gate_clk_setup);
+
+static void __init of_ti_hsdiv_gate_clk_setup(struct device_node *node)
+{
+       _of_ti_gate_clk_setup(node, &omap_gate_clk_hsdiv_restore_ops,
+                             &clkhwops_wait);
+}
+CLK_OF_DECLARE(ti_hsdiv_gate_clk, "ti,hsdiv-gate-clock",
+              of_ti_hsdiv_gate_clk_setup);
+
+static void __init of_ti_gate_clk_setup(struct device_node *node)
+{
+       _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, NULL);
+}
+CLK_OF_DECLARE(ti_gate_clk, "ti,gate-clock", of_ti_gate_clk_setup)
+
+static void __init of_ti_wait_gate_clk_setup(struct device_node *node)
+{
+       _of_ti_gate_clk_setup(node, &omap_gate_clk_ops, &clkhwops_wait);
+}
+CLK_OF_DECLARE(ti_wait_gate_clk, "ti,wait-gate-clock",
+              of_ti_wait_gate_clk_setup);
+
+#ifdef CONFIG_ARCH_OMAP3
+static void __init of_ti_am35xx_gate_clk_setup(struct device_node *node)
+{
+       _of_ti_gate_clk_setup(node, &omap_gate_clk_ops,
+                             &clkhwops_am35xx_ipss_module_wait);
+}
+CLK_OF_DECLARE(ti_am35xx_gate_clk, "ti,am35xx-gate-clock",
+              of_ti_am35xx_gate_clk_setup);
+
+static void __init of_ti_dss_gate_clk_setup(struct device_node *node)
+{
+       _of_ti_gate_clk_setup(node, &omap_gate_clk_ops,
+                             &clkhwops_omap3430es2_dss_usbhost_wait);
+}
+CLK_OF_DECLARE(ti_dss_gate_clk, "ti,dss-gate-clock",
+              of_ti_dss_gate_clk_setup);
+#endif
diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c
new file mode 100644 (file)
index 0000000..320a2b1
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * OMAP interface clock support
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+static const struct clk_ops ti_interface_clk_ops = {
+       .init           = &omap2_init_clk_clkdm,
+       .enable         = &omap2_dflt_clk_enable,
+       .disable        = &omap2_dflt_clk_disable,
+       .is_enabled     = &omap2_dflt_clk_is_enabled,
+};
+
+static void __init _of_ti_interface_clk_setup(struct device_node *node,
+                                             const struct clk_hw_omap_ops *ops)
+{
+       struct clk *clk;
+       struct clk_init_data init = { NULL };
+       struct clk_hw_omap *clk_hw;
+       const char *parent_name;
+       u32 val;
+
+       clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+       if (!clk_hw)
+               return;
+
+       clk_hw->hw.init = &init;
+       clk_hw->ops = ops;
+       clk_hw->flags = MEMMAP_ADDRESSING;
+
+       clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
+       if (!clk_hw->enable_reg)
+               goto cleanup;
+
+       if (!of_property_read_u32(node, "ti,bit-shift", &val))
+               clk_hw->enable_bit = val;
+
+       init.name = node->name;
+       init.ops = &ti_interface_clk_ops;
+       init.flags = 0;
+
+       parent_name = of_clk_get_parent_name(node, 0);
+       if (!parent_name) {
+               pr_err("%s must have a parent\n", node->name);
+               goto cleanup;
+       }
+
+       init.num_parents = 1;
+       init.parent_names = &parent_name;
+
+       clk = clk_register(NULL, &clk_hw->hw);
+
+       if (!IS_ERR(clk)) {
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+               omap2_init_clk_hw_omap_clocks(clk);
+               return;
+       }
+
+cleanup:
+       kfree(clk_hw);
+}
+
+static void __init of_ti_interface_clk_setup(struct device_node *node)
+{
+       _of_ti_interface_clk_setup(node, &clkhwops_iclk_wait);
+}
+CLK_OF_DECLARE(ti_interface_clk, "ti,omap3-interface-clock",
+              of_ti_interface_clk_setup);
+
+static void __init of_ti_no_wait_interface_clk_setup(struct device_node *node)
+{
+       _of_ti_interface_clk_setup(node, &clkhwops_iclk);
+}
+CLK_OF_DECLARE(ti_no_wait_interface_clk, "ti,omap3-no-wait-interface-clock",
+              of_ti_no_wait_interface_clk_setup);
+
+static void __init of_ti_hsotgusb_interface_clk_setup(struct device_node *node)
+{
+       _of_ti_interface_clk_setup(node,
+                                  &clkhwops_omap3430es2_iclk_hsotgusb_wait);
+}
+CLK_OF_DECLARE(ti_hsotgusb_interface_clk, "ti,omap3-hsotgusb-interface-clock",
+              of_ti_hsotgusb_interface_clk_setup);
+
+static void __init of_ti_dss_interface_clk_setup(struct device_node *node)
+{
+       _of_ti_interface_clk_setup(node,
+                                  &clkhwops_omap3430es2_iclk_dss_usbhost_wait);
+}
+CLK_OF_DECLARE(ti_dss_interface_clk, "ti,omap3-dss-interface-clock",
+              of_ti_dss_interface_clk_setup);
+
+static void __init of_ti_ssi_interface_clk_setup(struct device_node *node)
+{
+       _of_ti_interface_clk_setup(node, &clkhwops_omap3430es2_iclk_ssi_wait);
+}
+CLK_OF_DECLARE(ti_ssi_interface_clk, "ti,omap3-ssi-interface-clock",
+              of_ti_ssi_interface_clk_setup);
+
+static void __init of_ti_am35xx_interface_clk_setup(struct device_node *node)
+{
+       _of_ti_interface_clk_setup(node, &clkhwops_am35xx_ipss_wait);
+}
+CLK_OF_DECLARE(ti_am35xx_interface_clk, "ti,am35xx-interface-clock",
+              of_ti_am35xx_interface_clk_setup);
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
new file mode 100644 (file)
index 0000000..0197a47
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * TI Multiplexer Clock
+ *
+ * Copyright (C) 2013 Texas Instruments, Inc.
+ *
+ * Tero Kristo <t-kristo@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+
+#undef pr_fmt
+#define pr_fmt(fmt) "%s: " fmt, __func__
+
+#define to_clk_mux(_hw) container_of(_hw, struct clk_mux, hw)
+
+static u8 ti_clk_mux_get_parent(struct clk_hw *hw)
+{
+       struct clk_mux *mux = to_clk_mux(hw);
+       int num_parents = __clk_get_num_parents(hw->clk);
+       u32 val;
+
+       /*
+        * FIXME need a mux-specific flag to determine if val is bitwise or
+        * numeric. e.g. sys_clkin_ck's clksel field is 3 bits wide, but ranges
+        * from 0x1 to 0x7 (index starts at one)
+        * OTOH, pmd_trace_clk_mux_ck uses a separate bit for each clock, so
+        * val = 0x4 really means "bit 2, index starts at bit 0"
+        */
+       val = ti_clk_ll_ops->clk_readl(mux->reg) >> mux->shift;
+       val &= mux->mask;
+
+       if (mux->table) {
+               int i;
+
+               for (i = 0; i < num_parents; i++)
+                       if (mux->table[i] == val)
+                               return i;
+               return -EINVAL;
+       }
+
+       if (val && (mux->flags & CLK_MUX_INDEX_BIT))
+               val = ffs(val) - 1;
+
+       if (val && (mux->flags & CLK_MUX_INDEX_ONE))
+               val--;
+
+       if (val >= num_parents)
+               return -EINVAL;
+
+       return val;
+}
+
+static int ti_clk_mux_set_parent(struct clk_hw *hw, u8 index)
+{
+       struct clk_mux *mux = to_clk_mux(hw);
+       u32 val;
+       unsigned long flags = 0;
+
+       if (mux->table) {
+               index = mux->table[index];
+       } else {
+               if (mux->flags & CLK_MUX_INDEX_BIT)
+                       index = (1 << ffs(index));
+
+               if (mux->flags & CLK_MUX_INDEX_ONE)
+                       index++;
+       }
+
+       if (mux->lock)
+               spin_lock_irqsave(mux->lock, flags);
+
+       if (mux->flags & CLK_MUX_HIWORD_MASK) {
+               val = mux->mask << (mux->shift + 16);
+       } else {
+               val = ti_clk_ll_ops->clk_readl(mux->reg);
+               val &= ~(mux->mask << mux->shift);
+       }
+       val |= index << mux->shift;
+       ti_clk_ll_ops->clk_writel(val, mux->reg);
+
+       if (mux->lock)
+               spin_unlock_irqrestore(mux->lock, flags);
+
+       return 0;
+}
+
+const struct clk_ops ti_clk_mux_ops = {
+       .get_parent = ti_clk_mux_get_parent,
+       .set_parent = ti_clk_mux_set_parent,
+       .determine_rate = __clk_mux_determine_rate,
+};
+
+static struct clk *_register_mux(struct device *dev, const char *name,
+                                const char **parent_names, u8 num_parents,
+                                unsigned long flags, void __iomem *reg,
+                                u8 shift, u32 mask, u8 clk_mux_flags,
+                                u32 *table, spinlock_t *lock)
+{
+       struct clk_mux *mux;
+       struct clk *clk;
+       struct clk_init_data init;
+
+       /* allocate the mux */
+       mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+       if (!mux) {
+               pr_err("%s: could not allocate mux clk\n", __func__);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       init.name = name;
+       init.ops = &ti_clk_mux_ops;
+       init.flags = flags | CLK_IS_BASIC;
+       init.parent_names = parent_names;
+       init.num_parents = num_parents;
+
+       /* struct clk_mux assignments */
+       mux->reg = reg;
+       mux->shift = shift;
+       mux->mask = mask;
+       mux->flags = clk_mux_flags;
+       mux->lock = lock;
+       mux->table = table;
+       mux->hw.init = &init;
+
+       clk = clk_register(dev, &mux->hw);
+
+       if (IS_ERR(clk))
+               kfree(mux);
+
+       return clk;
+}
+
+/**
+ * of_mux_clk_setup - Setup function for simple mux rate clock
+ * @node: DT node for the clock
+ *
+ * Sets up a basic clock multiplexer.
+ */
+static void of_mux_clk_setup(struct device_node *node)
+{
+       struct clk *clk;
+       void __iomem *reg;
+       int num_parents;
+       const char **parent_names;
+       int i;
+       u8 clk_mux_flags = 0;
+       u32 mask = 0;
+       u32 shift = 0;
+       u32 flags = 0;
+
+       num_parents = of_clk_get_parent_count(node);
+       if (num_parents < 2) {
+               pr_err("mux-clock %s must have parents\n", node->name);
+               return;
+       }
+       parent_names = kzalloc((sizeof(char *) * num_parents), GFP_KERNEL);
+       if (!parent_names)
+               goto cleanup;
+
+       for (i = 0; i < num_parents; i++)
+               parent_names[i] = of_clk_get_parent_name(node, i);
+
+       reg = ti_clk_get_reg_addr(node, 0);
+
+       if (!reg)
+               goto cleanup;
+
+       of_property_read_u32(node, "ti,bit-shift", &shift);
+
+       if (of_property_read_bool(node, "ti,index-starts-at-one"))
+               clk_mux_flags |= CLK_MUX_INDEX_ONE;
+
+       if (of_property_read_bool(node, "ti,set-rate-parent"))
+               flags |= CLK_SET_RATE_PARENT;
+
+       /* Generate bit-mask based on parent info */
+       mask = num_parents;
+       if (!(clk_mux_flags & CLK_MUX_INDEX_ONE))
+               mask--;
+
+       mask = (1 << fls(mask)) - 1;
+
+       clk = _register_mux(NULL, node->name, parent_names, num_parents, flags,
+                           reg, shift, mask, clk_mux_flags, NULL, NULL);
+
+       if (!IS_ERR(clk))
+               of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+cleanup:
+       kfree(parent_names);
+}
+CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
+
+static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
+{
+       struct clk_mux *mux;
+       int num_parents;
+       u32 val;
+
+       mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+       if (!mux)
+               return;
+
+       mux->reg = ti_clk_get_reg_addr(node, 0);
+
+       if (!mux->reg)
+               goto cleanup;
+
+       if (!of_property_read_u32(node, "ti,bit-shift", &val))
+               mux->shift = val;
+
+       if (of_property_read_bool(node, "ti,index-starts-at-one"))
+               mux->flags |= CLK_MUX_INDEX_ONE;
+
+       num_parents = of_clk_get_parent_count(node);
+
+       if (num_parents < 2) {
+               pr_err("%s must have parents\n", node->name);
+               goto cleanup;
+       }
+
+       mux->mask = num_parents - 1;
+       mux->mask = (1 << fls(mux->mask)) - 1;
+
+       if (!ti_clk_add_component(node, &mux->hw, CLK_COMPONENT_TYPE_MUX))
+               return;
+
+cleanup:
+       kfree(mux);
+}
+CLK_OF_DECLARE(ti_composite_mux_clk_setup, "ti,composite-mux-clock",
+              of_ti_composite_mux_clk_setup);
index 79e5608e71b58742fe8342b0be1b163a60eace70..18448a7e9f8654e1560d2ec7eb354dd85ba094f4 100644 (file)
@@ -919,7 +919,7 @@ static void __init acpi_cpufreq_boost_init(void)
        }
 }
 
-static void __exit acpi_cpufreq_boost_exit(void)
+static void acpi_cpufreq_boost_exit(void)
 {
        if (msrs) {
                unregister_cpu_notifier(&boost_nb);
@@ -969,9 +969,10 @@ static int __init acpi_cpufreq_init(void)
        acpi_cpufreq_boost_init();
 
        ret = cpufreq_register_driver(&acpi_cpufreq_driver);
-       if (ret)
+       if (ret) {
                free_acpi_perf_data();
-
+               acpi_cpufreq_boost_exit();
+       }
        return ret;
 }
 
index b3fb81d7cf0410bb9358d94a4e345899323f1ef3..f04e25f6c98d5f024758fc63ea2167a06d82ae17 100644 (file)
@@ -35,6 +35,11 @@ depends on ARM
 source "drivers/cpuidle/Kconfig.arm"
 endmenu
 
+menu "POWERPC CPU Idle Drivers"
+depends on PPC
+source "drivers/cpuidle/Kconfig.powerpc"
+endmenu
+
 endif
 
 config ARCH_NEEDS_CPU_IDLE_COUPLED
diff --git a/drivers/cpuidle/Kconfig.powerpc b/drivers/cpuidle/Kconfig.powerpc
new file mode 100644 (file)
index 0000000..66c3a09
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# POWERPC CPU Idle Drivers
+#
+config PSERIES_CPUIDLE
+       bool "Cpuidle driver for pSeries platforms"
+       depends on CPU_IDLE
+       depends on PPC_PSERIES
+       default y
+       help
+         Select this option to enable processor idle state management
+         through cpuidle subsystem.
+
+config POWERNV_CPUIDLE
+       bool "Cpuidle driver for powernv platforms"
+       depends on CPU_IDLE
+       depends on PPC_POWERNV
+       default y
+       help
+         Select this option to enable processor idle state management
+         through cpuidle subsystem.
index 527be28e5c1e4e785032a83027899fdf47103b21..f71ae1b373c5e85fc1075622e144832b5d7a0d1e 100644 (file)
@@ -13,3 +13,8 @@ obj-$(CONFIG_ARM_KIRKWOOD_CPUIDLE)    += cpuidle-kirkwood.o
 obj-$(CONFIG_ARM_ZYNQ_CPUIDLE)         += cpuidle-zynq.o
 obj-$(CONFIG_ARM_U8500_CPUIDLE)         += cpuidle-ux500.o
 obj-$(CONFIG_ARM_AT91_CPUIDLE)          += cpuidle-at91.o
+
+###############################################################################
+# POWERPC drivers
+obj-$(CONFIG_PSERIES_CPUIDLE)          += cpuidle-pseries.o
+obj-$(CONFIG_POWERNV_CPUIDLE)          += cpuidle-powernv.o
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
new file mode 100644 (file)
index 0000000..78fd174
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ *  cpuidle-powernv - idle state cpuidle driver.
+ *  Adapted from drivers/cpuidle/cpuidle-pseries
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/moduleparam.h>
+#include <linux/cpuidle.h>
+#include <linux/cpu.h>
+#include <linux/notifier.h>
+
+#include <asm/machdep.h>
+#include <asm/firmware.h>
+
+struct cpuidle_driver powernv_idle_driver = {
+       .name             = "powernv_idle",
+       .owner            = THIS_MODULE,
+};
+
+static int max_idle_state;
+static struct cpuidle_state *cpuidle_state_table;
+
+static int snooze_loop(struct cpuidle_device *dev,
+                       struct cpuidle_driver *drv,
+                       int index)
+{
+       local_irq_enable();
+       set_thread_flag(TIF_POLLING_NRFLAG);
+
+       while (!need_resched()) {
+               HMT_low();
+               HMT_very_low();
+       }
+
+       HMT_medium();
+       clear_thread_flag(TIF_POLLING_NRFLAG);
+       smp_mb();
+       return index;
+}
+
+static int nap_loop(struct cpuidle_device *dev,
+                       struct cpuidle_driver *drv,
+                       int index)
+{
+       power7_idle();
+       return index;
+}
+
+/*
+ * States for dedicated partition case.
+ */
+static struct cpuidle_state powernv_states[] = {
+       { /* Snooze */
+               .name = "snooze",
+               .desc = "snooze",
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 0,
+               .target_residency = 0,
+               .enter = &snooze_loop },
+       { /* NAP */
+               .name = "NAP",
+               .desc = "NAP",
+               .flags = CPUIDLE_FLAG_TIME_VALID,
+               .exit_latency = 10,
+               .target_residency = 100,
+               .enter = &nap_loop },
+};
+
+static int powernv_cpuidle_add_cpu_notifier(struct notifier_block *n,
+                       unsigned long action, void *hcpu)
+{
+       int hotcpu = (unsigned long)hcpu;
+       struct cpuidle_device *dev =
+                               per_cpu(cpuidle_devices, hotcpu);
+
+       if (dev && cpuidle_get_driver()) {
+               switch (action) {
+               case CPU_ONLINE:
+               case CPU_ONLINE_FROZEN:
+                       cpuidle_pause_and_lock();
+                       cpuidle_enable_device(dev);
+                       cpuidle_resume_and_unlock();
+                       break;
+
+               case CPU_DEAD:
+               case CPU_DEAD_FROZEN:
+                       cpuidle_pause_and_lock();
+                       cpuidle_disable_device(dev);
+                       cpuidle_resume_and_unlock();
+                       break;
+
+               default:
+                       return NOTIFY_DONE;
+               }
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block setup_hotplug_notifier = {
+       .notifier_call = powernv_cpuidle_add_cpu_notifier,
+};
+
+/*
+ * powernv_cpuidle_driver_init()
+ */
+static int powernv_cpuidle_driver_init(void)
+{
+       int idle_state;
+       struct cpuidle_driver *drv = &powernv_idle_driver;
+
+       drv->state_count = 0;
+
+       for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
+               /* Is the state not enabled? */
+               if (cpuidle_state_table[idle_state].enter == NULL)
+                       continue;
+
+               drv->states[drv->state_count] = /* structure copy */
+                       cpuidle_state_table[idle_state];
+
+               drv->state_count += 1;
+       }
+
+       return 0;
+}
+
+/*
+ * powernv_idle_probe()
+ * Choose state table for shared versus dedicated partition
+ */
+static int powernv_idle_probe(void)
+{
+
+       if (cpuidle_disable != IDLE_NO_OVERRIDE)
+               return -ENODEV;
+
+       if (firmware_has_feature(FW_FEATURE_OPALv3)) {
+               cpuidle_state_table = powernv_states;
+               max_idle_state = ARRAY_SIZE(powernv_states);
+       } else
+               return -ENODEV;
+
+       return 0;
+}
+
+static int __init powernv_processor_idle_init(void)
+{
+       int retval;
+
+       retval = powernv_idle_probe();
+       if (retval)
+               return retval;
+
+       powernv_cpuidle_driver_init();
+       retval = cpuidle_register(&powernv_idle_driver, NULL);
+       if (retval) {
+               printk(KERN_DEBUG "Registration of powernv driver failed.\n");
+               return retval;
+       }
+
+       register_cpu_notifier(&setup_hotplug_notifier);
+       printk(KERN_DEBUG "powernv_idle_driver registered\n");
+       return 0;
+}
+
+device_initcall(powernv_processor_idle_init);
similarity index 74%
rename from arch/powerpc/platforms/pseries/processor_idle.c
rename to drivers/cpuidle/cpuidle-pseries.c
index 94134a5aecaac80ce2869826ce11c7ccd1703578..7ab564aa0b1c8c141e0b64f750592dc44bbbba3f 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  processor_idle - idle state cpuidle driver.
+ *  cpuidle-pseries - idle state cpuidle driver.
  *  Adapted from drivers/idle/intel_idle.c and
  *  drivers/acpi/processor_idle.c
  *
@@ -17,7 +17,6 @@
 #include <asm/reg.h>
 #include <asm/machdep.h>
 #include <asm/firmware.h>
-#include <asm/runlatch.h>
 #include <asm/plpar_wrappers.h>
 
 struct cpuidle_driver pseries_idle_driver = {
@@ -25,9 +24,7 @@ struct cpuidle_driver pseries_idle_driver = {
        .owner            = THIS_MODULE,
 };
 
-#define MAX_IDLE_STATE_COUNT   2
-
-static int max_idle_state = MAX_IDLE_STATE_COUNT - 1;
+static int max_idle_state;
 static struct cpuidle_state *cpuidle_state_table;
 
 static inline void idle_loop_prolog(unsigned long *in_purr)
@@ -55,14 +52,12 @@ static int snooze_loop(struct cpuidle_device *dev,
                        int index)
 {
        unsigned long in_purr;
-       int cpu = dev->cpu;
 
        idle_loop_prolog(&in_purr);
        local_irq_enable();
        set_thread_flag(TIF_POLLING_NRFLAG);
 
-       while ((!need_resched()) && cpu_online(cpu)) {
-               ppc64_runlatch_off();
+       while (!need_resched()) {
                HMT_low();
                HMT_very_low();
        }
@@ -102,7 +97,6 @@ static int dedicated_cede_loop(struct cpuidle_device *dev,
        idle_loop_prolog(&in_purr);
        get_lppaca()->donate_dedicated_cpu = 1;
 
-       ppc64_runlatch_off();
        HMT_medium();
        check_and_cede_processor();
 
@@ -138,7 +132,7 @@ static int shared_cede_loop(struct cpuidle_device *dev,
 /*
  * States for dedicated partition case.
  */
-static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
+static struct cpuidle_state dedicated_states[] = {
        { /* Snooze */
                .name = "snooze",
                .desc = "snooze",
@@ -158,7 +152,7 @@ static struct cpuidle_state dedicated_states[MAX_IDLE_STATE_COUNT] = {
 /*
  * States for shared partition case.
  */
-static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
+static struct cpuidle_state shared_states[] = {
        { /* Shared Cede */
                .name = "Shared Cede",
                .desc = "Shared Cede",
@@ -168,29 +162,12 @@ static struct cpuidle_state shared_states[MAX_IDLE_STATE_COUNT] = {
                .enter = &shared_cede_loop },
 };
 
-void update_smt_snooze_delay(int cpu, int residency)
-{
-       struct cpuidle_driver *drv = cpuidle_get_driver();
-       struct cpuidle_device *dev = per_cpu(cpuidle_devices, cpu);
-
-       if (cpuidle_state_table != dedicated_states)
-               return;
-
-       if (residency < 0) {
-               /* Disable the Nap state on that cpu */
-               if (dev)
-                       dev->states_usage[1].disable = 1;
-       } else
-               if (drv)
-                       drv->states[1].target_residency = residency;
-}
-
 static int pseries_cpuidle_add_cpu_notifier(struct notifier_block *n,
                        unsigned long action, void *hcpu)
 {
        int hotcpu = (unsigned long)hcpu;
        struct cpuidle_device *dev =
-                       per_cpu_ptr(cpuidle_devices, hotcpu);
+                               per_cpu(cpuidle_devices, hotcpu);
 
        if (dev && cpuidle_get_driver()) {
                switch (action) {
@@ -229,12 +206,8 @@ static int pseries_cpuidle_driver_init(void)
 
        drv->state_count = 0;
 
-       for (idle_state = 0; idle_state < MAX_IDLE_STATE_COUNT; ++idle_state) {
-
-               if (idle_state > max_idle_state)
-                       break;
-
-               /* is the state not enabled? */
+       for (idle_state = 0; idle_state < max_idle_state; ++idle_state) {
+               /* Is the state not enabled? */
                if (cpuidle_state_table[idle_state].enter == NULL)
                        continue;
 
@@ -254,21 +227,19 @@ static int pseries_cpuidle_driver_init(void)
 static int pseries_idle_probe(void)
 {
 
-       if (!firmware_has_feature(FW_FEATURE_SPLPAR))
-               return -ENODEV;
-
        if (cpuidle_disable != IDLE_NO_OVERRIDE)
                return -ENODEV;
 
-       if (max_idle_state == 0) {
-               printk(KERN_DEBUG "pseries processor idle disabled.\n");
-               return -EPERM;
-       }
-
-       if (lppaca_shared_proc(get_lppaca()))
-               cpuidle_state_table = shared_states;
-       else
-               cpuidle_state_table = dedicated_states;
+       if (firmware_has_feature(FW_FEATURE_SPLPAR)) {
+               if (lppaca_shared_proc(get_lppaca())) {
+                       cpuidle_state_table = shared_states;
+                       max_idle_state = ARRAY_SIZE(shared_states);
+               } else {
+                       cpuidle_state_table = dedicated_states;
+                       max_idle_state = ARRAY_SIZE(dedicated_states);
+               }
+       } else
+               return -ENODEV;
 
        return 0;
 }
@@ -290,22 +261,7 @@ static int __init pseries_processor_idle_init(void)
 
        register_cpu_notifier(&setup_hotplug_notifier);
        printk(KERN_DEBUG "pseries_idle_driver registered\n");
-
        return 0;
 }
 
-static void __exit pseries_processor_idle_exit(void)
-{
-
-       unregister_cpu_notifier(&setup_hotplug_notifier);
-       cpuidle_unregister(&pseries_idle_driver);
-
-       return;
-}
-
-module_init(pseries_processor_idle_init);
-module_exit(pseries_processor_idle_exit);
-
-MODULE_AUTHOR("Deepthi Dharwar <deepthi@linux.vnet.ibm.com>");
-MODULE_DESCRIPTION("Cpuidle driver for POWER");
-MODULE_LICENSE("GPL");
+device_initcall(pseries_processor_idle_init);
index 31f3adba4cf3f15a693e0f3ae40d921e53a576c5..7d2f4355070059943358f491320668e72ad3b64d 100644 (file)
@@ -67,7 +67,7 @@ comment "DEVFREQ Drivers"
 
 config ARM_EXYNOS4_BUS_DEVFREQ
        bool "ARM Exynos4210/4212/4412 Memory Bus DEVFREQ Driver"
-       depends on CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412
+       depends on (CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412) && !ARCH_MULTIPLATFORM
        select ARCH_HAS_OPP
        select DEVFREQ_GOV_SIMPLE_ONDEMAND
        help
index c10eb89a3c1bdd388da699f3ac4f8e00c92cc63b..9bed1a2a67a12e44cde304995b6895e3f8296c2a 100644 (file)
@@ -306,6 +306,12 @@ config DMA_OMAP
        select DMA_ENGINE
        select DMA_VIRTUAL_CHANNELS
 
+config DMA_BCM2835
+       tristate "BCM2835 DMA engine support"
+       depends on (ARCH_BCM2835 || MACH_BCM2708)
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+
 config TI_CPPI41
        tristate "AM33xx CPPI41 DMA support"
        depends on ARCH_OMAP
@@ -336,6 +342,14 @@ config K3_DMA
          Support the DMA engine for Hisilicon K3 platform
          devices.
 
+config MOXART_DMA
+       tristate "MOXART DMA support"
+       depends on ARCH_MOXART
+       select DMA_ENGINE
+       select DMA_VIRTUAL_CHANNELS
+       help
+         Enable support for the MOXA ART SoC DMA controller.
+
 config DMA_ENGINE
        bool
 
index 0ce2da97e42972b82a61197a4fe4bb52c35ceac4..a029d0f4a1be8088c00c459373f469580925d981 100644 (file)
@@ -38,7 +38,9 @@ obj-$(CONFIG_EP93XX_DMA) += ep93xx_dma.o
 obj-$(CONFIG_DMA_SA11X0) += sa11x0-dma.o
 obj-$(CONFIG_MMP_TDMA) += mmp_tdma.o
 obj-$(CONFIG_DMA_OMAP) += omap-dma.o
+obj-$(CONFIG_DMA_BCM2835) += bcm2835-dma.o
 obj-$(CONFIG_MMP_PDMA) += mmp_pdma.o
 obj-$(CONFIG_DMA_JZ4740) += dma-jz4740.o
 obj-$(CONFIG_TI_CPPI41) += cppi41.o
 obj-$(CONFIG_K3_DMA) += k3dma.o
+obj-$(CONFIG_MOXART_DMA) += moxart-dma.o
index e69b03c0fa50cfae7ca6528f5eef0d9eaf1d8d53..1e506afa33f5e5a9b95753ce0e98ceb2f4ce7e66 100644 (file)
@@ -30,11 +30,12 @@ static DEFINE_MUTEX(acpi_dma_lock);
  * @adev:      ACPI device to match with
  * @adma:      struct acpi_dma of the given DMA controller
  *
- * Returns 1 on success, 0 when no information is available, or appropriate
- * errno value on error.
- *
  * In order to match a device from DSDT table to the corresponding CSRT device
  * we use MMIO address and IRQ.
+ *
+ * Return:
+ * 1 on success, 0 when no information is available, or appropriate errno value
+ * on error.
  */
 static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
                struct acpi_device *adev, struct acpi_dma *adma)
@@ -101,7 +102,6 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
  *
  * We are using this table to get the request line range of the specific DMA
  * controller to be used later.
- *
  */
 static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
 {
@@ -141,10 +141,11 @@ static void acpi_dma_parse_csrt(struct acpi_device *adev, struct acpi_dma *adma)
  * @data               pointer to controller specific data to be used by
  *                     translation function
  *
- * Returns 0 on success or appropriate errno value on error.
- *
  * Allocated memory should be freed with appropriate acpi_dma_controller_free()
  * call.
+ *
+ * Return:
+ * 0 on success or appropriate errno value on error.
  */
 int acpi_dma_controller_register(struct device *dev,
                struct dma_chan *(*acpi_dma_xlate)
@@ -188,6 +189,9 @@ EXPORT_SYMBOL_GPL(acpi_dma_controller_register);
  * @dev:       struct device of DMA controller
  *
  * Memory allocated by acpi_dma_controller_register() is freed here.
+ *
+ * Return:
+ * 0 on success or appropriate errno value on error.
  */
 int acpi_dma_controller_free(struct device *dev)
 {
@@ -225,6 +229,9 @@ static void devm_acpi_dma_release(struct device *dev, void *res)
  * Managed acpi_dma_controller_register(). DMA controller registered by this
  * function are automatically freed on driver detach. See
  * acpi_dma_controller_register() for more information.
+ *
+ * Return:
+ * 0 on success or appropriate errno value on error.
  */
 int devm_acpi_dma_controller_register(struct device *dev,
                struct dma_chan *(*acpi_dma_xlate)
@@ -267,8 +274,6 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
  * @adma:      struct acpi_dma of DMA controller
  * @dma_spec:  dma specifier to update
  *
- * Returns 0, if no information is avaiable, -1 on mismatch, and 1 otherwise.
- *
  * Accordingly to ACPI 5.0 Specification Table 6-170 "Fixed DMA Resource
  * Descriptor":
  *     DMA Request Line bits is a platform-relative number uniquely
@@ -276,6 +281,9 @@ EXPORT_SYMBOL_GPL(devm_acpi_dma_controller_free);
  *     mapping is done in a controller-specific OS driver.
  * That's why we can safely adjust slave_id when the appropriate controller is
  * found.
+ *
+ * Return:
+ * 0, if no information is avaiable, -1 on mismatch, and 1 otherwise.
  */
 static int acpi_dma_update_dma_spec(struct acpi_dma *adma,
                struct acpi_dma_spec *dma_spec)
@@ -334,7 +342,8 @@ static int acpi_dma_parse_fixed_dma(struct acpi_resource *res, void *data)
  * @dev:       struct device to get DMA request from
  * @index:     index of FixedDMA descriptor for @dev
  *
- * Returns pointer to appropriate dma channel on success or NULL on error.
+ * Return:
+ * Pointer to appropriate dma channel on success or NULL on error.
  */
 struct dma_chan *acpi_dma_request_slave_chan_by_index(struct device *dev,
                size_t index)
@@ -403,7 +412,8 @@ EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_index);
  * translate the names "tx" and "rx" here based on the most common case where
  * the first FixedDMA descriptor is TX and second is RX.
  *
- * Returns pointer to appropriate dma channel on success or NULL on error.
+ * Return:
+ * Pointer to appropriate dma channel on success or NULL on error.
  */
 struct dma_chan *acpi_dma_request_slave_chan_by_name(struct device *dev,
                const char *name)
@@ -427,8 +437,10 @@ EXPORT_SYMBOL_GPL(acpi_dma_request_slave_chan_by_name);
  * @adma: pointer to ACPI DMA controller data
  *
  * A simple translation function for ACPI based devices. Passes &struct
- * dma_spec to the DMA controller driver provided filter function. Returns
- * pointer to the channel if found or %NULL otherwise.
+ * dma_spec to the DMA controller driver provided filter function.
+ *
+ * Return:
+ * Pointer to the channel if found or %NULL otherwise.
  */
 struct dma_chan *acpi_dma_simple_xlate(struct acpi_dma_spec *dma_spec,
                struct acpi_dma *adma)
index ec4ee5c1fe9dc2115e029d0c472bd32f48cb281c..8114731a1c62d6450cd5f8bbd490f87c7800b1ea 100644 (file)
@@ -83,6 +83,7 @@
 #include <linux/dmaengine.h>
 #include <linux/dmapool.h>
 #include <linux/dma-mapping.h>
+#include <linux/export.h>
 #include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
@@ -1771,6 +1772,7 @@ bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
 
        return false;
 }
+EXPORT_SYMBOL_GPL(pl08x_filter_id);
 
 /*
  * Just check that the device is there and active
@@ -2167,7 +2169,7 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
        /* Register slave channels */
        ret = pl08x_dma_init_virtual_channels(pl08x, &pl08x->slave,
                        pl08x->pd->num_slave_channels, true);
-       if (ret <= 0) {
+       if (ret < 0) {
                dev_warn(&pl08x->adev->dev,
                        "%s failed to enumerate slave channels - %d\n",
                                __func__, ret);
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
new file mode 100644 (file)
index 0000000..a036021
--- /dev/null
@@ -0,0 +1,707 @@
+/*
+ * BCM2835 DMA engine support
+ *
+ * This driver only supports cyclic DMA transfers
+ * as needed for the I2S module.
+ *
+ * Author:      Florian Meier <florian.meier@koalo.de>
+ *              Copyright 2013
+ *
+ * Based on
+ *     OMAP DMAengine support by Russell King
+ *
+ *     BCM2708 DMA Driver
+ *     Copyright (C) 2010 Broadcom
+ *
+ *     Raspberry Pi PCM I2S ALSA Driver
+ *     Copyright (c) by Phil Poole 2013
+ *
+ *     MARVELL MMP Peripheral DMA Driver
+ *     Copyright 2012 Marvell International Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+
+#include "virt-dma.h"
+
+struct bcm2835_dmadev {
+       struct dma_device ddev;
+       spinlock_t lock;
+       void __iomem *base;
+       struct device_dma_parameters dma_parms;
+};
+
+struct bcm2835_dma_cb {
+       uint32_t info;
+       uint32_t src;
+       uint32_t dst;
+       uint32_t length;
+       uint32_t stride;
+       uint32_t next;
+       uint32_t pad[2];
+};
+
+struct bcm2835_chan {
+       struct virt_dma_chan vc;
+       struct list_head node;
+
+       struct dma_slave_config cfg;
+       bool cyclic;
+       unsigned int dreq;
+
+       int ch;
+       struct bcm2835_desc *desc;
+
+       void __iomem *chan_base;
+       int irq_number;
+};
+
+struct bcm2835_desc {
+       struct virt_dma_desc vd;
+       enum dma_transfer_direction dir;
+
+       unsigned int control_block_size;
+       struct bcm2835_dma_cb *control_block_base;
+       dma_addr_t control_block_base_phys;
+
+       unsigned int frames;
+       size_t size;
+};
+
+#define BCM2835_DMA_CS         0x00
+#define BCM2835_DMA_ADDR       0x04
+#define BCM2835_DMA_SOURCE_AD  0x0c
+#define BCM2835_DMA_DEST_AD    0x10
+#define BCM2835_DMA_NEXTCB     0x1C
+
+/* DMA CS Control and Status bits */
+#define BCM2835_DMA_ACTIVE     BIT(0)
+#define BCM2835_DMA_INT        BIT(2)
+#define BCM2835_DMA_ISPAUSED   BIT(4)  /* Pause requested or not active */
+#define BCM2835_DMA_ISHELD     BIT(5)  /* Is held by DREQ flow control */
+#define BCM2835_DMA_ERR        BIT(8)
+#define BCM2835_DMA_ABORT      BIT(30) /* Stop current CB, go to next, WO */
+#define BCM2835_DMA_RESET      BIT(31) /* WO, self clearing */
+
+#define BCM2835_DMA_INT_EN     BIT(0)
+#define BCM2835_DMA_D_INC      BIT(4)
+#define BCM2835_DMA_D_DREQ     BIT(6)
+#define BCM2835_DMA_S_INC      BIT(8)
+#define BCM2835_DMA_S_DREQ     BIT(10)
+
+#define BCM2835_DMA_PER_MAP(x) ((x) << 16)
+
+#define BCM2835_DMA_DATA_TYPE_S8       1
+#define BCM2835_DMA_DATA_TYPE_S16      2
+#define BCM2835_DMA_DATA_TYPE_S32      4
+#define BCM2835_DMA_DATA_TYPE_S128     16
+
+#define BCM2835_DMA_BULK_MASK  BIT(0)
+#define BCM2835_DMA_FIQ_MASK   (BIT(2) | BIT(3))
+
+/* Valid only for channels 0 - 14, 15 has its own base address */
+#define BCM2835_DMA_CHAN(n)    ((n) << 8) /* Base address */
+#define BCM2835_DMA_CHANIO(base, n) ((base) + BCM2835_DMA_CHAN(n))
+
+static inline struct bcm2835_dmadev *to_bcm2835_dma_dev(struct dma_device *d)
+{
+       return container_of(d, struct bcm2835_dmadev, ddev);
+}
+
+static inline struct bcm2835_chan *to_bcm2835_dma_chan(struct dma_chan *c)
+{
+       return container_of(c, struct bcm2835_chan, vc.chan);
+}
+
+static inline struct bcm2835_desc *to_bcm2835_dma_desc(
+               struct dma_async_tx_descriptor *t)
+{
+       return container_of(t, struct bcm2835_desc, vd.tx);
+}
+
+static void bcm2835_dma_desc_free(struct virt_dma_desc *vd)
+{
+       struct bcm2835_desc *desc = container_of(vd, struct bcm2835_desc, vd);
+       dma_free_coherent(desc->vd.tx.chan->device->dev,
+                       desc->control_block_size,
+                       desc->control_block_base,
+                       desc->control_block_base_phys);
+       kfree(desc);
+}
+
+static int bcm2835_dma_abort(void __iomem *chan_base)
+{
+       unsigned long cs;
+       long int timeout = 10000;
+
+       cs = readl(chan_base + BCM2835_DMA_CS);
+       if (!(cs & BCM2835_DMA_ACTIVE))
+               return 0;
+
+       /* Write 0 to the active bit - Pause the DMA */
+       writel(0, chan_base + BCM2835_DMA_CS);
+
+       /* Wait for any current AXI transfer to complete */
+       while ((cs & BCM2835_DMA_ISPAUSED) && --timeout) {
+               cpu_relax();
+               cs = readl(chan_base + BCM2835_DMA_CS);
+       }
+
+       /* We'll un-pause when we set of our next DMA */
+       if (!timeout)
+               return -ETIMEDOUT;
+
+       if (!(cs & BCM2835_DMA_ACTIVE))
+               return 0;
+
+       /* Terminate the control block chain */
+       writel(0, chan_base + BCM2835_DMA_NEXTCB);
+
+       /* Abort the whole DMA */
+       writel(BCM2835_DMA_ABORT | BCM2835_DMA_ACTIVE,
+              chan_base + BCM2835_DMA_CS);
+
+       return 0;
+}
+
+static void bcm2835_dma_start_desc(struct bcm2835_chan *c)
+{
+       struct virt_dma_desc *vd = vchan_next_desc(&c->vc);
+       struct bcm2835_desc *d;
+
+       if (!vd) {
+               c->desc = NULL;
+               return;
+       }
+
+       list_del(&vd->node);
+
+       c->desc = d = to_bcm2835_dma_desc(&vd->tx);
+
+       writel(d->control_block_base_phys, c->chan_base + BCM2835_DMA_ADDR);
+       writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
+}
+
+static irqreturn_t bcm2835_dma_callback(int irq, void *data)
+{
+       struct bcm2835_chan *c = data;
+       struct bcm2835_desc *d;
+       unsigned long flags;
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+
+       /* Acknowledge interrupt */
+       writel(BCM2835_DMA_INT, c->chan_base + BCM2835_DMA_CS);
+
+       d = c->desc;
+
+       if (d) {
+               /* TODO Only works for cyclic DMA */
+               vchan_cyclic_callback(&d->vd);
+       }
+
+       /* Keep the DMA engine running */
+       writel(BCM2835_DMA_ACTIVE, c->chan_base + BCM2835_DMA_CS);
+
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+
+       return IRQ_HANDLED;
+}
+
+static int bcm2835_dma_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+
+       dev_dbg(c->vc.chan.device->dev,
+                       "Allocating DMA channel %d\n", c->ch);
+
+       return request_irq(c->irq_number,
+                       bcm2835_dma_callback, 0, "DMA IRQ", c);
+}
+
+static void bcm2835_dma_free_chan_resources(struct dma_chan *chan)
+{
+       struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+
+       vchan_free_chan_resources(&c->vc);
+       free_irq(c->irq_number, c);
+
+       dev_dbg(c->vc.chan.device->dev, "Freeing DMA channel %u\n", c->ch);
+}
+
+static size_t bcm2835_dma_desc_size(struct bcm2835_desc *d)
+{
+       return d->size;
+}
+
+static size_t bcm2835_dma_desc_size_pos(struct bcm2835_desc *d, dma_addr_t addr)
+{
+       unsigned int i;
+       size_t size;
+
+       for (size = i = 0; i < d->frames; i++) {
+               struct bcm2835_dma_cb *control_block =
+                       &d->control_block_base[i];
+               size_t this_size = control_block->length;
+               dma_addr_t dma;
+
+               if (d->dir == DMA_DEV_TO_MEM)
+                       dma = control_block->dst;
+               else
+                       dma = control_block->src;
+
+               if (size)
+                       size += this_size;
+               else if (addr >= dma && addr < dma + this_size)
+                       size += dma + this_size - addr;
+       }
+
+       return size;
+}
+
+static enum dma_status bcm2835_dma_tx_status(struct dma_chan *chan,
+       dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+       struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+       struct virt_dma_desc *vd;
+       enum dma_status ret;
+       unsigned long flags;
+
+       ret = dma_cookie_status(chan, cookie, txstate);
+       if (ret == DMA_COMPLETE || !txstate)
+               return ret;
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+       vd = vchan_find_desc(&c->vc, cookie);
+       if (vd) {
+               txstate->residue =
+                       bcm2835_dma_desc_size(to_bcm2835_dma_desc(&vd->tx));
+       } else if (c->desc && c->desc->vd.tx.cookie == cookie) {
+               struct bcm2835_desc *d = c->desc;
+               dma_addr_t pos;
+
+               if (d->dir == DMA_MEM_TO_DEV)
+                       pos = readl(c->chan_base + BCM2835_DMA_SOURCE_AD);
+               else if (d->dir == DMA_DEV_TO_MEM)
+                       pos = readl(c->chan_base + BCM2835_DMA_DEST_AD);
+               else
+                       pos = 0;
+
+               txstate->residue = bcm2835_dma_desc_size_pos(d, pos);
+       } else {
+               txstate->residue = 0;
+       }
+
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+
+       return ret;
+}
+
+static void bcm2835_dma_issue_pending(struct dma_chan *chan)
+{
+       struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+       unsigned long flags;
+
+       c->cyclic = true; /* Nothing else is implemented */
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+       if (vchan_issue_pending(&c->vc) && !c->desc)
+               bcm2835_dma_start_desc(c);
+
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+}
+
+static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
+       struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+       size_t period_len, enum dma_transfer_direction direction,
+       unsigned long flags, void *context)
+{
+       struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+       enum dma_slave_buswidth dev_width;
+       struct bcm2835_desc *d;
+       dma_addr_t dev_addr;
+       unsigned int es, sync_type;
+       unsigned int frame;
+
+       /* Grab configuration */
+       if (!is_slave_direction(direction)) {
+               dev_err(chan->device->dev, "%s: bad direction?\n", __func__);
+               return NULL;
+       }
+
+       if (direction == DMA_DEV_TO_MEM) {
+               dev_addr = c->cfg.src_addr;
+               dev_width = c->cfg.src_addr_width;
+               sync_type = BCM2835_DMA_S_DREQ;
+       } else {
+               dev_addr = c->cfg.dst_addr;
+               dev_width = c->cfg.dst_addr_width;
+               sync_type = BCM2835_DMA_D_DREQ;
+       }
+
+       /* Bus width translates to the element size (ES) */
+       switch (dev_width) {
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               es = BCM2835_DMA_DATA_TYPE_S32;
+               break;
+       default:
+               return NULL;
+       }
+
+       /* Now allocate and setup the descriptor. */
+       d = kzalloc(sizeof(*d), GFP_NOWAIT);
+       if (!d)
+               return NULL;
+
+       d->dir = direction;
+       d->frames = buf_len / period_len;
+
+       /* Allocate memory for control blocks */
+       d->control_block_size = d->frames * sizeof(struct bcm2835_dma_cb);
+       d->control_block_base = dma_zalloc_coherent(chan->device->dev,
+                       d->control_block_size, &d->control_block_base_phys,
+                       GFP_NOWAIT);
+
+       if (!d->control_block_base) {
+               kfree(d);
+               return NULL;
+       }
+
+       /*
+        * Iterate over all frames, create a control block
+        * for each frame and link them together.
+        */
+       for (frame = 0; frame < d->frames; frame++) {
+               struct bcm2835_dma_cb *control_block =
+                       &d->control_block_base[frame];
+
+               /* Setup adresses */
+               if (d->dir == DMA_DEV_TO_MEM) {
+                       control_block->info = BCM2835_DMA_D_INC;
+                       control_block->src = dev_addr;
+                       control_block->dst = buf_addr + frame * period_len;
+               } else {
+                       control_block->info = BCM2835_DMA_S_INC;
+                       control_block->src = buf_addr + frame * period_len;
+                       control_block->dst = dev_addr;
+               }
+
+               /* Enable interrupt */
+               control_block->info |= BCM2835_DMA_INT_EN;
+
+               /* Setup synchronization */
+               if (sync_type != 0)
+                       control_block->info |= sync_type;
+
+               /* Setup DREQ channel */
+               if (c->dreq != 0)
+                       control_block->info |=
+                               BCM2835_DMA_PER_MAP(c->dreq);
+
+               /* Length of a frame */
+               control_block->length = period_len;
+               d->size += control_block->length;
+
+               /*
+                * Next block is the next frame.
+                * This DMA engine driver currently only supports cyclic DMA.
+                * Therefore, wrap around at number of frames.
+                */
+               control_block->next = d->control_block_base_phys +
+                       sizeof(struct bcm2835_dma_cb)
+                       * ((frame + 1) % d->frames);
+       }
+
+       return vchan_tx_prep(&c->vc, &d->vd, flags);
+}
+
+static int bcm2835_dma_slave_config(struct bcm2835_chan *c,
+               struct dma_slave_config *cfg)
+{
+       if ((cfg->direction == DMA_DEV_TO_MEM &&
+            cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
+           (cfg->direction == DMA_MEM_TO_DEV &&
+            cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
+           !is_slave_direction(cfg->direction)) {
+               return -EINVAL;
+       }
+
+       c->cfg = *cfg;
+
+       return 0;
+}
+
+static int bcm2835_dma_terminate_all(struct bcm2835_chan *c)
+{
+       struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device);
+       unsigned long flags;
+       int timeout = 10000;
+       LIST_HEAD(head);
+
+       spin_lock_irqsave(&c->vc.lock, flags);
+
+       /* Prevent this channel being scheduled */
+       spin_lock(&d->lock);
+       list_del_init(&c->node);
+       spin_unlock(&d->lock);
+
+       /*
+        * Stop DMA activity: we assume the callback will not be called
+        * after bcm_dma_abort() returns (even if it does, it will see
+        * c->desc is NULL and exit.)
+        */
+       if (c->desc) {
+               c->desc = NULL;
+               bcm2835_dma_abort(c->chan_base);
+
+               /* Wait for stopping */
+               while (--timeout) {
+                       if (!(readl(c->chan_base + BCM2835_DMA_CS) &
+                                               BCM2835_DMA_ACTIVE))
+                               break;
+
+                       cpu_relax();
+               }
+
+               if (!timeout)
+                       dev_err(d->ddev.dev, "DMA transfer could not be terminated\n");
+       }
+
+       vchan_get_all_descriptors(&c->vc, &head);
+       spin_unlock_irqrestore(&c->vc.lock, flags);
+       vchan_dma_desc_free_list(&c->vc, &head);
+
+       return 0;
+}
+
+static int bcm2835_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+       unsigned long arg)
+{
+       struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+
+       switch (cmd) {
+       case DMA_SLAVE_CONFIG:
+               return bcm2835_dma_slave_config(c,
+                               (struct dma_slave_config *)arg);
+
+       case DMA_TERMINATE_ALL:
+               return bcm2835_dma_terminate_all(c);
+
+       default:
+               return -ENXIO;
+       }
+}
+
+static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq)
+{
+       struct bcm2835_chan *c;
+
+       c = devm_kzalloc(d->ddev.dev, sizeof(*c), GFP_KERNEL);
+       if (!c)
+               return -ENOMEM;
+
+       c->vc.desc_free = bcm2835_dma_desc_free;
+       vchan_init(&c->vc, &d->ddev);
+       INIT_LIST_HEAD(&c->node);
+
+       d->ddev.chancnt++;
+
+       c->chan_base = BCM2835_DMA_CHANIO(d->base, chan_id);
+       c->ch = chan_id;
+       c->irq_number = irq;
+
+       return 0;
+}
+
+static void bcm2835_dma_free(struct bcm2835_dmadev *od)
+{
+       struct bcm2835_chan *c, *next;
+
+       list_for_each_entry_safe(c, next, &od->ddev.channels,
+                                vc.chan.device_node) {
+               list_del(&c->vc.chan.device_node);
+               tasklet_kill(&c->vc.task);
+       }
+}
+
+static const struct of_device_id bcm2835_dma_of_match[] = {
+       { .compatible = "brcm,bcm2835-dma", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, bcm2835_dma_of_match);
+
+static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec,
+                                          struct of_dma *ofdma)
+{
+       struct bcm2835_dmadev *d = ofdma->of_dma_data;
+       struct dma_chan *chan;
+
+       chan = dma_get_any_slave_channel(&d->ddev);
+       if (!chan)
+               return NULL;
+
+       /* Set DREQ from param */
+       to_bcm2835_dma_chan(chan)->dreq = spec->args[0];
+
+       return chan;
+}
+
+static int bcm2835_dma_device_slave_caps(struct dma_chan *dchan,
+       struct dma_slave_caps *caps)
+{
+       caps->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+       caps->dstn_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+       caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       caps->cmd_pause = false;
+       caps->cmd_terminate = true;
+
+       return 0;
+}
+
+static int bcm2835_dma_probe(struct platform_device *pdev)
+{
+       struct bcm2835_dmadev *od;
+       struct resource *res;
+       void __iomem *base;
+       int rc;
+       int i;
+       int irq;
+       uint32_t chans_available;
+
+       if (!pdev->dev.dma_mask)
+               pdev->dev.dma_mask = &pdev->dev.coherent_dma_mask;
+
+       rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+       if (rc)
+               return rc;
+
+       od = devm_kzalloc(&pdev->dev, sizeof(*od), GFP_KERNEL);
+       if (!od)
+               return -ENOMEM;
+
+       pdev->dev.dma_parms = &od->dma_parms;
+       dma_set_max_seg_size(&pdev->dev, 0x3FFFFFFF);
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(base))
+               return PTR_ERR(base);
+
+       od->base = base;
+
+       dma_cap_set(DMA_SLAVE, od->ddev.cap_mask);
+       dma_cap_set(DMA_PRIVATE, od->ddev.cap_mask);
+       dma_cap_set(DMA_CYCLIC, od->ddev.cap_mask);
+       od->ddev.device_alloc_chan_resources = bcm2835_dma_alloc_chan_resources;
+       od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources;
+       od->ddev.device_tx_status = bcm2835_dma_tx_status;
+       od->ddev.device_issue_pending = bcm2835_dma_issue_pending;
+       od->ddev.device_slave_caps = bcm2835_dma_device_slave_caps;
+       od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic;
+       od->ddev.device_control = bcm2835_dma_control;
+       od->ddev.dev = &pdev->dev;
+       INIT_LIST_HEAD(&od->ddev.channels);
+       spin_lock_init(&od->lock);
+
+       platform_set_drvdata(pdev, od);
+
+       /* Request DMA channel mask from device tree */
+       if (of_property_read_u32(pdev->dev.of_node,
+                       "brcm,dma-channel-mask",
+                       &chans_available)) {
+               dev_err(&pdev->dev, "Failed to get channel mask\n");
+               rc = -EINVAL;
+               goto err_no_dma;
+       }
+
+       /*
+        * Do not use the FIQ and BULK channels,
+        * because they are used by the GPU.
+        */
+       chans_available &= ~(BCM2835_DMA_FIQ_MASK | BCM2835_DMA_BULK_MASK);
+
+       for (i = 0; i < pdev->num_resources; i++) {
+               irq = platform_get_irq(pdev, i);
+               if (irq < 0)
+                       break;
+
+               if (chans_available & (1 << i)) {
+                       rc = bcm2835_dma_chan_init(od, i, irq);
+                       if (rc)
+                               goto err_no_dma;
+               }
+       }
+
+       dev_dbg(&pdev->dev, "Initialized %i DMA channels\n", i);
+
+       /* Device-tree DMA controller registration */
+       rc = of_dma_controller_register(pdev->dev.of_node,
+                       bcm2835_dma_xlate, od);
+       if (rc) {
+               dev_err(&pdev->dev, "Failed to register DMA controller\n");
+               goto err_no_dma;
+       }
+
+       rc = dma_async_device_register(&od->ddev);
+       if (rc) {
+               dev_err(&pdev->dev,
+                       "Failed to register slave DMA engine device: %d\n", rc);
+               goto err_no_dma;
+       }
+
+       dev_dbg(&pdev->dev, "Load BCM2835 DMA engine driver\n");
+
+       return 0;
+
+err_no_dma:
+       bcm2835_dma_free(od);
+       return rc;
+}
+
+static int bcm2835_dma_remove(struct platform_device *pdev)
+{
+       struct bcm2835_dmadev *od = platform_get_drvdata(pdev);
+
+       dma_async_device_unregister(&od->ddev);
+       bcm2835_dma_free(od);
+
+       return 0;
+}
+
+static struct platform_driver bcm2835_dma_driver = {
+       .probe  = bcm2835_dma_probe,
+       .remove = bcm2835_dma_remove,
+       .driver = {
+               .name = "bcm2835-dma",
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(bcm2835_dma_of_match),
+       },
+};
+
+module_platform_driver(bcm2835_dma_driver);
+
+MODULE_ALIAS("platform:bcm2835-dma");
+MODULE_DESCRIPTION("BCM2835 DMA engine driver");
+MODULE_AUTHOR("Florian Meier <florian.meier@koalo.de>");
+MODULE_LICENSE("GPL v2");
index c29dacff66fa951f136657536a628b6743ccda30..c18aebf7d5aa9a23199b556bc9b54c8b3237253d 100644 (file)
@@ -972,8 +972,10 @@ static int cppi41_dma_probe(struct platform_device *pdev)
                goto err_chans;
 
        irq = irq_of_parse_and_map(dev->of_node, 0);
-       if (!irq)
+       if (!irq) {
+               ret = -EINVAL;
                goto err_irq;
+       }
 
        cppi_writel(USBSS_IRQ_PD_COMP, cdd->usbss_mem + USBSS_IRQ_ENABLER);
 
index 9dfcaf5c12888d3de80483329ffccc7fbbacd02a..05b6dea770a407fc94e614b82bdbdf0ef0212593 100644 (file)
@@ -31,7 +31,7 @@ module_param_string(channel, test_channel, sizeof(test_channel),
                S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(channel, "Bus ID of the channel to test (default: any)");
 
-static char test_device[20];
+static char test_device[32];
 module_param_string(device, test_device, sizeof(test_device),
                S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(device, "Bus ID of the DMA Engine to test (default: any)");
@@ -89,7 +89,7 @@ MODULE_PARM_DESC(verbose, "Enable \"success\" result messages (default: off)");
 struct dmatest_params {
        unsigned int    buf_size;
        char            channel[20];
-       char            device[20];
+       char            device[32];
        unsigned int    threads_per_chan;
        unsigned int    max_channels;
        unsigned int    iterations;
index 7516be4677cf7e778ba3bef2482cae9179ff41a3..13ac3f240e7963127c713f44f296bd421edf8999 100644 (file)
@@ -218,8 +218,10 @@ static inline void dwc_do_single_block(struct dw_dma_chan *dwc,
        struct dw_dma   *dw = to_dw_dma(dwc->chan.device);
        u32             ctllo;
 
-       /* Software emulation of LLP mode relies on interrupts to continue
-        * multi block transfer. */
+       /*
+        * Software emulation of LLP mode relies on interrupts to continue
+        * multi block transfer.
+        */
        ctllo = desc->lli.ctllo | DWC_CTLL_INT_EN;
 
        channel_writel(dwc, SAR, desc->lli.sar);
@@ -253,8 +255,7 @@ static void dwc_dostart(struct dw_dma_chan *dwc, struct dw_desc *first)
                                                &dwc->flags);
                if (was_soft_llp) {
                        dev_err(chan2dev(&dwc->chan),
-                               "BUG: Attempted to start new LLP transfer "
-                               "inside ongoing one\n");
+                               "BUG: Attempted to start new LLP transfer inside ongoing one\n");
                        return;
                }
 
@@ -420,8 +421,7 @@ static void dwc_scan_descriptors(struct dw_dma *dw, struct dw_dma_chan *dwc)
                return;
        }
 
-       dev_vdbg(chan2dev(&dwc->chan), "%s: llp=0x%llx\n", __func__,
-                       (unsigned long long)llp);
+       dev_vdbg(chan2dev(&dwc->chan), "%s: llp=%pad\n", __func__, &llp);
 
        list_for_each_entry_safe(desc, _desc, &dwc->active_list, desc_node) {
                /* Initial residue value */
@@ -567,9 +567,9 @@ static void dwc_handle_cyclic(struct dw_dma *dw, struct dw_dma_chan *dwc,
                        unlikely(status_xfer & dwc->mask)) {
                int i;
 
-               dev_err(chan2dev(&dwc->chan), "cyclic DMA unexpected %s "
-                               "interrupt, stopping DMA transfer\n",
-                               status_xfer ? "xfer" : "error");
+               dev_err(chan2dev(&dwc->chan),
+                       "cyclic DMA unexpected %s interrupt, stopping DMA transfer\n",
+                       status_xfer ? "xfer" : "error");
 
                spin_lock_irqsave(&dwc->lock, flags);
 
@@ -711,9 +711,8 @@ dwc_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
        u32                     ctllo;
 
        dev_vdbg(chan2dev(chan),
-                       "%s: d0x%llx s0x%llx l0x%zx f0x%lx\n", __func__,
-                       (unsigned long long)dest, (unsigned long long)src,
-                       len, flags);
+                       "%s: d%pad s%pad l0x%zx f0x%lx\n", __func__,
+                       &dest, &src, len, flags);
 
        if (unlikely(!len)) {
                dev_dbg(chan2dev(chan), "%s: length is zero!\n", __func__);
@@ -1401,9 +1400,9 @@ struct dw_cyclic_desc *dw_dma_cyclic_prep(struct dma_chan *chan,
        /* Let's make a cyclic list */
        last->lli.llp = cdesc->desc[0]->txd.phys;
 
-       dev_dbg(chan2dev(&dwc->chan), "cyclic prepared buf 0x%llx len %zu "
-                       "period %zu periods %d\n", (unsigned long long)buf_addr,
-                       buf_len, period_len, periods);
+       dev_dbg(chan2dev(&dwc->chan),
+                       "cyclic prepared buf %pad len %zu period %zu periods %d\n",
+                       &buf_addr, buf_len, period_len, periods);
 
        cdesc->periods = periods;
        dwc->cdesc = cdesc;
@@ -1603,9 +1602,11 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
                        dev_dbg(chip->dev, "DWC_PARAMS[%d]: 0x%08x\n", i,
                                           dwc_params);
 
-                       /* Decode maximum block size for given channel. The
+                       /*
+                        * Decode maximum block size for given channel. The
                         * stored 4 bit value represents blocks from 0x00 for 3
-                        * up to 0x0a for 4095. */
+                        * up to 0x0a for 4095.
+                        */
                        dwc->block_size =
                                (4 << ((max_blk_size >> 4 * i) & 0xf)) - 1;
                        dwc->nollp =
index 2539ea0cbc6394f918fb849ffd3c6f6ca73f33a0..cd8da451d1995fef8b6d076005b17ad1a17b44d1 100644 (file)
@@ -699,8 +699,8 @@ static int edma_alloc_chan_resources(struct dma_chan *chan)
        echan->alloced = true;
        echan->slot[0] = echan->ch_num;
 
-       dev_info(dev, "allocated channel for %u:%u\n",
-                EDMA_CTLR(echan->ch_num), EDMA_CHAN_SLOT(echan->ch_num));
+       dev_dbg(dev, "allocated channel for %u:%u\n",
+               EDMA_CTLR(echan->ch_num), EDMA_CHAN_SLOT(echan->ch_num));
 
        return 0;
 
@@ -736,7 +736,7 @@ static void edma_free_chan_resources(struct dma_chan *chan)
                echan->alloced = false;
        }
 
-       dev_info(dev, "freeing channel for %u\n", echan->ch_num);
+       dev_dbg(dev, "freeing channel for %u\n", echan->ch_num);
 }
 
 /* Send pending descriptor to hardware */
index 1ffc24484d23cdb0edd1e6011605aff5c9a6eb07..d56e83599825b16666960f78b91ea08620be4cef 100644 (file)
@@ -41,7 +41,7 @@
  * channel is allowed to transfer before the DMA engine pauses
  * the current channel and switches to the next channel
  */
-#define FSL_DMA_MR_BWC         0x08000000
+#define FSL_DMA_MR_BWC         0x0A000000
 
 /* Special MR definition for MPC8349 */
 #define FSL_DMA_MR_EOTIE       0x00000080
index c75679d420286c522679cdb9c344549c97e7a0c4..4e7918339b1263a2720c3da11d271714dd9669ad 100644 (file)
@@ -323,6 +323,7 @@ struct sdma_engine {
        struct clk                      *clk_ipg;
        struct clk                      *clk_ahb;
        spinlock_t                      channel_0_lock;
+       u32                             script_number;
        struct sdma_script_start_addrs  *script_addrs;
        const struct sdma_driver_data   *drvdata;
 };
@@ -724,6 +725,10 @@ static void sdma_get_pc(struct sdma_channel *sdmac,
                per_2_emi = sdma->script_addrs->app_2_mcu_addr;
                emi_2_per = sdma->script_addrs->mcu_2_app_addr;
                break;
+       case IMX_DMATYPE_SSI_DUAL:
+               per_2_emi = sdma->script_addrs->ssish_2_mcu_addr;
+               emi_2_per = sdma->script_addrs->mcu_2_ssish_addr;
+               break;
        case IMX_DMATYPE_SSI_SP:
        case IMX_DMATYPE_MMC:
        case IMX_DMATYPE_SDHC:
@@ -1238,6 +1243,7 @@ static void sdma_issue_pending(struct dma_chan *chan)
 }
 
 #define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1        34
+#define SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2        38
 
 static void sdma_add_scripts(struct sdma_engine *sdma,
                const struct sdma_script_start_addrs *addr)
@@ -1246,7 +1252,11 @@ static void sdma_add_scripts(struct sdma_engine *sdma,
        s32 *saddr_arr = (u32 *)sdma->script_addrs;
        int i;
 
-       for (i = 0; i < SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1; i++)
+       /* use the default firmware in ROM if missing external firmware */
+       if (!sdma->script_number)
+               sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
+
+       for (i = 0; i < sdma->script_number; i++)
                if (addr_arr[i] > 0)
                        saddr_arr[i] = addr_arr[i];
 }
@@ -1272,6 +1282,17 @@ static void sdma_load_firmware(const struct firmware *fw, void *context)
                goto err_firmware;
        if (header->ram_code_start + header->ram_code_size > fw->size)
                goto err_firmware;
+       switch (header->version_major) {
+               case 1:
+                       sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
+                       break;
+               case 2:
+                       sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2;
+                       break;
+               default:
+                       dev_err(sdma->dev, "unknown firmware version\n");
+                       goto err_firmware;
+       }
 
        addr = (void *)header + header->script_addrs_start;
        ram_code = (void *)header + header->ram_code_start;
index e26075408e9b95a365dfd188cad786593604412f..a1f911aaf220e0b107c1009a74edfaca1ff06634 100644 (file)
@@ -477,7 +477,7 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
        dma_addr_t addr, src = 0, dst = 0;
        int num = sglen, i;
 
-       if (sgl == 0)
+       if (sgl == NULL)
                return NULL;
 
        for_each_sg(sgl, sg, sglen, i) {
@@ -817,7 +817,7 @@ static int k3_dma_resume(struct device *dev)
        return 0;
 }
 
-SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend, k3_dma_resume);
+static SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend, k3_dma_resume);
 
 static struct platform_driver k3_pdma_driver = {
        .driver         = {
index c6a01ea8bc591c289777d2ab837ef48887cf64d1..b439679f4126e98dcd6484607971276b2baf512f 100644 (file)
@@ -5,6 +5,7 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
+
 #include <linux/err.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #define DTADR          0x0208
 #define DCMD           0x020c
 
-#define DCSR_RUN       (1 << 31)       /* Run Bit (read / write) */
-#define DCSR_NODESC    (1 << 30)       /* No-Descriptor Fetch (read / write) */
-#define DCSR_STOPIRQEN (1 << 29)       /* Stop Interrupt Enable (read / write) */
-#define DCSR_REQPEND   (1 << 8)        /* Request Pending (read-only) */
-#define DCSR_STOPSTATE (1 << 3)        /* Stop State (read-only) */
-#define DCSR_ENDINTR   (1 << 2)        /* End Interrupt (read / write) */
-#define DCSR_STARTINTR (1 << 1)        /* Start Interrupt (read / write) */
-#define DCSR_BUSERR    (1 << 0)        /* Bus Error Interrupt (read / write) */
-
-#define DCSR_EORIRQEN  (1 << 28)       /* End of Receive Interrupt Enable (R/W) */
-#define DCSR_EORJMPEN  (1 << 27)       /* Jump to next descriptor on EOR */
-#define DCSR_EORSTOPEN (1 << 26)       /* STOP on an EOR */
-#define DCSR_SETCMPST  (1 << 25)       /* Set Descriptor Compare Status */
-#define DCSR_CLRCMPST  (1 << 24)       /* Clear Descriptor Compare Status */
-#define DCSR_CMPST     (1 << 10)       /* The Descriptor Compare Status */
-#define DCSR_EORINTR   (1 << 9)        /* The end of Receive */
-
-#define DRCMR(n)       ((((n) < 64) ? 0x0100 : 0x1100) + \
-                                (((n) & 0x3f) << 2))
-#define DRCMR_MAPVLD   (1 << 7)        /* Map Valid (read / write) */
-#define DRCMR_CHLNUM   0x1f            /* mask for Channel Number (read / write) */
+#define DCSR_RUN       BIT(31) /* Run Bit (read / write) */
+#define DCSR_NODESC    BIT(30) /* No-Descriptor Fetch (read / write) */
+#define DCSR_STOPIRQEN BIT(29) /* Stop Interrupt Enable (read / write) */
+#define DCSR_REQPEND   BIT(8)  /* Request Pending (read-only) */
+#define DCSR_STOPSTATE BIT(3)  /* Stop State (read-only) */
+#define DCSR_ENDINTR   BIT(2)  /* End Interrupt (read / write) */
+#define DCSR_STARTINTR BIT(1)  /* Start Interrupt (read / write) */
+#define DCSR_BUSERR    BIT(0)  /* Bus Error Interrupt (read / write) */
+
+#define DCSR_EORIRQEN  BIT(28) /* End of Receive Interrupt Enable (R/W) */
+#define DCSR_EORJMPEN  BIT(27) /* Jump to next descriptor on EOR */
+#define DCSR_EORSTOPEN BIT(26) /* STOP on an EOR */
+#define DCSR_SETCMPST  BIT(25) /* Set Descriptor Compare Status */
+#define DCSR_CLRCMPST  BIT(24) /* Clear Descriptor Compare Status */
+#define DCSR_CMPST     BIT(10) /* The Descriptor Compare Status */
+#define DCSR_EORINTR   BIT(9)  /* The end of Receive */
+
+#define DRCMR(n)       ((((n) < 64) ? 0x0100 : 0x1100) + (((n) & 0x3f) << 2))
+#define DRCMR_MAPVLD   BIT(7)  /* Map Valid (read / write) */
+#define DRCMR_CHLNUM   0x1f    /* mask for Channel Number (read / write) */
 
 #define DDADR_DESCADDR 0xfffffff0      /* Address of next descriptor (mask) */
-#define DDADR_STOP     (1 << 0)        /* Stop (read / write) */
-
-#define DCMD_INCSRCADDR        (1 << 31)       /* Source Address Increment Setting. */
-#define DCMD_INCTRGADDR        (1 << 30)       /* Target Address Increment Setting. */
-#define DCMD_FLOWSRC   (1 << 29)       /* Flow Control by the source. */
-#define DCMD_FLOWTRG   (1 << 28)       /* Flow Control by the target. */
-#define DCMD_STARTIRQEN        (1 << 22)       /* Start Interrupt Enable */
-#define DCMD_ENDIRQEN  (1 << 21)       /* End Interrupt Enable */
-#define DCMD_ENDIAN    (1 << 18)       /* Device Endian-ness. */
+#define DDADR_STOP     BIT(0)  /* Stop (read / write) */
+
+#define DCMD_INCSRCADDR        BIT(31) /* Source Address Increment Setting. */
+#define DCMD_INCTRGADDR        BIT(30) /* Target Address Increment Setting. */
+#define DCMD_FLOWSRC   BIT(29) /* Flow Control by the source. */
+#define DCMD_FLOWTRG   BIT(28) /* Flow Control by the target. */
+#define DCMD_STARTIRQEN        BIT(22) /* Start Interrupt Enable */
+#define DCMD_ENDIRQEN  BIT(21) /* End Interrupt Enable */
+#define DCMD_ENDIAN    BIT(18) /* Device Endian-ness. */
 #define DCMD_BURST8    (1 << 16)       /* 8 byte burst */
 #define DCMD_BURST16   (2 << 16)       /* 16 byte burst */
 #define DCMD_BURST32   (3 << 16)       /* 32 byte burst */
@@ -132,10 +132,14 @@ struct mmp_pdma_device {
        spinlock_t phy_lock; /* protect alloc/free phy channels */
 };
 
-#define tx_to_mmp_pdma_desc(tx) container_of(tx, struct mmp_pdma_desc_sw, async_tx)
-#define to_mmp_pdma_desc(lh) container_of(lh, struct mmp_pdma_desc_sw, node)
-#define to_mmp_pdma_chan(dchan) container_of(dchan, struct mmp_pdma_chan, chan)
-#define to_mmp_pdma_dev(dmadev) container_of(dmadev, struct mmp_pdma_device, device)
+#define tx_to_mmp_pdma_desc(tx)                                        \
+       container_of(tx, struct mmp_pdma_desc_sw, async_tx)
+#define to_mmp_pdma_desc(lh)                                   \
+       container_of(lh, struct mmp_pdma_desc_sw, node)
+#define to_mmp_pdma_chan(dchan)                                        \
+       container_of(dchan, struct mmp_pdma_chan, chan)
+#define to_mmp_pdma_dev(dmadev)                                        \
+       container_of(dmadev, struct mmp_pdma_device, device)
 
 static void set_desc(struct mmp_pdma_phy *phy, dma_addr_t addr)
 {
@@ -162,19 +166,18 @@ static void enable_chan(struct mmp_pdma_phy *phy)
        writel(dalgn, phy->base + DALGN);
 
        reg = (phy->idx << 2) + DCSR;
-       writel(readl(phy->base + reg) | DCSR_RUN,
-                                       phy->base + reg);
+       writel(readl(phy->base + reg) | DCSR_RUN, phy->base + reg);
 }
 
 static void disable_chan(struct mmp_pdma_phy *phy)
 {
        u32 reg;
 
-       if (phy) {
-               reg = (phy->idx << 2) + DCSR;
-               writel(readl(phy->base + reg) & ~DCSR_RUN,
-                                               phy->base + reg);
-       }
+       if (!phy)
+               return;
+
+       reg = (phy->idx << 2) + DCSR;
+       writel(readl(phy->base + reg) & ~DCSR_RUN, phy->base + reg);
 }
 
 static int clear_chan_irq(struct mmp_pdma_phy *phy)
@@ -183,26 +186,27 @@ static int clear_chan_irq(struct mmp_pdma_phy *phy)
        u32 dint = readl(phy->base + DINT);
        u32 reg = (phy->idx << 2) + DCSR;
 
-       if (dint & BIT(phy->idx)) {
-               /* clear irq */
-               dcsr = readl(phy->base + reg);
-               writel(dcsr, phy->base + reg);
-               if ((dcsr & DCSR_BUSERR) && (phy->vchan))
-                       dev_warn(phy->vchan->dev, "DCSR_BUSERR\n");
-               return 0;
-       }
-       return -EAGAIN;
+       if (!(dint & BIT(phy->idx)))
+               return -EAGAIN;
+
+       /* clear irq */
+       dcsr = readl(phy->base + reg);
+       writel(dcsr, phy->base + reg);
+       if ((dcsr & DCSR_BUSERR) && (phy->vchan))
+               dev_warn(phy->vchan->dev, "DCSR_BUSERR\n");
+
+       return 0;
 }
 
 static irqreturn_t mmp_pdma_chan_handler(int irq, void *dev_id)
 {
        struct mmp_pdma_phy *phy = dev_id;
 
-       if (clear_chan_irq(phy) == 0) {
-               tasklet_schedule(&phy->vchan->tasklet);
-               return IRQ_HANDLED;
-       } else
+       if (clear_chan_irq(phy) != 0)
                return IRQ_NONE;
+
+       tasklet_schedule(&phy->vchan->tasklet);
+       return IRQ_HANDLED;
 }
 
 static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id)
@@ -224,8 +228,8 @@ static irqreturn_t mmp_pdma_int_handler(int irq, void *dev_id)
 
        if (irq_num)
                return IRQ_HANDLED;
-       else
-               return IRQ_NONE;
+
+       return IRQ_NONE;
 }
 
 /* lookup free phy channel as descending priority */
@@ -245,9 +249,9 @@ static struct mmp_pdma_phy *lookup_phy(struct mmp_pdma_chan *pchan)
         */
 
        spin_lock_irqsave(&pdev->phy_lock, flags);
-       for (prio = 0; prio <= (((pdev->dma_channels - 1) & 0xf) >> 2); prio++) {
+       for (prio = 0; prio <= ((pdev->dma_channels - 1) & 0xf) >> 2; prio++) {
                for (i = 0; i < pdev->dma_channels; i++) {
-                       if (prio != ((i & 0xf) >> 2))
+                       if (prio != (i & 0xf) >> 2)
                                continue;
                        phy = &pdev->phy[i];
                        if (!phy->vchan) {
@@ -389,14 +393,16 @@ static int mmp_pdma_alloc_chan_resources(struct dma_chan *dchan)
        if (chan->desc_pool)
                return 1;
 
-       chan->desc_pool =
-               dma_pool_create(dev_name(&dchan->dev->device), chan->dev,
-                                 sizeof(struct mmp_pdma_desc_sw),
-                                 __alignof__(struct mmp_pdma_desc_sw), 0);
+       chan->desc_pool = dma_pool_create(dev_name(&dchan->dev->device),
+                                         chan->dev,
+                                         sizeof(struct mmp_pdma_desc_sw),
+                                         __alignof__(struct mmp_pdma_desc_sw),
+                                         0);
        if (!chan->desc_pool) {
                dev_err(chan->dev, "unable to allocate descriptor pool\n");
                return -ENOMEM;
        }
+
        mmp_pdma_free_phy(chan);
        chan->idle = true;
        chan->dev_addr = 0;
@@ -404,7 +410,7 @@ static int mmp_pdma_alloc_chan_resources(struct dma_chan *dchan)
 }
 
 static void mmp_pdma_free_desc_list(struct mmp_pdma_chan *chan,
-                                 struct list_head *list)
+                                   struct list_head *list)
 {
        struct mmp_pdma_desc_sw *desc, *_desc;
 
@@ -434,8 +440,8 @@ static void mmp_pdma_free_chan_resources(struct dma_chan *dchan)
 
 static struct dma_async_tx_descriptor *
 mmp_pdma_prep_memcpy(struct dma_chan *dchan,
-       dma_addr_t dma_dst, dma_addr_t dma_src,
-       size_t len, unsigned long flags)
+                    dma_addr_t dma_dst, dma_addr_t dma_src,
+                    size_t len, unsigned long flags)
 {
        struct mmp_pdma_chan *chan;
        struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new;
@@ -515,8 +521,8 @@ fail:
 
 static struct dma_async_tx_descriptor *
 mmp_pdma_prep_slave_sg(struct dma_chan *dchan, struct scatterlist *sgl,
-                        unsigned int sg_len, enum dma_transfer_direction dir,
-                        unsigned long flags, void *context)
+                      unsigned int sg_len, enum dma_transfer_direction dir,
+                      unsigned long flags, void *context)
 {
        struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
        struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new = NULL;
@@ -591,10 +597,11 @@ fail:
        return NULL;
 }
 
-static struct dma_async_tx_descriptor *mmp_pdma_prep_dma_cyclic(
-       struct dma_chan *dchan, dma_addr_t buf_addr, size_t len,
-       size_t period_len, enum dma_transfer_direction direction,
-       unsigned long flags, void *context)
+static struct dma_async_tx_descriptor *
+mmp_pdma_prep_dma_cyclic(struct dma_chan *dchan,
+                        dma_addr_t buf_addr, size_t len, size_t period_len,
+                        enum dma_transfer_direction direction,
+                        unsigned long flags, void *context)
 {
        struct mmp_pdma_chan *chan;
        struct mmp_pdma_desc_sw *first = NULL, *prev = NULL, *new;
@@ -636,8 +643,8 @@ static struct dma_async_tx_descriptor *mmp_pdma_prep_dma_cyclic(
                        goto fail;
                }
 
-               new->desc.dcmd = chan->dcmd | DCMD_ENDIRQEN |
-                                       (DCMD_LENGTH & period_len);
+               new->desc.dcmd = (chan->dcmd | DCMD_ENDIRQEN |
+                                 (DCMD_LENGTH & period_len));
                new->desc.dsadr = dma_src;
                new->desc.dtadr = dma_dst;
 
@@ -677,12 +684,11 @@ fail:
 }
 
 static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
-               unsigned long arg)
+                           unsigned long arg)
 {
        struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
        struct dma_slave_config *cfg = (void *)arg;
        unsigned long flags;
-       int ret = 0;
        u32 maxburst = 0, addr = 0;
        enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
 
@@ -739,11 +745,12 @@ static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
                return -ENOSYS;
        }
 
-       return ret;
+       return 0;
 }
 
 static enum dma_status mmp_pdma_tx_status(struct dma_chan *dchan,
-                       dma_cookie_t cookie, struct dma_tx_state *txstate)
+                                         dma_cookie_t cookie,
+                                         struct dma_tx_state *txstate)
 {
        return dma_cookie_status(dchan, cookie, txstate);
 }
@@ -845,15 +852,14 @@ static int mmp_pdma_remove(struct platform_device *op)
        return 0;
 }
 
-static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev,
-                                                       int idx, int irq)
+static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev, int idx, int irq)
 {
        struct mmp_pdma_phy *phy  = &pdev->phy[idx];
        struct mmp_pdma_chan *chan;
        int ret;
 
-       chan = devm_kzalloc(pdev->dev,
-                       sizeof(struct mmp_pdma_chan), GFP_KERNEL);
+       chan = devm_kzalloc(pdev->dev, sizeof(struct mmp_pdma_chan),
+                           GFP_KERNEL);
        if (chan == NULL)
                return -ENOMEM;
 
@@ -861,8 +867,8 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev,
        phy->base = pdev->base;
 
        if (irq) {
-               ret = devm_request_irq(pdev->dev, irq,
-                       mmp_pdma_chan_handler, 0, "pdma", phy);
+               ret = devm_request_irq(pdev->dev, irq, mmp_pdma_chan_handler, 0,
+                                      "pdma", phy);
                if (ret) {
                        dev_err(pdev->dev, "channel request irq fail!\n");
                        return ret;
@@ -877,8 +883,7 @@ static int mmp_pdma_chan_init(struct mmp_pdma_device *pdev,
        INIT_LIST_HEAD(&chan->chain_running);
 
        /* register virt channel to dma engine */
-       list_add_tail(&chan->chan.device_node,
-                       &pdev->device.channels);
+       list_add_tail(&chan->chan.device_node, &pdev->device.channels);
 
        return 0;
 }
@@ -894,14 +899,12 @@ static struct dma_chan *mmp_pdma_dma_xlate(struct of_phandle_args *dma_spec,
 {
        struct mmp_pdma_device *d = ofdma->of_dma_data;
        struct dma_chan *chan;
-       struct mmp_pdma_chan *c;
 
        chan = dma_get_any_slave_channel(&d->device);
        if (!chan)
                return NULL;
 
-       c = to_mmp_pdma_chan(chan);
-       c->drcmr = dma_spec->args[0];
+       to_mmp_pdma_chan(chan)->drcmr = dma_spec->args[0];
 
        return chan;
 }
@@ -918,6 +921,7 @@ static int mmp_pdma_probe(struct platform_device *op)
        pdev = devm_kzalloc(&op->dev, sizeof(*pdev), GFP_KERNEL);
        if (!pdev)
                return -ENOMEM;
+
        pdev->dev = &op->dev;
 
        spin_lock_init(&pdev->phy_lock);
@@ -929,8 +933,8 @@ static int mmp_pdma_probe(struct platform_device *op)
 
        of_id = of_match_device(mmp_pdma_dt_ids, pdev->dev);
        if (of_id)
-               of_property_read_u32(pdev->dev->of_node,
-                               "#dma-channels", &dma_channels);
+               of_property_read_u32(pdev->dev->of_node, "#dma-channels",
+                                    &dma_channels);
        else if (pdata && pdata->dma_channels)
                dma_channels = pdata->dma_channels;
        else
@@ -942,8 +946,9 @@ static int mmp_pdma_probe(struct platform_device *op)
                        irq_num++;
        }
 
-       pdev->phy = devm_kzalloc(pdev->dev,
-               dma_channels * sizeof(struct mmp_pdma_chan), GFP_KERNEL);
+       pdev->phy = devm_kcalloc(pdev->dev,
+                                dma_channels, sizeof(struct mmp_pdma_chan),
+                                GFP_KERNEL);
        if (pdev->phy == NULL)
                return -ENOMEM;
 
@@ -952,8 +957,8 @@ static int mmp_pdma_probe(struct platform_device *op)
        if (irq_num != dma_channels) {
                /* all chan share one irq, demux inside */
                irq = platform_get_irq(op, 0);
-               ret = devm_request_irq(pdev->dev, irq,
-                       mmp_pdma_int_handler, 0, "pdma", pdev);
+               ret = devm_request_irq(pdev->dev, irq, mmp_pdma_int_handler, 0,
+                                      "pdma", pdev);
                if (ret)
                        return ret;
        }
@@ -1029,7 +1034,7 @@ bool mmp_pdma_filter_fn(struct dma_chan *chan, void *param)
        if (chan->device->dev->driver != &mmp_pdma_driver.driver)
                return false;
 
-       c->drcmr = *(unsigned int *) param;
+       c->drcmr = *(unsigned int *)param;
 
        return true;
 }
@@ -1037,6 +1042,6 @@ EXPORT_SYMBOL_GPL(mmp_pdma_filter_fn);
 
 module_platform_driver(mmp_pdma_driver);
 
-MODULE_DESCRIPTION("MARVELL MMP Periphera DMA Driver");
+MODULE_DESCRIPTION("MARVELL MMP Peripheral DMA Driver");
 MODULE_AUTHOR("Marvell International Ltd.");
 MODULE_LICENSE("GPL v2");
index 3ddacc14a7366611ffb089d21c70fb4ba3c896c5..33f96aaa80c759aff2f8098e2135dd6f1b67b90a 100644 (file)
@@ -121,11 +121,13 @@ struct mmp_tdma_chan {
        int                             idx;
        enum mmp_tdma_type              type;
        int                             irq;
-       unsigned long                   reg_base;
+       void __iomem                    *reg_base;
 
        size_t                          buf_len;
        size_t                          period_len;
        size_t                          pos;
+
+       struct gen_pool                 *pool;
 };
 
 #define TDMA_CHANNEL_NUM 2
@@ -182,7 +184,7 @@ static void mmp_tdma_pause_chan(struct mmp_tdma_chan *tdmac)
 
 static int mmp_tdma_config_chan(struct mmp_tdma_chan *tdmac)
 {
-       unsigned int tdcr;
+       unsigned int tdcr = 0;
 
        mmp_tdma_disable_chan(tdmac);
 
@@ -324,7 +326,7 @@ static void mmp_tdma_free_descriptor(struct mmp_tdma_chan *tdmac)
        struct gen_pool *gpool;
        int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
 
-       gpool = sram_get_gpool("asram");
+       gpool = tdmac->pool;
        if (tdmac->desc_arr)
                gen_pool_free(gpool, (unsigned long)tdmac->desc_arr,
                                size);
@@ -374,7 +376,7 @@ struct mmp_tdma_desc *mmp_tdma_alloc_descriptor(struct mmp_tdma_chan *tdmac)
        struct gen_pool *gpool;
        int size = tdmac->desc_num * sizeof(struct mmp_tdma_desc);
 
-       gpool = sram_get_gpool("asram");
+       gpool = tdmac->pool;
        if (!gpool)
                return NULL;
 
@@ -505,7 +507,8 @@ static int mmp_tdma_remove(struct platform_device *pdev)
 }
 
 static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
-                                               int idx, int irq, int type)
+                                       int idx, int irq,
+                                       int type, struct gen_pool *pool)
 {
        struct mmp_tdma_chan *tdmac;
 
@@ -526,7 +529,8 @@ static int mmp_tdma_chan_init(struct mmp_tdma_device *tdev,
        tdmac->chan.device = &tdev->device;
        tdmac->idx         = idx;
        tdmac->type        = type;
-       tdmac->reg_base    = (unsigned long)tdev->base + idx * 4;
+       tdmac->reg_base    = tdev->base + idx * 4;
+       tdmac->pool        = pool;
        tdmac->status = DMA_COMPLETE;
        tdev->tdmac[tdmac->idx] = tdmac;
        tasklet_init(&tdmac->tasklet, dma_do_tasklet, (unsigned long)tdmac);
@@ -553,6 +557,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
        int i, ret;
        int irq = 0, irq_num = 0;
        int chan_num = TDMA_CHANNEL_NUM;
+       struct gen_pool *pool;
 
        of_id = of_match_device(mmp_tdma_dt_ids, &pdev->dev);
        if (of_id)
@@ -579,6 +584,15 @@ static int mmp_tdma_probe(struct platform_device *pdev)
 
        INIT_LIST_HEAD(&tdev->device.channels);
 
+       if (pdev->dev.of_node)
+               pool = of_get_named_gen_pool(pdev->dev.of_node, "asram", 0);
+       else
+               pool = sram_get_gpool("asram");
+       if (!pool) {
+               dev_err(&pdev->dev, "asram pool not available\n");
+               return -ENOMEM;
+       }
+
        if (irq_num != chan_num) {
                irq = platform_get_irq(pdev, 0);
                ret = devm_request_irq(&pdev->dev, irq,
@@ -590,7 +604,7 @@ static int mmp_tdma_probe(struct platform_device *pdev)
        /* initialize channel parameters */
        for (i = 0; i < chan_num; i++) {
                irq = (irq_num != chan_num) ? 0 : platform_get_irq(pdev, i);
-               ret = mmp_tdma_chan_init(tdev, i, irq, type);
+               ret = mmp_tdma_chan_init(tdev, i, irq, type, pool);
                if (ret)
                        return ret;
        }
diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c
new file mode 100644 (file)
index 0000000..3258e48
--- /dev/null
@@ -0,0 +1,699 @@
+/*
+ * MOXA ART SoCs DMA Engine support.
+ *
+ * Copyright (C) 2013 Jonas Jensen
+ *
+ * Jonas Jensen <jonas.jensen@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_dma.h>
+#include <linux/bitops.h>
+
+#include <asm/cacheflush.h>
+
+#include "dmaengine.h"
+#include "virt-dma.h"
+
+#define APB_DMA_MAX_CHANNEL                    4
+
+#define REG_OFF_ADDRESS_SOURCE                 0
+#define REG_OFF_ADDRESS_DEST                   4
+#define REG_OFF_CYCLES                         8
+#define REG_OFF_CTRL                           12
+#define REG_OFF_CHAN_SIZE                      16
+
+#define APB_DMA_ENABLE                         BIT(0)
+#define APB_DMA_FIN_INT_STS                    BIT(1)
+#define APB_DMA_FIN_INT_EN                     BIT(2)
+#define APB_DMA_BURST_MODE                     BIT(3)
+#define APB_DMA_ERR_INT_STS                    BIT(4)
+#define APB_DMA_ERR_INT_EN                     BIT(5)
+
+/*
+ * Unset: APB
+ * Set:   AHB
+ */
+#define APB_DMA_SOURCE_SELECT                  0x40
+#define APB_DMA_DEST_SELECT                    0x80
+
+#define APB_DMA_SOURCE                         0x100
+#define APB_DMA_DEST                           0x1000
+
+#define APB_DMA_SOURCE_MASK                    0x700
+#define APB_DMA_DEST_MASK                      0x7000
+
+/*
+ * 000: No increment
+ * 001: +1 (Burst=0), +4  (Burst=1)
+ * 010: +2 (Burst=0), +8  (Burst=1)
+ * 011: +4 (Burst=0), +16 (Burst=1)
+ * 101: -1 (Burst=0), -4  (Burst=1)
+ * 110: -2 (Burst=0), -8  (Burst=1)
+ * 111: -4 (Burst=0), -16 (Burst=1)
+ */
+#define APB_DMA_SOURCE_INC_0                   0
+#define APB_DMA_SOURCE_INC_1_4                 0x100
+#define APB_DMA_SOURCE_INC_2_8                 0x200
+#define APB_DMA_SOURCE_INC_4_16                        0x300
+#define APB_DMA_SOURCE_DEC_1_4                 0x500
+#define APB_DMA_SOURCE_DEC_2_8                 0x600
+#define APB_DMA_SOURCE_DEC_4_16                        0x700
+#define APB_DMA_DEST_INC_0                     0
+#define APB_DMA_DEST_INC_1_4                   0x1000
+#define APB_DMA_DEST_INC_2_8                   0x2000
+#define APB_DMA_DEST_INC_4_16                  0x3000
+#define APB_DMA_DEST_DEC_1_4                   0x5000
+#define APB_DMA_DEST_DEC_2_8                   0x6000
+#define APB_DMA_DEST_DEC_4_16                  0x7000
+
+/*
+ * Request signal select source/destination address for DMA hardware handshake.
+ *
+ * The request line number is a property of the DMA controller itself,
+ * e.g. MMC must always request channels where dma_slave_config->slave_id is 5.
+ *
+ * 0:    No request / Grant signal
+ * 1-15: Request    / Grant signal
+ */
+#define APB_DMA_SOURCE_REQ_NO                  0x1000000
+#define APB_DMA_SOURCE_REQ_NO_MASK             0xf000000
+#define APB_DMA_DEST_REQ_NO                    0x10000
+#define APB_DMA_DEST_REQ_NO_MASK               0xf0000
+
+#define APB_DMA_DATA_WIDTH                     0x100000
+#define APB_DMA_DATA_WIDTH_MASK                        0x300000
+/*
+ * Data width of transfer:
+ *
+ * 00: Word
+ * 01: Half
+ * 10: Byte
+ */
+#define APB_DMA_DATA_WIDTH_4                   0
+#define APB_DMA_DATA_WIDTH_2                   0x100000
+#define APB_DMA_DATA_WIDTH_1                   0x200000
+
+#define APB_DMA_CYCLES_MASK                    0x00ffffff
+
+#define MOXART_DMA_DATA_TYPE_S8                        0x00
+#define MOXART_DMA_DATA_TYPE_S16               0x01
+#define MOXART_DMA_DATA_TYPE_S32               0x02
+
+struct moxart_sg {
+       dma_addr_t addr;
+       uint32_t len;
+};
+
+struct moxart_desc {
+       enum dma_transfer_direction     dma_dir;
+       dma_addr_t                      dev_addr;
+       unsigned int                    sglen;
+       unsigned int                    dma_cycles;
+       struct virt_dma_desc            vd;
+       uint8_t                         es;
+       struct moxart_sg                sg[0];
+};
+
+struct moxart_chan {
+       struct virt_dma_chan            vc;
+
+       void __iomem                    *base;
+       struct moxart_desc              *desc;
+
+       struct dma_slave_config         cfg;
+
+       bool                            allocated;
+       bool                            error;
+       int                             ch_num;
+       unsigned int                    line_reqno;
+       unsigned int                    sgidx;
+};
+
+struct moxart_dmadev {
+       struct dma_device               dma_slave;
+       struct moxart_chan              slave_chans[APB_DMA_MAX_CHANNEL];
+};
+
+struct moxart_filter_data {
+       struct moxart_dmadev            *mdc;
+       struct of_phandle_args          *dma_spec;
+};
+
+static const unsigned int es_bytes[] = {
+       [MOXART_DMA_DATA_TYPE_S8] = 1,
+       [MOXART_DMA_DATA_TYPE_S16] = 2,
+       [MOXART_DMA_DATA_TYPE_S32] = 4,
+};
+
+static struct device *chan2dev(struct dma_chan *chan)
+{
+       return &chan->dev->device;
+}
+
+static inline struct moxart_chan *to_moxart_dma_chan(struct dma_chan *c)
+{
+       return container_of(c, struct moxart_chan, vc.chan);
+}
+
+static inline struct moxart_desc *to_moxart_dma_desc(
+       struct dma_async_tx_descriptor *t)
+{
+       return container_of(t, struct moxart_desc, vd.tx);
+}
+
+static void moxart_dma_desc_free(struct virt_dma_desc *vd)
+{
+       kfree(container_of(vd, struct moxart_desc, vd));
+}
+
+static int moxart_terminate_all(struct dma_chan *chan)
+{
+       struct moxart_chan *ch = to_moxart_dma_chan(chan);
+       unsigned long flags;
+       LIST_HEAD(head);
+       u32 ctrl;
+
+       dev_dbg(chan2dev(chan), "%s: ch=%p\n", __func__, ch);
+
+       spin_lock_irqsave(&ch->vc.lock, flags);
+
+       if (ch->desc)
+               ch->desc = NULL;
+
+       ctrl = readl(ch->base + REG_OFF_CTRL);
+       ctrl &= ~(APB_DMA_ENABLE | APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
+       writel(ctrl, ch->base + REG_OFF_CTRL);
+
+       vchan_get_all_descriptors(&ch->vc, &head);
+       spin_unlock_irqrestore(&ch->vc.lock, flags);
+       vchan_dma_desc_free_list(&ch->vc, &head);
+
+       return 0;
+}
+
+static int moxart_slave_config(struct dma_chan *chan,
+                              struct dma_slave_config *cfg)
+{
+       struct moxart_chan *ch = to_moxart_dma_chan(chan);
+       u32 ctrl;
+
+       ch->cfg = *cfg;
+
+       ctrl = readl(ch->base + REG_OFF_CTRL);
+       ctrl |= APB_DMA_BURST_MODE;
+       ctrl &= ~(APB_DMA_DEST_MASK | APB_DMA_SOURCE_MASK);
+       ctrl &= ~(APB_DMA_DEST_REQ_NO_MASK | APB_DMA_SOURCE_REQ_NO_MASK);
+
+       switch (ch->cfg.src_addr_width) {
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               ctrl |= APB_DMA_DATA_WIDTH_1;
+               if (ch->cfg.direction != DMA_MEM_TO_DEV)
+                       ctrl |= APB_DMA_DEST_INC_1_4;
+               else
+                       ctrl |= APB_DMA_SOURCE_INC_1_4;
+               break;
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               ctrl |= APB_DMA_DATA_WIDTH_2;
+               if (ch->cfg.direction != DMA_MEM_TO_DEV)
+                       ctrl |= APB_DMA_DEST_INC_2_8;
+               else
+                       ctrl |= APB_DMA_SOURCE_INC_2_8;
+               break;
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               ctrl &= ~APB_DMA_DATA_WIDTH;
+               if (ch->cfg.direction != DMA_MEM_TO_DEV)
+                       ctrl |= APB_DMA_DEST_INC_4_16;
+               else
+                       ctrl |= APB_DMA_SOURCE_INC_4_16;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (ch->cfg.direction == DMA_MEM_TO_DEV) {
+               ctrl &= ~APB_DMA_DEST_SELECT;
+               ctrl |= APB_DMA_SOURCE_SELECT;
+               ctrl |= (ch->line_reqno << 16 &
+                        APB_DMA_DEST_REQ_NO_MASK);
+       } else {
+               ctrl |= APB_DMA_DEST_SELECT;
+               ctrl &= ~APB_DMA_SOURCE_SELECT;
+               ctrl |= (ch->line_reqno << 24 &
+                        APB_DMA_SOURCE_REQ_NO_MASK);
+       }
+
+       writel(ctrl, ch->base + REG_OFF_CTRL);
+
+       return 0;
+}
+
+static int moxart_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
+                         unsigned long arg)
+{
+       int ret = 0;
+
+       switch (cmd) {
+       case DMA_PAUSE:
+       case DMA_RESUME:
+               return -EINVAL;
+       case DMA_TERMINATE_ALL:
+               moxart_terminate_all(chan);
+               break;
+       case DMA_SLAVE_CONFIG:
+               ret = moxart_slave_config(chan, (struct dma_slave_config *)arg);
+               break;
+       default:
+               ret = -ENOSYS;
+       }
+
+       return ret;
+}
+
+static struct dma_async_tx_descriptor *moxart_prep_slave_sg(
+       struct dma_chan *chan, struct scatterlist *sgl,
+       unsigned int sg_len, enum dma_transfer_direction dir,
+       unsigned long tx_flags, void *context)
+{
+       struct moxart_chan *ch = to_moxart_dma_chan(chan);
+       struct moxart_desc *d;
+       enum dma_slave_buswidth dev_width;
+       dma_addr_t dev_addr;
+       struct scatterlist *sgent;
+       unsigned int es;
+       unsigned int i;
+
+       if (!is_slave_direction(dir)) {
+               dev_err(chan2dev(chan), "%s: invalid DMA direction\n",
+                       __func__);
+               return NULL;
+       }
+
+       if (dir == DMA_DEV_TO_MEM) {
+               dev_addr = ch->cfg.src_addr;
+               dev_width = ch->cfg.src_addr_width;
+       } else {
+               dev_addr = ch->cfg.dst_addr;
+               dev_width = ch->cfg.dst_addr_width;
+       }
+
+       switch (dev_width) {
+       case DMA_SLAVE_BUSWIDTH_1_BYTE:
+               es = MOXART_DMA_DATA_TYPE_S8;
+               break;
+       case DMA_SLAVE_BUSWIDTH_2_BYTES:
+               es = MOXART_DMA_DATA_TYPE_S16;
+               break;
+       case DMA_SLAVE_BUSWIDTH_4_BYTES:
+               es = MOXART_DMA_DATA_TYPE_S32;
+               break;
+       default:
+               dev_err(chan2dev(chan), "%s: unsupported data width (%u)\n",
+                       __func__, dev_width);
+               return NULL;
+       }
+
+       d = kzalloc(sizeof(*d) + sg_len * sizeof(d->sg[0]), GFP_ATOMIC);
+       if (!d)
+               return NULL;
+
+       d->dma_dir = dir;
+       d->dev_addr = dev_addr;
+       d->es = es;
+
+       for_each_sg(sgl, sgent, sg_len, i) {
+               d->sg[i].addr = sg_dma_address(sgent);
+               d->sg[i].len = sg_dma_len(sgent);
+       }
+
+       d->sglen = sg_len;
+
+       ch->error = 0;
+
+       return vchan_tx_prep(&ch->vc, &d->vd, tx_flags);
+}
+
+static struct dma_chan *moxart_of_xlate(struct of_phandle_args *dma_spec,
+                                       struct of_dma *ofdma)
+{
+       struct moxart_dmadev *mdc = ofdma->of_dma_data;
+       struct dma_chan *chan;
+       struct moxart_chan *ch;
+
+       chan = dma_get_any_slave_channel(&mdc->dma_slave);
+       if (!chan)
+               return NULL;
+
+       ch = to_moxart_dma_chan(chan);
+       ch->line_reqno = dma_spec->args[0];
+
+       return chan;
+}
+
+static int moxart_alloc_chan_resources(struct dma_chan *chan)
+{
+       struct moxart_chan *ch = to_moxart_dma_chan(chan);
+
+       dev_dbg(chan2dev(chan), "%s: allocating channel #%u\n",
+               __func__, ch->ch_num);
+       ch->allocated = 1;
+
+       return 0;
+}
+
+static void moxart_free_chan_resources(struct dma_chan *chan)
+{
+       struct moxart_chan *ch = to_moxart_dma_chan(chan);
+
+       vchan_free_chan_resources(&ch->vc);
+
+       dev_dbg(chan2dev(chan), "%s: freeing channel #%u\n",
+               __func__, ch->ch_num);
+       ch->allocated = 0;
+}
+
+static void moxart_dma_set_params(struct moxart_chan *ch, dma_addr_t src_addr,
+                                 dma_addr_t dst_addr)
+{
+       writel(src_addr, ch->base + REG_OFF_ADDRESS_SOURCE);
+       writel(dst_addr, ch->base + REG_OFF_ADDRESS_DEST);
+}
+
+static void moxart_set_transfer_params(struct moxart_chan *ch, unsigned int len)
+{
+       struct moxart_desc *d = ch->desc;
+       unsigned int sglen_div = es_bytes[d->es];
+
+       d->dma_cycles = len >> sglen_div;
+
+       /*
+        * There are 4 cycles on 64 bytes copied, i.e. one cycle copies 16
+        * bytes ( when width is APB_DMAB_DATA_WIDTH_4 ).
+        */
+       writel(d->dma_cycles, ch->base + REG_OFF_CYCLES);
+
+       dev_dbg(chan2dev(&ch->vc.chan), "%s: set %u DMA cycles (len=%u)\n",
+               __func__, d->dma_cycles, len);
+}
+
+static void moxart_start_dma(struct moxart_chan *ch)
+{
+       u32 ctrl;
+
+       ctrl = readl(ch->base + REG_OFF_CTRL);
+       ctrl |= (APB_DMA_ENABLE | APB_DMA_FIN_INT_EN | APB_DMA_ERR_INT_EN);
+       writel(ctrl, ch->base + REG_OFF_CTRL);
+}
+
+static void moxart_dma_start_sg(struct moxart_chan *ch, unsigned int idx)
+{
+       struct moxart_desc *d = ch->desc;
+       struct moxart_sg *sg = ch->desc->sg + idx;
+
+       if (ch->desc->dma_dir == DMA_MEM_TO_DEV)
+               moxart_dma_set_params(ch, sg->addr, d->dev_addr);
+       else if (ch->desc->dma_dir == DMA_DEV_TO_MEM)
+               moxart_dma_set_params(ch, d->dev_addr, sg->addr);
+
+       moxart_set_transfer_params(ch, sg->len);
+
+       moxart_start_dma(ch);
+}
+
+static void moxart_dma_start_desc(struct dma_chan *chan)
+{
+       struct moxart_chan *ch = to_moxart_dma_chan(chan);
+       struct virt_dma_desc *vd;
+
+       vd = vchan_next_desc(&ch->vc);
+
+       if (!vd) {
+               ch->desc = NULL;
+               return;
+       }
+
+       list_del(&vd->node);
+
+       ch->desc = to_moxart_dma_desc(&vd->tx);
+       ch->sgidx = 0;
+
+       moxart_dma_start_sg(ch, 0);
+}
+
+static void moxart_issue_pending(struct dma_chan *chan)
+{
+       struct moxart_chan *ch = to_moxart_dma_chan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&ch->vc.lock, flags);
+       if (vchan_issue_pending(&ch->vc) && !ch->desc)
+               moxart_dma_start_desc(chan);
+       spin_unlock_irqrestore(&ch->vc.lock, flags);
+}
+
+static size_t moxart_dma_desc_size(struct moxart_desc *d,
+                                  unsigned int completed_sgs)
+{
+       unsigned int i;
+       size_t size;
+
+       for (size = i = completed_sgs; i < d->sglen; i++)
+               size += d->sg[i].len;
+
+       return size;
+}
+
+static size_t moxart_dma_desc_size_in_flight(struct moxart_chan *ch)
+{
+       size_t size;
+       unsigned int completed_cycles, cycles;
+
+       size = moxart_dma_desc_size(ch->desc, ch->sgidx);
+       cycles = readl(ch->base + REG_OFF_CYCLES);
+       completed_cycles = (ch->desc->dma_cycles - cycles);
+       size -= completed_cycles << es_bytes[ch->desc->es];
+
+       dev_dbg(chan2dev(&ch->vc.chan), "%s: size=%zu\n", __func__, size);
+
+       return size;
+}
+
+static enum dma_status moxart_tx_status(struct dma_chan *chan,
+                                       dma_cookie_t cookie,
+                                       struct dma_tx_state *txstate)
+{
+       struct moxart_chan *ch = to_moxart_dma_chan(chan);
+       struct virt_dma_desc *vd;
+       struct moxart_desc *d;
+       enum dma_status ret;
+       unsigned long flags;
+
+       /*
+        * dma_cookie_status() assigns initial residue value.
+        */
+       ret = dma_cookie_status(chan, cookie, txstate);
+
+       spin_lock_irqsave(&ch->vc.lock, flags);
+       vd = vchan_find_desc(&ch->vc, cookie);
+       if (vd) {
+               d = to_moxart_dma_desc(&vd->tx);
+               txstate->residue = moxart_dma_desc_size(d, 0);
+       } else if (ch->desc && ch->desc->vd.tx.cookie == cookie) {
+               txstate->residue = moxart_dma_desc_size_in_flight(ch);
+       }
+       spin_unlock_irqrestore(&ch->vc.lock, flags);
+
+       if (ch->error)
+               return DMA_ERROR;
+
+       return ret;
+}
+
+static void moxart_dma_init(struct dma_device *dma, struct device *dev)
+{
+       dma->device_prep_slave_sg               = moxart_prep_slave_sg;
+       dma->device_alloc_chan_resources        = moxart_alloc_chan_resources;
+       dma->device_free_chan_resources         = moxart_free_chan_resources;
+       dma->device_issue_pending               = moxart_issue_pending;
+       dma->device_tx_status                   = moxart_tx_status;
+       dma->device_control                     = moxart_control;
+       dma->dev                                = dev;
+
+       INIT_LIST_HEAD(&dma->channels);
+}
+
+static irqreturn_t moxart_dma_interrupt(int irq, void *devid)
+{
+       struct moxart_dmadev *mc = devid;
+       struct moxart_chan *ch = &mc->slave_chans[0];
+       unsigned int i;
+       unsigned long flags;
+       u32 ctrl;
+
+       dev_dbg(chan2dev(&ch->vc.chan), "%s\n", __func__);
+
+       for (i = 0; i < APB_DMA_MAX_CHANNEL; i++, ch++) {
+               if (!ch->allocated)
+                       continue;
+
+               ctrl = readl(ch->base + REG_OFF_CTRL);
+
+               dev_dbg(chan2dev(&ch->vc.chan), "%s: ch=%p ch->base=%p ctrl=%x\n",
+                       __func__, ch, ch->base, ctrl);
+
+               if (ctrl & APB_DMA_FIN_INT_STS) {
+                       ctrl &= ~APB_DMA_FIN_INT_STS;
+                       if (ch->desc) {
+                               spin_lock_irqsave(&ch->vc.lock, flags);
+                               if (++ch->sgidx < ch->desc->sglen) {
+                                       moxart_dma_start_sg(ch, ch->sgidx);
+                               } else {
+                                       vchan_cookie_complete(&ch->desc->vd);
+                                       moxart_dma_start_desc(&ch->vc.chan);
+                               }
+                               spin_unlock_irqrestore(&ch->vc.lock, flags);
+                       }
+               }
+
+               if (ctrl & APB_DMA_ERR_INT_STS) {
+                       ctrl &= ~APB_DMA_ERR_INT_STS;
+                       ch->error = 1;
+               }
+
+               writel(ctrl, ch->base + REG_OFF_CTRL);
+       }
+
+       return IRQ_HANDLED;
+}
+
+static int moxart_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct device_node *node = dev->of_node;
+       struct resource *res;
+       static void __iomem *dma_base_addr;
+       int ret, i;
+       unsigned int irq;
+       struct moxart_chan *ch;
+       struct moxart_dmadev *mdc;
+
+       mdc = devm_kzalloc(dev, sizeof(*mdc), GFP_KERNEL);
+       if (!mdc) {
+               dev_err(dev, "can't allocate DMA container\n");
+               return -ENOMEM;
+       }
+
+       irq = irq_of_parse_and_map(node, 0);
+       if (irq == NO_IRQ) {
+               dev_err(dev, "no IRQ resource\n");
+               return -EINVAL;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dma_base_addr = devm_ioremap_resource(dev, res);
+       if (IS_ERR(dma_base_addr))
+               return PTR_ERR(dma_base_addr);
+
+       dma_cap_zero(mdc->dma_slave.cap_mask);
+       dma_cap_set(DMA_SLAVE, mdc->dma_slave.cap_mask);
+       dma_cap_set(DMA_PRIVATE, mdc->dma_slave.cap_mask);
+
+       moxart_dma_init(&mdc->dma_slave, dev);
+
+       ch = &mdc->slave_chans[0];
+       for (i = 0; i < APB_DMA_MAX_CHANNEL; i++, ch++) {
+               ch->ch_num = i;
+               ch->base = dma_base_addr + i * REG_OFF_CHAN_SIZE;
+               ch->allocated = 0;
+
+               ch->vc.desc_free = moxart_dma_desc_free;
+               vchan_init(&ch->vc, &mdc->dma_slave);
+
+               dev_dbg(dev, "%s: chs[%d]: ch->ch_num=%u ch->base=%p\n",
+                       __func__, i, ch->ch_num, ch->base);
+       }
+
+       platform_set_drvdata(pdev, mdc);
+
+       ret = devm_request_irq(dev, irq, moxart_dma_interrupt, 0,
+                              "moxart-dma-engine", mdc);
+       if (ret) {
+               dev_err(dev, "devm_request_irq failed\n");
+               return ret;
+       }
+
+       ret = dma_async_device_register(&mdc->dma_slave);
+       if (ret) {
+               dev_err(dev, "dma_async_device_register failed\n");
+               return ret;
+       }
+
+       ret = of_dma_controller_register(node, moxart_of_xlate, mdc);
+       if (ret) {
+               dev_err(dev, "of_dma_controller_register failed\n");
+               dma_async_device_unregister(&mdc->dma_slave);
+               return ret;
+       }
+
+       dev_dbg(dev, "%s: IRQ=%u\n", __func__, irq);
+
+       return 0;
+}
+
+static int moxart_remove(struct platform_device *pdev)
+{
+       struct moxart_dmadev *m = platform_get_drvdata(pdev);
+
+       dma_async_device_unregister(&m->dma_slave);
+
+       if (pdev->dev.of_node)
+               of_dma_controller_free(pdev->dev.of_node);
+
+       return 0;
+}
+
+static const struct of_device_id moxart_dma_match[] = {
+       { .compatible = "moxa,moxart-dma" },
+       { }
+};
+
+static struct platform_driver moxart_driver = {
+       .probe  = moxart_probe,
+       .remove = moxart_remove,
+       .driver = {
+               .name           = "moxart-dma-engine",
+               .owner          = THIS_MODULE,
+               .of_match_table = moxart_dma_match,
+       },
+};
+
+static int moxart_init(void)
+{
+       return platform_driver_register(&moxart_driver);
+}
+subsys_initcall(moxart_init);
+
+static void __exit moxart_exit(void)
+{
+       platform_driver_unregister(&moxart_driver);
+}
+module_exit(moxart_exit);
+
+MODULE_AUTHOR("Jonas Jensen <jonas.jensen@gmail.com>");
+MODULE_DESCRIPTION("MOXART DMA engine driver");
+MODULE_LICENSE("GPL v2");
index 2f66cf4e54fe367754378c3c8be213fe20bb8f64..362e7c49f2e1ad9d264eef1acff1b3102f0e1212 100644 (file)
@@ -190,7 +190,7 @@ static int omap_dma_alloc_chan_resources(struct dma_chan *chan)
 {
        struct omap_chan *c = to_omap_dma_chan(chan);
 
-       dev_info(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig);
+       dev_dbg(c->vc.chan.device->dev, "allocating channel for %u\n", c->dma_sig);
 
        return omap_request_dma(c->dma_sig, "DMA engine",
                omap_dma_callback, c, &c->dma_ch);
@@ -203,7 +203,7 @@ static void omap_dma_free_chan_resources(struct dma_chan *chan)
        vchan_free_chan_resources(&c->vc);
        omap_free_dma(c->dma_ch);
 
-       dev_info(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig);
+       dev_dbg(c->vc.chan.device->dev, "freeing channel for %u\n", c->dma_sig);
 }
 
 static size_t omap_dma_sg_size(struct omap_sg *sg)
index c90edecee4633c3b7d9b76777534ab424a66ac7a..73fa9b7a10ab36b05dbc54c2850325c1e1a0b566 100644 (file)
@@ -543,7 +543,9 @@ struct dma_pl330_chan {
        /* DMA-Engine Channel */
        struct dma_chan chan;
 
-       /* List of to be xfered descriptors */
+       /* List of submitted descriptors */
+       struct list_head submitted_list;
+       /* List of issued descriptors */
        struct list_head work_list;
        /* List of completed descriptors */
        struct list_head completed_list;
@@ -578,12 +580,16 @@ struct dma_pl330_dmac {
        /* DMA-Engine Device */
        struct dma_device ddma;
 
+       /* Holds info about sg limitations */
+       struct device_dma_parameters dma_parms;
+
        /* Pool of descriptors available for the DMAC's channels */
        struct list_head desc_pool;
        /* To protect desc_pool manipulation */
        spinlock_t pool_lock;
 
        /* Peripheral channels connected to this DMAC */
+       unsigned int num_peripherals;
        struct dma_pl330_chan *peripherals; /* keep at end */
 };
 
@@ -606,11 +612,6 @@ struct dma_pl330_desc {
        struct dma_pl330_chan *pchan;
 };
 
-struct dma_pl330_filter_args {
-       struct dma_pl330_dmac *pdmac;
-       unsigned int chan_id;
-};
-
 static inline void _callback(struct pl330_req *r, enum pl330_op_err err)
 {
        if (r && r->xfer_cb)
@@ -2298,16 +2299,6 @@ static void dma_pl330_rqcb(void *token, enum pl330_op_err err)
        tasklet_schedule(&pch->task);
 }
 
-static bool pl330_dt_filter(struct dma_chan *chan, void *param)
-{
-       struct dma_pl330_filter_args *fargs = param;
-
-       if (chan->device != &fargs->pdmac->ddma)
-               return false;
-
-       return (chan->chan_id == fargs->chan_id);
-}
-
 bool pl330_filter(struct dma_chan *chan, void *param)
 {
        u8 *peri_id;
@@ -2325,23 +2316,16 @@ static struct dma_chan *of_dma_pl330_xlate(struct of_phandle_args *dma_spec,
 {
        int count = dma_spec->args_count;
        struct dma_pl330_dmac *pdmac = ofdma->of_dma_data;
-       struct dma_pl330_filter_args fargs;
-       dma_cap_mask_t cap;
-
-       if (!pdmac)
-               return NULL;
+       unsigned int chan_id;
 
        if (count != 1)
                return NULL;
 
-       fargs.pdmac = pdmac;
-       fargs.chan_id = dma_spec->args[0];
-
-       dma_cap_zero(cap);
-       dma_cap_set(DMA_SLAVE, cap);
-       dma_cap_set(DMA_CYCLIC, cap);
+       chan_id = dma_spec->args[0];
+       if (chan_id >= pdmac->num_peripherals)
+               return NULL;
 
-       return dma_request_channel(cap, pl330_dt_filter, &fargs);
+       return dma_get_slave_channel(&pdmac->peripherals[chan_id].chan);
 }
 
 static int pl330_alloc_chan_resources(struct dma_chan *chan)
@@ -2385,6 +2369,11 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
                pl330_chan_ctrl(pch->pl330_chid, PL330_OP_FLUSH);
 
                /* Mark all desc done */
+               list_for_each_entry(desc, &pch->submitted_list, node) {
+                       desc->status = FREE;
+                       dma_cookie_complete(&desc->txd);
+               }
+
                list_for_each_entry(desc, &pch->work_list , node) {
                        desc->status = FREE;
                        dma_cookie_complete(&desc->txd);
@@ -2395,6 +2384,7 @@ static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned
                        dma_cookie_complete(&desc->txd);
                }
 
+               list_splice_tail_init(&pch->submitted_list, &pdmac->desc_pool);
                list_splice_tail_init(&pch->work_list, &pdmac->desc_pool);
                list_splice_tail_init(&pch->completed_list, &pdmac->desc_pool);
                spin_unlock_irqrestore(&pch->lock, flags);
@@ -2453,7 +2443,14 @@ pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
 
 static void pl330_issue_pending(struct dma_chan *chan)
 {
-       pl330_tasklet((unsigned long) to_pchan(chan));
+       struct dma_pl330_chan *pch = to_pchan(chan);
+       unsigned long flags;
+
+       spin_lock_irqsave(&pch->lock, flags);
+       list_splice_tail_init(&pch->submitted_list, &pch->work_list);
+       spin_unlock_irqrestore(&pch->lock, flags);
+
+       pl330_tasklet((unsigned long)pch);
 }
 
 /*
@@ -2480,11 +2477,11 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
 
                dma_cookie_assign(&desc->txd);
 
-               list_move_tail(&desc->node, &pch->work_list);
+               list_move_tail(&desc->node, &pch->submitted_list);
        }
 
        cookie = dma_cookie_assign(&last->txd);
-       list_add_tail(&last->node, &pch->work_list);
+       list_add_tail(&last->node, &pch->submitted_list);
        spin_unlock_irqrestore(&pch->lock, flags);
 
        return cookie;
@@ -2960,6 +2957,8 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
        else
                num_chan = max_t(int, pi->pcfg.num_peri, pi->pcfg.num_chan);
 
+       pdmac->num_peripherals = num_chan;
+
        pdmac->peripherals = kzalloc(num_chan * sizeof(*pch), GFP_KERNEL);
        if (!pdmac->peripherals) {
                ret = -ENOMEM;
@@ -2974,6 +2973,7 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
                else
                        pch->chan.private = adev->dev.of_node;
 
+               INIT_LIST_HEAD(&pch->submitted_list);
                INIT_LIST_HEAD(&pch->work_list);
                INIT_LIST_HEAD(&pch->completed_list);
                spin_lock_init(&pch->lock);
@@ -3021,6 +3021,9 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
                        "unable to register DMA to the generic DT DMA helpers\n");
                }
        }
+
+       adev->dev.dma_parms = &pdmac->dma_parms;
+
        /*
         * This is the limit for transfers with a buswidth of 1, larger
         * buswidths will have larger limits.
index 8bba298535b0984e241793403af6920399d7366d..ce7a8d7564ba6f96649407a5840323eb92669350 100644 (file)
@@ -4114,6 +4114,7 @@ static int ppc440spe_adma_probe(struct platform_device *ofdev)
        regs = ioremap(res.start, resource_size(&res));
        if (!regs) {
                dev_err(&ofdev->dev, "failed to ioremap regs!\n");
+               ret = -ENOMEM;
                goto err_regs_alloc;
        }
 
index 6aec3ad814d37f16b69c51f44347d9826e411885..d4d3a3109b163f3c3a4a471cfdbc82c838024437 100644 (file)
@@ -640,6 +640,25 @@ bool sirfsoc_dma_filter_id(struct dma_chan *chan, void *chan_id)
 }
 EXPORT_SYMBOL(sirfsoc_dma_filter_id);
 
+#define SIRFSOC_DMA_BUSWIDTHS \
+       (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
+       BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+       BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+       BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
+
+static int sirfsoc_dma_device_slave_caps(struct dma_chan *dchan,
+       struct dma_slave_caps *caps)
+{
+       caps->src_addr_widths = SIRFSOC_DMA_BUSWIDTHS;
+       caps->dstn_addr_widths = SIRFSOC_DMA_BUSWIDTHS;
+       caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+       caps->cmd_pause = true;
+       caps->cmd_terminate = true;
+
+       return 0;
+}
+
 static int sirfsoc_dma_probe(struct platform_device *op)
 {
        struct device_node *dn = op->dev.of_node;
@@ -712,6 +731,7 @@ static int sirfsoc_dma_probe(struct platform_device *op)
        dma->device_tx_status = sirfsoc_dma_tx_status;
        dma->device_prep_interleaved_dma = sirfsoc_dma_prep_interleaved;
        dma->device_prep_dma_cyclic = sirfsoc_dma_prep_cyclic;
+       dma->device_slave_caps = sirfsoc_dma_device_slave_caps;
 
        INIT_LIST_HEAD(&dma->channels);
        dma_cap_set(DMA_SLAVE, dma->cap_mask);
index d11bb3620f2783115b7a91058a297dfbf657033d..03ad64ecaaf043a4325dd6d7d325e676672a16b4 100644 (file)
 #define TEGRA_APBDMA_APBSEQ_DATA_SWAP          BIT(27)
 #define TEGRA_APBDMA_APBSEQ_WRAP_WORD_1                (1 << 16)
 
+/* Tegra148 specific registers */
+#define TEGRA_APBDMA_CHAN_WCOUNT               0x20
+
+#define TEGRA_APBDMA_CHAN_WORD_TRANSFER                0x24
+
 /*
  * If any burst is in flight and DMA paused then this is the time to complete
  * on-flight burst and update DMA status register.
 /* Channel base address offset from APBDMA base address */
 #define TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET   0x1000
 
-/* DMA channel register space size */
-#define TEGRA_APBDMA_CHANNEL_REGISTER_SIZE     0x20
-
 struct tegra_dma;
 
 /*
  * tegra_dma_chip_data Tegra chip specific DMA data
  * @nr_channels: Number of channels available in the controller.
+ * @channel_reg_size: Channel register size/stride.
  * @max_dma_count: Maximum DMA transfer count supported by DMA controller.
  * @support_channel_pause: Support channel wise pause of dma.
+ * @support_separate_wcount_reg: Support separate word count register.
  */
 struct tegra_dma_chip_data {
        int nr_channels;
+       int channel_reg_size;
        int max_dma_count;
        bool support_channel_pause;
+       bool support_separate_wcount_reg;
 };
 
 /* DMA channel registers */
@@ -133,6 +139,7 @@ struct tegra_dma_channel_regs {
        unsigned long   apb_ptr;
        unsigned long   ahb_seq;
        unsigned long   apb_seq;
+       unsigned long   wcount;
 };
 
 /*
@@ -426,6 +433,8 @@ static void tegra_dma_start(struct tegra_dma_channel *tdc,
        tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, ch_regs->apb_ptr);
        tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBSEQ, ch_regs->ahb_seq);
        tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, ch_regs->ahb_ptr);
+       if (tdc->tdma->chip_data->support_separate_wcount_reg)
+               tdc_write(tdc, TEGRA_APBDMA_CHAN_WCOUNT, ch_regs->wcount);
 
        /* Start DMA */
        tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR,
@@ -465,6 +474,9 @@ static void tegra_dma_configure_for_next(struct tegra_dma_channel *tdc,
        /* Safe to program new configuration */
        tdc_write(tdc, TEGRA_APBDMA_CHAN_APBPTR, nsg_req->ch_regs.apb_ptr);
        tdc_write(tdc, TEGRA_APBDMA_CHAN_AHBPTR, nsg_req->ch_regs.ahb_ptr);
+       if (tdc->tdma->chip_data->support_separate_wcount_reg)
+               tdc_write(tdc, TEGRA_APBDMA_CHAN_WCOUNT,
+                                               nsg_req->ch_regs.wcount);
        tdc_write(tdc, TEGRA_APBDMA_CHAN_CSR,
                                nsg_req->ch_regs.csr | TEGRA_APBDMA_CSR_ENB);
        nsg_req->configured = true;
@@ -718,6 +730,7 @@ static void tegra_dma_terminate_all(struct dma_chan *dc)
        struct tegra_dma_desc *dma_desc;
        unsigned long flags;
        unsigned long status;
+       unsigned long wcount;
        bool was_busy;
 
        spin_lock_irqsave(&tdc->lock, flags);
@@ -738,6 +751,10 @@ static void tegra_dma_terminate_all(struct dma_chan *dc)
                tdc->isr_handler(tdc, true);
                status = tdc_read(tdc, TEGRA_APBDMA_CHAN_STATUS);
        }
+       if (tdc->tdma->chip_data->support_separate_wcount_reg)
+               wcount = tdc_read(tdc, TEGRA_APBDMA_CHAN_WORD_TRANSFER);
+       else
+               wcount = status;
 
        was_busy = tdc->busy;
        tegra_dma_stop(tdc);
@@ -746,7 +763,7 @@ static void tegra_dma_terminate_all(struct dma_chan *dc)
                sgreq = list_first_entry(&tdc->pending_sg_req,
                                        typeof(*sgreq), node);
                sgreq->dma_desc->bytes_transferred +=
-                               get_current_xferred_count(tdc, sgreq, status);
+                               get_current_xferred_count(tdc, sgreq, wcount);
        }
        tegra_dma_resume(tdc);
 
@@ -908,6 +925,17 @@ static int get_transfer_param(struct tegra_dma_channel *tdc,
        return -EINVAL;
 }
 
+static void tegra_dma_prep_wcount(struct tegra_dma_channel *tdc,
+       struct tegra_dma_channel_regs *ch_regs, u32 len)
+{
+       u32 len_field = (len - 4) & 0xFFFC;
+
+       if (tdc->tdma->chip_data->support_separate_wcount_reg)
+               ch_regs->wcount = len_field;
+       else
+               ch_regs->csr |= len_field;
+}
+
 static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
        struct dma_chan *dc, struct scatterlist *sgl, unsigned int sg_len,
        enum dma_transfer_direction direction, unsigned long flags,
@@ -991,7 +1019,8 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_slave_sg(
 
                sg_req->ch_regs.apb_ptr = apb_ptr;
                sg_req->ch_regs.ahb_ptr = mem;
-               sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC);
+               sg_req->ch_regs.csr = csr;
+               tegra_dma_prep_wcount(tdc, &sg_req->ch_regs, len);
                sg_req->ch_regs.apb_seq = apb_seq;
                sg_req->ch_regs.ahb_seq = ahb_seq;
                sg_req->configured = false;
@@ -1120,7 +1149,8 @@ static struct dma_async_tx_descriptor *tegra_dma_prep_dma_cyclic(
                ahb_seq |= get_burst_size(tdc, burst_size, slave_bw, len);
                sg_req->ch_regs.apb_ptr = apb_ptr;
                sg_req->ch_regs.ahb_ptr = mem;
-               sg_req->ch_regs.csr = csr | ((len - 4) & 0xFFFC);
+               sg_req->ch_regs.csr = csr;
+               tegra_dma_prep_wcount(tdc, &sg_req->ch_regs, len);
                sg_req->ch_regs.apb_seq = apb_seq;
                sg_req->ch_regs.ahb_seq = ahb_seq;
                sg_req->configured = false;
@@ -1234,27 +1264,45 @@ static struct dma_chan *tegra_dma_of_xlate(struct of_phandle_args *dma_spec,
 /* Tegra20 specific DMA controller information */
 static const struct tegra_dma_chip_data tegra20_dma_chip_data = {
        .nr_channels            = 16,
+       .channel_reg_size       = 0x20,
        .max_dma_count          = 1024UL * 64,
        .support_channel_pause  = false,
+       .support_separate_wcount_reg = false,
 };
 
 /* Tegra30 specific DMA controller information */
 static const struct tegra_dma_chip_data tegra30_dma_chip_data = {
        .nr_channels            = 32,
+       .channel_reg_size       = 0x20,
        .max_dma_count          = 1024UL * 64,
        .support_channel_pause  = false,
+       .support_separate_wcount_reg = false,
 };
 
 /* Tegra114 specific DMA controller information */
 static const struct tegra_dma_chip_data tegra114_dma_chip_data = {
        .nr_channels            = 32,
+       .channel_reg_size       = 0x20,
        .max_dma_count          = 1024UL * 64,
        .support_channel_pause  = true,
+       .support_separate_wcount_reg = false,
+};
+
+/* Tegra148 specific DMA controller information */
+static const struct tegra_dma_chip_data tegra148_dma_chip_data = {
+       .nr_channels            = 32,
+       .channel_reg_size       = 0x40,
+       .max_dma_count          = 1024UL * 64,
+       .support_channel_pause  = true,
+       .support_separate_wcount_reg = true,
 };
 
 
 static const struct of_device_id tegra_dma_of_match[] = {
        {
+               .compatible = "nvidia,tegra148-apbdma",
+               .data = &tegra148_dma_chip_data,
+       }, {
                .compatible = "nvidia,tegra114-apbdma",
                .data = &tegra114_dma_chip_data,
        }, {
@@ -1348,7 +1396,7 @@ static int tegra_dma_probe(struct platform_device *pdev)
                struct tegra_dma_channel *tdc = &tdma->channels[i];
 
                tdc->chan_base_offset = TEGRA_APBDMA_CHANNEL_BASE_ADD_OFFSET +
-                                       i * TEGRA_APBDMA_CHANNEL_REGISTER_SIZE;
+                                       i * cdata->channel_reg_size;
 
                res = platform_get_resource(pdev, IORESOURCE_IRQ, i);
                if (!res) {
index 85c19d63f9fbe9b6392b73238a209d6f55411215..181b95267866b605f521860f973aa3860d694fa0 100644 (file)
@@ -84,10 +84,12 @@ static inline bool vchan_issue_pending(struct virt_dma_chan *vc)
 static inline void vchan_cookie_complete(struct virt_dma_desc *vd)
 {
        struct virt_dma_chan *vc = to_virt_chan(vd->tx.chan);
+       dma_cookie_t cookie;
 
+       cookie = vd->tx.cookie;
        dma_cookie_complete(&vd->tx);
        dev_vdbg(vc->chan.device->dev, "txd %p[%x]: marked complete\n",
-               vd, vd->tx.cookie);
+                vd, cookie);
        list_add_tail(&vd->node, &vc->desc_completed);
 
        tasklet_schedule(&vc->task);
index 0e799516a2ab998ae80c28fb8662ee0384120f9f..eb6935c8ad9449bb1c557ac8c596940fc2919096 100644 (file)
@@ -523,11 +523,11 @@ static DEFINE_SPINLOCK(address_handler_list_lock);
 static LIST_HEAD(address_handler_list);
 
 const struct fw_address_region fw_high_memory_region =
-       { .start = 0x000100000000ULL, .end = 0xffffe0000000ULL,  };
+       { .start = FW_MAX_PHYSICAL_RANGE, .end = 0xffffe0000000ULL, };
 EXPORT_SYMBOL(fw_high_memory_region);
 
 static const struct fw_address_region low_memory_region =
-       { .start = 0x000000000000ULL, .end = 0x000100000000ULL,  };
+       { .start = 0x000000000000ULL, .end = FW_MAX_PHYSICAL_RANGE, };
 
 #if 0
 const struct fw_address_region fw_private_region =
@@ -1217,7 +1217,7 @@ static void handle_low_memory(struct fw_card *card, struct fw_request *request,
 }
 
 static struct fw_address_handler low_memory = {
-       .length                 = 0x000100000000ULL,
+       .length                 = FW_MAX_PHYSICAL_RANGE,
        .address_callback       = handle_low_memory,
 };
 
index 515a42c786d0250e580f63ecf12971428592a387..c98764aeeec6112928fcde7ac0907949aab001ea 100644 (file)
@@ -237,6 +237,9 @@ static inline bool is_next_generation(int new_generation, int old_generation)
 
 #define LOCAL_BUS 0xffc0
 
+/* arbitrarily chosen maximum range for physical DMA: 128 TB */
+#define FW_MAX_PHYSICAL_RANGE          (128ULL << 40)
+
 void fw_core_handle_request(struct fw_card *card, struct fw_packet *request);
 void fw_core_handle_response(struct fw_card *card, struct fw_packet *packet);
 int fw_get_response_length(struct fw_request *request);
index 6aa8a86cb83b33223aa7e2d26db2308aa440bdd8..6f74d8d3f70015a089f02948294454863cb6bcd7 100644 (file)
@@ -370,6 +370,10 @@ MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
        ", busReset events = "  __stringify(OHCI_PARAM_DEBUG_BUSRESETS)
        ", or a combination, or all = -1)");
 
+static bool param_remote_dma;
+module_param_named(remote_dma, param_remote_dma, bool, 0444);
+MODULE_PARM_DESC(remote_dma, "Enable unfiltered remote DMA (default = N)");
+
 static void log_irqs(struct fw_ohci *ohci, u32 evt)
 {
        if (likely(!(param_debug &
@@ -2050,10 +2054,10 @@ static void bus_reset_work(struct work_struct *work)
                          be32_to_cpu(ohci->next_header));
        }
 
-#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA
-       reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0);
-       reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0);
-#endif
+       if (param_remote_dma) {
+               reg_write(ohci, OHCI1394_PhyReqFilterHiSet, ~0);
+               reg_write(ohci, OHCI1394_PhyReqFilterLoSet, ~0);
+       }
 
        spin_unlock_irq(&ohci->lock);
 
@@ -2363,7 +2367,7 @@ static int ohci_enable(struct fw_card *card,
        reg_write(ohci, OHCI1394_FairnessControl, 0);
        card->priority_budget_implemented = ohci->pri_req_max != 0;
 
-       reg_write(ohci, OHCI1394_PhyUpperBound, 0x00010000);
+       reg_write(ohci, OHCI1394_PhyUpperBound, FW_MAX_PHYSICAL_RANGE >> 16);
        reg_write(ohci, OHCI1394_IntEventClear, ~0);
        reg_write(ohci, OHCI1394_IntMaskClear, ~0);
 
@@ -2587,13 +2591,13 @@ static int ohci_cancel_packet(struct fw_card *card, struct fw_packet *packet)
 static int ohci_enable_phys_dma(struct fw_card *card,
                                int node_id, int generation)
 {
-#ifdef CONFIG_FIREWIRE_OHCI_REMOTE_DMA
-       return 0;
-#else
        struct fw_ohci *ohci = fw_ohci(card);
        unsigned long flags;
        int n, ret = 0;
 
+       if (param_remote_dma)
+               return 0;
+
        /*
         * FIXME:  Make sure this bitmask is cleared when we clear the busReset
         * interrupt bit.  Clear physReqResourceAllBuses on bus reset.
@@ -2622,7 +2626,6 @@ static int ohci_enable_phys_dma(struct fw_card *card,
        spin_unlock_irqrestore(&ohci->lock, flags);
 
        return ret;
-#endif /* CONFIG_FIREWIRE_OHCI_REMOTE_DMA */
 }
 
 static u32 ohci_read_csr(struct fw_card *card, int csr_offset)
@@ -3720,9 +3723,11 @@ static int pci_probe(struct pci_dev *dev,
        version = reg_read(ohci, OHCI1394_Version) & 0x00ff00ff;
        ohci_notice(ohci,
                    "added OHCI v%x.%x device as card %d, "
-                   "%d IR + %d IT contexts, quirks 0x%x\n",
+                   "%d IR + %d IT contexts, quirks 0x%x%s\n",
                    version >> 16, version & 0xff, ohci->card.index,
-                   ohci->n_ir, ohci->n_it, ohci->quirks);
+                   ohci->n_ir, ohci->n_it, ohci->quirks,
+                   reg_read(ohci, OHCI1394_PhyUpperBound) ?
+                       ", >4 GB phys DMA" : "");
 
        return 0;
 
index 2f21b0bfe6534c6478b6ee6ec8fbd8c86351329e..29c8cdda82a11dd423c4c5683c0244eaebf0de8f 100644 (file)
@@ -12,8 +12,7 @@ menu "Google Firmware Drivers"
 
 config GOOGLE_SMI
        tristate "SMI interface for Google platforms"
-       depends on ACPI && DMI
-       select EFI
+       depends on ACPI && DMI && EFI
        select EFI_VARS
        help
          Say Y here if you want to enable SMI callbacks for Google
index f8642759116770afa976a23f12f14f1f42149be4..8e7fa4dbaed867ca45cb9c885db53543a65a74b9 100644 (file)
@@ -20,6 +20,10 @@ menuconfig DRM
          details.  You should also select and configure AGP
          (/dev/agpgart) support if it is available for your platform.
 
+config DRM_MIPI_DSI
+       bool
+       depends on DRM
+
 config DRM_USB
        tristate
        depends on DRM
@@ -188,6 +192,10 @@ source "drivers/gpu/drm/tilcdc/Kconfig"
 
 source "drivers/gpu/drm/qxl/Kconfig"
 
+source "drivers/gpu/drm/bochs/Kconfig"
+
 source "drivers/gpu/drm/msm/Kconfig"
 
 source "drivers/gpu/drm/tegra/Kconfig"
+
+source "drivers/gpu/drm/panel/Kconfig"
index cc08b845f9655a6b8bb516dab365da2d4c829198..292a79d64146274428ad1ef251d08e1d78d46bf5 100644 (file)
@@ -18,6 +18,7 @@ drm-y       :=        drm_auth.o drm_buffer.o drm_bufs.o drm_cache.o \
 drm-$(CONFIG_COMPAT) += drm_ioc32.o
 drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
 drm-$(CONFIG_PCI) += ati_pcigart.o
+drm-$(CONFIG_DRM_PANEL) += drm_panel.o
 
 drm-usb-y   := drm_usb.o
 
@@ -31,6 +32,7 @@ obj-$(CONFIG_DRM_KMS_HELPER) += drm_kms_helper.o
 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/
@@ -56,6 +58,8 @@ obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
 obj-$(CONFIG_DRM_OMAP) += omapdrm/
 obj-$(CONFIG_DRM_TILCDC)       += tilcdc/
 obj-$(CONFIG_DRM_QXL) += qxl/
+obj-$(CONFIG_DRM_BOCHS) += bochs/
 obj-$(CONFIG_DRM_MSM) += msm/
 obj-$(CONFIG_DRM_TEGRA) += tegra/
 obj-y                  += i2c/
+obj-y                  += panel/
index 40d371521fe19fea47b4a59b0a4fe1db2054aa54..50ae88ad4d76fb85b863adfd6129ea7a75df2178 100644 (file)
@@ -5,6 +5,7 @@ config DRM_ARMADA
        select FB_CFB_COPYAREA
        select FB_CFB_IMAGEBLIT
        select DRM_KMS_HELPER
+       select DRM_KMS_FB_HELPER
        help
          Support the "LCD" controllers found on the Marvell Armada 510
          devices.  There are two controllers on the device, each controller
index 62d0ff3efddf9bb5a08e1b209b5a40c6b8148e47..acf3a36c9ebc453737b1a849aa6715f41b241d68 100644 (file)
@@ -128,6 +128,7 @@ static int armada_drm_load(struct drm_device *dev, unsigned long flags)
                return -ENOMEM;
        }
 
+       platform_set_drvdata(dev->platformdev, dev);
        dev->dev_private = priv;
 
        /* Get the implementation specific driver data. */
@@ -381,7 +382,7 @@ static int armada_drm_probe(struct platform_device *pdev)
 
 static int armada_drm_remove(struct platform_device *pdev)
 {
-       drm_platform_exit(&armada_drm_driver, pdev);
+       drm_put_dev(platform_get_drvdata(pdev));
        return 0;
 }
 
index 7b33e14e44aa17a8026d4c1c33b8e2dbc529f93f..3f65dd6676b2c1354a4faef7d723f171ad840c67 100644 (file)
@@ -65,7 +65,7 @@ static void ast_dirty_update(struct ast_fbdev *afbdev,
         * then the BO is being moved and we should
         * store up the damage until later.
         */
-       if (!in_interrupt())
+       if (!drm_can_sleep())
                ret = ast_bo_reserve(bo, true);
        if (ret) {
                if (ret != -EBUSY)
index af0b868a9dfd6c5b3849f147f01fbf2cc29c4471..50535fd5a88d258492b90ca9e9e9cebfaf2de563 100644 (file)
@@ -189,53 +189,6 @@ static int ast_get_dram_info(struct drm_device *dev)
        return 0;
 }
 
-uint32_t ast_get_max_dclk(struct drm_device *dev, int bpp)
-{
-       struct ast_private *ast = dev->dev_private;
-       uint32_t dclk, jreg;
-       uint32_t dram_bus_width, mclk, dram_bandwidth, actual_dram_bandwidth, dram_efficency = 500;
-
-       dram_bus_width = ast->dram_bus_width;
-       mclk = ast->mclk;
-
-       if (ast->chip == AST2100 ||
-           ast->chip == AST1100 ||
-           ast->chip == AST2200 ||
-           ast->chip == AST2150 ||
-           ast->dram_bus_width == 16)
-               dram_efficency = 600;
-       else if (ast->chip == AST2300)
-               dram_efficency = 400;
-
-       dram_bandwidth = mclk * dram_bus_width * 2 / 8;
-       actual_dram_bandwidth = dram_bandwidth * dram_efficency / 1000;
-
-       if (ast->chip == AST1180)
-               dclk = actual_dram_bandwidth / ((bpp + 1) / 8);
-       else {
-               jreg = ast_get_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xd0, 0xff);
-               if ((jreg & 0x08) && (ast->chip == AST2000))
-                       dclk = actual_dram_bandwidth / ((bpp + 1 + 16) / 8);
-               else if ((jreg & 0x08) && (bpp == 8))
-                       dclk = actual_dram_bandwidth / ((bpp + 1 + 24) / 8);
-               else
-                       dclk = actual_dram_bandwidth / ((bpp + 1) / 8);
-       }
-
-       if (ast->chip == AST2100 ||
-           ast->chip == AST2200 ||
-           ast->chip == AST2300 ||
-           ast->chip == AST1180) {
-               if (dclk > 200)
-                       dclk = 200;
-       } else {
-               if (dclk > 165)
-                       dclk = 165;
-       }
-
-       return dclk;
-}
-
 static void ast_user_framebuffer_destroy(struct drm_framebuffer *fb)
 {
        struct ast_framebuffer *ast_fb = to_ast_framebuffer(fb);
@@ -449,7 +402,7 @@ int ast_dumb_create(struct drm_file *file,
        return 0;
 }
 
-void ast_bo_unref(struct ast_bo **bo)
+static void ast_bo_unref(struct ast_bo **bo)
 {
        struct ttm_buffer_object *tbo;
 
index 7fc9f7272b56e7e9ebe846b650e9e2f18f28cc5f..cca063b110831aa4d4fc2f46afd6e9cc35ac30b9 100644 (file)
@@ -404,7 +404,7 @@ static void ast_set_ext_reg(struct drm_crtc *crtc, struct drm_display_mode *mode
        }
 }
 
-void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode,
+static void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode,
                      struct ast_vbios_mode_info *vbios_mode)
 {
        struct ast_private *ast = dev->dev_private;
@@ -415,7 +415,7 @@ void ast_set_sync_reg(struct drm_device *dev, struct drm_display_mode *mode,
        ast_io_write8(ast, AST_IO_MISC_PORT_WRITE, jreg);
 }
 
-bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
+static bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
                     struct ast_vbios_mode_info *vbios_mode)
 {
        switch (crtc->fb->bits_per_pixel) {
@@ -427,7 +427,7 @@ bool ast_set_dac_reg(struct drm_crtc *crtc, struct drm_display_mode *mode,
        return true;
 }
 
-void ast_set_start_address_crt1(struct drm_crtc *crtc, unsigned offset)
+static void ast_set_start_address_crt1(struct drm_crtc *crtc, unsigned offset)
 {
        struct ast_private *ast = crtc->dev->dev_private;
        u32 addr;
@@ -623,7 +623,7 @@ static const struct drm_crtc_funcs ast_crtc_funcs = {
        .destroy = ast_crtc_destroy,
 };
 
-int ast_crtc_init(struct drm_device *dev)
+static int ast_crtc_init(struct drm_device *dev)
 {
        struct ast_crtc *crtc;
        int i;
@@ -710,7 +710,7 @@ static const struct drm_encoder_helper_funcs ast_enc_helper_funcs = {
        .mode_set = ast_encoder_mode_set,
 };
 
-int ast_encoder_init(struct drm_device *dev)
+static int ast_encoder_init(struct drm_device *dev)
 {
        struct ast_encoder *ast_encoder;
 
@@ -777,7 +777,7 @@ static const struct drm_connector_funcs ast_connector_funcs = {
        .destroy = ast_connector_destroy,
 };
 
-int ast_connector_init(struct drm_device *dev)
+static int ast_connector_init(struct drm_device *dev)
 {
        struct ast_connector *ast_connector;
        struct drm_connector *connector;
@@ -810,7 +810,7 @@ int ast_connector_init(struct drm_device *dev)
 }
 
 /* allocate cursor cache and pin at start of VRAM */
-int ast_cursor_init(struct drm_device *dev)
+static int ast_cursor_init(struct drm_device *dev)
 {
        struct ast_private *ast = dev->dev_private;
        int size;
@@ -847,7 +847,7 @@ fail:
        return ret;
 }
 
-void ast_cursor_fini(struct drm_device *dev)
+static void ast_cursor_fini(struct drm_device *dev)
 {
        struct ast_private *ast = dev->dev_private;
        ttm_bo_kunmap(&ast->cache_kmap);
@@ -965,7 +965,7 @@ static void ast_i2c_destroy(struct ast_i2c_chan *i2c)
        kfree(i2c);
 }
 
-void ast_show_cursor(struct drm_crtc *crtc)
+static void ast_show_cursor(struct drm_crtc *crtc)
 {
        struct ast_private *ast = crtc->dev->dev_private;
        u8 jreg;
@@ -976,7 +976,7 @@ void ast_show_cursor(struct drm_crtc *crtc)
        ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, jreg);
 }
 
-void ast_hide_cursor(struct drm_crtc *crtc)
+static void ast_hide_cursor(struct drm_crtc *crtc)
 {
        struct ast_private *ast = crtc->dev->dev_private;
        ast_set_index_reg_mask(ast, AST_IO_CRTC_PORT, 0xcb, 0xfc, 0x00);
index 32aecb34dbced78308a393833e177fd46a1e5c9b..4ea9b17ac17a9c5459617898718f1145eaf232ba 100644 (file)
@@ -80,7 +80,7 @@ static int ast_ttm_global_init(struct ast_private *ast)
        return 0;
 }
 
-void
+static void
 ast_ttm_global_release(struct ast_private *ast)
 {
        if (ast->ttm.mem_global_ref.release == NULL)
@@ -102,7 +102,7 @@ static void ast_bo_ttm_destroy(struct ttm_buffer_object *tbo)
        kfree(bo);
 }
 
-bool ast_ttm_bo_is_ast_bo(struct ttm_buffer_object *bo)
+static bool ast_ttm_bo_is_ast_bo(struct ttm_buffer_object *bo)
 {
        if (bo->destroy == &ast_bo_ttm_destroy)
                return true;
@@ -208,7 +208,7 @@ static struct ttm_backend_func ast_tt_backend_func = {
 };
 
 
-struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev,
+static struct ttm_tt *ast_ttm_tt_create(struct ttm_bo_device *bdev,
                                 unsigned long size, uint32_t page_flags,
                                 struct page *dummy_read_page)
 {
diff --git a/drivers/gpu/drm/bochs/Kconfig b/drivers/gpu/drm/bochs/Kconfig
new file mode 100644 (file)
index 0000000..c8fcf12
--- /dev/null
@@ -0,0 +1,11 @@
+config DRM_BOCHS
+       tristate "DRM Support for bochs dispi vga interface (qemu stdvga)"
+       depends on DRM && PCI
+       select DRM_KMS_HELPER
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       select DRM_TTM
+       help
+         Choose this option for qemu.
+         If M is selected the module will be called bochs-drm.
diff --git a/drivers/gpu/drm/bochs/Makefile b/drivers/gpu/drm/bochs/Makefile
new file mode 100644 (file)
index 0000000..844a556
--- /dev/null
@@ -0,0 +1,4 @@
+ccflags-y := -Iinclude/drm
+bochs-drm-y := bochs_drv.o bochs_mm.o bochs_kms.o bochs_fbdev.o bochs_hw.o
+
+obj-$(CONFIG_DRM_BOCHS)        += bochs-drm.o
diff --git a/drivers/gpu/drm/bochs/bochs.h b/drivers/gpu/drm/bochs/bochs.h
new file mode 100644 (file)
index 0000000..741965c
--- /dev/null
@@ -0,0 +1,164 @@
+#include <linux/io.h>
+#include <linux/fb.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_helper.h>
+
+#include <ttm/ttm_bo_driver.h>
+#include <ttm/ttm_page_alloc.h>
+
+/* ---------------------------------------------------------------------- */
+
+#define VBE_DISPI_IOPORT_INDEX           0x01CE
+#define VBE_DISPI_IOPORT_DATA            0x01CF
+
+#define VBE_DISPI_INDEX_ID               0x0
+#define VBE_DISPI_INDEX_XRES             0x1
+#define VBE_DISPI_INDEX_YRES             0x2
+#define VBE_DISPI_INDEX_BPP              0x3
+#define VBE_DISPI_INDEX_ENABLE           0x4
+#define VBE_DISPI_INDEX_BANK             0x5
+#define VBE_DISPI_INDEX_VIRT_WIDTH       0x6
+#define VBE_DISPI_INDEX_VIRT_HEIGHT      0x7
+#define VBE_DISPI_INDEX_X_OFFSET         0x8
+#define VBE_DISPI_INDEX_Y_OFFSET         0x9
+#define VBE_DISPI_INDEX_VIDEO_MEMORY_64K 0xa
+
+#define VBE_DISPI_ID0                    0xB0C0
+#define VBE_DISPI_ID1                    0xB0C1
+#define VBE_DISPI_ID2                    0xB0C2
+#define VBE_DISPI_ID3                    0xB0C3
+#define VBE_DISPI_ID4                    0xB0C4
+#define VBE_DISPI_ID5                    0xB0C5
+
+#define VBE_DISPI_DISABLED               0x00
+#define VBE_DISPI_ENABLED                0x01
+#define VBE_DISPI_GETCAPS                0x02
+#define VBE_DISPI_8BIT_DAC               0x20
+#define VBE_DISPI_LFB_ENABLED            0x40
+#define VBE_DISPI_NOCLEARMEM             0x80
+
+/* ---------------------------------------------------------------------- */
+
+enum bochs_types {
+       BOCHS_QEMU_STDVGA,
+       BOCHS_UNKNOWN,
+};
+
+struct bochs_framebuffer {
+       struct drm_framebuffer base;
+       struct drm_gem_object *obj;
+};
+
+struct bochs_device {
+       /* hw */
+       void __iomem   *mmio;
+       int            ioports;
+       void __iomem   *fb_map;
+       unsigned long  fb_base;
+       unsigned long  fb_size;
+
+       /* mode */
+       u16 xres;
+       u16 yres;
+       u16 yres_virtual;
+       u32 stride;
+       u32 bpp;
+
+       /* drm */
+       struct drm_device  *dev;
+       struct drm_crtc crtc;
+       struct drm_encoder encoder;
+       struct drm_connector connector;
+       bool mode_config_initialized;
+
+       /* ttm */
+       struct {
+               struct drm_global_reference mem_global_ref;
+               struct ttm_bo_global_ref bo_global_ref;
+               struct ttm_bo_device bdev;
+               bool initialized;
+       } ttm;
+
+       /* fbdev */
+       struct {
+               struct bochs_framebuffer gfb;
+               struct drm_fb_helper helper;
+               int size;
+               int x1, y1, x2, y2; /* dirty rect */
+               spinlock_t dirty_lock;
+               bool initialized;
+       } fb;
+};
+
+#define to_bochs_framebuffer(x) container_of(x, struct bochs_framebuffer, base)
+
+struct bochs_bo {
+       struct ttm_buffer_object bo;
+       struct ttm_placement placement;
+       struct ttm_bo_kmap_obj kmap;
+       struct drm_gem_object gem;
+       u32 placements[3];
+       int pin_count;
+};
+
+static inline struct bochs_bo *bochs_bo(struct ttm_buffer_object *bo)
+{
+       return container_of(bo, struct bochs_bo, bo);
+}
+
+static inline struct bochs_bo *gem_to_bochs_bo(struct drm_gem_object *gem)
+{
+       return container_of(gem, struct bochs_bo, gem);
+}
+
+#define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
+
+static inline u64 bochs_bo_mmap_offset(struct bochs_bo *bo)
+{
+       return drm_vma_node_offset_addr(&bo->bo.vma_node);
+}
+
+/* ---------------------------------------------------------------------- */
+
+/* bochs_hw.c */
+int bochs_hw_init(struct drm_device *dev, uint32_t flags);
+void bochs_hw_fini(struct drm_device *dev);
+
+void bochs_hw_setmode(struct bochs_device *bochs,
+                     struct drm_display_mode *mode);
+void bochs_hw_setbase(struct bochs_device *bochs,
+                     int x, int y, u64 addr);
+
+/* bochs_mm.c */
+int bochs_mm_init(struct bochs_device *bochs);
+void bochs_mm_fini(struct bochs_device *bochs);
+int bochs_mmap(struct file *filp, struct vm_area_struct *vma);
+
+int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+                    struct drm_gem_object **obj);
+int bochs_gem_init_object(struct drm_gem_object *obj);
+void bochs_gem_free_object(struct drm_gem_object *obj);
+int bochs_dumb_create(struct drm_file *file, struct drm_device *dev,
+                     struct drm_mode_create_dumb *args);
+int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
+                          uint32_t handle, uint64_t *offset);
+
+int bochs_framebuffer_init(struct drm_device *dev,
+                          struct bochs_framebuffer *gfb,
+                          struct drm_mode_fb_cmd2 *mode_cmd,
+                          struct drm_gem_object *obj);
+int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr);
+int bochs_bo_unpin(struct bochs_bo *bo);
+
+extern const struct drm_mode_config_funcs bochs_mode_funcs;
+
+/* bochs_kms.c */
+int bochs_kms_init(struct bochs_device *bochs);
+void bochs_kms_fini(struct bochs_device *bochs);
+
+/* bochs_fbdev.c */
+int bochs_fbdev_init(struct bochs_device *bochs);
+void bochs_fbdev_fini(struct bochs_device *bochs);
diff --git a/drivers/gpu/drm/bochs/bochs_drv.c b/drivers/gpu/drm/bochs/bochs_drv.c
new file mode 100644 (file)
index 0000000..395bba2
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ * 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/mm.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "bochs.h"
+
+static bool enable_fbdev = true;
+module_param_named(fbdev, enable_fbdev, bool, 0444);
+MODULE_PARM_DESC(fbdev, "register fbdev device");
+
+/* ---------------------------------------------------------------------- */
+/* drm interface                                                          */
+
+static int bochs_unload(struct drm_device *dev)
+{
+       struct bochs_device *bochs = dev->dev_private;
+
+       bochs_fbdev_fini(bochs);
+       bochs_kms_fini(bochs);
+       bochs_mm_fini(bochs);
+       bochs_hw_fini(dev);
+       kfree(bochs);
+       dev->dev_private = NULL;
+       return 0;
+}
+
+static int bochs_load(struct drm_device *dev, unsigned long flags)
+{
+       struct bochs_device *bochs;
+       int ret;
+
+       bochs = kzalloc(sizeof(*bochs), GFP_KERNEL);
+       if (bochs == NULL)
+               return -ENOMEM;
+       dev->dev_private = bochs;
+       bochs->dev = dev;
+
+       ret = bochs_hw_init(dev, flags);
+       if (ret)
+               goto err;
+
+       ret = bochs_mm_init(bochs);
+       if (ret)
+               goto err;
+
+       ret = bochs_kms_init(bochs);
+       if (ret)
+               goto err;
+
+       if (enable_fbdev)
+               bochs_fbdev_init(bochs);
+
+       return 0;
+
+err:
+       bochs_unload(dev);
+       return ret;
+}
+
+static const struct file_operations bochs_fops = {
+       .owner          = THIS_MODULE,
+       .open           = drm_open,
+       .release        = drm_release,
+       .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = drm_compat_ioctl,
+#endif
+       .poll           = drm_poll,
+       .read           = drm_read,
+       .llseek         = no_llseek,
+       .mmap           = bochs_mmap,
+};
+
+static struct drm_driver bochs_driver = {
+       .driver_features        = DRIVER_GEM | DRIVER_MODESET,
+       .load                   = bochs_load,
+       .unload                 = bochs_unload,
+       .fops                   = &bochs_fops,
+       .name                   = "bochs-drm",
+       .desc                   = "bochs dispi vga interface (qemu stdvga)",
+       .date                   = "20130925",
+       .major                  = 1,
+       .minor                  = 0,
+       .gem_free_object        = bochs_gem_free_object,
+       .dumb_create            = bochs_dumb_create,
+       .dumb_map_offset        = bochs_dumb_mmap_offset,
+       .dumb_destroy           = drm_gem_dumb_destroy,
+};
+
+/* ---------------------------------------------------------------------- */
+/* pci interface                                                          */
+
+static int bochs_kick_out_firmware_fb(struct pci_dev *pdev)
+{
+       struct apertures_struct *ap;
+
+       ap = alloc_apertures(1);
+       if (!ap)
+               return -ENOMEM;
+
+       ap->ranges[0].base = pci_resource_start(pdev, 0);
+       ap->ranges[0].size = pci_resource_len(pdev, 0);
+       remove_conflicting_framebuffers(ap, "bochsdrmfb", false);
+       kfree(ap);
+
+       return 0;
+}
+
+static int bochs_pci_probe(struct pci_dev *pdev,
+                          const struct pci_device_id *ent)
+{
+       int ret;
+
+       ret = bochs_kick_out_firmware_fb(pdev);
+       if (ret)
+               return ret;
+
+       return drm_get_pci_dev(pdev, ent, &bochs_driver);
+}
+
+static void bochs_pci_remove(struct pci_dev *pdev)
+{
+       struct drm_device *dev = pci_get_drvdata(pdev);
+
+       drm_put_dev(dev);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(bochs_pci_tbl) = {
+       {
+               .vendor      = 0x1234,
+               .device      = 0x1111,
+               .subvendor   = 0x1af4,
+               .subdevice   = 0x1100,
+               .driver_data = BOCHS_QEMU_STDVGA,
+       },
+       {
+               .vendor      = 0x1234,
+               .device      = 0x1111,
+               .subvendor   = PCI_ANY_ID,
+               .subdevice   = PCI_ANY_ID,
+               .driver_data = BOCHS_UNKNOWN,
+       },
+       { /* end of list */ }
+};
+
+static struct pci_driver bochs_pci_driver = {
+       .name =         "bochs-drm",
+       .id_table =     bochs_pci_tbl,
+       .probe =        bochs_pci_probe,
+       .remove =       bochs_pci_remove,
+};
+
+/* ---------------------------------------------------------------------- */
+/* module init/exit                                                       */
+
+static int __init bochs_init(void)
+{
+       return drm_pci_init(&bochs_driver, &bochs_pci_driver);
+}
+
+static void __exit bochs_exit(void)
+{
+       drm_pci_exit(&bochs_driver, &bochs_pci_driver);
+}
+
+module_init(bochs_init);
+module_exit(bochs_exit);
+
+MODULE_DEVICE_TABLE(pci, bochs_pci_tbl);
+MODULE_AUTHOR("Gerd Hoffmann <kraxel@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c
new file mode 100644 (file)
index 0000000..4da5206
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * 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 "bochs.h"
+
+/* ---------------------------------------------------------------------- */
+
+static struct fb_ops bochsfb_ops = {
+       .owner = THIS_MODULE,
+       .fb_check_var = drm_fb_helper_check_var,
+       .fb_set_par = drm_fb_helper_set_par,
+       .fb_fillrect = sys_fillrect,
+       .fb_copyarea = sys_copyarea,
+       .fb_imageblit = sys_imageblit,
+       .fb_pan_display = drm_fb_helper_pan_display,
+       .fb_blank = drm_fb_helper_blank,
+       .fb_setcmap = drm_fb_helper_setcmap,
+};
+
+static int bochsfb_create_object(struct bochs_device *bochs,
+                                struct drm_mode_fb_cmd2 *mode_cmd,
+                                struct drm_gem_object **gobj_p)
+{
+       struct drm_device *dev = bochs->dev;
+       struct drm_gem_object *gobj;
+       u32 size;
+       int ret = 0;
+
+       size = mode_cmd->pitches[0] * mode_cmd->height;
+       ret = bochs_gem_create(dev, size, true, &gobj);
+       if (ret)
+               return ret;
+
+       *gobj_p = gobj;
+       return ret;
+}
+
+static int bochsfb_create(struct drm_fb_helper *helper,
+                         struct drm_fb_helper_surface_size *sizes)
+{
+       struct bochs_device *bochs =
+               container_of(helper, struct bochs_device, fb.helper);
+       struct drm_device *dev = bochs->dev;
+       struct fb_info *info;
+       struct drm_framebuffer *fb;
+       struct drm_mode_fb_cmd2 mode_cmd;
+       struct device *device = &dev->pdev->dev;
+       struct drm_gem_object *gobj = NULL;
+       struct bochs_bo *bo = NULL;
+       int size, ret;
+
+       if (sizes->surface_bpp != 32)
+               return -EINVAL;
+
+       mode_cmd.width = sizes->surface_width;
+       mode_cmd.height = sizes->surface_height;
+       mode_cmd.pitches[0] = mode_cmd.width * ((sizes->surface_bpp + 7) / 8);
+       mode_cmd.pixel_format = drm_mode_legacy_fb_format(sizes->surface_bpp,
+                                                         sizes->surface_depth);
+       size = mode_cmd.pitches[0] * mode_cmd.height;
+
+       /* alloc, pin & map bo */
+       ret = bochsfb_create_object(bochs, &mode_cmd, &gobj);
+       if (ret) {
+               DRM_ERROR("failed to create fbcon backing object %d\n", ret);
+               return ret;
+       }
+
+       bo = gem_to_bochs_bo(gobj);
+
+       ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
+       if (ret)
+               return ret;
+
+       ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, NULL);
+       if (ret) {
+               DRM_ERROR("failed to pin fbcon\n");
+               ttm_bo_unreserve(&bo->bo);
+               return ret;
+       }
+
+       ret = ttm_bo_kmap(&bo->bo, 0, bo->bo.num_pages,
+                         &bo->kmap);
+       if (ret) {
+               DRM_ERROR("failed to kmap fbcon\n");
+               ttm_bo_unreserve(&bo->bo);
+               return ret;
+       }
+
+       ttm_bo_unreserve(&bo->bo);
+
+       /* init fb device */
+       info = framebuffer_alloc(0, device);
+       if (info == NULL)
+               return -ENOMEM;
+
+       info->par = &bochs->fb.helper;
+
+       ret = bochs_framebuffer_init(bochs->dev, &bochs->fb.gfb, &mode_cmd, gobj);
+       if (ret)
+               return ret;
+
+       bochs->fb.size = size;
+
+       /* setup helper */
+       fb = &bochs->fb.gfb.base;
+       bochs->fb.helper.fb = fb;
+       bochs->fb.helper.fbdev = info;
+
+       strcpy(info->fix.id, "bochsdrmfb");
+
+       info->flags = FBINFO_DEFAULT;
+       info->fbops = &bochsfb_ops;
+
+       drm_fb_helper_fill_fix(info, fb->pitches[0], fb->depth);
+       drm_fb_helper_fill_var(info, &bochs->fb.helper, sizes->fb_width,
+                              sizes->fb_height);
+
+       info->screen_base = bo->kmap.virtual;
+       info->screen_size = size;
+
+#if 0
+       /* FIXME: get this right for mmap(/dev/fb0) */
+       info->fix.smem_start = bochs_bo_mmap_offset(bo);
+       info->fix.smem_len = size;
+#endif
+
+       ret = fb_alloc_cmap(&info->cmap, 256, 0);
+       if (ret) {
+               DRM_ERROR("%s: can't allocate color map\n", info->fix.id);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static int bochs_fbdev_destroy(struct bochs_device *bochs)
+{
+       struct bochs_framebuffer *gfb = &bochs->fb.gfb;
+       struct fb_info *info;
+
+       DRM_DEBUG_DRIVER("\n");
+
+       if (bochs->fb.helper.fbdev) {
+               info = bochs->fb.helper.fbdev;
+
+               unregister_framebuffer(info);
+               if (info->cmap.len)
+                       fb_dealloc_cmap(&info->cmap);
+               framebuffer_release(info);
+       }
+
+       if (gfb->obj) {
+               drm_gem_object_unreference_unlocked(gfb->obj);
+               gfb->obj = NULL;
+       }
+
+       drm_fb_helper_fini(&bochs->fb.helper);
+       drm_framebuffer_unregister_private(&gfb->base);
+       drm_framebuffer_cleanup(&gfb->base);
+
+       return 0;
+}
+
+void bochs_fb_gamma_set(struct drm_crtc *crtc, u16 red, u16 green,
+                       u16 blue, int regno)
+{
+}
+
+void bochs_fb_gamma_get(struct drm_crtc *crtc, u16 *red, u16 *green,
+                       u16 *blue, int regno)
+{
+       *red   = regno;
+       *green = regno;
+       *blue  = regno;
+}
+
+static struct drm_fb_helper_funcs bochs_fb_helper_funcs = {
+       .gamma_set = bochs_fb_gamma_set,
+       .gamma_get = bochs_fb_gamma_get,
+       .fb_probe = bochsfb_create,
+};
+
+int bochs_fbdev_init(struct bochs_device *bochs)
+{
+       int ret;
+
+       bochs->fb.helper.funcs = &bochs_fb_helper_funcs;
+       spin_lock_init(&bochs->fb.dirty_lock);
+
+       ret = drm_fb_helper_init(bochs->dev, &bochs->fb.helper,
+                                1, 1);
+       if (ret)
+               return ret;
+
+       drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
+       drm_helper_disable_unused_functions(bochs->dev);
+       drm_fb_helper_initial_config(&bochs->fb.helper, 32);
+
+       bochs->fb.initialized = true;
+       return 0;
+}
+
+void bochs_fbdev_fini(struct bochs_device *bochs)
+{
+       if (!bochs->fb.initialized)
+               return;
+
+       bochs_fbdev_destroy(bochs);
+       bochs->fb.initialized = false;
+}
diff --git a/drivers/gpu/drm/bochs/bochs_hw.c b/drivers/gpu/drm/bochs/bochs_hw.c
new file mode 100644 (file)
index 0000000..dbe619e
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * 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 "bochs.h"
+
+/* ---------------------------------------------------------------------- */
+
+static void bochs_vga_writeb(struct bochs_device *bochs, u16 ioport, u8 val)
+{
+       if (WARN_ON(ioport < 0x3c0 || ioport > 0x3df))
+               return;
+
+       if (bochs->mmio) {
+               int offset = ioport - 0x3c0 + 0x400;
+               writeb(val, bochs->mmio + offset);
+       } else {
+               outb(val, ioport);
+       }
+}
+
+static u16 bochs_dispi_read(struct bochs_device *bochs, u16 reg)
+{
+       u16 ret = 0;
+
+       if (bochs->mmio) {
+               int offset = 0x500 + (reg << 1);
+               ret = readw(bochs->mmio + offset);
+       } else {
+               outw(reg, VBE_DISPI_IOPORT_INDEX);
+               ret = inw(VBE_DISPI_IOPORT_DATA);
+       }
+       return ret;
+}
+
+static void bochs_dispi_write(struct bochs_device *bochs, u16 reg, u16 val)
+{
+       if (bochs->mmio) {
+               int offset = 0x500 + (reg << 1);
+               writew(val, bochs->mmio + offset);
+       } else {
+               outw(reg, VBE_DISPI_IOPORT_INDEX);
+               outw(val, VBE_DISPI_IOPORT_DATA);
+       }
+}
+
+int bochs_hw_init(struct drm_device *dev, uint32_t flags)
+{
+       struct bochs_device *bochs = dev->dev_private;
+       struct pci_dev *pdev = dev->pdev;
+       unsigned long addr, size, mem, ioaddr, iosize;
+       u16 id;
+
+       if (/* (ent->driver_data == BOCHS_QEMU_STDVGA) && */
+           (pdev->resource[2].flags & IORESOURCE_MEM)) {
+               /* mmio bar with vga and bochs registers present */
+               if (pci_request_region(pdev, 2, "bochs-drm") != 0) {
+                       DRM_ERROR("Cannot request mmio region\n");
+                       return -EBUSY;
+               }
+               ioaddr = pci_resource_start(pdev, 2);
+               iosize = pci_resource_len(pdev, 2);
+               bochs->mmio = ioremap(ioaddr, iosize);
+               if (bochs->mmio == NULL) {
+                       DRM_ERROR("Cannot map mmio region\n");
+                       return -ENOMEM;
+               }
+       } else {
+               ioaddr = VBE_DISPI_IOPORT_INDEX;
+               iosize = 2;
+               if (!request_region(ioaddr, iosize, "bochs-drm")) {
+                       DRM_ERROR("Cannot request ioports\n");
+                       return -EBUSY;
+               }
+               bochs->ioports = 1;
+       }
+
+       id = bochs_dispi_read(bochs, VBE_DISPI_INDEX_ID);
+       mem = bochs_dispi_read(bochs, VBE_DISPI_INDEX_VIDEO_MEMORY_64K)
+               * 64 * 1024;
+       if ((id & 0xfff0) != VBE_DISPI_ID0) {
+               DRM_ERROR("ID mismatch\n");
+               return -ENODEV;
+       }
+
+       if ((pdev->resource[0].flags & IORESOURCE_MEM) == 0)
+               return -ENODEV;
+       addr = pci_resource_start(pdev, 0);
+       size = pci_resource_len(pdev, 0);
+       if (addr == 0)
+               return -ENODEV;
+       if (size != mem) {
+               DRM_ERROR("Size mismatch: pci=%ld, bochs=%ld\n",
+                       size, mem);
+               size = min(size, mem);
+       }
+
+       if (pci_request_region(pdev, 0, "bochs-drm") != 0) {
+               DRM_ERROR("Cannot request framebuffer\n");
+               return -EBUSY;
+       }
+
+       bochs->fb_map = ioremap(addr, size);
+       if (bochs->fb_map == NULL) {
+               DRM_ERROR("Cannot map framebuffer\n");
+               return -ENOMEM;
+       }
+       bochs->fb_base = addr;
+       bochs->fb_size = size;
+
+       DRM_INFO("Found bochs VGA, ID 0x%x.\n", id);
+       DRM_INFO("Framebuffer size %ld kB @ 0x%lx, %s @ 0x%lx.\n",
+                size / 1024, addr,
+                bochs->ioports ? "ioports" : "mmio",
+                ioaddr);
+       return 0;
+}
+
+void bochs_hw_fini(struct drm_device *dev)
+{
+       struct bochs_device *bochs = dev->dev_private;
+
+       if (bochs->mmio)
+               iounmap(bochs->mmio);
+       if (bochs->ioports)
+               release_region(VBE_DISPI_IOPORT_INDEX, 2);
+       if (bochs->fb_map)
+               iounmap(bochs->fb_map);
+       pci_release_regions(dev->pdev);
+}
+
+void bochs_hw_setmode(struct bochs_device *bochs,
+                     struct drm_display_mode *mode)
+{
+       bochs->xres = mode->hdisplay;
+       bochs->yres = mode->vdisplay;
+       bochs->bpp = 32;
+       bochs->stride = mode->hdisplay * (bochs->bpp / 8);
+       bochs->yres_virtual = bochs->fb_size / bochs->stride;
+
+       DRM_DEBUG_DRIVER("%dx%d @ %d bpp, vy %d\n",
+                        bochs->xres, bochs->yres, bochs->bpp,
+                        bochs->yres_virtual);
+
+       bochs_vga_writeb(bochs, 0x3c0, 0x20); /* unblank */
+
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_BPP,         bochs->bpp);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_XRES,        bochs->xres);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_YRES,        bochs->yres);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_BANK,        0);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_WIDTH,  bochs->xres);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_VIRT_HEIGHT,
+                         bochs->yres_virtual);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET,    0);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET,    0);
+
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_ENABLE,
+                         VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
+}
+
+void bochs_hw_setbase(struct bochs_device *bochs,
+                     int x, int y, u64 addr)
+{
+       unsigned long offset = (unsigned long)addr +
+               y * bochs->stride +
+               x * (bochs->bpp / 8);
+       int vy = offset / bochs->stride;
+       int vx = (offset % bochs->stride) * 8 / bochs->bpp;
+
+       DRM_DEBUG_DRIVER("x %d, y %d, addr %llx -> offset %lx, vx %d, vy %d\n",
+                        x, y, addr, offset, vx, vy);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_X_OFFSET, vx);
+       bochs_dispi_write(bochs, VBE_DISPI_INDEX_Y_OFFSET, vy);
+}
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
new file mode 100644 (file)
index 0000000..62ec7d4
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ * 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 "bochs.h"
+
+static int defx = 1024;
+static int defy = 768;
+
+module_param(defx, int, 0444);
+module_param(defy, int, 0444);
+MODULE_PARM_DESC(defx, "default x resolution");
+MODULE_PARM_DESC(defy, "default y resolution");
+
+/* ---------------------------------------------------------------------- */
+
+static void bochs_crtc_load_lut(struct drm_crtc *crtc)
+{
+}
+
+static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       switch (mode) {
+       case DRM_MODE_DPMS_ON:
+       case DRM_MODE_DPMS_STANDBY:
+       case DRM_MODE_DPMS_SUSPEND:
+       case DRM_MODE_DPMS_OFF:
+       default:
+               return;
+       }
+}
+
+static bool bochs_crtc_mode_fixup(struct drm_crtc *crtc,
+                                 const struct drm_display_mode *mode,
+                                 struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static int bochs_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+                                   struct drm_framebuffer *old_fb)
+{
+       struct bochs_device *bochs =
+               container_of(crtc, struct bochs_device, crtc);
+       struct bochs_framebuffer *bochs_fb;
+       struct bochs_bo *bo;
+       u64 gpu_addr = 0;
+       int ret;
+
+       if (old_fb) {
+               bochs_fb = to_bochs_framebuffer(old_fb);
+               bo = gem_to_bochs_bo(bochs_fb->obj);
+               ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
+               if (ret) {
+                       DRM_ERROR("failed to reserve old_fb bo\n");
+               } else {
+                       bochs_bo_unpin(bo);
+                       ttm_bo_unreserve(&bo->bo);
+               }
+       }
+
+       if (WARN_ON(crtc->fb == NULL))
+               return -EINVAL;
+
+       bochs_fb = to_bochs_framebuffer(crtc->fb);
+       bo = gem_to_bochs_bo(bochs_fb->obj);
+       ret = ttm_bo_reserve(&bo->bo, true, false, false, 0);
+       if (ret)
+               return ret;
+
+       ret = bochs_bo_pin(bo, TTM_PL_FLAG_VRAM, &gpu_addr);
+       if (ret) {
+               ttm_bo_unreserve(&bo->bo);
+               return ret;
+       }
+
+       ttm_bo_unreserve(&bo->bo);
+       bochs_hw_setbase(bochs, x, y, gpu_addr);
+       return 0;
+}
+
+static int bochs_crtc_mode_set(struct drm_crtc *crtc,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode,
+                              int x, int y, struct drm_framebuffer *old_fb)
+{
+       struct bochs_device *bochs =
+               container_of(crtc, struct bochs_device, crtc);
+
+       bochs_hw_setmode(bochs, mode);
+       bochs_crtc_mode_set_base(crtc, x, y, old_fb);
+       return 0;
+}
+
+static void bochs_crtc_prepare(struct drm_crtc *crtc)
+{
+}
+
+static void bochs_crtc_commit(struct drm_crtc *crtc)
+{
+}
+
+static void bochs_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
+                                u16 *blue, uint32_t start, uint32_t size)
+{
+}
+
+/* These provide the minimum set of functions required to handle a CRTC */
+static const struct drm_crtc_funcs bochs_crtc_funcs = {
+       .gamma_set = bochs_crtc_gamma_set,
+       .set_config = drm_crtc_helper_set_config,
+       .destroy = drm_crtc_cleanup,
+};
+
+static const struct drm_crtc_helper_funcs bochs_helper_funcs = {
+       .dpms = bochs_crtc_dpms,
+       .mode_fixup = bochs_crtc_mode_fixup,
+       .mode_set = bochs_crtc_mode_set,
+       .mode_set_base = bochs_crtc_mode_set_base,
+       .prepare = bochs_crtc_prepare,
+       .commit = bochs_crtc_commit,
+       .load_lut = bochs_crtc_load_lut,
+};
+
+static void bochs_crtc_init(struct drm_device *dev)
+{
+       struct bochs_device *bochs = dev->dev_private;
+       struct drm_crtc *crtc = &bochs->crtc;
+
+       drm_crtc_init(dev, crtc, &bochs_crtc_funcs);
+       drm_mode_crtc_set_gamma_size(crtc, 256);
+       drm_crtc_helper_add(crtc, &bochs_helper_funcs);
+}
+
+static bool bochs_encoder_mode_fixup(struct drm_encoder *encoder,
+                                    const struct drm_display_mode *mode,
+                                    struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void bochs_encoder_mode_set(struct drm_encoder *encoder,
+                                  struct drm_display_mode *mode,
+                                  struct drm_display_mode *adjusted_mode)
+{
+}
+
+static void bochs_encoder_dpms(struct drm_encoder *encoder, int state)
+{
+}
+
+static void bochs_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void bochs_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static const struct drm_encoder_helper_funcs bochs_encoder_helper_funcs = {
+       .dpms = bochs_encoder_dpms,
+       .mode_fixup = bochs_encoder_mode_fixup,
+       .mode_set = bochs_encoder_mode_set,
+       .prepare = bochs_encoder_prepare,
+       .commit = bochs_encoder_commit,
+};
+
+static const struct drm_encoder_funcs bochs_encoder_encoder_funcs = {
+       .destroy = drm_encoder_cleanup,
+};
+
+static void bochs_encoder_init(struct drm_device *dev)
+{
+       struct bochs_device *bochs = dev->dev_private;
+       struct drm_encoder *encoder = &bochs->encoder;
+
+       encoder->possible_crtcs = 0x1;
+       drm_encoder_init(dev, encoder, &bochs_encoder_encoder_funcs,
+                        DRM_MODE_ENCODER_DAC);
+       drm_encoder_helper_add(encoder, &bochs_encoder_helper_funcs);
+}
+
+
+int bochs_connector_get_modes(struct drm_connector *connector)
+{
+       int count;
+
+       count = drm_add_modes_noedid(connector, 8192, 8192);
+       drm_set_preferred_mode(connector, defx, defy);
+       return count;
+}
+
+static int bochs_connector_mode_valid(struct drm_connector *connector,
+                                     struct drm_display_mode *mode)
+{
+       struct bochs_device *bochs =
+               container_of(connector, struct bochs_device, connector);
+       unsigned long size = mode->hdisplay * mode->vdisplay * 4;
+
+       /*
+        * Make sure we can fit two framebuffers into video memory.
+        * This allows up to 1600x1200 with 16 MB (default size).
+        * If you want more try this:
+        *     'qemu -vga std -global VGA.vgamem_mb=32 $otherargs'
+        */
+       if (size * 2 > bochs->fb_size)
+               return MODE_BAD;
+
+       return MODE_OK;
+}
+
+static struct drm_encoder *
+bochs_connector_best_encoder(struct drm_connector *connector)
+{
+       int enc_id = connector->encoder_ids[0];
+       struct drm_mode_object *obj;
+       struct drm_encoder *encoder;
+
+       /* pick the encoder ids */
+       if (enc_id) {
+               obj = drm_mode_object_find(connector->dev, enc_id,
+                                          DRM_MODE_OBJECT_ENCODER);
+               if (!obj)
+                       return NULL;
+               encoder = obj_to_encoder(obj);
+               return encoder;
+       }
+       return NULL;
+}
+
+static enum drm_connector_status bochs_connector_detect(struct drm_connector
+                                                       *connector, bool force)
+{
+       return connector_status_connected;
+}
+
+struct drm_connector_helper_funcs bochs_connector_connector_helper_funcs = {
+       .get_modes = bochs_connector_get_modes,
+       .mode_valid = bochs_connector_mode_valid,
+       .best_encoder = bochs_connector_best_encoder,
+};
+
+struct drm_connector_funcs bochs_connector_connector_funcs = {
+       .dpms = drm_helper_connector_dpms,
+       .detect = bochs_connector_detect,
+       .fill_modes = drm_helper_probe_single_connector_modes,
+       .destroy = drm_connector_cleanup,
+};
+
+static void bochs_connector_init(struct drm_device *dev)
+{
+       struct bochs_device *bochs = dev->dev_private;
+       struct drm_connector *connector = &bochs->connector;
+
+       drm_connector_init(dev, connector, &bochs_connector_connector_funcs,
+                          DRM_MODE_CONNECTOR_VIRTUAL);
+       drm_connector_helper_add(connector,
+                                &bochs_connector_connector_helper_funcs);
+}
+
+
+int bochs_kms_init(struct bochs_device *bochs)
+{
+       drm_mode_config_init(bochs->dev);
+       bochs->mode_config_initialized = true;
+
+       bochs->dev->mode_config.max_width = 8192;
+       bochs->dev->mode_config.max_height = 8192;
+
+       bochs->dev->mode_config.fb_base = bochs->fb_base;
+       bochs->dev->mode_config.preferred_depth = 24;
+       bochs->dev->mode_config.prefer_shadow = 0;
+
+       bochs->dev->mode_config.funcs = (void *)&bochs_mode_funcs;
+
+       bochs_crtc_init(bochs->dev);
+       bochs_encoder_init(bochs->dev);
+       bochs_connector_init(bochs->dev);
+       drm_mode_connector_attach_encoder(&bochs->connector,
+                                         &bochs->encoder);
+
+       return 0;
+}
+
+void bochs_kms_fini(struct bochs_device *bochs)
+{
+       if (bochs->mode_config_initialized) {
+               drm_mode_config_cleanup(bochs->dev);
+               bochs->mode_config_initialized = false;
+       }
+}
diff --git a/drivers/gpu/drm/bochs/bochs_mm.c b/drivers/gpu/drm/bochs/bochs_mm.c
new file mode 100644 (file)
index 0000000..ce68587
--- /dev/null
@@ -0,0 +1,546 @@
+/*
+ * 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 "bochs.h"
+
+static void bochs_ttm_placement(struct bochs_bo *bo, int domain);
+
+/* ---------------------------------------------------------------------- */
+
+static inline struct bochs_device *bochs_bdev(struct ttm_bo_device *bd)
+{
+       return container_of(bd, struct bochs_device, ttm.bdev);
+}
+
+static int bochs_ttm_mem_global_init(struct drm_global_reference *ref)
+{
+       return ttm_mem_global_init(ref->object);
+}
+
+static void bochs_ttm_mem_global_release(struct drm_global_reference *ref)
+{
+       ttm_mem_global_release(ref->object);
+}
+
+static int bochs_ttm_global_init(struct bochs_device *bochs)
+{
+       struct drm_global_reference *global_ref;
+       int r;
+
+       global_ref = &bochs->ttm.mem_global_ref;
+       global_ref->global_type = DRM_GLOBAL_TTM_MEM;
+       global_ref->size = sizeof(struct ttm_mem_global);
+       global_ref->init = &bochs_ttm_mem_global_init;
+       global_ref->release = &bochs_ttm_mem_global_release;
+       r = drm_global_item_ref(global_ref);
+       if (r != 0) {
+               DRM_ERROR("Failed setting up TTM memory accounting "
+                         "subsystem.\n");
+               return r;
+       }
+
+       bochs->ttm.bo_global_ref.mem_glob =
+               bochs->ttm.mem_global_ref.object;
+       global_ref = &bochs->ttm.bo_global_ref.ref;
+       global_ref->global_type = DRM_GLOBAL_TTM_BO;
+       global_ref->size = sizeof(struct ttm_bo_global);
+       global_ref->init = &ttm_bo_global_init;
+       global_ref->release = &ttm_bo_global_release;
+       r = drm_global_item_ref(global_ref);
+       if (r != 0) {
+               DRM_ERROR("Failed setting up TTM BO subsystem.\n");
+               drm_global_item_unref(&bochs->ttm.mem_global_ref);
+               return r;
+       }
+
+       return 0;
+}
+
+static void bochs_ttm_global_release(struct bochs_device *bochs)
+{
+       if (bochs->ttm.mem_global_ref.release == NULL)
+               return;
+
+       drm_global_item_unref(&bochs->ttm.bo_global_ref.ref);
+       drm_global_item_unref(&bochs->ttm.mem_global_ref);
+       bochs->ttm.mem_global_ref.release = NULL;
+}
+
+
+static void bochs_bo_ttm_destroy(struct ttm_buffer_object *tbo)
+{
+       struct bochs_bo *bo;
+
+       bo = container_of(tbo, struct bochs_bo, bo);
+       drm_gem_object_release(&bo->gem);
+       kfree(bo);
+}
+
+static bool bochs_ttm_bo_is_bochs_bo(struct ttm_buffer_object *bo)
+{
+       if (bo->destroy == &bochs_bo_ttm_destroy)
+               return true;
+       return false;
+}
+
+static int bochs_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+                                 struct ttm_mem_type_manager *man)
+{
+       switch (type) {
+       case TTM_PL_SYSTEM:
+               man->flags = TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_MASK_CACHING;
+               man->default_caching = TTM_PL_FLAG_CACHED;
+               break;
+       case TTM_PL_VRAM:
+               man->func = &ttm_bo_manager_func;
+               man->flags = TTM_MEMTYPE_FLAG_FIXED |
+                       TTM_MEMTYPE_FLAG_MAPPABLE;
+               man->available_caching = TTM_PL_FLAG_UNCACHED |
+                       TTM_PL_FLAG_WC;
+               man->default_caching = TTM_PL_FLAG_WC;
+               break;
+       default:
+               DRM_ERROR("Unsupported memory type %u\n", (unsigned)type);
+               return -EINVAL;
+       }
+       return 0;
+}
+
+static void
+bochs_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
+{
+       struct bochs_bo *bochsbo = bochs_bo(bo);
+
+       if (!bochs_ttm_bo_is_bochs_bo(bo))
+               return;
+
+       bochs_ttm_placement(bochsbo, TTM_PL_FLAG_SYSTEM);
+       *pl = bochsbo->placement;
+}
+
+static int bochs_bo_verify_access(struct ttm_buffer_object *bo,
+                                 struct file *filp)
+{
+       struct bochs_bo *bochsbo = bochs_bo(bo);
+
+       return drm_vma_node_verify_access(&bochsbo->gem.vma_node, filp);
+}
+
+static int bochs_ttm_io_mem_reserve(struct ttm_bo_device *bdev,
+                                   struct ttm_mem_reg *mem)
+{
+       struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
+       struct bochs_device *bochs = bochs_bdev(bdev);
+
+       mem->bus.addr = NULL;
+       mem->bus.offset = 0;
+       mem->bus.size = mem->num_pages << PAGE_SHIFT;
+       mem->bus.base = 0;
+       mem->bus.is_iomem = false;
+       if (!(man->flags & TTM_MEMTYPE_FLAG_MAPPABLE))
+               return -EINVAL;
+       switch (mem->mem_type) {
+       case TTM_PL_SYSTEM:
+               /* system memory */
+               return 0;
+       case TTM_PL_VRAM:
+               mem->bus.offset = mem->start << PAGE_SHIFT;
+               mem->bus.base = bochs->fb_base;
+               mem->bus.is_iomem = true;
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+       return 0;
+}
+
+static void bochs_ttm_io_mem_free(struct ttm_bo_device *bdev,
+                                 struct ttm_mem_reg *mem)
+{
+}
+
+static int bochs_bo_move(struct ttm_buffer_object *bo,
+                        bool evict, bool interruptible,
+                        bool no_wait_gpu,
+                        struct ttm_mem_reg *new_mem)
+{
+       return ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
+}
+
+
+static void bochs_ttm_backend_destroy(struct ttm_tt *tt)
+{
+       ttm_tt_fini(tt);
+       kfree(tt);
+}
+
+static struct ttm_backend_func bochs_tt_backend_func = {
+       .destroy = &bochs_ttm_backend_destroy,
+};
+
+static struct ttm_tt *bochs_ttm_tt_create(struct ttm_bo_device *bdev,
+                                         unsigned long size,
+                                         uint32_t page_flags,
+                                         struct page *dummy_read_page)
+{
+       struct ttm_tt *tt;
+
+       tt = kzalloc(sizeof(struct ttm_tt), GFP_KERNEL);
+       if (tt == NULL)
+               return NULL;
+       tt->func = &bochs_tt_backend_func;
+       if (ttm_tt_init(tt, bdev, size, page_flags, dummy_read_page)) {
+               kfree(tt);
+               return NULL;
+       }
+       return tt;
+}
+
+struct ttm_bo_driver bochs_bo_driver = {
+       .ttm_tt_create = bochs_ttm_tt_create,
+       .ttm_tt_populate = ttm_pool_populate,
+       .ttm_tt_unpopulate = ttm_pool_unpopulate,
+       .init_mem_type = bochs_bo_init_mem_type,
+       .evict_flags = bochs_bo_evict_flags,
+       .move = bochs_bo_move,
+       .verify_access = bochs_bo_verify_access,
+       .io_mem_reserve = &bochs_ttm_io_mem_reserve,
+       .io_mem_free = &bochs_ttm_io_mem_free,
+};
+
+int bochs_mm_init(struct bochs_device *bochs)
+{
+       struct ttm_bo_device *bdev = &bochs->ttm.bdev;
+       int ret;
+
+       ret = bochs_ttm_global_init(bochs);
+       if (ret)
+               return ret;
+
+       ret = ttm_bo_device_init(&bochs->ttm.bdev,
+                                bochs->ttm.bo_global_ref.ref.object,
+                                &bochs_bo_driver, DRM_FILE_PAGE_OFFSET,
+                                true);
+       if (ret) {
+               DRM_ERROR("Error initialising bo driver; %d\n", ret);
+               return ret;
+       }
+
+       ret = ttm_bo_init_mm(bdev, TTM_PL_VRAM,
+                            bochs->fb_size >> PAGE_SHIFT);
+       if (ret) {
+               DRM_ERROR("Failed ttm VRAM init: %d\n", ret);
+               return ret;
+       }
+
+       bochs->ttm.initialized = true;
+       return 0;
+}
+
+void bochs_mm_fini(struct bochs_device *bochs)
+{
+       if (!bochs->ttm.initialized)
+               return;
+
+       ttm_bo_device_release(&bochs->ttm.bdev);
+       bochs_ttm_global_release(bochs);
+       bochs->ttm.initialized = false;
+}
+
+static void bochs_ttm_placement(struct bochs_bo *bo, int domain)
+{
+       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
+                       | TTM_PL_FLAG_VRAM;
+       }
+       if (domain & TTM_PL_FLAG_SYSTEM) {
+               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+       }
+       if (!c) {
+               bo->placements[c++] = TTM_PL_MASK_CACHING | TTM_PL_FLAG_SYSTEM;
+       }
+       bo->placement.num_placement = c;
+       bo->placement.num_busy_placement = c;
+}
+
+static inline u64 bochs_bo_gpu_offset(struct bochs_bo *bo)
+{
+       return bo->bo.offset;
+}
+
+int bochs_bo_pin(struct bochs_bo *bo, u32 pl_flag, u64 *gpu_addr)
+{
+       int i, ret;
+
+       if (bo->pin_count) {
+               bo->pin_count++;
+               if (gpu_addr)
+                       *gpu_addr = bochs_bo_gpu_offset(bo);
+               return 0;
+       }
+
+       bochs_ttm_placement(bo, pl_flag);
+       for (i = 0; i < bo->placement.num_placement; i++)
+               bo->placements[i] |= TTM_PL_FLAG_NO_EVICT;
+       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+       if (ret)
+               return ret;
+
+       bo->pin_count = 1;
+       if (gpu_addr)
+               *gpu_addr = bochs_bo_gpu_offset(bo);
+       return 0;
+}
+
+int bochs_bo_unpin(struct bochs_bo *bo)
+{
+       int i, ret;
+
+       if (!bo->pin_count) {
+               DRM_ERROR("unpin bad %p\n", bo);
+               return 0;
+       }
+       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;
+       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
+       if (ret)
+               return ret;
+
+       return 0;
+}
+
+int bochs_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+       struct drm_file *file_priv;
+       struct bochs_device *bochs;
+
+       if (unlikely(vma->vm_pgoff < DRM_FILE_PAGE_OFFSET))
+               return drm_mmap(filp, vma);
+
+       file_priv = filp->private_data;
+       bochs = file_priv->minor->dev->dev_private;
+       return ttm_bo_mmap(filp, vma, &bochs->ttm.bdev);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int bochs_bo_create(struct drm_device *dev, int size, int align,
+                          uint32_t flags, struct bochs_bo **pbochsbo)
+{
+       struct bochs_device *bochs = dev->dev_private;
+       struct bochs_bo *bochsbo;
+       size_t acc_size;
+       int ret;
+
+       bochsbo = kzalloc(sizeof(struct bochs_bo), GFP_KERNEL);
+       if (!bochsbo)
+               return -ENOMEM;
+
+       ret = drm_gem_object_init(dev, &bochsbo->gem, size);
+       if (ret) {
+               kfree(bochsbo);
+               return ret;
+       }
+
+       bochsbo->bo.bdev = &bochs->ttm.bdev;
+       bochsbo->bo.bdev->dev_mapping = dev->dev_mapping;
+
+       bochs_ttm_placement(bochsbo, TTM_PL_FLAG_VRAM | TTM_PL_FLAG_SYSTEM);
+
+       acc_size = ttm_bo_dma_acc_size(&bochs->ttm.bdev, size,
+                                      sizeof(struct bochs_bo));
+
+       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);
+       if (ret)
+               return ret;
+
+       *pbochsbo = bochsbo;
+       return 0;
+}
+
+int bochs_gem_create(struct drm_device *dev, u32 size, bool iskernel,
+                    struct drm_gem_object **obj)
+{
+       struct bochs_bo *bochsbo;
+       int ret;
+
+       *obj = NULL;
+
+       size = ALIGN(size, PAGE_SIZE);
+       if (size == 0)
+               return -EINVAL;
+
+       ret = bochs_bo_create(dev, size, 0, 0, &bochsbo);
+       if (ret) {
+               if (ret != -ERESTARTSYS)
+                       DRM_ERROR("failed to allocate GEM object\n");
+               return ret;
+       }
+       *obj = &bochsbo->gem;
+       return 0;
+}
+
+int bochs_dumb_create(struct drm_file *file, struct drm_device *dev,
+                     struct drm_mode_create_dumb *args)
+{
+       struct drm_gem_object *gobj;
+       u32 handle;
+       int ret;
+
+       args->pitch = args->width * ((args->bpp + 7) / 8);
+       args->size = args->pitch * args->height;
+
+       ret = bochs_gem_create(dev, args->size, false,
+                              &gobj);
+       if (ret)
+               return ret;
+
+       ret = drm_gem_handle_create(file, gobj, &handle);
+       drm_gem_object_unreference_unlocked(gobj);
+       if (ret)
+               return ret;
+
+       args->handle = handle;
+       return 0;
+}
+
+static void bochs_bo_unref(struct bochs_bo **bo)
+{
+       struct ttm_buffer_object *tbo;
+
+       if ((*bo) == NULL)
+               return;
+
+       tbo = &((*bo)->bo);
+       ttm_bo_unref(&tbo);
+       if (tbo == NULL)
+               *bo = NULL;
+
+}
+
+void bochs_gem_free_object(struct drm_gem_object *obj)
+{
+       struct bochs_bo *bochs_bo = gem_to_bochs_bo(obj);
+
+       if (!bochs_bo)
+               return;
+       bochs_bo_unref(&bochs_bo);
+}
+
+int bochs_dumb_mmap_offset(struct drm_file *file, struct drm_device *dev,
+                          uint32_t handle, uint64_t *offset)
+{
+       struct drm_gem_object *obj;
+       int ret;
+       struct bochs_bo *bo;
+
+       mutex_lock(&dev->struct_mutex);
+       obj = drm_gem_object_lookup(dev, file, handle);
+       if (obj == NULL) {
+               ret = -ENOENT;
+               goto out_unlock;
+       }
+
+       bo = gem_to_bochs_bo(obj);
+       *offset = bochs_bo_mmap_offset(bo);
+
+       drm_gem_object_unreference(obj);
+       ret = 0;
+out_unlock:
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
+
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void bochs_user_framebuffer_destroy(struct drm_framebuffer *fb)
+{
+       struct bochs_framebuffer *bochs_fb = to_bochs_framebuffer(fb);
+       if (bochs_fb->obj)
+               drm_gem_object_unreference_unlocked(bochs_fb->obj);
+       drm_framebuffer_cleanup(fb);
+       kfree(fb);
+}
+
+static const struct drm_framebuffer_funcs bochs_fb_funcs = {
+       .destroy = bochs_user_framebuffer_destroy,
+};
+
+int bochs_framebuffer_init(struct drm_device *dev,
+                          struct bochs_framebuffer *gfb,
+                          struct drm_mode_fb_cmd2 *mode_cmd,
+                          struct drm_gem_object *obj)
+{
+       int ret;
+
+       drm_helper_mode_fill_fb_struct(&gfb->base, mode_cmd);
+       gfb->obj = obj;
+       ret = drm_framebuffer_init(dev, &gfb->base, &bochs_fb_funcs);
+       if (ret) {
+               DRM_ERROR("drm_framebuffer_init failed: %d\n", ret);
+               return ret;
+       }
+       return 0;
+}
+
+static struct drm_framebuffer *
+bochs_user_framebuffer_create(struct drm_device *dev,
+                             struct drm_file *filp,
+                             struct drm_mode_fb_cmd2 *mode_cmd)
+{
+       struct drm_gem_object *obj;
+       struct bochs_framebuffer *bochs_fb;
+       int ret;
+
+       DRM_DEBUG_DRIVER("%dx%d, format %c%c%c%c\n",
+              mode_cmd->width, mode_cmd->height,
+              (mode_cmd->pixel_format)       & 0xff,
+              (mode_cmd->pixel_format >> 8)  & 0xff,
+              (mode_cmd->pixel_format >> 16) & 0xff,
+              (mode_cmd->pixel_format >> 24) & 0xff);
+
+       if (mode_cmd->pixel_format != DRM_FORMAT_XRGB8888)
+               return ERR_PTR(-ENOENT);
+
+       obj = drm_gem_object_lookup(dev, filp, mode_cmd->handles[0]);
+       if (obj == NULL)
+               return ERR_PTR(-ENOENT);
+
+       bochs_fb = kzalloc(sizeof(*bochs_fb), GFP_KERNEL);
+       if (!bochs_fb) {
+               drm_gem_object_unreference_unlocked(obj);
+               return ERR_PTR(-ENOMEM);
+       }
+
+       ret = bochs_framebuffer_init(dev, bochs_fb, mode_cmd, obj);
+       if (ret) {
+               drm_gem_object_unreference_unlocked(obj);
+               kfree(bochs_fb);
+               return ERR_PTR(ret);
+       }
+       return &bochs_fb->base;
+}
+
+const struct drm_mode_config_funcs bochs_mode_funcs = {
+       .fb_create = bochs_user_framebuffer_create,
+};
index b6aded73838bca0fb11c5a936db40a8db1e1e180..117d3eca5e3782e5db3571a968d8e92111c1da4c 100644 (file)
@@ -222,7 +222,7 @@ void cirrus_fbdev_fini(struct cirrus_device *cdev);
 void cirrus_driver_irq_preinstall(struct drm_device *dev);
 int cirrus_driver_irq_postinstall(struct drm_device *dev);
 void cirrus_driver_irq_uninstall(struct drm_device *dev);
-irqreturn_t cirrus_driver_irq_handler(DRM_IRQ_ARGS);
+irqreturn_t cirrus_driver_irq_handler(int irq, void *arg);
 
                                /* cirrus_kms.c */
 int cirrus_driver_load(struct drm_device *dev, unsigned long flags);
index b27e95666fabf6fb28d56b07cd62fd3363776a0b..2fd4a92162cb8880b3c0834ee294184b57b7edf7 100644 (file)
@@ -39,7 +39,7 @@ static void cirrus_dirty_update(struct cirrus_fbdev *afbdev,
         * then the BO is being moved and we should
         * store up the damage until later.
         */
-       if (!in_interrupt())
+       if (!drm_can_sleep())
                ret = cirrus_bo_reserve(bo, true);
        if (ret) {
                if (ret != -EBUSY)
@@ -233,6 +233,9 @@ static int cirrusfb_create(struct drm_fb_helper *helper,
        info->apertures->ranges[0].base = cdev->dev->mode_config.fb_base;
        info->apertures->ranges[0].size = cdev->mc.vram_size;
 
+       info->fix.smem_start = cdev->dev->mode_config.fb_base;
+       info->fix.smem_len = cdev->mc.vram_size;
+
        info->screen_base = sysram;
        info->screen_size = size;
 
index 78e76f24343d17bad9bc81e5474f900fbd090b33..4b0170cf53fd9225f07f731766cb8fe71fb40e91 100644 (file)
@@ -255,7 +255,7 @@ int cirrus_dumb_create(struct drm_file *file,
        return 0;
 }
 
-void cirrus_bo_unref(struct cirrus_bo **bo)
+static void cirrus_bo_unref(struct cirrus_bo **bo)
 {
        struct ttm_buffer_object *tbo;
 
index adabc3daaa5b4f644969944a28de07921ab1895d..530f78f84deed250a2f96350254657b49a0166c9 100644 (file)
@@ -102,7 +102,7 @@ static bool cirrus_crtc_mode_fixup(struct drm_crtc *crtc,
        return true;
 }
 
-void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset)
+static void cirrus_set_start_address(struct drm_crtc *crtc, unsigned offset)
 {
        struct cirrus_device *cdev = crtc->dev->dev_private;
        u32 addr;
@@ -273,8 +273,8 @@ static int cirrus_crtc_mode_set(struct drm_crtc *crtc,
                sr07 |= 0x11;
                break;
        case 16:
-               sr07 |= 0xc1;
-               hdr = 0xc0;
+               sr07 |= 0x17;
+               hdr = 0xc1;
                break;
        case 24:
                sr07 |= 0x15;
@@ -453,7 +453,7 @@ static void cirrus_encoder_commit(struct drm_encoder *encoder)
 {
 }
 
-void cirrus_encoder_destroy(struct drm_encoder *encoder)
+static void cirrus_encoder_destroy(struct drm_encoder *encoder)
 {
        struct cirrus_encoder *cirrus_encoder = to_cirrus_encoder(encoder);
        drm_encoder_cleanup(encoder);
@@ -492,7 +492,7 @@ static struct drm_encoder *cirrus_encoder_init(struct drm_device *dev)
 }
 
 
-int cirrus_vga_get_modes(struct drm_connector *connector)
+static int cirrus_vga_get_modes(struct drm_connector *connector)
 {
        int count;
 
@@ -509,7 +509,7 @@ static int cirrus_vga_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
-struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector
+static struct drm_encoder *cirrus_connector_best_encoder(struct drm_connector
                                                  *connector)
 {
        int enc_id = connector->encoder_ids[0];
index 75becdeac07d710e1322a64096df65850bf31fd4..8b37c25ff9bd0074810fc942fcee38fab3cbab4a 100644 (file)
@@ -80,7 +80,7 @@ static int cirrus_ttm_global_init(struct cirrus_device *cirrus)
        return 0;
 }
 
-void
+static void
 cirrus_ttm_global_release(struct cirrus_device *cirrus)
 {
        if (cirrus->ttm.mem_global_ref.release == NULL)
@@ -102,7 +102,7 @@ static void cirrus_bo_ttm_destroy(struct ttm_buffer_object *tbo)
        kfree(bo);
 }
 
-bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo)
+static bool cirrus_ttm_bo_is_cirrus_bo(struct ttm_buffer_object *bo)
 {
        if (bo->destroy == &cirrus_bo_ttm_destroy)
                return true;
@@ -208,7 +208,7 @@ static struct ttm_backend_func cirrus_tt_backend_func = {
 };
 
 
-struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev,
+static struct ttm_tt *cirrus_ttm_tt_create(struct ttm_bo_device *bdev,
                                 unsigned long size, uint32_t page_flags,
                                 struct page *dummy_read_page)
 {
@@ -375,26 +375,6 @@ int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr)
        return 0;
 }
 
-int cirrus_bo_unpin(struct cirrus_bo *bo)
-{
-       int i, ret;
-       if (!bo->pin_count) {
-               DRM_ERROR("unpin bad %p\n", bo);
-               return 0;
-       }
-       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;
-       ret = ttm_bo_validate(&bo->bo, &bo->placement, false, false);
-       if (ret)
-               return ret;
-
-       return 0;
-}
-
 int cirrus_bo_push_sysram(struct cirrus_bo *bo)
 {
        int i, ret;
index e301d653d97e42f4537efdb50806cdc682930505..dde205cef384c08db92d114c16138c607ddc1da0 100644 (file)
@@ -53,7 +53,7 @@
  */
 int drm_agp_info(struct drm_device *dev, struct drm_agp_info *info)
 {
-       DRM_AGP_KERN *kern;
+       struct agp_kern_info *kern;
 
        if (!dev->agp || !dev->agp->acquired)
                return -EINVAL;
@@ -198,17 +198,15 @@ int drm_agp_enable_ioctl(struct drm_device *dev, void *data,
 int drm_agp_alloc(struct drm_device *dev, struct drm_agp_buffer *request)
 {
        struct drm_agp_mem *entry;
-       DRM_AGP_MEM *memory;
+       struct agp_memory *memory;
        unsigned long pages;
        u32 type;
 
        if (!dev->agp || !dev->agp->acquired)
                return -EINVAL;
-       if (!(entry = kmalloc(sizeof(*entry), GFP_KERNEL)))
+       if (!(entry = kzalloc(sizeof(*entry), GFP_KERNEL)))
                return -ENOMEM;
 
-       memset(entry, 0, sizeof(*entry));
-
        pages = (request->size + PAGE_SIZE - 1) / PAGE_SIZE;
        type = (u32) request->type;
        if (!(memory = agp_allocate_memory(dev->agp->bridge, pages, type))) {
@@ -393,14 +391,16 @@ int drm_agp_free_ioctl(struct drm_device *dev, void *data,
  * Gets the drm_agp_t structure which is made available by the agpgart module
  * via the inter_module_* functions. Creates and initializes a drm_agp_head
  * structure.
+ *
+ * Note that final cleanup of the kmalloced structure is directly done in
+ * drm_pci_agp_destroy.
  */
 struct drm_agp_head *drm_agp_init(struct drm_device *dev)
 {
        struct drm_agp_head *head = NULL;
 
-       if (!(head = kmalloc(sizeof(*head), GFP_KERNEL)))
+       if (!(head = kzalloc(sizeof(*head), GFP_KERNEL)))
                return NULL;
-       memset((void *)head, 0, sizeof(*head));
        head->bridge = agp_find_bridge(dev->pdev);
        if (!head->bridge) {
                if (!(head->bridge = agp_backend_acquire(dev->pdev))) {
@@ -439,7 +439,7 @@ void drm_agp_clear(struct drm_device *dev)
 {
        struct drm_agp_mem *entry, *tempe;
 
-       if (!drm_core_has_AGP(dev) || !dev->agp)
+       if (!dev->agp)
                return;
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return;
@@ -459,21 +459,6 @@ void drm_agp_clear(struct drm_device *dev)
        dev->agp->enabled = 0;
 }
 
-/**
- * drm_agp_destroy - Destroy AGP head
- * @dev: DRM device
- *
- * Destroy resources that were previously allocated via drm_agp_initp. Caller
- * must ensure to clean up all AGP resources before calling this. See
- * drm_agp_clear().
- *
- * Call this to destroy AGP heads allocated via drm_agp_init().
- */
-void drm_agp_destroy(struct drm_agp_head *agp)
-{
-       kfree(agp);
-}
-
 /**
  * Binds a collection of pages into AGP memory at the given offset, returning
  * the AGP memory structure containing them.
@@ -481,14 +466,14 @@ void drm_agp_destroy(struct drm_agp_head *agp)
  * No reference is held on the pages during this time -- it is up to the
  * caller to handle that.
  */
-DRM_AGP_MEM *
+struct agp_memory *
 drm_agp_bind_pages(struct drm_device *dev,
                   struct page **pages,
                   unsigned long num_pages,
                   uint32_t gtt_offset,
                   u32 type)
 {
-       DRM_AGP_MEM *mem;
+       struct agp_memory *mem;
        int ret, i;
 
        DRM_DEBUG("\n");
index 39a718340319ea13ce3f813ea30b82d60c0b9264..0406110f83edd2ac3f607fe575c8e7b6c491e88a 100644 (file)
@@ -114,7 +114,7 @@ int drm_buffer_copy_from_user(struct drm_buffer *buf,
 
        for (idx = 0; idx < nr_pages; ++idx) {
 
-               if (DRM_COPY_FROM_USER(buf->data[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"
index 471e051d295e383b61ebb2a2a19c0e0d67d8827a..edec31fe3fed865aa2669e7c8e17aec912a82058 100644 (file)
@@ -261,7 +261,7 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
                struct drm_agp_mem *entry;
                int valid = 0;
 
-               if (!drm_core_has_AGP(dev)) {
+               if (!dev->agp) {
                        kfree(map);
                        return -EINVAL;
                }
@@ -303,9 +303,6 @@ static int drm_addmap_core(struct drm_device * dev, resource_size_t offset,
 
                break;
        }
-       case _DRM_GEM:
-               DRM_ERROR("tried to addmap GEM object\n");
-               break;
        case _DRM_SCATTER_GATHER:
                if (!dev->sg) {
                        kfree(map);
@@ -483,9 +480,6 @@ int drm_rmmap_locked(struct drm_device *dev, struct drm_local_map *map)
                dmah.size = map->size;
                __drm_pci_free(dev, &dmah);
                break;
-       case _DRM_GEM:
-               DRM_ERROR("tried to rmmap GEM object\n");
-               break;
        }
        kfree(map);
 
@@ -1396,7 +1390,7 @@ int drm_mapbufs(struct drm_device *dev, void *data,
        spin_unlock(&dev->count_lock);
 
        if (request->count >= dma->buf_count) {
-               if ((drm_core_has_AGP(dev) && (dma->flags & _DRM_DMA_USE_AGP))
+               if ((dev->agp && (dma->flags & _DRM_DMA_USE_AGP))
                    || (drm_core_check_feature(dev, DRIVER_SG)
                        && (dma->flags & _DRM_DMA_USE_SG))) {
                        struct drm_local_map *map = dev->agp_buffer_map;
index d6cf77c472e710cf246193dca874bd3b8bc72b9e..3b7d32da16046ffcdc238ba41b1b03a3ec152435 100644 (file)
@@ -674,6 +674,29 @@ void drm_crtc_cleanup(struct drm_crtc *crtc)
 }
 EXPORT_SYMBOL(drm_crtc_cleanup);
 
+/**
+ * drm_crtc_index - find the index of a registered CRTC
+ * @crtc: CRTC to find index for
+ *
+ * Given a registered CRTC, return the index of that CRTC within a DRM
+ * device's list of CRTCs.
+ */
+unsigned int drm_crtc_index(struct drm_crtc *crtc)
+{
+       unsigned int index = 0;
+       struct drm_crtc *tmp;
+
+       list_for_each_entry(tmp, &crtc->dev->mode_config.crtc_list, head) {
+               if (tmp == crtc)
+                       return index;
+
+               index++;
+       }
+
+       BUG();
+}
+EXPORT_SYMBOL(drm_crtc_index);
+
 /**
  * drm_mode_probed_add - add a mode to a connector's probed mode list
  * @connector: connector the new mode
@@ -2767,10 +2790,8 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
        }
 
        if (fb->funcs->dirty) {
-               drm_modeset_lock_all(dev);
                ret = fb->funcs->dirty(fb, file_priv, flags, r->color,
                                       clips, num_clips);
-               drm_modeset_unlock_all(dev);
        } else {
                ret = -ENOSYS;
        }
index 01361aba033b4a39888a41bc15c4a7f5e4052152..ea92b827e787e3543a745b119822085618c16988 100644 (file)
@@ -324,35 +324,6 @@ void drm_helper_disable_unused_functions(struct drm_device *dev)
 }
 EXPORT_SYMBOL(drm_helper_disable_unused_functions);
 
-/**
- * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
- * @encoder: encoder to test
- * @crtc: crtc to test
- *
- * Return false if @encoder can't be driven by @crtc, true otherwise.
- */
-static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
-                               struct drm_crtc *crtc)
-{
-       struct drm_device *dev;
-       struct drm_crtc *tmp;
-       int crtc_mask = 1;
-
-       WARN(!crtc, "checking null crtc?\n");
-
-       dev = crtc->dev;
-
-       list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
-               if (tmp == crtc)
-                       break;
-               crtc_mask <<= 1;
-       }
-
-       if (encoder->possible_crtcs & crtc_mask)
-               return true;
-       return false;
-}
-
 /*
  * Check the CRTC we're going to map each output to vs. its current
  * CRTC.  If they don't match, we have to disable the output and the CRTC
@@ -536,7 +507,7 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
         * are later needed by vblank and swap-completion
         * timestamping. They are derived from true hwmode.
         */
-       drm_calc_timestamping_constants(crtc);
+       drm_calc_timestamping_constants(crtc, &crtc->hwmode);
 
        /* FIXME: add subpixel order */
 done:
index d9137e49c4e81594a992297a1dd10181006faf06..345be03c23db27203d4ce69bd74586a77e8f6ab1 100644 (file)
@@ -315,9 +315,6 @@ long drm_ioctl(struct file *filp,
        if (drm_device_is_unplugged(dev))
                return -ENODEV;
 
-       atomic_inc(&dev->ioctl_count);
-       ++file_priv->ioctl_count;
-
        if ((nr >= DRM_CORE_IOCTL_COUNT) &&
            ((nr < DRM_COMMAND_BASE) || (nr >= DRM_COMMAND_END)))
                goto err_i1;
@@ -410,7 +407,6 @@ long drm_ioctl(struct file *filp,
 
        if (kdata != stack_kdata)
                kfree(kdata);
-       atomic_dec(&dev->ioctl_count);
        if (retcode)
                DRM_DEBUG("ret = %d\n", retcode);
        return retcode;
index 8835dcddfac3ab7c3ee1a4ba72360443e730aa74..b924306b84775f39592887a632f76553297c5a57 100644 (file)
@@ -605,347 +605,347 @@ static const struct drm_display_mode edid_cea_modes[] = {
        { DRM_MODE("640x480", DRM_MODE_TYPE_DRIVER, 25175, 640, 656,
                   752, 800, 0, 480, 490, 492, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 2 - 720x480@60Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 3 - 720x480@60Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 27000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 4 - 1280x720@60Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1390,
                   1430, 1650, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 5 - 1920x1080i@60Hz */
        { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
-         .vrefresh = 60, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 60, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 60, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 60, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 10 - 2880x480i@60Hz */
        { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 11 - 2880x480i@60Hz */
        { DRM_MODE("2880x480i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 480, 488, 494, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 12 - 2880x240@60Hz */
        { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 240, 244, 247, 262, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 13 - 2880x240@60Hz */
        { DRM_MODE("2880x240", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2956,
                   3204, 3432, 0, 240, 244, 247, 262, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 14 - 1440x480@60Hz */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
                   1596, 1716, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 15 - 1440x480@60Hz */
        { DRM_MODE("1440x480", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1472,
                   1596, 1716, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 16 - 1920x1080@60Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 17 - 720x576@50Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 18 - 720x576@50Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 27000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 19 - 1280x720@50Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 1720,
                   1760, 1980, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 20 - 1920x1080i@50Hz */
        { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
-         .vrefresh = 50, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 50, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 50, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 50, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 25 - 2880x576i@50Hz */
        { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 26 - 2880x576i@50Hz */
        { DRM_MODE("2880x576i", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 576, 580, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 27 - 2880x288@50Hz */
        { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 288, 290, 293, 312, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 28 - 2880x288@50Hz */
        { DRM_MODE("2880x288", DRM_MODE_TYPE_DRIVER, 54000, 2880, 2928,
                   3180, 3456, 0, 288, 290, 293, 312, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 29 - 1440x576@50Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
                   1592, 1728, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 30 - 1440x576@50Hz */
        { DRM_MODE("1440x576", DRM_MODE_TYPE_DRIVER, 54000, 1440, 1464,
                   1592, 1728, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 31 - 1920x1080@50Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 32 - 1920x1080@24Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2558,
                   2602, 2750, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 24, },
+         .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 33 - 1920x1080@25Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 25, },
+         .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 34 - 1920x1080@30Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 74250, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 30, },
+         .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 35 - 2880x480@60Hz */
        { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
                   3192, 3432, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 36 - 2880x480@60Hz */
        { DRM_MODE("2880x480", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2944,
                   3192, 3432, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 60, },
+         .vrefresh = 60, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 37 - 2880x576@50Hz */
        { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
                   3184, 3456, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 38 - 2880x576@50Hz */
        { DRM_MODE("2880x576", DRM_MODE_TYPE_DRIVER, 108000, 2880, 2928,
                   3184, 3456, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 39 - 1920x1080i@50Hz */
        { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 72000, 1920, 1952,
                   2120, 2304, 0, 1080, 1126, 1136, 1250, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
-         .vrefresh = 50, },
+         .vrefresh = 50, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 40 - 1920x1080i@100Hz */
        { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
-         .vrefresh = 100, },
+         .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 41 - 1280x720@100Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1720,
                   1760, 1980, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 100, },
+         .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 42 - 720x576@100Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 100, },
+         .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 43 - 720x576@100Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 54000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 100, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 100, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 100, },
+         .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 46 - 1920x1080i@120Hz */
        { DRM_MODE("1920x1080i", DRM_MODE_TYPE_DRIVER, 148500, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC |
                        DRM_MODE_FLAG_INTERLACE),
-         .vrefresh = 120, },
+         .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 47 - 1280x720@120Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 148500, 1280, 1390,
                   1430, 1650, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 120, },
+         .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 48 - 720x480@120Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 120, },
+         .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 49 - 720x480@120Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 54000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 120, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 120, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 120, },
+         .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 52 - 720x576@200Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 200, },
+         .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 53 - 720x576@200Hz */
        { DRM_MODE("720x576", DRM_MODE_TYPE_DRIVER, 108000, 720, 732,
                   796, 864, 0, 576, 581, 586, 625, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 200, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 200, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 200, },
+         .vrefresh = 200, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 56 - 720x480@240Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 240, },
+         .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_4_3, },
        /* 57 - 720x480@240Hz */
        { DRM_MODE("720x480", DRM_MODE_TYPE_DRIVER, 108000, 720, 736,
                   798, 858, 0, 480, 489, 495, 525, 0,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC),
-         .vrefresh = 240, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 240, },
+         .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,
                   DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC |
                        DRM_MODE_FLAG_INTERLACE | DRM_MODE_FLAG_DBLCLK),
-         .vrefresh = 240, },
+         .vrefresh = 240, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 60 - 1280x720@24Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 59400, 1280, 3040,
                   3080, 3300, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 24, },
+         .vrefresh = 24, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 61 - 1280x720@25Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3700,
                   3740, 3960, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 25, },
+         .vrefresh = 25, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 62 - 1280x720@30Hz */
        { DRM_MODE("1280x720", DRM_MODE_TYPE_DRIVER, 74250, 1280, 3040,
                   3080, 3300, 0, 720, 725, 730, 750, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-         .vrefresh = 30, },
+         .vrefresh = 30, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 63 - 1920x1080@120Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2008,
                   2052, 2200, 0, 1080, 1084, 1089, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-        .vrefresh = 120, },
+        .vrefresh = 120, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
        /* 64 - 1920x1080@100Hz */
        { DRM_MODE("1920x1080", DRM_MODE_TYPE_DRIVER, 297000, 1920, 2448,
                   2492, 2640, 0, 1080, 1084, 1094, 1125, 0,
                   DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_PVSYNC),
-        .vrefresh = 100, },
+        .vrefresh = 100, .picture_aspect_ratio = HDMI_PICTURE_ASPECT_16_9, },
 };
 
 /*
@@ -2562,25 +2562,40 @@ add_alternate_cea_modes(struct drm_connector *connector, struct edid *edid)
        return modes;
 }
 
-static int
-do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
+static struct drm_display_mode *
+drm_display_mode_from_vic_index(struct drm_connector *connector,
+                               const u8 *video_db, u8 video_len,
+                               u8 video_index)
 {
        struct drm_device *dev = connector->dev;
-       const u8 *mode;
+       struct drm_display_mode *newmode;
        u8 cea_mode;
-       int modes = 0;
 
-       for (mode = db; mode < db + len; mode++) {
-               cea_mode = (*mode & 127) - 1; /* CEA modes are numbered 1..127 */
-               if (cea_mode < ARRAY_SIZE(edid_cea_modes)) {
-                       struct drm_display_mode *newmode;
-                       newmode = drm_mode_duplicate(dev,
-                                                    &edid_cea_modes[cea_mode]);
-                       if (newmode) {
-                               newmode->vrefresh = 0;
-                               drm_mode_probed_add(connector, newmode);
-                               modes++;
-                       }
+       if (video_db == NULL || video_index >= video_len)
+               return NULL;
+
+       /* CEA modes are numbered 1..127 */
+       cea_mode = (video_db[video_index] & 127) - 1;
+       if (cea_mode >= ARRAY_SIZE(edid_cea_modes))
+               return NULL;
+
+       newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]);
+       newmode->vrefresh = 0;
+
+       return newmode;
+}
+
+static int
+do_cea_modes(struct drm_connector *connector, const u8 *db, u8 len)
+{
+       int i, modes = 0;
+
+       for (i = 0; i < len; i++) {
+               struct drm_display_mode *mode;
+               mode = drm_display_mode_from_vic_index(connector, db, len, i);
+               if (mode) {
+                       drm_mode_probed_add(connector, mode);
+                       modes++;
                }
        }
 
@@ -2674,21 +2689,13 @@ static int add_hdmi_mode(struct drm_connector *connector, u8 vic)
 static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
                               const u8 *video_db, u8 video_len, u8 video_index)
 {
-       struct drm_device *dev = connector->dev;
        struct drm_display_mode *newmode;
        int modes = 0;
-       u8 cea_mode;
-
-       if (video_db == NULL || video_index >= video_len)
-               return 0;
-
-       /* CEA modes are numbered 1..127 */
-       cea_mode = (video_db[video_index] & 127) - 1;
-       if (cea_mode >= ARRAY_SIZE(edid_cea_modes))
-               return 0;
 
        if (structure & (1 << 0)) {
-               newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]);
+               newmode = drm_display_mode_from_vic_index(connector, video_db,
+                                                         video_len,
+                                                         video_index);
                if (newmode) {
                        newmode->flags |= DRM_MODE_FLAG_3D_FRAME_PACKING;
                        drm_mode_probed_add(connector, newmode);
@@ -2696,7 +2703,9 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
                }
        }
        if (structure & (1 << 6)) {
-               newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]);
+               newmode = drm_display_mode_from_vic_index(connector, video_db,
+                                                         video_len,
+                                                         video_index);
                if (newmode) {
                        newmode->flags |= DRM_MODE_FLAG_3D_TOP_AND_BOTTOM;
                        drm_mode_probed_add(connector, newmode);
@@ -2704,7 +2713,9 @@ static int add_3d_struct_modes(struct drm_connector *connector, u16 structure,
                }
        }
        if (structure & (1 << 8)) {
-               newmode = drm_mode_duplicate(dev, &edid_cea_modes[cea_mode]);
+               newmode = drm_display_mode_from_vic_index(connector, video_db,
+                                                         video_len,
+                                                         video_index);
                if (newmode) {
                        newmode->flags |= DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF;
                        drm_mode_probed_add(connector, newmode);
@@ -2728,7 +2739,7 @@ static int
 do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
                   const u8 *video_db, u8 video_len)
 {
-       int modes = 0, offset = 0, i, multi_present = 0;
+       int modes = 0, offset = 0, i, multi_present = 0, multi_len;
        u8 vic_len, hdmi_3d_len = 0;
        u16 mask;
        u16 structure_all;
@@ -2774,32 +2785,84 @@ do_hdmi_vsdb_modes(struct drm_connector *connector, const u8 *db, u8 len,
        }
        offset += 1 + vic_len;
 
-       if (!(multi_present == 1 || multi_present == 2))
-               goto out;
+       if (multi_present == 1)
+               multi_len = 2;
+       else if (multi_present == 2)
+               multi_len = 4;
+       else
+               multi_len = 0;
 
-       if ((multi_present == 1 && len < (9 + offset)) ||
-           (multi_present == 2 && len < (11 + offset)))
+       if (len < (8 + offset + hdmi_3d_len - 1))
                goto out;
 
-       if ((multi_present == 1 && hdmi_3d_len < 2) ||
-           (multi_present == 2 && hdmi_3d_len < 4))
+       if (hdmi_3d_len < multi_len)
                goto out;
 
-       /* 3D_Structure_ALL */
-       structure_all = (db[8 + offset] << 8) | db[9 + offset];
+       if (multi_present == 1 || multi_present == 2) {
+               /* 3D_Structure_ALL */
+               structure_all = (db[8 + offset] << 8) | db[9 + offset];
 
-       /* check if 3D_MASK is present */
-       if (multi_present == 2)
-               mask = (db[10 + offset] << 8) | db[11 + offset];
-       else
-               mask = 0xffff;
-
-       for (i = 0; i < 16; i++) {
-               if (mask & (1 << i))
-                       modes += add_3d_struct_modes(connector,
-                                                    structure_all,
-                                                    video_db,
-                                                    video_len, i);
+               /* check if 3D_MASK is present */
+               if (multi_present == 2)
+                       mask = (db[10 + offset] << 8) | db[11 + offset];
+               else
+                       mask = 0xffff;
+
+               for (i = 0; i < 16; i++) {
+                       if (mask & (1 << i))
+                               modes += add_3d_struct_modes(connector,
+                                               structure_all,
+                                               video_db,
+                                               video_len, i);
+               }
+       }
+
+       offset += multi_len;
+
+       for (i = 0; i < (hdmi_3d_len - multi_len); i++) {
+               int vic_index;
+               struct drm_display_mode *newmode = NULL;
+               unsigned int newflag = 0;
+               bool detail_present;
+
+               detail_present = ((db[8 + offset + i] & 0x0f) > 7);
+
+               if (detail_present && (i + 1 == hdmi_3d_len - multi_len))
+                       break;
+
+               /* 2D_VIC_order_X */
+               vic_index = db[8 + offset + i] >> 4;
+
+               /* 3D_Structure_X */
+               switch (db[8 + offset + i] & 0x0f) {
+               case 0:
+                       newflag = DRM_MODE_FLAG_3D_FRAME_PACKING;
+                       break;
+               case 6:
+                       newflag = DRM_MODE_FLAG_3D_TOP_AND_BOTTOM;
+                       break;
+               case 8:
+                       /* 3D_Detail_X */
+                       if ((db[9 + offset + i] >> 4) == 1)
+                               newflag = DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF;
+                       break;
+               }
+
+               if (newflag != 0) {
+                       newmode = drm_display_mode_from_vic_index(connector,
+                                                                 video_db,
+                                                                 video_len,
+                                                                 vic_index);
+
+                       if (newmode) {
+                               newmode->flags |= newflag;
+                               drm_mode_probed_add(connector, newmode);
+                               modes++;
+                       }
+               }
+
+               if (detail_present)
+                       i++;
        }
 
 out:
index 9081172ef0573a0eb1b17ac8e3681b0c559486cc..1b4c7a5442c5de22210925c2cea8317790340b04 100644 (file)
@@ -141,7 +141,7 @@ static int edid_size(const u8 *edid, int data_size)
        return (edid[0x7e] + 1) * EDID_LENGTH;
 }
 
-static u8 *edid_load(struct drm_connector *connector, const char *name,
+static void *edid_load(struct drm_connector *connector, const char *name,
                        const char *connector_name)
 {
        const struct firmware *fw = NULL;
@@ -263,7 +263,7 @@ int drm_load_edid_firmware(struct drm_connector *connector)
        if (*last == '\n')
                *last = '\0';
 
-       edid = (struct edid *) edid_load(connector, edidname, connector_name);
+       edid = edid_load(connector, edidname, connector_name);
        if (IS_ERR_OR_NULL(edid))
                return 0;
 
index 0a19401aff803bcf2a1ff4dddcbd1fab42a0a187..98a03639b413d834d08c5c73c0ef08cec3d37c55 100644 (file)
@@ -359,6 +359,11 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
        struct drm_crtc *crtc;
        int bound = 0, crtcs_bound = 0;
 
+       /* Sometimes user space wants everything disabled, so don't steal the
+        * display if there's a master. */
+       if (dev->primary->master)
+               return false;
+
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
                if (crtc->fb)
                        crtcs_bound++;
@@ -368,6 +373,7 @@ static bool drm_fb_helper_is_bound(struct drm_fb_helper *fb_helper)
 
        if (bound < crtcs_bound)
                return false;
+
        return true;
 }
 
index c5b929c3f77ae617d14fa87b387557bbf3cd3f7b..7f2af9aca03895b97c75af76968093a61930b501 100644 (file)
@@ -232,7 +232,6 @@ static int drm_open_helper(struct inode *inode, struct file *filp,
                goto out_put_pid;
        }
 
-       priv->ioctl_count = 0;
        /* for compatibility root is always authenticated */
        priv->always_authenticated = capable(CAP_SYS_ADMIN);
        priv->authenticated = priv->always_authenticated;
@@ -392,9 +391,6 @@ static void drm_legacy_dev_reinit(struct drm_device *dev)
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                return;
 
-       atomic_set(&dev->ioctl_count, 0);
-       atomic_set(&dev->vma_count, 0);
-
        dev->sigdata.lock = NULL;
 
        dev->context_flag = 0;
@@ -578,12 +574,7 @@ int drm_release(struct inode *inode, struct file *filp)
         */
 
        if (!--dev->open_count) {
-               if (atomic_read(&dev->ioctl_count)) {
-                       DRM_ERROR("Device busy: %d\n",
-                                 atomic_read(&dev->ioctl_count));
-                       retcode = -EBUSY;
-               } else
-                       retcode = drm_lastclose(dev);
+               retcode = drm_lastclose(dev);
                if (drm_device_is_unplugged(dev))
                        drm_put_dev(dev);
        }
index 4761adedad2abe5f03ae586354436f3bf1b32cbb..5bbad873c798a8e2168f50c33828f27828c378ed 100644 (file)
 int
 drm_gem_init(struct drm_device *dev)
 {
-       struct drm_gem_mm *mm;
+       struct drm_vma_offset_manager *vma_offset_manager;
 
        mutex_init(&dev->object_name_lock);
        idr_init(&dev->object_name_idr);
 
-       mm = kzalloc(sizeof(struct drm_gem_mm), GFP_KERNEL);
-       if (!mm) {
+       vma_offset_manager = kzalloc(sizeof(*vma_offset_manager), GFP_KERNEL);
+       if (!vma_offset_manager) {
                DRM_ERROR("out of memory\n");
                return -ENOMEM;
        }
 
-       dev->mm_private = mm;
-       drm_vma_offset_manager_init(&mm->vma_manager,
+       dev->vma_offset_manager = vma_offset_manager;
+       drm_vma_offset_manager_init(vma_offset_manager,
                                    DRM_FILE_PAGE_OFFSET_START,
                                    DRM_FILE_PAGE_OFFSET_SIZE);
 
@@ -113,11 +113,10 @@ drm_gem_init(struct drm_device *dev)
 void
 drm_gem_destroy(struct drm_device *dev)
 {
-       struct drm_gem_mm *mm = dev->mm_private;
 
-       drm_vma_offset_manager_destroy(&mm->vma_manager);
-       kfree(mm);
-       dev->mm_private = NULL;
+       drm_vma_offset_manager_destroy(dev->vma_offset_manager);
+       kfree(dev->vma_offset_manager);
+       dev->vma_offset_manager = NULL;
 }
 
 /**
@@ -129,11 +128,12 @@ int drm_gem_object_init(struct drm_device *dev,
 {
        struct file *filp;
 
+       drm_gem_private_object_init(dev, obj, size);
+
        filp = shmem_file_setup("drm mm object", size, VM_NORESERVE);
        if (IS_ERR(filp))
                return PTR_ERR(filp);
 
-       drm_gem_private_object_init(dev, obj, size);
        obj->filp = filp;
 
        return 0;
@@ -175,11 +175,6 @@ drm_gem_remove_prime_handles(struct drm_gem_object *obj, struct drm_file *filp)
        mutex_unlock(&filp->prime.lock);
 }
 
-static void drm_gem_object_ref_bug(struct kref *list_kref)
-{
-       BUG();
-}
-
 /**
  * Called after the last handle to the object has been closed
  *
@@ -195,13 +190,6 @@ static void drm_gem_object_handle_free(struct drm_gem_object *obj)
        if (obj->name) {
                idr_remove(&dev->object_name_idr, obj->name);
                obj->name = 0;
-               /*
-                * The object name held a reference to this object, drop
-                * that now.
-               *
-               * This cannot be the last reference, since the handle holds one too.
-                */
-               kref_put(&obj->refcount, drm_gem_object_ref_bug);
        }
 }
 
@@ -374,9 +362,8 @@ void
 drm_gem_free_mmap_offset(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
-       struct drm_gem_mm *mm = dev->mm_private;
 
-       drm_vma_offset_remove(&mm->vma_manager, &obj->vma_node);
+       drm_vma_offset_remove(dev->vma_offset_manager, &obj->vma_node);
 }
 EXPORT_SYMBOL(drm_gem_free_mmap_offset);
 
@@ -398,9 +385,8 @@ int
 drm_gem_create_mmap_offset_size(struct drm_gem_object *obj, size_t size)
 {
        struct drm_device *dev = obj->dev;
-       struct drm_gem_mm *mm = dev->mm_private;
 
-       return drm_vma_offset_add(&mm->vma_manager, &obj->vma_node,
+       return drm_vma_offset_add(dev->vma_offset_manager, &obj->vma_node,
                                  size / PAGE_SIZE);
 }
 EXPORT_SYMBOL(drm_gem_create_mmap_offset_size);
@@ -602,9 +588,6 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
                        goto err;
 
                obj->name = ret;
-
-               /* Allocate a reference for the name table.  */
-               drm_gem_object_reference(obj);
        }
 
        args->name = (uint64_t) obj->name;
@@ -833,7 +816,6 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 {
        struct drm_file *priv = filp->private_data;
        struct drm_device *dev = priv->minor->dev;
-       struct drm_gem_mm *mm = dev->mm_private;
        struct drm_gem_object *obj;
        struct drm_vma_offset_node *node;
        int ret = 0;
@@ -843,7 +825,8 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 
        mutex_lock(&dev->struct_mutex);
 
-       node = drm_vma_offset_exact_lookup(&mm->vma_manager, vma->vm_pgoff,
+       node = drm_vma_offset_exact_lookup(dev->vma_offset_manager,
+                                          vma->vm_pgoff,
                                           vma_pages(vma));
        if (!node) {
                mutex_unlock(&dev->struct_mutex);
index 7d5a152eeb0288f05e5770a9699b92e253f689e4..7473035dd28b781ed8f382d0e8b6cd3743df772e 100644 (file)
@@ -186,14 +186,14 @@ int drm_clients_info(struct seq_file *m, void *data)
        struct drm_file *priv;
 
        mutex_lock(&dev->struct_mutex);
-       seq_printf(m, "a dev    pid    uid      magic     ioctls\n\n");
+       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 %10lu\n",
+               seq_printf(m, "%c %3d %5d %5d %10u\n",
                           priv->authenticated ? 'y' : 'n',
                           priv->minor->index,
                           pid_vnr(priv->pid),
                           from_kuid_munged(seq_user_ns(m), priv->uid),
-                          priv->magic, priv->ioctl_count);
+                          priv->magic);
        }
        mutex_unlock(&dev->struct_mutex);
        return 0;
@@ -234,14 +234,18 @@ int drm_vma_info(struct seq_file *m, void *data)
        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);
-       seq_printf(m, "vma use count: %d, high_memory = %pK, 0x%pK\n",
-                  atomic_read(&dev->vma_count),
-                  high_memory, (void *)(unsigned long)virt_to_phys(high_memory));
+       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;
index 64c34d5876ffc7c8378b3df4a389db203dd1c576..c2676b5908d9f6edbcf4dd8d9fb126cfb93cd5ab 100644 (file)
@@ -368,7 +368,7 @@ 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++) {
-                       DRM_WAKEUP(&dev->vblank[i].queue);
+                       wake_up(&dev->vblank[i].queue);
                        dev->vblank[i].enabled = false;
                        dev->vblank[i].last =
                                dev->driver->get_vblank_counter(dev, i);
@@ -436,45 +436,41 @@ int drm_control(struct drm_device *dev, void *data,
 }
 
 /**
- * drm_calc_timestamping_constants - Calculate and
- * store various constants which are later needed by
- * vblank and swap-completion timestamping, e.g, by
- * drm_calc_vbltimestamp_from_scanoutpos().
- * They are derived from crtc's true scanout timing,
- * so they take things like panel scaling or other
- * adjustments into account.
+ * drm_calc_timestamping_constants - Calculate vblank timestamp constants
  *
  * @crtc drm_crtc whose timestamp constants should be updated.
+ * @mode display mode containing the scanout timings
  *
+ * Calculate and store various constants which are later
+ * needed by vblank and swap-completion timestamping, e.g,
+ * by drm_calc_vbltimestamp_from_scanoutpos(). They are
+ * derived from crtc's true scanout timing, so they take
+ * things like panel scaling or other adjustments into account.
  */
-void drm_calc_timestamping_constants(struct drm_crtc *crtc)
+void drm_calc_timestamping_constants(struct drm_crtc *crtc,
+                                    const struct drm_display_mode *mode)
 {
-       s64 linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
-       u64 dotclock;
-
-       /* Dot clock in Hz: */
-       dotclock = (u64) crtc->hwmode.clock * 1000;
-
-       /* Fields of interlaced scanout modes are only half a frame duration.
-        * Double the dotclock to get half the frame-/line-/pixelduration.
-        */
-       if (crtc->hwmode.flags & DRM_MODE_FLAG_INTERLACE)
-               dotclock *= 2;
+       int linedur_ns = 0, pixeldur_ns = 0, framedur_ns = 0;
+       int dotclock = mode->crtc_clock;
 
        /* Valid dotclock? */
        if (dotclock > 0) {
-               int frame_size;
-               /* Convert scanline length in pixels and video dot clock to
-                * line duration, frame duration and pixel duration in
-                * nanoseconds:
+               int frame_size = mode->crtc_htotal * mode->crtc_vtotal;
+
+               /*
+                * Convert scanline length in pixels and video
+                * dot clock to line duration, frame duration
+                * and pixel duration in nanoseconds:
                 */
-               pixeldur_ns = (s64) div64_u64(1000000000, dotclock);
-               linedur_ns  = (s64) div64_u64(((u64) crtc->hwmode.crtc_htotal *
-                                             1000000000), dotclock);
-               frame_size = crtc->hwmode.crtc_htotal *
-                               crtc->hwmode.crtc_vtotal;
-               framedur_ns = (s64) div64_u64((u64) frame_size * 1000000000,
-                                             dotclock);
+               pixeldur_ns = 1000000 / dotclock;
+               linedur_ns  = div_u64((u64) mode->crtc_htotal * 1000000, dotclock);
+               framedur_ns = div_u64((u64) frame_size * 1000000, dotclock);
+
+               /*
+                * Fields of interlaced scanout modes are only half a frame duration.
+                */
+               if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+                       framedur_ns /= 2;
        } else
                DRM_ERROR("crtc %d: Can't calculate constants, dotclock = 0!\n",
                          crtc->base.id);
@@ -484,11 +480,11 @@ void drm_calc_timestamping_constants(struct drm_crtc *crtc)
        crtc->framedur_ns = framedur_ns;
 
        DRM_DEBUG("crtc %d: hwmode: htotal %d, vtotal %d, vdisplay %d\n",
-                 crtc->base.id, crtc->hwmode.crtc_htotal,
-                 crtc->hwmode.crtc_vtotal, crtc->hwmode.crtc_vdisplay);
+                 crtc->base.id, mode->crtc_htotal,
+                 mode->crtc_vtotal, mode->crtc_vdisplay);
        DRM_DEBUG("crtc %d: clock %d kHz framedur %d linedur %d, pixeldur %d\n",
-                 crtc->base.id, (int) dotclock/1000, (int) framedur_ns,
-                 (int) linedur_ns, (int) pixeldur_ns);
+                 crtc->base.id, dotclock, framedur_ns,
+                 linedur_ns, pixeldur_ns);
 }
 EXPORT_SYMBOL(drm_calc_timestamping_constants);
 
@@ -521,6 +517,7 @@ EXPORT_SYMBOL(drm_calc_timestamping_constants);
  *         0 = Default.
  *         DRM_CALLED_FROM_VBLIRQ = If function is called from vbl irq handler.
  * @refcrtc: drm_crtc* of crtc which defines scanout timing.
+ * @mode: mode which defines the scanout timings
  *
  * Returns negative value on error, failure or if not supported in current
  * video mode:
@@ -540,14 +537,14 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
                                          int *max_error,
                                          struct timeval *vblank_time,
                                          unsigned flags,
-                                         struct drm_crtc *refcrtc)
+                                         const struct drm_crtc *refcrtc,
+                                         const struct drm_display_mode *mode)
 {
        ktime_t stime, etime, mono_time_offset;
        struct timeval tv_etime;
-       struct drm_display_mode *mode;
-       int vbl_status, vtotal, vdisplay;
+       int vbl_status;
        int vpos, hpos, i;
-       s64 framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
+       int framedur_ns, linedur_ns, pixeldur_ns, delta_ns, duration_ns;
        bool invbl;
 
        if (crtc < 0 || crtc >= dev->num_crtcs) {
@@ -561,10 +558,6 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
                return -EIO;
        }
 
-       mode = &refcrtc->hwmode;
-       vtotal = mode->crtc_vtotal;
-       vdisplay = mode->crtc_vdisplay;
-
        /* Durations of frames, lines, pixels in nanoseconds. */
        framedur_ns = refcrtc->framedur_ns;
        linedur_ns  = refcrtc->linedur_ns;
@@ -573,7 +566,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
        /* If mode timing undefined, just return as no-op:
         * Happens during initial modesetting of a crtc.
         */
-       if (vtotal <= 0 || vdisplay <= 0 || framedur_ns == 0) {
+       if (framedur_ns == 0) {
                DRM_DEBUG("crtc %d: Noop due to uninitialized mode.\n", crtc);
                return -EAGAIN;
        }
@@ -590,7 +583,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
                 * Get vertical and horizontal scanout position vpos, hpos,
                 * and bounding timestamps stime, etime, pre/post query.
                 */
-               vbl_status = dev->driver->get_scanout_position(dev, crtc, &vpos,
+               vbl_status = dev->driver->get_scanout_position(dev, crtc, flags, &vpos,
                                                               &hpos, &stime, &etime);
 
                /*
@@ -611,18 +604,18 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
                duration_ns = ktime_to_ns(etime) - ktime_to_ns(stime);
 
                /* Accept result with <  max_error nsecs timing uncertainty. */
-               if (duration_ns <= (s64) *max_error)
+               if (duration_ns <= *max_error)
                        break;
        }
 
        /* Noisy system timing? */
        if (i == DRM_TIMESTAMP_MAXRETRIES) {
                DRM_DEBUG("crtc %d: Noisy timestamp %d us > %d us [%d reps].\n",
-                         crtc, (int) duration_ns/1000, *max_error/1000, i);
+                         crtc, duration_ns/1000, *max_error/1000, i);
        }
 
        /* Return upper bound of timestamp precision error. */
-       *max_error = (int) duration_ns;
+       *max_error = duration_ns;
 
        /* Check if in vblank area:
         * vpos is >=0 in video scanout area, but negative
@@ -635,25 +628,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
         * since start of scanout at first display scanline. delta_ns
         * can be negative if start of scanout hasn't happened yet.
         */
-       delta_ns = (s64) vpos * linedur_ns + (s64) hpos * pixeldur_ns;
-
-       /* Is vpos outside nominal vblank area, but less than
-        * 1/100 of a frame height away from start of vblank?
-        * If so, assume this isn't a massively delayed vblank
-        * interrupt, but a vblank interrupt that fired a few
-        * microseconds before true start of vblank. Compensate
-        * by adding a full frame duration to the final timestamp.
-        * Happens, e.g., on ATI R500, R600.
-        *
-        * We only do this if DRM_CALLED_FROM_VBLIRQ.
-        */
-       if ((flags & DRM_CALLED_FROM_VBLIRQ) && !invbl &&
-           ((vdisplay - vpos) < vtotal / 100)) {
-               delta_ns = delta_ns - framedur_ns;
-
-               /* Signal this correction as "applied". */
-               vbl_status |= 0x8;
-       }
+       delta_ns = vpos * linedur_ns + hpos * pixeldur_ns;
 
        if (!drm_timestamp_monotonic)
                etime = ktime_sub(etime, mono_time_offset);
@@ -673,7 +648,7 @@ int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev, int crtc,
                  crtc, (int)vbl_status, hpos, vpos,
                  (long)tv_etime.tv_sec, (long)tv_etime.tv_usec,
                  (long)vblank_time->tv_sec, (long)vblank_time->tv_usec,
-                 (int)duration_ns/1000, i);
+                 duration_ns/1000, i);
 
        vbl_status = DRM_VBLANKTIME_SCANOUTPOS_METHOD;
        if (invbl)
@@ -960,7 +935,7 @@ void drm_vblank_put(struct drm_device *dev, int crtc)
        if (atomic_dec_and_test(&dev->vblank[crtc].refcount) &&
            (drm_vblank_offdelay > 0))
                mod_timer(&dev->vblank_disable_timer,
-                         jiffies + ((drm_vblank_offdelay * DRM_HZ)/1000));
+                         jiffies + ((drm_vblank_offdelay * HZ)/1000));
 }
 EXPORT_SYMBOL(drm_vblank_put);
 
@@ -980,7 +955,7 @@ void drm_vblank_off(struct drm_device *dev, int crtc)
 
        spin_lock_irqsave(&dev->vbl_lock, irqflags);
        vblank_disable_and_save(dev, crtc);
-       DRM_WAKEUP(&dev->vblank[crtc].queue);
+       wake_up(&dev->vblank[crtc].queue);
 
        /* Send any queued vblank events, lest the natives grow disquiet */
        seq = drm_vblank_count_and_time(dev, crtc, &now);
@@ -1244,7 +1219,7 @@ 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 * DRM_HZ,
+       DRM_WAIT_ON(ret, dev->vblank[crtc].queue, 3 * HZ,
                    (((drm_vblank_count(dev, crtc) -
                       vblwait->request.sequence) <= (1 << 23)) ||
                     !dev->irq_enabled));
@@ -1363,7 +1338,7 @@ bool drm_handle_vblank(struct drm_device *dev, int crtc)
                          crtc, (int) diff_ns);
        }
 
-       DRM_WAKEUP(&dev->vblank[crtc].queue);
+       wake_up(&dev->vblank[crtc].queue);
        drm_handle_vblank_events(dev, crtc);
 
        spin_unlock_irqrestore(&dev->vblank_time_lock, irqflags);
index 64e44fad8ae84282d43f449d21772c4346acab68..00c67c0f238127d1d36c8ba17e6caf184412c446 100644 (file)
@@ -82,19 +82,19 @@ static void *agp_remap(unsigned long offset, unsigned long size,
 }
 
 /** Wrapper around agp_free_memory() */
-void drm_free_agp(DRM_AGP_MEM * handle, int pages)
+void drm_free_agp(struct agp_memory * handle, int pages)
 {
        agp_free_memory(handle);
 }
 
 /** Wrapper around agp_bind_memory() */
-int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
+int drm_bind_agp(struct agp_memory * handle, unsigned int start)
 {
        return agp_bind_memory(handle, start);
 }
 
 /** Wrapper around agp_unbind_memory() */
-int drm_unbind_agp(DRM_AGP_MEM * handle)
+int drm_unbind_agp(struct agp_memory * handle)
 {
        return agp_unbind_memory(handle);
 }
@@ -110,8 +110,7 @@ static inline void *agp_remap(unsigned long offset, unsigned long size,
 
 void drm_core_ioremap(struct drm_local_map *map, struct drm_device *dev)
 {
-       if (drm_core_has_AGP(dev) &&
-           dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+       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);
@@ -120,8 +119,7 @@ EXPORT_SYMBOL(drm_core_ioremap);
 
 void drm_core_ioremap_wc(struct drm_local_map *map, struct drm_device *dev)
 {
-       if (drm_core_has_AGP(dev) &&
-           dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+       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);
@@ -133,8 +131,7 @@ void drm_core_ioremapfree(struct drm_local_map *map, struct drm_device *dev)
        if (!map->handle || !map->size)
                return;
 
-       if (drm_core_has_AGP(dev) &&
-           dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
+       if (dev->agp && dev->agp->cant_use_aperture && map->type == _DRM_AGP)
                vunmap(map->handle);
        else
                iounmap(map->handle);
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
new file mode 100644 (file)
index 0000000..b155ee2
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
+ * Andrzej Hajda <a.hajda@samsung.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, 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.
+ */
+
+#include <drm/drm_mipi_dsi.h>
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+
+#include <video/mipi_display.h>
+
+static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv)
+{
+       return of_driver_match_device(dev, drv);
+}
+
+static const struct dev_pm_ops mipi_dsi_device_pm_ops = {
+       .runtime_suspend = pm_generic_runtime_suspend,
+       .runtime_resume = pm_generic_runtime_resume,
+       .suspend = pm_generic_suspend,
+       .resume = pm_generic_resume,
+       .freeze = pm_generic_freeze,
+       .thaw = pm_generic_thaw,
+       .poweroff = pm_generic_poweroff,
+       .restore = pm_generic_restore,
+};
+
+static struct bus_type mipi_dsi_bus_type = {
+       .name = "mipi-dsi",
+       .match = mipi_dsi_device_match,
+       .pm = &mipi_dsi_device_pm_ops,
+};
+
+static void mipi_dsi_dev_release(struct device *dev)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+
+       of_node_put(dev->of_node);
+       kfree(dsi);
+}
+
+static const struct device_type mipi_dsi_device_type = {
+       .release = mipi_dsi_dev_release,
+};
+
+static struct mipi_dsi_device *mipi_dsi_device_alloc(struct mipi_dsi_host *host)
+{
+       struct mipi_dsi_device *dsi;
+
+       dsi = kzalloc(sizeof(*dsi), GFP_KERNEL);
+       if (!dsi)
+               return ERR_PTR(-ENOMEM);
+
+       dsi->host = host;
+       dsi->dev.bus = &mipi_dsi_bus_type;
+       dsi->dev.parent = host->dev;
+       dsi->dev.type = &mipi_dsi_device_type;
+
+       device_initialize(&dsi->dev);
+
+       return dsi;
+}
+
+static int mipi_dsi_device_add(struct mipi_dsi_device *dsi)
+{
+       struct mipi_dsi_host *host = dsi->host;
+
+       dev_set_name(&dsi->dev, "%s.%d", dev_name(host->dev),  dsi->channel);
+
+       return device_add(&dsi->dev);
+}
+
+static struct mipi_dsi_device *
+of_mipi_dsi_device_add(struct mipi_dsi_host *host, struct device_node *node)
+{
+       struct mipi_dsi_device *dsi;
+       struct device *dev = host->dev;
+       int ret;
+       u32 reg;
+
+       ret = of_property_read_u32(node, "reg", &reg);
+       if (ret) {
+               dev_err(dev, "device node %s has no valid reg property: %d\n",
+                       node->full_name, ret);
+               return ERR_PTR(-EINVAL);
+       }
+
+       if (reg > 3) {
+               dev_err(dev, "device node %s has invalid reg property: %u\n",
+                       node->full_name, reg);
+               return ERR_PTR(-EINVAL);
+       }
+
+       dsi = mipi_dsi_device_alloc(host);
+       if (IS_ERR(dsi)) {
+               dev_err(dev, "failed to allocate DSI device %s: %ld\n",
+                       node->full_name, PTR_ERR(dsi));
+               return dsi;
+       }
+
+       dsi->dev.of_node = of_node_get(node);
+       dsi->channel = reg;
+
+       ret = mipi_dsi_device_add(dsi);
+       if (ret) {
+               dev_err(dev, "failed to add DSI device %s: %d\n",
+                       node->full_name, ret);
+               kfree(dsi);
+               return ERR_PTR(ret);
+       }
+
+       return dsi;
+}
+
+int mipi_dsi_host_register(struct mipi_dsi_host *host)
+{
+       struct device_node *node;
+
+       for_each_available_child_of_node(host->dev->of_node, node)
+               of_mipi_dsi_device_add(host, node);
+
+       return 0;
+}
+EXPORT_SYMBOL(mipi_dsi_host_register);
+
+static int mipi_dsi_remove_device_fn(struct device *dev, void *priv)
+{
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+
+       device_unregister(&dsi->dev);
+
+       return 0;
+}
+
+void mipi_dsi_host_unregister(struct mipi_dsi_host *host)
+{
+       device_for_each_child(host->dev, NULL, mipi_dsi_remove_device_fn);
+}
+EXPORT_SYMBOL(mipi_dsi_host_unregister);
+
+/**
+ * mipi_dsi_attach - attach a DSI device to its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_attach(struct mipi_dsi_device *dsi)
+{
+       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+       if (!ops || !ops->attach)
+               return -ENOSYS;
+
+       return ops->attach(dsi->host, dsi);
+}
+EXPORT_SYMBOL(mipi_dsi_attach);
+
+/**
+ * mipi_dsi_detach - detach a DSI device from its DSI host
+ * @dsi: DSI peripheral
+ */
+int mipi_dsi_detach(struct mipi_dsi_device *dsi)
+{
+       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+
+       if (!ops || !ops->detach)
+               return -ENOSYS;
+
+       return ops->detach(dsi->host, dsi);
+}
+EXPORT_SYMBOL(mipi_dsi_detach);
+
+/**
+ * mipi_dsi_dcs_write - send DCS write command
+ * @dsi: DSI device
+ * @channel: virtual channel
+ * @data: pointer to the command followed by parameters
+ * @len: length of @data
+ */
+int mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel,
+                      const void *data, size_t len)
+{
+       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+       struct mipi_dsi_msg msg = {
+               .channel = channel,
+               .tx_buf = data,
+               .tx_len = len
+       };
+
+       if (!ops || !ops->transfer)
+               return -ENOSYS;
+
+       switch (len) {
+       case 0:
+               return -EINVAL;
+       case 1:
+               msg.type = MIPI_DSI_DCS_SHORT_WRITE;
+               break;
+       case 2:
+               msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
+               break;
+       default:
+               msg.type = MIPI_DSI_DCS_LONG_WRITE;
+               break;
+       }
+
+       return ops->transfer(dsi->host, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_write);
+
+/**
+ * mipi_dsi_dcs_read - send DCS read request command
+ * @dsi: DSI device
+ * @channel: virtual channel
+ * @cmd: DCS read command
+ * @data: pointer to read buffer
+ * @len: length of @data
+ *
+ * Function returns number of read bytes or error code.
+ */
+ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel,
+                         u8 cmd, void *data, size_t len)
+{
+       const struct mipi_dsi_host_ops *ops = dsi->host->ops;
+       struct mipi_dsi_msg msg = {
+               .channel = channel,
+               .type = MIPI_DSI_DCS_READ,
+               .tx_buf = &cmd,
+               .tx_len = 1,
+               .rx_buf = data,
+               .rx_len = len
+       };
+
+       if (!ops || !ops->transfer)
+               return -ENOSYS;
+
+       return ops->transfer(dsi->host, &msg);
+}
+EXPORT_SYMBOL(mipi_dsi_dcs_read);
+
+static int mipi_dsi_drv_probe(struct device *dev)
+{
+       struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+
+       return drv->probe(dsi);
+}
+
+static int mipi_dsi_drv_remove(struct device *dev)
+{
+       struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
+       struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
+
+       return drv->remove(dsi);
+}
+
+/**
+ * mipi_dsi_driver_register - register a driver for DSI devices
+ * @drv: DSI driver structure
+ */
+int mipi_dsi_driver_register(struct mipi_dsi_driver *drv)
+{
+       drv->driver.bus = &mipi_dsi_bus_type;
+       if (drv->probe)
+               drv->driver.probe = mipi_dsi_drv_probe;
+       if (drv->remove)
+               drv->driver.remove = mipi_dsi_drv_remove;
+
+       return driver_register(&drv->driver);
+}
+EXPORT_SYMBOL(mipi_dsi_driver_register);
+
+/**
+ * mipi_dsi_driver_unregister - unregister a driver for DSI devices
+ * @drv: DSI driver structure
+ */
+void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv)
+{
+       driver_unregister(&drv->driver);
+}
+EXPORT_SYMBOL(mipi_dsi_driver_unregister);
+
+static int __init mipi_dsi_bus_init(void)
+{
+       return bus_register(&mipi_dsi_bus_type);
+}
+postcore_initcall(mipi_dsi_bus_init);
+
+MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
+MODULE_DESCRIPTION("MIPI DSI Bus");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/drm_panel.c b/drivers/gpu/drm/drm_panel.c
new file mode 100644 (file)
index 0000000..2ef988e
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2013, NVIDIA Corporation.  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 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/err.h>
+#include <linux/module.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_panel.h>
+
+static DEFINE_MUTEX(panel_lock);
+static LIST_HEAD(panel_list);
+
+void drm_panel_init(struct drm_panel *panel)
+{
+       INIT_LIST_HEAD(&panel->list);
+}
+EXPORT_SYMBOL(drm_panel_init);
+
+int drm_panel_add(struct drm_panel *panel)
+{
+       mutex_lock(&panel_lock);
+       list_add_tail(&panel->list, &panel_list);
+       mutex_unlock(&panel_lock);
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_panel_add);
+
+void drm_panel_remove(struct drm_panel *panel)
+{
+       mutex_lock(&panel_lock);
+       list_del_init(&panel->list);
+       mutex_unlock(&panel_lock);
+}
+EXPORT_SYMBOL(drm_panel_remove);
+
+int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector)
+{
+       if (panel->connector)
+               return -EBUSY;
+
+       panel->connector = connector;
+       panel->drm = connector->dev;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_panel_attach);
+
+int drm_panel_detach(struct drm_panel *panel)
+{
+       panel->connector = NULL;
+       panel->drm = NULL;
+
+       return 0;
+}
+EXPORT_SYMBOL(drm_panel_detach);
+
+#ifdef CONFIG_OF
+struct drm_panel *of_drm_find_panel(struct device_node *np)
+{
+       struct drm_panel *panel;
+
+       mutex_lock(&panel_lock);
+
+       list_for_each_entry(panel, &panel_list, list) {
+               if (panel->dev->of_node == np) {
+                       mutex_unlock(&panel_lock);
+                       return panel;
+               }
+       }
+
+       mutex_unlock(&panel_lock);
+       return NULL;
+}
+EXPORT_SYMBOL(of_drm_find_panel);
+#endif
+
+MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
+MODULE_DESCRIPTION("DRM panel infrastructure");
+MODULE_LICENSE("GPL and additional rights");
index 02679793c9e2e73d3d175136bbfb638a7cd0784f..5736aaa7e86cb069d30fd458b5842fd42defae17 100644 (file)
@@ -262,16 +262,11 @@ static int drm_pci_irq_by_busid(struct drm_device *dev, struct drm_irq_busid *p)
        return 0;
 }
 
-static int drm_pci_agp_init(struct drm_device *dev)
+static void drm_pci_agp_init(struct drm_device *dev)
 {
-       if (drm_core_has_AGP(dev)) {
+       if (drm_core_check_feature(dev, DRIVER_USE_AGP)) {
                if (drm_pci_device_is_agp(dev))
                        dev->agp = drm_agp_init(dev);
-               if (drm_core_check_feature(dev, DRIVER_REQUIRE_AGP)
-                   && (dev->agp == NULL)) {
-                       DRM_ERROR("Cannot initialize the agpgart module.\n");
-                       return -EINVAL;
-               }
                if (dev->agp) {
                        dev->agp->agp_mtrr = arch_phys_wc_add(
                                dev->agp->agp_info.aper_base,
@@ -279,15 +274,14 @@ static int drm_pci_agp_init(struct drm_device *dev)
                                1024 * 1024);
                }
        }
-       return 0;
 }
 
-static void drm_pci_agp_destroy(struct drm_device *dev)
+void drm_pci_agp_destroy(struct drm_device *dev)
 {
-       if (drm_core_has_AGP(dev) && dev->agp) {
+       if (dev->agp) {
                arch_phys_wc_del(dev->agp->agp_mtrr);
                drm_agp_clear(dev);
-               drm_agp_destroy(dev->agp);
+               kfree(dev->agp);
                dev->agp = NULL;
        }
 }
@@ -299,8 +293,6 @@ static struct drm_bus drm_pci_bus = {
        .set_busid = drm_pci_set_busid,
        .set_unique = drm_pci_set_unique,
        .irq_by_busid = drm_pci_irq_by_busid,
-       .agp_init = drm_pci_agp_init,
-       .agp_destroy = drm_pci_agp_destroy,
 };
 
 /**
@@ -338,17 +330,25 @@ int drm_get_pci_dev(struct pci_dev *pdev, const struct pci_device_id *ent,
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                pci_set_drvdata(pdev, dev);
 
+       drm_pci_agp_init(dev);
+
        ret = drm_dev_register(dev, ent->driver_data);
        if (ret)
-               goto err_pci;
+               goto err_agp;
 
        DRM_INFO("Initialized %s %d.%d.%d %s for %s on minor %d\n",
                 driver->name, driver->major, driver->minor, driver->patchlevel,
                 driver->date, pci_name(pdev), dev->primary->index);
 
+       /* No locking needed since shadow-attach is single-threaded since it may
+        * only be called from the per-driver module init hook. */
+       if (!drm_core_check_feature(dev, DRIVER_MODESET))
+               list_add_tail(&dev->legacy_dev_list, &driver->legacy_dev_list);
+
        return 0;
 
-err_pci:
+err_agp:
+       drm_pci_agp_destroy(dev);
        pci_disable_device(pdev);
 err_free:
        drm_dev_free(dev);
@@ -375,7 +375,6 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
 
        DRM_DEBUG("\n");
 
-       INIT_LIST_HEAD(&driver->device_list);
        driver->kdriver.pci = pdriver;
        driver->bus = &drm_pci_bus;
 
@@ -383,6 +382,7 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
                return pci_register_driver(pdriver);
 
        /* If not using KMS, fall back to stealth mode manual scanning. */
+       INIT_LIST_HEAD(&driver->legacy_dev_list);
        for (i = 0; pdriver->id_table[i].vendor != 0; i++) {
                pid = &pdriver->id_table[i];
 
@@ -452,6 +452,7 @@ int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver)
        return -1;
 }
 
+void drm_pci_agp_destroy(struct drm_device *dev) {}
 #endif
 
 EXPORT_SYMBOL(drm_pci_init);
@@ -465,8 +466,11 @@ void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver)
        if (driver->driver_features & DRIVER_MODESET) {
                pci_unregister_driver(pdriver);
        } else {
-               list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
+               list_for_each_entry_safe(dev, tmp, &driver->legacy_dev_list,
+                                        legacy_dev_list) {
                        drm_put_dev(dev);
+                       list_del(&dev->legacy_dev_list);
+               }
        }
        DRM_INFO("Module unloaded\n");
 }
index fc24fee8ec833b6bdb2c26ada2b45e947622b941..21fc82006b78c3423c801b54ef5acd40d4f79805 100644 (file)
@@ -147,18 +147,6 @@ int drm_platform_init(struct drm_driver *driver, struct platform_device *platfor
 
        driver->kdriver.platform_device = platform_device;
        driver->bus = &drm_platform_bus;
-       INIT_LIST_HEAD(&driver->device_list);
        return drm_get_platform_dev(platform_device, driver);
 }
 EXPORT_SYMBOL(drm_platform_init);
-
-void drm_platform_exit(struct drm_driver *driver, struct platform_device *platform_device)
-{
-       struct drm_device *dev, *tmp;
-       DRM_DEBUG("\n");
-
-       list_for_each_entry_safe(dev, tmp, &driver->device_list, driver_item)
-               drm_put_dev(dev);
-       DRM_INFO("Module unloaded\n");
-}
-EXPORT_SYMBOL(drm_platform_exit);
index 66dd3a001cf1b5ee43ec75f190b03146e7bbe46d..98a33c580ca1aeceed513f2af38b6742cee30f85 100644 (file)
@@ -99,13 +99,19 @@ void drm_ut_debug_printk(unsigned int request_level,
                         const char *function_name,
                         const char *format, ...)
 {
+       struct va_format vaf;
        va_list args;
 
        if (drm_debug & request_level) {
-               if (function_name)
-                       printk(KERN_DEBUG "[%s:%s], ", prefix, function_name);
                va_start(args, format);
-               vprintk(format, args);
+               vaf.fmt = format;
+               vaf.va = &args;
+
+               if (function_name)
+                       printk(KERN_DEBUG "[%s:%s], %pV", prefix,
+                              function_name, &vaf);
+               else
+                       printk(KERN_DEBUG "%pV", &vaf);
                va_end(args);
        }
 }
@@ -521,16 +527,10 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
 
        mutex_lock(&drm_global_mutex);
 
-       if (dev->driver->bus->agp_init) {
-               ret = dev->driver->bus->agp_init(dev);
-               if (ret)
-                       goto out_unlock;
-       }
-
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                ret = drm_get_minor(dev, &dev->control, DRM_MINOR_CONTROL);
                if (ret)
-                       goto err_agp;
+                       goto out_unlock;
        }
 
        if (drm_core_check_feature(dev, DRIVER_RENDER) && drm_rnodes) {
@@ -557,8 +557,6 @@ int drm_dev_register(struct drm_device *dev, unsigned long flags)
                        goto err_unload;
        }
 
-       list_add_tail(&dev->driver_item, &dev->driver->device_list);
-
        ret = 0;
        goto out_unlock;
 
@@ -571,9 +569,6 @@ err_render_node:
        drm_unplug_minor(dev->render);
 err_control_node:
        drm_unplug_minor(dev->control);
-err_agp:
-       if (dev->driver->bus->agp_destroy)
-               dev->driver->bus->agp_destroy(dev);
 out_unlock:
        mutex_unlock(&drm_global_mutex);
        return ret;
@@ -597,8 +592,8 @@ void drm_dev_unregister(struct drm_device *dev)
        if (dev->driver->unload)
                dev->driver->unload(dev);
 
-       if (dev->driver->bus->agp_destroy)
-               dev->driver->bus->agp_destroy(dev);
+       if (dev->agp)
+               drm_pci_agp_destroy(dev);
 
        drm_vblank_cleanup(dev);
 
@@ -608,7 +603,5 @@ void drm_dev_unregister(struct drm_device *dev)
        drm_unplug_minor(dev->control);
        drm_unplug_minor(dev->render);
        drm_unplug_minor(dev->primary);
-
-       list_del(&dev->driver_item);
 }
 EXPORT_SYMBOL(drm_dev_unregister);
index b179b70e7853b4bb4eb69c9a97a57295ae26a084..0f8cb1ae76074d2bf21d75d678585222019f2cdd 100644 (file)
@@ -1,4 +1,5 @@
 #include <drm/drmP.h>
+#include <drm/drm_usb.h>
 #include <linux/usb.h>
 #include <linux/module.h>
 
@@ -63,7 +64,6 @@ int drm_usb_init(struct drm_driver *driver, struct usb_driver *udriver)
        int res;
        DRM_DEBUG("\n");
 
-       INIT_LIST_HEAD(&driver->device_list);
        driver->kdriver.usb = udriver;
        driver->bus = &drm_usb_bus;
 
index 93e95d7efd575fc7bf084e431ae560793e733728..24e045c4f53140270ebbb28f9a6be21209b704a7 100644 (file)
@@ -101,7 +101,7 @@ static int drm_do_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        /*
         * Find the right map
         */
-       if (!drm_core_has_AGP(dev))
+       if (!dev->agp)
                goto vm_fault_error;
 
        if (!dev->agp || !dev->agp->cant_use_aperture)
@@ -220,7 +220,6 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
 
        DRM_DEBUG("0x%08lx,0x%08lx\n",
                  vma->vm_start, vma->vm_end - vma->vm_start);
-       atomic_dec(&dev->vma_count);
 
        map = vma->vm_private_data;
 
@@ -266,9 +265,6 @@ static void drm_vm_shm_close(struct vm_area_struct *vma)
                                dmah.size = map->size;
                                __drm_pci_free(dev, &dmah);
                                break;
-                       case _DRM_GEM:
-                               DRM_ERROR("tried to rmmap GEM object\n");
-                               break;
                        }
                        kfree(map);
                }
@@ -408,7 +404,6 @@ void drm_vm_open_locked(struct drm_device *dev,
 
        DRM_DEBUG("0x%08lx,0x%08lx\n",
                  vma->vm_start, vma->vm_end - vma->vm_start);
-       atomic_inc(&dev->vma_count);
 
        vma_entry = kmalloc(sizeof(*vma_entry), GFP_KERNEL);
        if (vma_entry) {
@@ -436,7 +431,6 @@ void drm_vm_close_locked(struct drm_device *dev,
 
        DRM_DEBUG("0x%08lx,0x%08lx\n",
                  vma->vm_start, vma->vm_end - vma->vm_start);
-       atomic_dec(&dev->vma_count);
 
        list_for_each_entry_safe(pt, temp, &dev->vmalist, head) {
                if (pt->vma == vma) {
@@ -595,7 +589,7 @@ int drm_mmap_locked(struct file *filp, struct vm_area_struct *vma)
        switch (map->type) {
 #if !defined(__arm__)
        case _DRM_AGP:
-               if (drm_core_has_AGP(dev) && dev->agp->cant_use_aperture) {
+               if (dev->agp && dev->agp->cant_use_aperture) {
                        /*
                         * On some platforms we can't talk to bus dma address from the CPU, so for
                         * memory of type DRM_AGP, we'll deal with sorting out the real physical
index 22b8f5eced80f3407b0fa9fc365c1d9e349d7e54..9d096a0c5f8d5f6bf0583d37f5efe433085504e4 100644 (file)
@@ -14,6 +14,8 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 
+#include <linux/anon_inodes.h>
+
 #include <drm/exynos_drm.h>
 
 #include "exynos_drm_drv.h"
@@ -119,6 +121,8 @@ static int exynos_drm_load(struct drm_device *dev, unsigned long flags)
 
        drm_vblank_offdelay = VBLANK_OFF_DELAY;
 
+       platform_set_drvdata(dev->platformdev, dev);
+
        return 0;
 
 err_drm_device:
@@ -150,9 +154,14 @@ static int exynos_drm_unload(struct drm_device *dev)
        return 0;
 }
 
+static const struct file_operations exynos_drm_gem_fops = {
+       .mmap = exynos_drm_gem_mmap_buffer,
+};
+
 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);
@@ -167,6 +176,16 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
                file->driver_priv = NULL;
        }
 
+       anon_filp = anon_inode_getfile("exynos_gem", &exynos_drm_gem_fops,
+                                       NULL, 0);
+       if (IS_ERR(anon_filp)) {
+               kfree(file_priv);
+               return PTR_ERR(anon_filp);
+       }
+
+       anon_filp->f_mode = FMODE_READ | FMODE_WRITE;
+       file_priv->anon_filp = anon_filp;
+
        return ret;
 }
 
@@ -179,6 +198,7 @@ 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;
@@ -204,6 +224,9 @@ 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;
@@ -305,7 +328,7 @@ static int exynos_drm_platform_probe(struct platform_device *pdev)
 
 static int exynos_drm_platform_remove(struct platform_device *pdev)
 {
-       drm_platform_exit(&exynos_drm_driver, pdev);
+       drm_put_dev(platform_get_drvdata(pdev));
 
        return 0;
 }
index eaa19668bf00328657bdd370c304f27cf66ece5e..0eaf5a27e120e586129074446e816b902d7316f3 100644 (file)
@@ -226,6 +226,7 @@ struct exynos_drm_ipp_private {
 struct drm_exynos_file_private {
        struct exynos_drm_g2d_private   *g2d_priv;
        struct exynos_drm_ipp_private   *ipp_priv;
+       struct file                     *anon_filp;
 };
 
 /*
index a61878bf5dcd091cf31ed64a8374d230b580dc1e..a20440ce32e6c39ee450d926f668f5638df0cca8 100644 (file)
@@ -347,7 +347,7 @@ static void fimd_wait_for_vblank(struct device *dev)
         */
        if (!wait_event_timeout(ctx->wait_vsync_queue,
                                !atomic_read(&ctx->wait_vsync_event),
-                               DRM_HZ/20))
+                               HZ/20))
                DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
@@ -706,7 +706,7 @@ static irqreturn_t fimd_irq_handler(int irq, void *dev_id)
        /* set wait vsync event to zero and wake up queue. */
        if (atomic_read(&ctx->wait_vsync_event)) {
                atomic_set(&ctx->wait_vsync_event, 0);
-               DRM_WAKEUP(&ctx->wait_vsync_queue);
+               wake_up(&ctx->wait_vsync_queue);
        }
 out:
        return IRQ_HANDLED;
@@ -954,7 +954,7 @@ static int fimd_probe(struct platform_device *pdev)
        }
 
        ctx->driver_data = drm_fimd_get_driver_data(pdev);
-       DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
+       init_waitqueue_head(&ctx->wait_vsync_queue);
        atomic_set(&ctx->wait_vsync_event, 0);
 
        subdrv = &ctx->subdrv;
index be59d50d8b16c836fbd1a5c88ed2bea87a7b769f..42d2904d88c7e32d90cd6d2dd56f97a3c917dc84 100644 (file)
@@ -338,46 +338,22 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
                        &args->offset);
 }
 
-static struct drm_file *exynos_drm_find_drm_file(struct drm_device *drm_dev,
-                                                       struct file *filp)
-{
-       struct drm_file *file_priv;
-
-       /* find current process's drm_file from filelist. */
-       list_for_each_entry(file_priv, &drm_dev->filelist, lhead)
-               if (file_priv->filp == filp)
-                       return file_priv;
-
-       WARN_ON(1);
-
-       return ERR_PTR(-EFAULT);
-}
-
-static int exynos_drm_gem_mmap_buffer(struct file *filp,
+int exynos_drm_gem_mmap_buffer(struct file *filp,
                                      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 exynos_drm_gem_buf *buffer;
-       struct drm_file *file_priv;
        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;
 
-       /* restore it to driver's fops. */
-       filp->f_op = fops_get(drm_dev->driver->fops);
-
-       file_priv = exynos_drm_find_drm_file(drm_dev, filp);
-       if (IS_ERR(file_priv))
-               return PTR_ERR(file_priv);
-
-       /* restore it to drm_file. */
-       filp->private_data = file_priv;
-
        update_vm_cache_attr(exynos_gem_obj, vma);
 
        vm_size = vma->vm_end - vma->vm_start;
@@ -411,15 +387,13 @@ static int exynos_drm_gem_mmap_buffer(struct file *filp,
        return 0;
 }
 
-static const struct file_operations exynos_drm_gem_fops = {
-       .mmap = exynos_drm_gem_mmap_buffer,
-};
-
 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)) {
@@ -427,47 +401,25 @@ int exynos_drm_gem_mmap_ioctl(struct drm_device *dev, void *data,
                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;
        }
 
-       /*
-        * We have to use gem object and its fops for specific mmaper,
-        * but vm_mmap() can deliver only filp. So we have to change
-        * filp->f_op and filp->private_data temporarily, then restore
-        * again. So it is important to keep lock until restoration the
-        * settings to prevent others from misuse of filp->f_op or
-        * filp->private_data.
-        */
-       mutex_lock(&dev->struct_mutex);
-
-       /*
-        * Set specific mmper's fops. And it will be restored by
-        * exynos_drm_gem_mmap_buffer to dev->driver->fops.
-        * This is used to call specific mapper temporarily.
-        */
-       file_priv->filp->f_op = &exynos_drm_gem_fops;
-
-       /*
-        * Set gem object to private_data so that specific mmaper
-        * can get the gem object. And it will be restored by
-        * exynos_drm_gem_mmap_buffer to drm_file.
-        */
-       file_priv->filp->private_data = obj;
+       exynos_file_priv = file_priv->driver_priv;
+       anon_filp = exynos_file_priv->anon_filp;
+       anon_filp->private_data = obj;
 
-       addr = vm_mmap(file_priv->filp, 0, args->size,
-                       PROT_READ | PROT_WRITE, MAP_SHARED, 0);
+       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)) {
-               /* check filp->f_op, filp->private_data are restored */
-               if (file_priv->filp->f_op == &exynos_drm_gem_fops) {
-                       file_priv->filp->f_op = fops_get(dev->driver->fops);
-                       file_priv->filp->private_data = file_priv;
-               }
                mutex_unlock(&dev->struct_mutex);
                return (int)addr;
        }
index b8c818ba2ff450e104fe545106a544ed92341632..1592c0ba7de86b596f2000d5bb3f780fa17ca33e 100644 (file)
@@ -122,6 +122,9 @@ int exynos_drm_gem_map_offset_ioctl(struct drm_device *dev, void *data,
 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 63bc5f92fbb320e6287fa106a8357c7eac503435..2dfa48c76f54644d1c7efd6fb6e52bedacc02e70 100644 (file)
@@ -868,7 +868,7 @@ static void mixer_wait_for_vblank(void *ctx)
         */
        if (!wait_event_timeout(mixer_ctx->wait_vsync_queue,
                                !atomic_read(&mixer_ctx->wait_vsync_event),
-                               DRM_HZ/20))
+                               HZ/20))
                DRM_DEBUG_KMS("vblank wait timed out.\n");
 }
 
@@ -1019,7 +1019,7 @@ static irqreturn_t mixer_irq_handler(int irq, void *arg)
                /* set wait vsync event to zero and wake up queue. */
                if (atomic_read(&ctx->wait_vsync_event)) {
                        atomic_set(&ctx->wait_vsync_event, 0);
-                       DRM_WAKEUP(&ctx->wait_vsync_queue);
+                       wake_up(&ctx->wait_vsync_queue);
                }
        }
 
@@ -1209,7 +1209,7 @@ static int mixer_probe(struct platform_device *pdev)
        drm_hdmi_ctx->ctx = (void *)ctx;
        ctx->vp_enabled = drv->is_vp_enabled;
        ctx->mxr_ver = drv->version;
-       DRM_INIT_WAITQUEUE(&ctx->wait_vsync_queue);
+       init_waitqueue_head(&ctx->wait_vsync_queue);
        atomic_set(&ctx->wait_vsync_event, 0);
 
        platform_set_drvdata(pdev, drm_hdmi_ctx);
index d5ef1a5793c8832e9a251fa817f7e19c246c06e6..de6f62a6ceb7a2d85ab67ba2eb64e8f688c05320 100644 (file)
@@ -326,7 +326,7 @@ int psbfb_sync(struct fb_info *info)
        struct psb_framebuffer *psbfb = &fbdev->pfb;
        struct drm_device *dev = psbfb->base.dev;
        struct drm_psb_private *dev_priv = dev->dev_private;
-       unsigned long _end = jiffies + DRM_HZ;
+       unsigned long _end = jiffies + HZ;
        int busy = 0;
        unsigned long flags;
 
index f88a1815d87c4e795492ead6ef1c4c07a4d31b89..0490ce36b53fd9237e754de7877f51f3aaffee97 100644 (file)
@@ -483,7 +483,7 @@ cdv_intel_dp_aux_native_write(struct gma_encoder *encoder,
 
        if (send_bytes > 16)
                return -1;
-       msg[0] = AUX_NATIVE_WRITE << 4;
+       msg[0] = DP_AUX_NATIVE_WRITE << 4;
        msg[1] = address >> 8;
        msg[2] = address & 0xff;
        msg[3] = send_bytes - 1;
@@ -493,9 +493,10 @@ cdv_intel_dp_aux_native_write(struct gma_encoder *encoder,
                ret = cdv_intel_dp_aux_ch(encoder, msg, msg_bytes, &ack, 1);
                if (ret < 0)
                        return ret;
-               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+               ack >>= 4;
+               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
                        break;
-               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
                        udelay(100);
                else
                        return -EIO;
@@ -523,7 +524,7 @@ cdv_intel_dp_aux_native_read(struct gma_encoder *encoder,
        uint8_t ack;
        int ret;
 
-       msg[0] = AUX_NATIVE_READ << 4;
+       msg[0] = DP_AUX_NATIVE_READ << 4;
        msg[1] = address >> 8;
        msg[2] = address & 0xff;
        msg[3] = recv_bytes - 1;
@@ -538,12 +539,12 @@ cdv_intel_dp_aux_native_read(struct gma_encoder *encoder,
                        return -EPROTO;
                if (ret < 0)
                        return ret;
-               ack = reply[0];
-               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
+               ack = reply[0] >> 4;
+               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) {
                        memcpy(recv, reply + 1, ret - 1);
                        return ret - 1;
                }
-               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
                        udelay(100);
                else
                        return -EIO;
@@ -569,12 +570,12 @@ cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
 
        /* Set up the command byte */
        if (mode & MODE_I2C_READ)
-               msg[0] = AUX_I2C_READ << 4;
+               msg[0] = DP_AUX_I2C_READ << 4;
        else
-               msg[0] = AUX_I2C_WRITE << 4;
+               msg[0] = DP_AUX_I2C_WRITE << 4;
 
        if (!(mode & MODE_I2C_STOP))
-               msg[0] |= AUX_I2C_MOT << 4;
+               msg[0] |= DP_AUX_I2C_MOT << 4;
 
        msg[1] = address >> 8;
        msg[2] = address;
@@ -606,16 +607,16 @@ cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                        return ret;
                }
 
-               switch (reply[0] & AUX_NATIVE_REPLY_MASK) {
-               case AUX_NATIVE_REPLY_ACK:
+               switch ((reply[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK) {
+               case DP_AUX_NATIVE_REPLY_ACK:
                        /* I2C-over-AUX Reply field is only valid
                         * when paired with AUX ACK.
                         */
                        break;
-               case AUX_NATIVE_REPLY_NACK:
+               case DP_AUX_NATIVE_REPLY_NACK:
                        DRM_DEBUG_KMS("aux_ch native nack\n");
                        return -EREMOTEIO;
-               case AUX_NATIVE_REPLY_DEFER:
+               case DP_AUX_NATIVE_REPLY_DEFER:
                        udelay(100);
                        continue;
                default:
@@ -624,16 +625,16 @@ cdv_intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                        return -EREMOTEIO;
                }
 
-               switch (reply[0] & AUX_I2C_REPLY_MASK) {
-               case AUX_I2C_REPLY_ACK:
+               switch ((reply[0] >> 4) & DP_AUX_I2C_REPLY_MASK) {
+               case DP_AUX_I2C_REPLY_ACK:
                        if (mode == MODE_I2C_READ) {
                                *read_byte = reply[1];
                        }
                        return reply_bytes - 1;
-               case AUX_I2C_REPLY_NACK:
+               case DP_AUX_I2C_REPLY_NACK:
                        DRM_DEBUG_KMS("aux_i2c nack\n");
                        return -EREMOTEIO;
-               case AUX_I2C_REPLY_DEFER:
+               case DP_AUX_I2C_REPLY_DEFER:
                        DRM_DEBUG_KMS("aux_i2c defer\n");
                        udelay(100);
                        break;
@@ -677,7 +678,7 @@ cdv_intel_dp_i2c_init(struct gma_connector *connector,
        return ret;
 }
 
-void cdv_intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
+static void cdv_intel_fixed_panel_mode(struct drm_display_mode *fixed_mode,
        struct drm_display_mode *adjusted_mode)
 {
        adjusted_mode->hdisplay = fixed_mode->hdisplay;
index 24e8af3d22bfd34583d8b826b3fd75f7023002c7..386de2c9dc8649f449580a062d4d91c62fd3a733 100644 (file)
@@ -349,6 +349,7 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc,
        /* If we didn't get a handle then turn the cursor off */
        if (!handle) {
                temp = CURSOR_MODE_DISABLE;
+               mutex_lock(&dev->struct_mutex);
 
                if (gma_power_begin(dev, false)) {
                        REG_WRITE(control, temp);
@@ -365,6 +366,7 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc,
                        gma_crtc->cursor_obj = NULL;
                }
 
+               mutex_unlock(&dev->struct_mutex);
                return 0;
        }
 
@@ -374,9 +376,12 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc,
                return -EINVAL;
        }
 
+       mutex_lock(&dev->struct_mutex);
        obj = drm_gem_object_lookup(dev, file_priv, handle);
-       if (!obj)
-               return -ENOENT;
+       if (!obj) {
+               ret = -ENOENT;
+               goto unlock;
+       }
 
        if (obj->size < width * height * 4) {
                dev_dbg(dev->dev, "Buffer is too small\n");
@@ -440,10 +445,13 @@ int gma_crtc_cursor_set(struct drm_crtc *crtc,
        }
 
        gma_crtc->cursor_obj = obj;
+unlock:
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 
 unref_cursor:
        drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
        return ret;
 }
 
index b59e6588c34327b9162c0346de826729633b20cc..5ad6a03e477eae63aa8cc635981887febca71ac1 100644 (file)
@@ -212,8 +212,8 @@ enum {
 #define PSB_HIGH_REG_OFFS 0x0600
 
 #define PSB_NUM_VBLANKS 2
-#define PSB_WATCHDOG_DELAY (DRM_HZ * 2)
-#define PSB_LID_DELAY (DRM_HZ / 10)
+#define PSB_WATCHDOG_DELAY (HZ * 2)
+#define PSB_LID_DELAY (HZ / 10)
 
 #define MDFLD_PNW_B0 0x04
 #define MDFLD_PNW_C0 0x08
@@ -232,7 +232,7 @@ enum {
 #define MDFLD_DSR_RR           45
 #define MDFLD_DPU_ENABLE       (1 << 31)
 #define MDFLD_DSR_FULLSCREEN   (1 << 30)
-#define MDFLD_DSR_DELAY                (DRM_HZ / MDFLD_DSR_RR)
+#define MDFLD_DSR_DELAY                (HZ / MDFLD_DSR_RR)
 
 #define PSB_PWR_STATE_ON               1
 #define PSB_PWR_STATE_OFF              2
@@ -769,7 +769,7 @@ extern void psb_mmu_remove_pages(struct psb_mmu_pd *pd,
  *psb_irq.c
  */
 
-extern irqreturn_t psb_irq_handler(DRM_IRQ_ARGS);
+extern irqreturn_t psb_irq_handler(int irq, void *arg);
 extern int psb_irq_enable_dpst(struct drm_device *dev);
 extern int psb_irq_disable_dpst(struct drm_device *dev);
 extern void psb_irq_preinstall(struct drm_device *dev);
index bde27fdb41bf9d9a7ab79f0e3545e5ae0f9c96a5..dc2c8eb030faeaf29f4bd7d32c87c803ab846e30 100644 (file)
@@ -250,11 +250,6 @@ extern void psb_intel_sdvo_set_hotplug(struct drm_connector *connector,
 extern int intelfb_probe(struct drm_device *dev);
 extern int intelfb_remove(struct drm_device *dev,
                          struct drm_framebuffer *fb);
-extern struct drm_framebuffer *psb_intel_framebuffer_create(struct drm_device
-                                                       *dev, struct
-                                                       drm_mode_fb_cmd
-                                                       *mode_cmd,
-                                                       void *mm_private);
 extern bool psb_intel_lvds_mode_fixup(struct drm_encoder *encoder,
                                      const struct drm_display_mode *mode,
                                      struct drm_display_mode *adjusted_mode);
index ba4830342d3450593bbc1f49a5a6fded4419c510..f883f9e4c5240ee923cbaabb3c57b88472983431 100644 (file)
@@ -200,7 +200,7 @@ static void psb_vdc_interrupt(struct drm_device *dev, uint32_t vdc_stat)
                mid_pipe_event_handler(dev, 1);
 }
 
-irqreturn_t psb_irq_handler(DRM_IRQ_ARGS)
+irqreturn_t psb_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct drm_psb_private *dev_priv = dev->dev_private;
@@ -253,7 +253,7 @@ irqreturn_t psb_irq_handler(DRM_IRQ_ARGS)
 
        PSB_WVDC32(vdc_stat, PSB_INT_IDENTITY_R);
        (void) PSB_RVDC32(PSB_INT_IDENTITY_R);
-       DRM_READMEMORYBARRIER();
+       rmb();
 
        if (!handled)
                return IRQ_NONE;
@@ -450,21 +450,6 @@ int psb_irq_disable_dpst(struct drm_device *dev)
        return 0;
 }
 
-#ifdef PSB_FIXME
-static int psb_vblank_do_wait(struct drm_device *dev,
-                             unsigned int *sequence, atomic_t *counter)
-{
-       unsigned int cur_vblank;
-       int ret = 0;
-       DRM_WAIT_ON(ret, dev->vblank.queue, 3 * DRM_HZ,
-                   (((cur_vblank = atomic_read(counter))
-                     - *sequence) <= (1 << 23)));
-       *sequence = cur_vblank;
-
-       return ret;
-}
-#endif
-
 /*
  * It is used to enable VBLANK interrupt
  */
index debb7f190c062a725e43e38c567dc815823b38f0..d0b45ffa112600b65beb932f8fb1b4e5802453af 100644 (file)
@@ -32,7 +32,7 @@ void sysirq_uninit(struct drm_device *dev);
 void psb_irq_preinstall(struct drm_device *dev);
 int  psb_irq_postinstall(struct drm_device *dev);
 void psb_irq_uninstall(struct drm_device *dev);
-irqreturn_t psb_irq_handler(DRM_IRQ_ARGS);
+irqreturn_t psb_irq_handler(int irq, void *arg);
 
 int psb_irq_enable_dpst(struct drm_device *dev);
 int psb_irq_disable_dpst(struct drm_device *dev);
index 249fdff305c63b50fd72c2f62a499eb2a0d3e576..aeace37415aac8ae62ab2aa53a3b927ae648fb6c 100644 (file)
@@ -1193,6 +1193,10 @@ static int i810_flip_bufs(struct drm_device *dev, void *data,
 
 int i810_driver_load(struct drm_device *dev, unsigned long flags)
 {
+       /* Our userspace depends upon the agp mapping support. */
+       if (!dev->agp)
+               return -EINVAL;
+
        pci_set_master(dev->pdev);
 
        return 0;
index d8180d22ceddb38965e3c6f59367d75a8421dff2..441ccf8f5bdc3a7d2ebad9b4724eff2044d2c34b 100644 (file)
@@ -57,7 +57,7 @@ static const struct file_operations i810_driver_fops = {
 
 static struct drm_driver driver = {
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_REQUIRE_AGP |
+           DRIVER_USE_AGP |
            DRIVER_HAVE_DMA,
        .dev_priv_size = sizeof(drm_i810_buf_priv_t),
        .load = i810_driver_load,
index 6199d0b5b958fb2610e83810e117ea89c5057e6e..73ed59eff139a88948c7766dcc0c999398f59254 100644 (file)
@@ -1,8 +1,10 @@
 config DRM_I915
        tristate "Intel 8xx/9xx/G3x/G4x/HD Graphics"
        depends on DRM
-       depends on AGP
-       depends on AGP_INTEL
+       depends on X86 && PCI
+       depends on (AGP || AGP=n)
+       select INTEL_GTT
+       select AGP_INTEL if AGP
        # we need shmfs for the swappable backing store, and in particular
        # the shmem_readpage() which depends upon tmpfs
        select SHMEM
@@ -35,15 +37,14 @@ config DRM_I915
 config DRM_I915_KMS
        bool "Enable modesetting on intel by default"
        depends on DRM_I915
+       default y
        help
-         Choose this option if you want kernel modesetting enabled by default,
-         and you have a new enough userspace to support this. Running old
-         userspaces with this enabled will cause pain.  Note that this causes
-         the driver to bind to PCI devices, which precludes loading things
-         like intelfb.
+         Choose this option if you want kernel modesetting enabled by default.
+
+         If in doubt, say "Y".
 
 config DRM_I915_FBDEV
-       bool "Enable legacy fbdev support for the modesettting intel driver"
+       bool "Enable legacy fbdev support for the modesetting intel driver"
        depends on DRM_I915
        select DRM_KMS_FB_HELPER
        select FB_CFB_FILLRECT
@@ -55,9 +56,12 @@ config DRM_I915_FBDEV
          support. Note that this support also provide the linux console
          support on top of the intel modesetting driver.
 
+         If in doubt, say "Y".
+
 config DRM_I915_PRELIMINARY_HW_SUPPORT
        bool "Enable preliminary support for prerelease Intel hardware by default"
        depends on DRM_I915
+       default n
        help
          Choose this option if you have prerelease Intel hardware and want the
          i915 driver to support it by default.  You can enable such support at
@@ -65,3 +69,15 @@ config DRM_I915_PRELIMINARY_HW_SUPPORT
          option changes the default for that module option.
 
          If in doubt, say "N".
+
+config DRM_I915_UMS
+       bool "Enable userspace modesetting on Intel hardware (DEPRECATED)"
+       depends on DRM_I915
+       default n
+       help
+         Choose this option if you still need userspace modesetting.
+
+         Userspace modesetting is deprecated for quite some time now, so
+         enable this only if you have ancient versions of the DDX drivers.
+
+         If in doubt, say "N".
index d4ae48b04cf2b127630e309192cce4c05509cbf4..9fd44f5f3b3b40ff5f1acf497b613a36e153cac2 100644 (file)
@@ -4,7 +4,6 @@
 
 ccflags-y := -Iinclude/drm
 i915-y := i915_drv.o i915_dma.o i915_irq.o \
-         i915_debugfs.o \
          i915_gpu_error.o \
           i915_suspend.o \
          i915_gem.o \
@@ -54,6 +53,8 @@ i915-$(CONFIG_ACPI)   += intel_acpi.o intel_opregion.o
 
 i915-$(CONFIG_DRM_I915_FBDEV) += intel_fbdev.o
 
+i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
+
 obj-$(CONFIG_DRM_I915)  += i915.o
 
 CFLAGS_i915_trace_points.o := -I$(src)
index c4a255be697921caade4bf3dd064217e82230763..954acb2c7021d8eb9a90fe1e49ea5bc806f1f344 100644 (file)
@@ -87,49 +87,6 @@ struct ns2501_priv {
  * when switching the resolution.
  */
 
-static void enable_dvo(struct intel_dvo_device *dvo)
-{
-       struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_gmbus *bus = container_of(adapter,
-                                              struct intel_gmbus,
-                                              adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-
-       DRM_DEBUG_KMS("%s: Trying to re-enable the DVO\n", __FUNCTION__);
-
-       ns->dvoc = I915_READ(DVO_C);
-       ns->pll_a = I915_READ(_DPLL_A);
-       ns->srcdim = I915_READ(DVOC_SRCDIM);
-       ns->fw_blc = I915_READ(FW_BLC);
-
-       I915_WRITE(DVOC, 0x10004084);
-       I915_WRITE(_DPLL_A, 0xd0820000);
-       I915_WRITE(DVOC_SRCDIM, 0x400300);      // 1024x768
-       I915_WRITE(FW_BLC, 0x1080304);
-
-       I915_WRITE(DVOC, 0x90004084);
-}
-
-/*
- * Restore the I915 registers modified by the above
- * trigger function.
- */
-static void restore_dvo(struct intel_dvo_device *dvo)
-{
-       struct i2c_adapter *adapter = dvo->i2c_bus;
-       struct intel_gmbus *bus = container_of(adapter,
-                                              struct intel_gmbus,
-                                              adapter);
-       struct drm_i915_private *dev_priv = bus->dev_priv;
-       struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
-
-       I915_WRITE(DVOC, ns->dvoc);
-       I915_WRITE(_DPLL_A, ns->pll_a);
-       I915_WRITE(DVOC_SRCDIM, ns->srcdim);
-       I915_WRITE(FW_BLC, ns->fw_blc);
-}
-
 /*
 ** Read a register from the ns2501.
 ** Returns true if successful, false otherwise.
@@ -300,7 +257,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
                            struct drm_display_mode *adjusted_mode)
 {
        bool ok;
-       bool restore = false;
+       int retries = 10;
        struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
 
        DRM_DEBUG_KMS
@@ -476,20 +433,7 @@ static void ns2501_mode_set(struct intel_dvo_device *dvo,
                        ns->reg_8_shadow |= NS2501_8_BPAS;
                }
                ok &= ns2501_writeb(dvo, NS2501_REG8, ns->reg_8_shadow);
-
-               if (!ok) {
-                       if (restore)
-                               restore_dvo(dvo);
-                       enable_dvo(dvo);
-                       restore = true;
-               }
-       } while (!ok);
-       /*
-        * Restore the old i915 registers before
-        * forcing the ns2501 on.
-        */
-       if (restore)
-               restore_dvo(dvo);
+       } while (!ok && retries--);
 }
 
 /* set the NS2501 power state */
@@ -510,7 +454,7 @@ static bool ns2501_get_hw_state(struct intel_dvo_device *dvo)
 static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
 {
        bool ok;
-       bool restore = false;
+       int retries = 10;
        struct ns2501_priv *ns = (struct ns2501_priv *)(dvo->dev_priv);
        unsigned char ch;
 
@@ -537,16 +481,7 @@ static void ns2501_dpms(struct intel_dvo_device *dvo, bool enable)
                        ok &=
                            ns2501_writeb(dvo, 0x35,
                                          enable ? 0xff : 0x00);
-                       if (!ok) {
-                               if (restore)
-                                       restore_dvo(dvo);
-                               enable_dvo(dvo);
-                               restore = true;
-                       }
-               } while (!ok);
-
-               if (restore)
-                       restore_dvo(dvo);
+               } while (!ok && retries--);
        }
 }
 
index 6ed45a984230c6db3bb8cc4b8fbdc2eec9a661d1..b2b46c52294c6d4d9c2a20890fafaa4b122e7fa3 100644 (file)
@@ -40,8 +40,6 @@
 #include <drm/i915_drm.h>
 #include "i915_drv.h"
 
-#if defined(CONFIG_DEBUG_FS)
-
 enum {
        ACTIVE_LIST,
        INACTIVE_LIST,
@@ -406,16 +404,26 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
        seq_putc(m, '\n');
        list_for_each_entry_reverse(file, &dev->filelist, lhead) {
                struct file_stats stats;
+               struct task_struct *task;
 
                memset(&stats, 0, sizeof(stats));
                idr_for_each(&file->object_idr, per_file_stats, &stats);
+               /*
+                * Although we have a valid reference on file->pid, that does
+                * not guarantee that the task_struct who called get_pid() is
+                * still alive (e.g. get_pid(current) => fork() => exit()).
+                * Therefore, we need to protect this ->comm access using RCU.
+                */
+               rcu_read_lock();
+               task = pid_task(file->pid, PIDTYPE_PID);
                seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu unbound)\n",
-                          get_pid_task(file->pid, PIDTYPE_PID)->comm,
+                          task ? task->comm : "<unknown>",
                           stats.count,
                           stats.total,
                           stats.active,
                           stats.inactive,
                           stats.unbound);
+               rcu_read_unlock();
        }
 
        mutex_unlock(&dev->struct_mutex);
@@ -564,10 +572,12 @@ static int i915_gem_seqno_info(struct seq_file *m, void *data)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        for_each_ring(ring, dev_priv, i)
                i915_ring_seqno_info(m, ring);
 
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -585,6 +595,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        if (INTEL_INFO(dev)->gen >= 8) {
                int i;
@@ -711,6 +722,7 @@ static int i915_interrupt_info(struct seq_file *m, void *data)
                }
                i915_ring_seqno_info(m, ring);
        }
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -904,9 +916,11 @@ static int i915_rstdby_delays(struct seq_file *m, void *unused)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        crstanddelay = I915_READ16(CRSTANDVID);
 
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
        seq_printf(m, "w/ctx: %d, w/o ctx: %d\n", (crstanddelay >> 8) & 0x3f, (crstanddelay & 0x3f));
@@ -919,7 +933,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       int ret;
+       int ret = 0;
+
+       intel_runtime_pm_get(dev_priv);
 
        flush_delayed_work(&dev_priv->rps.delayed_resume_work);
 
@@ -945,9 +961,9 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                /* RPSTAT1 is in the GT power well */
                ret = mutex_lock_interruptible(&dev->struct_mutex);
                if (ret)
-                       return ret;
+                       goto out;
 
-               gen6_gt_force_wake_get(dev_priv);
+               gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
                reqf = I915_READ(GEN6_RPNSWREQ);
                reqf &= ~GEN6_TURBO_DISABLE;
@@ -970,7 +986,7 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                        cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
                cagf *= GT_FREQUENCY_MULTIPLIER;
 
-               gen6_gt_force_wake_put(dev_priv);
+               gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
                mutex_unlock(&dev->struct_mutex);
 
                seq_printf(m, "GT_PERF_STATUS: 0x%08x\n", gt_perf_status);
@@ -1018,23 +1034,24 @@ static int i915_cur_delayinfo(struct seq_file *m, void *unused)
                seq_printf(m, "PUNIT_REG_GPU_FREQ_STS: 0x%08x\n", freq_sts);
                seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq);
 
-               val = vlv_punit_read(dev_priv, PUNIT_FUSE_BUS1);
+               val = valleyview_rps_max_freq(dev_priv);
                seq_printf(m, "max GPU freq: %d MHz\n",
-                          vlv_gpu_freq(dev_priv->mem_freq, val));
+                          vlv_gpu_freq(dev_priv, val));
 
-               val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_LFM);
+               val = valleyview_rps_min_freq(dev_priv);
                seq_printf(m, "min GPU freq: %d MHz\n",
-                          vlv_gpu_freq(dev_priv->mem_freq, val));
+                          vlv_gpu_freq(dev_priv, val));
 
                seq_printf(m, "current GPU freq: %d MHz\n",
-                          vlv_gpu_freq(dev_priv->mem_freq,
-                                       (freq_sts >> 8) & 0xff));
+                          vlv_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff));
                mutex_unlock(&dev_priv->rps.hw_lock);
        } else {
                seq_puts(m, "no P-state info available\n");
        }
 
-       return 0;
+out:
+       intel_runtime_pm_put(dev_priv);
+       return ret;
 }
 
 static int i915_delayfreq_table(struct seq_file *m, void *unused)
@@ -1048,6 +1065,7 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        for (i = 0; i < 16; i++) {
                delayfreq = I915_READ(PXVFREQ_BASE + i * 4);
@@ -1055,6 +1073,8 @@ static int i915_delayfreq_table(struct seq_file *m, void *unused)
                           (delayfreq & PXVFREQ_PX_MASK) >> PXVFREQ_PX_SHIFT);
        }
 
+       intel_runtime_pm_put(dev_priv);
+
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -1076,12 +1096,14 @@ static int i915_inttoext_table(struct seq_file *m, void *unused)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        for (i = 1; i <= 32; i++) {
                inttoext = I915_READ(INTTOEXT_BASE_ILK + i * 4);
                seq_printf(m, "INTTOEXT%02d: 0x%08x\n", i, inttoext);
        }
 
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -1099,11 +1121,13 @@ static int ironlake_drpc_info(struct seq_file *m)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        rgvmodectl = I915_READ(MEMMODECTL);
        rstdbyctl = I915_READ(RSTDBYCTL);
        crstandvid = I915_READ16(CRSTANDVID);
 
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
        seq_printf(m, "HD boost: %s\n", (rgvmodectl & MEMMODE_BOOST_EN) ?
@@ -1154,6 +1178,50 @@ static int ironlake_drpc_info(struct seq_file *m)
        return 0;
 }
 
+static int vlv_drpc_info(struct seq_file *m)
+{
+
+       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;
+       u32 rpmodectl1, rcctl1;
+       unsigned fw_rendercount = 0, fw_mediacount = 0;
+
+       rpmodectl1 = I915_READ(GEN6_RP_CONTROL);
+       rcctl1 = I915_READ(GEN6_RC_CONTROL);
+
+       seq_printf(m, "Video Turbo Mode: %s\n",
+                  yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO));
+       seq_printf(m, "Turbo enabled: %s\n",
+                  yesno(rpmodectl1 & GEN6_RP_ENABLE));
+       seq_printf(m, "HW control enabled: %s\n",
+                  yesno(rpmodectl1 & GEN6_RP_ENABLE));
+       seq_printf(m, "SW control enabled: %s\n",
+                  yesno((rpmodectl1 & GEN6_RP_MEDIA_MODE_MASK) ==
+                         GEN6_RP_MEDIA_SW_MODE));
+       seq_printf(m, "RC6 Enabled: %s\n",
+                  yesno(rcctl1 & (GEN7_RC_CTL_TO_MODE |
+                                       GEN6_RC_CTL_EI_MODE(1))));
+       seq_printf(m, "Render Power Well: %s\n",
+                       (I915_READ(VLV_GTLC_PW_STATUS) &
+                               VLV_GTLC_PW_RENDER_STATUS_MASK) ? "Up" : "Down");
+       seq_printf(m, "Media Power Well: %s\n",
+                       (I915_READ(VLV_GTLC_PW_STATUS) &
+                               VLV_GTLC_PW_MEDIA_STATUS_MASK) ? "Up" : "Down");
+
+       spin_lock_irq(&dev_priv->uncore.lock);
+       fw_rendercount = dev_priv->uncore.fw_rendercount;
+       fw_mediacount = dev_priv->uncore.fw_mediacount;
+       spin_unlock_irq(&dev_priv->uncore.lock);
+
+       seq_printf(m, "Forcewake Render Count = %u\n", fw_rendercount);
+       seq_printf(m, "Forcewake Media Count = %u\n", fw_mediacount);
+
+
+       return 0;
+}
+
+
 static int gen6_drpc_info(struct seq_file *m)
 {
 
@@ -1167,6 +1235,7 @@ static int gen6_drpc_info(struct seq_file *m)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        spin_lock_irq(&dev_priv->uncore.lock);
        forcewake_count = dev_priv->uncore.forcewake_count;
@@ -1192,6 +1261,8 @@ static int gen6_drpc_info(struct seq_file *m)
        sandybridge_pcode_read(dev_priv, GEN6_PCODE_READ_RC6VIDS, &rc6vids);
        mutex_unlock(&dev_priv->rps.hw_lock);
 
+       intel_runtime_pm_put(dev_priv);
+
        seq_printf(m, "Video Turbo Mode: %s\n",
                   yesno(rpmodectl1 & GEN6_RP_MEDIA_TURBO));
        seq_printf(m, "HW control enabled: %s\n",
@@ -1256,7 +1327,9 @@ static int i915_drpc_info(struct seq_file *m, void *unused)
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
 
-       if (IS_GEN6(dev) || IS_GEN7(dev))
+       if (IS_VALLEYVIEW(dev))
+               return vlv_drpc_info(m);
+       else if (IS_GEN6(dev) || IS_GEN7(dev))
                return gen6_drpc_info(m);
        else
                return ironlake_drpc_info(m);
@@ -1268,7 +1341,7 @@ static int i915_fbc_status(struct seq_file *m, void *unused)
        struct drm_device *dev = node->minor->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
 
-       if (!I915_HAS_FBC(dev)) {
+       if (!HAS_FBC(dev)) {
                seq_puts(m, "FBC unsupported on this chipset\n");
                return 0;
        }
@@ -1330,7 +1403,7 @@ static int i915_ips_status(struct seq_file *m, void *unused)
                return 0;
        }
 
-       if (I915_READ(IPS_CTL) & IPS_ENABLE)
+       if (IS_BROADWELL(dev) || I915_READ(IPS_CTL) & IPS_ENABLE)
                seq_puts(m, "enabled\n");
        else
                seq_puts(m, "disabled\n");
@@ -1406,6 +1479,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
        ret = mutex_lock_interruptible(&dev_priv->rps.hw_lock);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        seq_puts(m, "GPU freq (MHz)\tEffective CPU freq (MHz)\tEffective Ring freq (MHz)\n");
 
@@ -1422,6 +1496,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
                           ((ia_freq >> 8) & 0xff) * 100);
        }
 
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return 0;
@@ -1437,8 +1512,10 @@ static int i915_gfxec(struct seq_file *m, void *unused)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        seq_printf(m, "GFXEC: %ld\n", (unsigned long)I915_READ(0x112f4));
+       intel_runtime_pm_put(dev_priv);
 
        mutex_unlock(&dev->struct_mutex);
 
@@ -1565,13 +1642,21 @@ static int i915_gen6_forcewake_count_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_i915_private *dev_priv = dev->dev_private;
-       unsigned forcewake_count;
+       unsigned forcewake_count = 0, fw_rendercount = 0, fw_mediacount = 0;
 
        spin_lock_irq(&dev_priv->uncore.lock);
-       forcewake_count = dev_priv->uncore.forcewake_count;
+       if (IS_VALLEYVIEW(dev)) {
+               fw_rendercount = dev_priv->uncore.fw_rendercount;
+               fw_mediacount = dev_priv->uncore.fw_mediacount;
+       } else
+               forcewake_count = dev_priv->uncore.forcewake_count;
        spin_unlock_irq(&dev_priv->uncore.lock);
 
-       seq_printf(m, "forcewake count = %u\n", forcewake_count);
+       if (IS_VALLEYVIEW(dev)) {
+               seq_printf(m, "fw_rendercount = %u\n", fw_rendercount);
+               seq_printf(m, "fw_mediacount = %u\n", fw_mediacount);
+       } else
+               seq_printf(m, "forcewake count = %u\n", forcewake_count);
 
        return 0;
 }
@@ -1610,6 +1695,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        seq_printf(m, "bit6 swizzle for X-tiling = %s\n",
                   swizzle_string(dev_priv->mm.bit_6_swizzle_x));
@@ -1641,6 +1727,7 @@ static int i915_swizzle_info(struct seq_file *m, void *data)
                seq_printf(m, "DISP_ARB_CTL = 0x%08x\n",
                           I915_READ(DISP_ARB_CTL));
        }
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -1701,16 +1788,19 @@ static int i915_ppgtt_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_i915_private *dev_priv = dev->dev_private;
 
        int ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        if (INTEL_INFO(dev)->gen >= 8)
                gen8_ppgtt_info(m, dev);
        else if (INTEL_INFO(dev)->gen >= 6)
                gen6_ppgtt_info(m, dev);
 
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
        return 0;
@@ -1735,28 +1825,28 @@ static int i915_dpio_info(struct seq_file *m, void *data)
 
        seq_printf(m, "DPIO_CTL: 0x%08x\n", I915_READ(DPIO_CTL));
 
-       seq_printf(m, "DPIO_DIV_A: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, _DPIO_DIV_A));
-       seq_printf(m, "DPIO_DIV_B: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, _DPIO_DIV_B));
+       seq_printf(m, "DPIO PLL DW3 CH0 : 0x%08x\n",
+                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(0)));
+       seq_printf(m, "DPIO PLL DW3 CH1: 0x%08x\n",
+                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW3(1)));
 
-       seq_printf(m, "DPIO_REFSFR_A: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, _DPIO_REFSFR_A));
-       seq_printf(m, "DPIO_REFSFR_B: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, _DPIO_REFSFR_B));
+       seq_printf(m, "DPIO PLL DW5 CH0: 0x%08x\n",
+                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(0)));
+       seq_printf(m, "DPIO PLL DW5 CH1: 0x%08x\n",
+                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW5(1)));
 
-       seq_printf(m, "DPIO_CORE_CLK_A: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, _DPIO_CORE_CLK_A));
-       seq_printf(m, "DPIO_CORE_CLK_B: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, _DPIO_CORE_CLK_B));
+       seq_printf(m, "DPIO PLL DW7 CH0: 0x%08x\n",
+                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(0)));
+       seq_printf(m, "DPIO PLL DW7 CH1: 0x%08x\n",
+                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW7(1)));
 
-       seq_printf(m, "DPIO_LPF_COEFF_A: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, _DPIO_LPF_COEFF_A));
-       seq_printf(m, "DPIO_LPF_COEFF_B: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, _DPIO_LPF_COEFF_B));
+       seq_printf(m, "DPIO PLL DW10 CH0: 0x%08x\n",
+                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(0)));
+       seq_printf(m, "DPIO PLL DW10 CH1: 0x%08x\n",
+                  vlv_dpio_read(dev_priv, PIPE_A, VLV_PLL_DW10(1)));
 
        seq_printf(m, "DPIO_FASTCLK_DISABLE: 0x%08x\n",
-                  vlv_dpio_read(dev_priv, PIPE_A, DPIO_FASTCLK_DISABLE));
+                  vlv_dpio_read(dev_priv, PIPE_A, VLV_CMN_DW0));
 
        mutex_unlock(&dev_priv->dpio_lock);
 
@@ -1784,6 +1874,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
        u32 psrperf = 0;
        bool enabled = false;
 
+       intel_runtime_pm_get(dev_priv);
+
        seq_printf(m, "Sink_Support: %s\n", yesno(dev_priv->psr.sink_support));
        seq_printf(m, "Source_OK: %s\n", yesno(dev_priv->psr.source_ok));
 
@@ -1796,6 +1888,7 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
                        EDP_PSR_PERF_CNT_MASK;
        seq_printf(m, "Performance_Counter: %u\n", psrperf);
 
+       intel_runtime_pm_put(dev_priv);
        return 0;
 }
 
@@ -1845,6 +1938,76 @@ static int i915_pc8_status(struct seq_file *m, void *unused)
        return 0;
 }
 
+static const char *power_domain_str(enum intel_display_power_domain domain)
+{
+       switch (domain) {
+       case POWER_DOMAIN_PIPE_A:
+               return "PIPE_A";
+       case POWER_DOMAIN_PIPE_B:
+               return "PIPE_B";
+       case POWER_DOMAIN_PIPE_C:
+               return "PIPE_C";
+       case POWER_DOMAIN_PIPE_A_PANEL_FITTER:
+               return "PIPE_A_PANEL_FITTER";
+       case POWER_DOMAIN_PIPE_B_PANEL_FITTER:
+               return "PIPE_B_PANEL_FITTER";
+       case POWER_DOMAIN_PIPE_C_PANEL_FITTER:
+               return "PIPE_C_PANEL_FITTER";
+       case POWER_DOMAIN_TRANSCODER_A:
+               return "TRANSCODER_A";
+       case POWER_DOMAIN_TRANSCODER_B:
+               return "TRANSCODER_B";
+       case POWER_DOMAIN_TRANSCODER_C:
+               return "TRANSCODER_C";
+       case POWER_DOMAIN_TRANSCODER_EDP:
+               return "TRANSCODER_EDP";
+       case POWER_DOMAIN_VGA:
+               return "VGA";
+       case POWER_DOMAIN_AUDIO:
+               return "AUDIO";
+       case POWER_DOMAIN_INIT:
+               return "INIT";
+       default:
+               WARN_ON(1);
+               return "?";
+       }
+}
+
+static int i915_power_domain_info(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 i915_power_domains *power_domains = &dev_priv->power_domains;
+       int i;
+
+       mutex_lock(&power_domains->lock);
+
+       seq_printf(m, "%-25s %s\n", "Power well/domain", "Use count");
+       for (i = 0; i < power_domains->power_well_count; i++) {
+               struct i915_power_well *power_well;
+               enum intel_display_power_domain power_domain;
+
+               power_well = &power_domains->power_wells[i];
+               seq_printf(m, "%-25s %d\n", power_well->name,
+                          power_well->count);
+
+               for (power_domain = 0; power_domain < POWER_DOMAIN_NUM;
+                    power_domain++) {
+                       if (!(BIT(power_domain) & power_well->domains))
+                               continue;
+
+                       seq_printf(m, "  %-23s %d\n",
+                                power_domain_str(power_domain),
+                                power_domains->domain_use_count[power_domain]);
+               }
+       }
+
+       mutex_unlock(&power_domains->lock);
+
+       return 0;
+}
+
 struct pipe_crc_info {
        const char *name;
        struct drm_device *dev;
@@ -1857,6 +2020,9 @@ static int i915_pipe_crc_open(struct inode *inode, struct file *filep)
        struct drm_i915_private *dev_priv = info->dev->dev_private;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe];
 
+       if (info->pipe >= INTEL_INFO(info->dev)->num_pipes)
+               return -ENODEV;
+
        spin_lock_irq(&pipe_crc->lock);
 
        if (pipe_crc->opened) {
@@ -2005,8 +2171,8 @@ static int i915_pipe_crc_create(struct dentry *root, struct drm_minor *minor,
        info->dev = dev;
        ent = debugfs_create_file(info->name, S_IRUGO, root, info,
                                  &i915_pipe_crc_fops);
-       if (IS_ERR(ent))
-               return PTR_ERR(ent);
+       if (!ent)
+               return -ENOMEM;
 
        return drm_add_fake_info_node(minor, ent, info);
 }
@@ -2347,7 +2513,7 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
-       u32 val;
+       u32 val = 0; /* shut up gcc */
        int ret;
 
        if (pipe_crc->source == source)
@@ -2742,7 +2908,7 @@ i915_drop_caches_set(void *data, u64 val)
        struct i915_vma *vma, *x;
        int ret;
 
-       DRM_DEBUG_DRIVER("Dropping caches: 0x%08llx\n", val);
+       DRM_DEBUG("Dropping caches: 0x%08llx\n", val);
 
        /* No need to check and wait for gpu resets, only libdrm auto-restarts
         * on ioctls on -EAGAIN. */
@@ -2810,8 +2976,7 @@ i915_max_freq_get(void *data, u64 *val)
                return ret;
 
        if (IS_VALLEYVIEW(dev))
-               *val = vlv_gpu_freq(dev_priv->mem_freq,
-                                   dev_priv->rps.max_delay);
+               *val = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay);
        else
                *val = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -2841,9 +3006,9 @@ i915_max_freq_set(void *data, u64 val)
         * Turbo will still be enabled, but won't go above the set value.
         */
        if (IS_VALLEYVIEW(dev)) {
-               val = vlv_freq_opcode(dev_priv->mem_freq, val);
+               val = vlv_freq_opcode(dev_priv, val);
                dev_priv->rps.max_delay = val;
-               gen6_set_rps(dev, val);
+               valleyview_set_rps(dev, val);
        } else {
                do_div(val, GT_FREQUENCY_MULTIPLIER);
                dev_priv->rps.max_delay = val;
@@ -2876,8 +3041,7 @@ i915_min_freq_get(void *data, u64 *val)
                return ret;
 
        if (IS_VALLEYVIEW(dev))
-               *val = vlv_gpu_freq(dev_priv->mem_freq,
-                                   dev_priv->rps.min_delay);
+               *val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay);
        else
                *val = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -2907,7 +3071,7 @@ i915_min_freq_set(void *data, u64 val)
         * Turbo will still be enabled, but won't go below the set value.
         */
        if (IS_VALLEYVIEW(dev)) {
-               val = vlv_freq_opcode(dev_priv->mem_freq, val);
+               val = vlv_freq_opcode(dev_priv, val);
                dev_priv->rps.min_delay = val;
                valleyview_set_rps(dev, val);
        } else {
@@ -2938,8 +3102,11 @@ i915_cache_sharing_get(void *data, u64 *val)
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
 
        snpcr = I915_READ(GEN6_MBCUNIT_SNPCR);
+
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev_priv->dev->struct_mutex);
 
        *val = (snpcr & GEN6_MBC_SNPCR_MASK) >> GEN6_MBC_SNPCR_SHIFT;
@@ -2960,6 +3127,7 @@ i915_cache_sharing_set(void *data, u64 val)
        if (val > 3)
                return -EINVAL;
 
+       intel_runtime_pm_get(dev_priv);
        DRM_DEBUG_DRIVER("Manually setting uncore sharing to %llu\n", val);
 
        /* Update the cache sharing policy here as well */
@@ -2968,6 +3136,7 @@ i915_cache_sharing_set(void *data, u64 val)
        snpcr |= (val << GEN6_MBC_SNPCR_SHIFT);
        I915_WRITE(GEN6_MBCUNIT_SNPCR, snpcr);
 
+       intel_runtime_pm_put(dev_priv);
        return 0;
 }
 
@@ -2983,7 +3152,8 @@ static int i915_forcewake_open(struct inode *inode, struct file *file)
        if (INTEL_INFO(dev)->gen < 6)
                return 0;
 
-       gen6_gt_force_wake_get(dev_priv);
+       intel_runtime_pm_get(dev_priv);
+       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
        return 0;
 }
@@ -2996,7 +3166,8 @@ static int i915_forcewake_release(struct inode *inode, struct file *file)
        if (INTEL_INFO(dev)->gen < 6)
                return 0;
 
-       gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+       intel_runtime_pm_put(dev_priv);
 
        return 0;
 }
@@ -3016,8 +3187,8 @@ static int i915_forcewake_create(struct dentry *root, struct drm_minor *minor)
                                  S_IRUSR,
                                  root, dev,
                                  &i915_forcewake_fops);
-       if (IS_ERR(ent))
-               return PTR_ERR(ent);
+       if (!ent)
+               return -ENOMEM;
 
        return drm_add_fake_info_node(minor, ent, &i915_forcewake_fops);
 }
@@ -3034,8 +3205,8 @@ static int i915_debugfs_create(struct dentry *root,
                                  S_IRUGO | S_IWUSR,
                                  root, dev,
                                  fops);
-       if (IS_ERR(ent))
-               return PTR_ERR(ent);
+       if (!ent)
+               return -ENOMEM;
 
        return drm_add_fake_info_node(minor, ent, fops);
 }
@@ -3079,6 +3250,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
        {"i915_edp_psr_status", i915_edp_psr_status, 0},
        {"i915_energy_uJ", i915_energy_uJ, 0},
        {"i915_pc8_status", i915_pc8_status, 0},
+       {"i915_power_domain_info", i915_power_domain_info, 0},
 };
 #define I915_DEBUGFS_ENTRIES ARRAY_SIZE(i915_debugfs_list)
 
@@ -3102,10 +3274,10 @@ static const struct i915_debugfs_files {
 void intel_display_crc_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       int i;
+       enum pipe pipe;
 
-       for (i = 0; i < INTEL_INFO(dev)->num_pipes; i++) {
-               struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[i];
+       for_each_pipe(pipe) {
+               struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[pipe];
 
                pipe_crc->opened = false;
                spin_lock_init(&pipe_crc->lock);
@@ -3164,5 +3336,3 @@ void i915_debugfs_cleanup(struct drm_minor *minor)
                drm_debugfs_remove_files(info_list, 1, minor);
        }
 }
-
-#endif /* CONFIG_DEBUG_FS */
index 5c648425c1e053616801b3e1e545791a5fe111c0..15a74f979b4bf8c773b6bde25c65f0badf6afb8e 100644 (file)
@@ -42,6 +42,8 @@
 #include <linux/vga_switcheroo.h>
 #include <linux/slab.h>
 #include <acpi/video.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
 
 #define LP_RING(d) (&((struct drm_i915_private *)(d))->ring[RCS])
 
@@ -791,7 +793,7 @@ static int i915_wait_irq(struct drm_device * dev, int irq_nr)
                master_priv->sarea_priv->perf_boxes |= I915_BOX_WAIT;
 
        if (ring->irq_get(ring)) {
-               DRM_WAIT_ON(ret, ring->irq_queue, 3 * DRM_HZ,
+               DRM_WAIT_ON(ret, ring->irq_queue, 3 * HZ,
                            READ_BREADCRUMB(dev_priv) >= irq_nr);
                ring->irq_put(ring);
        } else if (wait_for(READ_BREADCRUMB(dev_priv) >= irq_nr, 3000))
@@ -828,7 +830,7 @@ static int i915_irq_emit(struct drm_device *dev, void *data,
        result = i915_emit_irq(dev);
        mutex_unlock(&dev->struct_mutex);
 
-       if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
+       if (copy_to_user(emit->irq_seq, &result, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
                return -EFAULT;
        }
@@ -1016,8 +1018,8 @@ static int i915_getparam(struct drm_device *dev, void *data,
                return -EINVAL;
        }
 
-       if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
-               DRM_ERROR("DRM_COPY_TO_USER failed\n");
+       if (copy_to_user(param->value, &value, sizeof(int))) {
+               DRM_ERROR("copy_to_user failed\n");
                return -EFAULT;
        }
 
@@ -1411,7 +1413,7 @@ void i915_master_destroy(struct drm_device *dev, struct drm_master *master)
        master->driver_priv = NULL;
 }
 
-#ifdef CONFIG_DRM_I915_FBDEV
+#if IS_ENABLED(CONFIG_FB)
 static void i915_kick_out_firmware_fb(struct drm_i915_private *dev_priv)
 {
        struct apertures_struct *ap;
@@ -1484,6 +1486,10 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                return -ENODEV;
        }
 
+       /* UMS needs agp support. */
+       if (!drm_core_check_feature(dev, DRIVER_MODESET) && !dev->agp)
+               return -EINVAL;
+
        dev_priv = kzalloc(sizeof(*dev_priv), GFP_KERNEL);
        if (dev_priv == NULL)
                return -ENOMEM;
@@ -1494,7 +1500,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        spin_lock_init(&dev_priv->irq_lock);
        spin_lock_init(&dev_priv->gpu_error.lock);
-       spin_lock_init(&dev_priv->backlight.lock);
+       spin_lock_init(&dev_priv->backlight_lock);
        spin_lock_init(&dev_priv->uncore.lock);
        spin_lock_init(&dev_priv->mm.object_stat_lock);
        mutex_init(&dev_priv->dpio_lock);
@@ -1639,8 +1645,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
                        goto out_gem_unload;
        }
 
-       if (HAS_POWER_WELL(dev))
-               intel_power_domains_init(dev);
+       intel_power_domains_init(dev);
 
        if (drm_core_check_feature(dev, DRIVER_MODESET)) {
                ret = i915_load_modeset_init(dev);
@@ -1664,11 +1669,12 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (IS_GEN5(dev))
                intel_gpu_ips_init(dev_priv);
 
+       intel_init_runtime_pm(dev_priv);
+
        return 0;
 
 out_power_well:
-       if (HAS_POWER_WELL(dev))
-               intel_power_domains_remove(dev);
+       intel_power_domains_remove(dev);
        drm_vblank_cleanup(dev);
 out_gem_unload:
        if (dev_priv->mm.inactive_shrinker.scan_objects)
@@ -1679,6 +1685,7 @@ out_gem_unload:
 
        intel_teardown_gmbus(dev);
        intel_teardown_mchbar(dev);
+       pm_qos_remove_request(&dev_priv->pm_qos);
        destroy_workqueue(dev_priv->wq);
 out_mtrrfree:
        arch_phys_wc_del(dev_priv->gtt.mtrr);
@@ -1704,25 +1711,27 @@ int i915_driver_unload(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int ret;
 
+       ret = i915_gem_suspend(dev);
+       if (ret) {
+               DRM_ERROR("failed to idle hardware: %d\n", ret);
+               return ret;
+       }
+
+       intel_fini_runtime_pm(dev_priv);
+
        intel_gpu_ips_teardown();
 
-       if (HAS_POWER_WELL(dev)) {
-               /* The i915.ko module is still not prepared to be loaded when
-                * the power well is not enabled, so just enable it in case
-                * we're going to unload/reload. */
-               intel_display_set_init_power(dev, true);
-               intel_power_domains_remove(dev);
-       }
+       /* The i915.ko module is still not prepared to be loaded when
+        * the power well is not enabled, so just enable it in case
+        * we're going to unload/reload. */
+       intel_display_set_init_power(dev, true);
+       intel_power_domains_remove(dev);
 
        i915_teardown_sysfs(dev);
 
        if (dev_priv->mm.inactive_shrinker.scan_objects)
                unregister_shrinker(&dev_priv->mm.inactive_shrinker);
 
-       ret = i915_gem_suspend(dev);
-       if (ret)
-               DRM_ERROR("failed to idle hardware: %d\n", ret);
-
        io_mapping_free(dev_priv->gtt.mappable);
        arch_phys_wc_del(dev_priv->gtt.mtrr);
 
@@ -1777,7 +1786,6 @@ int i915_driver_unload(struct drm_device *dev)
 
        list_del(&dev_priv->gtt.base.global_link);
        WARN_ON(!list_empty(&dev_priv->vm_list));
-       drm_mm_takedown(&dev_priv->gtt.base.mm);
 
        drm_vblank_cleanup(dev);
 
@@ -1910,6 +1918,7 @@ const struct drm_ioctl_desc i915_ioctls[] = {
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_CREATE, i915_gem_context_create_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_DESTROY, i915_gem_context_destroy_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
        DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+       DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
 };
 
 int i915_max_ioctl = DRM_ARRAY_SIZE(i915_ioctls);
index 5b7b7e06cb3a09caec1cd7d5ab90401389df7a40..04f1f02c4019f57873caeb0c70fea14e0816ddeb 100644 (file)
@@ -59,7 +59,7 @@ MODULE_PARM_DESC(powersave,
                "Enable powersavings, fbc, downclocking, etc. (default: true)");
 
 int i915_semaphores __read_mostly = -1;
-module_param_named(semaphores, i915_semaphores, int, 0600);
+module_param_named(semaphores, i915_semaphores, int, 0400);
 MODULE_PARM_DESC(semaphores,
                "Use semaphores for inter-ring sync (default: -1 (use per-chip defaults))");
 
@@ -114,7 +114,7 @@ MODULE_PARM_DESC(enable_hangcheck,
                "(default: true)");
 
 int i915_enable_ppgtt __read_mostly = -1;
-module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0600);
+module_param_named(i915_enable_ppgtt, i915_enable_ppgtt, int, 0400);
 MODULE_PARM_DESC(i915_enable_ppgtt,
                "Enable PPGTT (default: true)");
 
@@ -155,7 +155,6 @@ MODULE_PARM_DESC(prefault_disable,
                "Disable page prefaulting for pread/pwrite/reloc (default:false). For developers only.");
 
 static struct drm_driver driver;
-extern int intel_agp_enabled;
 
 static const struct intel_device_info intel_i830_info = {
        .gen = 2, .is_mobile = 1, .cursor_needs_physical = 1, .num_pipes = 2,
@@ -173,6 +172,7 @@ static const struct intel_device_info intel_i85x_info = {
        .gen = 2, .is_i85x = 1, .is_mobile = 1, .num_pipes = 2,
        .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
+       .has_fbc = 1,
        .ring_mask = RENDER_RING,
 };
 
@@ -192,6 +192,7 @@ static const struct intel_device_info intel_i915gm_info = {
        .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .supports_tv = 1,
+       .has_fbc = 1,
        .ring_mask = RENDER_RING,
 };
 static const struct intel_device_info intel_i945g_info = {
@@ -204,6 +205,7 @@ static const struct intel_device_info intel_i945gm_info = {
        .has_hotplug = 1, .cursor_needs_physical = 1,
        .has_overlay = 1, .overlay_needs_physical = 1,
        .supports_tv = 1,
+       .has_fbc = 1,
        .ring_mask = RENDER_RING,
 };
 
@@ -265,6 +267,7 @@ static const struct intel_device_info intel_ironlake_m_info = {
 static const struct intel_device_info intel_sandybridge_d_info = {
        .gen = 6, .num_pipes = 2,
        .need_gfx_hws = 1, .has_hotplug = 1,
+       .has_fbc = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING,
        .has_llc = 1,
 };
@@ -280,6 +283,7 @@ static const struct intel_device_info intel_sandybridge_m_info = {
 #define GEN7_FEATURES  \
        .gen = 7, .num_pipes = 3, \
        .need_gfx_hws = 1, .has_hotplug = 1, \
+       .has_fbc = 1, \
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING, \
        .has_llc = 1
 
@@ -292,7 +296,6 @@ static const struct intel_device_info intel_ivybridge_m_info = {
        GEN7_FEATURES,
        .is_ivybridge = 1,
        .is_mobile = 1,
-       .has_fbc = 1,
 };
 
 static const struct intel_device_info intel_ivybridge_q_info = {
@@ -307,6 +310,7 @@ static const struct intel_device_info intel_valleyview_m_info = {
        .num_pipes = 2,
        .is_valleyview = 1,
        .display_mmio_offset = VLV_DISPLAY_BASE,
+       .has_fbc = 0, /* legal, last one wins */
        .has_llc = 0, /* legal, last one wins */
 };
 
@@ -315,6 +319,7 @@ static const struct intel_device_info intel_valleyview_d_info = {
        .num_pipes = 2,
        .is_valleyview = 1,
        .display_mmio_offset = VLV_DISPLAY_BASE,
+       .has_fbc = 0, /* legal, last one wins */
        .has_llc = 0, /* legal, last one wins */
 };
 
@@ -332,12 +337,10 @@ static const struct intel_device_info intel_haswell_m_info = {
        .is_mobile = 1,
        .has_ddi = 1,
        .has_fpga_dbg = 1,
-       .has_fbc = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
 };
 
 static const struct intel_device_info intel_broadwell_d_info = {
-       .is_preliminary = 1,
        .gen = 8, .num_pipes = 3,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
@@ -346,7 +349,6 @@ static const struct intel_device_info intel_broadwell_d_info = {
 };
 
 static const struct intel_device_info intel_broadwell_m_info = {
-       .is_preliminary = 1,
        .gen = 8, .is_mobile = 1, .num_pipes = 3,
        .need_gfx_hws = 1, .has_hotplug = 1,
        .ring_mask = RENDER_RING | BSD_RING | BLT_RING | VEBOX_RING,
@@ -476,12 +478,12 @@ check_next:
 bool i915_semaphore_is_enabled(struct drm_device *dev)
 {
        if (INTEL_INFO(dev)->gen < 6)
-               return 0;
+               return false;
 
        /* Until we get further testing... */
        if (IS_GEN8(dev)) {
                WARN_ON(!i915_preliminary_hw_support);
-               return 0;
+               return false;
        }
 
        if (i915_semaphores >= 0)
@@ -493,7 +495,7 @@ bool i915_semaphore_is_enabled(struct drm_device *dev)
                return false;
 #endif
 
-       return 1;
+       return true;
 }
 
 static int i915_drm_freeze(struct drm_device *dev)
@@ -501,6 +503,8 @@ static int i915_drm_freeze(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc;
 
+       intel_runtime_pm_get(dev_priv);
+
        /* ignore lid events during suspend */
        mutex_lock(&dev_priv->modeset_restore_lock);
        dev_priv->modeset_restore = MODESET_SUSPENDED;
@@ -688,6 +692,8 @@ static int __i915_drm_thaw(struct drm_device *dev, bool restore_gtt_mappings)
        mutex_lock(&dev_priv->modeset_restore_lock);
        dev_priv->modeset_restore = MODESET_DONE;
        mutex_unlock(&dev_priv->modeset_restore_lock);
+
+       intel_runtime_pm_put(dev_priv);
        return error;
 }
 
@@ -762,14 +768,14 @@ int i915_reset(struct drm_device *dev)
                DRM_INFO("Simulated gpu hang, resetting stop_rings\n");
                dev_priv->gpu_error.stop_rings = 0;
                if (ret == -ENODEV) {
-                       DRM_ERROR("Reset not implemented, but ignoring "
-                                 "error for simulated gpu hangs\n");
+                       DRM_INFO("Reset not implemented, but ignoring "
+                                "error for simulated gpu hangs\n");
                        ret = 0;
                }
        }
 
        if (ret) {
-               DRM_ERROR("Failed to reset chip.\n");
+               DRM_ERROR("Failed to reset chip: %i\n", ret);
                mutex_unlock(&dev->struct_mutex);
                return ret;
        }
@@ -790,12 +796,9 @@ int i915_reset(struct drm_device *dev)
         */
        if (drm_core_check_feature(dev, DRIVER_MODESET) ||
                        !dev_priv->ums.mm_suspended) {
-               bool hw_contexts_disabled = dev_priv->hw_contexts_disabled;
                dev_priv->ums.mm_suspended = 0;
 
                ret = i915_gem_init_hw(dev);
-               if (!hw_contexts_disabled && dev_priv->hw_contexts_disabled)
-                       DRM_ERROR("HW contexts didn't survive reset\n");
                mutex_unlock(&dev->struct_mutex);
                if (ret) {
                        DRM_ERROR("Failed hw init on reset %d\n", ret);
@@ -831,17 +834,7 @@ static int i915_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        if (PCI_FUNC(pdev->devfn))
                return -ENODEV;
 
-       /* We've managed to ship a kms-enabled ddx that shipped with an XvMC
-        * implementation for gen3 (and only gen3) that used legacy drm maps
-        * (gasp!) to share buffers between X and the client. Hence we need to
-        * keep around the fake agp stuff for gen3, even when kms is enabled. */
-       if (intel_info->gen != 3) {
-               driver.driver_features &=
-                       ~(DRIVER_USE_AGP | DRIVER_REQUIRE_AGP);
-       } else if (!intel_agp_enabled) {
-               DRM_ERROR("drm/i915 can't work without intel_agp module!\n");
-               return -ENODEV;
-       }
+       driver.driver_features &= ~(DRIVER_USE_AGP);
 
        return drm_get_pci_dev(pdev, ent, &driver);
 }
@@ -915,6 +908,49 @@ static int i915_pm_poweroff(struct device *dev)
        return i915_drm_freeze(drm_dev);
 }
 
+static int i915_runtime_suspend(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       WARN_ON(!HAS_RUNTIME_PM(dev));
+
+       DRM_DEBUG_KMS("Suspending device\n");
+
+       i915_gem_release_all_mmaps(dev_priv);
+
+       del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
+       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.
+        */
+       intel_opregion_notify_adapter(dev, PCI_D1);
+
+       return 0;
+}
+
+static int i915_runtime_resume(struct device *device)
+{
+       struct pci_dev *pdev = to_pci_dev(device);
+       struct drm_device *dev = pci_get_drvdata(pdev);
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       WARN_ON(!HAS_RUNTIME_PM(dev));
+
+       DRM_DEBUG_KMS("Resuming device\n");
+
+       intel_opregion_notify_adapter(dev, PCI_D0);
+       dev_priv->pm.suspended = false;
+
+       return 0;
+}
+
 static const struct dev_pm_ops i915_pm_ops = {
        .suspend = i915_pm_suspend,
        .resume = i915_pm_resume,
@@ -922,6 +958,8 @@ static const struct dev_pm_ops i915_pm_ops = {
        .thaw = i915_pm_thaw,
        .poweroff = i915_pm_poweroff,
        .restore = i915_pm_resume,
+       .runtime_suspend = i915_runtime_suspend,
+       .runtime_resume = i915_runtime_resume,
 };
 
 static const struct vm_operations_struct i915_gem_vm_ops = {
@@ -949,7 +987,7 @@ static struct drm_driver driver = {
         * deal with them for Intel hardware.
         */
        .driver_features =
-           DRIVER_USE_AGP | DRIVER_REQUIRE_AGP |
+           DRIVER_USE_AGP |
            DRIVER_HAVE_IRQ | DRIVER_IRQ_SHARED | DRIVER_GEM | DRIVER_PRIME |
            DRIVER_RENDER,
        .load = i915_driver_load,
@@ -1024,14 +1062,24 @@ static int __init i915_init(void)
                driver.driver_features &= ~DRIVER_MODESET;
 #endif
 
-       if (!(driver.driver_features & DRIVER_MODESET))
+       if (!(driver.driver_features & DRIVER_MODESET)) {
                driver.get_vblank_timestamp = NULL;
+#ifndef CONFIG_DRM_I915_UMS
+               /* Silently fail loading to not upset userspace. */
+               return 0;
+#endif
+       }
 
        return drm_pci_init(&driver, &i915_pci_driver);
 }
 
 static void __exit i915_exit(void)
 {
+#ifndef CONFIG_DRM_I915_UMS
+       if (!(driver.driver_features & DRIVER_MODESET))
+               return; /* Never loaded a driver. */
+#endif
+
        drm_pci_exit(&driver, &i915_pci_driver);
 }
 
index 1caa5e34fbe3d55825cd5b4340fbeb6575de4fa7..4a2bf8e3f739bff7b2b9f6e018100ec98e8b9c0e 100644 (file)
@@ -89,6 +89,18 @@ enum port {
 };
 #define port_name(p) ((p) + 'A')
 
+#define I915_NUM_PHYS_VLV 1
+
+enum dpio_channel {
+       DPIO_CH0,
+       DPIO_CH1
+};
+
+enum dpio_phy {
+       DPIO_PHY0,
+       DPIO_PHY1
+};
+
 enum intel_display_power_domain {
        POWER_DOMAIN_PIPE_A,
        POWER_DOMAIN_PIPE_B,
@@ -101,6 +113,7 @@ enum intel_display_power_domain {
        POWER_DOMAIN_TRANSCODER_C,
        POWER_DOMAIN_TRANSCODER_EDP,
        POWER_DOMAIN_VGA,
+       POWER_DOMAIN_AUDIO,
        POWER_DOMAIN_INIT,
 
        POWER_DOMAIN_NUM,
@@ -310,13 +323,14 @@ struct drm_i915_error_state {
        u32 instps[I915_NUM_RINGS];
        u32 extra_instdone[I915_NUM_INSTDONE_REG];
        u32 seqno[I915_NUM_RINGS];
-       u64 bbaddr;
+       u64 bbaddr[I915_NUM_RINGS];
        u32 fault_reg[I915_NUM_RINGS];
        u32 done_reg;
        u32 faddr[I915_NUM_RINGS];
        u64 fence[I915_MAX_NUM_FENCES];
        struct timeval time;
        struct drm_i915_error_ring {
+               bool valid;
                struct drm_i915_error_object {
                        int page_count;
                        u32 gtt_offset;
@@ -351,6 +365,7 @@ struct drm_i915_error_state {
        enum intel_ring_hangcheck_action hangcheck_action[I915_NUM_RINGS];
 };
 
+struct intel_connector;
 struct intel_crtc_config;
 struct intel_crtc;
 struct intel_limit;
@@ -358,7 +373,7 @@ struct dpll;
 
 struct drm_i915_display_funcs {
        bool (*fbc_enabled)(struct drm_device *dev);
-       void (*enable_fbc)(struct drm_crtc *crtc, unsigned long interval);
+       void (*enable_fbc)(struct drm_crtc *crtc);
        void (*disable_fbc)(struct drm_device *dev);
        int (*get_display_clock_speed)(struct drm_device *dev);
        int (*get_fifo_size)(struct drm_device *dev, int plane);
@@ -413,11 +428,20 @@ struct drm_i915_display_funcs {
        /* render clock increase/decrease */
        /* display clock increase/decrease */
        /* pll clock increase/decrease */
+
+       int (*setup_backlight)(struct intel_connector *connector);
+       uint32_t (*get_backlight)(struct intel_connector *connector);
+       void (*set_backlight)(struct intel_connector *connector,
+                             uint32_t level);
+       void (*disable_backlight)(struct intel_connector *connector);
+       void (*enable_backlight)(struct intel_connector *connector);
 };
 
 struct intel_uncore_funcs {
-       void (*force_wake_get)(struct drm_i915_private *dev_priv);
-       void (*force_wake_put)(struct drm_i915_private *dev_priv);
+       void (*force_wake_get)(struct drm_i915_private *dev_priv,
+                                                       int fw_engine);
+       void (*force_wake_put)(struct drm_i915_private *dev_priv,
+                                                       int fw_engine);
 
        uint8_t  (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
        uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
@@ -442,6 +466,9 @@ struct intel_uncore {
        unsigned fifo_count;
        unsigned forcewake_count;
 
+       unsigned fw_rendercount;
+       unsigned fw_mediacount;
+
        struct delayed_work force_wake_work;
 };
 
@@ -669,7 +696,6 @@ struct i915_fbc {
                struct delayed_work work;
                struct drm_crtc *crtc;
                struct drm_framebuffer *fb;
-               int interval;
        } *fbc_work;
 
        enum no_fbc_reason {
@@ -708,7 +734,6 @@ enum intel_sbi_destination {
 #define QUIRK_PIPEA_FORCE (1<<0)
 #define QUIRK_LVDS_SSC_DISABLE (1<<1)
 #define QUIRK_INVERT_BRIGHTNESS (1<<2)
-#define QUIRK_NO_PCH_PWM_ENABLE (1<<3)
 
 struct intel_fbdev;
 struct intel_fbc_work;
@@ -761,8 +786,6 @@ struct i915_suspend_saved_registers {
        u32 saveBLC_PWM_CTL;
        u32 saveBLC_PWM_CTL2;
        u32 saveBLC_HIST_CTL_B;
-       u32 saveBLC_PWM_CTL_B;
-       u32 saveBLC_PWM_CTL2_B;
        u32 saveBLC_CPU_PWM_CTL;
        u32 saveBLC_CPU_PWM_CTL2;
        u32 saveFPB0;
@@ -932,21 +955,29 @@ struct intel_ilk_power_mgmt {
 
 /* Power well structure for haswell */
 struct i915_power_well {
+       const char *name;
+       bool always_on;
        /* power well enable/disable usage count */
        int count;
+       unsigned long domains;
+       void *data;
+       void (*set)(struct drm_device *dev, struct i915_power_well *power_well,
+                   bool enable);
+       bool (*is_enabled)(struct drm_device *dev,
+                          struct i915_power_well *power_well);
 };
 
-#define I915_MAX_POWER_WELLS 1
-
 struct i915_power_domains {
        /*
         * Power wells needed for initialization at driver init and suspend
         * time are on. They are kept on until after the first modeset.
         */
        bool init_power_on;
+       int power_well_count;
 
        struct mutex lock;
-       struct i915_power_well power_wells[I915_MAX_POWER_WELLS];
+       int domain_use_count[POWER_DOMAIN_NUM];
+       struct i915_power_well *power_wells;
 };
 
 struct i915_dri1_state {
@@ -1077,34 +1108,30 @@ struct i915_gpu_error {
        unsigned long missed_irq_rings;
 
        /**
-        * State variable and reset counter controlling the reset flow
+        * State variable controlling the reset flow and count
         *
-        * Upper bits are for the reset counter.  This counter is used by the
-        * wait_seqno code to race-free noticed that a reset event happened and
-        * that it needs to restart the entire ioctl (since most likely the
-        * seqno it waited for won't ever signal anytime soon).
+        * This is a counter which gets incremented when reset is triggered,
+        * and again when reset has been handled. So odd values (lowest bit set)
+        * means that reset is in progress and even values that
+        * (reset_counter >> 1):th reset was successfully completed.
+        *
+        * If reset is not completed succesfully, the I915_WEDGE bit is
+        * set meaning that hardware is terminally sour and there is no
+        * recovery. All waiters on the reset_queue will be woken when
+        * that happens.
+        *
+        * This counter is used by the wait_seqno code to notice that reset
+        * event happened and it needs to restart the entire ioctl (since most
+        * likely the seqno it waited for won't ever signal anytime soon).
         *
         * This is important for lock-free wait paths, where no contended lock
         * naturally enforces the correct ordering between the bail-out of the
         * waiter and the gpu reset work code.
-        *
-        * Lowest bit controls the reset state machine: Set means a reset is in
-        * progress. This state will (presuming we don't have any bugs) decay
-        * into either unset (successful reset) or the special WEDGED value (hw
-        * terminally sour). All waiters on the reset_queue will be woken when
-        * that happens.
         */
        atomic_t reset_counter;
 
-       /**
-        * Special values/flags for reset_counter
-        *
-        * Note that the code relies on
-        *      I915_WEDGED & I915_RESET_IN_PROGRESS_FLAG
-        * being true.
-        */
 #define I915_RESET_IN_PROGRESS_FLAG    1
-#define I915_WEDGED                    0xffffffff
+#define I915_WEDGED                    (1 << 31)
 
        /**
         * Waitqueue to signal when the reset has completed. Used by clients
@@ -1158,6 +1185,11 @@ struct intel_vbt_data {
        int edp_bpp;
        struct edp_power_seq edp_pps;
 
+       struct {
+               u16 pwm_freq_hz;
+               bool active_low_pwm;
+       } backlight;
+
        /* MIPI DSI */
        struct {
                u16 panel_id;
@@ -1184,7 +1216,7 @@ struct intel_wm_level {
        uint32_t fbc_val;
 };
 
-struct hsw_wm_values {
+struct ilk_wm_values {
        uint32_t wm_pipe[3];
        uint32_t wm_lp[3];
        uint32_t wm_lp_spr[3];
@@ -1262,6 +1294,10 @@ struct i915_package_c8 {
        } regsave;
 };
 
+struct i915_runtime_pm {
+       bool suspended;
+};
+
 enum intel_pipe_crc_source {
        INTEL_PIPE_CRC_SOURCE_NONE,
        INTEL_PIPE_CRC_SOURCE_PLANE1,
@@ -1366,15 +1402,9 @@ typedef struct drm_i915_private {
 
        /* overlay */
        struct intel_overlay *overlay;
-       unsigned int sprite_scaling_enabled;
 
-       /* backlight */
-       struct {
-               int level;
-               bool enabled;
-               spinlock_t lock; /* bl registers and the above bl fields */
-               struct backlight_device *device;
-       } backlight;
+       /* backlight registers and fields in struct intel_panel */
+       spinlock_t backlight_lock;
 
        /* LVDS info */
        bool no_aux_handshake;
@@ -1426,6 +1456,7 @@ typedef struct drm_i915_private {
        int num_shared_dpll;
        struct intel_shared_dpll shared_dplls[I915_NUM_PLLS];
        struct intel_ddi_plls ddi_plls;
+       int dpio_phy_iosf_port[I915_NUM_PHYS_VLV];
 
        /* Reclocking support */
        bool render_reclock_avail;
@@ -1470,7 +1501,6 @@ typedef struct drm_i915_private {
        struct drm_property *broadcast_rgb_property;
        struct drm_property *force_audio_property;
 
-       bool hw_contexts_disabled;
        uint32_t hw_context_size;
        struct list_head context_list;
 
@@ -1492,11 +1522,13 @@ typedef struct drm_i915_private {
                uint16_t cur_latency[5];
 
                /* current hardware state */
-               struct hsw_wm_values hw;
+               struct ilk_wm_values hw;
        } wm;
 
        struct i915_package_c8 pc8;
 
+       struct i915_runtime_pm pm;
+
        /* Old dri1 support infrastructure, beware the dragons ya fools entering
         * here! */
        struct i915_dri1_state dri1;
@@ -1813,15 +1845,15 @@ struct drm_i915_file_private {
 
 #define HAS_FW_BLC(dev) (INTEL_INFO(dev)->gen > 2)
 #define HAS_PIPE_CXSR(dev) (INTEL_INFO(dev)->has_pipe_cxsr)
-#define I915_HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
+#define HAS_FBC(dev) (INTEL_INFO(dev)->has_fbc)
 
 #define HAS_IPS(dev)           (IS_ULT(dev) || IS_BROADWELL(dev))
 
 #define HAS_DDI(dev)           (INTEL_INFO(dev)->has_ddi)
-#define HAS_POWER_WELL(dev)    (IS_HASWELL(dev) || IS_BROADWELL(dev))
 #define HAS_FPGA_DBG_UNCLAIMED(dev)    (INTEL_INFO(dev)->has_fpga_dbg)
 #define HAS_PSR(dev)           (IS_HASWELL(dev) || IS_BROADWELL(dev))
 #define HAS_PC8(dev)           (IS_HASWELL(dev)) /* XXX HSW:ULX */
+#define HAS_RUNTIME_PM(dev)    (IS_HASWELL(dev))
 
 #define INTEL_PCH_DEVICE_ID_MASK               0xff00
 #define INTEL_PCH_IBX_DEVICE_ID_TYPE           0x3b00
@@ -1911,7 +1943,6 @@ extern void intel_hpd_init(struct drm_device *dev);
 extern void intel_uncore_sanitize(struct drm_device *dev);
 extern void intel_uncore_early_sanitize(struct drm_device *dev);
 extern void intel_uncore_init(struct drm_device *dev);
-extern void intel_uncore_clear_errors(struct drm_device *dev);
 extern void intel_uncore_check_errors(struct drm_device *dev);
 extern void intel_uncore_fini(struct drm_device *dev);
 
@@ -1987,6 +2018,7 @@ void i915_gem_object_unpin(struct drm_i915_gem_object *obj);
 int __must_check i915_vma_unbind(struct i915_vma *vma);
 int __must_check i915_gem_object_ggtt_unbind(struct drm_i915_gem_object *obj);
 int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
+void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
 void i915_gem_release_mmap(struct drm_i915_gem_object *obj);
 void i915_gem_lastclose(struct drm_device *dev);
 
@@ -2063,12 +2095,17 @@ int __must_check i915_gem_check_wedge(struct i915_gpu_error *error,
 static inline bool i915_reset_in_progress(struct i915_gpu_error *error)
 {
        return unlikely(atomic_read(&error->reset_counter)
-                       & I915_RESET_IN_PROGRESS_FLAG);
+                       & (I915_RESET_IN_PROGRESS_FLAG | I915_WEDGED));
 }
 
 static inline bool i915_terminally_wedged(struct i915_gpu_error *error)
 {
-       return atomic_read(&error->reset_counter) == I915_WEDGED;
+       return atomic_read(&error->reset_counter) & I915_WEDGED;
+}
+
+static inline u32 i915_reset_count(struct i915_gpu_error *error)
+{
+       return ((atomic_read(&error->reset_counter) & ~I915_WEDGED) + 1) / 2;
 }
 
 void i915_gem_reset(struct drm_device *dev);
@@ -2180,7 +2217,7 @@ i915_gem_obj_ggtt_pin(struct drm_i915_gem_object *obj,
 }
 
 /* i915_gem_context.c */
-void i915_gem_context_init(struct drm_device *dev);
+int __must_check i915_gem_context_init(struct drm_device *dev);
 void i915_gem_context_fini(struct drm_device *dev);
 void i915_gem_context_close(struct drm_device *dev, struct drm_file *file);
 int i915_switch_context(struct intel_ring_buffer *ring,
@@ -2399,6 +2436,8 @@ extern int intel_enable_rc6(const struct drm_device *dev);
 extern bool i915_semaphore_is_enabled(struct drm_device *dev);
 int i915_reg_read_ioctl(struct drm_device *dev, void *data,
                        struct drm_file *file);
+int i915_get_reset_stats_ioctl(struct drm_device *dev, void *data,
+                              struct drm_file *file);
 
 /* overlay */
 extern struct intel_overlay_error_state *intel_overlay_capture_error_state(struct drm_device *dev);
@@ -2414,8 +2453,8 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
  * must be set to prevent GT core from power down and stale values being
  * returned.
  */
-void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv);
-void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv);
+void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine);
+void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine);
 
 int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u8 mbox, u32 *val);
 int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val);
@@ -2430,6 +2469,8 @@ u32 vlv_cck_read(struct drm_i915_private *dev_priv, u32 reg);
 void vlv_cck_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
 u32 vlv_ccu_read(struct drm_i915_private *dev_priv, u32 reg);
 void vlv_ccu_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
+u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg);
+void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
 u32 vlv_gps_core_read(struct drm_i915_private *dev_priv, u32 reg);
 void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
 u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg);
@@ -2438,9 +2479,30 @@ u32 intel_sbi_read(struct drm_i915_private *dev_priv, u16 reg,
                   enum intel_sbi_destination destination);
 void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
                     enum intel_sbi_destination destination);
+u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg);
+void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
+
+int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val);
+int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val);
+
+void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine);
+void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine);
+
+#define FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg) \
+       (((reg) >= 0x2000 && (reg) < 0x4000) ||\
+       ((reg) >= 0x5000 && (reg) < 0x8000) ||\
+       ((reg) >= 0xB000 && (reg) < 0x12000) ||\
+       ((reg) >= 0x2E000 && (reg) < 0x30000))
+
+#define FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)\
+       (((reg) >= 0x12000 && (reg) < 0x14000) ||\
+       ((reg) >= 0x22000 && (reg) < 0x24000) ||\
+       ((reg) >= 0x30000 && (reg) < 0x40000))
+
+#define FORCEWAKE_RENDER       (1 << 0)
+#define FORCEWAKE_MEDIA                (1 << 1)
+#define FORCEWAKE_ALL          (FORCEWAKE_RENDER | FORCEWAKE_MEDIA)
 
-int vlv_gpu_freq(int ddr_freq, int val);
-int vlv_freq_opcode(int ddr_freq, int val);
 
 #define I915_READ8(reg)                dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true)
 #define I915_WRITE8(reg, val)  dev_priv->uncore.funcs.mmio_writeb(dev_priv, (reg), (val), true)
index 76d3d1ab73c6965063eba62527594dce82dc41d4..00c8361547253ecccf8ba17d6c06d730c688ca3b 100644 (file)
@@ -1015,9 +1015,11 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
                        struct drm_i915_file_private *file_priv)
 {
        drm_i915_private_t *dev_priv = ring->dev->dev_private;
+       const bool irq_test_in_progress =
+               ACCESS_ONCE(dev_priv->gpu_error.test_irq_rings) & intel_ring_flag(ring);
        struct timespec before, now;
        DEFINE_WAIT(wait);
-       long timeout_jiffies;
+       unsigned long timeout_expire;
        int ret;
 
        WARN(dev_priv->pc8.irqs_disabled, "IRQs disabled\n");
@@ -1025,7 +1027,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
        if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
                return 0;
 
-       timeout_jiffies = timeout ? timespec_to_jiffies_timeout(timeout) : 1;
+       timeout_expire = timeout ? jiffies + timespec_to_jiffies_timeout(timeout) : 0;
 
        if (dev_priv->info->gen >= 6 && can_wait_boost(file_priv)) {
                gen6_rps_boost(dev_priv);
@@ -1035,8 +1037,7 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
                                         msecs_to_jiffies(100));
        }
 
-       if (!(dev_priv->gpu_error.test_irq_rings & intel_ring_flag(ring)) &&
-           WARN_ON(!ring->irq_get(ring)))
+       if (!irq_test_in_progress && WARN_ON(!ring->irq_get(ring)))
                return -ENODEV;
 
        /* Record current time in case interrupted by signal, or wedged */
@@ -1044,7 +1045,6 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
        getrawmonotonic(&before);
        for (;;) {
                struct timer_list timer;
-               unsigned long expire;
 
                prepare_to_wait(&ring->irq_queue, &wait,
                                interruptible ? TASK_INTERRUPTIBLE : TASK_UNINTERRUPTIBLE);
@@ -1070,23 +1070,22 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
                        break;
                }
 
-               if (timeout_jiffies <= 0) {
+               if (timeout && time_after_eq(jiffies, timeout_expire)) {
                        ret = -ETIME;
                        break;
                }
 
                timer.function = NULL;
                if (timeout || missed_irq(dev_priv, ring)) {
+                       unsigned long expire;
+
                        setup_timer_on_stack(&timer, fake_irq, (unsigned long)current);
-                       expire = jiffies + (missed_irq(dev_priv, ring) ? 1: timeout_jiffies);
+                       expire = missed_irq(dev_priv, ring) ? jiffies + 1 : timeout_expire;
                        mod_timer(&timer, expire);
                }
 
                io_schedule();
 
-               if (timeout)
-                       timeout_jiffies = expire - jiffies;
-
                if (timer.function) {
                        del_singleshot_timer_sync(&timer);
                        destroy_timer_on_stack(&timer);
@@ -1095,7 +1094,8 @@ static int __wait_seqno(struct intel_ring_buffer *ring, u32 seqno,
        getrawmonotonic(&now);
        trace_i915_gem_request_wait_end(ring, seqno);
 
-       ring->irq_put(ring);
+       if (!irq_test_in_progress)
+               ring->irq_put(ring);
 
        finish_wait(&ring->irq_queue, &wait);
 
@@ -1380,6 +1380,8 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        int ret = 0;
        bool write = !!(vmf->flags & FAULT_FLAG_WRITE);
 
+       intel_runtime_pm_get(dev_priv);
+
        /* We don't use vmf->pgoff since that has the fake offset */
        page_offset = ((unsigned long)vmf->virtual_address - vma->vm_start) >>
                PAGE_SHIFT;
@@ -1427,8 +1429,10 @@ out:
                /* If this -EIO is due to a gpu hang, give the reset code a
                 * chance to clean up the mess. Otherwise return the proper
                 * SIGBUS. */
-               if (i915_terminally_wedged(&dev_priv->gpu_error))
-                       return VM_FAULT_SIGBUS;
+               if (i915_terminally_wedged(&dev_priv->gpu_error)) {
+                       ret = VM_FAULT_SIGBUS;
+                       break;
+               }
        case -EAGAIN:
                /*
                 * EAGAIN means the gpu is hung and we'll wait for the error
@@ -1443,15 +1447,38 @@ out:
                 * EBUSY is ok: this just means that another thread
                 * already did the job.
                 */
-               return VM_FAULT_NOPAGE;
+               ret = VM_FAULT_NOPAGE;
+               break;
        case -ENOMEM:
-               return VM_FAULT_OOM;
+               ret = VM_FAULT_OOM;
+               break;
        case -ENOSPC:
-               return VM_FAULT_SIGBUS;
+               ret = VM_FAULT_SIGBUS;
+               break;
        default:
                WARN_ONCE(ret, "unhandled error in i915_gem_fault: %i\n", ret);
-               return VM_FAULT_SIGBUS;
+               ret = VM_FAULT_SIGBUS;
+               break;
        }
+
+       intel_runtime_pm_put(dev_priv);
+       return ret;
+}
+
+void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv)
+{
+       struct i915_vma *vma;
+
+       /*
+        * Only the global gtt is relevant for gtt memory mappings, so restrict
+        * list traversal to objects bound into the global address space. Note
+        * that the active list should be empty, but better safe than sorry.
+        */
+       WARN_ON(!list_empty(&dev_priv->gtt.base.active_list));
+       list_for_each_entry(vma, &dev_priv->gtt.base.active_list, mm_list)
+               i915_gem_release_mmap(vma->obj);
+       list_for_each_entry(vma, &dev_priv->gtt.base.inactive_list, mm_list)
+               i915_gem_release_mmap(vma->obj);
 }
 
 /**
@@ -2303,7 +2330,7 @@ static void i915_set_reset_status(struct intel_ring_buffer *ring,
 
        if (ring->hangcheck.action != HANGCHECK_WAIT &&
            i915_request_guilty(request, acthd, &inside)) {
-               DRM_ERROR("%s hung %s bo (0x%lx ctx %d) at 0x%x\n",
+               DRM_DEBUG("%s hung %s bo (0x%lx ctx %d) at 0x%x\n",
                          ring->name,
                          inside ? "inside" : "flushing",
                          offset,
@@ -2361,16 +2388,6 @@ static void i915_gem_reset_ring_status(struct drm_i915_private *dev_priv,
 static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
                                        struct intel_ring_buffer *ring)
 {
-       while (!list_empty(&ring->request_list)) {
-               struct drm_i915_gem_request *request;
-
-               request = list_first_entry(&ring->request_list,
-                                          struct drm_i915_gem_request,
-                                          list);
-
-               i915_gem_free_request(request);
-       }
-
        while (!list_empty(&ring->active_list)) {
                struct drm_i915_gem_object *obj;
 
@@ -2380,6 +2397,23 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
 
                i915_gem_object_move_to_inactive(obj);
        }
+
+       /*
+        * We must free the requests after all the corresponding objects have
+        * been moved off active lists. Which is the same order as the normal
+        * retire_requests function does. This is important if object hold
+        * implicit references on things like e.g. ppgtt address spaces through
+        * the request.
+        */
+       while (!list_empty(&ring->request_list)) {
+               struct drm_i915_gem_request *request;
+
+               request = list_first_entry(&ring->request_list,
+                                          struct drm_i915_gem_request,
+                                          list);
+
+               i915_gem_free_request(request);
+       }
 }
 
 void i915_gem_restore_fences(struct drm_device *dev)
@@ -2760,7 +2794,6 @@ int i915_vma_unbind(struct i915_vma *vma)
                obj->has_aliasing_ppgtt_mapping = 0;
        }
        i915_gem_gtt_finish_object(obj);
-       i915_gem_object_unpin_pages(obj);
 
        list_del(&vma->mm_list);
        /* Avoid an unnecessary call to unbind on rebind. */
@@ -2768,7 +2801,6 @@ int i915_vma_unbind(struct i915_vma *vma)
                obj->map_and_fenceable = true;
 
        drm_mm_remove_node(&vma->node);
-
        i915_gem_vma_destroy(vma);
 
        /* Since the unbound list is global, only move to that list if
@@ -2776,6 +2808,12 @@ int i915_vma_unbind(struct i915_vma *vma)
        if (list_empty(&obj->vma_list))
                list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
 
+       /* And finally now the object is completely decoupled from this vma,
+        * we can drop its hold on the backing storage and allow it to be
+        * reaped by the shrinker.
+        */
+       i915_gem_object_unpin_pages(obj);
+
        return 0;
 }
 
@@ -3068,7 +3106,7 @@ i915_find_fence_reg(struct drm_device *dev)
        }
 
        if (avail == NULL)
-               return NULL;
+               goto deadlock;
 
        /* None available, try to steal one or wait for a user to finish */
        list_for_each_entry(reg, &dev_priv->mm.fence_list, lru_list) {
@@ -3078,7 +3116,12 @@ i915_find_fence_reg(struct drm_device *dev)
                return reg;
        }
 
-       return NULL;
+deadlock:
+       /* Wait for completion of pending flips which consume fences */
+       if (intel_has_pending_fb_unpin(dev))
+               return ERR_PTR(-EAGAIN);
+
+       return ERR_PTR(-EDEADLK);
 }
 
 /**
@@ -3123,8 +3166,8 @@ i915_gem_object_get_fence(struct drm_i915_gem_object *obj)
                }
        } else if (enable) {
                reg = i915_find_fence_reg(dev);
-               if (reg == NULL)
-                       return -EDEADLK;
+               if (IS_ERR(reg))
+                       return PTR_ERR(reg);
 
                if (reg->obj) {
                        struct drm_i915_gem_object *old = reg->obj;
@@ -4179,6 +4222,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct i915_vma *vma, *next;
 
+       intel_runtime_pm_get(dev_priv);
+
        trace_i915_gem_object_destroy(obj);
 
        if (obj->phys_obj)
@@ -4223,6 +4268,8 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
 
        kfree(obj->bit_17);
        i915_gem_object_free(obj);
+
+       intel_runtime_pm_put(dev_priv);
 }
 
 struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
@@ -4479,7 +4526,13 @@ i915_gem_init_hw(struct drm_device *dev)
         * XXX: There was some w/a described somewhere suggesting loading
         * contexts before PPGTT.
         */
-       i915_gem_context_init(dev);
+       ret = i915_gem_context_init(dev);
+       if (ret) {
+               i915_gem_cleanup_ringbuffer(dev);
+               DRM_ERROR("Context initialization failed %d\n", ret);
+               return ret;
+       }
+
        if (dev_priv->mm.aliasing_ppgtt) {
                ret = dev_priv->mm.aliasing_ppgtt->enable(dev);
                if (ret) {
index b0f42b9ca037ed472e1a0dd4cd663df6ffd70f06..e08acaba540269736777a7f7758a88d97f2aa4b6 100644 (file)
@@ -247,36 +247,34 @@ err_destroy:
        return ret;
 }
 
-void i915_gem_context_init(struct drm_device *dev)
+int i915_gem_context_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
 
-       if (!HAS_HW_CONTEXTS(dev)) {
-               dev_priv->hw_contexts_disabled = true;
-               DRM_DEBUG_DRIVER("Disabling HW Contexts; old hardware\n");
-               return;
-       }
+       if (!HAS_HW_CONTEXTS(dev))
+               return 0;
 
        /* If called from reset, or thaw... we've been here already */
-       if (dev_priv->hw_contexts_disabled ||
-           dev_priv->ring[RCS].default_context)
-               return;
+       if (dev_priv->ring[RCS].default_context)
+               return 0;
 
        dev_priv->hw_context_size = round_up(get_context_size(dev), 4096);
 
        if (dev_priv->hw_context_size > (1<<20)) {
-               dev_priv->hw_contexts_disabled = true;
                DRM_DEBUG_DRIVER("Disabling HW Contexts; invalid size\n");
-               return;
+               return -E2BIG;
        }
 
-       if (create_default_context(dev_priv)) {
-               dev_priv->hw_contexts_disabled = true;
-               DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed\n");
-               return;
+       ret = create_default_context(dev_priv);
+       if (ret) {
+               DRM_DEBUG_DRIVER("Disabling HW Contexts; create failed %d\n",
+                                ret);
+               return ret;
        }
 
        DRM_DEBUG_DRIVER("HW context support initialized\n");
+       return 0;
 }
 
 void i915_gem_context_fini(struct drm_device *dev)
@@ -284,7 +282,7 @@ void i915_gem_context_fini(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_hw_context *dctx = dev_priv->ring[RCS].default_context;
 
-       if (dev_priv->hw_contexts_disabled)
+       if (!HAS_HW_CONTEXTS(dev))
                return;
 
        /* The only known way to stop the gpu from accessing the hw context is
@@ -327,16 +325,16 @@ i915_gem_context_get_hang_stats(struct drm_device *dev,
                                struct drm_file *file,
                                u32 id)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_file_private *file_priv = file->driver_priv;
        struct i915_hw_context *ctx;
 
        if (id == DEFAULT_CONTEXT_ID)
                return &file_priv->hang_stats;
 
-       ctx = NULL;
-       if (!dev_priv->hw_contexts_disabled)
-               ctx = i915_gem_context_get(file->driver_priv, id);
+       if (!HAS_HW_CONTEXTS(dev))
+               return ERR_PTR(-ENOENT);
+
+       ctx = i915_gem_context_get(file->driver_priv, id);
        if (ctx == NULL)
                return ERR_PTR(-ENOENT);
 
@@ -502,8 +500,6 @@ static int do_switch(struct i915_hw_context *to)
  * @ring: ring for which we'll execute the context switch
  * @file_priv: file_priv associated with the context, may be NULL
  * @id: context id number
- * @seqno: sequence number by which the new context will be switched to
- * @flags:
  *
  * 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,
@@ -517,7 +513,7 @@ int i915_switch_context(struct intel_ring_buffer *ring,
        struct drm_i915_private *dev_priv = ring->dev->dev_private;
        struct i915_hw_context *to;
 
-       if (dev_priv->hw_contexts_disabled)
+       if (!HAS_HW_CONTEXTS(ring->dev))
                return 0;
 
        WARN_ON(!mutex_is_locked(&dev_priv->dev->struct_mutex));
@@ -542,7 +538,6 @@ int i915_switch_context(struct intel_ring_buffer *ring,
 int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_i915_gem_context_create *args = data;
        struct drm_i915_file_private *file_priv = file->driver_priv;
        struct i915_hw_context *ctx;
@@ -551,7 +546,7 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
        if (!(dev->driver->driver_features & DRIVER_GEM))
                return -ENODEV;
 
-       if (dev_priv->hw_contexts_disabled)
+       if (!HAS_HW_CONTEXTS(dev))
                return -ENODEV;
 
        ret = i915_mutex_lock_interruptible(dev);
index 8f3adc7d0dc823bd5e7848f013bda20d1d133cbc..2ca280f9ee53e3f6f6422fcc3605fa86b2f52afa 100644 (file)
  */
 
 #include <drm/drmP.h>
-#include "i915_drv.h"
 #include <drm/i915_drm.h>
+
+#include "i915_drv.h"
+#include "intel_drv.h"
 #include "i915_trace.h"
 
 static bool
@@ -53,6 +55,7 @@ i915_gem_evict_something(struct drm_device *dev, struct i915_address_space *vm,
        struct list_head eviction_list, unwind_list;
        struct i915_vma *vma;
        int ret = 0;
+       int pass = 0;
 
        trace_i915_gem_evict(dev, min_size, alignment, mappable);
 
@@ -119,14 +122,24 @@ none:
        /* Can we unpin some objects such as idle hw contents,
         * or pending flips?
         */
-       ret = nonblocking ? -ENOSPC : i915_gpu_idle(dev);
-       if (ret)
-               return ret;
+       if (nonblocking)
+               return -ENOSPC;
 
        /* Only idle the GPU and repeat the search once */
-       i915_gem_retire_requests(dev);
-       nonblocking = true;
-       goto search_again;
+       if (pass++ == 0) {
+               ret = i915_gpu_idle(dev);
+               if (ret)
+                       return ret;
+
+               i915_gem_retire_requests(dev);
+               goto search_again;
+       }
+
+       /* If we still have pending pageflip completions, drop
+        * back to userspace to give our workqueues time to
+        * acquire our locks and unpin the old scanouts.
+        */
+       return intel_has_pending_fb_unpin(dev) ? -EAGAIN : -ENOSPC;
 
 found:
        /* drm_mm doesn't allow any other other operations while
index a3ba9a8cd68794bbfd163c9236c91c7be9d15965..d269ecf46e264cbaaef6c9e1db6ddcfb57f1424d 100644 (file)
@@ -46,7 +46,7 @@ struct eb_vmas {
 };
 
 static struct eb_vmas *
-eb_create(struct drm_i915_gem_execbuffer2 *args, struct i915_address_space *vm)
+eb_create(struct drm_i915_gem_execbuffer2 *args)
 {
        struct eb_vmas *eb = NULL;
 
@@ -252,7 +252,7 @@ relocate_entry_cpu(struct drm_i915_gem_object *obj,
        struct drm_device *dev = obj->base.dev;
        uint32_t page_offset = offset_in_page(reloc->offset);
        char *vaddr;
-       int ret = -EINVAL;
+       int ret;
 
        ret = i915_gem_object_set_to_cpu_domain(obj, true);
        if (ret)
@@ -287,7 +287,7 @@ relocate_entry_gtt(struct drm_i915_gem_object *obj,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t __iomem *reloc_entry;
        void __iomem *reloc_page;
-       int ret = -EINVAL;
+       int ret;
 
        ret = i915_gem_object_set_to_gtt_domain(obj, true);
        if (ret)
@@ -335,7 +335,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        struct drm_i915_gem_object *target_i915_obj;
        struct i915_vma *target_vma;
        uint32_t target_offset;
-       int ret = -EINVAL;
+       int ret;
 
        /* we've already hold a reference to all valid objects */
        target_vma = eb_get_vma(eb, reloc->target_handle);
@@ -344,7 +344,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
        target_i915_obj = target_vma->obj;
        target_obj = &target_vma->obj->base;
 
-       target_offset = i915_gem_obj_ggtt_offset(target_i915_obj);
+       target_offset = target_vma->node.start;
 
        /* Sandybridge PPGTT errata: We need a global gtt mapping for MI and
         * pipe_control writes because the gpu doesn't properly redirect them
@@ -365,7 +365,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                          (int) reloc->offset,
                          reloc->read_domains,
                          reloc->write_domain);
-               return ret;
+               return -EINVAL;
        }
        if (unlikely((reloc->write_domain | reloc->read_domains)
                     & ~I915_GEM_GPU_DOMAINS)) {
@@ -376,7 +376,7 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                          (int) reloc->offset,
                          reloc->read_domains,
                          reloc->write_domain);
-               return ret;
+               return -EINVAL;
        }
 
        target_obj->pending_read_domains |= reloc->read_domains;
@@ -396,14 +396,14 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
                          obj, reloc->target_handle,
                          (int) reloc->offset,
                          (int) obj->base.size);
-               return ret;
+               return -EINVAL;
        }
        if (unlikely(reloc->offset & 3)) {
                DRM_DEBUG("Relocation not 4-byte aligned: "
                          "obj %p target %d offset %d.\n",
                          obj, reloc->target_handle,
                          (int) reloc->offset);
-               return ret;
+               return -EINVAL;
        }
 
        /* We can't wait for rendering with pagefaults disabled */
@@ -491,8 +491,7 @@ i915_gem_execbuffer_relocate_vma_slow(struct i915_vma *vma,
 }
 
 static int
-i915_gem_execbuffer_relocate(struct eb_vmas *eb,
-                            struct i915_address_space *vm)
+i915_gem_execbuffer_relocate(struct eb_vmas *eb)
 {
        struct i915_vma *vma;
        int ret = 0;
@@ -901,6 +900,24 @@ validate_exec_list(struct drm_i915_gem_exec_object2 *exec,
        return 0;
 }
 
+static int
+i915_gem_validate_context(struct drm_device *dev, struct drm_file *file,
+                         const u32 ctx_id)
+{
+       struct i915_ctx_hang_stats *hs;
+
+       hs = i915_gem_context_get_hang_stats(dev, file, ctx_id);
+       if (IS_ERR(hs))
+               return PTR_ERR(hs);
+
+       if (hs->banned) {
+               DRM_DEBUG("Context %u tried to submit while banned\n", ctx_id);
+               return -EIO;
+       }
+
+       return 0;
+}
+
 static void
 i915_gem_execbuffer_move_to_active(struct list_head *vmas,
                                   struct intel_ring_buffer *ring)
@@ -980,8 +997,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        struct drm_i915_gem_object *batch_obj;
        struct drm_clip_rect *cliprects = NULL;
        struct intel_ring_buffer *ring;
-       struct i915_ctx_hang_stats *hs;
-       u32 ctx_id = i915_execbuffer2_get_context_id(*args);
+       const u32 ctx_id = i915_execbuffer2_get_context_id(*args);
        u32 exec_start, exec_len;
        u32 mask, flags;
        int ret, mode, i;
@@ -1108,6 +1124,8 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                }
        }
 
+       intel_runtime_pm_get(dev_priv);
+
        ret = i915_mutex_lock_interruptible(dev);
        if (ret)
                goto pre_mutex_err;
@@ -1118,7 +1136,13 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
                goto pre_mutex_err;
        }
 
-       eb = eb_create(args, vm);
+       ret = i915_gem_validate_context(dev, file, ctx_id);
+       if (ret) {
+               mutex_unlock(&dev->struct_mutex);
+               goto pre_mutex_err;
+       }
+
+       eb = eb_create(args);
        if (eb == NULL) {
                mutex_unlock(&dev->struct_mutex);
                ret = -ENOMEM;
@@ -1141,7 +1165,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
 
        /* The objects are in their final locations, apply the relocations. */
        if (need_relocs)
-               ret = i915_gem_execbuffer_relocate(eb, vm);
+               ret = i915_gem_execbuffer_relocate(eb);
        if (ret) {
                if (ret == -EFAULT) {
                        ret = i915_gem_execbuffer_relocate_slow(dev, args, file, ring,
@@ -1170,17 +1194,6 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
        if (ret)
                goto err;
 
-       hs = i915_gem_context_get_hang_stats(dev, file, ctx_id);
-       if (IS_ERR(hs)) {
-               ret = PTR_ERR(hs);
-               goto err;
-       }
-
-       if (hs->banned) {
-               ret = -EIO;
-               goto err;
-       }
-
        ret = i915_switch_context(ring, file, ctx_id);
        if (ret)
                goto err;
@@ -1242,6 +1255,10 @@ err:
 
 pre_mutex_err:
        kfree(cliprects);
+
+       /* intel_gpu_busy should also get a ref, so it will free when the device
+        * is really idle. */
+       intel_runtime_pm_put(dev_priv);
        return ret;
 }
 
index 3540569948dbd62db3a2fd5980e141879162115d..40a2b36b276baa774028b56ae60b6ae6c59e919d 100644 (file)
@@ -240,10 +240,16 @@ static int gen8_ppgtt_enable(struct drm_device *dev)
                for_each_ring(ring, dev_priv, j) {
                        ret = gen8_write_pdp(ring, i, addr);
                        if (ret)
-                               return 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 void gen8_ppgtt_clear_range(struct i915_address_space *vm,
@@ -293,23 +299,23 @@ static void gen8_ppgtt_insert_entries(struct i915_address_space *vm,
        unsigned act_pte = first_entry % GEN8_PTES_PER_PAGE;
        struct sg_page_iter sg_iter;
 
-       pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]);
+       pt_vaddr = NULL;
        for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
-               dma_addr_t page_addr;
+               if (pt_vaddr == NULL)
+                       pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]);
 
-               page_addr = sg_dma_address(sg_iter.sg) +
-                               (sg_iter.sg_pgoffset << PAGE_SHIFT);
-               pt_vaddr[act_pte] = gen8_pte_encode(page_addr, cache_level,
-                                                   true);
+               pt_vaddr[act_pte] =
+                       gen8_pte_encode(sg_page_iter_dma_address(&sg_iter),
+                                       cache_level, true);
                if (++act_pte == GEN8_PTES_PER_PAGE) {
                        kunmap_atomic(pt_vaddr);
+                       pt_vaddr = NULL;
                        act_pt++;
-                       pt_vaddr = kmap_atomic(&ppgtt->gen8_pt_pages[act_pt]);
                        act_pte = 0;
-
                }
        }
-       kunmap_atomic(pt_vaddr);
+       if (pt_vaddr)
+               kunmap_atomic(pt_vaddr);
 }
 
 static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
@@ -318,6 +324,8 @@ static void gen8_ppgtt_cleanup(struct i915_address_space *vm)
                container_of(vm, struct i915_hw_ppgtt, base);
        int i, j;
 
+       drm_mm_takedown(&vm->mm);
+
        for (i = 0; i < ppgtt->num_pd_pages ; i++) {
                if (ppgtt->pd_dma_addr[i]) {
                        pci_unmap_page(ppgtt->base.dev->pdev,
@@ -381,6 +389,8 @@ static int gen8_ppgtt_init(struct i915_hw_ppgtt *ppgtt, uint64_t size)
        ppgtt->base.clear_range = gen8_ppgtt_clear_range;
        ppgtt->base.insert_entries = gen8_ppgtt_insert_entries;
        ppgtt->base.cleanup = gen8_ppgtt_cleanup;
+       ppgtt->base.start = 0;
+       ppgtt->base.total = ppgtt->num_pt_pages * GEN8_PTES_PER_PAGE * PAGE_SIZE;
 
        BUG_ON(ppgtt->num_pd_pages > GEN8_LEGACY_PDPS);
 
@@ -573,21 +583,23 @@ static void gen6_ppgtt_insert_entries(struct i915_address_space *vm,
        unsigned act_pte = first_entry % I915_PPGTT_PT_ENTRIES;
        struct sg_page_iter sg_iter;
 
-       pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
+       pt_vaddr = NULL;
        for_each_sg_page(pages->sgl, &sg_iter, pages->nents, 0) {
-               dma_addr_t page_addr;
+               if (pt_vaddr == NULL)
+                       pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
 
-               page_addr = sg_page_iter_dma_address(&sg_iter);
-               pt_vaddr[act_pte] = vm->pte_encode(page_addr, cache_level, true);
+               pt_vaddr[act_pte] =
+                       vm->pte_encode(sg_page_iter_dma_address(&sg_iter),
+                                      cache_level, true);
                if (++act_pte == I915_PPGTT_PT_ENTRIES) {
                        kunmap_atomic(pt_vaddr);
+                       pt_vaddr = NULL;
                        act_pt++;
-                       pt_vaddr = kmap_atomic(ppgtt->pt_pages[act_pt]);
                        act_pte = 0;
-
                }
        }
-       kunmap_atomic(pt_vaddr);
+       if (pt_vaddr)
+               kunmap_atomic(pt_vaddr);
 }
 
 static void gen6_ppgtt_cleanup(struct i915_address_space *vm)
@@ -632,6 +644,8 @@ static int gen6_ppgtt_init(struct i915_hw_ppgtt *ppgtt)
        ppgtt->base.insert_entries = gen6_ppgtt_insert_entries;
        ppgtt->base.cleanup = gen6_ppgtt_cleanup;
        ppgtt->base.scratch = dev_priv->gtt.base.scratch;
+       ppgtt->base.start = 0;
+       ppgtt->base.total = GEN6_PPGTT_PD_ENTRIES * I915_PPGTT_PT_ENTRIES * PAGE_SIZE;
        ppgtt->pt_pages = kcalloc(ppgtt->num_pd_entries, sizeof(struct page *),
                                  GFP_KERNEL);
        if (!ppgtt->pt_pages)
@@ -1124,7 +1138,6 @@ void i915_gem_setup_global_gtt(struct drm_device *dev,
                if (ret)
                        DRM_DEBUG_KMS("Reservation failed\n");
                obj->has_global_gtt_mapping = 1;
-               list_add(&vma->vma_link, &obj->vma_list);
        }
 
        dev_priv->gtt.base.start = start;
@@ -1400,6 +1413,8 @@ static void gen6_gmch_remove(struct i915_address_space *vm)
 {
 
        struct i915_gtt *gtt = container_of(vm, struct i915_gtt, base);
+
+       drm_mm_takedown(&vm->mm);
        iounmap(gtt->gsm);
        teardown_scratch_page(vm->dev);
 }
@@ -1425,6 +1440,9 @@ static int i915_gmch_probe(struct drm_device *dev,
        dev_priv->gtt.base.clear_range = i915_ggtt_clear_range;
        dev_priv->gtt.base.insert_entries = i915_ggtt_insert_entries;
 
+       if (unlikely(dev_priv->gtt.do_idle_maps))
+               DRM_INFO("applying Ironlake quirks for intel_iommu\n");
+
        return 0;
 }
 
index d284d892ed9491e8f2a618e22576673e06887f74..1a24e84f231578ae772d40ad75adda4c356b8d68 100644 (file)
@@ -250,7 +250,7 @@ i915_pages_create_for_stolen(struct drm_device *dev,
        }
 
        sg = st->sgl;
-       sg->offset = offset;
+       sg->offset = 0;
        sg->length = size;
 
        sg_dma_address(sg) = (dma_addr_t)dev_priv->mm.stolen_base + offset;
@@ -420,6 +420,7 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
 
        list_add_tail(&obj->global_list, &dev_priv->mm.bound_list);
        list_add_tail(&vma->mm_list, &ggtt->inactive_list);
+       i915_gem_object_pin_pages(obj);
 
        return obj;
 
index 79dcb8f896c6f34363e6bd62e90f1773bfcf8f0a..d7fd2fd2f0a5e1ba6ed25f9a4dce0c20dc03b9e3 100644 (file)
@@ -239,6 +239,9 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
                                  unsigned ring)
 {
        BUG_ON(ring >= I915_NUM_RINGS); /* shut up confused gcc */
+       if (!error->ring[ring].valid)
+               return;
+
        err_printf(m, "%s command stream:\n", ring_str(ring));
        err_printf(m, "  HEAD: 0x%08x\n", error->head[ring]);
        err_printf(m, "  TAIL: 0x%08x\n", error->tail[ring]);
@@ -247,12 +250,11 @@ static void i915_ring_error_state(struct drm_i915_error_state_buf *m,
        err_printf(m, "  IPEIR: 0x%08x\n", error->ipeir[ring]);
        err_printf(m, "  IPEHR: 0x%08x\n", error->ipehr[ring]);
        err_printf(m, "  INSTDONE: 0x%08x\n", error->instdone[ring]);
-       if (ring == RCS && INTEL_INFO(dev)->gen >= 4)
-               err_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr);
-       if (INTEL_INFO(dev)->gen >= 4)
+       if (INTEL_INFO(dev)->gen >= 4) {
+               err_printf(m, "  BBADDR: 0x%08llx\n", error->bbaddr[ring]);
                err_printf(m, "  BB_STATE: 0x%08x\n", error->bbstate[ring]);
-       if (INTEL_INFO(dev)->gen >= 4)
                err_printf(m, "  INSTPS: 0x%08x\n", error->instps[ring]);
+       }
        err_printf(m, "  INSTPM: 0x%08x\n", error->instpm[ring]);
        err_printf(m, "  FADDR: 0x%08x\n", error->faddr[ring]);
        if (INTEL_INFO(dev)->gen >= 6) {
@@ -294,7 +296,6 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        struct drm_device *dev = error_priv->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
        struct drm_i915_error_state *error = error_priv->error;
-       struct intel_ring_buffer *ring;
        int i, j, page, offset, elt;
 
        if (!error) {
@@ -329,7 +330,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
        if (INTEL_INFO(dev)->gen == 7)
                err_printf(m, "ERR_INT: 0x%08x\n", error->err_int);
 
-       for_each_ring(ring, dev_priv, i)
+       for (i = 0; i < ARRAY_SIZE(error->ring); i++)
                i915_ring_error_state(m, dev, error, i);
 
        if (error->active_bo)
@@ -386,8 +387,7 @@ int i915_error_state_to_str(struct drm_i915_error_state_buf *m,
                        }
                }
 
-               obj = error->ring[i].ctx;
-               if (obj) {
+               if ((obj = error->ring[i].ctx)) {
                        err_printf(m, "%s --- HW Context = 0x%08x\n",
                                   dev_priv->ring[i].name,
                                   obj->gtt_offset);
@@ -668,7 +668,8 @@ i915_error_first_batchbuffer(struct drm_i915_private *dev_priv,
                        return NULL;
 
                obj = ring->scratch.obj;
-               if (acthd >= i915_gem_obj_ggtt_offset(obj) &&
+               if (obj != NULL &&
+                   acthd >= i915_gem_obj_ggtt_offset(obj) &&
                    acthd < i915_gem_obj_ggtt_offset(obj) + obj->base.size)
                        return i915_error_object_create(dev_priv, obj);
        }
@@ -725,8 +726,9 @@ static void i915_record_ring_state(struct drm_device *dev,
                error->ipehr[ring->id] = I915_READ(RING_IPEHR(ring->mmio_base));
                error->instdone[ring->id] = I915_READ(RING_INSTDONE(ring->mmio_base));
                error->instps[ring->id] = I915_READ(RING_INSTPS(ring->mmio_base));
-               if (ring->id == RCS)
-                       error->bbaddr = I915_READ64(BB_ADDR);
+               error->bbaddr[ring->id] = I915_READ(RING_BBADDR(ring->mmio_base));
+               if (INTEL_INFO(dev)->gen >= 8)
+                       error->bbaddr[ring->id] |= (u64) I915_READ(RING_BBADDR_UDW(ring->mmio_base)) << 32;
                error->bbstate[ring->id] = I915_READ(RING_BBSTATE(ring->mmio_base));
        } else {
                error->faddr[ring->id] = I915_READ(DMA_FADD_I8XX);
@@ -775,11 +777,17 @@ static void i915_gem_record_rings(struct drm_device *dev,
                                  struct drm_i915_error_state *error)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct intel_ring_buffer *ring;
        struct drm_i915_gem_request *request;
        int i, count;
 
-       for_each_ring(ring, dev_priv, i) {
+       for (i = 0; i < I915_NUM_RINGS; i++) {
+               struct intel_ring_buffer *ring = &dev_priv->ring[i];
+
+               if (ring->dev == NULL)
+                       continue;
+
+               error->ring[i].valid = true;
+
                i915_record_ring_state(dev, error, ring);
 
                error->ring[i].batchbuffer =
index f13d5edc39d56c9bdfe3091a9218872ef59be071..17d8fcb1b6f7ac113b4c0c035088979b1c8083b4 100644 (file)
@@ -62,7 +62,7 @@ static const u32 hpd_mask_i915[] = {
        [HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
 };
 
-static const u32 hpd_status_gen4[] = {
+static const u32 hpd_status_g4x[] = {
        [HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
        [HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
        [HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
@@ -600,7 +600,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
         * Cook up a vblank counter by also checking the pixel
         * counter against vblank start.
         */
-       return ((high1 << 8) | low) + (pixel >= vbl_start);
+       return (((high1 << 8) | low) + (pixel >= vbl_start)) & 0xffffff;
 }
 
 static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
@@ -621,36 +621,15 @@ static u32 gm45_get_vblank_counter(struct drm_device *dev, int pipe)
 #define __raw_i915_read32(dev_priv__, reg__) readl((dev_priv__)->regs + (reg__))
 #define __raw_i915_read16(dev_priv__, reg__) readw((dev_priv__)->regs + (reg__))
 
-static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
+static bool ilk_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t status;
-       int reg;
 
-       if (IS_VALLEYVIEW(dev)) {
-               status = pipe == PIPE_A ?
-                       I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
-                       I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-
-               reg = VLV_ISR;
-       } else if (IS_GEN2(dev)) {
-               status = pipe == PIPE_A ?
-                       I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
-                       I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-
-               reg = ISR;
-       } else if (INTEL_INFO(dev)->gen < 5) {
-               status = pipe == PIPE_A ?
-                       I915_DISPLAY_PIPE_A_VBLANK_INTERRUPT :
-                       I915_DISPLAY_PIPE_B_VBLANK_INTERRUPT;
-
-               reg = ISR;
-       } else if (INTEL_INFO(dev)->gen < 7) {
+       if (INTEL_INFO(dev)->gen < 7) {
                status = pipe == PIPE_A ?
                        DE_PIPEA_VBLANK :
                        DE_PIPEB_VBLANK;
-
-               reg = DEISR;
        } else {
                switch (pipe) {
                default:
@@ -664,18 +643,14 @@ static bool intel_pipe_in_vblank_locked(struct drm_device *dev, enum pipe pipe)
                        status = DE_PIPEC_VBLANK_IVB;
                        break;
                }
-
-               reg = DEISR;
        }
 
-       if (IS_GEN2(dev))
-               return __raw_i915_read16(dev_priv, reg) & status;
-       else
-               return __raw_i915_read32(dev_priv, reg) & status;
+       return __raw_i915_read32(dev_priv, DEISR) & status;
 }
 
 static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
-                            int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
+                                   unsigned int flags, int *vpos, int *hpos,
+                                   ktime_t *stime, ktime_t *etime)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
@@ -698,6 +673,12 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
        vbl_start = mode->crtc_vblank_start;
        vbl_end = mode->crtc_vblank_end;
 
+       if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
+               vbl_start = DIV_ROUND_UP(vbl_start, 2);
+               vbl_end /= 2;
+               vtotal /= 2;
+       }
+
        ret |= DRM_SCANOUTPOS_VALID | DRM_SCANOUTPOS_ACCURATE;
 
        /*
@@ -722,17 +703,42 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
                else
                        position = __raw_i915_read32(dev_priv, PIPEDSL(pipe)) & DSL_LINEMASK_GEN3;
 
-               /*
-                * The scanline counter increments at the leading edge
-                * of hsync, ie. it completely misses the active portion
-                * of the line. Fix up the counter at both edges of vblank
-                * to get a more accurate picture whether we're in vblank
-                * or not.
-                */
-               in_vbl = intel_pipe_in_vblank_locked(dev, pipe);
-               if ((in_vbl && position == vbl_start - 1) ||
-                   (!in_vbl && position == vbl_end - 1))
-                       position = (position + 1) % vtotal;
+               if (HAS_PCH_SPLIT(dev)) {
+                       /*
+                        * The scanline counter increments at the leading edge
+                        * of hsync, ie. it completely misses the active portion
+                        * of the line. Fix up the counter at both edges of vblank
+                        * to get a more accurate picture whether we're in vblank
+                        * or not.
+                        */
+                       in_vbl = ilk_pipe_in_vblank_locked(dev, pipe);
+                       if ((in_vbl && position == vbl_start - 1) ||
+                           (!in_vbl && position == vbl_end - 1))
+                               position = (position + 1) % vtotal;
+               } else {
+                       /*
+                        * ISR vblank status bits don't work the way we'd want
+                        * them to work on non-PCH platforms (for
+                        * ilk_pipe_in_vblank_locked()), and there doesn't
+                        * appear any other way to determine if we're currently
+                        * in vblank.
+                        *
+                        * Instead let's assume that we're already in vblank if
+                        * we got called from the vblank interrupt and the
+                        * scanline counter value indicates that we're on the
+                        * line just prior to vblank start. This should result
+                        * in the correct answer, unless the vblank interrupt
+                        * delivery really got delayed for almost exactly one
+                        * full frame/field.
+                        */
+                       if (flags & DRM_CALLED_FROM_VBLIRQ &&
+                           position == vbl_start - 1) {
+                               position = (position + 1) % vtotal;
+
+                               /* Signal this correction as "applied". */
+                               ret |= 0x8;
+                       }
+               }
        } else {
                /* Have access to pixelcount since start of frame.
                 * We can split this into vertical and horizontal
@@ -809,7 +815,8 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
        /* Helper routine in DRM core does all the work: */
        return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
                                                     vblank_time, flags,
-                                                    crtc);
+                                                    crtc,
+                                                    &to_intel_crtc(crtc)->config.adjusted_mode);
 }
 
 static bool intel_hpd_irq_event(struct drm_device *dev,
@@ -1015,10 +1022,8 @@ static void gen6_pm_rps_work(struct work_struct *work)
        /* sysfs frequency interfaces may have snuck in while servicing the
         * interrupt
         */
-       if (new_delay < (int)dev_priv->rps.min_delay)
-               new_delay = dev_priv->rps.min_delay;
-       if (new_delay > (int)dev_priv->rps.max_delay)
-               new_delay = dev_priv->rps.max_delay;
+       new_delay = clamp_t(int, new_delay,
+                           dev_priv->rps.min_delay, dev_priv->rps.max_delay);
        dev_priv->rps.last_adj = new_delay - dev_priv->rps.cur_delay;
 
        if (IS_VALLEYVIEW(dev_priv->dev))
@@ -1235,9 +1240,10 @@ static inline void intel_hpd_irq_handler(struct drm_device *dev,
        spin_lock(&dev_priv->irq_lock);
        for (i = 1; i < HPD_NUM_PINS; i++) {
 
-               WARN(((hpd[i] & hotplug_trigger) &&
-                     dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED),
-                    "Received HPD interrupt although disabled\n");
+               WARN_ONCE(hpd[i] & hotplug_trigger &&
+                         dev_priv->hpd_stats[i].hpd_mark == HPD_DISABLED,
+                         "Received HPD interrupt (0x%08x) on pin %d (0x%08x) although disabled\n",
+                         hotplug_trigger, i, hpd[i]);
 
                if (!(hpd[i] & hotplug_trigger) ||
                    dev_priv->hpd_stats[i].hpd_mark != HPD_ENABLED)
@@ -1474,6 +1480,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
 
                        intel_hpd_irq_handler(dev, hotplug_trigger, hpd_status_i915);
 
+                       if (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X)
+                               dp_aux_irq_handler(dev);
+
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
                        I915_READ(PORT_HOTPLUG_STAT);
                }
@@ -1993,7 +2002,7 @@ static void i915_error_work_func(struct work_struct *work)
                        kobject_uevent_env(&dev->primary->kdev->kobj,
                                           KOBJ_CHANGE, reset_done_event);
                } else {
-                       atomic_set(&error->reset_counter, I915_WEDGED);
+                       atomic_set_mask(I915_WEDGED, &error->reset_counter);
                }
 
                /*
@@ -3140,10 +3149,10 @@ static int i8xx_irq_postinstall(struct drm_device *dev)
  * Returns true when a page flip has completed.
  */
 static bool i8xx_handle_vblank(struct drm_device *dev,
-                              int pipe, u16 iir)
+                              int plane, int pipe, u32 iir)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(pipe);
+       u16 flip_pending = DISPLAY_PLANE_FLIP_PENDING(plane);
 
        if (!drm_handle_vblank(dev, pipe))
                return false;
@@ -3151,7 +3160,7 @@ static bool i8xx_handle_vblank(struct drm_device *dev,
        if ((iir & flip_pending) == 0)
                return false;
 
-       intel_prepare_page_flip(dev, pipe);
+       intel_prepare_page_flip(dev, plane);
 
        /* We detect FlipDone by looking for the change in PendingFlip from '1'
         * to '0' on the following vblank, i.e. IIR has the Pendingflip
@@ -3220,9 +3229,13 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
                        notify_ring(dev, &dev_priv->ring[RCS]);
 
                for_each_pipe(pipe) {
+                       int plane = pipe;
+                       if (HAS_FBC(dev))
+                               plane = !plane;
+
                        if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
-                           i8xx_handle_vblank(dev, pipe, iir))
-                               flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(pipe);
+                           i8xx_handle_vblank(dev, plane, pipe, iir))
+                               flip_mask &= ~DISPLAY_PLANE_FLIP_PENDING(plane);
 
                        if (pipe_stats[pipe] & PIPE_CRC_DONE_INTERRUPT_STATUS)
                                i9xx_pipe_crc_irq_handler(dev, pipe);
@@ -3418,7 +3431,7 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
 
                for_each_pipe(pipe) {
                        int plane = pipe;
-                       if (IS_MOBILE(dev))
+                       if (HAS_FBC(dev))
                                plane = !plane;
 
                        if (pipe_stats[pipe] & PIPE_VBLANK_INTERRUPT_STATUS &&
@@ -3655,7 +3668,11 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
                                  hotplug_status);
 
                        intel_hpd_irq_handler(dev, hotplug_trigger,
-                                             IS_G4X(dev) ? hpd_status_gen4 : hpd_status_i915);
+                                             IS_G4X(dev) ? hpd_status_g4x : hpd_status_i915);
+
+                       if (IS_G4X(dev) &&
+                           (hotplug_status & DP_AUX_CHANNEL_MASK_INT_STATUS_G4X))
+                               dp_aux_irq_handler(dev);
 
                        I915_WRITE(PORT_HOTPLUG_STAT, hotplug_status);
                        I915_READ(PORT_HOTPLUG_STAT);
@@ -3893,8 +3910,8 @@ void hsw_pc8_disable_interrupts(struct drm_device *dev)
        dev_priv->pc8.regsave.gtier = I915_READ(GTIER);
        dev_priv->pc8.regsave.gen6_pmimr = I915_READ(GEN6_PMIMR);
 
-       ironlake_disable_display_irq(dev_priv, ~DE_PCH_EVENT_IVB);
-       ibx_disable_display_interrupt(dev_priv, ~SDE_HOTPLUG_MASK_CPT);
+       ironlake_disable_display_irq(dev_priv, 0xffffffff);
+       ibx_disable_display_interrupt(dev_priv, 0xffffffff);
        ilk_disable_gt_irq(dev_priv, 0xffffffff);
        snb_disable_pm_irq(dev_priv, 0xffffffff);
 
@@ -3908,34 +3925,26 @@ void hsw_pc8_restore_interrupts(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        unsigned long irqflags;
-       uint32_t val, expected;
+       uint32_t val;
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
 
        val = I915_READ(DEIMR);
-       expected = ~DE_PCH_EVENT_IVB;
-       WARN(val != expected, "DEIMR is 0x%08x, not 0x%08x\n", val, expected);
+       WARN(val != 0xffffffff, "DEIMR is 0x%08x\n", val);
 
-       val = I915_READ(SDEIMR) & ~SDE_HOTPLUG_MASK_CPT;
-       expected = ~SDE_HOTPLUG_MASK_CPT;
-       WARN(val != expected, "SDEIMR non-HPD bits are 0x%08x, not 0x%08x\n",
-            val, expected);
+       val = I915_READ(SDEIMR);
+       WARN(val != 0xffffffff, "SDEIMR is 0x%08x\n", val);
 
        val = I915_READ(GTIMR);
-       expected = 0xffffffff;
-       WARN(val != expected, "GTIMR is 0x%08x, not 0x%08x\n", val, expected);
+       WARN(val != 0xffffffff, "GTIMR is 0x%08x\n", val);
 
        val = I915_READ(GEN6_PMIMR);
-       expected = 0xffffffff;
-       WARN(val != expected, "GEN6_PMIMR is 0x%08x, not 0x%08x\n", val,
-            expected);
+       WARN(val != 0xffffffff, "GEN6_PMIMR is 0x%08x\n", val);
 
        dev_priv->pc8.irqs_disabled = false;
 
        ironlake_enable_display_irq(dev_priv, ~dev_priv->pc8.regsave.deimr);
-       ibx_enable_display_interrupt(dev_priv,
-                                    ~dev_priv->pc8.regsave.sdeimr &
-                                    ~SDE_HOTPLUG_MASK_CPT);
+       ibx_enable_display_interrupt(dev_priv, ~dev_priv->pc8.regsave.sdeimr);
        ilk_enable_gt_irq(dev_priv, ~dev_priv->pc8.regsave.gtimr);
        snb_enable_pm_irq(dev_priv, ~dev_priv->pc8.regsave.gen6_pmimr);
        I915_WRITE(GTIER, dev_priv->pc8.regsave.gtier);
index ee2742122a02561f910b6d9d5383418794234eff..a48b7cad6f1135c29742f39cacf23e359f92faf4 100644 (file)
 #define   MI_SCENE_COUNT       (1 << 3) /* just increment scene count */
 #define   MI_END_SCENE         (1 << 4) /* flush binner and incr scene count */
 #define   MI_INVALIDATE_ISP    (1 << 5) /* invalidate indirect state pointers */
+#define MI_REPORT_HEAD         MI_INSTR(0x07, 0)
+#define MI_ARB_ON_OFF          MI_INSTR(0x08, 0)
+#define   MI_ARB_ENABLE                        (1<<0)
+#define   MI_ARB_DISABLE               (0<<0)
 #define MI_BATCH_BUFFER_END    MI_INSTR(0x0a, 0)
 #define MI_SUSPEND_FLUSH       MI_INSTR(0x0b, 0)
 #define   MI_SUSPEND_FLUSH_EN  (1<<0)
-#define MI_REPORT_HEAD         MI_INSTR(0x07, 0)
 #define MI_OVERLAY_FLIP                MI_INSTR(0x11, 0)
 #define   MI_OVERLAY_CONTINUE  (0x0<<21)
 #define   MI_OVERLAY_ON                (0x1<<21)
 #define   MI_DISPLAY_FLIP_IVB_SPRITE_B (3 << 19)
 #define   MI_DISPLAY_FLIP_IVB_PLANE_C  (4 << 19)
 #define   MI_DISPLAY_FLIP_IVB_SPRITE_C (5 << 19)
-#define MI_ARB_ON_OFF          MI_INSTR(0x08, 0)
-#define   MI_ARB_ENABLE                        (1<<0)
-#define   MI_ARB_DISABLE               (0<<0)
-
+#define MI_SEMAPHORE_MBOX      MI_INSTR(0x16, 1) /* gen6+ */
+#define   MI_SEMAPHORE_GLOBAL_GTT    (1<<22)
+#define   MI_SEMAPHORE_UPDATE      (1<<21)
+#define   MI_SEMAPHORE_COMPARE     (1<<20)
+#define   MI_SEMAPHORE_REGISTER            (1<<18)
+#define   MI_SEMAPHORE_SYNC_VR     (0<<16) /* RCS  wait for VCS  (RVSYNC) */
+#define   MI_SEMAPHORE_SYNC_VER            (1<<16) /* RCS  wait for VECS (RVESYNC) */
+#define   MI_SEMAPHORE_SYNC_BR     (2<<16) /* RCS  wait for BCS  (RBSYNC) */
+#define   MI_SEMAPHORE_SYNC_BV     (0<<16) /* VCS  wait for BCS  (VBSYNC) */
+#define   MI_SEMAPHORE_SYNC_VEV            (1<<16) /* VCS  wait for VECS (VVESYNC) */
+#define   MI_SEMAPHORE_SYNC_RV     (2<<16) /* VCS  wait for RCS  (VRSYNC) */
+#define   MI_SEMAPHORE_SYNC_RB     (0<<16) /* BCS  wait for RCS  (BRSYNC) */
+#define   MI_SEMAPHORE_SYNC_VEB            (1<<16) /* BCS  wait for VECS (BVESYNC) */
+#define   MI_SEMAPHORE_SYNC_VB     (2<<16) /* BCS  wait for VCS  (BVSYNC) */
+#define   MI_SEMAPHORE_SYNC_BVE            (0<<16) /* VECS wait for BCS  (VEBSYNC) */
+#define   MI_SEMAPHORE_SYNC_VVE            (1<<16) /* VECS wait for VCS  (VEVSYNC) */
+#define   MI_SEMAPHORE_SYNC_RVE            (2<<16) /* VECS wait for RCS  (VERSYNC) */
+#define   MI_SEMAPHORE_SYNC_INVALID  (3<<16)
 #define MI_SET_CONTEXT         MI_INSTR(0x18, 0)
 #define   MI_MM_SPACE_GTT              (1<<8)
 #define   MI_MM_SPACE_PHYSICAL         (0<<8)
  */
 #define MI_LOAD_REGISTER_IMM(x)        MI_INSTR(0x22, 2*x-1)
 #define MI_STORE_REGISTER_MEM(x) MI_INSTR(0x24, 2*x-1)
-#define  MI_SRM_LRM_GLOBAL_GTT         (1<<22)
+#define   MI_SRM_LRM_GLOBAL_GTT                (1<<22)
 #define MI_FLUSH_DW            MI_INSTR(0x26, 1) /* for GEN6 */
 #define   MI_FLUSH_DW_STORE_INDEX      (1<<21)
 #define   MI_INVALIDATE_TLB            (1<<18)
 #define MI_BATCH_BUFFER                MI_INSTR(0x30, 1)
 #define   MI_BATCH_NON_SECURE          (1)
 /* for snb/ivb/vlv this also means "batch in ppgtt" when ppgtt is enabled. */
-#define   MI_BATCH_NON_SECURE_I965     (1<<8)
+#define   MI_BATCH_NON_SECURE_I965     (1<<8)
 #define   MI_BATCH_PPGTT_HSW           (1<<8)
-#define   MI_BATCH_NON_SECURE_HSW      (1<<13)
+#define   MI_BATCH_NON_SECURE_HSW      (1<<13)
 #define MI_BATCH_BUFFER_START  MI_INSTR(0x31, 0)
 #define   MI_BATCH_GTT             (2<<6) /* aliased with (1<<7) on gen4 */
 #define MI_BATCH_BUFFER_START_GEN8     MI_INSTR(0x31, 1)
-#define MI_SEMAPHORE_MBOX      MI_INSTR(0x16, 1) /* gen6+ */
-#define  MI_SEMAPHORE_GLOBAL_GTT    (1<<22)
-#define  MI_SEMAPHORE_UPDATE       (1<<21)
-#define  MI_SEMAPHORE_COMPARE      (1<<20)
-#define  MI_SEMAPHORE_REGISTER     (1<<18)
-#define  MI_SEMAPHORE_SYNC_VR      (0<<16) /* RCS  wait for VCS  (RVSYNC) */
-#define  MI_SEMAPHORE_SYNC_VER     (1<<16) /* RCS  wait for VECS (RVESYNC) */
-#define  MI_SEMAPHORE_SYNC_BR      (2<<16) /* RCS  wait for BCS  (RBSYNC) */
-#define  MI_SEMAPHORE_SYNC_BV      (0<<16) /* VCS  wait for BCS  (VBSYNC) */
-#define  MI_SEMAPHORE_SYNC_VEV     (1<<16) /* VCS  wait for VECS (VVESYNC) */
-#define  MI_SEMAPHORE_SYNC_RV      (2<<16) /* VCS  wait for RCS  (VRSYNC) */
-#define  MI_SEMAPHORE_SYNC_RB      (0<<16) /* BCS  wait for RCS  (BRSYNC) */
-#define  MI_SEMAPHORE_SYNC_VEB     (1<<16) /* BCS  wait for VECS (BVESYNC) */
-#define  MI_SEMAPHORE_SYNC_VB      (2<<16) /* BCS  wait for VCS  (BVSYNC) */
-#define  MI_SEMAPHORE_SYNC_BVE     (0<<16) /* VECS wait for BCS  (VEBSYNC) */
-#define  MI_SEMAPHORE_SYNC_VVE     (1<<16) /* VECS wait for VCS  (VEVSYNC) */
-#define  MI_SEMAPHORE_SYNC_RVE     (2<<16) /* VECS wait for RCS  (VERSYNC) */
-#define  MI_SEMAPHORE_SYNC_INVALID  (3<<16)
+
 
 #define MI_PREDICATE_RESULT_2  (0x2214)
 #define  LOWER_SLICE_ENABLED   (1<<0)
 #define   IOSF_BYTE_ENABLES_SHIFT              4
 #define   IOSF_BAR_SHIFT                       1
 #define   IOSF_SB_BUSY                         (1<<0)
+#define   IOSF_PORT_BUNIT                      0x3
 #define   IOSF_PORT_PUNIT                      0x4
 #define   IOSF_PORT_NC                         0x11
 #define   IOSF_PORT_DPIO                       0x12
 #define   IOSF_PORT_CCK                                0x14
 #define   IOSF_PORT_CCU                                0xA9
 #define   IOSF_PORT_GPS_CORE                   0x48
+#define   IOSF_PORT_FLISDSI                    0x1B
 #define VLV_IOSF_DATA                          (VLV_DISPLAY_BASE + 0x2104)
 #define VLV_IOSF_ADDR                          (VLV_DISPLAY_BASE + 0x2108)
 
+/* See configdb bunit SB addr map */
+#define BUNIT_REG_BISOC                                0x11
+
 #define PUNIT_OPCODE_REG_READ                  6
 #define PUNIT_OPCODE_REG_WRITE                 7
 
+#define PUNIT_REG_DSPFREQ                      0x36
+#define   DSPFREQSTAT_SHIFT                    30
+#define   DSPFREQSTAT_MASK                     (0x3 << DSPFREQSTAT_SHIFT)
+#define   DSPFREQGUAR_SHIFT                    14
+#define   DSPFREQGUAR_MASK                     (0x3 << DSPFREQGUAR_SHIFT)
 #define PUNIT_REG_PWRGT_CTRL                   0x60
 #define PUNIT_REG_PWRGT_STATUS                 0x61
 #define          PUNIT_CLK_GATE                        1
 #define  DSI_PLL_N1_DIV_MASK                   (3 << 16)
 #define  DSI_PLL_M1_DIV_SHIFT                  0
 #define  DSI_PLL_M1_DIV_MASK                   (0x1ff << 0)
+#define CCK_DISPLAY_CLOCK_CONTROL              0x6b
 
 /*
  * DPIO - a special bus for various display related registers to hide behind
 #define  DPIO_SFR_BYPASS               (1<<1)
 #define  DPIO_CMNRST                   (1<<0)
 
-#define _DPIO_TX3_SWING_CTL4_A         0x690
-#define _DPIO_TX3_SWING_CTL4_B         0x2a90
-#define DPIO_TX3_SWING_CTL4(pipe) _PIPE(pipe, _DPIO_TX3_SWING_CTL4_A, \
-                                       _DPIO_TX3_SWING_CTL4_B)
+#define DPIO_PHY(pipe)                 ((pipe) >> 1)
+#define DPIO_PHY_IOSF_PORT(phy)                (dev_priv->dpio_phy_iosf_port[phy])
 
 /*
  * Per pipe/PLL DPIO regs
  */
-#define _DPIO_DIV_A                    0x800c
+#define _VLV_PLL_DW3_CH0               0x800c
 #define   DPIO_POST_DIV_SHIFT          (28) /* 3 bits */
 #define   DPIO_POST_DIV_DAC            0
 #define   DPIO_POST_DIV_HDMIDP         1 /* DAC 225-400M rate */
 #define   DPIO_ENABLE_CALIBRATION      (1<<11)
 #define   DPIO_M1DIV_SHIFT             (8) /* 3 bits */
 #define   DPIO_M2DIV_MASK              0xff
-#define _DPIO_DIV_B                    0x802c
-#define DPIO_DIV(pipe) _PIPE(pipe, _DPIO_DIV_A, _DPIO_DIV_B)
+#define _VLV_PLL_DW3_CH1               0x802c
+#define VLV_PLL_DW3(ch) _PIPE(ch, _VLV_PLL_DW3_CH0, _VLV_PLL_DW3_CH1)
 
-#define _DPIO_REFSFR_A                 0x8014
+#define _VLV_PLL_DW5_CH0               0x8014
 #define   DPIO_REFSEL_OVERRIDE         27
 #define   DPIO_PLL_MODESEL_SHIFT       24 /* 3 bits */
 #define   DPIO_BIAS_CURRENT_CTL_SHIFT  21 /* 3 bits, always 0x7 */
 #define   DPIO_PLL_REFCLK_SEL_MASK     3
 #define   DPIO_DRIVER_CTL_SHIFT                12 /* always set to 0x8 */
 #define   DPIO_CLK_BIAS_CTL_SHIFT      8 /* always set to 0x5 */
-#define _DPIO_REFSFR_B                 0x8034
-#define DPIO_REFSFR(pipe) _PIPE(pipe, _DPIO_REFSFR_A, _DPIO_REFSFR_B)
+#define _VLV_PLL_DW5_CH1               0x8034
+#define VLV_PLL_DW5(ch) _PIPE(ch, _VLV_PLL_DW5_CH0, _VLV_PLL_DW5_CH1)
 
-#define _DPIO_CORE_CLK_A               0x801c
-#define _DPIO_CORE_CLK_B               0x803c
-#define DPIO_CORE_CLK(pipe) _PIPE(pipe, _DPIO_CORE_CLK_A, _DPIO_CORE_CLK_B)
+#define _VLV_PLL_DW7_CH0               0x801c
+#define _VLV_PLL_DW7_CH1               0x803c
+#define VLV_PLL_DW7(ch) _PIPE(ch, _VLV_PLL_DW7_CH0, _VLV_PLL_DW7_CH1)
 
-#define _DPIO_IREF_CTL_A               0x8040
-#define _DPIO_IREF_CTL_B               0x8060
-#define DPIO_IREF_CTL(pipe) _PIPE(pipe, _DPIO_IREF_CTL_A, _DPIO_IREF_CTL_B)
+#define _VLV_PLL_DW8_CH0               0x8040
+#define _VLV_PLL_DW8_CH1               0x8060
+#define VLV_PLL_DW8(ch) _PIPE(ch, _VLV_PLL_DW8_CH0, _VLV_PLL_DW8_CH1)
 
-#define DPIO_IREF_BCAST                        0xc044
-#define _DPIO_IREF_A                   0x8044
-#define _DPIO_IREF_B                   0x8064
-#define DPIO_IREF(pipe) _PIPE(pipe, _DPIO_IREF_A, _DPIO_IREF_B)
+#define VLV_PLL_DW9_BCAST              0xc044
+#define _VLV_PLL_DW9_CH0               0x8044
+#define _VLV_PLL_DW9_CH1               0x8064
+#define VLV_PLL_DW9(ch) _PIPE(ch, _VLV_PLL_DW9_CH0, _VLV_PLL_DW9_CH1)
 
-#define _DPIO_PLL_CML_A                        0x804c
-#define _DPIO_PLL_CML_B                        0x806c
-#define DPIO_PLL_CML(pipe) _PIPE(pipe, _DPIO_PLL_CML_A, _DPIO_PLL_CML_B)
+#define _VLV_PLL_DW10_CH0              0x8048
+#define _VLV_PLL_DW10_CH1              0x8068
+#define VLV_PLL_DW10(ch) _PIPE(ch, _VLV_PLL_DW10_CH0, _VLV_PLL_DW10_CH1)
 
-#define _DPIO_LPF_COEFF_A              0x8048
-#define _DPIO_LPF_COEFF_B              0x8068
-#define DPIO_LPF_COEFF(pipe) _PIPE(pipe, _DPIO_LPF_COEFF_A, _DPIO_LPF_COEFF_B)
+#define _VLV_PLL_DW11_CH0              0x804c
+#define _VLV_PLL_DW11_CH1              0x806c
+#define VLV_PLL_DW11(ch) _PIPE(ch, _VLV_PLL_DW11_CH0, _VLV_PLL_DW11_CH1)
 
-#define DPIO_CALIBRATION               0x80ac
+/* Spec for ref block start counts at DW10 */
+#define VLV_REF_DW13                   0x80ac
 
-#define DPIO_FASTCLK_DISABLE           0x8100
+#define VLV_CMN_DW0                    0x8100
 
 /*
  * Per DDI channel DPIO regs
  */
 
-#define _DPIO_PCS_TX_0                 0x8200
-#define _DPIO_PCS_TX_1                 0x8400
+#define _VLV_PCS_DW0_CH0               0x8200
+#define _VLV_PCS_DW0_CH1               0x8400
 #define   DPIO_PCS_TX_LANE2_RESET      (1<<16)
 #define   DPIO_PCS_TX_LANE1_RESET      (1<<7)
-#define DPIO_PCS_TX(port) _PORT(port, _DPIO_PCS_TX_0, _DPIO_PCS_TX_1)
+#define VLV_PCS_DW0(ch) _PORT(ch, _VLV_PCS_DW0_CH0, _VLV_PCS_DW0_CH1)
 
-#define _DPIO_PCS_CLK_0                        0x8204
-#define _DPIO_PCS_CLK_1                        0x8404
+#define _VLV_PCS_DW1_CH0               0x8204
+#define _VLV_PCS_DW1_CH1               0x8404
 #define   DPIO_PCS_CLK_CRI_RXEB_EIOS_EN        (1<<22)
 #define   DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN (1<<21)
 #define   DPIO_PCS_CLK_DATAWIDTH_SHIFT (6)
 #define   DPIO_PCS_CLK_SOFT_RESET      (1<<5)
-#define DPIO_PCS_CLK(port) _PORT(port, _DPIO_PCS_CLK_0, _DPIO_PCS_CLK_1)
-
-#define _DPIO_PCS_CTL_OVR1_A           0x8224
-#define _DPIO_PCS_CTL_OVR1_B           0x8424
-#define DPIO_PCS_CTL_OVER1(port) _PORT(port, _DPIO_PCS_CTL_OVR1_A, \
-                                      _DPIO_PCS_CTL_OVR1_B)
-
-#define _DPIO_PCS_STAGGER0_A           0x822c
-#define _DPIO_PCS_STAGGER0_B           0x842c
-#define DPIO_PCS_STAGGER0(port) _PORT(port, _DPIO_PCS_STAGGER0_A, \
-                                     _DPIO_PCS_STAGGER0_B)
-
-#define _DPIO_PCS_STAGGER1_A           0x8230
-#define _DPIO_PCS_STAGGER1_B           0x8430
-#define DPIO_PCS_STAGGER1(port) _PORT(port, _DPIO_PCS_STAGGER1_A, \
-                                     _DPIO_PCS_STAGGER1_B)
-
-#define _DPIO_PCS_CLOCKBUF0_A          0x8238
-#define _DPIO_PCS_CLOCKBUF0_B          0x8438
-#define DPIO_PCS_CLOCKBUF0(port) _PORT(port, _DPIO_PCS_CLOCKBUF0_A, \
-                                      _DPIO_PCS_CLOCKBUF0_B)
-
-#define _DPIO_PCS_CLOCKBUF8_A          0x825c
-#define _DPIO_PCS_CLOCKBUF8_B          0x845c
-#define DPIO_PCS_CLOCKBUF8(port) _PORT(port, _DPIO_PCS_CLOCKBUF8_A, \
-                                      _DPIO_PCS_CLOCKBUF8_B)
-
-#define _DPIO_TX_SWING_CTL2_A          0x8288
-#define _DPIO_TX_SWING_CTL2_B          0x8488
-#define DPIO_TX_SWING_CTL2(port) _PORT(port, _DPIO_TX_SWING_CTL2_A, \
-                                      _DPIO_TX_SWING_CTL2_B)
-
-#define _DPIO_TX_SWING_CTL3_A          0x828c
-#define _DPIO_TX_SWING_CTL3_B          0x848c
-#define DPIO_TX_SWING_CTL3(port) _PORT(port, _DPIO_TX_SWING_CTL3_A, \
-                                      _DPIO_TX_SWING_CTL3_B)
-
-#define _DPIO_TX_SWING_CTL4_A          0x8290
-#define _DPIO_TX_SWING_CTL4_B          0x8490
-#define DPIO_TX_SWING_CTL4(port) _PORT(port, _DPIO_TX_SWING_CTL4_A, \
-                                      _DPIO_TX_SWING_CTL4_B)
-
-#define _DPIO_TX_OCALINIT_0            0x8294
-#define _DPIO_TX_OCALINIT_1            0x8494
+#define VLV_PCS_DW1(ch) _PORT(ch, _VLV_PCS_DW1_CH0, _VLV_PCS_DW1_CH1)
+
+#define _VLV_PCS_DW8_CH0               0x8220
+#define _VLV_PCS_DW8_CH1               0x8420
+#define VLV_PCS_DW8(ch) _PORT(ch, _VLV_PCS_DW8_CH0, _VLV_PCS_DW8_CH1)
+
+#define _VLV_PCS01_DW8_CH0             0x0220
+#define _VLV_PCS23_DW8_CH0             0x0420
+#define _VLV_PCS01_DW8_CH1             0x2620
+#define _VLV_PCS23_DW8_CH1             0x2820
+#define VLV_PCS01_DW8(port) _PORT(port, _VLV_PCS01_DW8_CH0, _VLV_PCS01_DW8_CH1)
+#define VLV_PCS23_DW8(port) _PORT(port, _VLV_PCS23_DW8_CH0, _VLV_PCS23_DW8_CH1)
+
+#define _VLV_PCS_DW9_CH0               0x8224
+#define _VLV_PCS_DW9_CH1               0x8424
+#define        VLV_PCS_DW9(ch) _PORT(ch, _VLV_PCS_DW9_CH0, _VLV_PCS_DW9_CH1)
+
+#define _VLV_PCS_DW11_CH0              0x822c
+#define _VLV_PCS_DW11_CH1              0x842c
+#define VLV_PCS_DW11(ch) _PORT(ch, _VLV_PCS_DW11_CH0, _VLV_PCS_DW11_CH1)
+
+#define _VLV_PCS_DW12_CH0              0x8230
+#define _VLV_PCS_DW12_CH1              0x8430
+#define VLV_PCS_DW12(ch) _PORT(ch, _VLV_PCS_DW12_CH0, _VLV_PCS_DW12_CH1)
+
+#define _VLV_PCS_DW14_CH0              0x8238
+#define _VLV_PCS_DW14_CH1              0x8438
+#define        VLV_PCS_DW14(ch) _PORT(ch, _VLV_PCS_DW14_CH0, _VLV_PCS_DW14_CH1)
+
+#define _VLV_PCS_DW23_CH0              0x825c
+#define _VLV_PCS_DW23_CH1              0x845c
+#define VLV_PCS_DW23(ch) _PORT(ch, _VLV_PCS_DW23_CH0, _VLV_PCS_DW23_CH1)
+
+#define _VLV_TX_DW2_CH0                        0x8288
+#define _VLV_TX_DW2_CH1                        0x8488
+#define VLV_TX_DW2(ch) _PORT(ch, _VLV_TX_DW2_CH0, _VLV_TX_DW2_CH1)
+
+#define _VLV_TX_DW3_CH0                        0x828c
+#define _VLV_TX_DW3_CH1                        0x848c
+#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 VLV_TX_DW4(ch) _PORT(ch, _VLV_TX_DW4_CH0, _VLV_TX_DW4_CH1)
+
+#define _VLV_TX3_DW4_CH0               0x690
+#define _VLV_TX3_DW4_CH1               0x2a90
+#define VLV_TX3_DW4(ch) _PORT(ch, _VLV_TX3_DW4_CH0, _VLV_TX3_DW4_CH1)
+
+#define _VLV_TX_DW5_CH0                        0x8294
+#define _VLV_TX_DW5_CH1                        0x8494
 #define   DPIO_TX_OCALINIT_EN          (1<<31)
-#define DPIO_TX_OCALINIT(port) _PORT(port, _DPIO_TX_OCALINIT_0, \
-                                    _DPIO_TX_OCALINIT_1)
-
-#define _DPIO_TX_CTL_0                 0x82ac
-#define _DPIO_TX_CTL_1                 0x84ac
-#define DPIO_TX_CTL(port) _PORT(port, _DPIO_TX_CTL_0, _DPIO_TX_CTL_1)
-
-#define _DPIO_TX_LANE_0                        0x82b8
-#define _DPIO_TX_LANE_1                        0x84b8
-#define DPIO_TX_LANE(port) _PORT(port, _DPIO_TX_LANE_0, _DPIO_TX_LANE_1)
-
-#define _DPIO_DATA_CHANNEL1            0x8220
-#define _DPIO_DATA_CHANNEL2            0x8420
-#define DPIO_DATA_CHANNEL(port) _PORT(port, _DPIO_DATA_CHANNEL1, _DPIO_DATA_CHANNEL2)
-
-#define _DPIO_PORT0_PCS0               0x0220
-#define _DPIO_PORT0_PCS1               0x0420
-#define _DPIO_PORT1_PCS2               0x2620
-#define _DPIO_PORT1_PCS3               0x2820
-#define DPIO_DATA_LANE_A(port) _PORT(port, _DPIO_PORT0_PCS0, _DPIO_PORT1_PCS2)
-#define DPIO_DATA_LANE_B(port) _PORT(port, _DPIO_PORT0_PCS1, _DPIO_PORT1_PCS3)
-#define DPIO_DATA_CHANNEL1              0x8220
-#define DPIO_DATA_CHANNEL2              0x8420
+#define VLV_TX_DW5(ch) _PORT(ch, _VLV_TX_DW5_CH0, _VLV_TX_DW5_CH1)
+
+#define _VLV_TX_DW11_CH0               0x82ac
+#define _VLV_TX_DW11_CH1               0x84ac
+#define VLV_TX_DW11(ch) _PORT(ch, _VLV_TX_DW11_CH0, _VLV_TX_DW11_CH1)
+
+#define _VLV_TX_DW14_CH0               0x82b8
+#define _VLV_TX_DW14_CH1               0x84b8
+#define VLV_TX_DW14(ch) _PORT(ch, _VLV_TX_DW14_CH0, _VLV_TX_DW14_CH1)
 
 /*
  * Fence registers
 #define HWSTAM         0x02098
 #define DMA_FADD_I8XX  0x020d0
 #define RING_BBSTATE(base)     ((base)+0x110)
+#define RING_BBADDR(base)      ((base)+0x140)
+#define RING_BBADDR_UDW(base)  ((base)+0x168) /* gen8+ */
 
 #define ERROR_GEN6     0x040a0
 #define GEN7_ERR_INT   0x44040
 #define   CM0_COLOR_EVICT_DISABLE (1<<3)
 #define   CM0_DEPTH_WRITE_DISABLE (1<<1)
 #define   CM0_RC_OP_FLUSH_DISABLE (1<<0)
-#define BB_ADDR                0x02140 /* 8 bytes */
 #define GFX_FLSH_CNTL  0x02170 /* 915+ only */
 #define GFX_FLSH_CNTL_GEN6     0x101008
 #define   GFX_FLSH_CNTL_EN     (1<<0)
 
 #define GEN7_FF_THREAD_MODE            0x20a0
 #define   GEN7_FF_SCHED_MASK           0x0077070
+#define   GEN8_FF_DS_REF_CNT_FFME      (1 << 19)
 #define   GEN7_FF_TS_SCHED_HS1         (0x5<<16)
 #define   GEN7_FF_TS_SCHED_HS0         (0x3<<16)
 #define   GEN7_FF_TS_SCHED_LOAD_BALANCE        (0x1<<16)
 #define   FBC_CTL_UNCOMPRESSIBLE (1<<14)
 #define   FBC_CTL_C3_IDLE      (1<<13)
 #define   FBC_CTL_STRIDE_SHIFT (5)
-#define   FBC_CTL_FENCENO      (1<<0)
+#define   FBC_CTL_FENCENO_SHIFT        (0)
 #define FBC_COMMAND            0x0320c
 #define   FBC_CMD_COMPRESS     (1<<0)
 #define FBC_STATUS             0x03210
 #define   FBC_STAT_COMPRESSING (1<<31)
 #define   FBC_STAT_COMPRESSED  (1<<30)
 #define   FBC_STAT_MODIFIED    (1<<29)
-#define   FBC_STAT_CURRENT_LINE        (1<<0)
+#define   FBC_STAT_CURRENT_LINE_SHIFT  (0)
 #define FBC_CONTROL2           0x03214
 #define   FBC_CTL_FENCE_DBL    (0<<4)
 #define   FBC_CTL_IDLE_IMM     (0<<2)
  * Please check the detailed lore in the commit message for for experimental
  * evidence.
  */
-#define   PORTD_HOTPLUG_LIVE_STATUS               (1 << 29)
-#define   PORTC_HOTPLUG_LIVE_STATUS               (1 << 28)
-#define   PORTB_HOTPLUG_LIVE_STATUS               (1 << 27)
+#define   PORTD_HOTPLUG_LIVE_STATUS_G4X                (1 << 29)
+#define   PORTC_HOTPLUG_LIVE_STATUS_G4X                (1 << 28)
+#define   PORTB_HOTPLUG_LIVE_STATUS_G4X                (1 << 27)
+/* VLV DP/HDMI bits again match Bspec */
+#define   PORTD_HOTPLUG_LIVE_STATUS_VLV                (1 << 27)
+#define   PORTC_HOTPLUG_LIVE_STATUS_VLV                (1 << 28)
+#define   PORTB_HOTPLUG_LIVE_STATUS_VLV                (1 << 29)
 #define   PORTD_HOTPLUG_INT_STATUS             (3 << 21)
 #define   PORTC_HOTPLUG_INT_STATUS             (3 << 19)
 #define   PORTB_HOTPLUG_INT_STATUS             (3 << 17)
 #define   CRT_HOTPLUG_MONITOR_COLOR            (3 << 8)
 #define   CRT_HOTPLUG_MONITOR_MONO             (2 << 8)
 #define   CRT_HOTPLUG_MONITOR_NONE             (0 << 8)
+#define   DP_AUX_CHANNEL_D_INT_STATUS_G4X      (1 << 6)
+#define   DP_AUX_CHANNEL_C_INT_STATUS_G4X      (1 << 5)
+#define   DP_AUX_CHANNEL_B_INT_STATUS_G4X      (1 << 4)
+#define   DP_AUX_CHANNEL_MASK_INT_STATUS_G4X   (7 << 4)
+
 /* SDVO is different across gen3/4 */
 #define   SDVOC_HOTPLUG_INT_STATUS_G4X         (1 << 3)
 #define   SDVOB_HOTPLUG_INT_STATUS_G4X         (1 << 2)
 /* the unit of memory self-refresh latency time is 0.5us */
 #define  ILK_SRLT_MASK         0x3f
 
-/* define the fifo size on Ironlake */
-#define ILK_DISPLAY_FIFO       128
-#define ILK_DISPLAY_MAXWM      64
-#define ILK_DISPLAY_DFTWM      8
-#define ILK_CURSOR_FIFO                32
-#define ILK_CURSOR_MAXWM       16
-#define ILK_CURSOR_DFTWM       8
-
-#define ILK_DISPLAY_SR_FIFO    512
-#define ILK_DISPLAY_MAX_SRWM   0x1ff
-#define ILK_DISPLAY_DFT_SRWM   0x3f
-#define ILK_CURSOR_SR_FIFO     64
-#define ILK_CURSOR_MAX_SRWM    0x3f
-#define ILK_CURSOR_DFT_SRWM    8
-
-#define ILK_FIFO_LINE_SIZE     64
-
-/* define the WM info on Sandybridge */
-#define SNB_DISPLAY_FIFO       128
-#define SNB_DISPLAY_MAXWM      0x7f    /* bit 16:22 */
-#define SNB_DISPLAY_DFTWM      8
-#define SNB_CURSOR_FIFO                32
-#define SNB_CURSOR_MAXWM       0x1f    /* bit 4:0 */
-#define SNB_CURSOR_DFTWM       8
-
-#define SNB_DISPLAY_SR_FIFO    512
-#define SNB_DISPLAY_MAX_SRWM   0x1ff   /* bit 16:8 */
-#define SNB_DISPLAY_DFT_SRWM   0x3f
-#define SNB_CURSOR_SR_FIFO     64
-#define SNB_CURSOR_MAX_SRWM    0x3f    /* bit 5:0 */
-#define SNB_CURSOR_DFT_SRWM    8
-
-#define SNB_FBC_MAX_SRWM       0xf     /* bit 23:20 */
-
-#define SNB_FIFO_LINE_SIZE     64
-
 
 /* the address where we get all kinds of latency value */
 #define SSKPD                  0x5d10
 #define DISP_BASEADDR_MASK     (0xfffff000)
 #define I915_LO_DISPBASE(val)  (val & ~DISP_BASEADDR_MASK)
 #define I915_HI_DISPBASE(val)  (val & DISP_BASEADDR_MASK)
-#define I915_MODIFY_DISPBASE(reg, gfx_addr) \
-               (I915_WRITE((reg), (gfx_addr) | I915_LO_DISPBASE(I915_READ(reg))))
 
 /* VBIOS flags */
 #define SWF00                  (dev_priv->info->display_mmio_offset + 0x71410)
 
 #define _SPACNTR               (VLV_DISPLAY_BASE + 0x72180)
 #define   SP_ENABLE                    (1<<31)
-#define   SP_GEAMMA_ENABLE             (1<<30)
+#define   SP_GAMMA_ENABLE              (1<<30)
 #define   SP_PIXFORMAT_MASK            (0xf<<26)
 #define   SP_FORMAT_YUV422             (0<<26)
 #define   SP_FORMAT_BGR565             (5<<26)
 #define DISP_ARB_CTL   0x45000
 #define  DISP_TILE_SURFACE_SWIZZLING   (1<<13)
 #define  DISP_FBC_WM_DIS               (1<<15)
+#define DISP_ARB_CTL2  0x45004
+#define  DISP_DATA_PARTITION_5_6       (1<<6)
 #define GEN7_MSG_CTL   0x45010
 #define  WAIT_FOR_PCH_RESET_ACK                (1<<1)
 #define  WAIT_FOR_PCH_FLR_ACK          (1<<0)
 #define GEN7_L3SQCREG4                         0xb034
 #define  L3SQ_URB_READ_CAM_MATCH_DISABLE       (1<<27)
 
+/* GEN8 chicken */
+#define HDC_CHICKEN0                           0x7300
+#define  HDC_FORCE_NON_COHERENT                        (1<<4)
+
 /* WaCatErrorRejectionIssue */
 #define GEN7_SQ_CHICKEN_MBCUNIT_CONFIG         0x9030
 #define  GEN7_SQ_CHICKEN_MBCUNIT_SQINTMOB      (1<<11)
 #define  FORCEWAKE_ACK                         0x130090
 #define  VLV_GTLC_WAKE_CTRL                    0x130090
 #define  VLV_GTLC_PW_STATUS                    0x130094
+#define VLV_GTLC_PW_RENDER_STATUS_MASK         0x80
+#define VLV_GTLC_PW_MEDIA_STATUS_MASK          0x20
 #define  FORCEWAKE_MT                          0xa188 /* multi-threaded */
 #define   FORCEWAKE_KERNEL                     0x1
 #define   FORCEWAKE_USER                       0x2
 #define    FORCEWAKE_MT_ENABLE                 (1<<5)
 
 #define  GTFIFODBG                             0x120000
-#define    GT_FIFO_CPU_ERROR_MASK              7
+#define    GT_FIFO_SBDROPERR                   (1<<6)
+#define    GT_FIFO_BLOBDROPERR                 (1<<5)
+#define    GT_FIFO_SB_READ_ABORTERR            (1<<4)
+#define    GT_FIFO_DROPERR                     (1<<3)
 #define    GT_FIFO_OVFERR                      (1<<2)
 #define    GT_FIFO_IAWRERR                     (1<<1)
 #define    GT_FIFO_IARDERR                     (1<<0)
 
-#define  GT_FIFO_FREE_ENTRIES                  0x120008
+#define  GTFIFOCTL                             0x120008
+#define    GT_FIFO_FREE_ENTRIES_MASK           0x7f
 #define    GT_FIFO_NUM_RESERVED_ENTRIES                20
 
 #define  HSW_IDICR                             0x9008
 #define   GEN6_RC_CTL_RC6_ENABLE               (1<<18)
 #define   GEN6_RC_CTL_RC1e_ENABLE              (1<<20)
 #define   GEN6_RC_CTL_RC7_ENABLE               (1<<22)
+#define   VLV_RC_CTL_CTX_RST_PARALLEL          (1<<24)
 #define   GEN7_RC_CTL_TO_MODE                  (1<<28)
 #define   GEN6_RC_CTL_EI_MODE(x)               ((x)<<27)
 #define   GEN6_RC_CTL_HW_ENABLE                        (1<<31)
index 98790c7cccb1ab0902662e4cc541de9966f2058c..8150fdc08d497122c49959b9bbfaf0090259c7df 100644 (file)
@@ -192,7 +192,6 @@ static void i915_restore_vga(struct drm_device *dev)
 static void i915_save_display(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       unsigned long flags;
 
        /* Display arbitration control */
        if (INTEL_INFO(dev)->gen <= 4)
@@ -203,46 +202,27 @@ static void i915_save_display(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_save_display_reg(dev);
 
-       spin_lock_irqsave(&dev_priv->backlight.lock, flags);
-
        /* LVDS state */
        if (HAS_PCH_SPLIT(dev)) {
                dev_priv->regfile.savePP_CONTROL = I915_READ(PCH_PP_CONTROL);
-               dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1);
-               dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
-               dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL);
-               dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2);
                if (HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev))
                        dev_priv->regfile.saveLVDS = I915_READ(PCH_LVDS);
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
                dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
 
-               dev_priv->regfile.saveBLC_PWM_CTL =
-                       I915_READ(VLV_BLC_PWM_CTL(PIPE_A));
                dev_priv->regfile.saveBLC_HIST_CTL =
                        I915_READ(VLV_BLC_HIST_CTL(PIPE_A));
-               dev_priv->regfile.saveBLC_PWM_CTL2 =
-                       I915_READ(VLV_BLC_PWM_CTL2(PIPE_A));
-               dev_priv->regfile.saveBLC_PWM_CTL_B =
-                       I915_READ(VLV_BLC_PWM_CTL(PIPE_B));
                dev_priv->regfile.saveBLC_HIST_CTL_B =
                        I915_READ(VLV_BLC_HIST_CTL(PIPE_B));
-               dev_priv->regfile.saveBLC_PWM_CTL2_B =
-                       I915_READ(VLV_BLC_PWM_CTL2(PIPE_B));
        } else {
                dev_priv->regfile.savePP_CONTROL = I915_READ(PP_CONTROL);
                dev_priv->regfile.savePFIT_PGM_RATIOS = I915_READ(PFIT_PGM_RATIOS);
-               dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
                dev_priv->regfile.saveBLC_HIST_CTL = I915_READ(BLC_HIST_CTL);
-               if (INTEL_INFO(dev)->gen >= 4)
-                       dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
                if (IS_MOBILE(dev) && !IS_I830(dev))
                        dev_priv->regfile.saveLVDS = I915_READ(LVDS);
        }
 
-       spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
-
        if (!IS_I830(dev) && !IS_845G(dev) && !HAS_PCH_SPLIT(dev))
                dev_priv->regfile.savePFIT_CONTROL = I915_READ(PFIT_CONTROL);
 
@@ -257,7 +237,7 @@ static void i915_save_display(struct drm_device *dev)
        }
 
        /* Only regfile.save FBC state on the platform that supports FBC */
-       if (I915_HAS_FBC(dev)) {
+       if (HAS_FBC(dev)) {
                if (HAS_PCH_SPLIT(dev)) {
                        dev_priv->regfile.saveDPFC_CB_BASE = I915_READ(ILK_DPFC_CB_BASE);
                } else if (IS_GM45(dev)) {
@@ -278,7 +258,6 @@ static void i915_restore_display(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 mask = 0xffffffff;
-       unsigned long flags;
 
        /* Display arbitration */
        if (INTEL_INFO(dev)->gen <= 4)
@@ -287,12 +266,6 @@ static void i915_restore_display(struct drm_device *dev)
        if (!drm_core_check_feature(dev, DRIVER_MODESET))
                i915_restore_display_reg(dev);
 
-       spin_lock_irqsave(&dev_priv->backlight.lock, flags);
-
-       /* LVDS state */
-       if (INTEL_INFO(dev)->gen >= 4 && !HAS_PCH_SPLIT(dev))
-               I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
-
        if (drm_core_check_feature(dev, DRIVER_MODESET))
                mask = ~LVDS_PORT_EN;
 
@@ -305,13 +278,6 @@ static void i915_restore_display(struct drm_device *dev)
                I915_WRITE(PFIT_CONTROL, dev_priv->regfile.savePFIT_CONTROL);
 
        if (HAS_PCH_SPLIT(dev)) {
-               I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL);
-               I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
-               /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2;
-                * otherwise we get blank eDP screen after S3 on some machines
-                */
-               I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->regfile.saveBLC_CPU_PWM_CTL2);
-               I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->regfile.saveBLC_CPU_PWM_CTL);
                I915_WRITE(PCH_PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS);
                I915_WRITE(PCH_PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
                I915_WRITE(PCH_PP_DIVISOR, dev_priv->regfile.savePP_DIVISOR);
@@ -319,21 +285,12 @@ static void i915_restore_display(struct drm_device *dev)
                I915_WRITE(RSTDBYCTL,
                           dev_priv->regfile.saveMCHBAR_RENDER_STANDBY);
        } else if (IS_VALLEYVIEW(dev)) {
-               I915_WRITE(VLV_BLC_PWM_CTL(PIPE_A),
-                          dev_priv->regfile.saveBLC_PWM_CTL);
                I915_WRITE(VLV_BLC_HIST_CTL(PIPE_A),
                           dev_priv->regfile.saveBLC_HIST_CTL);
-               I915_WRITE(VLV_BLC_PWM_CTL2(PIPE_A),
-                          dev_priv->regfile.saveBLC_PWM_CTL2);
-               I915_WRITE(VLV_BLC_PWM_CTL(PIPE_B),
-                          dev_priv->regfile.saveBLC_PWM_CTL);
                I915_WRITE(VLV_BLC_HIST_CTL(PIPE_B),
                           dev_priv->regfile.saveBLC_HIST_CTL);
-               I915_WRITE(VLV_BLC_PWM_CTL2(PIPE_B),
-                          dev_priv->regfile.saveBLC_PWM_CTL2);
        } else {
                I915_WRITE(PFIT_PGM_RATIOS, dev_priv->regfile.savePFIT_PGM_RATIOS);
-               I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL);
                I915_WRITE(BLC_HIST_CTL, dev_priv->regfile.saveBLC_HIST_CTL);
                I915_WRITE(PP_ON_DELAYS, dev_priv->regfile.savePP_ON_DELAYS);
                I915_WRITE(PP_OFF_DELAYS, dev_priv->regfile.savePP_OFF_DELAYS);
@@ -341,11 +298,9 @@ static void i915_restore_display(struct drm_device *dev)
                I915_WRITE(PP_CONTROL, dev_priv->regfile.savePP_CONTROL);
        }
 
-       spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
-
        /* only restore FBC info on the platform that supports FBC*/
        intel_disable_fbc(dev);
-       if (I915_HAS_FBC(dev)) {
+       if (HAS_FBC(dev)) {
                if (HAS_PCH_SPLIT(dev)) {
                        I915_WRITE(ILK_DPFC_CB_BASE, dev_priv->regfile.saveDPFC_CB_BASE);
                } else if (IS_GM45(dev)) {
index cef38fd320a7c5c53c687ca5b67b0d1d3192d615..33bcae314bf86ea5f7a2deafb80625d0382634af 100644 (file)
@@ -40,10 +40,13 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u64 raw_time; /* 32b value may overflow during fixed point math */
        u64 units = 128ULL, div = 100000ULL, bias = 100ULL;
+       u32 ret;
 
        if (!intel_enable_rc6(dev))
                return 0;
 
+       intel_runtime_pm_get(dev_priv);
+
        /* On VLV, residency time is in CZ units rather than 1.28us */
        if (IS_VALLEYVIEW(dev)) {
                u32 clkctl2;
@@ -52,7 +55,8 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg)
                        CLK_CTL2_CZCOUNT_30NS_SHIFT;
                if (!clkctl2) {
                        WARN(!clkctl2, "bogus CZ count value");
-                       return 0;
+                       ret = 0;
+                       goto out;
                }
                units = DIV_ROUND_UP_ULL(30ULL * bias, (u64)clkctl2);
                if (I915_READ(VLV_COUNTER_CONTROL) & VLV_COUNT_RANGE_HIGH)
@@ -62,7 +66,11 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg)
        }
 
        raw_time = I915_READ(reg) * units;
-       return DIV_ROUND_UP_ULL(raw_time, div);
+       ret = DIV_ROUND_UP_ULL(raw_time, div);
+
+out:
+       intel_runtime_pm_put(dev_priv);
+       return ret;
 }
 
 static ssize_t
@@ -183,13 +191,13 @@ i915_l3_write(struct file *filp, struct kobject *kobj,
        int slice = (int)(uintptr_t)attr->private;
        int ret;
 
+       if (!HAS_HW_CONTEXTS(drm_dev))
+               return -ENXIO;
+
        ret = l3_access_valid(drm_dev, offset);
        if (ret)
                return ret;
 
-       if (dev_priv->hw_contexts_disabled)
-               return -ENXIO;
-
        ret = i915_mutex_lock_interruptible(drm_dev);
        if (ret)
                return ret;
@@ -259,7 +267,7 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
        if (IS_VALLEYVIEW(dev_priv->dev)) {
                u32 freq;
                freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
-               ret = vlv_gpu_freq(dev_priv->mem_freq, (freq >> 8) & 0xff);
+               ret = vlv_gpu_freq(dev_priv, (freq >> 8) & 0xff);
        } else {
                ret = dev_priv->rps.cur_delay * GT_FREQUENCY_MULTIPLIER;
        }
@@ -276,8 +284,7 @@ static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        return snprintf(buf, PAGE_SIZE, "%d\n",
-                       vlv_gpu_freq(dev_priv->mem_freq,
-                                    dev_priv->rps.rpe_delay));
+                       vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay));
 }
 
 static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
@@ -291,7 +298,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute
 
        mutex_lock(&dev_priv->rps.hw_lock);
        if (IS_VALLEYVIEW(dev_priv->dev))
-               ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.max_delay);
+               ret = vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay);
        else
                ret = dev_priv->rps.max_delay * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -318,7 +325,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
        mutex_lock(&dev_priv->rps.hw_lock);
 
        if (IS_VALLEYVIEW(dev_priv->dev)) {
-               val = vlv_freq_opcode(dev_priv->mem_freq, val);
+               val = vlv_freq_opcode(dev_priv, val);
 
                hw_max = valleyview_rps_max_freq(dev_priv);
                hw_min = valleyview_rps_min_freq(dev_priv);
@@ -342,15 +349,15 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
                DRM_DEBUG("User requested overclocking to %d\n",
                          val * GT_FREQUENCY_MULTIPLIER);
 
+       dev_priv->rps.max_delay = val;
+
        if (dev_priv->rps.cur_delay > val) {
-               if (IS_VALLEYVIEW(dev_priv->dev))
-                       valleyview_set_rps(dev_priv->dev, val);
+               if (IS_VALLEYVIEW(dev))
+                       valleyview_set_rps(dev, val);
                else
-                       gen6_set_rps(dev_priv->dev, val);
+                       gen6_set_rps(dev, val);
        }
 
-       dev_priv->rps.max_delay = val;
-
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return count;
@@ -367,7 +374,7 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute
 
        mutex_lock(&dev_priv->rps.hw_lock);
        if (IS_VALLEYVIEW(dev_priv->dev))
-               ret = vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.min_delay);
+               ret = vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay);
        else
                ret = dev_priv->rps.min_delay * GT_FREQUENCY_MULTIPLIER;
        mutex_unlock(&dev_priv->rps.hw_lock);
@@ -394,7 +401,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
        mutex_lock(&dev_priv->rps.hw_lock);
 
        if (IS_VALLEYVIEW(dev)) {
-               val = vlv_freq_opcode(dev_priv->mem_freq, val);
+               val = vlv_freq_opcode(dev_priv, val);
 
                hw_max = valleyview_rps_max_freq(dev_priv);
                hw_min = valleyview_rps_min_freq(dev_priv);
@@ -411,15 +418,15 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
                return -EINVAL;
        }
 
+       dev_priv->rps.min_delay = val;
+
        if (dev_priv->rps.cur_delay < val) {
                if (IS_VALLEYVIEW(dev))
                        valleyview_set_rps(dev, val);
                else
-                       gen6_set_rps(dev_priv->dev, val);
+                       gen6_set_rps(dev, val);
        }
 
-       dev_priv->rps.min_delay = val;
-
        mutex_unlock(&dev_priv->rps.hw_lock);
 
        return count;
@@ -449,7 +456,9 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr
        ret = mutex_lock_interruptible(&dev->struct_mutex);
        if (ret)
                return ret;
+       intel_runtime_pm_get(dev_priv);
        rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
+       intel_runtime_pm_put(dev_priv);
        mutex_unlock(&dev->struct_mutex);
 
        if (attr == &dev_attr_gt_RP0_freq_mhz) {
index 967da4772c449a2be05d16bce648fff9bd19a63e..caa18e855815eaf04a39ecb6eedcc572cf4d6290 100644 (file)
@@ -270,6 +270,18 @@ void i915_save_display_reg(struct drm_device *dev)
        }
        /* FIXME: regfile.save TV & SDVO state */
 
+       /* Backlight */
+       if (HAS_PCH_SPLIT(dev)) {
+               dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_PCH_CTL1);
+               dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_PCH_CTL2);
+               dev_priv->regfile.saveBLC_CPU_PWM_CTL = I915_READ(BLC_PWM_CPU_CTL);
+               dev_priv->regfile.saveBLC_CPU_PWM_CTL2 = I915_READ(BLC_PWM_CPU_CTL2);
+       } else {
+               dev_priv->regfile.saveBLC_PWM_CTL = I915_READ(BLC_PWM_CTL);
+               if (INTEL_INFO(dev)->gen >= 4)
+                       dev_priv->regfile.saveBLC_PWM_CTL2 = I915_READ(BLC_PWM_CTL2);
+       }
+
        return;
 }
 
@@ -280,6 +292,21 @@ void i915_restore_display_reg(struct drm_device *dev)
        int dpll_b_reg, fpb0_reg, fpb1_reg;
        int i;
 
+       /* Backlight */
+       if (HAS_PCH_SPLIT(dev)) {
+               I915_WRITE(BLC_PWM_PCH_CTL1, dev_priv->regfile.saveBLC_PWM_CTL);
+               I915_WRITE(BLC_PWM_PCH_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
+               /* NOTE: BLC_PWM_CPU_CTL must be written after BLC_PWM_CPU_CTL2;
+                * otherwise we get blank eDP screen after S3 on some machines
+                */
+               I915_WRITE(BLC_PWM_CPU_CTL2, dev_priv->regfile.saveBLC_CPU_PWM_CTL2);
+               I915_WRITE(BLC_PWM_CPU_CTL, dev_priv->regfile.saveBLC_CPU_PWM_CTL);
+       } else {
+               if (INTEL_INFO(dev)->gen >= 4)
+                       I915_WRITE(BLC_PWM_CTL2, dev_priv->regfile.saveBLC_PWM_CTL2);
+               I915_WRITE(BLC_PWM_CTL, dev_priv->regfile.saveBLC_PWM_CTL);
+       }
+
        /* Display port ratios (must be done before clock is set) */
        if (SUPPORTS_INTEGRATED_DP(dev)) {
                I915_WRITE(_PIPEA_DATA_M_G4X, dev_priv->regfile.savePIPEA_GMCH_DATA_M);
index e4fba39631a5ae2cd5901f85c73738406ef7cdc9..f22041973f3a0a426e29424cb60ba68e042c3ed8 100644 (file)
@@ -281,6 +281,34 @@ parse_lfp_panel_data(struct drm_i915_private *dev_priv,
        }
 }
 
+static void
+parse_lfp_backlight(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
+{
+       const struct bdb_lfp_backlight_data *backlight_data;
+       const struct bdb_lfp_backlight_data_entry *entry;
+
+       backlight_data = find_section(bdb, BDB_LVDS_BACKLIGHT);
+       if (!backlight_data)
+               return;
+
+       if (backlight_data->entry_size != sizeof(backlight_data->data[0])) {
+               DRM_DEBUG_KMS("Unsupported backlight data entry size %u\n",
+                             backlight_data->entry_size);
+               return;
+       }
+
+       entry = &backlight_data->data[panel_type];
+
+       dev_priv->vbt.backlight.pwm_freq_hz = entry->pwm_freq_hz;
+       dev_priv->vbt.backlight.active_low_pwm = entry->active_low_pwm;
+       DRM_DEBUG_KMS("VBT backlight PWM modulation frequency %u Hz, "
+                     "active %s, min brightness %u, level %u\n",
+                     dev_priv->vbt.backlight.pwm_freq_hz,
+                     dev_priv->vbt.backlight.active_low_pwm ? "low" : "high",
+                     entry->min_brightness,
+                     backlight_data->level[panel_type]);
+}
+
 /* Try to find sdvo panel data */
 static void
 parse_sdvo_panel_data(struct drm_i915_private *dev_priv,
@@ -327,12 +355,12 @@ static int intel_bios_ssc_frequency(struct drm_device *dev,
 {
        switch (INTEL_INFO(dev)->gen) {
        case 2:
-               return alternate ? 66 : 48;
+               return alternate ? 66667 : 48000;
        case 3:
        case 4:
-               return alternate ? 100 : 96;
+               return alternate ? 100000 : 96000;
        default:
-               return alternate ? 100 : 120;
+               return alternate ? 100000 : 120000;
        }
 }
 
@@ -796,7 +824,7 @@ init_vbt_defaults(struct drm_i915_private *dev_priv)
         */
        dev_priv->vbt.lvds_ssc_freq = intel_bios_ssc_frequency(dev,
                        !HAS_PCH_SPLIT(dev));
-       DRM_DEBUG_KMS("Set default to SSC at %dMHz\n", dev_priv->vbt.lvds_ssc_freq);
+       DRM_DEBUG_KMS("Set default to SSC at %d kHz\n", dev_priv->vbt.lvds_ssc_freq);
 
        for (port = PORT_A; port < I915_MAX_PORTS; port++) {
                struct ddi_vbt_port_info *info =
@@ -894,6 +922,7 @@ intel_parse_bios(struct drm_device *dev)
        parse_general_features(dev_priv, bdb);
        parse_general_definitions(dev_priv, bdb);
        parse_lfp_panel_data(dev_priv, bdb);
+       parse_lfp_backlight(dev_priv, bdb);
        parse_sdvo_panel_data(dev_priv, bdb);
        parse_sdvo_device_mapping(dev_priv, bdb);
        parse_device_mapping(dev_priv, bdb);
index f580a2b0ddd30f5d4338c7ab61414b6fe8bc62fc..282de5e9f39dee6566bb6d220f378864df86e8b9 100644 (file)
@@ -39,7 +39,7 @@ struct vbt_header {
        u8 reserved0;
        u32 bdb_offset;                 /**< from beginning of VBT */
        u32 aim_offset[4];              /**< from beginning of VBT */
-} __attribute__((packed));
+} __packed;
 
 struct bdb_header {
        u8 signature[16];               /**< Always 'BIOS_DATA_BLOCK' */
@@ -65,7 +65,7 @@ struct vbios_data {
        u8 rsvd4; /* popup memory size */
        u8 resize_pci_bios;
        u8 rsvd5; /* is crt already on ddc2 */
-} __attribute__((packed));
+} __packed;
 
 /*
  * There are several types of BIOS data blocks (BDBs), each block has
@@ -142,7 +142,7 @@ struct bdb_general_features {
        u8 dp_ssc_enb:1;        /* PCH attached eDP supports SSC */
        u8 dp_ssc_freq:1;       /* SSC freq for PCH attached eDP */
        u8 rsvd11:3; /* finish byte */
-} __attribute__((packed));
+} __packed;
 
 /* pre-915 */
 #define GPIO_PIN_DVI_LVDS      0x03 /* "DVI/LVDS DDC GPIO pins" */
@@ -225,7 +225,7 @@ struct old_child_dev_config {
        u8  dvo2_wiring;
        u16 extended_type;
        u8  dvo_function;
-} __attribute__((packed));
+} __packed;
 
 /* This one contains field offsets that are known to be common for all BDB
  * versions. Notice that the meaning of the contents contents may still change,
@@ -238,7 +238,7 @@ struct common_child_dev_config {
        u8 not_common2[2];
        u8 ddc_pin;
        u16 edid_ptr;
-} __attribute__((packed));
+} __packed;
 
 /* This field changes depending on the BDB version, so the most reliable way to
  * read it is by checking the BDB version and reading the raw pointer. */
@@ -279,7 +279,7 @@ struct bdb_general_definitions {
         *           sizeof(child_device_config);
         */
        union child_device_config devices[0];
-} __attribute__((packed));
+} __packed;
 
 struct bdb_lvds_options {
        u8 panel_type;
@@ -293,7 +293,7 @@ struct bdb_lvds_options {
        u8 lvds_edid:1;
        u8 rsvd2:1;
        u8 rsvd4;
-} __attribute__((packed));
+} __packed;
 
 /* LFP pointer table contains entries to the struct below */
 struct bdb_lvds_lfp_data_ptr {
@@ -303,12 +303,12 @@ struct bdb_lvds_lfp_data_ptr {
        u8 dvo_table_size;
        u16 panel_pnp_id_offset;
        u8 pnp_table_size;
-} __attribute__((packed));
+} __packed;
 
 struct bdb_lvds_lfp_data_ptrs {
        u8 lvds_entries; /* followed by one or more lvds_data_ptr structs */
        struct bdb_lvds_lfp_data_ptr ptr[16];
-} __attribute__((packed));
+} __packed;
 
 /* LFP data has 3 blocks per entry */
 struct lvds_fp_timing {
@@ -325,7 +325,7 @@ struct lvds_fp_timing {
        u32 pfit_reg;
        u32 pfit_reg_val;
        u16 terminator;
-} __attribute__((packed));
+} __packed;
 
 struct lvds_dvo_timing {
        u16 clock;              /**< In 10khz */
@@ -353,7 +353,7 @@ struct lvds_dvo_timing {
        u8 vsync_positive:1;
        u8 hsync_positive:1;
        u8 rsvd2:1;
-} __attribute__((packed));
+} __packed;
 
 struct lvds_pnp_id {
        u16 mfg_name;
@@ -361,17 +361,33 @@ struct lvds_pnp_id {
        u32 serial;
        u8 mfg_week;
        u8 mfg_year;
-} __attribute__((packed));
+} __packed;
 
 struct bdb_lvds_lfp_data_entry {
        struct lvds_fp_timing fp_timing;
        struct lvds_dvo_timing dvo_timing;
        struct lvds_pnp_id pnp_id;
-} __attribute__((packed));
+} __packed;
 
 struct bdb_lvds_lfp_data {
        struct bdb_lvds_lfp_data_entry data[16];
-} __attribute__((packed));
+} __packed;
+
+struct bdb_lfp_backlight_data_entry {
+       u8 type:2;
+       u8 active_low_pwm:1;
+       u8 obsolete1:5;
+       u16 pwm_freq_hz;
+       u8 min_brightness;
+       u8 obsolete2;
+       u8 obsolete3;
+} __packed;
+
+struct bdb_lfp_backlight_data {
+       u8 entry_size;
+       struct bdb_lfp_backlight_data_entry data[16];
+       u8 level[16];
+} __packed;
 
 struct aimdb_header {
        char signature[16];
@@ -379,12 +395,12 @@ struct aimdb_header {
        u16 aimdb_version;
        u16 aimdb_header_size;
        u16 aimdb_size;
-} __attribute__((packed));
+} __packed;
 
 struct aimdb_block {
        u8 aimdb_id;
        u16 aimdb_size;
-} __attribute__((packed));
+} __packed;
 
 struct vch_panel_data {
        u16 fp_timing_offset;
@@ -395,12 +411,12 @@ struct vch_panel_data {
        u8 text_fitting_size;
        u16 graphics_fitting_offset;
        u8 graphics_fitting_size;
-} __attribute__((packed));
+} __packed;
 
 struct vch_bdb_22 {
        struct aimdb_block aimdb_block;
        struct vch_panel_data panels[16];
-} __attribute__((packed));
+} __packed;
 
 struct bdb_sdvo_lvds_options {
        u8 panel_backlight;
@@ -416,7 +432,7 @@ struct bdb_sdvo_lvds_options {
        u8 panel_misc_bits_2;
        u8 panel_misc_bits_3;
        u8 panel_misc_bits_4;
-} __attribute__((packed));
+} __packed;
 
 
 #define BDB_DRIVER_FEATURE_NO_LVDS             0
@@ -462,7 +478,7 @@ struct bdb_driver_features {
 
        u8 hdmi_termination;
        u8 custom_vbt_version;
-} __attribute__((packed));
+} __packed;
 
 #define EDP_18BPP      0
 #define EDP_24BPP      1
@@ -487,14 +503,14 @@ struct edp_power_seq {
        u16 t9;
        u16 t10;
        u16 t11_t12;
-} __attribute__ ((packed));
+} __packed;
 
 struct edp_link_params {
        u8 rate:4;
        u8 lanes:4;
        u8 preemphasis:4;
        u8 vswing:4;
-} __attribute__ ((packed));
+} __packed;
 
 struct bdb_edp {
        struct edp_power_seq power_seqs[16];
@@ -505,7 +521,7 @@ struct bdb_edp {
        /* ith bit indicates enabled/disabled for (i+1)th panel */
        u16 edp_s3d_feature;
        u16 edp_t3_optimization;
-} __attribute__ ((packed));
+} __packed;
 
 void intel_setup_bios(struct drm_device *dev);
 int intel_parse_bios(struct drm_device *dev);
@@ -733,6 +749,6 @@ struct bdb_mipi {
        u32 hl_switch_cnt;
        u32 lp_byte_clk;
        u32 clk_lane_switch_cnt;
-} __attribute__((packed));
+} __packed;
 
 #endif /* _I830_BIOS_H_ */
index b5b1b9b23adf1b24559e7ffdce658ba37e6bbbab..e2e39e65f10954b8076b3ed01b565f0cb173bb0d 100644 (file)
@@ -222,8 +222,9 @@ static void intel_crt_dpms(struct drm_connector *connector, int mode)
        intel_modeset_check_state(connector->dev);
 }
 
-static int intel_crt_mode_valid(struct drm_connector *connector,
-                               struct drm_display_mode *mode)
+static enum drm_mode_status
+intel_crt_mode_valid(struct drm_connector *connector,
+                    struct drm_display_mode *mode)
 {
        struct drm_device *dev = connector->dev;
 
index b69dc3e66c165ac77782943450d98602ef75c205..e06b9e017d6ba918b87557de301df47076852434 100644 (file)
@@ -73,7 +73,7 @@ static const u32 hsw_ddi_translations_hdmi[] = {
 };
 
 static const u32 bdw_ddi_translations_edp[] = {
-       0x00FFFFFF, 0x00000012,         /* DP parameters */
+       0x00FFFFFF, 0x00000012,         /* eDP parameters */
        0x00EBAFFF, 0x00020011,
        0x00C71FFF, 0x0006000F,
        0x00FFFFFF, 0x00020011,
@@ -696,25 +696,25 @@ intel_ddi_calculate_wrpll(int clock /* in Hz */,
        *n2_out = best.n2;
        *p_out = best.p;
        *r2_out = best.r2;
-
-       DRM_DEBUG_KMS("WRPLL: %dHz refresh rate with p=%d, n2=%d r2=%d\n",
-                     clock, *p_out, *n2_out, *r2_out);
 }
 
-bool intel_ddi_pll_mode_set(struct drm_crtc *crtc)
+/*
+ * 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)
 {
-       struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+       struct drm_crtc *crtc = &intel_crtc->base;
        struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
        struct drm_encoder *encoder = &intel_encoder->base;
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
        struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
        int type = intel_encoder->type;
        enum pipe pipe = intel_crtc->pipe;
-       uint32_t reg, val;
        int clock = intel_crtc->config.port_clock;
 
-       /* TODO: reuse PLLs when possible (compare values) */
-
        intel_ddi_put_crtc_pll(crtc);
 
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
@@ -736,66 +736,145 @@ bool intel_ddi_pll_mode_set(struct drm_crtc *crtc)
                        return false;
                }
 
-               /* We don't need to turn any PLL on because we'll use LCPLL. */
-               return true;
-
        } else if (type == INTEL_OUTPUT_HDMI) {
+               uint32_t reg, val;
                unsigned p, n2, r2;
 
-               if (plls->wrpll1_refcount == 0) {
+               intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
+
+               val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 |
+                     WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
+                     WRPLL_DIVIDER_POST(p);
+
+               if (val == I915_READ(WRPLL_CTL1)) {
+                       DRM_DEBUG_KMS("Reusing WRPLL 1 on pipe %c\n",
+                                     pipe_name(pipe));
+                       reg = WRPLL_CTL1;
+               } else if (val == I915_READ(WRPLL_CTL2)) {
+                       DRM_DEBUG_KMS("Reusing WRPLL 2 on pipe %c\n",
+                                     pipe_name(pipe));
+                       reg = WRPLL_CTL2;
+               } else if (plls->wrpll1_refcount == 0) {
                        DRM_DEBUG_KMS("Using WRPLL 1 on pipe %c\n",
                                      pipe_name(pipe));
-                       plls->wrpll1_refcount++;
                        reg = WRPLL_CTL1;
-                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1;
                } else if (plls->wrpll2_refcount == 0) {
                        DRM_DEBUG_KMS("Using WRPLL 2 on pipe %c\n",
                                      pipe_name(pipe));
-                       plls->wrpll2_refcount++;
                        reg = WRPLL_CTL2;
-                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2;
                } else {
                        DRM_ERROR("No WRPLLs available!\n");
                        return false;
                }
 
-               WARN(I915_READ(reg) & WRPLL_PLL_ENABLE,
-                    "WRPLL already enabled\n");
+               DRM_DEBUG_KMS("WRPLL: %dKHz refresh rate with p=%d, n2=%d r2=%d\n",
+                             clock, p, n2, r2);
 
-               intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
-
-               val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 |
-                     WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
-                     WRPLL_DIVIDER_POST(p);
+               if (reg == WRPLL_CTL1) {
+                       plls->wrpll1_refcount++;
+                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL1;
+               } else {
+                       plls->wrpll2_refcount++;
+                       intel_crtc->ddi_pll_sel = PORT_CLK_SEL_WRPLL2;
+               }
 
        } else if (type == INTEL_OUTPUT_ANALOG) {
                if (plls->spll_refcount == 0) {
                        DRM_DEBUG_KMS("Using SPLL on pipe %c\n",
                                      pipe_name(pipe));
                        plls->spll_refcount++;
-                       reg = SPLL_CTL;
                        intel_crtc->ddi_pll_sel = PORT_CLK_SEL_SPLL;
                } else {
                        DRM_ERROR("SPLL already in use\n");
                        return false;
                }
 
-               WARN(I915_READ(reg) & SPLL_PLL_ENABLE,
-                    "SPLL already enabled\n");
-
-               val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz | SPLL_PLL_SSC;
-
        } else {
                WARN(1, "Invalid DDI encoder type %d\n", type);
                return false;
        }
 
-       I915_WRITE(reg, val);
-       udelay(20);
-
        return true;
 }
 
+/*
+ * To be called after intel_ddi_pll_select(). That one selects the PLL to be
+ * used, this one actually enables the PLL.
+ */
+void intel_ddi_pll_enable(struct intel_crtc *crtc)
+{
+       struct drm_device *dev = crtc->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_ddi_plls *plls = &dev_priv->ddi_plls;
+       int clock = crtc->config.port_clock;
+       uint32_t reg, cur_val, new_val;
+       int refcount;
+       const char *pll_name;
+       uint32_t enable_bit = (1 << 31);
+       unsigned int p, n2, r2;
+
+       BUILD_BUG_ON(enable_bit != SPLL_PLL_ENABLE);
+       BUILD_BUG_ON(enable_bit != WRPLL_PLL_ENABLE);
+
+       switch (crtc->ddi_pll_sel) {
+       case PORT_CLK_SEL_LCPLL_2700:
+       case PORT_CLK_SEL_LCPLL_1350:
+       case PORT_CLK_SEL_LCPLL_810:
+               /*
+                * LCPLL should always be enabled at this point of the mode set
+                * sequence, so nothing to do.
+                */
+               return;
+
+       case PORT_CLK_SEL_SPLL:
+               pll_name = "SPLL";
+               reg = SPLL_CTL;
+               refcount = plls->spll_refcount;
+               new_val = SPLL_PLL_ENABLE | SPLL_PLL_FREQ_1350MHz |
+                         SPLL_PLL_SSC;
+               break;
+
+       case PORT_CLK_SEL_WRPLL1:
+       case PORT_CLK_SEL_WRPLL2:
+               if (crtc->ddi_pll_sel == PORT_CLK_SEL_WRPLL1) {
+                       pll_name = "WRPLL1";
+                       reg = WRPLL_CTL1;
+                       refcount = plls->wrpll1_refcount;
+               } else {
+                       pll_name = "WRPLL2";
+                       reg = WRPLL_CTL2;
+                       refcount = plls->wrpll2_refcount;
+               }
+
+               intel_ddi_calculate_wrpll(clock * 1000, &r2, &n2, &p);
+
+               new_val = WRPLL_PLL_ENABLE | WRPLL_PLL_SELECT_LCPLL_2700 |
+                         WRPLL_DIVIDER_REFERENCE(r2) |
+                         WRPLL_DIVIDER_FEEDBACK(n2) | WRPLL_DIVIDER_POST(p);
+
+               break;
+
+       case PORT_CLK_SEL_NONE:
+               WARN(1, "Bad selected pll: PORT_CLK_SEL_NONE\n");
+               return;
+       default:
+               WARN(1, "Bad selected pll: 0x%08x\n", crtc->ddi_pll_sel);
+               return;
+       }
+
+       cur_val = I915_READ(reg);
+
+       WARN(refcount < 1, "Bad %s refcount: %d\n", pll_name, refcount);
+       if (refcount == 1) {
+               WARN(cur_val & enable_bit, "%s already enabled\n", pll_name);
+               I915_WRITE(reg, new_val);
+               POSTING_READ(reg);
+               udelay(20);
+       } else {
+               WARN((cur_val & enable_bit) == 0, "%s disabled\n", pll_name);
+       }
+}
+
 void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
 {
        struct drm_i915_private *dev_priv = crtc->dev->dev_private;
@@ -1121,9 +1200,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
 
        if (type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-               ironlake_edp_panel_vdd_on(intel_dp);
                ironlake_edp_panel_on(intel_dp);
-               ironlake_edp_panel_vdd_off(intel_dp, true);
        }
 
        WARN_ON(intel_crtc->ddi_pll_sel == PORT_CLK_SEL_NONE);
@@ -1166,7 +1243,6 @@ static void intel_ddi_post_disable(struct intel_encoder *intel_encoder)
 
        if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
                struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
-               ironlake_edp_panel_vdd_on(intel_dp);
                intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
                ironlake_edp_panel_off(intel_dp);
        }
index 2bde35d34eb99d121aee6a51bfff5e2c8f75524a..9fa24347963a38d360e365cfa20bf7cefed8beaa 100644 (file)
@@ -90,8 +90,8 @@ intel_fdi_link_freq(struct drm_device *dev)
 
 static const intel_limit_t intel_limits_i8xx_dac = {
        .dot = { .min = 25000, .max = 350000 },
-       .vco = { .min = 930000, .max = 1400000 },
-       .n = { .min = 3, .max = 16 },
+       .vco = { .min = 908000, .max = 1512000 },
+       .n = { .min = 2, .max = 16 },
        .m = { .min = 96, .max = 140 },
        .m1 = { .min = 18, .max = 26 },
        .m2 = { .min = 6, .max = 16 },
@@ -103,8 +103,8 @@ static const intel_limit_t intel_limits_i8xx_dac = {
 
 static const intel_limit_t intel_limits_i8xx_dvo = {
        .dot = { .min = 25000, .max = 350000 },
-       .vco = { .min = 930000, .max = 1400000 },
-       .n = { .min = 3, .max = 16 },
+       .vco = { .min = 908000, .max = 1512000 },
+       .n = { .min = 2, .max = 16 },
        .m = { .min = 96, .max = 140 },
        .m1 = { .min = 18, .max = 26 },
        .m2 = { .min = 6, .max = 16 },
@@ -116,8 +116,8 @@ static const intel_limit_t intel_limits_i8xx_dvo = {
 
 static const intel_limit_t intel_limits_i8xx_lvds = {
        .dot = { .min = 25000, .max = 350000 },
-       .vco = { .min = 930000, .max = 1400000 },
-       .n = { .min = 3, .max = 16 },
+       .vco = { .min = 908000, .max = 1512000 },
+       .n = { .min = 2, .max = 16 },
        .m = { .min = 96, .max = 140 },
        .m1 = { .min = 18, .max = 26 },
        .m2 = { .min = 6, .max = 16 },
@@ -329,6 +329,8 @@ static void vlv_clock(int refclk, intel_clock_t *clock)
 {
        clock->m = clock->m1 * clock->m2;
        clock->p = clock->p1 * clock->p2;
+       if (WARN_ON(clock->n == 0 || clock->p == 0))
+               return;
        clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
        clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
 }
@@ -430,6 +432,8 @@ static void pineview_clock(int refclk, intel_clock_t *clock)
 {
        clock->m = clock->m2 + 2;
        clock->p = clock->p1 * clock->p2;
+       if (WARN_ON(clock->n == 0 || clock->p == 0))
+               return;
        clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n);
        clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
 }
@@ -443,6 +447,8 @@ static void i9xx_clock(int refclk, intel_clock_t *clock)
 {
        clock->m = i9xx_dpll_compute_m(clock);
        clock->p = clock->p1 * clock->p2;
+       if (WARN_ON(clock->n + 2 == 0 || clock->p == 0))
+               return;
        clock->vco = DIV_ROUND_CLOSEST(refclk * clock->m, clock->n + 2);
        clock->dot = DIV_ROUND_CLOSEST(clock->vco, clock->p);
 }
@@ -748,10 +754,10 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
        return intel_crtc->config.cpu_transcoder;
 }
 
-static void ironlake_wait_for_vblank(struct drm_device *dev, int pipe)
+static void g4x_wait_for_vblank(struct drm_device *dev, int pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 frame, frame_reg = PIPEFRAME(pipe);
+       u32 frame, frame_reg = PIPE_FRMCOUNT_GM45(pipe);
 
        frame = I915_READ(frame_reg);
 
@@ -772,8 +778,8 @@ void intel_wait_for_vblank(struct drm_device *dev, int pipe)
        struct drm_i915_private *dev_priv = dev->dev_private;
        int pipestat_reg = PIPESTAT(pipe);
 
-       if (INTEL_INFO(dev)->gen >= 5) {
-               ironlake_wait_for_vblank(dev, pipe);
+       if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+               g4x_wait_for_vblank(dev, pipe);
                return;
        }
 
@@ -1205,15 +1211,12 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
        }
 }
 
-static void assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
+static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
 {
        u32 val;
        bool enabled;
 
-       if (HAS_PCH_LPT(dev_priv->dev)) {
-               DRM_DEBUG_DRIVER("LPT does not has PCH refclk, skipping check\n");
-               return;
-       }
+       WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
 
        val = I915_READ(PCH_DREF_CONTROL);
        enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
@@ -1361,6 +1364,24 @@ static void intel_init_dpio(struct drm_device *dev)
        if (!IS_VALLEYVIEW(dev))
                return;
 
+       DPIO_PHY_IOSF_PORT(DPIO_PHY0) = IOSF_PORT_DPIO;
+}
+
+static void intel_reset_dpio(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (!IS_VALLEYVIEW(dev))
+               return;
+
+       /*
+        * Enable the CRI clock source so we can get at the display and the
+        * reference clock for VGA hotplug / manual detection.
+        */
+       I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
+                  DPLL_REFA_CLK_ENABLE_VLV |
+                  DPLL_INTEGRATED_CRI_CLK_VLV);
+
        /*
         * From VLV2A0_DP_eDP_DPIO_driver_vbios_notes_10.docx -
         *  6.  De-assert cmn_reset/side_reset. Same as VLV X0.
@@ -1487,25 +1508,35 @@ static void vlv_disable_pll(struct drm_i915_private *dev_priv, enum pipe pipe)
        /* Make sure the pipe isn't still relying on us */
        assert_pipe_disabled(dev_priv, pipe);
 
-       /* Leave integrated clock source enabled */
+       /*
+        * Leave integrated clock source and reference clock enabled for pipe B.
+        * The latter is needed for VGA hotplug / manual detection.
+        */
        if (pipe == PIPE_B)
-               val = DPLL_INTEGRATED_CRI_CLK_VLV;
+               val = DPLL_INTEGRATED_CRI_CLK_VLV | DPLL_REFA_CLK_ENABLE_VLV;
        I915_WRITE(DPLL(pipe), val);
        POSTING_READ(DPLL(pipe));
 }
 
-void vlv_wait_port_ready(struct drm_i915_private *dev_priv, int port)
+void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
+               struct intel_digital_port *dport)
 {
        u32 port_mask;
 
-       if (!port)
+       switch (dport->port) {
+       case PORT_B:
                port_mask = DPLL_PORTB_READY_MASK;
-       else
+               break;
+       case PORT_C:
                port_mask = DPLL_PORTC_READY_MASK;
+               break;
+       default:
+               BUG();
+       }
 
        if (wait_for((I915_READ(DPLL(0)) & port_mask) == 0, 1000))
                WARN(1, "timed out waiting for port %c ready: 0x%08x\n",
-                    'B' + port, I915_READ(DPLL(0)));
+                    port_name(dport->port), I915_READ(DPLL(0)));
 }
 
 /**
@@ -2083,8 +2114,8 @@ static int i9xx_update_plane(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                      fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
        if (INTEL_INFO(dev)->gen >= 4) {
-               I915_MODIFY_DISPBASE(DSPSURF(plane),
-                                    i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
+               I915_WRITE(DSPSURF(plane),
+                          i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
                I915_WRITE(DSPTILEOFF(plane), (y << 16) | x);
                I915_WRITE(DSPLINOFF(plane), linear_offset);
        } else
@@ -2174,8 +2205,8 @@ static int ironlake_update_plane(struct drm_crtc *crtc,
                      i915_gem_obj_ggtt_offset(obj), linear_offset, x, y,
                      fb->pitches[0]);
        I915_WRITE(DSPSTRIDE(plane), fb->pitches[0]);
-       I915_MODIFY_DISPBASE(DSPSURF(plane),
-                            i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
+       I915_WRITE(DSPSURF(plane),
+                  i915_gem_obj_ggtt_offset(obj) + intel_crtc->dspaddr_offset);
        if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                I915_WRITE(DSPOFFSET(plane), (y << 16) | x);
        } else {
@@ -2233,7 +2264,12 @@ void intel_display_handle_reset(struct drm_device *dev)
                struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 
                mutex_lock(&crtc->mutex);
-               if (intel_crtc->active)
+               /*
+                * FIXME: Once we have proper support for primary planes (and
+                * disabling them without disabling the entire crtc) allow again
+                * a NULL crtc->fb.
+                */
+               if (intel_crtc->active && crtc->fb)
                        dev_priv->display.update_plane(crtc, crtc->fb,
                                                       crtc->x, crtc->y);
                mutex_unlock(&crtc->mutex);
@@ -2350,6 +2386,8 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                        I915_WRITE(PF_WIN_POS(intel_crtc->pipe), 0);
                        I915_WRITE(PF_WIN_SZ(intel_crtc->pipe), 0);
                }
+               intel_crtc->config.pipe_src_w = adjusted_mode->crtc_hdisplay;
+               intel_crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay;
        }
 
        ret = dev_priv->display.update_plane(crtc, fb, x, y);
@@ -2944,6 +2982,30 @@ static bool intel_crtc_has_pending_flip(struct drm_crtc *crtc)
        return pending;
 }
 
+bool intel_has_pending_fb_unpin(struct drm_device *dev)
+{
+       struct intel_crtc *crtc;
+
+       /* Note that we don't need to be called with mode_config.lock here
+        * as our list of CRTC objects is static for the lifetime of the
+        * device and so cannot disappear as we iterate. Similarly, we can
+        * happily treat the predicates as racy, atomic checks as userspace
+        * cannot claim and pin a new fb without at least acquring the
+        * struct_mutex and so serialising with us.
+        */
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, base.head) {
+               if (atomic_read(&crtc->unpin_work_count) == 0)
+                       continue;
+
+               if (crtc->unpin_work)
+                       intel_wait_for_vblank(dev, crtc->pipe);
+
+               return true;
+       }
+
+       return false;
+}
+
 static void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -3399,9 +3461,8 @@ void hsw_enable_ips(struct intel_crtc *crtc)
                mutex_unlock(&dev_priv->rps.hw_lock);
                /* Quoting Art Runyan: "its not safe to expect any particular
                 * value in IPS_CTL bit 31 after enabling IPS through the
-                * mailbox." Therefore we need to defer waiting on the state
-                * change.
-                * TODO: need to fix this for state checker
+                * mailbox." Moreover, the mailbox may return a bogus state,
+                * so we need to just enable it and continue on.
                 */
        } else {
                I915_WRITE(IPS_CTL, IPS_ENABLE);
@@ -3428,9 +3489,10 @@ void hsw_disable_ips(struct intel_crtc *crtc)
                mutex_lock(&dev_priv->rps.hw_lock);
                WARN_ON(sandybridge_pcode_write(dev_priv, DISPLAY_IPS_CONTROL, 0));
                mutex_unlock(&dev_priv->rps.hw_lock);
-       } else
+       } else {
                I915_WRITE(IPS_CTL, 0);
-       POSTING_READ(IPS_CTL);
+               POSTING_READ(IPS_CTL);
+       }
 
        /* We need to wait for a vblank before we can disable the plane. */
        intel_wait_for_vblank(dev, crtc->pipe);
@@ -3465,7 +3527,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
        /* Workaround : Do not read or write the pipe palette/gamma data while
         * GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
         */
-       if (intel_crtc->config.ips_enabled &&
+       if (IS_HASWELL(dev) && intel_crtc->config.ips_enabled &&
            ((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) ==
             GAMMA_MODE_MODE_SPLIT)) {
                hsw_disable_ips(intel_crtc);
@@ -3910,6 +3972,174 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)
        I915_WRITE(BCLRPAT(crtc->pipe), 0);
 }
 
+int valleyview_get_vco(struct drm_i915_private *dev_priv)
+{
+       int hpll_freq, vco_freq[] = { 800, 1600, 2000, 2400 };
+
+       /* Obtain SKU information */
+       mutex_lock(&dev_priv->dpio_lock);
+       hpll_freq = vlv_cck_read(dev_priv, CCK_FUSE_REG) &
+               CCK_FUSE_HPLL_FREQ_MASK;
+       mutex_unlock(&dev_priv->dpio_lock);
+
+       return vco_freq[hpll_freq];
+}
+
+/* Adjust CDclk dividers to allow high res or save power if possible */
+static void valleyview_set_cdclk(struct drm_device *dev, int cdclk)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 val, cmd;
+
+       if (cdclk >= 320) /* jump to highest voltage for 400MHz too */
+               cmd = 2;
+       else if (cdclk == 266)
+               cmd = 1;
+       else
+               cmd = 0;
+
+       mutex_lock(&dev_priv->rps.hw_lock);
+       val = vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ);
+       val &= ~DSPFREQGUAR_MASK;
+       val |= (cmd << DSPFREQGUAR_SHIFT);
+       vlv_punit_write(dev_priv, PUNIT_REG_DSPFREQ, val);
+       if (wait_for((vlv_punit_read(dev_priv, PUNIT_REG_DSPFREQ) &
+                     DSPFREQSTAT_MASK) == (cmd << DSPFREQSTAT_SHIFT),
+                    50)) {
+               DRM_ERROR("timed out waiting for CDclk change\n");
+       }
+       mutex_unlock(&dev_priv->rps.hw_lock);
+
+       if (cdclk == 400) {
+               u32 divider, vco;
+
+               vco = valleyview_get_vco(dev_priv);
+               divider = ((vco << 1) / cdclk) - 1;
+
+               mutex_lock(&dev_priv->dpio_lock);
+               /* adjust cdclk divider */
+               val = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
+               val &= ~0xf;
+               val |= divider;
+               vlv_cck_write(dev_priv, CCK_DISPLAY_CLOCK_CONTROL, val);
+               mutex_unlock(&dev_priv->dpio_lock);
+       }
+
+       mutex_lock(&dev_priv->dpio_lock);
+       /* adjust self-refresh exit latency value */
+       val = vlv_bunit_read(dev_priv, BUNIT_REG_BISOC);
+       val &= ~0x7f;
+
+       /*
+        * For high bandwidth configs, we set a higher latency in the bunit
+        * so that the core display fetch happens in time to avoid underruns.
+        */
+       if (cdclk == 400)
+               val |= 4500 / 250; /* 4.5 usec */
+       else
+               val |= 3000 / 250; /* 3.0 usec */
+       vlv_bunit_write(dev_priv, BUNIT_REG_BISOC, val);
+       mutex_unlock(&dev_priv->dpio_lock);
+
+       /* Since we changed the CDclk, we need to update the GMBUSFREQ too */
+       intel_i2c_reset(dev);
+}
+
+static int valleyview_cur_cdclk(struct drm_i915_private *dev_priv)
+{
+       int cur_cdclk, vco;
+       int divider;
+
+       vco = valleyview_get_vco(dev_priv);
+
+       mutex_lock(&dev_priv->dpio_lock);
+       divider = vlv_cck_read(dev_priv, CCK_DISPLAY_CLOCK_CONTROL);
+       mutex_unlock(&dev_priv->dpio_lock);
+
+       divider &= 0xf;
+
+       cur_cdclk = (vco << 1) / (divider + 1);
+
+       return cur_cdclk;
+}
+
+static int valleyview_calc_cdclk(struct drm_i915_private *dev_priv,
+                                int max_pixclk)
+{
+       int cur_cdclk;
+
+       cur_cdclk = valleyview_cur_cdclk(dev_priv);
+
+       /*
+        * Really only a few cases to deal with, as only 4 CDclks are supported:
+        *   200MHz
+        *   267MHz
+        *   320MHz
+        *   400MHz
+        * So we check to see whether we're above 90% of the lower bin and
+        * adjust if needed.
+        */
+       if (max_pixclk > 288000) {
+               return 400;
+       } else if (max_pixclk > 240000) {
+               return 320;
+       } else
+               return 266;
+       /* Looks like the 200MHz CDclk freq doesn't work on some configs */
+}
+
+static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv,
+                                unsigned modeset_pipes,
+                                struct intel_crtc_config *pipe_config)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct intel_crtc *intel_crtc;
+       int max_pixclk = 0;
+
+       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
+                           base.head) {
+               if (modeset_pipes & (1 << intel_crtc->pipe))
+                       max_pixclk = max(max_pixclk,
+                                        pipe_config->adjusted_mode.crtc_clock);
+               else if (intel_crtc->base.enabled)
+                       max_pixclk = max(max_pixclk,
+                                        intel_crtc->config.adjusted_mode.crtc_clock);
+       }
+
+       return max_pixclk;
+}
+
+static void valleyview_modeset_global_pipes(struct drm_device *dev,
+                                           unsigned *prepare_pipes,
+                                           unsigned modeset_pipes,
+                                           struct intel_crtc_config *pipe_config)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_crtc *intel_crtc;
+       int max_pixclk = intel_mode_max_pixclk(dev_priv, modeset_pipes,
+                                              pipe_config);
+       int cur_cdclk = valleyview_cur_cdclk(dev_priv);
+
+       if (valleyview_calc_cdclk(dev_priv, max_pixclk) == cur_cdclk)
+               return;
+
+       list_for_each_entry(intel_crtc, &dev->mode_config.crtc_list,
+                           base.head)
+               if (intel_crtc->base.enabled)
+                       *prepare_pipes |= (1 << intel_crtc->pipe);
+}
+
+static void valleyview_modeset_global_resources(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int max_pixclk = intel_mode_max_pixclk(dev_priv, 0, NULL);
+       int cur_cdclk = valleyview_cur_cdclk(dev_priv);
+       int req_cdclk = valleyview_calc_cdclk(dev_priv, max_pixclk);
+
+       if (req_cdclk != cur_cdclk)
+               valleyview_set_cdclk(dev, req_cdclk);
+}
+
 static void valleyview_crtc_enable(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
@@ -4570,9 +4800,8 @@ static int i9xx_get_refclk(struct drm_crtc *crtc, int num_connectors)
                refclk = 100000;
        } else if (intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) &&
            intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
-               refclk = dev_priv->vbt.lvds_ssc_freq * 1000;
-               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
-                             refclk / 1000);
+               refclk = dev_priv->vbt.lvds_ssc_freq;
+               DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n", refclk);
        } else if (!IS_GEN2(dev)) {
                refclk = 96000;
        } else {
@@ -4634,24 +4863,24 @@ static void vlv_pllb_recal_opamp(struct drm_i915_private *dev_priv, enum pipe
         * PLLB opamp always calibrates to max value of 0x3f, force enable it
         * and set it to a reasonable value instead.
         */
-       reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF(1));
+       reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1));
        reg_val &= 0xffffff00;
        reg_val |= 0x00000030;
-       vlv_dpio_write(dev_priv, pipe, DPIO_IREF(1), reg_val);
+       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val);
 
-       reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_CALIBRATION);
+       reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13);
        reg_val &= 0x8cffffff;
        reg_val = 0x8c000000;
-       vlv_dpio_write(dev_priv, pipe, DPIO_CALIBRATION, reg_val);
+       vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val);
 
-       reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF(1));
+       reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW9(1));
        reg_val &= 0xffffff00;
-       vlv_dpio_write(dev_priv, pipe, DPIO_IREF(1), reg_val);
+       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9(1), reg_val);
 
-       reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_CALIBRATION);
+       reg_val = vlv_dpio_read(dev_priv, pipe, VLV_REF_DW13);
        reg_val &= 0x00ffffff;
        reg_val |= 0xb0000000;
-       vlv_dpio_write(dev_priv, pipe, DPIO_CALIBRATION, reg_val);
+       vlv_dpio_write(dev_priv, pipe, VLV_REF_DW13, reg_val);
 }
 
 static void intel_pch_transcoder_set_m_n(struct intel_crtc *crtc,
@@ -4720,15 +4949,15 @@ static void vlv_update_pll(struct intel_crtc *crtc)
                vlv_pllb_recal_opamp(dev_priv, pipe);
 
        /* Set up Tx target for periodic Rcomp update */
-       vlv_dpio_write(dev_priv, pipe, DPIO_IREF_BCAST, 0x0100000f);
+       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW9_BCAST, 0x0100000f);
 
        /* Disable target IRef on PLL */
-       reg_val = vlv_dpio_read(dev_priv, pipe, DPIO_IREF_CTL(pipe));
+       reg_val = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW8(pipe));
        reg_val &= 0x00ffffff;
-       vlv_dpio_write(dev_priv, pipe, DPIO_IREF_CTL(pipe), reg_val);
+       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW8(pipe), reg_val);
 
        /* Disable fast lock */
-       vlv_dpio_write(dev_priv, pipe, DPIO_FASTCLK_DISABLE, 0x610);
+       vlv_dpio_write(dev_priv, pipe, VLV_CMN_DW0, 0x610);
 
        /* Set idtafcrecal before PLL is enabled */
        mdiv = ((bestm1 << DPIO_M1DIV_SHIFT) | (bestm2 & DPIO_M2DIV_MASK));
@@ -4742,50 +4971,54 @@ static void vlv_update_pll(struct intel_crtc *crtc)
         * Note: don't use the DAC post divider as it seems unstable.
         */
        mdiv |= (DPIO_POST_DIV_HDMIDP << DPIO_POST_DIV_SHIFT);
-       vlv_dpio_write(dev_priv, pipe, DPIO_DIV(pipe), mdiv);
+       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv);
 
        mdiv |= DPIO_ENABLE_CALIBRATION;
-       vlv_dpio_write(dev_priv, pipe, DPIO_DIV(pipe), mdiv);
+       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW3(pipe), mdiv);
 
        /* Set HBR and RBR LPF coefficients */
        if (crtc->config.port_clock == 162000 ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_ANALOG) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_HDMI))
-               vlv_dpio_write(dev_priv, pipe, DPIO_LPF_COEFF(pipe),
+               vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
                                 0x009f0003);
        else
-               vlv_dpio_write(dev_priv, pipe, DPIO_LPF_COEFF(pipe),
+               vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
                                 0x00d0000f);
 
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT)) {
                /* Use SSC source */
                if (!pipe)
-                       vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe),
+                       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
                                         0x0df40000);
                else
-                       vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe),
+                       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
                                         0x0df70000);
        } else { /* HDMI or VGA */
                /* Use bend source */
                if (!pipe)
-                       vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe),
+                       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
                                         0x0df70000);
                else
-                       vlv_dpio_write(dev_priv, pipe, DPIO_REFSFR(pipe),
+                       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
                                         0x0df40000);
        }
 
-       coreclk = vlv_dpio_read(dev_priv, pipe, DPIO_CORE_CLK(pipe));
+       coreclk = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW7(pipe));
        coreclk = (coreclk & 0x0000ff00) | 0x01c00000;
        if (intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_DISPLAYPORT) ||
            intel_pipe_has_type(&crtc->base, INTEL_OUTPUT_EDP))
                coreclk |= 0x01000000;
-       vlv_dpio_write(dev_priv, pipe, DPIO_CORE_CLK(pipe), coreclk);
+       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW7(pipe), coreclk);
 
-       vlv_dpio_write(dev_priv, pipe, DPIO_PLL_CML(pipe), 0x87871000);
+       vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW11(pipe), 0x87871000);
 
-       /* Enable DPIO clock input */
+       /*
+        * Enable DPIO clock input. We should never disable the reference
+        * clock for pipe B, since VGA hotplug / manual detection depends
+        * on it.
+        */
        dpll = DPLL_EXT_BUFFER_ENABLE_VLV | DPLL_REFA_CLK_ENABLE_VLV |
                DPLL_VGA_MODE_DIS | DPLL_INTEGRATED_CLOCK_VLV;
        /* We should never disable this, set it here for state tracking */
@@ -5230,6 +5463,9 @@ static void i9xx_get_pfit_config(struct intel_crtc *crtc,
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t tmp;
 
+       if (INTEL_INFO(dev)->gen <= 3 && (IS_I830(dev) || !IS_MOBILE(dev)))
+               return;
+
        tmp = I915_READ(PFIT_CONTROL);
        if (!(tmp & PFIT_ENABLE))
                return;
@@ -5261,7 +5497,7 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc,
        int refclk = 100000;
 
        mutex_lock(&dev_priv->dpio_lock);
-       mdiv = vlv_dpio_read(dev_priv, pipe, DPIO_DIV(pipe));
+       mdiv = vlv_dpio_read(dev_priv, pipe, VLV_PLL_DW3(pipe));
        mutex_unlock(&dev_priv->dpio_lock);
 
        clock.m1 = (mdiv >> DPIO_M1DIV_SHIFT) & 7;
@@ -5718,9 +5954,9 @@ static int ironlake_get_refclk(struct drm_crtc *crtc)
        }
 
        if (is_lvds && intel_panel_use_ssc(dev_priv) && num_connectors < 2) {
-               DRM_DEBUG_KMS("using SSC reference clock of %d MHz\n",
+               DRM_DEBUG_KMS("using SSC reference clock of %d kHz\n",
                              dev_priv->vbt.lvds_ssc_freq);
-               return dev_priv->vbt.lvds_ssc_freq * 1000;
+               return dev_priv->vbt.lvds_ssc_freq;
        }
 
        return 120000;
@@ -5982,7 +6218,7 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
        factor = 21;
        if (is_lvds) {
                if ((intel_panel_use_ssc(dev_priv) &&
-                    dev_priv->vbt.lvds_ssc_freq == 100) ||
+                    dev_priv->vbt.lvds_ssc_freq == 100000) ||
                    (HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev)))
                        factor = 25;
        } else if (intel_crtc->config.sdvo_tv_clock)
@@ -6323,7 +6559,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
 
        spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
        val = I915_READ(DEIMR);
-       WARN((val & ~DE_PCH_EVENT_IVB) != val,
+       WARN((val | DE_PCH_EVENT_IVB) != 0xffffffff,
             "Unexpected DEIMR bits enabled: 0x%x\n", val);
        val = I915_READ(SDEIMR);
        WARN((val | SDE_HOTPLUG_MASK_CPT) != 0xffffffff,
@@ -6402,7 +6638,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
 
        /* Make sure we're not on PC8 state before disabling PC8, otherwise
         * we'll hang the machine! */
-       gen6_gt_force_wake_get(dev_priv);
+       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
        if (val & LCPLL_POWER_DOWN_ALLOW) {
                val &= ~LCPLL_POWER_DOWN_ALLOW;
@@ -6436,7 +6672,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
                        DRM_ERROR("Switching back to LCPLL failed\n");
        }
 
-       gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 void hsw_enable_pc8_work(struct work_struct *__work)
@@ -6447,6 +6683,8 @@ void hsw_enable_pc8_work(struct work_struct *__work)
        struct drm_device *dev = dev_priv->dev;
        uint32_t val;
 
+       WARN_ON(!HAS_PC8(dev));
+
        if (dev_priv->pc8.enabled)
                return;
 
@@ -6463,6 +6701,8 @@ void hsw_enable_pc8_work(struct work_struct *__work)
        lpt_disable_clkout_dp(dev);
        hsw_pc8_disable_interrupts(dev);
        hsw_disable_lcpll(dev_priv, true, true);
+
+       intel_runtime_pm_put(dev_priv);
 }
 
 static void __hsw_enable_package_c8(struct drm_i915_private *dev_priv)
@@ -6492,12 +6732,16 @@ static void __hsw_disable_package_c8(struct drm_i915_private *dev_priv)
        if (dev_priv->pc8.disable_count != 1)
                return;
 
+       WARN_ON(!HAS_PC8(dev));
+
        cancel_delayed_work_sync(&dev_priv->pc8.enable_work);
        if (!dev_priv->pc8.enabled)
                return;
 
        DRM_DEBUG_KMS("Disabling package C8+\n");
 
+       intel_runtime_pm_get(dev_priv);
+
        hsw_restore_lcpll(dev_priv);
        hsw_pc8_restore_interrupts(dev);
        lpt_init_pch_refclk(dev);
@@ -6704,8 +6948,9 @@ static int haswell_crtc_mode_set(struct drm_crtc *crtc,
        int plane = intel_crtc->plane;
        int ret;
 
-       if (!intel_ddi_pll_mode_set(crtc))
+       if (!intel_ddi_pll_select(intel_crtc))
                return -EINVAL;
+       intel_ddi_pll_enable(intel_crtc);
 
        if (intel_crtc->config.has_dp_encoder)
                intel_dp_set_m_n(intel_crtc);
@@ -6796,8 +7041,9 @@ static bool haswell_get_pipe_config(struct intel_crtc *crtc,
        if (intel_display_power_enabled(dev, pfit_domain))
                ironlake_get_pfit_config(crtc, pipe_config);
 
-       pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
-                                  (I915_READ(IPS_CTL) & IPS_ENABLE);
+       if (IS_HASWELL(dev))
+               pipe_config->ips_enabled = hsw_crtc_supports_ips(crtc) &&
+                       (I915_READ(IPS_CTL) & IPS_ENABLE);
 
        pipe_config->pixel_multiplier = 1;
 
@@ -7689,7 +7935,7 @@ static int i9xx_pll_refclk(struct drm_device *dev,
        u32 dpll = pipe_config->dpll_hw_state.dpll;
 
        if ((dpll & PLL_REF_INPUT_MASK) == PLLB_REF_INPUT_SPREADSPECTRUMIN)
-               return dev_priv->vbt.lvds_ssc_freq * 1000;
+               return dev_priv->vbt.lvds_ssc_freq;
        else if (HAS_PCH_SPLIT(dev))
                return 120000;
        else if (!IS_GEN2(dev))
@@ -7752,12 +7998,17 @@ static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
                else
                        i9xx_clock(refclk, &clock);
        } else {
-               bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
+               u32 lvds = IS_I830(dev) ? 0 : I915_READ(LVDS);
+               bool is_lvds = (pipe == 1) && (lvds & LVDS_PORT_EN);
 
                if (is_lvds) {
                        clock.p1 = ffs((dpll & DPLL_FPA01_P1_POST_DIV_MASK_I830_LVDS) >>
                                       DPLL_FPA01_P1_POST_DIV_SHIFT);
-                       clock.p2 = 14;
+
+                       if (lvds & LVDS_CLKB_POWER_UP)
+                               clock.p2 = 7;
+                       else
+                               clock.p2 = 14;
                } else {
                        if (dpll & PLL_P1_DIVIDE_BY_TWO)
                                clock.p1 = 2;
@@ -8493,28 +8744,6 @@ static struct drm_crtc_helper_funcs intel_helper_funcs = {
        .load_lut = intel_crtc_load_lut,
 };
 
-static bool intel_encoder_crtc_ok(struct drm_encoder *encoder,
-                                 struct drm_crtc *crtc)
-{
-       struct drm_device *dev;
-       struct drm_crtc *tmp;
-       int crtc_mask = 1;
-
-       WARN(!crtc, "checking null crtc?\n");
-
-       dev = crtc->dev;
-
-       list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
-               if (tmp == crtc)
-                       break;
-               crtc_mask <<= 1;
-       }
-
-       if (encoder->possible_crtcs & crtc_mask)
-               return true;
-       return false;
-}
-
 /**
  * intel_modeset_update_staged_output_state
  *
@@ -9122,7 +9351,9 @@ intel_pipe_config_compare(struct drm_device *dev,
                PIPE_CONF_CHECK_I(pch_pfit.size);
        }
 
-       PIPE_CONF_CHECK_I(ips_enabled);
+       /* BDW+ don't expose a synchronous way to read the state */
+       if (IS_HASWELL(dev))
+               PIPE_CONF_CHECK_I(ips_enabled);
 
        PIPE_CONF_CHECK_I(double_wide);
 
@@ -9368,21 +9599,19 @@ static int __intel_set_mode(struct drm_crtc *crtc,
 {
        struct drm_device *dev = crtc->dev;
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_display_mode *saved_mode, *saved_hwmode;
+       struct drm_display_mode *saved_mode;
        struct intel_crtc_config *pipe_config = NULL;
        struct intel_crtc *intel_crtc;
        unsigned disable_pipes, prepare_pipes, modeset_pipes;
        int ret = 0;
 
-       saved_mode = kcalloc(2, sizeof(*saved_mode), GFP_KERNEL);
+       saved_mode = kmalloc(sizeof(*saved_mode), GFP_KERNEL);
        if (!saved_mode)
                return -ENOMEM;
-       saved_hwmode = saved_mode + 1;
 
        intel_modeset_affected_pipes(crtc, &modeset_pipes,
                                     &prepare_pipes, &disable_pipes);
 
-       *saved_hwmode = crtc->hwmode;
        *saved_mode = crtc->mode;
 
        /* Hack: Because we don't (yet) support global modeset on multiple
@@ -9402,6 +9631,21 @@ static int __intel_set_mode(struct drm_crtc *crtc,
                                       "[modeset]");
        }
 
+       /*
+        * See if the config requires any additional preparation, e.g.
+        * to adjust global state with pipes off.  We need to do this
+        * here so we can get the modeset_pipe updated config for the new
+        * mode set on this crtc.  For other crtcs we need to use the
+        * adjusted_mode bits in the crtc directly.
+        */
+       if (IS_VALLEYVIEW(dev)) {
+               valleyview_modeset_global_pipes(dev, &prepare_pipes,
+                                               modeset_pipes, pipe_config);
+
+               /* may have added more to prepare_pipes than we should */
+               prepare_pipes &= ~disable_pipes;
+       }
+
        for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
                intel_crtc_disable(&intel_crtc->base);
 
@@ -9418,6 +9662,14 @@ static int __intel_set_mode(struct drm_crtc *crtc,
                /* mode_set/enable/disable functions rely on a correct pipe
                 * config. */
                to_intel_crtc(crtc)->config = *pipe_config;
+
+               /*
+                * Calculate and store various constants which
+                * are later needed by vblank and swap-completion
+                * timestamping. They are derived from true hwmode.
+                */
+               drm_calc_timestamping_constants(crtc,
+                                               &pipe_config->adjusted_mode);
        }
 
        /* Only after disabling all output pipelines that will be changed can we
@@ -9441,23 +9693,10 @@ static int __intel_set_mode(struct drm_crtc *crtc,
        for_each_intel_crtc_masked(dev, prepare_pipes, intel_crtc)
                dev_priv->display.crtc_enable(&intel_crtc->base);
 
-       if (modeset_pipes) {
-               /* Store real post-adjustment hardware mode. */
-               crtc->hwmode = pipe_config->adjusted_mode;
-
-               /* Calculate and store various constants which
-                * are later needed by vblank and swap-completion
-                * timestamping. They are derived from true hwmode.
-                */
-               drm_calc_timestamping_constants(crtc);
-       }
-
        /* FIXME: add subpixel order */
 done:
-       if (ret && crtc->enabled) {
-               crtc->hwmode = *saved_hwmode;
+       if (ret && crtc->enabled)
                crtc->mode = *saved_mode;
-       }
 
 out:
        kfree(pipe_config);
@@ -9679,8 +9918,8 @@ intel_modeset_stage_output_state(struct drm_device *dev,
                }
 
                /* Make sure the new CRTC will work with the encoder */
-               if (!intel_encoder_crtc_ok(&connector->new_encoder->base,
-                                          new_crtc)) {
+               if (!drm_encoder_crtc_ok(&connector->new_encoder->base,
+                                        new_crtc)) {
                        return -EINVAL;
                }
                connector->encoder->new_crtc = to_intel_crtc(new_crtc);
@@ -9694,17 +9933,21 @@ 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) {
+               int num_connectors = 0;
                list_for_each_entry(connector,
                                    &dev->mode_config.connector_list,
                                    base.head) {
                        if (connector->new_encoder == encoder) {
                                WARN_ON(!connector->new_encoder->new_crtc);
-
-                               goto next_encoder;
+                               num_connectors++;
                        }
                }
-               encoder->new_crtc = NULL;
-next_encoder:
+
+               if (num_connectors == 0)
+                       encoder->new_crtc = NULL;
+               else if (num_connectors > 1)
+                       return -EINVAL;
+
                /* Only now check for crtc changes so we don't miss encoders
                 * that will be disabled. */
                if (&encoder->new_crtc->base != encoder->base.crtc) {
@@ -9775,6 +10018,16 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
 
                ret = intel_pipe_set_base(set->crtc,
                                          set->x, set->y, set->fb);
+               /*
+                * In the fastboot case this may be our only check of the
+                * state after boot.  It would be better to only do it on
+                * the first update, but we don't have a nice way of doing that
+                * (and really, set_config isn't used much for high freq page
+                * flipping, so increasing its cost here shouldn't be a big
+                * deal).
+                */
+               if (i915_fastboot && ret == 0)
+                       intel_modeset_check_state(set->crtc->dev);
        }
 
        if (ret) {
@@ -9835,7 +10088,7 @@ static void ibx_pch_dpll_enable(struct drm_i915_private *dev_priv,
                                struct intel_shared_dpll *pll)
 {
        /* PCH refclock must be enabled first */
-       assert_pch_refclk_enabled(dev_priv);
+       ibx_assert_pch_refclk_enabled(dev_priv);
 
        I915_WRITE(PCH_DPLL(pll->id), pll->hw_state.dpll);
 
@@ -9903,8 +10156,6 @@ static void intel_shared_dpll_init(struct drm_device *dev)
                dev_priv->num_shared_dpll = 0;
 
        BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
-       DRM_DEBUG_KMS("%i shared PLLs initialized\n",
-                     dev_priv->num_shared_dpll);
 }
 
 static void intel_crtc_init(struct drm_device *dev, int pipe)
@@ -9926,10 +10177,13 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
                intel_crtc->lut_b[i] = i;
        }
 
-       /* Swap pipes & planes for FBC on pre-965 */
+       /*
+        * On gen2/3 only plane A can do fbc, but the panel fitter and lvds port
+        * is hooked to plane B. Hence we want plane A feeding pipe B.
+        */
        intel_crtc->pipe = pipe;
        intel_crtc->plane = pipe;
-       if (IS_MOBILE(dev) && IS_GEN3(dev)) {
+       if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4) {
                DRM_DEBUG_KMS("swapping pipes & planes for FBC\n");
                intel_crtc->plane = !pipe;
        }
@@ -10018,6 +10272,28 @@ static bool has_edp_a(struct drm_device *dev)
        return true;
 }
 
+const char *intel_output_name(int output)
+{
+       static const char *names[] = {
+               [INTEL_OUTPUT_UNUSED] = "Unused",
+               [INTEL_OUTPUT_ANALOG] = "Analog",
+               [INTEL_OUTPUT_DVO] = "DVO",
+               [INTEL_OUTPUT_SDVO] = "SDVO",
+               [INTEL_OUTPUT_LVDS] = "LVDS",
+               [INTEL_OUTPUT_TVOUT] = "TV",
+               [INTEL_OUTPUT_HDMI] = "HDMI",
+               [INTEL_OUTPUT_DISPLAYPORT] = "DisplayPort",
+               [INTEL_OUTPUT_EDP] = "eDP",
+               [INTEL_OUTPUT_DSI] = "DSI",
+               [INTEL_OUTPUT_UNKNOWN] = "Unknown",
+       };
+
+       if (output < 0 || output >= ARRAY_SIZE(names) || !names[output])
+               return "Invalid";
+
+       return names[output];
+}
+
 static void intel_setup_outputs(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -10412,8 +10688,11 @@ static void intel_init_display(struct drm_device *dev)
                }
        } else if (IS_G4X(dev)) {
                dev_priv->display.write_eld = g4x_write_eld;
-       } else if (IS_VALLEYVIEW(dev))
+       } else if (IS_VALLEYVIEW(dev)) {
+               dev_priv->display.modeset_global_resources =
+                       valleyview_modeset_global_resources;
                dev_priv->display.write_eld = ironlake_write_eld;
+       }
 
        /* Default just returns -ENODEV to indicate unsupported */
        dev_priv->display.queue_flip = intel_default_queue_flip;
@@ -10440,6 +10719,8 @@ static void intel_init_display(struct drm_device *dev)
                dev_priv->display.queue_flip = intel_gen7_queue_flip;
                break;
        }
+
+       intel_panel_init_backlight_funcs(dev);
 }
 
 /*
@@ -10476,17 +10757,6 @@ static void quirk_invert_brightness(struct drm_device *dev)
        DRM_INFO("applying inverted panel brightness quirk\n");
 }
 
-/*
- * Some machines (Dell XPS13) suffer broken backlight controls if
- * BLM_PCH_PWM_ENABLE is set.
- */
-static void quirk_no_pcm_pwm_enable(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       dev_priv->quirks |= QUIRK_NO_PCH_PWM_ENABLE;
-       DRM_INFO("applying no-PCH_PWM_ENABLE quirk\n");
-}
-
 struct intel_quirk {
        int device;
        int subsystem_vendor;
@@ -10555,11 +10825,6 @@ static struct intel_quirk intel_quirks[] = {
 
        /* Acer Aspire 4736Z */
        { 0x2a42, 0x1025, 0x0260, quirk_invert_brightness },
-
-       /* Dell XPS13 HD Sandy Bridge */
-       { 0x0116, 0x1028, 0x052e, quirk_no_pcm_pwm_enable },
-       /* Dell XPS13 HD and XPS13 FHD Ivy Bridge */
-       { 0x0166, 0x1028, 0x058b, quirk_no_pcm_pwm_enable },
 };
 
 static void intel_init_quirks(struct drm_device *dev)
@@ -10603,18 +10868,11 @@ static void i915_disable_vga(struct drm_device *dev)
 
 void intel_modeset_init_hw(struct drm_device *dev)
 {
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
        intel_prepare_ddi(dev);
 
        intel_init_clock_gating(dev);
 
-       /* Enable the CRI clock source so we can get at the display */
-       if (IS_VALLEYVIEW(dev))
-               I915_WRITE(DPLL(PIPE_B), I915_READ(DPLL(PIPE_B)) |
-                          DPLL_INTEGRATED_CRI_CLK_VLV);
-
-       intel_init_dpio(dev);
+       intel_reset_dpio(dev);
 
        mutex_lock(&dev->struct_mutex);
        intel_enable_gt_powersave(dev);
@@ -10676,6 +10934,9 @@ void intel_modeset_init(struct drm_device *dev)
                }
        }
 
+       intel_init_dpio(dev);
+       intel_reset_dpio(dev);
+
        intel_cpu_pll_init(dev);
        intel_shared_dpll_init(dev);
 
@@ -10879,7 +11140,7 @@ void i915_redisable_vga(struct drm_device *dev)
         * level, just check if the power well is enabled instead of trying to
         * follow the "don't touch the power well if we don't need it" policy
         * the rest of the driver uses. */
-       if (HAS_POWER_WELL(dev) &&
+       if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) &&
            (I915_READ(HSW_PWR_WELL_DRIVER) & HSW_PWR_WELL_STATE_ENABLED) == 0)
                return;
 
@@ -11023,7 +11284,7 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
                pll->on = false;
        }
 
-       if (IS_HASWELL(dev))
+       if (HAS_PCH_SPLIT(dev))
                ilk_wm_get_hw_state(dev);
 
        if (force_restore) {
@@ -11101,12 +11362,11 @@ void intel_modeset_cleanup(struct drm_device *dev)
        /* flush any delayed tasks or pending work */
        flush_scheduled_work();
 
-       /* destroy backlight, if any, before the connectors */
-       intel_panel_destroy_backlight(dev);
-
-       /* destroy the sysfs files before encoders/connectors */
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+       /* destroy the backlight and sysfs files before encoders/connectors */
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               intel_panel_destroy_backlight(connector);
                drm_sysfs_connector_remove(connector);
+       }
 
        drm_mode_config_cleanup(dev);
 
@@ -11161,6 +11421,7 @@ struct intel_display_error_state {
        } cursor[I915_MAX_PIPES];
 
        struct intel_pipe_error_state {
+               bool power_domain_on;
                u32 source;
        } pipe[I915_MAX_PIPES];
 
@@ -11175,6 +11436,7 @@ struct intel_display_error_state {
        } plane[I915_MAX_PIPES];
 
        struct intel_transcoder_error_state {
+               bool power_domain_on;
                enum transcoder cpu_transcoder;
 
                u32 conf;
@@ -11208,11 +11470,13 @@ intel_display_capture_error_state(struct drm_device *dev)
        if (error == NULL)
                return NULL;
 
-       if (HAS_POWER_WELL(dev))
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                error->power_well_driver = I915_READ(HSW_PWR_WELL_DRIVER);
 
        for_each_pipe(i) {
-               if (!intel_display_power_enabled(dev, POWER_DOMAIN_PIPE(i)))
+               error->pipe[i].power_domain_on =
+                       intel_display_power_enabled_sw(dev, POWER_DOMAIN_PIPE(i));
+               if (!error->pipe[i].power_domain_on)
                        continue;
 
                if (INTEL_INFO(dev)->gen <= 6 || IS_VALLEYVIEW(dev)) {
@@ -11248,8 +11512,10 @@ intel_display_capture_error_state(struct drm_device *dev)
        for (i = 0; i < error->num_transcoders; i++) {
                enum transcoder cpu_transcoder = transcoders[i];
 
-               if (!intel_display_power_enabled(dev,
-                               POWER_DOMAIN_TRANSCODER(cpu_transcoder)))
+               error->transcoder[i].power_domain_on =
+                       intel_display_power_enabled_sw(dev,
+                               POWER_DOMAIN_TRANSCODER(cpu_transcoder));
+               if (!error->transcoder[i].power_domain_on)
                        continue;
 
                error->transcoder[i].cpu_transcoder = cpu_transcoder;
@@ -11279,11 +11545,13 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
                return;
 
        err_printf(m, "Num Pipes: %d\n", INTEL_INFO(dev)->num_pipes);
-       if (HAS_POWER_WELL(dev))
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                err_printf(m, "PWR_WELL_CTL2: %08x\n",
                           error->power_well_driver);
        for_each_pipe(i) {
                err_printf(m, "Pipe [%d]:\n", i);
+               err_printf(m, "  Power: %s\n",
+                          error->pipe[i].power_domain_on ? "on" : "off");
                err_printf(m, "  SRC: %08x\n", error->pipe[i].source);
 
                err_printf(m, "Plane [%d]:\n", i);
@@ -11309,6 +11577,8 @@ intel_display_print_error_state(struct drm_i915_error_state_buf *m,
        for (i = 0; i < error->num_transcoders; i++) {
                err_printf(m, "CPU transcoder: %c\n",
                           transcoder_name(error->transcoder[i].cpu_transcoder));
+               err_printf(m, "  Power: %s\n",
+                          error->transcoder[i].power_domain_on ? "on" : "off");
                err_printf(m, "  CONF: %08x\n", error->transcoder[i].conf);
                err_printf(m, "  HTOTAL: %08x\n", error->transcoder[i].htotal);
                err_printf(m, "  HBLANK: %08x\n", error->transcoder[i].hblank);
index 30c627c7b7ba18a0dbd546859b047a769cad1d64..5ede4e8e290df5cc2f3e1b7046ec409b9f50d538 100644 (file)
@@ -142,7 +142,7 @@ intel_dp_max_data_rate(int max_link_clock, int max_lanes)
        return (max_link_clock * max_lanes * 8) / 10;
 }
 
-static int
+static enum drm_mode_status
 intel_dp_mode_valid(struct drm_connector *connector,
                    struct drm_display_mode *mode)
 {
@@ -404,7 +404,7 @@ intel_dp_aux_ch(struct intel_dp *intel_dp,
        int i, ret, recv_bytes;
        uint32_t status;
        int try, precharge, clock = 0;
-       bool has_aux_irq = INTEL_INFO(dev)->gen >= 5 && !IS_VALLEYVIEW(dev);
+       bool has_aux_irq = true;
        uint32_t timeout;
 
        /* dp aux is extremely sensitive to irq latency, hence request the
@@ -542,7 +542,7 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
                return -E2BIG;
 
        intel_dp_check_edp(intel_dp);
-       msg[0] = AUX_NATIVE_WRITE << 4;
+       msg[0] = DP_AUX_NATIVE_WRITE << 4;
        msg[1] = address >> 8;
        msg[2] = address & 0xff;
        msg[3] = send_bytes - 1;
@@ -552,9 +552,10 @@ intel_dp_aux_native_write(struct intel_dp *intel_dp,
                ret = intel_dp_aux_ch(intel_dp, msg, msg_bytes, &ack, 1);
                if (ret < 0)
                        return ret;
-               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+               ack >>= 4;
+               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
                        break;
-               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
                        udelay(100);
                else
                        return -EIO;
@@ -586,7 +587,7 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
                return -E2BIG;
 
        intel_dp_check_edp(intel_dp);
-       msg[0] = AUX_NATIVE_READ << 4;
+       msg[0] = DP_AUX_NATIVE_READ << 4;
        msg[1] = address >> 8;
        msg[2] = address & 0xff;
        msg[3] = recv_bytes - 1;
@@ -601,12 +602,12 @@ intel_dp_aux_native_read(struct intel_dp *intel_dp,
                        return -EPROTO;
                if (ret < 0)
                        return ret;
-               ack = reply[0];
-               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK) {
+               ack = reply[0] >> 4;
+               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK) {
                        memcpy(recv, reply + 1, ret - 1);
                        return ret - 1;
                }
-               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
+               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
                        udelay(100);
                else
                        return -EIO;
@@ -633,12 +634,12 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
        intel_dp_check_edp(intel_dp);
        /* Set up the command byte */
        if (mode & MODE_I2C_READ)
-               msg[0] = AUX_I2C_READ << 4;
+               msg[0] = DP_AUX_I2C_READ << 4;
        else
-               msg[0] = AUX_I2C_WRITE << 4;
+               msg[0] = DP_AUX_I2C_WRITE << 4;
 
        if (!(mode & MODE_I2C_STOP))
-               msg[0] |= AUX_I2C_MOT << 4;
+               msg[0] |= DP_AUX_I2C_MOT << 4;
 
        msg[1] = address >> 8;
        msg[2] = address;
@@ -675,17 +676,17 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                        goto out;
                }
 
-               switch (reply[0] & AUX_NATIVE_REPLY_MASK) {
-               case AUX_NATIVE_REPLY_ACK:
+               switch ((reply[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK) {
+               case DP_AUX_NATIVE_REPLY_ACK:
                        /* I2C-over-AUX Reply field is only valid
                         * when paired with AUX ACK.
                         */
                        break;
-               case AUX_NATIVE_REPLY_NACK:
+               case DP_AUX_NATIVE_REPLY_NACK:
                        DRM_DEBUG_KMS("aux_ch native nack\n");
                        ret = -EREMOTEIO;
                        goto out;
-               case AUX_NATIVE_REPLY_DEFER:
+               case DP_AUX_NATIVE_REPLY_DEFER:
                        /*
                         * For now, just give more slack to branch devices. We
                         * could check the DPCD for I2C bit rate capabilities,
@@ -706,18 +707,18 @@ intel_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                        goto out;
                }
 
-               switch (reply[0] & AUX_I2C_REPLY_MASK) {
-               case AUX_I2C_REPLY_ACK:
+               switch ((reply[0] >> 4) & DP_AUX_I2C_REPLY_MASK) {
+               case DP_AUX_I2C_REPLY_ACK:
                        if (mode == MODE_I2C_READ) {
                                *read_byte = reply[1];
                        }
                        ret = reply_bytes - 1;
                        goto out;
-               case AUX_I2C_REPLY_NACK:
+               case DP_AUX_I2C_REPLY_NACK:
                        DRM_DEBUG_KMS("aux_i2c nack\n");
                        ret = -EREMOTEIO;
                        goto out;
-               case AUX_I2C_REPLY_DEFER:
+               case DP_AUX_I2C_REPLY_DEFER:
                        DRM_DEBUG_KMS("aux_i2c defer\n");
                        udelay(100);
                        break;
@@ -1037,6 +1038,8 @@ static void ironlake_wait_panel_status(struct intel_dp *intel_dp,
                                I915_READ(pp_stat_reg),
                                I915_READ(pp_ctrl_reg));
        }
+
+       DRM_DEBUG_KMS("Wait complete\n");
 }
 
 static void ironlake_wait_panel_on(struct intel_dp *intel_dp)
@@ -1092,6 +1095,8 @@ void ironlake_edp_panel_vdd_on(struct intel_dp *intel_dp)
        if (ironlake_edp_have_panel_vdd(intel_dp))
                return;
 
+       intel_runtime_pm_get(dev_priv);
+
        DRM_DEBUG_KMS("Turning eDP VDD on\n");
 
        if (!ironlake_edp_have_panel_power(intel_dp))
@@ -1140,7 +1145,11 @@ static void ironlake_panel_vdd_off_sync(struct intel_dp *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));
-               msleep(intel_dp->panel_power_down_delay);
+
+               if ((pp & POWER_TARGET_ON) == 0)
+                       msleep(intel_dp->panel_power_cycle_delay);
+
+               intel_runtime_pm_put(dev_priv);
        }
 }
 
@@ -1233,20 +1242,16 @@ void ironlake_edp_panel_off(struct intel_dp *intel_dp)
 
        DRM_DEBUG_KMS("Turn eDP power off\n");
 
-       WARN(!intel_dp->want_panel_vdd, "Need VDD to turn off panel\n");
-
        pp = ironlake_get_pp_control(intel_dp);
        /* We need to switch off panel power _and_ force vdd, for otherwise some
         * panels get very unhappy and cease to work. */
-       pp &= ~(POWER_TARGET_ON | EDP_FORCE_VDD | PANEL_POWER_RESET | EDP_BLC_ENABLE);
+       pp &= ~(POWER_TARGET_ON | PANEL_POWER_RESET | EDP_BLC_ENABLE);
 
        pp_ctrl_reg = _pp_ctrl_reg(intel_dp);
 
        I915_WRITE(pp_ctrl_reg, pp);
        POSTING_READ(pp_ctrl_reg);
 
-       intel_dp->want_panel_vdd = false;
-
        ironlake_wait_panel_off(intel_dp);
 }
 
@@ -1772,7 +1777,6 @@ static void intel_disable_dp(struct intel_encoder *encoder)
 
        /* Make sure the panel is off before trying to change the mode. But also
         * ensure that we have vdd while we switch off the panel. */
-       ironlake_edp_panel_vdd_on(intel_dp);
        ironlake_edp_backlight_off(intel_dp);
        intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF);
        ironlake_edp_panel_off(intel_dp);
@@ -1845,23 +1849,23 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)
        struct drm_device *dev = encoder->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
-       int port = vlv_dport_to_channel(dport);
+       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);
 
-       val = vlv_dpio_read(dev_priv, pipe, DPIO_DATA_LANE_A(port));
+       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port));
        val = 0;
        if (pipe)
                val |= (1<<21);
        else
                val &= ~(1<<21);
        val |= 0x001000c4;
-       vlv_dpio_write(dev_priv, pipe, DPIO_DATA_CHANNEL(port), val);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF0(port), 0x00760018);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF8(port), 0x00400888);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888);
 
        mutex_unlock(&dev_priv->dpio_lock);
 
@@ -1872,7 +1876,7 @@ static void vlv_pre_enable_dp(struct intel_encoder *encoder)
 
        intel_enable_dp(encoder);
 
-       vlv_wait_port_ready(dev_priv, port);
+       vlv_wait_port_ready(dev_priv, dport);
 }
 
 static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder)
@@ -1882,24 +1886,24 @@ static void vlv_dp_pre_pll_enable(struct intel_encoder *encoder)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc =
                to_intel_crtc(encoder->base.crtc);
-       int port = vlv_dport_to_channel(dport);
+       enum dpio_channel port = vlv_dport_to_channel(dport);
        int pipe = intel_crtc->pipe;
 
        /* Program Tx lane resets to default */
        mutex_lock(&dev_priv->dpio_lock);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_TX(port),
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port),
                         DPIO_PCS_TX_LANE2_RESET |
                         DPIO_PCS_TX_LANE1_RESET);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLK(port),
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port),
                         DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
                         DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
                         (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
                                 DPIO_PCS_CLK_SOFT_RESET);
 
        /* Fix up inter-pair skew failure */
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER1(port), 0x00750f00);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_CTL(port), 0x00001500);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_LANE(port), 0x40400000);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000);
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
@@ -1941,18 +1945,6 @@ intel_dp_get_link_status(struct intel_dp *intel_dp, uint8_t link_status[DP_LINK_
                                              DP_LINK_STATUS_SIZE);
 }
 
-#if 0
-static char    *voltage_names[] = {
-       "0.4V", "0.6V", "0.8V", "1.2V"
-};
-static char    *pre_emph_names[] = {
-       "0dB", "3.5dB", "6dB", "9.5dB"
-};
-static char    *link_train_names[] = {
-       "pattern 1", "pattern 2", "idle", "off"
-};
-#endif
-
 /*
  * These are source-specific values; current Intel hardware supports
  * a maximum voltage of 800mV and a maximum pre-emphasis of 6dB
@@ -2050,7 +2042,7 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
        unsigned long demph_reg_value, preemph_reg_value,
                uniqtranscale_reg_value;
        uint8_t train_set = intel_dp->train_set[0];
-       int port = vlv_dport_to_channel(dport);
+       enum dpio_channel port = vlv_dport_to_channel(dport);
        int pipe = intel_crtc->pipe;
 
        switch (train_set & DP_TRAIN_PRE_EMPHASIS_MASK) {
@@ -2127,14 +2119,14 @@ static uint32_t intel_vlv_signal_levels(struct intel_dp *intel_dp)
        }
 
        mutex_lock(&dev_priv->dpio_lock);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), 0x00000000);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL4(port), demph_reg_value);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL2(port),
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x00000000);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), demph_reg_value);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port),
                         uniqtranscale_reg_value);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL3(port), 0x0C782040);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER0(port), 0x00030000);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CTL_OVER1(port), preemph_reg_value);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), 0x80000000);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0C782040);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), preemph_reg_value);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0x80000000);
        mutex_unlock(&dev_priv->dpio_lock);
 
        return 0;
@@ -2646,7 +2638,6 @@ intel_dp_complete_link_train(struct intel_dp *intel_dp)
 
                if (cr_tries > 5) {
                        DRM_ERROR("failed to train DP, aborting\n");
-                       intel_dp_link_down(intel_dp);
                        break;
                }
 
@@ -2899,13 +2890,11 @@ intel_dp_check_link_status(struct intel_dp *intel_dp)
 
        /* Try to read receiver status if the link appears to be up */
        if (!intel_dp_get_link_status(intel_dp, link_status)) {
-               intel_dp_link_down(intel_dp);
                return;
        }
 
        /* Now read the DPCD to see if it's actually running */
        if (!intel_dp_get_dpcd(intel_dp)) {
-               intel_dp_link_down(intel_dp);
                return;
        }
 
@@ -3020,18 +3009,34 @@ g4x_dp_detect(struct intel_dp *intel_dp)
                return status;
        }
 
-       switch (intel_dig_port->port) {
-       case PORT_B:
-               bit = PORTB_HOTPLUG_LIVE_STATUS;
-               break;
-       case PORT_C:
-               bit = PORTC_HOTPLUG_LIVE_STATUS;
-               break;
-       case PORT_D:
-               bit = PORTD_HOTPLUG_LIVE_STATUS;
-               break;
-       default:
-               return connector_status_unknown;
+       if (IS_VALLEYVIEW(dev)) {
+               switch (intel_dig_port->port) {
+               case PORT_B:
+                       bit = PORTB_HOTPLUG_LIVE_STATUS_VLV;
+                       break;
+               case PORT_C:
+                       bit = PORTC_HOTPLUG_LIVE_STATUS_VLV;
+                       break;
+               case PORT_D:
+                       bit = PORTD_HOTPLUG_LIVE_STATUS_VLV;
+                       break;
+               default:
+                       return connector_status_unknown;
+               }
+       } else {
+               switch (intel_dig_port->port) {
+               case PORT_B:
+                       bit = PORTB_HOTPLUG_LIVE_STATUS_G4X;
+                       break;
+               case PORT_C:
+                       bit = PORTC_HOTPLUG_LIVE_STATUS_G4X;
+                       break;
+               case PORT_D:
+                       bit = PORTD_HOTPLUG_LIVE_STATUS_G4X;
+                       break;
+               default:
+                       return connector_status_unknown;
+               }
        }
 
        if ((I915_READ(PORT_HOTPLUG_STAT) & bit) == 0)
@@ -3082,9 +3087,12 @@ 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;
        struct edid *edid = NULL;
 
+       intel_runtime_pm_get(dev_priv);
+
        DRM_DEBUG_KMS("[CONNECTOR:%d:%s]\n",
                      connector->base.id, drm_get_connector_name(connector));
 
@@ -3096,7 +3104,7 @@ intel_dp_detect(struct drm_connector *connector, bool force)
                status = g4x_dp_detect(intel_dp);
 
        if (status != connector_status_connected)
-               return status;
+               goto out;
 
        intel_dp_probe_oui(intel_dp);
 
@@ -3112,7 +3120,11 @@ intel_dp_detect(struct drm_connector *connector, bool force)
 
        if (intel_encoder->type != INTEL_OUTPUT_EDP)
                intel_encoder->type = INTEL_OUTPUT_DISPLAYPORT;
-       return connector_status_connected;
+       status = connector_status_connected;
+
+out:
+       intel_runtime_pm_put(dev_priv);
+       return status;
 }
 
 static int intel_dp_get_modes(struct drm_connector *connector)
index 79f91f26e288d4bf2ae7815cb82cfc3271745bd5..fbfaaba5cc3b2a079ae9749401d5602c6674cf07 100644 (file)
@@ -65,8 +65,8 @@
 #define wait_for_atomic_us(COND, US) _wait_for((COND), \
                                               DIV_ROUND_UP((US), 1000), 0)
 
-#define KHz(x) (1000*x)
-#define MHz(x) KHz(1000*x)
+#define KHz(x) (1000 * (x))
+#define MHz(x) KHz(1000 * (x))
 
 /*
  * Display related stuff
@@ -155,7 +155,19 @@ struct intel_encoder {
 
 struct intel_panel {
        struct drm_display_mode *fixed_mode;
+       struct drm_display_mode *downclock_mode;
        int fitting_mode;
+
+       /* backlight */
+       struct {
+               bool present;
+               u32 level;
+               u32 max;
+               bool enabled;
+               bool combination_mode;  /* gen 2/4 only */
+               bool active_low_pwm;
+               struct backlight_device *device;
+       } backlight;
 };
 
 struct intel_connector {
@@ -443,7 +455,7 @@ struct intel_hdmi {
        bool rgb_quant_range_selectable;
        void (*write_infoframe)(struct drm_encoder *encoder,
                                enum hdmi_infoframe_type type,
-                               const uint8_t *frame, ssize_t len);
+                               const void *frame, ssize_t len);
        void (*set_infoframes)(struct drm_encoder *encoder,
                               struct drm_display_mode *adjusted_mode);
 };
@@ -490,9 +502,9 @@ vlv_dport_to_channel(struct intel_digital_port *dport)
 {
        switch (dport->port) {
        case PORT_B:
-               return 0;
+               return DPIO_CH0;
        case PORT_C:
-               return 1;
+               return DPIO_CH1;
        default:
                BUG();
        }
@@ -601,7 +613,8 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
 void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc);
 void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc);
 void intel_ddi_setup_hw_pll_state(struct drm_device *dev);
-bool intel_ddi_pll_mode_set(struct drm_crtc *crtc);
+bool intel_ddi_pll_select(struct intel_crtc *crtc);
+void intel_ddi_pll_enable(struct intel_crtc *crtc);
 void intel_ddi_put_crtc_pll(struct drm_crtc *crtc);
 void intel_ddi_set_pipe_settings(struct drm_crtc *crtc);
 void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder);
@@ -612,6 +625,8 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
 
 
 /* intel_display.c */
+const char *intel_output_name(int output);
+bool intel_has_pending_fb_unpin(struct drm_device *dev);
 int intel_pch_rawclk(struct drm_device *dev);
 void intel_mark_busy(struct drm_device *dev);
 void intel_mark_fb_busy(struct drm_i915_gem_object *obj,
@@ -638,7 +653,8 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
 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, int port);
+void vlv_wait_port_ready(struct drm_i915_private *dev_priv,
+                        struct intel_digital_port *dport);
 bool intel_get_load_detect_pipe(struct drm_connector *connector,
                                struct drm_display_mode *mode,
                                struct intel_load_detect_pipe *old);
@@ -690,11 +706,10 @@ void
 ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
                                int dotclock);
 bool intel_crtc_active(struct drm_crtc *crtc);
-void i915_disable_vga_mem(struct drm_device *dev);
 void hsw_enable_ips(struct intel_crtc *crtc);
 void hsw_disable_ips(struct intel_crtc *crtc);
 void intel_display_set_init_power(struct drm_device *dev, bool enable);
-
+int valleyview_get_vco(struct drm_i915_private *dev_priv);
 
 /* intel_dp.c */
 void intel_dp_init(struct drm_device *dev, int output_reg, enum port port);
@@ -808,9 +823,13 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level,
 int intel_panel_setup_backlight(struct drm_connector *connector);
 void intel_panel_enable_backlight(struct intel_connector *connector);
 void intel_panel_disable_backlight(struct intel_connector *connector);
-void intel_panel_destroy_backlight(struct drm_device *dev);
+void intel_panel_destroy_backlight(struct drm_connector *connector);
+void intel_panel_init_backlight_funcs(struct drm_device *dev);
 enum drm_connector_status intel_panel_detect(struct drm_device *dev);
-
+extern struct drm_display_mode *intel_find_panel_downclock(
+                               struct drm_device *dev,
+                               struct drm_display_mode *fixed_mode,
+                               struct drm_connector *connector);
 
 /* intel_pm.c */
 void intel_init_clock_gating(struct drm_device *dev);
@@ -830,6 +849,8 @@ int intel_power_domains_init(struct drm_device *dev);
 void intel_power_domains_remove(struct drm_device *dev);
 bool intel_display_power_enabled(struct drm_device *dev,
                                 enum intel_display_power_domain domain);
+bool intel_display_power_enabled_sw(struct drm_device *dev,
+                                   enum intel_display_power_domain domain);
 void intel_display_power_get(struct drm_device *dev,
                             enum intel_display_power_domain domain);
 void intel_display_power_put(struct drm_device *dev,
@@ -844,6 +865,10 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv);
 void gen6_rps_boost(struct drm_i915_private *dev_priv);
 void intel_aux_display_runtime_get(struct drm_i915_private *dev_priv);
 void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv);
+void intel_runtime_pm_get(struct drm_i915_private *dev_priv);
+void intel_runtime_pm_put(struct drm_i915_private *dev_priv);
+void intel_init_runtime_pm(struct drm_i915_private *dev_priv);
+void intel_fini_runtime_pm(struct drm_i915_private *dev_priv);
 void ilk_wm_get_hw_state(struct drm_device *dev);
 
 
index d257b093ca68757874925999fae766a727755212..fabbf0d895cf2a5e133d804d5e8e05f0f26f79ad 100644 (file)
 static const struct intel_dsi_device intel_dsi_devices[] = {
 };
 
-
-static void vlv_cck_modify(struct drm_i915_private *dev_priv, u32 reg, u32 val,
-                          u32 mask)
-{
-       u32 tmp = vlv_cck_read(dev_priv, reg);
-       tmp &= ~mask;
-       tmp |= val;
-       vlv_cck_write(dev_priv, reg, tmp);
-}
-
-static void band_gap_wa(struct drm_i915_private *dev_priv)
+static void band_gap_reset(struct drm_i915_private *dev_priv)
 {
        mutex_lock(&dev_priv->dpio_lock);
 
-       /* Enable bandgap fix in GOP driver */
-       vlv_cck_modify(dev_priv, 0x6D, 0x00010000, 0x00030000);
-       msleep(20);
-       vlv_cck_modify(dev_priv, 0x6E, 0x00010000, 0x00030000);
-       msleep(20);
-       vlv_cck_modify(dev_priv, 0x6F, 0x00010000, 0x00030000);
-       msleep(20);
-       vlv_cck_modify(dev_priv, 0x00, 0x00008000, 0x00008000);
-       msleep(20);
-       vlv_cck_modify(dev_priv, 0x00, 0x00000000, 0x00008000);
-       msleep(20);
-
-       /* Turn Display Trunk on */
-       vlv_cck_modify(dev_priv, 0x6B, 0x00020000, 0x00030000);
-       msleep(20);
-
-       vlv_cck_modify(dev_priv, 0x6C, 0x00020000, 0x00030000);
-       msleep(20);
-
-       vlv_cck_modify(dev_priv, 0x6D, 0x00020000, 0x00030000);
-       msleep(20);
-       vlv_cck_modify(dev_priv, 0x6E, 0x00020000, 0x00030000);
-       msleep(20);
-       vlv_cck_modify(dev_priv, 0x6F, 0x00020000, 0x00030000);
+       vlv_flisdsi_write(dev_priv, 0x08, 0x0001);
+       vlv_flisdsi_write(dev_priv, 0x0F, 0x0005);
+       vlv_flisdsi_write(dev_priv, 0x0F, 0x0025);
+       udelay(150);
+       vlv_flisdsi_write(dev_priv, 0x0F, 0x0000);
+       vlv_flisdsi_write(dev_priv, 0x08, 0x0000);
 
        mutex_unlock(&dev_priv->dpio_lock);
-
-       /* Need huge delay, otherwise clock is not stable */
-       msleep(100);
 }
 
 static struct intel_dsi *intel_attached_dsi(struct drm_connector *connector)
@@ -132,14 +101,47 @@ static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder)
        vlv_enable_dsi_pll(encoder);
 }
 
+static void intel_dsi_device_ready(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);
+       int pipe = intel_crtc->pipe;
+       u32 val;
+
+       DRM_DEBUG_KMS("\n");
+
+       val = I915_READ(MIPI_PORT_CTRL(pipe));
+       I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD);
+       usleep_range(1000, 1500);
+       I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_EXIT);
+       usleep_range(2000, 2500);
+       I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY);
+       usleep_range(2000, 2500);
+       I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00);
+       usleep_range(2000, 2500);
+       I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY);
+       usleep_range(2000, 2500);
+}
 static void intel_dsi_pre_enable(struct intel_encoder *encoder)
 {
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
        DRM_DEBUG_KMS("\n");
+
+       if (intel_dsi->dev.dev_ops->panel_reset)
+               intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev);
+
+       /* put device in ready state */
+       intel_dsi_device_ready(encoder);
+
+       if (intel_dsi->dev.dev_ops->send_otp_cmds)
+               intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev);
 }
 
 static void intel_dsi_enable(struct intel_encoder *encoder)
 {
-       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
        int pipe = intel_crtc->pipe;
@@ -147,41 +149,28 @@ static void intel_dsi_enable(struct intel_encoder *encoder)
 
        DRM_DEBUG_KMS("\n");
 
-       temp = I915_READ(MIPI_DEVICE_READY(pipe));
-       if ((temp & DEVICE_READY) == 0) {
-               temp &= ~ULPS_STATE_MASK;
-               I915_WRITE(MIPI_DEVICE_READY(pipe), temp | DEVICE_READY);
-       } else if (temp & ULPS_STATE_MASK) {
-               temp &= ~ULPS_STATE_MASK;
-               I915_WRITE(MIPI_DEVICE_READY(pipe), temp | ULPS_STATE_EXIT);
-               /*
-                * We need to ensure that there is a minimum of 1 ms time
-                * available before clearing the UPLS exit state.
-                */
-               msleep(2);
-               I915_WRITE(MIPI_DEVICE_READY(pipe), temp);
-       }
-
        if (is_cmd_mode(intel_dsi))
                I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4);
-
-       if (is_vid_mode(intel_dsi)) {
+       else {
                msleep(20); /* XXX */
                dpi_send_cmd(intel_dsi, TURN_ON);
                msleep(100);
 
                /* assert ip_tg_enable signal */
-               temp = I915_READ(MIPI_PORT_CTRL(pipe));
+               temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK;
+               temp = temp | intel_dsi->port_bits;
                I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE);
                POSTING_READ(MIPI_PORT_CTRL(pipe));
        }
 
-       intel_dsi->dev.dev_ops->enable(&intel_dsi->dev);
+       if (intel_dsi->dev.dev_ops->enable)
+               intel_dsi->dev.dev_ops->enable(&intel_dsi->dev);
 }
 
 static void intel_dsi_disable(struct intel_encoder *encoder)
 {
-       struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+       struct drm_device *dev = encoder->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
        struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
        int pipe = intel_crtc->pipe;
@@ -189,8 +178,6 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
 
        DRM_DEBUG_KMS("\n");
 
-       intel_dsi->dev.dev_ops->disable(&intel_dsi->dev);
-
        if (is_vid_mode(intel_dsi)) {
                dpi_send_cmd(intel_dsi, SHUTDOWN);
                msleep(10);
@@ -203,20 +190,54 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
                msleep(2);
        }
 
-       temp = I915_READ(MIPI_DEVICE_READY(pipe));
-       if (temp & DEVICE_READY) {
-               temp &= ~DEVICE_READY;
-               temp &= ~ULPS_STATE_MASK;
-               I915_WRITE(MIPI_DEVICE_READY(pipe), temp);
-       }
+       /* if disable packets are sent before sending shutdown packet then in
+        * some next enable sequence send turn on packet error is observed */
+       if (intel_dsi->dev.dev_ops->disable)
+               intel_dsi->dev.dev_ops->disable(&intel_dsi->dev);
 }
 
-static void intel_dsi_post_disable(struct intel_encoder *encoder)
+static void intel_dsi_clear_device_ready(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);
+       int pipe = intel_crtc->pipe;
+       u32 val;
+
        DRM_DEBUG_KMS("\n");
 
+       I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER);
+       usleep_range(2000, 2500);
+
+       I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_EXIT);
+       usleep_range(2000, 2500);
+
+       I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER);
+       usleep_range(2000, 2500);
+
+       val = I915_READ(MIPI_PORT_CTRL(pipe));
+       I915_WRITE(MIPI_PORT_CTRL(pipe), val & ~LP_OUTPUT_HOLD);
+       usleep_range(1000, 1500);
+
+       if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT)
+                                       == 0x00000), 30))
+               DRM_ERROR("DSI LP not going Low\n");
+
+       I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00);
+       usleep_range(2000, 2500);
+
        vlv_disable_dsi_pll(encoder);
 }
+static void intel_dsi_post_disable(struct intel_encoder *encoder)
+{
+       struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+
+       DRM_DEBUG_KMS("\n");
+
+       intel_dsi_clear_device_ready(encoder);
+
+       if (intel_dsi->dev.dev_ops->disable_panel_power)
+               intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev);
+}
 
 static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
                                   enum pipe *pipe)
@@ -251,8 +272,9 @@ static void intel_dsi_get_config(struct intel_encoder *encoder,
        /* XXX: read flags, set to adjusted_mode */
 }
 
-static int intel_dsi_mode_valid(struct drm_connector *connector,
-                               struct drm_display_mode *mode)
+static enum drm_mode_status
+intel_dsi_mode_valid(struct drm_connector *connector,
+                    struct drm_display_mode *mode)
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
        struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
@@ -352,11 +374,8 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder)
 
        DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
 
-       /* Update the DSI PLL */
-       vlv_enable_dsi_pll(intel_encoder);
-
        /* XXX: Location of the call */
-       band_gap_wa(dev_priv);
+       band_gap_reset(dev_priv);
 
        /* escape clock divider, 20MHz, shared for A and C. device ready must be
         * off when doing this! txclkesc? */
@@ -373,11 +392,7 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder)
        I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff);
        I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff);
 
-       I915_WRITE(MIPI_DPHY_PARAM(pipe),
-                  0x3c << EXIT_ZERO_COUNT_SHIFT |
-                  0x1f << TRAIL_COUNT_SHIFT |
-                  0xc5 << CLK_ZERO_COUNT_SHIFT |
-                  0x1f << PREPARE_COUNT_SHIFT);
+       I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg);
 
        I915_WRITE(MIPI_DPI_RESOLUTION(pipe),
                   adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT |
@@ -425,9 +440,9 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder)
                                       adjusted_mode->htotal,
                                       bpp, intel_dsi->lane_count) + 1);
        }
-       I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), 8309); /* max */
-       I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), 0x14); /* max */
-       I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), 0xffff); /* max */
+       I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout);
+       I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val);
+       I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), intel_dsi->rst_timer_val);
 
        /* dphy stuff */
 
@@ -442,29 +457,31 @@ static void intel_dsi_mode_set(struct intel_encoder *intel_encoder)
         *
         * XXX: write MIPI_STOP_STATE_STALL?
         */
-       I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe), 0x46);
+       I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe),
+                                               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
         * and txclkesc. txclkesc time / txbyteclk time * (105 +
         * MIPI_STOP_STATE_STALL) / 105.???
         */
-       I915_WRITE(MIPI_LP_BYTECLK(pipe), 4);
+       I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk);
 
        /* the bw essential for transmitting 16 long packets containing 252
         * bytes meant for dcs write memory command is programmed in this
         * register in terms of byte clocks. based on dsi transfer rate and the
         * number of lanes configured the time taken to transmit 16 long packets
         * in a dsi stream varies. */
-       I915_WRITE(MIPI_DBI_BW_CTRL(pipe), 0x820);
+       I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer);
 
        I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe),
-                  0xa << LP_HS_SSW_CNT_SHIFT |
-                  0x14 << HS_LP_PWR_SW_CNT_SHIFT);
+                  intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
+                  intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
 
        if (is_vid_mode(intel_dsi))
                I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe),
-                          intel_dsi->video_mode_format);
+                               intel_dsi->video_frmt_cfg_bits |
+                               intel_dsi->video_mode_format);
 }
 
 static enum drm_connector_status
index c7765f33d5245fa2ff1fd03fe2bb12339a716473..b4a27cec882f76d7cab17400d8adf438532b4c9d 100644 (file)
@@ -39,6 +39,13 @@ struct intel_dsi_device {
 struct intel_dsi_dev_ops {
        bool (*init)(struct intel_dsi_device *dsi);
 
+       void (*panel_reset)(struct intel_dsi_device *dsi);
+
+       void (*disable_panel_power)(struct intel_dsi_device *dsi);
+
+       /* one time programmable commands if needed */
+       void (*send_otp_cmds)(struct intel_dsi_device *dsi);
+
        /* This callback must be able to assume DSI commands can be sent */
        void (*enable)(struct intel_dsi_device *dsi);
 
@@ -89,6 +96,20 @@ struct intel_dsi {
 
        /* eot for MIPI_EOT_DISABLE register */
        u32 eot_disable;
+
+       u32 port_bits;
+       u32 bw_timer;
+       u32 dphy_reg;
+       u32 video_frmt_cfg_bits;
+       u16 lp_byte_clk;
+
+       /* timeouts in byte clocks */
+       u16 lp_rx_timeout;
+       u16 turn_arnd_val;
+       u16 rst_timer_val;
+       u16 hs_to_lp_count;
+       u16 clk_lp_to_hs_count;
+       u16 clk_hs_to_lp_count;
 };
 
 static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
index 44279b2ade888a7821d75da44ab523ab8f1f318a..ba79ec19da3b8ce8d4379df2545c1ea54c3a8f3e 100644 (file)
@@ -50,6 +50,8 @@ static const u32 lfsr_converts[] = {
        71, 35                                                  /* 91 - 92 */
 };
 
+#ifdef DSI_CLK_FROM_RR
+
 static u32 dsi_rr_formula(const struct drm_display_mode *mode,
                          int pixel_format, int video_mode_format,
                          int lane_count, bool eotp)
@@ -121,7 +123,7 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode,
 
        /* the dsi clock is divided by 2 in the hardware to get dsi ddr clock */
        dsi_bit_clock_hz = bytes_per_x_frames_x_lanes * 8;
-       dsi_clk = dsi_bit_clock_hz / (1000 * 1000);
+       dsi_clk = dsi_bit_clock_hz / 1000;
 
        if (eotp && video_mode_format == VIDEO_MODE_BURST)
                dsi_clk *= 2;
@@ -129,64 +131,37 @@ static u32 dsi_rr_formula(const struct drm_display_mode *mode,
        return dsi_clk;
 }
 
-#ifdef MNP_FROM_TABLE
-
-struct dsi_clock_table {
-       u32 freq;
-       u8 m;
-       u8 p;
-};
-
-static const struct dsi_clock_table dsi_clk_tbl[] = {
-       {300, 72, 6}, {313, 75, 6}, {323, 78, 6}, {333, 80, 6},
-       {343, 82, 6}, {353, 85, 6}, {363, 87, 6}, {373, 90, 6},
-       {383, 92, 6}, {390, 78, 5}, {393, 79, 5}, {400, 80, 5},
-       {401, 80, 5}, {402, 80, 5}, {403, 81, 5}, {404, 81, 5},
-       {405, 81, 5}, {406, 81, 5}, {407, 81, 5}, {408, 82, 5},
-       {409, 82, 5}, {410, 82, 5}, {411, 82, 5}, {412, 82, 5},
-       {413, 83, 5}, {414, 83, 5}, {415, 83, 5}, {416, 83, 5},
-       {417, 83, 5}, {418, 84, 5}, {419, 84, 5}, {420, 84, 5},
-       {430, 86, 5}, {440, 88, 5}, {450, 90, 5}, {460, 92, 5},
-       {470, 75, 4}, {480, 77, 4}, {490, 78, 4}, {500, 80, 4},
-       {510, 82, 4}, {520, 83, 4}, {530, 85, 4}, {540, 86, 4},
-       {550, 88, 4}, {560, 90, 4}, {570, 91, 4}, {580, 70, 3},
-       {590, 71, 3}, {600, 72, 3}, {610, 73, 3}, {620, 74, 3},
-       {630, 76, 3}, {640, 77, 3}, {650, 78, 3}, {660, 79, 3},
-       {670, 80, 3}, {680, 82, 3}, {690, 83, 3}, {700, 84, 3},
-       {710, 85, 3}, {720, 86, 3}, {730, 88, 3}, {740, 89, 3},
-       {750, 90, 3}, {760, 91, 3}, {770, 92, 3}, {780, 62, 2},
-       {790, 63, 2}, {800, 64, 2}, {880, 70, 2}, {900, 72, 2},
-       {1000, 80, 2},          /* dsi clock frequency in Mhz*/
-};
+#else
 
-static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp)
+/* Get DSI clock from pixel clock */
+static u32 dsi_clk_from_pclk(const struct drm_display_mode *mode,
+                         int pixel_format, int lane_count)
 {
-       unsigned int i;
-       u8 m;
-       u8 n;
-       u8 p;
-       u32 m_seed;
-
-       if (dsi_clk < 300 || dsi_clk > 1000)
-               return -ECHRNG;
+       u32 dsi_clk_khz;
+       u32 bpp;
 
-       for (i = 0; i <= ARRAY_SIZE(dsi_clk_tbl); i++) {
-               if (dsi_clk_tbl[i].freq > dsi_clk)
-                       break;
+       switch (pixel_format) {
+       default:
+       case VID_MODE_FORMAT_RGB888:
+       case VID_MODE_FORMAT_RGB666_LOOSE:
+               bpp = 24;
+               break;
+       case VID_MODE_FORMAT_RGB666:
+               bpp = 18;
+               break;
+       case VID_MODE_FORMAT_RGB565:
+               bpp = 16;
+               break;
        }
 
-       m = dsi_clk_tbl[i].m;
-       p = dsi_clk_tbl[i].p;
-       m_seed = lfsr_converts[m - 62];
-       n = 1;
-       dsi_mnp->dsi_pll_ctrl = 1 << (DSI_PLL_P1_POST_DIV_SHIFT + p - 2);
-       dsi_mnp->dsi_pll_div = (n - 1) << DSI_PLL_N1_DIV_SHIFT |
-               m_seed << DSI_PLL_M1_DIV_SHIFT;
+       /* 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);
 
-       return 0;
+       return dsi_clk_khz;
 }
 
-#else
+#endif
 
 static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp)
 {
@@ -194,36 +169,47 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp)
        u32 ref_clk;
        u32 error;
        u32 tmp_error;
-       u32 target_dsi_clk;
-       u32 calc_dsi_clk;
+       int target_dsi_clk;
+       int calc_dsi_clk;
        u32 calc_m;
        u32 calc_p;
        u32 m_seed;
 
-       if (dsi_clk < 300 || dsi_clk > 1150) {
+       /* dsi_clk is expected in KHZ */
+       if (dsi_clk < 300000 || dsi_clk > 1150000) {
                DRM_ERROR("DSI CLK Out of Range\n");
                return -ECHRNG;
        }
 
        ref_clk = 25000;
-       target_dsi_clk = dsi_clk * 1000;
+       target_dsi_clk = dsi_clk;
        error = 0xFFFFFFFF;
+       tmp_error = 0xFFFFFFFF;
        calc_m = 0;
        calc_p = 0;
 
        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 */
                        calc_dsi_clk = (m * ref_clk) / p;
-                       if (calc_dsi_clk >= target_dsi_clk) {
-                               tmp_error = calc_dsi_clk - target_dsi_clk;
-                               if (tmp_error < error) {
-                                       error = tmp_error;
-                                       calc_m = m;
-                                       calc_p = p;
-                               }
+                       if (calc_dsi_clk == target_dsi_clk) {
+                               calc_m = m;
+                               calc_p = p;
+                               error = 0;
+                               break;
+                       } else
+                               tmp_error = abs(target_dsi_clk - calc_dsi_clk);
+
+                       if (tmp_error < error) {
+                               error = tmp_error;
+                               calc_m = m;
+                               calc_p = p;
                        }
                }
+
+               if (error == 0)
+                       break;
        }
 
        m_seed = lfsr_converts[calc_m - 62];
@@ -235,8 +221,6 @@ static int dsi_calc_mnp(u32 dsi_clk, struct dsi_mnp *dsi_mnp)
        return 0;
 }
 
-#endif
-
 /*
  * XXX: The muxing and gating is hard coded for now. Need to add support for
  * sharing PLLs with two DSI outputs.
@@ -251,9 +235,8 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder)
        struct dsi_mnp dsi_mnp;
        u32 dsi_clk;
 
-       dsi_clk = dsi_rr_formula(mode, intel_dsi->pixel_format,
-                                intel_dsi->video_mode_format,
-                                intel_dsi->lane_count, !intel_dsi->eot_disable);
+       dsi_clk = dsi_clk_from_pclk(mode, intel_dsi->pixel_format,
+                                               intel_dsi->lane_count);
 
        ret = dsi_calc_mnp(dsi_clk, &dsi_mnp);
        if (ret) {
index 3c77365468562ab026910a1e111fb932b288f242..eeff998e52efdea93534ffb680582503f9f2a56c 100644 (file)
@@ -234,8 +234,9 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
        intel_modeset_check_state(connector->dev);
 }
 
-static int intel_dvo_mode_valid(struct drm_connector *connector,
-                               struct drm_display_mode *mode)
+static enum drm_mode_status
+intel_dvo_mode_valid(struct drm_connector *connector,
+                    struct drm_display_mode *mode)
 {
        struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
 
index 895fcb4fbd9446bfbfafc90f95948d9a4bea5c55..39eac9937a4aa1a89c176ef77d727cfb615b8cd1 100644 (file)
@@ -57,18 +57,14 @@ static struct fb_ops intelfb_ops = {
        .fb_debug_leave = drm_fb_helper_debug_leave,
 };
 
-static int intelfb_create(struct drm_fb_helper *helper,
-                         struct drm_fb_helper_surface_size *sizes)
+static int intelfb_alloc(struct drm_fb_helper *helper,
+                        struct drm_fb_helper_surface_size *sizes)
 {
        struct intel_fbdev *ifbdev =
                container_of(helper, struct intel_fbdev, helper);
        struct drm_device *dev = helper->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct fb_info *info;
-       struct drm_framebuffer *fb;
        struct drm_mode_fb_cmd2 mode_cmd = {};
        struct drm_i915_gem_object *obj;
-       struct device *device = &dev->pdev->dev;
        int size, ret;
 
        /* we don't do packed 24bpp */
@@ -94,8 +90,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
                goto out;
        }
 
-       mutex_lock(&dev->struct_mutex);
-
        /* Flush everything out, we'll be doing GTT only from now on */
        ret = intel_pin_and_fence_fb_obj(dev, obj, NULL);
        if (ret) {
@@ -103,7 +97,50 @@ static int intelfb_create(struct drm_fb_helper *helper,
                goto out_unref;
        }
 
-       info = framebuffer_alloc(0, device);
+       ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
+       if (ret)
+               goto out_unpin;
+
+       return 0;
+
+out_unpin:
+       i915_gem_object_unpin(obj);
+out_unref:
+       drm_gem_object_unreference(&obj->base);
+out:
+       return ret;
+}
+
+static int intelfb_create(struct drm_fb_helper *helper,
+                         struct drm_fb_helper_surface_size *sizes)
+{
+       struct intel_fbdev *ifbdev =
+               container_of(helper, struct intel_fbdev, helper);
+       struct intel_framebuffer *intel_fb = &ifbdev->ifb;
+       struct drm_device *dev = helper->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct fb_info *info;
+       struct drm_framebuffer *fb;
+       struct drm_i915_gem_object *obj;
+       int size, ret;
+
+       mutex_lock(&dev->struct_mutex);
+
+       if (!intel_fb->obj) {
+               DRM_DEBUG_KMS("no BIOS fb, allocating a new one\n");
+               ret = intelfb_alloc(helper, sizes);
+               if (ret)
+                       goto out_unlock;
+       } else {
+               DRM_DEBUG_KMS("re-using BIOS fb\n");
+               sizes->fb_width = intel_fb->base.width;
+               sizes->fb_height = intel_fb->base.height;
+       }
+
+       obj = intel_fb->obj;
+       size = obj->base.size;
+
+       info = framebuffer_alloc(0, &dev->pdev->dev);
        if (!info) {
                ret = -ENOMEM;
                goto out_unpin;
@@ -111,10 +148,6 @@ static int intelfb_create(struct drm_fb_helper *helper,
 
        info->par = helper;
 
-       ret = intel_framebuffer_init(dev, &ifbdev->ifb, &mode_cmd, obj);
-       if (ret)
-               goto out_unpin;
-
        fb = &ifbdev->ifb.base;
 
        ifbdev->helper.fb = fb;
@@ -170,17 +203,15 @@ static int intelfb_create(struct drm_fb_helper *helper,
                      fb->width, fb->height,
                      i915_gem_obj_ggtt_offset(obj), obj);
 
-
        mutex_unlock(&dev->struct_mutex);
        vga_switcheroo_client_fb_set(dev->pdev, info);
        return 0;
 
 out_unpin:
        i915_gem_object_unpin(obj);
-out_unref:
        drm_gem_object_unreference(&obj->base);
+out_unlock:
        mutex_unlock(&dev->struct_mutex);
-out:
        return ret;
 }
 
@@ -297,8 +328,6 @@ void intel_fbdev_set_suspend(struct drm_device *dev, int state)
        fb_set_suspend(info, state);
 }
 
-MODULE_LICENSE("GPL and additional rights");
-
 void intel_fbdev_output_poll_changed(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
index 03f9ca70530c03f441ae037b16cf0c5e80b908ab..6db0d9d17f47e7b5ce5c43a7aa7795de71ea6346 100644 (file)
@@ -130,9 +130,9 @@ static u32 hsw_infoframe_data_reg(enum hdmi_infoframe_type type,
 
 static void g4x_write_infoframe(struct drm_encoder *encoder,
                                enum hdmi_infoframe_type type,
-                               const uint8_t *frame, ssize_t len)
+                               const void *frame, ssize_t len)
 {
-       uint32_t *data = (uint32_t *)frame;
+       const uint32_t *data = frame;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val = I915_READ(VIDEO_DIP_CTL);
@@ -167,9 +167,9 @@ static void g4x_write_infoframe(struct drm_encoder *encoder,
 
 static void ibx_write_infoframe(struct drm_encoder *encoder,
                                enum hdmi_infoframe_type type,
-                               const uint8_t *frame, ssize_t len)
+                               const void *frame, ssize_t len)
 {
-       uint32_t *data = (uint32_t *)frame;
+       const uint32_t *data = frame;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
@@ -205,9 +205,9 @@ static void ibx_write_infoframe(struct drm_encoder *encoder,
 
 static void cpt_write_infoframe(struct drm_encoder *encoder,
                                enum hdmi_infoframe_type type,
-                               const uint8_t *frame, ssize_t len)
+                               const void *frame, ssize_t len)
 {
-       uint32_t *data = (uint32_t *)frame;
+       const uint32_t *data = frame;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
@@ -246,9 +246,9 @@ static void cpt_write_infoframe(struct drm_encoder *encoder,
 
 static void vlv_write_infoframe(struct drm_encoder *encoder,
                                enum hdmi_infoframe_type type,
-                               const uint8_t *frame, ssize_t len)
+                               const void *frame, ssize_t len)
 {
-       uint32_t *data = (uint32_t *)frame;
+       const uint32_t *data = frame;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
@@ -284,9 +284,9 @@ static void vlv_write_infoframe(struct drm_encoder *encoder,
 
 static void hsw_write_infoframe(struct drm_encoder *encoder,
                                enum hdmi_infoframe_type type,
-                               const uint8_t *frame, ssize_t len)
+                               const void *frame, ssize_t len)
 {
-       uint32_t *data = (uint32_t *)frame;
+       const uint32_t *data = frame;
        struct drm_device *dev = encoder->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
@@ -853,8 +853,9 @@ static int hdmi_portclock_limit(struct intel_hdmi *hdmi)
                return 225000;
 }
 
-static int intel_hdmi_mode_valid(struct drm_connector *connector,
-                                struct drm_display_mode *mode)
+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)))
                return MODE_CLOCK_HIGH;
@@ -1081,7 +1082,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc =
                to_intel_crtc(encoder->base.crtc);
-       int port = vlv_dport_to_channel(dport);
+       enum dpio_channel port = vlv_dport_to_channel(dport);
        int pipe = intel_crtc->pipe;
        u32 val;
 
@@ -1090,41 +1091,33 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
 
        /* Enable clock channels for this port */
        mutex_lock(&dev_priv->dpio_lock);
-       val = vlv_dpio_read(dev_priv, pipe, DPIO_DATA_LANE_A(port));
+       val = vlv_dpio_read(dev_priv, pipe, VLV_PCS01_DW8(port));
        val = 0;
        if (pipe)
                val |= (1<<21);
        else
                val &= ~(1<<21);
        val |= 0x001000c4;
-       vlv_dpio_write(dev_priv, pipe, DPIO_DATA_CHANNEL(port), val);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW8(port), val);
 
        /* HDMI 1.0V-2dB */
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port), 0);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL4(port),
-                        0x2b245f5f);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL2(port),
-                        0x5578b83a);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_SWING_CTL3(port),
-                        0x0c782040);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX3_SWING_CTL4(port),
-                        0x2b247878);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER0(port), 0x00030000);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CTL_OVER1(port),
-                        0x00002000);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port),
-                        DPIO_TX_OCALINIT_EN);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), 0);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW4(port), 0x2b245f5f);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW2(port), 0x5578b83a);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW3(port), 0x0c782040);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX3_DW4(port), 0x2b247878);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW11(port), 0x00030000);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN);
 
        /* Program lane clock */
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF0(port),
-                        0x00760018);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLOCKBUF8(port),
-                        0x00400888);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW14(port), 0x00760018);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW23(port), 0x00400888);
        mutex_unlock(&dev_priv->dpio_lock);
 
        intel_enable_hdmi(encoder);
 
-       vlv_wait_port_ready(dev_priv, port);
+       vlv_wait_port_ready(dev_priv, dport);
 }
 
 static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
@@ -1134,7 +1127,7 @@ static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_crtc *intel_crtc =
                to_intel_crtc(encoder->base.crtc);
-       int port = vlv_dport_to_channel(dport);
+       enum dpio_channel port = vlv_dport_to_channel(dport);
        int pipe = intel_crtc->pipe;
 
        if (!IS_VALLEYVIEW(dev))
@@ -1142,24 +1135,22 @@ static void vlv_hdmi_pre_pll_enable(struct intel_encoder *encoder)
 
        /* Program Tx lane resets to default */
        mutex_lock(&dev_priv->dpio_lock);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_TX(port),
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port),
                         DPIO_PCS_TX_LANE2_RESET |
                         DPIO_PCS_TX_LANE1_RESET);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLK(port),
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port),
                         DPIO_PCS_CLK_CRI_RXEB_EIOS_EN |
                         DPIO_PCS_CLK_CRI_RXDIGFILTSG_EN |
                         (1<<DPIO_PCS_CLK_DATAWIDTH_SHIFT) |
                         DPIO_PCS_CLK_SOFT_RESET);
 
        /* Fix up inter-pair skew failure */
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_STAGGER1(port), 0x00750f00);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_CTL(port), 0x00001500);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_LANE(port), 0x40400000);
-
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CTL_OVER1(port),
-                        0x00002000);
-       vlv_dpio_write(dev_priv, pipe, DPIO_TX_OCALINIT(port),
-                        DPIO_TX_OCALINIT_EN);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW12(port), 0x00750f00);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW11(port), 0x00001500);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW14(port), 0x40400000);
+
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW9(port), 0x00002000);
+       vlv_dpio_write(dev_priv, pipe, VLV_TX_DW5(port), DPIO_TX_OCALINIT_EN);
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
@@ -1169,13 +1160,13 @@ static void vlv_hdmi_post_disable(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);
-       int port = vlv_dport_to_channel(dport);
+       enum dpio_channel port = vlv_dport_to_channel(dport);
        int pipe = intel_crtc->pipe;
 
        /* Reset lanes to avoid HDMI flicker (VLV w/a) */
        mutex_lock(&dev_priv->dpio_lock);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_TX(port), 0x00000000);
-       vlv_dpio_write(dev_priv, pipe, DPIO_PCS_CLK(port), 0x00e00060);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW0(port), 0x00000000);
+       vlv_dpio_write(dev_priv, pipe, VLV_PCS_DW1(port), 0x00e00060);
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
index 2ca17b14b6c1c91710601dfcb34c661b45707347..b1dc33f478991755ec114fe66fbad7bc40fec4c0 100644 (file)
@@ -82,20 +82,11 @@ static int get_disp_clk_div(struct drm_i915_private *dev_priv,
 
 static void gmbus_set_freq(struct drm_i915_private *dev_priv)
 {
-       int vco_freq[] = { 800, 1600, 2000, 2400 };
-       int gmbus_freq = 0, cdclk_div, hpll_freq;
+       int vco, gmbus_freq = 0, cdclk_div;
 
        BUG_ON(!IS_VALLEYVIEW(dev_priv->dev));
 
-       /* Skip setting the gmbus freq if BIOS has already programmed it */
-       if (I915_READ(GMBUSFREQ_VLV) != 0xA0)
-               return;
-
-       /* Obtain SKU information */
-       mutex_lock(&dev_priv->dpio_lock);
-       hpll_freq =
-               vlv_cck_read(dev_priv, CCK_FUSE_REG) & CCK_FUSE_HPLL_FREQ_MASK;
-       mutex_unlock(&dev_priv->dpio_lock);
+       vco = valleyview_get_vco(dev_priv);
 
        /* Get the CDCLK divide ratio */
        cdclk_div = get_disp_clk_div(dev_priv, CDCLK);
@@ -106,7 +97,7 @@ static void gmbus_set_freq(struct drm_i915_private *dev_priv)
         * in fact 1MHz is the correct frequency.
         */
        if (cdclk_div)
-               gmbus_freq = (vco_freq[hpll_freq] << 1) / cdclk_div;
+               gmbus_freq = (vco << 1) / cdclk_div;
 
        if (WARN_ON(gmbus_freq == 0))
                return;
index c3b4da7895ed1c82b185b78ca06d00053cff2402..8bcb93a2a9f6b1d09780c3154f6c656895451e8e 100644 (file)
@@ -256,8 +256,9 @@ static void intel_disable_lvds(struct intel_encoder *encoder)
        POSTING_READ(lvds_encoder->reg);
 }
 
-static int intel_lvds_mode_valid(struct drm_connector *connector,
-                                struct drm_display_mode *mode)
+static enum drm_mode_status
+intel_lvds_mode_valid(struct drm_connector *connector,
+                     struct drm_display_mode *mode)
 {
        struct intel_connector *intel_connector = to_intel_connector(connector);
        struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
@@ -446,9 +447,19 @@ static int intel_lid_notify(struct notifier_block *nb, unsigned long val,
        if (dev_priv->modeset_restore == MODESET_DONE)
                goto exit;
 
-       drm_modeset_lock_all(dev);
-       intel_modeset_setup_hw_state(dev, true);
-       drm_modeset_unlock_all(dev);
+       /*
+        * Some old platform's BIOS love to wreak havoc while the lid is closed.
+        * We try to detect this here and undo any damage. The split for PCH
+        * platforms is rather conservative and a bit arbitrary expect that on
+        * those platforms VGA disabling requires actual legacy VGA I/O access,
+        * and as part of the cleanup in the hw state restore we also redisable
+        * the vga plane.
+        */
+       if (!HAS_PCH_SPLIT(dev)) {
+               drm_modeset_lock_all(dev);
+               intel_modeset_setup_hw_state(dev, true);
+               drm_modeset_unlock_all(dev);
+       }
 
        dev_priv->modeset_restore = MODESET_DONE;
 
@@ -744,57 +755,6 @@ static const struct dmi_system_id intel_no_lvds[] = {
        { }     /* terminating entry */
 };
 
-/**
- * intel_find_lvds_downclock - find the reduced downclock for LVDS in EDID
- * @dev: drm device
- * @connector: LVDS connector
- *
- * Find the reduced downclock for LVDS in EDID.
- */
-static void intel_find_lvds_downclock(struct drm_device *dev,
-                                     struct drm_display_mode *fixed_mode,
-                                     struct drm_connector *connector)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_display_mode *scan;
-       int temp_downclock;
-
-       temp_downclock = fixed_mode->clock;
-       list_for_each_entry(scan, &connector->probed_modes, head) {
-               /*
-                * If one mode has the same resolution with the fixed_panel
-                * mode while they have the different refresh rate, it means
-                * that the reduced downclock is found for the LVDS. In such
-                * case we can set the different FPx0/1 to dynamically select
-                * between low and high frequency.
-                */
-               if (scan->hdisplay == fixed_mode->hdisplay &&
-                   scan->hsync_start == fixed_mode->hsync_start &&
-                   scan->hsync_end == fixed_mode->hsync_end &&
-                   scan->htotal == fixed_mode->htotal &&
-                   scan->vdisplay == fixed_mode->vdisplay &&
-                   scan->vsync_start == fixed_mode->vsync_start &&
-                   scan->vsync_end == fixed_mode->vsync_end &&
-                   scan->vtotal == fixed_mode->vtotal) {
-                       if (scan->clock < temp_downclock) {
-                               /*
-                                * The downclock is already found. But we
-                                * expect to find the lower downclock.
-                                */
-                               temp_downclock = scan->clock;
-                       }
-               }
-       }
-       if (temp_downclock < fixed_mode->clock && i915_lvds_downclock) {
-               /* We found the downclock for LVDS. */
-               dev_priv->lvds_downclock_avail = 1;
-               dev_priv->lvds_downclock = temp_downclock;
-               DRM_DEBUG_KMS("LVDS downclock is found in EDID. "
-                             "Normal clock %dKhz, downclock %dKhz\n",
-                             fixed_mode->clock, temp_downclock);
-       }
-}
-
 /*
  * Enumerate the child dev array parsed from VBT to check whether
  * the LVDS is present.
@@ -1072,8 +1032,22 @@ void intel_lvds_init(struct drm_device *dev)
 
                        fixed_mode = drm_mode_duplicate(dev, scan);
                        if (fixed_mode) {
-                               intel_find_lvds_downclock(dev, fixed_mode,
-                                                         connector);
+                               intel_connector->panel.downclock_mode =
+                                       intel_find_panel_downclock(dev,
+                                       fixed_mode, connector);
+                               if (intel_connector->panel.downclock_mode !=
+                                       NULL && i915_lvds_downclock) {
+                                       /* We found the downclock for LVDS. */
+                                       dev_priv->lvds_downclock_avail = true;
+                                       dev_priv->lvds_downclock =
+                                               intel_connector->panel.
+                                               downclock_mode->clock;
+                                       DRM_DEBUG_KMS("LVDS downclock is found"
+                                       " in EDID. Normal clock %dKhz, "
+                                       "downclock %dKhz\n",
+                                       fixed_mode->clock,
+                                       dev_priv->lvds_downclock);
+                               }
                                goto out;
                        }
                }
index 9a8804bee5cdfd08276592672d35d83e564fc9ef..4e960ec7419fb6802398b9b118b3b3a513199350 100644 (file)
@@ -63,7 +63,7 @@ struct opregion_header {
        u8 driver_ver[16];
        u32 mboxes;
        u8 reserved[164];
-} __attribute__((packed));
+} __packed;
 
 /* OpRegion mailbox #1: public ACPI methods */
 struct opregion_acpi {
@@ -85,7 +85,7 @@ struct opregion_acpi {
        u32 cnot;       /* current OS notification */
        u32 nrdy;       /* driver status */
        u8 rsvd2[60];
-} __attribute__((packed));
+} __packed;
 
 /* OpRegion mailbox #2: SWSCI */
 struct opregion_swsci {
@@ -93,7 +93,7 @@ struct opregion_swsci {
        u32 parm;       /* command parameters */
        u32 dslp;       /* driver sleep time-out */
        u8 rsvd[244];
-} __attribute__((packed));
+} __packed;
 
 /* OpRegion mailbox #3: ASLE */
 struct opregion_asle {
@@ -114,7 +114,7 @@ struct opregion_asle {
        u32 srot;       /* supported rotation angles */
        u32 iuer;       /* IUER events */
        u8 rsvd[86];
-} __attribute__((packed));
+} __packed;
 
 /* Driver readiness indicator */
 #define ASLE_ARDY_READY                (1 << 0)
@@ -395,13 +395,8 @@ int intel_opregion_notify_adapter(struct drm_device *dev, pci_power_t state)
 static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct drm_encoder *encoder;
-       struct drm_connector *connector;
-       struct intel_connector *intel_connector = NULL;
-       struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[0];
+       struct intel_connector *intel_connector;
        struct opregion_asle __iomem *asle = dev_priv->opregion.asle;
-       u32 ret = 0;
-       bool found = false;
 
        DRM_DEBUG_DRIVER("bclp = 0x%08x\n", bclp);
 
@@ -413,38 +408,20 @@ static u32 asle_set_backlight(struct drm_device *dev, u32 bclp)
                return ASLC_BACKLIGHT_FAILED;
 
        mutex_lock(&dev->mode_config.mutex);
+
        /*
-        * Could match the OpRegion connector here instead, but we'd also need
-        * to verify the connector could handle a backlight call.
+        * Update backlight on all connectors that support backlight (usually
+        * only one).
         */
-       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
-               if (encoder->crtc == crtc) {
-                       found = true;
-                       break;
-               }
-
-       if (!found) {
-               ret = ASLC_BACKLIGHT_FAILED;
-               goto out;
-       }
-
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
-               if (connector->encoder == encoder)
-                       intel_connector = to_intel_connector(connector);
-
-       if (!intel_connector) {
-               ret = ASLC_BACKLIGHT_FAILED;
-               goto out;
-       }
-
        DRM_DEBUG_KMS("updating opregion backlight %d/255\n", bclp);
-       intel_panel_set_backlight(intel_connector, bclp, 255);
+       list_for_each_entry(intel_connector, &dev->mode_config.connector_list, base.head)
+               intel_panel_set_backlight(intel_connector, bclp, 255);
        iowrite32(DIV_ROUND_UP(bclp * 100, 255) | ASLE_CBLV_VALID, &asle->cblv);
 
-out:
        mutex_unlock(&dev->mode_config.mutex);
 
-       return ret;
+
+       return 0;
 }
 
 static u32 asle_set_als_illum(struct drm_device *dev, u32 alsi)
index a98a990fbab3561368239ce7a7ac020c1d44f0c7..a759ecdb7a6ebaddee622ffd5a1d7900fcf5aee3 100644 (file)
@@ -1005,7 +1005,7 @@ static int intel_panel_fitter_pipe(struct drm_device *dev)
        u32  pfit_control;
 
        /* i830 doesn't have a panel fitter */
-       if (IS_I830(dev))
+       if (INTEL_INFO(dev)->gen <= 3 && (IS_I830(dev) || !IS_MOBILE(dev)))
                return -1;
 
        pfit_control = I915_READ(PFIT_CONTROL);
index e6f782d1c6696d94fe4d4a80cf7f4d6ee6b5c7d7..350de359123af9cbd42354c182424f356281aa16 100644 (file)
@@ -325,214 +325,170 @@ out:
        pipe_config->gmch_pfit.lvds_border_bits = border;
 }
 
-static int is_backlight_combination_mode(struct drm_device *dev)
+static int i915_panel_invert_brightness;
+MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
+       "(-1 force normal, 0 machine defaults, 1 force inversion), please "
+       "report PCI device ID, subsystem vendor and subsystem device ID "
+       "to dri-devel@lists.freedesktop.org, if your machine needs it. "
+       "It will then be included in an upcoming module version.");
+module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
+static u32 intel_panel_compute_brightness(struct intel_connector *connector,
+                                         u32 val)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
 
-       if (IS_GEN4(dev))
-               return I915_READ(BLC_PWM_CTL2) & BLM_COMBINATION_MODE;
+       WARN_ON(panel->backlight.max == 0);
 
-       if (IS_GEN2(dev))
-               return I915_READ(BLC_PWM_CTL) & BLM_LEGACY_MODE;
+       if (i915_panel_invert_brightness < 0)
+               return val;
 
-       return 0;
+       if (i915_panel_invert_brightness > 0 ||
+           dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
+               return panel->backlight.max - val;
+       }
+
+       return val;
 }
 
-/* XXX: query mode clock or hardware clock and program max PWM appropriately
- * when it's 0.
- */
-static u32 i915_read_blc_pwm_ctl(struct drm_device *dev, enum pipe pipe)
+static u32 bdw_get_backlight(struct intel_connector *connector)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 val;
 
-       WARN_ON_SMP(!spin_is_locked(&dev_priv->backlight.lock));
-
-       /* Restore the CTL value if it lost, e.g. GPU reset */
-
-       if (HAS_PCH_SPLIT(dev_priv->dev)) {
-               val = I915_READ(BLC_PWM_PCH_CTL2);
-               if (dev_priv->regfile.saveBLC_PWM_CTL2 == 0) {
-                       dev_priv->regfile.saveBLC_PWM_CTL2 = val;
-               } else if (val == 0) {
-                       val = dev_priv->regfile.saveBLC_PWM_CTL2;
-                       I915_WRITE(BLC_PWM_PCH_CTL2, val);
-               }
-       } else if (IS_VALLEYVIEW(dev)) {
-               val = I915_READ(VLV_BLC_PWM_CTL(pipe));
-               if (dev_priv->regfile.saveBLC_PWM_CTL == 0) {
-                       dev_priv->regfile.saveBLC_PWM_CTL = val;
-                       dev_priv->regfile.saveBLC_PWM_CTL2 =
-                               I915_READ(VLV_BLC_PWM_CTL2(pipe));
-               } else if (val == 0) {
-                       val = dev_priv->regfile.saveBLC_PWM_CTL;
-                       I915_WRITE(VLV_BLC_PWM_CTL(pipe), val);
-                       I915_WRITE(VLV_BLC_PWM_CTL2(pipe),
-                                  dev_priv->regfile.saveBLC_PWM_CTL2);
-               }
+       return I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
+}
 
-               if (!val)
-                       val = 0x0f42ffff;
-       } else {
-               val = I915_READ(BLC_PWM_CTL);
-               if (dev_priv->regfile.saveBLC_PWM_CTL == 0) {
-                       dev_priv->regfile.saveBLC_PWM_CTL = val;
-                       if (INTEL_INFO(dev)->gen >= 4)
-                               dev_priv->regfile.saveBLC_PWM_CTL2 =
-                                       I915_READ(BLC_PWM_CTL2);
-               } else if (val == 0) {
-                       val = dev_priv->regfile.saveBLC_PWM_CTL;
-                       I915_WRITE(BLC_PWM_CTL, val);
-                       if (INTEL_INFO(dev)->gen >= 4)
-                               I915_WRITE(BLC_PWM_CTL2,
-                                          dev_priv->regfile.saveBLC_PWM_CTL2);
-               }
-       }
+static u32 pch_get_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
 
-       return val;
+       return I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
 }
 
-static u32 intel_panel_get_max_backlight(struct drm_device *dev,
-                                        enum pipe pipe)
+static u32 i9xx_get_backlight(struct intel_connector *connector)
 {
-       u32 max;
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       u32 val;
 
-       max = i915_read_blc_pwm_ctl(dev, pipe);
+       val = I915_READ(BLC_PWM_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
+       if (INTEL_INFO(dev)->gen < 4)
+               val >>= 1;
 
-       if (HAS_PCH_SPLIT(dev)) {
-               max >>= 16;
-       } else {
-               if (INTEL_INFO(dev)->gen < 4)
-                       max >>= 17;
-               else
-                       max >>= 16;
+       if (panel->backlight.combination_mode) {
+               u8 lbpc;
 
-               if (is_backlight_combination_mode(dev))
-                       max *= 0xff;
+               pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
+               val *= lbpc;
        }
 
-       DRM_DEBUG_DRIVER("max backlight PWM = %d\n", max);
-
-       return max;
+       return val;
 }
 
-static int i915_panel_invert_brightness;
-MODULE_PARM_DESC(invert_brightness, "Invert backlight brightness "
-       "(-1 force normal, 0 machine defaults, 1 force inversion), please "
-       "report PCI device ID, subsystem vendor and subsystem device ID "
-       "to dri-devel@lists.freedesktop.org, if your machine needs it. "
-       "It will then be included in an upcoming module version.");
-module_param_named(invert_brightness, i915_panel_invert_brightness, int, 0600);
-static u32 intel_panel_compute_brightness(struct drm_device *dev,
-                                         enum pipe pipe, u32 val)
+static u32 _vlv_get_backlight(struct drm_device *dev, enum pipe pipe)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (i915_panel_invert_brightness < 0)
-               return val;
+       return I915_READ(VLV_BLC_PWM_CTL(pipe)) & BACKLIGHT_DUTY_CYCLE_MASK;
+}
 
-       if (i915_panel_invert_brightness > 0 ||
-           dev_priv->quirks & QUIRK_INVERT_BRIGHTNESS) {
-               u32 max = intel_panel_get_max_backlight(dev, pipe);
-               if (max)
-                       return max - val;
-       }
+static u32 vlv_get_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       enum pipe pipe = intel_get_pipe_from_connector(connector);
 
-       return val;
+       return _vlv_get_backlight(dev, pipe);
 }
 
-static u32 intel_panel_get_backlight(struct drm_device *dev,
-                                    enum pipe pipe)
+static u32 intel_panel_get_backlight(struct intel_connector *connector)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val;
        unsigned long flags;
-       int reg;
-
-       spin_lock_irqsave(&dev_priv->backlight.lock, flags);
-
-       if (IS_BROADWELL(dev)) {
-               val = I915_READ(BLC_PWM_PCH_CTL2) & BACKLIGHT_DUTY_CYCLE_MASK;
-       } else if (HAS_PCH_SPLIT(dev)) {
-               val = I915_READ(BLC_PWM_CPU_CTL) & BACKLIGHT_DUTY_CYCLE_MASK;
-       } else {
-               if (IS_VALLEYVIEW(dev))
-                       reg = VLV_BLC_PWM_CTL(pipe);
-               else
-                       reg = BLC_PWM_CTL;
-
-               val = I915_READ(reg) & BACKLIGHT_DUTY_CYCLE_MASK;
-               if (INTEL_INFO(dev)->gen < 4)
-                       val >>= 1;
-
-               if (is_backlight_combination_mode(dev)) {
-                       u8 lbpc;
 
-                       pci_read_config_byte(dev->pdev, PCI_LBPC, &lbpc);
-                       val *= lbpc;
-               }
-       }
+       spin_lock_irqsave(&dev_priv->backlight_lock, flags);
 
-       val = intel_panel_compute_brightness(dev, pipe, val);
+       val = dev_priv->display.get_backlight(connector);
+       val = intel_panel_compute_brightness(connector, val);
 
-       spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
+       spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
 
        DRM_DEBUG_DRIVER("get backlight PWM = %d\n", val);
        return val;
 }
 
-static void intel_bdw_panel_set_backlight(struct drm_device *dev, u32 level)
+static void bdw_set_backlight(struct intel_connector *connector, u32 level)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 val = I915_READ(BLC_PWM_PCH_CTL2) & ~BACKLIGHT_DUTY_CYCLE_MASK;
        I915_WRITE(BLC_PWM_PCH_CTL2, val | level);
 }
 
-static void intel_pch_panel_set_backlight(struct drm_device *dev, u32 level)
+static void pch_set_backlight(struct intel_connector *connector, u32 level)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 val = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
-       I915_WRITE(BLC_PWM_CPU_CTL, val | level);
+       u32 tmp;
+
+       tmp = I915_READ(BLC_PWM_CPU_CTL) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(BLC_PWM_CPU_CTL, tmp | level);
 }
 
-static void intel_panel_actually_set_backlight(struct drm_device *dev,
-                                              enum pipe pipe, u32 level)
+static void i9xx_set_backlight(struct intel_connector *connector, u32 level)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 tmp;
-       int reg;
-
-       DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
-       level = intel_panel_compute_brightness(dev, pipe, level);
+       struct intel_panel *panel = &connector->panel;
+       u32 tmp, mask;
 
-       if (IS_BROADWELL(dev))
-               return intel_bdw_panel_set_backlight(dev, level);
-       else if (HAS_PCH_SPLIT(dev))
-               return intel_pch_panel_set_backlight(dev, level);
+       WARN_ON(panel->backlight.max == 0);
 
-       if (is_backlight_combination_mode(dev)) {
-               u32 max = intel_panel_get_max_backlight(dev, pipe);
+       if (panel->backlight.combination_mode) {
                u8 lbpc;
 
-               /* we're screwed, but keep behaviour backwards compatible */
-               if (!max)
-                       max = 1;
-
-               lbpc = level * 0xfe / max + 1;
+               lbpc = level * 0xfe / panel->backlight.max + 1;
                level /= lbpc;
                pci_write_config_byte(dev->pdev, PCI_LBPC, lbpc);
        }
 
-       if (IS_VALLEYVIEW(dev))
-               reg = VLV_BLC_PWM_CTL(pipe);
-       else
-               reg = BLC_PWM_CTL;
-
-       tmp = I915_READ(reg);
-       if (INTEL_INFO(dev)->gen < 4)
+       if (IS_GEN4(dev)) {
+               mask = BACKLIGHT_DUTY_CYCLE_MASK;
+       } else {
                level <<= 1;
-       tmp &= ~BACKLIGHT_DUTY_CYCLE_MASK;
-       I915_WRITE(reg, tmp | level);
+               mask = BACKLIGHT_DUTY_CYCLE_MASK_PNV;
+       }
+
+       tmp = I915_READ(BLC_PWM_CTL) & ~mask;
+       I915_WRITE(BLC_PWM_CTL, tmp | level);
+}
+
+static void vlv_set_backlight(struct intel_connector *connector, u32 level)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe = intel_get_pipe_from_connector(connector);
+       u32 tmp;
+
+       tmp = I915_READ(VLV_BLC_PWM_CTL(pipe)) & ~BACKLIGHT_DUTY_CYCLE_MASK;
+       I915_WRITE(VLV_BLC_PWM_CTL(pipe), tmp | level);
+}
+
+static void
+intel_panel_actually_set_backlight(struct intel_connector *connector, u32 level)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       DRM_DEBUG_DRIVER("set backlight PWM = %d\n", level);
+
+       level = intel_panel_compute_brightness(connector, level);
+       dev_priv->display.set_backlight(connector, level);
 }
 
 /* set backlight brightness to level in range [0..max] */
@@ -541,45 +497,89 @@ void intel_panel_set_backlight(struct intel_connector *connector, u32 level,
 {
        struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
        enum pipe pipe = intel_get_pipe_from_connector(connector);
        u32 freq;
        unsigned long flags;
 
-       if (pipe == INVALID_PIPE)
+       if (!panel->backlight.present || pipe == INVALID_PIPE)
                return;
 
-       spin_lock_irqsave(&dev_priv->backlight.lock, flags);
+       spin_lock_irqsave(&dev_priv->backlight_lock, flags);
 
-       freq = intel_panel_get_max_backlight(dev, pipe);
-       if (!freq) {
-               /* we are screwed, bail out */
-               goto out;
-       }
+       WARN_ON(panel->backlight.max == 0);
 
-       /* scale to hardware, but be careful to not overflow */
+       /* scale to hardware max, but be careful to not overflow */
+       freq = panel->backlight.max;
        if (freq < max)
                level = level * freq / max;
        else
                level = freq / max * level;
 
-       dev_priv->backlight.level = level;
-       if (dev_priv->backlight.device)
-               dev_priv->backlight.device->props.brightness = level;
+       panel->backlight.level = level;
+       if (panel->backlight.device)
+               panel->backlight.device->props.brightness = level;
 
-       if (dev_priv->backlight.enabled)
-               intel_panel_actually_set_backlight(dev, pipe, level);
-out:
-       spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
+       if (panel->backlight.enabled)
+               intel_panel_actually_set_backlight(connector, level);
+
+       spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
+}
+
+static void pch_disable_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
+
+       intel_panel_actually_set_backlight(connector, 0);
+
+       tmp = I915_READ(BLC_PWM_CPU_CTL2);
+       I915_WRITE(BLC_PWM_CPU_CTL2, tmp & ~BLM_PWM_ENABLE);
+
+       tmp = I915_READ(BLC_PWM_PCH_CTL1);
+       I915_WRITE(BLC_PWM_PCH_CTL1, tmp & ~BLM_PCH_PWM_ENABLE);
+}
+
+static void i9xx_disable_backlight(struct intel_connector *connector)
+{
+       intel_panel_actually_set_backlight(connector, 0);
+}
+
+static void i965_disable_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       u32 tmp;
+
+       intel_panel_actually_set_backlight(connector, 0);
+
+       tmp = I915_READ(BLC_PWM_CTL2);
+       I915_WRITE(BLC_PWM_CTL2, tmp & ~BLM_PWM_ENABLE);
+}
+
+static void vlv_disable_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       enum pipe pipe = intel_get_pipe_from_connector(connector);
+       u32 tmp;
+
+       intel_panel_actually_set_backlight(connector, 0);
+
+       tmp = I915_READ(VLV_BLC_PWM_CTL2(pipe));
+       I915_WRITE(VLV_BLC_PWM_CTL2(pipe), tmp & ~BLM_PWM_ENABLE);
 }
 
 void intel_panel_disable_backlight(struct intel_connector *connector)
 {
        struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
        enum pipe pipe = intel_get_pipe_from_connector(connector);
        unsigned long flags;
 
-       if (pipe == INVALID_PIPE)
+       if (!panel->backlight.present || pipe == INVALID_PIPE)
                return;
 
        /*
@@ -593,150 +593,215 @@ void intel_panel_disable_backlight(struct intel_connector *connector)
                return;
        }
 
-       spin_lock_irqsave(&dev_priv->backlight.lock, flags);
+       spin_lock_irqsave(&dev_priv->backlight_lock, flags);
 
-       dev_priv->backlight.enabled = false;
-       intel_panel_actually_set_backlight(dev, pipe, 0);
+       panel->backlight.enabled = false;
+       dev_priv->display.disable_backlight(connector);
 
-       if (INTEL_INFO(dev)->gen >= 4) {
-               uint32_t reg, tmp;
+       spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
+}
 
-               if (HAS_PCH_SPLIT(dev))
-                       reg = BLC_PWM_CPU_CTL2;
-               else if (IS_VALLEYVIEW(dev))
-                       reg = VLV_BLC_PWM_CTL2(pipe);
-               else
-                       reg = BLC_PWM_CTL2;
+static void bdw_enable_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       u32 pch_ctl1, pch_ctl2;
+
+       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
+       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
+               DRM_DEBUG_KMS("pch backlight already enabled\n");
+               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
+               I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
+       }
 
-               I915_WRITE(reg, I915_READ(reg) & ~BLM_PWM_ENABLE);
+       pch_ctl2 = panel->backlight.max << 16;
+       I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
 
-               if (HAS_PCH_SPLIT(dev)) {
-                       tmp = I915_READ(BLC_PWM_PCH_CTL1);
-                       tmp &= ~BLM_PCH_PWM_ENABLE;
-                       I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
-               }
-       }
+       pch_ctl1 = 0;
+       if (panel->backlight.active_low_pwm)
+               pch_ctl1 |= BLM_PCH_POLARITY;
 
-       spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
+       /* BDW always uses the pch pwm controls. */
+       pch_ctl1 |= BLM_PCH_OVERRIDE_ENABLE;
+
+       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
+       POSTING_READ(BLC_PWM_PCH_CTL1);
+       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
+
+       /* This won't stick until the above enable. */
+       intel_panel_actually_set_backlight(connector, panel->backlight.level);
 }
 
-void intel_panel_enable_backlight(struct intel_connector *connector)
+static void pch_enable_backlight(struct intel_connector *connector)
 {
        struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
        enum pipe pipe = intel_get_pipe_from_connector(connector);
        enum transcoder cpu_transcoder =
                intel_pipe_to_cpu_transcoder(dev_priv, pipe);
-       unsigned long flags;
+       u32 cpu_ctl2, pch_ctl1, pch_ctl2;
 
-       if (pipe == INVALID_PIPE)
-               return;
+       cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
+       if (cpu_ctl2 & BLM_PWM_ENABLE) {
+               WARN(1, "cpu backlight already enabled\n");
+               cpu_ctl2 &= ~BLM_PWM_ENABLE;
+               I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
+       }
 
-       DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
+       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
+       if (pch_ctl1 & BLM_PCH_PWM_ENABLE) {
+               DRM_DEBUG_KMS("pch backlight already enabled\n");
+               pch_ctl1 &= ~BLM_PCH_PWM_ENABLE;
+               I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
+       }
+
+       if (cpu_transcoder == TRANSCODER_EDP)
+               cpu_ctl2 = BLM_TRANSCODER_EDP;
+       else
+               cpu_ctl2 = BLM_PIPE(cpu_transcoder);
+       I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2);
+       POSTING_READ(BLC_PWM_CPU_CTL2);
+       I915_WRITE(BLC_PWM_CPU_CTL2, cpu_ctl2 | BLM_PWM_ENABLE);
+
+       /* This won't stick until the above enable. */
+       intel_panel_actually_set_backlight(connector, panel->backlight.level);
+
+       pch_ctl2 = panel->backlight.max << 16;
+       I915_WRITE(BLC_PWM_PCH_CTL2, pch_ctl2);
+
+       pch_ctl1 = 0;
+       if (panel->backlight.active_low_pwm)
+               pch_ctl1 |= BLM_PCH_POLARITY;
+
+       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1);
+       POSTING_READ(BLC_PWM_PCH_CTL1);
+       I915_WRITE(BLC_PWM_PCH_CTL1, pch_ctl1 | BLM_PCH_PWM_ENABLE);
+}
 
-       spin_lock_irqsave(&dev_priv->backlight.lock, flags);
+static void i9xx_enable_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, freq;
 
-       if (dev_priv->backlight.level == 0) {
-               dev_priv->backlight.level = intel_panel_get_max_backlight(dev,
-                                                                         pipe);
-               if (dev_priv->backlight.device)
-                       dev_priv->backlight.device->props.brightness =
-                               dev_priv->backlight.level;
+       ctl = I915_READ(BLC_PWM_CTL);
+       if (ctl & BACKLIGHT_DUTY_CYCLE_MASK_PNV) {
+               WARN(1, "backlight already enabled\n");
+               I915_WRITE(BLC_PWM_CTL, 0);
        }
 
-       if (INTEL_INFO(dev)->gen >= 4) {
-               uint32_t reg, tmp;
+       freq = panel->backlight.max;
+       if (panel->backlight.combination_mode)
+               freq /= 0xff;
 
-               if (HAS_PCH_SPLIT(dev))
-                       reg = BLC_PWM_CPU_CTL2;
-               else if (IS_VALLEYVIEW(dev))
-                       reg = VLV_BLC_PWM_CTL2(pipe);
-               else
-                       reg = BLC_PWM_CTL2;
+       ctl = freq << 17;
+       if (IS_GEN2(dev) && panel->backlight.combination_mode)
+               ctl |= BLM_LEGACY_MODE;
+       if (IS_PINEVIEW(dev) && panel->backlight.active_low_pwm)
+               ctl |= BLM_POLARITY_PNV;
 
-               tmp = I915_READ(reg);
+       I915_WRITE(BLC_PWM_CTL, ctl);
+       POSTING_READ(BLC_PWM_CTL);
 
-               /* Note that this can also get called through dpms changes. And
-                * we don't track the backlight dpms state, hence check whether
-                * we have to do anything first. */
-               if (tmp & BLM_PWM_ENABLE)
-                       goto set_level;
+       /* XXX: combine this into above write? */
+       intel_panel_actually_set_backlight(connector, panel->backlight.level);
+}
 
-               if (INTEL_INFO(dev)->num_pipes == 3)
-                       tmp &= ~BLM_PIPE_SELECT_IVB;
-               else
-                       tmp &= ~BLM_PIPE_SELECT;
+static void i965_enable_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = intel_get_pipe_from_connector(connector);
+       u32 ctl, ctl2, freq;
 
-               if (cpu_transcoder == TRANSCODER_EDP)
-                       tmp |= BLM_TRANSCODER_EDP;
-               else
-                       tmp |= BLM_PIPE(cpu_transcoder);
-               tmp &= ~BLM_PWM_ENABLE;
-
-               I915_WRITE(reg, tmp);
-               POSTING_READ(reg);
-               I915_WRITE(reg, tmp | BLM_PWM_ENABLE);
-
-               if (IS_BROADWELL(dev)) {
-                       /*
-                        * Broadwell requires PCH override to drive the PCH
-                        * backlight pin. The above will configure the CPU
-                        * backlight pin, which we don't plan to use.
-                        */
-                       tmp = I915_READ(BLC_PWM_PCH_CTL1);
-                       tmp |= BLM_PCH_OVERRIDE_ENABLE | BLM_PCH_PWM_ENABLE;
-                       I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
-               } else if (HAS_PCH_SPLIT(dev) &&
-                   !(dev_priv->quirks & QUIRK_NO_PCH_PWM_ENABLE)) {
-                       tmp = I915_READ(BLC_PWM_PCH_CTL1);
-                       tmp |= BLM_PCH_PWM_ENABLE;
-                       tmp &= ~BLM_PCH_OVERRIDE_ENABLE;
-                       I915_WRITE(BLC_PWM_PCH_CTL1, tmp);
-               }
+       ctl2 = I915_READ(BLC_PWM_CTL2);
+       if (ctl2 & BLM_PWM_ENABLE) {
+               WARN(1, "backlight already enabled\n");
+               ctl2 &= ~BLM_PWM_ENABLE;
+               I915_WRITE(BLC_PWM_CTL2, ctl2);
        }
 
-set_level:
-       /* Call below after setting BLC_PWM_CPU_CTL2 and BLC_PWM_PCH_CTL1.
-        * BLC_PWM_CPU_CTL may be cleared to zero automatically when these
-        * registers are set.
-        */
-       dev_priv->backlight.enabled = true;
-       intel_panel_actually_set_backlight(dev, pipe,
-                                          dev_priv->backlight.level);
+       freq = panel->backlight.max;
+       if (panel->backlight.combination_mode)
+               freq /= 0xff;
+
+       ctl = freq << 16;
+       I915_WRITE(BLC_PWM_CTL, ctl);
+
+       /* XXX: combine this into above write? */
+       intel_panel_actually_set_backlight(connector, panel->backlight.level);
 
-       spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
+       ctl2 = BLM_PIPE(pipe);
+       if (panel->backlight.combination_mode)
+               ctl2 |= BLM_COMBINATION_MODE;
+       if (panel->backlight.active_low_pwm)
+               ctl2 |= BLM_POLARITY_I965;
+       I915_WRITE(BLC_PWM_CTL2, ctl2);
+       POSTING_READ(BLC_PWM_CTL2);
+       I915_WRITE(BLC_PWM_CTL2, ctl2 | BLM_PWM_ENABLE);
 }
 
-/* FIXME: use VBT vals to init PWM_CTL and PWM_CTL2 correctly */
-static void intel_panel_init_backlight_regs(struct drm_device *dev)
+static void vlv_enable_backlight(struct intel_connector *connector)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = intel_get_pipe_from_connector(connector);
+       u32 ctl, ctl2;
 
-       if (IS_VALLEYVIEW(dev)) {
-               enum pipe pipe;
+       ctl2 = I915_READ(VLV_BLC_PWM_CTL2(pipe));
+       if (ctl2 & BLM_PWM_ENABLE) {
+               WARN(1, "backlight already enabled\n");
+               ctl2 &= ~BLM_PWM_ENABLE;
+               I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
+       }
 
-               for_each_pipe(pipe) {
-                       u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe));
+       ctl = panel->backlight.max << 16;
+       I915_WRITE(VLV_BLC_PWM_CTL(pipe), ctl);
 
-                       /* Skip if the modulation freq is already set */
-                       if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK)
-                               continue;
+       /* XXX: combine this into above write? */
+       intel_panel_actually_set_backlight(connector, panel->backlight.level);
 
-                       cur_val &= BACKLIGHT_DUTY_CYCLE_MASK;
-                       I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) |
-                                  cur_val);
-               }
-       }
+       ctl2 = 0;
+       if (panel->backlight.active_low_pwm)
+               ctl2 |= BLM_POLARITY_I965;
+       I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2);
+       POSTING_READ(VLV_BLC_PWM_CTL2(pipe));
+       I915_WRITE(VLV_BLC_PWM_CTL2(pipe), ctl2 | BLM_PWM_ENABLE);
 }
 
-static void intel_panel_init_backlight(struct drm_device *dev)
+void intel_panel_enable_backlight(struct intel_connector *connector)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe = intel_get_pipe_from_connector(connector);
+       unsigned long flags;
+
+       if (!panel->backlight.present || pipe == INVALID_PIPE)
+               return;
+
+       DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
+
+       spin_lock_irqsave(&dev_priv->backlight_lock, flags);
+
+       WARN_ON(panel->backlight.max == 0);
 
-       intel_panel_init_backlight_regs(dev);
+       if (panel->backlight.level == 0) {
+               panel->backlight.level = panel->backlight.max;
+               if (panel->backlight.device)
+                       panel->backlight.device->props.brightness =
+                               panel->backlight.level;
+       }
+
+       dev_priv->display.enable_backlight(connector);
+       panel->backlight.enabled = true;
 
-       dev_priv->backlight.level = intel_panel_get_backlight(dev, 0);
-       dev_priv->backlight.enabled = dev_priv->backlight.level != 0;
+       spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
 }
 
 enum drm_connector_status
@@ -762,7 +827,7 @@ intel_panel_detect(struct drm_device *dev)
 }
 
 #if IS_ENABLED(CONFIG_BACKLIGHT_CLASS_DEVICE)
-static int intel_panel_update_status(struct backlight_device *bd)
+static int intel_backlight_device_update_status(struct backlight_device *bd)
 {
        struct intel_connector *connector = bl_get_data(bd);
        struct drm_device *dev = connector->base.dev;
@@ -776,85 +841,362 @@ static int intel_panel_update_status(struct backlight_device *bd)
        return 0;
 }
 
-static int intel_panel_get_brightness(struct backlight_device *bd)
+static int intel_backlight_device_get_brightness(struct backlight_device *bd)
 {
        struct intel_connector *connector = bl_get_data(bd);
        struct drm_device *dev = connector->base.dev;
-       enum pipe pipe;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret;
 
+       intel_runtime_pm_get(dev_priv);
        mutex_lock(&dev->mode_config.mutex);
-       pipe = intel_get_pipe_from_connector(connector);
+       ret = intel_panel_get_backlight(connector);
        mutex_unlock(&dev->mode_config.mutex);
-       if (pipe == INVALID_PIPE)
-               return 0;
+       intel_runtime_pm_put(dev_priv);
 
-       return intel_panel_get_backlight(connector->base.dev, pipe);
+       return ret;
 }
 
-static const struct backlight_ops intel_panel_bl_ops = {
-       .update_status = intel_panel_update_status,
-       .get_brightness = intel_panel_get_brightness,
+static const struct backlight_ops intel_backlight_device_ops = {
+       .update_status = intel_backlight_device_update_status,
+       .get_brightness = intel_backlight_device_get_brightness,
 };
 
-int intel_panel_setup_backlight(struct drm_connector *connector)
+static int intel_backlight_device_register(struct intel_connector *connector)
 {
-       struct drm_device *dev = connector->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
        struct backlight_properties props;
-       unsigned long flags;
 
-       intel_panel_init_backlight(dev);
-
-       if (WARN_ON(dev_priv->backlight.device))
+       if (WARN_ON(panel->backlight.device))
                return -ENODEV;
 
+       BUG_ON(panel->backlight.max == 0);
+
        memset(&props, 0, sizeof(props));
        props.type = BACKLIGHT_RAW;
-       props.brightness = dev_priv->backlight.level;
+       props.brightness = panel->backlight.level;
+       props.max_brightness = panel->backlight.max;
 
-       spin_lock_irqsave(&dev_priv->backlight.lock, flags);
-       props.max_brightness = intel_panel_get_max_backlight(dev, 0);
-       spin_unlock_irqrestore(&dev_priv->backlight.lock, flags);
-
-       if (props.max_brightness == 0) {
-               DRM_DEBUG_DRIVER("Failed to get maximum backlight value\n");
-               return -ENODEV;
-       }
-       dev_priv->backlight.device =
+       /*
+        * Note: using the same name independent of the connector prevents
+        * registration of multiple backlight devices in the driver.
+        */
+       panel->backlight.device =
                backlight_device_register("intel_backlight",
-                                         connector->kdev,
-                                         to_intel_connector(connector),
-                                         &intel_panel_bl_ops, &props);
+                                         connector->base.kdev,
+                                         connector,
+                                         &intel_backlight_device_ops, &props);
 
-       if (IS_ERR(dev_priv->backlight.device)) {
+       if (IS_ERR(panel->backlight.device)) {
                DRM_ERROR("Failed to register backlight: %ld\n",
-                         PTR_ERR(dev_priv->backlight.device));
-               dev_priv->backlight.device = NULL;
+                         PTR_ERR(panel->backlight.device));
+               panel->backlight.device = NULL;
                return -ENODEV;
        }
        return 0;
 }
 
-void intel_panel_destroy_backlight(struct drm_device *dev)
+static void intel_backlight_device_unregister(struct intel_connector *connector)
+{
+       struct intel_panel *panel = &connector->panel;
+
+       if (panel->backlight.device) {
+               backlight_device_unregister(panel->backlight.device);
+               panel->backlight.device = NULL;
+       }
+}
+#else /* CONFIG_BACKLIGHT_CLASS_DEVICE */
+static int intel_backlight_device_register(struct intel_connector *connector)
+{
+       return 0;
+}
+static void intel_backlight_device_unregister(struct intel_connector *connector)
+{
+}
+#endif /* CONFIG_BACKLIGHT_CLASS_DEVICE */
+
+/*
+ * Note: The setup hooks can't assume pipe is set!
+ *
+ * XXX: Query mode clock or hardware clock and program PWM modulation frequency
+ * appropriately when it's 0. Use VBT and/or sane defaults.
+ */
+static int bdw_setup_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       u32 pch_ctl1, pch_ctl2, val;
+
+       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
+       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
+
+       pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
+       panel->backlight.max = pch_ctl2 >> 16;
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       val = bdw_get_backlight(connector);
+       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+
+       panel->backlight.enabled = (pch_ctl1 & BLM_PCH_PWM_ENABLE) &&
+               panel->backlight.level != 0;
+
+       return 0;
+}
+
+static int pch_setup_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       u32 cpu_ctl2, pch_ctl1, pch_ctl2, val;
+
+       pch_ctl1 = I915_READ(BLC_PWM_PCH_CTL1);
+       panel->backlight.active_low_pwm = pch_ctl1 & BLM_PCH_POLARITY;
+
+       pch_ctl2 = I915_READ(BLC_PWM_PCH_CTL2);
+       panel->backlight.max = pch_ctl2 >> 16;
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       val = pch_get_backlight(connector);
+       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+
+       cpu_ctl2 = I915_READ(BLC_PWM_CPU_CTL2);
+       panel->backlight.enabled = (cpu_ctl2 & BLM_PWM_ENABLE) &&
+               (pch_ctl1 & BLM_PCH_PWM_ENABLE) && panel->backlight.level != 0;
+
+       return 0;
+}
+
+static int i9xx_setup_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, val;
+
+       ctl = I915_READ(BLC_PWM_CTL);
+
+       if (IS_GEN2(dev))
+               panel->backlight.combination_mode = ctl & BLM_LEGACY_MODE;
+
+       if (IS_PINEVIEW(dev))
+               panel->backlight.active_low_pwm = ctl & BLM_POLARITY_PNV;
+
+       panel->backlight.max = ctl >> 17;
+       if (panel->backlight.combination_mode)
+               panel->backlight.max *= 0xff;
+
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       val = i9xx_get_backlight(connector);
+       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+
+       panel->backlight.enabled = panel->backlight.level != 0;
+
+       return 0;
+}
+
+static int i965_setup_backlight(struct intel_connector *connector)
+{
+       struct drm_device *dev = connector->base.dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_panel *panel = &connector->panel;
+       u32 ctl, ctl2, val;
+
+       ctl2 = I915_READ(BLC_PWM_CTL2);
+       panel->backlight.combination_mode = ctl2 & BLM_COMBINATION_MODE;
+       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
+
+       ctl = I915_READ(BLC_PWM_CTL);
+       panel->backlight.max = ctl >> 16;
+       if (panel->backlight.combination_mode)
+               panel->backlight.max *= 0xff;
+
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       val = i9xx_get_backlight(connector);
+       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+
+       panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
+               panel->backlight.level != 0;
+
+       return 0;
+}
+
+static int vlv_setup_backlight(struct intel_connector *connector)
 {
+       struct drm_device *dev = connector->base.dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       if (dev_priv->backlight.device) {
-               backlight_device_unregister(dev_priv->backlight.device);
-               dev_priv->backlight.device = NULL;
+       struct intel_panel *panel = &connector->panel;
+       enum pipe pipe;
+       u32 ctl, ctl2, val;
+
+       for_each_pipe(pipe) {
+               u32 cur_val = I915_READ(VLV_BLC_PWM_CTL(pipe));
+
+               /* Skip if the modulation freq is already set */
+               if (cur_val & ~BACKLIGHT_DUTY_CYCLE_MASK)
+                       continue;
+
+               cur_val &= BACKLIGHT_DUTY_CYCLE_MASK;
+               I915_WRITE(VLV_BLC_PWM_CTL(pipe), (0xf42 << 16) |
+                          cur_val);
        }
+
+       ctl2 = I915_READ(VLV_BLC_PWM_CTL2(PIPE_A));
+       panel->backlight.active_low_pwm = ctl2 & BLM_POLARITY_I965;
+
+       ctl = I915_READ(VLV_BLC_PWM_CTL(PIPE_A));
+       panel->backlight.max = ctl >> 16;
+       if (!panel->backlight.max)
+               return -ENODEV;
+
+       val = _vlv_get_backlight(dev, PIPE_A);
+       panel->backlight.level = intel_panel_compute_brightness(connector, val);
+
+       panel->backlight.enabled = (ctl2 & BLM_PWM_ENABLE) &&
+               panel->backlight.level != 0;
+
+       return 0;
 }
-#else
+
 int intel_panel_setup_backlight(struct drm_connector *connector)
 {
-       intel_panel_init_backlight(connector->dev);
+       struct drm_device *dev = connector->dev;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_panel *panel = &intel_connector->panel;
+       unsigned long flags;
+       int ret;
+
+       /* set level and max in panel struct */
+       spin_lock_irqsave(&dev_priv->backlight_lock, flags);
+       ret = dev_priv->display.setup_backlight(intel_connector);
+       spin_unlock_irqrestore(&dev_priv->backlight_lock, flags);
+
+       if (ret) {
+               DRM_DEBUG_KMS("failed to setup backlight for connector %s\n",
+                             drm_get_connector_name(connector));
+               return ret;
+       }
+
+       intel_backlight_device_register(intel_connector);
+
+       panel->backlight.present = true;
+
+       DRM_DEBUG_KMS("backlight initialized, %s, brightness %u/%u, "
+                     "sysfs interface %sregistered\n",
+                     panel->backlight.enabled ? "enabled" : "disabled",
+                     panel->backlight.level, panel->backlight.max,
+                     panel->backlight.device ? "" : "not ");
+
        return 0;
 }
 
-void intel_panel_destroy_backlight(struct drm_device *dev)
+void intel_panel_destroy_backlight(struct drm_connector *connector)
+{
+       struct intel_connector *intel_connector = to_intel_connector(connector);
+       struct intel_panel *panel = &intel_connector->panel;
+
+       panel->backlight.present = false;
+       intel_backlight_device_unregister(intel_connector);
+}
+
+/**
+ * intel_find_panel_downclock - find the reduced downclock for LVDS in EDID
+ * @dev: drm device
+ * @fixed_mode : panel native mode
+ * @connector: LVDS/eDP connector
+ *
+ * Return downclock_avail
+ * Find the reduced downclock for LVDS/eDP in EDID.
+ */
+struct drm_display_mode *
+intel_find_panel_downclock(struct drm_device *dev,
+                       struct drm_display_mode *fixed_mode,
+                       struct drm_connector *connector)
+{
+       struct drm_display_mode *scan, *tmp_mode;
+       int temp_downclock;
+
+       temp_downclock = fixed_mode->clock;
+       tmp_mode = NULL;
+
+       list_for_each_entry(scan, &connector->probed_modes, head) {
+               /*
+                * If one mode has the same resolution with the fixed_panel
+                * mode while they have the different refresh rate, it means
+                * that the reduced downclock is found. In such
+                * case we can set the different FPx0/1 to dynamically select
+                * between low and high frequency.
+                */
+               if (scan->hdisplay == fixed_mode->hdisplay &&
+                   scan->hsync_start == fixed_mode->hsync_start &&
+                   scan->hsync_end == fixed_mode->hsync_end &&
+                   scan->htotal == fixed_mode->htotal &&
+                   scan->vdisplay == fixed_mode->vdisplay &&
+                   scan->vsync_start == fixed_mode->vsync_start &&
+                   scan->vsync_end == fixed_mode->vsync_end &&
+                   scan->vtotal == fixed_mode->vtotal) {
+                       if (scan->clock < temp_downclock) {
+                               /*
+                                * The downclock is already found. But we
+                                * expect to find the lower downclock.
+                                */
+                               temp_downclock = scan->clock;
+                               tmp_mode = scan;
+                       }
+               }
+       }
+
+       if (temp_downclock < fixed_mode->clock)
+               return drm_mode_duplicate(dev, tmp_mode);
+       else
+               return NULL;
+}
+
+/* Set up chip specific backlight functions */
+void intel_panel_init_backlight_funcs(struct drm_device *dev)
 {
-       return;
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (IS_BROADWELL(dev)) {
+               dev_priv->display.setup_backlight = bdw_setup_backlight;
+               dev_priv->display.enable_backlight = bdw_enable_backlight;
+               dev_priv->display.disable_backlight = pch_disable_backlight;
+               dev_priv->display.set_backlight = bdw_set_backlight;
+               dev_priv->display.get_backlight = bdw_get_backlight;
+       } else if (HAS_PCH_SPLIT(dev)) {
+               dev_priv->display.setup_backlight = pch_setup_backlight;
+               dev_priv->display.enable_backlight = pch_enable_backlight;
+               dev_priv->display.disable_backlight = pch_disable_backlight;
+               dev_priv->display.set_backlight = pch_set_backlight;
+               dev_priv->display.get_backlight = pch_get_backlight;
+       } else if (IS_VALLEYVIEW(dev)) {
+               dev_priv->display.setup_backlight = vlv_setup_backlight;
+               dev_priv->display.enable_backlight = vlv_enable_backlight;
+               dev_priv->display.disable_backlight = vlv_disable_backlight;
+               dev_priv->display.set_backlight = vlv_set_backlight;
+               dev_priv->display.get_backlight = vlv_get_backlight;
+       } else if (IS_GEN4(dev)) {
+               dev_priv->display.setup_backlight = i965_setup_backlight;
+               dev_priv->display.enable_backlight = i965_enable_backlight;
+               dev_priv->display.disable_backlight = i965_disable_backlight;
+               dev_priv->display.set_backlight = i9xx_set_backlight;
+               dev_priv->display.get_backlight = i9xx_get_backlight;
+       } else {
+               dev_priv->display.setup_backlight = i9xx_setup_backlight;
+               dev_priv->display.enable_backlight = i9xx_enable_backlight;
+               dev_priv->display.disable_backlight = i9xx_disable_backlight;
+               dev_priv->display.set_backlight = i9xx_set_backlight;
+               dev_priv->display.get_backlight = i9xx_get_backlight;
+       }
 }
-#endif
 
 int intel_panel_init(struct intel_panel *panel,
                     struct drm_display_mode *fixed_mode)
@@ -871,4 +1213,8 @@ void intel_panel_fini(struct intel_panel *panel)
 
        if (panel->fixed_mode)
                drm_mode_destroy(intel_connector->base.dev, panel->fixed_mode);
+
+       if (panel->downclock_mode)
+               drm_mode_destroy(intel_connector->base.dev,
+                               panel->downclock_mode);
 }
index 26c29c173221058aeeaa9a3c0d889500b8db9fec..d77cc81900f92100ba2f61d7130bc9b0b60454b5 100644 (file)
@@ -30,7 +30,9 @@
 #include "intel_drv.h"
 #include "../../../platform/x86/intel_ips.h"
 #include <linux/module.h>
+#include <linux/vgaarb.h>
 #include <drm/i915_powerwell.h>
+#include <linux/pm_runtime.h>
 
 /**
  * RC6 is a special power stage which allows the GPU to enter an very
@@ -86,7 +88,7 @@ static void i8xx_disable_fbc(struct drm_device *dev)
        DRM_DEBUG_KMS("disabled FBC\n");
 }
 
-static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+static void i8xx_enable_fbc(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -96,32 +98,40 @@ static void i8xx_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int cfb_pitch;
        int plane, i;
-       u32 fbc_ctl, fbc_ctl2;
+       u32 fbc_ctl;
 
        cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
        if (fb->pitches[0] < cfb_pitch)
                cfb_pitch = fb->pitches[0];
 
-       /* FBC_CTL wants 64B units */
-       cfb_pitch = (cfb_pitch / 64) - 1;
+       /* FBC_CTL wants 32B or 64B units */
+       if (IS_GEN2(dev))
+               cfb_pitch = (cfb_pitch / 32) - 1;
+       else
+               cfb_pitch = (cfb_pitch / 64) - 1;
        plane = intel_crtc->plane == 0 ? FBC_CTL_PLANEA : FBC_CTL_PLANEB;
 
        /* Clear old tags */
        for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
                I915_WRITE(FBC_TAG + (i * 4), 0);
 
-       /* Set it up... */
-       fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
-       fbc_ctl2 |= plane;
-       I915_WRITE(FBC_CONTROL2, fbc_ctl2);
-       I915_WRITE(FBC_FENCE_OFF, crtc->y);
+       if (IS_GEN4(dev)) {
+               u32 fbc_ctl2;
+
+               /* Set it up... */
+               fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
+               fbc_ctl2 |= plane;
+               I915_WRITE(FBC_CONTROL2, fbc_ctl2);
+               I915_WRITE(FBC_FENCE_OFF, crtc->y);
+       }
 
        /* enable it... */
-       fbc_ctl = FBC_CTL_EN | FBC_CTL_PERIODIC;
+       fbc_ctl = I915_READ(FBC_CONTROL);
+       fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT;
+       fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC;
        if (IS_I945GM(dev))
                fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
        fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
-       fbc_ctl |= (interval & 0x2fff) << FBC_CTL_INTERVAL_SHIFT;
        fbc_ctl |= obj->fence_reg;
        I915_WRITE(FBC_CONTROL, fbc_ctl);
 
@@ -136,7 +146,7 @@ static bool i8xx_fbc_enabled(struct drm_device *dev)
        return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
 }
 
-static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+static void g4x_enable_fbc(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -145,16 +155,12 @@ static void g4x_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct drm_i915_gem_object *obj = intel_fb->obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
-       unsigned long stall_watermark = 200;
        u32 dpfc_ctl;
 
        dpfc_ctl = plane | DPFC_SR_EN | DPFC_CTL_LIMIT_1X;
        dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
        I915_WRITE(DPFC_CHICKEN, DPFC_HT_MODIFY);
 
-       I915_WRITE(DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
-                  (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
-                  (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
        I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
 
        /* enable it... */
@@ -191,7 +197,11 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
        u32 blt_ecoskpd;
 
        /* Make sure blitter notifies FBC of writes */
-       gen6_gt_force_wake_get(dev_priv);
+
+       /* Blitter is part of Media powerwell on VLV. No impact of
+        * his param in other platforms for now */
+       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA);
+
        blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
        blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
                GEN6_BLITTER_LOCK_SHIFT;
@@ -202,10 +212,11 @@ static void sandybridge_blit_fbc_update(struct drm_device *dev)
                         GEN6_BLITTER_LOCK_SHIFT);
        I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
        POSTING_READ(GEN6_BLITTER_ECOSKPD);
-       gen6_gt_force_wake_put(dev_priv);
+
+       gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA);
 }
 
-static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+static void ironlake_enable_fbc(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -214,7 +225,6 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        struct drm_i915_gem_object *obj = intel_fb->obj;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        int plane = intel_crtc->plane == 0 ? DPFC_CTL_PLANEA : DPFC_CTL_PLANEB;
-       unsigned long stall_watermark = 200;
        u32 dpfc_ctl;
 
        dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
@@ -222,12 +232,11 @@ static void ironlake_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        dpfc_ctl |= (plane | DPFC_CTL_LIMIT_1X);
        /* Set persistent mode for front-buffer rendering, ala X. */
        dpfc_ctl |= DPFC_CTL_PERSISTENT_MODE;
-       dpfc_ctl |= (DPFC_CTL_FENCE_EN | obj->fence_reg);
+       dpfc_ctl |= DPFC_CTL_FENCE_EN;
+       if (IS_GEN5(dev))
+               dpfc_ctl |= obj->fence_reg;
        I915_WRITE(ILK_DPFC_CHICKEN, DPFC_HT_MODIFY);
 
-       I915_WRITE(ILK_DPFC_RECOMP_CTL, DPFC_RECOMP_STALL_EN |
-                  (stall_watermark << DPFC_RECOMP_STALL_WM_SHIFT) |
-                  (interval << DPFC_RECOMP_TIMER_COUNT_SHIFT));
        I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
        I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
        /* enable it... */
@@ -265,7 +274,7 @@ static bool ironlake_fbc_enabled(struct drm_device *dev)
        return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
 }
 
-static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+static void gen7_enable_fbc(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -295,7 +304,7 @@ static void gen7_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
 
        sandybridge_blit_fbc_update(dev);
 
-       DRM_DEBUG_KMS("enabled fbc on plane %d\n", intel_crtc->plane);
+       DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
 }
 
 bool intel_fbc_enabled(struct drm_device *dev)
@@ -322,8 +331,7 @@ static void intel_fbc_work_fn(struct work_struct *__work)
                 * the prior work.
                 */
                if (work->crtc->fb == work->fb) {
-                       dev_priv->display.enable_fbc(work->crtc,
-                                                    work->interval);
+                       dev_priv->display.enable_fbc(work->crtc);
 
                        dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
                        dev_priv->fbc.fb_id = work->crtc->fb->base.id;
@@ -360,7 +368,7 @@ static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
        dev_priv->fbc.fbc_work = NULL;
 }
 
-static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
+static void intel_enable_fbc(struct drm_crtc *crtc)
 {
        struct intel_fbc_work *work;
        struct drm_device *dev = crtc->dev;
@@ -374,13 +382,12 @@ static void intel_enable_fbc(struct drm_crtc *crtc, unsigned long interval)
        work = kzalloc(sizeof(*work), GFP_KERNEL);
        if (work == NULL) {
                DRM_ERROR("Failed to allocate FBC work structure\n");
-               dev_priv->display.enable_fbc(crtc, interval);
+               dev_priv->display.enable_fbc(crtc);
                return;
        }
 
        work->crtc = crtc;
        work->fb = crtc->fb;
-       work->interval = interval;
        INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
 
        dev_priv->fbc.fbc_work = work;
@@ -454,7 +461,7 @@ void intel_update_fbc(struct drm_device *dev)
        const struct drm_display_mode *adjusted_mode;
        unsigned int max_width, max_height;
 
-       if (!I915_HAS_FBC(dev)) {
+       if (!HAS_FBC(dev)) {
                set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
                return;
        }
@@ -530,10 +537,10 @@ void intel_update_fbc(struct drm_device *dev)
                        DRM_DEBUG_KMS("mode too large for compression, disabling\n");
                goto out_disable;
        }
-       if ((IS_I915GM(dev) || IS_I945GM(dev) || IS_HASWELL(dev)) &&
-           intel_crtc->plane != 0) {
+       if ((INTEL_INFO(dev)->gen < 4 || IS_HASWELL(dev)) &&
+           intel_crtc->plane != PLANE_A) {
                if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
-                       DRM_DEBUG_KMS("plane not 0, disabling compression\n");
+                       DRM_DEBUG_KMS("plane not A, disabling compression\n");
                goto out_disable;
        }
 
@@ -595,7 +602,7 @@ void intel_update_fbc(struct drm_device *dev)
                intel_disable_fbc(dev);
        }
 
-       intel_enable_fbc(crtc, 500);
+       intel_enable_fbc(crtc);
        dev_priv->fbc.no_fbc_reason = FBC_OK;
        return;
 
@@ -817,7 +824,7 @@ static int i9xx_get_fifo_size(struct drm_device *dev, int plane)
        return size;
 }
 
-static int i85x_get_fifo_size(struct drm_device *dev, int plane)
+static int i830_get_fifo_size(struct drm_device *dev, int plane)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t dsparb = I915_READ(DSPARB);
@@ -850,21 +857,6 @@ static int i845_get_fifo_size(struct drm_device *dev, int plane)
        return size;
 }
 
-static int i830_get_fifo_size(struct drm_device *dev, int plane)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       uint32_t dsparb = I915_READ(DSPARB);
-       int size;
-
-       size = dsparb & 0x7f;
-       size >>= 1; /* Convert to cachelines */
-
-       DRM_DEBUG_KMS("FIFO size - (0x%08x) %s: %d\n", dsparb,
-                     plane ? "B" : "A", size);
-
-       return size;
-}
-
 /* Pineview has different values for various configs */
 static const struct intel_watermark_params pineview_display_wm = {
        PINEVIEW_DISPLAY_FIFO,
@@ -943,14 +935,14 @@ static const struct intel_watermark_params i915_wm_info = {
        2,
        I915_FIFO_LINE_SIZE
 };
-static const struct intel_watermark_params i855_wm_info = {
+static const struct intel_watermark_params i830_wm_info = {
        I855GM_FIFO_SIZE,
        I915_MAX_WM,
        1,
        2,
        I830_FIFO_LINE_SIZE
 };
-static const struct intel_watermark_params i830_wm_info = {
+static const struct intel_watermark_params i845_wm_info = {
        I830_FIFO_SIZE,
        I915_MAX_WM,
        1,
@@ -958,65 +950,6 @@ static const struct intel_watermark_params i830_wm_info = {
        I830_FIFO_LINE_SIZE
 };
 
-static const struct intel_watermark_params ironlake_display_wm_info = {
-       ILK_DISPLAY_FIFO,
-       ILK_DISPLAY_MAXWM,
-       ILK_DISPLAY_DFTWM,
-       2,
-       ILK_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params ironlake_cursor_wm_info = {
-       ILK_CURSOR_FIFO,
-       ILK_CURSOR_MAXWM,
-       ILK_CURSOR_DFTWM,
-       2,
-       ILK_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params ironlake_display_srwm_info = {
-       ILK_DISPLAY_SR_FIFO,
-       ILK_DISPLAY_MAX_SRWM,
-       ILK_DISPLAY_DFT_SRWM,
-       2,
-       ILK_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params ironlake_cursor_srwm_info = {
-       ILK_CURSOR_SR_FIFO,
-       ILK_CURSOR_MAX_SRWM,
-       ILK_CURSOR_DFT_SRWM,
-       2,
-       ILK_FIFO_LINE_SIZE
-};
-
-static const struct intel_watermark_params sandybridge_display_wm_info = {
-       SNB_DISPLAY_FIFO,
-       SNB_DISPLAY_MAXWM,
-       SNB_DISPLAY_DFTWM,
-       2,
-       SNB_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params sandybridge_cursor_wm_info = {
-       SNB_CURSOR_FIFO,
-       SNB_CURSOR_MAXWM,
-       SNB_CURSOR_DFTWM,
-       2,
-       SNB_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params sandybridge_display_srwm_info = {
-       SNB_DISPLAY_SR_FIFO,
-       SNB_DISPLAY_MAX_SRWM,
-       SNB_DISPLAY_DFT_SRWM,
-       2,
-       SNB_FIFO_LINE_SIZE
-};
-static const struct intel_watermark_params sandybridge_cursor_srwm_info = {
-       SNB_CURSOR_SR_FIFO,
-       SNB_CURSOR_MAX_SRWM,
-       SNB_CURSOR_DFT_SRWM,
-       2,
-       SNB_FIFO_LINE_SIZE
-};
-
-
 /**
  * intel_calculate_wm - calculate watermark level
  * @clock_in_khz: pixel clock
@@ -1567,7 +1500,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
        else if (!IS_GEN2(dev))
                wm_info = &i915_wm_info;
        else
-               wm_info = &i855_wm_info;
+               wm_info = &i830_wm_info;
 
        fifo_size = dev_priv->display.get_fifo_size(dev, 0);
        crtc = intel_get_crtc_for_plane(dev, 0);
@@ -1615,7 +1548,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
        if (IS_I945G(dev) || IS_I945GM(dev))
                I915_WRITE(FW_BLC_SELF, FW_BLC_SELF_EN_MASK | 0);
        else if (IS_I915GM(dev))
-               I915_WRITE(INSTPM, I915_READ(INSTPM) & ~INSTPM_SELF_EN);
+               I915_WRITE(INSTPM, _MASKED_BIT_DISABLE(INSTPM_SELF_EN));
 
        /* Calc sr entries for one plane configs */
        if (HAS_FW_BLC(dev) && enabled) {
@@ -1667,14 +1600,14 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
                                I915_WRITE(FW_BLC_SELF,
                                           FW_BLC_SELF_EN_MASK | FW_BLC_SELF_EN);
                        else if (IS_I915GM(dev))
-                               I915_WRITE(INSTPM, I915_READ(INSTPM) | INSTPM_SELF_EN);
+                               I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_SELF_EN));
                        DRM_DEBUG_KMS("memory self refresh enabled\n");
                } else
                        DRM_DEBUG_KMS("memory self refresh disabled\n");
        }
 }
 
-static void i830_update_wm(struct drm_crtc *unused_crtc)
+static void i845_update_wm(struct drm_crtc *unused_crtc)
 {
        struct drm_device *dev = unused_crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1689,7 +1622,7 @@ static void i830_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,
-                                      &i830_wm_info,
+                                      &i845_wm_info,
                                       dev_priv->display.get_fifo_size(dev, 0),
                                       4, latency_ns);
        fwater_lo = I915_READ(FW_BLC) & ~0xfff;
@@ -1700,423 +1633,6 @@ static void i830_update_wm(struct drm_crtc *unused_crtc)
        I915_WRITE(FW_BLC, fwater_lo);
 }
 
-/*
- * Check the wm result.
- *
- * If any calculated watermark values is larger than the maximum value that
- * can be programmed into the associated watermark register, that watermark
- * must be disabled.
- */
-static bool ironlake_check_srwm(struct drm_device *dev, int level,
-                               int fbc_wm, int display_wm, int cursor_wm,
-                               const struct intel_watermark_params *display,
-                               const struct intel_watermark_params *cursor)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       DRM_DEBUG_KMS("watermark %d: display plane %d, fbc lines %d,"
-                     " cursor %d\n", level, display_wm, fbc_wm, cursor_wm);
-
-       if (fbc_wm > SNB_FBC_MAX_SRWM) {
-               DRM_DEBUG_KMS("fbc watermark(%d) is too large(%d), disabling wm%d+\n",
-                             fbc_wm, SNB_FBC_MAX_SRWM, level);
-
-               /* fbc has it's own way to disable FBC WM */
-               I915_WRITE(DISP_ARB_CTL,
-                          I915_READ(DISP_ARB_CTL) | DISP_FBC_WM_DIS);
-               return false;
-       } else if (INTEL_INFO(dev)->gen >= 6) {
-               /* enable FBC WM (except on ILK, where it must remain off) */
-               I915_WRITE(DISP_ARB_CTL,
-                          I915_READ(DISP_ARB_CTL) & ~DISP_FBC_WM_DIS);
-       }
-
-       if (display_wm > display->max_wm) {
-               DRM_DEBUG_KMS("display watermark(%d) is too large(%d), disabling wm%d+\n",
-                             display_wm, SNB_DISPLAY_MAX_SRWM, level);
-               return false;
-       }
-
-       if (cursor_wm > cursor->max_wm) {
-               DRM_DEBUG_KMS("cursor watermark(%d) is too large(%d), disabling wm%d+\n",
-                             cursor_wm, SNB_CURSOR_MAX_SRWM, level);
-               return false;
-       }
-
-       if (!(fbc_wm || display_wm || cursor_wm)) {
-               DRM_DEBUG_KMS("latency %d is 0, disabling wm%d+\n", level, level);
-               return false;
-       }
-
-       return true;
-}
-
-/*
- * Compute watermark values of WM[1-3],
- */
-static bool ironlake_compute_srwm(struct drm_device *dev, int level, int plane,
-                                 int latency_ns,
-                                 const struct intel_watermark_params *display,
-                                 const struct intel_watermark_params *cursor,
-                                 int *fbc_wm, int *display_wm, int *cursor_wm)
-{
-       struct drm_crtc *crtc;
-       const struct drm_display_mode *adjusted_mode;
-       unsigned long line_time_us;
-       int hdisplay, htotal, pixel_size, clock;
-       int line_count, line_size;
-       int small, large;
-       int entries;
-
-       if (!latency_ns) {
-               *fbc_wm = *display_wm = *cursor_wm = 0;
-               return false;
-       }
-
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
-       clock = adjusted_mode->crtc_clock;
-       htotal = adjusted_mode->crtc_htotal;
-       hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
-       pixel_size = crtc->fb->bits_per_pixel / 8;
-
-       line_time_us = (htotal * 1000) / clock;
-       line_count = (latency_ns / line_time_us + 1000) / 1000;
-       line_size = hdisplay * pixel_size;
-
-       /* Use the minimum of the small and large buffer method for primary */
-       small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
-       large = line_count * line_size;
-
-       entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
-       *display_wm = entries + display->guard_size;
-
-       /*
-        * Spec says:
-        * FBC WM = ((Final Primary WM * 64) / number of bytes per line) + 2
-        */
-       *fbc_wm = DIV_ROUND_UP(*display_wm * 64, line_size) + 2;
-
-       /* calculate the self-refresh watermark for display cursor */
-       entries = line_count * pixel_size * 64;
-       entries = DIV_ROUND_UP(entries, cursor->cacheline_size);
-       *cursor_wm = entries + cursor->guard_size;
-
-       return ironlake_check_srwm(dev, level,
-                                  *fbc_wm, *display_wm, *cursor_wm,
-                                  display, cursor);
-}
-
-static void ironlake_update_wm(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int fbc_wm, plane_wm, cursor_wm;
-       unsigned int enabled;
-
-       enabled = 0;
-       if (g4x_compute_wm0(dev, PIPE_A,
-                           &ironlake_display_wm_info,
-                           dev_priv->wm.pri_latency[0] * 100,
-                           &ironlake_cursor_wm_info,
-                           dev_priv->wm.cur_latency[0] * 100,
-                           &plane_wm, &cursor_wm)) {
-               I915_WRITE(WM0_PIPEA_ILK,
-                          (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
-               DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
-                             " plane %d, " "cursor: %d\n",
-                             plane_wm, cursor_wm);
-               enabled |= 1 << PIPE_A;
-       }
-
-       if (g4x_compute_wm0(dev, PIPE_B,
-                           &ironlake_display_wm_info,
-                           dev_priv->wm.pri_latency[0] * 100,
-                           &ironlake_cursor_wm_info,
-                           dev_priv->wm.cur_latency[0] * 100,
-                           &plane_wm, &cursor_wm)) {
-               I915_WRITE(WM0_PIPEB_ILK,
-                          (plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm);
-               DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
-                             " plane %d, cursor: %d\n",
-                             plane_wm, cursor_wm);
-               enabled |= 1 << PIPE_B;
-       }
-
-       /*
-        * Calculate and update the self-refresh watermark only when one
-        * display plane is used.
-        */
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
-
-       if (!single_plane_enabled(enabled))
-               return;
-       enabled = ffs(enabled) - 1;
-
-       /* WM1 */
-       if (!ironlake_compute_srwm(dev, 1, enabled,
-                                  dev_priv->wm.pri_latency[1] * 500,
-                                  &ironlake_display_srwm_info,
-                                  &ironlake_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
-
-       I915_WRITE(WM1_LP_ILK,
-                  WM1_LP_SR_EN |
-                  (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-
-       /* WM2 */
-       if (!ironlake_compute_srwm(dev, 2, enabled,
-                                  dev_priv->wm.pri_latency[2] * 500,
-                                  &ironlake_display_srwm_info,
-                                  &ironlake_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
-
-       I915_WRITE(WM2_LP_ILK,
-                  WM2_LP_EN |
-                  (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-
-       /*
-        * WM3 is unsupported on ILK, probably because we don't have latency
-        * data for that power state
-        */
-}
-
-static void sandybridge_update_wm(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int latency = dev_priv->wm.pri_latency[0] * 100;        /* In unit 0.1us */
-       u32 val;
-       int fbc_wm, plane_wm, cursor_wm;
-       unsigned int enabled;
-
-       enabled = 0;
-       if (g4x_compute_wm0(dev, PIPE_A,
-                           &sandybridge_display_wm_info, latency,
-                           &sandybridge_cursor_wm_info, latency,
-                           &plane_wm, &cursor_wm)) {
-               val = I915_READ(WM0_PIPEA_ILK);
-               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEA_ILK, val |
-                          ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
-               DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
-                             " plane %d, " "cursor: %d\n",
-                             plane_wm, cursor_wm);
-               enabled |= 1 << PIPE_A;
-       }
-
-       if (g4x_compute_wm0(dev, PIPE_B,
-                           &sandybridge_display_wm_info, latency,
-                           &sandybridge_cursor_wm_info, latency,
-                           &plane_wm, &cursor_wm)) {
-               val = I915_READ(WM0_PIPEB_ILK);
-               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEB_ILK, val |
-                          ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
-               DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
-                             " plane %d, cursor: %d\n",
-                             plane_wm, cursor_wm);
-               enabled |= 1 << PIPE_B;
-       }
-
-       /*
-        * Calculate and update the self-refresh watermark only when one
-        * display plane is used.
-        *
-        * SNB support 3 levels of watermark.
-        *
-        * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
-        * and disabled in the descending order
-        *
-        */
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
-
-       if (!single_plane_enabled(enabled) ||
-           dev_priv->sprite_scaling_enabled)
-               return;
-       enabled = ffs(enabled) - 1;
-
-       /* WM1 */
-       if (!ironlake_compute_srwm(dev, 1, enabled,
-                                  dev_priv->wm.pri_latency[1] * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
-
-       I915_WRITE(WM1_LP_ILK,
-                  WM1_LP_SR_EN |
-                  (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-
-       /* WM2 */
-       if (!ironlake_compute_srwm(dev, 2, enabled,
-                                  dev_priv->wm.pri_latency[2] * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
-
-       I915_WRITE(WM2_LP_ILK,
-                  WM2_LP_EN |
-                  (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-
-       /* WM3 */
-       if (!ironlake_compute_srwm(dev, 3, enabled,
-                                  dev_priv->wm.pri_latency[3] * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
-
-       I915_WRITE(WM3_LP_ILK,
-                  WM3_LP_EN |
-                  (dev_priv->wm.pri_latency[3] << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-}
-
-static void ivybridge_update_wm(struct drm_crtc *crtc)
-{
-       struct drm_device *dev = crtc->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int latency = dev_priv->wm.pri_latency[0] * 100;        /* In unit 0.1us */
-       u32 val;
-       int fbc_wm, plane_wm, cursor_wm;
-       int ignore_fbc_wm, ignore_plane_wm, ignore_cursor_wm;
-       unsigned int enabled;
-
-       enabled = 0;
-       if (g4x_compute_wm0(dev, PIPE_A,
-                           &sandybridge_display_wm_info, latency,
-                           &sandybridge_cursor_wm_info, latency,
-                           &plane_wm, &cursor_wm)) {
-               val = I915_READ(WM0_PIPEA_ILK);
-               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEA_ILK, val |
-                          ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
-               DRM_DEBUG_KMS("FIFO watermarks For pipe A -"
-                             " plane %d, " "cursor: %d\n",
-                             plane_wm, cursor_wm);
-               enabled |= 1 << PIPE_A;
-       }
-
-       if (g4x_compute_wm0(dev, PIPE_B,
-                           &sandybridge_display_wm_info, latency,
-                           &sandybridge_cursor_wm_info, latency,
-                           &plane_wm, &cursor_wm)) {
-               val = I915_READ(WM0_PIPEB_ILK);
-               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEB_ILK, val |
-                          ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
-               DRM_DEBUG_KMS("FIFO watermarks For pipe B -"
-                             " plane %d, cursor: %d\n",
-                             plane_wm, cursor_wm);
-               enabled |= 1 << PIPE_B;
-       }
-
-       if (g4x_compute_wm0(dev, PIPE_C,
-                           &sandybridge_display_wm_info, latency,
-                           &sandybridge_cursor_wm_info, latency,
-                           &plane_wm, &cursor_wm)) {
-               val = I915_READ(WM0_PIPEC_IVB);
-               val &= ~(WM0_PIPE_PLANE_MASK | WM0_PIPE_CURSOR_MASK);
-               I915_WRITE(WM0_PIPEC_IVB, val |
-                          ((plane_wm << WM0_PIPE_PLANE_SHIFT) | cursor_wm));
-               DRM_DEBUG_KMS("FIFO watermarks For pipe C -"
-                             " plane %d, cursor: %d\n",
-                             plane_wm, cursor_wm);
-               enabled |= 1 << PIPE_C;
-       }
-
-       /*
-        * Calculate and update the self-refresh watermark only when one
-        * display plane is used.
-        *
-        * SNB support 3 levels of watermark.
-        *
-        * WM1/WM2/WM2 watermarks have to be enabled in the ascending order,
-        * and disabled in the descending order
-        *
-        */
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
-
-       if (!single_plane_enabled(enabled) ||
-           dev_priv->sprite_scaling_enabled)
-               return;
-       enabled = ffs(enabled) - 1;
-
-       /* WM1 */
-       if (!ironlake_compute_srwm(dev, 1, enabled,
-                                  dev_priv->wm.pri_latency[1] * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
-
-       I915_WRITE(WM1_LP_ILK,
-                  WM1_LP_SR_EN |
-                  (dev_priv->wm.pri_latency[1] << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-
-       /* WM2 */
-       if (!ironlake_compute_srwm(dev, 2, enabled,
-                                  dev_priv->wm.pri_latency[2] * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &cursor_wm))
-               return;
-
-       I915_WRITE(WM2_LP_ILK,
-                  WM2_LP_EN |
-                  (dev_priv->wm.pri_latency[2] << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-
-       /* WM3, note we have to correct the cursor latency */
-       if (!ironlake_compute_srwm(dev, 3, enabled,
-                                  dev_priv->wm.pri_latency[3] * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &fbc_wm, &plane_wm, &ignore_cursor_wm) ||
-           !ironlake_compute_srwm(dev, 3, enabled,
-                                  dev_priv->wm.cur_latency[3] * 500,
-                                  &sandybridge_display_srwm_info,
-                                  &sandybridge_cursor_srwm_info,
-                                  &ignore_fbc_wm, &ignore_plane_wm, &cursor_wm))
-               return;
-
-       I915_WRITE(WM3_LP_ILK,
-                  WM3_LP_EN |
-                  (dev_priv->wm.pri_latency[3] << WM1_LP_LATENCY_SHIFT) |
-                  (fbc_wm << WM1_LP_FBC_SHIFT) |
-                  (plane_wm << WM1_LP_SR_SHIFT) |
-                  cursor_wm);
-}
-
 static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev,
                                    struct drm_crtc *crtc)
 {
@@ -2185,7 +1701,7 @@ static uint32_t ilk_wm_fbc(uint32_t pri_val, uint32_t horiz_pixels,
        return DIV_ROUND_UP(pri_val * 64, horiz_pixels * bytes_per_pixel) + 2;
 }
 
-struct hsw_pipe_wm_parameters {
+struct ilk_pipe_wm_parameters {
        bool active;
        uint32_t pipe_htotal;
        uint32_t pixel_rate;
@@ -2194,7 +1710,7 @@ struct hsw_pipe_wm_parameters {
        struct intel_plane_wm_parameters cur;
 };
 
-struct hsw_wm_maximums {
+struct ilk_wm_maximums {
        uint16_t pri;
        uint16_t spr;
        uint16_t cur;
@@ -2212,7 +1728,7 @@ struct intel_wm_config {
  * For both WM_PIPE and WM_LP.
  * mem_value must be in 0.1us units.
  */
-static uint32_t ilk_compute_pri_wm(const struct hsw_pipe_wm_parameters *params,
+static uint32_t ilk_compute_pri_wm(const struct ilk_pipe_wm_parameters *params,
                                   uint32_t mem_value,
                                   bool is_lp)
 {
@@ -2241,7 +1757,7 @@ static uint32_t ilk_compute_pri_wm(const struct hsw_pipe_wm_parameters *params,
  * For both WM_PIPE and WM_LP.
  * mem_value must be in 0.1us units.
  */
-static uint32_t ilk_compute_spr_wm(const struct hsw_pipe_wm_parameters *params,
+static uint32_t ilk_compute_spr_wm(const struct ilk_pipe_wm_parameters *params,
                                   uint32_t mem_value)
 {
        uint32_t method1, method2;
@@ -2264,7 +1780,7 @@ static uint32_t ilk_compute_spr_wm(const struct hsw_pipe_wm_parameters *params,
  * For both WM_PIPE and WM_LP.
  * mem_value must be in 0.1us units.
  */
-static uint32_t ilk_compute_cur_wm(const struct hsw_pipe_wm_parameters *params,
+static uint32_t ilk_compute_cur_wm(const struct ilk_pipe_wm_parameters *params,
                                   uint32_t mem_value)
 {
        if (!params->active || !params->cur.enabled)
@@ -2278,7 +1794,7 @@ static uint32_t ilk_compute_cur_wm(const struct hsw_pipe_wm_parameters *params,
 }
 
 /* Only for WM_LP. */
-static uint32_t ilk_compute_fbc_wm(const struct hsw_pipe_wm_parameters *params,
+static uint32_t ilk_compute_fbc_wm(const struct ilk_pipe_wm_parameters *params,
                                   uint32_t pri_val)
 {
        if (!params->active || !params->pri.enabled)
@@ -2383,7 +1899,7 @@ static void ilk_compute_wm_maximums(struct drm_device *dev,
                                    int level,
                                    const struct intel_wm_config *config,
                                    enum intel_ddb_partitioning ddb_partitioning,
-                                   struct hsw_wm_maximums *max)
+                                   struct ilk_wm_maximums *max)
 {
        max->pri = ilk_plane_wm_max(dev, level, config, ddb_partitioning, false);
        max->spr = ilk_plane_wm_max(dev, level, config, ddb_partitioning, true);
@@ -2392,7 +1908,7 @@ static void ilk_compute_wm_maximums(struct drm_device *dev,
 }
 
 static bool ilk_validate_wm_level(int level,
-                                 const struct hsw_wm_maximums *max,
+                                 const struct ilk_wm_maximums *max,
                                  struct intel_wm_level *result)
 {
        bool ret;
@@ -2434,7 +1950,7 @@ static bool ilk_validate_wm_level(int level,
 
 static void ilk_compute_wm_level(struct drm_i915_private *dev_priv,
                                 int level,
-                                const struct hsw_pipe_wm_parameters *p,
+                                const struct ilk_pipe_wm_parameters *p,
                                 struct intel_wm_level *result)
 {
        uint16_t pri_latency = dev_priv->wm.pri_latency[level];
@@ -2482,7 +1998,7 @@ static void intel_read_wm_latency(struct drm_device *dev, uint16_t wm[5])
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (IS_HASWELL(dev)) {
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
                uint64_t sskpd = I915_READ64(MCH_SSKPD);
 
                wm[0] = (sskpd >> 56) & 0xFF;
@@ -2530,7 +2046,7 @@ static void intel_fixup_cur_wm_latency(struct drm_device *dev, uint16_t wm[5])
 static int ilk_wm_max_level(const struct drm_device *dev)
 {
        /* how many WM levels are we expecting */
-       if (IS_HASWELL(dev))
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
                return 4;
        else if (INTEL_INFO(dev)->gen >= 6)
                return 3;
@@ -2582,8 +2098,8 @@ static void intel_setup_wm_latency(struct drm_device *dev)
        intel_print_wm_latency(dev, "Cursor", dev_priv->wm.cur_latency);
 }
 
-static void hsw_compute_wm_parameters(struct drm_crtc *crtc,
-                                     struct hsw_pipe_wm_parameters *p,
+static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
+                                     struct ilk_pipe_wm_parameters *p,
                                      struct intel_wm_config *config)
 {
        struct drm_device *dev = crtc->dev;
@@ -2593,7 +2109,7 @@ static void hsw_compute_wm_parameters(struct drm_crtc *crtc,
 
        p->active = intel_crtc_active(crtc);
        if (p->active) {
-               p->pipe_htotal = intel_crtc->config.adjusted_mode.htotal;
+               p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
                p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
                p->pri.bytes_per_pixel = crtc->fb->bits_per_pixel / 8;
                p->cur.bytes_per_pixel = 4;
@@ -2620,7 +2136,7 @@ static void hsw_compute_wm_parameters(struct drm_crtc *crtc,
 
 /* Compute new watermarks for the pipe */
 static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
-                                 const struct hsw_pipe_wm_parameters *params,
+                                 const struct ilk_pipe_wm_parameters *params,
                                  struct intel_pipe_wm *pipe_wm)
 {
        struct drm_device *dev = crtc->dev;
@@ -2632,16 +2148,25 @@ static bool intel_compute_pipe_wm(struct drm_crtc *crtc,
                .sprites_enabled = params->spr.enabled,
                .sprites_scaled = params->spr.scaled,
        };
-       struct hsw_wm_maximums max;
+       struct ilk_wm_maximums max;
 
        /* LP0 watermarks always use 1/2 DDB partitioning */
        ilk_compute_wm_maximums(dev, 0, &config, INTEL_DDB_PART_1_2, &max);
 
+       /* ILK/SNB: LP2+ watermarks only w/o sprites */
+       if (INTEL_INFO(dev)->gen <= 6 && params->spr.enabled)
+               max_level = 1;
+
+       /* ILK/SNB/IVB: LP1+ watermarks only w/o scaling */
+       if (params->spr.scaled)
+               max_level = 0;
+
        for (level = 0; level <= max_level; level++)
                ilk_compute_wm_level(dev_priv, level, params,
                                     &pipe_wm->wm[level]);
 
-       pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               pipe_wm->linetime = hsw_compute_linetime_wm(dev, crtc);
 
        /* At least LP0 must be valid */
        return ilk_validate_wm_level(0, &max, &pipe_wm->wm[0]);
@@ -2676,12 +2201,19 @@ static void ilk_merge_wm_level(struct drm_device *dev,
  * Merge all low power watermarks for all active pipes.
  */
 static void ilk_wm_merge(struct drm_device *dev,
-                        const struct hsw_wm_maximums *max,
+                        const struct intel_wm_config *config,
+                        const struct ilk_wm_maximums *max,
                         struct intel_pipe_wm *merged)
 {
        int level, max_level = ilk_wm_max_level(dev);
 
-       merged->fbc_wm_enabled = true;
+       /* ILK/SNB/IVB: LP1+ watermarks only w/ single pipe */
+       if ((INTEL_INFO(dev)->gen <= 6 || IS_IVYBRIDGE(dev)) &&
+           config->num_pipes_active > 1)
+               return;
+
+       /* ILK: FBC WM must be disabled always */
+       merged->fbc_wm_enabled = INTEL_INFO(dev)->gen >= 6;
 
        /* merge each WM1+ level */
        for (level = 1; level <= max_level; level++) {
@@ -2701,6 +2233,20 @@ static void ilk_wm_merge(struct drm_device *dev,
                        wm->fbc_val = 0;
                }
        }
+
+       /* ILK: LP2+ must be disabled when FBC WM is disabled but FBC enabled */
+       /*
+        * FIXME this is racy. FBC might get enabled later.
+        * What we should check here is whether FBC can be
+        * enabled sometime later.
+        */
+       if (IS_GEN5(dev) && !merged->fbc_wm_enabled && intel_fbc_enabled(dev)) {
+               for (level = 2; level <= max_level; level++) {
+                       struct intel_wm_level *wm = &merged->wm[level];
+
+                       wm->enable = false;
+               }
+       }
 }
 
 static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm)
@@ -2709,10 +2255,21 @@ static int ilk_wm_lp_to_level(int wm_lp, const struct intel_pipe_wm *pipe_wm)
        return wm_lp + (wm_lp >= 2 && pipe_wm->wm[4].enable);
 }
 
-static void hsw_compute_wm_results(struct drm_device *dev,
+/* The value we need to program into the WM_LPx latency field */
+static unsigned int ilk_wm_lp_latency(struct drm_device *dev, int level)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               return 2 * level;
+       else
+               return dev_priv->wm.pri_latency[level];
+}
+
+static void ilk_compute_wm_results(struct drm_device *dev,
                                   const struct intel_pipe_wm *merged,
                                   enum intel_ddb_partitioning partitioning,
-                                  struct hsw_wm_values *results)
+                                  struct ilk_wm_values *results)
 {
        struct intel_crtc *intel_crtc;
        int level, wm_lp;
@@ -2731,7 +2288,7 @@ static void hsw_compute_wm_results(struct drm_device *dev,
                        break;
 
                results->wm_lp[wm_lp - 1] = WM3_LP_EN |
-                       ((level * 2) << WM1_LP_LATENCY_SHIFT) |
+                       (ilk_wm_lp_latency(dev, level) << WM1_LP_LATENCY_SHIFT) |
                        (r->pri_val << WM1_LP_SR_SHIFT) |
                        r->cur_val;
 
@@ -2742,7 +2299,11 @@ static void hsw_compute_wm_results(struct drm_device *dev,
                        results->wm_lp[wm_lp - 1] |=
                                r->fbc_val << WM1_LP_FBC_SHIFT;
 
-               results->wm_lp_spr[wm_lp - 1] = r->spr_val;
+               if (INTEL_INFO(dev)->gen <= 6 && r->spr_val) {
+                       WARN_ON(wm_lp != 1);
+                       results->wm_lp_spr[wm_lp - 1] = WM1S_LP_EN | r->spr_val;
+               } else
+                       results->wm_lp_spr[wm_lp - 1] = r->spr_val;
        }
 
        /* LP0 register values */
@@ -2765,7 +2326,7 @@ static void hsw_compute_wm_results(struct drm_device *dev,
 
 /* Find the result with the highest level enabled. Check for enable_fbc_wm in
  * case both are at the same level. Prefer r1 in case they're the same. */
-static struct intel_pipe_wm *hsw_find_best_result(struct drm_device *dev,
+static struct intel_pipe_wm *ilk_find_best_result(struct drm_device *dev,
                                                  struct intel_pipe_wm *r1,
                                                  struct intel_pipe_wm *r2)
 {
@@ -2800,8 +2361,8 @@ static struct intel_pipe_wm *hsw_find_best_result(struct drm_device *dev,
 #define WM_DIRTY_DDB (1 << 25)
 
 static unsigned int ilk_compute_wm_dirty(struct drm_device *dev,
-                                        const struct hsw_wm_values *old,
-                                        const struct hsw_wm_values *new)
+                                        const struct ilk_wm_values *old,
+                                        const struct ilk_wm_values *new)
 {
        unsigned int dirty = 0;
        enum pipe pipe;
@@ -2851,27 +2412,53 @@ static unsigned int ilk_compute_wm_dirty(struct drm_device *dev,
        return dirty;
 }
 
+static bool _ilk_disable_lp_wm(struct drm_i915_private *dev_priv,
+                              unsigned int dirty)
+{
+       struct ilk_wm_values *previous = &dev_priv->wm.hw;
+       bool changed = false;
+
+       if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] & WM1_LP_SR_EN) {
+               previous->wm_lp[2] &= ~WM1_LP_SR_EN;
+               I915_WRITE(WM3_LP_ILK, previous->wm_lp[2]);
+               changed = true;
+       }
+       if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] & WM1_LP_SR_EN) {
+               previous->wm_lp[1] &= ~WM1_LP_SR_EN;
+               I915_WRITE(WM2_LP_ILK, previous->wm_lp[1]);
+               changed = true;
+       }
+       if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] & WM1_LP_SR_EN) {
+               previous->wm_lp[0] &= ~WM1_LP_SR_EN;
+               I915_WRITE(WM1_LP_ILK, previous->wm_lp[0]);
+               changed = true;
+       }
+
+       /*
+        * Don't touch WM1S_LP_EN here.
+        * Doing so could cause underruns.
+        */
+
+       return changed;
+}
+
 /*
  * The spec says we shouldn't write when we don't need, because every write
  * causes WMs to be re-evaluated, expending some power.
  */
-static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
-                               struct hsw_wm_values *results)
+static void ilk_write_wm_values(struct drm_i915_private *dev_priv,
+                               struct ilk_wm_values *results)
 {
-       struct hsw_wm_values *previous = &dev_priv->wm.hw;
+       struct drm_device *dev = dev_priv->dev;
+       struct ilk_wm_values *previous = &dev_priv->wm.hw;
        unsigned int dirty;
        uint32_t val;
 
-       dirty = ilk_compute_wm_dirty(dev_priv->dev, previous, results);
+       dirty = ilk_compute_wm_dirty(dev, previous, results);
        if (!dirty)
                return;
 
-       if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != 0)
-               I915_WRITE(WM3_LP_ILK, 0);
-       if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != 0)
-               I915_WRITE(WM2_LP_ILK, 0);
-       if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != 0)
-               I915_WRITE(WM1_LP_ILK, 0);
+       _ilk_disable_lp_wm(dev_priv, dirty);
 
        if (dirty & WM_DIRTY_PIPE(PIPE_A))
                I915_WRITE(WM0_PIPEA_ILK, results->wm_pipe[0]);
@@ -2888,12 +2475,21 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
                I915_WRITE(PIPE_WM_LINETIME(PIPE_C), results->wm_linetime[2]);
 
        if (dirty & WM_DIRTY_DDB) {
-               val = I915_READ(WM_MISC);
-               if (results->partitioning == INTEL_DDB_PART_1_2)
-                       val &= ~WM_MISC_DATA_PARTITION_5_6;
-               else
-                       val |= WM_MISC_DATA_PARTITION_5_6;
-               I915_WRITE(WM_MISC, val);
+               if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+                       val = I915_READ(WM_MISC);
+                       if (results->partitioning == INTEL_DDB_PART_1_2)
+                               val &= ~WM_MISC_DATA_PARTITION_5_6;
+                       else
+                               val |= WM_MISC_DATA_PARTITION_5_6;
+                       I915_WRITE(WM_MISC, val);
+               } else {
+                       val = I915_READ(DISP_ARB_CTL2);
+                       if (results->partitioning == INTEL_DDB_PART_1_2)
+                               val &= ~DISP_DATA_PARTITION_5_6;
+                       else
+                               val |= DISP_DATA_PARTITION_5_6;
+                       I915_WRITE(DISP_ARB_CTL2, val);
+               }
        }
 
        if (dirty & WM_DIRTY_FBC) {
@@ -2905,37 +2501,48 @@ static void hsw_write_wm_values(struct drm_i915_private *dev_priv,
                I915_WRITE(DISP_ARB_CTL, val);
        }
 
-       if (dirty & WM_DIRTY_LP(1) && previous->wm_lp_spr[0] != results->wm_lp_spr[0])
+       if (dirty & WM_DIRTY_LP(1) &&
+           previous->wm_lp_spr[0] != results->wm_lp_spr[0])
                I915_WRITE(WM1S_LP_ILK, results->wm_lp_spr[0]);
-       if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1])
-               I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]);
-       if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2])
-               I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]);
 
-       if (dirty & WM_DIRTY_LP(1) && results->wm_lp[0] != 0)
+       if (INTEL_INFO(dev)->gen >= 7) {
+               if (dirty & WM_DIRTY_LP(2) && previous->wm_lp_spr[1] != results->wm_lp_spr[1])
+                       I915_WRITE(WM2S_LP_IVB, results->wm_lp_spr[1]);
+               if (dirty & WM_DIRTY_LP(3) && previous->wm_lp_spr[2] != results->wm_lp_spr[2])
+                       I915_WRITE(WM3S_LP_IVB, results->wm_lp_spr[2]);
+       }
+
+       if (dirty & WM_DIRTY_LP(1) && previous->wm_lp[0] != results->wm_lp[0])
                I915_WRITE(WM1_LP_ILK, results->wm_lp[0]);
-       if (dirty & WM_DIRTY_LP(2) && results->wm_lp[1] != 0)
+       if (dirty & WM_DIRTY_LP(2) && previous->wm_lp[1] != results->wm_lp[1])
                I915_WRITE(WM2_LP_ILK, results->wm_lp[1]);
-       if (dirty & WM_DIRTY_LP(3) && results->wm_lp[2] != 0)
+       if (dirty & WM_DIRTY_LP(3) && previous->wm_lp[2] != results->wm_lp[2])
                I915_WRITE(WM3_LP_ILK, results->wm_lp[2]);
 
        dev_priv->wm.hw = *results;
 }
 
-static void haswell_update_wm(struct drm_crtc *crtc)
+static bool ilk_disable_lp_wm(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       return _ilk_disable_lp_wm(dev_priv, WM_DIRTY_LP_ALL);
+}
+
+static void ilk_update_wm(struct drm_crtc *crtc)
 {
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct hsw_wm_maximums max;
-       struct hsw_pipe_wm_parameters params = {};
-       struct hsw_wm_values results = {};
+       struct ilk_wm_maximums max;
+       struct ilk_pipe_wm_parameters params = {};
+       struct ilk_wm_values results = {};
        enum intel_ddb_partitioning partitioning;
        struct intel_pipe_wm pipe_wm = {};
        struct intel_pipe_wm lp_wm_1_2 = {}, lp_wm_5_6 = {}, *best_lp_wm;
        struct intel_wm_config config = {};
 
-       hsw_compute_wm_parameters(crtc, &params, &config);
+       ilk_compute_wm_parameters(crtc, &params, &config);
 
        intel_compute_pipe_wm(crtc, &params, &pipe_wm);
 
@@ -2945,15 +2552,15 @@ static void haswell_update_wm(struct drm_crtc *crtc)
        intel_crtc->wm.active = pipe_wm;
 
        ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_1_2, &max);
-       ilk_wm_merge(dev, &max, &lp_wm_1_2);
+       ilk_wm_merge(dev, &config, &max, &lp_wm_1_2);
 
        /* 5/6 split only in single pipe config on IVB+ */
        if (INTEL_INFO(dev)->gen >= 7 &&
            config.num_pipes_active == 1 && config.sprites_enabled) {
                ilk_compute_wm_maximums(dev, 1, &config, INTEL_DDB_PART_5_6, &max);
-               ilk_wm_merge(dev, &max, &lp_wm_5_6);
+               ilk_wm_merge(dev, &config, &max, &lp_wm_5_6);
 
-               best_lp_wm = hsw_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6);
+               best_lp_wm = ilk_find_best_result(dev, &lp_wm_1_2, &lp_wm_5_6);
        } else {
                best_lp_wm = &lp_wm_1_2;
        }
@@ -2961,193 +2568,42 @@ static void haswell_update_wm(struct drm_crtc *crtc)
        partitioning = (best_lp_wm == &lp_wm_1_2) ?
                       INTEL_DDB_PART_1_2 : INTEL_DDB_PART_5_6;
 
-       hsw_compute_wm_results(dev, best_lp_wm, partitioning, &results);
+       ilk_compute_wm_results(dev, best_lp_wm, partitioning, &results);
 
-       hsw_write_wm_values(dev_priv, &results);
+       ilk_write_wm_values(dev_priv, &results);
 }
 
-static void haswell_update_sprite_wm(struct drm_plane *plane,
+static void ilk_update_sprite_wm(struct drm_plane *plane,
                                     struct drm_crtc *crtc,
                                     uint32_t sprite_width, int pixel_size,
                                     bool enabled, bool scaled)
-{
-       struct intel_plane *intel_plane = to_intel_plane(plane);
-
-       intel_plane->wm.enabled = enabled;
-       intel_plane->wm.scaled = scaled;
-       intel_plane->wm.horiz_pixels = sprite_width;
-       intel_plane->wm.bytes_per_pixel = pixel_size;
-
-       haswell_update_wm(crtc);
-}
-
-static bool
-sandybridge_compute_sprite_wm(struct drm_device *dev, int plane,
-                             uint32_t sprite_width, int pixel_size,
-                             const struct intel_watermark_params *display,
-                             int display_latency_ns, int *sprite_wm)
-{
-       struct drm_crtc *crtc;
-       int clock;
-       int entries, tlb_miss;
-
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       if (!intel_crtc_active(crtc)) {
-               *sprite_wm = display->guard_size;
-               return false;
-       }
-
-       clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
-
-       /* Use the small buffer method to calculate the sprite watermark */
-       entries = ((clock * pixel_size / 1000) * display_latency_ns) / 1000;
-       tlb_miss = display->fifo_size*display->cacheline_size -
-               sprite_width * 8;
-       if (tlb_miss > 0)
-               entries += tlb_miss;
-       entries = DIV_ROUND_UP(entries, display->cacheline_size);
-       *sprite_wm = entries + display->guard_size;
-       if (*sprite_wm > (int)display->max_wm)
-               *sprite_wm = display->max_wm;
-
-       return true;
-}
-
-static bool
-sandybridge_compute_sprite_srwm(struct drm_device *dev, int plane,
-                               uint32_t sprite_width, int pixel_size,
-                               const struct intel_watermark_params *display,
-                               int latency_ns, int *sprite_wm)
-{
-       struct drm_crtc *crtc;
-       unsigned long line_time_us;
-       int clock;
-       int line_count, line_size;
-       int small, large;
-       int entries;
-
-       if (!latency_ns) {
-               *sprite_wm = 0;
-               return false;
-       }
-
-       crtc = intel_get_crtc_for_plane(dev, plane);
-       clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
-       if (!clock) {
-               *sprite_wm = 0;
-               return false;
-       }
-
-       line_time_us = (sprite_width * 1000) / clock;
-       if (!line_time_us) {
-               *sprite_wm = 0;
-               return false;
-       }
-
-       line_count = (latency_ns / line_time_us + 1000) / 1000;
-       line_size = sprite_width * pixel_size;
-
-       /* Use the minimum of the small and large buffer method for primary */
-       small = ((clock * pixel_size / 1000) * latency_ns) / 1000;
-       large = line_count * line_size;
-
-       entries = DIV_ROUND_UP(min(small, large), display->cacheline_size);
-       *sprite_wm = entries + display->guard_size;
-
-       return *sprite_wm > 0x3ff ? false : true;
-}
-
-static void sandybridge_update_sprite_wm(struct drm_plane *plane,
-                                        struct drm_crtc *crtc,
-                                        uint32_t sprite_width, int pixel_size,
-                                        bool enabled, bool scaled)
 {
        struct drm_device *dev = plane->dev;
-       struct drm_i915_private *dev_priv = dev->dev_private;
-       int pipe = to_intel_plane(plane)->pipe;
-       int latency = dev_priv->wm.spr_latency[0] * 100;        /* In unit 0.1us */
-       u32 val;
-       int sprite_wm, reg;
-       int ret;
-
-       if (!enabled)
-               return;
-
-       switch (pipe) {
-       case 0:
-               reg = WM0_PIPEA_ILK;
-               break;
-       case 1:
-               reg = WM0_PIPEB_ILK;
-               break;
-       case 2:
-               reg = WM0_PIPEC_IVB;
-               break;
-       default:
-               return; /* bad pipe */
-       }
-
-       ret = sandybridge_compute_sprite_wm(dev, pipe, sprite_width, pixel_size,
-                                           &sandybridge_display_wm_info,
-                                           latency, &sprite_wm);
-       if (!ret) {
-               DRM_DEBUG_KMS("failed to compute sprite wm for pipe %c\n",
-                             pipe_name(pipe));
-               return;
-       }
-
-       val = I915_READ(reg);
-       val &= ~WM0_PIPE_SPRITE_MASK;
-       I915_WRITE(reg, val | (sprite_wm << WM0_PIPE_SPRITE_SHIFT));
-       DRM_DEBUG_KMS("sprite watermarks For pipe %c - %d\n", pipe_name(pipe), sprite_wm);
-
-
-       ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
-                                             pixel_size,
-                                             &sandybridge_display_srwm_info,
-                                             dev_priv->wm.spr_latency[1] * 500,
-                                             &sprite_wm);
-       if (!ret) {
-               DRM_DEBUG_KMS("failed to compute sprite lp1 wm on pipe %c\n",
-                             pipe_name(pipe));
-               return;
-       }
-       I915_WRITE(WM1S_LP_ILK, sprite_wm);
+       struct intel_plane *intel_plane = to_intel_plane(plane);
 
-       /* Only IVB has two more LP watermarks for sprite */
-       if (!IS_IVYBRIDGE(dev))
-               return;
+       intel_plane->wm.enabled = enabled;
+       intel_plane->wm.scaled = scaled;
+       intel_plane->wm.horiz_pixels = sprite_width;
+       intel_plane->wm.bytes_per_pixel = pixel_size;
 
-       ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
-                                             pixel_size,
-                                             &sandybridge_display_srwm_info,
-                                             dev_priv->wm.spr_latency[2] * 500,
-                                             &sprite_wm);
-       if (!ret) {
-               DRM_DEBUG_KMS("failed to compute sprite lp2 wm on pipe %c\n",
-                             pipe_name(pipe));
-               return;
-       }
-       I915_WRITE(WM2S_LP_IVB, sprite_wm);
+       /*
+        * IVB workaround: must disable low power watermarks for at least
+        * one frame before enabling scaling.  LP watermarks can be re-enabled
+        * when scaling is disabled.
+        *
+        * WaCxSRDisabledForSpriteScaling:ivb
+        */
+       if (IS_IVYBRIDGE(dev) && scaled && ilk_disable_lp_wm(dev))
+               intel_wait_for_vblank(dev, intel_plane->pipe);
 
-       ret = sandybridge_compute_sprite_srwm(dev, pipe, sprite_width,
-                                             pixel_size,
-                                             &sandybridge_display_srwm_info,
-                                             dev_priv->wm.spr_latency[3] * 500,
-                                             &sprite_wm);
-       if (!ret) {
-               DRM_DEBUG_KMS("failed to compute sprite lp3 wm on pipe %c\n",
-                             pipe_name(pipe));
-               return;
-       }
-       I915_WRITE(WM3S_LP_IVB, sprite_wm);
+       ilk_update_wm(crtc);
 }
 
 static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct hsw_wm_values *hw = &dev_priv->wm.hw;
+       struct ilk_wm_values *hw = &dev_priv->wm.hw;
        struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
        struct intel_pipe_wm *active = &intel_crtc->wm.active;
        enum pipe pipe = intel_crtc->pipe;
@@ -3158,7 +2614,8 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
        };
 
        hw->wm_pipe[pipe] = I915_READ(wm0_pipe_reg[pipe]);
-       hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe));
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               hw->wm_linetime[pipe] = I915_READ(PIPE_WM_LINETIME(pipe));
 
        if (intel_crtc_active(crtc)) {
                u32 tmp = hw->wm_pipe[pipe];
@@ -3190,7 +2647,7 @@ static void ilk_pipe_wm_get_hw_state(struct drm_crtc *crtc)
 void ilk_wm_get_hw_state(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       struct hsw_wm_values *hw = &dev_priv->wm.hw;
+       struct ilk_wm_values *hw = &dev_priv->wm.hw;
        struct drm_crtc *crtc;
 
        list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
@@ -3204,8 +2661,12 @@ void ilk_wm_get_hw_state(struct drm_device *dev)
        hw->wm_lp_spr[1] = I915_READ(WM2S_LP_IVB);
        hw->wm_lp_spr[2] = I915_READ(WM3S_LP_IVB);
 
-       hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
-               INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
+       if (IS_HASWELL(dev) || IS_BROADWELL(dev))
+               hw->partitioning = (I915_READ(WM_MISC) & WM_MISC_DATA_PARTITION_5_6) ?
+                       INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
+       else if (IS_IVYBRIDGE(dev))
+               hw->partitioning = (I915_READ(DISP_ARB_CTL2) & DISP_DATA_PARTITION_5_6) ?
+                       INTEL_DDB_PART_5_6 : INTEL_DDB_PART_1_2;
 
        hw->enable_fbc_wm =
                !(I915_READ(DISP_ARB_CTL) & DISP_FBC_WM_DIS);
@@ -3430,26 +2891,19 @@ static void ironlake_disable_drps(struct drm_device *dev)
  * ourselves, instead of doing a rmw cycle (which might result in us clearing
  * all limits and the gpu stuck at whatever frequency it is at atm).
  */
-static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 *val)
+static u32 gen6_rps_limits(struct drm_i915_private *dev_priv, u8 val)
 {
        u32 limits;
 
-       limits = 0;
-
-       if (*val >= dev_priv->rps.max_delay)
-               *val = dev_priv->rps.max_delay;
-       limits |= dev_priv->rps.max_delay << 24;
-
        /* Only set the down limit when we've reached the lowest level to avoid
         * getting more interrupts, otherwise leave this clear. This prevents a
         * race in the hw when coming out of rc6: There's a tiny window where
         * the hw runs at the minimal clock before selecting the desired
         * frequency, if the down threshold expires in that window we will not
         * receive a down interrupt. */
-       if (*val <= dev_priv->rps.min_delay) {
-               *val = dev_priv->rps.min_delay;
+       limits = dev_priv->rps.max_delay << 24;
+       if (val <= dev_priv->rps.min_delay)
                limits |= dev_priv->rps.min_delay << 16;
-       }
 
        return limits;
 }
@@ -3549,7 +3003,6 @@ static void gen6_set_rps_thresholds(struct drm_i915_private *dev_priv, u8 val)
 void gen6_set_rps(struct drm_device *dev, u8 val)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
-       u32 limits = gen6_rps_limits(dev_priv, &val);
 
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
        WARN_ON(val > dev_priv->rps.max_delay);
@@ -3572,7 +3025,8 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
        /* Make sure we continue to get interrupts
         * until we hit the minimum or maximum frequencies.
         */
-       I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, limits);
+       I915_WRITE(GEN6_RP_INTERRUPT_LIMITS,
+                  gen6_rps_limits(dev_priv, val));
 
        POSTING_READ(GEN6_RPNSWREQ);
 
@@ -3583,9 +3037,11 @@ void gen6_set_rps(struct drm_device *dev, u8 val)
 
 void gen6_rps_idle(struct drm_i915_private *dev_priv)
 {
+       struct drm_device *dev = dev_priv->dev;
+
        mutex_lock(&dev_priv->rps.hw_lock);
        if (dev_priv->rps.enabled) {
-               if (dev_priv->info->is_valleyview)
+               if (IS_VALLEYVIEW(dev))
                        valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_delay);
                else
                        gen6_set_rps(dev_priv->dev, dev_priv->rps.min_delay);
@@ -3596,9 +3052,11 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
 
 void gen6_rps_boost(struct drm_i915_private *dev_priv)
 {
+       struct drm_device *dev = dev_priv->dev;
+
        mutex_lock(&dev_priv->rps.hw_lock);
        if (dev_priv->rps.enabled) {
-               if (dev_priv->info->is_valleyview)
+               if (IS_VALLEYVIEW(dev))
                        valleyview_set_rps(dev_priv->dev, dev_priv->rps.max_delay);
                else
                        gen6_set_rps(dev_priv->dev, dev_priv->rps.max_delay);
@@ -3607,48 +3065,18 @@ void gen6_rps_boost(struct drm_i915_private *dev_priv)
        mutex_unlock(&dev_priv->rps.hw_lock);
 }
 
-/*
- * Wait until the previous freq change has completed,
- * or the timeout elapsed, and then update our notion
- * of the current GPU frequency.
- */
-static void vlv_update_rps_cur_delay(struct drm_i915_private *dev_priv)
-{
-       u32 pval;
-
-       WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
-
-       if (wait_for(((pval = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS)) & GENFREQSTATUS) == 0, 10))
-               DRM_DEBUG_DRIVER("timed out waiting for Punit\n");
-
-       pval >>= 8;
-
-       if (pval != dev_priv->rps.cur_delay)
-               DRM_DEBUG_DRIVER("Punit overrode GPU freq: %d MHz (%u) requested, but got %d Mhz (%u)\n",
-                                vlv_gpu_freq(dev_priv->mem_freq, dev_priv->rps.cur_delay),
-                                dev_priv->rps.cur_delay,
-                                vlv_gpu_freq(dev_priv->mem_freq, pval), pval);
-
-       dev_priv->rps.cur_delay = pval;
-}
-
 void valleyview_set_rps(struct drm_device *dev, u8 val)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       gen6_rps_limits(dev_priv, &val);
-
        WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
        WARN_ON(val > dev_priv->rps.max_delay);
        WARN_ON(val < dev_priv->rps.min_delay);
 
-       vlv_update_rps_cur_delay(dev_priv);
-
        DRM_DEBUG_DRIVER("GPU freq request from %d MHz (%u) to %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv->mem_freq,
-                                     dev_priv->rps.cur_delay),
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay),
                         dev_priv->rps.cur_delay,
-                        vlv_gpu_freq(dev_priv->mem_freq, val), val);
+                        vlv_gpu_freq(dev_priv, val), val);
 
        if (val == dev_priv->rps.cur_delay)
                return;
@@ -3657,7 +3085,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
 
        dev_priv->rps.cur_delay = val;
 
-       trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv->mem_freq, val));
+       trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
 }
 
 static void gen6_disable_rps_interrupts(struct drm_device *dev)
@@ -3775,7 +3203,7 @@ static void gen8_enable_rps(struct drm_device *dev)
 
        /* 1c & 1d: Get forcewake during program sequence. Although the driver
         * hasn't enabled a state yet where we need forcewake, BIOS may have.*/
-       gen6_gt_force_wake_get(dev_priv);
+       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
        /* 2a: Disable RC states. */
        I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -3832,7 +3260,7 @@ static void gen8_enable_rps(struct drm_device *dev)
 
        gen6_enable_rps_interrupts(dev);
 
-       gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 static void gen6_enable_rps(struct drm_device *dev)
@@ -3862,7 +3290,7 @@ static void gen6_enable_rps(struct drm_device *dev)
                I915_WRITE(GTFIFODBG, gtfifodbg);
        }
 
-       gen6_gt_force_wake_get(dev_priv);
+       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);
@@ -3954,7 +3382,7 @@ static void gen6_enable_rps(struct drm_device *dev)
                        DRM_ERROR("Couldn't fix incorrect rc6 voltage\n");
        }
 
-       gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 void gen6_update_ring_freq(struct drm_device *dev)
@@ -4116,7 +3544,8 @@ static void valleyview_enable_rps(struct drm_device *dev)
 
        valleyview_setup_pctx(dev);
 
-       gen6_gt_force_wake_get(dev_priv);
+       /* If VLV, Forcewake all wells, else re-direct to regular path */
+       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
        I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
        I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
@@ -4140,7 +3569,7 @@ static void valleyview_enable_rps(struct drm_device *dev)
        for_each_ring(ring, dev_priv, i)
                I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
 
-       I915_WRITE(GEN6_RC6_THRESHOLD, 0xc350);
+       I915_WRITE(GEN6_RC6_THRESHOLD, 0x557);
 
        /* allows RC6 residency counter to work */
        I915_WRITE(VLV_COUNTER_CONTROL,
@@ -4148,65 +3577,47 @@ static void valleyview_enable_rps(struct drm_device *dev)
                                      VLV_MEDIA_RC6_COUNT_EN |
                                      VLV_RENDER_RC6_COUNT_EN));
        if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
-               rc6_mode = GEN7_RC_CTL_TO_MODE;
+               rc6_mode = GEN7_RC_CTL_TO_MODE | VLV_RC_CTL_CTX_RST_PARALLEL;
 
        intel_print_rc6_info(dev, rc6_mode);
 
        I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
 
        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);
 
        DRM_DEBUG_DRIVER("GPLL enabled? %s\n", val & 0x10 ? "yes" : "no");
        DRM_DEBUG_DRIVER("GPU status: 0x%08x\n", val);
 
        dev_priv->rps.cur_delay = (val >> 8) & 0xff;
        DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv->mem_freq,
-                                     dev_priv->rps.cur_delay),
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.cur_delay),
                         dev_priv->rps.cur_delay);
 
        dev_priv->rps.max_delay = valleyview_rps_max_freq(dev_priv);
        dev_priv->rps.hw_max = dev_priv->rps.max_delay;
        DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv->mem_freq,
-                                     dev_priv->rps.max_delay),
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.max_delay),
                         dev_priv->rps.max_delay);
 
        dev_priv->rps.rpe_delay = valleyview_rps_rpe_freq(dev_priv);
        DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv->mem_freq,
-                                     dev_priv->rps.rpe_delay),
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay),
                         dev_priv->rps.rpe_delay);
 
        dev_priv->rps.min_delay = valleyview_rps_min_freq(dev_priv);
        DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv->mem_freq,
-                                     dev_priv->rps.min_delay),
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.min_delay),
                         dev_priv->rps.min_delay);
 
        DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
-                        vlv_gpu_freq(dev_priv->mem_freq,
-                                     dev_priv->rps.rpe_delay),
+                        vlv_gpu_freq(dev_priv, dev_priv->rps.rpe_delay),
                         dev_priv->rps.rpe_delay);
 
        valleyview_set_rps(dev_priv->dev, dev_priv->rps.rpe_delay);
 
        gen6_enable_rps_interrupts(dev);
 
-       gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 }
 
 void ironlake_teardown_rc6(struct drm_device *dev)
@@ -5019,6 +4430,20 @@ static void g4x_disable_trickle_feed(struct drm_device *dev)
        }
 }
 
+static void ilk_init_lp_watermarks(struct drm_device *dev)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       I915_WRITE(WM3_LP_ILK, I915_READ(WM3_LP_ILK) & ~WM1_LP_SR_EN);
+       I915_WRITE(WM2_LP_ILK, I915_READ(WM2_LP_ILK) & ~WM1_LP_SR_EN);
+       I915_WRITE(WM1_LP_ILK, I915_READ(WM1_LP_ILK) & ~WM1_LP_SR_EN);
+
+       /*
+        * Don't touch WM1S_LP_EN here.
+        * Doing so could cause underruns.
+        */
+}
+
 static void ironlake_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5052,9 +4477,8 @@ static void ironlake_init_clock_gating(struct drm_device *dev)
        I915_WRITE(DISP_ARB_CTL,
                   (I915_READ(DISP_ARB_CTL) |
                    DISP_FBC_WM_DIS));
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
+
+       ilk_init_lp_watermarks(dev);
 
        /*
         * Based on the document from hardware guys the following bits
@@ -5161,9 +4585,7 @@ static void gen6_init_clock_gating(struct drm_device *dev)
                I915_WRITE(GEN6_GT_MODE,
                           _MASKED_BIT_ENABLE(GEN6_TD_FOUR_ROW_DISPATCH_DISABLE));
 
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
+       ilk_init_lp_watermarks(dev);
 
        I915_WRITE(CACHE_MODE_0,
                   _MASKED_BIT_DISABLE(CM0_STC_EVICT_DISABLE_LRA_SNB));
@@ -5304,28 +4726,40 @@ static void gen8_init_clock_gating(struct drm_device *dev)
        I915_WRITE(GEN7_HALF_SLICE_CHICKEN1,
                   _MASKED_BIT_ENABLE(GEN7_SINGLE_SUBSCAN_DISPATCH_ENABLE));
 
-       /* WaSwitchSolVfFArbitrationPriority */
+       /* WaSwitchSolVfFArbitrationPriority:bdw */
        I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
 
-       /* WaPsrDPAMaskVBlankInSRD */
+       /* WaPsrDPAMaskVBlankInSRD:bdw */
        I915_WRITE(CHICKEN_PAR1_1,
                   I915_READ(CHICKEN_PAR1_1) | DPA_MASK_VBLANK_SRD);
 
-       /* WaPsrDPRSUnmaskVBlankInSRD */
+       /* WaPsrDPRSUnmaskVBlankInSRD:bdw */
        for_each_pipe(i) {
                I915_WRITE(CHICKEN_PIPESL_1(i),
                           I915_READ(CHICKEN_PIPESL_1(i) |
                                     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));
 }
 
 static void haswell_init_clock_gating(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
+       ilk_init_lp_watermarks(dev);
 
        /* According to the spec, bit 13 (RCZUNIT) must be set on IVB.
         * This implements the WaDisableRCZUnitClockGating:hsw workaround.
@@ -5374,9 +4808,7 @@ static void ivybridge_init_clock_gating(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        uint32_t snpcr;
 
-       I915_WRITE(WM3_LP_ILK, 0);
-       I915_WRITE(WM2_LP_ILK, 0);
-       I915_WRITE(WM1_LP_ILK, 0);
+       ilk_init_lp_watermarks(dev);
 
        I915_WRITE(ILK_DSPCLK_GATE_D, ILK_VRHUNIT_CLOCK_GATE_DISABLE);
 
@@ -5463,6 +4895,26 @@ 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:
+               dev_priv->mem_freq = 800;
+               break;
+       case 1:
+               dev_priv->mem_freq = 1066;
+               break;
+       case 2:
+               dev_priv->mem_freq = 1333;
+               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);
 
@@ -5642,50 +5094,133 @@ void intel_suspend_hw(struct drm_device *dev)
                lpt_suspend_hw(dev);
 }
 
-static bool is_always_on_power_domain(struct drm_device *dev,
-                                     enum intel_display_power_domain domain)
-{
-       unsigned long always_on_domains;
-
-       BUG_ON(BIT(domain) & ~POWER_DOMAIN_MASK);
-
-       if (IS_BROADWELL(dev)) {
-               always_on_domains = BDW_ALWAYS_ON_POWER_DOMAINS;
-       } else if (IS_HASWELL(dev)) {
-               always_on_domains = HSW_ALWAYS_ON_POWER_DOMAINS;
-       } else {
-               WARN_ON(1);
-               return true;
-       }
+#define for_each_power_well(i, power_well, domain_mask, power_domains) \
+       for (i = 0;                                                     \
+            i < (power_domains)->power_well_count &&                   \
+                ((power_well) = &(power_domains)->power_wells[i]);     \
+            i++)                                                       \
+               if ((power_well)->domains & (domain_mask))
 
-       return BIT(domain) & always_on_domains;
-}
+#define for_each_power_well_rev(i, power_well, domain_mask, power_domains) \
+       for (i = (power_domains)->power_well_count - 1;                  \
+            i >= 0 && ((power_well) = &(power_domains)->power_wells[i]);\
+            i--)                                                        \
+               if ((power_well)->domains & (domain_mask))
 
 /**
  * We should only use the power well if we explicitly asked the hardware to
  * enable it, so check if it's enabled and also check if we've requested it to
  * be enabled.
  */
+static bool hsw_power_well_enabled(struct drm_device *dev,
+                                  struct i915_power_well *power_well)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+
+       return I915_READ(HSW_PWR_WELL_DRIVER) ==
+                    (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
+}
+
+bool intel_display_power_enabled_sw(struct drm_device *dev,
+                                   enum intel_display_power_domain domain)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_power_domains *power_domains;
+
+       power_domains = &dev_priv->power_domains;
+
+       return power_domains->domain_use_count[domain];
+}
+
 bool intel_display_power_enabled(struct drm_device *dev,
                                 enum intel_display_power_domain domain)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
+       struct i915_power_domains *power_domains;
+       struct i915_power_well *power_well;
+       bool is_enabled;
+       int i;
+
+       power_domains = &dev_priv->power_domains;
 
-       if (!HAS_POWER_WELL(dev))
-               return true;
+       is_enabled = true;
 
-       if (is_always_on_power_domain(dev, domain))
-               return true;
+       mutex_lock(&power_domains->lock);
+       for_each_power_well_rev(i, power_well, BIT(domain), power_domains) {
+               if (power_well->always_on)
+                       continue;
 
-       return I915_READ(HSW_PWR_WELL_DRIVER) ==
-                    (HSW_PWR_WELL_ENABLE_REQUEST | HSW_PWR_WELL_STATE_ENABLED);
+               if (!power_well->is_enabled(dev, power_well)) {
+                       is_enabled = false;
+                       break;
+               }
+       }
+       mutex_unlock(&power_domains->lock);
+
+       return is_enabled;
+}
+
+static void hsw_power_well_post_enable(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       unsigned long irqflags;
+
+       /*
+        * After we re-enable the power well, if we touch VGA register 0x3d5
+        * we'll get unclaimed register interrupts. This stops after we write
+        * anything to the VGA MSR register. The vgacon module uses this
+        * register all the time, so if we unbind our driver and, as a
+        * consequence, bind vgacon, we'll get stuck in an infinite loop at
+        * console_unlock(). So make here we touch the VGA MSR register, making
+        * sure vgacon can keep working normally without triggering interrupts
+        * and error messages.
+        */
+       vga_get_uninterruptible(dev->pdev, VGA_RSRC_LEGACY_IO);
+       outb(inb(VGA_MSR_READ), VGA_MSR_WRITE);
+       vga_put(dev->pdev, VGA_RSRC_LEGACY_IO);
+
+       if (IS_BROADWELL(dev)) {
+               spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
+               I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B),
+                          dev_priv->de_irq_mask[PIPE_B]);
+               I915_WRITE(GEN8_DE_PIPE_IER(PIPE_B),
+                          ~dev_priv->de_irq_mask[PIPE_B] |
+                          GEN8_PIPE_VBLANK);
+               I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_C),
+                          dev_priv->de_irq_mask[PIPE_C]);
+               I915_WRITE(GEN8_DE_PIPE_IER(PIPE_C),
+                          ~dev_priv->de_irq_mask[PIPE_C] |
+                          GEN8_PIPE_VBLANK);
+               POSTING_READ(GEN8_DE_PIPE_IER(PIPE_C));
+               spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
+       }
+}
+
+static void hsw_power_well_post_disable(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       enum pipe p;
+       unsigned long irqflags;
+
+       /*
+        * After this, the registers on the pipes that are part of the power
+        * well will become zero, so we have to adjust our counters according to
+        * that.
+        *
+        * FIXME: Should we do this in general in drm_vblank_post_modeset?
+        */
+       spin_lock_irqsave(&dev->vbl_lock, irqflags);
+       for_each_pipe(p)
+               if (p != PIPE_A)
+                       dev->vblank[p].last = 0;
+       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
 }
 
-static void __intel_set_power_well(struct drm_device *dev, bool enable)
+static void hsw_set_power_well(struct drm_device *dev,
+                              struct i915_power_well *power_well, bool enable)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        bool is_enabled, enable_requested;
-       unsigned long irqflags;
        uint32_t tmp;
 
        WARN_ON(dev_priv->pc8.enabled);
@@ -5706,42 +5241,14 @@ static void __intel_set_power_well(struct drm_device *dev, bool enable)
                                DRM_ERROR("Timeout enabling power well\n");
                }
 
-               if (IS_BROADWELL(dev)) {
-                       spin_lock_irqsave(&dev_priv->irq_lock, irqflags);
-                       I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_B),
-                                  dev_priv->de_irq_mask[PIPE_B]);
-                       I915_WRITE(GEN8_DE_PIPE_IER(PIPE_B),
-                                  ~dev_priv->de_irq_mask[PIPE_B] |
-                                  GEN8_PIPE_VBLANK);
-                       I915_WRITE(GEN8_DE_PIPE_IMR(PIPE_C),
-                                  dev_priv->de_irq_mask[PIPE_C]);
-                       I915_WRITE(GEN8_DE_PIPE_IER(PIPE_C),
-                                  ~dev_priv->de_irq_mask[PIPE_C] |
-                                  GEN8_PIPE_VBLANK);
-                       POSTING_READ(GEN8_DE_PIPE_IER(PIPE_C));
-                       spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
-               }
+               hsw_power_well_post_enable(dev_priv);
        } else {
                if (enable_requested) {
-                       enum pipe p;
-
                        I915_WRITE(HSW_PWR_WELL_DRIVER, 0);
                        POSTING_READ(HSW_PWR_WELL_DRIVER);
                        DRM_DEBUG_KMS("Requesting to disable the power well\n");
 
-                       /*
-                        * After this, the registers on the pipes that are part
-                        * of the power well will become zero, so we have to
-                        * adjust our counters according to that.
-                        *
-                        * FIXME: Should we do this in general in
-                        * drm_vblank_post_modeset?
-                        */
-                       spin_lock_irqsave(&dev->vbl_lock, irqflags);
-                       for_each_pipe(p)
-                               if (p != PIPE_A)
-                                       dev->vblank[p].last = 0;
-                       spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
+                       hsw_power_well_post_disable(dev_priv);
                }
        }
 }
@@ -5751,9 +5258,9 @@ static void __intel_power_well_get(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (!power_well->count++) {
+       if (!power_well->count++ && power_well->set) {
                hsw_disable_package_c8(dev_priv);
-               __intel_set_power_well(dev, true);
+               power_well->set(dev, power_well, true);
        }
 }
 
@@ -5763,8 +5270,10 @@ static void __intel_power_well_put(struct drm_device *dev,
        struct drm_i915_private *dev_priv = dev->dev_private;
 
        WARN_ON(!power_well->count);
-       if (!--power_well->count && i915_disable_power_well) {
-               __intel_set_power_well(dev, false);
+
+       if (!--power_well->count && power_well->set &&
+           i915_disable_power_well) {
+               power_well->set(dev, power_well, false);
                hsw_enable_package_c8(dev_priv);
        }
 }
@@ -5774,17 +5283,18 @@ void intel_display_power_get(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains;
-
-       if (!HAS_POWER_WELL(dev))
-               return;
-
-       if (is_always_on_power_domain(dev, domain))
-               return;
+       struct i915_power_well *power_well;
+       int i;
 
        power_domains = &dev_priv->power_domains;
 
        mutex_lock(&power_domains->lock);
-       __intel_power_well_get(dev, &power_domains->power_wells[0]);
+
+       for_each_power_well(i, power_well, BIT(domain), power_domains)
+               __intel_power_well_get(dev, power_well);
+
+       power_domains->domain_use_count[domain]++;
+
        mutex_unlock(&power_domains->lock);
 }
 
@@ -5793,17 +5303,19 @@ void intel_display_power_put(struct drm_device *dev,
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains;
-
-       if (!HAS_POWER_WELL(dev))
-               return;
-
-       if (is_always_on_power_domain(dev, domain))
-               return;
+       struct i915_power_well *power_well;
+       int i;
 
        power_domains = &dev_priv->power_domains;
 
        mutex_lock(&power_domains->lock);
-       __intel_power_well_put(dev, &power_domains->power_wells[0]);
+
+       WARN_ON(!power_domains->domain_use_count[domain]);
+       power_domains->domain_use_count[domain]--;
+
+       for_each_power_well_rev(i, power_well, BIT(domain), power_domains)
+               __intel_power_well_put(dev, power_well);
+
        mutex_unlock(&power_domains->lock);
 }
 
@@ -5819,10 +5331,7 @@ void i915_request_power_well(void)
 
        dev_priv = container_of(hsw_pwr, struct drm_i915_private,
                                power_domains);
-
-       mutex_lock(&hsw_pwr->lock);
-       __intel_power_well_get(dev_priv->dev, &hsw_pwr->power_wells[0]);
-       mutex_unlock(&hsw_pwr->lock);
+       intel_display_power_get(dev_priv->dev, POWER_DOMAIN_AUDIO);
 }
 EXPORT_SYMBOL_GPL(i915_request_power_well);
 
@@ -5836,24 +5345,71 @@ void i915_release_power_well(void)
 
        dev_priv = container_of(hsw_pwr, struct drm_i915_private,
                                power_domains);
-
-       mutex_lock(&hsw_pwr->lock);
-       __intel_power_well_put(dev_priv->dev, &hsw_pwr->power_wells[0]);
-       mutex_unlock(&hsw_pwr->lock);
+       intel_display_power_put(dev_priv->dev, POWER_DOMAIN_AUDIO);
 }
 EXPORT_SYMBOL_GPL(i915_release_power_well);
 
+static struct i915_power_well i9xx_always_on_power_well[] = {
+       {
+               .name = "always-on",
+               .always_on = 1,
+               .domains = POWER_DOMAIN_MASK,
+       },
+};
+
+static struct i915_power_well hsw_power_wells[] = {
+       {
+               .name = "always-on",
+               .always_on = 1,
+               .domains = HSW_ALWAYS_ON_POWER_DOMAINS,
+       },
+       {
+               .name = "display",
+               .domains = POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS,
+               .is_enabled = hsw_power_well_enabled,
+               .set = hsw_set_power_well,
+       },
+};
+
+static struct i915_power_well bdw_power_wells[] = {
+       {
+               .name = "always-on",
+               .always_on = 1,
+               .domains = BDW_ALWAYS_ON_POWER_DOMAINS,
+       },
+       {
+               .name = "display",
+               .domains = POWER_DOMAIN_MASK & ~BDW_ALWAYS_ON_POWER_DOMAINS,
+               .is_enabled = hsw_power_well_enabled,
+               .set = hsw_set_power_well,
+       },
+};
+
+#define set_power_wells(power_domains, __power_wells) ({               \
+       (power_domains)->power_wells = (__power_wells);                 \
+       (power_domains)->power_well_count = ARRAY_SIZE(__power_wells);  \
+})
+
 int intel_power_domains_init(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
-       struct i915_power_well *power_well;
 
        mutex_init(&power_domains->lock);
-       hsw_pwr = power_domains;
 
-       power_well = &power_domains->power_wells[0];
-       power_well->count = 0;
+       /*
+        * The enabling order will be from lower to higher indexed wells,
+        * the disabling order is reversed.
+        */
+       if (IS_HASWELL(dev)) {
+               set_power_wells(power_domains, hsw_power_wells);
+               hsw_pwr = power_domains;
+       } else if (IS_BROADWELL(dev)) {
+               set_power_wells(power_domains, bdw_power_wells);
+               hsw_pwr = power_domains;
+       } else {
+               set_power_wells(power_domains, i9xx_always_on_power_well);
+       }
 
        return 0;
 }
@@ -5868,15 +5424,13 @@ static void intel_power_domains_resume(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct i915_power_domains *power_domains = &dev_priv->power_domains;
        struct i915_power_well *power_well;
-
-       if (!HAS_POWER_WELL(dev))
-               return;
+       int i;
 
        mutex_lock(&power_domains->lock);
-
-       power_well = &power_domains->power_wells[0];
-       __intel_set_power_well(dev, power_well->count > 0);
-
+       for_each_power_well(i, power_well, POWER_DOMAIN_MASK, power_domains) {
+               if (power_well->set)
+                       power_well->set(dev, power_well, power_well->count > 0);
+       }
        mutex_unlock(&power_domains->lock);
 }
 
@@ -5890,13 +5444,13 @@ void intel_power_domains_init_hw(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (!HAS_POWER_WELL(dev))
-               return;
-
        /* For now, we need the power well to be always enabled. */
        intel_display_set_init_power(dev, true);
        intel_power_domains_resume(dev);
 
+       if (!(IS_HASWELL(dev) || IS_BROADWELL(dev)))
+               return;
+
        /* We're taking over the BIOS, so clear any requests made by it since
         * the driver is in charge now. */
        if (I915_READ(HSW_PWR_WELL_BIOS) & HSW_PWR_WELL_ENABLE_REQUEST)
@@ -5914,31 +5468,86 @@ void intel_aux_display_runtime_put(struct drm_i915_private *dev_priv)
        hsw_enable_package_c8(dev_priv);
 }
 
+void intel_runtime_pm_get(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct device *device = &dev->pdev->dev;
+
+       if (!HAS_RUNTIME_PM(dev))
+               return;
+
+       pm_runtime_get_sync(device);
+       WARN(dev_priv->pm.suspended, "Device still suspended.\n");
+}
+
+void intel_runtime_pm_put(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct device *device = &dev->pdev->dev;
+
+       if (!HAS_RUNTIME_PM(dev))
+               return;
+
+       pm_runtime_mark_last_busy(device);
+       pm_runtime_put_autosuspend(device);
+}
+
+void intel_init_runtime_pm(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct device *device = &dev->pdev->dev;
+
+       dev_priv->pm.suspended = false;
+
+       if (!HAS_RUNTIME_PM(dev))
+               return;
+
+       pm_runtime_set_active(device);
+
+       pm_runtime_set_autosuspend_delay(device, 10000); /* 10s */
+       pm_runtime_mark_last_busy(device);
+       pm_runtime_use_autosuspend(device);
+}
+
+void intel_fini_runtime_pm(struct drm_i915_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+       struct device *device = &dev->pdev->dev;
+
+       if (!HAS_RUNTIME_PM(dev))
+               return;
+
+       /* Make sure we're not suspended first. */
+       pm_runtime_get_sync(device);
+       pm_runtime_disable(device);
+}
+
 /* Set up chip specific power management-related functions */
 void intel_init_pm(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
 
-       if (I915_HAS_FBC(dev)) {
-               if (HAS_PCH_SPLIT(dev)) {
+       if (HAS_FBC(dev)) {
+               if (INTEL_INFO(dev)->gen >= 7) {
                        dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
-                       if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev))
-                               dev_priv->display.enable_fbc =
-                                       gen7_enable_fbc;
-                       else
-                               dev_priv->display.enable_fbc =
-                                       ironlake_enable_fbc;
+                       dev_priv->display.enable_fbc = gen7_enable_fbc;
+                       dev_priv->display.disable_fbc = ironlake_disable_fbc;
+               } else if (INTEL_INFO(dev)->gen >= 5) {
+                       dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
+                       dev_priv->display.enable_fbc = ironlake_enable_fbc;
                        dev_priv->display.disable_fbc = ironlake_disable_fbc;
                } else if (IS_GM45(dev)) {
                        dev_priv->display.fbc_enabled = g4x_fbc_enabled;
                        dev_priv->display.enable_fbc = g4x_enable_fbc;
                        dev_priv->display.disable_fbc = g4x_disable_fbc;
-               } else if (IS_CRESTLINE(dev)) {
+               } else {
                        dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
                        dev_priv->display.enable_fbc = i8xx_enable_fbc;
                        dev_priv->display.disable_fbc = i8xx_disable_fbc;
+
+                       /* This value was pulled out of someone's hat */
+                       I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
                }
-               /* 855GM needs testing */
        }
 
        /* For cxsr */
@@ -5951,58 +5560,27 @@ void intel_init_pm(struct drm_device *dev)
        if (HAS_PCH_SPLIT(dev)) {
                intel_setup_wm_latency(dev);
 
-               if (IS_GEN5(dev)) {
-                       if (dev_priv->wm.pri_latency[1] &&
-                           dev_priv->wm.spr_latency[1] &&
-                           dev_priv->wm.cur_latency[1])
-                               dev_priv->display.update_wm = ironlake_update_wm;
-                       else {
-                               DRM_DEBUG_KMS("Failed to get proper latency. "
-                                             "Disable CxSR\n");
-                               dev_priv->display.update_wm = NULL;
-                       }
+               if ((IS_GEN5(dev) && dev_priv->wm.pri_latency[1] &&
+                    dev_priv->wm.spr_latency[1] && dev_priv->wm.cur_latency[1]) ||
+                   (!IS_GEN5(dev) && dev_priv->wm.pri_latency[0] &&
+                    dev_priv->wm.spr_latency[0] && dev_priv->wm.cur_latency[0])) {
+                       dev_priv->display.update_wm = ilk_update_wm;
+                       dev_priv->display.update_sprite_wm = ilk_update_sprite_wm;
+               } else {
+                       DRM_DEBUG_KMS("Failed to read display plane latency. "
+                                     "Disable CxSR\n");
+               }
+
+               if (IS_GEN5(dev))
                        dev_priv->display.init_clock_gating = ironlake_init_clock_gating;
-               } else if (IS_GEN6(dev)) {
-                       if (dev_priv->wm.pri_latency[0] &&
-                           dev_priv->wm.spr_latency[0] &&
-                           dev_priv->wm.cur_latency[0]) {
-                               dev_priv->display.update_wm = sandybridge_update_wm;
-                               dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
-                       } else {
-                               DRM_DEBUG_KMS("Failed to read display plane latency. "
-                                             "Disable CxSR\n");
-                               dev_priv->display.update_wm = NULL;
-                       }
+               else if (IS_GEN6(dev))
                        dev_priv->display.init_clock_gating = gen6_init_clock_gating;
-               } else if (IS_IVYBRIDGE(dev)) {
-                       if (dev_priv->wm.pri_latency[0] &&
-                           dev_priv->wm.spr_latency[0] &&
-                           dev_priv->wm.cur_latency[0]) {
-                               dev_priv->display.update_wm = ivybridge_update_wm;
-                               dev_priv->display.update_sprite_wm = sandybridge_update_sprite_wm;
-                       } else {
-                               DRM_DEBUG_KMS("Failed to read display plane latency. "
-                                             "Disable CxSR\n");
-                               dev_priv->display.update_wm = NULL;
-                       }
+               else if (IS_IVYBRIDGE(dev))
                        dev_priv->display.init_clock_gating = ivybridge_init_clock_gating;
-               } else if (IS_HASWELL(dev)) {
-                       if (dev_priv->wm.pri_latency[0] &&
-                           dev_priv->wm.spr_latency[0] &&
-                           dev_priv->wm.cur_latency[0]) {
-                               dev_priv->display.update_wm = haswell_update_wm;
-                               dev_priv->display.update_sprite_wm =
-                                       haswell_update_sprite_wm;
-                       } else {
-                               DRM_DEBUG_KMS("Failed to read display plane latency. "
-                                             "Disable CxSR\n");
-                               dev_priv->display.update_wm = NULL;
-                       }
+               else if (IS_HASWELL(dev))
                        dev_priv->display.init_clock_gating = haswell_init_clock_gating;
-               } else if (INTEL_INFO(dev)->gen == 8) {
+               else if (INTEL_INFO(dev)->gen == 8)
                        dev_priv->display.init_clock_gating = gen8_init_clock_gating;
-               } else
-                       dev_priv->display.update_wm = NULL;
        } else if (IS_VALLEYVIEW(dev)) {
                dev_priv->display.update_wm = valleyview_update_wm;
                dev_priv->display.init_clock_gating =
@@ -6036,21 +5614,21 @@ void intel_init_pm(struct drm_device *dev)
                dev_priv->display.update_wm = i9xx_update_wm;
                dev_priv->display.get_fifo_size = i9xx_get_fifo_size;
                dev_priv->display.init_clock_gating = gen3_init_clock_gating;
-       } else if (IS_I865G(dev)) {
-               dev_priv->display.update_wm = i830_update_wm;
-               dev_priv->display.init_clock_gating = i85x_init_clock_gating;
-               dev_priv->display.get_fifo_size = i830_get_fifo_size;
-       } else if (IS_I85X(dev)) {
-               dev_priv->display.update_wm = i9xx_update_wm;
-               dev_priv->display.get_fifo_size = i85x_get_fifo_size;
-               dev_priv->display.init_clock_gating = i85x_init_clock_gating;
-       } else {
-               dev_priv->display.update_wm = i830_update_wm;
-               dev_priv->display.init_clock_gating = i830_init_clock_gating;
-               if (IS_845G(dev))
+       } else if (IS_GEN2(dev)) {
+               if (INTEL_INFO(dev)->num_pipes == 1) {
+                       dev_priv->display.update_wm = i845_update_wm;
                        dev_priv->display.get_fifo_size = i845_get_fifo_size;
-               else
+               } else {
+                       dev_priv->display.update_wm = i9xx_update_wm;
                        dev_priv->display.get_fifo_size = i830_get_fifo_size;
+               }
+
+               if (IS_I85X(dev) || IS_I865G(dev))
+                       dev_priv->display.init_clock_gating = i85x_init_clock_gating;
+               else
+                       dev_priv->display.init_clock_gating = i830_init_clock_gating;
+       } else {
+               DRM_ERROR("unexpected fall-through in intel_init_pm\n");
        }
 }
 
@@ -6101,59 +5679,48 @@ int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u8 mbox, u32 val)
        return 0;
 }
 
-int vlv_gpu_freq(int ddr_freq, int val)
+int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val)
 {
-       int mult, base;
+       int div;
 
-       switch (ddr_freq) {
+       /* 4 x czclk */
+       switch (dev_priv->mem_freq) {
        case 800:
-               mult = 20;
-               base = 120;
+               div = 10;
                break;
        case 1066:
-               mult = 22;
-               base = 133;
+               div = 12;
                break;
        case 1333:
-               mult = 21;
-               base = 125;
+               div = 16;
                break;
        default:
                return -1;
        }
 
-       return ((val - 0xbd) * mult) + base;
+       return DIV_ROUND_CLOSEST(dev_priv->mem_freq * (val + 6 - 0xbd), 4 * div);
 }
 
-int vlv_freq_opcode(int ddr_freq, int val)
+int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val)
 {
-       int mult, base;
+       int mul;
 
-       switch (ddr_freq) {
+       /* 4 x czclk */
+       switch (dev_priv->mem_freq) {
        case 800:
-               mult = 20;
-               base = 120;
+               mul = 10;
                break;
        case 1066:
-               mult = 22;
-               base = 133;
+               mul = 12;
                break;
        case 1333:
-               mult = 21;
-               base = 125;
+               mul = 16;
                break;
        default:
                return -1;
        }
 
-       val /= mult;
-       val -= base / mult;
-       val += 0xbd;
-
-       if (val > 0xea)
-               val = 0xea;
-
-       return val;
+       return DIV_ROUND_CLOSEST(4 * mul * val, dev_priv->mem_freq) + 0xbd - 6;
 }
 
 void intel_pm_setup(struct drm_device *dev)
index c2f09d4563008ff7e32238675dab1b4da02ec967..b7f1742caf878250c3fb6dc98b5bdbe63ae4a601 100644 (file)
@@ -285,14 +285,16 @@ static int gen7_ring_fbc_flush(struct intel_ring_buffer *ring, u32 value)
        if (!ring->fbc_dirty)
                return 0;
 
-       ret = intel_ring_begin(ring, 4);
+       ret = intel_ring_begin(ring, 6);
        if (ret)
                return ret;
-       intel_ring_emit(ring, MI_NOOP);
        /* WaFbcNukeOn3DBlt:ivb/hsw */
        intel_ring_emit(ring, MI_LOAD_REGISTER_IMM(1));
        intel_ring_emit(ring, MSG_FBC_REND_STATE);
        intel_ring_emit(ring, value);
+       intel_ring_emit(ring, MI_STORE_REGISTER_MEM(1) | MI_SRM_LRM_GLOBAL_GTT);
+       intel_ring_emit(ring, MSG_FBC_REND_STATE);
+       intel_ring_emit(ring, ring->scratch.gtt_offset + 256);
        intel_ring_advance(ring);
 
        ring->fbc_dirty = false;
@@ -354,7 +356,7 @@ gen7_render_ring_flush(struct intel_ring_buffer *ring,
        intel_ring_emit(ring, 0);
        intel_ring_advance(ring);
 
-       if (flush_domains)
+       if (!invalidate_domains && flush_domains)
                return gen7_ring_fbc_flush(ring, FBC_REND_NUKE);
 
        return 0;
@@ -436,7 +438,7 @@ static int init_ring_common(struct intel_ring_buffer *ring)
        int ret = 0;
        u32 head;
 
-       gen6_gt_force_wake_get(dev_priv);
+       gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
 
        if (I915_NEED_GFX_HWS(dev))
                intel_ring_setup_status_page(ring);
@@ -509,7 +511,7 @@ static int init_ring_common(struct intel_ring_buffer *ring)
        memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
 
 out:
-       gen6_gt_force_wake_put(dev_priv);
+       gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
 
        return ret;
 }
@@ -661,19 +663,22 @@ gen6_add_request(struct intel_ring_buffer *ring)
        struct drm_device *dev = ring->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_ring_buffer *useless;
-       int i, ret;
+       int i, ret, num_dwords = 4;
 
-       ret = intel_ring_begin(ring, ((I915_NUM_RINGS-1) *
-                                     MBOX_UPDATE_DWORDS) +
-                                     4);
+       if (i915_semaphore_is_enabled(dev))
+               num_dwords += ((I915_NUM_RINGS-1) * MBOX_UPDATE_DWORDS);
+#undef MBOX_UPDATE_DWORDS
+
+       ret = intel_ring_begin(ring, num_dwords);
        if (ret)
                return ret;
-#undef MBOX_UPDATE_DWORDS
 
-       for_each_ring(useless, dev_priv, i) {
-               u32 mbox_reg = ring->signal_mbox[i];
-               if (mbox_reg != GEN6_NOSYNC)
-                       update_mboxes(ring, mbox_reg);
+       if (i915_semaphore_is_enabled(dev)) {
+               for_each_ring(useless, dev_priv, i) {
+                       u32 mbox_reg = ring->signal_mbox[i];
+                       if (mbox_reg != GEN6_NOSYNC)
+                               update_mboxes(ring, mbox_reg);
+               }
        }
 
        intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
@@ -1030,11 +1035,6 @@ gen6_ring_get_irq(struct intel_ring_buffer *ring)
        if (!dev->irq_enabled)
               return false;
 
-       /* It looks like we need to prevent the gt from suspending while waiting
-        * for an notifiy irq, otherwise irqs seem to get lost on at least the
-        * blt/bsd rings on ivb. */
-       gen6_gt_force_wake_get(dev_priv);
-
        spin_lock_irqsave(&dev_priv->irq_lock, flags);
        if (ring->irq_refcount++ == 0) {
                if (HAS_L3_DPF(dev) && ring->id == RCS)
@@ -1066,8 +1066,6 @@ gen6_ring_put_irq(struct intel_ring_buffer *ring)
                ilk_disable_gt_irq(dev_priv, ring->irq_enable_mask);
        }
        spin_unlock_irqrestore(&dev_priv->irq_lock, flags);
-
-       gen6_gt_force_wake_put(dev_priv);
 }
 
 static bool
@@ -1611,8 +1609,8 @@ intel_ring_alloc_seqno(struct intel_ring_buffer *ring)
        return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno);
 }
 
-static int __intel_ring_begin(struct intel_ring_buffer *ring,
-                             int bytes)
+static int __intel_ring_prepare(struct intel_ring_buffer *ring,
+                               int bytes)
 {
        int ret;
 
@@ -1628,7 +1626,6 @@ static int __intel_ring_begin(struct intel_ring_buffer *ring,
                        return ret;
        }
 
-       ring->space -= bytes;
        return 0;
 }
 
@@ -1643,12 +1640,17 @@ int intel_ring_begin(struct intel_ring_buffer *ring,
        if (ret)
                return ret;
 
+       ret = __intel_ring_prepare(ring, num_dwords * sizeof(uint32_t));
+       if (ret)
+               return ret;
+
        /* Preallocate the olr before touching the ring */
        ret = intel_ring_alloc_seqno(ring);
        if (ret)
                return ret;
 
-       return __intel_ring_begin(ring, num_dwords * sizeof(uint32_t));
+       ring->space -= num_dwords * sizeof(uint32_t);
+       return 0;
 }
 
 void intel_ring_init_seqno(struct intel_ring_buffer *ring, u32 seqno)
@@ -1838,7 +1840,7 @@ static int gen6_ring_flush(struct intel_ring_buffer *ring,
        }
        intel_ring_advance(ring);
 
-       if (IS_GEN7(dev) && flush)
+       if (IS_GEN7(dev) && !invalidate && flush)
                return gen7_ring_fbc_flush(ring, FBC_REND_CACHE_CLEAN);
 
        return 0;
index a583e8f718a7f0f4b87b4fe724336c73ad1a8198..95bdfb3c431c8467b105c616f6d5f9567505804f 100644 (file)
@@ -413,23 +413,34 @@ static const struct _sdvo_cmd_name {
 static void intel_sdvo_debug_write(struct intel_sdvo *intel_sdvo, u8 cmd,
                                   const void *args, int args_len)
 {
-       int i;
+       int i, pos = 0;
+#define BUF_LEN 256
+       char buffer[BUF_LEN];
+
+#define BUF_PRINT(args...) \
+       pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args)
+
 
-       DRM_DEBUG_KMS("%s: W: %02X ",
-                               SDVO_NAME(intel_sdvo), cmd);
-       for (i = 0; i < args_len; i++)
-               DRM_LOG_KMS("%02X ", ((u8 *)args)[i]);
-       for (; i < 8; i++)
-               DRM_LOG_KMS("   ");
+       for (i = 0; i < args_len; i++) {
+               BUF_PRINT("%02X ", ((u8 *)args)[i]);
+       }
+       for (; i < 8; i++) {
+               BUF_PRINT("   ");
+       }
        for (i = 0; i < ARRAY_SIZE(sdvo_cmd_names); i++) {
                if (cmd == sdvo_cmd_names[i].cmd) {
-                       DRM_LOG_KMS("(%s)", sdvo_cmd_names[i].name);
+                       BUF_PRINT("(%s)", sdvo_cmd_names[i].name);
                        break;
                }
        }
-       if (i == ARRAY_SIZE(sdvo_cmd_names))
-               DRM_LOG_KMS("(%02X)", cmd);
-       DRM_LOG_KMS("\n");
+       if (i == ARRAY_SIZE(sdvo_cmd_names)) {
+               BUF_PRINT("(%02X)", cmd);
+       }
+       BUG_ON(pos >= BUF_LEN - 1);
+#undef BUF_PRINT
+#undef BUF_LEN
+
+       DRM_DEBUG_KMS("%s: W: %02X %s\n", SDVO_NAME(intel_sdvo), cmd, buffer);
 }
 
 static const char *cmd_status_names[] = {
@@ -512,9 +523,10 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
 {
        u8 retry = 15; /* 5 quick checks, followed by 10 long checks */
        u8 status;
-       int i;
+       int i, pos = 0;
+#define BUF_LEN 256
+       char buffer[BUF_LEN];
 
-       DRM_DEBUG_KMS("%s: R: ", SDVO_NAME(intel_sdvo));
 
        /*
         * The documentation states that all commands will be
@@ -551,10 +563,13 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
                        goto log_fail;
        }
 
+#define BUF_PRINT(args...) \
+       pos += snprintf(buffer + pos, max_t(int, BUF_LEN - pos, 0), args)
+
        if (status <= SDVO_CMD_STATUS_SCALING_NOT_SUPP)
-               DRM_LOG_KMS("(%s)", cmd_status_names[status]);
+               BUF_PRINT("(%s)", cmd_status_names[status]);
        else
-               DRM_LOG_KMS("(??? %d)", status);
+               BUF_PRINT("(??? %d)", status);
 
        if (status != SDVO_CMD_STATUS_SUCCESS)
                goto log_fail;
@@ -565,13 +580,17 @@ static bool intel_sdvo_read_response(struct intel_sdvo *intel_sdvo,
                                          SDVO_I2C_RETURN_0 + i,
                                          &((u8 *)response)[i]))
                        goto log_fail;
-               DRM_LOG_KMS(" %02X", ((u8 *)response)[i]);
+               BUF_PRINT(" %02X", ((u8 *)response)[i]);
        }
-       DRM_LOG_KMS("\n");
+       BUG_ON(pos >= BUF_LEN - 1);
+#undef BUF_PRINT
+#undef BUF_LEN
+
+       DRM_DEBUG_KMS("%s: R: %s\n", SDVO_NAME(intel_sdvo), buffer);
        return true;
 
 log_fail:
-       DRM_LOG_KMS("... failed\n");
+       DRM_DEBUG_KMS("%s: R: ... failed\n", SDVO_NAME(intel_sdvo));
        return false;
 }
 
@@ -933,7 +952,7 @@ static void intel_sdvo_dump_hdmi_buf(struct intel_sdvo *intel_sdvo)
 
 static bool intel_sdvo_write_infoframe(struct intel_sdvo *intel_sdvo,
                                       unsigned if_index, uint8_t tx_rate,
-                                      uint8_t *data, unsigned length)
+                                      const uint8_t *data, unsigned length)
 {
        uint8_t set_buf_index[2] = { if_index, 0 };
        uint8_t hbuf_size, tmp[8];
@@ -1517,8 +1536,9 @@ static void intel_sdvo_dpms(struct drm_connector *connector, int mode)
        intel_modeset_check_state(connector->dev);
 }
 
-static int intel_sdvo_mode_valid(struct drm_connector *connector,
-                                struct drm_display_mode *mode)
+static enum drm_mode_status
+intel_sdvo_mode_valid(struct drm_connector *connector,
+                     struct drm_display_mode *mode)
 {
        struct intel_sdvo *intel_sdvo = intel_attached_sdvo(connector);
 
index 770bdd6ecd9fb96b46365bbadd97ba3011c0ef96..2e2d4eb4a00d190b24c03c1998b4e9f0cd9f06c5 100644 (file)
@@ -59,7 +59,7 @@ struct intel_sdvo_caps {
        unsigned int stall_support:1;
        unsigned int pad:1;
        u16 output_flags;
-} __attribute__((packed));
+} __packed;
 
 /* Note: SDVO detailed timing flags match EDID misc flags. */
 #define DTD_FLAG_HSYNC_POSITIVE (1 << 1)
@@ -94,12 +94,12 @@ struct intel_sdvo_dtd {
                u8 v_sync_off_high;
                u8 reserved;
        } part2;
-} __attribute__((packed));
+} __packed;
 
 struct intel_sdvo_pixel_clock_range {
        u16 min;        /**< pixel clock, in 10kHz units */
        u16 max;        /**< pixel clock, in 10kHz units */
-} __attribute__((packed));
+} __packed;
 
 struct intel_sdvo_preferred_input_timing_args {
        u16 clock;
@@ -108,7 +108,7 @@ struct intel_sdvo_preferred_input_timing_args {
        u8      interlace:1;
        u8      scaled:1;
        u8      pad:6;
-} __attribute__((packed));
+} __packed;
 
 /* I2C registers for SDVO */
 #define SDVO_I2C_ARG_0                         0x07
@@ -162,7 +162,7 @@ struct intel_sdvo_get_trained_inputs_response {
        unsigned int input0_trained:1;
        unsigned int input1_trained:1;
        unsigned int pad:6;
-} __attribute__((packed));
+} __packed;
 
 /** Returns a struct intel_sdvo_output_flags of active outputs. */
 #define SDVO_CMD_GET_ACTIVE_OUTPUTS                    0x04
@@ -219,7 +219,7 @@ struct intel_sdvo_get_interrupt_event_source_response {
        unsigned int ambient_light_interrupt:1;
        unsigned int hdmi_audio_encrypt_change:1;
        unsigned int pad:6;
-} __attribute__((packed));
+} __packed;
 
 /**
  * Selects which input is affected by future input commands.
@@ -232,7 +232,7 @@ struct intel_sdvo_get_interrupt_event_source_response {
 struct intel_sdvo_set_target_input_args {
        unsigned int target_1:1;
        unsigned int pad:7;
-} __attribute__((packed));
+} __packed;
 
 /**
  * Takes a struct intel_sdvo_output_flags of which outputs are targeted by
@@ -370,7 +370,7 @@ struct intel_sdvo_tv_format {
        unsigned int hdtv_std_eia_7702a_480i_60:1;
        unsigned int hdtv_std_eia_7702a_480p_60:1;
        unsigned int pad:3;
-} __attribute__((packed));
+} __packed;
 
 #define SDVO_CMD_GET_TV_FORMAT                         0x28
 
@@ -401,7 +401,7 @@ struct intel_sdvo_sdtv_resolution_request {
        unsigned int secam_l:1;
        unsigned int secam_60:1;
        unsigned int pad:5;
-} __attribute__((packed));
+} __packed;
 
 struct intel_sdvo_sdtv_resolution_reply {
        unsigned int res_320x200:1;
@@ -426,7 +426,7 @@ struct intel_sdvo_sdtv_resolution_reply {
        unsigned int res_1024x768:1;
        unsigned int res_1280x1024:1;
        unsigned int pad:5;
-} __attribute__((packed));
+} __packed;
 
 /* Get supported resolution with squire pixel aspect ratio that can be
    scaled for the requested HDTV format */
@@ -463,7 +463,7 @@ struct intel_sdvo_hdtv_resolution_request {
        unsigned int hdtv_std_eia_7702a_480i_60:1;
        unsigned int hdtv_std_eia_7702a_480p_60:1;
        unsigned int pad:6;
-} __attribute__((packed));
+} __packed;
 
 struct intel_sdvo_hdtv_resolution_reply {
        unsigned int res_640x480:1;
@@ -517,7 +517,7 @@ struct intel_sdvo_hdtv_resolution_reply {
 
        unsigned int res_1280x768:1;
        unsigned int pad5:7;
-} __attribute__((packed));
+} __packed;
 
 /* Get supported power state returns info for encoder and monitor, rely on
    last SetTargetInput and SetTargetOutput calls */
@@ -557,13 +557,13 @@ struct sdvo_panel_power_sequencing {
 
        unsigned int t4_high:2;
        unsigned int pad:6;
-} __attribute__((packed));
+} __packed;
 
 #define SDVO_CMD_GET_MAX_BACKLIGHT_LEVEL               0x30
 struct sdvo_max_backlight_reply {
        u8 max_value;
        u8 default_value;
-} __attribute__((packed));
+} __packed;
 
 #define SDVO_CMD_GET_BACKLIGHT_LEVEL                   0x31
 #define SDVO_CMD_SET_BACKLIGHT_LEVEL                   0x32
@@ -573,14 +573,14 @@ struct sdvo_get_ambient_light_reply {
        u16 trip_low;
        u16 trip_high;
        u16 value;
-} __attribute__((packed));
+} __packed;
 #define SDVO_CMD_SET_AMBIENT_LIGHT                     0x34
 struct sdvo_set_ambient_light_reply {
        u16 trip_low;
        u16 trip_high;
        unsigned int enable:1;
        unsigned int pad:7;
-} __attribute__((packed));
+} __packed;
 
 /* Set display power state */
 #define SDVO_CMD_SET_DISPLAY_POWER_STATE               0x7d
@@ -608,7 +608,7 @@ struct intel_sdvo_enhancements_reply {
        unsigned int dither:1;
        unsigned int tv_chroma_filter:1;
        unsigned int tv_luma_filter:1;
-} __attribute__((packed));
+} __packed;
 
 /* Picture enhancement limits below are dependent on the current TV format,
  * and thus need to be queried and set after it.
@@ -630,7 +630,7 @@ struct intel_sdvo_enhancements_reply {
 struct intel_sdvo_enhancement_limits_reply {
        u16 max_value;
        u16 default_value;
-} __attribute__((packed));
+} __packed;
 
 #define SDVO_CMD_GET_LVDS_PANEL_INFORMATION            0x7f
 #define SDVO_CMD_SET_LVDS_PANEL_INFORMATION            0x80
@@ -671,7 +671,7 @@ struct intel_sdvo_enhancement_limits_reply {
 #define SDVO_CMD_SET_TV_LUMA_FILTER                    0x79
 struct intel_sdvo_enhancements_arg {
        u16 value;
-} __attribute__((packed));
+} __packed;
 
 #define SDVO_CMD_GET_DOT_CRAWL                         0x70
 #define SDVO_CMD_SET_DOT_CRAWL                         0x71
@@ -727,4 +727,4 @@ struct intel_sdvo_enhancements_arg {
 struct intel_sdvo_encode {
        u8 dvi_rev;
        u8 hdmi_rev;
-} __attribute__ ((packed));
+} __packed;
index 9944d8135e87f88215d5d07d54a5fd87fcf4dc60..0954f132726ea0ae15593364ef976168fc2c909f 100644 (file)
@@ -90,6 +90,22 @@ void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val)
        mutex_unlock(&dev_priv->dpio_lock);
 }
 
+u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg)
+{
+       u32 val = 0;
+
+       vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT,
+                       PUNIT_OPCODE_REG_READ, reg, &val);
+
+       return val;
+}
+
+void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
+{
+       vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT,
+                       PUNIT_OPCODE_REG_WRITE, reg, &val);
+}
+
 u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr)
 {
        u32 val = 0;
@@ -160,27 +176,18 @@ void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
                        PUNIT_OPCODE_REG_WRITE, reg, &val);
 }
 
-static u32 vlv_get_phy_port(enum pipe pipe)
-{
-       u32 port = IOSF_PORT_DPIO;
-
-       WARN_ON ((pipe != PIPE_A) && (pipe != PIPE_B));
-
-       return port;
-}
-
 u32 vlv_dpio_read(struct drm_i915_private *dev_priv, enum pipe pipe, int reg)
 {
        u32 val = 0;
 
-       vlv_sideband_rw(dev_priv, DPIO_DEVFN, vlv_get_phy_port(pipe),
+       vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)),
                        DPIO_OPCODE_REG_READ, reg, &val);
        return val;
 }
 
 void vlv_dpio_write(struct drm_i915_private *dev_priv, enum pipe pipe, int reg, u32 val)
 {
-       vlv_sideband_rw(dev_priv, DPIO_DEVFN, vlv_get_phy_port(pipe),
+       vlv_sideband_rw(dev_priv, DPIO_DEVFN, DPIO_PHY_IOSF_PORT(DPIO_PHY(pipe)),
                        DPIO_OPCODE_REG_WRITE, reg, &val);
 }
 
@@ -242,3 +249,17 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
                return;
        }
 }
+
+u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg)
+{
+       u32 val = 0;
+       vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI,
+                                       DPIO_OPCODE_REG_READ, reg, &val);
+       return val;
+}
+
+void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
+{
+       vlv_sideband_rw(dev_priv, DPIO_DEVFN, IOSF_PORT_FLISDSI,
+                                       DPIO_OPCODE_REG_WRITE, reg, &val);
+}
index b9fabf826f7de71f224bd9b808780f81ba1c9027..716a3c9c0751c18927cb1b10633b6effff584e7b 100644 (file)
@@ -104,6 +104,12 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
                break;
        }
 
+       /*
+        * Enable gamma to match primary/cursor plane behaviour.
+        * FIXME should be user controllable via propertiesa.
+        */
+       sprctl |= SP_GAMMA_ENABLE;
+
        if (obj->tiling_mode != I915_TILING_NONE)
                sprctl |= SP_TILED;
 
@@ -135,8 +141,8 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
 
        I915_WRITE(SPSIZE(pipe, plane), (crtc_h << 16) | crtc_w);
        I915_WRITE(SPCNTR(pipe, plane), sprctl);
-       I915_MODIFY_DISPBASE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
-                            sprsurf_offset);
+       I915_WRITE(SPSURF(pipe, plane), i915_gem_obj_ggtt_offset(obj) +
+                  sprsurf_offset);
        POSTING_READ(SPSURF(pipe, plane));
 }
 
@@ -152,7 +158,7 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
        I915_WRITE(SPCNTR(pipe, plane), I915_READ(SPCNTR(pipe, plane)) &
                   ~SP_ENABLE);
        /* Activate double buffered register update */
-       I915_MODIFY_DISPBASE(SPSURF(pipe, plane), 0);
+       I915_WRITE(SPSURF(pipe, plane), 0);
        POSTING_READ(SPSURF(pipe, plane));
 
        intel_update_sprite_watermarks(dplane, crtc, 0, 0, false, false);
@@ -224,7 +230,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        u32 sprctl, sprscale = 0;
        unsigned long sprsurf_offset, linear_offset;
        int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
-       bool scaling_was_enabled = dev_priv->sprite_scaling_enabled;
 
        sprctl = I915_READ(SPRCTL(pipe));
 
@@ -257,6 +262,12 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                BUG();
        }
 
+       /*
+        * Enable gamma to match primary/cursor plane behaviour.
+        * FIXME should be user controllable via propertiesa.
+        */
+       sprctl |= SPRITE_GAMMA_ENABLE;
+
        if (obj->tiling_mode != I915_TILING_NONE)
                sprctl |= SPRITE_TILED;
 
@@ -279,21 +290,8 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        crtc_w--;
        crtc_h--;
 
-       /*
-        * IVB workaround: must disable low power watermarks for at least
-        * one frame before enabling scaling.  LP watermarks can be re-enabled
-        * when scaling is disabled.
-        */
-       if (crtc_w != src_w || crtc_h != src_h) {
-               dev_priv->sprite_scaling_enabled |= 1 << pipe;
-
-               if (!scaling_was_enabled) {
-                       intel_update_watermarks(crtc);
-                       intel_wait_for_vblank(dev, pipe);
-               }
+       if (crtc_w != src_w || crtc_h != src_h)
                sprscale = SPRITE_SCALE_ENABLE | (src_w << 16) | src_h;
-       } else
-               dev_priv->sprite_scaling_enabled &= ~(1 << pipe);
 
        I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
        I915_WRITE(SPRPOS(pipe), (crtc_y << 16) | crtc_x);
@@ -317,13 +315,9 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        if (intel_plane->can_scale)
                I915_WRITE(SPRSCALE(pipe), sprscale);
        I915_WRITE(SPRCTL(pipe), sprctl);
-       I915_MODIFY_DISPBASE(SPRSURF(pipe),
-                            i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
+       I915_WRITE(SPRSURF(pipe),
+                  i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
        POSTING_READ(SPRSURF(pipe));
-
-       /* potentially re-enable LP watermarks */
-       if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled)
-               intel_update_watermarks(crtc);
 }
 
 static void
@@ -333,23 +327,22 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
        struct drm_i915_private *dev_priv = dev->dev_private;
        struct intel_plane *intel_plane = to_intel_plane(plane);
        int pipe = intel_plane->pipe;
-       bool scaling_was_enabled = dev_priv->sprite_scaling_enabled;
 
        I915_WRITE(SPRCTL(pipe), I915_READ(SPRCTL(pipe)) & ~SPRITE_ENABLE);
        /* Can't leave the scaler enabled... */
        if (intel_plane->can_scale)
                I915_WRITE(SPRSCALE(pipe), 0);
        /* Activate double buffered register update */
-       I915_MODIFY_DISPBASE(SPRSURF(pipe), 0);
+       I915_WRITE(SPRSURF(pipe), 0);
        POSTING_READ(SPRSURF(pipe));
 
-       dev_priv->sprite_scaling_enabled &= ~(1 << pipe);
+       /*
+        * Avoid underruns when disabling the sprite.
+        * FIXME remove once watermark updates are done properly.
+        */
+       intel_wait_for_vblank(dev, pipe);
 
        intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
-
-       /* potentially re-enable LP watermarks */
-       if (scaling_was_enabled && !dev_priv->sprite_scaling_enabled)
-               intel_update_watermarks(crtc);
 }
 
 static int
@@ -453,6 +446,12 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                BUG();
        }
 
+       /*
+        * Enable gamma to match primary/cursor plane behaviour.
+        * FIXME should be user controllable via propertiesa.
+        */
+       dvscntr |= DVS_GAMMA_ENABLE;
+
        if (obj->tiling_mode != I915_TILING_NONE)
                dvscntr |= DVS_TILED;
 
@@ -470,7 +469,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        crtc_h--;
 
        dvsscale = 0;
-       if (IS_GEN5(dev) || crtc_w != src_w || crtc_h != src_h)
+       if (crtc_w != src_w || crtc_h != src_h)
                dvsscale = DVS_SCALE_ENABLE | (src_w << 16) | src_h;
 
        I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
@@ -490,8 +489,8 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        I915_WRITE(DVSSIZE(pipe), (crtc_h << 16) | crtc_w);
        I915_WRITE(DVSSCALE(pipe), dvsscale);
        I915_WRITE(DVSCNTR(pipe), dvscntr);
-       I915_MODIFY_DISPBASE(DVSSURF(pipe),
-                            i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
+       I915_WRITE(DVSSURF(pipe),
+                  i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
        POSTING_READ(DVSSURF(pipe));
 }
 
@@ -507,9 +506,15 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
        /* Disable the scaler */
        I915_WRITE(DVSSCALE(pipe), 0);
        /* Flush double buffered register updates */
-       I915_MODIFY_DISPBASE(DVSSURF(pipe), 0);
+       I915_WRITE(DVSSURF(pipe), 0);
        POSTING_READ(DVSSURF(pipe));
 
+       /*
+        * Avoid underruns when disabling the sprite.
+        * FIXME remove once watermark updates are done properly.
+        */
+       intel_wait_for_vblank(dev, pipe);
+
        intel_update_sprite_watermarks(plane, crtc, 0, 0, false, false);
 }
 
@@ -643,6 +648,15 @@ format_is_yuv(uint32_t format)
        }
 }
 
+static bool colorkey_enabled(struct intel_plane *intel_plane)
+{
+       struct drm_intel_sprite_colorkey key;
+
+       intel_plane->get_colorkey(&intel_plane->base, &key);
+
+       return key.flags != I915_SET_COLORKEY_NONE;
+}
+
 static int
 intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
                   struct drm_framebuffer *fb, int crtc_x, int crtc_y,
@@ -828,7 +842,7 @@ intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
         * If the sprite is completely covering the primary plane,
         * we can disable the primary and save power.
         */
-       disable_primary = drm_rect_equals(&dst, &clip);
+       disable_primary = drm_rect_equals(&dst, &clip) && !colorkey_enabled(intel_plane);
        WARN_ON(disable_primary && !visible && intel_crtc->active);
 
        mutex_lock(&dev->struct_mutex);
index 25cbe073c388a3185d1a32afeb805993e43d12d3..87df68f5f504b5a2dd352f503d1af4dbf06c30ba 100644 (file)
@@ -64,7 +64,8 @@ static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv)
        __raw_posting_read(dev_priv, ECOBUS);
 }
 
-static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv,
+                                                       int fw_engine)
 {
        if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK) & 1) == 0,
                            FORCEWAKE_ACK_TIMEOUT_MS))
@@ -89,7 +90,8 @@ static void __gen6_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv)
        __raw_posting_read(dev_priv, ECOBUS);
 }
 
-static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv)
+static void __gen6_gt_force_wake_mt_get(struct drm_i915_private *dev_priv,
+                                                       int fw_engine)
 {
        u32 forcewake_ack;
 
@@ -121,12 +123,12 @@ static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
        u32 gtfifodbg;
 
        gtfifodbg = __raw_i915_read32(dev_priv, GTFIFODBG);
-       if (WARN(gtfifodbg & GT_FIFO_CPU_ERROR_MASK,
-            "MMIO read or write has been dropped %x\n", gtfifodbg))
-               __raw_i915_write32(dev_priv, GTFIFODBG, GT_FIFO_CPU_ERROR_MASK);
+       if (WARN(gtfifodbg, "GT wake FIFO error 0x%x\n", gtfifodbg))
+               __raw_i915_write32(dev_priv, GTFIFODBG, gtfifodbg);
 }
 
-static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv,
+                                                       int fw_engine)
 {
        __raw_i915_write32(dev_priv, FORCEWAKE, 0);
        /* something from same cacheline, but !FORCEWAKE */
@@ -134,7 +136,8 @@ static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
        gen6_gt_check_fifodbg(dev_priv);
 }
 
-static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv)
+static void __gen6_gt_force_wake_mt_put(struct drm_i915_private *dev_priv,
+                                                       int fw_engine)
 {
        __raw_i915_write32(dev_priv, FORCEWAKE_MT,
                           _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
@@ -147,12 +150,19 @@ static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
 {
        int ret = 0;
 
+       /* On VLV, FIFO will be shared by both SW and HW.
+        * So, we need to read the FREE_ENTRIES everytime */
+       if (IS_VALLEYVIEW(dev_priv->dev))
+               dev_priv->uncore.fifo_count =
+                       __raw_i915_read32(dev_priv, GTFIFOCTL) &
+                                               GT_FIFO_FREE_ENTRIES_MASK;
+
        if (dev_priv->uncore.fifo_count < GT_FIFO_NUM_RESERVED_ENTRIES) {
                int loop = 500;
-               u32 fifo = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES);
+               u32 fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK;
                while (fifo <= GT_FIFO_NUM_RESERVED_ENTRIES && loop--) {
                        udelay(10);
-                       fifo = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES);
+                       fifo = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK;
                }
                if (WARN_ON(loop < 0 && fifo <= GT_FIFO_NUM_RESERVED_ENTRIES))
                        ++ret;
@@ -171,38 +181,112 @@ static void vlv_force_wake_reset(struct drm_i915_private *dev_priv)
        __raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV);
 }
 
-static void vlv_force_wake_get(struct drm_i915_private *dev_priv)
+static void __vlv_force_wake_get(struct drm_i915_private *dev_priv,
+                                               int fw_engine)
 {
-       if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL) == 0,
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
+       /* Check for Render Engine */
+       if (FORCEWAKE_RENDER & fw_engine) {
+               if (wait_for_atomic((__raw_i915_read32(dev_priv,
+                                               FORCEWAKE_ACK_VLV) &
+                                               FORCEWAKE_KERNEL) == 0,
+                                       FORCEWAKE_ACK_TIMEOUT_MS))
+                       DRM_ERROR("Timed out: Render forcewake old ack to clear.\n");
 
-       __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
-                          _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-       __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
-                          _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
+               __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
+                                  _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
 
-       if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_VLV) & FORCEWAKE_KERNEL),
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for GT to ack forcewake request.\n");
+               if (wait_for_atomic((__raw_i915_read32(dev_priv,
+                                               FORCEWAKE_ACK_VLV) &
+                                               FORCEWAKE_KERNEL),
+                                       FORCEWAKE_ACK_TIMEOUT_MS))
+                       DRM_ERROR("Timed out: waiting for Render to ack.\n");
+       }
 
-       if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK_MEDIA_VLV) &
-                            FORCEWAKE_KERNEL),
-                           FORCEWAKE_ACK_TIMEOUT_MS))
-               DRM_ERROR("Timed out waiting for media to ack forcewake request.\n");
+       /* Check for Media Engine */
+       if (FORCEWAKE_MEDIA & fw_engine) {
+               if (wait_for_atomic((__raw_i915_read32(dev_priv,
+                                               FORCEWAKE_ACK_MEDIA_VLV) &
+                                               FORCEWAKE_KERNEL) == 0,
+                                       FORCEWAKE_ACK_TIMEOUT_MS))
+                       DRM_ERROR("Timed out: Media forcewake old ack to clear.\n");
+
+               __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
+                                  _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
+
+               if (wait_for_atomic((__raw_i915_read32(dev_priv,
+                                               FORCEWAKE_ACK_MEDIA_VLV) &
+                                               FORCEWAKE_KERNEL),
+                                       FORCEWAKE_ACK_TIMEOUT_MS))
+                       DRM_ERROR("Timed out: waiting for media to ack.\n");
+       }
 
        /* WaRsForcewakeWaitTC0:vlv */
        __gen6_gt_wait_for_thread_c0(dev_priv);
+
 }
 
-static void vlv_force_wake_put(struct drm_i915_private *dev_priv)
+static void __vlv_force_wake_put(struct drm_i915_private *dev_priv,
+                                       int fw_engine)
 {
-       __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
-                          _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-       __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
-                          _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
+
+       /* Check for Render Engine */
+       if (FORCEWAKE_RENDER & fw_engine)
+               __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
+                                       _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
+
+
+       /* Check for Media Engine */
+       if (FORCEWAKE_MEDIA & fw_engine)
+               __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
+                               _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
+
        /* The below doubles as a POSTING_READ */
        gen6_gt_check_fifodbg(dev_priv);
+
+}
+
+void vlv_force_wake_get(struct drm_i915_private *dev_priv,
+                                               int fw_engine)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+       if (FORCEWAKE_RENDER & fw_engine) {
+               if (dev_priv->uncore.fw_rendercount++ == 0)
+                       dev_priv->uncore.funcs.force_wake_get(dev_priv,
+                                                       FORCEWAKE_RENDER);
+       }
+       if (FORCEWAKE_MEDIA & fw_engine) {
+               if (dev_priv->uncore.fw_mediacount++ == 0)
+                       dev_priv->uncore.funcs.force_wake_get(dev_priv,
+                                                       FORCEWAKE_MEDIA);
+       }
+
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+}
+
+void vlv_force_wake_put(struct drm_i915_private *dev_priv,
+                                               int fw_engine)
+{
+       unsigned long irqflags;
+
+       spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+
+       if (FORCEWAKE_RENDER & fw_engine) {
+               WARN_ON(dev_priv->uncore.fw_rendercount == 0);
+               if (--dev_priv->uncore.fw_rendercount == 0)
+                       dev_priv->uncore.funcs.force_wake_put(dev_priv,
+                                                       FORCEWAKE_RENDER);
+       }
+
+       if (FORCEWAKE_MEDIA & fw_engine) {
+               WARN_ON(dev_priv->uncore.fw_mediacount == 0);
+               if (--dev_priv->uncore.fw_mediacount == 0)
+                       dev_priv->uncore.funcs.force_wake_put(dev_priv,
+                                                       FORCEWAKE_MEDIA);
+       }
+
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
 static void gen6_force_wake_work(struct work_struct *work)
@@ -213,7 +297,7 @@ static void gen6_force_wake_work(struct work_struct *work)
 
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
        if (--dev_priv->uncore.forcewake_count == 0)
-               dev_priv->uncore.funcs.force_wake_put(dev_priv);
+               dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
@@ -248,6 +332,11 @@ void intel_uncore_early_sanitize(struct drm_device *dev)
                DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size);
        }
 
+       /* clear out old GT FIFO errors */
+       if (IS_GEN6(dev) || IS_GEN7(dev))
+               __raw_i915_write32(dev_priv, GTFIFODBG,
+                                  __raw_i915_read32(dev_priv, GTFIFODBG));
+
        intel_uncore_forcewake_reset(dev);
 }
 
@@ -256,8 +345,6 @@ void intel_uncore_sanitize(struct drm_device *dev)
        struct drm_i915_private *dev_priv = dev->dev_private;
        u32 reg_val;
 
-       intel_uncore_forcewake_reset(dev);
-
        /* BIOS often leaves RC6 enabled, but disable it for hw init */
        intel_disable_gt_powersave(dev);
 
@@ -281,29 +368,40 @@ void intel_uncore_sanitize(struct drm_device *dev)
  * be called at the beginning of the sequence followed by a call to
  * gen6_gt_force_wake_put() at the end of the sequence.
  */
-void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv)
+void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
 {
        unsigned long irqflags;
 
        if (!dev_priv->uncore.funcs.force_wake_get)
                return;
 
+       intel_runtime_pm_get(dev_priv);
+
+       /* Redirect to VLV specific routine */
+       if (IS_VALLEYVIEW(dev_priv->dev))
+               return vlv_force_wake_get(dev_priv, fw_engine);
+
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
        if (dev_priv->uncore.forcewake_count++ == 0)
-               dev_priv->uncore.funcs.force_wake_get(dev_priv);
+               dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
 }
 
 /*
  * see gen6_gt_force_wake_get()
  */
-void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
+void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
 {
        unsigned long irqflags;
 
        if (!dev_priv->uncore.funcs.force_wake_put)
                return;
 
+       /* Redirect to VLV specific routine */
+       if (IS_VALLEYVIEW(dev_priv->dev))
+               return vlv_force_wake_put(dev_priv, fw_engine);
+
+
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
        if (--dev_priv->uncore.forcewake_count == 0) {
                dev_priv->uncore.forcewake_count++;
@@ -312,6 +410,8 @@ void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv)
                                 1);
        }
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+
+       intel_runtime_pm_put(dev_priv);
 }
 
 /* We give fast paths for the really cool registers */
@@ -346,6 +446,13 @@ hsw_unclaimed_reg_check(struct drm_i915_private *dev_priv, u32 reg)
        }
 }
 
+static void
+assert_device_not_suspended(struct drm_i915_private *dev_priv)
+{
+       WARN(HAS_RUNTIME_PM(dev_priv->dev) && dev_priv->pm.suspended,
+            "Device suspended\n");
+}
+
 #define REG_READ_HEADER(x) \
        unsigned long irqflags; \
        u##x val = 0; \
@@ -379,16 +486,51 @@ gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
        REG_READ_HEADER(x); \
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
                if (dev_priv->uncore.forcewake_count == 0) \
-                       dev_priv->uncore.funcs.force_wake_get(dev_priv); \
+                       dev_priv->uncore.funcs.force_wake_get(dev_priv, \
+                                                       FORCEWAKE_ALL); \
                val = __raw_i915_read##x(dev_priv, reg); \
                if (dev_priv->uncore.forcewake_count == 0) \
-                       dev_priv->uncore.funcs.force_wake_put(dev_priv); \
+                       dev_priv->uncore.funcs.force_wake_put(dev_priv, \
+                                                       FORCEWAKE_ALL); \
        } else { \
                val = __raw_i915_read##x(dev_priv, reg); \
        } \
        REG_READ_FOOTER; \
 }
 
+#define __vlv_read(x) \
+static u##x \
+vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+       unsigned fwengine = 0; \
+       unsigned *fwcount; \
+       REG_READ_HEADER(x); \
+       if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) {   \
+               fwengine = FORCEWAKE_RENDER;            \
+               fwcount = &dev_priv->uncore.fw_rendercount;    \
+       }                                               \
+       else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) {       \
+               fwengine = FORCEWAKE_MEDIA;             \
+               fwcount = &dev_priv->uncore.fw_mediacount;     \
+       }  \
+       if (fwengine != 0) {            \
+               if ((*fwcount)++ == 0) \
+                       (dev_priv)->uncore.funcs.force_wake_get(dev_priv, \
+                                                               fwengine); \
+               val = __raw_i915_read##x(dev_priv, reg); \
+               if (--(*fwcount) == 0) \
+                       (dev_priv)->uncore.funcs.force_wake_put(dev_priv, \
+                                                       fwengine); \
+       } else { \
+               val = __raw_i915_read##x(dev_priv, reg); \
+       } \
+       REG_READ_FOOTER; \
+}
+
+
+__vlv_read(8)
+__vlv_read(16)
+__vlv_read(32)
+__vlv_read(64)
 __gen6_read(8)
 __gen6_read(16)
 __gen6_read(32)
@@ -402,6 +544,7 @@ __gen4_read(16)
 __gen4_read(32)
 __gen4_read(64)
 
+#undef __vlv_read
 #undef __gen6_read
 #undef __gen5_read
 #undef __gen4_read
@@ -413,12 +556,15 @@ __gen4_read(64)
        trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
        spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
 
+#define REG_WRITE_FOOTER \
+       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags)
+
 #define __gen4_write(x) \
 static void \
 gen4_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
        REG_WRITE_HEADER; \
        __raw_i915_write##x(dev_priv, reg, val); \
-       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+       REG_WRITE_FOOTER; \
 }
 
 #define __gen5_write(x) \
@@ -427,7 +573,7 @@ gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace
        REG_WRITE_HEADER; \
        ilk_dummy_write(dev_priv); \
        __raw_i915_write##x(dev_priv, reg, val); \
-       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+       REG_WRITE_FOOTER; \
 }
 
 #define __gen6_write(x) \
@@ -438,11 +584,12 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
                __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
        } \
+       assert_device_not_suspended(dev_priv); \
        __raw_i915_write##x(dev_priv, reg, val); \
        if (unlikely(__fifo_ret)) { \
                gen6_gt_check_fifodbg(dev_priv); \
        } \
-       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+       REG_WRITE_FOOTER; \
 }
 
 #define __hsw_write(x) \
@@ -453,13 +600,14 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace)
        if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
                __fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
        } \
+       assert_device_not_suspended(dev_priv); \
        hsw_unclaimed_reg_clear(dev_priv, reg); \
        __raw_i915_write##x(dev_priv, reg, val); \
        if (unlikely(__fifo_ret)) { \
                gen6_gt_check_fifodbg(dev_priv); \
        } \
        hsw_unclaimed_reg_check(dev_priv, reg); \
-       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+       REG_WRITE_FOOTER; \
 }
 
 static const u32 gen8_shadowed_regs[] = {
@@ -486,16 +634,18 @@ static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg)
 #define __gen8_write(x) \
 static void \
 gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
-       bool __needs_put = !is_gen8_shadowed(dev_priv, reg); \
+       bool __needs_put = reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg); \
        REG_WRITE_HEADER; \
        if (__needs_put) { \
-               dev_priv->uncore.funcs.force_wake_get(dev_priv); \
+               dev_priv->uncore.funcs.force_wake_get(dev_priv, \
+                                                       FORCEWAKE_ALL); \
        } \
        __raw_i915_write##x(dev_priv, reg, val); \
        if (__needs_put) { \
-               dev_priv->uncore.funcs.force_wake_put(dev_priv); \
+               dev_priv->uncore.funcs.force_wake_put(dev_priv, \
+                                                       FORCEWAKE_ALL); \
        } \
-       spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+       REG_WRITE_FOOTER; \
 }
 
 __gen8_write(8)
@@ -524,6 +674,7 @@ __gen4_write(64)
 #undef __gen6_write
 #undef __gen5_write
 #undef __gen4_write
+#undef REG_WRITE_FOOTER
 #undef REG_WRITE_HEADER
 
 void intel_uncore_init(struct drm_device *dev)
@@ -534,8 +685,8 @@ void intel_uncore_init(struct drm_device *dev)
                          gen6_force_wake_work);
 
        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;
+               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)) {
                dev_priv->uncore.funcs.force_wake_get = __gen6_gt_force_wake_mt_get;
                dev_priv->uncore.funcs.force_wake_put = __gen6_gt_force_wake_mt_put;
@@ -552,9 +703,9 @@ void intel_uncore_init(struct drm_device *dev)
                 * forcewake being disabled.
                 */
                mutex_lock(&dev->struct_mutex);
-               __gen6_gt_force_wake_mt_get(dev_priv);
+               __gen6_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL);
                ecobus = __raw_i915_read32(dev_priv, ECOBUS);
-               __gen6_gt_force_wake_mt_put(dev_priv);
+               __gen6_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL);
                mutex_unlock(&dev->struct_mutex);
 
                if (ecobus & FORCEWAKE_MT_ENABLE) {
@@ -601,10 +752,18 @@ void intel_uncore_init(struct drm_device *dev)
                        dev_priv->uncore.funcs.mmio_writel  = gen6_write32;
                        dev_priv->uncore.funcs.mmio_writeq  = gen6_write64;
                }
-               dev_priv->uncore.funcs.mmio_readb  = gen6_read8;
-               dev_priv->uncore.funcs.mmio_readw  = gen6_read16;
-               dev_priv->uncore.funcs.mmio_readl  = gen6_read32;
-               dev_priv->uncore.funcs.mmio_readq  = gen6_read64;
+
+               if (IS_VALLEYVIEW(dev)) {
+                       dev_priv->uncore.funcs.mmio_readb  = vlv_read8;
+                       dev_priv->uncore.funcs.mmio_readw  = vlv_read16;
+                       dev_priv->uncore.funcs.mmio_readl  = vlv_read32;
+                       dev_priv->uncore.funcs.mmio_readq  = vlv_read64;
+               } else {
+                       dev_priv->uncore.funcs.mmio_readb  = gen6_read8;
+                       dev_priv->uncore.funcs.mmio_readw  = gen6_read16;
+                       dev_priv->uncore.funcs.mmio_readl  = gen6_read32;
+                       dev_priv->uncore.funcs.mmio_readq  = gen6_read64;
+               }
                break;
        case 5:
                dev_priv->uncore.funcs.mmio_writeb  = gen5_write8;
@@ -646,7 +805,7 @@ static const struct register_whitelist {
        uint32_t size;
        uint32_t gen_bitmask; /* support gens, 0x10 for 4, 0x30 for 4 and 5, etc. */
 } whitelist[] = {
-       { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0xF0 },
+       { RING_TIMESTAMP(RENDER_RING_BASE), 8, 0x1F0 },
 };
 
 int i915_reg_read_ioctl(struct drm_device *dev,
@@ -687,6 +846,43 @@ int i915_reg_read_ioctl(struct drm_device *dev,
        return 0;
 }
 
+int i915_get_reset_stats_ioctl(struct drm_device *dev,
+                              void *data, struct drm_file *file)
+{
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       struct drm_i915_reset_stats *args = data;
+       struct i915_ctx_hang_stats *hs;
+       int ret;
+
+       if (args->flags || args->pad)
+               return -EINVAL;
+
+       if (args->ctx_id == DEFAULT_CONTEXT_ID && !capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       ret = mutex_lock_interruptible(&dev->struct_mutex);
+       if (ret)
+               return ret;
+
+       hs = i915_gem_context_get_hang_stats(dev, file, args->ctx_id);
+       if (IS_ERR(hs)) {
+               mutex_unlock(&dev->struct_mutex);
+               return PTR_ERR(hs);
+       }
+
+       if (capable(CAP_SYS_ADMIN))
+               args->reset_count = i915_reset_count(&dev_priv->gpu_error);
+       else
+               args->reset_count = 0;
+
+       args->batch_active = hs->batch_active;
+       args->batch_pending = hs->batch_pending;
+
+       mutex_unlock(&dev->struct_mutex);
+
+       return 0;
+}
+
 static int i965_reset_complete(struct drm_device *dev)
 {
        u8 gdrst;
@@ -770,12 +966,12 @@ static int gen6_do_reset(struct drm_device *dev)
 
        /* If reset with a user forcewake, try to restore, otherwise turn it off */
        if (dev_priv->uncore.forcewake_count)
-               dev_priv->uncore.funcs.force_wake_get(dev_priv);
+               dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
        else
-               dev_priv->uncore.funcs.force_wake_put(dev_priv);
+               dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
 
        /* Restore fifo count */
-       dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GT_FIFO_FREE_ENTRIES);
+       dev_priv->uncore.fifo_count = __raw_i915_read32(dev_priv, GTFIFOCTL) & GT_FIFO_FREE_ENTRIES_MASK;
 
        spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
        return ret;
@@ -793,15 +989,6 @@ int intel_gpu_reset(struct drm_device *dev)
        }
 }
 
-void intel_uncore_clear_errors(struct drm_device *dev)
-{
-       struct drm_i915_private *dev_priv = dev->dev_private;
-
-       /* XXX needs spinlock around caller's grouping */
-       if (HAS_FPGA_DBG_UNCLAIMED(dev))
-               __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
-}
-
 void intel_uncore_check_errors(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
index 087db33f6cff19f8cdaa32f390c6c4dd52a8c79d..c3bf059ba720569540145f225222e0f2b444827c 100644 (file)
@@ -1075,10 +1075,10 @@ static int mga_dma_get_buffers(struct drm_device *dev,
 
                buf->file_priv = file_priv;
 
-               if (DRM_COPY_TO_USER(&d->request_indices[i],
+               if (copy_to_user(&d->request_indices[i],
                                     &buf->idx, sizeof(buf->idx)))
                        return -EFAULT;
-               if (DRM_COPY_TO_USER(&d->request_sizes[i],
+               if (copy_to_user(&d->request_sizes[i],
                                     &buf->total, sizeof(buf->total)))
                        return -EFAULT;
 
index ca4bc54ea2146303f4cedf7bdd879b3c3bc812fd..fe453213600ab728e57385e40b272e4e8b8ebc49 100644 (file)
@@ -186,14 +186,14 @@ extern void mga_disable_vblank(struct drm_device *dev, int crtc);
 extern u32 mga_get_vblank_counter(struct drm_device *dev, int crtc);
 extern int mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence);
 extern int mga_driver_vblank_wait(struct drm_device *dev, unsigned int *sequence);
-extern irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS);
+extern irqreturn_t mga_driver_irq_handler(int irq, void *arg);
 extern void mga_driver_irq_preinstall(struct drm_device *dev);
 extern int mga_driver_irq_postinstall(struct drm_device *dev);
 extern void mga_driver_irq_uninstall(struct drm_device *dev);
 extern long mga_compat_ioctl(struct file *filp, unsigned int cmd,
                             unsigned long arg);
 
-#define mga_flush_write_combine()      DRM_WRITEMEMORYBARRIER()
+#define mga_flush_write_combine()      wmb()
 
 #define MGA_READ8(reg)         DRM_READ8(dev_priv->mmio, (reg))
 #define MGA_READ(reg)          DRM_READ32(dev_priv->mmio, (reg))
index 709e90db8c4087dfcb782a51deab776271a7feb0..86b4bb80485200e1067c47574117fa1c46c17b8f 100644 (file)
@@ -34,6 +34,7 @@
 
 #include <drm/drmP.h>
 #include <drm/mga_drm.h>
+#include "mga_drv.h"
 
 typedef struct drm32_mga_init {
        int func;
index 2b0ceb8dc11b8dce6894cf056998714603087a3d..1b071b8ff9dccec81e1d93376d0b6b09bc58521b 100644 (file)
@@ -47,7 +47,7 @@ u32 mga_get_vblank_counter(struct drm_device *dev, int crtc)
 }
 
 
-irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
+irqreturn_t mga_driver_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
@@ -79,7 +79,7 @@ irqreturn_t mga_driver_irq_handler(DRM_IRQ_ARGS)
                        MGA_WRITE(MGA_PRIMEND, prim_end);
 
                atomic_inc(&dev_priv->last_fence_retired);
-               DRM_WAKEUP(&dev_priv->fence_queue);
+               wake_up(&dev_priv->fence_queue);
                handled = 1;
        }
 
@@ -128,7 +128,7 @@ int mga_driver_fence_wait(struct drm_device *dev, unsigned int *sequence)
         * by about a day rather than she wants to wait for years
         * using fences.
         */
-       DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * DRM_HZ,
+       DRM_WAIT_ON(ret, dev_priv->fence_queue, 3 * HZ,
                    (((cur_fence = atomic_read(&dev_priv->last_fence_retired))
                      - *sequence) <= (1 << 23)));
 
@@ -151,7 +151,7 @@ int mga_driver_irq_postinstall(struct drm_device *dev)
 {
        drm_mga_private_t *dev_priv = (drm_mga_private_t *) dev->dev_private;
 
-       DRM_INIT_WAITQUEUE(&dev_priv->fence_queue);
+       init_waitqueue_head(&dev_priv->fence_queue);
 
        /* Turn on soft trap interrupt.  Vertical blank interrupts are enabled
         * in mga_enable_vblank.
index 37cc2fb4eadd9a033316f5951eddc81f8fb072e0..314685b7f41fc4acb21a2c9c0cad86ecbd1ccad2 100644 (file)
@@ -1029,7 +1029,7 @@ static int mga_getparam(struct drm_device *dev, void *data, struct drm_file *fil
                return -EINVAL;
        }
 
-       if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
+       if (copy_to_user(param->value, &value, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
                return -EFAULT;
        }
index 801731aeab61cddf3db56419dea57f5240ed5994..9f9780b7ddf0be7d3a82ba77205d21d29984b02f 100644 (file)
@@ -22,8 +22,10 @@ static void mga_hide_cursor(struct mga_device *mdev)
 {
        WREG8(MGA_CURPOSXL, 0);
        WREG8(MGA_CURPOSXH, 0);
-       mgag200_bo_unpin(mdev->cursor.pixels_1);
-       mgag200_bo_unpin(mdev->cursor.pixels_2);
+       if (mdev->cursor.pixels_1->pin_count)
+               mgag200_bo_unpin(mdev->cursor.pixels_1);
+       if (mdev->cursor.pixels_2->pin_count)
+               mgag200_bo_unpin(mdev->cursor.pixels_2);
 }
 
 int mga_crtc_cursor_set(struct drm_crtc *crtc,
@@ -32,7 +34,7 @@ int mga_crtc_cursor_set(struct drm_crtc *crtc,
                        uint32_t width,
                        uint32_t height)
 {
-       struct drm_device *dev = (struct drm_device *)file_priv->minor->dev;
+       struct drm_device *dev = crtc->dev;
        struct mga_device *mdev = (struct mga_device *)dev->dev_private;
        struct mgag200_bo *pixels_1 = mdev->cursor.pixels_1;
        struct mgag200_bo *pixels_2 = mdev->cursor.pixels_2;
index 964f58cee5ea67b37f02e680b0f1ab7ebb3e5ed3..f9adc27ef32a05fdee5b66a23e35b7e6df21fd3d 100644 (file)
@@ -41,7 +41,7 @@ static void mga_dirty_update(struct mga_fbdev *mfbdev,
         * then the BO is being moved and we should
         * store up the damage until later.
         */
-       if (!in_interrupt())
+       if (!drm_can_sleep())
                ret = mgag200_bo_reserve(bo, true);
        if (ret) {
                if (ret != -EBUSY)
@@ -282,6 +282,11 @@ int mgag200_fbdev_init(struct mga_device *mdev)
 {
        struct mga_fbdev *mfbdev;
        int ret;
+       int bpp_sel = 32;
+
+       /* prefer 16bpp on low end gpus with limited VRAM */
+       if (IS_G200_SE(mdev) && mdev->mc.vram_size < (2048*1024))
+               bpp_sel = 16;
 
        mfbdev = devm_kzalloc(mdev->dev->dev, sizeof(struct mga_fbdev), GFP_KERNEL);
        if (!mfbdev)
@@ -301,7 +306,7 @@ int mgag200_fbdev_init(struct mga_device *mdev)
        /* disable all the possible outputs/crtcs before entering KMS mode */
        drm_helper_disable_unused_functions(mdev->dev);
 
-       drm_fb_helper_initial_config(&mfbdev->helper, 32);
+       drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel);
 
        return 0;
 }
index b1120cb1db6d76b76fd38afd3279a3684e6b188b..26868e5c55b076352188d34962b928a87a64d1a9 100644 (file)
@@ -217,7 +217,10 @@ int mgag200_driver_load(struct drm_device *dev, unsigned long flags)
 
        drm_mode_config_init(dev);
        dev->mode_config.funcs = (void *)&mga_mode_funcs;
-       dev->mode_config.preferred_depth = 24;
+       if (IS_G200_SE(mdev) && mdev->mc.vram_size < (2048*1024))
+               dev->mode_config.preferred_depth = 16;
+       else
+               dev->mode_config.preferred_depth = 24;
        dev->mode_config.prefer_shadow = 1;
 
        r = mgag200_modeset_init(mdev);
@@ -310,7 +313,7 @@ int mgag200_dumb_create(struct drm_file *file,
        return 0;
 }
 
-void mgag200_bo_unref(struct mgag200_bo **bo)
+static void mgag200_bo_unref(struct mgag200_bo **bo)
 {
        struct ttm_buffer_object *tbo;
 
index ee6ed633b7b1c1bb34ac6b59ec85db52c69a4f27..b8583f275e80519dd46d922d1f5c1a0ed9c8bcbf 100644 (file)
@@ -691,7 +691,7 @@ static void mga_g200wb_commit(struct drm_crtc *crtc)
    CRTCEXT0 has to be programmed last to trigger an update and make the
    new addr variable take effect.
  */
-void mga_set_start_address(struct drm_crtc *crtc, unsigned offset)
+static void mga_set_start_address(struct drm_crtc *crtc, unsigned offset)
 {
        struct mga_device *mdev = crtc->dev->dev_private;
        u32 addr;
@@ -1398,7 +1398,7 @@ static void mga_encoder_commit(struct drm_encoder *encoder)
 {
 }
 
-void mga_encoder_destroy(struct drm_encoder *encoder)
+static void mga_encoder_destroy(struct drm_encoder *encoder)
 {
        struct mga_encoder *mga_encoder = to_mga_encoder(encoder);
        drm_encoder_cleanup(encoder);
@@ -1558,7 +1558,7 @@ static int mga_vga_mode_valid(struct drm_connector *connector,
        return MODE_OK;
 }
 
-struct drm_encoder *mga_connector_best_encoder(struct drm_connector
+static struct drm_encoder *mga_connector_best_encoder(struct drm_connector
                                                  *connector)
 {
        int enc_id = connector->encoder_ids[0];
index 07b192fe15c6c6f9d0c23434280972616693ca48..adb5166a5dfdbe3a77e4e7154411e5162df1abd3 100644 (file)
@@ -80,7 +80,7 @@ static int mgag200_ttm_global_init(struct mga_device *ast)
        return 0;
 }
 
-void
+static void
 mgag200_ttm_global_release(struct mga_device *ast)
 {
        if (ast->ttm.mem_global_ref.release == NULL)
@@ -102,7 +102,7 @@ static void mgag200_bo_ttm_destroy(struct ttm_buffer_object *tbo)
        kfree(bo);
 }
 
-bool mgag200_ttm_bo_is_mgag200_bo(struct ttm_buffer_object *bo)
+static bool mgag200_ttm_bo_is_mgag200_bo(struct ttm_buffer_object *bo)
 {
        if (bo->destroy == &mgag200_bo_ttm_destroy)
                return true;
@@ -208,7 +208,7 @@ static struct ttm_backend_func mgag200_tt_backend_func = {
 };
 
 
-struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev,
+static struct ttm_tt *mgag200_ttm_tt_create(struct ttm_bo_device *bdev,
                                 unsigned long size, uint32_t page_flags,
                                 struct page *dummy_read_page)
 {
index f39ab7554fc992175630831acf28bbf223cd9f50..c69d1e07a3a67b397ac798e312df7b31b62e3d20 100644 (file)
@@ -2,8 +2,8 @@
 config DRM_MSM
        tristate "MSM DRM"
        depends on DRM
-       depends on ARCH_MSM
-       depends on ARCH_MSM8960
+       depends on MSM_IOMMU
+       depends on (ARCH_MSM && ARCH_MSM8960) || (ARM && COMPILE_TEST)
        select DRM_KMS_HELPER
        select SHMEM
        select TMPFS
index e5fa12b0d21eca645a2cc5efa8f74bef595ad2bb..4f977a593bea13334aebca905c87be43223b2e06 100644 (file)
@@ -12,18 +12,27 @@ msm-y := \
        hdmi/hdmi_i2c.o \
        hdmi/hdmi_phy_8960.o \
        hdmi/hdmi_phy_8x60.o \
-       mdp4/mdp4_crtc.o \
-       mdp4/mdp4_dtv_encoder.o \
-       mdp4/mdp4_format.o \
-       mdp4/mdp4_irq.o \
-       mdp4/mdp4_kms.o \
-       mdp4/mdp4_plane.o \
+       hdmi/hdmi_phy_8x74.o \
+       mdp/mdp_format.o \
+       mdp/mdp_kms.o \
+       mdp/mdp4/mdp4_crtc.o \
+       mdp/mdp4/mdp4_dtv_encoder.o \
+       mdp/mdp4/mdp4_irq.o \
+       mdp/mdp4/mdp4_kms.o \
+       mdp/mdp4/mdp4_plane.o \
+       mdp/mdp5/mdp5_crtc.o \
+       mdp/mdp5/mdp5_encoder.o \
+       mdp/mdp5/mdp5_irq.o \
+       mdp/mdp5/mdp5_kms.o \
+       mdp/mdp5/mdp5_plane.o \
+       mdp/mdp5/mdp5_smp.o \
        msm_drv.o \
        msm_fb.o \
        msm_gem.o \
        msm_gem_prime.o \
        msm_gem_submit.o \
        msm_gpu.o \
+       msm_iommu.o \
        msm_ringbuffer.o
 
 msm-$(CONFIG_DRM_MSM_FBDEV) += msm_fbdev.o
index e036f6c1db9447180ddca1a518174ec692d94738..9c4255b980218c229ae5f40a7c89c8445435d43a 100644 (file)
@@ -4,7 +4,7 @@ In the current snapdragon SoC's, we have (at least) 3 different
 display controller blocks at play:
  + MDP3 - ?? seems to be what is on geeksphone peak device
  + MDP4 - S3 (APQ8060, touchpad), S4-pro (APQ8064, nexus4 & ifc6410)
- + MDSS - snapdragon 800
+ + MDP5 - snapdragon 800
 
 (I don't have a completely clear picture on which display controller
 maps to which part #)
@@ -46,6 +46,24 @@ and treat the MDP4 block's irq as "the" irq.  Even though the connectors
 may have their own irqs which they install themselves.  For this reason
 the display controller is the "master" device.
 
+For MDP5, the mapping is:
+
+  plane   -> PIPE{RGBn,VIGn}             \
+  crtc    -> LM (layer mixer)            |-> MDP "device"
+  encoder -> INTF                        /
+  connector -> HDMI/DSI/eDP/etc          --> other device(s)
+
+Unlike MDP4, it appears we can get by with a single encoder, rather
+than needing a different implementation for DTV, DSI, etc.  (Ie. the
+register interface is same, just different bases.)
+
+Also unlike MDP4, with MDP5 all the IRQs for other blocks (HDMI, DSI,
+etc) are routed through MDP.
+
+And finally, MDP5 has this "Shared Memory Pool" (called "SMP"), from
+which blocks need to be allocated to the active pipes based on fetch
+stride.
+
 Each connector probably ends up being a separate device, just for the
 logistics of finding/mapping io region, irq, etc.  Idealy we would
 have a better way than just stashing the platform device in a global
index 9588098741b5b7f76e379d715eb358bfa78d92f0..85d615e7d62fb75789a127fcc021c111a0baa74e 100644 (file)
@@ -8,12 +8,13 @@ http://github.com/freedreno/envytools/
 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/adreno.xml              (    327 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  31003 bytes, from 2013-09-19 18:50:16)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml       (   8983 bytes, from 2013-07-24 01:38:36)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9759 bytes, from 2013-09-10 00:52:33)
-- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51983 bytes, from 2013-09-10 00:52:32)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
+- /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          (  32814 bytes, from 2013-11-30 15:07:33)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   8900 bytes, from 2013-10-22 23:57:49)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  10574 bytes, from 2013-11-13 05:44:45)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  53644 bytes, from 2013-11-30 15:07:33)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (   8344 bytes, from 2013-11-30 14:49:47)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -202,6 +203,12 @@ enum a2xx_rb_copy_sample_select {
        SAMPLE_0123 = 6,
 };
 
+enum adreno_mmu_clnt_beh {
+       BEH_NEVR = 0,
+       BEH_TRAN_RNG = 1,
+       BEH_TRAN_FLT = 2,
+};
+
 enum sq_tex_clamp {
        SQ_TEX_WRAP = 0,
        SQ_TEX_MIRROR = 1,
@@ -238,6 +245,92 @@ enum sq_tex_filter {
 
 #define REG_A2XX_CP_PFP_UCODE_DATA                             0x000000c1
 
+#define REG_A2XX_MH_MMU_CONFIG                                 0x00000040
+#define A2XX_MH_MMU_CONFIG_MMU_ENABLE                          0x00000001
+#define A2XX_MH_MMU_CONFIG_SPLIT_MODE_ENABLE                   0x00000002
+#define A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK            0x00000030
+#define A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT           4
+static inline uint32_t A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK            0x000000c0
+#define A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT           6
+static inline uint32_t A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK           0x00000300
+#define A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT          8
+static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK           0x00000c00
+#define A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT          10
+static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK           0x00003000
+#define A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT          12
+static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK           0x0000c000
+#define A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT          14
+static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK           0x00030000
+#define A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT          16
+static inline uint32_t A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK          0x000c0000
+#define A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT         18
+static inline uint32_t A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK          0x00300000
+#define A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT         20
+static inline uint32_t A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK            0x00c00000
+#define A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT           22
+static inline uint32_t A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK;
+}
+#define A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK            0x03000000
+#define A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT           24
+static inline uint32_t A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
+{
+       return ((val) << A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT) & A2XX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK;
+}
+
+#define REG_A2XX_MH_MMU_VA_RANGE                               0x00000041
+
+#define REG_A2XX_MH_MMU_PT_BASE                                        0x00000042
+
+#define REG_A2XX_MH_MMU_PAGE_FAULT                             0x00000043
+
+#define REG_A2XX_MH_MMU_TRAN_ERROR                             0x00000044
+
+#define REG_A2XX_MH_MMU_INVALIDATE                             0x00000045
+
+#define REG_A2XX_MH_MMU_MPU_BASE                               0x00000046
+
+#define REG_A2XX_MH_MMU_MPU_END                                        0x00000047
+
+#define REG_A2XX_NQWAIT_UNTIL                                  0x00000394
+
 #define REG_A2XX_RBBM_PERFCOUNTER1_SELECT                      0x00000395
 
 #define REG_A2XX_RBBM_PERFCOUNTER1_LO                          0x00000397
@@ -276,20 +369,6 @@ enum sq_tex_filter {
 
 #define REG_A2XX_CP_PERFCOUNTER_HI                             0x00000447
 
-#define REG_A2XX_CP_ST_BASE                                    0x0000044d
-
-#define REG_A2XX_CP_ST_BUFSZ                                   0x0000044e
-
-#define REG_A2XX_CP_IB1_BASE                                   0x00000458
-
-#define REG_A2XX_CP_IB1_BUFSZ                                  0x00000459
-
-#define REG_A2XX_CP_IB2_BASE                                   0x0000045a
-
-#define REG_A2XX_CP_IB2_BUFSZ                                  0x0000045b
-
-#define REG_A2XX_CP_STAT                                       0x0000047f
-
 #define REG_A2XX_RBBM_STATUS                                   0x000005d0
 #define A2XX_RBBM_STATUS_CMDFIFO_AVAIL__MASK                   0x0000001f
 #define A2XX_RBBM_STATUS_CMDFIFO_AVAIL__SHIFT                  0
@@ -808,6 +887,12 @@ static inline uint32_t A2XX_SQ_CONTEXT_MISC_PARAM_GEN_POS(uint32_t val)
 
 #define REG_A2XX_SQ_VS_PROGRAM                                 0x000021f7
 
+#define REG_A2XX_VGT_EVENT_INITIATOR                           0x000021f9
+
+#define REG_A2XX_VGT_DRAW_INITIATOR                            0x000021fc
+
+#define REG_A2XX_VGT_IMMED_DATA                                        0x000021fd
+
 #define REG_A2XX_RB_DEPTHCONTROL                               0x00002200
 #define A2XX_RB_DEPTHCONTROL_STENCIL_ENABLE                    0x00000001
 #define A2XX_RB_DEPTHCONTROL_Z_ENABLE                          0x00000002
index d4afdf6575597f0dd4d06ed2eac5fc09b2cad076..a7be56163d2324f4a24ae7e4836168f95db967a2 100644 (file)
@@ -8,12 +8,13 @@ http://github.com/freedreno/envytools/
 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/adreno.xml              (    327 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  31003 bytes, from 2013-09-19 18:50:16)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml       (   8983 bytes, from 2013-07-24 01:38:36)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9759 bytes, from 2013-09-10 00:52:33)
-- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51983 bytes, from 2013-09-10 00:52:32)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
+- /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          (  32814 bytes, from 2013-11-30 15:07:33)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   8900 bytes, from 2013-10-22 23:57:49)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  10574 bytes, from 2013-11-13 05:44:45)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  53644 bytes, from 2013-11-30 15:07:33)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (   8344 bytes, from 2013-11-30 14:49:47)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -292,6 +293,8 @@ enum a3xx_tex_type {
 #define A3XX_RBBM_STATUS_GPU_BUSY_NOHC                         0x40000000
 #define A3XX_RBBM_STATUS_GPU_BUSY                              0x80000000
 
+#define REG_A3XX_RBBM_NQWAIT_UNTIL                             0x00000040
+
 #define REG_A3XX_RBBM_WAIT_IDLE_CLOCKS_CTL                     0x00000033
 
 #define REG_A3XX_RBBM_INTERFACE_HANG_INT_CTL                   0x00000050
@@ -304,6 +307,8 @@ enum a3xx_tex_type {
 
 #define REG_A3XX_RBBM_INTERFACE_HANG_MASK_CTL3                 0x0000005a
 
+#define REG_A3XX_RBBM_INT_SET_CMD                              0x00000060
+
 #define REG_A3XX_RBBM_INT_CLEAR_CMD                            0x00000061
 
 #define REG_A3XX_RBBM_INT_0_MASK                               0x00000063
@@ -937,13 +942,13 @@ static inline uint32_t A3XX_RB_BLEND_ALPHA_FLOAT(float val)
        return ((util_float_to_half(val)) << A3XX_RB_BLEND_ALPHA_FLOAT__SHIFT) & A3XX_RB_BLEND_ALPHA_FLOAT__MASK;
 }
 
-#define REG_A3XX_UNKNOWN_20E8                                  0x000020e8
+#define REG_A3XX_RB_CLEAR_COLOR_DW0                            0x000020e8
 
-#define REG_A3XX_UNKNOWN_20E9                                  0x000020e9
+#define REG_A3XX_RB_CLEAR_COLOR_DW1                            0x000020e9
 
-#define REG_A3XX_UNKNOWN_20EA                                  0x000020ea
+#define REG_A3XX_RB_CLEAR_COLOR_DW2                            0x000020ea
 
-#define REG_A3XX_UNKNOWN_20EB                                  0x000020eb
+#define REG_A3XX_RB_CLEAR_COLOR_DW3                            0x000020eb
 
 #define REG_A3XX_RB_COPY_CONTROL                               0x000020ec
 #define A3XX_RB_COPY_CONTROL_MSAA_RESOLVE__MASK                        0x00000003
@@ -1026,7 +1031,7 @@ static inline uint32_t A3XX_RB_DEPTH_CONTROL_ZFUNC(enum adreno_compare_func val)
 #define A3XX_RB_DEPTH_CONTROL_BF_ENABLE                                0x00000080
 #define A3XX_RB_DEPTH_CONTROL_Z_TEST_ENABLE                    0x80000000
 
-#define REG_A3XX_UNKNOWN_2101                                  0x00002101
+#define REG_A3XX_RB_DEPTH_CLEAR                                        0x00002101
 
 #define REG_A3XX_RB_DEPTH_INFO                                 0x00002102
 #define A3XX_RB_DEPTH_INFO_DEPTH_FORMAT__MASK                  0x00000001
@@ -1103,11 +1108,11 @@ static inline uint32_t A3XX_RB_STENCIL_CONTROL_ZFAIL_BF(enum adreno_stencil_op v
        return ((val) << A3XX_RB_STENCIL_CONTROL_ZFAIL_BF__SHIFT) & A3XX_RB_STENCIL_CONTROL_ZFAIL_BF__MASK;
 }
 
-#define REG_A3XX_UNKNOWN_2105                                  0x00002105
+#define REG_A3XX_RB_STENCIL_CLEAR                              0x00002105
 
-#define REG_A3XX_UNKNOWN_2106                                  0x00002106
+#define REG_A3XX_RB_STENCIL_BUF_INFO                           0x00002106
 
-#define REG_A3XX_UNKNOWN_2107                                  0x00002107
+#define REG_A3XX_RB_STENCIL_BUF_PITCH                          0x00002107
 
 #define REG_A3XX_RB_STENCILREFMASK                             0x00002108
 #define A3XX_RB_STENCILREFMASK_STENCILREF__MASK                        0x000000ff
@@ -1149,20 +1154,31 @@ static inline uint32_t A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK(uint32_t val)
        return ((val) << A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__SHIFT) & A3XX_RB_STENCILREFMASK_BF_STENCILWRITEMASK__MASK;
 }
 
-#define REG_A3XX_PA_SC_WINDOW_OFFSET                           0x0000210e
-#define A3XX_PA_SC_WINDOW_OFFSET_X__MASK                       0x0000ffff
-#define A3XX_PA_SC_WINDOW_OFFSET_X__SHIFT                      0
-static inline uint32_t A3XX_PA_SC_WINDOW_OFFSET_X(uint32_t val)
+#define REG_A3XX_RB_LRZ_VSC_CONTROL                            0x0000210c
+#define A3XX_RB_LRZ_VSC_CONTROL_BINNING_ENABLE                 0x00000002
+
+#define REG_A3XX_RB_WINDOW_OFFSET                              0x0000210e
+#define A3XX_RB_WINDOW_OFFSET_X__MASK                          0x0000ffff
+#define A3XX_RB_WINDOW_OFFSET_X__SHIFT                         0
+static inline uint32_t A3XX_RB_WINDOW_OFFSET_X(uint32_t val)
 {
-       return ((val) << A3XX_PA_SC_WINDOW_OFFSET_X__SHIFT) & A3XX_PA_SC_WINDOW_OFFSET_X__MASK;
+       return ((val) << A3XX_RB_WINDOW_OFFSET_X__SHIFT) & A3XX_RB_WINDOW_OFFSET_X__MASK;
 }
-#define A3XX_PA_SC_WINDOW_OFFSET_Y__MASK                       0xffff0000
-#define A3XX_PA_SC_WINDOW_OFFSET_Y__SHIFT                      16
-static inline uint32_t A3XX_PA_SC_WINDOW_OFFSET_Y(uint32_t val)
+#define A3XX_RB_WINDOW_OFFSET_Y__MASK                          0xffff0000
+#define A3XX_RB_WINDOW_OFFSET_Y__SHIFT                         16
+static inline uint32_t A3XX_RB_WINDOW_OFFSET_Y(uint32_t val)
 {
-       return ((val) << A3XX_PA_SC_WINDOW_OFFSET_Y__SHIFT) & A3XX_PA_SC_WINDOW_OFFSET_Y__MASK;
+       return ((val) << A3XX_RB_WINDOW_OFFSET_Y__SHIFT) & A3XX_RB_WINDOW_OFFSET_Y__MASK;
 }
 
+#define REG_A3XX_RB_SAMPLE_COUNT_CONTROL                       0x00002110
+
+#define REG_A3XX_RB_SAMPLE_COUNT_ADDR                          0x00002111
+
+#define REG_A3XX_RB_Z_CLAMP_MIN                                        0x00002114
+
+#define REG_A3XX_RB_Z_CLAMP_MAX                                        0x00002115
+
 #define REG_A3XX_PC_VSTREAM_CONTROL                            0x000021e4
 
 #define REG_A3XX_PC_VERTEX_REUSE_BLOCK_CNTL                    0x000021ea
@@ -1309,6 +1325,8 @@ static inline uint32_t A3XX_HLSQ_CONST_FSPRESV_RANGE_REG_ENDENTRY(uint32_t val)
 
 #define REG_A3XX_HLSQ_CL_KERNEL_GROUP_X_REG                    0x00002215
 
+#define REG_A3XX_HLSQ_CL_KERNEL_GROUP_Y_REG                    0x00002216
+
 #define REG_A3XX_HLSQ_CL_KERNEL_GROUP_Z_REG                    0x00002217
 
 #define REG_A3XX_HLSQ_CL_WG_OFFSET_REG                         0x0000221a
@@ -1491,12 +1509,13 @@ static inline uint32_t REG_A3XX_VPC_VARYING_PS_REPL_MODE(uint32_t i0) { return 0
 
 #define REG_A3XX_SP_SP_CTRL_REG                                        0x000022c0
 #define A3XX_SP_SP_CTRL_REG_RESOLVE                            0x00010000
-#define A3XX_SP_SP_CTRL_REG_CONSTMODE__MASK                    0x000c0000
+#define A3XX_SP_SP_CTRL_REG_CONSTMODE__MASK                    0x00040000
 #define A3XX_SP_SP_CTRL_REG_CONSTMODE__SHIFT                   18
 static inline uint32_t A3XX_SP_SP_CTRL_REG_CONSTMODE(uint32_t val)
 {
        return ((val) << A3XX_SP_SP_CTRL_REG_CONSTMODE__SHIFT) & A3XX_SP_SP_CTRL_REG_CONSTMODE__MASK;
 }
+#define A3XX_SP_SP_CTRL_REG_BINNING                            0x00080000
 #define A3XX_SP_SP_CTRL_REG_SLEEPMODE__MASK                    0x00300000
 #define A3XX_SP_SP_CTRL_REG_SLEEPMODE__SHIFT                   20
 static inline uint32_t A3XX_SP_SP_CTRL_REG_SLEEPMODE(uint32_t val)
@@ -1669,7 +1688,7 @@ static inline uint32_t A3XX_SP_VS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
 
 #define REG_A3XX_SP_VS_OBJ_START_REG                           0x000022d5
 
-#define REG_A3XX_SP_VS_PVT_MEM_CTRL_REG                                0x000022d6
+#define REG_A3XX_SP_VS_PVT_MEM_PARAM_REG                       0x000022d6
 
 #define REG_A3XX_SP_VS_PVT_MEM_ADDR_REG                                0x000022d7
 
@@ -1772,7 +1791,7 @@ static inline uint32_t A3XX_SP_FS_OBJ_OFFSET_REG_SHADEROBJOFFSET(uint32_t val)
 
 #define REG_A3XX_SP_FS_OBJ_START_REG                           0x000022e3
 
-#define REG_A3XX_SP_FS_PVT_MEM_CTRL_REG                                0x000022e4
+#define REG_A3XX_SP_FS_PVT_MEM_PARAM_REG                       0x000022e4
 
 #define REG_A3XX_SP_FS_PVT_MEM_ADDR_REG                                0x000022e5
 
@@ -1943,6 +1962,9 @@ static inline uint32_t REG_A3XX_VSC_PIPE_DATA_ADDRESS(uint32_t i0) { return 0x00
 
 static inline uint32_t REG_A3XX_VSC_PIPE_DATA_LENGTH(uint32_t i0) { return 0x00000c08 + 0x3*i0; }
 
+#define REG_A3XX_VSC_BIN_CONTROL                               0x00000c3c
+#define A3XX_VSC_BIN_CONTROL_BINNING_ENABLE                    0x00000001
+
 #define REG_A3XX_UNKNOWN_0C3D                                  0x00000c3d
 
 #define REG_A3XX_PC_PERFCOUNTER0_SELECT                                0x00000c48
@@ -1953,7 +1975,7 @@ static inline uint32_t REG_A3XX_VSC_PIPE_DATA_LENGTH(uint32_t i0) { return 0x000
 
 #define REG_A3XX_PC_PERFCOUNTER3_SELECT                                0x00000c4b
 
-#define REG_A3XX_UNKNOWN_0C81                                  0x00000c81
+#define REG_A3XX_GRAS_TSE_DEBUG_ECO                            0x00000c81
 
 #define REG_A3XX_GRAS_PERFCOUNTER0_SELECT                      0x00000c88
 
@@ -1975,22 +1997,24 @@ static inline uint32_t REG_A3XX_GRAS_CL_USER_PLANE_W(uint32_t i0) { return 0x000
 
 #define REG_A3XX_RB_GMEM_BASE_ADDR                             0x00000cc0
 
+#define REG_A3XX_RB_DEBUG_ECO_CONTROLS_ADDR                    0x00000cc1
+
 #define REG_A3XX_RB_PERFCOUNTER0_SELECT                                0x00000cc6
 
 #define REG_A3XX_RB_PERFCOUNTER1_SELECT                                0x00000cc7
 
-#define REG_A3XX_RB_WINDOW_SIZE                                        0x00000ce0
-#define A3XX_RB_WINDOW_SIZE_WIDTH__MASK                                0x00003fff
-#define A3XX_RB_WINDOW_SIZE_WIDTH__SHIFT                       0
-static inline uint32_t A3XX_RB_WINDOW_SIZE_WIDTH(uint32_t val)
+#define REG_A3XX_RB_FRAME_BUFFER_DIMENSION                     0x00000ce0
+#define A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__MASK             0x00003fff
+#define A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__SHIFT            0
+static inline uint32_t A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH(uint32_t val)
 {
-       return ((val) << A3XX_RB_WINDOW_SIZE_WIDTH__SHIFT) & A3XX_RB_WINDOW_SIZE_WIDTH__MASK;
+       return ((val) << A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__SHIFT) & A3XX_RB_FRAME_BUFFER_DIMENSION_WIDTH__MASK;
 }
-#define A3XX_RB_WINDOW_SIZE_HEIGHT__MASK                       0x0fffc000
-#define A3XX_RB_WINDOW_SIZE_HEIGHT__SHIFT                      14
-static inline uint32_t A3XX_RB_WINDOW_SIZE_HEIGHT(uint32_t val)
+#define A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__MASK            0x0fffc000
+#define A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__SHIFT           14
+static inline uint32_t A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT(uint32_t val)
 {
-       return ((val) << A3XX_RB_WINDOW_SIZE_HEIGHT__SHIFT) & A3XX_RB_WINDOW_SIZE_HEIGHT__MASK;
+       return ((val) << A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__SHIFT) & A3XX_RB_FRAME_BUFFER_DIMENSION_HEIGHT__MASK;
 }
 
 #define REG_A3XX_HLSQ_PERFCOUNTER0_SELECT                      0x00000e00
@@ -2088,6 +2112,14 @@ static inline uint32_t A3XX_UCHE_CACHE_INVALIDATE1_REG_OPCODE(enum a3xx_cache_op
 
 #define REG_A3XX_TP_PERFCOUNTER5_SELECT                                0x00000f09
 
+#define REG_A3XX_VGT_CL_INITIATOR                              0x000021f0
+
+#define REG_A3XX_VGT_EVENT_INITIATOR                           0x000021f9
+
+#define REG_A3XX_VGT_DRAW_INITIATOR                            0x000021fc
+
+#define REG_A3XX_VGT_IMMED_DATA                                        0x000021fd
+
 #define REG_A3XX_TEX_SAMP_0                                    0x00000000
 #define A3XX_TEX_SAMP_0_MIPFILTER_LINEAR                       0x00000002
 #define A3XX_TEX_SAMP_0_XY_MAG__MASK                           0x0000000c
@@ -2123,6 +2155,18 @@ static inline uint32_t A3XX_TEX_SAMP_0_WRAP_R(enum a3xx_tex_clamp val)
 #define A3XX_TEX_SAMP_0_UNNORM_COORDS                          0x80000000
 
 #define REG_A3XX_TEX_SAMP_1                                    0x00000001
+#define A3XX_TEX_SAMP_1_MAX_LOD__MASK                          0x003ff000
+#define A3XX_TEX_SAMP_1_MAX_LOD__SHIFT                         12
+static inline uint32_t A3XX_TEX_SAMP_1_MAX_LOD(float val)
+{
+       return ((((uint32_t)(val * 12.0))) << A3XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A3XX_TEX_SAMP_1_MAX_LOD__MASK;
+}
+#define A3XX_TEX_SAMP_1_MIN_LOD__MASK                          0xffc00000
+#define A3XX_TEX_SAMP_1_MIN_LOD__SHIFT                         22
+static inline uint32_t A3XX_TEX_SAMP_1_MIN_LOD(float val)
+{
+       return ((((uint32_t)(val * 12.0))) << A3XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A3XX_TEX_SAMP_1_MIN_LOD__MASK;
+}
 
 #define REG_A3XX_TEX_CONST_0                                   0x00000000
 #define A3XX_TEX_CONST_0_TILED                                 0x00000001
index 035bd13dc8bdc3ab039bc2f1bab291cbf4c9bf17..461df93e825edf81e98d22683cfbf4fe7b4404aa 100644 (file)
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#ifdef CONFIG_MSM_OCMEM
+#  include <mach/ocmem.h>
+#endif
+
 #include "a3xx_gpu.h"
 
 #define A3XX_INT0_MASK \
@@ -63,6 +67,7 @@ static void a3xx_me_init(struct msm_gpu *gpu)
 static int a3xx_hw_init(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
+       struct a3xx_gpu *a3xx_gpu = to_a3xx_gpu(adreno_gpu);
        uint32_t *ptr, len;
        int i, ret;
 
@@ -105,6 +110,21 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
                gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x000000ff);
                gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
 
+       } else if (adreno_is_a330v2(adreno_gpu)) {
+               /*
+                * Most of the VBIF registers on 8974v2 have the correct
+                * values at power on, so we won't modify those if we don't
+                * need to
+                */
+               /* Enable 1k sort: */
+               gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);
+               gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
+               /* Enable WR-REQ: */
+               gpu_write(gpu, REG_A3XX_VBIF_GATE_OFF_WRREQ_EN, 0x00003f);
+               gpu_write(gpu, REG_A3XX_VBIF_DDR_OUT_MAX_BURST, 0x0000303);
+               /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */
+               gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0003);
+
        } else if (adreno_is_a330(adreno_gpu)) {
                /* Set up 16 deep read/write request queues: */
                gpu_write(gpu, REG_A3XX_VBIF_IN_RD_LIM_CONF0, 0x18181818);
@@ -121,10 +141,10 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
                /* Set up VBIF_ROUND_ROBIN_QOS_ARB: */
                gpu_write(gpu, REG_A3XX_VBIF_ROUND_ROBIN_QOS_ARB, 0x0001);
                /* Set up AOOO: */
-               gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000ffff);
-               gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0xffffffff);
+               gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO_EN, 0x0000003f);
+               gpu_write(gpu, REG_A3XX_VBIF_OUT_AXI_AOOO, 0x003f003f);
                /* Enable 1K sort: */
-               gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001ffff);
+               gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT, 0x0001003f);
                gpu_write(gpu, REG_A3XX_VBIF_ABIT_SORT_CONF, 0x000000a4);
                /* Disable VBIF clock gating. This is to enable AXI running
                 * higher frequency than GPU:
@@ -162,14 +182,23 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
        gpu_write(gpu, REG_A3XX_UCHE_CACHE_MODE_CONTROL_REG, 0x00000001);
 
        /* Enable Clock gating: */
-       gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff);
-
-       /* Set the OCMEM base address for A330 */
-//TODO:
-//     if (adreno_is_a330(adreno_gpu)) {
-//             gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR,
-//                     (unsigned int)(a3xx_gpu->ocmem_base >> 14));
-//     }
+       if (adreno_is_a320(adreno_gpu))
+               gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbfffffff);
+       else if (adreno_is_a330v2(adreno_gpu))
+               gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xaaaaaaaa);
+       else if (adreno_is_a330(adreno_gpu))
+               gpu_write(gpu, REG_A3XX_RBBM_CLOCK_CTL, 0xbffcffff);
+
+       if (adreno_is_a330v2(adreno_gpu))
+               gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x05515455);
+       else if (adreno_is_a330(adreno_gpu))
+               gpu_write(gpu, REG_A3XX_RBBM_GPR0_CTL, 0x00000000);
+
+       /* Set the OCMEM base address for A330, etc */
+       if (a3xx_gpu->ocmem_hdl) {
+               gpu_write(gpu, REG_A3XX_RB_GMEM_BASE_ADDR,
+                       (unsigned int)(a3xx_gpu->ocmem_base >> 14));
+       }
 
        /* Turn on performance counters: */
        gpu_write(gpu, REG_A3XX_RBBM_PERFCTR_CTL, 0x01);
@@ -219,7 +248,7 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
        /* Load PM4: */
        ptr = (uint32_t *)(adreno_gpu->pm4->data);
        len = adreno_gpu->pm4->size / 4;
-       DBG("loading PM4 ucode version: %u", ptr[0]);
+       DBG("loading PM4 ucode version: %x", ptr[1]);
 
        gpu_write(gpu, REG_AXXX_CP_DEBUG,
                        AXXX_CP_DEBUG_DYNAMIC_CLK_DISABLE |
@@ -231,19 +260,26 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
        /* Load PFP: */
        ptr = (uint32_t *)(adreno_gpu->pfp->data);
        len = adreno_gpu->pfp->size / 4;
-       DBG("loading PFP ucode version: %u", ptr[0]);
+       DBG("loading PFP ucode version: %x", ptr[5]);
 
        gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_ADDR, 0);
        for (i = 1; i < len; i++)
                gpu_write(gpu, REG_A3XX_CP_PFP_UCODE_DATA, ptr[i]);
 
        /* CP ROQ queue sizes (bytes) - RB:16, ST:16, IB1:32, IB2:64 */
-       if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu))
+       if (adreno_is_a305(adreno_gpu) || adreno_is_a320(adreno_gpu)) {
                gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS,
                                AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB1_START(2) |
                                AXXX_CP_QUEUE_THRESHOLDS_CSQ_IB2_START(6) |
                                AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(14));
-
+       } else if (adreno_is_a330(adreno_gpu)) {
+               /* NOTE: this (value take from downstream android driver)
+                * includes some bits outside of the known bitfields.  But
+                * A330 has this "MERCIU queue" thing too, which might
+                * explain a new bitfield or reshuffling:
+                */
+               gpu_write(gpu, REG_AXXX_CP_QUEUE_THRESHOLDS, 0x003e2008);
+       }
 
        /* clear ME_HALT to start micro engine */
        gpu_write(gpu, REG_AXXX_CP_ME_CNTL, 0);
@@ -253,6 +289,14 @@ static int a3xx_hw_init(struct msm_gpu *gpu)
        return 0;
 }
 
+static void a3xx_recover(struct msm_gpu *gpu)
+{
+       gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 1);
+       gpu_read(gpu, REG_A3XX_RBBM_SW_RESET_CMD);
+       gpu_write(gpu, REG_A3XX_RBBM_SW_RESET_CMD, 0);
+       adreno_recover(gpu);
+}
+
 static void a3xx_destroy(struct msm_gpu *gpu)
 {
        struct adreno_gpu *adreno_gpu = to_adreno_gpu(gpu);
@@ -261,6 +305,12 @@ static void a3xx_destroy(struct msm_gpu *gpu)
        DBG("%s", gpu->name);
 
        adreno_gpu_cleanup(adreno_gpu);
+
+#ifdef CONFIG_MSM_OCMEM
+       if (a3xx_gpu->ocmem_base)
+               ocmem_free(OCMEM_GRAPHICS, a3xx_gpu->ocmem_hdl);
+#endif
+
        put_device(&a3xx_gpu->pdev->dev);
        kfree(a3xx_gpu);
 }
@@ -371,7 +421,7 @@ static const struct adreno_gpu_funcs funcs = {
                .hw_init = a3xx_hw_init,
                .pm_suspend = msm_gpu_pm_suspend,
                .pm_resume = msm_gpu_pm_resume,
-               .recover = adreno_recover,
+               .recover = a3xx_recover,
                .last_fence = adreno_last_fence,
                .submit = adreno_submit,
                .flush = adreno_flush,
@@ -387,6 +437,7 @@ static const struct adreno_gpu_funcs funcs = {
 struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
 {
        struct a3xx_gpu *a3xx_gpu = NULL;
+       struct adreno_gpu *adreno_gpu;
        struct msm_gpu *gpu;
        struct platform_device *pdev = a3xx_pdev;
        struct adreno_platform_config *config;
@@ -406,7 +457,8 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
                goto fail;
        }
 
-       gpu = &a3xx_gpu->base.base;
+       adreno_gpu = &a3xx_gpu->base;
+       gpu = &adreno_gpu->base;
 
        get_device(&pdev->dev);
        a3xx_gpu->pdev = pdev;
@@ -414,16 +466,46 @@ struct msm_gpu *a3xx_gpu_init(struct drm_device *dev)
        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);
 
-       ret = adreno_gpu_init(dev, pdev, &a3xx_gpu->base,
-                       &funcs, config->rev);
+       ret = adreno_gpu_init(dev, pdev, adreno_gpu, &funcs, config->rev);
        if (ret)
                goto fail;
 
-       return &a3xx_gpu->base.base;
+       /* if needed, allocate gmem: */
+       if (adreno_is_a330(adreno_gpu)) {
+#ifdef CONFIG_MSM_OCMEM
+               /* TODO this is different/missing upstream: */
+               struct ocmem_buf *ocmem_hdl =
+                               ocmem_allocate(OCMEM_GRAPHICS, adreno_gpu->gmem);
+
+               a3xx_gpu->ocmem_hdl = ocmem_hdl;
+               a3xx_gpu->ocmem_base = ocmem_hdl->addr;
+               adreno_gpu->gmem = ocmem_hdl->len;
+               DBG("using %dK of OCMEM at 0x%08x", adreno_gpu->gmem / 1024,
+                               a3xx_gpu->ocmem_base);
+#endif
+       }
+
+       if (!gpu->mmu) {
+               /* TODO we think it is possible to configure the GPU to
+                * restrict access to VRAM carveout.  But the required
+                * registers are unknown.  For now just bail out and
+                * limp along with just modesetting.  If it turns out
+                * to not be possible to restrict access, then we must
+                * implement a cmdstream validator.
+                */
+               dev_err(dev->dev, "No memory protection without IOMMU\n");
+               ret = -ENXIO;
+               goto fail;
+       }
+
+       return gpu;
 
 fail:
        if (a3xx_gpu)
@@ -436,19 +518,59 @@ fail:
  * The a3xx device:
  */
 
+#if defined(CONFIG_MSM_BUS_SCALING) && !defined(CONFIG_OF)
+#  include <mach/kgsl.h>
+#endif
+
 static int a3xx_probe(struct platform_device *pdev)
 {
        static struct adreno_platform_config config = {};
 #ifdef CONFIG_OF
-       /* TODO */
+       struct device_node *child, *node = pdev->dev.of_node;
+       u32 val;
+       int ret;
+
+       ret = of_property_read_u32(node, "qcom,chipid", &val);
+       if (ret) {
+               dev_err(&pdev->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(&pdev->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(&pdev->dev, "could not find clk rates\n");
+               return -ENXIO;
+       }
+
 #else
+       struct kgsl_device_platform_data *pdata = pdev->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() || cpu_is_msm8960ab()) {
+       } else if (cpu_is_apq8064()) {
                config.fast_rate = 400000000;
                config.slow_rate = 27000000;
                config.bus_freq  = 4;
@@ -461,6 +583,16 @@ static int a3xx_probe(struct platform_device *pdev)
                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;
@@ -473,6 +605,9 @@ static int a3xx_probe(struct platform_device *pdev)
                        config.rev = ADRENO_REV(3, 0, 5, 0);
 
        }
+#  ifdef CONFIG_MSM_BUS_SCALING
+       config.bus_scale_table = pdata->bus_scale_table;
+#  endif
 #endif
        pdev->dev.platform_data = &config;
        a3xx_pdev = pdev;
@@ -485,10 +620,19 @@ static int a3xx_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id dt_match[] = {
+       { .compatible = "qcom,kgsl-3d0" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, dt_match);
+
 static struct platform_driver a3xx_driver = {
        .probe = a3xx_probe,
        .remove = a3xx_remove,
-       .driver.name = "kgsl-3d0",
+       .driver = {
+               .name = "kgsl-3d0",
+               .of_match_table = dt_match,
+       },
 };
 
 void __init a3xx_register(void)
index 32c398c2d00a7103a64a0e76f248b0ce4a712db0..bb9a8ca0507b3cdf4a16be9d59383459d6ff4c13 100644 (file)
 struct a3xx_gpu {
        struct adreno_gpu base;
        struct platform_device *pdev;
+
+       /* if OCMEM is used for GMEM: */
+       uint32_t ocmem_base;
+       void *ocmem_hdl;
 };
 #define to_a3xx_gpu(x) container_of(x, struct a3xx_gpu, base)
 
index 33dcc606c7c556a55a8e463d87bf56a0368c6363..d6e6ce2d1abde84742d02a0e950911fb1a401f8d 100644 (file)
@@ -8,12 +8,13 @@ http://github.com/freedreno/envytools/
 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/adreno.xml              (    327 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  31003 bytes, from 2013-09-19 18:50:16)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml       (   8983 bytes, from 2013-07-24 01:38:36)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9759 bytes, from 2013-09-10 00:52:33)
-- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51983 bytes, from 2013-09-10 00:52:32)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
+- /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          (  32814 bytes, from 2013-11-30 15:07:33)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   8900 bytes, from 2013-10-22 23:57:49)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  10574 bytes, from 2013-11-13 05:44:45)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  53644 bytes, from 2013-11-30 15:07:33)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (   8344 bytes, from 2013-11-30 14:49:47)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -115,96 +116,6 @@ enum adreno_rb_depth_format {
        DEPTHX_24_8 = 1,
 };
 
-enum adreno_mmu_clnt_beh {
-       BEH_NEVR = 0,
-       BEH_TRAN_RNG = 1,
-       BEH_TRAN_FLT = 2,
-};
-
-#define REG_AXXX_MH_MMU_CONFIG                                 0x00000040
-#define AXXX_MH_MMU_CONFIG_MMU_ENABLE                          0x00000001
-#define AXXX_MH_MMU_CONFIG_SPLIT_MODE_ENABLE                   0x00000002
-#define AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK            0x00000030
-#define AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT           4
-static inline uint32_t AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_RB_W_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK            0x000000c0
-#define AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT           6
-static inline uint32_t AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_W_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK           0x00000300
-#define AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT          8
-static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R0_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK           0x00000c00
-#define AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT          10
-static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R1_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK           0x00003000
-#define AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT          12
-static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R2_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK           0x0000c000
-#define AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT          14
-static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R3_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK           0x00030000
-#define AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT          16
-static inline uint32_t AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_CP_R4_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK          0x000c0000
-#define AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT         18
-static inline uint32_t AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_VGT_R0_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK          0x00300000
-#define AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT         20
-static inline uint32_t AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_VGT_R1_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK            0x00c00000
-#define AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT           22
-static inline uint32_t AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_TC_R_CLNT_BEHAVIOR__MASK;
-}
-#define AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK            0x03000000
-#define AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT           24
-static inline uint32_t AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR(enum adreno_mmu_clnt_beh val)
-{
-       return ((val) << AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__SHIFT) & AXXX_MH_MMU_CONFIG_PA_W_CLNT_BEHAVIOR__MASK;
-}
-
-#define REG_AXXX_MH_MMU_VA_RANGE                               0x00000041
-
-#define REG_AXXX_MH_MMU_PT_BASE                                        0x00000042
-
-#define REG_AXXX_MH_MMU_PAGE_FAULT                             0x00000043
-
-#define REG_AXXX_MH_MMU_TRAN_ERROR                             0x00000044
-
-#define REG_AXXX_MH_MMU_INVALIDATE                             0x00000045
-
-#define REG_AXXX_MH_MMU_MPU_BASE                               0x00000046
-
-#define REG_AXXX_MH_MMU_MPU_END                                        0x00000047
-
 #define REG_AXXX_CP_RB_BASE                                    0x000001c0
 
 #define REG_AXXX_CP_RB_CNTL                                    0x000001c1
@@ -275,6 +186,18 @@ static inline uint32_t AXXX_CP_QUEUE_THRESHOLDS_CSQ_ST_START(uint32_t val)
 }
 
 #define REG_AXXX_CP_MEQ_THRESHOLDS                             0x000001d6
+#define AXXX_CP_MEQ_THRESHOLDS_MEQ_END__MASK                   0x001f0000
+#define AXXX_CP_MEQ_THRESHOLDS_MEQ_END__SHIFT                  16
+static inline uint32_t AXXX_CP_MEQ_THRESHOLDS_MEQ_END(uint32_t val)
+{
+       return ((val) << AXXX_CP_MEQ_THRESHOLDS_MEQ_END__SHIFT) & AXXX_CP_MEQ_THRESHOLDS_MEQ_END__MASK;
+}
+#define AXXX_CP_MEQ_THRESHOLDS_ROQ_END__MASK                   0x1f000000
+#define AXXX_CP_MEQ_THRESHOLDS_ROQ_END__SHIFT                  24
+static inline uint32_t AXXX_CP_MEQ_THRESHOLDS_ROQ_END(uint32_t val)
+{
+       return ((val) << AXXX_CP_MEQ_THRESHOLDS_ROQ_END__SHIFT) & AXXX_CP_MEQ_THRESHOLDS_ROQ_END__MASK;
+}
 
 #define REG_AXXX_CP_CSQ_AVAIL                                  0x000001d7
 #define AXXX_CP_CSQ_AVAIL_RING__MASK                           0x0000007f
@@ -402,6 +325,36 @@ static inline uint32_t AXXX_CP_CSQ_IB2_STAT_WPTR(uint32_t val)
        return ((val) << AXXX_CP_CSQ_IB2_STAT_WPTR__SHIFT) & AXXX_CP_CSQ_IB2_STAT_WPTR__MASK;
 }
 
+#define REG_AXXX_CP_NON_PREFETCH_CNTRS                         0x00000440
+
+#define REG_AXXX_CP_STQ_ST_STAT                                        0x00000443
+
+#define REG_AXXX_CP_ST_BASE                                    0x0000044d
+
+#define REG_AXXX_CP_ST_BUFSZ                                   0x0000044e
+
+#define REG_AXXX_CP_MEQ_STAT                                   0x0000044f
+
+#define REG_AXXX_CP_MIU_TAG_STAT                               0x00000452
+
+#define REG_AXXX_CP_BIN_MASK_LO                                        0x00000454
+
+#define REG_AXXX_CP_BIN_MASK_HI                                        0x00000455
+
+#define REG_AXXX_CP_BIN_SELECT_LO                              0x00000456
+
+#define REG_AXXX_CP_BIN_SELECT_HI                              0x00000457
+
+#define REG_AXXX_CP_IB1_BASE                                   0x00000458
+
+#define REG_AXXX_CP_IB1_BUFSZ                                  0x00000459
+
+#define REG_AXXX_CP_IB2_BASE                                   0x0000045a
+
+#define REG_AXXX_CP_IB2_BUFSZ                                  0x0000045b
+
+#define REG_AXXX_CP_STAT                                       0x0000047f
+
 #define REG_AXXX_CP_SCRATCH_REG0                               0x00000578
 
 #define REG_AXXX_CP_SCRATCH_REG1                               0x00000579
@@ -418,6 +371,26 @@ static inline uint32_t AXXX_CP_CSQ_IB2_STAT_WPTR(uint32_t val)
 
 #define REG_AXXX_CP_SCRATCH_REG7                               0x0000057f
 
+#define REG_AXXX_CP_ME_VS_EVENT_SRC                            0x00000600
+
+#define REG_AXXX_CP_ME_VS_EVENT_ADDR                           0x00000601
+
+#define REG_AXXX_CP_ME_VS_EVENT_DATA                           0x00000602
+
+#define REG_AXXX_CP_ME_VS_EVENT_ADDR_SWM                       0x00000603
+
+#define REG_AXXX_CP_ME_VS_EVENT_DATA_SWM                       0x00000604
+
+#define REG_AXXX_CP_ME_PS_EVENT_SRC                            0x00000605
+
+#define REG_AXXX_CP_ME_PS_EVENT_ADDR                           0x00000606
+
+#define REG_AXXX_CP_ME_PS_EVENT_DATA                           0x00000607
+
+#define REG_AXXX_CP_ME_PS_EVENT_ADDR_SWM                       0x00000608
+
+#define REG_AXXX_CP_ME_PS_EVENT_DATA_SWM                       0x00000609
+
 #define REG_AXXX_CP_ME_CF_EVENT_SRC                            0x0000060a
 
 #define REG_AXXX_CP_ME_CF_EVENT_ADDR                           0x0000060b
@@ -428,5 +401,11 @@ static inline uint32_t AXXX_CP_CSQ_IB2_STAT_WPTR(uint32_t val)
 
 #define REG_AXXX_CP_ME_NRT_DATA                                        0x0000060e
 
+#define REG_AXXX_CP_ME_VS_FETCH_DONE_SRC                       0x00000612
+
+#define REG_AXXX_CP_ME_VS_FETCH_DONE_ADDR                      0x00000613
+
+#define REG_AXXX_CP_ME_VS_FETCH_DONE_DATA                      0x00000614
+
 
 #endif /* ADRENO_COMMON_XML */
index a0b9d8a95b16c17ad6b11ae1b6da662e80484b04..d321099abdd45ac17b37bc32ae8399ce95bc6f32 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "adreno_gpu.h"
 #include "msm_gem.h"
+#include "msm_mmu.h"
 
 struct adreno_info {
        struct adreno_rev rev;
@@ -44,7 +45,7 @@ static const struct adreno_info gpulist[] = {
                .pfpfw = "a300_pfp.fw",
                .gmem  = SZ_512K,
        }, {
-               .rev   = ADRENO_REV(3, 3, 0, 0),
+               .rev   = ADRENO_REV(3, 3, 0, ANY_ID),
                .revn  = 330,
                .name  = "A330",
                .pm4fw = "a330_pm4.fw",
@@ -53,6 +54,11 @@ static const struct adreno_info gpulist[] = {
        },
 };
 
+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
 
@@ -65,7 +71,7 @@ int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value)
                *value = adreno_gpu->info->revn;
                return 0;
        case MSM_PARAM_GMEM_SIZE:
-               *value = adreno_gpu->info->gmem;
+               *value = adreno_gpu->gmem;
                return 0;
        default:
                DBG("%s: invalid param: %u", gpu->name, param);
@@ -86,7 +92,7 @@ int adreno_hw_init(struct msm_gpu *gpu)
        gpu_write(gpu, REG_AXXX_CP_RB_CNTL,
                        /* size is log2(quad-words): */
                        AXXX_CP_RB_CNTL_BUFSZ(ilog2(gpu->rb->size / 8)) |
-                       AXXX_CP_RB_CNTL_BLKSZ(RB_BLKSIZE));
+                       AXXX_CP_RB_CNTL_BLKSZ(ilog2(RB_BLKSIZE / 8)));
 
        /* Setup ringbuffer address: */
        gpu_write(gpu, REG_AXXX_CP_RB_BASE, gpu->rb_iova);
@@ -286,6 +292,7 @@ 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 msm_mmu *mmu;
        int i, ret;
 
        /* identify gpu: */
@@ -311,6 +318,7 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                        rev.core, rev.major, rev.minor, rev.patchid);
 
        gpu->funcs = funcs;
+       gpu->gmem = gpu->info->gmem;
        gpu->rev = rev;
 
        ret = request_firmware(&gpu->pm4, gpu->info->pm4fw, drm->dev);
@@ -333,10 +341,13 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
        if (ret)
                return ret;
 
-       ret = msm_iommu_attach(drm, gpu->base.iommu,
-                       iommu_ports, ARRAY_SIZE(iommu_ports));
-       if (ret)
-               return ret;
+       mmu = gpu->base.mmu;
+       if (mmu) {
+               ret = mmu->funcs->attach(mmu, iommu_ports,
+                               ARRAY_SIZE(iommu_ports));
+               if (ret)
+                       return ret;
+       }
 
        gpu->memptrs_bo = msm_gem_new(drm, sizeof(*gpu->memptrs),
                        MSM_BO_UNCACHED);
index f73abfba7c22eb03b4aa0c7f1e962ade219edf1f..ca11ea4da165082fd3ab2f2ecae981d5cd7543ad 100644 (file)
@@ -51,6 +51,7 @@ struct adreno_gpu {
        struct msm_gpu base;
        struct adreno_rev rev;
        const struct adreno_info *info;
+       uint32_t gmem;  /* actual gmem size */
        uint32_t revn;  /* numeric revision name */
        const struct adreno_gpu_funcs *funcs;
 
@@ -70,6 +71,9 @@ struct adreno_gpu {
 struct adreno_platform_config {
        struct adreno_rev rev;
        uint32_t fast_rate, slow_rate, bus_freq;
+#ifdef CONFIG_MSM_BUS_SCALING
+       struct msm_bus_scale_pdata *bus_scale_table;
+#endif
 };
 
 #define ADRENO_IDLE_TIMEOUT (20 * 1000)
@@ -94,6 +98,11 @@ static inline bool adreno_is_a330(struct adreno_gpu *gpu)
        return gpu->revn == 330;
 }
 
+static inline bool adreno_is_a330v2(struct adreno_gpu *gpu)
+{
+       return adreno_is_a330(gpu) && (gpu->rev.patchid > 0);
+}
+
 int adreno_get_param(struct msm_gpu *gpu, uint32_t param, uint64_t *value);
 int adreno_hw_init(struct msm_gpu *gpu);
 uint32_t adreno_last_fence(struct msm_gpu *gpu);
index 259ad709b0cc0467d1a4e6a55435e63ea4cb3415..ae992c71703f1ccc5151b1cf72b904c89e1cd8ec 100644 (file)
@@ -8,12 +8,13 @@ http://github.com/freedreno/envytools/
 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/adreno.xml              (    327 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml (   1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/a2xx/a2xx.xml           (  31003 bytes, from 2013-09-19 18:50:16)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_common.xml       (   8983 bytes, from 2013-07-24 01:38:36)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno_pm4.xml          (   9759 bytes, from 2013-09-10 00:52:33)
-- /home/robclark/src/freedreno/envytools/rnndb/a3xx/a3xx.xml           (  51983 bytes, from 2013-09-10 00:52:32)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno.xml               (    364 bytes, from 2013-11-30 14:47:15)
+- /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          (  32814 bytes, from 2013-11-30 15:07:33)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml (   8900 bytes, from 2013-10-22 23:57:49)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml    (  10574 bytes, from 2013-11-13 05:44:45)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml          (  53644 bytes, from 2013-11-30 15:07:33)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml          (   8344 bytes, from 2013-11-30 14:49:47)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -66,13 +67,15 @@ enum vgt_event_type {
 
 enum pc_di_primtype {
        DI_PT_NONE = 0,
-       DI_PT_POINTLIST = 1,
+       DI_PT_POINTLIST_A2XX = 1,
        DI_PT_LINELIST = 2,
        DI_PT_LINESTRIP = 3,
        DI_PT_TRILIST = 4,
        DI_PT_TRIFAN = 5,
        DI_PT_TRISTRIP = 6,
+       DI_PT_LINELOOP = 7,
        DI_PT_RECTLIST = 8,
+       DI_PT_POINTLIST_A3XX = 9,
        DI_PT_QUADLIST = 13,
        DI_PT_QUADSTRIP = 14,
        DI_PT_POLYGON = 15,
@@ -119,7 +122,7 @@ enum adreno_pm4_type3_packets {
        CP_WAIT_FOR_IDLE = 38,
        CP_WAIT_REG_MEM = 60,
        CP_WAIT_REG_EQ = 82,
-       CP_WAT_REG_GTE = 83,
+       CP_WAIT_REG_GTE = 83,
        CP_WAIT_UNTIL_READ = 92,
        CP_WAIT_IB_PFD_COMPLETE = 93,
        CP_REG_RMW = 33,
@@ -151,7 +154,6 @@ enum adreno_pm4_type3_packets {
        CP_CONTEXT_UPDATE = 94,
        CP_INTERRUPT = 64,
        CP_IM_STORE = 44,
-       CP_SET_BIN_BASE_OFFSET = 75,
        CP_SET_DRAW_INIT_FLAGS = 75,
        CP_SET_PROTECTED_MODE = 95,
        CP_LOAD_STATE = 48,
@@ -159,6 +161,16 @@ enum adreno_pm4_type3_packets {
        CP_COND_INDIRECT_BUFFER_PFD = 50,
        CP_INDIRECT_BUFFER_PFE = 63,
        CP_SET_BIN = 76,
+       CP_TEST_TWO_MEMS = 113,
+       CP_WAIT_FOR_ME = 19,
+       IN_IB_PREFETCH_END = 23,
+       IN_SUBBLK_PREFETCH = 31,
+       IN_INSTR_PREFETCH = 32,
+       IN_INSTR_MATCH = 71,
+       IN_CONST_PREFETCH = 73,
+       IN_INCR_UPDT_STATE = 85,
+       IN_INCR_UPDT_CONST = 86,
+       IN_INCR_UPDT_INSTR = 87,
 };
 
 enum adreno_state_block {
index 6d4c62bf70dc482cf9f38ea1739046cb19732943..87be647e3825f0ad96491f5df5b8cf271158f848 100644 (file)
@@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/
 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                 (    595 bytes, from 2013-07-05 19:21:12)
+- /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/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
+- /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 2013-12-03 20:59:13)
 - /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/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  19288 bytes, from 2013-08-11 18:14:15)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index d1df38bf574783bf98c39253315e3810527d1377..747a6ef4211f71748e759343213ce7ecdc5fb335 100644 (file)
@@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/
 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                 (    595 bytes, from 2013-07-05 19:21:12)
+- /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/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
+- /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 2013-12-03 20:59:13)
 - /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/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  19288 bytes, from 2013-08-11 18:14:15)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index 0030a111302dae44c6a4ecc0e21d5aa9e7364032..48e03acf19bf5bdf61659c96acd4444e6c716c73 100644 (file)
@@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/
 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                 (    595 bytes, from 2013-07-05 19:21:12)
+- /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/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
+- /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 2013-12-03 20:59:13)
 - /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/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  19288 bytes, from 2013-08-11 18:14:15)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
index 50d11df35b21f1cac9ac15d41f649015a664cfbf..6f1588aa9071f8db8642dcb8b32e46642381b38d 100644 (file)
@@ -41,7 +41,7 @@ void hdmi_set_mode(struct hdmi *hdmi, bool power_on)
                        power_on ? "Enable" : "Disable", ctrl);
 }
 
-static irqreturn_t hdmi_irq(int irq, void *dev_id)
+irqreturn_t hdmi_irq(int irq, void *dev_id)
 {
        struct hdmi *hdmi = dev_id;
 
@@ -71,13 +71,13 @@ void hdmi_destroy(struct kref *kref)
 }
 
 /* initialize connector */
-int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
+struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 {
        struct hdmi *hdmi = NULL;
        struct msm_drm_private *priv = dev->dev_private;
        struct platform_device *pdev = hdmi_pdev;
        struct hdmi_platform_config *config;
-       int ret;
+       int i, ret;
 
        if (!pdev) {
                dev_err(dev->dev, "no hdmi device\n");
@@ -99,6 +99,7 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
 
        hdmi->dev = dev;
        hdmi->pdev = pdev;
+       hdmi->config = config;
        hdmi->encoder = encoder;
 
        /* not sure about which phy maps to which msm.. probably I miss some */
@@ -114,44 +115,70 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                goto fail;
        }
 
-       hdmi->mmio = msm_ioremap(pdev, "hdmi_msm_hdmi_addr", "HDMI");
+       hdmi->mmio = msm_ioremap(pdev, config->mmio_name, "HDMI");
        if (IS_ERR(hdmi->mmio)) {
                ret = PTR_ERR(hdmi->mmio);
                goto fail;
        }
 
-       hdmi->mvs = devm_regulator_get(&pdev->dev, "8901_hdmi_mvs");
-       if (IS_ERR(hdmi->mvs))
-               hdmi->mvs = devm_regulator_get(&pdev->dev, "hdmi_mvs");
-       if (IS_ERR(hdmi->mvs)) {
-               ret = PTR_ERR(hdmi->mvs);
-               dev_err(dev->dev, "failed to get mvs regulator: %d\n", ret);
-               goto fail;
+       BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs));
+       for (i = 0; i < config->hpd_reg_cnt; i++) {
+               struct regulator *reg;
+
+               reg = devm_regulator_get(&pdev->dev, config->hpd_reg_names[i]);
+               if (IS_ERR(reg)) {
+                       ret = PTR_ERR(reg);
+                       dev_err(dev->dev, "failed to get hpd regulator: %s (%d)\n",
+                                       config->hpd_reg_names[i], ret);
+                       goto fail;
+               }
+
+               hdmi->hpd_regs[i] = reg;
        }
 
-       hdmi->mpp0 = devm_regulator_get(&pdev->dev, "8901_mpp0");
-       if (IS_ERR(hdmi->mpp0))
-               hdmi->mpp0 = NULL;
+       BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs));
+       for (i = 0; i < config->pwr_reg_cnt; i++) {
+               struct regulator *reg;
 
-       hdmi->clk = devm_clk_get(&pdev->dev, "core_clk");
-       if (IS_ERR(hdmi->clk)) {
-               ret = PTR_ERR(hdmi->clk);
-               dev_err(dev->dev, "failed to get 'clk': %d\n", ret);
-               goto fail;
+               reg = devm_regulator_get(&pdev->dev, config->pwr_reg_names[i]);
+               if (IS_ERR(reg)) {
+                       ret = PTR_ERR(reg);
+                       dev_err(dev->dev, "failed to get pwr regulator: %s (%d)\n",
+                                       config->pwr_reg_names[i], ret);
+                       goto fail;
+               }
+
+               hdmi->pwr_regs[i] = reg;
        }
 
-       hdmi->m_pclk = devm_clk_get(&pdev->dev, "master_iface_clk");
-       if (IS_ERR(hdmi->m_pclk)) {
-               ret = PTR_ERR(hdmi->m_pclk);
-               dev_err(dev->dev, "failed to get 'm_pclk': %d\n", ret);
-               goto fail;
+       BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks));
+       for (i = 0; i < config->hpd_clk_cnt; i++) {
+               struct clk *clk;
+
+               clk = devm_clk_get(&pdev->dev, config->hpd_clk_names[i]);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       dev_err(dev->dev, "failed to get hpd clk: %s (%d)\n",
+                                       config->hpd_clk_names[i], ret);
+                       goto fail;
+               }
+
+               hdmi->hpd_clks[i] = clk;
        }
 
-       hdmi->s_pclk = devm_clk_get(&pdev->dev, "slave_iface_clk");
-       if (IS_ERR(hdmi->s_pclk)) {
-               ret = PTR_ERR(hdmi->s_pclk);
-               dev_err(dev->dev, "failed to get 's_pclk': %d\n", ret);
-               goto fail;
+       BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks));
+       for (i = 0; i < config->pwr_clk_cnt; i++) {
+               struct clk *clk;
+
+               clk = devm_clk_get(&pdev->dev, config->pwr_clk_names[i]);
+               if (IS_ERR(clk)) {
+                       ret = PTR_ERR(clk);
+                       dev_err(dev->dev, "failed to get pwr clk: %s (%d)\n",
+                                       config->pwr_clk_names[i], ret);
+                       goto fail;
+               }
+
+               hdmi->pwr_clks[i] = clk;
        }
 
        hdmi->i2c = hdmi_i2c_init(hdmi);
@@ -178,20 +205,22 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
                goto fail;
        }
 
-       hdmi->irq = platform_get_irq(pdev, 0);
-       if (hdmi->irq < 0) {
-               ret = hdmi->irq;
-               dev_err(dev->dev, "failed to get irq: %d\n", ret);
-               goto fail;
-       }
+       if (!config->shared_irq) {
+               hdmi->irq = platform_get_irq(pdev, 0);
+               if (hdmi->irq < 0) {
+                       ret = hdmi->irq;
+                       dev_err(dev->dev, "failed to get irq: %d\n", ret);
+                       goto fail;
+               }
 
-       ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq,
-                       NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
-                       "hdmi_isr", hdmi);
-       if (ret < 0) {
-               dev_err(dev->dev, "failed to request IRQ%u: %d\n",
-                               hdmi->irq, ret);
-               goto fail;
+               ret = devm_request_threaded_irq(&pdev->dev, hdmi->irq,
+                               NULL, hdmi_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+                               "hdmi_isr", hdmi);
+               if (ret < 0) {
+                       dev_err(dev->dev, "failed to request IRQ%u: %d\n",
+                                       hdmi->irq, ret);
+                       goto fail;
+               }
        }
 
        encoder->bridge = hdmi->bridge;
@@ -199,7 +228,7 @@ int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder)
        priv->bridges[priv->num_bridges++]       = hdmi->bridge;
        priv->connectors[priv->num_connectors++] = hdmi->connector;
 
-       return 0;
+       return hdmi;
 
 fail:
        if (hdmi) {
@@ -211,37 +240,100 @@ fail:
                hdmi_destroy(&hdmi->refcount);
        }
 
-       return ret;
+       return ERR_PTR(ret);
 }
 
 /*
  * The hdmi device:
  */
 
+#include <linux/of_gpio.h>
+
 static int hdmi_dev_probe(struct platform_device *pdev)
 {
        static struct hdmi_platform_config config = {};
 #ifdef CONFIG_OF
-       /* TODO */
+       struct device_node *of_node = pdev->dev.of_node;
+
+       int get_gpio(const char *name)
+       {
+               int gpio = of_get_named_gpio(of_node, name, 0);
+               if (gpio < 0) {
+                       dev_err(&pdev->dev, "failed to get gpio: %s (%d)\n",
+                                       name, gpio);
+                       gpio = -1;
+               }
+               return gpio;
+       }
+
+       /* TODO actually use DT.. */
+       static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"};
+       static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"};
+       static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"};
+       static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"};
+
+       config.phy_init      = hdmi_phy_8x74_init;
+       config.mmio_name     = "core_physical";
+       config.hpd_reg_names = hpd_reg_names;
+       config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
+       config.pwr_reg_names = pwr_reg_names;
+       config.pwr_reg_cnt   = ARRAY_SIZE(pwr_reg_names);
+       config.hpd_clk_names = hpd_clk_names;
+       config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
+       config.pwr_clk_names = pwr_clk_names;
+       config.pwr_clk_cnt   = ARRAY_SIZE(pwr_clk_names);
+       config.ddc_clk_gpio  = get_gpio("qcom,hdmi-tx-ddc-clk");
+       config.ddc_data_gpio = get_gpio("qcom,hdmi-tx-ddc-data");
+       config.hpd_gpio      = get_gpio("qcom,hdmi-tx-hpd");
+       config.mux_en_gpio   = get_gpio("qcom,hdmi-tx-mux-en");
+       config.mux_sel_gpio  = get_gpio("qcom,hdmi-tx-mux-sel");
+       config.shared_irq    = true;
+
 #else
+       static const char *hpd_clk_names[] = {
+                       "core_clk", "master_iface_clk", "slave_iface_clk",
+       };
        if (cpu_is_apq8064()) {
+               static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
                config.phy_init      = hdmi_phy_8960_init;
+               config.mmio_name     = "hdmi_msm_hdmi_addr";
+               config.hpd_reg_names = hpd_reg_names;
+               config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
+               config.hpd_clk_names = hpd_clk_names;
+               config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
                config.ddc_clk_gpio  = 70;
                config.ddc_data_gpio = 71;
                config.hpd_gpio      = 72;
-               config.pmic_gpio     = 13 + NR_GPIO_IRQS;
-       } else if (cpu_is_msm8960()) {
+               config.mux_en_gpio   = -1;
+               config.mux_sel_gpio  = 13 + NR_GPIO_IRQS;
+       } else if (cpu_is_msm8960() || cpu_is_msm8960ab()) {
+               static const char *hpd_reg_names[] = {"8921_hdmi_mvs"};
                config.phy_init      = hdmi_phy_8960_init;
+               config.mmio_name     = "hdmi_msm_hdmi_addr";
+               config.hpd_reg_names = hpd_reg_names;
+               config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
+               config.hpd_clk_names = hpd_clk_names;
+               config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
                config.ddc_clk_gpio  = 100;
                config.ddc_data_gpio = 101;
                config.hpd_gpio      = 102;
-               config.pmic_gpio     = -1;
+               config.mux_en_gpio   = -1;
+               config.mux_sel_gpio  = -1;
        } else if (cpu_is_msm8x60()) {
+               static const char *hpd_reg_names[] = {
+                               "8901_hdmi_mvs", "8901_mpp0"
+               };
                config.phy_init      = hdmi_phy_8x60_init;
+               config.mmio_name     = "hdmi_msm_hdmi_addr";
+               config.hpd_reg_names = hpd_reg_names;
+               config.hpd_reg_cnt   = ARRAY_SIZE(hpd_reg_names);
+               config.hpd_clk_names = hpd_clk_names;
+               config.hpd_clk_cnt   = ARRAY_SIZE(hpd_clk_names);
                config.ddc_clk_gpio  = 170;
                config.ddc_data_gpio = 171;
                config.hpd_gpio      = 172;
-               config.pmic_gpio     = -1;
+               config.mux_en_gpio   = -1;
+               config.mux_sel_gpio  = -1;
        }
 #endif
        pdev->dev.platform_data = &config;
@@ -255,10 +347,19 @@ static int hdmi_dev_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct of_device_id dt_match[] = {
+       { .compatible = "qcom,hdmi-tx" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, dt_match);
+
 static struct platform_driver hdmi_driver = {
        .probe = hdmi_dev_probe,
        .remove = hdmi_dev_remove,
-       .driver.name = "hdmi_msm",
+       .driver = {
+               .name = "hdmi_msm",
+               .of_match_table = dt_match,
+       },
 };
 
 void __init hdmi_register(void)
index 2c2ec566394c7ac314c9bf3e97b70071bfce4d48..41b29add70b1be7a19b480d5a84ba25aeb79518b 100644 (file)
@@ -28,6 +28,7 @@
 
 
 struct hdmi_phy;
+struct hdmi_platform_config;
 
 struct hdmi {
        struct kref refcount;
@@ -35,14 +36,14 @@ struct hdmi {
        struct drm_device *dev;
        struct platform_device *pdev;
 
-       void __iomem *mmio;
+       const struct hdmi_platform_config *config;
 
-       struct regulator *mvs;        /* HDMI_5V */
-       struct regulator *mpp0;       /* External 5V */
+       void __iomem *mmio;
 
-       struct clk *clk;
-       struct clk *m_pclk;
-       struct clk *s_pclk;
+       struct regulator *hpd_regs[2];
+       struct regulator *pwr_regs[2];
+       struct clk *hpd_clks[3];
+       struct clk *pwr_clks[2];
 
        struct hdmi_phy *phy;
        struct i2c_adapter *i2c;
@@ -60,7 +61,29 @@ struct hdmi {
 /* platform config data (ie. from DT, or pdata) */
 struct hdmi_platform_config {
        struct hdmi_phy *(*phy_init)(struct hdmi *hdmi);
-       int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, pmic_gpio;
+       const char *mmio_name;
+
+       /* regulators that need to be on for hpd: */
+       const char **hpd_reg_names;
+       int hpd_reg_cnt;
+
+       /* regulators that need to be on for screen pwr: */
+       const char **pwr_reg_names;
+       int pwr_reg_cnt;
+
+       /* clks that need to be on for hpd: */
+       const char **hpd_clk_names;
+       int hpd_clk_cnt;
+
+       /* clks that need to be on for screen pwr (ie pixel clk): */
+       const char **pwr_clk_names;
+       int pwr_clk_cnt;
+
+       /* gpio's: */
+       int ddc_clk_gpio, ddc_data_gpio, hpd_gpio, mux_en_gpio, mux_sel_gpio;
+
+       /* older devices had their own irq, mdp5+ it is shared w/ mdp: */
+       bool shared_irq;
 };
 
 void hdmi_set_mode(struct hdmi *hdmi, bool power_on);
@@ -106,6 +129,7 @@ struct hdmi_phy {
 
 struct hdmi_phy *hdmi_phy_8960_init(struct hdmi *hdmi);
 struct hdmi_phy *hdmi_phy_8x60_init(struct hdmi *hdmi);
+struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi);
 
 /*
  * hdmi bridge:
index 4e939f82918c68daee08cc95253eeb25f31c24b8..e2636582cfd753bc2443659ee615db428530e2dc 100644 (file)
@@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/
 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                 (    595 bytes, from 2013-07-05 19:21:12)
+- /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/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
+- /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 2013-12-03 20:59:13)
 - /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/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  19288 bytes, from 2013-08-11 18:14:15)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -212,6 +214,20 @@ static inline uint32_t HDMI_HDCP_LINK0_STATUS_KEY_STATE(enum hdmi_hdcp_key_state
 #define REG_HDMI_HDCP_RESET                                    0x00000130
 #define HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE                   0x00000001
 
+#define REG_HDMI_VENSPEC_INFO0                                 0x0000016c
+
+#define REG_HDMI_VENSPEC_INFO1                                 0x00000170
+
+#define REG_HDMI_VENSPEC_INFO2                                 0x00000174
+
+#define REG_HDMI_VENSPEC_INFO3                                 0x00000178
+
+#define REG_HDMI_VENSPEC_INFO4                                 0x0000017c
+
+#define REG_HDMI_VENSPEC_INFO5                                 0x00000180
+
+#define REG_HDMI_VENSPEC_INFO6                                 0x00000184
+
 #define REG_HDMI_AUDIO_CFG                                     0x000001d0
 #define HDMI_AUDIO_CFG_ENGINE_ENABLE                           0x00000001
 #define HDMI_AUDIO_CFG_FIFO_WATERMARK__MASK                    0x000000f0
@@ -235,6 +251,9 @@ static inline uint32_t HDMI_DDC_CTRL_TRANSACTION_CNT(uint32_t val)
        return ((val) << HDMI_DDC_CTRL_TRANSACTION_CNT__SHIFT) & HDMI_DDC_CTRL_TRANSACTION_CNT__MASK;
 }
 
+#define REG_HDMI_DDC_ARBITRATION                               0x00000210
+#define HDMI_DDC_ARBITRATION_HW_ARBITRATION                    0x00000010
+
 #define REG_HDMI_DDC_INT_CTRL                                  0x00000214
 #define HDMI_DDC_INT_CTRL_SW_DONE_INT                          0x00000001
 #define HDMI_DDC_INT_CTRL_SW_DONE_ACK                          0x00000002
@@ -340,6 +359,20 @@ static inline uint32_t HDMI_DDC_REF_REFTIMER(uint32_t val)
        return ((val) << HDMI_DDC_REF_REFTIMER__SHIFT) & HDMI_DDC_REF_REFTIMER__MASK;
 }
 
+#define REG_HDMI_CEC_STATUS                                    0x00000298
+
+#define REG_HDMI_CEC_INT                                       0x0000029c
+
+#define REG_HDMI_CEC_ADDR                                      0x000002a0
+
+#define REG_HDMI_CEC_TIME                                      0x000002a4
+
+#define REG_HDMI_CEC_REFTIMER                                  0x000002a8
+
+#define REG_HDMI_CEC_RD_DATA                                   0x000002ac
+
+#define REG_HDMI_CEC_RD_FILTER                                 0x000002b0
+
 #define REG_HDMI_ACTIVE_HSYNC                                  0x000002b4
 #define HDMI_ACTIVE_HSYNC_START__MASK                          0x00000fff
 #define HDMI_ACTIVE_HSYNC_START__SHIFT                         0
@@ -410,17 +443,33 @@ static inline uint32_t HDMI_VSYNC_TOTAL_F2_V_TOTAL(uint32_t val)
 #define HDMI_FRAME_CTRL_HSYNC_LOW                              0x20000000
 #define HDMI_FRAME_CTRL_INTERLACED_EN                          0x80000000
 
+#define REG_HDMI_AUD_INT                                       0x000002cc
+#define HDMI_AUD_INT_AUD_FIFO_URUN_INT                         0x00000001
+#define HDMI_AUD_INT_AUD_FIFO_URAN_MASK                                0x00000002
+#define HDMI_AUD_INT_AUD_SAM_DROP_INT                          0x00000004
+#define HDMI_AUD_INT_AUD_SAM_DROP_MASK                         0x00000008
+
 #define REG_HDMI_PHY_CTRL                                      0x000002d4
 #define HDMI_PHY_CTRL_SW_RESET_PLL                             0x00000001
 #define HDMI_PHY_CTRL_SW_RESET_PLL_LOW                         0x00000002
 #define HDMI_PHY_CTRL_SW_RESET                                 0x00000004
 #define HDMI_PHY_CTRL_SW_RESET_LOW                             0x00000008
 
-#define REG_HDMI_AUD_INT                                       0x000002cc
-#define HDMI_AUD_INT_AUD_FIFO_URUN_INT                         0x00000001
-#define HDMI_AUD_INT_AUD_FIFO_URAN_MASK                                0x00000002
-#define HDMI_AUD_INT_AUD_SAM_DROP_INT                          0x00000004
-#define HDMI_AUD_INT_AUD_SAM_DROP_MASK                         0x00000008
+#define REG_HDMI_CEC_WR_RANGE                                  0x000002dc
+
+#define REG_HDMI_CEC_RD_RANGE                                  0x000002e0
+
+#define REG_HDMI_VERSION                                       0x000002e4
+
+#define REG_HDMI_CEC_COMPL_CTL                                 0x00000360
+
+#define REG_HDMI_CEC_RD_START_RANGE                            0x00000364
+
+#define REG_HDMI_CEC_RD_TOTAL_RANGE                            0x00000368
+
+#define REG_HDMI_CEC_RD_ERR_RESP_LO                            0x0000036c
+
+#define REG_HDMI_CEC_WR_CHECK_CONFIG                           0x00000370
 
 #define REG_HDMI_8x60_PHY_REG0                                 0x00000300
 #define HDMI_8x60_PHY_REG0_DESER_DEL_CTRL__MASK                        0x0000001c
@@ -504,5 +553,23 @@ static inline uint32_t HDMI_8x60_PHY_REG1_OUTVOL_SWING_CTRL(uint32_t val)
 
 #define REG_HDMI_8960_PHY_REG12                                        0x00000430
 
+#define REG_HDMI_8x74_ANA_CFG0                                 0x00000000
+
+#define REG_HDMI_8x74_ANA_CFG1                                 0x00000004
+
+#define REG_HDMI_8x74_PD_CTRL0                                 0x00000010
+
+#define REG_HDMI_8x74_PD_CTRL1                                 0x00000014
+
+#define REG_HDMI_8x74_BIST_CFG0                                        0x00000034
+
+#define REG_HDMI_8x74_BIST_PATN0                               0x0000003c
+
+#define REG_HDMI_8x74_BIST_PATN1                               0x00000040
+
+#define REG_HDMI_8x74_BIST_PATN2                               0x00000044
+
+#define REG_HDMI_8x74_BIST_PATN3                               0x00000048
+
 
 #endif /* HDMI_XML */
index 5a8ee3473cf5e0e229ec5c94743e4f7749950ea7..7d10e55403c61da733c1e60c7922799063eef79f 100644 (file)
@@ -21,6 +21,7 @@ struct hdmi_bridge {
        struct drm_bridge base;
 
        struct hdmi *hdmi;
+       bool power_on;
 
        unsigned long int pixclock;
 };
@@ -34,6 +35,65 @@ static void hdmi_bridge_destroy(struct drm_bridge *bridge)
        kfree(hdmi_bridge);
 }
 
+static void power_on(struct drm_bridge *bridge)
+{
+       struct drm_device *dev = bridge->dev;
+       struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+       struct hdmi *hdmi = hdmi_bridge->hdmi;
+       const struct hdmi_platform_config *config = hdmi->config;
+       int i, ret;
+
+       for (i = 0; i < config->pwr_reg_cnt; i++) {
+               ret = regulator_enable(hdmi->pwr_regs[i]);
+               if (ret) {
+                       dev_err(dev->dev, "failed to enable pwr regulator: %s (%d)\n",
+                                       config->pwr_reg_names[i], ret);
+               }
+       }
+
+       if (config->pwr_clk_cnt > 0) {
+               DBG("pixclock: %lu", hdmi_bridge->pixclock);
+               ret = clk_set_rate(hdmi->pwr_clks[0], hdmi_bridge->pixclock);
+               if (ret) {
+                       dev_err(dev->dev, "failed to set pixel clk: %s (%d)\n",
+                                       config->pwr_clk_names[0], ret);
+               }
+       }
+
+       for (i = 0; i < config->pwr_clk_cnt; i++) {
+               ret = clk_prepare_enable(hdmi->pwr_clks[i]);
+               if (ret) {
+                       dev_err(dev->dev, "failed to enable pwr clk: %s (%d)\n",
+                                       config->pwr_clk_names[i], ret);
+               }
+       }
+}
+
+static void power_off(struct drm_bridge *bridge)
+{
+       struct drm_device *dev = bridge->dev;
+       struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
+       struct hdmi *hdmi = hdmi_bridge->hdmi;
+       const struct hdmi_platform_config *config = hdmi->config;
+       int i, ret;
+
+       /* TODO do we need to wait for final vblank somewhere before
+        * cutting the clocks?
+        */
+       mdelay(16 + 4);
+
+       for (i = 0; i < config->pwr_clk_cnt; i++)
+               clk_disable_unprepare(hdmi->pwr_clks[i]);
+
+       for (i = 0; i < config->pwr_reg_cnt; i++) {
+               ret = regulator_disable(hdmi->pwr_regs[i]);
+               if (ret) {
+                       dev_err(dev->dev, "failed to disable pwr regulator: %s (%d)\n",
+                                       config->pwr_reg_names[i], ret);
+               }
+       }
+}
+
 static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
 {
        struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
@@ -41,6 +101,12 @@ static void hdmi_bridge_pre_enable(struct drm_bridge *bridge)
        struct hdmi_phy *phy = hdmi->phy;
 
        DBG("power up");
+
+       if (!hdmi_bridge->power_on) {
+               power_on(bridge);
+               hdmi_bridge->power_on = true;
+       }
+
        phy->funcs->powerup(phy, hdmi_bridge->pixclock);
        hdmi_set_mode(hdmi, true);
 }
@@ -62,6 +128,11 @@ static void hdmi_bridge_post_disable(struct drm_bridge *bridge)
        DBG("power down");
        hdmi_set_mode(hdmi, false);
        phy->funcs->powerdown(phy);
+
+       if (hdmi_bridge->power_on) {
+               power_off(bridge);
+               hdmi_bridge->power_on = false;
+       }
 }
 
 static void hdmi_bridge_mode_set(struct drm_bridge *bridge,
index 823eee521a31b523e04e7470ab01612cdeb0887e..7dedfdd120759d51c7bd5a940bb01e874b87f579 100644 (file)
 
 #include <linux/gpio.h>
 
+#include "msm_kms.h"
 #include "hdmi.h"
 
 struct hdmi_connector {
        struct drm_connector base;
        struct hdmi *hdmi;
+       struct work_struct hpd_work;
 };
 #define to_hdmi_connector(x) container_of(x, struct hdmi_connector, base)
 
 static int gpio_config(struct hdmi *hdmi, bool on)
 {
        struct drm_device *dev = hdmi->dev;
-       struct hdmi_platform_config *config =
-                       hdmi->pdev->dev.platform_data;
+       const struct hdmi_platform_config *config = hdmi->config;
        int ret;
 
        if (on) {
@@ -39,26 +40,43 @@ static int gpio_config(struct hdmi *hdmi, bool on)
                                "HDMI_DDC_CLK", config->ddc_clk_gpio, ret);
                        goto error1;
                }
+               gpio_set_value_cansleep(config->ddc_clk_gpio, 1);
+
                ret = gpio_request(config->ddc_data_gpio, "HDMI_DDC_DATA");
                if (ret) {
                        dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
                                "HDMI_DDC_DATA", config->ddc_data_gpio, ret);
                        goto error2;
                }
+               gpio_set_value_cansleep(config->ddc_data_gpio, 1);
+
                ret = gpio_request(config->hpd_gpio, "HDMI_HPD");
                if (ret) {
                        dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
                                "HDMI_HPD", config->hpd_gpio, ret);
                        goto error3;
                }
-               if (config->pmic_gpio != -1) {
-                       ret = gpio_request(config->pmic_gpio, "PMIC_HDMI_MUX_SEL");
+               gpio_direction_input(config->hpd_gpio);
+               gpio_set_value_cansleep(config->hpd_gpio, 1);
+
+               if (config->mux_en_gpio != -1) {
+                       ret = gpio_request(config->mux_en_gpio, "HDMI_MUX_EN");
                        if (ret) {
                                dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
-                                       "PMIC_HDMI_MUX_SEL", config->pmic_gpio, ret);
+                                       "HDMI_MUX_SEL", config->mux_en_gpio, ret);
                                goto error4;
                        }
-                       gpio_set_value_cansleep(config->pmic_gpio, 0);
+                       gpio_set_value_cansleep(config->mux_en_gpio, 1);
+               }
+
+               if (config->mux_sel_gpio != -1) {
+                       ret = gpio_request(config->mux_sel_gpio, "HDMI_MUX_SEL");
+                       if (ret) {
+                               dev_err(dev->dev, "'%s'(%d) gpio_request failed: %d\n",
+                                       "HDMI_MUX_SEL", config->mux_sel_gpio, ret);
+                               goto error5;
+                       }
+                       gpio_set_value_cansleep(config->mux_sel_gpio, 0);
                }
                DBG("gpio on");
        } else {
@@ -66,15 +84,23 @@ static int gpio_config(struct hdmi *hdmi, bool on)
                gpio_free(config->ddc_data_gpio);
                gpio_free(config->hpd_gpio);
 
-               if (config->pmic_gpio != -1) {
-                       gpio_set_value_cansleep(config->pmic_gpio, 1);
-                       gpio_free(config->pmic_gpio);
+               if (config->mux_en_gpio != -1) {
+                       gpio_set_value_cansleep(config->mux_en_gpio, 0);
+                       gpio_free(config->mux_en_gpio);
+               }
+
+               if (config->mux_sel_gpio != -1) {
+                       gpio_set_value_cansleep(config->mux_sel_gpio, 1);
+                       gpio_free(config->mux_sel_gpio);
                }
                DBG("gpio off");
        }
 
        return 0;
 
+error5:
+       if (config->mux_en_gpio != -1)
+               gpio_free(config->mux_en_gpio);
 error4:
        gpio_free(config->hpd_gpio);
 error3:
@@ -88,10 +114,11 @@ error1:
 static int hpd_enable(struct hdmi_connector *hdmi_connector)
 {
        struct hdmi *hdmi = hdmi_connector->hdmi;
+       const struct hdmi_platform_config *config = hdmi->config;
        struct drm_device *dev = hdmi_connector->base.dev;
        struct hdmi_phy *phy = hdmi->phy;
        uint32_t hpd_ctrl;
-       int ret;
+       int i, ret;
 
        ret = gpio_config(hdmi, true);
        if (ret) {
@@ -99,31 +126,22 @@ static int hpd_enable(struct hdmi_connector *hdmi_connector)
                goto fail;
        }
 
-       ret = clk_prepare_enable(hdmi->clk);
-       if (ret) {
-               dev_err(dev->dev, "failed to enable 'clk': %d\n", ret);
-               goto fail;
-       }
-
-       ret = clk_prepare_enable(hdmi->m_pclk);
-       if (ret) {
-               dev_err(dev->dev, "failed to enable 'm_pclk': %d\n", ret);
-               goto fail;
-       }
-
-       ret = clk_prepare_enable(hdmi->s_pclk);
-       if (ret) {
-               dev_err(dev->dev, "failed to enable 's_pclk': %d\n", ret);
-               goto fail;
+       for (i = 0; i < config->hpd_clk_cnt; i++) {
+               ret = clk_prepare_enable(hdmi->hpd_clks[i]);
+               if (ret) {
+                       dev_err(dev->dev, "failed to enable hpd clk: %s (%d)\n",
+                                       config->hpd_clk_names[i], ret);
+                       goto fail;
+               }
        }
 
-       if (hdmi->mpp0)
-               ret = regulator_enable(hdmi->mpp0);
-       if (!ret)
-               ret = regulator_enable(hdmi->mvs);
-       if (ret) {
-               dev_err(dev->dev, "failed to enable regulators: %d\n", ret);
-               goto fail;
+       for (i = 0; i < config->hpd_reg_cnt; i++) {
+               ret = regulator_enable(hdmi->hpd_regs[i]);
+               if (ret) {
+                       dev_err(dev->dev, "failed to enable hpd regulator: %s (%d)\n",
+                                       config->hpd_reg_names[i], ret);
+                       goto fail;
+               }
        }
 
        hdmi_set_mode(hdmi, false);
@@ -156,26 +174,26 @@ fail:
 static int hdp_disable(struct hdmi_connector *hdmi_connector)
 {
        struct hdmi *hdmi = hdmi_connector->hdmi;
+       const struct hdmi_platform_config *config = hdmi->config;
        struct drm_device *dev = hdmi_connector->base.dev;
-       int ret = 0;
+       int i, ret = 0;
 
        /* Disable HPD interrupt */
        hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, 0);
 
        hdmi_set_mode(hdmi, false);
 
-       if (hdmi->mpp0)
-               ret = regulator_disable(hdmi->mpp0);
-       if (!ret)
-               ret = regulator_disable(hdmi->mvs);
-       if (ret) {
-               dev_err(dev->dev, "failed to enable regulators: %d\n", ret);
-               goto fail;
+       for (i = 0; i < config->hpd_reg_cnt; i++) {
+               ret = regulator_disable(hdmi->hpd_regs[i]);
+               if (ret) {
+                       dev_err(dev->dev, "failed to disable hpd regulator: %s (%d)\n",
+                                       config->hpd_reg_names[i], ret);
+                       goto fail;
+               }
        }
 
-       clk_disable_unprepare(hdmi->clk);
-       clk_disable_unprepare(hdmi->m_pclk);
-       clk_disable_unprepare(hdmi->s_pclk);
+       for (i = 0; i < config->hpd_clk_cnt; i++)
+               clk_disable_unprepare(hdmi->hpd_clks[i]);
 
        ret = gpio_config(hdmi, false);
        if (ret) {
@@ -189,9 +207,19 @@ fail:
        return ret;
 }
 
+static void
+hotplug_work(struct work_struct *work)
+{
+       struct hdmi_connector *hdmi_connector =
+               container_of(work, struct hdmi_connector, hpd_work);
+       struct drm_connector *connector = &hdmi_connector->base;
+       drm_helper_hpd_irq_event(connector->dev);
+}
+
 void hdmi_connector_irq(struct drm_connector *connector)
 {
        struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
+       struct msm_drm_private *priv = connector->dev->dev_private;
        struct hdmi *hdmi = hdmi_connector->hdmi;
        uint32_t hpd_int_status, hpd_int_ctrl;
 
@@ -209,13 +237,13 @@ void hdmi_connector_irq(struct drm_connector *connector)
                hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL,
                                hpd_int_ctrl | HDMI_HPD_INT_CTRL_INT_ACK);
 
-               drm_helper_hpd_irq_event(connector->dev);
-
                /* detect disconnect if we are connected or visa versa: */
                hpd_int_ctrl = HDMI_HPD_INT_CTRL_INT_EN;
                if (!detected)
                        hpd_int_ctrl |= HDMI_HPD_INT_CTRL_INT_CONNECT;
                hdmi_write(hdmi, REG_HDMI_HPD_INT_CTRL, hpd_int_ctrl);
+
+               queue_work(priv->wq, &hdmi_connector->hpd_work);
        }
 }
 
@@ -224,6 +252,7 @@ static enum drm_connector_status hdmi_connector_detect(
 {
        struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
        struct hdmi *hdmi = hdmi_connector->hdmi;
+       const struct hdmi_platform_config *config = hdmi->config;
        uint32_t hpd_int_status;
        int retry = 20;
 
@@ -233,6 +262,14 @@ static enum drm_connector_status hdmi_connector_detect(
         * let that trick us into thinking the monitor is gone:
         */
        while (retry-- && !(hpd_int_status & HDMI_HPD_INT_STATUS_CABLE_DETECTED)) {
+               /* hdmi debounce logic seems to get stuck sometimes,
+                * read directly the gpio to get a second opinion:
+                */
+               if (gpio_get_value(config->hpd_gpio)) {
+                       DBG("gpio tells us we are connected!");
+                       hpd_int_status |= HDMI_HPD_INT_STATUS_CABLE_DETECTED;
+                       break;
+               }
                mdelay(10);
                hpd_int_status = hdmi_read(hdmi, REG_HDMI_HPD_INT_STATUS);
                DBG("status=%08x", hpd_int_status);
@@ -285,6 +322,8 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
                                 struct drm_display_mode *mode)
 {
        struct hdmi_connector *hdmi_connector = to_hdmi_connector(connector);
+       struct hdmi *hdmi = hdmi_connector->hdmi;
+       const struct hdmi_platform_config *config = hdmi->config;
        struct msm_drm_private *priv = connector->dev->dev_private;
        struct msm_kms *kms = priv->kms;
        long actual, requested;
@@ -293,6 +332,13 @@ static int hdmi_connector_mode_valid(struct drm_connector *connector,
        actual = kms->funcs->round_pixclk(kms,
                        requested, hdmi_connector->hdmi->encoder);
 
+       /* for mdp5/apq8074, we manage our own pixel clk (as opposed to
+        * mdp4/dtv stuff where pixel clk is assigned to mdp/encoder
+        * instead):
+        */
+       if (config->pwr_clk_cnt > 0)
+               actual = clk_round_rate(hdmi->pwr_clks[0], actual);
+
        DBG("requested=%ld, actual=%ld", requested, actual);
 
        if (actual != requested)
@@ -335,6 +381,7 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
        }
 
        hdmi_connector->hdmi = hdmi_reference(hdmi);
+       INIT_WORK(&hdmi_connector->hpd_work, hotplug_work);
 
        connector = &hdmi_connector->base;
 
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c b/drivers/gpu/drm/msm/hdmi/hdmi_phy_8x74.c
new file mode 100644 (file)
index 0000000..59fa6cd
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2013 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 "hdmi.h"
+
+struct hdmi_phy_8x74 {
+       struct hdmi_phy base;
+       struct hdmi *hdmi;
+       void __iomem *mmio;
+};
+#define to_hdmi_phy_8x74(x) container_of(x, struct hdmi_phy_8x74, base)
+
+
+static void phy_write(struct hdmi_phy_8x74 *phy, u32 reg, u32 data)
+{
+       msm_writel(data, phy->mmio + reg);
+}
+
+//static u32 phy_read(struct hdmi_phy_8x74 *phy, u32 reg)
+//{
+//     return msm_readl(phy->mmio + reg);
+//}
+
+static void hdmi_phy_8x74_destroy(struct hdmi_phy *phy)
+{
+       struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy);
+       kfree(phy_8x74);
+}
+
+static void hdmi_phy_8x74_reset(struct hdmi_phy *phy)
+{
+       struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy);
+       struct hdmi *hdmi = phy_8x74->hdmi;
+       unsigned int val;
+
+       /* NOTE that HDMI_PHY_CTL is in core mmio, not phy mmio: */
+
+       val = hdmi_read(hdmi, REG_HDMI_PHY_CTRL);
+
+       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
+               /* pull low */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val & ~HDMI_PHY_CTRL_SW_RESET);
+       } else {
+               /* pull high */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val | HDMI_PHY_CTRL_SW_RESET);
+       }
+
+       if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
+               /* pull low */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
+       } else {
+               /* pull high */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val | HDMI_PHY_CTRL_SW_RESET_PLL);
+       }
+
+       msleep(100);
+
+       if (val & HDMI_PHY_CTRL_SW_RESET_LOW) {
+               /* pull high */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val | HDMI_PHY_CTRL_SW_RESET);
+       } else {
+               /* pull low */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val & ~HDMI_PHY_CTRL_SW_RESET);
+       }
+
+       if (val & HDMI_PHY_CTRL_SW_RESET_PLL_LOW) {
+               /* pull high */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val | HDMI_PHY_CTRL_SW_RESET_PLL);
+       } else {
+               /* pull low */
+               hdmi_write(hdmi, REG_HDMI_PHY_CTRL,
+                               val & ~HDMI_PHY_CTRL_SW_RESET_PLL);
+       }
+}
+
+static void hdmi_phy_8x74_powerup(struct hdmi_phy *phy,
+               unsigned long int pixclock)
+{
+       struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy);
+
+       phy_write(phy_8x74, REG_HDMI_8x74_ANA_CFG0,   0x1b);
+       phy_write(phy_8x74, REG_HDMI_8x74_ANA_CFG1,   0xf2);
+       phy_write(phy_8x74, REG_HDMI_8x74_BIST_CFG0,  0x0);
+       phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN0, 0x0);
+       phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN1, 0x0);
+       phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN2, 0x0);
+       phy_write(phy_8x74, REG_HDMI_8x74_BIST_PATN3, 0x0);
+       phy_write(phy_8x74, REG_HDMI_8x74_PD_CTRL1,   0x20);
+}
+
+static void hdmi_phy_8x74_powerdown(struct hdmi_phy *phy)
+{
+       struct hdmi_phy_8x74 *phy_8x74 = to_hdmi_phy_8x74(phy);
+       phy_write(phy_8x74, REG_HDMI_8x74_PD_CTRL0, 0x7f);
+}
+
+static const struct hdmi_phy_funcs hdmi_phy_8x74_funcs = {
+               .destroy = hdmi_phy_8x74_destroy,
+               .reset = hdmi_phy_8x74_reset,
+               .powerup = hdmi_phy_8x74_powerup,
+               .powerdown = hdmi_phy_8x74_powerdown,
+};
+
+struct hdmi_phy *hdmi_phy_8x74_init(struct hdmi *hdmi)
+{
+       struct hdmi_phy_8x74 *phy_8x74;
+       struct hdmi_phy *phy = NULL;
+       int ret;
+
+       phy_8x74 = kzalloc(sizeof(*phy_8x74), GFP_KERNEL);
+       if (!phy_8x74) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       phy = &phy_8x74->base;
+
+       phy->funcs = &hdmi_phy_8x74_funcs;
+
+       phy_8x74->hdmi = hdmi;
+
+       /* for 8x74, the phy mmio is mapped separately: */
+       phy_8x74->mmio = msm_ioremap(hdmi->pdev,
+                       "phy_physical", "HDMI_8x74");
+       if (IS_ERR(phy_8x74->mmio)) {
+               ret = PTR_ERR(phy_8x74->mmio);
+               goto fail;
+       }
+
+       return phy;
+
+fail:
+       if (phy)
+               hdmi_phy_8x74_destroy(phy);
+       return ERR_PTR(ret);
+}
index dbde4f6339b9f82b257c2d3ba24cc534d066760e..d591567173c405226eea5fc9d06b4591887f29d1 100644 (file)
@@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/
 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                 (    595 bytes, from 2013-07-05 19:21:12)
+- /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/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
+- /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 2013-12-03 20:59:13)
 - /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/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  19288 bytes, from 2013-08-11 18:14:15)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
similarity index 94%
rename from drivers/gpu/drm/msm/mdp4/mdp4.xml.h
rename to drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
index 9908ffe1c3ad093f7f73bdac19cd34a9abc6e450..416a26e1e58d1f7cdbbf401220a9928a80721a9e 100644 (file)
@@ -8,14 +8,16 @@ http://github.com/freedreno/envytools/
 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                 (    595 bytes, from 2013-07-05 19:21:12)
+- /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/mdp4/mdp4.xml           (  19332 bytes, from 2013-10-07 16:36:48)
+- /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 2013-12-03 20:59:13)
 - /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/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  19288 bytes, from 2013-08-11 18:14:15)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04)
 
 Copyright (C) 2013 by the following authors:
 - Rob Clark <robdclark@gmail.com> (robclark)
@@ -42,27 +44,6 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 
 
-enum mdp4_bpc {
-       BPC1 = 0,
-       BPC5 = 1,
-       BPC6 = 2,
-       BPC8 = 3,
-};
-
-enum mdp4_bpc_alpha {
-       BPC1A = 0,
-       BPC4A = 1,
-       BPC6A = 2,
-       BPC8A = 3,
-};
-
-enum mdp4_alpha_type {
-       FG_CONST = 0,
-       BG_CONST = 1,
-       FG_PIXEL = 2,
-       BG_PIXEL = 3,
-};
-
 enum mdp4_pipe {
        VG1 = 0,
        VG2 = 1,
@@ -79,15 +60,6 @@ enum mdp4_mixer {
        MIXER2 = 2,
 };
 
-enum mdp4_mixer_stage_id {
-       STAGE_UNUSED = 0,
-       STAGE_BASE = 1,
-       STAGE0 = 2,
-       STAGE1 = 3,
-       STAGE2 = 4,
-       STAGE3 = 5,
-};
-
 enum mdp4_intf {
        INTF_LCDC_DTV = 0,
        INTF_DSI_VIDEO = 1,
@@ -194,56 +166,56 @@ static inline uint32_t MDP4_DISP_INTF_SEL_EXT(enum mdp4_intf val)
 #define REG_MDP4_LAYERMIXER2_IN_CFG                            0x000100f0
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK                    0x00000007
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT                   0
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE0(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE0(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE0__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE0_MIXER1                   0x00000008
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK                    0x00000070
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT                   4
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE1(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE1(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE1__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE1_MIXER1                   0x00000080
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK                    0x00000700
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT                   8
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE2(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE2(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE2__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE2_MIXER1                   0x00000800
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK                    0x00007000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT                   12
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE3(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE3(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE3__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE3_MIXER1                   0x00008000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK                    0x00070000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT                   16
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE4(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE4(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE4__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE4_MIXER1                   0x00080000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK                    0x00700000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT                   20
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE5(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE5(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE5__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE5_MIXER1                   0x00800000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK                    0x07000000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT                   24
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE6(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE6(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE6__MASK;
 }
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE6_MIXER1                   0x08000000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK                    0x70000000
 #define MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT                   28
-static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER2_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER2_IN_CFG_PIPE7__MASK;
 }
@@ -254,56 +226,56 @@ static inline uint32_t MDP4_LAYERMIXER2_IN_CFG_PIPE7(enum mdp4_mixer_stage_id va
 #define REG_MDP4_LAYERMIXER_IN_CFG                             0x00010100
 #define MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK                     0x00000007
 #define MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT                    0
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE0(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE0(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE0__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE0__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE0_MIXER1                    0x00000008
 #define MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK                     0x00000070
 #define MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT                    4
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE1(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE1(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE1__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE1__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE1_MIXER1                    0x00000080
 #define MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK                     0x00000700
 #define MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT                    8
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE2(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE2(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE2__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE2__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE2_MIXER1                    0x00000800
 #define MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK                     0x00007000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT                    12
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE3(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE3(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE3__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE3__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE3_MIXER1                    0x00008000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK                     0x00070000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT                    16
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE4(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE4(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE4__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE4__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE4_MIXER1                    0x00080000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK                     0x00700000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT                    20
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE5(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE5(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE5__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE5__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE5_MIXER1                    0x00800000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK                     0x07000000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT                    24
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE6(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE6(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE6__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE6__MASK;
 }
 #define MDP4_LAYERMIXER_IN_CFG_PIPE6_MIXER1                    0x08000000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK                     0x70000000
 #define MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT                    28
-static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE7(enum mdp4_mixer_stage_id val)
+static inline uint32_t MDP4_LAYERMIXER_IN_CFG_PIPE7(enum mdp_mixer_stage_id val)
 {
        return ((val) << MDP4_LAYERMIXER_IN_CFG_PIPE7__SHIFT) & MDP4_LAYERMIXER_IN_CFG_PIPE7__MASK;
 }
@@ -369,7 +341,7 @@ static inline uint32_t REG_MDP4_OVLP_STAGE(uint32_t i0, uint32_t i1) { return 0x
 static inline uint32_t REG_MDP4_OVLP_STAGE_OP(uint32_t i0, uint32_t i1) { return 0x00000000 + __offset_OVLP(i0) + __offset_STAGE(i1); }
 #define MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK                      0x00000003
 #define MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT                     0
-static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp4_alpha_type val)
+static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp_alpha_type val)
 {
        return ((val) << MDP4_OVLP_STAGE_OP_FG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_FG_ALPHA__MASK;
 }
@@ -377,7 +349,7 @@ static inline uint32_t MDP4_OVLP_STAGE_OP_FG_ALPHA(enum mdp4_alpha_type val)
 #define MDP4_OVLP_STAGE_OP_FG_MOD_ALPHA                                0x00000008
 #define MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK                      0x00000030
 #define MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT                     4
-static inline uint32_t MDP4_OVLP_STAGE_OP_BG_ALPHA(enum mdp4_alpha_type val)
+static inline uint32_t MDP4_OVLP_STAGE_OP_BG_ALPHA(enum mdp_alpha_type val)
 {
        return ((val) << MDP4_OVLP_STAGE_OP_BG_ALPHA__SHIFT) & MDP4_OVLP_STAGE_OP_BG_ALPHA__MASK;
 }
@@ -472,19 +444,19 @@ static inline uint32_t REG_MDP4_DMA(enum mdp4_dma i0) { return 0x00000000 + __of
 static inline uint32_t REG_MDP4_DMA_CONFIG(enum mdp4_dma i0) { return 0x00000000 + __offset_DMA(i0); }
 #define MDP4_DMA_CONFIG_G_BPC__MASK                            0x00000003
 #define MDP4_DMA_CONFIG_G_BPC__SHIFT                           0
-static inline uint32_t MDP4_DMA_CONFIG_G_BPC(enum mdp4_bpc val)
+static inline uint32_t MDP4_DMA_CONFIG_G_BPC(enum mdp_bpc val)
 {
        return ((val) << MDP4_DMA_CONFIG_G_BPC__SHIFT) & MDP4_DMA_CONFIG_G_BPC__MASK;
 }
 #define MDP4_DMA_CONFIG_B_BPC__MASK                            0x0000000c
 #define MDP4_DMA_CONFIG_B_BPC__SHIFT                           2
-static inline uint32_t MDP4_DMA_CONFIG_B_BPC(enum mdp4_bpc val)
+static inline uint32_t MDP4_DMA_CONFIG_B_BPC(enum mdp_bpc val)
 {
        return ((val) << MDP4_DMA_CONFIG_B_BPC__SHIFT) & MDP4_DMA_CONFIG_B_BPC__MASK;
 }
 #define MDP4_DMA_CONFIG_R_BPC__MASK                            0x00000030
 #define MDP4_DMA_CONFIG_R_BPC__SHIFT                           4
-static inline uint32_t MDP4_DMA_CONFIG_R_BPC(enum mdp4_bpc val)
+static inline uint32_t MDP4_DMA_CONFIG_R_BPC(enum mdp_bpc val)
 {
        return ((val) << MDP4_DMA_CONFIG_R_BPC__SHIFT) & MDP4_DMA_CONFIG_R_BPC__MASK;
 }
@@ -710,25 +682,25 @@ static inline uint32_t MDP4_PIPE_FRAME_SIZE_WIDTH(uint32_t val)
 static inline uint32_t REG_MDP4_PIPE_SRC_FORMAT(enum mdp4_pipe i0) { return 0x00020050 + 0x10000*i0; }
 #define MDP4_PIPE_SRC_FORMAT_G_BPC__MASK                       0x00000003
 #define MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT                      0
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_G_BPC(enum mdp4_bpc val)
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val)
 {
        return ((val) << MDP4_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_G_BPC__MASK;
 }
 #define MDP4_PIPE_SRC_FORMAT_B_BPC__MASK                       0x0000000c
 #define MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT                      2
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_B_BPC(enum mdp4_bpc val)
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val)
 {
        return ((val) << MDP4_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_B_BPC__MASK;
 }
 #define MDP4_PIPE_SRC_FORMAT_R_BPC__MASK                       0x00000030
 #define MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT                      4
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_R_BPC(enum mdp4_bpc val)
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val)
 {
        return ((val) << MDP4_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_R_BPC__MASK;
 }
 #define MDP4_PIPE_SRC_FORMAT_A_BPC__MASK                       0x000000c0
 #define MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT                      6
-static inline uint32_t MDP4_PIPE_SRC_FORMAT_A_BPC(enum mdp4_bpc_alpha val)
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val)
 {
        return ((val) << MDP4_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP4_PIPE_SRC_FORMAT_A_BPC__MASK;
 }
similarity index 96%
rename from drivers/gpu/drm/msm/mdp4/mdp4_crtc.c
rename to drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index 019d530187ff2c52a0523790047b216d51baed16..1964f4f0d452377c87d2e2db4bd218a1f0451ff5 100644 (file)
@@ -66,15 +66,15 @@ struct mdp4_crtc {
        /* for unref'ing cursor bo's after scanout completes: */
        struct drm_flip_work unref_cursor_work;
 
-       struct mdp4_irq vblank;
-       struct mdp4_irq err;
+       struct mdp_irq vblank;
+       struct mdp_irq err;
 };
 #define to_mdp4_crtc(x) container_of(x, struct mdp4_crtc, base)
 
 static struct mdp4_kms *get_kms(struct drm_crtc *crtc)
 {
        struct msm_drm_private *priv = crtc->dev->dev_private;
-       return to_mdp4_kms(priv->kms);
+       return to_mdp4_kms(to_mdp_kms(priv->kms));
 }
 
 static void update_fb(struct drm_crtc *crtc, bool async,
@@ -93,7 +93,7 @@ static void update_fb(struct drm_crtc *crtc, bool async,
 
        if (!async) {
                /* enable vblank to pick up the old_fb */
-               mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank);
+               mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
        }
 }
 
@@ -145,7 +145,7 @@ static void request_pending(struct drm_crtc *crtc, uint32_t pending)
        struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
 
        atomic_or(pending, &mdp4_crtc->pending);
-       mdp4_irq_register(get_kms(crtc), &mdp4_crtc->vblank);
+       mdp_irq_register(&get_kms(crtc)->base, &mdp4_crtc->vblank);
 }
 
 static void pageflip_cb(struct msm_fence_cb *cb)
@@ -210,9 +210,9 @@ static void mdp4_crtc_dpms(struct drm_crtc *crtc, int mode)
        if (enabled != mdp4_crtc->enabled) {
                if (enabled) {
                        mdp4_enable(mdp4_kms);
-                       mdp4_irq_register(mdp4_kms, &mdp4_crtc->err);
+                       mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err);
                } else {
-                       mdp4_irq_unregister(mdp4_kms, &mdp4_crtc->err);
+                       mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err);
                        mdp4_disable(mdp4_kms);
                }
                mdp4_crtc->enabled = enabled;
@@ -232,7 +232,7 @@ static void blend_setup(struct drm_crtc *crtc)
        struct mdp4_kms *mdp4_kms = get_kms(crtc);
        int i, ovlp = mdp4_crtc->ovlp;
        uint32_t mixer_cfg = 0;
-       static const enum mdp4_mixer_stage_id stages[] = {
+       static const enum mdp_mixer_stage_id stages[] = {
                        STAGE_BASE, STAGE0, STAGE1, STAGE2, STAGE3,
        };
        /* statically (for now) map planes to mixer stage (z-order): */
@@ -262,8 +262,8 @@ static void blend_setup(struct drm_crtc *crtc)
                        enum mdp4_pipe pipe_id = mdp4_plane_pipe(plane);
                        int idx = idxs[pipe_id];
                        if (idx > 0) {
-                               const struct mdp4_format *format =
-                                       to_mdp4_format(msm_framebuffer_format(plane->fb));
+                               const struct mdp_format *format =
+                                       to_mdp_format(msm_framebuffer_format(plane->fb));
                                alpha[idx-1] = format->alpha_enable;
                        }
                        mixer_cfg |= mixercfg(mdp4_crtc->mixer, pipe_id, stages[idx]);
@@ -571,14 +571,14 @@ static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = {
        .load_lut = mdp4_crtc_load_lut,
 };
 
-static void mdp4_crtc_vblank_irq(struct mdp4_irq *irq, uint32_t irqstatus)
+static void mdp4_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
 {
        struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, vblank);
        struct drm_crtc *crtc = &mdp4_crtc->base;
        struct msm_drm_private *priv = crtc->dev->dev_private;
        unsigned pending;
 
-       mdp4_irq_unregister(get_kms(crtc), &mdp4_crtc->vblank);
+       mdp_irq_unregister(&get_kms(crtc)->base, &mdp4_crtc->vblank);
 
        pending = atomic_xchg(&mdp4_crtc->pending, 0);
 
@@ -593,7 +593,7 @@ static void mdp4_crtc_vblank_irq(struct mdp4_irq *irq, uint32_t irqstatus)
        }
 }
 
-static void mdp4_crtc_err_irq(struct mdp4_irq *irq, uint32_t irqstatus)
+static void mdp4_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
 {
        struct mdp4_crtc *mdp4_crtc = container_of(irq, struct mdp4_crtc, err);
        struct drm_crtc *crtc = &mdp4_crtc->base;
similarity index 98%
rename from drivers/gpu/drm/msm/mdp4/mdp4_dtv_encoder.c
rename to drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
index 5e0dcae70ab5d14999e2991c113a5835adda3900..067ed03b35fef964f530746a877efb77bf9fcbe5 100644 (file)
@@ -15,8 +15,6 @@
  * this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <mach/clk.h>
-
 #include "mdp4_kms.h"
 
 #include "drm_crtc.h"
@@ -37,7 +35,7 @@ struct mdp4_dtv_encoder {
 static struct mdp4_kms *get_kms(struct drm_encoder *encoder)
 {
        struct msm_drm_private *priv = encoder->dev->dev_private;
-       return to_mdp4_kms(priv->kms);
+       return to_mdp4_kms(to_mdp_kms(priv->kms));
 }
 
 #ifdef CONFIG_MSM_BUS_SCALING
@@ -139,7 +137,7 @@ static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
                 * the settings changes for the new modeset (like new
                 * scanout buffer) don't latch properly..
                 */
-               mdp4_irq_wait(mdp4_kms, MDP4_IRQ_EXTERNAL_VSYNC);
+               mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC);
 
                clk_disable_unprepare(mdp4_dtv_encoder->src_clk);
                clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk);
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_irq.c
new file mode 100644 (file)
index 0000000..c740ccd
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 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 "msm_drv.h"
+#include "mdp4_kms.h"
+
+void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask)
+{
+       mdp4_write(to_mdp4_kms(mdp_kms), REG_MDP4_INTR_ENABLE, irqmask);
+}
+
+static void mdp4_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
+{
+       DRM_ERROR("errors: %08x\n", irqstatus);
+}
+
+void mdp4_irq_preinstall(struct msm_kms *kms)
+{
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff);
+}
+
+int mdp4_irq_postinstall(struct msm_kms *kms)
+{
+       struct mdp_kms *mdp_kms = to_mdp_kms(kms);
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms);
+       struct mdp_irq *error_handler = &mdp4_kms->error_handler;
+
+       error_handler->irq = mdp4_irq_error_handler;
+       error_handler->irqmask = MDP4_IRQ_PRIMARY_INTF_UDERRUN |
+                       MDP4_IRQ_EXTERNAL_INTF_UDERRUN;
+
+       mdp_irq_register(mdp_kms, error_handler);
+
+       return 0;
+}
+
+void mdp4_irq_uninstall(struct msm_kms *kms)
+{
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+       mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
+}
+
+irqreturn_t mdp4_irq(struct msm_kms *kms)
+{
+       struct mdp_kms *mdp_kms = to_mdp_kms(kms);
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(mdp_kms);
+       struct drm_device *dev = mdp4_kms->dev;
+       struct msm_drm_private *priv = dev->dev_private;
+       unsigned int id;
+       uint32_t status;
+
+       status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS);
+       mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, status);
+
+       VERB("status=%08x", status);
+
+       for (id = 0; id < priv->num_crtcs; id++)
+               if (status & mdp4_crtc_vblank(priv->crtcs[id]))
+                       drm_handle_vblank(dev, id);
+
+       mdp_dispatch_irqs(mdp_kms, status);
+
+       return IRQ_HANDLED;
+}
+
+int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+       mdp_update_vblank_mask(to_mdp_kms(kms),
+                       mdp4_crtc_vblank(crtc), true);
+       return 0;
+}
+
+void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+       mdp_update_vblank_mask(to_mdp_kms(kms),
+                       mdp4_crtc_vblank(crtc), false);
+}
similarity index 89%
rename from drivers/gpu/drm/msm/mdp4/mdp4_kms.c
rename to drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index 8972ac35a43dab9f1006641e69734d1c9c0c40d4..272e707c948704e6ff36cc8df263723fdbbd2a71 100644 (file)
 
 
 #include "msm_drv.h"
+#include "msm_mmu.h"
 #include "mdp4_kms.h"
 
 static struct mdp4_platform_config *mdp4_get_config(struct platform_device *dev);
 
 static int mdp4_hw_init(struct msm_kms *kms)
 {
-       struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms);
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
        struct drm_device *dev = mdp4_kms->dev;
        uint32_t version, major, minor, dmap_cfg, vg_cfg;
        unsigned long clk;
@@ -31,12 +32,14 @@ static int mdp4_hw_init(struct msm_kms *kms)
 
        pm_runtime_get_sync(dev->dev);
 
+       mdp4_enable(mdp4_kms);
        version = mdp4_read(mdp4_kms, REG_MDP4_VERSION);
+       mdp4_disable(mdp4_kms);
 
        major = FIELD(version, MDP4_VERSION_MAJOR);
        minor = FIELD(version, MDP4_VERSION_MINOR);
 
-       DBG("found MDP version v%d.%d", major, minor);
+       DBG("found MDP4 version v%d.%d", major, minor);
 
        if (major != 4) {
                dev_err(dev->dev, "unexpected MDP version: v%d.%d\n",
@@ -130,7 +133,7 @@ static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
 
 static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
 {
-       struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms);
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
        struct msm_drm_private *priv = mdp4_kms->dev->dev_private;
        unsigned i;
 
@@ -140,11 +143,12 @@ static void mdp4_preclose(struct msm_kms *kms, struct drm_file *file)
 
 static void mdp4_destroy(struct msm_kms *kms)
 {
-       struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms);
+       struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
        kfree(mdp4_kms);
 }
 
-static const struct msm_kms_funcs kms_funcs = {
+static const struct mdp_kms_funcs kms_funcs = {
+       .base = {
                .hw_init         = mdp4_hw_init,
                .irq_preinstall  = mdp4_irq_preinstall,
                .irq_postinstall = mdp4_irq_postinstall,
@@ -152,10 +156,12 @@ static const struct msm_kms_funcs kms_funcs = {
                .irq             = mdp4_irq,
                .enable_vblank   = mdp4_enable_vblank,
                .disable_vblank  = mdp4_disable_vblank,
-               .get_format      = mdp4_get_format,
+               .get_format      = mdp_get_format,
                .round_pixclk    = mdp4_round_pixclk,
                .preclose        = mdp4_preclose,
                .destroy         = mdp4_destroy,
+       },
+       .set_irqmask         = mdp4_set_irqmask,
 };
 
 int mdp4_disable(struct mdp4_kms *mdp4_kms)
@@ -189,6 +195,7 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        struct drm_plane *plane;
        struct drm_crtc *crtc;
        struct drm_encoder *encoder;
+       struct hdmi *hdmi;
        int ret;
 
        /*
@@ -238,9 +245,10 @@ static int modeset_init(struct mdp4_kms *mdp4_kms)
        encoder->possible_crtcs = 0x1;     /* DTV can be hooked to DMA_E */
        priv->encoders[priv->num_encoders++] = encoder;
 
-       ret = hdmi_init(dev, encoder);
-       if (ret) {
-               dev_err(dev->dev, "failed to initialize HDMI\n");
+       hdmi = hdmi_init(dev, encoder);
+       if (IS_ERR(hdmi)) {
+               ret = PTR_ERR(hdmi);
+               dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
                goto fail;
        }
 
@@ -260,6 +268,7 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
        struct mdp4_platform_config *config = mdp4_get_config(pdev);
        struct mdp4_kms *mdp4_kms;
        struct msm_kms *kms = NULL;
+       struct msm_mmu *mmu;
        int ret;
 
        mdp4_kms = kzalloc(sizeof(*mdp4_kms), GFP_KERNEL);
@@ -269,8 +278,9 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
                goto fail;
        }
 
-       kms = &mdp4_kms->base;
-       kms->funcs = &kms_funcs;
+       mdp_kms_init(&mdp4_kms->base, &kms_funcs);
+
+       kms = &mdp4_kms->base.base;
 
        mdp4_kms->dev = dev;
 
@@ -322,27 +332,34 @@ struct msm_kms *mdp4_kms_init(struct drm_device *dev)
        clk_set_rate(mdp4_kms->clk, config->max_clk);
        clk_set_rate(mdp4_kms->lut_clk, config->max_clk);
 
-       if (!config->iommu) {
-               dev_err(dev->dev, "no iommu\n");
-               ret = -ENXIO;
-               goto fail;
-       }
-
        /* make sure things are off before attaching iommu (bootloader could
         * have left things on, in which case we'll start getting faults if
         * we don't disable):
         */
+       mdp4_enable(mdp4_kms);
        mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0);
        mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
        mdp4_write(mdp4_kms, REG_MDP4_DSI_ENABLE, 0);
+       mdp4_disable(mdp4_kms);
        mdelay(16);
 
-       ret = msm_iommu_attach(dev, config->iommu,
-                       iommu_ports, ARRAY_SIZE(iommu_ports));
-       if (ret)
-               goto fail;
+       if (config->iommu) {
+               mmu = msm_iommu_new(dev, config->iommu);
+               if (IS_ERR(mmu)) {
+                       ret = PTR_ERR(mmu);
+                       goto fail;
+               }
+               ret = mmu->funcs->attach(mmu, iommu_ports,
+                               ARRAY_SIZE(iommu_ports));
+               if (ret)
+                       goto fail;
+       } else {
+               dev_info(dev->dev, "no iommu, fallback to phys "
+                               "contig buffers for scanout\n");
+               mmu = NULL;
+       }
 
-       mdp4_kms->id = msm_register_iommu(dev, config->iommu);
+       mdp4_kms->id = msm_register_mmu(dev, mmu);
        if (mdp4_kms->id < 0) {
                ret = mdp4_kms->id;
                dev_err(dev->dev, "failed to register mdp4 iommu: %d\n", ret);
similarity index 79%
rename from drivers/gpu/drm/msm/mdp4/mdp4_kms.h
rename to drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
index eb015c834087c00189f9afcbe843ae1b0f0a14db..66a4d31aec80e010e5f5914705f05f7f346dc68c 100644 (file)
 #ifndef __MDP4_KMS_H__
 #define __MDP4_KMS_H__
 
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/consumer.h>
-
 #include "msm_drv.h"
+#include "msm_kms.h"
+#include "mdp/mdp_kms.h"
 #include "mdp4.xml.h"
 
-
-/* For transiently registering for different MDP4 irqs that various parts
- * of the KMS code need during setup/configuration.  We these are not
- * necessarily the same as what drm_vblank_get/put() are requesting, and
- * the hysteresis in drm_vblank_put() is not necessarily desirable for
- * internal housekeeping related irq usage.
- */
-struct mdp4_irq {
-       struct list_head node;
-       uint32_t irqmask;
-       bool registered;
-       void (*irq)(struct mdp4_irq *irq, uint32_t irqstatus);
-};
-
 struct mdp4_kms {
-       struct msm_kms base;
+       struct mdp_kms base;
 
        struct drm_device *dev;
 
@@ -59,11 +43,7 @@ struct mdp4_kms {
        struct clk *pclk;
        struct clk *lut_clk;
 
-       /* irq handling: */
-       bool in_irq;
-       struct list_head irq_list;    /* list of mdp4_irq */
-       uint32_t vblank_mask;         /* irq bits set for userspace vblank */
-       struct mdp4_irq error_handler;
+       struct mdp_irq error_handler;
 };
 #define to_mdp4_kms(x) container_of(x, struct mdp4_kms, base)
 
@@ -73,16 +53,6 @@ struct mdp4_platform_config {
        uint32_t max_clk;
 };
 
-struct mdp4_format {
-       struct msm_format base;
-       enum mdp4_bpc bpc_r, bpc_g, bpc_b;
-       enum mdp4_bpc_alpha bpc_a;
-       uint8_t unpack[4];
-       bool alpha_enable, unpack_tight;
-       uint8_t cpp, unpack_count;
-};
-#define to_mdp4_format(x) container_of(x, struct mdp4_format, base)
-
 static inline void mdp4_write(struct mdp4_kms *mdp4_kms, u32 reg, u32 data)
 {
        msm_writel(data, mdp4_kms->mmio + reg);
@@ -134,7 +104,7 @@ static inline uint32_t dma2err(enum mdp4_dma dma)
 }
 
 static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe,
-               enum mdp4_mixer_stage_id stage)
+               enum mdp_mixer_stage_id stage)
 {
        uint32_t mixer_cfg = 0;
 
@@ -178,19 +148,23 @@ static inline uint32_t mixercfg(int mixer, enum mdp4_pipe pipe,
 int mdp4_disable(struct mdp4_kms *mdp4_kms);
 int mdp4_enable(struct mdp4_kms *mdp4_kms);
 
+void mdp4_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask);
 void mdp4_irq_preinstall(struct msm_kms *kms);
 int mdp4_irq_postinstall(struct msm_kms *kms);
 void mdp4_irq_uninstall(struct msm_kms *kms);
 irqreturn_t mdp4_irq(struct msm_kms *kms);
-void mdp4_irq_wait(struct mdp4_kms *mdp4_kms, uint32_t irqmask);
-void mdp4_irq_register(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq);
-void mdp4_irq_unregister(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq);
 int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
 
-uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *formats,
-               uint32_t max_formats);
-const struct msm_format *mdp4_get_format(struct msm_kms *kms, uint32_t format);
+static inline
+uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
+               uint32_t max_formats)
+{
+       /* TODO when we have YUV, we need to filter supported formats
+        * based on pipe_id..
+        */
+       return mdp_get_formats(pixel_formats, max_formats);
+}
 
 void mdp4_plane_install_properties(struct drm_plane *plane,
                struct drm_mode_object *obj);
similarity index 98%
rename from drivers/gpu/drm/msm/mdp4/mdp4_plane.c
rename to drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 0f0af243f6fc41cb030f40985cf3466aed945aa6..2406027200ec597e5d6a10674e82db82f122adff 100644 (file)
@@ -34,7 +34,7 @@ struct mdp4_plane {
 static struct mdp4_kms *get_kms(struct drm_plane *plane)
 {
        struct msm_drm_private *priv = plane->dev->dev_private;
-       return to_mdp4_kms(priv->kms);
+       return to_mdp4_kms(to_mdp_kms(priv->kms));
 }
 
 static int mdp4_plane_update(struct drm_plane *plane,
@@ -132,7 +132,7 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
        struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
        struct mdp4_kms *mdp4_kms = get_kms(plane);
        enum mdp4_pipe pipe = mdp4_plane->pipe;
-       const struct mdp4_format *format;
+       const struct mdp_format *format;
        uint32_t op_mode = 0;
        uint32_t phasex_step = MDP4_VG_PHASE_STEP_DEFAULT;
        uint32_t phasey_step = MDP4_VG_PHASE_STEP_DEFAULT;
@@ -175,7 +175,7 @@ int mdp4_plane_mode_set(struct drm_plane *plane,
 
        mdp4_plane_set_scanout(plane, fb);
 
-       format = to_mdp4_format(msm_framebuffer_format(fb));
+       format = to_mdp_format(msm_framebuffer_format(fb));
 
        mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe),
                        MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
new file mode 100644 (file)
index 0000000..0aa5151
--- /dev/null
@@ -0,0 +1,1036 @@
+#ifndef MDP5_XML
+#define MDP5_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/freedreno/envytools/
+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 2013-12-03 20:59:13)
+- /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/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04)
+
+Copyright (C) 2013 by the following authors:
+- Rob Clark <robdclark@gmail.com> (robclark)
+
+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 COPYRIGHT OWNER(S) 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.
+*/
+
+
+enum mdp5_intf {
+       INTF_DSI = 1,
+       INTF_HDMI = 3,
+       INTF_LCDC = 5,
+       INTF_eDP = 9,
+};
+
+enum mdp5_intfnum {
+       NO_INTF = 0,
+       INTF0 = 1,
+       INTF1 = 2,
+       INTF2 = 3,
+       INTF3 = 4,
+};
+
+enum mdp5_pipe {
+       SSPP_VIG0 = 0,
+       SSPP_VIG1 = 1,
+       SSPP_VIG2 = 2,
+       SSPP_RGB0 = 3,
+       SSPP_RGB1 = 4,
+       SSPP_RGB2 = 5,
+       SSPP_DMA0 = 6,
+       SSPP_DMA1 = 7,
+};
+
+enum mdp5_ctl_mode {
+       MODE_NONE = 0,
+       MODE_ROT0 = 1,
+       MODE_ROT1 = 2,
+       MODE_WB0 = 3,
+       MODE_WB1 = 4,
+       MODE_WFD = 5,
+};
+
+enum mdp5_pack_3d {
+       PACK_3D_FRAME_INT = 0,
+       PACK_3D_H_ROW_INT = 1,
+       PACK_3D_V_ROW_INT = 2,
+       PACK_3D_COL_INT = 3,
+};
+
+enum mdp5_chroma_samp_type {
+       CHROMA_RGB = 0,
+       CHROMA_H2V1 = 1,
+       CHROMA_H1V2 = 2,
+       CHROMA_420 = 3,
+};
+
+enum mdp5_scale_filter {
+       SCALE_FILTER_NEAREST = 0,
+       SCALE_FILTER_BIL = 1,
+       SCALE_FILTER_PCMN = 2,
+       SCALE_FILTER_CA = 3,
+};
+
+enum mdp5_pipe_bwc {
+       BWC_LOSSLESS = 0,
+       BWC_Q_HIGH = 1,
+       BWC_Q_MED = 2,
+};
+
+enum mdp5_client_id {
+       CID_UNUSED = 0,
+       CID_VIG0_Y = 1,
+       CID_VIG0_CR = 2,
+       CID_VIG0_CB = 3,
+       CID_VIG1_Y = 4,
+       CID_VIG1_CR = 5,
+       CID_VIG1_CB = 6,
+       CID_VIG2_Y = 7,
+       CID_VIG2_CR = 8,
+       CID_VIG2_CB = 9,
+       CID_DMA0_Y = 10,
+       CID_DMA0_CR = 11,
+       CID_DMA0_CB = 12,
+       CID_DMA1_Y = 13,
+       CID_DMA1_CR = 14,
+       CID_DMA1_CB = 15,
+       CID_RGB0 = 16,
+       CID_RGB1 = 17,
+       CID_RGB2 = 18,
+       CID_MAX = 19,
+};
+
+enum mdp5_igc_type {
+       IGC_VIG = 0,
+       IGC_RGB = 1,
+       IGC_DMA = 2,
+       IGC_DSPP = 3,
+};
+
+#define MDP5_IRQ_INTF0_WB_ROT_COMP                             0x00000001
+#define MDP5_IRQ_INTF1_WB_ROT_COMP                             0x00000002
+#define MDP5_IRQ_INTF2_WB_ROT_COMP                             0x00000004
+#define MDP5_IRQ_INTF3_WB_ROT_COMP                             0x00000008
+#define MDP5_IRQ_INTF0_WB_WFD                                  0x00000010
+#define MDP5_IRQ_INTF1_WB_WFD                                  0x00000020
+#define MDP5_IRQ_INTF2_WB_WFD                                  0x00000040
+#define MDP5_IRQ_INTF3_WB_WFD                                  0x00000080
+#define MDP5_IRQ_INTF0_PING_PONG_COMP                          0x00000100
+#define MDP5_IRQ_INTF1_PING_PONG_COMP                          0x00000200
+#define MDP5_IRQ_INTF2_PING_PONG_COMP                          0x00000400
+#define MDP5_IRQ_INTF3_PING_PONG_COMP                          0x00000800
+#define MDP5_IRQ_INTF0_PING_PONG_RD_PTR                                0x00001000
+#define MDP5_IRQ_INTF1_PING_PONG_RD_PTR                                0x00002000
+#define MDP5_IRQ_INTF2_PING_PONG_RD_PTR                                0x00004000
+#define MDP5_IRQ_INTF3_PING_PONG_RD_PTR                                0x00008000
+#define MDP5_IRQ_INTF0_PING_PONG_WR_PTR                                0x00010000
+#define MDP5_IRQ_INTF1_PING_PONG_WR_PTR                                0x00020000
+#define MDP5_IRQ_INTF2_PING_PONG_WR_PTR                                0x00040000
+#define MDP5_IRQ_INTF3_PING_PONG_WR_PTR                                0x00080000
+#define MDP5_IRQ_INTF0_PING_PONG_AUTO_REF                      0x00100000
+#define MDP5_IRQ_INTF1_PING_PONG_AUTO_REF                      0x00200000
+#define MDP5_IRQ_INTF2_PING_PONG_AUTO_REF                      0x00400000
+#define MDP5_IRQ_INTF3_PING_PONG_AUTO_REF                      0x00800000
+#define MDP5_IRQ_INTF0_UNDER_RUN                               0x01000000
+#define MDP5_IRQ_INTF0_VSYNC                                   0x02000000
+#define MDP5_IRQ_INTF1_UNDER_RUN                               0x04000000
+#define MDP5_IRQ_INTF1_VSYNC                                   0x08000000
+#define MDP5_IRQ_INTF2_UNDER_RUN                               0x10000000
+#define MDP5_IRQ_INTF2_VSYNC                                   0x20000000
+#define MDP5_IRQ_INTF3_UNDER_RUN                               0x40000000
+#define MDP5_IRQ_INTF3_VSYNC                                   0x80000000
+#define REG_MDP5_HW_VERSION                                    0x00000000
+
+#define REG_MDP5_HW_INTR_STATUS                                        0x00000010
+#define MDP5_HW_INTR_STATUS_INTR_MDP                           0x00000001
+#define MDP5_HW_INTR_STATUS_INTR_DSI0                          0x00000010
+#define MDP5_HW_INTR_STATUS_INTR_DSI1                          0x00000020
+#define MDP5_HW_INTR_STATUS_INTR_HDMI                          0x00000100
+#define MDP5_HW_INTR_STATUS_INTR_EDP                           0x00001000
+
+#define REG_MDP5_MDP_VERSION                                   0x00000100
+#define MDP5_MDP_VERSION_MINOR__MASK                           0x00ff0000
+#define MDP5_MDP_VERSION_MINOR__SHIFT                          16
+static inline uint32_t MDP5_MDP_VERSION_MINOR(uint32_t val)
+{
+       return ((val) << MDP5_MDP_VERSION_MINOR__SHIFT) & MDP5_MDP_VERSION_MINOR__MASK;
+}
+#define MDP5_MDP_VERSION_MAJOR__MASK                           0xf0000000
+#define MDP5_MDP_VERSION_MAJOR__SHIFT                          28
+static inline uint32_t MDP5_MDP_VERSION_MAJOR(uint32_t val)
+{
+       return ((val) << MDP5_MDP_VERSION_MAJOR__SHIFT) & MDP5_MDP_VERSION_MAJOR__MASK;
+}
+
+#define REG_MDP5_DISP_INTF_SEL                                 0x00000104
+#define MDP5_DISP_INTF_SEL_INTF0__MASK                         0x000000ff
+#define MDP5_DISP_INTF_SEL_INTF0__SHIFT                                0
+static inline uint32_t MDP5_DISP_INTF_SEL_INTF0(enum mdp5_intf val)
+{
+       return ((val) << MDP5_DISP_INTF_SEL_INTF0__SHIFT) & MDP5_DISP_INTF_SEL_INTF0__MASK;
+}
+#define MDP5_DISP_INTF_SEL_INTF1__MASK                         0x0000ff00
+#define MDP5_DISP_INTF_SEL_INTF1__SHIFT                                8
+static inline uint32_t MDP5_DISP_INTF_SEL_INTF1(enum mdp5_intf val)
+{
+       return ((val) << MDP5_DISP_INTF_SEL_INTF1__SHIFT) & MDP5_DISP_INTF_SEL_INTF1__MASK;
+}
+#define MDP5_DISP_INTF_SEL_INTF2__MASK                         0x00ff0000
+#define MDP5_DISP_INTF_SEL_INTF2__SHIFT                                16
+static inline uint32_t MDP5_DISP_INTF_SEL_INTF2(enum mdp5_intf val)
+{
+       return ((val) << MDP5_DISP_INTF_SEL_INTF2__SHIFT) & MDP5_DISP_INTF_SEL_INTF2__MASK;
+}
+#define MDP5_DISP_INTF_SEL_INTF3__MASK                         0xff000000
+#define MDP5_DISP_INTF_SEL_INTF3__SHIFT                                24
+static inline uint32_t MDP5_DISP_INTF_SEL_INTF3(enum mdp5_intf val)
+{
+       return ((val) << MDP5_DISP_INTF_SEL_INTF3__SHIFT) & MDP5_DISP_INTF_SEL_INTF3__MASK;
+}
+
+#define REG_MDP5_INTR_EN                                       0x00000110
+
+#define REG_MDP5_INTR_STATUS                                   0x00000114
+
+#define REG_MDP5_INTR_CLEAR                                    0x00000118
+
+#define REG_MDP5_HIST_INTR_EN                                  0x0000011c
+
+#define REG_MDP5_HIST_INTR_STATUS                              0x00000120
+
+#define REG_MDP5_HIST_INTR_CLEAR                               0x00000124
+
+static inline uint32_t REG_MDP5_SMP_ALLOC_W(uint32_t i0) { return 0x00000180 + 0x4*i0; }
+
+static inline uint32_t REG_MDP5_SMP_ALLOC_W_REG(uint32_t i0) { return 0x00000180 + 0x4*i0; }
+#define MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK                     0x000000ff
+#define MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT                    0
+static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT0(enum mdp5_client_id val)
+{
+       return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
+}
+#define MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK                     0x0000ff00
+#define MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT                    8
+static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT1(enum mdp5_client_id val)
+{
+       return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
+}
+#define MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK                     0x00ff0000
+#define MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT                    16
+static inline uint32_t MDP5_SMP_ALLOC_W_REG_CLIENT2(enum mdp5_client_id val)
+{
+       return ((val) << MDP5_SMP_ALLOC_W_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
+}
+
+static inline uint32_t REG_MDP5_SMP_ALLOC_R(uint32_t i0) { return 0x00000230 + 0x4*i0; }
+
+static inline uint32_t REG_MDP5_SMP_ALLOC_R_REG(uint32_t i0) { return 0x00000230 + 0x4*i0; }
+#define MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK                     0x000000ff
+#define MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT                    0
+static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT0(enum mdp5_client_id val)
+{
+       return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT0__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT0__MASK;
+}
+#define MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK                     0x0000ff00
+#define MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT                    8
+static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT1(enum mdp5_client_id val)
+{
+       return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT1__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT1__MASK;
+}
+#define MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK                     0x00ff0000
+#define MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT                    16
+static inline uint32_t MDP5_SMP_ALLOC_R_REG_CLIENT2(enum mdp5_client_id val)
+{
+       return ((val) << MDP5_SMP_ALLOC_R_REG_CLIENT2__SHIFT) & MDP5_SMP_ALLOC_R_REG_CLIENT2__MASK;
+}
+
+static inline uint32_t __offset_IGC(enum mdp5_igc_type idx)
+{
+       switch (idx) {
+               case IGC_VIG: return 0x00000300;
+               case IGC_RGB: return 0x00000310;
+               case IGC_DMA: return 0x00000320;
+               case IGC_DSPP: return 0x00000400;
+               default: return INVALID_IDX(idx);
+       }
+}
+static inline uint32_t REG_MDP5_IGC(enum mdp5_igc_type i0) { return 0x00000000 + __offset_IGC(i0); }
+
+static inline uint32_t REG_MDP5_IGC_LUT(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_IGC_LUT_REG(enum mdp5_igc_type i0, uint32_t i1) { return 0x00000000 + __offset_IGC(i0) + 0x4*i1; }
+#define MDP5_IGC_LUT_REG_VAL__MASK                             0x00000fff
+#define MDP5_IGC_LUT_REG_VAL__SHIFT                            0
+static inline uint32_t MDP5_IGC_LUT_REG_VAL(uint32_t val)
+{
+       return ((val) << MDP5_IGC_LUT_REG_VAL__SHIFT) & MDP5_IGC_LUT_REG_VAL__MASK;
+}
+#define MDP5_IGC_LUT_REG_INDEX_UPDATE                          0x02000000
+#define MDP5_IGC_LUT_REG_DISABLE_PIPE_0                                0x10000000
+#define MDP5_IGC_LUT_REG_DISABLE_PIPE_1                                0x20000000
+#define MDP5_IGC_LUT_REG_DISABLE_PIPE_2                                0x40000000
+
+static inline uint32_t REG_MDP5_CTL(uint32_t i0) { return 0x00000600 + 0x100*i0; }
+
+static inline uint32_t REG_MDP5_CTL_LAYER(uint32_t i0, uint32_t i1) { return 0x00000600 + 0x100*i0 + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_CTL_LAYER_REG(uint32_t i0, uint32_t i1) { return 0x00000600 + 0x100*i0 + 0x4*i1; }
+#define MDP5_CTL_LAYER_REG_VIG0__MASK                          0x00000007
+#define MDP5_CTL_LAYER_REG_VIG0__SHIFT                         0
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG0(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_REG_VIG0__SHIFT) & MDP5_CTL_LAYER_REG_VIG0__MASK;
+}
+#define MDP5_CTL_LAYER_REG_VIG1__MASK                          0x00000038
+#define MDP5_CTL_LAYER_REG_VIG1__SHIFT                         3
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG1(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_REG_VIG1__SHIFT) & MDP5_CTL_LAYER_REG_VIG1__MASK;
+}
+#define MDP5_CTL_LAYER_REG_VIG2__MASK                          0x000001c0
+#define MDP5_CTL_LAYER_REG_VIG2__SHIFT                         6
+static inline uint32_t MDP5_CTL_LAYER_REG_VIG2(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_REG_VIG2__SHIFT) & MDP5_CTL_LAYER_REG_VIG2__MASK;
+}
+#define MDP5_CTL_LAYER_REG_RGB0__MASK                          0x00000e00
+#define MDP5_CTL_LAYER_REG_RGB0__SHIFT                         9
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB0(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_REG_RGB0__SHIFT) & MDP5_CTL_LAYER_REG_RGB0__MASK;
+}
+#define MDP5_CTL_LAYER_REG_RGB1__MASK                          0x00007000
+#define MDP5_CTL_LAYER_REG_RGB1__SHIFT                         12
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB1(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_REG_RGB1__SHIFT) & MDP5_CTL_LAYER_REG_RGB1__MASK;
+}
+#define MDP5_CTL_LAYER_REG_RGB2__MASK                          0x00038000
+#define MDP5_CTL_LAYER_REG_RGB2__SHIFT                         15
+static inline uint32_t MDP5_CTL_LAYER_REG_RGB2(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_REG_RGB2__SHIFT) & MDP5_CTL_LAYER_REG_RGB2__MASK;
+}
+#define MDP5_CTL_LAYER_REG_DMA0__MASK                          0x001c0000
+#define MDP5_CTL_LAYER_REG_DMA0__SHIFT                         18
+static inline uint32_t MDP5_CTL_LAYER_REG_DMA0(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_REG_DMA0__SHIFT) & MDP5_CTL_LAYER_REG_DMA0__MASK;
+}
+#define MDP5_CTL_LAYER_REG_DMA1__MASK                          0x00e00000
+#define MDP5_CTL_LAYER_REG_DMA1__SHIFT                         21
+static inline uint32_t MDP5_CTL_LAYER_REG_DMA1(enum mdp_mixer_stage_id val)
+{
+       return ((val) << MDP5_CTL_LAYER_REG_DMA1__SHIFT) & MDP5_CTL_LAYER_REG_DMA1__MASK;
+}
+#define MDP5_CTL_LAYER_REG_BORDER_COLOR                                0x01000000
+#define MDP5_CTL_LAYER_REG_CURSOR_OUT                          0x02000000
+
+static inline uint32_t REG_MDP5_CTL_OP(uint32_t i0) { return 0x00000614 + 0x100*i0; }
+#define MDP5_CTL_OP_MODE__MASK                                 0x0000000f
+#define MDP5_CTL_OP_MODE__SHIFT                                        0
+static inline uint32_t MDP5_CTL_OP_MODE(enum mdp5_ctl_mode val)
+{
+       return ((val) << MDP5_CTL_OP_MODE__SHIFT) & MDP5_CTL_OP_MODE__MASK;
+}
+#define MDP5_CTL_OP_INTF_NUM__MASK                             0x00000070
+#define MDP5_CTL_OP_INTF_NUM__SHIFT                            4
+static inline uint32_t MDP5_CTL_OP_INTF_NUM(enum mdp5_intfnum val)
+{
+       return ((val) << MDP5_CTL_OP_INTF_NUM__SHIFT) & MDP5_CTL_OP_INTF_NUM__MASK;
+}
+#define MDP5_CTL_OP_CMD_MODE                                   0x00020000
+#define MDP5_CTL_OP_PACK_3D_ENABLE                             0x00080000
+#define MDP5_CTL_OP_PACK_3D__MASK                              0x00300000
+#define MDP5_CTL_OP_PACK_3D__SHIFT                             20
+static inline uint32_t MDP5_CTL_OP_PACK_3D(enum mdp5_pack_3d val)
+{
+       return ((val) << MDP5_CTL_OP_PACK_3D__SHIFT) & MDP5_CTL_OP_PACK_3D__MASK;
+}
+
+static inline uint32_t REG_MDP5_CTL_FLUSH(uint32_t i0) { return 0x00000618 + 0x100*i0; }
+#define MDP5_CTL_FLUSH_VIG0                                    0x00000001
+#define MDP5_CTL_FLUSH_VIG1                                    0x00000002
+#define MDP5_CTL_FLUSH_VIG2                                    0x00000004
+#define MDP5_CTL_FLUSH_RGB0                                    0x00000008
+#define MDP5_CTL_FLUSH_RGB1                                    0x00000010
+#define MDP5_CTL_FLUSH_RGB2                                    0x00000020
+#define MDP5_CTL_FLUSH_LM0                                     0x00000040
+#define MDP5_CTL_FLUSH_LM1                                     0x00000080
+#define MDP5_CTL_FLUSH_LM2                                     0x00000100
+#define MDP5_CTL_FLUSH_DMA0                                    0x00000800
+#define MDP5_CTL_FLUSH_DMA1                                    0x00001000
+#define MDP5_CTL_FLUSH_DSPP0                                   0x00002000
+#define MDP5_CTL_FLUSH_DSPP1                                   0x00004000
+#define MDP5_CTL_FLUSH_DSPP2                                   0x00008000
+#define MDP5_CTL_FLUSH_CTL                                     0x00020000
+
+static inline uint32_t REG_MDP5_CTL_START(uint32_t i0) { return 0x0000061c + 0x100*i0; }
+
+static inline uint32_t REG_MDP5_CTL_PACK_3D(uint32_t i0) { return 0x00000620 + 0x100*i0; }
+
+static inline uint32_t REG_MDP5_PIPE(enum mdp5_pipe i0) { return 0x00001200 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_HIST_CTL_BASE(enum mdp5_pipe i0) { return 0x000014c4 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_HIST_LUT_BASE(enum mdp5_pipe i0) { return 0x000014f0 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_HIST_LUT_SWAP(enum mdp5_pipe i0) { return 0x00001500 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SRC_SIZE(enum mdp5_pipe i0) { return 0x00001200 + 0x400*i0; }
+#define MDP5_PIPE_SRC_SIZE_HEIGHT__MASK                                0xffff0000
+#define MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT                       16
+static inline uint32_t MDP5_PIPE_SRC_SIZE_HEIGHT(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_SIZE_HEIGHT__MASK;
+}
+#define MDP5_PIPE_SRC_SIZE_WIDTH__MASK                         0x0000ffff
+#define MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT                                0
+static inline uint32_t MDP5_PIPE_SRC_SIZE_WIDTH(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_IMG_SIZE(enum mdp5_pipe i0) { return 0x00001204 + 0x400*i0; }
+#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK                    0xffff0000
+#define MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT                   16
+static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_HEIGHT__MASK;
+}
+#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK                     0x0000ffff
+#define MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT                    0
+static inline uint32_t MDP5_PIPE_SRC_IMG_SIZE_WIDTH(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_IMG_SIZE_WIDTH__SHIFT) & MDP5_PIPE_SRC_IMG_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_XY(enum mdp5_pipe i0) { return 0x00001208 + 0x400*i0; }
+#define MDP5_PIPE_SRC_XY_Y__MASK                               0xffff0000
+#define MDP5_PIPE_SRC_XY_Y__SHIFT                              16
+static inline uint32_t MDP5_PIPE_SRC_XY_Y(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_XY_Y__SHIFT) & MDP5_PIPE_SRC_XY_Y__MASK;
+}
+#define MDP5_PIPE_SRC_XY_X__MASK                               0x0000ffff
+#define MDP5_PIPE_SRC_XY_X__SHIFT                              0
+static inline uint32_t MDP5_PIPE_SRC_XY_X(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_XY_X__SHIFT) & MDP5_PIPE_SRC_XY_X__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_OUT_SIZE(enum mdp5_pipe i0) { return 0x0000120c + 0x400*i0; }
+#define MDP5_PIPE_OUT_SIZE_HEIGHT__MASK                                0xffff0000
+#define MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT                       16
+static inline uint32_t MDP5_PIPE_OUT_SIZE_HEIGHT(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_OUT_SIZE_HEIGHT__SHIFT) & MDP5_PIPE_OUT_SIZE_HEIGHT__MASK;
+}
+#define MDP5_PIPE_OUT_SIZE_WIDTH__MASK                         0x0000ffff
+#define MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT                                0
+static inline uint32_t MDP5_PIPE_OUT_SIZE_WIDTH(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_OUT_SIZE_WIDTH__SHIFT) & MDP5_PIPE_OUT_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_OUT_XY(enum mdp5_pipe i0) { return 0x00001210 + 0x400*i0; }
+#define MDP5_PIPE_OUT_XY_Y__MASK                               0xffff0000
+#define MDP5_PIPE_OUT_XY_Y__SHIFT                              16
+static inline uint32_t MDP5_PIPE_OUT_XY_Y(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_OUT_XY_Y__SHIFT) & MDP5_PIPE_OUT_XY_Y__MASK;
+}
+#define MDP5_PIPE_OUT_XY_X__MASK                               0x0000ffff
+#define MDP5_PIPE_OUT_XY_X__SHIFT                              0
+static inline uint32_t MDP5_PIPE_OUT_XY_X(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_OUT_XY_X__SHIFT) & MDP5_PIPE_OUT_XY_X__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC0_ADDR(enum mdp5_pipe i0) { return 0x00001214 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SRC1_ADDR(enum mdp5_pipe i0) { return 0x00001218 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SRC2_ADDR(enum mdp5_pipe i0) { return 0x0000121c + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SRC3_ADDR(enum mdp5_pipe i0) { return 0x00001220 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_A(enum mdp5_pipe i0) { return 0x00001224 + 0x400*i0; }
+#define MDP5_PIPE_SRC_STRIDE_A_P0__MASK                                0x0000ffff
+#define MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT                       0
+static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P0(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_STRIDE_A_P0__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P0__MASK;
+}
+#define MDP5_PIPE_SRC_STRIDE_A_P1__MASK                                0xffff0000
+#define MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT                       16
+static inline uint32_t MDP5_PIPE_SRC_STRIDE_A_P1(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_STRIDE_A_P1__SHIFT) & MDP5_PIPE_SRC_STRIDE_A_P1__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_STRIDE_B(enum mdp5_pipe i0) { return 0x00001228 + 0x400*i0; }
+#define MDP5_PIPE_SRC_STRIDE_B_P2__MASK                                0x0000ffff
+#define MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT                       0
+static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P2(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_STRIDE_B_P2__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P2__MASK;
+}
+#define MDP5_PIPE_SRC_STRIDE_B_P3__MASK                                0xffff0000
+#define MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT                       16
+static inline uint32_t MDP5_PIPE_SRC_STRIDE_B_P3(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_STRIDE_B_P3__SHIFT) & MDP5_PIPE_SRC_STRIDE_B_P3__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_STILE_FRAME_SIZE(enum mdp5_pipe i0) { return 0x0000122c + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SRC_FORMAT(enum mdp5_pipe i0) { return 0x00001230 + 0x400*i0; }
+#define MDP5_PIPE_SRC_FORMAT_G_BPC__MASK                       0x00000003
+#define MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT                      0
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_G_BPC(enum mdp_bpc val)
+{
+       return ((val) << MDP5_PIPE_SRC_FORMAT_G_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_G_BPC__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_B_BPC__MASK                       0x0000000c
+#define MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT                      2
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_B_BPC(enum mdp_bpc val)
+{
+       return ((val) << MDP5_PIPE_SRC_FORMAT_B_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_B_BPC__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_R_BPC__MASK                       0x00000030
+#define MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT                      4
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_R_BPC(enum mdp_bpc val)
+{
+       return ((val) << MDP5_PIPE_SRC_FORMAT_R_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_R_BPC__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_A_BPC__MASK                       0x000000c0
+#define MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT                      6
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_A_BPC(enum mdp_bpc_alpha val)
+{
+       return ((val) << MDP5_PIPE_SRC_FORMAT_A_BPC__SHIFT) & MDP5_PIPE_SRC_FORMAT_A_BPC__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE                      0x00000100
+#define MDP5_PIPE_SRC_FORMAT_CPP__MASK                         0x00000600
+#define MDP5_PIPE_SRC_FORMAT_CPP__SHIFT                                9
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_CPP(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_FORMAT_CPP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CPP__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_ROT90                             0x00000800
+#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK                        0x00003000
+#define MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT               12
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__SHIFT) & MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT                      0x00020000
+#define MDP5_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB                  0x00040000
+#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK                  0x00780000
+#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT                 19
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT) & MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK;
+}
+#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK                 0x01800000
+#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT                        23
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp5_chroma_samp_type val)
+{
+       return ((val) << MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_UNPACK(enum mdp5_pipe i0) { return 0x00001234 + 0x400*i0; }
+#define MDP5_PIPE_SRC_UNPACK_ELEM0__MASK                       0x000000ff
+#define MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT                      0
+static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM0(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM0__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM0__MASK;
+}
+#define MDP5_PIPE_SRC_UNPACK_ELEM1__MASK                       0x0000ff00
+#define MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT                      8
+static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM1(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM1__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM1__MASK;
+}
+#define MDP5_PIPE_SRC_UNPACK_ELEM2__MASK                       0x00ff0000
+#define MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT                      16
+static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM2(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM2__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM2__MASK;
+}
+#define MDP5_PIPE_SRC_UNPACK_ELEM3__MASK                       0xff000000
+#define MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT                      24
+static inline uint32_t MDP5_PIPE_SRC_UNPACK_ELEM3(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_SRC_UNPACK_ELEM3__SHIFT) & MDP5_PIPE_SRC_UNPACK_ELEM3__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SRC_OP_MODE(enum mdp5_pipe i0) { return 0x00001238 + 0x400*i0; }
+#define MDP5_PIPE_SRC_OP_MODE_BWC_EN                           0x00000001
+#define MDP5_PIPE_SRC_OP_MODE_BWC__MASK                                0x00000006
+#define MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT                       1
+static inline uint32_t MDP5_PIPE_SRC_OP_MODE_BWC(enum mdp5_pipe_bwc val)
+{
+       return ((val) << MDP5_PIPE_SRC_OP_MODE_BWC__SHIFT) & MDP5_PIPE_SRC_OP_MODE_BWC__MASK;
+}
+#define MDP5_PIPE_SRC_OP_MODE_FLIP_LR                          0x00002000
+#define MDP5_PIPE_SRC_OP_MODE_FLIP_UD                          0x00004000
+#define MDP5_PIPE_SRC_OP_MODE_IGC_EN                           0x00010000
+#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_0                                0x00020000
+#define MDP5_PIPE_SRC_OP_MODE_IGC_ROM_1                                0x00040000
+#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE                      0x00400000
+#define MDP5_PIPE_SRC_OP_MODE_DEINTERLACE_ODD                  0x00800000
+
+static inline uint32_t REG_MDP5_PIPE_SRC_CONSTANT_COLOR(enum mdp5_pipe i0) { return 0x0000123c + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_FETCH_CONFIG(enum mdp5_pipe i0) { return 0x00001248 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_VC1_RANGE(enum mdp5_pipe i0) { return 0x0000124c + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(enum mdp5_pipe i0) { return 0x00001250 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(enum mdp5_pipe i0) { return 0x00001254 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(enum mdp5_pipe i0) { return 0x00001258 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(enum mdp5_pipe i0) { return 0x00001270 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC0_ADDR(enum mdp5_pipe i0) { return 0x000012a4 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC1_ADDR(enum mdp5_pipe i0) { return 0x000012a8 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC2_ADDR(enum mdp5_pipe i0) { return 0x000012ac + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_CURRENT_SRC3_ADDR(enum mdp5_pipe i0) { return 0x000012b0 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_DECIMATION(enum mdp5_pipe i0) { return 0x000012b4 + 0x400*i0; }
+#define MDP5_PIPE_DECIMATION_VERT__MASK                                0x000000ff
+#define MDP5_PIPE_DECIMATION_VERT__SHIFT                       0
+static inline uint32_t MDP5_PIPE_DECIMATION_VERT(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_DECIMATION_VERT__SHIFT) & MDP5_PIPE_DECIMATION_VERT__MASK;
+}
+#define MDP5_PIPE_DECIMATION_HORZ__MASK                                0x0000ff00
+#define MDP5_PIPE_DECIMATION_HORZ__SHIFT                       8
+static inline uint32_t MDP5_PIPE_DECIMATION_HORZ(uint32_t val)
+{
+       return ((val) << MDP5_PIPE_DECIMATION_HORZ__SHIFT) & MDP5_PIPE_DECIMATION_HORZ__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_CONFIG(enum mdp5_pipe i0) { return 0x00001404 + 0x400*i0; }
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_EN                       0x00000001
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_EN                       0x00000002
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__MASK         0x00000300
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__SHIFT                8
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(enum mdp5_scale_filter val)
+{
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__MASK         0x00000c00
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__SHIFT                10
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(enum mdp5_scale_filter val)
+{
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__MASK          0x00003000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__SHIFT         12
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(enum mdp5_scale_filter val)
+{
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__MASK          0x0000c000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__SHIFT         14
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(enum mdp5_scale_filter val)
+{
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__MASK         0x00030000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__SHIFT                16
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(enum mdp5_scale_filter val)
+{
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER__MASK;
+}
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__MASK         0x000c0000
+#define MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__SHIFT                18
+static inline uint32_t MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(enum mdp5_scale_filter val)
+{
+       return ((val) << MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__SHIFT) & MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00001410 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x00001414 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_X(enum mdp5_pipe i0) { return 0x00001420 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_Y(enum mdp5_pipe i0) { return 0x00001424 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM(uint32_t i0) { return 0x00003200 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_COLOR_OUT(uint32_t i0) { return 0x00003200 + 0x400*i0; }
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA                        0x00000002
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE1_FG_ALPHA                        0x00000004
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE2_FG_ALPHA                        0x00000008
+#define MDP5_LM_BLEND_COLOR_OUT_STAGE3_FG_ALPHA                        0x00000010
+
+static inline uint32_t REG_MDP5_LM_OUT_SIZE(uint32_t i0) { return 0x00003204 + 0x400*i0; }
+#define MDP5_LM_OUT_SIZE_HEIGHT__MASK                          0xffff0000
+#define MDP5_LM_OUT_SIZE_HEIGHT__SHIFT                         16
+static inline uint32_t MDP5_LM_OUT_SIZE_HEIGHT(uint32_t val)
+{
+       return ((val) << MDP5_LM_OUT_SIZE_HEIGHT__SHIFT) & MDP5_LM_OUT_SIZE_HEIGHT__MASK;
+}
+#define MDP5_LM_OUT_SIZE_WIDTH__MASK                           0x0000ffff
+#define MDP5_LM_OUT_SIZE_WIDTH__SHIFT                          0
+static inline uint32_t MDP5_LM_OUT_SIZE_WIDTH(uint32_t val)
+{
+       return ((val) << MDP5_LM_OUT_SIZE_WIDTH__SHIFT) & MDP5_LM_OUT_SIZE_WIDTH__MASK;
+}
+
+static inline uint32_t REG_MDP5_LM_BORDER_COLOR_0(uint32_t i0) { return 0x00003208 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_BORDER_COLOR_1(uint32_t i0) { return 0x00003210 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_BLEND(uint32_t i0, uint32_t i1) { return 0x00003220 + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_OP_MODE(uint32_t i0, uint32_t i1) { return 0x00003220 + 0x400*i0 + 0x30*i1; }
+#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK                   0x00000003
+#define MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT                  0
+static inline uint32_t MDP5_LM_BLEND_OP_MODE_FG_ALPHA(enum mdp_alpha_type val)
+{
+       return ((val) << MDP5_LM_BLEND_OP_MODE_FG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_FG_ALPHA__MASK;
+}
+#define MDP5_LM_BLEND_OP_MODE_FG_INV_ALPHA                     0x00000004
+#define MDP5_LM_BLEND_OP_MODE_FG_MOD_ALPHA                     0x00000008
+#define MDP5_LM_BLEND_OP_MODE_FG_INV_MOD_ALPHA                 0x00000010
+#define MDP5_LM_BLEND_OP_MODE_FG_TRANSP_EN                     0x00000020
+#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK                   0x00000300
+#define MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT                  8
+static inline uint32_t MDP5_LM_BLEND_OP_MODE_BG_ALPHA(enum mdp_alpha_type val)
+{
+       return ((val) << MDP5_LM_BLEND_OP_MODE_BG_ALPHA__SHIFT) & MDP5_LM_BLEND_OP_MODE_BG_ALPHA__MASK;
+}
+#define MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA                     0x00000400
+#define MDP5_LM_BLEND_OP_MODE_BG_MOD_ALPHA                     0x00000800
+#define MDP5_LM_BLEND_OP_MODE_BG_INV_MOD_ALPHA                 0x00001000
+#define MDP5_LM_BLEND_OP_MODE_BG_TRANSP_EN                     0x00002000
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00003224 + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_ALPHA(uint32_t i0, uint32_t i1) { return 0x00003228 + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000322c + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00003230 + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00003234 + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_FG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00003238 + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW0(uint32_t i0, uint32_t i1) { return 0x0000323c + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_LOW1(uint32_t i0, uint32_t i1) { return 0x00003240 + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i1) { return 0x00003244 + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00003248 + 0x400*i0 + 0x30*i1; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_IMG_SIZE(uint32_t i0) { return 0x000032e0 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_SIZE(uint32_t i0) { return 0x000032e4 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_XY(uint32_t i0) { return 0x000032e8 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_STRIDE(uint32_t i0) { return 0x000032dc + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_FORMAT(uint32_t i0) { return 0x000032ec + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BASE_ADDR(uint32_t i0) { return 0x000032f0 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_START_XY(uint32_t i0) { return 0x000032f4 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_CONFIG(uint32_t i0) { return 0x000032f8 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_PARAM(uint32_t i0) { return 0x000032fc + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW0(uint32_t i0) { return 0x00003300 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_LOW1(uint32_t i0) { return 0x00003304 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH0(uint32_t i0) { return 0x00003308 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_TRANSP_HIGH1(uint32_t i0) { return 0x0000330c + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_LM_GC_LUT_BASE(uint32_t i0) { return 0x00003310 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_DSPP(uint32_t i0) { return 0x00004600 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_DSPP_OP_MODE(uint32_t i0) { return 0x00004600 + 0x400*i0; }
+#define MDP5_DSPP_OP_MODE_IGC_LUT_EN                           0x00000001
+#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK                    0x0000000e
+#define MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT                   1
+static inline uint32_t MDP5_DSPP_OP_MODE_IGC_TBL_IDX(uint32_t val)
+{
+       return ((val) << MDP5_DSPP_OP_MODE_IGC_TBL_IDX__SHIFT) & MDP5_DSPP_OP_MODE_IGC_TBL_IDX__MASK;
+}
+#define MDP5_DSPP_OP_MODE_PCC_EN                               0x00000010
+#define MDP5_DSPP_OP_MODE_DITHER_EN                            0x00000100
+#define MDP5_DSPP_OP_MODE_HIST_EN                              0x00010000
+#define MDP5_DSPP_OP_MODE_AUTO_CLEAR                           0x00020000
+#define MDP5_DSPP_OP_MODE_HIST_LUT_EN                          0x00080000
+#define MDP5_DSPP_OP_MODE_PA_EN                                        0x00100000
+#define MDP5_DSPP_OP_MODE_GAMUT_EN                             0x00800000
+#define MDP5_DSPP_OP_MODE_GAMUT_ORDER                          0x01000000
+
+static inline uint32_t REG_MDP5_DSPP_PCC_BASE(uint32_t i0) { return 0x00004630 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_DSPP_DITHER_DEPTH(uint32_t i0) { return 0x00004750 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_DSPP_HIST_CTL_BASE(uint32_t i0) { return 0x00004810 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_DSPP_HIST_LUT_BASE(uint32_t i0) { return 0x00004830 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_DSPP_HIST_LUT_SWAP(uint32_t i0) { return 0x00004834 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_DSPP_PA_BASE(uint32_t i0) { return 0x00004838 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_DSPP_GAMUT_BASE(uint32_t i0) { return 0x000048dc + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_DSPP_GC_BASE(uint32_t i0) { return 0x000048b0 + 0x400*i0; }
+
+static inline uint32_t REG_MDP5_INTF(uint32_t i0) { return 0x00012500 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TIMING_ENGINE_EN(uint32_t i0) { return 0x00012500 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_CONFIG(uint32_t i0) { return 0x00012504 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_HSYNC_CTL(uint32_t i0) { return 0x00012508 + 0x200*i0; }
+#define MDP5_INTF_HSYNC_CTL_PULSEW__MASK                       0x0000ffff
+#define MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT                      0
+static inline uint32_t MDP5_INTF_HSYNC_CTL_PULSEW(uint32_t val)
+{
+       return ((val) << MDP5_INTF_HSYNC_CTL_PULSEW__SHIFT) & MDP5_INTF_HSYNC_CTL_PULSEW__MASK;
+}
+#define MDP5_INTF_HSYNC_CTL_PERIOD__MASK                       0xffff0000
+#define MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT                      16
+static inline uint32_t MDP5_INTF_HSYNC_CTL_PERIOD(uint32_t val)
+{
+       return ((val) << MDP5_INTF_HSYNC_CTL_PERIOD__SHIFT) & MDP5_INTF_HSYNC_CTL_PERIOD__MASK;
+}
+
+static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F0(uint32_t i0) { return 0x0001250c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_VSYNC_PERIOD_F1(uint32_t i0) { return 0x00012510 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F0(uint32_t i0) { return 0x00012514 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_VSYNC_LEN_F1(uint32_t i0) { return 0x00012518 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F0(uint32_t i0) { return 0x0001251c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_VSTART_F1(uint32_t i0) { return 0x00012520 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F0(uint32_t i0) { return 0x00012524 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_VEND_F1(uint32_t i0) { return 0x00012528 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F0(uint32_t i0) { return 0x0001252c + 0x200*i0; }
+#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK                   0x7fffffff
+#define MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT                  0
+static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F0_VAL(uint32_t val)
+{
+       return ((val) << MDP5_INTF_ACTIVE_VSTART_F0_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F0_VAL__MASK;
+}
+#define MDP5_INTF_ACTIVE_VSTART_F0_ACTIVE_V_ENABLE             0x80000000
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_VSTART_F1(uint32_t i0) { return 0x00012530 + 0x200*i0; }
+#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK                   0x7fffffff
+#define MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT                  0
+static inline uint32_t MDP5_INTF_ACTIVE_VSTART_F1_VAL(uint32_t val)
+{
+       return ((val) << MDP5_INTF_ACTIVE_VSTART_F1_VAL__SHIFT) & MDP5_INTF_ACTIVE_VSTART_F1_VAL__MASK;
+}
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F0(uint32_t i0) { return 0x00012534 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_VEND_F1(uint32_t i0) { return 0x00012538 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_DISPLAY_HCTL(uint32_t i0) { return 0x0001253c + 0x200*i0; }
+#define MDP5_INTF_DISPLAY_HCTL_START__MASK                     0x0000ffff
+#define MDP5_INTF_DISPLAY_HCTL_START__SHIFT                    0
+static inline uint32_t MDP5_INTF_DISPLAY_HCTL_START(uint32_t val)
+{
+       return ((val) << MDP5_INTF_DISPLAY_HCTL_START__SHIFT) & MDP5_INTF_DISPLAY_HCTL_START__MASK;
+}
+#define MDP5_INTF_DISPLAY_HCTL_END__MASK                       0xffff0000
+#define MDP5_INTF_DISPLAY_HCTL_END__SHIFT                      16
+static inline uint32_t MDP5_INTF_DISPLAY_HCTL_END(uint32_t val)
+{
+       return ((val) << MDP5_INTF_DISPLAY_HCTL_END__SHIFT) & MDP5_INTF_DISPLAY_HCTL_END__MASK;
+}
+
+static inline uint32_t REG_MDP5_INTF_ACTIVE_HCTL(uint32_t i0) { return 0x00012540 + 0x200*i0; }
+#define MDP5_INTF_ACTIVE_HCTL_START__MASK                      0x00007fff
+#define MDP5_INTF_ACTIVE_HCTL_START__SHIFT                     0
+static inline uint32_t MDP5_INTF_ACTIVE_HCTL_START(uint32_t val)
+{
+       return ((val) << MDP5_INTF_ACTIVE_HCTL_START__SHIFT) & MDP5_INTF_ACTIVE_HCTL_START__MASK;
+}
+#define MDP5_INTF_ACTIVE_HCTL_END__MASK                                0x7fff0000
+#define MDP5_INTF_ACTIVE_HCTL_END__SHIFT                       16
+static inline uint32_t MDP5_INTF_ACTIVE_HCTL_END(uint32_t val)
+{
+       return ((val) << MDP5_INTF_ACTIVE_HCTL_END__SHIFT) & MDP5_INTF_ACTIVE_HCTL_END__MASK;
+}
+#define MDP5_INTF_ACTIVE_HCTL_ACTIVE_H_ENABLE                  0x80000000
+
+static inline uint32_t REG_MDP5_INTF_BORDER_COLOR(uint32_t i0) { return 0x00012544 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_UNDERFLOW_COLOR(uint32_t i0) { return 0x00012548 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_HSYNC_SKEW(uint32_t i0) { return 0x0001254c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_POLARITY_CTL(uint32_t i0) { return 0x00012550 + 0x200*i0; }
+#define MDP5_INTF_POLARITY_CTL_HSYNC_LOW                       0x00000001
+#define MDP5_INTF_POLARITY_CTL_VSYNC_LOW                       0x00000002
+#define MDP5_INTF_POLARITY_CTL_DATA_EN_LOW                     0x00000004
+
+static inline uint32_t REG_MDP5_INTF_TEST_CTL(uint32_t i0) { return 0x00012554 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TP_COLOR0(uint32_t i0) { return 0x00012558 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TP_COLOR1(uint32_t i0) { return 0x0001255c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_DSI_CMD_MODE_TRIGGER_EN(uint32_t i0) { return 0x00012584 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_PANEL_FORMAT(uint32_t i0) { return 0x00012590 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_FRAME_LINE_COUNT_EN(uint32_t i0) { return 0x000125a8 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_FRAME_COUNT(uint32_t i0) { return 0x000125ac + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_LINE_COUNT(uint32_t i0) { return 0x000125b0 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_DEFLICKER_CONFIG(uint32_t i0) { return 0x000125f0 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_DEFLICKER_STRNG_COEFF(uint32_t i0) { return 0x000125f4 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_DEFLICKER_WEAK_COEFF(uint32_t i0) { return 0x000125f8 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TPG_ENABLE(uint32_t i0) { return 0x00012600 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TPG_MAIN_CONTROL(uint32_t i0) { return 0x00012604 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TPG_VIDEO_CONFIG(uint32_t i0) { return 0x00012608 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TPG_COMPONENT_LIMITS(uint32_t i0) { return 0x0001260c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TPG_RECTANGLE(uint32_t i0) { return 0x00012610 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TPG_INITIAL_VALUE(uint32_t i0) { return 0x00012614 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TPG_BLK_WHITE_PATTERN_FRAME(uint32_t i0) { return 0x00012618 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_INTF_TPG_RGB_MAPPING(uint32_t i0) { return 0x0001261c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD(uint32_t i0) { return 0x00013100 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_BYPASS(uint32_t i0) { return 0x00013100 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_CTRL_0(uint32_t i0) { return 0x00013104 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_CTRL_1(uint32_t i0) { return 0x00013108 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_FRAME_SIZE(uint32_t i0) { return 0x0001310c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_CON_CTRL_0(uint32_t i0) { return 0x00013110 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_CON_CTRL_1(uint32_t i0) { return 0x00013114 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_STR_MAN(uint32_t i0) { return 0x00013118 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_VAR(uint32_t i0) { return 0x0001311c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_DITH(uint32_t i0) { return 0x00013120 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_DITH_CTRL(uint32_t i0) { return 0x00013124 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_AMP_LIM(uint32_t i0) { return 0x00013128 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_SLOPE(uint32_t i0) { return 0x0001312c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_BW_LVL(uint32_t i0) { return 0x00013130 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_LOGO_POS(uint32_t i0) { return 0x00013134 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_LUT_FI(uint32_t i0) { return 0x00013138 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_LUT_CC(uint32_t i0) { return 0x0001317c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_STR_LIM(uint32_t i0) { return 0x000131c8 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_CALIB_AB(uint32_t i0) { return 0x000131cc + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_CALIB_CD(uint32_t i0) { return 0x000131d0 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_MODE_SEL(uint32_t i0) { return 0x000131d4 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_TFILT_CTRL(uint32_t i0) { return 0x000131d8 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_BL_MINMAX(uint32_t i0) { return 0x000131dc + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_BL(uint32_t i0) { return 0x000131e0 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_BL_MAX(uint32_t i0) { return 0x000131e8 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_AL(uint32_t i0) { return 0x000131ec + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_AL_MIN(uint32_t i0) { return 0x000131f0 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_AL_FILT(uint32_t i0) { return 0x000131f4 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_CFG_BUF(uint32_t i0) { return 0x000131f8 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_LUT_AL(uint32_t i0) { return 0x00013200 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_TARG_STR(uint32_t i0) { return 0x00013244 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_START_CALC(uint32_t i0) { return 0x00013248 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_STR_OUT(uint32_t i0) { return 0x0001324c + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_BL_OUT(uint32_t i0) { return 0x00013254 + 0x200*i0; }
+
+static inline uint32_t REG_MDP5_AD_CALC_DONE(uint32_t i0) { return 0x00013258 + 0x200*i0; }
+
+
+#endif /* MDP5_XML */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
new file mode 100644 (file)
index 0000000..71a3b23
--- /dev/null
@@ -0,0 +1,569 @@
+/*
+ * Copyright (C) 2013 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 "mdp5_kms.h"
+
+#include <drm/drm_mode.h>
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "drm_flip_work.h"
+
+struct mdp5_crtc {
+       struct drm_crtc base;
+       char name[8];
+       struct drm_plane *plane;
+       struct drm_plane *planes[8];
+       int id;
+       bool enabled;
+
+       /* which mixer/encoder we route output to: */
+       int mixer;
+
+       /* if there is a pending flip, these will be non-null: */
+       struct drm_pending_vblank_event *event;
+       struct msm_fence_cb pageflip_cb;
+
+#define PENDING_CURSOR 0x1
+#define PENDING_FLIP   0x2
+       atomic_t pending;
+
+       /* the fb that we logically (from PoV of KMS API) hold a ref
+        * to.  Which we may not yet be scanning out (we may still
+        * be scanning out previous in case of page_flip while waiting
+        * for gpu rendering to complete:
+        */
+       struct drm_framebuffer *fb;
+
+       /* the fb that we currently hold a scanout ref to: */
+       struct drm_framebuffer *scanout_fb;
+
+       /* for unref'ing framebuffers after scanout completes: */
+       struct drm_flip_work unref_fb_work;
+
+       struct mdp_irq vblank;
+       struct mdp_irq err;
+};
+#define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
+
+static struct mdp5_kms *get_kms(struct drm_crtc *crtc)
+{
+       struct msm_drm_private *priv = crtc->dev->dev_private;
+       return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+static void request_pending(struct drm_crtc *crtc, uint32_t pending)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+
+       atomic_or(pending, &mdp5_crtc->pending);
+       mdp_irq_register(&get_kms(crtc)->base, &mdp5_crtc->vblank);
+}
+
+static void crtc_flush(struct drm_crtc *crtc)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct mdp5_kms *mdp5_kms = get_kms(crtc);
+       int id = mdp5_crtc->id;
+       uint32_t i, flush = 0;
+
+       for (i = 0; i < ARRAY_SIZE(mdp5_crtc->planes); i++) {
+               struct drm_plane *plane = mdp5_crtc->planes[i];
+               if (plane) {
+                       enum mdp5_pipe pipe = mdp5_plane_pipe(plane);
+                       flush |= pipe2flush(pipe);
+               }
+       }
+       flush |= mixer2flush(mdp5_crtc->id);
+       flush |= MDP5_CTL_FLUSH_CTL;
+
+       DBG("%s: flush=%08x", mdp5_crtc->name, flush);
+
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_FLUSH(id), flush);
+}
+
+static void update_fb(struct drm_crtc *crtc, struct drm_framebuffer *new_fb)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct drm_framebuffer *old_fb = mdp5_crtc->fb;
+
+       /* grab reference to incoming scanout fb: */
+       drm_framebuffer_reference(new_fb);
+       mdp5_crtc->base.fb = new_fb;
+       mdp5_crtc->fb = new_fb;
+
+       if (old_fb)
+               drm_flip_work_queue(&mdp5_crtc->unref_fb_work, old_fb);
+}
+
+/* unlike update_fb(), take a ref to the new scanout fb *before* updating
+ * plane, then call this.  Needed to ensure we don't unref the buffer that
+ * is actually still being scanned out.
+ *
+ * Note that this whole thing goes away with atomic.. since we can defer
+ * calling into driver until rendering is done.
+ */
+static void update_scanout(struct drm_crtc *crtc, struct drm_framebuffer *fb)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+
+       /* flush updates, to make sure hw is updated to new scanout fb,
+        * so that we can safely queue unref to current fb (ie. next
+        * vblank we know hw is done w/ previous scanout_fb).
+        */
+       crtc_flush(crtc);
+
+       if (mdp5_crtc->scanout_fb)
+               drm_flip_work_queue(&mdp5_crtc->unref_fb_work,
+                               mdp5_crtc->scanout_fb);
+
+       mdp5_crtc->scanout_fb = fb;
+
+       /* enable vblank to complete flip: */
+       request_pending(crtc, PENDING_FLIP);
+}
+
+/* if file!=NULL, this is preclose potential cancel-flip path */
+static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct drm_pending_vblank_event *event;
+       unsigned long flags, i;
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       event = mdp5_crtc->event;
+       if (event) {
+               /* if regular vblank case (!file) or if cancel-flip from
+                * preclose on file that requested flip, then send the
+                * event:
+                */
+               if (!file || (event->base.file_priv == file)) {
+                       mdp5_crtc->event = NULL;
+                       drm_send_vblank_event(dev, mdp5_crtc->id, event);
+               }
+       }
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       for (i = 0; i < ARRAY_SIZE(mdp5_crtc->planes); i++) {
+               struct drm_plane *plane = mdp5_crtc->planes[i];
+               if (plane)
+                       mdp5_plane_complete_flip(plane);
+       }
+}
+
+static void pageflip_cb(struct msm_fence_cb *cb)
+{
+       struct mdp5_crtc *mdp5_crtc =
+               container_of(cb, struct mdp5_crtc, pageflip_cb);
+       struct drm_crtc *crtc = &mdp5_crtc->base;
+       struct drm_framebuffer *fb = mdp5_crtc->fb;
+
+       if (!fb)
+               return;
+
+       drm_framebuffer_reference(fb);
+       mdp5_plane_set_scanout(mdp5_crtc->plane, fb);
+       update_scanout(crtc, fb);
+}
+
+static void unref_fb_worker(struct drm_flip_work *work, void *val)
+{
+       struct mdp5_crtc *mdp5_crtc =
+               container_of(work, struct mdp5_crtc, unref_fb_work);
+       struct drm_device *dev = mdp5_crtc->base.dev;
+
+       mutex_lock(&dev->mode_config.mutex);
+       drm_framebuffer_unreference(val);
+       mutex_unlock(&dev->mode_config.mutex);
+}
+
+static void mdp5_crtc_destroy(struct drm_crtc *crtc)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+
+       mdp5_crtc->plane->funcs->destroy(mdp5_crtc->plane);
+
+       drm_crtc_cleanup(crtc);
+       drm_flip_work_cleanup(&mdp5_crtc->unref_fb_work);
+
+       kfree(mdp5_crtc);
+}
+
+static void mdp5_crtc_dpms(struct drm_crtc *crtc, int mode)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct mdp5_kms *mdp5_kms = get_kms(crtc);
+       bool enabled = (mode == DRM_MODE_DPMS_ON);
+
+       DBG("%s: mode=%d", mdp5_crtc->name, mode);
+
+       if (enabled != mdp5_crtc->enabled) {
+               if (enabled) {
+                       mdp5_enable(mdp5_kms);
+                       mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
+               } else {
+                       mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
+                       mdp5_disable(mdp5_kms);
+               }
+               mdp5_crtc->enabled = enabled;
+       }
+}
+
+static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc,
+               const struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void blend_setup(struct drm_crtc *crtc)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct mdp5_kms *mdp5_kms = get_kms(crtc);
+       int id = mdp5_crtc->id;
+
+       /*
+        * Hard-coded setup for now until I figure out how the
+        * layer-mixer works
+        */
+
+       /* LM[id]: */
+       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_COLOR_OUT(id),
+                       MDP5_LM_BLEND_COLOR_OUT_STAGE0_FG_ALPHA);
+       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_OP_MODE(id, 0),
+                       MDP5_LM_BLEND_OP_MODE_FG_ALPHA(FG_CONST) |
+                       MDP5_LM_BLEND_OP_MODE_BG_ALPHA(FG_PIXEL) |
+                       MDP5_LM_BLEND_OP_MODE_BG_INV_ALPHA);
+       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_FG_ALPHA(id, 0), 0xff);
+       mdp5_write(mdp5_kms, REG_MDP5_LM_BLEND_BG_ALPHA(id, 0), 0x00);
+
+       /* NOTE: seems that LM[n] and CTL[m], we do not need n==m.. but
+        * we want to be setting CTL[m].LAYER[n].  Not sure what the
+        * point of having CTL[m].LAYER[o] (for o!=n).. maybe that is
+        * used when chaining up mixers for high resolution displays?
+        */
+
+       /* CTL[id]: */
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 0),
+                       MDP5_CTL_LAYER_REG_RGB0(STAGE0) |
+                       MDP5_CTL_LAYER_REG_BORDER_COLOR);
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 1), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 2), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 3), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_LAYER_REG(id, 4), 0);
+}
+
+static int mdp5_crtc_mode_set(struct drm_crtc *crtc,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode,
+               int x, int y,
+               struct drm_framebuffer *old_fb)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct mdp5_kms *mdp5_kms = get_kms(crtc);
+       int ret;
+
+       mode = adjusted_mode;
+
+       DBG("%s: set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+                       mdp5_crtc->name, 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);
+
+       /* grab extra ref for update_scanout() */
+       drm_framebuffer_reference(crtc->fb);
+
+       ret = mdp5_plane_mode_set(mdp5_crtc->plane, crtc, crtc->fb,
+                       0, 0, mode->hdisplay, mode->vdisplay,
+                       x << 16, y << 16,
+                       mode->hdisplay << 16, mode->vdisplay << 16);
+       if (ret) {
+               dev_err(crtc->dev->dev, "%s: failed to set mode on plane: %d\n",
+                               mdp5_crtc->name, ret);
+               return ret;
+       }
+
+       mdp5_write(mdp5_kms, REG_MDP5_LM_OUT_SIZE(mdp5_crtc->id),
+                       MDP5_LM_OUT_SIZE_WIDTH(mode->hdisplay) |
+                       MDP5_LM_OUT_SIZE_HEIGHT(mode->vdisplay));
+
+       update_fb(crtc, crtc->fb);
+       update_scanout(crtc, crtc->fb);
+
+       return 0;
+}
+
+static void mdp5_crtc_prepare(struct drm_crtc *crtc)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       DBG("%s", mdp5_crtc->name);
+       /* make sure we hold a ref to mdp clks while setting up mode: */
+       mdp5_enable(get_kms(crtc));
+       mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void mdp5_crtc_commit(struct drm_crtc *crtc)
+{
+       mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+       crtc_flush(crtc);
+       /* drop the ref to mdp clk's that we got in prepare: */
+       mdp5_disable(get_kms(crtc));
+}
+
+static int mdp5_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
+               struct drm_framebuffer *old_fb)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct drm_plane *plane = mdp5_crtc->plane;
+       struct drm_display_mode *mode = &crtc->mode;
+       int ret;
+
+       /* grab extra ref for update_scanout() */
+       drm_framebuffer_reference(crtc->fb);
+
+       ret = mdp5_plane_mode_set(plane, crtc, crtc->fb,
+                       0, 0, mode->hdisplay, mode->vdisplay,
+                       x << 16, y << 16,
+                       mode->hdisplay << 16, mode->vdisplay << 16);
+
+       update_fb(crtc, crtc->fb);
+       update_scanout(crtc, crtc->fb);
+
+       return ret;
+}
+
+static void mdp5_crtc_load_lut(struct drm_crtc *crtc)
+{
+}
+
+static int mdp5_crtc_page_flip(struct drm_crtc *crtc,
+               struct drm_framebuffer *new_fb,
+               struct drm_pending_vblank_event *event,
+               uint32_t page_flip_flags)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct drm_device *dev = crtc->dev;
+       struct drm_gem_object *obj;
+       unsigned long flags;
+
+       if (mdp5_crtc->event) {
+               dev_err(dev->dev, "already pending flip!\n");
+               return -EBUSY;
+       }
+
+       obj = msm_framebuffer_bo(new_fb, 0);
+
+       spin_lock_irqsave(&dev->event_lock, flags);
+       mdp5_crtc->event = event;
+       spin_unlock_irqrestore(&dev->event_lock, flags);
+
+       update_fb(crtc, new_fb);
+
+       return msm_gem_queue_inactive_cb(obj, &mdp5_crtc->pageflip_cb);
+}
+
+static int mdp5_crtc_set_property(struct drm_crtc *crtc,
+               struct drm_property *property, uint64_t val)
+{
+       // XXX
+       return -EINVAL;
+}
+
+static const struct drm_crtc_funcs mdp5_crtc_funcs = {
+       .set_config = drm_crtc_helper_set_config,
+       .destroy = mdp5_crtc_destroy,
+       .page_flip = mdp5_crtc_page_flip,
+       .set_property = mdp5_crtc_set_property,
+};
+
+static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
+       .dpms = mdp5_crtc_dpms,
+       .mode_fixup = mdp5_crtc_mode_fixup,
+       .mode_set = mdp5_crtc_mode_set,
+       .prepare = mdp5_crtc_prepare,
+       .commit = mdp5_crtc_commit,
+       .mode_set_base = mdp5_crtc_mode_set_base,
+       .load_lut = mdp5_crtc_load_lut,
+};
+
+static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
+{
+       struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank);
+       struct drm_crtc *crtc = &mdp5_crtc->base;
+       struct msm_drm_private *priv = crtc->dev->dev_private;
+       unsigned pending;
+
+       mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank);
+
+       pending = atomic_xchg(&mdp5_crtc->pending, 0);
+
+       if (pending & PENDING_FLIP) {
+               complete_flip(crtc, NULL);
+               drm_flip_work_commit(&mdp5_crtc->unref_fb_work, priv->wq);
+       }
+}
+
+static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
+{
+       struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, err);
+       struct drm_crtc *crtc = &mdp5_crtc->base;
+       DBG("%s: error: %08x", mdp5_crtc->name, irqstatus);
+       crtc_flush(crtc);
+}
+
+uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       return mdp5_crtc->vblank.irqmask;
+}
+
+void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file)
+{
+       DBG("cancel: %p", file);
+       complete_flip(crtc, file);
+}
+
+/* set interface for routing crtc->encoder: */
+void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
+               enum mdp5_intf intf_id)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+       struct mdp5_kms *mdp5_kms = get_kms(crtc);
+       static const enum mdp5_intfnum intfnum[] = {
+                       INTF0, INTF1, INTF2, INTF3,
+       };
+       uint32_t intf_sel;
+
+       /* now that we know what irq's we want: */
+       mdp5_crtc->err.irqmask = intf2err(intf);
+       mdp5_crtc->vblank.irqmask = intf2vblank(intf);
+
+       /* when called from modeset_init(), skip the rest until later: */
+       if (!mdp5_kms)
+               return;
+
+       intf_sel = mdp5_read(mdp5_kms, REG_MDP5_DISP_INTF_SEL);
+
+       switch (intf) {
+       case 0:
+               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF0__MASK;
+               intf_sel |= MDP5_DISP_INTF_SEL_INTF0(intf_id);
+               break;
+       case 1:
+               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF1__MASK;
+               intf_sel |= MDP5_DISP_INTF_SEL_INTF1(intf_id);
+               break;
+       case 2:
+               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF2__MASK;
+               intf_sel |= MDP5_DISP_INTF_SEL_INTF2(intf_id);
+               break;
+       case 3:
+               intf_sel &= ~MDP5_DISP_INTF_SEL_INTF3__MASK;
+               intf_sel |= MDP5_DISP_INTF_SEL_INTF3(intf_id);
+               break;
+       default:
+               BUG();
+               break;
+       }
+
+       blend_setup(crtc);
+
+       DBG("%s: intf_sel=%08x", mdp5_crtc->name, intf_sel);
+
+       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, intf_sel);
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(mdp5_crtc->id),
+                       MDP5_CTL_OP_MODE(MODE_NONE) |
+                       MDP5_CTL_OP_INTF_NUM(intfnum[intf]));
+
+       crtc_flush(crtc);
+}
+
+static void set_attach(struct drm_crtc *crtc, enum mdp5_pipe pipe_id,
+               struct drm_plane *plane)
+{
+       struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+
+       BUG_ON(pipe_id >= ARRAY_SIZE(mdp5_crtc->planes));
+
+       if (mdp5_crtc->planes[pipe_id] == plane)
+               return;
+
+       mdp5_crtc->planes[pipe_id] = plane;
+       blend_setup(crtc);
+       if (mdp5_crtc->enabled && (plane != mdp5_crtc->plane))
+               crtc_flush(crtc);
+}
+
+void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+       set_attach(crtc, mdp5_plane_pipe(plane), plane);
+}
+
+void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane)
+{
+       set_attach(crtc, mdp5_plane_pipe(plane), NULL);
+}
+
+/* initialize crtc */
+struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
+               struct drm_plane *plane, int id)
+{
+       struct drm_crtc *crtc = NULL;
+       struct mdp5_crtc *mdp5_crtc;
+       int ret;
+
+       mdp5_crtc = kzalloc(sizeof(*mdp5_crtc), GFP_KERNEL);
+       if (!mdp5_crtc) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       crtc = &mdp5_crtc->base;
+
+       mdp5_crtc->plane = plane;
+       mdp5_crtc->id = id;
+
+       mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq;
+       mdp5_crtc->err.irq = mdp5_crtc_err_irq;
+
+       snprintf(mdp5_crtc->name, sizeof(mdp5_crtc->name), "%s:%d",
+                       pipe2name(mdp5_plane_pipe(plane)), id);
+
+       ret = drm_flip_work_init(&mdp5_crtc->unref_fb_work, 16,
+                       "unref fb", unref_fb_worker);
+       if (ret)
+               goto fail;
+
+       INIT_FENCE_CB(&mdp5_crtc->pageflip_cb, pageflip_cb);
+
+       drm_crtc_init(dev, crtc, &mdp5_crtc_funcs);
+       drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
+
+       mdp5_plane_install_properties(mdp5_crtc->plane, &crtc->base);
+
+       return crtc;
+
+fail:
+       if (crtc)
+               mdp5_crtc_destroy(crtc);
+
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
new file mode 100644 (file)
index 0000000..edec7bf
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2013 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 "mdp5_kms.h"
+
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+
+struct mdp5_encoder {
+       struct drm_encoder base;
+       int intf;
+       enum mdp5_intf intf_id;
+       bool enabled;
+       uint32_t bsc;
+};
+#define to_mdp5_encoder(x) container_of(x, struct mdp5_encoder, base)
+
+static struct mdp5_kms *get_kms(struct drm_encoder *encoder)
+{
+       struct msm_drm_private *priv = encoder->dev->dev_private;
+       return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+#ifdef CONFIG_MSM_BUS_SCALING
+#include <mach/board.h>
+#include <mach/msm_bus.h>
+#include <mach/msm_bus_board.h>
+#define MDP_BUS_VECTOR_ENTRY(ab_val, ib_val)           \
+       {                                               \
+               .src = MSM_BUS_MASTER_MDP_PORT0,        \
+               .dst = MSM_BUS_SLAVE_EBI_CH0,           \
+               .ab = (ab_val),                         \
+               .ib = (ib_val),                         \
+       }
+
+static struct msm_bus_vectors mdp_bus_vectors[] = {
+       MDP_BUS_VECTOR_ENTRY(0, 0),
+       MDP_BUS_VECTOR_ENTRY(2000000000, 2000000000),
+};
+static struct msm_bus_paths mdp_bus_usecases[] = { {
+               .num_paths = 1,
+               .vectors = &mdp_bus_vectors[0],
+}, {
+               .num_paths = 1,
+               .vectors = &mdp_bus_vectors[1],
+} };
+static struct msm_bus_scale_pdata mdp_bus_scale_table = {
+       .usecase = mdp_bus_usecases,
+       .num_usecases = ARRAY_SIZE(mdp_bus_usecases),
+       .name = "mdss_mdp",
+};
+
+static void bs_init(struct mdp5_encoder *mdp5_encoder)
+{
+       mdp5_encoder->bsc = msm_bus_scale_register_client(
+                       &mdp_bus_scale_table);
+       DBG("bus scale client: %08x", mdp5_encoder->bsc);
+}
+
+static void bs_fini(struct mdp5_encoder *mdp5_encoder)
+{
+       if (mdp5_encoder->bsc) {
+               msm_bus_scale_unregister_client(mdp5_encoder->bsc);
+               mdp5_encoder->bsc = 0;
+       }
+}
+
+static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx)
+{
+       if (mdp5_encoder->bsc) {
+               DBG("set bus scaling: %d", idx);
+               /* HACK: scaling down, and then immediately back up
+                * seems to leave things broken (underflow).. so
+                * never disable:
+                */
+               idx = 1;
+               msm_bus_scale_client_update_request(mdp5_encoder->bsc, idx);
+       }
+}
+#else
+static void bs_init(struct mdp5_encoder *mdp5_encoder) {}
+static void bs_fini(struct mdp5_encoder *mdp5_encoder) {}
+static void bs_set(struct mdp5_encoder *mdp5_encoder, int idx) {}
+#endif
+
+static void mdp5_encoder_destroy(struct drm_encoder *encoder)
+{
+       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+       bs_fini(mdp5_encoder);
+       drm_encoder_cleanup(encoder);
+       kfree(mdp5_encoder);
+}
+
+static const struct drm_encoder_funcs mdp5_encoder_funcs = {
+       .destroy = mdp5_encoder_destroy,
+};
+
+static void mdp5_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       int intf = mdp5_encoder->intf;
+       bool enabled = (mode == DRM_MODE_DPMS_ON);
+
+       DBG("mode=%d", mode);
+
+       if (enabled == mdp5_encoder->enabled)
+               return;
+
+       if (enabled) {
+               bs_set(mdp5_encoder, 1);
+               mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
+       } else {
+               mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
+               bs_set(mdp5_encoder, 0);
+       }
+
+       mdp5_encoder->enabled = enabled;
+}
+
+static bool mdp5_encoder_mode_fixup(struct drm_encoder *encoder,
+               const struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       return true;
+}
+
+static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
+               struct drm_display_mode *mode,
+               struct drm_display_mode *adjusted_mode)
+{
+       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+       struct mdp5_kms *mdp5_kms = get_kms(encoder);
+       int intf = mdp5_encoder->intf;
+       uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
+       uint32_t display_v_start, display_v_end;
+       uint32_t hsync_start_x, hsync_end_x;
+       uint32_t format;
+
+       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);
+
+       ctrl_pol = 0;
+       if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+               ctrl_pol |= MDP5_INTF_POLARITY_CTL_HSYNC_LOW;
+       if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+               ctrl_pol |= MDP5_INTF_POLARITY_CTL_VSYNC_LOW;
+       /* probably need to get DATA_EN polarity from panel.. */
+
+       dtv_hsync_skew = 0;  /* get this from panel? */
+       format = 0x213f;     /* 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 + dtv_hsync_skew;
+       display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1;
+
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_CTL(intf),
+                       MDP5_INTF_HSYNC_CTL_PULSEW(mode->hsync_end - mode->hsync_start) |
+                       MDP5_INTF_HSYNC_CTL_PERIOD(mode->htotal));
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_PERIOD_F0(intf), vsync_period);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_VSYNC_LEN_F0(intf), vsync_len);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_HCTL(intf),
+                       MDP5_INTF_DISPLAY_HCTL_START(hsync_start_x) |
+                       MDP5_INTF_DISPLAY_HCTL_END(hsync_end_x));
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VSTART_F0(intf), display_v_start);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_DISPLAY_VEND_F0(intf), display_v_end);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_BORDER_COLOR(intf), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_UNDERFLOW_COLOR(intf), 0xff);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_SKEW(intf), dtv_hsync_skew);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_POLARITY_CTL(intf), ctrl_pol);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_HCTL(intf),
+                       MDP5_INTF_ACTIVE_HCTL_START(0) |
+                       MDP5_INTF_ACTIVE_HCTL_END(0));
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VSTART_F0(intf), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_ACTIVE_VEND_F0(intf), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_PANEL_FORMAT(intf), format);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_FRAME_LINE_COUNT_EN(intf), 0x3);  /* frame+line? */
+}
+
+static void mdp5_encoder_prepare(struct drm_encoder *encoder)
+{
+       mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void mdp5_encoder_commit(struct drm_encoder *encoder)
+{
+       struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+       mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf,
+                       mdp5_encoder->intf_id);
+       mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
+       .dpms = mdp5_encoder_dpms,
+       .mode_fixup = mdp5_encoder_mode_fixup,
+       .mode_set = mdp5_encoder_mode_set,
+       .prepare = mdp5_encoder_prepare,
+       .commit = mdp5_encoder_commit,
+};
+
+/* initialize encoder */
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
+               enum mdp5_intf intf_id)
+{
+       struct drm_encoder *encoder = NULL;
+       struct mdp5_encoder *mdp5_encoder;
+       int ret;
+
+       mdp5_encoder = kzalloc(sizeof(*mdp5_encoder), GFP_KERNEL);
+       if (!mdp5_encoder) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       mdp5_encoder->intf = intf;
+       mdp5_encoder->intf_id = intf_id;
+       encoder = &mdp5_encoder->base;
+
+       drm_encoder_init(dev, encoder, &mdp5_encoder_funcs,
+                        DRM_MODE_ENCODER_TMDS);
+       drm_encoder_helper_add(encoder, &mdp5_encoder_helper_funcs);
+
+       bs_init(mdp5_encoder);
+
+       return encoder;
+
+fail:
+       if (encoder)
+               mdp5_encoder_destroy(encoder);
+
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_irq.c
new file mode 100644 (file)
index 0000000..353d494
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2013 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 "msm_drv.h"
+#include "mdp5_kms.h"
+
+void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask)
+{
+       mdp5_write(to_mdp5_kms(mdp_kms), REG_MDP5_INTR_EN, irqmask);
+}
+
+static void mdp5_irq_error_handler(struct mdp_irq *irq, uint32_t irqstatus)
+{
+       DRM_ERROR("errors: %08x\n", irqstatus);
+}
+
+void mdp5_irq_preinstall(struct msm_kms *kms)
+{
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, 0xffffffff);
+}
+
+int mdp5_irq_postinstall(struct msm_kms *kms)
+{
+       struct mdp_kms *mdp_kms = to_mdp_kms(kms);
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
+       struct mdp_irq *error_handler = &mdp5_kms->error_handler;
+
+       error_handler->irq = mdp5_irq_error_handler;
+       error_handler->irqmask = MDP5_IRQ_INTF0_UNDER_RUN |
+                       MDP5_IRQ_INTF1_UNDER_RUN |
+                       MDP5_IRQ_INTF2_UNDER_RUN |
+                       MDP5_IRQ_INTF3_UNDER_RUN;
+
+       mdp_irq_register(mdp_kms, error_handler);
+
+       return 0;
+}
+
+void mdp5_irq_uninstall(struct msm_kms *kms)
+{
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       mdp5_write(mdp5_kms, REG_MDP5_INTR_EN, 0x00000000);
+}
+
+static void mdp5_irq_mdp(struct mdp_kms *mdp_kms)
+{
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
+       struct drm_device *dev = mdp5_kms->dev;
+       struct msm_drm_private *priv = dev->dev_private;
+       unsigned int id;
+       uint32_t status;
+
+       status = mdp5_read(mdp5_kms, REG_MDP5_INTR_STATUS);
+       mdp5_write(mdp5_kms, REG_MDP5_INTR_CLEAR, status);
+
+       VERB("status=%08x", status);
+
+       for (id = 0; id < priv->num_crtcs; id++)
+               if (status & mdp5_crtc_vblank(priv->crtcs[id]))
+                       drm_handle_vblank(dev, id);
+
+       mdp_dispatch_irqs(mdp_kms, status);
+}
+
+irqreturn_t mdp5_irq(struct msm_kms *kms)
+{
+       struct mdp_kms *mdp_kms = to_mdp_kms(kms);
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(mdp_kms);
+       uint32_t intr;
+
+       intr = mdp5_read(mdp5_kms, REG_MDP5_HW_INTR_STATUS);
+
+       VERB("intr=%08x", intr);
+
+       if (intr & MDP5_HW_INTR_STATUS_INTR_MDP)
+               mdp5_irq_mdp(mdp_kms);
+
+       if (intr & MDP5_HW_INTR_STATUS_INTR_HDMI)
+               hdmi_irq(0, mdp5_kms->hdmi);
+
+       return IRQ_HANDLED;
+}
+
+int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+       mdp_update_vblank_mask(to_mdp_kms(kms),
+                       mdp5_crtc_vblank(crtc), true);
+       return 0;
+}
+
+void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
+{
+       mdp_update_vblank_mask(to_mdp_kms(kms),
+                       mdp5_crtc_vblank(crtc), false);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
new file mode 100644 (file)
index 0000000..ee8446c
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2013 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 "msm_drv.h"
+#include "msm_mmu.h"
+#include "mdp5_kms.h"
+
+static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev);
+
+static int mdp5_hw_init(struct msm_kms *kms)
+{
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       struct drm_device *dev = mdp5_kms->dev;
+       uint32_t version, major, minor;
+       int ret = 0;
+
+       pm_runtime_get_sync(dev->dev);
+
+       mdp5_enable(mdp5_kms);
+       version = mdp5_read(mdp5_kms, REG_MDP5_MDP_VERSION);
+       mdp5_disable(mdp5_kms);
+
+       major = FIELD(version, MDP5_MDP_VERSION_MAJOR);
+       minor = FIELD(version, MDP5_MDP_VERSION_MINOR);
+
+       DBG("found MDP5 version v%d.%d", major, minor);
+
+       if ((major != 1) || ((minor != 0) && (minor != 2))) {
+               dev_err(dev->dev, "unexpected MDP version: v%d.%d\n",
+                               major, minor);
+               ret = -ENXIO;
+               goto out;
+       }
+
+       mdp5_kms->rev = minor;
+
+       /* Magic unknown register writes:
+        *
+        *    W VBIF:0x004 00000001      (mdss_mdp.c:839)
+        *    W MDP5:0x2e0 0xe9          (mdss_mdp.c:839)
+        *    W MDP5:0x2e4 0x55          (mdss_mdp.c:839)
+        *    W MDP5:0x3ac 0xc0000ccc    (mdss_mdp.c:839)
+        *    W MDP5:0x3b4 0xc0000ccc    (mdss_mdp.c:839)
+        *    W MDP5:0x3bc 0xcccccc      (mdss_mdp.c:839)
+        *    W MDP5:0x4a8 0xcccc0c0     (mdss_mdp.c:839)
+        *    W MDP5:0x4b0 0xccccc0c0    (mdss_mdp.c:839)
+        *    W MDP5:0x4b8 0xccccc000    (mdss_mdp.c:839)
+        *
+        * Downstream fbdev driver gets these register offsets/values
+        * from DT.. not really sure what these registers are or if
+        * different values for different boards/SoC's, etc.  I guess
+        * they are the golden registers.
+        *
+        * Not setting these does not seem to cause any problem.  But
+        * we may be getting lucky with the bootloader initializing
+        * them for us.  OTOH, if we can always count on the bootloader
+        * setting the golden registers, then perhaps we don't need to
+        * care.
+        */
+
+       mdp5_write(mdp5_kms, REG_MDP5_DISP_INTF_SEL, 0);
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(0), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(1), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(2), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_CTL_OP(3), 0);
+
+out:
+       pm_runtime_put_sync(dev->dev);
+
+       return ret;
+}
+
+static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
+               struct drm_encoder *encoder)
+{
+       return rate;
+}
+
+static void mdp5_preclose(struct msm_kms *kms, struct drm_file *file)
+{
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       struct msm_drm_private *priv = mdp5_kms->dev->dev_private;
+       unsigned i;
+
+       for (i = 0; i < priv->num_crtcs; i++)
+               mdp5_crtc_cancel_pending_flip(priv->crtcs[i], file);
+}
+
+static void mdp5_destroy(struct msm_kms *kms)
+{
+       struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+       kfree(mdp5_kms);
+}
+
+static const struct mdp_kms_funcs kms_funcs = {
+       .base = {
+               .hw_init         = mdp5_hw_init,
+               .irq_preinstall  = mdp5_irq_preinstall,
+               .irq_postinstall = mdp5_irq_postinstall,
+               .irq_uninstall   = mdp5_irq_uninstall,
+               .irq             = mdp5_irq,
+               .enable_vblank   = mdp5_enable_vblank,
+               .disable_vblank  = mdp5_disable_vblank,
+               .get_format      = mdp_get_format,
+               .round_pixclk    = mdp5_round_pixclk,
+               .preclose        = mdp5_preclose,
+               .destroy         = mdp5_destroy,
+       },
+       .set_irqmask         = mdp5_set_irqmask,
+};
+
+int mdp5_disable(struct mdp5_kms *mdp5_kms)
+{
+       DBG("");
+
+       clk_disable_unprepare(mdp5_kms->ahb_clk);
+       clk_disable_unprepare(mdp5_kms->axi_clk);
+       clk_disable_unprepare(mdp5_kms->core_clk);
+       clk_disable_unprepare(mdp5_kms->lut_clk);
+
+       return 0;
+}
+
+int mdp5_enable(struct mdp5_kms *mdp5_kms)
+{
+       DBG("");
+
+       clk_prepare_enable(mdp5_kms->ahb_clk);
+       clk_prepare_enable(mdp5_kms->axi_clk);
+       clk_prepare_enable(mdp5_kms->core_clk);
+       clk_prepare_enable(mdp5_kms->lut_clk);
+
+       return 0;
+}
+
+static int modeset_init(struct mdp5_kms *mdp5_kms)
+{
+       static const enum mdp5_pipe crtcs[] = {
+                       SSPP_RGB0, SSPP_RGB1, SSPP_RGB2,
+       };
+       struct drm_device *dev = mdp5_kms->dev;
+       struct msm_drm_private *priv = dev->dev_private;
+       struct drm_encoder *encoder;
+       int i, ret;
+
+       /* construct CRTCs: */
+       for (i = 0; i < ARRAY_SIZE(crtcs); i++) {
+               struct drm_plane *plane;
+               struct drm_crtc *crtc;
+
+               plane = mdp5_plane_init(dev, crtcs[i], true);
+               if (IS_ERR(plane)) {
+                       ret = PTR_ERR(plane);
+                       dev_err(dev->dev, "failed to construct plane for %s (%d)\n",
+                                       pipe2name(crtcs[i]), ret);
+                       goto fail;
+               }
+
+               crtc  = mdp5_crtc_init(dev, plane, i);
+               if (IS_ERR(crtc)) {
+                       ret = PTR_ERR(crtc);
+                       dev_err(dev->dev, "failed to construct crtc for %s (%d)\n",
+                                       pipe2name(crtcs[i]), ret);
+                       goto fail;
+               }
+               priv->crtcs[priv->num_crtcs++] = crtc;
+       }
+
+       /* Construct encoder for HDMI: */
+       encoder = mdp5_encoder_init(dev, 3, INTF_HDMI);
+       if (IS_ERR(encoder)) {
+               dev_err(dev->dev, "failed to construct encoder\n");
+               ret = PTR_ERR(encoder);
+               goto fail;
+       }
+
+       /* NOTE: the vsync and error irq's are actually associated with
+        * the INTF/encoder.. the easiest way to deal with this (ie. what
+        * we do now) is assume a fixed relationship between crtc's and
+        * encoders.  I'm not sure if there is ever a need to more freely
+        * assign crtcs to encoders, but if there is then we need to take
+        * care of error and vblank irq's that the crtc has registered,
+        * and also update user-requested vblank_mask.
+        */
+       encoder->possible_crtcs = BIT(0);
+       mdp5_crtc_set_intf(priv->crtcs[0], 3, INTF_HDMI);
+
+       priv->encoders[priv->num_encoders++] = encoder;
+
+       /* Construct bridge/connector for HDMI: */
+       mdp5_kms->hdmi = hdmi_init(dev, encoder);
+       if (IS_ERR(mdp5_kms->hdmi)) {
+               ret = PTR_ERR(mdp5_kms->hdmi);
+               dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
+               goto fail;
+       }
+
+       return 0;
+
+fail:
+       return ret;
+}
+
+static const char *iommu_ports[] = {
+               "mdp_0",
+};
+
+static int get_clk(struct platform_device *pdev, struct clk **clkp,
+               const char *name)
+{
+       struct device *dev = &pdev->dev;
+       struct clk *clk = devm_clk_get(dev, name);
+       if (IS_ERR(clk)) {
+               dev_err(dev, "failed to get %s (%ld)\n", name, PTR_ERR(clk));
+               return PTR_ERR(clk);
+       }
+       *clkp = clk;
+       return 0;
+}
+
+struct msm_kms *mdp5_kms_init(struct drm_device *dev)
+{
+       struct platform_device *pdev = dev->platformdev;
+       struct mdp5_platform_config *config = mdp5_get_config(pdev);
+       struct mdp5_kms *mdp5_kms;
+       struct msm_kms *kms = NULL;
+       struct msm_mmu *mmu;
+       int ret;
+
+       mdp5_kms = kzalloc(sizeof(*mdp5_kms), GFP_KERNEL);
+       if (!mdp5_kms) {
+               dev_err(dev->dev, "failed to allocate kms\n");
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       mdp_kms_init(&mdp5_kms->base, &kms_funcs);
+
+       kms = &mdp5_kms->base.base;
+
+       mdp5_kms->dev = dev;
+       mdp5_kms->smp_blk_cnt = config->smp_blk_cnt;
+
+       mdp5_kms->mmio = msm_ioremap(pdev, "mdp_phys", "MDP5");
+       if (IS_ERR(mdp5_kms->mmio)) {
+               ret = PTR_ERR(mdp5_kms->mmio);
+               goto fail;
+       }
+
+       mdp5_kms->vbif = msm_ioremap(pdev, "vbif_phys", "VBIF");
+       if (IS_ERR(mdp5_kms->vbif)) {
+               ret = PTR_ERR(mdp5_kms->vbif);
+               goto fail;
+       }
+
+       mdp5_kms->vdd = devm_regulator_get(&pdev->dev, "vdd");
+       if (IS_ERR(mdp5_kms->vdd)) {
+               ret = PTR_ERR(mdp5_kms->vdd);
+               goto fail;
+       }
+
+       ret = regulator_enable(mdp5_kms->vdd);
+       if (ret) {
+               dev_err(dev->dev, "failed to enable regulator vdd: %d\n", ret);
+               goto fail;
+       }
+
+       ret = get_clk(pdev, &mdp5_kms->axi_clk, "bus_clk") ||
+                       get_clk(pdev, &mdp5_kms->ahb_clk, "iface_clk") ||
+                       get_clk(pdev, &mdp5_kms->src_clk, "core_clk_src") ||
+                       get_clk(pdev, &mdp5_kms->core_clk, "core_clk") ||
+                       get_clk(pdev, &mdp5_kms->lut_clk, "lut_clk") ||
+                       get_clk(pdev, &mdp5_kms->vsync_clk, "vsync_clk");
+       if (ret)
+               goto fail;
+
+       ret = clk_set_rate(mdp5_kms->src_clk, config->max_clk);
+
+       /* make sure things are off before attaching iommu (bootloader could
+        * have left things on, in which case we'll start getting faults if
+        * we don't disable):
+        */
+       mdp5_enable(mdp5_kms);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(0), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(1), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(2), 0);
+       mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(3), 0);
+       mdp5_disable(mdp5_kms);
+       mdelay(16);
+
+       if (config->iommu) {
+               mmu = msm_iommu_new(dev, config->iommu);
+               if (IS_ERR(mmu)) {
+                       ret = PTR_ERR(mmu);
+                       goto fail;
+               }
+               ret = mmu->funcs->attach(mmu, iommu_ports,
+                               ARRAY_SIZE(iommu_ports));
+               if (ret)
+                       goto fail;
+       } else {
+               dev_info(dev->dev, "no iommu, fallback to phys "
+                               "contig buffers for scanout\n");
+               mmu = NULL;
+       }
+
+       mdp5_kms->id = msm_register_mmu(dev, mmu);
+       if (mdp5_kms->id < 0) {
+               ret = mdp5_kms->id;
+               dev_err(dev->dev, "failed to register mdp5 iommu: %d\n", ret);
+               goto fail;
+       }
+
+       ret = modeset_init(mdp5_kms);
+       if (ret) {
+               dev_err(dev->dev, "modeset_init failed: %d\n", ret);
+               goto fail;
+       }
+
+       return kms;
+
+fail:
+       if (kms)
+               mdp5_destroy(kms);
+       return ERR_PTR(ret);
+}
+
+static struct mdp5_platform_config *mdp5_get_config(struct platform_device *dev)
+{
+       static struct mdp5_platform_config config = {};
+#ifdef CONFIG_OF
+       /* TODO */
+#endif
+       return &config;
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
new file mode 100644 (file)
index 0000000..c8b1a25
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2013 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/>.
+ */
+
+#ifndef __MDP5_KMS_H__
+#define __MDP5_KMS_H__
+
+#include "msm_drv.h"
+#include "msm_kms.h"
+#include "mdp/mdp_kms.h"
+#include "mdp5.xml.h"
+#include "mdp5_smp.h"
+
+struct mdp5_kms {
+       struct mdp_kms base;
+
+       struct drm_device *dev;
+
+       int rev;
+
+       /* mapper-id used to request GEM buffer mapped for scanout: */
+       int id;
+
+       /* for tracking smp allocation amongst pipes: */
+       mdp5_smp_state_t smp_state;
+       struct mdp5_client_smp_state smp_client_state[CID_MAX];
+       int smp_blk_cnt;
+
+       /* io/register spaces: */
+       void __iomem *mmio, *vbif;
+
+       struct regulator *vdd;
+
+       struct clk *axi_clk;
+       struct clk *ahb_clk;
+       struct clk *src_clk;
+       struct clk *core_clk;
+       struct clk *lut_clk;
+       struct clk *vsync_clk;
+
+       struct hdmi *hdmi;
+
+       struct mdp_irq error_handler;
+};
+#define to_mdp5_kms(x) container_of(x, struct mdp5_kms, base)
+
+/* platform config data (ie. from DT, or pdata) */
+struct mdp5_platform_config {
+       struct iommu_domain *iommu;
+       uint32_t max_clk;
+       int smp_blk_cnt;
+};
+
+static inline void mdp5_write(struct mdp5_kms *mdp5_kms, u32 reg, u32 data)
+{
+       msm_writel(data, mdp5_kms->mmio + reg);
+}
+
+static inline u32 mdp5_read(struct mdp5_kms *mdp5_kms, u32 reg)
+{
+       return msm_readl(mdp5_kms->mmio + reg);
+}
+
+static inline const char *pipe2name(enum mdp5_pipe pipe)
+{
+       static const char *names[] = {
+#define NAME(n) [SSPP_ ## n] = #n
+               NAME(VIG0), NAME(VIG1), NAME(VIG2),
+               NAME(RGB0), NAME(RGB1), NAME(RGB2),
+               NAME(DMA0), NAME(DMA1),
+#undef NAME
+       };
+       return names[pipe];
+}
+
+static inline uint32_t pipe2flush(enum mdp5_pipe pipe)
+{
+       switch (pipe) {
+       case SSPP_VIG0: return MDP5_CTL_FLUSH_VIG0;
+       case SSPP_VIG1: return MDP5_CTL_FLUSH_VIG1;
+       case SSPP_VIG2: return MDP5_CTL_FLUSH_VIG2;
+       case SSPP_RGB0: return MDP5_CTL_FLUSH_RGB0;
+       case SSPP_RGB1: return MDP5_CTL_FLUSH_RGB1;
+       case SSPP_RGB2: return MDP5_CTL_FLUSH_RGB2;
+       case SSPP_DMA0: return MDP5_CTL_FLUSH_DMA0;
+       case SSPP_DMA1: return MDP5_CTL_FLUSH_DMA1;
+       default:        return 0;
+       }
+}
+
+static inline int pipe2nclients(enum mdp5_pipe pipe)
+{
+       switch (pipe) {
+       case SSPP_RGB0:
+       case SSPP_RGB1:
+       case SSPP_RGB2:
+               return 1;
+       default:
+               return 3;
+       }
+}
+
+static inline enum mdp5_client_id pipe2client(enum mdp5_pipe pipe, int plane)
+{
+       WARN_ON(plane >= pipe2nclients(pipe));
+       switch (pipe) {
+       case SSPP_VIG0: return CID_VIG0_Y + plane;
+       case SSPP_VIG1: return CID_VIG1_Y + plane;
+       case SSPP_VIG2: return CID_VIG2_Y + plane;
+       case SSPP_RGB0: return CID_RGB0;
+       case SSPP_RGB1: return CID_RGB1;
+       case SSPP_RGB2: return CID_RGB2;
+       case SSPP_DMA0: return CID_DMA0_Y + plane;
+       case SSPP_DMA1: return CID_DMA1_Y + plane;
+       default:        return CID_UNUSED;
+       }
+}
+
+static inline uint32_t mixer2flush(int lm)
+{
+       switch (lm) {
+       case 0:  return MDP5_CTL_FLUSH_LM0;
+       case 1:  return MDP5_CTL_FLUSH_LM1;
+       case 2:  return MDP5_CTL_FLUSH_LM2;
+       default: return 0;
+       }
+}
+
+static inline uint32_t intf2err(int intf)
+{
+       switch (intf) {
+       case 0:  return MDP5_IRQ_INTF0_UNDER_RUN;
+       case 1:  return MDP5_IRQ_INTF1_UNDER_RUN;
+       case 2:  return MDP5_IRQ_INTF2_UNDER_RUN;
+       case 3:  return MDP5_IRQ_INTF3_UNDER_RUN;
+       default: return 0;
+       }
+}
+
+static inline uint32_t intf2vblank(int intf)
+{
+       switch (intf) {
+       case 0:  return MDP5_IRQ_INTF0_VSYNC;
+       case 1:  return MDP5_IRQ_INTF1_VSYNC;
+       case 2:  return MDP5_IRQ_INTF2_VSYNC;
+       case 3:  return MDP5_IRQ_INTF3_VSYNC;
+       default: return 0;
+       }
+}
+
+int mdp5_disable(struct mdp5_kms *mdp5_kms);
+int mdp5_enable(struct mdp5_kms *mdp5_kms);
+
+void mdp5_set_irqmask(struct mdp_kms *mdp_kms, uint32_t irqmask);
+void mdp5_irq_preinstall(struct msm_kms *kms);
+int mdp5_irq_postinstall(struct msm_kms *kms);
+void mdp5_irq_uninstall(struct msm_kms *kms);
+irqreturn_t mdp5_irq(struct msm_kms *kms);
+int mdp5_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+
+static inline
+uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats,
+               uint32_t max_formats)
+{
+       /* TODO when we have YUV, we need to filter supported formats
+        * based on pipe id..
+        */
+       return mdp_get_formats(pixel_formats, max_formats);
+}
+
+void mdp5_plane_install_properties(struct drm_plane *plane,
+               struct drm_mode_object *obj);
+void mdp5_plane_set_scanout(struct drm_plane *plane,
+               struct drm_framebuffer *fb);
+int mdp5_plane_mode_set(struct drm_plane *plane,
+               struct drm_crtc *crtc, struct drm_framebuffer *fb,
+               int crtc_x, int crtc_y,
+               unsigned int crtc_w, unsigned int crtc_h,
+               uint32_t src_x, uint32_t src_y,
+               uint32_t src_w, uint32_t src_h);
+void mdp5_plane_complete_flip(struct drm_plane *plane);
+enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane);
+struct drm_plane *mdp5_plane_init(struct drm_device *dev,
+               enum mdp5_pipe pipe, bool private_plane);
+
+uint32_t mdp5_crtc_vblank(struct drm_crtc *crtc);
+
+void mdp5_crtc_cancel_pending_flip(struct drm_crtc *crtc, struct drm_file *file);
+void mdp5_crtc_set_intf(struct drm_crtc *crtc, int intf,
+               enum mdp5_intf intf_id);
+void mdp5_crtc_attach(struct drm_crtc *crtc, struct drm_plane *plane);
+void mdp5_crtc_detach(struct drm_crtc *crtc, struct drm_plane *plane);
+struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
+               struct drm_plane *plane, int id);
+
+struct drm_encoder *mdp5_encoder_init(struct drm_device *dev, int intf,
+               enum mdp5_intf intf_id);
+
+#endif /* __MDP5_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
new file mode 100644 (file)
index 0000000..0ac8bb5
--- /dev/null
@@ -0,0 +1,389 @@
+/*
+ * Copyright (C) 2013 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 "mdp5_kms.h"
+
+
+struct mdp5_plane {
+       struct drm_plane base;
+       const char *name;
+
+       enum mdp5_pipe pipe;
+
+       uint32_t nformats;
+       uint32_t formats[32];
+
+       bool enabled;
+};
+#define to_mdp5_plane(x) container_of(x, struct mdp5_plane, base)
+
+static struct mdp5_kms *get_kms(struct drm_plane *plane)
+{
+       struct msm_drm_private *priv = plane->dev->dev_private;
+       return to_mdp5_kms(to_mdp_kms(priv->kms));
+}
+
+static int mdp5_plane_update(struct drm_plane *plane,
+               struct drm_crtc *crtc, struct drm_framebuffer *fb,
+               int crtc_x, int crtc_y,
+               unsigned int crtc_w, unsigned int crtc_h,
+               uint32_t src_x, uint32_t src_y,
+               uint32_t src_w, uint32_t src_h)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+
+       mdp5_plane->enabled = true;
+
+       if (plane->fb)
+               drm_framebuffer_unreference(plane->fb);
+
+       drm_framebuffer_reference(fb);
+
+       return mdp5_plane_mode_set(plane, crtc, fb,
+                       crtc_x, crtc_y, crtc_w, crtc_h,
+                       src_x, src_y, src_w, src_h);
+}
+
+static int mdp5_plane_disable(struct drm_plane *plane)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       enum mdp5_pipe pipe = mdp5_plane->pipe;
+       int i;
+
+       DBG("%s: disable", mdp5_plane->name);
+
+       /* update our SMP request to zero (release all our blks): */
+       for (i = 0; i < pipe2nclients(pipe); i++)
+               mdp5_smp_request(mdp5_kms, pipe2client(pipe, i), 0);
+
+       /* TODO detaching now will cause us not to get the last
+        * vblank and mdp5_smp_commit().. so other planes will
+        * still see smp blocks previously allocated to us as
+        * in-use..
+        */
+       if (plane->crtc)
+               mdp5_crtc_detach(plane->crtc, plane);
+
+       return 0;
+}
+
+static void mdp5_plane_destroy(struct drm_plane *plane)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+
+       mdp5_plane_disable(plane);
+       drm_plane_cleanup(plane);
+
+       kfree(mdp5_plane);
+}
+
+/* helper to install properties which are common to planes and crtcs */
+void mdp5_plane_install_properties(struct drm_plane *plane,
+               struct drm_mode_object *obj)
+{
+       // XXX
+}
+
+int mdp5_plane_set_property(struct drm_plane *plane,
+               struct drm_property *property, uint64_t val)
+{
+       // XXX
+       return -EINVAL;
+}
+
+static const struct drm_plane_funcs mdp5_plane_funcs = {
+               .update_plane = mdp5_plane_update,
+               .disable_plane = mdp5_plane_disable,
+               .destroy = mdp5_plane_destroy,
+               .set_property = mdp5_plane_set_property,
+};
+
+void mdp5_plane_set_scanout(struct drm_plane *plane,
+               struct drm_framebuffer *fb)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       enum mdp5_pipe pipe = mdp5_plane->pipe;
+       uint32_t nplanes = drm_format_num_planes(fb->pixel_format);
+       uint32_t iova[4];
+       int i;
+
+       for (i = 0; i < nplanes; i++) {
+               struct drm_gem_object *bo = msm_framebuffer_bo(fb, i);
+               msm_gem_get_iova(bo, mdp5_kms->id, &iova[i]);
+       }
+       for (; i < 4; i++)
+               iova[i] = 0;
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_A(pipe),
+                       MDP5_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
+                       MDP5_PIPE_SRC_STRIDE_A_P1(fb->pitches[1]));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_STRIDE_B(pipe),
+                       MDP5_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
+                       MDP5_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC0_ADDR(pipe), iova[0]);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC1_ADDR(pipe), iova[1]);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC2_ADDR(pipe), iova[2]);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC3_ADDR(pipe), iova[3]);
+
+       plane->fb = fb;
+}
+
+/* NOTE: looks like if horizontal decimation is used (if we supported that)
+ * then the width used to calculate SMP block requirements is the post-
+ * decimated width.  Ie. SMP buffering sits downstream of decimation (which
+ * presumably happens during the dma from scanout buffer).
+ */
+static int request_smp_blocks(struct drm_plane *plane, uint32_t format,
+               uint32_t nplanes, uint32_t width)
+{
+       struct drm_device *dev = plane->dev;
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       enum mdp5_pipe pipe = mdp5_plane->pipe;
+       int i, hsub, nlines, nblks, ret;
+
+       hsub = drm_format_horz_chroma_subsampling(format);
+
+       /* different if BWC (compressed framebuffer?) enabled: */
+       nlines = 2;
+
+       for (i = 0, nblks = 0; i < nplanes; i++) {
+               int n, fetch_stride, cpp;
+
+               cpp = drm_format_plane_cpp(format, i);
+               fetch_stride = width * cpp / (i ? hsub : 1);
+
+               n = DIV_ROUND_UP(fetch_stride * nlines, SMP_BLK_SIZE);
+
+               /* for hw rev v1.00 */
+               if (mdp5_kms->rev == 0)
+                       n = roundup_pow_of_two(n);
+
+               DBG("%s[%d]: request %d SMP blocks", mdp5_plane->name, i, n);
+               ret = mdp5_smp_request(mdp5_kms, pipe2client(pipe, i), n);
+               if (ret) {
+                       dev_err(dev->dev, "Could not allocate %d SMP blocks: %d\n",
+                                       n, ret);
+                       return ret;
+               }
+
+               nblks += n;
+       }
+
+       /* in success case, return total # of blocks allocated: */
+       return nblks;
+}
+
+static void set_fifo_thresholds(struct drm_plane *plane, int nblks)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       enum mdp5_pipe pipe = mdp5_plane->pipe;
+       uint32_t val;
+
+       /* 1/4 of SMP pool that is being fetched */
+       val = (nblks * SMP_ENTRIES_PER_BLK) / 4;
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_0(pipe), val * 1);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_1(pipe), val * 2);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_REQPRIO_FIFO_WM_2(pipe), val * 3);
+
+}
+
+int mdp5_plane_mode_set(struct drm_plane *plane,
+               struct drm_crtc *crtc, struct drm_framebuffer *fb,
+               int crtc_x, int crtc_y,
+               unsigned int crtc_w, unsigned int crtc_h,
+               uint32_t src_x, uint32_t src_y,
+               uint32_t src_w, uint32_t src_h)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       enum mdp5_pipe pipe = mdp5_plane->pipe;
+       const struct mdp_format *format;
+       uint32_t nplanes, config = 0;
+       uint32_t phasex_step = 0, phasey_step = 0;
+       uint32_t hdecm = 0, vdecm = 0;
+       int i, nblks;
+
+       nplanes = drm_format_num_planes(fb->pixel_format);
+
+       /* bad formats should already be rejected: */
+       if (WARN_ON(nplanes > pipe2nclients(pipe)))
+               return -EINVAL;
+
+       /* src values are in Q16 fixed point, convert to integer: */
+       src_x = src_x >> 16;
+       src_y = src_y >> 16;
+       src_w = src_w >> 16;
+       src_h = src_h >> 16;
+
+       DBG("%s: FB[%u] %u,%u,%u,%u -> CRTC[%u] %d,%d,%u,%u", mdp5_plane->name,
+                       fb->base.id, src_x, src_y, src_w, src_h,
+                       crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
+
+       /*
+        * Calculate and request required # of smp blocks:
+        */
+       nblks = request_smp_blocks(plane, fb->pixel_format, nplanes, src_w);
+       if (nblks < 0)
+               return nblks;
+
+       /*
+        * Currently we update the hw for allocations/requests immediately,
+        * but once atomic modeset/pageflip is in place, the allocation
+        * would move into atomic->check_plane_state(), while updating the
+        * hw would remain here:
+        */
+       for (i = 0; i < pipe2nclients(pipe); i++)
+               mdp5_smp_configure(mdp5_kms, pipe2client(pipe, i));
+
+       if (src_w != crtc_w) {
+               config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN;
+               /* TODO calc phasex_step, hdecm */
+       }
+
+       if (src_h != crtc_h) {
+               config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN;
+               /* TODO calc phasey_step, vdecm */
+       }
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_IMG_SIZE(pipe),
+                       MDP5_PIPE_SRC_IMG_SIZE_WIDTH(src_w) |
+                       MDP5_PIPE_SRC_IMG_SIZE_HEIGHT(src_h));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_SIZE(pipe),
+                       MDP5_PIPE_SRC_SIZE_WIDTH(src_w) |
+                       MDP5_PIPE_SRC_SIZE_HEIGHT(src_h));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_XY(pipe),
+                       MDP5_PIPE_SRC_XY_X(src_x) |
+                       MDP5_PIPE_SRC_XY_Y(src_y));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_SIZE(pipe),
+                       MDP5_PIPE_OUT_SIZE_WIDTH(crtc_w) |
+                       MDP5_PIPE_OUT_SIZE_HEIGHT(crtc_h));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_OUT_XY(pipe),
+                       MDP5_PIPE_OUT_XY_X(crtc_x) |
+                       MDP5_PIPE_OUT_XY_Y(crtc_y));
+
+       mdp5_plane_set_scanout(plane, fb);
+
+       format = to_mdp_format(msm_framebuffer_format(fb));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
+                       MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
+                       MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
+                       MDP5_PIPE_SRC_FORMAT_G_BPC(format->bpc_g) |
+                       MDP5_PIPE_SRC_FORMAT_B_BPC(format->bpc_b) |
+                       COND(format->alpha_enable, MDP5_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
+                       MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
+                       MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
+                       COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
+                       MDP5_PIPE_SRC_FORMAT_NUM_PLANES(nplanes - 1) |
+                       MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
+                       MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
+                       MDP5_PIPE_SRC_UNPACK_ELEM1(format->unpack[1]) |
+                       MDP5_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
+                       MDP5_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_OP_MODE(pipe),
+                       MDP5_PIPE_SRC_OP_MODE_BWC(BWC_LOSSLESS));
+
+       /* not using secure mode: */
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
+
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step);
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
+                       MDP5_PIPE_DECIMATION_VERT(vdecm) |
+                       MDP5_PIPE_DECIMATION_HORZ(hdecm));
+       mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe),
+                       MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) |
+                       MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) |
+                       MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) |
+                       MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) |
+                       MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) |
+                       MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST));
+
+       set_fifo_thresholds(plane, nblks);
+
+       /* TODO detach from old crtc (if we had more than one) */
+       mdp5_crtc_attach(crtc, plane);
+
+       return 0;
+}
+
+void mdp5_plane_complete_flip(struct drm_plane *plane)
+{
+       struct mdp5_kms *mdp5_kms = get_kms(plane);
+       enum mdp5_pipe pipe = to_mdp5_plane(plane)->pipe;
+       int i;
+
+       for (i = 0; i < pipe2nclients(pipe); i++)
+               mdp5_smp_commit(mdp5_kms, pipe2client(pipe, i));
+}
+
+enum mdp5_pipe mdp5_plane_pipe(struct drm_plane *plane)
+{
+       struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
+       return mdp5_plane->pipe;
+}
+
+/* initialize plane */
+struct drm_plane *mdp5_plane_init(struct drm_device *dev,
+               enum mdp5_pipe pipe, bool private_plane)
+{
+       struct drm_plane *plane = NULL;
+       struct mdp5_plane *mdp5_plane;
+       int ret;
+
+       mdp5_plane = kzalloc(sizeof(*mdp5_plane), GFP_KERNEL);
+       if (!mdp5_plane) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       plane = &mdp5_plane->base;
+
+       mdp5_plane->pipe = pipe;
+       mdp5_plane->name = pipe2name(pipe);
+
+       mdp5_plane->nformats = mdp5_get_formats(pipe, mdp5_plane->formats,
+                       ARRAY_SIZE(mdp5_plane->formats));
+
+       drm_plane_init(dev, plane, 0xff, &mdp5_plane_funcs,
+                       mdp5_plane->formats, mdp5_plane->nformats,
+                       private_plane);
+
+       mdp5_plane_install_properties(plane, &plane->base);
+
+       return plane;
+
+fail:
+       if (plane)
+               mdp5_plane_destroy(plane);
+
+       return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
new file mode 100644 (file)
index 0000000..2d0236b
--- /dev/null
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2013 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 "mdp5_kms.h"
+#include "mdp5_smp.h"
+
+
+/* SMP - Shared Memory Pool
+ *
+ * These are shared between all the clients, where each plane in a
+ * scanout buffer is a SMP client.  Ie. scanout of 3 plane I420 on
+ * pipe VIG0 => 3 clients: VIG0_Y, VIG0_CB, VIG0_CR.
+ *
+ * Based on the size of the attached scanout buffer, a certain # of
+ * blocks must be allocated to that client out of the shared pool.
+ *
+ * For each block, it can be either free, or pending/in-use by a
+ * client.  The updates happen in three steps:
+ *
+ *  1) mdp5_smp_request():
+ *     When plane scanout is setup, calculate required number of
+ *     blocks needed per client, and request.  Blocks not inuse or
+ *     pending by any other client are added to client's pending
+ *     set.
+ *
+ *  2) mdp5_smp_configure():
+ *     As hw is programmed, before FLUSH, MDP5_SMP_ALLOC registers
+ *     are configured for the union(pending, inuse)
+ *
+ *  3) mdp5_smp_commit():
+ *     After next vblank, copy pending -> inuse.  Optionally update
+ *     MDP5_SMP_ALLOC registers if there are newly unused blocks
+ *
+ * On the next vblank after changes have been committed to hw, the
+ * client's pending blocks become it's in-use blocks (and no-longer
+ * in-use blocks become available to other clients).
+ *
+ * btw, hurray for confusing overloaded acronyms!  :-/
+ *
+ * NOTE: for atomic modeset/pageflip NONBLOCK operations, step #1
+ * should happen at (or before)? atomic->check().  And we'd need
+ * an API to discard previous requests if update is aborted or
+ * (test-only).
+ *
+ * TODO would perhaps be nice to have debugfs to dump out kernel
+ * inuse and pending state of all clients..
+ */
+
+static DEFINE_SPINLOCK(smp_lock);
+
+
+/* step #1: update # of blocks pending for the client: */
+int mdp5_smp_request(struct mdp5_kms *mdp5_kms,
+               enum mdp5_client_id cid, int nblks)
+{
+       struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid];
+       int i, ret, avail, cur_nblks, cnt = mdp5_kms->smp_blk_cnt;
+       unsigned long flags;
+
+       spin_lock_irqsave(&smp_lock, flags);
+
+       avail = cnt - bitmap_weight(mdp5_kms->smp_state, cnt);
+       if (nblks > avail) {
+               ret = -ENOSPC;
+               goto fail;
+       }
+
+       cur_nblks = bitmap_weight(ps->pending, cnt);
+       if (nblks > cur_nblks) {
+               /* grow the existing pending reservation: */
+               for (i = cur_nblks; i < nblks; i++) {
+                       int blk = find_first_zero_bit(mdp5_kms->smp_state, cnt);
+                       set_bit(blk, ps->pending);
+                       set_bit(blk, mdp5_kms->smp_state);
+               }
+       } else {
+               /* shrink the existing pending reservation: */
+               for (i = cur_nblks; i > nblks; i--) {
+                       int blk = find_first_bit(ps->pending, cnt);
+                       clear_bit(blk, ps->pending);
+                       /* don't clear in global smp_state until _commit() */
+               }
+       }
+
+fail:
+       spin_unlock_irqrestore(&smp_lock, flags);
+       return 0;
+}
+
+static void update_smp_state(struct mdp5_kms *mdp5_kms,
+               enum mdp5_client_id cid, mdp5_smp_state_t *assigned)
+{
+       int cnt = mdp5_kms->smp_blk_cnt;
+       uint32_t blk, val;
+
+       for_each_set_bit(blk, *assigned, cnt) {
+               int idx = blk / 3;
+               int fld = blk % 3;
+
+               val = mdp5_read(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx));
+
+               switch (fld) {
+               case 0:
+                       val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT0__MASK;
+                       val |= MDP5_SMP_ALLOC_W_REG_CLIENT0(cid);
+                       break;
+               case 1:
+                       val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT1__MASK;
+                       val |= MDP5_SMP_ALLOC_W_REG_CLIENT1(cid);
+                       break;
+               case 2:
+                       val &= ~MDP5_SMP_ALLOC_W_REG_CLIENT2__MASK;
+                       val |= MDP5_SMP_ALLOC_W_REG_CLIENT2(cid);
+                       break;
+               }
+
+               mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_W_REG(idx), val);
+               mdp5_write(mdp5_kms, REG_MDP5_SMP_ALLOC_R_REG(idx), val);
+       }
+}
+
+/* step #2: configure hw for union(pending, inuse): */
+void mdp5_smp_configure(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid)
+{
+       struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid];
+       int cnt = mdp5_kms->smp_blk_cnt;
+       mdp5_smp_state_t assigned;
+
+       bitmap_or(assigned, ps->inuse, ps->pending, cnt);
+       update_smp_state(mdp5_kms, cid, &assigned);
+}
+
+/* step #3: after vblank, copy pending -> inuse: */
+void mdp5_smp_commit(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid)
+{
+       struct mdp5_client_smp_state *ps = &mdp5_kms->smp_client_state[cid];
+       int cnt = mdp5_kms->smp_blk_cnt;
+       mdp5_smp_state_t released;
+
+       /*
+        * Figure out if there are any blocks we where previously
+        * using, which can be released and made available to other
+        * clients:
+        */
+       if (bitmap_andnot(released, ps->inuse, ps->pending, cnt)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&smp_lock, flags);
+               /* clear released blocks: */
+               bitmap_andnot(mdp5_kms->smp_state, mdp5_kms->smp_state,
+                               released, cnt);
+               spin_unlock_irqrestore(&smp_lock, flags);
+
+               update_smp_state(mdp5_kms, CID_UNUSED, &released);
+       }
+
+       bitmap_copy(ps->inuse, ps->pending, cnt);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.h
new file mode 100644 (file)
index 0000000..0ab739e
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2013 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/>.
+ */
+
+#ifndef __MDP5_SMP_H__
+#define __MDP5_SMP_H__
+
+#include "msm_drv.h"
+
+#define MAX_SMP_BLOCKS  22
+#define SMP_BLK_SIZE    4096
+#define SMP_ENTRIES_PER_BLK (SMP_BLK_SIZE / 16)
+
+typedef DECLARE_BITMAP(mdp5_smp_state_t, MAX_SMP_BLOCKS);
+
+struct mdp5_client_smp_state {
+       mdp5_smp_state_t inuse;
+       mdp5_smp_state_t pending;
+};
+
+struct mdp5_kms;
+
+int mdp5_smp_request(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid, int nblks);
+void mdp5_smp_configure(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid);
+void mdp5_smp_commit(struct mdp5_kms *mdp5_kms, enum mdp5_client_id cid);
+
+
+#endif /* __MDP5_SMP_H__ */
diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h
new file mode 100644 (file)
index 0000000..a9629b8
--- /dev/null
@@ -0,0 +1,78 @@
+#ifndef MDP_COMMON_XML
+#define MDP_COMMON_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/freedreno/envytools/
+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 2013-12-03 20:59:13)
+- /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/hdmi/qfprom.xml         (    600 bytes, from 2013-07-05 19:21:12)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml           (  20932 bytes, from 2013-12-01 15:13:04)
+
+Copyright (C) 2013 by the following authors:
+- Rob Clark <robdclark@gmail.com> (robclark)
+
+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 COPYRIGHT OWNER(S) 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.
+*/
+
+
+enum mdp_mixer_stage_id {
+       STAGE_UNUSED = 0,
+       STAGE_BASE = 1,
+       STAGE0 = 2,
+       STAGE1 = 3,
+       STAGE2 = 4,
+       STAGE3 = 5,
+};
+
+enum mdp_alpha_type {
+       FG_CONST = 0,
+       BG_CONST = 1,
+       FG_PIXEL = 2,
+       BG_PIXEL = 3,
+};
+
+enum mdp_bpc {
+       BPC1 = 0,
+       BPC5 = 1,
+       BPC6 = 2,
+       BPC8 = 3,
+};
+
+enum mdp_bpc_alpha {
+       BPC1A = 0,
+       BPC4A = 1,
+       BPC6A = 2,
+       BPC8A = 3,
+};
+
+
+#endif /* MDP_COMMON_XML */
similarity index 85%
rename from drivers/gpu/drm/msm/mdp4/mdp4_format.c
rename to drivers/gpu/drm/msm/mdp/mdp_format.c
index 17330b0927b2a0ac0f608b2e9a98777cb96016ec..e0a6ffbe6ab42e00c9f829b20499367cb28d99d6 100644 (file)
@@ -17,7 +17,7 @@
 
 
 #include "msm_drv.h"
-#include "mdp4_kms.h"
+#include "mdp_kms.h"
 
 #define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt) { \
                .base = { .pixel_format = DRM_FORMAT_ ## name }, \
@@ -34,7 +34,7 @@
 
 #define BPC0A 0
 
-static const struct mdp4_format formats[] = {
+static const struct mdp_format formats[] = {
        /*  name      a  r  g  b   e0 e1 e2 e3  alpha   tight  cpp cnt */
        FMT(ARGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  true,   true,  4,  4),
        FMT(XRGB8888, 8, 8, 8, 8,  1, 0, 2, 3,  false,  true,  4,  4),
@@ -44,12 +44,11 @@ static const struct mdp4_format formats[] = {
        FMT(BGR565,   0, 5, 6, 5,  2, 0, 1, 0,  false,  true,  2,  3),
 };
 
-uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
-               uint32_t max_formats)
+uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats)
 {
        uint32_t i;
        for (i = 0; i < ARRAY_SIZE(formats); i++) {
-               const struct mdp4_format *f = &formats[i];
+               const struct mdp_format *f = &formats[i];
 
                if (i == max_formats)
                        break;
@@ -60,11 +59,11 @@ uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
        return i;
 }
 
-const struct msm_format *mdp4_get_format(struct msm_kms *kms, uint32_t format)
+const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format)
 {
        int i;
        for (i = 0; i < ARRAY_SIZE(formats); i++) {
-               const struct mdp4_format *f = &formats[i];
+               const struct mdp_format *f = &formats[i];
                if (f->base.pixel_format == format)
                        return &f->base;
        }
diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c
new file mode 100644 (file)
index 0000000..3be48f7
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2013 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 "msm_drv.h"
+#include "mdp_kms.h"
+
+
+struct mdp_irq_wait {
+       struct mdp_irq irq;
+       int count;
+};
+
+static DECLARE_WAIT_QUEUE_HEAD(wait_event);
+
+static DEFINE_SPINLOCK(list_lock);
+
+static void update_irq(struct mdp_kms *mdp_kms)
+{
+       struct mdp_irq *irq;
+       uint32_t irqmask = mdp_kms->vblank_mask;
+
+       BUG_ON(!spin_is_locked(&list_lock));
+
+       list_for_each_entry(irq, &mdp_kms->irq_list, node)
+               irqmask |= irq->irqmask;
+
+       mdp_kms->funcs->set_irqmask(mdp_kms, irqmask);
+}
+
+static void update_irq_unlocked(struct mdp_kms *mdp_kms)
+{
+       unsigned long flags;
+       spin_lock_irqsave(&list_lock, flags);
+       update_irq(mdp_kms);
+       spin_unlock_irqrestore(&list_lock, flags);
+}
+
+void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status)
+{
+       struct mdp_irq *handler, *n;
+       unsigned long flags;
+
+       spin_lock_irqsave(&list_lock, flags);
+       mdp_kms->in_irq = true;
+       list_for_each_entry_safe(handler, n, &mdp_kms->irq_list, node) {
+               if (handler->irqmask & status) {
+                       spin_unlock_irqrestore(&list_lock, flags);
+                       handler->irq(handler, handler->irqmask & status);
+                       spin_lock_irqsave(&list_lock, flags);
+               }
+       }
+       mdp_kms->in_irq = false;
+       update_irq(mdp_kms);
+       spin_unlock_irqrestore(&list_lock, flags);
+
+}
+
+void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&list_lock, flags);
+       if (enable)
+               mdp_kms->vblank_mask |= mask;
+       else
+               mdp_kms->vblank_mask &= ~mask;
+       update_irq(mdp_kms);
+       spin_unlock_irqrestore(&list_lock, flags);
+}
+
+static void wait_irq(struct mdp_irq *irq, uint32_t irqstatus)
+{
+       struct mdp_irq_wait *wait =
+                       container_of(irq, struct mdp_irq_wait, irq);
+       wait->count--;
+       wake_up_all(&wait_event);
+}
+
+void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask)
+{
+       struct mdp_irq_wait wait = {
+               .irq = {
+                       .irq = wait_irq,
+                       .irqmask = irqmask,
+               },
+               .count = 1,
+       };
+       mdp_irq_register(mdp_kms, &wait.irq);
+       wait_event(wait_event, (wait.count <= 0));
+       mdp_irq_unregister(mdp_kms, &wait.irq);
+}
+
+void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
+{
+       unsigned long flags;
+       bool needs_update = false;
+
+       spin_lock_irqsave(&list_lock, flags);
+
+       if (!irq->registered) {
+               irq->registered = true;
+               list_add(&irq->node, &mdp_kms->irq_list);
+               needs_update = !mdp_kms->in_irq;
+       }
+
+       spin_unlock_irqrestore(&list_lock, flags);
+
+       if (needs_update)
+               update_irq_unlocked(mdp_kms);
+}
+
+void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq)
+{
+       unsigned long flags;
+       bool needs_update = false;
+
+       spin_lock_irqsave(&list_lock, flags);
+
+       if (irq->registered) {
+               irq->registered = false;
+               list_del(&irq->node);
+               needs_update = !mdp_kms->in_irq;
+       }
+
+       spin_unlock_irqrestore(&list_lock, flags);
+
+       if (needs_update)
+               update_irq_unlocked(mdp_kms);
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h
new file mode 100644 (file)
index 0000000..99557b5
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2013 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/>.
+ */
+
+#ifndef __MDP_KMS_H__
+#define __MDP_KMS_H__
+
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include "msm_drv.h"
+#include "msm_kms.h"
+#include "mdp_common.xml.h"
+
+struct mdp_kms;
+
+struct mdp_kms_funcs {
+       struct msm_kms_funcs base;
+       void (*set_irqmask)(struct mdp_kms *mdp_kms, uint32_t irqmask);
+};
+
+struct mdp_kms {
+       struct msm_kms base;
+
+       const struct mdp_kms_funcs *funcs;
+
+       /* irq handling: */
+       bool in_irq;
+       struct list_head irq_list;    /* list of mdp4_irq */
+       uint32_t vblank_mask;         /* irq bits set for userspace vblank */
+};
+#define to_mdp_kms(x) container_of(x, struct mdp_kms, base)
+
+static inline void mdp_kms_init(struct mdp_kms *mdp_kms,
+               const struct mdp_kms_funcs *funcs)
+{
+       mdp_kms->funcs = funcs;
+       INIT_LIST_HEAD(&mdp_kms->irq_list);
+       msm_kms_init(&mdp_kms->base, &funcs->base);
+}
+
+/*
+ * irq helpers:
+ */
+
+/* For transiently registering for different MDP irqs that various parts
+ * of the KMS code need during setup/configuration.  These are not
+ * necessarily the same as what drm_vblank_get/put() are requesting, and
+ * the hysteresis in drm_vblank_put() is not necessarily desirable for
+ * internal housekeeping related irq usage.
+ */
+struct mdp_irq {
+       struct list_head node;
+       uint32_t irqmask;
+       bool registered;
+       void (*irq)(struct mdp_irq *irq, uint32_t irqstatus);
+};
+
+void mdp_dispatch_irqs(struct mdp_kms *mdp_kms, uint32_t status);
+void mdp_update_vblank_mask(struct mdp_kms *mdp_kms, uint32_t mask, bool enable);
+void mdp_irq_wait(struct mdp_kms *mdp_kms, uint32_t irqmask);
+void mdp_irq_register(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
+void mdp_irq_unregister(struct mdp_kms *mdp_kms, struct mdp_irq *irq);
+
+
+/*
+ * pixel format helpers:
+ */
+
+struct mdp_format {
+       struct msm_format base;
+       enum mdp_bpc bpc_r, bpc_g, bpc_b;
+       enum mdp_bpc_alpha bpc_a;
+       uint8_t unpack[4];
+       bool alpha_enable, unpack_tight;
+       uint8_t cpp, unpack_count;
+};
+#define to_mdp_format(x) container_of(x, struct mdp_format, base)
+
+uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats);
+const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format);
+
+#endif /* __MDP_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/mdp4/mdp4_irq.c b/drivers/gpu/drm/msm/mdp4/mdp4_irq.c
deleted file mode 100644 (file)
index 5c6b7fc..0000000
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2013 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 "msm_drv.h"
-#include "mdp4_kms.h"
-
-
-struct mdp4_irq_wait {
-       struct mdp4_irq irq;
-       int count;
-};
-
-static DECLARE_WAIT_QUEUE_HEAD(wait_event);
-
-static DEFINE_SPINLOCK(list_lock);
-
-static void update_irq(struct mdp4_kms *mdp4_kms)
-{
-       struct mdp4_irq *irq;
-       uint32_t irqmask = mdp4_kms->vblank_mask;
-
-       BUG_ON(!spin_is_locked(&list_lock));
-
-       list_for_each_entry(irq, &mdp4_kms->irq_list, node)
-               irqmask |= irq->irqmask;
-
-       mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, irqmask);
-}
-
-static void update_irq_unlocked(struct mdp4_kms *mdp4_kms)
-{
-       unsigned long flags;
-       spin_lock_irqsave(&list_lock, flags);
-       update_irq(mdp4_kms);
-       spin_unlock_irqrestore(&list_lock, flags);
-}
-
-static void mdp4_irq_error_handler(struct mdp4_irq *irq, uint32_t irqstatus)
-{
-       DRM_ERROR("errors: %08x\n", irqstatus);
-}
-
-void mdp4_irq_preinstall(struct msm_kms *kms)
-{
-       struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms);
-       mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, 0xffffffff);
-}
-
-int mdp4_irq_postinstall(struct msm_kms *kms)
-{
-       struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms);
-       struct mdp4_irq *error_handler = &mdp4_kms->error_handler;
-
-       INIT_LIST_HEAD(&mdp4_kms->irq_list);
-
-       error_handler->irq = mdp4_irq_error_handler;
-       error_handler->irqmask = MDP4_IRQ_PRIMARY_INTF_UDERRUN |
-                       MDP4_IRQ_EXTERNAL_INTF_UDERRUN;
-
-       mdp4_irq_register(mdp4_kms, error_handler);
-
-       return 0;
-}
-
-void mdp4_irq_uninstall(struct msm_kms *kms)
-{
-       struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms);
-       mdp4_write(mdp4_kms, REG_MDP4_INTR_ENABLE, 0x00000000);
-}
-
-irqreturn_t mdp4_irq(struct msm_kms *kms)
-{
-       struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms);
-       struct drm_device *dev = mdp4_kms->dev;
-       struct msm_drm_private *priv = dev->dev_private;
-       struct mdp4_irq *handler, *n;
-       unsigned long flags;
-       unsigned int id;
-       uint32_t status;
-
-       status = mdp4_read(mdp4_kms, REG_MDP4_INTR_STATUS);
-       mdp4_write(mdp4_kms, REG_MDP4_INTR_CLEAR, status);
-
-       VERB("status=%08x", status);
-
-       for (id = 0; id < priv->num_crtcs; id++)
-               if (status & mdp4_crtc_vblank(priv->crtcs[id]))
-                       drm_handle_vblank(dev, id);
-
-       spin_lock_irqsave(&list_lock, flags);
-       mdp4_kms->in_irq = true;
-       list_for_each_entry_safe(handler, n, &mdp4_kms->irq_list, node) {
-               if (handler->irqmask & status) {
-                       spin_unlock_irqrestore(&list_lock, flags);
-                       handler->irq(handler, handler->irqmask & status);
-                       spin_lock_irqsave(&list_lock, flags);
-               }
-       }
-       mdp4_kms->in_irq = false;
-       update_irq(mdp4_kms);
-       spin_unlock_irqrestore(&list_lock, flags);
-
-       return IRQ_HANDLED;
-}
-
-int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
-{
-       struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms);
-       unsigned long flags;
-
-       spin_lock_irqsave(&list_lock, flags);
-       mdp4_kms->vblank_mask |= mdp4_crtc_vblank(crtc);
-       update_irq(mdp4_kms);
-       spin_unlock_irqrestore(&list_lock, flags);
-
-       return 0;
-}
-
-void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc)
-{
-       struct mdp4_kms *mdp4_kms = to_mdp4_kms(kms);
-       unsigned long flags;
-
-       spin_lock_irqsave(&list_lock, flags);
-       mdp4_kms->vblank_mask &= ~mdp4_crtc_vblank(crtc);
-       update_irq(mdp4_kms);
-       spin_unlock_irqrestore(&list_lock, flags);
-}
-
-static void wait_irq(struct mdp4_irq *irq, uint32_t irqstatus)
-{
-       struct mdp4_irq_wait *wait =
-                       container_of(irq, struct mdp4_irq_wait, irq);
-       wait->count--;
-       wake_up_all(&wait_event);
-}
-
-void mdp4_irq_wait(struct mdp4_kms *mdp4_kms, uint32_t irqmask)
-{
-       struct mdp4_irq_wait wait = {
-               .irq = {
-                       .irq = wait_irq,
-                       .irqmask = irqmask,
-               },
-               .count = 1,
-       };
-       mdp4_irq_register(mdp4_kms, &wait.irq);
-       wait_event(wait_event, (wait.count <= 0));
-       mdp4_irq_unregister(mdp4_kms, &wait.irq);
-}
-
-void mdp4_irq_register(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq)
-{
-       unsigned long flags;
-       bool needs_update = false;
-
-       spin_lock_irqsave(&list_lock, flags);
-
-       if (!irq->registered) {
-               irq->registered = true;
-               list_add(&irq->node, &mdp4_kms->irq_list);
-               needs_update = !mdp4_kms->in_irq;
-       }
-
-       spin_unlock_irqrestore(&list_lock, flags);
-
-       if (needs_update)
-               update_irq_unlocked(mdp4_kms);
-}
-
-void mdp4_irq_unregister(struct mdp4_kms *mdp4_kms, struct mdp4_irq *irq)
-{
-       unsigned long flags;
-       bool needs_update = false;
-
-       spin_lock_irqsave(&list_lock, flags);
-
-       if (irq->registered) {
-               irq->registered = false;
-               list_del(&irq->node);
-               needs_update = !mdp4_kms->in_irq;
-       }
-
-       spin_unlock_irqrestore(&list_lock, flags);
-
-       if (needs_update)
-               update_irq_unlocked(mdp4_kms);
-}
index 86537692e45c4efaeae162d32753cf5613216954..e6adafc7eff3177b789395f6bc81f4ab62042e11 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "msm_drv.h"
 #include "msm_gpu.h"
+#include "msm_kms.h"
 
 static void msm_fb_output_poll_changed(struct drm_device *dev)
 {
@@ -30,50 +31,19 @@ static const struct drm_mode_config_funcs mode_config_funcs = {
        .output_poll_changed = msm_fb_output_poll_changed,
 };
 
-static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
-               unsigned long iova, int flags, void *arg)
-{
-       DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
-       return 0;
-}
-
-int msm_register_iommu(struct drm_device *dev, struct iommu_domain *iommu)
+int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu)
 {
        struct msm_drm_private *priv = dev->dev_private;
-       int idx = priv->num_iommus++;
+       int idx = priv->num_mmus++;
 
-       if (WARN_ON(idx >= ARRAY_SIZE(priv->iommus)))
+       if (WARN_ON(idx >= ARRAY_SIZE(priv->mmus)))
                return -EINVAL;
 
-       priv->iommus[idx] = iommu;
-
-       iommu_set_fault_handler(iommu, msm_fault_handler, dev);
-
-       /* need to iommu_attach_device() somewhere??  on resume?? */
+       priv->mmus[idx] = mmu;
 
        return idx;
 }
 
-int msm_iommu_attach(struct drm_device *dev, struct iommu_domain *iommu,
-               const char **names, int cnt)
-{
-       int i, ret;
-
-       for (i = 0; i < cnt; i++) {
-               /* TODO maybe some day msm iommu won't require this hack: */
-               struct device *msm_iommu_get_ctx(const char *ctx_name);
-               struct device *ctx = msm_iommu_get_ctx(names[i]);
-               if (!ctx)
-                       continue;
-               ret = iommu_attach_device(iommu, ctx);
-               if (ret) {
-                       dev_warn(dev->dev, "could not attach iommu to %s", names[i]);
-                       return ret;
-               }
-       }
-       return 0;
-}
-
 #ifdef CONFIG_DRM_MSM_REGISTER_LOGGING
 static bool reglog = false;
 MODULE_PARM_DESC(reglog, "Enable register read/write logging");
@@ -82,6 +52,10 @@ module_param(reglog, bool, 0600);
 #define reglog 0
 #endif
 
+static char *vram;
+MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU");
+module_param(vram, charp, 0);
+
 void __iomem *msm_ioremap(struct platform_device *pdev, const char *name,
                const char *dbgname)
 {
@@ -161,6 +135,14 @@ static int msm_unload(struct drm_device *dev)
                mutex_unlock(&dev->struct_mutex);
        }
 
+       if (priv->vram.paddr) {
+               DEFINE_DMA_ATTRS(attrs);
+               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+               drm_mm_takedown(&priv->vram.mm);
+               dma_free_attrs(dev->dev, priv->vram.size, NULL,
+                               priv->vram.paddr, &attrs);
+       }
+
        dev->dev_private = NULL;
 
        kfree(priv);
@@ -168,6 +150,24 @@ static int msm_unload(struct drm_device *dev)
        return 0;
 }
 
+static int get_mdp_ver(struct platform_device *pdev)
+{
+#ifdef CONFIG_OF
+       const static struct of_device_id match_types[] = { {
+               .compatible = "qcom,mdss_mdp",
+               .data   = (void *)5,
+       }, {
+               /* end node */
+       } };
+       struct device *dev = &pdev->dev;
+       const struct of_device_id *match;
+       match = of_match_node(match_types, dev->of_node);
+       if (match)
+               return (int)match->data;
+#endif
+       return 4;
+}
+
 static int msm_load(struct drm_device *dev, unsigned long flags)
 {
        struct platform_device *pdev = dev->platformdev;
@@ -191,7 +191,53 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
 
        drm_mode_config_init(dev);
 
-       kms = mdp4_kms_init(dev);
+       /* if we have no IOMMU, then we need to use carveout allocator.
+        * Grab the entire CMA chunk carved out in early startup in
+        * mach-msm:
+        */
+       if (!iommu_present(&platform_bus_type)) {
+               DEFINE_DMA_ATTRS(attrs);
+               unsigned long size;
+               void *p;
+
+               DBG("using %s VRAM carveout", vram);
+               size = memparse(vram, NULL);
+               priv->vram.size = size;
+
+               drm_mm_init(&priv->vram.mm, 0, (size >> PAGE_SHIFT) - 1);
+
+               dma_set_attr(DMA_ATTR_NO_KERNEL_MAPPING, &attrs);
+               dma_set_attr(DMA_ATTR_WRITE_COMBINE, &attrs);
+
+               /* note that for no-kernel-mapping, the vaddr returned
+                * is bogus, but non-null if allocation succeeded:
+                */
+               p = dma_alloc_attrs(dev->dev, size,
+                               &priv->vram.paddr, 0, &attrs);
+               if (!p) {
+                       dev_err(dev->dev, "failed to allocate VRAM\n");
+                       priv->vram.paddr = 0;
+                       ret = -ENOMEM;
+                       goto fail;
+               }
+
+               dev_info(dev->dev, "VRAM: %08x->%08x\n",
+                               (uint32_t)priv->vram.paddr,
+                               (uint32_t)(priv->vram.paddr + size));
+       }
+
+       switch (get_mdp_ver(pdev)) {
+       case 4:
+               kms = mdp4_kms_init(dev);
+               break;
+       case 5:
+               kms = mdp5_kms_init(dev);
+               break;
+       default:
+               kms = ERR_PTR(-ENODEV);
+               break;
+       }
+
        if (IS_ERR(kms)) {
                /*
                 * NOTE: once we have GPU support, having no kms should not
@@ -326,7 +372,7 @@ static void msm_lastclose(struct drm_device *dev)
        }
 }
 
-static irqreturn_t msm_irq(DRM_IRQ_ARGS)
+static irqreturn_t msm_irq(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct msm_drm_private *priv = dev->dev_private;
@@ -415,7 +461,7 @@ static int msm_gem_show(struct drm_device *dev, struct seq_file *m)
 
 static int msm_mm_show(struct drm_device *dev, struct seq_file *m)
 {
-       return drm_mm_dump_table(m, dev->mm_private);
+       return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);
 }
 
 static int msm_fb_show(struct drm_device *dev, struct seq_file *m)
@@ -778,12 +824,13 @@ static const struct dev_pm_ops msm_pm_ops = {
 
 static int msm_pdev_probe(struct platform_device *pdev)
 {
+       pdev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
        return drm_platform_init(&msm_driver, pdev);
 }
 
 static int msm_pdev_remove(struct platform_device *pdev)
 {
-       drm_platform_exit(&msm_driver, pdev);
+       drm_put_dev(platform_get_drvdata(pdev));
 
        return 0;
 }
@@ -793,12 +840,19 @@ static const struct platform_device_id msm_id[] = {
        { }
 };
 
+static const struct of_device_id dt_match[] = {
+       { .compatible = "qcom,mdss_mdp" },
+       {}
+};
+MODULE_DEVICE_TABLE(of, dt_match);
+
 static struct platform_driver msm_platform_driver = {
        .probe      = msm_pdev_probe,
        .remove     = msm_pdev_remove,
        .driver     = {
                .owner  = THIS_MODULE,
                .name   = "msm",
+               .of_match_table = dt_match,
                .pm     = &msm_pm_ops,
        },
        .id_table   = msm_id,
index d39f0862b19ebe8db2a74fdcedbb8a52086df3a7..3d63269c5b29c51e69bc0dfe7714dddae71e4fee 100644 (file)
 #include <linux/types.h>
 #include <asm/sizes.h>
 
+
+#if defined(CONFIG_COMPILE_TEST) && !defined(CONFIG_ARCH_MSM)
+/* stubs we need for compile-test: */
+static inline struct device *msm_iommu_get_ctx(const char *ctx_name)
+{
+       return NULL;
+}
+#endif
+
 #ifndef CONFIG_OF
 #include <mach/board.h>
 #include <mach/socinfo.h>
@@ -44,6 +53,7 @@
 
 struct msm_kms;
 struct msm_gpu;
+struct msm_mmu;
 
 #define NUM_DOMAINS 2    /* one for KMS, then one per gpu core (?) */
 
@@ -76,9 +86,9 @@ struct msm_drm_private {
        /* callbacks deferred until bo is inactive: */
        struct list_head fence_cbs;
 
-       /* registered IOMMU domains: */
-       unsigned int num_iommus;
-       struct iommu_domain *iommus[NUM_DOMAINS];
+       /* registered MMUs: */
+       unsigned int num_mmus;
+       struct msm_mmu *mmus[NUM_DOMAINS];
 
        unsigned int num_planes;
        struct drm_plane *planes[8];
@@ -94,6 +104,16 @@ struct msm_drm_private {
 
        unsigned int num_connectors;
        struct drm_connector *connectors[8];
+
+       /* VRAM carveout, used when no IOMMU: */
+       struct {
+               unsigned long size;
+               dma_addr_t paddr;
+               /* NOTE: mm managed at the page level, size is in # of pages
+                * and position mm_node->start is in # of pages:
+                */
+               struct drm_mm mm;
+       } vram;
 };
 
 struct msm_format {
@@ -114,39 +134,7 @@ void __msm_fence_worker(struct work_struct *work);
                (_cb)->func = _func;                         \
        } while (0)
 
-/* As there are different display controller blocks depending on the
- * snapdragon version, the kms support is split out and the appropriate
- * implementation is loaded at runtime.  The kms module is responsible
- * for constructing the appropriate planes/crtcs/encoders/connectors.
- */
-struct msm_kms_funcs {
-       /* hw initialization: */
-       int (*hw_init)(struct msm_kms *kms);
-       /* irq handling: */
-       void (*irq_preinstall)(struct msm_kms *kms);
-       int (*irq_postinstall)(struct msm_kms *kms);
-       void (*irq_uninstall)(struct msm_kms *kms);
-       irqreturn_t (*irq)(struct msm_kms *kms);
-       int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
-       void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
-       /* misc: */
-       const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format);
-       long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
-                       struct drm_encoder *encoder);
-       /* cleanup: */
-       void (*preclose)(struct msm_kms *kms, struct drm_file *file);
-       void (*destroy)(struct msm_kms *kms);
-};
-
-struct msm_kms {
-       const struct msm_kms_funcs *funcs;
-};
-
-struct msm_kms *mdp4_kms_init(struct drm_device *dev);
-
-int msm_register_iommu(struct drm_device *dev, struct iommu_domain *iommu);
-int msm_iommu_attach(struct drm_device *dev, struct iommu_domain *iommu,
-               const char **names, int cnt);
+int msm_register_mmu(struct drm_device *dev, struct msm_mmu *mmu);
 
 int msm_wait_fence_interruptable(struct drm_device *dev, uint32_t fence,
                struct timespec *timeout);
@@ -202,7 +190,9 @@ struct drm_framebuffer *msm_framebuffer_create(struct drm_device *dev,
 
 struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev);
 
-int hdmi_init(struct drm_device *dev, struct drm_encoder *encoder);
+struct hdmi;
+struct hdmi *hdmi_init(struct drm_device *dev, struct drm_encoder *encoder);
+irqreturn_t hdmi_irq(int irq, void *dev_id);
 void __init hdmi_register(void);
 void __exit hdmi_unregister(void);
 
index 0286c0eeb10ca1e967c27bf559928de58d14358f..81bafdf19ab39fc32428e6f5be692c597a6a8276 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include "msm_drv.h"
+#include "msm_kms.h"
 
 #include "drm_crtc.h"
 #include "drm_crtc_helper.h"
index e587d251c5900cd4532cdbff584d0683131616ed..d8d60c969ac7858bce0e6114f092a5f1aad450aa 100644 (file)
 #include "msm_drv.h"
 #include "msm_gem.h"
 #include "msm_gpu.h"
+#include "msm_mmu.h"
 
+static dma_addr_t physaddr(struct drm_gem_object *obj)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       struct msm_drm_private *priv = obj->dev->dev_private;
+       return (((dma_addr_t)msm_obj->vram_node->start) << PAGE_SHIFT) +
+                       priv->vram.paddr;
+}
+
+/* allocate pages from VRAM carveout, used when no IOMMU: */
+static struct page **get_pages_vram(struct drm_gem_object *obj,
+               int npages)
+{
+       struct msm_gem_object *msm_obj = to_msm_bo(obj);
+       struct msm_drm_private *priv = obj->dev->dev_private;
+       dma_addr_t paddr;
+       struct page **p;
+       int ret, i;
+
+       p = drm_malloc_ab(npages, sizeof(struct page *));
+       if (!p)
+               return ERR_PTR(-ENOMEM);
+
+       ret = drm_mm_insert_node(&priv->vram.mm, msm_obj->vram_node,
+                       npages, 0, DRM_MM_SEARCH_DEFAULT);
+       if (ret) {
+               drm_free_large(p);
+               return ERR_PTR(ret);
+       }
+
+       paddr = physaddr(obj);
+       for (i = 0; i < npages; i++) {
+               p[i] = phys_to_page(paddr);
+               paddr += PAGE_SIZE;
+       }
+
+       return p;
+}
 
 /* called with dev->struct_mutex held */
 static struct page **get_pages(struct drm_gem_object *obj)
@@ -31,9 +69,14 @@ static struct page **get_pages(struct drm_gem_object *obj)
 
        if (!msm_obj->pages) {
                struct drm_device *dev = obj->dev;
-               struct page **p = drm_gem_get_pages(obj, 0);
+               struct page **p;
                int npages = obj->size >> PAGE_SHIFT;
 
+               if (iommu_present(&platform_bus_type))
+                       p = drm_gem_get_pages(obj, 0);
+               else
+                       p = get_pages_vram(obj, npages);
+
                if (IS_ERR(p)) {
                        dev_err(dev->dev, "could not get pages: %ld\n",
                                        PTR_ERR(p));
@@ -73,7 +116,11 @@ static void put_pages(struct drm_gem_object *obj)
                sg_free_table(msm_obj->sgt);
                kfree(msm_obj->sgt);
 
-               drm_gem_put_pages(obj, msm_obj->pages, true, false);
+               if (iommu_present(&platform_bus_type))
+                       drm_gem_put_pages(obj, msm_obj->pages, true, false);
+               else
+                       drm_mm_remove_node(msm_obj->vram_node);
+
                msm_obj->pages = NULL;
        }
 }
@@ -138,7 +185,6 @@ int msm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct drm_gem_object *obj = vma->vm_private_data;
-       struct msm_gem_object *msm_obj = to_msm_bo(obj);
        struct drm_device *dev = obj->dev;
        struct page **pages;
        unsigned long pfn;
@@ -163,7 +209,7 @@ int msm_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        pgoff = ((unsigned long)vmf->virtual_address -
                        vma->vm_start) >> PAGE_SHIFT;
 
-       pfn = page_to_pfn(msm_obj->pages[pgoff]);
+       pfn = page_to_pfn(pages[pgoff]);
 
        VERB("Inserting %p pfn %lx, pa %lx", vmf->virtual_address,
                        pfn, pfn << PAGE_SHIFT);
@@ -219,67 +265,6 @@ uint64_t msm_gem_mmap_offset(struct drm_gem_object *obj)
        return offset;
 }
 
-/* helpers for dealing w/ iommu: */
-static int map_range(struct iommu_domain *domain, unsigned int iova,
-               struct sg_table *sgt, unsigned int len, int prot)
-{
-       struct scatterlist *sg;
-       unsigned int da = iova;
-       unsigned int i, j;
-       int ret;
-
-       if (!domain || !sgt)
-               return -EINVAL;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               u32 pa = sg_phys(sg) - sg->offset;
-               size_t bytes = sg->length + sg->offset;
-
-               VERB("map[%d]: %08x %08x(%x)", i, iova, pa, bytes);
-
-               ret = iommu_map(domain, da, pa, bytes, prot);
-               if (ret)
-                       goto fail;
-
-               da += bytes;
-       }
-
-       return 0;
-
-fail:
-       da = iova;
-
-       for_each_sg(sgt->sgl, sg, i, j) {
-               size_t bytes = sg->length + sg->offset;
-               iommu_unmap(domain, da, bytes);
-               da += bytes;
-       }
-       return ret;
-}
-
-static void unmap_range(struct iommu_domain *domain, unsigned int iova,
-               struct sg_table *sgt, unsigned int len)
-{
-       struct scatterlist *sg;
-       unsigned int da = iova;
-       int i;
-
-       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
-               size_t bytes = sg->length + sg->offset;
-               size_t unmapped;
-
-               unmapped = iommu_unmap(domain, da, bytes);
-               if (unmapped < bytes)
-                       break;
-
-               VERB("unmap[%d]: %08x(%x)", i, iova, bytes);
-
-               BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE));
-
-               da += bytes;
-       }
-}
-
 /* should be called under struct_mutex.. although it can be called
  * from atomic context without struct_mutex to acquire an extra
  * iova ref if you know one is already held.
@@ -295,15 +280,20 @@ int msm_gem_get_iova_locked(struct drm_gem_object *obj, int id,
 
        if (!msm_obj->domain[id].iova) {
                struct msm_drm_private *priv = obj->dev->dev_private;
-               uint32_t offset = (uint32_t)mmap_offset(obj);
-               struct page **pages;
-               pages = get_pages(obj);
+               struct msm_mmu *mmu = priv->mmus[id];
+               struct page **pages = get_pages(obj);
+
                if (IS_ERR(pages))
                        return PTR_ERR(pages);
-               // XXX ideally we would not map buffers writable when not needed...
-               ret = map_range(priv->iommus[id], offset, msm_obj->sgt,
-                               obj->size, IOMMU_READ | IOMMU_WRITE);
-               msm_obj->domain[id].iova = offset;
+
+               if (iommu_present(&platform_bus_type)) {
+                       uint32_t offset = (uint32_t)mmap_offset(obj);
+                       ret = mmu->funcs->map(mmu, offset, msm_obj->sgt,
+                                       obj->size, IOMMU_READ | IOMMU_WRITE);
+                       msm_obj->domain[id].iova = offset;
+               } else {
+                       msm_obj->domain[id].iova = physaddr(obj);
+               }
        }
 
        if (!ret)
@@ -514,6 +504,7 @@ void msm_gem_describe_objects(struct list_head *list, struct seq_file *m)
 void msm_gem_free_object(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
+       struct msm_drm_private *priv = obj->dev->dev_private;
        struct msm_gem_object *msm_obj = to_msm_bo(obj);
        int id;
 
@@ -525,11 +516,10 @@ void msm_gem_free_object(struct drm_gem_object *obj)
        list_del(&msm_obj->mm_list);
 
        for (id = 0; id < ARRAY_SIZE(msm_obj->domain); id++) {
-               if (msm_obj->domain[id].iova) {
-                       struct msm_drm_private *priv = obj->dev->dev_private;
+               struct msm_mmu *mmu = priv->mmus[id];
+               if (mmu && msm_obj->domain[id].iova) {
                        uint32_t offset = (uint32_t)mmap_offset(obj);
-                       unmap_range(priv->iommus[id], offset,
-                                       msm_obj->sgt, obj->size);
+                       mmu->funcs->unmap(mmu, offset, msm_obj->sgt, obj->size);
                }
        }
 
@@ -591,6 +581,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
 {
        struct msm_drm_private *priv = dev->dev_private;
        struct msm_gem_object *msm_obj;
+       unsigned sz;
 
        switch (flags & MSM_BO_CACHE_MASK) {
        case MSM_BO_UNCACHED:
@@ -603,10 +594,17 @@ static int msm_gem_new_impl(struct drm_device *dev,
                return -EINVAL;
        }
 
-       msm_obj = kzalloc(sizeof(*msm_obj), GFP_KERNEL);
+       sz = sizeof(*msm_obj);
+       if (!iommu_present(&platform_bus_type))
+               sz += sizeof(struct drm_mm_node);
+
+       msm_obj = kzalloc(sz, GFP_KERNEL);
        if (!msm_obj)
                return -ENOMEM;
 
+       if (!iommu_present(&platform_bus_type))
+               msm_obj->vram_node = (void *)&msm_obj[1];
+
        msm_obj->flags = flags;
 
        msm_obj->resv = &msm_obj->_resv;
@@ -623,7 +621,7 @@ static int msm_gem_new_impl(struct drm_device *dev,
 struct drm_gem_object *msm_gem_new(struct drm_device *dev,
                uint32_t size, uint32_t flags)
 {
-       struct drm_gem_object *obj;
+       struct drm_gem_object *obj = NULL;
        int ret;
 
        WARN_ON(!mutex_is_locked(&dev->struct_mutex));
@@ -634,9 +632,13 @@ struct drm_gem_object *msm_gem_new(struct drm_device *dev,
        if (ret)
                goto fail;
 
-       ret = drm_gem_object_init(dev, obj, size);
-       if (ret)
-               goto fail;
+       if (iommu_present(&platform_bus_type)) {
+               ret = drm_gem_object_init(dev, obj, size);
+               if (ret)
+                       goto fail;
+       } else {
+               drm_gem_private_object_init(dev, obj, size);
+       }
 
        return obj;
 
@@ -654,6 +656,12 @@ struct drm_gem_object *msm_gem_import(struct drm_device *dev,
        struct drm_gem_object *obj;
        int ret, npages;
 
+       /* if we don't have IOMMU, don't bother pretending we can import: */
+       if (!iommu_present(&platform_bus_type)) {
+               dev_err(dev->dev, "cannot import without IOMMU\n");
+               return ERR_PTR(-EINVAL);
+       }
+
        size = PAGE_ALIGN(size);
 
        ret = msm_gem_new_impl(dev, size, MSM_BO_WC, &obj);
index f4f23a578d9dc76fe4b7d03498729b099471694a..3246bb46c4f2add0636bca94b1b4c726542b1178 100644 (file)
@@ -57,6 +57,11 @@ struct msm_gem_object {
        /* normally (resv == &_resv) except for imported bo's */
        struct reservation_object *resv;
        struct reservation_object _resv;
+
+       /* For physically contiguous buffers.  Used when we don't have
+        * an IOMMU.
+        */
+       struct drm_mm_node *vram_node;
 };
 #define to_msm_bo(x) container_of(x, struct msm_gem_object, base)
 
index 4583d61556f5bed5c7d9cf9d26988d1160ddb386..4ebce8be489db6cdf51f6ba88fb8f7bfd1dbd5ce 100644 (file)
@@ -17,6 +17,7 @@
 
 #include "msm_gpu.h"
 #include "msm_gem.h"
+#include "msm_mmu.h"
 
 
 /*
 
 #ifdef CONFIG_MSM_BUS_SCALING
 #include <mach/board.h>
-#include <mach/kgsl.h>
-static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev)
+static void bs_init(struct msm_gpu *gpu)
 {
-       struct drm_device *dev = gpu->dev;
-       struct kgsl_device_platform_data *pdata;
-
-       if (!pdev) {
-               dev_err(dev->dev, "could not find dtv pdata\n");
-               return;
-       }
-
-       pdata = pdev->dev.platform_data;
-       if (pdata->bus_scale_table) {
-               gpu->bsc = msm_bus_scale_register_client(pdata->bus_scale_table);
+       if (gpu->bus_scale_table) {
+               gpu->bsc = msm_bus_scale_register_client(gpu->bus_scale_table);
                DBG("bus scale client: %08x", gpu->bsc);
        }
 }
@@ -59,7 +50,7 @@ static void bs_set(struct msm_gpu *gpu, int idx)
        }
 }
 #else
-static void bs_init(struct msm_gpu *gpu, struct platform_device *pdev) {}
+static void bs_init(struct msm_gpu *gpu) {}
 static void bs_fini(struct msm_gpu *gpu) {}
 static void bs_set(struct msm_gpu *gpu, int idx) {}
 #endif
@@ -363,6 +354,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                struct msm_gpu *gpu, const struct msm_gpu_funcs *funcs,
                const char *name, const char *ioname, const char *irqname, int ringsz)
 {
+       struct iommu_domain *iommu;
        int i, ret;
 
        gpu->dev = drm;
@@ -428,13 +420,14 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
         * and have separate page tables per context.  For now, to keep things
         * simple and to get something working, just use a single address space:
         */
-       gpu->iommu = iommu_domain_alloc(&platform_bus_type);
-       if (!gpu->iommu) {
-               dev_err(drm->dev, "failed to allocate IOMMU\n");
-               ret = -ENOMEM;
-               goto fail;
+       iommu = iommu_domain_alloc(&platform_bus_type);
+       if (iommu) {
+               dev_info(drm->dev, "%s: using IOMMU\n", name);
+               gpu->mmu = msm_iommu_new(drm, iommu);
+       } else {
+               dev_info(drm->dev, "%s: no IOMMU, fallback to VRAM carveout!\n", name);
        }
-       gpu->id = msm_register_iommu(drm, gpu->iommu);
+       gpu->id = msm_register_mmu(drm, gpu->mmu);
 
        /* Create ringbuffer: */
        gpu->rb = msm_ringbuffer_new(gpu, ringsz);
@@ -452,7 +445,7 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
                goto fail;
        }
 
-       bs_init(gpu, pdev);
+       bs_init(gpu);
 
        return 0;
 
@@ -474,6 +467,6 @@ void msm_gpu_cleanup(struct msm_gpu *gpu)
                msm_ringbuffer_destroy(gpu->rb);
        }
 
-       if (gpu->iommu)
-               iommu_domain_free(gpu->iommu);
+       if (gpu->mmu)
+               gpu->mmu->funcs->destroy(gpu->mmu);
 }
index 8cd829e520bb84b6bfa10d90fce8236cf9fbd3c5..458db8c64c28873f260aa59b44bbd96da7a3b18f 100644 (file)
@@ -78,14 +78,18 @@ struct msm_gpu {
        void __iomem *mmio;
        int irq;
 
-       struct iommu_domain *iommu;
+       struct msm_mmu *mmu;
        int id;
 
        /* Power Control: */
        struct regulator *gpu_reg, *gpu_cx;
        struct clk *ebi1_clk, *grp_clks[5];
        uint32_t fast_rate, slow_rate, bus_freq;
+
+#ifdef CONFIG_MSM_BUS_SCALING
+       struct msm_bus_scale_pdata *bus_scale_table;
        uint32_t bsc;
+#endif
 
        /* Hang Detction: */
 #define DRM_MSM_HANGCHECK_PERIOD 500 /* in ms */
diff --git a/drivers/gpu/drm/msm/msm_iommu.c b/drivers/gpu/drm/msm/msm_iommu.c
new file mode 100644 (file)
index 0000000..92b7459
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2013 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 "msm_drv.h"
+#include "msm_mmu.h"
+
+struct msm_iommu {
+       struct msm_mmu base;
+       struct iommu_domain *domain;
+};
+#define to_msm_iommu(x) container_of(x, struct msm_iommu, base)
+
+static int msm_fault_handler(struct iommu_domain *iommu, struct device *dev,
+               unsigned long iova, int flags, void *arg)
+{
+       DBG("*** fault: iova=%08lx, flags=%d", iova, flags);
+       return 0;
+}
+
+static int msm_iommu_attach(struct msm_mmu *mmu, const char **names, int cnt)
+{
+       struct drm_device *dev = mmu->dev;
+       struct msm_iommu *iommu = to_msm_iommu(mmu);
+       int i, ret;
+
+       for (i = 0; i < cnt; i++) {
+               struct device *msm_iommu_get_ctx(const char *ctx_name);
+               struct device *ctx = msm_iommu_get_ctx(names[i]);
+               if (IS_ERR_OR_NULL(ctx))
+                       continue;
+               ret = iommu_attach_device(iommu->domain, ctx);
+               if (ret) {
+                       dev_warn(dev->dev, "could not attach iommu to %s", names[i]);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+static int msm_iommu_map(struct msm_mmu *mmu, uint32_t iova,
+               struct sg_table *sgt, unsigned len, int prot)
+{
+       struct msm_iommu *iommu = to_msm_iommu(mmu);
+       struct iommu_domain *domain = iommu->domain;
+       struct scatterlist *sg;
+       unsigned int da = iova;
+       unsigned int i, j;
+       int ret;
+
+       if (!domain || !sgt)
+               return -EINVAL;
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               u32 pa = sg_phys(sg) - sg->offset;
+               size_t bytes = sg->length + sg->offset;
+
+               VERB("map[%d]: %08x %08x(%x)", i, iova, pa, bytes);
+
+               ret = iommu_map(domain, da, pa, bytes, prot);
+               if (ret)
+                       goto fail;
+
+               da += bytes;
+       }
+
+       return 0;
+
+fail:
+       da = iova;
+
+       for_each_sg(sgt->sgl, sg, i, j) {
+               size_t bytes = sg->length + sg->offset;
+               iommu_unmap(domain, da, bytes);
+               da += bytes;
+       }
+       return ret;
+}
+
+static int msm_iommu_unmap(struct msm_mmu *mmu, uint32_t iova,
+               struct sg_table *sgt, unsigned len)
+{
+       struct msm_iommu *iommu = to_msm_iommu(mmu);
+       struct iommu_domain *domain = iommu->domain;
+       struct scatterlist *sg;
+       unsigned int da = iova;
+       int i;
+
+       for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+               size_t bytes = sg->length + sg->offset;
+               size_t unmapped;
+
+               unmapped = iommu_unmap(domain, da, bytes);
+               if (unmapped < bytes)
+                       return unmapped;
+
+               VERB("unmap[%d]: %08x(%x)", i, iova, bytes);
+
+               BUG_ON(!IS_ALIGNED(bytes, PAGE_SIZE));
+
+               da += bytes;
+       }
+
+       return 0;
+}
+
+static void msm_iommu_destroy(struct msm_mmu *mmu)
+{
+       struct msm_iommu *iommu = to_msm_iommu(mmu);
+       iommu_domain_free(iommu->domain);
+       kfree(iommu);
+}
+
+static const struct msm_mmu_funcs funcs = {
+               .attach = msm_iommu_attach,
+               .map = msm_iommu_map,
+               .unmap = msm_iommu_unmap,
+               .destroy = msm_iommu_destroy,
+};
+
+struct msm_mmu *msm_iommu_new(struct drm_device *dev, struct iommu_domain *domain)
+{
+       struct msm_iommu *iommu;
+
+       iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
+       if (!iommu)
+               return ERR_PTR(-ENOMEM);
+
+       iommu->domain = domain;
+       msm_mmu_init(&iommu->base, dev, &funcs);
+       iommu_set_fault_handler(domain, msm_fault_handler, dev);
+
+       return &iommu->base;
+}
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
new file mode 100644 (file)
index 0000000..0643774
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2013 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/>.
+ */
+
+#ifndef __MSM_KMS_H__
+#define __MSM_KMS_H__
+
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+
+#include "msm_drv.h"
+
+/* As there are different display controller blocks depending on the
+ * snapdragon version, the kms support is split out and the appropriate
+ * implementation is loaded at runtime.  The kms module is responsible
+ * for constructing the appropriate planes/crtcs/encoders/connectors.
+ */
+struct msm_kms_funcs {
+       /* hw initialization: */
+       int (*hw_init)(struct msm_kms *kms);
+       /* irq handling: */
+       void (*irq_preinstall)(struct msm_kms *kms);
+       int (*irq_postinstall)(struct msm_kms *kms);
+       void (*irq_uninstall)(struct msm_kms *kms);
+       irqreturn_t (*irq)(struct msm_kms *kms);
+       int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
+       void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
+       /* misc: */
+       const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format);
+       long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
+                       struct drm_encoder *encoder);
+       /* cleanup: */
+       void (*preclose)(struct msm_kms *kms, struct drm_file *file);
+       void (*destroy)(struct msm_kms *kms);
+};
+
+struct msm_kms {
+       const struct msm_kms_funcs *funcs;
+
+       /* irq handling: */
+       bool in_irq;
+       struct list_head irq_list;    /* list of mdp4_irq */
+       uint32_t vblank_mask;         /* irq bits set for userspace vblank */
+};
+
+static inline void msm_kms_init(struct msm_kms *kms,
+               const struct msm_kms_funcs *funcs)
+{
+       kms->funcs = funcs;
+}
+
+struct msm_kms *mdp4_kms_init(struct drm_device *dev);
+struct msm_kms *mdp5_kms_init(struct drm_device *dev);
+
+#endif /* __MSM_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/msm_mmu.h b/drivers/gpu/drm/msm/msm_mmu.h
new file mode 100644 (file)
index 0000000..0303244
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2013 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/>.
+ */
+
+#ifndef __MSM_MMU_H__
+#define __MSM_MMU_H__
+
+#include <linux/iommu.h>
+
+struct msm_mmu_funcs {
+       int (*attach)(struct msm_mmu *mmu, const char **names, int cnt);
+       int (*map)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
+                       unsigned len, int prot);
+       int (*unmap)(struct msm_mmu *mmu, uint32_t iova, struct sg_table *sgt,
+                       unsigned len);
+       void (*destroy)(struct msm_mmu *mmu);
+};
+
+struct msm_mmu {
+       const struct msm_mmu_funcs *funcs;
+       struct drm_device *dev;
+};
+
+static inline void msm_mmu_init(struct msm_mmu *mmu, struct drm_device *dev,
+               const struct msm_mmu_funcs *funcs)
+{
+       mmu->dev = dev;
+       mmu->funcs = funcs;
+}
+
+struct msm_mmu *msm_iommu_new(struct drm_device *dev, struct iommu_domain *domain);
+struct msm_mmu *msm_gpummu_new(struct drm_device *dev, struct msm_gpu *gpu);
+
+#endif /* __MSM_MMU_H__ */
index b3fa1ba191b7115be412894936c3633bf9221188..e88145ba1bf515429a3b85753bde5df7d28bde70 100644 (file)
@@ -41,6 +41,7 @@ nouveau-y += core/subdev/bios/init.o
 nouveau-y += core/subdev/bios/mxm.o
 nouveau-y += core/subdev/bios/perf.o
 nouveau-y += core/subdev/bios/pll.o
+nouveau-y += core/subdev/bios/ramcfg.o
 nouveau-y += core/subdev/bios/rammap.o
 nouveau-y += core/subdev/bios/timing.o
 nouveau-y += core/subdev/bios/therm.o
@@ -71,7 +72,10 @@ nouveau-y += core/subdev/devinit/nv10.o
 nouveau-y += core/subdev/devinit/nv1a.o
 nouveau-y += core/subdev/devinit/nv20.o
 nouveau-y += core/subdev/devinit/nv50.o
+nouveau-y += core/subdev/devinit/nv84.o
+nouveau-y += core/subdev/devinit/nv98.o
 nouveau-y += core/subdev/devinit/nva3.o
+nouveau-y += core/subdev/devinit/nvaf.o
 nouveau-y += core/subdev/devinit/nvc0.o
 nouveau-y += core/subdev/fb/base.o
 nouveau-y += core/subdev/fb/nv04.o
@@ -232,6 +236,7 @@ nouveau-y += core/engine/fifo/nv50.o
 nouveau-y += core/engine/fifo/nv84.o
 nouveau-y += core/engine/fifo/nvc0.o
 nouveau-y += core/engine/fifo/nve0.o
+nouveau-y += core/engine/fifo/nv108.o
 nouveau-y += core/engine/graph/ctxnv40.o
 nouveau-y += core/engine/graph/ctxnv50.o
 nouveau-y += core/engine/graph/ctxnvc0.o
@@ -242,6 +247,7 @@ nouveau-y += core/engine/graph/ctxnvd7.o
 nouveau-y += core/engine/graph/ctxnvd9.o
 nouveau-y += core/engine/graph/ctxnve4.o
 nouveau-y += core/engine/graph/ctxnvf0.o
+nouveau-y += core/engine/graph/ctxnv108.o
 nouveau-y += core/engine/graph/nv04.o
 nouveau-y += core/engine/graph/nv10.o
 nouveau-y += core/engine/graph/nv20.o
@@ -260,6 +266,7 @@ nouveau-y += core/engine/graph/nvd7.o
 nouveau-y += core/engine/graph/nvd9.o
 nouveau-y += core/engine/graph/nve4.o
 nouveau-y += core/engine/graph/nvf0.o
+nouveau-y += core/engine/graph/nv108.o
 nouveau-y += core/engine/mpeg/nv31.o
 nouveau-y += core/engine/mpeg/nv40.o
 nouveau-y += core/engine/mpeg/nv44.o
index c8bed4a2683339072786a0b4d146b06c9594cc5b..1f6954ae9dd36e51141a9b810d91e49f1ddad2b2 100644 (file)
@@ -42,11 +42,24 @@ nouveau_engine_create_(struct nouveau_object *parent,
        if (ret)
                return ret;
 
-       if ( parent &&
-           !nouveau_boolopt(nv_device(parent)->cfgopt, iname, enable)) {
-               if (!enable)
-                       nv_warn(engine, "disabled, %s=1 to enable\n", iname);
-               return -ENODEV;
+       if (parent) {
+               struct nouveau_device *device = nv_device(parent);
+               int engidx = nv_engidx(nv_object(engine));
+
+               if (device->disable_mask & (1ULL << engidx)) {
+                       if (!nouveau_boolopt(device->cfgopt, iname, false)) {
+                               nv_debug(engine, "engine disabled by hw/fw\n");
+                               return -ENODEV;
+                       }
+
+                       nv_warn(engine, "ignoring hw/fw engine disable\n");
+               }
+
+               if (!nouveau_boolopt(device->cfgopt, iname, enable)) {
+                       if (!enable)
+                               nv_warn(engine, "disabled, %s=1 to enable\n", iname);
+                       return -ENODEV;
+               }
        }
 
        INIT_LIST_HEAD(&engine->contexts);
index 993df09ad64386e51ab7316e1dbc57de5cba5409..ac3291f781f6e4c204506e02d39d8ca521cf8917 100644 (file)
@@ -105,9 +105,6 @@ nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nvc0_copy_priv *priv;
        int ret;
 
-       if (nv_rd32(parent, 0x022500) & 0x00000100)
-               return -ENODEV;
-
        ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, true,
                                    "PCE0", "copy0", &priv);
        *pobject = nv_object(priv);
@@ -133,9 +130,6 @@ nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nvc0_copy_priv *priv;
        int ret;
 
-       if (nv_rd32(parent, 0x022500) & 0x00000200)
-               return -ENODEV;
-
        ret = nouveau_falcon_create(parent, engine, oclass, 0x105000, true,
                                    "PCE1", "copy1", &priv);
        *pobject = nv_object(priv);
index 30f1ef1edcc59db83deb0e12a41f6d1f399e23c6..748a61eb3c6f25fe4c08bed0a374b2148852e0f5 100644 (file)
@@ -88,9 +88,6 @@ nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nve0_copy_priv *priv;
        int ret;
 
-       if (nv_rd32(parent, 0x022500) & 0x00000100)
-               return -ENODEV;
-
        ret = nouveau_engine_create(parent, engine, oclass, true,
                                    "PCE0", "copy0", &priv);
        *pobject = nv_object(priv);
@@ -112,9 +109,6 @@ nve0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nve0_copy_priv *priv;
        int ret;
 
-       if (nv_rd32(parent, 0x022500) & 0x00000200)
-               return -ENODEV;
-
        ret = nouveau_engine_create(parent, engine, oclass, true,
                                    "PCE1", "copy1", &priv);
        *pobject = nv_object(priv);
index dbd2dde7b7e7649d2873c513d69a263b59329b77..32113b08c4d5fb16e401e871ec65080d61a63e7c 100644 (file)
@@ -49,12 +49,12 @@ nv04_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv04_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv04_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv04_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
@@ -67,12 +67,12 @@ nv04_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_VBIOS  ] = &nouveau_bios_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv05_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv05_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv04_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv04_fifo_oclass;
index 6e03dd6abeea51da34fe9e1046e50075fc481070..744f15d7e1315a6a3b9406f364d0a8bf78231cd5 100644 (file)
@@ -51,12 +51,12 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_GR     ] = &nv10_graph_oclass;
@@ -68,12 +68,12 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
@@ -87,12 +87,12 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
@@ -106,12 +106,12 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv1a_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
@@ -125,12 +125,12 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv10_fifo_oclass;
@@ -144,12 +144,12 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
@@ -163,12 +163,12 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv1a_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
@@ -182,12 +182,12 @@ nv10_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
index dcde53b9f07f7cd77f2886b8c8b927054691f289..27ba61fb271045c1efa9acd2982c48ce7b60f278 100644 (file)
@@ -52,12 +52,12 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv20_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
@@ -71,12 +71,12 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
@@ -90,12 +90,12 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
@@ -109,12 +109,12 @@ nv20_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv25_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
index 7b8662ef4f59193a91246ad074c8e87d84bb9019..fd47ace67543cd15f6be3c6b6799aefe497e4dcf 100644 (file)
@@ -52,12 +52,12 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv30_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
@@ -71,12 +71,12 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv04_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv35_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
@@ -90,12 +90,12 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv30_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
@@ -110,12 +110,12 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv20_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv20_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv36_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
@@ -130,12 +130,12 @@ nv30_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_GPIO   ] = &nv10_gpio_oclass;
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv04_clock_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv10_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv10_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv04_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv10_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv04_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv04_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
                device->oclass[NVDEV_ENGINE_FIFO   ] =  nv17_fifo_oclass;
index c8c41e93695ee3d0f83da140f0615cb737c14472..1b653dd74a7046ceaae41bca181f3097827dcccd 100644 (file)
@@ -57,12 +57,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -80,12 +80,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -103,12 +103,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -126,12 +126,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv41_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -149,12 +149,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv40_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv04_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -172,12 +172,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv47_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -195,12 +195,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -218,12 +218,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv40_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv49_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv41_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -241,12 +241,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -264,12 +264,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -287,12 +287,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv44_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -310,12 +310,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -333,12 +333,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv4e_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv4e_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -356,12 +356,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -379,12 +379,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
@@ -402,12 +402,12 @@ nv40_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_I2C    ] = &nv04_i2c_oclass;
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nv40_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv40_therm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv1a_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv1a_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv44_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv31_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv46_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv40_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv40_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv44_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nv04_dmaeng_oclass;
index db3fc7be856a733d07f8431a182326e3f20b4182..81d5c26643d50dcff2067abdf0f2bb7a227621ad 100644 (file)
@@ -65,12 +65,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv50_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv50_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv50_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv50_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -90,12 +90,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -118,12 +118,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -146,12 +146,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv50_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv50_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -174,12 +174,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv94_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -202,12 +202,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv94_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -230,12 +230,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv98_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -258,12 +258,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nv84_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv84_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nv84_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -286,12 +286,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nvaa_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv98_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvaa_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -314,12 +314,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] =  nvaa_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nv84_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nv50_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nv98_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvaa_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
@@ -342,12 +342,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nva3_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nva3_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
@@ -372,12 +372,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nva3_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nva3_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
@@ -401,12 +401,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nva3_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nva3_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
@@ -430,12 +430,12 @@ nv50_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nva3_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nva3_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvaf_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nv98_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nv94_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvaf_fb_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nv50_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nv50_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nva3_pwr_oclass;
index dbc5e33de94f8b6caebbab7319d3bfb7117c57f2..b7d66b59f43d4c7cc3ea0c733f809f966c37aa3d 100644 (file)
@@ -65,14 +65,14 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
@@ -97,14 +97,14 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
@@ -129,14 +129,14 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
@@ -160,14 +160,14 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
@@ -192,14 +192,14 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
@@ -224,14 +224,14 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
@@ -255,14 +255,14 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nva3_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc0_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvc0_pwr_oclass;
@@ -287,14 +287,14 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
@@ -318,14 +318,14 @@ nvc0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nvc0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nvc0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nvc0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
index 3900104976fc7bfc2ca3df441318254bdae3bf97..987edbc30a0917cc2db2a035c749f42c5818b5b9 100644 (file)
@@ -65,14 +65,14 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
@@ -98,14 +98,14 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
@@ -131,14 +131,14 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
@@ -164,14 +164,14 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nvd0_pwr_oclass;
@@ -199,29 +199,27 @@ nve0_identify(struct nouveau_device *device)
                device->oclass[NVDEV_SUBDEV_CLOCK  ] = &nve0_clock_oclass;
                device->oclass[NVDEV_SUBDEV_THERM  ] = &nvd0_therm_oclass;
                device->oclass[NVDEV_SUBDEV_MXM    ] = &nv50_mxm_oclass;
-               device->oclass[NVDEV_SUBDEV_DEVINIT] = &nvc0_devinit_oclass;
+               device->oclass[NVDEV_SUBDEV_DEVINIT] =  nvc0_devinit_oclass;
                device->oclass[NVDEV_SUBDEV_MC     ] =  nvc3_mc_oclass;
                device->oclass[NVDEV_SUBDEV_BUS    ] =  nvc0_bus_oclass;
                device->oclass[NVDEV_SUBDEV_TIMER  ] = &nv04_timer_oclass;
                device->oclass[NVDEV_SUBDEV_FB     ] =  nve0_fb_oclass;
                device->oclass[NVDEV_SUBDEV_LTCG   ] = &nvc0_ltcg_oclass;
                device->oclass[NVDEV_SUBDEV_IBUS   ] = &nve0_ibus_oclass;
-               device->oclass[NVDEV_SUBDEV_INSTMEM] = &nv50_instmem_oclass;
+               device->oclass[NVDEV_SUBDEV_INSTMEM] =  nv50_instmem_oclass;
                device->oclass[NVDEV_SUBDEV_VM     ] = &nvc0_vmmgr_oclass;
                device->oclass[NVDEV_SUBDEV_BAR    ] = &nvc0_bar_oclass;
                device->oclass[NVDEV_SUBDEV_PWR    ] = &nv108_pwr_oclass;
                device->oclass[NVDEV_SUBDEV_VOLT   ] = &nv40_volt_oclass;
                device->oclass[NVDEV_ENGINE_DMAOBJ ] = &nvd0_dmaeng_oclass;
-#if 0
-               device->oclass[NVDEV_ENGINE_FIFO   ] =  nve0_fifo_oclass;
+               device->oclass[NVDEV_ENGINE_FIFO   ] =  nv108_fifo_oclass;
                device->oclass[NVDEV_ENGINE_SW     ] =  nvc0_software_oclass;
-               device->oclass[NVDEV_ENGINE_GR     ] =  nvf0_graph_oclass;
-#endif
+               device->oclass[NVDEV_ENGINE_GR     ] =  nv108_graph_oclass;
                device->oclass[NVDEV_ENGINE_DISP   ] = &nvf0_disp_oclass;
-#if 0
                device->oclass[NVDEV_ENGINE_COPY0  ] = &nve0_copy0_oclass;
                device->oclass[NVDEV_ENGINE_COPY1  ] = &nve0_copy1_oclass;
                device->oclass[NVDEV_ENGINE_COPY2  ] = &nve0_copy2_oclass;
+#if 0
                device->oclass[NVDEV_ENGINE_BSP    ] = &nve0_bsp_oclass;
                device->oclass[NVDEV_ENGINE_VP     ] = &nve0_vp_oclass;
                device->oclass[NVDEV_ENGINE_PPP    ] = &nvc0_ppp_oclass;
index a0bc8a89b69941b1bcf449084ce1dcea9a2ff666..7cf8b13486326fdcf64066cb368203668024d11a 100644 (file)
@@ -31,9 +31,45 @@ struct nv04_disp_priv {
        struct nouveau_disp base;
 };
 
+static int
+nv04_disp_scanoutpos(struct nouveau_object *object, u32 mthd,
+                    void *data, u32 size)
+{
+       struct nv04_disp_priv *priv = (void *)object->engine;
+       struct nv04_display_scanoutpos *args = data;
+       const int head = (mthd & NV04_DISP_MTHD_HEAD);
+       u32 line;
+
+       if (size < sizeof(*args))
+               return -EINVAL;
+
+       args->vblanks = nv_rd32(priv, 0x680800 + (head * 0x2000)) & 0xffff;
+       args->vtotal  = nv_rd32(priv, 0x680804 + (head * 0x2000)) & 0xffff;
+       args->vblanke = args->vtotal - 1;
+
+       args->hblanks = nv_rd32(priv, 0x680820 + (head * 0x2000)) & 0xffff;
+       args->htotal  = nv_rd32(priv, 0x680824 + (head * 0x2000)) & 0xffff;
+       args->hblanke = args->htotal - 1;
+
+       args->time[0] = ktime_to_ns(ktime_get());
+       line = nv_rd32(priv, 0x600868 + (head * 0x2000));
+       args->time[1] = ktime_to_ns(ktime_get());
+       args->hline = (line & 0xffff0000) >> 16;
+       args->vline = (line & 0x0000ffff);
+       return 0;
+}
+
+#define HEAD_MTHD(n) (n), (n) + 0x01
+
+static struct nouveau_omthds
+nv04_disp_omthds[] = {
+       { HEAD_MTHD(NV04_DISP_SCANOUTPOS), nv04_disp_scanoutpos },
+       {}
+};
+
 static struct nouveau_oclass
 nv04_disp_sclass[] = {
-       { NV04_DISP_CLASS, &nouveau_object_ofuncs },
+       { NV04_DISP_CLASS, &nouveau_object_ofuncs, nv04_disp_omthds },
        {},
 };
 
index c168ae3eaa97cab0a18e6a10b9ee811e815a5a66..940eaa5d8b9a4bb0e3ea224cfe2ced8ec8585b44 100644 (file)
@@ -541,6 +541,35 @@ nv50_disp_curs_ofuncs = {
  * Base display object
  ******************************************************************************/
 
+int
+nv50_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
+                         void *data, u32 size)
+{
+       struct nv50_disp_priv *priv = (void *)object->engine;
+       struct nv04_display_scanoutpos *args = data;
+       const int head = (mthd & NV50_DISP_MTHD_HEAD);
+       u32 blanke, blanks, total;
+
+       if (size < sizeof(*args) || head >= priv->head.nr)
+               return -EINVAL;
+       blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
+       blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
+       total  = nv_rd32(priv, 0x610afc + (head * 0x540));
+
+       args->vblanke = (blanke & 0xffff0000) >> 16;
+       args->hblanke = (blanke & 0x0000ffff);
+       args->vblanks = (blanks & 0xffff0000) >> 16;
+       args->hblanks = (blanks & 0x0000ffff);
+       args->vtotal  = ( total & 0xffff0000) >> 16;
+       args->htotal  = ( total & 0x0000ffff);
+
+       args->time[0] = ktime_to_ns(ktime_get());
+       args->vline   = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+       args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
+       args->hline   = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+       return 0;
+}
+
 static void
 nv50_disp_base_vblank_enable(struct nouveau_event *event, int head)
 {
@@ -675,6 +704,7 @@ nv50_disp_base_ofuncs = {
 
 static struct nouveau_omthds
 nv50_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
        { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
        { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
        { DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
index 1ae6ceb5670403b0150f931f2cb01815a4a56569..d31d426ea1f6327c96d77e21210d0b792ba87505 100644 (file)
@@ -43,6 +43,10 @@ struct nv50_disp_priv {
        } pior;
 };
 
+#define HEAD_MTHD(n) (n), (n) + 0x03
+
+int nv50_disp_base_scanoutpos(struct nouveau_object *, u32, void *, u32);
+
 #define DAC_MTHD(n) (n), (n) + 0x03
 
 int nv50_dac_mthd(struct nouveau_object *, u32, void *, u32);
@@ -132,13 +136,12 @@ void nv50_disp_intr(struct nouveau_subdev *);
 
 extern struct nouveau_omthds nv84_disp_base_omthds[];
 
-extern struct nouveau_omthds nva3_disp_base_omthds[];
-
 extern struct nouveau_ofuncs nvd0_disp_mast_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_sync_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_ovly_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_oimm_ofuncs;
 extern struct nouveau_ofuncs nvd0_disp_curs_ofuncs;
+extern struct nouveau_omthds nvd0_disp_base_omthds[];
 extern struct nouveau_ofuncs nvd0_disp_base_ofuncs;
 extern struct nouveau_oclass nvd0_disp_cclass;
 void nvd0_disp_intr_supervisor(struct work_struct *);
index d8c74c0883a16904b92081857552182721eca183..ef9ce300a496e0dc1c5baae4c5f1a041d112ea2a 100644 (file)
@@ -41,6 +41,7 @@ nv84_disp_sclass[] = {
 
 struct nouveau_omthds
 nv84_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
        { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
        { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
        { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
index a66f949c1f84119479f5c5ffbe809fad278db4d2..a518543c00ab624f8df1b4fd22e66293943b8f02 100644 (file)
@@ -41,6 +41,7 @@ nv94_disp_sclass[] = {
 
 static struct nouveau_omthds
 nv94_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
        { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
        { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
        { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
index b75413169eaee91e07dd73dd08e1a7efada6ed34..6ad6dcece43bde52062c5c4563662586dfaef7d6 100644 (file)
@@ -39,8 +39,9 @@ nva3_disp_sclass[] = {
        {}
 };
 
-struct nouveau_omthds
+static struct nouveau_omthds
 nva3_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nv50_disp_base_scanoutpos },
        { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
        { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD)     , nv50_sor_mthd },
        { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
index 378a015091d2bf22d9a2ba5e49cd095b3ac774c7..1c5e4e8b2c822b37a140932d5b5378d5d2deb309 100644 (file)
@@ -440,6 +440,36 @@ nvd0_disp_curs_ofuncs = {
  * Base display object
  ******************************************************************************/
 
+static int
+nvd0_disp_base_scanoutpos(struct nouveau_object *object, u32 mthd,
+                         void *data, u32 size)
+{
+       struct nv50_disp_priv *priv = (void *)object->engine;
+       struct nv04_display_scanoutpos *args = data;
+       const int head = (mthd & NV50_DISP_MTHD_HEAD);
+       u32 blanke, blanks, total;
+
+       if (size < sizeof(*args) || head >= priv->head.nr)
+               return -EINVAL;
+
+       total  = nv_rd32(priv, 0x640414 + (head * 0x300));
+       blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
+       blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
+
+       args->vblanke = (blanke & 0xffff0000) >> 16;
+       args->hblanke = (blanke & 0x0000ffff);
+       args->vblanks = (blanks & 0xffff0000) >> 16;
+       args->hblanks = (blanks & 0x0000ffff);
+       args->vtotal  = ( total & 0xffff0000) >> 16;
+       args->htotal  = ( total & 0x0000ffff);
+
+       args->time[0] = ktime_to_ns(ktime_get());
+       args->vline   = nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+       args->time[1] = ktime_to_ns(ktime_get()); /* vline read locks hline */
+       args->hline   = nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+       return 0;
+}
+
 static void
 nvd0_disp_base_vblank_enable(struct nouveau_event *event, int head)
 {
@@ -573,9 +603,24 @@ nvd0_disp_base_ofuncs = {
        .fini = nvd0_disp_base_fini,
 };
 
+struct nouveau_omthds
+nvd0_disp_base_omthds[] = {
+       { HEAD_MTHD(NV50_DISP_SCANOUTPOS)     , nvd0_disp_base_scanoutpos },
+       { SOR_MTHD(NV50_DISP_SOR_PWR)         , nv50_sor_mthd },
+       { SOR_MTHD(NVA3_DISP_SOR_HDA_ELD)     , nv50_sor_mthd },
+       { SOR_MTHD(NV84_DISP_SOR_HDMI_PWR)    , nv50_sor_mthd },
+       { SOR_MTHD(NV50_DISP_SOR_LVDS_SCRIPT) , nv50_sor_mthd },
+       { DAC_MTHD(NV50_DISP_DAC_PWR)         , nv50_dac_mthd },
+       { DAC_MTHD(NV50_DISP_DAC_LOAD)        , nv50_dac_mthd },
+       { PIOR_MTHD(NV50_DISP_PIOR_PWR)       , nv50_pior_mthd },
+       { PIOR_MTHD(NV50_DISP_PIOR_TMDS_PWR)  , nv50_pior_mthd },
+       { PIOR_MTHD(NV50_DISP_PIOR_DP_PWR)    , nv50_pior_mthd },
+       {},
+};
+
 static struct nouveau_oclass
 nvd0_disp_base_oclass[] = {
-       { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
+       { NVD0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
        {}
 };
 
@@ -967,9 +1012,6 @@ nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        int heads = nv_rd32(parent, 0x022448);
        int ret;
 
-       if (nv_rd32(parent, 0x022500) & 0x00000001)
-               return -ENODEV;
-
        ret = nouveau_disp_create(parent, engine, oclass, heads,
                                  "PDISP", "display", &priv);
        *pobject = nv_object(priv);
index fb1fe6ae5e74ddbd6f3336a3d34de8eb58757b5b..ab63f32c00b2478d2cb0a2ebd062f946d394044d 100644 (file)
@@ -41,7 +41,7 @@ nve0_disp_sclass[] = {
 
 static struct nouveau_oclass
 nve0_disp_base_oclass[] = {
-       { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
+       { NVE0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
        {}
 };
 
@@ -54,9 +54,6 @@ nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        int heads = nv_rd32(parent, 0x022448);
        int ret;
 
-       if (nv_rd32(parent, 0x022500) & 0x00000001)
-               return -ENODEV;
-
        ret = nouveau_disp_create(parent, engine, oclass, heads,
                                  "PDISP", "display", &priv);
        *pobject = nv_object(priv);
index 42aa6b97dbea3c5867676f0209151a1ead3a849d..05fee10e0c975a166fec5b68d98d6e53cd1fae55 100644 (file)
@@ -41,7 +41,7 @@ nvf0_disp_sclass[] = {
 
 static struct nouveau_oclass
 nvf0_disp_base_oclass[] = {
-       { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nva3_disp_base_omthds },
+       { NVF0_DISP_CLASS, &nvd0_disp_base_ofuncs, nvd0_disp_base_omthds },
        {}
 };
 
@@ -54,9 +54,6 @@ nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        int heads = nv_rd32(parent, 0x022448);
        int ret;
 
-       if (nv_rd32(parent, 0x022500) & 0x00000001)
-               return -ENODEV;
-
        ret = nouveau_disp_create(parent, engine, oclass, heads,
                                  "PDISP", "display", &priv);
        *pobject = nv_object(priv);
index 5a1c68474597cbc979eb216735941714b1ce4901..8836c3cb99c3862a84ed2b946e6c3e34c47e520d 100644 (file)
@@ -138,10 +138,15 @@ nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value)
 bool
 nv_lockvgac(void *obj, bool lock)
 {
+       struct nouveau_device *dev = nv_device(obj);
+
        bool locked = !nv_rdvgac(obj, 0, 0x1f);
        u8 data = lock ? 0x99 : 0x57;
-       nv_wrvgac(obj, 0, 0x1f, data);
-       if (nv_device(obj)->chipset == 0x11) {
+       if (dev->card_type < NV_50)
+               nv_wrvgac(obj, 0, 0x1f, data);
+       else
+               nv_wrvgac(obj, 0, 0x3f, data);
+       if (dev->chipset == 0x11) {
                if (!(nv_rd32(obj, 0x001084) & 0x10000000))
                        nv_wrvgac(obj, 1, 0x1f, data);
        }
index e03fc8e4dc1dac8c8262a93b2b0b812dcae60841..5e077e4ed7f6aa23d0e8ed3fde50ad58c2fd99d7 100644 (file)
@@ -56,6 +56,16 @@ _nouveau_falcon_wr32(struct nouveau_object *object, u64 addr, u32 data)
        nv_wr32(falcon, falcon->addr + addr, data);
 }
 
+static void *
+vmemdup(const void *src, size_t len)
+{
+       void *p = vmalloc(len);
+
+       if (p)
+               memcpy(p, src, len);
+       return p;
+}
+
 int
 _nouveau_falcon_init(struct nouveau_object *object)
 {
@@ -111,7 +121,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
 
                ret = request_firmware(&fw, name, &device->pdev->dev);
                if (ret == 0) {
-                       falcon->code.data = kmemdup(fw->data, fw->size, GFP_KERNEL);
+                       falcon->code.data = vmemdup(fw->data, fw->size);
                        falcon->code.size = fw->size;
                        falcon->data.data = NULL;
                        falcon->data.size = 0;
@@ -134,7 +144,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
                        return ret;
                }
 
-               falcon->data.data = kmemdup(fw->data, fw->size, GFP_KERNEL);
+               falcon->data.data = vmemdup(fw->data, fw->size);
                falcon->data.size = fw->size;
                release_firmware(fw);
                if (!falcon->data.data)
@@ -149,7 +159,7 @@ _nouveau_falcon_init(struct nouveau_object *object)
                        return ret;
                }
 
-               falcon->code.data = kmemdup(fw->data, fw->size, GFP_KERNEL);
+               falcon->code.data = vmemdup(fw->data, fw->size);
                falcon->code.size = fw->size;
                release_firmware(fw);
                if (!falcon->code.data)
@@ -235,8 +245,8 @@ _nouveau_falcon_fini(struct nouveau_object *object, bool suspend)
        if (!suspend) {
                nouveau_gpuobj_ref(NULL, &falcon->core);
                if (falcon->external) {
-                       kfree(falcon->data.data);
-                       kfree(falcon->code.data);
+                       vfree(falcon->data.data);
+                       vfree(falcon->code.data);
                        falcon->code.data = NULL;
                }
        }
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c
new file mode 100644 (file)
index 0000000..09362a5
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * 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 "nve0.h"
+
+struct nouveau_oclass *
+nv108_fifo_oclass = &(struct nve0_fifo_impl) {
+       .base.handle = NV_ENGINE(FIFO, 0x08),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nve0_fifo_ctor,
+               .dtor = nve0_fifo_dtor,
+               .init = nve0_fifo_init,
+               .fini = _nouveau_fifo_fini,
+       },
+       .channels = 1024,
+}.base;
index 9ac94d4e5646d2cd24579f3b47777f2e17f5e9fe..b22a33f0702dd0159ed01f79edb00b7349f6b561 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <subdev/timer.h>
 #include <subdev/bar.h>
+#include <subdev/fb.h>
 #include <subdev/vm.h>
 
 #include <engine/dmaobj.h>
index 04f412922d2d43f5a5fbce11185fc2f9f4196e7e..9a850fe19515fe2ddcd513c3497c7d87c86cba8a 100644 (file)
 
 #include <subdev/timer.h>
 #include <subdev/bar.h>
+#include <subdev/fb.h>
 #include <subdev/vm.h>
 
 #include <engine/dmaobj.h>
-#include <engine/fifo.h>
+
+#include "nve0.h"
 
 #define _(a,b) { (a), ((1ULL << (a)) | (b)) }
 static const struct {
@@ -56,8 +58,8 @@ static const struct {
 #define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine)
 
 struct nve0_fifo_engn {
-       struct nouveau_gpuobj *playlist[2];
-       int cur_playlist;
+       struct nouveau_gpuobj *runlist[2];
+       int cur_runlist;
 };
 
 struct nve0_fifo_priv {
@@ -86,7 +88,7 @@ struct nve0_fifo_chan {
  ******************************************************************************/
 
 static void
-nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine)
+nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine)
 {
        struct nouveau_bar *bar = nouveau_bar(priv);
        struct nve0_fifo_engn *engn = &priv->engine[engine];
@@ -95,8 +97,8 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine)
        int i, p;
 
        mutex_lock(&nv_subdev(priv)->mutex);
-       cur = engn->playlist[engn->cur_playlist];
-       engn->cur_playlist = !engn->cur_playlist;
+       cur = engn->runlist[engn->cur_runlist];
+       engn->cur_runlist = !engn->cur_runlist;
 
        for (i = 0, p = 0; i < priv->base.max; i++) {
                u32 ctrl = nv_rd32(priv, 0x800004 + (i * 8)) & 0x001f0001;
@@ -111,7 +113,7 @@ nve0_fifo_playlist_update(struct nve0_fifo_priv *priv, u32 engine)
        nv_wr32(priv, 0x002270, cur->addr >> 12);
        nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
        if (!nv_wait(priv, 0x002284 + (engine * 4), 0x00100000, 0x00000000))
-               nv_error(priv, "playlist %d update timeout\n", engine);
+               nv_error(priv, "runlist %d update timeout\n", engine);
        mutex_unlock(&nv_subdev(priv)->mutex);
 }
 
@@ -278,7 +280,7 @@ nve0_fifo_chan_init(struct nouveau_object *object)
        nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
        nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
        nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
-       nve0_fifo_playlist_update(priv, chan->engine);
+       nve0_fifo_runlist_update(priv, chan->engine);
        nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
        return 0;
 }
@@ -291,7 +293,7 @@ nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
        u32 chid = chan->base.chid;
 
        nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
-       nve0_fifo_playlist_update(priv, chan->engine);
+       nve0_fifo_runlist_update(priv, chan->engine);
        nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
 
        return nouveau_fifo_channel_fini(&chan->base, suspend);
@@ -375,54 +377,189 @@ nve0_fifo_cclass = {
  * PFIFO engine
  ******************************************************************************/
 
-static const struct nouveau_enum nve0_fifo_fault_unit[] = {
+static const struct nouveau_enum nve0_fifo_sched_reason[] = {
+       { 0x0a, "CTXSW_TIMEOUT" },
+       {}
+};
+
+static const struct nouveau_enum nve0_fifo_fault_engine[] = {
+       { 0x00, "GR", NULL, NVDEV_ENGINE_GR },
+       { 0x03, "IFB" },
+       { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
+       { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
+       { 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO },
+       { 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO },
+       { 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO },
+       { 0x10, "MSVLD", NULL, NVDEV_ENGINE_BSP },
+       { 0x11, "MSPPP", NULL, NVDEV_ENGINE_PPP },
+       { 0x13, "PERF" },
+       { 0x14, "MSPDEC", NULL, NVDEV_ENGINE_VP },
+       { 0x15, "CE0", NULL, NVDEV_ENGINE_COPY0 },
+       { 0x16, "CE1", NULL, NVDEV_ENGINE_COPY1 },
+       { 0x17, "PMU" },
+       { 0x19, "MSENC", NULL, NVDEV_ENGINE_VENC },
+       { 0x1b, "CE2", NULL, NVDEV_ENGINE_COPY2 },
        {}
 };
 
 static const struct nouveau_enum nve0_fifo_fault_reason[] = {
-       { 0x00, "PT_NOT_PRESENT" },
-       { 0x01, "PT_TOO_SHORT" },
-       { 0x02, "PAGE_NOT_PRESENT" },
-       { 0x03, "VM_LIMIT_EXCEEDED" },
-       { 0x04, "NO_CHANNEL" },
-       { 0x05, "PAGE_SYSTEM_ONLY" },
-       { 0x06, "PAGE_READ_ONLY" },
-       { 0x0a, "COMPRESSED_SYSRAM" },
-       { 0x0c, "INVALID_STORAGE_TYPE" },
+       { 0x00, "PDE" },
+       { 0x01, "PDE_SIZE" },
+       { 0x02, "PTE" },
+       { 0x03, "VA_LIMIT_VIOLATION" },
+       { 0x04, "UNBOUND_INST_BLOCK" },
+       { 0x05, "PRIV_VIOLATION" },
+       { 0x06, "RO_VIOLATION" },
+       { 0x07, "WO_VIOLATION" },
+       { 0x08, "PITCH_MASK_VIOLATION" },
+       { 0x09, "WORK_CREATION" },
+       { 0x0a, "UNSUPPORTED_APERTURE" },
+       { 0x0b, "COMPRESSION_FAILURE" },
+       { 0x0c, "UNSUPPORTED_KIND" },
+       { 0x0d, "REGION_VIOLATION" },
+       { 0x0e, "BOTH_PTES_VALID" },
+       { 0x0f, "INFO_TYPE_POISONED" },
        {}
 };
 
 static const struct nouveau_enum nve0_fifo_fault_hubclient[] = {
+       { 0x00, "VIP" },
+       { 0x01, "CE0" },
+       { 0x02, "CE1" },
+       { 0x03, "DNISO" },
+       { 0x04, "FE" },
+       { 0x05, "FECS" },
+       { 0x06, "HOST" },
+       { 0x07, "HOST_CPU" },
+       { 0x08, "HOST_CPU_NB" },
+       { 0x09, "ISO" },
+       { 0x0a, "MMU" },
+       { 0x0b, "MSPDEC" },
+       { 0x0c, "MSPPP" },
+       { 0x0d, "MSVLD" },
+       { 0x0e, "NISO" },
+       { 0x0f, "P2P" },
+       { 0x10, "PD" },
+       { 0x11, "PERF" },
+       { 0x12, "PMU" },
+       { 0x13, "RASTERTWOD" },
+       { 0x14, "SCC" },
+       { 0x15, "SCC_NB" },
+       { 0x16, "SEC" },
+       { 0x17, "SSYNC" },
+       { 0x18, "GR_COPY" },
+       { 0x19, "CE2" },
+       { 0x1a, "XV" },
+       { 0x1b, "MMU_NB" },
+       { 0x1c, "MSENC" },
+       { 0x1d, "DFALCON" },
+       { 0x1e, "SKED" },
+       { 0x1f, "AFALCON" },
        {}
 };
 
 static const struct nouveau_enum nve0_fifo_fault_gpcclient[] = {
+       { 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" },
+       { 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" },
+       { 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" },
+       { 0x09, "L1_3" }, { 0x0a, "T1_3" }, { 0x0b, "PE_3" },
+       { 0x0c, "RAST" },
+       { 0x0d, "GCC" },
+       { 0x0e, "GPCCS" },
+       { 0x0f, "PROP_0" },
+       { 0x10, "PROP_1" },
+       { 0x11, "PROP_2" },
+       { 0x12, "PROP_3" },
+       { 0x13, "L1_4" }, { 0x14, "T1_4" }, { 0x15, "PE_4" },
+       { 0x16, "L1_5" }, { 0x17, "T1_5" }, { 0x18, "PE_5" },
+       { 0x19, "L1_6" }, { 0x1a, "T1_6" }, { 0x1b, "PE_6" },
+       { 0x1c, "L1_7" }, { 0x1d, "T1_7" }, { 0x1e, "PE_7" },
+       { 0x1f, "GPM" },
+       { 0x20, "LTP_UTLB_0" },
+       { 0x21, "LTP_UTLB_1" },
+       { 0x22, "LTP_UTLB_2" },
+       { 0x23, "LTP_UTLB_3" },
+       { 0x24, "GPC_RGG_UTLB" },
        {}
 };
 
-static const struct nouveau_bitfield nve0_fifo_subfifo_intr[] = {
-       { 0x00200000, "ILLEGAL_MTHD" },
-       { 0x00800000, "EMPTY_SUBC" },
+static const struct nouveau_bitfield nve0_fifo_pbdma_intr[] = {
+       { 0x00000001, "MEMREQ" },
+       { 0x00000002, "MEMACK_TIMEOUT" },
+       { 0x00000004, "MEMACK_EXTRA" },
+       { 0x00000008, "MEMDAT_TIMEOUT" },
+       { 0x00000010, "MEMDAT_EXTRA" },
+       { 0x00000020, "MEMFLUSH" },
+       { 0x00000040, "MEMOP" },
+       { 0x00000080, "LBCONNECT" },
+       { 0x00000100, "LBREQ" },
+       { 0x00000200, "LBACK_TIMEOUT" },
+       { 0x00000400, "LBACK_EXTRA" },
+       { 0x00000800, "LBDAT_TIMEOUT" },
+       { 0x00001000, "LBDAT_EXTRA" },
+       { 0x00002000, "GPFIFO" },
+       { 0x00004000, "GPPTR" },
+       { 0x00008000, "GPENTRY" },
+       { 0x00010000, "GPCRC" },
+       { 0x00020000, "PBPTR" },
+       { 0x00040000, "PBENTRY" },
+       { 0x00080000, "PBCRC" },
+       { 0x00100000, "XBARCONNECT" },
+       { 0x00200000, "METHOD" },
+       { 0x00400000, "METHODCRC" },
+       { 0x00800000, "DEVICE" },
+       { 0x02000000, "SEMAPHORE" },
+       { 0x04000000, "ACQUIRE" },
+       { 0x08000000, "PRI" },
+       { 0x20000000, "NO_CTXSW_SEG" },
+       { 0x40000000, "PBSEG" },
+       { 0x80000000, "SIGNATURE" },
        {}
 };
 
 static void
-nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit)
+nve0_fifo_intr_sched(struct nve0_fifo_priv *priv)
+{
+       u32 intr = nv_rd32(priv, 0x00254c);
+       u32 code = intr & 0x000000ff;
+       nv_error(priv, "SCHED_ERROR [");
+       nouveau_enum_print(nve0_fifo_sched_reason, code);
+       pr_cont("]\n");
+}
+
+static void
+nve0_fifo_intr_chsw(struct nve0_fifo_priv *priv)
+{
+       u32 stat = nv_rd32(priv, 0x00256c);
+       nv_error(priv, "CHSW_ERROR 0x%08x\n", stat);
+       nv_wr32(priv, 0x00256c, stat);
+}
+
+static void
+nve0_fifo_intr_dropped_fault(struct nve0_fifo_priv *priv)
+{
+       u32 stat = nv_rd32(priv, 0x00259c);
+       nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat);
+}
+
+static void
+nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit)
 {
        u32 inst = nv_rd32(priv, 0x2800 + (unit * 0x10));
        u32 valo = nv_rd32(priv, 0x2804 + (unit * 0x10));
        u32 vahi = nv_rd32(priv, 0x2808 + (unit * 0x10));
        u32 stat = nv_rd32(priv, 0x280c + (unit * 0x10));
        u32 client = (stat & 0x00001f00) >> 8;
-       const struct nouveau_enum *en;
-       struct nouveau_engine *engine;
+       struct nouveau_engine *engine = NULL;
        struct nouveau_object *engctx = NULL;
+       const struct nouveau_enum *en;
+       const char *name = "unknown";
 
        nv_error(priv, "PFIFO: %s fault at 0x%010llx [", (stat & 0x00000080) ?
                       "write" : "read", (u64)vahi << 32 | valo);
        nouveau_enum_print(nve0_fifo_fault_reason, stat & 0x0000000f);
        pr_cont("] from ");
-       en = nouveau_enum_print(nve0_fifo_fault_unit, unit);
+       en = nouveau_enum_print(nve0_fifo_fault_engine, unit);
        if (stat & 0x00000040) {
                pr_cont("/");
                nouveau_enum_print(nve0_fifo_fault_hubclient, client);
@@ -432,14 +569,22 @@ nve0_fifo_isr_vm_fault(struct nve0_fifo_priv *priv, int unit)
        }
 
        if (en && en->data2) {
-               engine = nouveau_engine(priv, en->data2);
-               if (engine)
-                       engctx = nouveau_engctx_get(engine, inst);
-
+               if (en->data2 == NVDEV_SUBDEV_BAR) {
+                       nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
+                       name = "BAR1";
+               } else
+               if (en->data2 == NVDEV_SUBDEV_INSTMEM) {
+                       nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
+                       name = "BAR3";
+               } else {
+                       engine = nouveau_engine(priv, en->data2);
+                       if (engine) {
+                               engctx = nouveau_engctx_get(engine, inst);
+                               name   = nouveau_client_name(engctx);
+                       }
+               }
        }
-
-       pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12,
-                       nouveau_client_name(engctx));
+       pr_cont(" on channel 0x%010llx [%s]\n", (u64)inst << 12, name);
 
        nouveau_engctx_put(engctx);
 }
@@ -471,7 +616,7 @@ out:
 }
 
 static void
-nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit)
+nve0_fifo_intr_pbdma(struct nve0_fifo_priv *priv, int unit)
 {
        u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
        u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
@@ -487,11 +632,11 @@ nve0_fifo_isr_subfifo_intr(struct nve0_fifo_priv *priv, int unit)
        }
 
        if (show) {
-               nv_error(priv, "SUBFIFO%d:", unit);
-               nouveau_bitfield_print(nve0_fifo_subfifo_intr, show);
+               nv_error(priv, "PBDMA%d:", unit);
+               nouveau_bitfield_print(nve0_fifo_pbdma_intr, show);
                pr_cont("\n");
                nv_error(priv,
-                        "SUBFIFO%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
+                        "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
                         unit, chid,
                         nouveau_client_name_for_fifo_chid(&priv->base, chid),
                         subc, mthd, data);
@@ -508,19 +653,56 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
        u32 mask = nv_rd32(priv, 0x002140);
        u32 stat = nv_rd32(priv, 0x002100) & mask;
 
+       if (stat & 0x00000001) {
+               u32 stat = nv_rd32(priv, 0x00252c);
+               nv_error(priv, "BIND_ERROR 0x%08x\n", stat);
+               nv_wr32(priv, 0x002100, 0x00000001);
+               stat &= ~0x00000001;
+       }
+
+       if (stat & 0x00000010) {
+               nv_error(priv, "PIO_ERROR\n");
+               nv_wr32(priv, 0x002100, 0x00000010);
+               stat &= ~0x00000010;
+       }
+
        if (stat & 0x00000100) {
-               nv_warn(priv, "unknown status 0x00000100\n");
+               nve0_fifo_intr_sched(priv);
                nv_wr32(priv, 0x002100, 0x00000100);
                stat &= ~0x00000100;
        }
 
+       if (stat & 0x00010000) {
+               nve0_fifo_intr_chsw(priv);
+               nv_wr32(priv, 0x002100, 0x00010000);
+               stat &= ~0x00010000;
+       }
+
+       if (stat & 0x00800000) {
+               nv_error(priv, "FB_FLUSH_TIMEOUT\n");
+               nv_wr32(priv, 0x002100, 0x00800000);
+               stat &= ~0x00800000;
+       }
+
+       if (stat & 0x01000000) {
+               nv_error(priv, "LB_ERROR\n");
+               nv_wr32(priv, 0x002100, 0x01000000);
+               stat &= ~0x01000000;
+       }
+
+       if (stat & 0x08000000) {
+               nve0_fifo_intr_dropped_fault(priv);
+               nv_wr32(priv, 0x002100, 0x08000000);
+               stat &= ~0x08000000;
+       }
+
        if (stat & 0x10000000) {
                u32 units = nv_rd32(priv, 0x00259c);
                u32 u = units;
 
                while (u) {
                        int i = ffs(u) - 1;
-                       nve0_fifo_isr_vm_fault(priv, i);
+                       nve0_fifo_intr_fault(priv, i);
                        u &= ~(1 << i);
                }
 
@@ -529,22 +711,28 @@ nve0_fifo_intr(struct nouveau_subdev *subdev)
        }
 
        if (stat & 0x20000000) {
-               u32 units = nv_rd32(priv, 0x0025a0);
-               u32 u = units;
+               u32 mask = nv_rd32(priv, 0x0025a0);
+               u32 temp = mask;
 
-               while (u) {
-                       int i = ffs(u) - 1;
-                       nve0_fifo_isr_subfifo_intr(priv, i);
-                       u &= ~(1 << i);
+               while (temp) {
+                       u32 unit = ffs(temp) - 1;
+                       nve0_fifo_intr_pbdma(priv, unit);
+                       temp &= ~(1 << unit);
                }
 
-               nv_wr32(priv, 0x0025a0, units);
+               nv_wr32(priv, 0x0025a0, mask);
                stat &= ~0x20000000;
        }
 
        if (stat & 0x40000000) {
-               nv_warn(priv, "unknown status 0x40000000\n");
-               nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
+               u32 mask = nv_mask(priv, 0x002a00, 0x00000000, 0x00000000);
+
+               while (mask) {
+                       u32 engn = ffs(mask) - 1;
+                       /* runlist event, not currently used */
+                       mask &= ~(1 << engn);
+               }
+
                stat &= ~0x40000000;
        }
 
@@ -575,53 +763,52 @@ nve0_fifo_uevent_disable(struct nouveau_event *event, int index)
        nv_mask(priv, 0x002140, 0x80000000, 0x00000000);
 }
 
-static int
-nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-              struct nouveau_oclass *oclass, void *data, u32 size,
-              struct nouveau_object **pobject)
+int
+nve0_fifo_fini(struct nouveau_object *object, bool suspend)
 {
-       struct nve0_fifo_priv *priv;
-       int ret, i;
+       struct nve0_fifo_priv *priv = (void *)object;
+       int ret;
 
-       ret = nouveau_fifo_create(parent, engine, oclass, 0, 4095, &priv);
-       *pobject = nv_object(priv);
+       ret = nouveau_fifo_fini(&priv->base, suspend);
        if (ret)
                return ret;
 
-       for (i = 0; i < FIFO_ENGINE_NR; i++) {
-               ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
-                                        0, &priv->engine[i].playlist[0]);
-               if (ret)
-                       return ret;
+       /* allow mmu fault interrupts, even when we're not using fifo */
+       nv_mask(priv, 0x002140, 0x10000000, 0x10000000);
+       return 0;
+}
 
-               ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
-                                        0, &priv->engine[i].playlist[1]);
-               if (ret)
-                       return ret;
-       }
+int
+nve0_fifo_init(struct nouveau_object *object)
+{
+       struct nve0_fifo_priv *priv = (void *)object;
+       int ret, i;
 
-       ret = nouveau_gpuobj_new(nv_object(priv), NULL, 4096 * 0x200, 0x1000,
-                                NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+       ret = nouveau_fifo_init(&priv->base);
        if (ret)
                return ret;
 
-       ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
-                               &priv->user.bar);
-       if (ret)
-               return ret;
+       /* enable all available PBDMA units */
+       nv_wr32(priv, 0x000204, 0xffffffff);
+       priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204));
+       nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
 
-       priv->base.uevent->enable = nve0_fifo_uevent_enable;
-       priv->base.uevent->disable = nve0_fifo_uevent_disable;
-       priv->base.uevent->priv = priv;
+       /* PBDMA[n] */
+       for (i = 0; i < priv->spoon_nr; i++) {
+               nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+               nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+               nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
+       }
 
-       nv_subdev(priv)->unit = 0x00000100;
-       nv_subdev(priv)->intr = nve0_fifo_intr;
-       nv_engine(priv)->cclass = &nve0_fifo_cclass;
-       nv_engine(priv)->sclass = nve0_fifo_sclass;
+       nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
+
+       nv_wr32(priv, 0x002a00, 0xffffffff);
+       nv_wr32(priv, 0x002100, 0xffffffff);
+       nv_wr32(priv, 0x002140, 0x3fffffff);
        return 0;
 }
 
-static void
+void
 nve0_fifo_dtor(struct nouveau_object *object)
 {
        struct nve0_fifo_priv *priv = (void *)object;
@@ -631,50 +818,69 @@ nve0_fifo_dtor(struct nouveau_object *object)
        nouveau_gpuobj_ref(NULL, &priv->user.mem);
 
        for (i = 0; i < FIFO_ENGINE_NR; i++) {
-               nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[1]);
-               nouveau_gpuobj_ref(NULL, &priv->engine[i].playlist[0]);
+               nouveau_gpuobj_ref(NULL, &priv->engine[i].runlist[1]);
+               nouveau_gpuobj_ref(NULL, &priv->engine[i].runlist[0]);
        }
 
        nouveau_fifo_destroy(&priv->base);
 }
 
-static int
-nve0_fifo_init(struct nouveau_object *object)
+int
+nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+              struct nouveau_oclass *oclass, void *data, u32 size,
+              struct nouveau_object **pobject)
 {
-       struct nve0_fifo_priv *priv = (void *)object;
+       struct nve0_fifo_impl *impl = (void *)oclass;
+       struct nve0_fifo_priv *priv;
        int ret, i;
 
-       ret = nouveau_fifo_init(&priv->base);
+       ret = nouveau_fifo_create(parent, engine, oclass, 0,
+                                 impl->channels - 1, &priv);
+       *pobject = nv_object(priv);
        if (ret)
                return ret;
 
-       /* enable all available PSUBFIFOs */
-       nv_wr32(priv, 0x000204, 0xffffffff);
-       priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204));
-       nv_debug(priv, "%d subfifo(s)\n", priv->spoon_nr);
+       for (i = 0; i < FIFO_ENGINE_NR; i++) {
+               ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+                                        0, &priv->engine[i].runlist[0]);
+               if (ret)
+                       return ret;
 
-       /* PSUBFIFO[n] */
-       for (i = 0; i < priv->spoon_nr; i++) {
-               nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
-               nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
-               nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
+               ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+                                        0, &priv->engine[i].runlist[1]);
+               if (ret)
+                       return ret;
        }
 
-       nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
+       ret = nouveau_gpuobj_new(nv_object(priv), NULL, 4096 * 0x200, 0x1000,
+                                NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+       if (ret)
+               return ret;
 
-       nv_wr32(priv, 0x002a00, 0xffffffff);
-       nv_wr32(priv, 0x002100, 0xffffffff);
-       nv_wr32(priv, 0x002140, 0x3fffffff);
+       ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
+                               &priv->user.bar);
+       if (ret)
+               return ret;
+
+       priv->base.uevent->enable = nve0_fifo_uevent_enable;
+       priv->base.uevent->disable = nve0_fifo_uevent_disable;
+       priv->base.uevent->priv = priv;
+
+       nv_subdev(priv)->unit = 0x00000100;
+       nv_subdev(priv)->intr = nve0_fifo_intr;
+       nv_engine(priv)->cclass = &nve0_fifo_cclass;
+       nv_engine(priv)->sclass = nve0_fifo_sclass;
        return 0;
 }
 
 struct nouveau_oclass *
-nve0_fifo_oclass = &(struct nouveau_oclass) {
-       .handle = NV_ENGINE(FIFO, 0xe0),
-       .ofuncs = &(struct nouveau_ofuncs) {
+nve0_fifo_oclass = &(struct nve0_fifo_impl) {
+       .base.handle = NV_ENGINE(FIFO, 0xe0),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nve0_fifo_ctor,
                .dtor = nve0_fifo_dtor,
                .init = nve0_fifo_init,
-               .fini = _nouveau_fifo_fini,
+               .fini = nve0_fifo_fini,
        },
-};
+       .channels = 4096,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h
new file mode 100644 (file)
index 0000000..014344e
--- /dev/null
@@ -0,0 +1,17 @@
+#ifndef __NVKM_FIFO_NVE0_H__
+#define __NVKM_FIFO_NVE0_H__
+
+#include <engine/fifo.h>
+
+int  nve0_fifo_ctor(struct nouveau_object *, struct nouveau_object *,
+                   struct nouveau_oclass *, void *, u32,
+                   struct nouveau_object **);
+void nve0_fifo_dtor(struct nouveau_object *);
+int  nve0_fifo_init(struct nouveau_object *);
+
+struct nve0_fifo_impl {
+       struct nouveau_oclass base;
+       u32 channels;
+};
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c
new file mode 100644 (file)
index 0000000..a86bd33
--- /dev/null
@@ -0,0 +1,1408 @@
+/*
+ * 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 <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+static struct nvc0_graph_init
+nv108_grctx_init_icmd[] = {
+       { 0x001000,   1, 0x01, 0x00000004 },
+       { 0x000039,   3, 0x01, 0x00000000 },
+       { 0x0000a9,   1, 0x01, 0x0000ffff },
+       { 0x000038,   1, 0x01, 0x0fac6881 },
+       { 0x00003d,   1, 0x01, 0x00000001 },
+       { 0x0000e8,   8, 0x01, 0x00000400 },
+       { 0x000078,   8, 0x01, 0x00000300 },
+       { 0x000050,   1, 0x01, 0x00000011 },
+       { 0x000058,   8, 0x01, 0x00000008 },
+       { 0x000208,   8, 0x01, 0x00000001 },
+       { 0x000081,   1, 0x01, 0x00000001 },
+       { 0x000085,   1, 0x01, 0x00000004 },
+       { 0x000088,   1, 0x01, 0x00000400 },
+       { 0x000090,   1, 0x01, 0x00000300 },
+       { 0x000098,   1, 0x01, 0x00001001 },
+       { 0x0000e3,   1, 0x01, 0x00000001 },
+       { 0x0000da,   1, 0x01, 0x00000001 },
+       { 0x0000f8,   1, 0x01, 0x00000003 },
+       { 0x0000fa,   1, 0x01, 0x00000001 },
+       { 0x00009f,   4, 0x01, 0x0000ffff },
+       { 0x0000b1,   1, 0x01, 0x00000001 },
+       { 0x0000ad,   1, 0x01, 0x0000013e },
+       { 0x0000e1,   1, 0x01, 0x00000010 },
+       { 0x000290,  16, 0x01, 0x00000000 },
+       { 0x0003b0,  16, 0x01, 0x00000000 },
+       { 0x0002a0,  16, 0x01, 0x00000000 },
+       { 0x000420,  16, 0x01, 0x00000000 },
+       { 0x0002b0,  16, 0x01, 0x00000000 },
+       { 0x000430,  16, 0x01, 0x00000000 },
+       { 0x0002c0,  16, 0x01, 0x00000000 },
+       { 0x0004d0,  16, 0x01, 0x00000000 },
+       { 0x000720,  16, 0x01, 0x00000000 },
+       { 0x0008c0,  16, 0x01, 0x00000000 },
+       { 0x000890,  16, 0x01, 0x00000000 },
+       { 0x0008e0,  16, 0x01, 0x00000000 },
+       { 0x0008a0,  16, 0x01, 0x00000000 },
+       { 0x0008f0,  16, 0x01, 0x00000000 },
+       { 0x00094c,   1, 0x01, 0x000000ff },
+       { 0x00094d,   1, 0x01, 0xffffffff },
+       { 0x00094e,   1, 0x01, 0x00000002 },
+       { 0x0002ec,   1, 0x01, 0x00000001 },
+       { 0x0002f2,   2, 0x01, 0x00000001 },
+       { 0x0002f5,   1, 0x01, 0x00000001 },
+       { 0x0002f7,   1, 0x01, 0x00000001 },
+       { 0x000303,   1, 0x01, 0x00000001 },
+       { 0x0002e6,   1, 0x01, 0x00000001 },
+       { 0x000466,   1, 0x01, 0x00000052 },
+       { 0x000301,   1, 0x01, 0x3f800000 },
+       { 0x000304,   1, 0x01, 0x30201000 },
+       { 0x000305,   1, 0x01, 0x70605040 },
+       { 0x000306,   1, 0x01, 0xb8a89888 },
+       { 0x000307,   1, 0x01, 0xf8e8d8c8 },
+       { 0x00030a,   1, 0x01, 0x00ffff00 },
+       { 0x00030b,   1, 0x01, 0x0000001a },
+       { 0x00030c,   1, 0x01, 0x00000001 },
+       { 0x000318,   1, 0x01, 0x00000001 },
+       { 0x000340,   1, 0x01, 0x00000000 },
+       { 0x000375,   1, 0x01, 0x00000001 },
+       { 0x00037d,   1, 0x01, 0x00000006 },
+       { 0x0003a0,   1, 0x01, 0x00000002 },
+       { 0x0003aa,   1, 0x01, 0x00000001 },
+       { 0x0003a9,   1, 0x01, 0x00000001 },
+       { 0x000380,   1, 0x01, 0x00000001 },
+       { 0x000383,   1, 0x01, 0x00000011 },
+       { 0x000360,   1, 0x01, 0x00000040 },
+       { 0x000366,   2, 0x01, 0x00000000 },
+       { 0x000368,   1, 0x01, 0x00000fff },
+       { 0x000370,   2, 0x01, 0x00000000 },
+       { 0x000372,   1, 0x01, 0x000fffff },
+       { 0x00037a,   1, 0x01, 0x00000012 },
+       { 0x000619,   1, 0x01, 0x00000003 },
+       { 0x000811,   1, 0x01, 0x00000003 },
+       { 0x000812,   1, 0x01, 0x00000004 },
+       { 0x000813,   1, 0x01, 0x00000006 },
+       { 0x000814,   1, 0x01, 0x00000008 },
+       { 0x000815,   1, 0x01, 0x0000000b },
+       { 0x000800,   6, 0x01, 0x00000001 },
+       { 0x000632,   1, 0x01, 0x00000001 },
+       { 0x000633,   1, 0x01, 0x00000002 },
+       { 0x000634,   1, 0x01, 0x00000003 },
+       { 0x000635,   1, 0x01, 0x00000004 },
+       { 0x000654,   1, 0x01, 0x3f800000 },
+       { 0x000657,   1, 0x01, 0x3f800000 },
+       { 0x000655,   2, 0x01, 0x3f800000 },
+       { 0x0006cd,   1, 0x01, 0x3f800000 },
+       { 0x0007f5,   1, 0x01, 0x3f800000 },
+       { 0x0007dc,   1, 0x01, 0x39291909 },
+       { 0x0007dd,   1, 0x01, 0x79695949 },
+       { 0x0007de,   1, 0x01, 0xb9a99989 },
+       { 0x0007df,   1, 0x01, 0xf9e9d9c9 },
+       { 0x0007e8,   1, 0x01, 0x00003210 },
+       { 0x0007e9,   1, 0x01, 0x00007654 },
+       { 0x0007ea,   1, 0x01, 0x00000098 },
+       { 0x0007ec,   1, 0x01, 0x39291909 },
+       { 0x0007ed,   1, 0x01, 0x79695949 },
+       { 0x0007ee,   1, 0x01, 0xb9a99989 },
+       { 0x0007ef,   1, 0x01, 0xf9e9d9c9 },
+       { 0x0007f0,   1, 0x01, 0x00003210 },
+       { 0x0007f1,   1, 0x01, 0x00007654 },
+       { 0x0007f2,   1, 0x01, 0x00000098 },
+       { 0x0005a5,   1, 0x01, 0x00000001 },
+       { 0x000980, 128, 0x01, 0x00000000 },
+       { 0x000468,   1, 0x01, 0x00000004 },
+       { 0x00046c,   1, 0x01, 0x00000001 },
+       { 0x000470,  96, 0x01, 0x00000000 },
+       { 0x000510,  16, 0x01, 0x3f800000 },
+       { 0x000520,   1, 0x01, 0x000002b6 },
+       { 0x000529,   1, 0x01, 0x00000001 },
+       { 0x000530,  16, 0x01, 0xffff0000 },
+       { 0x000585,   1, 0x01, 0x0000003f },
+       { 0x000576,   1, 0x01, 0x00000003 },
+       { 0x00057b,   1, 0x01, 0x00000059 },
+       { 0x000586,   1, 0x01, 0x00000040 },
+       { 0x000582,   2, 0x01, 0x00000080 },
+       { 0x0005c2,   1, 0x01, 0x00000001 },
+       { 0x000638,   2, 0x01, 0x00000001 },
+       { 0x00063a,   1, 0x01, 0x00000002 },
+       { 0x00063b,   2, 0x01, 0x00000001 },
+       { 0x00063d,   1, 0x01, 0x00000002 },
+       { 0x00063e,   1, 0x01, 0x00000001 },
+       { 0x0008b8,   8, 0x01, 0x00000001 },
+       { 0x000900,   8, 0x01, 0x00000001 },
+       { 0x000908,   8, 0x01, 0x00000002 },
+       { 0x000910,  16, 0x01, 0x00000001 },
+       { 0x000920,   8, 0x01, 0x00000002 },
+       { 0x000928,   8, 0x01, 0x00000001 },
+       { 0x000662,   1, 0x01, 0x00000001 },
+       { 0x000648,   9, 0x01, 0x00000001 },
+       { 0x000658,   1, 0x01, 0x0000000f },
+       { 0x0007ff,   1, 0x01, 0x0000000a },
+       { 0x00066a,   1, 0x01, 0x40000000 },
+       { 0x00066b,   1, 0x01, 0x10000000 },
+       { 0x00066c,   2, 0x01, 0xffff0000 },
+       { 0x0007af,   2, 0x01, 0x00000008 },
+       { 0x0007f6,   1, 0x01, 0x00000001 },
+       { 0x00080b,   1, 0x01, 0x00000002 },
+       { 0x0006b2,   1, 0x01, 0x00000055 },
+       { 0x0007ad,   1, 0x01, 0x00000003 },
+       { 0x000937,   1, 0x01, 0x00000001 },
+       { 0x000971,   1, 0x01, 0x00000008 },
+       { 0x000972,   1, 0x01, 0x00000040 },
+       { 0x000973,   1, 0x01, 0x0000012c },
+       { 0x00097c,   1, 0x01, 0x00000040 },
+       { 0x000979,   1, 0x01, 0x00000003 },
+       { 0x000975,   1, 0x01, 0x00000020 },
+       { 0x000976,   1, 0x01, 0x00000001 },
+       { 0x000977,   1, 0x01, 0x00000020 },
+       { 0x000978,   1, 0x01, 0x00000001 },
+       { 0x000957,   1, 0x01, 0x00000003 },
+       { 0x00095e,   1, 0x01, 0x20164010 },
+       { 0x00095f,   1, 0x01, 0x00000020 },
+       { 0x000a0d,   1, 0x01, 0x00000006 },
+       { 0x00097d,   1, 0x01, 0x00000020 },
+       { 0x000683,   1, 0x01, 0x00000006 },
+       { 0x000685,   1, 0x01, 0x003fffff },
+       { 0x000687,   1, 0x01, 0x003fffff },
+       { 0x0006a0,   1, 0x01, 0x00000005 },
+       { 0x000840,   1, 0x01, 0x00400008 },
+       { 0x000841,   1, 0x01, 0x08000080 },
+       { 0x000842,   1, 0x01, 0x00400008 },
+       { 0x000843,   1, 0x01, 0x08000080 },
+       { 0x0006aa,   1, 0x01, 0x00000001 },
+       { 0x0006ab,   1, 0x01, 0x00000002 },
+       { 0x0006ac,   1, 0x01, 0x00000080 },
+       { 0x0006ad,   2, 0x01, 0x00000100 },
+       { 0x0006b1,   1, 0x01, 0x00000011 },
+       { 0x0006bb,   1, 0x01, 0x000000cf },
+       { 0x0006ce,   1, 0x01, 0x2a712488 },
+       { 0x000739,   1, 0x01, 0x4085c000 },
+       { 0x00073a,   1, 0x01, 0x00000080 },
+       { 0x000786,   1, 0x01, 0x80000100 },
+       { 0x00073c,   1, 0x01, 0x00010100 },
+       { 0x00073d,   1, 0x01, 0x02800000 },
+       { 0x000787,   1, 0x01, 0x000000cf },
+       { 0x00078c,   1, 0x01, 0x00000008 },
+       { 0x000792,   1, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
+       { 0x000797,   1, 0x01, 0x000000cf },
+       { 0x000836,   1, 0x01, 0x00000001 },
+       { 0x00079a,   1, 0x01, 0x00000002 },
+       { 0x000833,   1, 0x01, 0x04444480 },
+       { 0x0007a1,   1, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
+       { 0x000831,   1, 0x01, 0x00000004 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x000a04,   1, 0x01, 0x000000ff },
+       { 0x000a0b,   1, 0x01, 0x00000040 },
+       { 0x00097f,   1, 0x01, 0x00000100 },
+       { 0x000a02,   1, 0x01, 0x00000001 },
+       { 0x000809,   1, 0x01, 0x00000007 },
+       { 0x00c221,   1, 0x01, 0x00000040 },
+       { 0x00c1b0,   8, 0x01, 0x0000000f },
+       { 0x00c1b8,   1, 0x01, 0x0fac6881 },
+       { 0x00c1b9,   1, 0x01, 0x00fac688 },
+       { 0x00c401,   1, 0x01, 0x00000001 },
+       { 0x00c402,   1, 0x01, 0x00010001 },
+       { 0x00c403,   2, 0x01, 0x00000001 },
+       { 0x00c40e,   1, 0x01, 0x00000020 },
+       { 0x00c500,   1, 0x01, 0x00000003 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000002 },
+       { 0x0006aa,   1, 0x01, 0x00000001 },
+       { 0x0006ad,   2, 0x01, 0x00000100 },
+       { 0x0006b1,   1, 0x01, 0x00000011 },
+       { 0x00078c,   1, 0x01, 0x00000008 },
+       { 0x000792,   1, 0x01, 0x00000001 },
+       { 0x000794,   3, 0x01, 0x00000001 },
+       { 0x000797,   1, 0x01, 0x000000cf },
+       { 0x00079a,   1, 0x01, 0x00000002 },
+       { 0x0007a1,   1, 0x01, 0x00000001 },
+       { 0x0007a3,   3, 0x01, 0x00000001 },
+       { 0x000831,   1, 0x01, 0x00000004 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000008 },
+       { 0x000039,   3, 0x01, 0x00000000 },
+       { 0x000380,   1, 0x01, 0x00000001 },
+       { 0x000366,   2, 0x01, 0x00000000 },
+       { 0x000368,   1, 0x01, 0x00000fff },
+       { 0x000370,   2, 0x01, 0x00000000 },
+       { 0x000372,   1, 0x01, 0x000fffff },
+       { 0x000813,   1, 0x01, 0x00000006 },
+       { 0x000814,   1, 0x01, 0x00000008 },
+       { 0x000957,   1, 0x01, 0x00000003 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x000a04,   1, 0x01, 0x000000ff },
+       { 0x000a0b,   1, 0x01, 0x00000040 },
+       { 0x00097f,   1, 0x01, 0x00000100 },
+       { 0x000a02,   1, 0x01, 0x00000001 },
+       { 0x000809,   1, 0x01, 0x00000007 },
+       { 0x00c221,   1, 0x01, 0x00000040 },
+       { 0x00c401,   1, 0x01, 0x00000001 },
+       { 0x00c402,   1, 0x01, 0x00010001 },
+       { 0x00c403,   2, 0x01, 0x00000001 },
+       { 0x00c40e,   1, 0x01, 0x00000020 },
+       { 0x00c500,   1, 0x01, 0x00000003 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       { 0x001000,   1, 0x01, 0x00000001 },
+       { 0x000b07,   1, 0x01, 0x00000002 },
+       { 0x000b08,   2, 0x01, 0x00000100 },
+       { 0x000b0a,   1, 0x01, 0x00000001 },
+       { 0x01e100,   1, 0x01, 0x00000001 },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_grctx_init_a197[] = {
+       { 0x000800,   1, 0x04, 0x00000000 },
+       { 0x000840,   1, 0x04, 0x00000000 },
+       { 0x000880,   1, 0x04, 0x00000000 },
+       { 0x0008c0,   1, 0x04, 0x00000000 },
+       { 0x000900,   1, 0x04, 0x00000000 },
+       { 0x000940,   1, 0x04, 0x00000000 },
+       { 0x000980,   1, 0x04, 0x00000000 },
+       { 0x0009c0,   1, 0x04, 0x00000000 },
+       { 0x000804,   1, 0x04, 0x00000000 },
+       { 0x000844,   1, 0x04, 0x00000000 },
+       { 0x000884,   1, 0x04, 0x00000000 },
+       { 0x0008c4,   1, 0x04, 0x00000000 },
+       { 0x000904,   1, 0x04, 0x00000000 },
+       { 0x000944,   1, 0x04, 0x00000000 },
+       { 0x000984,   1, 0x04, 0x00000000 },
+       { 0x0009c4,   1, 0x04, 0x00000000 },
+       { 0x000808,   1, 0x04, 0x00000400 },
+       { 0x000848,   1, 0x04, 0x00000400 },
+       { 0x000888,   1, 0x04, 0x00000400 },
+       { 0x0008c8,   1, 0x04, 0x00000400 },
+       { 0x000908,   1, 0x04, 0x00000400 },
+       { 0x000948,   1, 0x04, 0x00000400 },
+       { 0x000988,   1, 0x04, 0x00000400 },
+       { 0x0009c8,   1, 0x04, 0x00000400 },
+       { 0x00080c,   1, 0x04, 0x00000300 },
+       { 0x00084c,   1, 0x04, 0x00000300 },
+       { 0x00088c,   1, 0x04, 0x00000300 },
+       { 0x0008cc,   1, 0x04, 0x00000300 },
+       { 0x00090c,   1, 0x04, 0x00000300 },
+       { 0x00094c,   1, 0x04, 0x00000300 },
+       { 0x00098c,   1, 0x04, 0x00000300 },
+       { 0x0009cc,   1, 0x04, 0x00000300 },
+       { 0x000810,   1, 0x04, 0x000000cf },
+       { 0x000850,   1, 0x04, 0x00000000 },
+       { 0x000890,   1, 0x04, 0x00000000 },
+       { 0x0008d0,   1, 0x04, 0x00000000 },
+       { 0x000910,   1, 0x04, 0x00000000 },
+       { 0x000950,   1, 0x04, 0x00000000 },
+       { 0x000990,   1, 0x04, 0x00000000 },
+       { 0x0009d0,   1, 0x04, 0x00000000 },
+       { 0x000814,   1, 0x04, 0x00000040 },
+       { 0x000854,   1, 0x04, 0x00000040 },
+       { 0x000894,   1, 0x04, 0x00000040 },
+       { 0x0008d4,   1, 0x04, 0x00000040 },
+       { 0x000914,   1, 0x04, 0x00000040 },
+       { 0x000954,   1, 0x04, 0x00000040 },
+       { 0x000994,   1, 0x04, 0x00000040 },
+       { 0x0009d4,   1, 0x04, 0x00000040 },
+       { 0x000818,   1, 0x04, 0x00000001 },
+       { 0x000858,   1, 0x04, 0x00000001 },
+       { 0x000898,   1, 0x04, 0x00000001 },
+       { 0x0008d8,   1, 0x04, 0x00000001 },
+       { 0x000918,   1, 0x04, 0x00000001 },
+       { 0x000958,   1, 0x04, 0x00000001 },
+       { 0x000998,   1, 0x04, 0x00000001 },
+       { 0x0009d8,   1, 0x04, 0x00000001 },
+       { 0x00081c,   1, 0x04, 0x00000000 },
+       { 0x00085c,   1, 0x04, 0x00000000 },
+       { 0x00089c,   1, 0x04, 0x00000000 },
+       { 0x0008dc,   1, 0x04, 0x00000000 },
+       { 0x00091c,   1, 0x04, 0x00000000 },
+       { 0x00095c,   1, 0x04, 0x00000000 },
+       { 0x00099c,   1, 0x04, 0x00000000 },
+       { 0x0009dc,   1, 0x04, 0x00000000 },
+       { 0x000820,   1, 0x04, 0x00000000 },
+       { 0x000860,   1, 0x04, 0x00000000 },
+       { 0x0008a0,   1, 0x04, 0x00000000 },
+       { 0x0008e0,   1, 0x04, 0x00000000 },
+       { 0x000920,   1, 0x04, 0x00000000 },
+       { 0x000960,   1, 0x04, 0x00000000 },
+       { 0x0009a0,   1, 0x04, 0x00000000 },
+       { 0x0009e0,   1, 0x04, 0x00000000 },
+       { 0x001c00,   1, 0x04, 0x00000000 },
+       { 0x001c10,   1, 0x04, 0x00000000 },
+       { 0x001c20,   1, 0x04, 0x00000000 },
+       { 0x001c30,   1, 0x04, 0x00000000 },
+       { 0x001c40,   1, 0x04, 0x00000000 },
+       { 0x001c50,   1, 0x04, 0x00000000 },
+       { 0x001c60,   1, 0x04, 0x00000000 },
+       { 0x001c70,   1, 0x04, 0x00000000 },
+       { 0x001c80,   1, 0x04, 0x00000000 },
+       { 0x001c90,   1, 0x04, 0x00000000 },
+       { 0x001ca0,   1, 0x04, 0x00000000 },
+       { 0x001cb0,   1, 0x04, 0x00000000 },
+       { 0x001cc0,   1, 0x04, 0x00000000 },
+       { 0x001cd0,   1, 0x04, 0x00000000 },
+       { 0x001ce0,   1, 0x04, 0x00000000 },
+       { 0x001cf0,   1, 0x04, 0x00000000 },
+       { 0x001c04,   1, 0x04, 0x00000000 },
+       { 0x001c14,   1, 0x04, 0x00000000 },
+       { 0x001c24,   1, 0x04, 0x00000000 },
+       { 0x001c34,   1, 0x04, 0x00000000 },
+       { 0x001c44,   1, 0x04, 0x00000000 },
+       { 0x001c54,   1, 0x04, 0x00000000 },
+       { 0x001c64,   1, 0x04, 0x00000000 },
+       { 0x001c74,   1, 0x04, 0x00000000 },
+       { 0x001c84,   1, 0x04, 0x00000000 },
+       { 0x001c94,   1, 0x04, 0x00000000 },
+       { 0x001ca4,   1, 0x04, 0x00000000 },
+       { 0x001cb4,   1, 0x04, 0x00000000 },
+       { 0x001cc4,   1, 0x04, 0x00000000 },
+       { 0x001cd4,   1, 0x04, 0x00000000 },
+       { 0x001ce4,   1, 0x04, 0x00000000 },
+       { 0x001cf4,   1, 0x04, 0x00000000 },
+       { 0x001c08,   1, 0x04, 0x00000000 },
+       { 0x001c18,   1, 0x04, 0x00000000 },
+       { 0x001c28,   1, 0x04, 0x00000000 },
+       { 0x001c38,   1, 0x04, 0x00000000 },
+       { 0x001c48,   1, 0x04, 0x00000000 },
+       { 0x001c58,   1, 0x04, 0x00000000 },
+       { 0x001c68,   1, 0x04, 0x00000000 },
+       { 0x001c78,   1, 0x04, 0x00000000 },
+       { 0x001c88,   1, 0x04, 0x00000000 },
+       { 0x001c98,   1, 0x04, 0x00000000 },
+       { 0x001ca8,   1, 0x04, 0x00000000 },
+       { 0x001cb8,   1, 0x04, 0x00000000 },
+       { 0x001cc8,   1, 0x04, 0x00000000 },
+       { 0x001cd8,   1, 0x04, 0x00000000 },
+       { 0x001ce8,   1, 0x04, 0x00000000 },
+       { 0x001cf8,   1, 0x04, 0x00000000 },
+       { 0x001c0c,   1, 0x04, 0x00000000 },
+       { 0x001c1c,   1, 0x04, 0x00000000 },
+       { 0x001c2c,   1, 0x04, 0x00000000 },
+       { 0x001c3c,   1, 0x04, 0x00000000 },
+       { 0x001c4c,   1, 0x04, 0x00000000 },
+       { 0x001c5c,   1, 0x04, 0x00000000 },
+       { 0x001c6c,   1, 0x04, 0x00000000 },
+       { 0x001c7c,   1, 0x04, 0x00000000 },
+       { 0x001c8c,   1, 0x04, 0x00000000 },
+       { 0x001c9c,   1, 0x04, 0x00000000 },
+       { 0x001cac,   1, 0x04, 0x00000000 },
+       { 0x001cbc,   1, 0x04, 0x00000000 },
+       { 0x001ccc,   1, 0x04, 0x00000000 },
+       { 0x001cdc,   1, 0x04, 0x00000000 },
+       { 0x001cec,   1, 0x04, 0x00000000 },
+       { 0x001cfc,   2, 0x04, 0x00000000 },
+       { 0x001d10,   1, 0x04, 0x00000000 },
+       { 0x001d20,   1, 0x04, 0x00000000 },
+       { 0x001d30,   1, 0x04, 0x00000000 },
+       { 0x001d40,   1, 0x04, 0x00000000 },
+       { 0x001d50,   1, 0x04, 0x00000000 },
+       { 0x001d60,   1, 0x04, 0x00000000 },
+       { 0x001d70,   1, 0x04, 0x00000000 },
+       { 0x001d80,   1, 0x04, 0x00000000 },
+       { 0x001d90,   1, 0x04, 0x00000000 },
+       { 0x001da0,   1, 0x04, 0x00000000 },
+       { 0x001db0,   1, 0x04, 0x00000000 },
+       { 0x001dc0,   1, 0x04, 0x00000000 },
+       { 0x001dd0,   1, 0x04, 0x00000000 },
+       { 0x001de0,   1, 0x04, 0x00000000 },
+       { 0x001df0,   1, 0x04, 0x00000000 },
+       { 0x001d04,   1, 0x04, 0x00000000 },
+       { 0x001d14,   1, 0x04, 0x00000000 },
+       { 0x001d24,   1, 0x04, 0x00000000 },
+       { 0x001d34,   1, 0x04, 0x00000000 },
+       { 0x001d44,   1, 0x04, 0x00000000 },
+       { 0x001d54,   1, 0x04, 0x00000000 },
+       { 0x001d64,   1, 0x04, 0x00000000 },
+       { 0x001d74,   1, 0x04, 0x00000000 },
+       { 0x001d84,   1, 0x04, 0x00000000 },
+       { 0x001d94,   1, 0x04, 0x00000000 },
+       { 0x001da4,   1, 0x04, 0x00000000 },
+       { 0x001db4,   1, 0x04, 0x00000000 },
+       { 0x001dc4,   1, 0x04, 0x00000000 },
+       { 0x001dd4,   1, 0x04, 0x00000000 },
+       { 0x001de4,   1, 0x04, 0x00000000 },
+       { 0x001df4,   1, 0x04, 0x00000000 },
+       { 0x001d08,   1, 0x04, 0x00000000 },
+       { 0x001d18,   1, 0x04, 0x00000000 },
+       { 0x001d28,   1, 0x04, 0x00000000 },
+       { 0x001d38,   1, 0x04, 0x00000000 },
+       { 0x001d48,   1, 0x04, 0x00000000 },
+       { 0x001d58,   1, 0x04, 0x00000000 },
+       { 0x001d68,   1, 0x04, 0x00000000 },
+       { 0x001d78,   1, 0x04, 0x00000000 },
+       { 0x001d88,   1, 0x04, 0x00000000 },
+       { 0x001d98,   1, 0x04, 0x00000000 },
+       { 0x001da8,   1, 0x04, 0x00000000 },
+       { 0x001db8,   1, 0x04, 0x00000000 },
+       { 0x001dc8,   1, 0x04, 0x00000000 },
+       { 0x001dd8,   1, 0x04, 0x00000000 },
+       { 0x001de8,   1, 0x04, 0x00000000 },
+       { 0x001df8,   1, 0x04, 0x00000000 },
+       { 0x001d0c,   1, 0x04, 0x00000000 },
+       { 0x001d1c,   1, 0x04, 0x00000000 },
+       { 0x001d2c,   1, 0x04, 0x00000000 },
+       { 0x001d3c,   1, 0x04, 0x00000000 },
+       { 0x001d4c,   1, 0x04, 0x00000000 },
+       { 0x001d5c,   1, 0x04, 0x00000000 },
+       { 0x001d6c,   1, 0x04, 0x00000000 },
+       { 0x001d7c,   1, 0x04, 0x00000000 },
+       { 0x001d8c,   1, 0x04, 0x00000000 },
+       { 0x001d9c,   1, 0x04, 0x00000000 },
+       { 0x001dac,   1, 0x04, 0x00000000 },
+       { 0x001dbc,   1, 0x04, 0x00000000 },
+       { 0x001dcc,   1, 0x04, 0x00000000 },
+       { 0x001ddc,   1, 0x04, 0x00000000 },
+       { 0x001dec,   1, 0x04, 0x00000000 },
+       { 0x001dfc,   1, 0x04, 0x00000000 },
+       { 0x001f00,   1, 0x04, 0x00000000 },
+       { 0x001f08,   1, 0x04, 0x00000000 },
+       { 0x001f10,   1, 0x04, 0x00000000 },
+       { 0x001f18,   1, 0x04, 0x00000000 },
+       { 0x001f20,   1, 0x04, 0x00000000 },
+       { 0x001f28,   1, 0x04, 0x00000000 },
+       { 0x001f30,   1, 0x04, 0x00000000 },
+       { 0x001f38,   1, 0x04, 0x00000000 },
+       { 0x001f40,   1, 0x04, 0x00000000 },
+       { 0x001f48,   1, 0x04, 0x00000000 },
+       { 0x001f50,   1, 0x04, 0x00000000 },
+       { 0x001f58,   1, 0x04, 0x00000000 },
+       { 0x001f60,   1, 0x04, 0x00000000 },
+       { 0x001f68,   1, 0x04, 0x00000000 },
+       { 0x001f70,   1, 0x04, 0x00000000 },
+       { 0x001f78,   1, 0x04, 0x00000000 },
+       { 0x001f04,   1, 0x04, 0x00000000 },
+       { 0x001f0c,   1, 0x04, 0x00000000 },
+       { 0x001f14,   1, 0x04, 0x00000000 },
+       { 0x001f1c,   1, 0x04, 0x00000000 },
+       { 0x001f24,   1, 0x04, 0x00000000 },
+       { 0x001f2c,   1, 0x04, 0x00000000 },
+       { 0x001f34,   1, 0x04, 0x00000000 },
+       { 0x001f3c,   1, 0x04, 0x00000000 },
+       { 0x001f44,   1, 0x04, 0x00000000 },
+       { 0x001f4c,   1, 0x04, 0x00000000 },
+       { 0x001f54,   1, 0x04, 0x00000000 },
+       { 0x001f5c,   1, 0x04, 0x00000000 },
+       { 0x001f64,   1, 0x04, 0x00000000 },
+       { 0x001f6c,   1, 0x04, 0x00000000 },
+       { 0x001f74,   1, 0x04, 0x00000000 },
+       { 0x001f7c,   2, 0x04, 0x00000000 },
+       { 0x001f88,   1, 0x04, 0x00000000 },
+       { 0x001f90,   1, 0x04, 0x00000000 },
+       { 0x001f98,   1, 0x04, 0x00000000 },
+       { 0x001fa0,   1, 0x04, 0x00000000 },
+       { 0x001fa8,   1, 0x04, 0x00000000 },
+       { 0x001fb0,   1, 0x04, 0x00000000 },
+       { 0x001fb8,   1, 0x04, 0x00000000 },
+       { 0x001fc0,   1, 0x04, 0x00000000 },
+       { 0x001fc8,   1, 0x04, 0x00000000 },
+       { 0x001fd0,   1, 0x04, 0x00000000 },
+       { 0x001fd8,   1, 0x04, 0x00000000 },
+       { 0x001fe0,   1, 0x04, 0x00000000 },
+       { 0x001fe8,   1, 0x04, 0x00000000 },
+       { 0x001ff0,   1, 0x04, 0x00000000 },
+       { 0x001ff8,   1, 0x04, 0x00000000 },
+       { 0x001f84,   1, 0x04, 0x00000000 },
+       { 0x001f8c,   1, 0x04, 0x00000000 },
+       { 0x001f94,   1, 0x04, 0x00000000 },
+       { 0x001f9c,   1, 0x04, 0x00000000 },
+       { 0x001fa4,   1, 0x04, 0x00000000 },
+       { 0x001fac,   1, 0x04, 0x00000000 },
+       { 0x001fb4,   1, 0x04, 0x00000000 },
+       { 0x001fbc,   1, 0x04, 0x00000000 },
+       { 0x001fc4,   1, 0x04, 0x00000000 },
+       { 0x001fcc,   1, 0x04, 0x00000000 },
+       { 0x001fd4,   1, 0x04, 0x00000000 },
+       { 0x001fdc,   1, 0x04, 0x00000000 },
+       { 0x001fe4,   1, 0x04, 0x00000000 },
+       { 0x001fec,   1, 0x04, 0x00000000 },
+       { 0x001ff4,   1, 0x04, 0x00000000 },
+       { 0x001ffc,   2, 0x04, 0x00000000 },
+       { 0x002040,   1, 0x04, 0x00000011 },
+       { 0x002080,   1, 0x04, 0x00000020 },
+       { 0x0020c0,   1, 0x04, 0x00000030 },
+       { 0x002100,   1, 0x04, 0x00000040 },
+       { 0x002140,   1, 0x04, 0x00000051 },
+       { 0x00200c,   1, 0x04, 0x00000001 },
+       { 0x00204c,   1, 0x04, 0x00000001 },
+       { 0x00208c,   1, 0x04, 0x00000001 },
+       { 0x0020cc,   1, 0x04, 0x00000001 },
+       { 0x00210c,   1, 0x04, 0x00000001 },
+       { 0x00214c,   1, 0x04, 0x00000001 },
+       { 0x002010,   1, 0x04, 0x00000000 },
+       { 0x002050,   1, 0x04, 0x00000000 },
+       { 0x002090,   1, 0x04, 0x00000001 },
+       { 0x0020d0,   1, 0x04, 0x00000002 },
+       { 0x002110,   1, 0x04, 0x00000003 },
+       { 0x002150,   1, 0x04, 0x00000004 },
+       { 0x000380,   1, 0x04, 0x00000000 },
+       { 0x0003a0,   1, 0x04, 0x00000000 },
+       { 0x0003c0,   1, 0x04, 0x00000000 },
+       { 0x0003e0,   1, 0x04, 0x00000000 },
+       { 0x000384,   1, 0x04, 0x00000000 },
+       { 0x0003a4,   1, 0x04, 0x00000000 },
+       { 0x0003c4,   1, 0x04, 0x00000000 },
+       { 0x0003e4,   1, 0x04, 0x00000000 },
+       { 0x000388,   1, 0x04, 0x00000000 },
+       { 0x0003a8,   1, 0x04, 0x00000000 },
+       { 0x0003c8,   1, 0x04, 0x00000000 },
+       { 0x0003e8,   1, 0x04, 0x00000000 },
+       { 0x00038c,   1, 0x04, 0x00000000 },
+       { 0x0003ac,   1, 0x04, 0x00000000 },
+       { 0x0003cc,   1, 0x04, 0x00000000 },
+       { 0x0003ec,   1, 0x04, 0x00000000 },
+       { 0x000700,   1, 0x04, 0x00000000 },
+       { 0x000710,   1, 0x04, 0x00000000 },
+       { 0x000720,   1, 0x04, 0x00000000 },
+       { 0x000730,   1, 0x04, 0x00000000 },
+       { 0x000704,   1, 0x04, 0x00000000 },
+       { 0x000714,   1, 0x04, 0x00000000 },
+       { 0x000724,   1, 0x04, 0x00000000 },
+       { 0x000734,   1, 0x04, 0x00000000 },
+       { 0x000708,   1, 0x04, 0x00000000 },
+       { 0x000718,   1, 0x04, 0x00000000 },
+       { 0x000728,   1, 0x04, 0x00000000 },
+       { 0x000738,   1, 0x04, 0x00000000 },
+       { 0x002800, 128, 0x04, 0x00000000 },
+       { 0x000a00,   1, 0x04, 0x00000000 },
+       { 0x000a20,   1, 0x04, 0x00000000 },
+       { 0x000a40,   1, 0x04, 0x00000000 },
+       { 0x000a60,   1, 0x04, 0x00000000 },
+       { 0x000a80,   1, 0x04, 0x00000000 },
+       { 0x000aa0,   1, 0x04, 0x00000000 },
+       { 0x000ac0,   1, 0x04, 0x00000000 },
+       { 0x000ae0,   1, 0x04, 0x00000000 },
+       { 0x000b00,   1, 0x04, 0x00000000 },
+       { 0x000b20,   1, 0x04, 0x00000000 },
+       { 0x000b40,   1, 0x04, 0x00000000 },
+       { 0x000b60,   1, 0x04, 0x00000000 },
+       { 0x000b80,   1, 0x04, 0x00000000 },
+       { 0x000ba0,   1, 0x04, 0x00000000 },
+       { 0x000bc0,   1, 0x04, 0x00000000 },
+       { 0x000be0,   1, 0x04, 0x00000000 },
+       { 0x000a04,   1, 0x04, 0x00000000 },
+       { 0x000a24,   1, 0x04, 0x00000000 },
+       { 0x000a44,   1, 0x04, 0x00000000 },
+       { 0x000a64,   1, 0x04, 0x00000000 },
+       { 0x000a84,   1, 0x04, 0x00000000 },
+       { 0x000aa4,   1, 0x04, 0x00000000 },
+       { 0x000ac4,   1, 0x04, 0x00000000 },
+       { 0x000ae4,   1, 0x04, 0x00000000 },
+       { 0x000b04,   1, 0x04, 0x00000000 },
+       { 0x000b24,   1, 0x04, 0x00000000 },
+       { 0x000b44,   1, 0x04, 0x00000000 },
+       { 0x000b64,   1, 0x04, 0x00000000 },
+       { 0x000b84,   1, 0x04, 0x00000000 },
+       { 0x000ba4,   1, 0x04, 0x00000000 },
+       { 0x000bc4,   1, 0x04, 0x00000000 },
+       { 0x000be4,   1, 0x04, 0x00000000 },
+       { 0x000a08,   1, 0x04, 0x00000000 },
+       { 0x000a28,   1, 0x04, 0x00000000 },
+       { 0x000a48,   1, 0x04, 0x00000000 },
+       { 0x000a68,   1, 0x04, 0x00000000 },
+       { 0x000a88,   1, 0x04, 0x00000000 },
+       { 0x000aa8,   1, 0x04, 0x00000000 },
+       { 0x000ac8,   1, 0x04, 0x00000000 },
+       { 0x000ae8,   1, 0x04, 0x00000000 },
+       { 0x000b08,   1, 0x04, 0x00000000 },
+       { 0x000b28,   1, 0x04, 0x00000000 },
+       { 0x000b48,   1, 0x04, 0x00000000 },
+       { 0x000b68,   1, 0x04, 0x00000000 },
+       { 0x000b88,   1, 0x04, 0x00000000 },
+       { 0x000ba8,   1, 0x04, 0x00000000 },
+       { 0x000bc8,   1, 0x04, 0x00000000 },
+       { 0x000be8,   1, 0x04, 0x00000000 },
+       { 0x000a0c,   1, 0x04, 0x00000000 },
+       { 0x000a2c,   1, 0x04, 0x00000000 },
+       { 0x000a4c,   1, 0x04, 0x00000000 },
+       { 0x000a6c,   1, 0x04, 0x00000000 },
+       { 0x000a8c,   1, 0x04, 0x00000000 },
+       { 0x000aac,   1, 0x04, 0x00000000 },
+       { 0x000acc,   1, 0x04, 0x00000000 },
+       { 0x000aec,   1, 0x04, 0x00000000 },
+       { 0x000b0c,   1, 0x04, 0x00000000 },
+       { 0x000b2c,   1, 0x04, 0x00000000 },
+       { 0x000b4c,   1, 0x04, 0x00000000 },
+       { 0x000b6c,   1, 0x04, 0x00000000 },
+       { 0x000b8c,   1, 0x04, 0x00000000 },
+       { 0x000bac,   1, 0x04, 0x00000000 },
+       { 0x000bcc,   1, 0x04, 0x00000000 },
+       { 0x000bec,   1, 0x04, 0x00000000 },
+       { 0x000a10,   1, 0x04, 0x00000000 },
+       { 0x000a30,   1, 0x04, 0x00000000 },
+       { 0x000a50,   1, 0x04, 0x00000000 },
+       { 0x000a70,   1, 0x04, 0x00000000 },
+       { 0x000a90,   1, 0x04, 0x00000000 },
+       { 0x000ab0,   1, 0x04, 0x00000000 },
+       { 0x000ad0,   1, 0x04, 0x00000000 },
+       { 0x000af0,   1, 0x04, 0x00000000 },
+       { 0x000b10,   1, 0x04, 0x00000000 },
+       { 0x000b30,   1, 0x04, 0x00000000 },
+       { 0x000b50,   1, 0x04, 0x00000000 },
+       { 0x000b70,   1, 0x04, 0x00000000 },
+       { 0x000b90,   1, 0x04, 0x00000000 },
+       { 0x000bb0,   1, 0x04, 0x00000000 },
+       { 0x000bd0,   1, 0x04, 0x00000000 },
+       { 0x000bf0,   1, 0x04, 0x00000000 },
+       { 0x000a14,   1, 0x04, 0x00000000 },
+       { 0x000a34,   1, 0x04, 0x00000000 },
+       { 0x000a54,   1, 0x04, 0x00000000 },
+       { 0x000a74,   1, 0x04, 0x00000000 },
+       { 0x000a94,   1, 0x04, 0x00000000 },
+       { 0x000ab4,   1, 0x04, 0x00000000 },
+       { 0x000ad4,   1, 0x04, 0x00000000 },
+       { 0x000af4,   1, 0x04, 0x00000000 },
+       { 0x000b14,   1, 0x04, 0x00000000 },
+       { 0x000b34,   1, 0x04, 0x00000000 },
+       { 0x000b54,   1, 0x04, 0x00000000 },
+       { 0x000b74,   1, 0x04, 0x00000000 },
+       { 0x000b94,   1, 0x04, 0x00000000 },
+       { 0x000bb4,   1, 0x04, 0x00000000 },
+       { 0x000bd4,   1, 0x04, 0x00000000 },
+       { 0x000bf4,   1, 0x04, 0x00000000 },
+       { 0x000c00,   1, 0x04, 0x00000000 },
+       { 0x000c10,   1, 0x04, 0x00000000 },
+       { 0x000c20,   1, 0x04, 0x00000000 },
+       { 0x000c30,   1, 0x04, 0x00000000 },
+       { 0x000c40,   1, 0x04, 0x00000000 },
+       { 0x000c50,   1, 0x04, 0x00000000 },
+       { 0x000c60,   1, 0x04, 0x00000000 },
+       { 0x000c70,   1, 0x04, 0x00000000 },
+       { 0x000c80,   1, 0x04, 0x00000000 },
+       { 0x000c90,   1, 0x04, 0x00000000 },
+       { 0x000ca0,   1, 0x04, 0x00000000 },
+       { 0x000cb0,   1, 0x04, 0x00000000 },
+       { 0x000cc0,   1, 0x04, 0x00000000 },
+       { 0x000cd0,   1, 0x04, 0x00000000 },
+       { 0x000ce0,   1, 0x04, 0x00000000 },
+       { 0x000cf0,   1, 0x04, 0x00000000 },
+       { 0x000c04,   1, 0x04, 0x00000000 },
+       { 0x000c14,   1, 0x04, 0x00000000 },
+       { 0x000c24,   1, 0x04, 0x00000000 },
+       { 0x000c34,   1, 0x04, 0x00000000 },
+       { 0x000c44,   1, 0x04, 0x00000000 },
+       { 0x000c54,   1, 0x04, 0x00000000 },
+       { 0x000c64,   1, 0x04, 0x00000000 },
+       { 0x000c74,   1, 0x04, 0x00000000 },
+       { 0x000c84,   1, 0x04, 0x00000000 },
+       { 0x000c94,   1, 0x04, 0x00000000 },
+       { 0x000ca4,   1, 0x04, 0x00000000 },
+       { 0x000cb4,   1, 0x04, 0x00000000 },
+       { 0x000cc4,   1, 0x04, 0x00000000 },
+       { 0x000cd4,   1, 0x04, 0x00000000 },
+       { 0x000ce4,   1, 0x04, 0x00000000 },
+       { 0x000cf4,   1, 0x04, 0x00000000 },
+       { 0x000c08,   1, 0x04, 0x00000000 },
+       { 0x000c18,   1, 0x04, 0x00000000 },
+       { 0x000c28,   1, 0x04, 0x00000000 },
+       { 0x000c38,   1, 0x04, 0x00000000 },
+       { 0x000c48,   1, 0x04, 0x00000000 },
+       { 0x000c58,   1, 0x04, 0x00000000 },
+       { 0x000c68,   1, 0x04, 0x00000000 },
+       { 0x000c78,   1, 0x04, 0x00000000 },
+       { 0x000c88,   1, 0x04, 0x00000000 },
+       { 0x000c98,   1, 0x04, 0x00000000 },
+       { 0x000ca8,   1, 0x04, 0x00000000 },
+       { 0x000cb8,   1, 0x04, 0x00000000 },
+       { 0x000cc8,   1, 0x04, 0x00000000 },
+       { 0x000cd8,   1, 0x04, 0x00000000 },
+       { 0x000ce8,   1, 0x04, 0x00000000 },
+       { 0x000cf8,   1, 0x04, 0x00000000 },
+       { 0x000c0c,   1, 0x04, 0x3f800000 },
+       { 0x000c1c,   1, 0x04, 0x3f800000 },
+       { 0x000c2c,   1, 0x04, 0x3f800000 },
+       { 0x000c3c,   1, 0x04, 0x3f800000 },
+       { 0x000c4c,   1, 0x04, 0x3f800000 },
+       { 0x000c5c,   1, 0x04, 0x3f800000 },
+       { 0x000c6c,   1, 0x04, 0x3f800000 },
+       { 0x000c7c,   1, 0x04, 0x3f800000 },
+       { 0x000c8c,   1, 0x04, 0x3f800000 },
+       { 0x000c9c,   1, 0x04, 0x3f800000 },
+       { 0x000cac,   1, 0x04, 0x3f800000 },
+       { 0x000cbc,   1, 0x04, 0x3f800000 },
+       { 0x000ccc,   1, 0x04, 0x3f800000 },
+       { 0x000cdc,   1, 0x04, 0x3f800000 },
+       { 0x000cec,   1, 0x04, 0x3f800000 },
+       { 0x000cfc,   1, 0x04, 0x3f800000 },
+       { 0x000d00,   1, 0x04, 0xffff0000 },
+       { 0x000d08,   1, 0x04, 0xffff0000 },
+       { 0x000d10,   1, 0x04, 0xffff0000 },
+       { 0x000d18,   1, 0x04, 0xffff0000 },
+       { 0x000d20,   1, 0x04, 0xffff0000 },
+       { 0x000d28,   1, 0x04, 0xffff0000 },
+       { 0x000d30,   1, 0x04, 0xffff0000 },
+       { 0x000d38,   1, 0x04, 0xffff0000 },
+       { 0x000d04,   1, 0x04, 0xffff0000 },
+       { 0x000d0c,   1, 0x04, 0xffff0000 },
+       { 0x000d14,   1, 0x04, 0xffff0000 },
+       { 0x000d1c,   1, 0x04, 0xffff0000 },
+       { 0x000d24,   1, 0x04, 0xffff0000 },
+       { 0x000d2c,   1, 0x04, 0xffff0000 },
+       { 0x000d34,   1, 0x04, 0xffff0000 },
+       { 0x000d3c,   1, 0x04, 0xffff0000 },
+       { 0x000e00,   1, 0x04, 0x00000000 },
+       { 0x000e10,   1, 0x04, 0x00000000 },
+       { 0x000e20,   1, 0x04, 0x00000000 },
+       { 0x000e30,   1, 0x04, 0x00000000 },
+       { 0x000e40,   1, 0x04, 0x00000000 },
+       { 0x000e50,   1, 0x04, 0x00000000 },
+       { 0x000e60,   1, 0x04, 0x00000000 },
+       { 0x000e70,   1, 0x04, 0x00000000 },
+       { 0x000e80,   1, 0x04, 0x00000000 },
+       { 0x000e90,   1, 0x04, 0x00000000 },
+       { 0x000ea0,   1, 0x04, 0x00000000 },
+       { 0x000eb0,   1, 0x04, 0x00000000 },
+       { 0x000ec0,   1, 0x04, 0x00000000 },
+       { 0x000ed0,   1, 0x04, 0x00000000 },
+       { 0x000ee0,   1, 0x04, 0x00000000 },
+       { 0x000ef0,   1, 0x04, 0x00000000 },
+       { 0x000e04,   1, 0x04, 0xffff0000 },
+       { 0x000e14,   1, 0x04, 0xffff0000 },
+       { 0x000e24,   1, 0x04, 0xffff0000 },
+       { 0x000e34,   1, 0x04, 0xffff0000 },
+       { 0x000e44,   1, 0x04, 0xffff0000 },
+       { 0x000e54,   1, 0x04, 0xffff0000 },
+       { 0x000e64,   1, 0x04, 0xffff0000 },
+       { 0x000e74,   1, 0x04, 0xffff0000 },
+       { 0x000e84,   1, 0x04, 0xffff0000 },
+       { 0x000e94,   1, 0x04, 0xffff0000 },
+       { 0x000ea4,   1, 0x04, 0xffff0000 },
+       { 0x000eb4,   1, 0x04, 0xffff0000 },
+       { 0x000ec4,   1, 0x04, 0xffff0000 },
+       { 0x000ed4,   1, 0x04, 0xffff0000 },
+       { 0x000ee4,   1, 0x04, 0xffff0000 },
+       { 0x000ef4,   1, 0x04, 0xffff0000 },
+       { 0x000e08,   1, 0x04, 0xffff0000 },
+       { 0x000e18,   1, 0x04, 0xffff0000 },
+       { 0x000e28,   1, 0x04, 0xffff0000 },
+       { 0x000e38,   1, 0x04, 0xffff0000 },
+       { 0x000e48,   1, 0x04, 0xffff0000 },
+       { 0x000e58,   1, 0x04, 0xffff0000 },
+       { 0x000e68,   1, 0x04, 0xffff0000 },
+       { 0x000e78,   1, 0x04, 0xffff0000 },
+       { 0x000e88,   1, 0x04, 0xffff0000 },
+       { 0x000e98,   1, 0x04, 0xffff0000 },
+       { 0x000ea8,   1, 0x04, 0xffff0000 },
+       { 0x000eb8,   1, 0x04, 0xffff0000 },
+       { 0x000ec8,   1, 0x04, 0xffff0000 },
+       { 0x000ed8,   1, 0x04, 0xffff0000 },
+       { 0x000ee8,   1, 0x04, 0xffff0000 },
+       { 0x000ef8,   1, 0x04, 0xffff0000 },
+       { 0x000d40,   1, 0x04, 0x00000000 },
+       { 0x000d48,   1, 0x04, 0x00000000 },
+       { 0x000d50,   1, 0x04, 0x00000000 },
+       { 0x000d58,   1, 0x04, 0x00000000 },
+       { 0x000d44,   1, 0x04, 0x00000000 },
+       { 0x000d4c,   1, 0x04, 0x00000000 },
+       { 0x000d54,   1, 0x04, 0x00000000 },
+       { 0x000d5c,   1, 0x04, 0x00000000 },
+       { 0x001e00,   1, 0x04, 0x00000001 },
+       { 0x001e20,   1, 0x04, 0x00000001 },
+       { 0x001e40,   1, 0x04, 0x00000001 },
+       { 0x001e60,   1, 0x04, 0x00000001 },
+       { 0x001e80,   1, 0x04, 0x00000001 },
+       { 0x001ea0,   1, 0x04, 0x00000001 },
+       { 0x001ec0,   1, 0x04, 0x00000001 },
+       { 0x001ee0,   1, 0x04, 0x00000001 },
+       { 0x001e04,   1, 0x04, 0x00000001 },
+       { 0x001e24,   1, 0x04, 0x00000001 },
+       { 0x001e44,   1, 0x04, 0x00000001 },
+       { 0x001e64,   1, 0x04, 0x00000001 },
+       { 0x001e84,   1, 0x04, 0x00000001 },
+       { 0x001ea4,   1, 0x04, 0x00000001 },
+       { 0x001ec4,   1, 0x04, 0x00000001 },
+       { 0x001ee4,   1, 0x04, 0x00000001 },
+       { 0x001e08,   1, 0x04, 0x00000002 },
+       { 0x001e28,   1, 0x04, 0x00000002 },
+       { 0x001e48,   1, 0x04, 0x00000002 },
+       { 0x001e68,   1, 0x04, 0x00000002 },
+       { 0x001e88,   1, 0x04, 0x00000002 },
+       { 0x001ea8,   1, 0x04, 0x00000002 },
+       { 0x001ec8,   1, 0x04, 0x00000002 },
+       { 0x001ee8,   1, 0x04, 0x00000002 },
+       { 0x001e0c,   1, 0x04, 0x00000001 },
+       { 0x001e2c,   1, 0x04, 0x00000001 },
+       { 0x001e4c,   1, 0x04, 0x00000001 },
+       { 0x001e6c,   1, 0x04, 0x00000001 },
+       { 0x001e8c,   1, 0x04, 0x00000001 },
+       { 0x001eac,   1, 0x04, 0x00000001 },
+       { 0x001ecc,   1, 0x04, 0x00000001 },
+       { 0x001eec,   1, 0x04, 0x00000001 },
+       { 0x001e10,   1, 0x04, 0x00000001 },
+       { 0x001e30,   1, 0x04, 0x00000001 },
+       { 0x001e50,   1, 0x04, 0x00000001 },
+       { 0x001e70,   1, 0x04, 0x00000001 },
+       { 0x001e90,   1, 0x04, 0x00000001 },
+       { 0x001eb0,   1, 0x04, 0x00000001 },
+       { 0x001ed0,   1, 0x04, 0x00000001 },
+       { 0x001ef0,   1, 0x04, 0x00000001 },
+       { 0x001e14,   1, 0x04, 0x00000002 },
+       { 0x001e34,   1, 0x04, 0x00000002 },
+       { 0x001e54,   1, 0x04, 0x00000002 },
+       { 0x001e74,   1, 0x04, 0x00000002 },
+       { 0x001e94,   1, 0x04, 0x00000002 },
+       { 0x001eb4,   1, 0x04, 0x00000002 },
+       { 0x001ed4,   1, 0x04, 0x00000002 },
+       { 0x001ef4,   1, 0x04, 0x00000002 },
+       { 0x001e18,   1, 0x04, 0x00000001 },
+       { 0x001e38,   1, 0x04, 0x00000001 },
+       { 0x001e58,   1, 0x04, 0x00000001 },
+       { 0x001e78,   1, 0x04, 0x00000001 },
+       { 0x001e98,   1, 0x04, 0x00000001 },
+       { 0x001eb8,   1, 0x04, 0x00000001 },
+       { 0x001ed8,   1, 0x04, 0x00000001 },
+       { 0x001ef8,   1, 0x04, 0x00000001 },
+       { 0x003400, 128, 0x04, 0x00000000 },
+       { 0x00030c,   1, 0x04, 0x00000001 },
+       { 0x001944,   1, 0x04, 0x00000000 },
+       { 0x001514,   1, 0x04, 0x00000000 },
+       { 0x000d68,   1, 0x04, 0x0000ffff },
+       { 0x00121c,   1, 0x04, 0x0fac6881 },
+       { 0x000fac,   1, 0x04, 0x00000001 },
+       { 0x001538,   1, 0x04, 0x00000001 },
+       { 0x000fe0,   2, 0x04, 0x00000000 },
+       { 0x000fe8,   1, 0x04, 0x00000014 },
+       { 0x000fec,   1, 0x04, 0x00000040 },
+       { 0x000ff0,   1, 0x04, 0x00000000 },
+       { 0x00179c,   1, 0x04, 0x00000000 },
+       { 0x001228,   1, 0x04, 0x00000400 },
+       { 0x00122c,   1, 0x04, 0x00000300 },
+       { 0x001230,   1, 0x04, 0x00010001 },
+       { 0x0007f8,   1, 0x04, 0x00000000 },
+       { 0x0015b4,   1, 0x04, 0x00000001 },
+       { 0x0015cc,   1, 0x04, 0x00000000 },
+       { 0x001534,   1, 0x04, 0x00000000 },
+       { 0x000fb0,   1, 0x04, 0x00000000 },
+       { 0x0015d0,   1, 0x04, 0x00000000 },
+       { 0x00153c,   1, 0x04, 0x00000000 },
+       { 0x0016b4,   1, 0x04, 0x00000003 },
+       { 0x000fbc,   4, 0x04, 0x0000ffff },
+       { 0x000df8,   2, 0x04, 0x00000000 },
+       { 0x001948,   1, 0x04, 0x00000000 },
+       { 0x001970,   1, 0x04, 0x00000001 },
+       { 0x00161c,   1, 0x04, 0x000009f0 },
+       { 0x000dcc,   1, 0x04, 0x00000010 },
+       { 0x00163c,   1, 0x04, 0x00000000 },
+       { 0x0015e4,   1, 0x04, 0x00000000 },
+       { 0x001160,  32, 0x04, 0x25e00040 },
+       { 0x001880,  32, 0x04, 0x00000000 },
+       { 0x000f84,   2, 0x04, 0x00000000 },
+       { 0x0017c8,   2, 0x04, 0x00000000 },
+       { 0x0017d0,   1, 0x04, 0x000000ff },
+       { 0x0017d4,   1, 0x04, 0xffffffff },
+       { 0x0017d8,   1, 0x04, 0x00000002 },
+       { 0x0017dc,   1, 0x04, 0x00000000 },
+       { 0x0015f4,   2, 0x04, 0x00000000 },
+       { 0x001434,   2, 0x04, 0x00000000 },
+       { 0x000d74,   1, 0x04, 0x00000000 },
+       { 0x000dec,   1, 0x04, 0x00000001 },
+       { 0x0013a4,   1, 0x04, 0x00000000 },
+       { 0x001318,   1, 0x04, 0x00000001 },
+       { 0x001644,   1, 0x04, 0x00000000 },
+       { 0x000748,   1, 0x04, 0x00000000 },
+       { 0x000de8,   1, 0x04, 0x00000000 },
+       { 0x001648,   1, 0x04, 0x00000000 },
+       { 0x0012a4,   1, 0x04, 0x00000000 },
+       { 0x001120,   4, 0x04, 0x00000000 },
+       { 0x001118,   1, 0x04, 0x00000000 },
+       { 0x00164c,   1, 0x04, 0x00000000 },
+       { 0x001658,   1, 0x04, 0x00000000 },
+       { 0x001910,   1, 0x04, 0x00000290 },
+       { 0x001518,   1, 0x04, 0x00000000 },
+       { 0x00165c,   1, 0x04, 0x00000001 },
+       { 0x001520,   1, 0x04, 0x00000000 },
+       { 0x001604,   1, 0x04, 0x00000000 },
+       { 0x001570,   1, 0x04, 0x00000000 },
+       { 0x0013b0,   2, 0x04, 0x3f800000 },
+       { 0x00020c,   1, 0x04, 0x00000000 },
+       { 0x001670,   1, 0x04, 0x30201000 },
+       { 0x001674,   1, 0x04, 0x70605040 },
+       { 0x001678,   1, 0x04, 0xb8a89888 },
+       { 0x00167c,   1, 0x04, 0xf8e8d8c8 },
+       { 0x00166c,   1, 0x04, 0x00000000 },
+       { 0x001680,   1, 0x04, 0x00ffff00 },
+       { 0x0012d0,   1, 0x04, 0x00000003 },
+       { 0x0012d4,   1, 0x04, 0x00000002 },
+       { 0x001684,   2, 0x04, 0x00000000 },
+       { 0x000dac,   2, 0x04, 0x00001b02 },
+       { 0x000db4,   1, 0x04, 0x00000000 },
+       { 0x00168c,   1, 0x04, 0x00000000 },
+       { 0x0015bc,   1, 0x04, 0x00000000 },
+       { 0x00156c,   1, 0x04, 0x00000000 },
+       { 0x00187c,   1, 0x04, 0x00000000 },
+       { 0x001110,   1, 0x04, 0x00000001 },
+       { 0x000dc0,   3, 0x04, 0x00000000 },
+       { 0x001234,   1, 0x04, 0x00000000 },
+       { 0x001690,   1, 0x04, 0x00000000 },
+       { 0x0012ac,   1, 0x04, 0x00000001 },
+       { 0x0002c4,   1, 0x04, 0x00000000 },
+       { 0x000790,   5, 0x04, 0x00000000 },
+       { 0x00077c,   1, 0x04, 0x00000000 },
+       { 0x001000,   1, 0x04, 0x00000010 },
+       { 0x0010fc,   1, 0x04, 0x00000000 },
+       { 0x001290,   1, 0x04, 0x00000000 },
+       { 0x000218,   1, 0x04, 0x00000010 },
+       { 0x0012d8,   1, 0x04, 0x00000000 },
+       { 0x0012dc,   1, 0x04, 0x00000010 },
+       { 0x000d94,   1, 0x04, 0x00000001 },
+       { 0x00155c,   2, 0x04, 0x00000000 },
+       { 0x001564,   1, 0x04, 0x00000fff },
+       { 0x001574,   2, 0x04, 0x00000000 },
+       { 0x00157c,   1, 0x04, 0x000fffff },
+       { 0x001354,   1, 0x04, 0x00000000 },
+       { 0x001610,   1, 0x04, 0x00000012 },
+       { 0x001608,   2, 0x04, 0x00000000 },
+       { 0x00260c,   1, 0x04, 0x00000000 },
+       { 0x0007ac,   1, 0x04, 0x00000000 },
+       { 0x00162c,   1, 0x04, 0x00000003 },
+       { 0x000210,   1, 0x04, 0x00000000 },
+       { 0x000320,   1, 0x04, 0x00000000 },
+       { 0x000324,   6, 0x04, 0x3f800000 },
+       { 0x000750,   1, 0x04, 0x00000000 },
+       { 0x000760,   1, 0x04, 0x39291909 },
+       { 0x000764,   1, 0x04, 0x79695949 },
+       { 0x000768,   1, 0x04, 0xb9a99989 },
+       { 0x00076c,   1, 0x04, 0xf9e9d9c9 },
+       { 0x000770,   1, 0x04, 0x30201000 },
+       { 0x000774,   1, 0x04, 0x70605040 },
+       { 0x000778,   1, 0x04, 0x00009080 },
+       { 0x000780,   1, 0x04, 0x39291909 },
+       { 0x000784,   1, 0x04, 0x79695949 },
+       { 0x000788,   1, 0x04, 0xb9a99989 },
+       { 0x00078c,   1, 0x04, 0xf9e9d9c9 },
+       { 0x0007d0,   1, 0x04, 0x30201000 },
+       { 0x0007d4,   1, 0x04, 0x70605040 },
+       { 0x0007d8,   1, 0x04, 0x00009080 },
+       { 0x00037c,   1, 0x04, 0x00000001 },
+       { 0x000740,   2, 0x04, 0x00000000 },
+       { 0x002600,   1, 0x04, 0x00000000 },
+       { 0x001918,   1, 0x04, 0x00000000 },
+       { 0x00191c,   1, 0x04, 0x00000900 },
+       { 0x001920,   1, 0x04, 0x00000405 },
+       { 0x001308,   1, 0x04, 0x00000001 },
+       { 0x001924,   1, 0x04, 0x00000000 },
+       { 0x0013ac,   1, 0x04, 0x00000000 },
+       { 0x00192c,   1, 0x04, 0x00000001 },
+       { 0x00193c,   1, 0x04, 0x00002c1c },
+       { 0x000d7c,   1, 0x04, 0x00000000 },
+       { 0x000f8c,   1, 0x04, 0x00000000 },
+       { 0x0002c0,   1, 0x04, 0x00000001 },
+       { 0x001510,   1, 0x04, 0x00000000 },
+       { 0x001940,   1, 0x04, 0x00000000 },
+       { 0x000ff4,   2, 0x04, 0x00000000 },
+       { 0x00194c,   2, 0x04, 0x00000000 },
+       { 0x001968,   1, 0x04, 0x00000000 },
+       { 0x001590,   1, 0x04, 0x0000003f },
+       { 0x0007e8,   4, 0x04, 0x00000000 },
+       { 0x00196c,   1, 0x04, 0x00000011 },
+       { 0x0002e4,   1, 0x04, 0x0000b001 },
+       { 0x00036c,   2, 0x04, 0x00000000 },
+       { 0x00197c,   1, 0x04, 0x00000000 },
+       { 0x000fcc,   2, 0x04, 0x00000000 },
+       { 0x0002d8,   1, 0x04, 0x00000040 },
+       { 0x001980,   1, 0x04, 0x00000080 },
+       { 0x001504,   1, 0x04, 0x00000080 },
+       { 0x001984,   1, 0x04, 0x00000000 },
+       { 0x000300,   1, 0x04, 0x00000001 },
+       { 0x0013a8,   1, 0x04, 0x00000000 },
+       { 0x0012ec,   1, 0x04, 0x00000000 },
+       { 0x001310,   1, 0x04, 0x00000000 },
+       { 0x001314,   1, 0x04, 0x00000001 },
+       { 0x001380,   1, 0x04, 0x00000000 },
+       { 0x001384,   4, 0x04, 0x00000001 },
+       { 0x001394,   1, 0x04, 0x00000000 },
+       { 0x00139c,   1, 0x04, 0x00000000 },
+       { 0x001398,   1, 0x04, 0x00000000 },
+       { 0x001594,   1, 0x04, 0x00000000 },
+       { 0x001598,   4, 0x04, 0x00000001 },
+       { 0x000f54,   3, 0x04, 0x00000000 },
+       { 0x0019bc,   1, 0x04, 0x00000000 },
+       { 0x000f9c,   2, 0x04, 0x00000000 },
+       { 0x0012cc,   1, 0x04, 0x00000000 },
+       { 0x0012e8,   1, 0x04, 0x00000000 },
+       { 0x00130c,   1, 0x04, 0x00000001 },
+       { 0x001360,   8, 0x04, 0x00000000 },
+       { 0x00133c,   2, 0x04, 0x00000001 },
+       { 0x001344,   1, 0x04, 0x00000002 },
+       { 0x001348,   2, 0x04, 0x00000001 },
+       { 0x001350,   1, 0x04, 0x00000002 },
+       { 0x001358,   1, 0x04, 0x00000001 },
+       { 0x0012e4,   1, 0x04, 0x00000000 },
+       { 0x00131c,   4, 0x04, 0x00000000 },
+       { 0x0019c0,   1, 0x04, 0x00000000 },
+       { 0x001140,   1, 0x04, 0x00000000 },
+       { 0x0019c4,   1, 0x04, 0x00000000 },
+       { 0x0019c8,   1, 0x04, 0x00001500 },
+       { 0x00135c,   1, 0x04, 0x00000000 },
+       { 0x000f90,   1, 0x04, 0x00000000 },
+       { 0x0019e0,   8, 0x04, 0x00000001 },
+       { 0x0019cc,   1, 0x04, 0x00000001 },
+       { 0x0015b8,   1, 0x04, 0x00000000 },
+       { 0x001a00,   1, 0x04, 0x00001111 },
+       { 0x001a04,   7, 0x04, 0x00000000 },
+       { 0x000d6c,   2, 0x04, 0xffff0000 },
+       { 0x0010f8,   1, 0x04, 0x00001010 },
+       { 0x000d80,   5, 0x04, 0x00000000 },
+       { 0x000da0,   1, 0x04, 0x00000000 },
+       { 0x0007a4,   2, 0x04, 0x00000000 },
+       { 0x001508,   1, 0x04, 0x80000000 },
+       { 0x00150c,   1, 0x04, 0x40000000 },
+       { 0x001668,   1, 0x04, 0x00000000 },
+       { 0x000318,   2, 0x04, 0x00000008 },
+       { 0x000d9c,   1, 0x04, 0x00000001 },
+       { 0x000ddc,   1, 0x04, 0x00000002 },
+       { 0x000374,   1, 0x04, 0x00000000 },
+       { 0x000378,   1, 0x04, 0x00000020 },
+       { 0x0007dc,   1, 0x04, 0x00000000 },
+       { 0x00074c,   1, 0x04, 0x00000055 },
+       { 0x001420,   1, 0x04, 0x00000003 },
+       { 0x0017bc,   2, 0x04, 0x00000000 },
+       { 0x0017c4,   1, 0x04, 0x00000001 },
+       { 0x001008,   1, 0x04, 0x00000008 },
+       { 0x00100c,   1, 0x04, 0x00000040 },
+       { 0x001010,   1, 0x04, 0x0000012c },
+       { 0x000d60,   1, 0x04, 0x00000040 },
+       { 0x00075c,   1, 0x04, 0x00000003 },
+       { 0x001018,   1, 0x04, 0x00000020 },
+       { 0x00101c,   1, 0x04, 0x00000001 },
+       { 0x001020,   1, 0x04, 0x00000020 },
+       { 0x001024,   1, 0x04, 0x00000001 },
+       { 0x001444,   3, 0x04, 0x00000000 },
+       { 0x000360,   1, 0x04, 0x20164010 },
+       { 0x000364,   1, 0x04, 0x00000020 },
+       { 0x000368,   1, 0x04, 0x00000000 },
+       { 0x000de4,   1, 0x04, 0x00000000 },
+       { 0x000204,   1, 0x04, 0x00000006 },
+       { 0x000208,   1, 0x04, 0x00000000 },
+       { 0x0002cc,   2, 0x04, 0x003fffff },
+       { 0x001220,   1, 0x04, 0x00000005 },
+       { 0x000fdc,   1, 0x04, 0x00000000 },
+       { 0x000f98,   1, 0x04, 0x00400008 },
+       { 0x001284,   1, 0x04, 0x08000080 },
+       { 0x001450,   1, 0x04, 0x00400008 },
+       { 0x001454,   1, 0x04, 0x08000080 },
+       { 0x000214,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_grctx_init_unk40xx[] = {
+       { 0x404004,   8, 0x04, 0x00000000 },
+       { 0x404024,   1, 0x04, 0x0000e000 },
+       { 0x404028,   8, 0x04, 0x00000000 },
+       { 0x4040a8,   8, 0x04, 0x00000000 },
+       { 0x4040c8,   1, 0x04, 0xf800008f },
+       { 0x4040d0,   6, 0x04, 0x00000000 },
+       { 0x4040e8,   1, 0x04, 0x00001000 },
+       { 0x4040f8,   1, 0x04, 0x00000000 },
+       { 0x404100,  10, 0x04, 0x00000000 },
+       { 0x404130,   2, 0x04, 0x00000000 },
+       { 0x404138,   1, 0x04, 0x20000040 },
+       { 0x404150,   1, 0x04, 0x0000002e },
+       { 0x404154,   1, 0x04, 0x00000400 },
+       { 0x404158,   1, 0x04, 0x00000200 },
+       { 0x404164,   1, 0x04, 0x00000055 },
+       { 0x40417c,   2, 0x04, 0x00000000 },
+       { 0x404194,   1, 0x04, 0x01000700 },
+       { 0x4041a0,   4, 0x04, 0x00000000 },
+       { 0x404200,   1, 0x04, 0x0000a197 },
+       { 0x404204,   1, 0x04, 0x0000a1c0 },
+       { 0x404208,   1, 0x04, 0x0000a140 },
+       { 0x40420c,   1, 0x04, 0x0000902d },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_grctx_init_unk58xx[] = {
+       { 0x405800,   1, 0x04, 0x0f8000bf },
+       { 0x405830,   1, 0x04, 0x02180648 },
+       { 0x405834,   1, 0x04, 0x08000000 },
+       { 0x405838,   1, 0x04, 0x00000000 },
+       { 0x405854,   1, 0x04, 0x00000000 },
+       { 0x405870,   4, 0x04, 0x00000001 },
+       { 0x405a00,   2, 0x04, 0x00000000 },
+       { 0x405a18,   1, 0x04, 0x00000000 },
+       { 0x405a1c,   1, 0x04, 0x000000ff },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_grctx_init_unk64xx[] = {
+       { 0x4064a8,   1, 0x04, 0x00000000 },
+       { 0x4064ac,   1, 0x04, 0x00003fff },
+       { 0x4064b0,   3, 0x04, 0x00000000 },
+       { 0x4064c0,   1, 0x04, 0x802000f0 },
+       { 0x4064c4,   1, 0x04, 0x0192ffff },
+       { 0x4064c8,   1, 0x04, 0x00c20200 },
+       { 0x4064cc,   9, 0x04, 0x00000000 },
+       { 0x4064fc,   1, 0x04, 0x0000022a },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_grctx_init_unk78xx[] = {
+       { 0x407804,   1, 0x04, 0x00000063 },
+       { 0x40780c,   1, 0x04, 0x0a418820 },
+       { 0x407810,   1, 0x04, 0x062080e6 },
+       { 0x407814,   1, 0x04, 0x020398a4 },
+       { 0x407818,   1, 0x04, 0x0e629062 },
+       { 0x40781c,   1, 0x04, 0x0a418820 },
+       { 0x407820,   1, 0x04, 0x000000e6 },
+       { 0x4078bc,   1, 0x04, 0x00000103 },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_grctx_init_unk88xx[] = {
+       { 0x408800,   1, 0x04, 0x32802a3c },
+       { 0x408804,   1, 0x04, 0x00000040 },
+       { 0x408808,   1, 0x04, 0x1003e005 },
+       { 0x408840,   1, 0x04, 0x0000000b },
+       { 0x408900,   1, 0x04, 0xb080b801 },
+       { 0x408904,   1, 0x04, 0x62000001 },
+       { 0x408908,   1, 0x04, 0x02c8102f },
+       { 0x408980,   1, 0x04, 0x0000011d },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_grctx_init_gpc_0[] = {
+       { 0x418380,   1, 0x04, 0x00000016 },
+       { 0x418400,   1, 0x04, 0x38005e00 },
+       { 0x418404,   1, 0x04, 0x71e0ffff },
+       { 0x41840c,   1, 0x04, 0x00001008 },
+       { 0x418410,   1, 0x04, 0x0fff0fff },
+       { 0x418414,   1, 0x04, 0x02200fff },
+       { 0x418450,   6, 0x04, 0x00000000 },
+       { 0x418468,   1, 0x04, 0x00000001 },
+       { 0x41846c,   2, 0x04, 0x00000000 },
+       { 0x418600,   1, 0x04, 0x0000007f },
+       { 0x418684,   1, 0x04, 0x0000001f },
+       { 0x418700,   1, 0x04, 0x00000002 },
+       { 0x418704,   2, 0x04, 0x00000080 },
+       { 0x41870c,   2, 0x04, 0x00000000 },
+       { 0x418800,   1, 0x04, 0x7006863a },
+       { 0x418808,   1, 0x04, 0x00000000 },
+       { 0x41880c,   1, 0x04, 0x00000030 },
+       { 0x418810,   1, 0x04, 0x00000000 },
+       { 0x418828,   1, 0x04, 0x00000044 },
+       { 0x418830,   1, 0x04, 0x10000001 },
+       { 0x4188d8,   1, 0x04, 0x00000008 },
+       { 0x4188e0,   1, 0x04, 0x01000000 },
+       { 0x4188e8,   5, 0x04, 0x00000000 },
+       { 0x4188fc,   1, 0x04, 0x20100058 },
+       { 0x41891c,   1, 0x04, 0x00ff00ff },
+       { 0x418924,   1, 0x04, 0x00000000 },
+       { 0x418928,   1, 0x04, 0x00ffff00 },
+       { 0x41892c,   1, 0x04, 0x0000ff00 },
+       { 0x418b00,   1, 0x04, 0x0000001e },
+       { 0x418b08,   1, 0x04, 0x0a418820 },
+       { 0x418b0c,   1, 0x04, 0x062080e6 },
+       { 0x418b10,   1, 0x04, 0x020398a4 },
+       { 0x418b14,   1, 0x04, 0x0e629062 },
+       { 0x418b18,   1, 0x04, 0x0a418820 },
+       { 0x418b1c,   1, 0x04, 0x000000e6 },
+       { 0x418bb8,   1, 0x04, 0x00000103 },
+       { 0x418c08,   1, 0x04, 0x00000001 },
+       { 0x418c10,   8, 0x04, 0x00000000 },
+       { 0x418c40,   1, 0x04, 0xffffffff },
+       { 0x418c6c,   1, 0x04, 0x00000001 },
+       { 0x418c80,   1, 0x04, 0x2020000c },
+       { 0x418c8c,   1, 0x04, 0x00000001 },
+       { 0x418d24,   1, 0x04, 0x00000000 },
+       { 0x419000,   1, 0x04, 0x00000780 },
+       { 0x419004,   2, 0x04, 0x00000000 },
+       { 0x419014,   1, 0x04, 0x00000004 },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_grctx_init_tpc[] = {
+       { 0x419848,   1, 0x04, 0x00000000 },
+       { 0x419864,   1, 0x04, 0x00000129 },
+       { 0x419888,   1, 0x04, 0x00000000 },
+       { 0x419a00,   1, 0x04, 0x000100f0 },
+       { 0x419a04,   1, 0x04, 0x00000001 },
+       { 0x419a08,   1, 0x04, 0x00000421 },
+       { 0x419a0c,   1, 0x04, 0x00120000 },
+       { 0x419a10,   1, 0x04, 0x00000000 },
+       { 0x419a14,   1, 0x04, 0x00000200 },
+       { 0x419a1c,   1, 0x04, 0x0000c000 },
+       { 0x419a20,   1, 0x04, 0x00000800 },
+       { 0x419a30,   1, 0x04, 0x00000001 },
+       { 0x419ac4,   1, 0x04, 0x0037f440 },
+       { 0x419c00,   1, 0x04, 0x0000001a },
+       { 0x419c04,   1, 0x04, 0x80000006 },
+       { 0x419c08,   1, 0x04, 0x00000002 },
+       { 0x419c20,   1, 0x04, 0x00000000 },
+       { 0x419c24,   1, 0x04, 0x00084210 },
+       { 0x419c28,   1, 0x04, 0x3efbefbe },
+       { 0x419ce8,   1, 0x04, 0x00000000 },
+       { 0x419cf4,   1, 0x04, 0x00000203 },
+       { 0x419e04,   1, 0x04, 0x00000000 },
+       { 0x419e08,   1, 0x04, 0x0000001d },
+       { 0x419e0c,   1, 0x04, 0x00000000 },
+       { 0x419e10,   1, 0x04, 0x00001c02 },
+       { 0x419e44,   1, 0x04, 0x0013eff2 },
+       { 0x419e48,   1, 0x04, 0x00000000 },
+       { 0x419e4c,   1, 0x04, 0x0000007f },
+       { 0x419e50,   2, 0x04, 0x00000000 },
+       { 0x419e58,   1, 0x04, 0x00000001 },
+       { 0x419e5c,   3, 0x04, 0x00000000 },
+       { 0x419e68,   1, 0x04, 0x00000002 },
+       { 0x419e6c,  12, 0x04, 0x00000000 },
+       { 0x419eac,   1, 0x04, 0x00001f8f },
+       { 0x419eb0,   1, 0x04, 0x0db00da0 },
+       { 0x419eb8,   1, 0x04, 0x00000000 },
+       { 0x419ec8,   1, 0x04, 0x0001304f },
+       { 0x419f30,   4, 0x04, 0x00000000 },
+       { 0x419f40,   1, 0x04, 0x00000018 },
+       { 0x419f44,   3, 0x04, 0x00000000 },
+       { 0x419f58,   1, 0x04, 0x00000020 },
+       { 0x419f70,   1, 0x04, 0x00000000 },
+       { 0x419f78,   1, 0x04, 0x000001eb },
+       { 0x419f7c,   1, 0x04, 0x00000404 },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_grctx_init_unk[] = {
+       { 0x41be24,   1, 0x04, 0x00000006 },
+       { 0x41bec0,   1, 0x04, 0x10000000 },
+       { 0x41bec4,   1, 0x04, 0x00037f7f },
+       { 0x41bee4,   1, 0x04, 0x00000000 },
+       { 0x41bef0,   1, 0x04, 0x000003ff },
+       { 0x41bf00,   1, 0x04, 0x0a418820 },
+       { 0x41bf04,   1, 0x04, 0x062080e6 },
+       { 0x41bf08,   1, 0x04, 0x020398a4 },
+       { 0x41bf0c,   1, 0x04, 0x0e629062 },
+       { 0x41bf10,   1, 0x04, 0x0a418820 },
+       { 0x41bf14,   1, 0x04, 0x000000e6 },
+       { 0x41bfd0,   1, 0x04, 0x00900103 },
+       { 0x41bfe0,   1, 0x04, 0x00400001 },
+       { 0x41bfe4,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static void
+nv108_grctx_generate_mods(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
+{
+       u32 magic[GPC_MAX][2];
+       u32 offset;
+       int gpc;
+
+       mmio_data(0x003000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+       mmio_data(0x008000, 0x0100, NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS);
+       mmio_data(0x060000, 0x1000, NV_MEM_ACCESS_RW);
+       mmio_list(0x40800c, 0x00000000,  8, 1);
+       mmio_list(0x408010, 0x80000000,  0, 0);
+       mmio_list(0x419004, 0x00000000,  8, 1);
+       mmio_list(0x419008, 0x00000000,  0, 0);
+       mmio_list(0x408004, 0x00000000,  8, 0);
+       mmio_list(0x408008, 0x80000030,  0, 0);
+       mmio_list(0x418808, 0x00000000,  8, 0);
+       mmio_list(0x41880c, 0x80000030,  0, 0);
+       mmio_list(0x418810, 0x80000000, 12, 2);
+       mmio_list(0x419848, 0x10000000, 12, 2);
+
+       mmio_list(0x405830, 0x02180648,  0, 0);
+       mmio_list(0x4064c4, 0x0192ffff,  0, 0);
+
+       for (gpc = 0, offset = 0; gpc < priv->gpc_nr; gpc++) {
+               u16 magic0 = 0x0218 * priv->tpc_nr[gpc];
+               u16 magic1 = 0x0648 * priv->tpc_nr[gpc];
+               magic[gpc][0]  = 0x10000000 | (magic0 << 16) | offset;
+               magic[gpc][1]  = 0x00000000 | (magic1 << 16);
+               offset += 0x0324 * priv->tpc_nr[gpc];
+       }
+
+       for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+               mmio_list(GPC_UNIT(gpc, 0x30c0), magic[gpc][0], 0, 0);
+               mmio_list(GPC_UNIT(gpc, 0x30e4), magic[gpc][1] | offset, 0, 0);
+               offset += 0x07ff * priv->tpc_nr[gpc];
+       }
+
+       mmio_list(0x17e91c, 0x0b040a0b, 0, 0);
+       mmio_list(0x17e920, 0x00090d08, 0, 0);
+}
+
+static struct nvc0_graph_init *
+nv108_grctx_init_hub[] = {
+       nvc0_grctx_init_base,
+       nv108_grctx_init_unk40xx,
+       nvf0_grctx_init_unk44xx,
+       nve4_grctx_init_unk46xx,
+       nve4_grctx_init_unk47xx,
+       nv108_grctx_init_unk58xx,
+       nvf0_grctx_init_unk5bxx,
+       nvf0_grctx_init_unk60xx,
+       nv108_grctx_init_unk64xx,
+       nv108_grctx_init_unk78xx,
+       nve4_grctx_init_unk80xx,
+       nv108_grctx_init_unk88xx,
+       NULL
+};
+
+struct nvc0_graph_init *
+nv108_grctx_init_gpc[] = {
+       nv108_grctx_init_gpc_0,
+       nvc0_grctx_init_gpc_1,
+       nv108_grctx_init_tpc,
+       nv108_grctx_init_unk,
+       NULL
+};
+
+struct nvc0_graph_init
+nv108_grctx_init_mthd_magic[] = {
+       { 0x3410, 1, 0x04, 0x8e0e2006 },
+       { 0x3414, 1, 0x04, 0x00000038 },
+       {}
+};
+
+static struct nvc0_graph_mthd
+nv108_grctx_init_mthd[] = {
+       { 0xa197, nv108_grctx_init_a197, },
+       { 0x902d, nvc0_grctx_init_902d, },
+       { 0x902d, nv108_grctx_init_mthd_magic, },
+       {}
+};
+
+struct nouveau_oclass *
+nv108_grctx_oclass = &(struct nvc0_grctx_oclass) {
+       .base.handle = NV_ENGCTX(GR, 0x08),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_graph_context_ctor,
+               .dtor = nvc0_graph_context_dtor,
+               .init = _nouveau_graph_context_init,
+               .fini = _nouveau_graph_context_fini,
+               .rd32 = _nouveau_graph_context_rd32,
+               .wr32 = _nouveau_graph_context_wr32,
+       },
+       .main = nve4_grctx_generate_main,
+       .mods = nv108_grctx_generate_mods,
+       .unkn = nve4_grctx_generate_unkn,
+       .hub  = nv108_grctx_init_hub,
+       .gpc  = nv108_grctx_init_gpc,
+       .icmd = nv108_grctx_init_icmd,
+       .mthd = nv108_grctx_init_mthd,
+}.base;
index dcb2ebb8c29d93ac211bebd3d79f6224b48604b8..44012c3da53832c325e2286bafcc191208d9e946 100644 (file)
@@ -50,7 +50,7 @@ nvf0_grctx_init_unk40xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
+struct nvc0_graph_init
 nvf0_grctx_init_unk44xx[] = {
        { 0x404404,  12, 0x04, 0x00000000 },
        { 0x404438,   1, 0x04, 0x00000000 },
@@ -62,7 +62,7 @@ nvf0_grctx_init_unk44xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
+struct nvc0_graph_init
 nvf0_grctx_init_unk5bxx[] = {
        { 0x405b00,   1, 0x04, 0x00000000 },
        { 0x405b10,   1, 0x04, 0x00001000 },
@@ -70,7 +70,7 @@ nvf0_grctx_init_unk5bxx[] = {
        {}
 };
 
-static struct nvc0_graph_init
+struct nvc0_graph_init
 nvf0_grctx_init_unk60xx[] = {
        { 0x406020,   1, 0x04, 0x034103c1 },
        { 0x406028,   4, 0x04, 0x00000001 },
@@ -286,7 +286,6 @@ nvf0_grctx_init_hub[] = {
        nvf0_grctx_init_unk64xx,
        nve4_grctx_init_unk80xx,
        nvf0_grctx_init_unk88xx,
-       nvd9_grctx_init_rop,
        NULL
 };
 
index 5d24b6de16cce636e3db922c7c81d09018d9f2cc..e148961b8075e96be5ab2f1b86ebc7170676db4e 100644 (file)
@@ -38,7 +38,7 @@ queue_put:
        cmpu b32 $r8 $r9
        bra ne #queue_put_next
                mov $r15 E_CMD_OVERFLOW
-               call #error
+               call(error)
                ret
 
        // store cmd/data on queue
@@ -92,18 +92,16 @@ queue_get_done:
 // Out: $r15 value
 //
 nv_rd32:
-       mov $r11 0x728
-       shl b32 $r11 6
        mov b32 $r12 $r14
        bset $r12 31                    // MMIO_CTRL_PENDING
-       iowr I[$r11 + 0x000] $r12       // MMIO_CTRL
+       nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
        nv_rd32_wait:
-               iord $r12 I[$r11 + 0x000]
+               nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
                xbit $r12 $r12 31
                bra ne #nv_rd32_wait
        mov $r10 6                      // DONE_MMIO_RD
-       call #wait_doneo
-       iord $r15 I[$r11 + 0x100]       // MMIO_RDVAL
+       call(wait_doneo)
+       nv_iord($r15, NV_PGRAPH_FECS_MMIO_RDVAL, 0)
        ret
 
 // nv_wr32 - write 32-bit value to nv register
@@ -112,37 +110,17 @@ nv_rd32:
 //      $r15 value
 //
 nv_wr32:
-       mov $r11 0x728
-       shl b32 $r11 6
-       iowr I[$r11 + 0x200] $r15       // MMIO_WRVAL
+       nv_iowr(NV_PGRAPH_FECS_MMIO_WRVAL, 0, $r15)
        mov b32 $r12 $r14
        bset $r12 31                    // MMIO_CTRL_PENDING
        bset $r12 30                    // MMIO_CTRL_WRITE
-       iowr I[$r11 + 0x000] $r12       // MMIO_CTRL
+       nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
        nv_wr32_wait:
-               iord $r12 I[$r11 + 0x000]
+               nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
                xbit $r12 $r12 31
                bra ne #nv_wr32_wait
        ret
 
-// (re)set watchdog timer
-//
-// In : $r15 timeout
-//
-watchdog_reset:
-       mov $r8 0x430
-       shl b32 $r8 6
-       bset $r15 31
-       iowr I[$r8 + 0x000] $r15
-       ret
-
-// clear watchdog timer
-watchdog_clear:
-       mov $r8 0x430
-       shl b32 $r8 6
-       iowr I[$r8 + 0x000] $r0
-       ret
-
 // wait_donez - wait on FUC_DONE bit to become clear
 //
 // In : $r10 bit to wait on
@@ -163,13 +141,9 @@ wait_donez:
 //
 wait_doneo:
        trace_set(T_WAIT);
-       mov $r8 0x818
-       shl b32 $r8 6
-       iowr I[$r8 + 0x000] $r10
+       nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
        wait_doneo_e:
-               mov $r8 0x400
-               shl b32 $r8 6
-               iord $r8 I[$r8 + 0x000]
+               nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
                xbit $r8 $r8 $r10
                bra e #wait_doneo_e
        trace_clr(T_WAIT)
@@ -209,21 +183,18 @@ mmctx_size:
 //
 mmctx_xfer:
        trace_set(T_MMCTX)
-       mov $r8 0x710
-       shl b32 $r8 6
        clear b32 $r9
        or $r11 $r11
        bra e #mmctx_base_disabled
-               iowr I[$r8 + 0x000] $r11        // MMCTX_BASE
+               nv_iowr(NV_PGRAPH_FECS_MMCTX_BASE, 0, $r11)
                bset $r9 0                      // BASE_EN
        mmctx_base_disabled:
        or $r14 $r14
        bra e #mmctx_multi_disabled
-               iowr I[$r8 + 0x200] $r14        // MMCTX_MULTI_STRIDE
-               iowr I[$r8 + 0x300] $r15        // MMCTX_MULTI_MASK
+               nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_STRIDE, 0, $r14)
+               nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_MASK, 0, $r15)
                bset $r9 1                      // MULTI_EN
        mmctx_multi_disabled:
-       add b32 $r8 0x100
 
        xbit $r11 $r10 0
        shl b32 $r11 16                 // DIR
@@ -231,20 +202,20 @@ mmctx_xfer:
        xbit $r14 $r10 1
        shl b32 $r14 17
        or $r11 $r14                    // START_TRIGGER
-       iowr I[$r8 + 0x000] $r11        // MMCTX_CTRL
+       nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
 
        // loop over the mmio list, and send requests to the hw
        mmctx_exec_loop:
                // wait for space in mmctx queue
                mmctx_wait_free:
-                       iord $r14 I[$r8 + 0x000] // MMCTX_CTRL
+                       nv_iord($r14, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
                        and $r14 0x1f
                        bra e #mmctx_wait_free
 
                // queue up an entry
                ld b32 $r14 D[$r12]
                or $r14 $r9
-               iowr I[$r8 + 0x300] $r14
+               nv_iowr(NV_PGRAPH_FECS_MMCTX_QUEUE, 0, $r14)
                add b32 $r12 4
                cmpu b32 $r12 $r13
                bra ne #mmctx_exec_loop
@@ -253,22 +224,22 @@ mmctx_xfer:
        bra ne #mmctx_stop
                // wait for queue to empty
                mmctx_fini_wait:
-                       iord $r11 I[$r8 + 0x000]        // MMCTX_CTRL
+                       nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
                        and $r11 0x1f
                        cmpu b32 $r11 0x10
                        bra ne #mmctx_fini_wait
                mov $r10 2                              // DONE_MMCTX
-               call #wait_donez
+               call(wait_donez)
                bra #mmctx_done
        mmctx_stop:
                xbit $r11 $r10 0
                shl b32 $r11 16                 // DIR
                bset $r11 12                    // QLIMIT = 0x10
                bset $r11 18                    // STOP_TRIGGER
-               iowr I[$r8 + 0x000] $r11        // MMCTX_CTRL
+               nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
                mmctx_stop_wait:
                        // wait for STOP_TRIGGER to clear
-                       iord $r11 I[$r8 + 0x000] // MMCTX_CTRL
+                       nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
                        xbit $r11 $r11 18
                        bra ne #mmctx_stop_wait
        mmctx_done:
@@ -280,28 +251,24 @@ mmctx_xfer:
 strand_wait:
        push $r10
        mov $r10 2
-       call #wait_donez
+       call(wait_donez)
        pop $r10
        ret
 
 // unknown - call before issuing strand commands
 //
 strand_pre:
-       mov $r8 0x4afc
-       sethi $r8 0x20000
-       mov $r9 0xc
-       iowr I[$r8] $r9
-       call #strand_wait
+       mov $r9 NV_PGRAPH_FECS_STRAND_CMD_ENABLE
+       nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
+       call(strand_wait)
        ret
 
 // unknown - call after issuing strand commands
 //
 strand_post:
-       mov $r8 0x4afc
-       sethi $r8 0x20000
-       mov $r9 0xd
-       iowr I[$r8] $r9
-       call #strand_wait
+       mov $r9 NV_PGRAPH_FECS_STRAND_CMD_DISABLE
+       nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
+       call(strand_wait)
        ret
 
 // Selects strand set?!
@@ -309,18 +276,14 @@ strand_post:
 // In: $r14 id
 //
 strand_set:
-       mov $r10 0x4ffc
-       sethi $r10 0x20000
-       sub b32 $r11 $r10 0x500
        mov $r12 0xf
-       iowr I[$r10 + 0x000] $r12               // 0x93c = 0xf
-       mov $r12 0xb
-       iowr I[$r11 + 0x000] $r12               // 0x928 = 0xb
-       call #strand_wait
-       iowr I[$r10 + 0x000] $r14               // 0x93c = <id>
-       mov $r12 0xa
-       iowr I[$r11 + 0x000] $r12               // 0x928 = 0xa
-       call #strand_wait
+       nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r12)
+       mov $r12 NV_PGRAPH_FECS_STRAND_CMD_DEACTIVATE_FILTER
+       nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+       nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r14)
+       mov $r12 NV_PGRAPH_FECS_STRAND_CMD_ACTIVATE_FILTER
+       nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+       call(strand_wait)
        ret
 
 // Initialise strand context data
@@ -332,30 +295,27 @@ strand_set:
 //
 strand_ctx_init:
        trace_set(T_STRINIT)
-       call #strand_pre
+       call(strand_pre)
        mov $r14 3
-       call #strand_set
-       mov $r10 0x46fc
-       sethi $r10 0x20000
-       add b32 $r11 $r10 0x400
-       iowr I[$r10 + 0x100] $r0        // STRAND_FIRST_GENE = 0
-       mov $r12 1
-       iowr I[$r11 + 0x000] $r12       // STRAND_CMD = LATCH_FIRST_GENE
-       call #strand_wait
+       call(strand_set)
+
+       clear b32 $r12
+       nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r12)
+       mov $r12 NV_PGRAPH_FECS_STRAND_CMD_SEEK
+       nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+       call(strand_wait)
        sub b32 $r12 $r0 1
-       iowr I[$r10 + 0x000] $r12       // STRAND_GENE_CNT = 0xffffffff
-       mov $r12 2
-       iowr I[$r11 + 0x000] $r12       // STRAND_CMD = LATCH_GENE_CNT
-       call #strand_wait
-       call #strand_post
+       nv_iowr(NV_PGRAPH_FECS_STRAND_DATA, 0x3f, $r12)
+       mov $r12 NV_PGRAPH_FECS_STRAND_CMD_GET_INFO
+       nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+       call(strand_wait)
+       call(strand_post)
 
        // read the size of each strand, poke the context offset of
        // each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
        // about it later then.
-       mov $r8 0x880
-       shl b32 $r8 6
-       iord $r9 I[$r8 + 0x000]         // STRANDS
-       add b32 $r8 0x2200
+       nv_mkio($r8, NV_PGRAPH_FECS_STRAND_SAVE_SWBASE, 0x00)
+       nv_iord($r9, NV_PGRAPH_FECS_STRANDS_CNT, 0x00)
        shr b32 $r14 $r15 8
        ctx_init_strand_loop:
                iowr I[$r8 + 0x000] $r14        // STRAND_SAVE_SWBASE
index 5547c1b3f4f29414a1334e2a7d5cae9f7452e998..96cbcea3b2c96aa71f2c7ef3d59b3d3184a67e17 100644 (file)
@@ -58,12 +58,9 @@ mmio_list_base:
 //
 error:
        push $r14
-       mov $r14 -0x67ec        // 0x9814
-       sethi $r14 0x400000
-       call #nv_wr32           // HUB_CTXCTL_CC_SCRATCH[5] = error code
-       add b32 $r14 0x41c
+       nv_wr32(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), $r15)
        mov $r15 1
-       call #nv_wr32           // HUB_CTXCTL_INTR_UP_SET
+       nv_wr32(NV_PGRAPH_FECS_INTR_UP_SET, $r15)
        pop $r14
        ret
 
@@ -84,46 +81,40 @@ init:
        mov $sp $r0
 
        // enable fifo access
-       mov $r1 0x1200
-       mov $r2 2
-       iowr I[$r1 + 0x000] $r2         // FIFO_ENABLE
+       mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_ACCESS, 0, $r2)
 
        // setup i0 handler, and route all interrupts to it
        mov $r1 #ih
        mov $iv0 $r1
-       mov $r1 0x400
-       iowr I[$r1 + 0x300] $r0         // INTR_DISPATCH
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE, 0, $r0)
 
        // enable fifo interrupt
-       mov $r2 4
-       iowr I[$r1 + 0x000] $r2         // INTR_EN_SET
+       mov $r2 NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET, 0, $r2)
 
        // enable interrupts
        bset $flags ie0
 
        // figure out which GPC we are, and how many TPCs we have
-       mov $r1 0x608
-       shl b32 $r1 6
-       iord $r2 I[$r1 + 0x000]         // UNITS
+       nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_UNITS, 0)
        mov $r3 1
        and $r2 0x1f
        shl b32 $r3 $r2
        sub b32 $r3 1
        st b32 D[$r0 + #tpc_count] $r2
        st b32 D[$r0 + #tpc_mask] $r3
-       add b32 $r1 0x400
-       iord $r2 I[$r1 + 0x000]         // MYINDEX
+       nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_MYINDEX, 0)
        st b32 D[$r0 + #gpc_id] $r2
 
 #if NV_PGRAPH_GPCX_UNK__SIZE > 0
        // figure out which, and how many, UNKs are actually present
-       mov $r14 0x0c30
-       sethi $r14 0x500000
+       imm32($r14, 0x500c30)
        clear b32 $r2
        clear b32 $r3
        clear b32 $r4
        init_unk_loop:
-               call #nv_rd32
+               call(nv_rd32)
                cmp b32 $r15 0
                bra z #init_unk_next
                        mov $r15 1
@@ -146,23 +137,21 @@ init:
 
        // set mmctx base addresses now so we don't have to do it later,
        // they don't currently ever change
-       mov $r4 0x700
-       shl b32 $r4 6
        shr b32 $r5 $r2 8
-       iowr I[$r4 + 0x000] $r5         // MMCTX_SAVE_SWBASE
-       iowr I[$r4 + 0x100] $r5         // MMCTX_LOAD_SWBASE
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE, 0, $r5)
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE, 0, $r5)
 
        // calculate GPC mmio context size
        ld b32 $r14 D[$r0 + #gpc_mmio_list_head]
        ld b32 $r15 D[$r0 + #gpc_mmio_list_tail]
-       call #mmctx_size
+       call(mmctx_size)
        add b32 $r2 $r15
        add b32 $r3 $r15
 
        // calculate per-TPC mmio context size
        ld b32 $r14 D[$r0 + #tpc_mmio_list_head]
        ld b32 $r15 D[$r0 + #tpc_mmio_list_tail]
-       call #mmctx_size
+       call(mmctx_size)
        ld b32 $r14 D[$r0 + #tpc_count]
        mulu $r14 $r15
        add b32 $r2 $r14
@@ -172,7 +161,7 @@ init:
        // calculate per-UNK mmio context size
        ld b32 $r14 D[$r0 + #unk_mmio_list_head]
        ld b32 $r15 D[$r0 + #unk_mmio_list_tail]
-       call #mmctx_size
+       call(mmctx_size)
        ld b32 $r14 D[$r0 + #unk_count]
        mulu $r14 $r15
        add b32 $r2 $r14
@@ -180,9 +169,8 @@ init:
 #endif
 
        // round up base/size to 256 byte boundary (for strand SWBASE)
-       add b32 $r4 0x1300
        shr b32 $r3 2
-       iowr I[$r4 + 0x000] $r3         // MMCTX_LOAD_COUNT, wtf for?!?
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT, 0, $r3) // wtf for?!
        shr b32 $r2 8
        shr b32 $r3 6
        add b32 $r2 1
@@ -192,7 +180,7 @@ init:
 
        // calculate size of strand context data
        mov b32 $r15 $r2
-       call #strand_ctx_init
+       call(strand_ctx_init)
        add b32 $r3 $r15
 
        // save context size, and tell HUB we're done
@@ -208,7 +196,7 @@ main:
        bset $flags $p0
        sleep $p0
        mov $r13 #cmd_queue
-       call #queue_get
+       call(queue_get)
        bra $p1 #main
 
        // 0x0000-0x0003 are all context transfers
@@ -224,13 +212,13 @@ main:
                or $r1 $r14
                mov $flags $r1
                // transfer context data
-               call #ctx_xfer
+               call(ctx_xfer)
                bra #main
 
        main_not_ctx_xfer:
        shl b32 $r15 $r14 16
        or $r15 E_BAD_COMMAND
-       call #error
+       call(error)
        bra #main
 
 // interrupt handler
@@ -247,22 +235,20 @@ ih:
        clear b32 $r0
 
        // incoming fifo command?
-       iord $r10 I[$r0 + 0x200]        // INTR
-       and $r11 $r10 0x00000004
+       nv_iord($r10, NV_PGRAPH_GPCX_GPCCS_INTR, 0)
+       and $r11 $r10 NV_PGRAPH_GPCX_GPCCS_INTR_FIFO
        bra e #ih_no_fifo
                // queue incoming fifo command for later processing
-               mov $r11 0x1900
                mov $r13 #cmd_queue
-               iord $r14 I[$r11 + 0x100]       // FIFO_CMD
-               iord $r15 I[$r11 + 0x000]       // FIFO_DATA
-               call #queue_put
-               add b32 $r11 0x400
+               nv_iord($r14, NV_PGRAPH_GPCX_GPCCS_FIFO_CMD, 0)
+               nv_iord($r15, NV_PGRAPH_GPCX_GPCCS_FIFO_DATA, 0)
+               call(queue_put)
                mov $r14 1
-               iowr I[$r11 + 0x000] $r14       // FIFO_ACK
+               nv_iowr(NV_PGRAPH_GPCX_GPCCS_FIFO_ACK, 0, $r14)
 
        // ack, and wake up main()
        ih_no_fifo:
-       iowr I[$r0 + 0x100] $r10        // INTR_ACK
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ACK, 0, $r10)
 
        pop $r15
        pop $r14
@@ -283,9 +269,7 @@ hub_barrier_done:
        mov $r15 1
        ld b32 $r14 D[$r0 + #gpc_id]
        shl b32 $r15 $r14
-       mov $r14 -0x6be8        // 0x409418 - HUB_BAR_SET
-       sethi $r14 0x400000
-       call #nv_wr32
+       nv_wr32(0x409418, $r15) // 0x409418 - HUB_BAR_SET
        ret
 
 // Disables various things, waits a bit, and re-enables them..
@@ -295,16 +279,15 @@ hub_barrier_done:
 // funny things happen.
 //
 ctx_redswitch:
-       mov $r14 0x614
-       shl b32 $r14 6
-       mov $r15 0x020
-       iowr I[$r14] $r15       // GPC_RED_SWITCH = POWER
-       mov $r15 8
+       mov $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
+       mov $r14 8
        ctx_redswitch_delay:
-               sub b32 $r15 1
+               sub b32 $r14 1
                bra ne #ctx_redswitch_delay
-       mov $r15 0xa20
-       iowr I[$r14] $r15       // GPC_RED_SWITCH = UNK11, ENABLE, POWER
+       or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11
+       or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
        ret
 
 // Transfer GPC context data between GPU and storage area
@@ -317,46 +300,37 @@ ctx_redswitch:
 //
 ctx_xfer:
        // set context base address
-       mov $r1 0xa04
-       shl b32 $r1 6
-       iowr I[$r1 + 0x000] $r15// MEM_BASE
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_MEM_BASE, 0, $r15)
        bra not $p1 #ctx_xfer_not_load
-               call #ctx_redswitch
+               call(ctx_redswitch)
        ctx_xfer_not_load:
 
        // strands
-       mov $r1 0x4afc
-       sethi $r1 0x20000
-       mov $r2 0xc
-       iowr I[$r1] $r2         // STRAND_CMD(0x3f) = 0x0c
-       call #strand_wait
-       mov $r2 0x47fc
-       sethi $r2 0x20000
-       iowr I[$r2] $r0         // STRAND_FIRST_GENE(0x3f) = 0x00
-       xbit $r2 $flags $p1
-       add b32 $r2 3
-       iowr I[$r1] $r2         // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
+       call(strand_pre)
+       clear b32 $r2
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT, 0x3f, $r2)
+       xbit $r2 $flags $p1     // SAVE/LOAD
+       add b32 $r2 NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE
+       nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_CMD, 0x3f, $r2)
 
        // mmio context
        xbit $r10 $flags $p1    // direction
        or $r10 2               // first
-       mov $r11 0x0000
-       sethi $r11 0x500000
+       imm32($r11,0x500000)
        ld b32 $r12 D[$r0 + #gpc_id]
        shl b32 $r12 15
        add b32 $r11 $r12       // base = NV_PGRAPH_GPCn
        ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
        ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
        mov $r14 0              // not multi
-       call #mmctx_xfer
+       call(mmctx_xfer)
 
        // per-TPC mmio context
        xbit $r10 $flags $p1    // direction
 #if !NV_PGRAPH_GPCX_UNK__SIZE
        or $r10 4               // last
 #endif
-       mov $r11 0x4000
-       sethi $r11 0x500000     // base = NV_PGRAPH_GPC0_TPC0
+       imm32($r11, 0x504000)
        ld b32 $r12 D[$r0 + #gpc_id]
        shl b32 $r12 15
        add b32 $r11 $r12       // base = NV_PGRAPH_GPCn_TPC0
@@ -364,14 +338,13 @@ ctx_xfer:
        ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
        ld b32 $r15 D[$r0 + #tpc_mask]
        mov $r14 0x800          // stride = 0x800
-       call #mmctx_xfer
+       call(mmctx_xfer)
 
 #if NV_PGRAPH_GPCX_UNK__SIZE > 0
        // per-UNK mmio context
        xbit $r10 $flags $p1    // direction
        or $r10 4               // last
-       mov $r11 0x3000
-       sethi $r11 0x500000     // base = NV_PGRAPH_GPC0_UNK0
+       imm32($r11, 0x503000)
        ld b32 $r12 D[$r0 + #gpc_id]
        shl b32 $r12 15
        add b32 $r11 $r12       // base = NV_PGRAPH_GPCn_UNK0
@@ -379,11 +352,11 @@ ctx_xfer:
        ld b32 $r13 D[$r0 + #unk_mmio_list_tail]
        ld b32 $r15 D[$r0 + #unk_mask]
        mov $r14 0x200          // stride = 0x200
-       call #mmctx_xfer
+       call(mmctx_xfer)
 #endif
 
        // wait for strands to finish
-       call #strand_wait
+       call(strand_wait)
 
        // if load, or a save without a load following, do some
        // unknown stuff that's done after finishing a block of
@@ -391,14 +364,10 @@ ctx_xfer:
        bra $p1 #ctx_xfer_post
        bra not $p2 #ctx_xfer_done
        ctx_xfer_post:
-               mov $r1 0x4afc
-               sethi $r1 0x20000
-               mov $r2 0xd
-               iowr I[$r1] $r2         // STRAND_CMD(0x3f) = 0x0d
-               call #strand_wait
+               call(strand_post)
 
        // mark completion in HUB's barrier
        ctx_xfer_done:
-       call #hub_barrier_done
+       call(hub_barrier_done)
        ret
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5
new file mode 100644 (file)
index 0000000..bd30262
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * 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 <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE                                     0x00000001
+
+#define CHIPSET GK208
+#include "macros.fuc"
+
+.section #nv108_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #nv108_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h
new file mode 100644 (file)
index 0000000..27dc128
--- /dev/null
@@ -0,0 +1,473 @@
+uint32_t nv108_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+       0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+       0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+       0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+       0x0000006c,
+/* 0x0010: gpc_id */
+       0x00000000,
+/* 0x0014: tpc_count */
+       0x00000000,
+/* 0x0018: tpc_mask */
+       0x00000000,
+/* 0x001c: unk_count */
+       0x00000000,
+/* 0x0020: unk_mask */
+       0x00000000,
+/* 0x0024: cmd_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+};
+
+uint32_t nv108_grgpc_code[] = {
+       0x03140ef5,
+/* 0x0004: queue_put */
+       0x9800d898,
+       0x86f001d9,
+       0xf489a408,
+       0x020f0b1b,
+       0x0002f87e,
+/* 0x001a: queue_put_next */
+       0x98c400f8,
+       0x0384b607,
+       0xb6008dbb,
+       0x8eb50880,
+       0x018fb500,
+       0xf00190b6,
+       0xd9b50f94,
+/* 0x0037: queue_get */
+       0xf400f801,
+       0xd8980131,
+       0x01d99800,
+       0x0bf489a4,
+       0x0789c421,
+       0xbb0394b6,
+       0x90b6009d,
+       0x009e9808,
+       0xb6019f98,
+       0x84f00180,
+       0x00d8b50f,
+/* 0x0063: queue_get_done */
+       0xf80132f4,
+/* 0x0065: nv_rd32 */
+       0xf0ecb200,
+       0x00801fc9,
+       0x0cf601ca,
+/* 0x0073: nv_rd32_wait */
+       0x8c04bd00,
+       0xcf01ca00,
+       0xccc800cc,
+       0xf61bf41f,
+       0xec7e060a,
+       0x008f0000,
+       0xffcf01cb,
+/* 0x008f: nv_wr32 */
+       0x8000f800,
+       0xf601cc00,
+       0x04bd000f,
+       0xc9f0ecb2,
+       0x1ec9f01f,
+       0x01ca0080,
+       0xbd000cf6,
+/* 0x00a9: nv_wr32_wait */
+       0xca008c04,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f61b,
+/* 0x00b8: wait_donez */
+       0x99f094bd,
+       0x37008000,
+       0x0009f602,
+       0x008004bd,
+       0x0af60206,
+/* 0x00cf: wait_donez_ne */
+       0x8804bd00,
+       0xcf010000,
+       0x8aff0088,
+       0xf61bf488,
+       0x99f094bd,
+       0x17008000,
+       0x0009f602,
+       0x00f804bd,
+/* 0x00ec: wait_doneo */
+       0x99f094bd,
+       0x37008000,
+       0x0009f602,
+       0x008004bd,
+       0x0af60206,
+/* 0x0103: wait_doneo_e */
+       0x8804bd00,
+       0xcf010000,
+       0x8aff0088,
+       0xf60bf488,
+       0x99f094bd,
+       0x17008000,
+       0x0009f602,
+       0x00f804bd,
+/* 0x0120: mmctx_size */
+/* 0x0122: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0x1bf4efa4,
+       0xf89fb2ec,
+/* 0x013d: mmctx_xfer */
+       0xf094bd00,
+       0x00800199,
+       0x09f60237,
+       0xbd04bd00,
+       0x05bbfd94,
+       0x800f0bf4,
+       0xf601c400,
+       0x04bd000b,
+/* 0x015f: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0xc6008018,
+       0x000ef601,
+       0x008004bd,
+       0x0ff601c7,
+       0xf004bd00,
+/* 0x017a: mmctx_multi_disabled */
+       0xabc80199,
+       0x10b4b600,
+       0xc80cb9f0,
+       0xe4b601ae,
+       0x05befd11,
+       0x01c50080,
+       0xbd000bf6,
+/* 0x0195: mmctx_exec_loop */
+/* 0x0195: mmctx_wait_free */
+       0xc5008e04,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f60b,
+       0x05e9fd00,
+       0x01c80080,
+       0xbd000ef6,
+       0x04c0b604,
+       0x1bf4cda4,
+       0x02abc8df,
+/* 0x01bf: mmctx_fini_wait */
+       0x8b1c1bf4,
+       0xcf01c500,
+       0xb4f000bb,
+       0x10b4b01f,
+       0x0af31bf4,
+       0x00b87e02,
+       0x250ef400,
+/* 0x01d8: mmctx_stop */
+       0xb600abc8,
+       0xb9f010b4,
+       0x12b9f00c,
+       0x01c50080,
+       0xbd000bf6,
+/* 0x01ed: mmctx_stop_wait */
+       0xc5008b04,
+       0x00bbcf01,
+       0xf412bbc8,
+/* 0x01fa: mmctx_done */
+       0x94bdf61b,
+       0x800199f0,
+       0xf6021700,
+       0x04bd0009,
+/* 0x020a: strand_wait */
+       0xa0f900f8,
+       0xb87e020a,
+       0xa0fc0000,
+/* 0x0216: strand_pre */
+       0x0c0900f8,
+       0x024afc80,
+       0xbd0009f6,
+       0x020a7e04,
+/* 0x0227: strand_post */
+       0x0900f800,
+       0x4afc800d,
+       0x0009f602,
+       0x0a7e04bd,
+       0x00f80002,
+/* 0x0238: strand_set */
+       0xfc800f0c,
+       0x0cf6024f,
+       0x0c04bd00,
+       0x4afc800b,
+       0x000cf602,
+       0xfc8004bd,
+       0x0ef6024f,
+       0x0c04bd00,
+       0x4afc800a,
+       0x000cf602,
+       0x0a7e04bd,
+       0x00f80002,
+/* 0x0268: strand_ctx_init */
+       0x99f094bd,
+       0x37008003,
+       0x0009f602,
+       0x167e04bd,
+       0x030e0002,
+       0x0002387e,
+       0xfc80c4bd,
+       0x0cf60247,
+       0x0c04bd00,
+       0x4afc8001,
+       0x000cf602,
+       0x0a7e04bd,
+       0x0c920002,
+       0x46fc8001,
+       0x000cf602,
+       0x020c04bd,
+       0x024afc80,
+       0xbd000cf6,
+       0x020a7e04,
+       0x02277e00,
+       0x42008800,
+       0x20008902,
+       0x0099cf02,
+/* 0x02c7: ctx_init_strand_loop */
+       0xf608fe95,
+       0x8ef6008e,
+       0x808acf40,
+       0xb606a5b6,
+       0xeabb01a0,
+       0x0480b600,
+       0xf40192b6,
+       0xe4b6e81b,
+       0xf2efbc08,
+       0x99f094bd,
+       0x17008003,
+       0x0009f602,
+       0x00f804bd,
+/* 0x02f8: error */
+       0xffb2e0f9,
+       0x4098148e,
+       0x00008f7e,
+       0xffb2010f,
+       0x409c1c8e,
+       0x00008f7e,
+       0x00f8e0fc,
+/* 0x0314: init */
+       0x04fe04bd,
+       0x40020200,
+       0x02f61200,
+       0x4104bd00,
+       0x10fe0465,
+       0x07004000,
+       0xbd0000f6,
+       0x40040204,
+       0x02f60400,
+       0xf404bd00,
+       0x00821031,
+       0x22cf0182,
+       0xf0010300,
+       0x32bb1f24,
+       0x0132b604,
+       0xb50502b5,
+       0x00820603,
+       0x22cf0186,
+       0x0402b500,
+       0x500c308e,
+       0x34bd24bd,
+/* 0x036a: init_unk_loop */
+       0x657e44bd,
+       0xf6b00000,
+       0x0e0bf400,
+       0xf2bb010f,
+       0x054ffd04,
+/* 0x037f: init_unk_next */
+       0xb60130b6,
+       0xe0b60120,
+       0x0126b004,
+/* 0x038b: init_unk_done */
+       0xb5e21bf4,
+       0x04b50703,
+       0x01008208,
+       0x0022cf02,
+       0x259534bd,
+       0xc0008008,
+       0x0005f601,
+       0x008004bd,
+       0x05f601c1,
+       0x9804bd00,
+       0x0f98000e,
+       0x01207e01,
+       0x002fbb00,
+       0x98003fbb,
+       0x0f98010e,
+       0x01207e02,
+       0x050e9800,
+       0xbb00effd,
+       0x3ebb002e,
+       0x020e9800,
+       0x7e030f98,
+       0x98000120,
+       0xeffd070e,
+       0x002ebb00,
+       0xb6003ebb,
+       0x00800235,
+       0x03f601d3,
+       0xb604bd00,
+       0x35b60825,
+       0x0120b606,
+       0xb60130b6,
+       0x34b60824,
+       0x7e2fb208,
+       0xbb000268,
+       0x0080003f,
+       0x03f60201,
+       0xbd04bd00,
+       0x1f29f024,
+       0x02300080,
+       0xbd0002f6,
+/* 0x0429: main */
+       0x0031f404,
+       0x0d0028f4,
+       0x00377e24,
+       0xf401f400,
+       0xf404e4b0,
+       0x81fe1d18,
+       0xbd060201,
+       0x0412fd20,
+       0xfd01e4b6,
+       0x18fe051e,
+       0x04fc7e00,
+       0xd40ef400,
+/* 0x0458: main_not_ctx_xfer */
+       0xf010ef94,
+       0xf87e01f5,
+       0x0ef40002,
+/* 0x0465: ih */
+       0xfe80f9c7,
+       0x80f90188,
+       0xa0f990f9,
+       0xd0f9b0f9,
+       0xf0f9e0f9,
+       0x004a04bd,
+       0x00aacf02,
+       0xf404abc4,
+       0x240d1f0b,
+       0xcf1a004e,
+       0x004f00ee,
+       0x00ffcf19,
+       0x0000047e,
+       0x0040010e,
+       0x000ef61d,
+/* 0x04a2: ih_no_fifo */
+       0x004004bd,
+       0x000af601,
+       0xf0fc04bd,
+       0xd0fce0fc,
+       0xa0fcb0fc,
+       0x80fc90fc,
+       0xfc0088fe,
+       0x0032f480,
+/* 0x04c2: hub_barrier_done */
+       0x010f01f8,
+       0xbb040e98,
+       0xffb204fe,
+       0x4094188e,
+       0x00008f7e,
+/* 0x04d6: ctx_redswitch */
+       0x200f00f8,
+       0x01850080,
+       0xbd000ff6,
+/* 0x04e3: ctx_redswitch_delay */
+       0xb6080e04,
+       0x1bf401e2,
+       0x00f5f1fd,
+       0x00f5f108,
+       0x85008002,
+       0x000ff601,
+       0x00f804bd,
+/* 0x04fc: ctx_xfer */
+       0x02810080,
+       0xbd000ff6,
+       0x0711f404,
+       0x0004d67e,
+/* 0x050c: ctx_xfer_not_load */
+       0x0002167e,
+       0xfc8024bd,
+       0x02f60247,
+       0xf004bd00,
+       0x20b6012c,
+       0x4afc8003,
+       0x0002f602,
+       0xacf004bd,
+       0x02a5f001,
+       0x5000008b,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x000c9800,
+       0x0e010d98,
+       0x013d7e00,
+       0x01acf000,
+       0x5040008b,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x010c9800,
+       0x98020d98,
+       0x004e060f,
+       0x013d7e08,
+       0x01acf000,
+       0x8b04a5f0,
+       0x98503000,
+       0xc4b6040c,
+       0x00bcbb0f,
+       0x98020c98,
+       0x0f98030d,
+       0x02004e08,
+       0x00013d7e,
+       0x00020a7e,
+       0xf40601f4,
+/* 0x0596: ctx_xfer_post */
+       0x277e0712,
+/* 0x059a: ctx_xfer_done */
+       0xc27e0002,
+       0x00f80004,
+       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 f2b0dea80116fd7b42de0a2d1ff8fad4dbd26b96..0e7b01efae8d2979cdffac5bbf4e4a4030580d2d 100644 (file)
@@ -37,14 +37,14 @@ uint32_t nvc0_grgpc_data[] = {
 };
 
 uint32_t nvc0_grgpc_code[] = {
-       0x03180ef5,
+       0x03a10ef5,
 /* 0x0004: queue_put */
        0x9800d898,
        0x86f001d9,
        0x0489b808,
        0xf00c1bf4,
        0x21f502f7,
-       0x00f802fe,
+       0x00f8037e,
 /* 0x001c: queue_put_next */
        0xb60798c4,
        0x8dbb0384,
@@ -68,184 +68,214 @@ uint32_t nvc0_grgpc_code[] = {
 /* 0x0066: queue_get_done */
        0x00f80132,
 /* 0x0068: nv_rd32 */
-       0x0728b7f1,
-       0xb906b4b6,
-       0xc9f002ec,
-       0x00bcd01f,
-/* 0x0078: nv_rd32_wait */
-       0xc800bccf,
-       0x1bf41fcc,
-       0x06a7f0fa,
-       0x010921f5,
-       0xf840bfcf,
-/* 0x008d: nv_wr32 */
-       0x28b7f100,
-       0x06b4b607,
-       0xb980bfd0,
-       0xc9f002ec,
-       0x1ec9f01f,
-/* 0x00a3: nv_wr32_wait */
-       0xcf00bcd0,
-       0xccc800bc,
-       0xfa1bf41f,
-/* 0x00ae: watchdog_reset */
-       0x87f100f8,
-       0x84b60430,
-       0x1ff9f006,
-       0xf8008fd0,
-/* 0x00bd: watchdog_clear */
-       0x3087f100,
-       0x0684b604,
-       0xf80080d0,
-/* 0x00c9: wait_donez */
-       0xf094bd00,
-       0x07f10099,
-       0x03f00f00,
-       0x0009d002,
-       0x07f104bd,
-       0x03f00600,
-       0x000ad002,
-/* 0x00e6: wait_donez_ne */
-       0x87f104bd,
-       0x83f00000,
-       0x0088cf01,
-       0xf4888aff,
-       0x94bdf31b,
-       0xf10099f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0109: wait_doneo */
-       0xf094bd00,
+       0xf002ecb9,
+       0x07f11fc9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x007a: nv_rd32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0xa7f0f31b,
+       0x1021f506,
+       0x00f7f101,
+       0x01f3f0cb,
+       0xf800ffcf,
+/* 0x009d: nv_wr32 */
+       0x0007f100,
+       0x0103f0cc,
+       0xbd000fd0,
+       0x02ecb904,
+       0xf01fc9f0,
+       0x07f11ec9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x00be: nv_wr32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f31b,
+/* 0x00d0: wait_donez */
+       0x99f094bd,
+       0x0007f100,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x1bf4888a,
+       0xf094bdf3,
        0x07f10099,
-       0x03f00f00,
+       0x03f01700,
        0x0009d002,
-       0x87f104bd,
-       0x84b60818,
-       0x008ad006,
-/* 0x0124: wait_doneo_e */
-       0x040087f1,
-       0xcf0684b6,
-       0x8aff0088,
-       0xf30bf488,
+       0x00f804bd,
+/* 0x0110: wait_doneo */
        0x99f094bd,
        0x0007f100,
-       0x0203f017,
+       0x0203f00f,
        0xbd0009d0,
-/* 0x0147: mmctx_size */
-       0xbd00f804,
-/* 0x0149: nv_mmctx_size_loop */
-       0x00e89894,
-       0xb61a85b6,
-       0x84b60180,
-       0x0098bb02,
-       0xb804e0b6,
-       0x1bf404ef,
-       0x029fb9eb,
-/* 0x0166: mmctx_xfer */
-       0x94bd00f8,
-       0xf10199f0,
-       0xf00f0007,
-       0x09d00203,
-       0xf104bd00,
-       0xb6071087,
-       0x94bd0684,
-       0xf405bbfd,
-       0x8bd0090b,
-       0x0099f000,
-/* 0x018c: mmctx_base_disabled */
-       0xf405eefd,
-       0x8ed00c0b,
-       0xc08fd080,
-/* 0x019b: mmctx_multi_disabled */
-       0xb70199f0,
-       0xc8010080,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x0bf4888a,
+       0xf094bdf3,
+       0x07f10099,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0xf404efb8,
+       0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+       0xbd00f802,
+       0x0199f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0xbbfd94bd,
+       0x120bf405,
+       0xc40007f1,
+       0xd00103f0,
+       0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0x0007f11e,
+       0x0103f0c6,
+       0xbd000ed0,
+       0x0007f104,
+       0x0103f0c7,
+       0xbd000fd0,
+       0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+       0xb600abc8,
+       0xb9f010b4,
+       0x01aec80c,
+       0xfd11e4b6,
+       0x07f105be,
+       0x03f0c500,
+       0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+       0xe7f104bd,
+       0xe3f0c500,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f30b,
+       0x05e9fd00,
+       0xc80007f1,
+       0xd00103f0,
+       0x04bd000e,
+       0xb804c0b6,
+       0x1bf404cd,
+       0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+       0xf11f1bf4,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x1fb4f000,
+       0xf410b4b0,
+       0xa7f0f01b,
+       0xd021f402,
+/* 0x0223: mmctx_stop */
+       0xc82b0ef4,
        0xb4b600ab,
        0x0cb9f010,
-       0xb601aec8,
-       0xbefd11e4,
-       0x008bd005,
-/* 0x01b4: mmctx_exec_loop */
-/* 0x01b4: mmctx_wait_free */
-       0xf0008ecf,
-       0x0bf41fe4,
-       0x00ce98fa,
-       0xd005e9fd,
-       0xc0b6c08e,
-       0x04cdb804,
-       0xc8e81bf4,
-       0x1bf402ab,
-/* 0x01d5: mmctx_fini_wait */
-       0x008bcf18,
-       0xb01fb4f0,
-       0x1bf410b4,
-       0x02a7f0f7,
-       0xf4c921f4,
-/* 0x01ea: mmctx_stop */
-       0xabc81b0e,
-       0x10b4b600,
-       0xf00cb9f0,
-       0x8bd012b9,
-/* 0x01f9: mmctx_stop_wait */
-       0x008bcf00,
-       0xf412bbc8,
-/* 0x0202: mmctx_done */
-       0x94bdfa1b,
-       0xf10199f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0215: strand_wait */
-       0xf0a0f900,
-       0x21f402a7,
-       0xf8a0fcc9,
-/* 0x0221: strand_pre */
-       0xfc87f100,
-       0x0283f04a,
-       0xd00c97f0,
-       0x21f50089,
-       0x00f80215,
-/* 0x0234: strand_post */
-       0x4afc87f1,
-       0xf00283f0,
-       0x89d00d97,
-       0x1521f500,
-/* 0x0247: strand_set */
-       0xf100f802,
-       0xf04ffca7,
-       0xaba202a3,
-       0xc7f00500,
-       0x00acd00f,
-       0xd00bc7f0,
-       0x21f500bc,
-       0xaed00215,
-       0x0ac7f000,
-       0xf500bcd0,
-       0xf8021521,
-/* 0x0271: strand_ctx_init */
-       0xf094bd00,
-       0x07f10399,
-       0x03f00f00,
+       0xf112b9f0,
+       0xf0c50007,
+       0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+       0xf104bd00,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x12bbc800,
+/* 0x024b: mmctx_done */
+       0xbdf31bf4,
+       0x0199f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x025e: strand_wait */
+       0xa0f900f8,
+       0xf402a7f0,
+       0xa0fcd021,
+/* 0x026a: strand_pre */
+       0x97f000f8,
+       0xfc07f10c,
+       0x0203f04a,
+       0xbd0009d0,
+       0x5e21f504,
+/* 0x027f: strand_post */
+       0xf000f802,
+       0x07f10d97,
+       0x03f04afc,
        0x0009d002,
        0x21f504bd,
-       0xe7f00221,
-       0x4721f503,
-       0xfca7f102,
-       0x02a3f046,
-       0x0400aba0,
-       0xf040a0d0,
-       0xbcd001c7,
-       0x1521f500,
-       0x010c9202,
-       0xf000acd0,
-       0xbcd002c7,
-       0x1521f500,
-       0x3421f502,
-       0x8087f102,
-       0x0684b608,
-       0xb70089cf,
-       0x95220080,
-/* 0x02ca: ctx_init_strand_loop */
+       0x00f8025e,
+/* 0x0294: strand_set */
+       0xf10fc7f0,
+       0xf04ffc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f10bc7,
+       0x03f04afc,
+       0x000cd002,
+       0x07f104bd,
+       0x03f04ffc,
+       0x000ed002,
+       0xc7f004bd,
+       0xfc07f10a,
+       0x0203f04a,
+       0xbd000cd0,
+       0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+       0xbd00f802,
+       0x0399f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0x026a21f5,
+       0xf503e7f0,
+       0xbd029421,
+       0xfc07f1c4,
+       0x0203f047,
+       0xbd000cd0,
+       0x01c7f004,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd000c,
+       0x025e21f5,
+       0xf1010c92,
+       0xf046fc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f102c7,
+       0x03f04afc,
+       0x000cd002,
+       0x21f504bd,
+       0x21f5025e,
+       0x87f1027f,
+       0x83f04200,
+       0x0097f102,
+       0x0293f020,
+       0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
        0x8ed008fe,
        0x408ed000,
        0xb6808acf,
@@ -259,167 +289,199 @@ uint32_t nvc0_grgpc_code[] = {
        0x170007f1,
        0xd00203f0,
        0x04bd0009,
-/* 0x02fe: error */
+/* 0x037e: error */
        0xe0f900f8,
-       0x9814e7f1,
-       0xf440e3f0,
-       0xe0b78d21,
-       0xf7f0041c,
-       0x8d21f401,
-       0x00f8e0fc,
-/* 0x0318: init */
-       0x04fe04bd,
-       0x0017f100,
-       0x0227f012,
-       0xf10012d0,
-       0xfe042617,
-       0x17f10010,
-       0x10d00400,
-       0x0427f0c0,
-       0xf40012d0,
-       0x17f11031,
-       0x14b60608,
-       0x0012cf06,
+       0xf102ffb9,
+       0xf09814e7,
+       0x21f440e3,
+       0x01f7f09d,
+       0xf102ffb9,
+       0xf09c1ce7,
+       0x21f440e3,
+       0xf8e0fc9d,
+/* 0x03a1: init */
+       0xfe04bd00,
+       0x27f00004,
+       0x0007f102,
+       0x0003f012,
+       0xbd0002d0,
+       0xd517f104,
+       0x0010fe04,
+       0x070007f1,
+       0xd00003f0,
+       0x04bd0000,
+       0xf10427f0,
+       0xf0040007,
+       0x02d00003,
+       0xf404bd00,
+       0x27f11031,
+       0x23f08200,
+       0x0022cf01,
        0xf00137f0,
        0x32bb1f24,
        0x0132b604,
        0x80050280,
-       0x10b70603,
-       0x12cf0400,
-       0x04028000,
-       0x010027f1,
-       0xcf0223f0,
-       0x34bd0022,
-       0x070047f1,
-       0x950644b6,
-       0x45d00825,
-       0x4045d000,
-       0x98000e98,
-       0x21f5010f,
-       0x2fbb0147,
-       0x003fbb00,
-       0x98010e98,
-       0x21f5020f,
-       0x0e980147,
-       0x00effd05,
-       0xbb002ebb,
-       0x40b7003e,
-       0x35b61300,
-       0x0043d002,
-       0xb60825b6,
-       0x20b60635,
-       0x0130b601,
-       0xb60824b6,
-       0x2fb90834,
-       0x7121f502,
-       0x003fbb02,
-       0x010007f1,
+       0x27f10603,
+       0x23f08600,
+       0x0022cf01,
+       0xf1040280,
+       0xf0010027,
+       0x22cf0223,
+       0x9534bd00,
+       0x07f10825,
+       0x03f0c000,
+       0x0005d001,
+       0x07f104bd,
+       0x03f0c100,
+       0x0005d001,
+       0x0e9804bd,
+       0x010f9800,
+       0x015021f5,
+       0xbb002fbb,
+       0x0e98003f,
+       0x020f9801,
+       0x015021f5,
+       0xfd050e98,
+       0x2ebb00ef,
+       0x003ebb00,
+       0xf10235b6,
+       0xf0d30007,
+       0x03d00103,
+       0xb604bd00,
+       0x35b60825,
+       0x0120b606,
+       0xb60130b6,
+       0x34b60824,
+       0x022fb908,
+       0x02d321f5,
+       0xf1003fbb,
+       0xf0010007,
+       0x03d00203,
+       0xbd04bd00,
+       0x1f29f024,
+       0x080007f1,
        0xd00203f0,
-       0x04bd0003,
-       0x29f024bd,
-       0x0007f11f,
-       0x0203f008,
-       0xbd0002d0,
-/* 0x03e9: main */
-       0x0031f404,
-       0xf00028f4,
-       0x21f41cd7,
-       0xf401f439,
-       0xf404e4b0,
-       0x81fe1e18,
-       0x0627f001,
-       0x12fd20bd,
-       0x01e4b604,
-       0xfe051efd,
-       0x21f50018,
-       0x0ef404ad,
-/* 0x0419: main_not_ctx_xfer */
-       0x10ef94d3,
-       0xf501f5f0,
-       0xf402fe21,
-/* 0x0426: ih */
-       0x80f9c60e,
-       0xf90188fe,
-       0xf990f980,
-       0xf9b0f9a0,
-       0xf9e0f9d0,
-       0xcf04bdf0,
-       0xabc4800a,
-       0x1d0bf404,
-       0x1900b7f1,
-       0xcf1cd7f0,
-       0xbfcf40be,
+       0x04bd0002,
+/* 0x0498: main */
+       0xf40031f4,
+       0xd7f00028,
+       0x3921f41c,
+       0xb0f401f4,
+       0x18f404e4,
+       0x0181fe1e,
+       0xbd0627f0,
+       0x0412fd20,
+       0xfd01e4b6,
+       0x18fe051e,
+       0x8d21f500,
+       0xd30ef405,
+/* 0x04c8: main_not_ctx_xfer */
+       0xf010ef94,
+       0x21f501f5,
+       0x0ef4037e,
+/* 0x04d5: ih */
+       0xfe80f9c6,
+       0x80f90188,
+       0xa0f990f9,
+       0xd0f9b0f9,
+       0xf0f9e0f9,
+       0xa7f104bd,
+       0xa3f00200,
+       0x00aacf00,
+       0xf404abc4,
+       0xd7f02c0b,
+       0x00e7f11c,
+       0x00e3f01a,
+       0xf100eecf,
+       0xf01900f7,
+       0xffcf00f3,
        0x0421f400,
-       0x0400b0b7,
-       0xd001e7f0,
-/* 0x045e: ih_no_fifo */
-       0x0ad000be,
-       0xfcf0fc40,
-       0xfcd0fce0,
-       0xfca0fcb0,
-       0xfe80fc90,
-       0x80fc0088,
-       0xf80032f4,
-/* 0x0479: hub_barrier_done */
-       0x01f7f001,
-       0xbb040e98,
-       0xe7f104fe,
-       0xe3f09418,
-       0x8d21f440,
-/* 0x048e: ctx_redswitch */
-       0xe7f100f8,
-       0xe4b60614,
-       0x20f7f006,
-       0xf000efd0,
-/* 0x049e: ctx_redswitch_delay */
-       0xf2b608f7,
-       0xfd1bf401,
-       0x0a20f7f1,
-       0xf800efd0,
-/* 0x04ad: ctx_xfer */
-       0x0417f100,
-       0x0614b60a,
-       0xf4001fd0,
-       0x21f50711,
-/* 0x04be: ctx_xfer_not_load */
-       0x17f1048e,
-       0x13f04afc,
-       0x0c27f002,
-       0xf50012d0,
-       0xf1021521,
-       0xf047fc27,
-       0x20d00223,
-       0x012cf000,
-       0xd00320b6,
-       0xacf00012,
-       0x02a5f001,
-       0xf000b7f0,
-       0x0c9850b3,
-       0x0fc4b604,
-       0x9800bcbb,
-       0x0d98000c,
-       0x00e7f001,
-       0x016621f5,
+       0xf101e7f0,
+       0xf01d0007,
+       0x0ed00003,
+/* 0x0523: ih_no_fifo */
+       0xf104bd00,
+       0xf0010007,
+       0x0ad00003,
+       0xfc04bd00,
+       0xfce0fcf0,
+       0xfcb0fcd0,
+       0xfc90fca0,
+       0x0088fe80,
+       0x32f480fc,
+/* 0x0547: hub_barrier_done */
+       0xf001f800,
+       0x0e9801f7,
+       0x04febb04,
+       0xf102ffb9,
+       0xf09418e7,
+       0x21f440e3,
+/* 0x055f: ctx_redswitch */
+       0xf000f89d,
+       0x07f120f7,
+       0x03f08500,
+       0x000fd001,
+       0xe7f004bd,
+/* 0x0571: ctx_redswitch_delay */
+       0x01e2b608,
+       0xf1fd1bf4,
+       0xf10800f5,
+       0xf10200f5,
+       0xf0850007,
+       0x0fd00103,
+       0xf804bd00,
+/* 0x058d: ctx_xfer */
+       0x0007f100,
+       0x0203f081,
+       0xbd000fd0,
+       0x0711f404,
+       0x055f21f5,
+/* 0x05a0: ctx_xfer_not_load */
+       0x026a21f5,
+       0x07f124bd,
+       0x03f047fc,
+       0x0002d002,
+       0x2cf004bd,
+       0x0320b601,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd0002,
        0xf001acf0,
-       0xb7f104a5,
-       0xb3f04000,
+       0xb7f102a5,
+       0xb3f00000,
        0x040c9850,
        0xbb0fc4b6,
        0x0c9800bc,
-       0x020d9801,
-       0xf1060f98,
-       0xf50800e7,
-       0xf5016621,
-       0xf4021521,
-       0x12f40601,
-/* 0x0535: ctx_xfer_post */
-       0xfc17f114,
-       0x0213f04a,
-       0xd00d27f0,
-       0x21f50012,
-/* 0x0546: ctx_xfer_done */
-       0x21f50215,
-       0x00f80479,
+       0x010d9800,
+       0xf500e7f0,
+       0xf0016f21,
+       0xa5f001ac,
+       0x00b7f104,
+       0x50b3f040,
+       0xb6040c98,
+       0xbcbb0fc4,
+       0x010c9800,
+       0x98020d98,
+       0xe7f1060f,
+       0x21f50800,
+       0x21f5016f,
+       0x01f4025e,
+       0x0712f406,
+/* 0x0618: ctx_xfer_post */
+       0x027f21f5,
+/* 0x061c: ctx_xfer_done */
+       0x054721f5,
+       0x000000f8,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
index dd346c2a16245849b773e382bad75499a85aa00a..84dd32db28a02cff0118eec2bae837ddf56dcc90 100644 (file)
@@ -41,14 +41,14 @@ uint32_t nvd7_grgpc_data[] = {
 };
 
 uint32_t nvd7_grgpc_code[] = {
-       0x03180ef5,
+       0x03a10ef5,
 /* 0x0004: queue_put */
        0x9800d898,
        0x86f001d9,
        0x0489b808,
        0xf00c1bf4,
        0x21f502f7,
-       0x00f802fe,
+       0x00f8037e,
 /* 0x001c: queue_put_next */
        0xb60798c4,
        0x8dbb0384,
@@ -72,184 +72,214 @@ uint32_t nvd7_grgpc_code[] = {
 /* 0x0066: queue_get_done */
        0x00f80132,
 /* 0x0068: nv_rd32 */
-       0x0728b7f1,
-       0xb906b4b6,
-       0xc9f002ec,
-       0x00bcd01f,
-/* 0x0078: nv_rd32_wait */
-       0xc800bccf,
-       0x1bf41fcc,
-       0x06a7f0fa,
-       0x010921f5,
-       0xf840bfcf,
-/* 0x008d: nv_wr32 */
-       0x28b7f100,
-       0x06b4b607,
-       0xb980bfd0,
-       0xc9f002ec,
-       0x1ec9f01f,
-/* 0x00a3: nv_wr32_wait */
-       0xcf00bcd0,
-       0xccc800bc,
-       0xfa1bf41f,
-/* 0x00ae: watchdog_reset */
-       0x87f100f8,
-       0x84b60430,
-       0x1ff9f006,
-       0xf8008fd0,
-/* 0x00bd: watchdog_clear */
-       0x3087f100,
-       0x0684b604,
-       0xf80080d0,
-/* 0x00c9: wait_donez */
-       0xf094bd00,
-       0x07f10099,
-       0x03f00f00,
-       0x0009d002,
-       0x07f104bd,
-       0x03f00600,
-       0x000ad002,
-/* 0x00e6: wait_donez_ne */
-       0x87f104bd,
-       0x83f00000,
-       0x0088cf01,
-       0xf4888aff,
-       0x94bdf31b,
-       0xf10099f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0109: wait_doneo */
-       0xf094bd00,
+       0xf002ecb9,
+       0x07f11fc9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x007a: nv_rd32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0xa7f0f31b,
+       0x1021f506,
+       0x00f7f101,
+       0x01f3f0cb,
+       0xf800ffcf,
+/* 0x009d: nv_wr32 */
+       0x0007f100,
+       0x0103f0cc,
+       0xbd000fd0,
+       0x02ecb904,
+       0xf01fc9f0,
+       0x07f11ec9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x00be: nv_wr32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f31b,
+/* 0x00d0: wait_donez */
+       0x99f094bd,
+       0x0007f100,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x1bf4888a,
+       0xf094bdf3,
        0x07f10099,
-       0x03f00f00,
+       0x03f01700,
        0x0009d002,
-       0x87f104bd,
-       0x84b60818,
-       0x008ad006,
-/* 0x0124: wait_doneo_e */
-       0x040087f1,
-       0xcf0684b6,
-       0x8aff0088,
-       0xf30bf488,
+       0x00f804bd,
+/* 0x0110: wait_doneo */
        0x99f094bd,
        0x0007f100,
-       0x0203f017,
+       0x0203f00f,
        0xbd0009d0,
-/* 0x0147: mmctx_size */
-       0xbd00f804,
-/* 0x0149: nv_mmctx_size_loop */
-       0x00e89894,
-       0xb61a85b6,
-       0x84b60180,
-       0x0098bb02,
-       0xb804e0b6,
-       0x1bf404ef,
-       0x029fb9eb,
-/* 0x0166: mmctx_xfer */
-       0x94bd00f8,
-       0xf10199f0,
-       0xf00f0007,
-       0x09d00203,
-       0xf104bd00,
-       0xb6071087,
-       0x94bd0684,
-       0xf405bbfd,
-       0x8bd0090b,
-       0x0099f000,
-/* 0x018c: mmctx_base_disabled */
-       0xf405eefd,
-       0x8ed00c0b,
-       0xc08fd080,
-/* 0x019b: mmctx_multi_disabled */
-       0xb70199f0,
-       0xc8010080,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x0bf4888a,
+       0xf094bdf3,
+       0x07f10099,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0xf404efb8,
+       0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+       0xbd00f802,
+       0x0199f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0xbbfd94bd,
+       0x120bf405,
+       0xc40007f1,
+       0xd00103f0,
+       0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0x0007f11e,
+       0x0103f0c6,
+       0xbd000ed0,
+       0x0007f104,
+       0x0103f0c7,
+       0xbd000fd0,
+       0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+       0xb600abc8,
+       0xb9f010b4,
+       0x01aec80c,
+       0xfd11e4b6,
+       0x07f105be,
+       0x03f0c500,
+       0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+       0xe7f104bd,
+       0xe3f0c500,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f30b,
+       0x05e9fd00,
+       0xc80007f1,
+       0xd00103f0,
+       0x04bd000e,
+       0xb804c0b6,
+       0x1bf404cd,
+       0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+       0xf11f1bf4,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x1fb4f000,
+       0xf410b4b0,
+       0xa7f0f01b,
+       0xd021f402,
+/* 0x0223: mmctx_stop */
+       0xc82b0ef4,
        0xb4b600ab,
        0x0cb9f010,
-       0xb601aec8,
-       0xbefd11e4,
-       0x008bd005,
-/* 0x01b4: mmctx_exec_loop */
-/* 0x01b4: mmctx_wait_free */
-       0xf0008ecf,
-       0x0bf41fe4,
-       0x00ce98fa,
-       0xd005e9fd,
-       0xc0b6c08e,
-       0x04cdb804,
-       0xc8e81bf4,
-       0x1bf402ab,
-/* 0x01d5: mmctx_fini_wait */
-       0x008bcf18,
-       0xb01fb4f0,
-       0x1bf410b4,
-       0x02a7f0f7,
-       0xf4c921f4,
-/* 0x01ea: mmctx_stop */
-       0xabc81b0e,
-       0x10b4b600,
-       0xf00cb9f0,
-       0x8bd012b9,
-/* 0x01f9: mmctx_stop_wait */
-       0x008bcf00,
-       0xf412bbc8,
-/* 0x0202: mmctx_done */
-       0x94bdfa1b,
-       0xf10199f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0215: strand_wait */
-       0xf0a0f900,
-       0x21f402a7,
-       0xf8a0fcc9,
-/* 0x0221: strand_pre */
-       0xfc87f100,
-       0x0283f04a,
-       0xd00c97f0,
-       0x21f50089,
-       0x00f80215,
-/* 0x0234: strand_post */
-       0x4afc87f1,
-       0xf00283f0,
-       0x89d00d97,
-       0x1521f500,
-/* 0x0247: strand_set */
-       0xf100f802,
-       0xf04ffca7,
-       0xaba202a3,
-       0xc7f00500,
-       0x00acd00f,
-       0xd00bc7f0,
-       0x21f500bc,
-       0xaed00215,
-       0x0ac7f000,
-       0xf500bcd0,
-       0xf8021521,
-/* 0x0271: strand_ctx_init */
-       0xf094bd00,
-       0x07f10399,
-       0x03f00f00,
+       0xf112b9f0,
+       0xf0c50007,
+       0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+       0xf104bd00,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x12bbc800,
+/* 0x024b: mmctx_done */
+       0xbdf31bf4,
+       0x0199f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x025e: strand_wait */
+       0xa0f900f8,
+       0xf402a7f0,
+       0xa0fcd021,
+/* 0x026a: strand_pre */
+       0x97f000f8,
+       0xfc07f10c,
+       0x0203f04a,
+       0xbd0009d0,
+       0x5e21f504,
+/* 0x027f: strand_post */
+       0xf000f802,
+       0x07f10d97,
+       0x03f04afc,
        0x0009d002,
        0x21f504bd,
-       0xe7f00221,
-       0x4721f503,
-       0xfca7f102,
-       0x02a3f046,
-       0x0400aba0,
-       0xf040a0d0,
-       0xbcd001c7,
-       0x1521f500,
-       0x010c9202,
-       0xf000acd0,
-       0xbcd002c7,
-       0x1521f500,
-       0x3421f502,
-       0x8087f102,
-       0x0684b608,
-       0xb70089cf,
-       0x95220080,
-/* 0x02ca: ctx_init_strand_loop */
+       0x00f8025e,
+/* 0x0294: strand_set */
+       0xf10fc7f0,
+       0xf04ffc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f10bc7,
+       0x03f04afc,
+       0x000cd002,
+       0x07f104bd,
+       0x03f04ffc,
+       0x000ed002,
+       0xc7f004bd,
+       0xfc07f10a,
+       0x0203f04a,
+       0xbd000cd0,
+       0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+       0xbd00f802,
+       0x0399f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0x026a21f5,
+       0xf503e7f0,
+       0xbd029421,
+       0xfc07f1c4,
+       0x0203f047,
+       0xbd000cd0,
+       0x01c7f004,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd000c,
+       0x025e21f5,
+       0xf1010c92,
+       0xf046fc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f102c7,
+       0x03f04afc,
+       0x000cd002,
+       0x21f504bd,
+       0x21f5025e,
+       0x87f1027f,
+       0x83f04200,
+       0x0097f102,
+       0x0293f020,
+       0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
        0x8ed008fe,
        0x408ed000,
        0xb6808acf,
@@ -263,198 +293,230 @@ uint32_t nvd7_grgpc_code[] = {
        0x170007f1,
        0xd00203f0,
        0x04bd0009,
-/* 0x02fe: error */
+/* 0x037e: error */
        0xe0f900f8,
-       0x9814e7f1,
-       0xf440e3f0,
-       0xe0b78d21,
-       0xf7f0041c,
-       0x8d21f401,
-       0x00f8e0fc,
-/* 0x0318: init */
-       0x04fe04bd,
-       0x0017f100,
-       0x0227f012,
-       0xf10012d0,
-       0xfe047017,
-       0x17f10010,
-       0x10d00400,
-       0x0427f0c0,
-       0xf40012d0,
-       0x17f11031,
-       0x14b60608,
-       0x0012cf06,
+       0xf102ffb9,
+       0xf09814e7,
+       0x21f440e3,
+       0x01f7f09d,
+       0xf102ffb9,
+       0xf09c1ce7,
+       0x21f440e3,
+       0xf8e0fc9d,
+/* 0x03a1: init */
+       0xfe04bd00,
+       0x27f00004,
+       0x0007f102,
+       0x0003f012,
+       0xbd0002d0,
+       0x1f17f104,
+       0x0010fe05,
+       0x070007f1,
+       0xd00003f0,
+       0x04bd0000,
+       0xf10427f0,
+       0xf0040007,
+       0x02d00003,
+       0xf404bd00,
+       0x27f11031,
+       0x23f08200,
+       0x0022cf01,
        0xf00137f0,
        0x32bb1f24,
        0x0132b604,
        0x80050280,
-       0x10b70603,
-       0x12cf0400,
-       0x04028000,
-       0x0c30e7f1,
-       0xbd50e3f0,
-       0xbd34bd24,
-/* 0x0371: init_unk_loop */
-       0x6821f444,
-       0xf400f6b0,
-       0xf7f00f0b,
-       0x04f2bb01,
-       0xb6054ffd,
-/* 0x0386: init_unk_next */
-       0x20b60130,
-       0x04e0b601,
-       0xf40126b0,
-/* 0x0392: init_unk_done */
-       0x0380e21b,
-       0x08048007,
-       0x010027f1,
-       0xcf0223f0,
-       0x34bd0022,
-       0x070047f1,
-       0x950644b6,
-       0x45d00825,
-       0x4045d000,
-       0x98000e98,
-       0x21f5010f,
-       0x2fbb0147,
-       0x003fbb00,
-       0x98010e98,
-       0x21f5020f,
-       0x0e980147,
-       0x00effd05,
-       0xbb002ebb,
-       0x0e98003e,
-       0x030f9802,
-       0x014721f5,
-       0xfd070e98,
+       0x27f10603,
+       0x23f08600,
+       0x0022cf01,
+       0xf1040280,
+       0xf00c30e7,
+       0x24bd50e3,
+       0x44bd34bd,
+/* 0x0410: init_unk_loop */
+       0xb06821f4,
+       0x0bf400f6,
+       0x01f7f00f,
+       0xfd04f2bb,
+       0x30b6054f,
+/* 0x0425: init_unk_next */
+       0x0120b601,
+       0xb004e0b6,
+       0x1bf40126,
+/* 0x0431: init_unk_done */
+       0x070380e2,
+       0xf1080480,
+       0xf0010027,
+       0x22cf0223,
+       0x9534bd00,
+       0x07f10825,
+       0x03f0c000,
+       0x0005d001,
+       0x07f104bd,
+       0x03f0c100,
+       0x0005d001,
+       0x0e9804bd,
+       0x010f9800,
+       0x015021f5,
+       0xbb002fbb,
+       0x0e98003f,
+       0x020f9801,
+       0x015021f5,
+       0xfd050e98,
        0x2ebb00ef,
        0x003ebb00,
-       0x130040b7,
-       0xd00235b6,
-       0x25b60043,
-       0x0635b608,
-       0xb60120b6,
-       0x24b60130,
-       0x0834b608,
-       0xf5022fb9,
-       0xbb027121,
-       0x07f1003f,
-       0x03f00100,
-       0x0003d002,
-       0x24bd04bd,
-       0xf11f29f0,
-       0xf0080007,
-       0x02d00203,
-/* 0x0433: main */
+       0x98020e98,
+       0x21f5030f,
+       0x0e980150,
+       0x00effd07,
+       0xbb002ebb,
+       0x35b6003e,
+       0x0007f102,
+       0x0103f0d3,
+       0xbd0003d0,
+       0x0825b604,
+       0xb60635b6,
+       0x30b60120,
+       0x0824b601,
+       0xb90834b6,
+       0x21f5022f,
+       0x3fbb02d3,
+       0x0007f100,
+       0x0203f001,
+       0xbd0003d0,
+       0xf024bd04,
+       0x07f11f29,
+       0x03f00800,
+       0x0002d002,
+/* 0x04e2: main */
+       0x31f404bd,
+       0x0028f400,
+       0xf424d7f0,
+       0x01f43921,
+       0x04e4b0f4,
+       0xfe1e18f4,
+       0x27f00181,
+       0xfd20bd06,
+       0xe4b60412,
+       0x051efd01,
+       0xf50018fe,
+       0xf405d721,
+/* 0x0512: main_not_ctx_xfer */
+       0xef94d30e,
+       0x01f5f010,
+       0x037e21f5,
+/* 0x051f: ih */
+       0xf9c60ef4,
+       0x0188fe80,
+       0x90f980f9,
+       0xb0f9a0f9,
+       0xe0f9d0f9,
+       0x04bdf0f9,
+       0x0200a7f1,
+       0xcf00a3f0,
+       0xabc400aa,
+       0x2c0bf404,
+       0xf124d7f0,
+       0xf01a00e7,
+       0xeecf00e3,
+       0x00f7f100,
+       0x00f3f019,
+       0xf400ffcf,
+       0xe7f00421,
+       0x0007f101,
+       0x0003f01d,
+       0xbd000ed0,
+/* 0x056d: ih_no_fifo */
+       0x0007f104,
+       0x0003f001,
+       0xbd000ad0,
+       0xfcf0fc04,
+       0xfcd0fce0,
+       0xfca0fcb0,
+       0xfe80fc90,
+       0x80fc0088,
+       0xf80032f4,
+/* 0x0591: hub_barrier_done */
+       0x01f7f001,
+       0xbb040e98,
+       0xffb904fe,
+       0x18e7f102,
+       0x40e3f094,
+       0xf89d21f4,
+/* 0x05a9: ctx_redswitch */
+       0x20f7f000,
+       0x850007f1,
+       0xd00103f0,
+       0x04bd000f,
+/* 0x05bb: ctx_redswitch_delay */
+       0xb608e7f0,
+       0x1bf401e2,
+       0x00f5f1fd,
+       0x00f5f108,
+       0x0007f102,
+       0x0103f085,
+       0xbd000fd0,
+/* 0x05d7: ctx_xfer */
+       0xf100f804,
+       0xf0810007,
+       0x0fd00203,
        0xf404bd00,
-       0x28f40031,
-       0x24d7f000,
-       0xf43921f4,
-       0xe4b0f401,
-       0x1e18f404,
-       0xf00181fe,
-       0x20bd0627,
-       0xb60412fd,
-       0x1efd01e4,
-       0x0018fe05,
-       0x04f721f5,
-/* 0x0463: main_not_ctx_xfer */
-       0x94d30ef4,
-       0xf5f010ef,
-       0xfe21f501,
-       0xc60ef402,
-/* 0x0470: ih */
-       0x88fe80f9,
-       0xf980f901,
-       0xf9a0f990,
-       0xf9d0f9b0,
-       0xbdf0f9e0,
-       0x800acf04,
-       0xf404abc4,
-       0xb7f11d0b,
-       0xd7f01900,
-       0x40becf24,
-       0xf400bfcf,
-       0xb0b70421,
-       0xe7f00400,
-       0x00bed001,
-/* 0x04a8: ih_no_fifo */
-       0xfc400ad0,
-       0xfce0fcf0,
-       0xfcb0fcd0,
-       0xfc90fca0,
-       0x0088fe80,
-       0x32f480fc,
-/* 0x04c3: hub_barrier_done */
-       0xf001f800,
-       0x0e9801f7,
-       0x04febb04,
-       0x9418e7f1,
-       0xf440e3f0,
-       0x00f88d21,
-/* 0x04d8: ctx_redswitch */
-       0x0614e7f1,
-       0xf006e4b6,
-       0xefd020f7,
-       0x08f7f000,
-/* 0x04e8: ctx_redswitch_delay */
-       0xf401f2b6,
-       0xf7f1fd1b,
-       0xefd00a20,
-/* 0x04f7: ctx_xfer */
-       0xf100f800,
-       0xb60a0417,
-       0x1fd00614,
-       0x0711f400,
-       0x04d821f5,
-/* 0x0508: ctx_xfer_not_load */
-       0x4afc17f1,
-       0xf00213f0,
-       0x12d00c27,
-       0x1521f500,
-       0xfc27f102,
-       0x0223f047,
-       0xf00020d0,
-       0x20b6012c,
-       0x0012d003,
-       0xf001acf0,
-       0xb7f002a5,
-       0x50b3f000,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x000c9800,
-       0xf0010d98,
-       0x21f500e7,
-       0xacf00166,
-       0x00b7f101,
-       0x50b3f040,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x010c9800,
-       0x98020d98,
-       0xe7f1060f,
-       0x21f50800,
-       0xacf00166,
-       0x04a5f001,
-       0x3000b7f1,
+       0x21f50711,
+/* 0x05ea: ctx_xfer_not_load */
+       0x21f505a9,
+       0x24bd026a,
+       0x47fc07f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xb6012cf0,
+       0x07f10320,
+       0x03f04afc,
+       0x0002d002,
+       0xacf004bd,
+       0x02a5f001,
+       0x0000b7f1,
        0x9850b3f0,
        0xc4b6040c,
        0x00bcbb0f,
-       0x98020c98,
-       0x0f98030d,
-       0x00e7f108,
-       0x6621f502,
-       0x1521f501,
-       0x0601f402,
-/* 0x05a3: ctx_xfer_post */
-       0xf11412f4,
-       0xf04afc17,
-       0x27f00213,
-       0x0012d00d,
-       0x021521f5,
-/* 0x05b4: ctx_xfer_done */
-       0x04c321f5,
-       0x000000f8,
+       0x98000c98,
+       0xe7f0010d,
+       0x6f21f500,
+       0x01acf001,
+       0x4000b7f1,
+       0x9850b3f0,
+       0xc4b6040c,
+       0x00bcbb0f,
+       0x98010c98,
+       0x0f98020d,
+       0x00e7f106,
+       0x6f21f508,
+       0x01acf001,
+       0xf104a5f0,
+       0xf03000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98020c,
+       0x080f9803,
+       0x0200e7f1,
+       0x016f21f5,
+       0x025e21f5,
+       0xf40601f4,
+/* 0x0686: ctx_xfer_post */
+       0x21f50712,
+/* 0x068a: ctx_xfer_done */
+       0x21f5027f,
+       0x00f80591,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
index 7ff5ef6b08048e0d0b12d8b1cf788f97d4f01143..b6da800ee9c2ddbd2baae4cf5812c681c09fccc6 100644 (file)
@@ -41,14 +41,14 @@ uint32_t nve0_grgpc_data[] = {
 };
 
 uint32_t nve0_grgpc_code[] = {
-       0x03180ef5,
+       0x03a10ef5,
 /* 0x0004: queue_put */
        0x9800d898,
        0x86f001d9,
        0x0489b808,
        0xf00c1bf4,
        0x21f502f7,
-       0x00f802fe,
+       0x00f8037e,
 /* 0x001c: queue_put_next */
        0xb60798c4,
        0x8dbb0384,
@@ -72,184 +72,214 @@ uint32_t nve0_grgpc_code[] = {
 /* 0x0066: queue_get_done */
        0x00f80132,
 /* 0x0068: nv_rd32 */
-       0x0728b7f1,
-       0xb906b4b6,
-       0xc9f002ec,
-       0x00bcd01f,
-/* 0x0078: nv_rd32_wait */
-       0xc800bccf,
-       0x1bf41fcc,
-       0x06a7f0fa,
-       0x010921f5,
-       0xf840bfcf,
-/* 0x008d: nv_wr32 */
-       0x28b7f100,
-       0x06b4b607,
-       0xb980bfd0,
-       0xc9f002ec,
-       0x1ec9f01f,
-/* 0x00a3: nv_wr32_wait */
-       0xcf00bcd0,
-       0xccc800bc,
-       0xfa1bf41f,
-/* 0x00ae: watchdog_reset */
-       0x87f100f8,
-       0x84b60430,
-       0x1ff9f006,
-       0xf8008fd0,
-/* 0x00bd: watchdog_clear */
-       0x3087f100,
-       0x0684b604,
-       0xf80080d0,
-/* 0x00c9: wait_donez */
-       0xf094bd00,
-       0x07f10099,
-       0x03f00f00,
-       0x0009d002,
-       0x07f104bd,
-       0x03f00600,
-       0x000ad002,
-/* 0x00e6: wait_donez_ne */
-       0x87f104bd,
-       0x83f00000,
-       0x0088cf01,
-       0xf4888aff,
-       0x94bdf31b,
-       0xf10099f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0109: wait_doneo */
-       0xf094bd00,
+       0xf002ecb9,
+       0x07f11fc9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x007a: nv_rd32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0xa7f0f31b,
+       0x1021f506,
+       0x00f7f101,
+       0x01f3f0cb,
+       0xf800ffcf,
+/* 0x009d: nv_wr32 */
+       0x0007f100,
+       0x0103f0cc,
+       0xbd000fd0,
+       0x02ecb904,
+       0xf01fc9f0,
+       0x07f11ec9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x00be: nv_wr32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f31b,
+/* 0x00d0: wait_donez */
+       0x99f094bd,
+       0x0007f100,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x1bf4888a,
+       0xf094bdf3,
        0x07f10099,
-       0x03f00f00,
+       0x03f01700,
        0x0009d002,
-       0x87f104bd,
-       0x84b60818,
-       0x008ad006,
-/* 0x0124: wait_doneo_e */
-       0x040087f1,
-       0xcf0684b6,
-       0x8aff0088,
-       0xf30bf488,
+       0x00f804bd,
+/* 0x0110: wait_doneo */
        0x99f094bd,
        0x0007f100,
-       0x0203f017,
+       0x0203f00f,
        0xbd0009d0,
-/* 0x0147: mmctx_size */
-       0xbd00f804,
-/* 0x0149: nv_mmctx_size_loop */
-       0x00e89894,
-       0xb61a85b6,
-       0x84b60180,
-       0x0098bb02,
-       0xb804e0b6,
-       0x1bf404ef,
-       0x029fb9eb,
-/* 0x0166: mmctx_xfer */
-       0x94bd00f8,
-       0xf10199f0,
-       0xf00f0007,
-       0x09d00203,
-       0xf104bd00,
-       0xb6071087,
-       0x94bd0684,
-       0xf405bbfd,
-       0x8bd0090b,
-       0x0099f000,
-/* 0x018c: mmctx_base_disabled */
-       0xf405eefd,
-       0x8ed00c0b,
-       0xc08fd080,
-/* 0x019b: mmctx_multi_disabled */
-       0xb70199f0,
-       0xc8010080,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x0bf4888a,
+       0xf094bdf3,
+       0x07f10099,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0xf404efb8,
+       0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+       0xbd00f802,
+       0x0199f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0xbbfd94bd,
+       0x120bf405,
+       0xc40007f1,
+       0xd00103f0,
+       0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0x0007f11e,
+       0x0103f0c6,
+       0xbd000ed0,
+       0x0007f104,
+       0x0103f0c7,
+       0xbd000fd0,
+       0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+       0xb600abc8,
+       0xb9f010b4,
+       0x01aec80c,
+       0xfd11e4b6,
+       0x07f105be,
+       0x03f0c500,
+       0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+       0xe7f104bd,
+       0xe3f0c500,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f30b,
+       0x05e9fd00,
+       0xc80007f1,
+       0xd00103f0,
+       0x04bd000e,
+       0xb804c0b6,
+       0x1bf404cd,
+       0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+       0xf11f1bf4,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x1fb4f000,
+       0xf410b4b0,
+       0xa7f0f01b,
+       0xd021f402,
+/* 0x0223: mmctx_stop */
+       0xc82b0ef4,
        0xb4b600ab,
        0x0cb9f010,
-       0xb601aec8,
-       0xbefd11e4,
-       0x008bd005,
-/* 0x01b4: mmctx_exec_loop */
-/* 0x01b4: mmctx_wait_free */
-       0xf0008ecf,
-       0x0bf41fe4,
-       0x00ce98fa,
-       0xd005e9fd,
-       0xc0b6c08e,
-       0x04cdb804,
-       0xc8e81bf4,
-       0x1bf402ab,
-/* 0x01d5: mmctx_fini_wait */
-       0x008bcf18,
-       0xb01fb4f0,
-       0x1bf410b4,
-       0x02a7f0f7,
-       0xf4c921f4,
-/* 0x01ea: mmctx_stop */
-       0xabc81b0e,
-       0x10b4b600,
-       0xf00cb9f0,
-       0x8bd012b9,
-/* 0x01f9: mmctx_stop_wait */
-       0x008bcf00,
-       0xf412bbc8,
-/* 0x0202: mmctx_done */
-       0x94bdfa1b,
-       0xf10199f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0215: strand_wait */
-       0xf0a0f900,
-       0x21f402a7,
-       0xf8a0fcc9,
-/* 0x0221: strand_pre */
-       0xfc87f100,
-       0x0283f04a,
-       0xd00c97f0,
-       0x21f50089,
-       0x00f80215,
-/* 0x0234: strand_post */
-       0x4afc87f1,
-       0xf00283f0,
-       0x89d00d97,
-       0x1521f500,
-/* 0x0247: strand_set */
-       0xf100f802,
-       0xf04ffca7,
-       0xaba202a3,
-       0xc7f00500,
-       0x00acd00f,
-       0xd00bc7f0,
-       0x21f500bc,
-       0xaed00215,
-       0x0ac7f000,
-       0xf500bcd0,
-       0xf8021521,
-/* 0x0271: strand_ctx_init */
-       0xf094bd00,
-       0x07f10399,
-       0x03f00f00,
+       0xf112b9f0,
+       0xf0c50007,
+       0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+       0xf104bd00,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x12bbc800,
+/* 0x024b: mmctx_done */
+       0xbdf31bf4,
+       0x0199f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x025e: strand_wait */
+       0xa0f900f8,
+       0xf402a7f0,
+       0xa0fcd021,
+/* 0x026a: strand_pre */
+       0x97f000f8,
+       0xfc07f10c,
+       0x0203f04a,
+       0xbd0009d0,
+       0x5e21f504,
+/* 0x027f: strand_post */
+       0xf000f802,
+       0x07f10d97,
+       0x03f04afc,
        0x0009d002,
        0x21f504bd,
-       0xe7f00221,
-       0x4721f503,
-       0xfca7f102,
-       0x02a3f046,
-       0x0400aba0,
-       0xf040a0d0,
-       0xbcd001c7,
-       0x1521f500,
-       0x010c9202,
-       0xf000acd0,
-       0xbcd002c7,
-       0x1521f500,
-       0x3421f502,
-       0x8087f102,
-       0x0684b608,
-       0xb70089cf,
-       0x95220080,
-/* 0x02ca: ctx_init_strand_loop */
+       0x00f8025e,
+/* 0x0294: strand_set */
+       0xf10fc7f0,
+       0xf04ffc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f10bc7,
+       0x03f04afc,
+       0x000cd002,
+       0x07f104bd,
+       0x03f04ffc,
+       0x000ed002,
+       0xc7f004bd,
+       0xfc07f10a,
+       0x0203f04a,
+       0xbd000cd0,
+       0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+       0xbd00f802,
+       0x0399f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0x026a21f5,
+       0xf503e7f0,
+       0xbd029421,
+       0xfc07f1c4,
+       0x0203f047,
+       0xbd000cd0,
+       0x01c7f004,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd000c,
+       0x025e21f5,
+       0xf1010c92,
+       0xf046fc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f102c7,
+       0x03f04afc,
+       0x000cd002,
+       0x21f504bd,
+       0x21f5025e,
+       0x87f1027f,
+       0x83f04200,
+       0x0097f102,
+       0x0293f020,
+       0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
        0x8ed008fe,
        0x408ed000,
        0xb6808acf,
@@ -263,198 +293,230 @@ uint32_t nve0_grgpc_code[] = {
        0x170007f1,
        0xd00203f0,
        0x04bd0009,
-/* 0x02fe: error */
+/* 0x037e: error */
        0xe0f900f8,
-       0x9814e7f1,
-       0xf440e3f0,
-       0xe0b78d21,
-       0xf7f0041c,
-       0x8d21f401,
-       0x00f8e0fc,
-/* 0x0318: init */
-       0x04fe04bd,
-       0x0017f100,
-       0x0227f012,
-       0xf10012d0,
-       0xfe047017,
-       0x17f10010,
-       0x10d00400,
-       0x0427f0c0,
-       0xf40012d0,
-       0x17f11031,
-       0x14b60608,
-       0x0012cf06,
+       0xf102ffb9,
+       0xf09814e7,
+       0x21f440e3,
+       0x01f7f09d,
+       0xf102ffb9,
+       0xf09c1ce7,
+       0x21f440e3,
+       0xf8e0fc9d,
+/* 0x03a1: init */
+       0xfe04bd00,
+       0x27f00004,
+       0x0007f102,
+       0x0003f012,
+       0xbd0002d0,
+       0x1f17f104,
+       0x0010fe05,
+       0x070007f1,
+       0xd00003f0,
+       0x04bd0000,
+       0xf10427f0,
+       0xf0040007,
+       0x02d00003,
+       0xf404bd00,
+       0x27f11031,
+       0x23f08200,
+       0x0022cf01,
        0xf00137f0,
        0x32bb1f24,
        0x0132b604,
        0x80050280,
-       0x10b70603,
-       0x12cf0400,
-       0x04028000,
-       0x0c30e7f1,
-       0xbd50e3f0,
-       0xbd34bd24,
-/* 0x0371: init_unk_loop */
-       0x6821f444,
-       0xf400f6b0,
-       0xf7f00f0b,
-       0x04f2bb01,
-       0xb6054ffd,
-/* 0x0386: init_unk_next */
-       0x20b60130,
-       0x04e0b601,
-       0xf40126b0,
-/* 0x0392: init_unk_done */
-       0x0380e21b,
-       0x08048007,
-       0x010027f1,
-       0xcf0223f0,
-       0x34bd0022,
-       0x070047f1,
-       0x950644b6,
-       0x45d00825,
-       0x4045d000,
-       0x98000e98,
-       0x21f5010f,
-       0x2fbb0147,
-       0x003fbb00,
-       0x98010e98,
-       0x21f5020f,
-       0x0e980147,
-       0x00effd05,
-       0xbb002ebb,
-       0x0e98003e,
-       0x030f9802,
-       0x014721f5,
-       0xfd070e98,
+       0x27f10603,
+       0x23f08600,
+       0x0022cf01,
+       0xf1040280,
+       0xf00c30e7,
+       0x24bd50e3,
+       0x44bd34bd,
+/* 0x0410: init_unk_loop */
+       0xb06821f4,
+       0x0bf400f6,
+       0x01f7f00f,
+       0xfd04f2bb,
+       0x30b6054f,
+/* 0x0425: init_unk_next */
+       0x0120b601,
+       0xb004e0b6,
+       0x1bf40126,
+/* 0x0431: init_unk_done */
+       0x070380e2,
+       0xf1080480,
+       0xf0010027,
+       0x22cf0223,
+       0x9534bd00,
+       0x07f10825,
+       0x03f0c000,
+       0x0005d001,
+       0x07f104bd,
+       0x03f0c100,
+       0x0005d001,
+       0x0e9804bd,
+       0x010f9800,
+       0x015021f5,
+       0xbb002fbb,
+       0x0e98003f,
+       0x020f9801,
+       0x015021f5,
+       0xfd050e98,
        0x2ebb00ef,
        0x003ebb00,
-       0x130040b7,
-       0xd00235b6,
-       0x25b60043,
-       0x0635b608,
-       0xb60120b6,
-       0x24b60130,
-       0x0834b608,
-       0xf5022fb9,
-       0xbb027121,
-       0x07f1003f,
-       0x03f00100,
-       0x0003d002,
-       0x24bd04bd,
-       0xf11f29f0,
-       0xf0080007,
-       0x02d00203,
-/* 0x0433: main */
+       0x98020e98,
+       0x21f5030f,
+       0x0e980150,
+       0x00effd07,
+       0xbb002ebb,
+       0x35b6003e,
+       0x0007f102,
+       0x0103f0d3,
+       0xbd0003d0,
+       0x0825b604,
+       0xb60635b6,
+       0x30b60120,
+       0x0824b601,
+       0xb90834b6,
+       0x21f5022f,
+       0x3fbb02d3,
+       0x0007f100,
+       0x0203f001,
+       0xbd0003d0,
+       0xf024bd04,
+       0x07f11f29,
+       0x03f00800,
+       0x0002d002,
+/* 0x04e2: main */
+       0x31f404bd,
+       0x0028f400,
+       0xf424d7f0,
+       0x01f43921,
+       0x04e4b0f4,
+       0xfe1e18f4,
+       0x27f00181,
+       0xfd20bd06,
+       0xe4b60412,
+       0x051efd01,
+       0xf50018fe,
+       0xf405d721,
+/* 0x0512: main_not_ctx_xfer */
+       0xef94d30e,
+       0x01f5f010,
+       0x037e21f5,
+/* 0x051f: ih */
+       0xf9c60ef4,
+       0x0188fe80,
+       0x90f980f9,
+       0xb0f9a0f9,
+       0xe0f9d0f9,
+       0x04bdf0f9,
+       0x0200a7f1,
+       0xcf00a3f0,
+       0xabc400aa,
+       0x2c0bf404,
+       0xf124d7f0,
+       0xf01a00e7,
+       0xeecf00e3,
+       0x00f7f100,
+       0x00f3f019,
+       0xf400ffcf,
+       0xe7f00421,
+       0x0007f101,
+       0x0003f01d,
+       0xbd000ed0,
+/* 0x056d: ih_no_fifo */
+       0x0007f104,
+       0x0003f001,
+       0xbd000ad0,
+       0xfcf0fc04,
+       0xfcd0fce0,
+       0xfca0fcb0,
+       0xfe80fc90,
+       0x80fc0088,
+       0xf80032f4,
+/* 0x0591: hub_barrier_done */
+       0x01f7f001,
+       0xbb040e98,
+       0xffb904fe,
+       0x18e7f102,
+       0x40e3f094,
+       0xf89d21f4,
+/* 0x05a9: ctx_redswitch */
+       0x20f7f000,
+       0x850007f1,
+       0xd00103f0,
+       0x04bd000f,
+/* 0x05bb: ctx_redswitch_delay */
+       0xb608e7f0,
+       0x1bf401e2,
+       0x00f5f1fd,
+       0x00f5f108,
+       0x0007f102,
+       0x0103f085,
+       0xbd000fd0,
+/* 0x05d7: ctx_xfer */
+       0xf100f804,
+       0xf0810007,
+       0x0fd00203,
        0xf404bd00,
-       0x28f40031,
-       0x24d7f000,
-       0xf43921f4,
-       0xe4b0f401,
-       0x1e18f404,
-       0xf00181fe,
-       0x20bd0627,
-       0xb60412fd,
-       0x1efd01e4,
-       0x0018fe05,
-       0x04f721f5,
-/* 0x0463: main_not_ctx_xfer */
-       0x94d30ef4,
-       0xf5f010ef,
-       0xfe21f501,
-       0xc60ef402,
-/* 0x0470: ih */
-       0x88fe80f9,
-       0xf980f901,
-       0xf9a0f990,
-       0xf9d0f9b0,
-       0xbdf0f9e0,
-       0x800acf04,
-       0xf404abc4,
-       0xb7f11d0b,
-       0xd7f01900,
-       0x40becf24,
-       0xf400bfcf,
-       0xb0b70421,
-       0xe7f00400,
-       0x00bed001,
-/* 0x04a8: ih_no_fifo */
-       0xfc400ad0,
-       0xfce0fcf0,
-       0xfcb0fcd0,
-       0xfc90fca0,
-       0x0088fe80,
-       0x32f480fc,
-/* 0x04c3: hub_barrier_done */
-       0xf001f800,
-       0x0e9801f7,
-       0x04febb04,
-       0x9418e7f1,
-       0xf440e3f0,
-       0x00f88d21,
-/* 0x04d8: ctx_redswitch */
-       0x0614e7f1,
-       0xf006e4b6,
-       0xefd020f7,
-       0x08f7f000,
-/* 0x04e8: ctx_redswitch_delay */
-       0xf401f2b6,
-       0xf7f1fd1b,
-       0xefd00a20,
-/* 0x04f7: ctx_xfer */
-       0xf100f800,
-       0xb60a0417,
-       0x1fd00614,
-       0x0711f400,
-       0x04d821f5,
-/* 0x0508: ctx_xfer_not_load */
-       0x4afc17f1,
-       0xf00213f0,
-       0x12d00c27,
-       0x1521f500,
-       0xfc27f102,
-       0x0223f047,
-       0xf00020d0,
-       0x20b6012c,
-       0x0012d003,
-       0xf001acf0,
-       0xb7f002a5,
-       0x50b3f000,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x000c9800,
-       0xf0010d98,
-       0x21f500e7,
-       0xacf00166,
-       0x00b7f101,
-       0x50b3f040,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x010c9800,
-       0x98020d98,
-       0xe7f1060f,
-       0x21f50800,
-       0xacf00166,
-       0x04a5f001,
-       0x3000b7f1,
+       0x21f50711,
+/* 0x05ea: ctx_xfer_not_load */
+       0x21f505a9,
+       0x24bd026a,
+       0x47fc07f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xb6012cf0,
+       0x07f10320,
+       0x03f04afc,
+       0x0002d002,
+       0xacf004bd,
+       0x02a5f001,
+       0x0000b7f1,
        0x9850b3f0,
        0xc4b6040c,
        0x00bcbb0f,
-       0x98020c98,
-       0x0f98030d,
-       0x00e7f108,
-       0x6621f502,
-       0x1521f501,
-       0x0601f402,
-/* 0x05a3: ctx_xfer_post */
-       0xf11412f4,
-       0xf04afc17,
-       0x27f00213,
-       0x0012d00d,
-       0x021521f5,
-/* 0x05b4: ctx_xfer_done */
-       0x04c321f5,
-       0x000000f8,
+       0x98000c98,
+       0xe7f0010d,
+       0x6f21f500,
+       0x01acf001,
+       0x4000b7f1,
+       0x9850b3f0,
+       0xc4b6040c,
+       0x00bcbb0f,
+       0x98010c98,
+       0x0f98020d,
+       0x00e7f106,
+       0x6f21f508,
+       0x01acf001,
+       0xf104a5f0,
+       0xf03000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98020c,
+       0x080f9803,
+       0x0200e7f1,
+       0x016f21f5,
+       0x025e21f5,
+       0xf40601f4,
+/* 0x0686: ctx_xfer_post */
+       0x21f50712,
+/* 0x068a: ctx_xfer_done */
+       0x21f5027f,
+       0x00f80591,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
index f870507be88019cd9167d82a2fd85b3626f820d3..6316ebaf5d9a581dae8ac9e5a6d0464d0f8ec478 100644 (file)
@@ -41,14 +41,14 @@ uint32_t nvf0_grgpc_data[] = {
 };
 
 uint32_t nvf0_grgpc_code[] = {
-       0x03180ef5,
+       0x03a10ef5,
 /* 0x0004: queue_put */
        0x9800d898,
        0x86f001d9,
        0x0489b808,
        0xf00c1bf4,
        0x21f502f7,
-       0x00f802fe,
+       0x00f8037e,
 /* 0x001c: queue_put_next */
        0xb60798c4,
        0x8dbb0384,
@@ -72,184 +72,214 @@ uint32_t nvf0_grgpc_code[] = {
 /* 0x0066: queue_get_done */
        0x00f80132,
 /* 0x0068: nv_rd32 */
-       0x0728b7f1,
-       0xb906b4b6,
-       0xc9f002ec,
-       0x00bcd01f,
-/* 0x0078: nv_rd32_wait */
-       0xc800bccf,
-       0x1bf41fcc,
-       0x06a7f0fa,
-       0x010921f5,
-       0xf840bfcf,
-/* 0x008d: nv_wr32 */
-       0x28b7f100,
-       0x06b4b607,
-       0xb980bfd0,
-       0xc9f002ec,
-       0x1ec9f01f,
-/* 0x00a3: nv_wr32_wait */
-       0xcf00bcd0,
-       0xccc800bc,
-       0xfa1bf41f,
-/* 0x00ae: watchdog_reset */
-       0x87f100f8,
-       0x84b60430,
-       0x1ff9f006,
-       0xf8008fd0,
-/* 0x00bd: watchdog_clear */
-       0x3087f100,
-       0x0684b604,
-       0xf80080d0,
-/* 0x00c9: wait_donez */
-       0xf094bd00,
-       0x07f10099,
-       0x03f03700,
-       0x0009d002,
-       0x07f104bd,
-       0x03f00600,
-       0x000ad002,
-/* 0x00e6: wait_donez_ne */
-       0x87f104bd,
-       0x83f00000,
-       0x0088cf01,
-       0xf4888aff,
-       0x94bdf31b,
-       0xf10099f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0109: wait_doneo */
-       0xf094bd00,
+       0xf002ecb9,
+       0x07f11fc9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x007a: nv_rd32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0xa7f0f31b,
+       0x1021f506,
+       0x00f7f101,
+       0x01f3f0cb,
+       0xf800ffcf,
+/* 0x009d: nv_wr32 */
+       0x0007f100,
+       0x0103f0cc,
+       0xbd000fd0,
+       0x02ecb904,
+       0xf01fc9f0,
+       0x07f11ec9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x00be: nv_wr32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f31b,
+/* 0x00d0: wait_donez */
+       0x99f094bd,
+       0x0007f100,
+       0x0203f037,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x1bf4888a,
+       0xf094bdf3,
        0x07f10099,
-       0x03f03700,
+       0x03f01700,
        0x0009d002,
-       0x87f104bd,
-       0x84b60818,
-       0x008ad006,
-/* 0x0124: wait_doneo_e */
-       0x040087f1,
-       0xcf0684b6,
-       0x8aff0088,
-       0xf30bf488,
+       0x00f804bd,
+/* 0x0110: wait_doneo */
        0x99f094bd,
        0x0007f100,
-       0x0203f017,
+       0x0203f037,
        0xbd0009d0,
-/* 0x0147: mmctx_size */
-       0xbd00f804,
-/* 0x0149: nv_mmctx_size_loop */
-       0x00e89894,
-       0xb61a85b6,
-       0x84b60180,
-       0x0098bb02,
-       0xb804e0b6,
-       0x1bf404ef,
-       0x029fb9eb,
-/* 0x0166: mmctx_xfer */
-       0x94bd00f8,
-       0xf10199f0,
-       0xf0370007,
-       0x09d00203,
-       0xf104bd00,
-       0xb6071087,
-       0x94bd0684,
-       0xf405bbfd,
-       0x8bd0090b,
-       0x0099f000,
-/* 0x018c: mmctx_base_disabled */
-       0xf405eefd,
-       0x8ed00c0b,
-       0xc08fd080,
-/* 0x019b: mmctx_multi_disabled */
-       0xb70199f0,
-       0xc8010080,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x0bf4888a,
+       0xf094bdf3,
+       0x07f10099,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0xf404efb8,
+       0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+       0xbd00f802,
+       0x0199f094,
+       0x370007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0xbbfd94bd,
+       0x120bf405,
+       0xc40007f1,
+       0xd00103f0,
+       0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0x0007f11e,
+       0x0103f0c6,
+       0xbd000ed0,
+       0x0007f104,
+       0x0103f0c7,
+       0xbd000fd0,
+       0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+       0xb600abc8,
+       0xb9f010b4,
+       0x01aec80c,
+       0xfd11e4b6,
+       0x07f105be,
+       0x03f0c500,
+       0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+       0xe7f104bd,
+       0xe3f0c500,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f30b,
+       0x05e9fd00,
+       0xc80007f1,
+       0xd00103f0,
+       0x04bd000e,
+       0xb804c0b6,
+       0x1bf404cd,
+       0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+       0xf11f1bf4,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x1fb4f000,
+       0xf410b4b0,
+       0xa7f0f01b,
+       0xd021f402,
+/* 0x0223: mmctx_stop */
+       0xc82b0ef4,
        0xb4b600ab,
        0x0cb9f010,
-       0xb601aec8,
-       0xbefd11e4,
-       0x008bd005,
-/* 0x01b4: mmctx_exec_loop */
-/* 0x01b4: mmctx_wait_free */
-       0xf0008ecf,
-       0x0bf41fe4,
-       0x00ce98fa,
-       0xd005e9fd,
-       0xc0b6c08e,
-       0x04cdb804,
-       0xc8e81bf4,
-       0x1bf402ab,
-/* 0x01d5: mmctx_fini_wait */
-       0x008bcf18,
-       0xb01fb4f0,
-       0x1bf410b4,
-       0x02a7f0f7,
-       0xf4c921f4,
-/* 0x01ea: mmctx_stop */
-       0xabc81b0e,
-       0x10b4b600,
-       0xf00cb9f0,
-       0x8bd012b9,
-/* 0x01f9: mmctx_stop_wait */
-       0x008bcf00,
-       0xf412bbc8,
-/* 0x0202: mmctx_done */
-       0x94bdfa1b,
-       0xf10199f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0215: strand_wait */
-       0xf0a0f900,
-       0x21f402a7,
-       0xf8a0fcc9,
-/* 0x0221: strand_pre */
-       0xfc87f100,
-       0x0283f04a,
-       0xd00c97f0,
-       0x21f50089,
-       0x00f80215,
-/* 0x0234: strand_post */
-       0x4afc87f1,
-       0xf00283f0,
-       0x89d00d97,
-       0x1521f500,
-/* 0x0247: strand_set */
-       0xf100f802,
-       0xf04ffca7,
-       0xaba202a3,
-       0xc7f00500,
-       0x00acd00f,
-       0xd00bc7f0,
-       0x21f500bc,
-       0xaed00215,
-       0x0ac7f000,
-       0xf500bcd0,
-       0xf8021521,
-/* 0x0271: strand_ctx_init */
-       0xf094bd00,
-       0x07f10399,
-       0x03f03700,
+       0xf112b9f0,
+       0xf0c50007,
+       0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+       0xf104bd00,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x12bbc800,
+/* 0x024b: mmctx_done */
+       0xbdf31bf4,
+       0x0199f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x025e: strand_wait */
+       0xa0f900f8,
+       0xf402a7f0,
+       0xa0fcd021,
+/* 0x026a: strand_pre */
+       0x97f000f8,
+       0xfc07f10c,
+       0x0203f04a,
+       0xbd0009d0,
+       0x5e21f504,
+/* 0x027f: strand_post */
+       0xf000f802,
+       0x07f10d97,
+       0x03f04afc,
        0x0009d002,
        0x21f504bd,
-       0xe7f00221,
-       0x4721f503,
-       0xfca7f102,
-       0x02a3f046,
-       0x0400aba0,
-       0xf040a0d0,
-       0xbcd001c7,
-       0x1521f500,
-       0x010c9202,
-       0xf000acd0,
-       0xbcd002c7,
-       0x1521f500,
-       0x3421f502,
-       0x8087f102,
-       0x0684b608,
-       0xb70089cf,
-       0x95220080,
-/* 0x02ca: ctx_init_strand_loop */
+       0x00f8025e,
+/* 0x0294: strand_set */
+       0xf10fc7f0,
+       0xf04ffc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f10bc7,
+       0x03f04afc,
+       0x000cd002,
+       0x07f104bd,
+       0x03f04ffc,
+       0x000ed002,
+       0xc7f004bd,
+       0xfc07f10a,
+       0x0203f04a,
+       0xbd000cd0,
+       0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+       0xbd00f802,
+       0x0399f094,
+       0x370007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0x026a21f5,
+       0xf503e7f0,
+       0xbd029421,
+       0xfc07f1c4,
+       0x0203f047,
+       0xbd000cd0,
+       0x01c7f004,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd000c,
+       0x025e21f5,
+       0xf1010c92,
+       0xf046fc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f102c7,
+       0x03f04afc,
+       0x000cd002,
+       0x21f504bd,
+       0x21f5025e,
+       0x87f1027f,
+       0x83f04200,
+       0x0097f102,
+       0x0293f020,
+       0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
        0x8ed008fe,
        0x408ed000,
        0xb6808acf,
@@ -263,198 +293,230 @@ uint32_t nvf0_grgpc_code[] = {
        0x170007f1,
        0xd00203f0,
        0x04bd0009,
-/* 0x02fe: error */
+/* 0x037e: error */
        0xe0f900f8,
-       0x9814e7f1,
-       0xf440e3f0,
-       0xe0b78d21,
-       0xf7f0041c,
-       0x8d21f401,
-       0x00f8e0fc,
-/* 0x0318: init */
-       0x04fe04bd,
-       0x0017f100,
-       0x0227f012,
-       0xf10012d0,
-       0xfe047017,
-       0x17f10010,
-       0x10d00400,
-       0x0427f0c0,
-       0xf40012d0,
-       0x17f11031,
-       0x14b60608,
-       0x0012cf06,
+       0xf102ffb9,
+       0xf09814e7,
+       0x21f440e3,
+       0x01f7f09d,
+       0xf102ffb9,
+       0xf09c1ce7,
+       0x21f440e3,
+       0xf8e0fc9d,
+/* 0x03a1: init */
+       0xfe04bd00,
+       0x27f00004,
+       0x0007f102,
+       0x0003f012,
+       0xbd0002d0,
+       0x1f17f104,
+       0x0010fe05,
+       0x070007f1,
+       0xd00003f0,
+       0x04bd0000,
+       0xf10427f0,
+       0xf0040007,
+       0x02d00003,
+       0xf404bd00,
+       0x27f11031,
+       0x23f08200,
+       0x0022cf01,
        0xf00137f0,
        0x32bb1f24,
        0x0132b604,
        0x80050280,
-       0x10b70603,
-       0x12cf0400,
-       0x04028000,
-       0x0c30e7f1,
-       0xbd50e3f0,
-       0xbd34bd24,
-/* 0x0371: init_unk_loop */
-       0x6821f444,
-       0xf400f6b0,
-       0xf7f00f0b,
-       0x04f2bb01,
-       0xb6054ffd,
-/* 0x0386: init_unk_next */
-       0x20b60130,
-       0x04e0b601,
-       0xf40226b0,
-/* 0x0392: init_unk_done */
-       0x0380e21b,
-       0x08048007,
-       0x010027f1,
-       0xcf0223f0,
-       0x34bd0022,
-       0x070047f1,
-       0x950644b6,
-       0x45d00825,
-       0x4045d000,
-       0x98000e98,
-       0x21f5010f,
-       0x2fbb0147,
-       0x003fbb00,
-       0x98010e98,
-       0x21f5020f,
-       0x0e980147,
-       0x00effd05,
-       0xbb002ebb,
-       0x0e98003e,
-       0x030f9802,
-       0x014721f5,
-       0xfd070e98,
+       0x27f10603,
+       0x23f08600,
+       0x0022cf01,
+       0xf1040280,
+       0xf00c30e7,
+       0x24bd50e3,
+       0x44bd34bd,
+/* 0x0410: init_unk_loop */
+       0xb06821f4,
+       0x0bf400f6,
+       0x01f7f00f,
+       0xfd04f2bb,
+       0x30b6054f,
+/* 0x0425: init_unk_next */
+       0x0120b601,
+       0xb004e0b6,
+       0x1bf40226,
+/* 0x0431: init_unk_done */
+       0x070380e2,
+       0xf1080480,
+       0xf0010027,
+       0x22cf0223,
+       0x9534bd00,
+       0x07f10825,
+       0x03f0c000,
+       0x0005d001,
+       0x07f104bd,
+       0x03f0c100,
+       0x0005d001,
+       0x0e9804bd,
+       0x010f9800,
+       0x015021f5,
+       0xbb002fbb,
+       0x0e98003f,
+       0x020f9801,
+       0x015021f5,
+       0xfd050e98,
        0x2ebb00ef,
        0x003ebb00,
-       0x130040b7,
-       0xd00235b6,
-       0x25b60043,
-       0x0635b608,
-       0xb60120b6,
-       0x24b60130,
-       0x0834b608,
-       0xf5022fb9,
-       0xbb027121,
-       0x07f1003f,
-       0x03f00100,
-       0x0003d002,
-       0x24bd04bd,
-       0xf11f29f0,
-       0xf0300007,
-       0x02d00203,
-/* 0x0433: main */
+       0x98020e98,
+       0x21f5030f,
+       0x0e980150,
+       0x00effd07,
+       0xbb002ebb,
+       0x35b6003e,
+       0x0007f102,
+       0x0103f0d3,
+       0xbd0003d0,
+       0x0825b604,
+       0xb60635b6,
+       0x30b60120,
+       0x0824b601,
+       0xb90834b6,
+       0x21f5022f,
+       0x3fbb02d3,
+       0x0007f100,
+       0x0203f001,
+       0xbd0003d0,
+       0xf024bd04,
+       0x07f11f29,
+       0x03f03000,
+       0x0002d002,
+/* 0x04e2: main */
+       0x31f404bd,
+       0x0028f400,
+       0xf424d7f0,
+       0x01f43921,
+       0x04e4b0f4,
+       0xfe1e18f4,
+       0x27f00181,
+       0xfd20bd06,
+       0xe4b60412,
+       0x051efd01,
+       0xf50018fe,
+       0xf405d721,
+/* 0x0512: main_not_ctx_xfer */
+       0xef94d30e,
+       0x01f5f010,
+       0x037e21f5,
+/* 0x051f: ih */
+       0xf9c60ef4,
+       0x0188fe80,
+       0x90f980f9,
+       0xb0f9a0f9,
+       0xe0f9d0f9,
+       0x04bdf0f9,
+       0x0200a7f1,
+       0xcf00a3f0,
+       0xabc400aa,
+       0x2c0bf404,
+       0xf124d7f0,
+       0xf01a00e7,
+       0xeecf00e3,
+       0x00f7f100,
+       0x00f3f019,
+       0xf400ffcf,
+       0xe7f00421,
+       0x0007f101,
+       0x0003f01d,
+       0xbd000ed0,
+/* 0x056d: ih_no_fifo */
+       0x0007f104,
+       0x0003f001,
+       0xbd000ad0,
+       0xfcf0fc04,
+       0xfcd0fce0,
+       0xfca0fcb0,
+       0xfe80fc90,
+       0x80fc0088,
+       0xf80032f4,
+/* 0x0591: hub_barrier_done */
+       0x01f7f001,
+       0xbb040e98,
+       0xffb904fe,
+       0x18e7f102,
+       0x40e3f094,
+       0xf89d21f4,
+/* 0x05a9: ctx_redswitch */
+       0x20f7f000,
+       0x850007f1,
+       0xd00103f0,
+       0x04bd000f,
+/* 0x05bb: ctx_redswitch_delay */
+       0xb608e7f0,
+       0x1bf401e2,
+       0x00f5f1fd,
+       0x00f5f108,
+       0x0007f102,
+       0x0103f085,
+       0xbd000fd0,
+/* 0x05d7: ctx_xfer */
+       0xf100f804,
+       0xf0810007,
+       0x0fd00203,
        0xf404bd00,
-       0x28f40031,
-       0x24d7f000,
-       0xf43921f4,
-       0xe4b0f401,
-       0x1e18f404,
-       0xf00181fe,
-       0x20bd0627,
-       0xb60412fd,
-       0x1efd01e4,
-       0x0018fe05,
-       0x04f721f5,
-/* 0x0463: main_not_ctx_xfer */
-       0x94d30ef4,
-       0xf5f010ef,
-       0xfe21f501,
-       0xc60ef402,
-/* 0x0470: ih */
-       0x88fe80f9,
-       0xf980f901,
-       0xf9a0f990,
-       0xf9d0f9b0,
-       0xbdf0f9e0,
-       0x800acf04,
-       0xf404abc4,
-       0xb7f11d0b,
-       0xd7f01900,
-       0x40becf24,
-       0xf400bfcf,
-       0xb0b70421,
-       0xe7f00400,
-       0x00bed001,
-/* 0x04a8: ih_no_fifo */
-       0xfc400ad0,
-       0xfce0fcf0,
-       0xfcb0fcd0,
-       0xfc90fca0,
-       0x0088fe80,
-       0x32f480fc,
-/* 0x04c3: hub_barrier_done */
-       0xf001f800,
-       0x0e9801f7,
-       0x04febb04,
-       0x9418e7f1,
-       0xf440e3f0,
-       0x00f88d21,
-/* 0x04d8: ctx_redswitch */
-       0x0614e7f1,
-       0xf006e4b6,
-       0xefd020f7,
-       0x08f7f000,
-/* 0x04e8: ctx_redswitch_delay */
-       0xf401f2b6,
-       0xf7f1fd1b,
-       0xefd00a20,
-/* 0x04f7: ctx_xfer */
-       0xf100f800,
-       0xb60a0417,
-       0x1fd00614,
-       0x0711f400,
-       0x04d821f5,
-/* 0x0508: ctx_xfer_not_load */
-       0x4afc17f1,
-       0xf00213f0,
-       0x12d00c27,
-       0x1521f500,
-       0xfc27f102,
-       0x0223f047,
-       0xf00020d0,
-       0x20b6012c,
-       0x0012d003,
-       0xf001acf0,
-       0xb7f002a5,
-       0x50b3f000,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x000c9800,
-       0xf0010d98,
-       0x21f500e7,
-       0xacf00166,
-       0x00b7f101,
-       0x50b3f040,
-       0xb6040c98,
-       0xbcbb0fc4,
-       0x010c9800,
-       0x98020d98,
-       0xe7f1060f,
-       0x21f50800,
-       0xacf00166,
-       0x04a5f001,
-       0x3000b7f1,
+       0x21f50711,
+/* 0x05ea: ctx_xfer_not_load */
+       0x21f505a9,
+       0x24bd026a,
+       0x47fc07f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xb6012cf0,
+       0x07f10320,
+       0x03f04afc,
+       0x0002d002,
+       0xacf004bd,
+       0x02a5f001,
+       0x0000b7f1,
        0x9850b3f0,
        0xc4b6040c,
        0x00bcbb0f,
-       0x98020c98,
-       0x0f98030d,
-       0x00e7f108,
-       0x6621f502,
-       0x1521f501,
-       0x0601f402,
-/* 0x05a3: ctx_xfer_post */
-       0xf11412f4,
-       0xf04afc17,
-       0x27f00213,
-       0x0012d00d,
-       0x021521f5,
-/* 0x05b4: ctx_xfer_done */
-       0x04c321f5,
-       0x000000f8,
+       0x98000c98,
+       0xe7f0010d,
+       0x6f21f500,
+       0x01acf001,
+       0x4000b7f1,
+       0x9850b3f0,
+       0xc4b6040c,
+       0x00bcbb0f,
+       0x98010c98,
+       0x0f98020d,
+       0x00e7f106,
+       0x6f21f508,
+       0x01acf001,
+       0xf104a5f0,
+       0xf03000b7,
+       0x0c9850b3,
+       0x0fc4b604,
+       0x9800bcbb,
+       0x0d98020c,
+       0x080f9803,
+       0x0200e7f1,
+       0x016f21f5,
+       0x025e21f5,
+       0xf40601f4,
+/* 0x0686: ctx_xfer_post */
+       0x21f50712,
+/* 0x068a: ctx_xfer_done */
+       0x21f5027f,
+       0x00f80591,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
index b82d2ae8991742e7eb58902f4935663590fbe795..c8ddb8d71b915c668c7b116f1b7f9cf9547289b3 100644 (file)
@@ -68,60 +68,57 @@ error:
 //
 init:
        clear b32 $r0
-       mov $sp $r0
        mov $xdbase $r0
 
+       // setup stack
+       nv_iord($r1, NV_PGRAPH_FECS_CAPS, 0)
+       extr $r1 $r1 9:17
+       shl b32 $r1 8
+       mov $sp $r1
+
        // enable fifo access
-       mov $r1 0x1200
-       mov $r2 2
-       iowr I[$r1 + 0x000] $r2 // FIFO_ENABLE
+       mov $r2 NV_PGRAPH_FECS_ACCESS_FIFO
+       nv_iowr(NV_PGRAPH_FECS_ACCESS, 0, $r2)
 
        // setup i0 handler, and route all interrupts to it
        mov $r1 #ih
        mov $iv0 $r1
-       mov $r1 0x400
-       iowr I[$r1 + 0x300] $r0 // INTR_DISPATCH
 
-       // route HUB_CHANNEL_SWITCH to fuc interrupt 8
-       mov $r3 0x404
-       shl b32 $r3 6
-       mov $r2 0x2003          // { HUB_CHANNEL_SWITCH, ZERO } -> intr 8
-       iowr I[$r3 + 0x000] $r2
+       clear b32 $r2
+       nv_iowr(NV_PGRAPH_FECS_INTR_ROUTE, 0, $r2)
+
+       // route HUB_CHSW_PULSE to fuc interrupt 8
+       mov $r2 0x2003          // { HUB_CHSW_PULSE, ZERO } -> intr 8
+       nv_iowr(NV_PGRAPH_FECS_IROUTE, 0, $r2)
 
        // not sure what these are, route them because NVIDIA does, and
        // the IRQ handler will signal the host if we ever get one.. we
        // may find out if/why we need to handle these if so..
        //
-       mov $r2 0x2004
-       iowr I[$r3 + 0x004] $r2 // { 0x04, ZERO } -> intr 9
-       mov $r2 0x200b
-       iowr I[$r3 + 0x008] $r2 // { 0x0b, ZERO } -> intr 10
-       mov $r2 0x200c
-       iowr I[$r3 + 0x01c] $r2 // { 0x0c, ZERO } -> intr 15
+       mov $r2 0x2004          // { 0x04, ZERO } -> intr 9
+       nv_iowr(NV_PGRAPH_FECS_IROUTE, 1, $r2)
+       mov $r2 0x200b          // { HUB_FIRMWARE_MTHD, ZERO } -> intr 10
+       nv_iowr(NV_PGRAPH_FECS_IROUTE, 2, $r2)
+       mov $r2 0x200c          // { 0x0c, ZERO } -> intr 15
+       nv_iowr(NV_PGRAPH_FECS_IROUTE, 7, $r2)
 
        // enable all INTR_UP interrupts
-       mov $r2 0xc24
-       shl b32 $r2 6
-       not b32 $r3 $r0
-       iowr I[$r2] $r3
+       sub b32 $r3 $r0 1
+       nv_iowr(NV_PGRAPH_FECS_INTR_UP_EN, 0, $r3)
 
-       // enable fifo, ctxsw, 9, 10, 15 interrupts
-       mov $r2 -0x78fc         // 0x8704
-       sethi $r2 0
-       iowr I[$r1 + 0x000] $r2 // INTR_EN_SET
+       // enable fifo, ctxsw, 9, fwmthd, 15 interrupts
+       imm32($r2, 0x8704)
+       nv_iowr(NV_PGRAPH_FECS_INTR_EN_SET, 0, $r2)
 
        // fifo level triggered, rest edge
-       sub b32 $r1 0x100
-       mov $r2 4
-       iowr I[$r1] $r2
+       mov $r2 NV_PGRAPH_FECS_INTR_MODE_FIFO_LEVEL
+       nv_iowr(NV_PGRAPH_FECS_INTR_MODE, 0, $r2)
 
        // enable interrupts
        bset $flags ie0
 
        // fetch enabled GPC/ROP counts
-       mov $r14 -0x69fc        // 0x409604
-       sethi $r14 0x400000
-       call #nv_rd32
+       nv_rd32($r14, 0x409604)
        extr $r1 $r15 16:20
        st b32 D[$r0 + #rop_count] $r1
        and $r15 0x1f
@@ -131,37 +128,40 @@ init:
        mov $r1 1
        shl b32 $r1 $r15
        sub b32 $r1 1
-       mov $r2 0x40c
-       shl b32 $r2 6
-       iowr I[$r2 + 0x000] $r1
-       iowr I[$r2 + 0x100] $r1
+       nv_iowr(NV_PGRAPH_FECS_BAR_MASK0, 0, $r1)
+       nv_iowr(NV_PGRAPH_FECS_BAR_MASK1, 0, $r1)
 
        // context size calculation, reserve first 256 bytes for use by fuc
        mov $r1 256
 
+       //
+       mov $r15 2
+       call(ctx_4170s)
+       call(ctx_4170w)
+       mov $r15 0x10
+       call(ctx_86c)
+
        // calculate size of mmio context data
        ld b32 $r14 D[$r0 + #hub_mmio_list_head]
        ld b32 $r15 D[$r0 + #hub_mmio_list_tail]
-       call #mmctx_size
+       call(mmctx_size)
 
        // set mmctx base addresses now so we don't have to do it later,
        // they don't (currently) ever change
-       mov $r3 0x700
-       shl b32 $r3 6
        shr b32 $r4 $r1 8
-       iowr I[$r3 + 0x000] $r4         // MMCTX_SAVE_SWBASE
-       iowr I[$r3 + 0x100] $r4         // MMCTX_LOAD_SWBASE
+       nv_iowr(NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE, 0, $r4)
+       nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE, 0, $r4)
        add b32 $r3 0x1300
        add b32 $r1 $r15
        shr b32 $r15 2
-       iowr I[$r3 + 0x000] $r15        // MMCTX_LOAD_COUNT, wtf for?!?
+       nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_COUNT, 0, $r15) // wtf??
 
        // strands, base offset needs to be aligned to 256 bytes
        shr b32 $r1 8
        add b32 $r1 1
        shl b32 $r1 8
        mov b32 $r15 $r1
-       call #strand_ctx_init
+       call(strand_ctx_init)
        add b32 $r1 $r15
 
        // initialise each GPC in sequence by passing in the offset of its
@@ -173,30 +173,29 @@ init:
        // in GPCn_CC_SCRATCH[1]
        //
        ld b32 $r3 D[$r0 + #gpc_count]
-       mov $r4 0x2000
-       sethi $r4 0x500000
+       imm32($r4, 0x502000)
        init_gpc:
                // setup, and start GPC ucode running
                add b32 $r14 $r4 0x804
                mov b32 $r15 $r1
-               call #nv_wr32                   // CC_SCRATCH[1] = ctx offset
+               call(nv_wr32)                   // CC_SCRATCH[1] = ctx offset
                add b32 $r14 $r4 0x10c
                clear b32 $r15
-               call #nv_wr32
+               call(nv_wr32)
                add b32 $r14 $r4 0x104
-               call #nv_wr32                   // ENTRY
+               call(nv_wr32)                   // ENTRY
                add b32 $r14 $r4 0x100
                mov $r15 2                      // CTRL_START_TRIGGER
-               call #nv_wr32                   // CTRL
+               call(nv_wr32)                   // CTRL
 
                // wait for it to complete, and adjust context size
                add b32 $r14 $r4 0x800
                init_gpc_wait:
-                       call #nv_rd32
+                       call(nv_rd32)
                        xbit $r15 $r15 31
                        bra e #init_gpc_wait
                add b32 $r14 $r4 0x804
-               call #nv_rd32
+               call(nv_rd32)
                add b32 $r1 $r15
 
                // next!
@@ -204,6 +203,12 @@ init:
                sub b32 $r3 1
                bra ne #init_gpc
 
+       //
+       mov $r15 0
+       call(ctx_86c)
+       mov $r15 0
+       call(ctx_4170s)
+
        // save context size, and tell host we're ready
        nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(1), 0, $r1)
        clear b32 $r1
@@ -218,17 +223,15 @@ main:
        bset $flags $p0
        sleep $p0
        mov $r13 #cmd_queue
-       call #queue_get
+       call(queue_get)
        bra $p1 #main
 
        // context switch, requested by GPU?
        cmpu b32 $r14 0x4001
        bra ne #main_not_ctx_switch
                trace_set(T_AUTO)
-               mov $r1 0xb00
-               shl b32 $r1 6
-               iord $r2 I[$r1 + 0x100]         // CHAN_NEXT
-               iord $r1 I[$r1 + 0x000]         // CHAN_CUR
+               nv_iord($r1, NV_PGRAPH_FECS_CHAN_ADDR, 0)
+               nv_iord($r2, NV_PGRAPH_FECS_CHAN_NEXT, 0)
 
                xbit $r3 $r1 31
                bra e #chsw_no_prev
@@ -239,12 +242,12 @@ main:
                                trace_set(T_SAVE)
                                bclr $flags $p1
                                bset $flags $p2
-                               call #ctx_xfer
+                               call(ctx_xfer)
                                trace_clr(T_SAVE);
                                pop $r2
                                trace_set(T_LOAD);
                                bset $flags $p1
-                               call #ctx_xfer
+                               call(ctx_xfer)
                                trace_clr(T_LOAD);
                                bra #chsw_done
                        chsw_prev_no_next:
@@ -252,25 +255,21 @@ main:
                                mov b32 $r2 $r1
                                bclr $flags $p1
                                bclr $flags $p2
-                               call #ctx_xfer
+                               call(ctx_xfer)
                                pop $r2
-                               mov $r1 0xb00
-                               shl b32 $r1 6
-                               iowr I[$r1] $r2
+                               nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
                                bra #chsw_done
                chsw_no_prev:
                        xbit $r3 $r2 31
                        bra e #chsw_done
                                bset $flags $p1
                                bclr $flags $p2
-                               call #ctx_xfer
+                               call(ctx_xfer)
 
                // ack the context switch request
                chsw_done:
-               mov $r1 0xb0c
-               shl b32 $r1 6
-               mov $r2 1
-               iowr I[$r1 + 0x000] $r2         // 0x409b0c
+               mov $r2 NV_PGRAPH_FECS_CHSW_ACK
+               nv_iowr(NV_PGRAPH_FECS_CHSW, 0, $r2)
                trace_clr(T_AUTO)
                bra #main
 
@@ -279,7 +278,7 @@ main:
        cmpu b32 $r14 0x0001
        bra ne #main_not_ctx_chan
                mov b32 $r2 $r15
-               call #ctx_chan
+               call(ctx_chan)
                bra #main_done
 
        // request to store current channel context?
@@ -289,14 +288,14 @@ main:
                trace_set(T_SAVE)
                bclr $flags $p1
                bclr $flags $p2
-               call #ctx_xfer
+               call(ctx_xfer)
                trace_clr(T_SAVE)
                bra #main_done
 
        main_not_ctx_save:
                shl b32 $r15 $r14 16
                or $r15 E_BAD_COMMAND
-               call #error
+               call(error)
                bra #main
 
        main_done:
@@ -319,41 +318,46 @@ ih:
        clear b32 $r0
 
        // incoming fifo command?
-       iord $r10 I[$r0 + 0x200]        // INTR
-       and $r11 $r10 0x00000004
+       nv_iord($r10, NV_PGRAPH_FECS_INTR, 0)
+       and $r11 $r10 NV_PGRAPH_FECS_INTR_FIFO
        bra e #ih_no_fifo
                // queue incoming fifo command for later processing
-               mov $r11 0x1900
                mov $r13 #cmd_queue
-               iord $r14 I[$r11 + 0x100]       // FIFO_CMD
-               iord $r15 I[$r11 + 0x000]       // FIFO_DATA
-               call #queue_put
+               nv_iord($r14, NV_PGRAPH_FECS_FIFO_CMD, 0)
+               nv_iord($r15, NV_PGRAPH_FECS_FIFO_DATA, 0)
+               call(queue_put)
                add b32 $r11 0x400
                mov $r14 1
-               iowr I[$r11 + 0x000] $r14       // FIFO_ACK
+               nv_iowr(NV_PGRAPH_FECS_FIFO_ACK, 0, $r14)
 
        // context switch request?
        ih_no_fifo:
-       and $r11 $r10 0x00000100
+       and $r11 $r10 NV_PGRAPH_FECS_INTR_CHSW
        bra e #ih_no_ctxsw
                // enqueue a context switch for later processing
                mov $r13 #cmd_queue
                mov $r14 0x4001
-               call #queue_put
+               call(queue_put)
 
-       // anything we didn't handle, bring it to the host's attention
+       // firmware method?
        ih_no_ctxsw:
-       mov $r11 0x104
+       and $r11 $r10 NV_PGRAPH_FECS_INTR_FWMTHD
+       bra e #ih_no_fwmthd
+               // none we handle, ack, and fall-through to unhandled
+               mov $r11 0x100
+               nv_wr32(0x400144, $r11)
+
+       // anything we didn't handle, bring it to the host's attention
+       ih_no_fwmthd:
+       mov $r11 0x104 // FIFO | CHSW
        not b32 $r11
        and $r11 $r10 $r11
        bra e #ih_no_other
-               mov $r10 0xc1c
-               shl b32 $r10 6
-               iowr I[$r10] $r11       // INTR_UP_SET
+               nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r11)
 
        // ack, and wake up main()
        ih_no_other:
-       iowr I[$r0 + 0x100] $r10        // INTR_ACK
+       nv_iowr(NV_PGRAPH_FECS_INTR_ACK, 0, $r10)
 
        pop $r15
        pop $r14
@@ -370,12 +374,10 @@ ih:
 #if CHIPSET < GK100
 // Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
 ctx_4160s:
-       mov $r14 0x4160
-       sethi $r14 0x400000
        mov $r15 1
-       call #nv_wr32
+       nv_wr32(0x404160, $r15)
        ctx_4160s_wait:
-               call #nv_rd32
+               nv_rd32($r15, 0x404160)
                xbit $r15 $r15 4
                bra e #ctx_4160s_wait
        ret
@@ -384,10 +386,8 @@ ctx_4160s:
 // to hang with STATUS=0x00000007 until it's cleared.. fbcon can
 // still function with it set however...
 ctx_4160c:
-       mov $r14 0x4160
-       sethi $r14 0x400000
        clear b32 $r15
-       call #nv_wr32
+       nv_wr32(0x404160, $r15)
        ret
 #endif
 
@@ -396,18 +396,14 @@ ctx_4160c:
 // In: $r15 value to set 0x404170 to
 //
 ctx_4170s:
-       mov $r14 0x4170
-       sethi $r14 0x400000
        or $r15 0x10
-       call #nv_wr32
+       nv_wr32(0x404170, $r15)
        ret
 
 // Waits for a ctx_4170s() call to complete
 //
 ctx_4170w:
-       mov $r14 0x4170
-       sethi $r14 0x400000
-       call #nv_rd32
+       nv_rd32($r15, 0x404170)
        and $r15 0x10
        bra ne #ctx_4170w
        ret
@@ -419,16 +415,18 @@ ctx_4170w:
 // funny things happen.
 //
 ctx_redswitch:
-       mov $r14 0x614
-       shl b32 $r14 6
-       mov $r15 0x270
-       iowr I[$r14] $r15       // HUB_RED_SWITCH = ENABLE_GPC, POWER_ALL
+       mov $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_GPC
+       or  $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_ROP
+       or  $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_GPC
+       or  $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_MAIN
+       nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
        mov $r15 8
        ctx_redswitch_delay:
                sub b32 $r15 1
                bra ne #ctx_redswitch_delay
-       mov $r15 0x770
-       iowr I[$r14] $r15       // HUB_RED_SWITCH = ENABLE_ALL, POWER_ALL
+       or  $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_ROP
+       or  $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_MAIN
+       nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
        ret
 
 // Not a clue what this is for, except that unless the value is 0x10, the
@@ -437,15 +435,18 @@ ctx_redswitch:
 // In: $r15 value to set to (0x00/0x10 are used)
 //
 ctx_86c:
-       mov $r14 0x86c
-       shl b32 $r14 6
-       iowr I[$r14] $r15       // HUB(0x86c) = val
-       mov $r14 -0x75ec
-       sethi $r14 0x400000
-       call #nv_wr32           // ROP(0xa14) = val
-       mov $r14 -0x5794
-       sethi $r14 0x410000
-       call #nv_wr32           // GPC(0x86c) = val
+       nv_iowr(NV_PGRAPH_FECS_UNK86C, 0, $r15)
+       nv_wr32(0x408a14, $r15)
+       nv_wr32(NV_PGRAPH_GPCX_GPCCS_UNK86C, $r15)
+       ret
+
+// In: $r15 NV_PGRAPH_FECS_MEM_CMD_*
+ctx_mem:
+       nv_iowr(NV_PGRAPH_FECS_MEM_CMD, 0, $r15)
+       ctx_mem_wait:
+               nv_iord($r15, NV_PGRAPH_FECS_MEM_CMD, 0)
+               or $r15 $r15
+               bra ne #ctx_mem_wait
        ret
 
 // ctx_load - load's a channel's ctxctl data, and selects its vm
@@ -457,23 +458,14 @@ ctx_load:
 
        // switch to channel, somewhat magic in parts..
        mov $r10 12             // DONE_UNK12
-       call #wait_donez
-       mov $r1 0xa24
-       shl b32 $r1 6
-       iowr I[$r1 + 0x000] $r0 // 0x409a24
-       mov $r3 0xb00
-       shl b32 $r3 6
-       iowr I[$r3 + 0x100] $r2 // CHAN_NEXT
-       mov $r1 0xa0c
-       shl b32 $r1 6
-       mov $r4 7
-       iowr I[$r1 + 0x000] $r2 // MEM_CHAN
-       iowr I[$r1 + 0x100] $r4 // MEM_CMD
-       ctx_chan_wait_0:
-               iord $r4 I[$r1 + 0x100]
-               and $r4 0x1f
-               bra ne #ctx_chan_wait_0
-       iowr I[$r3 + 0x000] $r2 // CHAN_CUR
+       call(wait_donez)
+       clear b32 $r15
+       nv_iowr(0x409a24, 0, $r15)
+       nv_iowr(NV_PGRAPH_FECS_CHAN_NEXT, 0, $r2)
+       nv_iowr(NV_PGRAPH_FECS_MEM_CHAN, 0, $r2)
+       mov $r15 NV_PGRAPH_FECS_MEM_CMD_LOAD_CHAN
+       call(ctx_mem)
+       nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
 
        // load channel header, fetch PGRAPH context pointer
        mov $xtargets $r0
@@ -482,14 +474,10 @@ ctx_load:
        add b32 $r2 2
 
        trace_set(T_LCHAN)
-       mov $r1 0xa04
-       shl b32 $r1 6
-       iowr I[$r1 + 0x000] $r2         // MEM_BASE
-       mov $r1 0xa20
-       shl b32 $r1 6
-       mov $r2 0x0002
-       sethi $r2 0x80000000
-       iowr I[$r1 + 0x000] $r2         // MEM_TARGET = vram
+       nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r2)
+       imm32($r2, NV_PGRAPH_FECS_MEM_TARGET_UNK31)
+       or  $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VRAM
+       nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
        mov $r1 0x10                    // chan + 0x0210
        mov $r2 #xfer_data
        sethi $r2 0x00020000            // 16 bytes
@@ -507,13 +495,9 @@ ctx_load:
 
        // set transfer base to start of context, and fetch context header
        trace_set(T_LCTXH)
-       mov $r2 0xa04
-       shl b32 $r2 6
-       iowr I[$r2 + 0x000] $r1         // MEM_BASE
-       mov $r2 1
-       mov $r1 0xa20
-       shl b32 $r1 6
-       iowr I[$r1 + 0x000] $r2         // MEM_TARGET = vm
+       nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r1)
+       mov $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VM
+       nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
        mov $r1 #chan_data
        sethi $r1 0x00060000            // 256 bytes
        xdld $r0 $r1
@@ -532,21 +516,15 @@ ctx_load:
 //
 ctx_chan:
 #if CHIPSET < GK100
-       call #ctx_4160s
+       call(ctx_4160s)
 #endif
-       call #ctx_load
+       call(ctx_load)
        mov $r10 12                     // DONE_UNK12
-       call #wait_donez
-       mov $r1 0xa10
-       shl b32 $r1 6
-       mov $r2 5
-       iowr I[$r1 + 0x000] $r2         // MEM_CMD = 5 (???)
-       ctx_chan_wait:
-               iord $r2 I[$r1 + 0x000]
-               or $r2 $r2
-               bra ne #ctx_chan_wait
+       call(wait_donez)
+       mov $r15 5 // MEM_CMD 5 ???
+       call(ctx_mem)
 #if CHIPSET < GK100
-       call #ctx_4160c
+       call(ctx_4160c)
 #endif
        ret
 
@@ -562,9 +540,7 @@ ctx_chan:
 ctx_mmio_exec:
        // set transfer base to be the mmio list
        ld b32 $r3 D[$r0 + #chan_mmio_address]
-       mov $r2 0xa04
-       shl b32 $r2 6
-       iowr I[$r2 + 0x000] $r3         // MEM_BASE
+       nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
 
        clear b32 $r3
        ctx_mmio_loop:
@@ -580,7 +556,7 @@ ctx_mmio_exec:
                ctx_mmio_pull:
                ld b32 $r14 D[$r4 + #xfer_data + 0x00]
                ld b32 $r15 D[$r4 + #xfer_data + 0x04]
-               call #nv_wr32
+               call(nv_wr32)
 
                // next!
                add b32 $r3 8
@@ -590,7 +566,7 @@ ctx_mmio_exec:
        // set transfer base back to the current context
        ctx_mmio_done:
        ld b32 $r3 D[$r0 + #ctx_current]
-       iowr I[$r2 + 0x000] $r3         // MEM_BASE
+       nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
 
        // disable the mmio list now, we don't need/want to execute it again
        st b32 D[$r0 + #chan_mmio_count] $r0
@@ -610,12 +586,10 @@ ctx_mmio_exec:
 //
 ctx_xfer:
        // according to mwk, some kind of wait for idle
-       mov $r15 0xc00
-       shl b32 $r15 6
        mov $r14 4
-       iowr I[$r15 + 0x200] $r14
+       nv_iowr(0x409c08, 0, $r14)
        ctx_xfer_idle:
-               iord $r14 I[$r15 + 0x000]
+               nv_iord($r14, 0x409c00, 0)
                and $r14 0x2000
                bra ne #ctx_xfer_idle
 
@@ -623,50 +597,42 @@ ctx_xfer:
        bra $p2 #ctx_xfer_pre_load
        ctx_xfer_pre:
                mov $r15 0x10
-               call #ctx_86c
+               call(ctx_86c)
 #if CHIPSET < GK100
-               call #ctx_4160s
+               call(ctx_4160s)
 #endif
                bra not $p1 #ctx_xfer_exec
 
        ctx_xfer_pre_load:
                mov $r15 2
-               call #ctx_4170s
-               call #ctx_4170w
-               call #ctx_redswitch
+               call(ctx_4170s)
+               call(ctx_4170w)
+               call(ctx_redswitch)
                clear b32 $r15
-               call #ctx_4170s
-               call #ctx_load
+               call(ctx_4170s)
+               call(ctx_load)
 
        // fetch context pointer, and initiate xfer on all GPCs
        ctx_xfer_exec:
        ld b32 $r1 D[$r0 + #ctx_current]
-       mov $r2 0x414
-       shl b32 $r2 6
-       iowr I[$r2 + 0x000] $r0 // BAR_STATUS = reset
-       mov $r14 -0x5b00
-       sethi $r14 0x410000
-       mov b32 $r15 $r1
-       call #nv_wr32           // GPC_BCAST_WRCMD_DATA = ctx pointer
-       add b32 $r14 4
+
+       clear b32 $r2
+       nv_iowr(NV_PGRAPH_FECS_BAR, 0, $r2)
+
+       nv_wr32(0x41a500, $r1)  // GPC_BCAST_WRCMD_DATA = ctx pointer
        xbit $r15 $flags $p1
        xbit $r2 $flags $p2
        shl b32 $r2 1
        or $r15 $r2
-       call #nv_wr32           // GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
+       nv_wr32(0x41a504, $r15) // GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
 
        // strands
-       mov $r1 0x4afc
-       sethi $r1 0x20000
-       mov $r2 0xc
-       iowr I[$r1] $r2         // STRAND_CMD(0x3f) = 0x0c
-       call #strand_wait
-       mov $r2 0x47fc
-       sethi $r2 0x20000
-       iowr I[$r2] $r0         // STRAND_FIRST_GENE(0x3f) = 0x00
-       xbit $r2 $flags $p1
-       add b32 $r2 3
-       iowr I[$r1] $r2         // STRAND_CMD(0x3f) = 0x03/0x04 (SAVE/LOAD)
+       call(strand_pre)
+       clear b32 $r2
+       nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r2)
+       xbit $r2 $flags $p1     // SAVE/LOAD
+       add b32 $r2 NV_PGRAPH_FECS_STRAND_CMD_SAVE
+       nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r2)
 
        // mmio context
        xbit $r10 $flags $p1    // direction
@@ -675,48 +641,42 @@ ctx_xfer:
        ld b32 $r12 D[$r0 + #hub_mmio_list_head]
        ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
        mov $r14 0              // not multi
-       call #mmctx_xfer
+       call(mmctx_xfer)
 
        // wait for GPCs to all complete
        mov $r10 8              // DONE_BAR
-       call #wait_doneo
+       call(wait_doneo)
 
        // wait for strand xfer to complete
-       call #strand_wait
+       call(strand_wait)
 
        // post-op
        bra $p1 #ctx_xfer_post
                mov $r10 12             // DONE_UNK12
-               call #wait_donez
-               mov $r1 0xa10
-               shl b32 $r1 6
-               mov $r2 5
-               iowr I[$r1] $r2         // MEM_CMD
-               ctx_xfer_post_save_wait:
-                       iord $r2 I[$r1]
-                       or $r2 $r2
-                       bra ne #ctx_xfer_post_save_wait
+               call(wait_donez)
+               mov $r15 5 // MEM_CMD 5 ???
+               call(ctx_mem)
 
        bra $p2 #ctx_xfer_done
        ctx_xfer_post:
                mov $r15 2
-               call #ctx_4170s
+               call(ctx_4170s)
                clear b32 $r15
-               call #ctx_86c
-               call #strand_post
-               call #ctx_4170w
+               call(ctx_86c)
+               call(strand_post)
+               call(ctx_4170w)
                clear b32 $r15
-               call #ctx_4170s
+               call(ctx_4170s)
 
                bra not $p1 #ctx_xfer_no_post_mmio
                ld b32 $r1 D[$r0 + #chan_mmio_count]
                or $r1 $r1
                bra e #ctx_xfer_no_post_mmio
-                       call #ctx_mmio_exec
+                       call(ctx_mmio_exec)
 
                ctx_xfer_no_post_mmio:
 #if CHIPSET < GK100
-               call #ctx_4160c
+               call(ctx_4160c)
 #endif
 
        ctx_xfer_done:
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5
new file mode 100644 (file)
index 0000000..7c5d256
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * 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 <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK208
+#include "macros.fuc"
+
+.section #nv108_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #nv108_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h
new file mode 100644 (file)
index 0000000..4750984
--- /dev/null
@@ -0,0 +1,916 @@
+uint32_t nv108_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+       0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+       0x00000304,
+/* 0x0008: gpc_count */
+       0x00000000,
+/* 0x000c: rop_count */
+       0x00000000,
+/* 0x0010: cmd_queue */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0058: ctx_current */
+       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,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+       0x00000000,
+/* 0x0104: chan_mmio_address */
+       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,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0200: xfer_data */
+       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,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+/* 0x0300: hub_mmio_list_base */
+       0x0417e91c,
+};
+
+uint32_t nv108_grhub_code[] = {
+       0x030e0ef5,
+/* 0x0004: queue_put */
+       0x9800d898,
+       0x86f001d9,
+       0xf489a408,
+       0x020f0b1b,
+       0x0002f87e,
+/* 0x001a: queue_put_next */
+       0x98c400f8,
+       0x0384b607,
+       0xb6008dbb,
+       0x8eb50880,
+       0x018fb500,
+       0xf00190b6,
+       0xd9b50f94,
+/* 0x0037: queue_get */
+       0xf400f801,
+       0xd8980131,
+       0x01d99800,
+       0x0bf489a4,
+       0x0789c421,
+       0xbb0394b6,
+       0x90b6009d,
+       0x009e9808,
+       0xb6019f98,
+       0x84f00180,
+       0x00d8b50f,
+/* 0x0063: queue_get_done */
+       0xf80132f4,
+/* 0x0065: nv_rd32 */
+       0xf0ecb200,
+       0x00801fc9,
+       0x0cf601ca,
+/* 0x0073: nv_rd32_wait */
+       0x8c04bd00,
+       0xcf01ca00,
+       0xccc800cc,
+       0xf61bf41f,
+       0xec7e060a,
+       0x008f0000,
+       0xffcf01cb,
+/* 0x008f: nv_wr32 */
+       0x8000f800,
+       0xf601cc00,
+       0x04bd000f,
+       0xc9f0ecb2,
+       0x1ec9f01f,
+       0x01ca0080,
+       0xbd000cf6,
+/* 0x00a9: nv_wr32_wait */
+       0xca008c04,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f61b,
+/* 0x00b8: wait_donez */
+       0x99f094bd,
+       0x37008000,
+       0x0009f602,
+       0x008004bd,
+       0x0af60206,
+/* 0x00cf: wait_donez_ne */
+       0x8804bd00,
+       0xcf010000,
+       0x8aff0088,
+       0xf61bf488,
+       0x99f094bd,
+       0x17008000,
+       0x0009f602,
+       0x00f804bd,
+/* 0x00ec: wait_doneo */
+       0x99f094bd,
+       0x37008000,
+       0x0009f602,
+       0x008004bd,
+       0x0af60206,
+/* 0x0103: wait_doneo_e */
+       0x8804bd00,
+       0xcf010000,
+       0x8aff0088,
+       0xf60bf488,
+       0x99f094bd,
+       0x17008000,
+       0x0009f602,
+       0x00f804bd,
+/* 0x0120: mmctx_size */
+/* 0x0122: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0x1bf4efa4,
+       0xf89fb2ec,
+/* 0x013d: mmctx_xfer */
+       0xf094bd00,
+       0x00800199,
+       0x09f60237,
+       0xbd04bd00,
+       0x05bbfd94,
+       0x800f0bf4,
+       0xf601c400,
+       0x04bd000b,
+/* 0x015f: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0xc6008018,
+       0x000ef601,
+       0x008004bd,
+       0x0ff601c7,
+       0xf004bd00,
+/* 0x017a: mmctx_multi_disabled */
+       0xabc80199,
+       0x10b4b600,
+       0xc80cb9f0,
+       0xe4b601ae,
+       0x05befd11,
+       0x01c50080,
+       0xbd000bf6,
+/* 0x0195: mmctx_exec_loop */
+/* 0x0195: mmctx_wait_free */
+       0xc5008e04,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f60b,
+       0x05e9fd00,
+       0x01c80080,
+       0xbd000ef6,
+       0x04c0b604,
+       0x1bf4cda4,
+       0x02abc8df,
+/* 0x01bf: mmctx_fini_wait */
+       0x8b1c1bf4,
+       0xcf01c500,
+       0xb4f000bb,
+       0x10b4b01f,
+       0x0af31bf4,
+       0x00b87e02,
+       0x250ef400,
+/* 0x01d8: mmctx_stop */
+       0xb600abc8,
+       0xb9f010b4,
+       0x12b9f00c,
+       0x01c50080,
+       0xbd000bf6,
+/* 0x01ed: mmctx_stop_wait */
+       0xc5008b04,
+       0x00bbcf01,
+       0xf412bbc8,
+/* 0x01fa: mmctx_done */
+       0x94bdf61b,
+       0x800199f0,
+       0xf6021700,
+       0x04bd0009,
+/* 0x020a: strand_wait */
+       0xa0f900f8,
+       0xb87e020a,
+       0xa0fc0000,
+/* 0x0216: strand_pre */
+       0x0c0900f8,
+       0x024afc80,
+       0xbd0009f6,
+       0x020a7e04,
+/* 0x0227: strand_post */
+       0x0900f800,
+       0x4afc800d,
+       0x0009f602,
+       0x0a7e04bd,
+       0x00f80002,
+/* 0x0238: strand_set */
+       0xfc800f0c,
+       0x0cf6024f,
+       0x0c04bd00,
+       0x4afc800b,
+       0x000cf602,
+       0xfc8004bd,
+       0x0ef6024f,
+       0x0c04bd00,
+       0x4afc800a,
+       0x000cf602,
+       0x0a7e04bd,
+       0x00f80002,
+/* 0x0268: strand_ctx_init */
+       0x99f094bd,
+       0x37008003,
+       0x0009f602,
+       0x167e04bd,
+       0x030e0002,
+       0x0002387e,
+       0xfc80c4bd,
+       0x0cf60247,
+       0x0c04bd00,
+       0x4afc8001,
+       0x000cf602,
+       0x0a7e04bd,
+       0x0c920002,
+       0x46fc8001,
+       0x000cf602,
+       0x020c04bd,
+       0x024afc80,
+       0xbd000cf6,
+       0x020a7e04,
+       0x02277e00,
+       0x42008800,
+       0x20008902,
+       0x0099cf02,
+/* 0x02c7: ctx_init_strand_loop */
+       0xf608fe95,
+       0x8ef6008e,
+       0x808acf40,
+       0xb606a5b6,
+       0xeabb01a0,
+       0x0480b600,
+       0xf40192b6,
+       0xe4b6e81b,
+       0xf2efbc08,
+       0x99f094bd,
+       0x17008003,
+       0x0009f602,
+       0x00f804bd,
+/* 0x02f8: error */
+       0x02050080,
+       0xbd000ff6,
+       0x80010f04,
+       0xf6030700,
+       0x04bd000f,
+/* 0x030e: init */
+       0x04bd00f8,
+       0x410007fe,
+       0x11cf4200,
+       0x0911e700,
+       0x0814b601,
+       0x020014fe,
+       0x12004002,
+       0xbd0002f6,
+       0x05c94104,
+       0xbd0010fe,
+       0x07004024,
+       0xbd0002f6,
+       0x20034204,
+       0x01010080,
+       0xbd0002f6,
+       0x20044204,
+       0x01010480,
+       0xbd0002f6,
+       0x200b4204,
+       0x01010880,
+       0xbd0002f6,
+       0x200c4204,
+       0x01011c80,
+       0xbd0002f6,
+       0x01039204,
+       0x03090080,
+       0xbd0003f6,
+       0x87044204,
+       0xf6040040,
+       0x04bd0002,
+       0x00400402,
+       0x0002f603,
+       0x31f404bd,
+       0x96048e10,
+       0x00657e40,
+       0xc7feb200,
+       0x01b590f1,
+       0x1ff4f003,
+       0x01020fb5,
+       0x041fbb01,
+       0x800112b6,
+       0xf6010300,
+       0x04bd0001,
+       0x01040080,
+       0xbd0001f6,
+       0x01004104,
+       0x627e020f,
+       0x717e0006,
+       0x100f0006,
+       0x0006b37e,
+       0x98000e98,
+       0x207e010f,
+       0x14950001,
+       0xc0008008,
+       0x0004f601,
+       0x008004bd,
+       0x04f601c1,
+       0xb704bd00,
+       0xbb130030,
+       0xf5b6001f,
+       0xd3008002,
+       0x000ff601,
+       0x15b604bd,
+       0x0110b608,
+       0xb20814b6,
+       0x02687e1f,
+       0x001fbb00,
+       0x84020398,
+/* 0x041f: init_gpc */
+       0xb8502000,
+       0x0008044e,
+       0x8f7e1fb2,
+       0x4eb80000,
+       0xbd00010c,
+       0x008f7ef4,
+       0x044eb800,
+       0x8f7e0001,
+       0x4eb80000,
+       0x0f000100,
+       0x008f7e02,
+       0x004eb800,
+/* 0x044e: init_gpc_wait */
+       0x657e0008,
+       0xffc80000,
+       0xf90bf41f,
+       0x08044eb8,
+       0x00657e00,
+       0x001fbb00,
+       0x800040b7,
+       0xf40132b6,
+       0x000fb41b,
+       0x0006b37e,
+       0x627e000f,
+       0x00800006,
+       0x01f60201,
+       0xbd04bd00,
+       0x1f19f014,
+       0x02300080,
+       0xbd0001f6,
+/* 0x0491: main */
+       0x0031f404,
+       0x0d0028f4,
+       0x00377e10,
+       0xf401f400,
+       0x4001e4b1,
+       0x00c71bf5,
+       0x99f094bd,
+       0x37008004,
+       0x0009f602,
+       0x008104bd,
+       0x11cf02c0,
+       0xc1008200,
+       0x0022cf02,
+       0xf41f13c8,
+       0x23c8770b,
+       0x550bf41f,
+       0x12b220f9,
+       0x99f094bd,
+       0x37008007,
+       0x0009f602,
+       0x32f404bd,
+       0x0231f401,
+       0x0008367e,
+       0x99f094bd,
+       0x17008007,
+       0x0009f602,
+       0x20fc04bd,
+       0x99f094bd,
+       0x37008006,
+       0x0009f602,
+       0x31f404bd,
+       0x08367e01,
+       0xf094bd00,
+       0x00800699,
+       0x09f60217,
+       0xf404bd00,
+/* 0x0522: chsw_prev_no_next */
+       0x20f92f0e,
+       0x32f412b2,
+       0x0232f401,
+       0x0008367e,
+       0x008020fc,
+       0x02f602c0,
+       0xf404bd00,
+/* 0x053e: chsw_no_prev */
+       0x23c8130e,
+       0x0d0bf41f,
+       0xf40131f4,
+       0x367e0232,
+/* 0x054e: chsw_done */
+       0x01020008,
+       0x02c30080,
+       0xbd0002f6,
+       0xf094bd04,
+       0x00800499,
+       0x09f60217,
+       0xf504bd00,
+/* 0x056b: main_not_ctx_switch */
+       0xb0ff2a0e,
+       0x1bf401e4,
+       0x7ef2b20c,
+       0xf40007d6,
+/* 0x057a: main_not_ctx_chan */
+       0xe4b0400e,
+       0x2c1bf402,
+       0x99f094bd,
+       0x37008007,
+       0x0009f602,
+       0x32f404bd,
+       0x0232f401,
+       0x0008367e,
+       0x99f094bd,
+       0x17008007,
+       0x0009f602,
+       0x0ef404bd,
+/* 0x05a9: main_not_ctx_save */
+       0x10ef9411,
+       0x7e01f5f0,
+       0xf50002f8,
+/* 0x05b7: main_done */
+       0xbdfede0e,
+       0x1f29f024,
+       0x02300080,
+       0xbd0002f6,
+       0xcc0ef504,
+/* 0x05c9: ih */
+       0xfe80f9fe,
+       0x80f90188,
+       0xa0f990f9,
+       0xd0f9b0f9,
+       0xf0f9e0f9,
+       0x004a04bd,
+       0x00aacf02,
+       0xf404abc4,
+       0x100d230b,
+       0xcf1a004e,
+       0x004f00ee,
+       0x00ffcf19,
+       0x0000047e,
+       0x0400b0b7,
+       0x0040010e,
+       0x000ef61d,
+/* 0x060a: ih_no_fifo */
+       0xabe404bd,
+       0x0bf40100,
+       0x4e100d0c,
+       0x047e4001,
+/* 0x061a: ih_no_ctxsw */
+       0xabe40000,
+       0x0bf40400,
+       0x01004b10,
+       0x448ebfb2,
+       0x8f7e4001,
+/* 0x062e: ih_no_fwmthd */
+       0x044b0000,
+       0xffb0bd01,
+       0x0bf4b4ab,
+       0x0700800c,
+       0x000bf603,
+/* 0x0642: ih_no_other */
+       0x004004bd,
+       0x000af601,
+       0xf0fc04bd,
+       0xd0fce0fc,
+       0xa0fcb0fc,
+       0x80fc90fc,
+       0xfc0088fe,
+       0x0032f480,
+/* 0x0662: ctx_4170s */
+       0xf5f001f8,
+       0x8effb210,
+       0x7e404170,
+       0xf800008f,
+/* 0x0671: ctx_4170w */
+       0x41708e00,
+       0x00657e40,
+       0xf0ffb200,
+       0x1bf410f4,
+/* 0x0683: ctx_redswitch */
+       0x4e00f8f3,
+       0xe5f00200,
+       0x20e5f040,
+       0x8010e5f0,
+       0xf6018500,
+       0x04bd000e,
+/* 0x069a: ctx_redswitch_delay */
+       0xf2b6080f,
+       0xfd1bf401,
+       0x0400e5f1,
+       0x0100e5f1,
+       0x01850080,
+       0xbd000ef6,
+/* 0x06b3: ctx_86c */
+       0x8000f804,
+       0xf6022300,
+       0x04bd000f,
+       0x148effb2,
+       0x8f7e408a,
+       0xffb20000,
+       0x41a88c8e,
+       0x00008f7e,
+/* 0x06d2: ctx_mem */
+       0x008000f8,
+       0x0ff60284,
+/* 0x06db: ctx_mem_wait */
+       0x8f04bd00,
+       0xcf028400,
+       0xfffd00ff,
+       0xf61bf405,
+/* 0x06ea: ctx_load */
+       0x94bd00f8,
+       0x800599f0,
+       0xf6023700,
+       0x04bd0009,
+       0xb87e0c0a,
+       0xf4bd0000,
+       0x02890080,
+       0xbd000ff6,
+       0xc1008004,
+       0x0002f602,
+       0x008004bd,
+       0x02f60283,
+       0x0f04bd00,
+       0x06d27e07,
+       0xc0008000,
+       0x0002f602,
+       0x0bfe04bd,
+       0x1f2af000,
+       0xb60424b6,
+       0x94bd0220,
+       0x800899f0,
+       0xf6023700,
+       0x04bd0009,
+       0x02810080,
+       0xbd0002f6,
+       0x0000d204,
+       0x25f08000,
+       0x88008002,
+       0x0002f602,
+       0x100104bd,
+       0xf0020042,
+       0x12fa0223,
+       0xbd03f805,
+       0x0899f094,
+       0x02170080,
+       0xbd0009f6,
+       0x81019804,
+       0x981814b6,
+       0x25b68002,
+       0x0512fd08,
+       0xbd1601b5,
+       0x0999f094,
+       0x02370080,
+       0xbd0009f6,
+       0x81008004,
+       0x0001f602,
+       0x010204bd,
+       0x02880080,
+       0xbd0002f6,
+       0x01004104,
+       0xfa0613f0,
+       0x03f80501,
+       0x99f094bd,
+       0x17008009,
+       0x0009f602,
+       0x94bd04bd,
+       0x800599f0,
+       0xf6021700,
+       0x04bd0009,
+/* 0x07d6: ctx_chan */
+       0xea7e00f8,
+       0x0c0a0006,
+       0x0000b87e,
+       0xd27e050f,
+       0x00f80006,
+/* 0x07e8: ctx_mmio_exec */
+       0x80410398,
+       0xf6028100,
+       0x04bd0003,
+/* 0x07f6: ctx_mmio_loop */
+       0x34c434bd,
+       0x0e1bf4ff,
+       0xf0020045,
+       0x35fa0653,
+/* 0x0807: ctx_mmio_pull */
+       0x9803f805,
+       0x4f98804e,
+       0x008f7e81,
+       0x0830b600,
+       0xf40112b6,
+/* 0x081a: ctx_mmio_done */
+       0x0398df1b,
+       0x81008016,
+       0x0003f602,
+       0x00b504bd,
+       0x01004140,
+       0xfa0613f0,
+       0x03f80601,
+/* 0x0836: ctx_xfer */
+       0x040e00f8,
+       0x03020080,
+       0xbd000ef6,
+/* 0x0841: ctx_xfer_idle */
+       0x00008e04,
+       0x00eecf03,
+       0x2000e4f1,
+       0xf4f51bf4,
+       0x02f40611,
+/* 0x0855: ctx_xfer_pre */
+       0x7e100f0c,
+       0xf40006b3,
+/* 0x085e: ctx_xfer_pre_load */
+       0x020f1b11,
+       0x0006627e,
+       0x0006717e,
+       0x0006837e,
+       0x627ef4bd,
+       0xea7e0006,
+/* 0x0876: ctx_xfer_exec */
+       0x01980006,
+       0x8024bd16,
+       0xf6010500,
+       0x04bd0002,
+       0x008e1fb2,
+       0x8f7e41a5,
+       0xfcf00000,
+       0x022cf001,
+       0xfd0124b6,
+       0xffb205f2,
+       0x41a5048e,
+       0x00008f7e,
+       0x0002167e,
+       0xfc8024bd,
+       0x02f60247,
+       0xf004bd00,
+       0x20b6012c,
+       0x4afc8003,
+       0x0002f602,
+       0xacf004bd,
+       0x06a5f001,
+       0x0c98000b,
+       0x010d9800,
+       0x3d7e000e,
+       0x080a0001,
+       0x0000ec7e,
+       0x00020a7e,
+       0x0a1201f4,
+       0x00b87e0c,
+       0x7e050f00,
+       0xf40006d2,
+/* 0x08f2: ctx_xfer_post */
+       0x020f2d02,
+       0x0006627e,
+       0xb37ef4bd,
+       0x277e0006,
+       0x717e0002,
+       0xf4bd0006,
+       0x0006627e,
+       0x981011f4,
+       0x11fd4001,
+       0x070bf405,
+       0x0007e87e,
+/* 0x091c: ctx_xfer_no_post_mmio */
+/* 0x091c: ctx_xfer_done */
+       0x000000f8,
+       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,
+};
index b59f694c0423e35afddc26e2388ae8a7d6514472..132f684b1946a9357697eace024fa866af43b72f 100644 (file)
@@ -206,14 +206,14 @@ uint32_t nvc0_grhub_data[] = {
 };
 
 uint32_t nvc0_grhub_code[] = {
-       0x031b0ef5,
+       0x039b0ef5,
 /* 0x0004: queue_put */
        0x9800d898,
        0x86f001d9,
        0x0489b808,
        0xf00c1bf4,
        0x21f502f7,
-       0x00f802fe,
+       0x00f8037e,
 /* 0x001c: queue_put_next */
        0xb60798c4,
        0x8dbb0384,
@@ -237,184 +237,214 @@ uint32_t nvc0_grhub_code[] = {
 /* 0x0066: queue_get_done */
        0x00f80132,
 /* 0x0068: nv_rd32 */
-       0x0728b7f1,
-       0xb906b4b6,
-       0xc9f002ec,
-       0x00bcd01f,
-/* 0x0078: nv_rd32_wait */
-       0xc800bccf,
-       0x1bf41fcc,
-       0x06a7f0fa,
-       0x010921f5,
-       0xf840bfcf,
-/* 0x008d: nv_wr32 */
-       0x28b7f100,
-       0x06b4b607,
-       0xb980bfd0,
-       0xc9f002ec,
-       0x1ec9f01f,
-/* 0x00a3: nv_wr32_wait */
-       0xcf00bcd0,
-       0xccc800bc,
-       0xfa1bf41f,
-/* 0x00ae: watchdog_reset */
-       0x87f100f8,
-       0x84b60430,
-       0x1ff9f006,
-       0xf8008fd0,
-/* 0x00bd: watchdog_clear */
-       0x3087f100,
-       0x0684b604,
-       0xf80080d0,
-/* 0x00c9: wait_donez */
-       0xf094bd00,
-       0x07f10099,
-       0x03f00f00,
-       0x0009d002,
-       0x07f104bd,
-       0x03f00600,
-       0x000ad002,
-/* 0x00e6: wait_donez_ne */
-       0x87f104bd,
-       0x83f00000,
-       0x0088cf01,
-       0xf4888aff,
-       0x94bdf31b,
-       0xf10099f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0109: wait_doneo */
-       0xf094bd00,
+       0xf002ecb9,
+       0x07f11fc9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x007a: nv_rd32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0xa7f0f31b,
+       0x1021f506,
+       0x00f7f101,
+       0x01f3f0cb,
+       0xf800ffcf,
+/* 0x009d: nv_wr32 */
+       0x0007f100,
+       0x0103f0cc,
+       0xbd000fd0,
+       0x02ecb904,
+       0xf01fc9f0,
+       0x07f11ec9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x00be: nv_wr32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f31b,
+/* 0x00d0: wait_donez */
+       0x99f094bd,
+       0x0007f100,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x1bf4888a,
+       0xf094bdf3,
        0x07f10099,
-       0x03f00f00,
+       0x03f01700,
        0x0009d002,
-       0x87f104bd,
-       0x84b60818,
-       0x008ad006,
-/* 0x0124: wait_doneo_e */
-       0x040087f1,
-       0xcf0684b6,
-       0x8aff0088,
-       0xf30bf488,
+       0x00f804bd,
+/* 0x0110: wait_doneo */
        0x99f094bd,
        0x0007f100,
-       0x0203f017,
+       0x0203f00f,
        0xbd0009d0,
-/* 0x0147: mmctx_size */
-       0xbd00f804,
-/* 0x0149: nv_mmctx_size_loop */
-       0x00e89894,
-       0xb61a85b6,
-       0x84b60180,
-       0x0098bb02,
-       0xb804e0b6,
-       0x1bf404ef,
-       0x029fb9eb,
-/* 0x0166: mmctx_xfer */
-       0x94bd00f8,
-       0xf10199f0,
-       0xf00f0007,
-       0x09d00203,
-       0xf104bd00,
-       0xb6071087,
-       0x94bd0684,
-       0xf405bbfd,
-       0x8bd0090b,
-       0x0099f000,
-/* 0x018c: mmctx_base_disabled */
-       0xf405eefd,
-       0x8ed00c0b,
-       0xc08fd080,
-/* 0x019b: mmctx_multi_disabled */
-       0xb70199f0,
-       0xc8010080,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x0bf4888a,
+       0xf094bdf3,
+       0x07f10099,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0xf404efb8,
+       0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+       0xbd00f802,
+       0x0199f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0xbbfd94bd,
+       0x120bf405,
+       0xc40007f1,
+       0xd00103f0,
+       0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0x0007f11e,
+       0x0103f0c6,
+       0xbd000ed0,
+       0x0007f104,
+       0x0103f0c7,
+       0xbd000fd0,
+       0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+       0xb600abc8,
+       0xb9f010b4,
+       0x01aec80c,
+       0xfd11e4b6,
+       0x07f105be,
+       0x03f0c500,
+       0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+       0xe7f104bd,
+       0xe3f0c500,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f30b,
+       0x05e9fd00,
+       0xc80007f1,
+       0xd00103f0,
+       0x04bd000e,
+       0xb804c0b6,
+       0x1bf404cd,
+       0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+       0xf11f1bf4,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x1fb4f000,
+       0xf410b4b0,
+       0xa7f0f01b,
+       0xd021f402,
+/* 0x0223: mmctx_stop */
+       0xc82b0ef4,
        0xb4b600ab,
        0x0cb9f010,
-       0xb601aec8,
-       0xbefd11e4,
-       0x008bd005,
-/* 0x01b4: mmctx_exec_loop */
-/* 0x01b4: mmctx_wait_free */
-       0xf0008ecf,
-       0x0bf41fe4,
-       0x00ce98fa,
-       0xd005e9fd,
-       0xc0b6c08e,
-       0x04cdb804,
-       0xc8e81bf4,
-       0x1bf402ab,
-/* 0x01d5: mmctx_fini_wait */
-       0x008bcf18,
-       0xb01fb4f0,
-       0x1bf410b4,
-       0x02a7f0f7,
-       0xf4c921f4,
-/* 0x01ea: mmctx_stop */
-       0xabc81b0e,
-       0x10b4b600,
-       0xf00cb9f0,
-       0x8bd012b9,
-/* 0x01f9: mmctx_stop_wait */
-       0x008bcf00,
-       0xf412bbc8,
-/* 0x0202: mmctx_done */
-       0x94bdfa1b,
-       0xf10199f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0215: strand_wait */
-       0xf0a0f900,
-       0x21f402a7,
-       0xf8a0fcc9,
-/* 0x0221: strand_pre */
-       0xfc87f100,
-       0x0283f04a,
-       0xd00c97f0,
-       0x21f50089,
-       0x00f80215,
-/* 0x0234: strand_post */
-       0x4afc87f1,
-       0xf00283f0,
-       0x89d00d97,
-       0x1521f500,
-/* 0x0247: strand_set */
-       0xf100f802,
-       0xf04ffca7,
-       0xaba202a3,
-       0xc7f00500,
-       0x00acd00f,
-       0xd00bc7f0,
-       0x21f500bc,
-       0xaed00215,
-       0x0ac7f000,
-       0xf500bcd0,
-       0xf8021521,
-/* 0x0271: strand_ctx_init */
-       0xf094bd00,
-       0x07f10399,
-       0x03f00f00,
+       0xf112b9f0,
+       0xf0c50007,
+       0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+       0xf104bd00,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x12bbc800,
+/* 0x024b: mmctx_done */
+       0xbdf31bf4,
+       0x0199f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x025e: strand_wait */
+       0xa0f900f8,
+       0xf402a7f0,
+       0xa0fcd021,
+/* 0x026a: strand_pre */
+       0x97f000f8,
+       0xfc07f10c,
+       0x0203f04a,
+       0xbd0009d0,
+       0x5e21f504,
+/* 0x027f: strand_post */
+       0xf000f802,
+       0x07f10d97,
+       0x03f04afc,
        0x0009d002,
        0x21f504bd,
-       0xe7f00221,
-       0x4721f503,
-       0xfca7f102,
-       0x02a3f046,
-       0x0400aba0,
-       0xf040a0d0,
-       0xbcd001c7,
-       0x1521f500,
-       0x010c9202,
-       0xf000acd0,
-       0xbcd002c7,
-       0x1521f500,
-       0x3421f502,
-       0x8087f102,
-       0x0684b608,
-       0xb70089cf,
-       0x95220080,
-/* 0x02ca: ctx_init_strand_loop */
+       0x00f8025e,
+/* 0x0294: strand_set */
+       0xf10fc7f0,
+       0xf04ffc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f10bc7,
+       0x03f04afc,
+       0x000cd002,
+       0x07f104bd,
+       0x03f04ffc,
+       0x000ed002,
+       0xc7f004bd,
+       0xfc07f10a,
+       0x0203f04a,
+       0xbd000cd0,
+       0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+       0xbd00f802,
+       0x0399f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0x026a21f5,
+       0xf503e7f0,
+       0xbd029421,
+       0xfc07f1c4,
+       0x0203f047,
+       0xbd000cd0,
+       0x01c7f004,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd000c,
+       0x025e21f5,
+       0xf1010c92,
+       0xf046fc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f102c7,
+       0x03f04afc,
+       0x000cd002,
+       0x21f504bd,
+       0x21f5025e,
+       0x87f1027f,
+       0x83f04200,
+       0x0097f102,
+       0x0293f020,
+       0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
        0x8ed008fe,
        0x408ed000,
        0xb6808acf,
@@ -428,7 +458,7 @@ uint32_t nvc0_grhub_code[] = {
        0x170007f1,
        0xd00203f0,
        0x04bd0009,
-/* 0x02fe: error */
+/* 0x037e: error */
        0x07f100f8,
        0x03f00500,
        0x000fd002,
@@ -436,82 +466,117 @@ uint32_t nvc0_grhub_code[] = {
        0x0007f101,
        0x0303f007,
        0xbd000fd0,
-/* 0x031b: init */
+/* 0x039b: init */
        0xbd00f804,
-       0x0004fe04,
-       0xf10007fe,
-       0xf0120017,
-       0x12d00227,
-       0xb117f100,
-       0x0010fe05,
-       0x040017f1,
-       0xf1c010d0,
-       0xb6040437,
-       0x27f10634,
-       0x32d02003,
-       0x0427f100,
-       0x0132d020,
+       0x0007fe04,
+       0x420017f1,
+       0xcf0013f0,
+       0x11e70011,
+       0x14b60109,
+       0x0014fe08,
+       0xf10227f0,
+       0xf0120007,
+       0x02d00003,
+       0xf104bd00,
+       0xfe06c817,
+       0x24bd0010,
+       0x070007f1,
+       0xd00003f0,
+       0x04bd0002,
+       0x200327f1,
+       0x010007f1,
+       0xd00103f0,
+       0x04bd0002,
+       0x200427f1,
+       0x010407f1,
+       0xd00103f0,
+       0x04bd0002,
        0x200b27f1,
-       0xf10232d0,
-       0xd0200c27,
-       0x27f10732,
-       0x24b60c24,
-       0x0003b906,
-       0xf10023d0,
+       0x010807f1,
+       0xd00103f0,
+       0x04bd0002,
+       0x200c27f1,
+       0x011c07f1,
+       0xd00103f0,
+       0x04bd0002,
+       0xf1010392,
+       0xf0090007,
+       0x03d00303,
+       0xf104bd00,
        0xf0870427,
-       0x12d00023,
-       0x0012b700,
-       0x0427f001,
-       0xf40012d0,
-       0xe7f11031,
-       0xe3f09604,
-       0x6821f440,
-       0x8090f1c7,
-       0xf4f00301,
-       0x020f801f,
-       0xbb0117f0,
-       0x12b6041f,
-       0x0c27f101,
-       0x0624b604,
-       0xd00021d0,
-       0x17f14021,
-       0x0e980100,
-       0x010f9800,
-       0x014721f5,
-       0x070037f1,
-       0x950634b6,
-       0x34d00814,
-       0x4034d000,
-       0x130030b7,
-       0xb6001fbb,
-       0x3fd002f5,
-       0x0815b600,
-       0xb60110b6,
-       0x1fb90814,
-       0x7121f502,
-       0x001fbb02,
-       0xf1020398,
-       0xf0200047,
-/* 0x03f6: init_gpc */
-       0x4ea05043,
-       0x1fb90804,
-       0x8d21f402,
-       0x010c4ea0,
-       0x21f4f4bd,
-       0x044ea08d,
-       0x8d21f401,
-       0x01004ea0,
-       0xf402f7f0,
-       0x4ea08d21,
-/* 0x041e: init_gpc_wait */
-       0x21f40800,
-       0x1fffc868,
-       0xa0fa0bf4,
-       0xf408044e,
-       0x1fbb6821,
-       0x0040b700,
-       0x0132b680,
-       0xf1be1bf4,
+       0x07f10023,
+       0x03f00400,
+       0x0002d000,
+       0x27f004bd,
+       0x0007f104,
+       0x0003f003,
+       0xbd0002d0,
+       0x1031f404,
+       0x9604e7f1,
+       0xf440e3f0,
+       0xfeb96821,
+       0x90f1c702,
+       0xf0030180,
+       0x0f801ff4,
+       0x0117f002,
+       0xb6041fbb,
+       0x07f10112,
+       0x03f00300,
+       0x0001d001,
+       0x07f104bd,
+       0x03f00400,
+       0x0001d001,
+       0x17f104bd,
+       0xf7f00100,
+       0xb521f502,
+       0xc721f507,
+       0x10f7f007,
+       0x081421f5,
+       0x98000e98,
+       0x21f5010f,
+       0x14950150,
+       0x0007f108,
+       0x0103f0c0,
+       0xbd0004d0,
+       0x0007f104,
+       0x0103f0c1,
+       0xbd0004d0,
+       0x0030b704,
+       0x001fbb13,
+       0xf102f5b6,
+       0xf0d30007,
+       0x0fd00103,
+       0xb604bd00,
+       0x10b60815,
+       0x0814b601,
+       0xf5021fb9,
+       0xbb02d321,
+       0x0398001f,
+       0x0047f102,
+       0x5043f020,
+/* 0x04f4: init_gpc */
+       0x08044ea0,
+       0xf4021fb9,
+       0x4ea09d21,
+       0xf4bd010c,
+       0xa09d21f4,
+       0xf401044e,
+       0x4ea09d21,
+       0xf7f00100,
+       0x9d21f402,
+       0x08004ea0,
+/* 0x051c: init_gpc_wait */
+       0xc86821f4,
+       0x0bf41fff,
+       0x044ea0fa,
+       0x6821f408,
+       0xb7001fbb,
+       0xb6800040,
+       0x1bf40132,
+       0x00f7f0be,
+       0x081421f5,
+       0xf500f7f0,
+       0xf107b521,
        0xf0010007,
        0x01d00203,
        0xbd04bd00,
@@ -519,402 +584,399 @@ uint32_t nvc0_grhub_code[] = {
        0x080007f1,
        0xd00203f0,
        0x04bd0001,
-/* 0x0458: main */
+/* 0x0564: main */
        0xf40031f4,
        0xd7f00028,
        0x3921f410,
        0xb1f401f4,
        0xf54001e4,
-       0xbd00de1b,
+       0xbd00e91b,
        0x0499f094,
        0x0f0007f1,
        0xd00203f0,
        0x04bd0009,
-       0x0b0017f1,
-       0xcf0614b6,
-       0x11cf4012,
-       0x1f13c800,
-       0x00870bf5,
-       0xf41f23c8,
-       0x20f9620b,
-       0xbd0212b9,
-       0x0799f094,
-       0x0f0007f1,
-       0xd00203f0,
-       0x04bd0009,
-       0xf40132f4,
-       0x21f50231,
-       0x94bd082f,
+       0xc00017f1,
+       0xcf0213f0,
+       0x27f10011,
+       0x23f0c100,
+       0x0022cf02,
+       0xf51f13c8,
+       0xc800890b,
+       0x0bf41f23,
+       0xb920f962,
+       0x94bd0212,
        0xf10799f0,
-       0xf0170007,
+       0xf00f0007,
        0x09d00203,
-       0xfc04bd00,
-       0xf094bd20,
-       0x07f10699,
-       0x03f00f00,
-       0x0009d002,
-       0x31f404bd,
-       0x2f21f501,
-       0xf094bd08,
-       0x07f10699,
+       0xf404bd00,
+       0x31f40132,
+       0xe821f502,
+       0xf094bd09,
+       0x07f10799,
        0x03f01700,
        0x0009d002,
-       0x0ef404bd,
-/* 0x04f9: chsw_prev_no_next */
-       0xb920f931,
-       0x32f40212,
-       0x0232f401,
-       0x082f21f5,
-       0x17f120fc,
-       0x14b60b00,
-       0x0012d006,
-/* 0x0517: chsw_no_prev */
-       0xc8130ef4,
-       0x0bf41f23,
-       0x0131f40d,
-       0xf50232f4,
-/* 0x0527: chsw_done */
-       0xf1082f21,
-       0xb60b0c17,
-       0x27f00614,
-       0x0012d001,
+       0x20fc04bd,
        0x99f094bd,
-       0x0007f104,
+       0x0007f106,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0131f404,
+       0x09e821f5,
+       0x99f094bd,
+       0x0007f106,
        0x0203f017,
        0xbd0009d0,
-       0x130ef504,
-/* 0x0549: main_not_ctx_switch */
-       0x01e4b0ff,
-       0xb90d1bf4,
-       0x21f502f2,
-       0x0ef407bb,
-/* 0x0559: main_not_ctx_chan */
-       0x02e4b046,
-       0xbd321bf4,
-       0x0799f094,
-       0x0f0007f1,
+       0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+       0x12b920f9,
+       0x0132f402,
+       0xf50232f4,
+       0xfc09e821,
+       0x0007f120,
+       0x0203f0c0,
+       0xbd0002d0,
+       0x130ef404,
+/* 0x062c: chsw_no_prev */
+       0xf41f23c8,
+       0x31f40d0b,
+       0x0232f401,
+       0x09e821f5,
+/* 0x063c: chsw_done */
+       0xf10127f0,
+       0xf0c30007,
+       0x02d00203,
+       0xbd04bd00,
+       0x0499f094,
+       0x170007f1,
        0xd00203f0,
        0x04bd0009,
-       0xf40132f4,
-       0x21f50232,
-       0x94bd082f,
+       0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+       0xf401e4b0,
+       0xf2b90d1b,
+       0x7821f502,
+       0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+       0xf402e4b0,
+       0x94bd321b,
        0xf10799f0,
-       0xf0170007,
+       0xf00f0007,
        0x09d00203,
        0xf404bd00,
-/* 0x058e: main_not_ctx_save */
-       0xef94110e,
-       0x01f5f010,
-       0x02fe21f5,
-       0xfec00ef5,
-/* 0x059c: main_done */
-       0x29f024bd,
-       0x0007f11f,
-       0x0203f008,
-       0xbd0002d0,
-       0xab0ef504,
-/* 0x05b1: ih */
-       0xfe80f9fe,
-       0x80f90188,
-       0xa0f990f9,
-       0xd0f9b0f9,
-       0xf0f9e0f9,
-       0x0acf04bd,
-       0x04abc480,
-       0xf11d0bf4,
-       0xf01900b7,
-       0xbecf10d7,
-       0x00bfcf40,
+       0x32f40132,
+       0xe821f502,
+       0xf094bd09,
+       0x07f10799,
+       0x03f01700,
+       0x0009d002,
+       0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+       0x10ef9411,
+       0xf501f5f0,
+       0xf5037e21,
+/* 0x06b3: main_done */
+       0xbdfeb50e,
+       0x1f29f024,
+       0x080007f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xfea00ef5,
+/* 0x06c8: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x00a7f104,
+       0x00a3f002,
+       0xc400aacf,
+       0x0bf404ab,
+       0x10d7f030,
+       0x1a00e7f1,
+       0xcf00e3f0,
+       0xf7f100ee,
+       0xf3f01900,
+       0x00ffcf00,
        0xb70421f4,
        0xf00400b0,
-       0xbed001e7,
-/* 0x05e9: ih_no_fifo */
-       0x00abe400,
-       0x0d0bf401,
-       0xf110d7f0,
-       0xf44001e7,
-/* 0x05fa: ih_no_ctxsw */
-       0xb7f10421,
-       0xb0bd0104,
-       0xf4b4abff,
-       0xa7f10d0b,
-       0xa4b60c1c,
-       0x00abd006,
-/* 0x0610: ih_no_other */
-       0xfc400ad0,
+       0x07f101e7,
+       0x03f01d00,
+       0x000ed000,
+/* 0x071a: ih_no_fifo */
+       0xabe404bd,
+       0x0bf40100,
+       0x10d7f00d,
+       0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+       0xe40421f4,
+       0xf40400ab,
+       0xb7f1140b,
+       0xbfb90100,
+       0x44e7f102,
+       0x40e3f001,
+/* 0x0743: ih_no_fwmthd */
+       0xf19d21f4,
+       0xbd0104b7,
+       0xb4abffb0,
+       0xf10f0bf4,
+       0xf0070007,
+       0x0bd00303,
+/* 0x075b: ih_no_other */
+       0xf104bd00,
+       0xf0010007,
+       0x0ad00003,
+       0xfc04bd00,
        0xfce0fcf0,
        0xfcb0fcd0,
        0xfc90fca0,
        0x0088fe80,
        0x32f480fc,
-/* 0x062b: ctx_4160s */
-       0xf101f800,
-       0xf04160e7,
-       0xf7f040e3,
-       0x8d21f401,
-/* 0x0638: ctx_4160s_wait */
-       0xc86821f4,
-       0x0bf404ff,
-/* 0x0643: ctx_4160c */
-       0xf100f8fa,
+/* 0x077f: ctx_4160s */
+       0xf001f800,
+       0xffb901f7,
+       0x60e7f102,
+       0x40e3f041,
+/* 0x078f: ctx_4160s_wait */
+       0xf19d21f4,
        0xf04160e7,
-       0xf4bd40e3,
-       0xf88d21f4,
-/* 0x0651: ctx_4170s */
-       0x70e7f100,
+       0x21f440e3,
+       0x02ffb968,
+       0xf404ffc8,
+       0x00f8f00b,
+/* 0x07a4: ctx_4160c */
+       0xffb9f4bd,
+       0x60e7f102,
        0x40e3f041,
-       0xf410f5f0,
-       0x00f88d21,
-/* 0x0660: ctx_4170w */
-       0x4170e7f1,
-       0xf440e3f0,
-       0xf4f06821,
-       0xf31bf410,
-/* 0x0672: ctx_redswitch */
-       0xe7f100f8,
-       0xe4b60614,
-       0x70f7f106,
-       0x00efd002,
-/* 0x0683: ctx_redswitch_delay */
-       0xb608f7f0,
-       0x1bf401f2,
-       0x70f7f1fd,
-       0x00efd007,
-/* 0x0692: ctx_86c */
-       0xe7f100f8,
-       0xe4b6086c,
-       0x00efd006,
-       0x8a14e7f1,
-       0xf440e3f0,
-       0xe7f18d21,
-       0xe3f0a86c,
-       0x8d21f441,
-/* 0x06b2: ctx_load */
+       0xf89d21f4,
+/* 0x07b5: ctx_4170s */
+       0x10f5f000,
+       0xf102ffb9,
+       0xf04170e7,
+       0x21f440e3,
+/* 0x07c7: ctx_4170w */
+       0xf100f89d,
+       0xf04170e7,
+       0x21f440e3,
+       0x02ffb968,
+       0xf410f4f0,
+       0x00f8f01b,
+/* 0x07dc: ctx_redswitch */
+       0x0200e7f1,
+       0xf040e5f0,
+       0xe5f020e5,
+       0x0007f110,
+       0x0103f085,
+       0xbd000ed0,
+       0x08f7f004,
+/* 0x07f8: ctx_redswitch_delay */
+       0xf401f2b6,
+       0xe5f1fd1b,
+       0xe5f10400,
+       0x07f10100,
+       0x03f08500,
+       0x000ed001,
+       0x00f804bd,
+/* 0x0814: ctx_86c */
+       0x1b0007f1,
+       0xd00203f0,
+       0x04bd000f,
+       0xf102ffb9,
+       0xf08a14e7,
+       0x21f440e3,
+       0x02ffb99d,
+       0xa86ce7f1,
+       0xf441e3f0,
+       0x00f89d21,
+/* 0x083c: ctx_mem */
+       0x840007f1,
+       0xd00203f0,
+       0x04bd000f,
+/* 0x0848: ctx_mem_wait */
+       0x8400f7f1,
+       0xcf02f3f0,
+       0xfffd00ff,
+       0xf31bf405,
+/* 0x085a: ctx_load */
        0x94bd00f8,
        0xf10599f0,
        0xf00f0007,
        0x09d00203,
        0xf004bd00,
        0x21f40ca7,
-       0x2417f1c9,
-       0x0614b60a,
-       0xf10010d0,
-       0xb60b0037,
-       0x32d00634,
-       0x0c17f140,
-       0x0614b60a,
-       0xd00747f0,
-       0x14d00012,
-/* 0x06ed: ctx_chan_wait_0 */
-       0x4014cf40,
-       0xf41f44f0,
-       0x32d0fa1b,
-       0x000bfe00,
-       0xb61f2af0,
-       0x20b60424,
-       0xf094bd02,
+       0xf1f4bdd0,
+       0xf0890007,
+       0x0fd00203,
+       0xf104bd00,
+       0xf0c10007,
+       0x02d00203,
+       0xf104bd00,
+       0xf0830007,
+       0x02d00203,
+       0xf004bd00,
+       0x21f507f7,
+       0x07f1083c,
+       0x03f0c000,
+       0x0002d002,
+       0x0bfe04bd,
+       0x1f2af000,
+       0xb60424b6,
+       0x94bd0220,
+       0xf10899f0,
+       0xf00f0007,
+       0x09d00203,
+       0xf104bd00,
+       0xf0810007,
+       0x02d00203,
+       0xf104bd00,
+       0xf1000027,
+       0xf0800023,
+       0x07f10225,
+       0x03f08800,
+       0x0002d002,
+       0x17f004bd,
+       0x0027f110,
+       0x0223f002,
+       0xf80512fa,
+       0xf094bd03,
        0x07f10899,
-       0x03f00f00,
+       0x03f01700,
        0x0009d002,
-       0x17f104bd,
-       0x14b60a04,
-       0x0012d006,
-       0x0a2017f1,
-       0xf00614b6,
-       0x23f10227,
-       0x12d08000,
-       0x1017f000,
-       0x020027f1,
-       0xfa0223f0,
-       0x03f80512,
+       0x019804bd,
+       0x1814b681,
+       0xb6800298,
+       0x12fd0825,
+       0x16018005,
        0x99f094bd,
-       0x0007f108,
-       0x0203f017,
+       0x0007f109,
+       0x0203f00f,
        0xbd0009d0,
-       0x81019804,
-       0x981814b6,
-       0x25b68002,
-       0x0512fd08,
-       0xbd160180,
-       0x0999f094,
-       0x0f0007f1,
-       0xd00203f0,
-       0x04bd0009,
-       0x0a0427f1,
-       0xd00624b6,
-       0x27f00021,
-       0x2017f101,
-       0x0614b60a,
-       0xf10012d0,
-       0xf0010017,
-       0x01fa0613,
-       0xbd03f805,
-       0x0999f094,
-       0x170007f1,
+       0x0007f104,
+       0x0203f081,
+       0xbd0001d0,
+       0x0127f004,
+       0x880007f1,
        0xd00203f0,
-       0x04bd0009,
+       0x04bd0002,
+       0x010017f1,
+       0xfa0613f0,
+       0x03f80501,
        0x99f094bd,
-       0x0007f105,
+       0x0007f109,
        0x0203f017,
        0xbd0009d0,
-/* 0x07bb: ctx_chan */
-       0xf500f804,
-       0xf5062b21,
-       0xf006b221,
-       0x21f40ca7,
-       0x1017f1c9,
-       0x0614b60a,
-       0xd00527f0,
-/* 0x07d6: ctx_chan_wait */
-       0x12cf0012,
-       0x0522fd00,
-       0xf5fa1bf4,
-       0xf8064321,
-/* 0x07e5: ctx_mmio_exec */
-       0x41039800,
-       0x0a0427f1,
-       0xd00624b6,
-       0x34bd0023,
-/* 0x07f4: ctx_mmio_loop */
+       0xf094bd04,
+       0x07f10599,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0978: ctx_chan */
+       0x077f21f5,
+       0x085a21f5,
+       0xf40ca7f0,
+       0xf7f0d021,
+       0x3c21f505,
+       0xa421f508,
+/* 0x0993: ctx_mmio_exec */
+       0x9800f807,
+       0x07f14103,
+       0x03f08100,
+       0x0003d002,
+       0x34bd04bd,
+/* 0x09a4: ctx_mmio_loop */
        0xf4ff34c4,
        0x57f10f1b,
        0x53f00200,
        0x0535fa06,
-/* 0x0806: ctx_mmio_pull */
+/* 0x09b6: ctx_mmio_pull */
        0x4e9803f8,
        0x814f9880,
-       0xb68d21f4,
+       0xb69d21f4,
        0x12b60830,
        0xdf1bf401,
-/* 0x0818: ctx_mmio_done */
-       0xd0160398,
-       0x00800023,
-       0x0017f140,
-       0x0613f001,
-       0xf80601fa,
-/* 0x082f: ctx_xfer */
-       0xf100f803,
-       0xb60c00f7,
-       0xe7f006f4,
-       0x80fed004,
-/* 0x083c: ctx_xfer_idle */
-       0xf100fecf,
-       0xf42000e4,
-       0x11f4f91b,
-       0x1102f406,
-/* 0x084c: ctx_xfer_pre */
-       0xf510f7f0,
-       0xf5069221,
-       0xf4062b21,
-/* 0x085a: ctx_xfer_pre_load */
-       0xf7f01c11,
-       0x5121f502,
-       0x6021f506,
-       0x7221f506,
-       0xf5f4bd06,
-       0xf5065121,
-/* 0x0873: ctx_xfer_exec */
-       0x9806b221,
-       0x27f11601,
-       0x24b60414,
-       0x0020d006,
-       0xa500e7f1,
-       0xb941e3f0,
-       0x21f4021f,
-       0x04e0b68d,
-       0xf001fcf0,
-       0x24b6022c,
-       0x05f2fd01,
-       0xf18d21f4,
-       0xf04afc17,
-       0x27f00213,
-       0x0012d00c,
-       0x021521f5,
-       0x47fc27f1,
-       0xd00223f0,
-       0x2cf00020,
+/* 0x09c8: ctx_mmio_done */
+       0xf1160398,
+       0xf0810007,
+       0x03d00203,
+       0x8004bd00,
+       0x17f14000,
+       0x13f00100,
+       0x0601fa06,
+       0x00f803f8,
+/* 0x09e8: ctx_xfer */
+       0xf104e7f0,
+       0xf0020007,
+       0x0ed00303,
+/* 0x09f7: ctx_xfer_idle */
+       0xf104bd00,
+       0xf00000e7,
+       0xeecf03e3,
+       0x00e4f100,
+       0xf21bf420,
+       0xf40611f4,
+/* 0x0a0e: ctx_xfer_pre */
+       0xf7f01102,
+       0x1421f510,
+       0x7f21f508,
+       0x1c11f407,
+/* 0x0a1c: ctx_xfer_pre_load */
+       0xf502f7f0,
+       0xf507b521,
+       0xf507c721,
+       0xbd07dc21,
+       0xb521f5f4,
+       0x5a21f507,
+/* 0x0a35: ctx_xfer_exec */
+       0x16019808,
+       0x07f124bd,
+       0x03f00500,
+       0x0002d001,
+       0x1fb904bd,
+       0x00e7f102,
+       0x41e3f0a5,
+       0xf09d21f4,
+       0x2cf001fc,
+       0x0124b602,
+       0xb905f2fd,
+       0xe7f102ff,
+       0xe3f0a504,
+       0x9d21f441,
+       0x026a21f5,
+       0x07f124bd,
+       0x03f047fc,
+       0x0002d002,
+       0x2cf004bd,
        0x0320b601,
-       0xf00012d0,
-       0xa5f001ac,
-       0x00b7f006,
-       0x98000c98,
-       0xe7f0010d,
-       0x6621f500,
-       0x08a7f001,
-       0x010921f5,
-       0x021521f5,
-       0xf02201f4,
-       0x21f40ca7,
-       0x1017f1c9,
-       0x0614b60a,
-       0xd00527f0,
-/* 0x08fa: ctx_xfer_post_save_wait */
-       0x12cf0012,
-       0x0522fd00,
-       0xf4fa1bf4,
-/* 0x0906: ctx_xfer_post */
-       0xf7f03202,
-       0x5121f502,
-       0xf5f4bd06,
-       0xf5069221,
-       0xf5023421,
-       0xbd066021,
-       0x5121f5f4,
-       0x1011f406,
-       0xfd400198,
-       0x0bf40511,
-       0xe521f507,
-/* 0x0931: ctx_xfer_no_post_mmio */
-       0x4321f507,
-/* 0x0935: ctx_xfer_done */
-       0x0000f806,
-       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,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xf001acf0,
+       0xb7f006a5,
+       0x000c9800,
+       0xf0010d98,
+       0x21f500e7,
+       0xa7f0016f,
+       0x1021f508,
+       0x5e21f501,
+       0x1301f402,
+       0xf40ca7f0,
+       0xf7f0d021,
+       0x3c21f505,
+       0x3202f408,
+/* 0x0ac4: ctx_xfer_post */
+       0xf502f7f0,
+       0xbd07b521,
+       0x1421f5f4,
+       0x7f21f508,
+       0xc721f502,
+       0xf5f4bd07,
+       0xf407b521,
+       0x01981011,
+       0x0511fd40,
+       0xf5070bf4,
+/* 0x0aef: ctx_xfer_no_post_mmio */
+       0xf5099321,
+/* 0x0af3: ctx_xfer_done */
+       0xf807a421,
        0x00000000,
        0x00000000,
        0x00000000,
index a1b9f763996a349d0def2c0770568accbfea9b8d..84af8241898764bfef6116d881c0425346684ee2 100644 (file)
@@ -206,14 +206,14 @@ uint32_t nvd7_grhub_data[] = {
 };
 
 uint32_t nvd7_grhub_code[] = {
-       0x031b0ef5,
+       0x039b0ef5,
 /* 0x0004: queue_put */
        0x9800d898,
        0x86f001d9,
        0x0489b808,
        0xf00c1bf4,
        0x21f502f7,
-       0x00f802fe,
+       0x00f8037e,
 /* 0x001c: queue_put_next */
        0xb60798c4,
        0x8dbb0384,
@@ -237,184 +237,214 @@ uint32_t nvd7_grhub_code[] = {
 /* 0x0066: queue_get_done */
        0x00f80132,
 /* 0x0068: nv_rd32 */
-       0x0728b7f1,
-       0xb906b4b6,
-       0xc9f002ec,
-       0x00bcd01f,
-/* 0x0078: nv_rd32_wait */
-       0xc800bccf,
-       0x1bf41fcc,
-       0x06a7f0fa,
-       0x010921f5,
-       0xf840bfcf,
-/* 0x008d: nv_wr32 */
-       0x28b7f100,
-       0x06b4b607,
-       0xb980bfd0,
-       0xc9f002ec,
-       0x1ec9f01f,
-/* 0x00a3: nv_wr32_wait */
-       0xcf00bcd0,
-       0xccc800bc,
-       0xfa1bf41f,
-/* 0x00ae: watchdog_reset */
-       0x87f100f8,
-       0x84b60430,
-       0x1ff9f006,
-       0xf8008fd0,
-/* 0x00bd: watchdog_clear */
-       0x3087f100,
-       0x0684b604,
-       0xf80080d0,
-/* 0x00c9: wait_donez */
-       0xf094bd00,
-       0x07f10099,
-       0x03f00f00,
-       0x0009d002,
-       0x07f104bd,
-       0x03f00600,
-       0x000ad002,
-/* 0x00e6: wait_donez_ne */
-       0x87f104bd,
-       0x83f00000,
-       0x0088cf01,
-       0xf4888aff,
-       0x94bdf31b,
-       0xf10099f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0109: wait_doneo */
-       0xf094bd00,
+       0xf002ecb9,
+       0x07f11fc9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x007a: nv_rd32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0xa7f0f31b,
+       0x1021f506,
+       0x00f7f101,
+       0x01f3f0cb,
+       0xf800ffcf,
+/* 0x009d: nv_wr32 */
+       0x0007f100,
+       0x0103f0cc,
+       0xbd000fd0,
+       0x02ecb904,
+       0xf01fc9f0,
+       0x07f11ec9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x00be: nv_wr32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f31b,
+/* 0x00d0: wait_donez */
+       0x99f094bd,
+       0x0007f100,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x1bf4888a,
+       0xf094bdf3,
        0x07f10099,
-       0x03f00f00,
+       0x03f01700,
        0x0009d002,
-       0x87f104bd,
-       0x84b60818,
-       0x008ad006,
-/* 0x0124: wait_doneo_e */
-       0x040087f1,
-       0xcf0684b6,
-       0x8aff0088,
-       0xf30bf488,
+       0x00f804bd,
+/* 0x0110: wait_doneo */
        0x99f094bd,
        0x0007f100,
-       0x0203f017,
+       0x0203f00f,
        0xbd0009d0,
-/* 0x0147: mmctx_size */
-       0xbd00f804,
-/* 0x0149: nv_mmctx_size_loop */
-       0x00e89894,
-       0xb61a85b6,
-       0x84b60180,
-       0x0098bb02,
-       0xb804e0b6,
-       0x1bf404ef,
-       0x029fb9eb,
-/* 0x0166: mmctx_xfer */
-       0x94bd00f8,
-       0xf10199f0,
-       0xf00f0007,
-       0x09d00203,
-       0xf104bd00,
-       0xb6071087,
-       0x94bd0684,
-       0xf405bbfd,
-       0x8bd0090b,
-       0x0099f000,
-/* 0x018c: mmctx_base_disabled */
-       0xf405eefd,
-       0x8ed00c0b,
-       0xc08fd080,
-/* 0x019b: mmctx_multi_disabled */
-       0xb70199f0,
-       0xc8010080,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x0bf4888a,
+       0xf094bdf3,
+       0x07f10099,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0xf404efb8,
+       0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+       0xbd00f802,
+       0x0199f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0xbbfd94bd,
+       0x120bf405,
+       0xc40007f1,
+       0xd00103f0,
+       0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0x0007f11e,
+       0x0103f0c6,
+       0xbd000ed0,
+       0x0007f104,
+       0x0103f0c7,
+       0xbd000fd0,
+       0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+       0xb600abc8,
+       0xb9f010b4,
+       0x01aec80c,
+       0xfd11e4b6,
+       0x07f105be,
+       0x03f0c500,
+       0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+       0xe7f104bd,
+       0xe3f0c500,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f30b,
+       0x05e9fd00,
+       0xc80007f1,
+       0xd00103f0,
+       0x04bd000e,
+       0xb804c0b6,
+       0x1bf404cd,
+       0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+       0xf11f1bf4,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x1fb4f000,
+       0xf410b4b0,
+       0xa7f0f01b,
+       0xd021f402,
+/* 0x0223: mmctx_stop */
+       0xc82b0ef4,
        0xb4b600ab,
        0x0cb9f010,
-       0xb601aec8,
-       0xbefd11e4,
-       0x008bd005,
-/* 0x01b4: mmctx_exec_loop */
-/* 0x01b4: mmctx_wait_free */
-       0xf0008ecf,
-       0x0bf41fe4,
-       0x00ce98fa,
-       0xd005e9fd,
-       0xc0b6c08e,
-       0x04cdb804,
-       0xc8e81bf4,
-       0x1bf402ab,
-/* 0x01d5: mmctx_fini_wait */
-       0x008bcf18,
-       0xb01fb4f0,
-       0x1bf410b4,
-       0x02a7f0f7,
-       0xf4c921f4,
-/* 0x01ea: mmctx_stop */
-       0xabc81b0e,
-       0x10b4b600,
-       0xf00cb9f0,
-       0x8bd012b9,
-/* 0x01f9: mmctx_stop_wait */
-       0x008bcf00,
-       0xf412bbc8,
-/* 0x0202: mmctx_done */
-       0x94bdfa1b,
-       0xf10199f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0215: strand_wait */
-       0xf0a0f900,
-       0x21f402a7,
-       0xf8a0fcc9,
-/* 0x0221: strand_pre */
-       0xfc87f100,
-       0x0283f04a,
-       0xd00c97f0,
-       0x21f50089,
-       0x00f80215,
-/* 0x0234: strand_post */
-       0x4afc87f1,
-       0xf00283f0,
-       0x89d00d97,
-       0x1521f500,
-/* 0x0247: strand_set */
-       0xf100f802,
-       0xf04ffca7,
-       0xaba202a3,
-       0xc7f00500,
-       0x00acd00f,
-       0xd00bc7f0,
-       0x21f500bc,
-       0xaed00215,
-       0x0ac7f000,
-       0xf500bcd0,
-       0xf8021521,
-/* 0x0271: strand_ctx_init */
-       0xf094bd00,
-       0x07f10399,
-       0x03f00f00,
+       0xf112b9f0,
+       0xf0c50007,
+       0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+       0xf104bd00,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x12bbc800,
+/* 0x024b: mmctx_done */
+       0xbdf31bf4,
+       0x0199f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x025e: strand_wait */
+       0xa0f900f8,
+       0xf402a7f0,
+       0xa0fcd021,
+/* 0x026a: strand_pre */
+       0x97f000f8,
+       0xfc07f10c,
+       0x0203f04a,
+       0xbd0009d0,
+       0x5e21f504,
+/* 0x027f: strand_post */
+       0xf000f802,
+       0x07f10d97,
+       0x03f04afc,
        0x0009d002,
        0x21f504bd,
-       0xe7f00221,
-       0x4721f503,
-       0xfca7f102,
-       0x02a3f046,
-       0x0400aba0,
-       0xf040a0d0,
-       0xbcd001c7,
-       0x1521f500,
-       0x010c9202,
-       0xf000acd0,
-       0xbcd002c7,
-       0x1521f500,
-       0x3421f502,
-       0x8087f102,
-       0x0684b608,
-       0xb70089cf,
-       0x95220080,
-/* 0x02ca: ctx_init_strand_loop */
+       0x00f8025e,
+/* 0x0294: strand_set */
+       0xf10fc7f0,
+       0xf04ffc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f10bc7,
+       0x03f04afc,
+       0x000cd002,
+       0x07f104bd,
+       0x03f04ffc,
+       0x000ed002,
+       0xc7f004bd,
+       0xfc07f10a,
+       0x0203f04a,
+       0xbd000cd0,
+       0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+       0xbd00f802,
+       0x0399f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0x026a21f5,
+       0xf503e7f0,
+       0xbd029421,
+       0xfc07f1c4,
+       0x0203f047,
+       0xbd000cd0,
+       0x01c7f004,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd000c,
+       0x025e21f5,
+       0xf1010c92,
+       0xf046fc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f102c7,
+       0x03f04afc,
+       0x000cd002,
+       0x21f504bd,
+       0x21f5025e,
+       0x87f1027f,
+       0x83f04200,
+       0x0097f102,
+       0x0293f020,
+       0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
        0x8ed008fe,
        0x408ed000,
        0xb6808acf,
@@ -428,7 +458,7 @@ uint32_t nvd7_grhub_code[] = {
        0x170007f1,
        0xd00203f0,
        0x04bd0009,
-/* 0x02fe: error */
+/* 0x037e: error */
        0x07f100f8,
        0x03f00500,
        0x000fd002,
@@ -436,82 +466,117 @@ uint32_t nvd7_grhub_code[] = {
        0x0007f101,
        0x0303f007,
        0xbd000fd0,
-/* 0x031b: init */
+/* 0x039b: init */
        0xbd00f804,
-       0x0004fe04,
-       0xf10007fe,
-       0xf0120017,
-       0x12d00227,
-       0xb117f100,
-       0x0010fe05,
-       0x040017f1,
-       0xf1c010d0,
-       0xb6040437,
-       0x27f10634,
-       0x32d02003,
-       0x0427f100,
-       0x0132d020,
+       0x0007fe04,
+       0x420017f1,
+       0xcf0013f0,
+       0x11e70011,
+       0x14b60109,
+       0x0014fe08,
+       0xf10227f0,
+       0xf0120007,
+       0x02d00003,
+       0xf104bd00,
+       0xfe06c817,
+       0x24bd0010,
+       0x070007f1,
+       0xd00003f0,
+       0x04bd0002,
+       0x200327f1,
+       0x010007f1,
+       0xd00103f0,
+       0x04bd0002,
+       0x200427f1,
+       0x010407f1,
+       0xd00103f0,
+       0x04bd0002,
        0x200b27f1,
-       0xf10232d0,
-       0xd0200c27,
-       0x27f10732,
-       0x24b60c24,
-       0x0003b906,
-       0xf10023d0,
+       0x010807f1,
+       0xd00103f0,
+       0x04bd0002,
+       0x200c27f1,
+       0x011c07f1,
+       0xd00103f0,
+       0x04bd0002,
+       0xf1010392,
+       0xf0090007,
+       0x03d00303,
+       0xf104bd00,
        0xf0870427,
-       0x12d00023,
-       0x0012b700,
-       0x0427f001,
-       0xf40012d0,
-       0xe7f11031,
-       0xe3f09604,
-       0x6821f440,
-       0x8090f1c7,
-       0xf4f00301,
-       0x020f801f,
-       0xbb0117f0,
-       0x12b6041f,
-       0x0c27f101,
-       0x0624b604,
-       0xd00021d0,
-       0x17f14021,
-       0x0e980100,
-       0x010f9800,
-       0x014721f5,
-       0x070037f1,
-       0x950634b6,
-       0x34d00814,
-       0x4034d000,
-       0x130030b7,
-       0xb6001fbb,
-       0x3fd002f5,
-       0x0815b600,
-       0xb60110b6,
-       0x1fb90814,
-       0x7121f502,
-       0x001fbb02,
-       0xf1020398,
-       0xf0200047,
-/* 0x03f6: init_gpc */
-       0x4ea05043,
-       0x1fb90804,
-       0x8d21f402,
-       0x010c4ea0,
-       0x21f4f4bd,
-       0x044ea08d,
-       0x8d21f401,
-       0x01004ea0,
-       0xf402f7f0,
-       0x4ea08d21,
-/* 0x041e: init_gpc_wait */
-       0x21f40800,
-       0x1fffc868,
-       0xa0fa0bf4,
-       0xf408044e,
-       0x1fbb6821,
-       0x0040b700,
-       0x0132b680,
-       0xf1be1bf4,
+       0x07f10023,
+       0x03f00400,
+       0x0002d000,
+       0x27f004bd,
+       0x0007f104,
+       0x0003f003,
+       0xbd0002d0,
+       0x1031f404,
+       0x9604e7f1,
+       0xf440e3f0,
+       0xfeb96821,
+       0x90f1c702,
+       0xf0030180,
+       0x0f801ff4,
+       0x0117f002,
+       0xb6041fbb,
+       0x07f10112,
+       0x03f00300,
+       0x0001d001,
+       0x07f104bd,
+       0x03f00400,
+       0x0001d001,
+       0x17f104bd,
+       0xf7f00100,
+       0xb521f502,
+       0xc721f507,
+       0x10f7f007,
+       0x081421f5,
+       0x98000e98,
+       0x21f5010f,
+       0x14950150,
+       0x0007f108,
+       0x0103f0c0,
+       0xbd0004d0,
+       0x0007f104,
+       0x0103f0c1,
+       0xbd0004d0,
+       0x0030b704,
+       0x001fbb13,
+       0xf102f5b6,
+       0xf0d30007,
+       0x0fd00103,
+       0xb604bd00,
+       0x10b60815,
+       0x0814b601,
+       0xf5021fb9,
+       0xbb02d321,
+       0x0398001f,
+       0x0047f102,
+       0x5043f020,
+/* 0x04f4: init_gpc */
+       0x08044ea0,
+       0xf4021fb9,
+       0x4ea09d21,
+       0xf4bd010c,
+       0xa09d21f4,
+       0xf401044e,
+       0x4ea09d21,
+       0xf7f00100,
+       0x9d21f402,
+       0x08004ea0,
+/* 0x051c: init_gpc_wait */
+       0xc86821f4,
+       0x0bf41fff,
+       0x044ea0fa,
+       0x6821f408,
+       0xb7001fbb,
+       0xb6800040,
+       0x1bf40132,
+       0x00f7f0be,
+       0x081421f5,
+       0xf500f7f0,
+       0xf107b521,
        0xf0010007,
        0x01d00203,
        0xbd04bd00,
@@ -519,402 +584,399 @@ uint32_t nvd7_grhub_code[] = {
        0x080007f1,
        0xd00203f0,
        0x04bd0001,
-/* 0x0458: main */
+/* 0x0564: main */
        0xf40031f4,
        0xd7f00028,
        0x3921f410,
        0xb1f401f4,
        0xf54001e4,
-       0xbd00de1b,
+       0xbd00e91b,
        0x0499f094,
        0x0f0007f1,
        0xd00203f0,
        0x04bd0009,
-       0x0b0017f1,
-       0xcf0614b6,
-       0x11cf4012,
-       0x1f13c800,
-       0x00870bf5,
-       0xf41f23c8,
-       0x20f9620b,
-       0xbd0212b9,
-       0x0799f094,
-       0x0f0007f1,
-       0xd00203f0,
-       0x04bd0009,
-       0xf40132f4,
-       0x21f50231,
-       0x94bd082f,
+       0xc00017f1,
+       0xcf0213f0,
+       0x27f10011,
+       0x23f0c100,
+       0x0022cf02,
+       0xf51f13c8,
+       0xc800890b,
+       0x0bf41f23,
+       0xb920f962,
+       0x94bd0212,
        0xf10799f0,
-       0xf0170007,
+       0xf00f0007,
        0x09d00203,
-       0xfc04bd00,
-       0xf094bd20,
-       0x07f10699,
-       0x03f00f00,
-       0x0009d002,
-       0x31f404bd,
-       0x2f21f501,
-       0xf094bd08,
-       0x07f10699,
+       0xf404bd00,
+       0x31f40132,
+       0xe821f502,
+       0xf094bd09,
+       0x07f10799,
        0x03f01700,
        0x0009d002,
-       0x0ef404bd,
-/* 0x04f9: chsw_prev_no_next */
-       0xb920f931,
-       0x32f40212,
-       0x0232f401,
-       0x082f21f5,
-       0x17f120fc,
-       0x14b60b00,
-       0x0012d006,
-/* 0x0517: chsw_no_prev */
-       0xc8130ef4,
-       0x0bf41f23,
-       0x0131f40d,
-       0xf50232f4,
-/* 0x0527: chsw_done */
-       0xf1082f21,
-       0xb60b0c17,
-       0x27f00614,
-       0x0012d001,
+       0x20fc04bd,
        0x99f094bd,
-       0x0007f104,
+       0x0007f106,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0131f404,
+       0x09e821f5,
+       0x99f094bd,
+       0x0007f106,
        0x0203f017,
        0xbd0009d0,
-       0x130ef504,
-/* 0x0549: main_not_ctx_switch */
-       0x01e4b0ff,
-       0xb90d1bf4,
-       0x21f502f2,
-       0x0ef407bb,
-/* 0x0559: main_not_ctx_chan */
-       0x02e4b046,
-       0xbd321bf4,
-       0x0799f094,
-       0x0f0007f1,
+       0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+       0x12b920f9,
+       0x0132f402,
+       0xf50232f4,
+       0xfc09e821,
+       0x0007f120,
+       0x0203f0c0,
+       0xbd0002d0,
+       0x130ef404,
+/* 0x062c: chsw_no_prev */
+       0xf41f23c8,
+       0x31f40d0b,
+       0x0232f401,
+       0x09e821f5,
+/* 0x063c: chsw_done */
+       0xf10127f0,
+       0xf0c30007,
+       0x02d00203,
+       0xbd04bd00,
+       0x0499f094,
+       0x170007f1,
        0xd00203f0,
        0x04bd0009,
-       0xf40132f4,
-       0x21f50232,
-       0x94bd082f,
+       0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+       0xf401e4b0,
+       0xf2b90d1b,
+       0x7821f502,
+       0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+       0xf402e4b0,
+       0x94bd321b,
        0xf10799f0,
-       0xf0170007,
+       0xf00f0007,
        0x09d00203,
        0xf404bd00,
-/* 0x058e: main_not_ctx_save */
-       0xef94110e,
-       0x01f5f010,
-       0x02fe21f5,
-       0xfec00ef5,
-/* 0x059c: main_done */
-       0x29f024bd,
-       0x0007f11f,
-       0x0203f008,
-       0xbd0002d0,
-       0xab0ef504,
-/* 0x05b1: ih */
-       0xfe80f9fe,
-       0x80f90188,
-       0xa0f990f9,
-       0xd0f9b0f9,
-       0xf0f9e0f9,
-       0x0acf04bd,
-       0x04abc480,
-       0xf11d0bf4,
-       0xf01900b7,
-       0xbecf10d7,
-       0x00bfcf40,
+       0x32f40132,
+       0xe821f502,
+       0xf094bd09,
+       0x07f10799,
+       0x03f01700,
+       0x0009d002,
+       0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+       0x10ef9411,
+       0xf501f5f0,
+       0xf5037e21,
+/* 0x06b3: main_done */
+       0xbdfeb50e,
+       0x1f29f024,
+       0x080007f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xfea00ef5,
+/* 0x06c8: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x00a7f104,
+       0x00a3f002,
+       0xc400aacf,
+       0x0bf404ab,
+       0x10d7f030,
+       0x1a00e7f1,
+       0xcf00e3f0,
+       0xf7f100ee,
+       0xf3f01900,
+       0x00ffcf00,
        0xb70421f4,
        0xf00400b0,
-       0xbed001e7,
-/* 0x05e9: ih_no_fifo */
-       0x00abe400,
-       0x0d0bf401,
-       0xf110d7f0,
-       0xf44001e7,
-/* 0x05fa: ih_no_ctxsw */
-       0xb7f10421,
-       0xb0bd0104,
-       0xf4b4abff,
-       0xa7f10d0b,
-       0xa4b60c1c,
-       0x00abd006,
-/* 0x0610: ih_no_other */
-       0xfc400ad0,
+       0x07f101e7,
+       0x03f01d00,
+       0x000ed000,
+/* 0x071a: ih_no_fifo */
+       0xabe404bd,
+       0x0bf40100,
+       0x10d7f00d,
+       0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+       0xe40421f4,
+       0xf40400ab,
+       0xb7f1140b,
+       0xbfb90100,
+       0x44e7f102,
+       0x40e3f001,
+/* 0x0743: ih_no_fwmthd */
+       0xf19d21f4,
+       0xbd0104b7,
+       0xb4abffb0,
+       0xf10f0bf4,
+       0xf0070007,
+       0x0bd00303,
+/* 0x075b: ih_no_other */
+       0xf104bd00,
+       0xf0010007,
+       0x0ad00003,
+       0xfc04bd00,
        0xfce0fcf0,
        0xfcb0fcd0,
        0xfc90fca0,
        0x0088fe80,
        0x32f480fc,
-/* 0x062b: ctx_4160s */
-       0xf101f800,
-       0xf04160e7,
-       0xf7f040e3,
-       0x8d21f401,
-/* 0x0638: ctx_4160s_wait */
-       0xc86821f4,
-       0x0bf404ff,
-/* 0x0643: ctx_4160c */
-       0xf100f8fa,
+/* 0x077f: ctx_4160s */
+       0xf001f800,
+       0xffb901f7,
+       0x60e7f102,
+       0x40e3f041,
+/* 0x078f: ctx_4160s_wait */
+       0xf19d21f4,
        0xf04160e7,
-       0xf4bd40e3,
-       0xf88d21f4,
-/* 0x0651: ctx_4170s */
-       0x70e7f100,
+       0x21f440e3,
+       0x02ffb968,
+       0xf404ffc8,
+       0x00f8f00b,
+/* 0x07a4: ctx_4160c */
+       0xffb9f4bd,
+       0x60e7f102,
        0x40e3f041,
-       0xf410f5f0,
-       0x00f88d21,
-/* 0x0660: ctx_4170w */
-       0x4170e7f1,
-       0xf440e3f0,
-       0xf4f06821,
-       0xf31bf410,
-/* 0x0672: ctx_redswitch */
-       0xe7f100f8,
-       0xe4b60614,
-       0x70f7f106,
-       0x00efd002,
-/* 0x0683: ctx_redswitch_delay */
-       0xb608f7f0,
-       0x1bf401f2,
-       0x70f7f1fd,
-       0x00efd007,
-/* 0x0692: ctx_86c */
-       0xe7f100f8,
-       0xe4b6086c,
-       0x00efd006,
-       0x8a14e7f1,
-       0xf440e3f0,
-       0xe7f18d21,
-       0xe3f0a86c,
-       0x8d21f441,
-/* 0x06b2: ctx_load */
+       0xf89d21f4,
+/* 0x07b5: ctx_4170s */
+       0x10f5f000,
+       0xf102ffb9,
+       0xf04170e7,
+       0x21f440e3,
+/* 0x07c7: ctx_4170w */
+       0xf100f89d,
+       0xf04170e7,
+       0x21f440e3,
+       0x02ffb968,
+       0xf410f4f0,
+       0x00f8f01b,
+/* 0x07dc: ctx_redswitch */
+       0x0200e7f1,
+       0xf040e5f0,
+       0xe5f020e5,
+       0x0007f110,
+       0x0103f085,
+       0xbd000ed0,
+       0x08f7f004,
+/* 0x07f8: ctx_redswitch_delay */
+       0xf401f2b6,
+       0xe5f1fd1b,
+       0xe5f10400,
+       0x07f10100,
+       0x03f08500,
+       0x000ed001,
+       0x00f804bd,
+/* 0x0814: ctx_86c */
+       0x1b0007f1,
+       0xd00203f0,
+       0x04bd000f,
+       0xf102ffb9,
+       0xf08a14e7,
+       0x21f440e3,
+       0x02ffb99d,
+       0xa86ce7f1,
+       0xf441e3f0,
+       0x00f89d21,
+/* 0x083c: ctx_mem */
+       0x840007f1,
+       0xd00203f0,
+       0x04bd000f,
+/* 0x0848: ctx_mem_wait */
+       0x8400f7f1,
+       0xcf02f3f0,
+       0xfffd00ff,
+       0xf31bf405,
+/* 0x085a: ctx_load */
        0x94bd00f8,
        0xf10599f0,
        0xf00f0007,
        0x09d00203,
        0xf004bd00,
        0x21f40ca7,
-       0x2417f1c9,
-       0x0614b60a,
-       0xf10010d0,
-       0xb60b0037,
-       0x32d00634,
-       0x0c17f140,
-       0x0614b60a,
-       0xd00747f0,
-       0x14d00012,
-/* 0x06ed: ctx_chan_wait_0 */
-       0x4014cf40,
-       0xf41f44f0,
-       0x32d0fa1b,
-       0x000bfe00,
-       0xb61f2af0,
-       0x20b60424,
-       0xf094bd02,
+       0xf1f4bdd0,
+       0xf0890007,
+       0x0fd00203,
+       0xf104bd00,
+       0xf0c10007,
+       0x02d00203,
+       0xf104bd00,
+       0xf0830007,
+       0x02d00203,
+       0xf004bd00,
+       0x21f507f7,
+       0x07f1083c,
+       0x03f0c000,
+       0x0002d002,
+       0x0bfe04bd,
+       0x1f2af000,
+       0xb60424b6,
+       0x94bd0220,
+       0xf10899f0,
+       0xf00f0007,
+       0x09d00203,
+       0xf104bd00,
+       0xf0810007,
+       0x02d00203,
+       0xf104bd00,
+       0xf1000027,
+       0xf0800023,
+       0x07f10225,
+       0x03f08800,
+       0x0002d002,
+       0x17f004bd,
+       0x0027f110,
+       0x0223f002,
+       0xf80512fa,
+       0xf094bd03,
        0x07f10899,
-       0x03f00f00,
+       0x03f01700,
        0x0009d002,
-       0x17f104bd,
-       0x14b60a04,
-       0x0012d006,
-       0x0a2017f1,
-       0xf00614b6,
-       0x23f10227,
-       0x12d08000,
-       0x1017f000,
-       0x020027f1,
-       0xfa0223f0,
-       0x03f80512,
+       0x019804bd,
+       0x1814b681,
+       0xb6800298,
+       0x12fd0825,
+       0x16018005,
        0x99f094bd,
-       0x0007f108,
-       0x0203f017,
+       0x0007f109,
+       0x0203f00f,
        0xbd0009d0,
-       0x81019804,
-       0x981814b6,
-       0x25b68002,
-       0x0512fd08,
-       0xbd160180,
-       0x0999f094,
-       0x0f0007f1,
-       0xd00203f0,
-       0x04bd0009,
-       0x0a0427f1,
-       0xd00624b6,
-       0x27f00021,
-       0x2017f101,
-       0x0614b60a,
-       0xf10012d0,
-       0xf0010017,
-       0x01fa0613,
-       0xbd03f805,
-       0x0999f094,
-       0x170007f1,
+       0x0007f104,
+       0x0203f081,
+       0xbd0001d0,
+       0x0127f004,
+       0x880007f1,
        0xd00203f0,
-       0x04bd0009,
+       0x04bd0002,
+       0x010017f1,
+       0xfa0613f0,
+       0x03f80501,
        0x99f094bd,
-       0x0007f105,
+       0x0007f109,
        0x0203f017,
        0xbd0009d0,
-/* 0x07bb: ctx_chan */
-       0xf500f804,
-       0xf5062b21,
-       0xf006b221,
-       0x21f40ca7,
-       0x1017f1c9,
-       0x0614b60a,
-       0xd00527f0,
-/* 0x07d6: ctx_chan_wait */
-       0x12cf0012,
-       0x0522fd00,
-       0xf5fa1bf4,
-       0xf8064321,
-/* 0x07e5: ctx_mmio_exec */
-       0x41039800,
-       0x0a0427f1,
-       0xd00624b6,
-       0x34bd0023,
-/* 0x07f4: ctx_mmio_loop */
+       0xf094bd04,
+       0x07f10599,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0978: ctx_chan */
+       0x077f21f5,
+       0x085a21f5,
+       0xf40ca7f0,
+       0xf7f0d021,
+       0x3c21f505,
+       0xa421f508,
+/* 0x0993: ctx_mmio_exec */
+       0x9800f807,
+       0x07f14103,
+       0x03f08100,
+       0x0003d002,
+       0x34bd04bd,
+/* 0x09a4: ctx_mmio_loop */
        0xf4ff34c4,
        0x57f10f1b,
        0x53f00200,
        0x0535fa06,
-/* 0x0806: ctx_mmio_pull */
+/* 0x09b6: ctx_mmio_pull */
        0x4e9803f8,
        0x814f9880,
-       0xb68d21f4,
+       0xb69d21f4,
        0x12b60830,
        0xdf1bf401,
-/* 0x0818: ctx_mmio_done */
-       0xd0160398,
-       0x00800023,
-       0x0017f140,
-       0x0613f001,
-       0xf80601fa,
-/* 0x082f: ctx_xfer */
-       0xf100f803,
-       0xb60c00f7,
-       0xe7f006f4,
-       0x80fed004,
-/* 0x083c: ctx_xfer_idle */
-       0xf100fecf,
-       0xf42000e4,
-       0x11f4f91b,
-       0x1102f406,
-/* 0x084c: ctx_xfer_pre */
-       0xf510f7f0,
-       0xf5069221,
-       0xf4062b21,
-/* 0x085a: ctx_xfer_pre_load */
-       0xf7f01c11,
-       0x5121f502,
-       0x6021f506,
-       0x7221f506,
-       0xf5f4bd06,
-       0xf5065121,
-/* 0x0873: ctx_xfer_exec */
-       0x9806b221,
-       0x27f11601,
-       0x24b60414,
-       0x0020d006,
-       0xa500e7f1,
-       0xb941e3f0,
-       0x21f4021f,
-       0x04e0b68d,
-       0xf001fcf0,
-       0x24b6022c,
-       0x05f2fd01,
-       0xf18d21f4,
-       0xf04afc17,
-       0x27f00213,
-       0x0012d00c,
-       0x021521f5,
-       0x47fc27f1,
-       0xd00223f0,
-       0x2cf00020,
+/* 0x09c8: ctx_mmio_done */
+       0xf1160398,
+       0xf0810007,
+       0x03d00203,
+       0x8004bd00,
+       0x17f14000,
+       0x13f00100,
+       0x0601fa06,
+       0x00f803f8,
+/* 0x09e8: ctx_xfer */
+       0xf104e7f0,
+       0xf0020007,
+       0x0ed00303,
+/* 0x09f7: ctx_xfer_idle */
+       0xf104bd00,
+       0xf00000e7,
+       0xeecf03e3,
+       0x00e4f100,
+       0xf21bf420,
+       0xf40611f4,
+/* 0x0a0e: ctx_xfer_pre */
+       0xf7f01102,
+       0x1421f510,
+       0x7f21f508,
+       0x1c11f407,
+/* 0x0a1c: ctx_xfer_pre_load */
+       0xf502f7f0,
+       0xf507b521,
+       0xf507c721,
+       0xbd07dc21,
+       0xb521f5f4,
+       0x5a21f507,
+/* 0x0a35: ctx_xfer_exec */
+       0x16019808,
+       0x07f124bd,
+       0x03f00500,
+       0x0002d001,
+       0x1fb904bd,
+       0x00e7f102,
+       0x41e3f0a5,
+       0xf09d21f4,
+       0x2cf001fc,
+       0x0124b602,
+       0xb905f2fd,
+       0xe7f102ff,
+       0xe3f0a504,
+       0x9d21f441,
+       0x026a21f5,
+       0x07f124bd,
+       0x03f047fc,
+       0x0002d002,
+       0x2cf004bd,
        0x0320b601,
-       0xf00012d0,
-       0xa5f001ac,
-       0x00b7f006,
-       0x98000c98,
-       0xe7f0010d,
-       0x6621f500,
-       0x08a7f001,
-       0x010921f5,
-       0x021521f5,
-       0xf02201f4,
-       0x21f40ca7,
-       0x1017f1c9,
-       0x0614b60a,
-       0xd00527f0,
-/* 0x08fa: ctx_xfer_post_save_wait */
-       0x12cf0012,
-       0x0522fd00,
-       0xf4fa1bf4,
-/* 0x0906: ctx_xfer_post */
-       0xf7f03202,
-       0x5121f502,
-       0xf5f4bd06,
-       0xf5069221,
-       0xf5023421,
-       0xbd066021,
-       0x5121f5f4,
-       0x1011f406,
-       0xfd400198,
-       0x0bf40511,
-       0xe521f507,
-/* 0x0931: ctx_xfer_no_post_mmio */
-       0x4321f507,
-/* 0x0935: ctx_xfer_done */
-       0x0000f806,
-       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,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xf001acf0,
+       0xb7f006a5,
+       0x000c9800,
+       0xf0010d98,
+       0x21f500e7,
+       0xa7f0016f,
+       0x1021f508,
+       0x5e21f501,
+       0x1301f402,
+       0xf40ca7f0,
+       0xf7f0d021,
+       0x3c21f505,
+       0x3202f408,
+/* 0x0ac4: ctx_xfer_post */
+       0xf502f7f0,
+       0xbd07b521,
+       0x1421f5f4,
+       0x7f21f508,
+       0xc721f502,
+       0xf5f4bd07,
+       0xf407b521,
+       0x01981011,
+       0x0511fd40,
+       0xf5070bf4,
+/* 0x0aef: ctx_xfer_no_post_mmio */
+       0xf5099321,
+/* 0x0af3: ctx_xfer_done */
+       0xf807a421,
        0x00000000,
        0x00000000,
        0x00000000,
index eb7bc0e9576eab1a841bb93fcb3af4e3f924b6d0..1c179bdd48cc2a0ddd3228a3e8bfc0005f1bf06a 100644 (file)
@@ -206,14 +206,14 @@ uint32_t nve0_grhub_data[] = {
 };
 
 uint32_t nve0_grhub_code[] = {
-       0x031b0ef5,
+       0x039b0ef5,
 /* 0x0004: queue_put */
        0x9800d898,
        0x86f001d9,
        0x0489b808,
        0xf00c1bf4,
        0x21f502f7,
-       0x00f802fe,
+       0x00f8037e,
 /* 0x001c: queue_put_next */
        0xb60798c4,
        0x8dbb0384,
@@ -237,184 +237,214 @@ uint32_t nve0_grhub_code[] = {
 /* 0x0066: queue_get_done */
        0x00f80132,
 /* 0x0068: nv_rd32 */
-       0x0728b7f1,
-       0xb906b4b6,
-       0xc9f002ec,
-       0x00bcd01f,
-/* 0x0078: nv_rd32_wait */
-       0xc800bccf,
-       0x1bf41fcc,
-       0x06a7f0fa,
-       0x010921f5,
-       0xf840bfcf,
-/* 0x008d: nv_wr32 */
-       0x28b7f100,
-       0x06b4b607,
-       0xb980bfd0,
-       0xc9f002ec,
-       0x1ec9f01f,
-/* 0x00a3: nv_wr32_wait */
-       0xcf00bcd0,
-       0xccc800bc,
-       0xfa1bf41f,
-/* 0x00ae: watchdog_reset */
-       0x87f100f8,
-       0x84b60430,
-       0x1ff9f006,
-       0xf8008fd0,
-/* 0x00bd: watchdog_clear */
-       0x3087f100,
-       0x0684b604,
-       0xf80080d0,
-/* 0x00c9: wait_donez */
-       0xf094bd00,
-       0x07f10099,
-       0x03f00f00,
-       0x0009d002,
-       0x07f104bd,
-       0x03f00600,
-       0x000ad002,
-/* 0x00e6: wait_donez_ne */
-       0x87f104bd,
-       0x83f00000,
-       0x0088cf01,
-       0xf4888aff,
-       0x94bdf31b,
-       0xf10099f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0109: wait_doneo */
-       0xf094bd00,
+       0xf002ecb9,
+       0x07f11fc9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x007a: nv_rd32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0xa7f0f31b,
+       0x1021f506,
+       0x00f7f101,
+       0x01f3f0cb,
+       0xf800ffcf,
+/* 0x009d: nv_wr32 */
+       0x0007f100,
+       0x0103f0cc,
+       0xbd000fd0,
+       0x02ecb904,
+       0xf01fc9f0,
+       0x07f11ec9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x00be: nv_wr32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f31b,
+/* 0x00d0: wait_donez */
+       0x99f094bd,
+       0x0007f100,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x1bf4888a,
+       0xf094bdf3,
        0x07f10099,
-       0x03f00f00,
+       0x03f01700,
        0x0009d002,
-       0x87f104bd,
-       0x84b60818,
-       0x008ad006,
-/* 0x0124: wait_doneo_e */
-       0x040087f1,
-       0xcf0684b6,
-       0x8aff0088,
-       0xf30bf488,
+       0x00f804bd,
+/* 0x0110: wait_doneo */
        0x99f094bd,
        0x0007f100,
-       0x0203f017,
+       0x0203f00f,
        0xbd0009d0,
-/* 0x0147: mmctx_size */
-       0xbd00f804,
-/* 0x0149: nv_mmctx_size_loop */
-       0x00e89894,
-       0xb61a85b6,
-       0x84b60180,
-       0x0098bb02,
-       0xb804e0b6,
-       0x1bf404ef,
-       0x029fb9eb,
-/* 0x0166: mmctx_xfer */
-       0x94bd00f8,
-       0xf10199f0,
-       0xf00f0007,
-       0x09d00203,
-       0xf104bd00,
-       0xb6071087,
-       0x94bd0684,
-       0xf405bbfd,
-       0x8bd0090b,
-       0x0099f000,
-/* 0x018c: mmctx_base_disabled */
-       0xf405eefd,
-       0x8ed00c0b,
-       0xc08fd080,
-/* 0x019b: mmctx_multi_disabled */
-       0xb70199f0,
-       0xc8010080,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x0bf4888a,
+       0xf094bdf3,
+       0x07f10099,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0xf404efb8,
+       0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+       0xbd00f802,
+       0x0199f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0xbbfd94bd,
+       0x120bf405,
+       0xc40007f1,
+       0xd00103f0,
+       0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0x0007f11e,
+       0x0103f0c6,
+       0xbd000ed0,
+       0x0007f104,
+       0x0103f0c7,
+       0xbd000fd0,
+       0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+       0xb600abc8,
+       0xb9f010b4,
+       0x01aec80c,
+       0xfd11e4b6,
+       0x07f105be,
+       0x03f0c500,
+       0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+       0xe7f104bd,
+       0xe3f0c500,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f30b,
+       0x05e9fd00,
+       0xc80007f1,
+       0xd00103f0,
+       0x04bd000e,
+       0xb804c0b6,
+       0x1bf404cd,
+       0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+       0xf11f1bf4,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x1fb4f000,
+       0xf410b4b0,
+       0xa7f0f01b,
+       0xd021f402,
+/* 0x0223: mmctx_stop */
+       0xc82b0ef4,
        0xb4b600ab,
        0x0cb9f010,
-       0xb601aec8,
-       0xbefd11e4,
-       0x008bd005,
-/* 0x01b4: mmctx_exec_loop */
-/* 0x01b4: mmctx_wait_free */
-       0xf0008ecf,
-       0x0bf41fe4,
-       0x00ce98fa,
-       0xd005e9fd,
-       0xc0b6c08e,
-       0x04cdb804,
-       0xc8e81bf4,
-       0x1bf402ab,
-/* 0x01d5: mmctx_fini_wait */
-       0x008bcf18,
-       0xb01fb4f0,
-       0x1bf410b4,
-       0x02a7f0f7,
-       0xf4c921f4,
-/* 0x01ea: mmctx_stop */
-       0xabc81b0e,
-       0x10b4b600,
-       0xf00cb9f0,
-       0x8bd012b9,
-/* 0x01f9: mmctx_stop_wait */
-       0x008bcf00,
-       0xf412bbc8,
-/* 0x0202: mmctx_done */
-       0x94bdfa1b,
-       0xf10199f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0215: strand_wait */
-       0xf0a0f900,
-       0x21f402a7,
-       0xf8a0fcc9,
-/* 0x0221: strand_pre */
-       0xfc87f100,
-       0x0283f04a,
-       0xd00c97f0,
-       0x21f50089,
-       0x00f80215,
-/* 0x0234: strand_post */
-       0x4afc87f1,
-       0xf00283f0,
-       0x89d00d97,
-       0x1521f500,
-/* 0x0247: strand_set */
-       0xf100f802,
-       0xf04ffca7,
-       0xaba202a3,
-       0xc7f00500,
-       0x00acd00f,
-       0xd00bc7f0,
-       0x21f500bc,
-       0xaed00215,
-       0x0ac7f000,
-       0xf500bcd0,
-       0xf8021521,
-/* 0x0271: strand_ctx_init */
-       0xf094bd00,
-       0x07f10399,
-       0x03f00f00,
+       0xf112b9f0,
+       0xf0c50007,
+       0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+       0xf104bd00,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x12bbc800,
+/* 0x024b: mmctx_done */
+       0xbdf31bf4,
+       0x0199f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x025e: strand_wait */
+       0xa0f900f8,
+       0xf402a7f0,
+       0xa0fcd021,
+/* 0x026a: strand_pre */
+       0x97f000f8,
+       0xfc07f10c,
+       0x0203f04a,
+       0xbd0009d0,
+       0x5e21f504,
+/* 0x027f: strand_post */
+       0xf000f802,
+       0x07f10d97,
+       0x03f04afc,
        0x0009d002,
        0x21f504bd,
-       0xe7f00221,
-       0x4721f503,
-       0xfca7f102,
-       0x02a3f046,
-       0x0400aba0,
-       0xf040a0d0,
-       0xbcd001c7,
-       0x1521f500,
-       0x010c9202,
-       0xf000acd0,
-       0xbcd002c7,
-       0x1521f500,
-       0x3421f502,
-       0x8087f102,
-       0x0684b608,
-       0xb70089cf,
-       0x95220080,
-/* 0x02ca: ctx_init_strand_loop */
+       0x00f8025e,
+/* 0x0294: strand_set */
+       0xf10fc7f0,
+       0xf04ffc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f10bc7,
+       0x03f04afc,
+       0x000cd002,
+       0x07f104bd,
+       0x03f04ffc,
+       0x000ed002,
+       0xc7f004bd,
+       0xfc07f10a,
+       0x0203f04a,
+       0xbd000cd0,
+       0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+       0xbd00f802,
+       0x0399f094,
+       0x0f0007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0x026a21f5,
+       0xf503e7f0,
+       0xbd029421,
+       0xfc07f1c4,
+       0x0203f047,
+       0xbd000cd0,
+       0x01c7f004,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd000c,
+       0x025e21f5,
+       0xf1010c92,
+       0xf046fc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f102c7,
+       0x03f04afc,
+       0x000cd002,
+       0x21f504bd,
+       0x21f5025e,
+       0x87f1027f,
+       0x83f04200,
+       0x0097f102,
+       0x0293f020,
+       0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
        0x8ed008fe,
        0x408ed000,
        0xb6808acf,
@@ -428,7 +458,7 @@ uint32_t nve0_grhub_code[] = {
        0x170007f1,
        0xd00203f0,
        0x04bd0009,
-/* 0x02fe: error */
+/* 0x037e: error */
        0x07f100f8,
        0x03f00500,
        0x000fd002,
@@ -436,82 +466,117 @@ uint32_t nve0_grhub_code[] = {
        0x0007f101,
        0x0303f007,
        0xbd000fd0,
-/* 0x031b: init */
+/* 0x039b: init */
        0xbd00f804,
-       0x0004fe04,
-       0xf10007fe,
-       0xf0120017,
-       0x12d00227,
-       0xb117f100,
-       0x0010fe05,
-       0x040017f1,
-       0xf1c010d0,
-       0xb6040437,
-       0x27f10634,
-       0x32d02003,
-       0x0427f100,
-       0x0132d020,
+       0x0007fe04,
+       0x420017f1,
+       0xcf0013f0,
+       0x11e70011,
+       0x14b60109,
+       0x0014fe08,
+       0xf10227f0,
+       0xf0120007,
+       0x02d00003,
+       0xf104bd00,
+       0xfe06c817,
+       0x24bd0010,
+       0x070007f1,
+       0xd00003f0,
+       0x04bd0002,
+       0x200327f1,
+       0x010007f1,
+       0xd00103f0,
+       0x04bd0002,
+       0x200427f1,
+       0x010407f1,
+       0xd00103f0,
+       0x04bd0002,
        0x200b27f1,
-       0xf10232d0,
-       0xd0200c27,
-       0x27f10732,
-       0x24b60c24,
-       0x0003b906,
-       0xf10023d0,
+       0x010807f1,
+       0xd00103f0,
+       0x04bd0002,
+       0x200c27f1,
+       0x011c07f1,
+       0xd00103f0,
+       0x04bd0002,
+       0xf1010392,
+       0xf0090007,
+       0x03d00303,
+       0xf104bd00,
        0xf0870427,
-       0x12d00023,
-       0x0012b700,
-       0x0427f001,
-       0xf40012d0,
-       0xe7f11031,
-       0xe3f09604,
-       0x6821f440,
-       0x8090f1c7,
-       0xf4f00301,
-       0x020f801f,
-       0xbb0117f0,
-       0x12b6041f,
-       0x0c27f101,
-       0x0624b604,
-       0xd00021d0,
-       0x17f14021,
-       0x0e980100,
-       0x010f9800,
-       0x014721f5,
-       0x070037f1,
-       0x950634b6,
-       0x34d00814,
-       0x4034d000,
-       0x130030b7,
-       0xb6001fbb,
-       0x3fd002f5,
-       0x0815b600,
-       0xb60110b6,
-       0x1fb90814,
-       0x7121f502,
-       0x001fbb02,
-       0xf1020398,
-       0xf0200047,
-/* 0x03f6: init_gpc */
-       0x4ea05043,
-       0x1fb90804,
-       0x8d21f402,
-       0x010c4ea0,
-       0x21f4f4bd,
-       0x044ea08d,
-       0x8d21f401,
-       0x01004ea0,
-       0xf402f7f0,
-       0x4ea08d21,
-/* 0x041e: init_gpc_wait */
-       0x21f40800,
-       0x1fffc868,
-       0xa0fa0bf4,
-       0xf408044e,
-       0x1fbb6821,
-       0x0040b700,
-       0x0132b680,
-       0xf1be1bf4,
+       0x07f10023,
+       0x03f00400,
+       0x0002d000,
+       0x27f004bd,
+       0x0007f104,
+       0x0003f003,
+       0xbd0002d0,
+       0x1031f404,
+       0x9604e7f1,
+       0xf440e3f0,
+       0xfeb96821,
+       0x90f1c702,
+       0xf0030180,
+       0x0f801ff4,
+       0x0117f002,
+       0xb6041fbb,
+       0x07f10112,
+       0x03f00300,
+       0x0001d001,
+       0x07f104bd,
+       0x03f00400,
+       0x0001d001,
+       0x17f104bd,
+       0xf7f00100,
+       0x7f21f502,
+       0x9121f507,
+       0x10f7f007,
+       0x07de21f5,
+       0x98000e98,
+       0x21f5010f,
+       0x14950150,
+       0x0007f108,
+       0x0103f0c0,
+       0xbd0004d0,
+       0x0007f104,
+       0x0103f0c1,
+       0xbd0004d0,
+       0x0030b704,
+       0x001fbb13,
+       0xf102f5b6,
+       0xf0d30007,
+       0x0fd00103,
+       0xb604bd00,
+       0x10b60815,
+       0x0814b601,
+       0xf5021fb9,
+       0xbb02d321,
+       0x0398001f,
+       0x0047f102,
+       0x5043f020,
+/* 0x04f4: init_gpc */
+       0x08044ea0,
+       0xf4021fb9,
+       0x4ea09d21,
+       0xf4bd010c,
+       0xa09d21f4,
+       0xf401044e,
+       0x4ea09d21,
+       0xf7f00100,
+       0x9d21f402,
+       0x08004ea0,
+/* 0x051c: init_gpc_wait */
+       0xc86821f4,
+       0x0bf41fff,
+       0x044ea0fa,
+       0x6821f408,
+       0xb7001fbb,
+       0xb6800040,
+       0x1bf40132,
+       0x00f7f0be,
+       0x07de21f5,
+       0xf500f7f0,
+       0xf1077f21,
        0xf0010007,
        0x01d00203,
        0xbd04bd00,
@@ -519,382 +584,379 @@ uint32_t nve0_grhub_code[] = {
        0x080007f1,
        0xd00203f0,
        0x04bd0001,
-/* 0x0458: main */
+/* 0x0564: main */
        0xf40031f4,
        0xd7f00028,
        0x3921f410,
        0xb1f401f4,
        0xf54001e4,
-       0xbd00de1b,
+       0xbd00e91b,
        0x0499f094,
        0x0f0007f1,
        0xd00203f0,
        0x04bd0009,
-       0x0b0017f1,
-       0xcf0614b6,
-       0x11cf4012,
-       0x1f13c800,
-       0x00870bf5,
-       0xf41f23c8,
-       0x20f9620b,
-       0xbd0212b9,
-       0x0799f094,
-       0x0f0007f1,
-       0xd00203f0,
-       0x04bd0009,
-       0xf40132f4,
-       0x21f50231,
-       0x94bd0801,
+       0xc00017f1,
+       0xcf0213f0,
+       0x27f10011,
+       0x23f0c100,
+       0x0022cf02,
+       0xf51f13c8,
+       0xc800890b,
+       0x0bf41f23,
+       0xb920f962,
+       0x94bd0212,
        0xf10799f0,
-       0xf0170007,
+       0xf00f0007,
        0x09d00203,
-       0xfc04bd00,
-       0xf094bd20,
-       0x07f10699,
-       0x03f00f00,
-       0x0009d002,
-       0x31f404bd,
-       0x0121f501,
-       0xf094bd08,
-       0x07f10699,
+       0xf404bd00,
+       0x31f40132,
+       0xaa21f502,
+       0xf094bd09,
+       0x07f10799,
        0x03f01700,
        0x0009d002,
-       0x0ef404bd,
-/* 0x04f9: chsw_prev_no_next */
-       0xb920f931,
-       0x32f40212,
-       0x0232f401,
-       0x080121f5,
-       0x17f120fc,
-       0x14b60b00,
-       0x0012d006,
-/* 0x0517: chsw_no_prev */
-       0xc8130ef4,
-       0x0bf41f23,
-       0x0131f40d,
-       0xf50232f4,
-/* 0x0527: chsw_done */
-       0xf1080121,
-       0xb60b0c17,
-       0x27f00614,
-       0x0012d001,
+       0x20fc04bd,
        0x99f094bd,
-       0x0007f104,
+       0x0007f106,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0131f404,
+       0x09aa21f5,
+       0x99f094bd,
+       0x0007f106,
        0x0203f017,
        0xbd0009d0,
-       0x130ef504,
-/* 0x0549: main_not_ctx_switch */
-       0x01e4b0ff,
-       0xb90d1bf4,
-       0x21f502f2,
-       0x0ef40795,
-/* 0x0559: main_not_ctx_chan */
-       0x02e4b046,
-       0xbd321bf4,
-       0x0799f094,
-       0x0f0007f1,
+       0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+       0x12b920f9,
+       0x0132f402,
+       0xf50232f4,
+       0xfc09aa21,
+       0x0007f120,
+       0x0203f0c0,
+       0xbd0002d0,
+       0x130ef404,
+/* 0x062c: chsw_no_prev */
+       0xf41f23c8,
+       0x31f40d0b,
+       0x0232f401,
+       0x09aa21f5,
+/* 0x063c: chsw_done */
+       0xf10127f0,
+       0xf0c30007,
+       0x02d00203,
+       0xbd04bd00,
+       0x0499f094,
+       0x170007f1,
        0xd00203f0,
        0x04bd0009,
-       0xf40132f4,
-       0x21f50232,
-       0x94bd0801,
+       0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+       0xf401e4b0,
+       0xf2b90d1b,
+       0x4221f502,
+       0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+       0xf402e4b0,
+       0x94bd321b,
        0xf10799f0,
-       0xf0170007,
+       0xf00f0007,
        0x09d00203,
        0xf404bd00,
-/* 0x058e: main_not_ctx_save */
-       0xef94110e,
-       0x01f5f010,
-       0x02fe21f5,
-       0xfec00ef5,
-/* 0x059c: main_done */
-       0x29f024bd,
-       0x0007f11f,
-       0x0203f008,
-       0xbd0002d0,
-       0xab0ef504,
-/* 0x05b1: ih */
-       0xfe80f9fe,
-       0x80f90188,
-       0xa0f990f9,
-       0xd0f9b0f9,
-       0xf0f9e0f9,
-       0x0acf04bd,
-       0x04abc480,
-       0xf11d0bf4,
-       0xf01900b7,
-       0xbecf10d7,
-       0x00bfcf40,
+       0x32f40132,
+       0xaa21f502,
+       0xf094bd09,
+       0x07f10799,
+       0x03f01700,
+       0x0009d002,
+       0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+       0x10ef9411,
+       0xf501f5f0,
+       0xf5037e21,
+/* 0x06b3: main_done */
+       0xbdfeb50e,
+       0x1f29f024,
+       0x080007f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xfea00ef5,
+/* 0x06c8: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x00a7f104,
+       0x00a3f002,
+       0xc400aacf,
+       0x0bf404ab,
+       0x10d7f030,
+       0x1a00e7f1,
+       0xcf00e3f0,
+       0xf7f100ee,
+       0xf3f01900,
+       0x00ffcf00,
        0xb70421f4,
        0xf00400b0,
-       0xbed001e7,
-/* 0x05e9: ih_no_fifo */
-       0x00abe400,
-       0x0d0bf401,
-       0xf110d7f0,
-       0xf44001e7,
-/* 0x05fa: ih_no_ctxsw */
-       0xb7f10421,
-       0xb0bd0104,
-       0xf4b4abff,
-       0xa7f10d0b,
-       0xa4b60c1c,
-       0x00abd006,
-/* 0x0610: ih_no_other */
-       0xfc400ad0,
+       0x07f101e7,
+       0x03f01d00,
+       0x000ed000,
+/* 0x071a: ih_no_fifo */
+       0xabe404bd,
+       0x0bf40100,
+       0x10d7f00d,
+       0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+       0xe40421f4,
+       0xf40400ab,
+       0xb7f1140b,
+       0xbfb90100,
+       0x44e7f102,
+       0x40e3f001,
+/* 0x0743: ih_no_fwmthd */
+       0xf19d21f4,
+       0xbd0104b7,
+       0xb4abffb0,
+       0xf10f0bf4,
+       0xf0070007,
+       0x0bd00303,
+/* 0x075b: ih_no_other */
+       0xf104bd00,
+       0xf0010007,
+       0x0ad00003,
+       0xfc04bd00,
        0xfce0fcf0,
        0xfcb0fcd0,
        0xfc90fca0,
        0x0088fe80,
        0x32f480fc,
-/* 0x062b: ctx_4170s */
-       0xf101f800,
-       0xf04170e7,
-       0xf5f040e3,
-       0x8d21f410,
-/* 0x063a: ctx_4170w */
+/* 0x077f: ctx_4170s */
+       0xf001f800,
+       0xffb910f5,
+       0x70e7f102,
+       0x40e3f041,
+       0xf89d21f4,
+/* 0x0791: ctx_4170w */
+       0x70e7f100,
+       0x40e3f041,
+       0xb96821f4,
+       0xf4f002ff,
+       0xf01bf410,
+/* 0x07a6: ctx_redswitch */
        0xe7f100f8,
-       0xe3f04170,
-       0x6821f440,
-       0xf410f4f0,
+       0xe5f00200,
+       0x20e5f040,
+       0xf110e5f0,
+       0xf0850007,
+       0x0ed00103,
+       0xf004bd00,
+/* 0x07c2: ctx_redswitch_delay */
+       0xf2b608f7,
+       0xfd1bf401,
+       0x0400e5f1,
+       0x0100e5f1,
+       0x850007f1,
+       0xd00103f0,
+       0x04bd000e,
+/* 0x07de: ctx_86c */
+       0x07f100f8,
+       0x03f01b00,
+       0x000fd002,
+       0xffb904bd,
+       0x14e7f102,
+       0x40e3f08a,
+       0xb99d21f4,
+       0xe7f102ff,
+       0xe3f0a86c,
+       0x9d21f441,
+/* 0x0806: ctx_mem */
+       0x07f100f8,
+       0x03f08400,
+       0x000fd002,
+/* 0x0812: ctx_mem_wait */
+       0xf7f104bd,
+       0xf3f08400,
+       0x00ffcf02,
+       0xf405fffd,
        0x00f8f31b,
-/* 0x064c: ctx_redswitch */
-       0x0614e7f1,
-       0xf106e4b6,
-       0xd00270f7,
-       0xf7f000ef,
-/* 0x065d: ctx_redswitch_delay */
-       0x01f2b608,
-       0xf1fd1bf4,
-       0xd00770f7,
-       0x00f800ef,
-/* 0x066c: ctx_86c */
-       0x086ce7f1,
-       0xd006e4b6,
-       0xe7f100ef,
-       0xe3f08a14,
-       0x8d21f440,
-       0xa86ce7f1,
-       0xf441e3f0,
-       0x00f88d21,
-/* 0x068c: ctx_load */
+/* 0x0824: ctx_load */
        0x99f094bd,
        0x0007f105,
        0x0203f00f,
        0xbd0009d0,
        0x0ca7f004,
-       0xf1c921f4,
-       0xb60a2417,
-       0x10d00614,
-       0x0037f100,
-       0x0634b60b,
-       0xf14032d0,
-       0xb60a0c17,
-       0x47f00614,
-       0x0012d007,
-/* 0x06c7: ctx_chan_wait_0 */
-       0xcf4014d0,
-       0x44f04014,
-       0xfa1bf41f,
-       0xfe0032d0,
-       0x2af0000b,
-       0x0424b61f,
-       0xbd0220b6,
+       0xbdd021f4,
+       0x0007f1f4,
+       0x0203f089,
+       0xbd000fd0,
+       0x0007f104,
+       0x0203f0c1,
+       0xbd0002d0,
+       0x0007f104,
+       0x0203f083,
+       0xbd0002d0,
+       0x07f7f004,
+       0x080621f5,
+       0xc00007f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xf0000bfe,
+       0x24b61f2a,
+       0x0220b604,
+       0x99f094bd,
+       0x0007f108,
+       0x0203f00f,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f081,
+       0xbd0002d0,
+       0x0027f104,
+       0x0023f100,
+       0x0225f080,
+       0x880007f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xf11017f0,
+       0xf0020027,
+       0x12fa0223,
+       0xbd03f805,
        0x0899f094,
-       0x0f0007f1,
+       0x170007f1,
        0xd00203f0,
        0x04bd0009,
-       0x0a0417f1,
-       0xd00614b6,
-       0x17f10012,
-       0x14b60a20,
-       0x0227f006,
-       0x800023f1,
-       0xf00012d0,
-       0x27f11017,
-       0x23f00200,
-       0x0512fa02,
-       0x94bd03f8,
-       0xf10899f0,
-       0xf0170007,
+       0xb6810198,
+       0x02981814,
+       0x0825b680,
+       0x800512fd,
+       0x94bd1601,
+       0xf10999f0,
+       0xf00f0007,
        0x09d00203,
-       0x9804bd00,
-       0x14b68101,
-       0x80029818,
-       0xfd0825b6,
-       0x01800512,
-       0xf094bd16,
-       0x07f10999,
-       0x03f00f00,
-       0x0009d002,
-       0x27f104bd,
-       0x24b60a04,
-       0x0021d006,
-       0xf10127f0,
-       0xb60a2017,
-       0x12d00614,
-       0x0017f100,
-       0x0613f001,
-       0xf80501fa,
-       0xf094bd03,
-       0x07f10999,
-       0x03f01700,
-       0x0009d002,
-       0x94bd04bd,
-       0xf10599f0,
+       0xf104bd00,
+       0xf0810007,
+       0x01d00203,
+       0xf004bd00,
+       0x07f10127,
+       0x03f08800,
+       0x0002d002,
+       0x17f104bd,
+       0x13f00100,
+       0x0501fa06,
+       0x94bd03f8,
+       0xf10999f0,
        0xf0170007,
        0x09d00203,
-       0xf804bd00,
-/* 0x0795: ctx_chan */
-       0x8c21f500,
-       0x0ca7f006,
-       0xf1c921f4,
-       0xb60a1017,
-       0x27f00614,
-       0x0012d005,
-/* 0x07ac: ctx_chan_wait */
-       0xfd0012cf,
-       0x1bf40522,
-/* 0x07b7: ctx_mmio_exec */
-       0x9800f8fa,
-       0x27f14103,
-       0x24b60a04,
-       0x0023d006,
-/* 0x07c6: ctx_mmio_loop */
+       0xbd04bd00,
+       0x0599f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x0942: ctx_chan */
+       0x21f500f8,
+       0xa7f00824,
+       0xd021f40c,
+       0xf505f7f0,
+       0xf8080621,
+/* 0x0955: ctx_mmio_exec */
+       0x41039800,
+       0x810007f1,
+       0xd00203f0,
+       0x04bd0003,
+/* 0x0966: ctx_mmio_loop */
        0x34c434bd,
        0x0f1bf4ff,
        0x020057f1,
        0xfa0653f0,
        0x03f80535,
-/* 0x07d8: ctx_mmio_pull */
+/* 0x0978: ctx_mmio_pull */
        0x98804e98,
        0x21f4814f,
-       0x0830b68d,
+       0x0830b69d,
        0xf40112b6,
-/* 0x07ea: ctx_mmio_done */
+/* 0x098a: ctx_mmio_done */
        0x0398df1b,
-       0x0023d016,
-       0xf1400080,
-       0xf0010017,
-       0x01fa0613,
-       0xf803f806,
-/* 0x0801: ctx_xfer */
-       0x00f7f100,
-       0x06f4b60c,
-       0xd004e7f0,
-/* 0x080e: ctx_xfer_idle */
-       0xfecf80fe,
-       0x00e4f100,
-       0xf91bf420,
-       0xf40611f4,
-/* 0x081e: ctx_xfer_pre */
-       0xf7f00d02,
-       0x6c21f510,
-       0x1c11f406,
-/* 0x0828: ctx_xfer_pre_load */
-       0xf502f7f0,
-       0xf5062b21,
-       0xf5063a21,
-       0xbd064c21,
-       0x2b21f5f4,
-       0x8c21f506,
-/* 0x0841: ctx_xfer_exec */
-       0x16019806,
-       0x041427f1,
-       0xd00624b6,
-       0xe7f10020,
-       0xe3f0a500,
-       0x021fb941,
-       0xb68d21f4,
-       0xfcf004e0,
-       0x022cf001,
-       0xfd0124b6,
-       0x21f405f2,
-       0xfc17f18d,
-       0x0213f04a,
-       0xd00c27f0,
-       0x21f50012,
-       0x27f10215,
-       0x23f047fc,
-       0x0020d002,
+       0x0007f116,
+       0x0203f081,
+       0xbd0003d0,
+       0x40008004,
+       0x010017f1,
+       0xfa0613f0,
+       0x03f80601,
+/* 0x09aa: ctx_xfer */
+       0xe7f000f8,
+       0x0007f104,
+       0x0303f002,
+       0xbd000ed0,
+/* 0x09b9: ctx_xfer_idle */
+       0x00e7f104,
+       0x03e3f000,
+       0xf100eecf,
+       0xf42000e4,
+       0x11f4f21b,
+       0x0d02f406,
+/* 0x09d0: ctx_xfer_pre */
+       0xf510f7f0,
+       0xf407de21,
+/* 0x09da: ctx_xfer_pre_load */
+       0xf7f01c11,
+       0x7f21f502,
+       0x9121f507,
+       0xa621f507,
+       0xf5f4bd07,
+       0xf5077f21,
+/* 0x09f3: ctx_xfer_exec */
+       0x98082421,
+       0x24bd1601,
+       0x050007f1,
+       0xd00103f0,
+       0x04bd0002,
+       0xf1021fb9,
+       0xf0a500e7,
+       0x21f441e3,
+       0x01fcf09d,
+       0xb6022cf0,
+       0xf2fd0124,
+       0x02ffb905,
+       0xa504e7f1,
+       0xf441e3f0,
+       0x21f59d21,
+       0x24bd026a,
+       0x47fc07f1,
+       0xd00203f0,
+       0x04bd0002,
        0xb6012cf0,
-       0x12d00320,
-       0x01acf000,
-       0xf006a5f0,
-       0x0c9800b7,
-       0x010d9800,
-       0xf500e7f0,
-       0xf0016621,
-       0x21f508a7,
-       0x21f50109,
-       0x01f40215,
-       0x0ca7f022,
-       0xf1c921f4,
-       0xb60a1017,
-       0x27f00614,
-       0x0012d005,
-/* 0x08c8: ctx_xfer_post_save_wait */
-       0xfd0012cf,
-       0x1bf40522,
-       0x2e02f4fa,
-/* 0x08d4: ctx_xfer_post */
-       0xf502f7f0,
-       0xbd062b21,
-       0x6c21f5f4,
-       0x3421f506,
-       0x3a21f502,
-       0xf5f4bd06,
-       0xf4062b21,
-       0x01981011,
-       0x0511fd40,
-       0xf5070bf4,
-/* 0x08ff: ctx_xfer_no_post_mmio */
-/* 0x08ff: ctx_xfer_done */
-       0xf807b721,
-       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,
+       0x07f10320,
+       0x03f04afc,
+       0x0002d002,
+       0xacf004bd,
+       0x06a5f001,
+       0x9800b7f0,
+       0x0d98000c,
+       0x00e7f001,
+       0x016f21f5,
+       0xf508a7f0,
+       0xf5011021,
+       0xf4025e21,
+       0xa7f01301,
+       0xd021f40c,
+       0xf505f7f0,
+       0xf4080621,
+/* 0x0a82: ctx_xfer_post */
+       0xf7f02e02,
+       0x7f21f502,
+       0xf5f4bd07,
+       0xf507de21,
+       0xf5027f21,
+       0xbd079121,
+       0x7f21f5f4,
+       0x1011f407,
+       0xfd400198,
+       0x0bf40511,
+       0x5521f507,
+/* 0x0aad: ctx_xfer_no_post_mmio */
+/* 0x0aad: ctx_xfer_done */
+       0x0000f809,
        0x00000000,
        0x00000000,
        0x00000000,
index 438506d1474992af9d35ee538282594984a4d81f..229c0ae3722844c16d39e33fb669b677bcefa13c 100644 (file)
@@ -206,14 +206,14 @@ uint32_t nvf0_grhub_data[] = {
 };
 
 uint32_t nvf0_grhub_code[] = {
-       0x031b0ef5,
+       0x039b0ef5,
 /* 0x0004: queue_put */
        0x9800d898,
        0x86f001d9,
        0x0489b808,
        0xf00c1bf4,
        0x21f502f7,
-       0x00f802fe,
+       0x00f8037e,
 /* 0x001c: queue_put_next */
        0xb60798c4,
        0x8dbb0384,
@@ -237,184 +237,214 @@ uint32_t nvf0_grhub_code[] = {
 /* 0x0066: queue_get_done */
        0x00f80132,
 /* 0x0068: nv_rd32 */
-       0x0728b7f1,
-       0xb906b4b6,
-       0xc9f002ec,
-       0x00bcd01f,
-/* 0x0078: nv_rd32_wait */
-       0xc800bccf,
-       0x1bf41fcc,
-       0x06a7f0fa,
-       0x010921f5,
-       0xf840bfcf,
-/* 0x008d: nv_wr32 */
-       0x28b7f100,
-       0x06b4b607,
-       0xb980bfd0,
-       0xc9f002ec,
-       0x1ec9f01f,
-/* 0x00a3: nv_wr32_wait */
-       0xcf00bcd0,
-       0xccc800bc,
-       0xfa1bf41f,
-/* 0x00ae: watchdog_reset */
-       0x87f100f8,
-       0x84b60430,
-       0x1ff9f006,
-       0xf8008fd0,
-/* 0x00bd: watchdog_clear */
-       0x3087f100,
-       0x0684b604,
-       0xf80080d0,
-/* 0x00c9: wait_donez */
-       0xf094bd00,
-       0x07f10099,
-       0x03f03700,
-       0x0009d002,
-       0x07f104bd,
-       0x03f00600,
-       0x000ad002,
-/* 0x00e6: wait_donez_ne */
-       0x87f104bd,
-       0x83f00000,
-       0x0088cf01,
-       0xf4888aff,
-       0x94bdf31b,
-       0xf10099f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0109: wait_doneo */
-       0xf094bd00,
+       0xf002ecb9,
+       0x07f11fc9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x007a: nv_rd32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0xa7f0f31b,
+       0x1021f506,
+       0x00f7f101,
+       0x01f3f0cb,
+       0xf800ffcf,
+/* 0x009d: nv_wr32 */
+       0x0007f100,
+       0x0103f0cc,
+       0xbd000fd0,
+       0x02ecb904,
+       0xf01fc9f0,
+       0x07f11ec9,
+       0x03f0ca00,
+       0x000cd001,
+/* 0x00be: nv_wr32_wait */
+       0xc7f104bd,
+       0xc3f0ca00,
+       0x00cccf01,
+       0xf41fccc8,
+       0x00f8f31b,
+/* 0x00d0: wait_donez */
+       0x99f094bd,
+       0x0007f100,
+       0x0203f037,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x1bf4888a,
+       0xf094bdf3,
        0x07f10099,
-       0x03f03700,
+       0x03f01700,
        0x0009d002,
-       0x87f104bd,
-       0x84b60818,
-       0x008ad006,
-/* 0x0124: wait_doneo_e */
-       0x040087f1,
-       0xcf0684b6,
-       0x8aff0088,
-       0xf30bf488,
+       0x00f804bd,
+/* 0x0110: wait_doneo */
        0x99f094bd,
        0x0007f100,
-       0x0203f017,
+       0x0203f037,
        0xbd0009d0,
-/* 0x0147: mmctx_size */
-       0xbd00f804,
-/* 0x0149: nv_mmctx_size_loop */
-       0x00e89894,
-       0xb61a85b6,
-       0x84b60180,
-       0x0098bb02,
-       0xb804e0b6,
-       0x1bf404ef,
-       0x029fb9eb,
-/* 0x0166: mmctx_xfer */
-       0x94bd00f8,
-       0xf10199f0,
-       0xf0370007,
-       0x09d00203,
-       0xf104bd00,
-       0xb6071087,
-       0x94bd0684,
-       0xf405bbfd,
-       0x8bd0090b,
-       0x0099f000,
-/* 0x018c: mmctx_base_disabled */
-       0xf405eefd,
-       0x8ed00c0b,
-       0xc08fd080,
-/* 0x019b: mmctx_multi_disabled */
-       0xb70199f0,
-       0xc8010080,
+       0x0007f104,
+       0x0203f006,
+       0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+       0x0087f104,
+       0x0183f000,
+       0xff0088cf,
+       0x0bf4888a,
+       0xf094bdf3,
+       0x07f10099,
+       0x03f01700,
+       0x0009d002,
+       0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+       0xe89894bd,
+       0x1a85b600,
+       0xb60180b6,
+       0x98bb0284,
+       0x04e0b600,
+       0xf404efb8,
+       0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+       0xbd00f802,
+       0x0199f094,
+       0x370007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0xbbfd94bd,
+       0x120bf405,
+       0xc40007f1,
+       0xd00103f0,
+       0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+       0xfd0099f0,
+       0x0bf405ee,
+       0x0007f11e,
+       0x0103f0c6,
+       0xbd000ed0,
+       0x0007f104,
+       0x0103f0c7,
+       0xbd000fd0,
+       0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+       0xb600abc8,
+       0xb9f010b4,
+       0x01aec80c,
+       0xfd11e4b6,
+       0x07f105be,
+       0x03f0c500,
+       0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+       0xe7f104bd,
+       0xe3f0c500,
+       0x00eecf01,
+       0xf41fe4f0,
+       0xce98f30b,
+       0x05e9fd00,
+       0xc80007f1,
+       0xd00103f0,
+       0x04bd000e,
+       0xb804c0b6,
+       0x1bf404cd,
+       0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+       0xf11f1bf4,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x1fb4f000,
+       0xf410b4b0,
+       0xa7f0f01b,
+       0xd021f402,
+/* 0x0223: mmctx_stop */
+       0xc82b0ef4,
        0xb4b600ab,
        0x0cb9f010,
-       0xb601aec8,
-       0xbefd11e4,
-       0x008bd005,
-/* 0x01b4: mmctx_exec_loop */
-/* 0x01b4: mmctx_wait_free */
-       0xf0008ecf,
-       0x0bf41fe4,
-       0x00ce98fa,
-       0xd005e9fd,
-       0xc0b6c08e,
-       0x04cdb804,
-       0xc8e81bf4,
-       0x1bf402ab,
-/* 0x01d5: mmctx_fini_wait */
-       0x008bcf18,
-       0xb01fb4f0,
-       0x1bf410b4,
-       0x02a7f0f7,
-       0xf4c921f4,
-/* 0x01ea: mmctx_stop */
-       0xabc81b0e,
-       0x10b4b600,
-       0xf00cb9f0,
-       0x8bd012b9,
-/* 0x01f9: mmctx_stop_wait */
-       0x008bcf00,
-       0xf412bbc8,
-/* 0x0202: mmctx_done */
-       0x94bdfa1b,
-       0xf10199f0,
-       0xf0170007,
-       0x09d00203,
-       0xf804bd00,
-/* 0x0215: strand_wait */
-       0xf0a0f900,
-       0x21f402a7,
-       0xf8a0fcc9,
-/* 0x0221: strand_pre */
-       0xfc87f100,
-       0x0283f04a,
-       0xd00c97f0,
-       0x21f50089,
-       0x00f80215,
-/* 0x0234: strand_post */
-       0x4afc87f1,
-       0xf00283f0,
-       0x89d00d97,
-       0x1521f500,
-/* 0x0247: strand_set */
-       0xf100f802,
-       0xf04ffca7,
-       0xaba202a3,
-       0xc7f00500,
-       0x00acd00f,
-       0xd00bc7f0,
-       0x21f500bc,
-       0xaed00215,
-       0x0ac7f000,
-       0xf500bcd0,
-       0xf8021521,
-/* 0x0271: strand_ctx_init */
-       0xf094bd00,
-       0x07f10399,
-       0x03f03700,
+       0xf112b9f0,
+       0xf0c50007,
+       0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+       0xf104bd00,
+       0xf0c500b7,
+       0xbbcf01b3,
+       0x12bbc800,
+/* 0x024b: mmctx_done */
+       0xbdf31bf4,
+       0x0199f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x025e: strand_wait */
+       0xa0f900f8,
+       0xf402a7f0,
+       0xa0fcd021,
+/* 0x026a: strand_pre */
+       0x97f000f8,
+       0xfc07f10c,
+       0x0203f04a,
+       0xbd0009d0,
+       0x5e21f504,
+/* 0x027f: strand_post */
+       0xf000f802,
+       0x07f10d97,
+       0x03f04afc,
        0x0009d002,
        0x21f504bd,
-       0xe7f00221,
-       0x4721f503,
-       0xfca7f102,
-       0x02a3f046,
-       0x0400aba0,
-       0xf040a0d0,
-       0xbcd001c7,
-       0x1521f500,
-       0x010c9202,
-       0xf000acd0,
-       0xbcd002c7,
-       0x1521f500,
-       0x3421f502,
-       0x8087f102,
-       0x0684b608,
-       0xb70089cf,
-       0x95220080,
-/* 0x02ca: ctx_init_strand_loop */
+       0x00f8025e,
+/* 0x0294: strand_set */
+       0xf10fc7f0,
+       0xf04ffc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f10bc7,
+       0x03f04afc,
+       0x000cd002,
+       0x07f104bd,
+       0x03f04ffc,
+       0x000ed002,
+       0xc7f004bd,
+       0xfc07f10a,
+       0x0203f04a,
+       0xbd000cd0,
+       0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+       0xbd00f802,
+       0x0399f094,
+       0x370007f1,
+       0xd00203f0,
+       0x04bd0009,
+       0x026a21f5,
+       0xf503e7f0,
+       0xbd029421,
+       0xfc07f1c4,
+       0x0203f047,
+       0xbd000cd0,
+       0x01c7f004,
+       0x4afc07f1,
+       0xd00203f0,
+       0x04bd000c,
+       0x025e21f5,
+       0xf1010c92,
+       0xf046fc07,
+       0x0cd00203,
+       0xf004bd00,
+       0x07f102c7,
+       0x03f04afc,
+       0x000cd002,
+       0x21f504bd,
+       0x21f5025e,
+       0x87f1027f,
+       0x83f04200,
+       0x0097f102,
+       0x0293f020,
+       0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
        0x8ed008fe,
        0x408ed000,
        0xb6808acf,
@@ -428,7 +458,7 @@ uint32_t nvf0_grhub_code[] = {
        0x170007f1,
        0xd00203f0,
        0x04bd0009,
-/* 0x02fe: error */
+/* 0x037e: error */
        0x07f100f8,
        0x03f00500,
        0x000fd002,
@@ -436,82 +466,117 @@ uint32_t nvf0_grhub_code[] = {
        0x0007f101,
        0x0303f007,
        0xbd000fd0,
-/* 0x031b: init */
+/* 0x039b: init */
        0xbd00f804,
-       0x0004fe04,
-       0xf10007fe,
-       0xf0120017,
-       0x12d00227,
-       0xb117f100,
-       0x0010fe05,
-       0x040017f1,
-       0xf1c010d0,
-       0xb6040437,
-       0x27f10634,
-       0x32d02003,
-       0x0427f100,
-       0x0132d020,
+       0x0007fe04,
+       0x420017f1,
+       0xcf0013f0,
+       0x11e70011,
+       0x14b60109,
+       0x0014fe08,
+       0xf10227f0,
+       0xf0120007,
+       0x02d00003,
+       0xf104bd00,
+       0xfe06c817,
+       0x24bd0010,
+       0x070007f1,
+       0xd00003f0,
+       0x04bd0002,
+       0x200327f1,
+       0x010007f1,
+       0xd00103f0,
+       0x04bd0002,
+       0x200427f1,
+       0x010407f1,
+       0xd00103f0,
+       0x04bd0002,
        0x200b27f1,
-       0xf10232d0,
-       0xd0200c27,
-       0x27f10732,
-       0x24b60c24,
-       0x0003b906,
-       0xf10023d0,
+       0x010807f1,
+       0xd00103f0,
+       0x04bd0002,
+       0x200c27f1,
+       0x011c07f1,
+       0xd00103f0,
+       0x04bd0002,
+       0xf1010392,
+       0xf0090007,
+       0x03d00303,
+       0xf104bd00,
        0xf0870427,
-       0x12d00023,
-       0x0012b700,
-       0x0427f001,
-       0xf40012d0,
-       0xe7f11031,
-       0xe3f09604,
-       0x6821f440,
-       0x8090f1c7,
-       0xf4f00301,
-       0x020f801f,
-       0xbb0117f0,
-       0x12b6041f,
-       0x0c27f101,
-       0x0624b604,
-       0xd00021d0,
-       0x17f14021,
-       0x0e980100,
-       0x010f9800,
-       0x014721f5,
-       0x070037f1,
-       0x950634b6,
-       0x34d00814,
-       0x4034d000,
-       0x130030b7,
-       0xb6001fbb,
-       0x3fd002f5,
-       0x0815b600,
-       0xb60110b6,
-       0x1fb90814,
-       0x7121f502,
-       0x001fbb02,
-       0xf1020398,
-       0xf0200047,
-/* 0x03f6: init_gpc */
-       0x4ea05043,
-       0x1fb90804,
-       0x8d21f402,
-       0x010c4ea0,
-       0x21f4f4bd,
-       0x044ea08d,
-       0x8d21f401,
-       0x01004ea0,
-       0xf402f7f0,
-       0x4ea08d21,
-/* 0x041e: init_gpc_wait */
-       0x21f40800,
-       0x1fffc868,
-       0xa0fa0bf4,
-       0xf408044e,
-       0x1fbb6821,
-       0x0040b700,
-       0x0132b680,
-       0xf1be1bf4,
+       0x07f10023,
+       0x03f00400,
+       0x0002d000,
+       0x27f004bd,
+       0x0007f104,
+       0x0003f003,
+       0xbd0002d0,
+       0x1031f404,
+       0x9604e7f1,
+       0xf440e3f0,
+       0xfeb96821,
+       0x90f1c702,
+       0xf0030180,
+       0x0f801ff4,
+       0x0117f002,
+       0xb6041fbb,
+       0x07f10112,
+       0x03f00300,
+       0x0001d001,
+       0x07f104bd,
+       0x03f00400,
+       0x0001d001,
+       0x17f104bd,
+       0xf7f00100,
+       0x7f21f502,
+       0x9121f507,
+       0x10f7f007,
+       0x07de21f5,
+       0x98000e98,
+       0x21f5010f,
+       0x14950150,
+       0x0007f108,
+       0x0103f0c0,
+       0xbd0004d0,
+       0x0007f104,
+       0x0103f0c1,
+       0xbd0004d0,
+       0x0030b704,
+       0x001fbb13,
+       0xf102f5b6,
+       0xf0d30007,
+       0x0fd00103,
+       0xb604bd00,
+       0x10b60815,
+       0x0814b601,
+       0xf5021fb9,
+       0xbb02d321,
+       0x0398001f,
+       0x0047f102,
+       0x5043f020,
+/* 0x04f4: init_gpc */
+       0x08044ea0,
+       0xf4021fb9,
+       0x4ea09d21,
+       0xf4bd010c,
+       0xa09d21f4,
+       0xf401044e,
+       0x4ea09d21,
+       0xf7f00100,
+       0x9d21f402,
+       0x08004ea0,
+/* 0x051c: init_gpc_wait */
+       0xc86821f4,
+       0x0bf41fff,
+       0x044ea0fa,
+       0x6821f408,
+       0xb7001fbb,
+       0xb6800040,
+       0x1bf40132,
+       0x00f7f0be,
+       0x07de21f5,
+       0xf500f7f0,
+       0xf1077f21,
        0xf0010007,
        0x01d00203,
        0xbd04bd00,
@@ -519,382 +584,379 @@ uint32_t nvf0_grhub_code[] = {
        0x300007f1,
        0xd00203f0,
        0x04bd0001,
-/* 0x0458: main */
+/* 0x0564: main */
        0xf40031f4,
        0xd7f00028,
        0x3921f410,
        0xb1f401f4,
        0xf54001e4,
-       0xbd00de1b,
+       0xbd00e91b,
        0x0499f094,
        0x370007f1,
        0xd00203f0,
        0x04bd0009,
-       0x0b0017f1,
-       0xcf0614b6,
-       0x11cf4012,
-       0x1f13c800,
-       0x00870bf5,
-       0xf41f23c8,
-       0x20f9620b,
-       0xbd0212b9,
-       0x0799f094,
-       0x370007f1,
-       0xd00203f0,
-       0x04bd0009,
-       0xf40132f4,
-       0x21f50231,
-       0x94bd0801,
+       0xc00017f1,
+       0xcf0213f0,
+       0x27f10011,
+       0x23f0c100,
+       0x0022cf02,
+       0xf51f13c8,
+       0xc800890b,
+       0x0bf41f23,
+       0xb920f962,
+       0x94bd0212,
        0xf10799f0,
-       0xf0170007,
+       0xf0370007,
        0x09d00203,
-       0xfc04bd00,
-       0xf094bd20,
-       0x07f10699,
-       0x03f03700,
-       0x0009d002,
-       0x31f404bd,
-       0x0121f501,
-       0xf094bd08,
-       0x07f10699,
+       0xf404bd00,
+       0x31f40132,
+       0xaa21f502,
+       0xf094bd09,
+       0x07f10799,
        0x03f01700,
        0x0009d002,
-       0x0ef404bd,
-/* 0x04f9: chsw_prev_no_next */
-       0xb920f931,
-       0x32f40212,
-       0x0232f401,
-       0x080121f5,
-       0x17f120fc,
-       0x14b60b00,
-       0x0012d006,
-/* 0x0517: chsw_no_prev */
-       0xc8130ef4,
-       0x0bf41f23,
-       0x0131f40d,
-       0xf50232f4,
-/* 0x0527: chsw_done */
-       0xf1080121,
-       0xb60b0c17,
-       0x27f00614,
-       0x0012d001,
+       0x20fc04bd,
        0x99f094bd,
-       0x0007f104,
+       0x0007f106,
+       0x0203f037,
+       0xbd0009d0,
+       0x0131f404,
+       0x09aa21f5,
+       0x99f094bd,
+       0x0007f106,
        0x0203f017,
        0xbd0009d0,
-       0x130ef504,
-/* 0x0549: main_not_ctx_switch */
-       0x01e4b0ff,
-       0xb90d1bf4,
-       0x21f502f2,
-       0x0ef40795,
-/* 0x0559: main_not_ctx_chan */
-       0x02e4b046,
-       0xbd321bf4,
-       0x0799f094,
-       0x370007f1,
+       0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+       0x12b920f9,
+       0x0132f402,
+       0xf50232f4,
+       0xfc09aa21,
+       0x0007f120,
+       0x0203f0c0,
+       0xbd0002d0,
+       0x130ef404,
+/* 0x062c: chsw_no_prev */
+       0xf41f23c8,
+       0x31f40d0b,
+       0x0232f401,
+       0x09aa21f5,
+/* 0x063c: chsw_done */
+       0xf10127f0,
+       0xf0c30007,
+       0x02d00203,
+       0xbd04bd00,
+       0x0499f094,
+       0x170007f1,
        0xd00203f0,
        0x04bd0009,
-       0xf40132f4,
-       0x21f50232,
-       0x94bd0801,
+       0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+       0xf401e4b0,
+       0xf2b90d1b,
+       0x4221f502,
+       0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+       0xf402e4b0,
+       0x94bd321b,
        0xf10799f0,
-       0xf0170007,
+       0xf0370007,
        0x09d00203,
        0xf404bd00,
-/* 0x058e: main_not_ctx_save */
-       0xef94110e,
-       0x01f5f010,
-       0x02fe21f5,
-       0xfec00ef5,
-/* 0x059c: main_done */
-       0x29f024bd,
-       0x0007f11f,
-       0x0203f030,
-       0xbd0002d0,
-       0xab0ef504,
-/* 0x05b1: ih */
-       0xfe80f9fe,
-       0x80f90188,
-       0xa0f990f9,
-       0xd0f9b0f9,
-       0xf0f9e0f9,
-       0x0acf04bd,
-       0x04abc480,
-       0xf11d0bf4,
-       0xf01900b7,
-       0xbecf10d7,
-       0x00bfcf40,
+       0x32f40132,
+       0xaa21f502,
+       0xf094bd09,
+       0x07f10799,
+       0x03f01700,
+       0x0009d002,
+       0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+       0x10ef9411,
+       0xf501f5f0,
+       0xf5037e21,
+/* 0x06b3: main_done */
+       0xbdfeb50e,
+       0x1f29f024,
+       0x300007f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xfea00ef5,
+/* 0x06c8: ih */
+       0x88fe80f9,
+       0xf980f901,
+       0xf9a0f990,
+       0xf9d0f9b0,
+       0xbdf0f9e0,
+       0x00a7f104,
+       0x00a3f002,
+       0xc400aacf,
+       0x0bf404ab,
+       0x10d7f030,
+       0x1a00e7f1,
+       0xcf00e3f0,
+       0xf7f100ee,
+       0xf3f01900,
+       0x00ffcf00,
        0xb70421f4,
        0xf00400b0,
-       0xbed001e7,
-/* 0x05e9: ih_no_fifo */
-       0x00abe400,
-       0x0d0bf401,
-       0xf110d7f0,
-       0xf44001e7,
-/* 0x05fa: ih_no_ctxsw */
-       0xb7f10421,
-       0xb0bd0104,
-       0xf4b4abff,
-       0xa7f10d0b,
-       0xa4b60c1c,
-       0x00abd006,
-/* 0x0610: ih_no_other */
-       0xfc400ad0,
+       0x07f101e7,
+       0x03f01d00,
+       0x000ed000,
+/* 0x071a: ih_no_fifo */
+       0xabe404bd,
+       0x0bf40100,
+       0x10d7f00d,
+       0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+       0xe40421f4,
+       0xf40400ab,
+       0xb7f1140b,
+       0xbfb90100,
+       0x44e7f102,
+       0x40e3f001,
+/* 0x0743: ih_no_fwmthd */
+       0xf19d21f4,
+       0xbd0104b7,
+       0xb4abffb0,
+       0xf10f0bf4,
+       0xf0070007,
+       0x0bd00303,
+/* 0x075b: ih_no_other */
+       0xf104bd00,
+       0xf0010007,
+       0x0ad00003,
+       0xfc04bd00,
        0xfce0fcf0,
        0xfcb0fcd0,
        0xfc90fca0,
        0x0088fe80,
        0x32f480fc,
-/* 0x062b: ctx_4170s */
-       0xf101f800,
-       0xf04170e7,
-       0xf5f040e3,
-       0x8d21f410,
-/* 0x063a: ctx_4170w */
+/* 0x077f: ctx_4170s */
+       0xf001f800,
+       0xffb910f5,
+       0x70e7f102,
+       0x40e3f041,
+       0xf89d21f4,
+/* 0x0791: ctx_4170w */
+       0x70e7f100,
+       0x40e3f041,
+       0xb96821f4,
+       0xf4f002ff,
+       0xf01bf410,
+/* 0x07a6: ctx_redswitch */
        0xe7f100f8,
-       0xe3f04170,
-       0x6821f440,
-       0xf410f4f0,
+       0xe5f00200,
+       0x20e5f040,
+       0xf110e5f0,
+       0xf0850007,
+       0x0ed00103,
+       0xf004bd00,
+/* 0x07c2: ctx_redswitch_delay */
+       0xf2b608f7,
+       0xfd1bf401,
+       0x0400e5f1,
+       0x0100e5f1,
+       0x850007f1,
+       0xd00103f0,
+       0x04bd000e,
+/* 0x07de: ctx_86c */
+       0x07f100f8,
+       0x03f02300,
+       0x000fd002,
+       0xffb904bd,
+       0x14e7f102,
+       0x40e3f08a,
+       0xb99d21f4,
+       0xe7f102ff,
+       0xe3f0a88c,
+       0x9d21f441,
+/* 0x0806: ctx_mem */
+       0x07f100f8,
+       0x03f08400,
+       0x000fd002,
+/* 0x0812: ctx_mem_wait */
+       0xf7f104bd,
+       0xf3f08400,
+       0x00ffcf02,
+       0xf405fffd,
        0x00f8f31b,
-/* 0x064c: ctx_redswitch */
-       0x0614e7f1,
-       0xf106e4b6,
-       0xd00270f7,
-       0xf7f000ef,
-/* 0x065d: ctx_redswitch_delay */
-       0x01f2b608,
-       0xf1fd1bf4,
-       0xd00770f7,
-       0x00f800ef,
-/* 0x066c: ctx_86c */
-       0x086ce7f1,
-       0xd006e4b6,
-       0xe7f100ef,
-       0xe3f08a14,
-       0x8d21f440,
-       0xa86ce7f1,
-       0xf441e3f0,
-       0x00f88d21,
-/* 0x068c: ctx_load */
+/* 0x0824: ctx_load */
        0x99f094bd,
        0x0007f105,
        0x0203f037,
        0xbd0009d0,
        0x0ca7f004,
-       0xf1c921f4,
-       0xb60a2417,
-       0x10d00614,
-       0x0037f100,
-       0x0634b60b,
-       0xf14032d0,
-       0xb60a0c17,
-       0x47f00614,
-       0x0012d007,
-/* 0x06c7: ctx_chan_wait_0 */
-       0xcf4014d0,
-       0x44f04014,
-       0xfa1bf41f,
-       0xfe0032d0,
-       0x2af0000b,
-       0x0424b61f,
-       0xbd0220b6,
+       0xbdd021f4,
+       0x0007f1f4,
+       0x0203f089,
+       0xbd000fd0,
+       0x0007f104,
+       0x0203f0c1,
+       0xbd0002d0,
+       0x0007f104,
+       0x0203f083,
+       0xbd0002d0,
+       0x07f7f004,
+       0x080621f5,
+       0xc00007f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xf0000bfe,
+       0x24b61f2a,
+       0x0220b604,
+       0x99f094bd,
+       0x0007f108,
+       0x0203f037,
+       0xbd0009d0,
+       0x0007f104,
+       0x0203f081,
+       0xbd0002d0,
+       0x0027f104,
+       0x0023f100,
+       0x0225f080,
+       0x880007f1,
+       0xd00203f0,
+       0x04bd0002,
+       0xf11017f0,
+       0xf0020027,
+       0x12fa0223,
+       0xbd03f805,
        0x0899f094,
-       0x370007f1,
+       0x170007f1,
        0xd00203f0,
        0x04bd0009,
-       0x0a0417f1,
-       0xd00614b6,
-       0x17f10012,
-       0x14b60a20,
-       0x0227f006,
-       0x800023f1,
-       0xf00012d0,
-       0x27f11017,
-       0x23f00200,
-       0x0512fa02,
-       0x94bd03f8,
-       0xf10899f0,
-       0xf0170007,
+       0xb6810198,
+       0x02981814,
+       0x0825b680,
+       0x800512fd,
+       0x94bd1601,
+       0xf10999f0,
+       0xf0370007,
        0x09d00203,
-       0x9804bd00,
-       0x14b68101,
-       0x80029818,
-       0xfd0825b6,
-       0x01800512,
-       0xf094bd16,
-       0x07f10999,
-       0x03f03700,
-       0x0009d002,
-       0x27f104bd,
-       0x24b60a04,
-       0x0021d006,
-       0xf10127f0,
-       0xb60a2017,
-       0x12d00614,
-       0x0017f100,
-       0x0613f001,
-       0xf80501fa,
-       0xf094bd03,
-       0x07f10999,
-       0x03f01700,
-       0x0009d002,
-       0x94bd04bd,
-       0xf10599f0,
+       0xf104bd00,
+       0xf0810007,
+       0x01d00203,
+       0xf004bd00,
+       0x07f10127,
+       0x03f08800,
+       0x0002d002,
+       0x17f104bd,
+       0x13f00100,
+       0x0501fa06,
+       0x94bd03f8,
+       0xf10999f0,
        0xf0170007,
        0x09d00203,
-       0xf804bd00,
-/* 0x0795: ctx_chan */
-       0x8c21f500,
-       0x0ca7f006,
-       0xf1c921f4,
-       0xb60a1017,
-       0x27f00614,
-       0x0012d005,
-/* 0x07ac: ctx_chan_wait */
-       0xfd0012cf,
-       0x1bf40522,
-/* 0x07b7: ctx_mmio_exec */
-       0x9800f8fa,
-       0x27f14103,
-       0x24b60a04,
-       0x0023d006,
-/* 0x07c6: ctx_mmio_loop */
+       0xbd04bd00,
+       0x0599f094,
+       0x170007f1,
+       0xd00203f0,
+       0x04bd0009,
+/* 0x0942: ctx_chan */
+       0x21f500f8,
+       0xa7f00824,
+       0xd021f40c,
+       0xf505f7f0,
+       0xf8080621,
+/* 0x0955: ctx_mmio_exec */
+       0x41039800,
+       0x810007f1,
+       0xd00203f0,
+       0x04bd0003,
+/* 0x0966: ctx_mmio_loop */
        0x34c434bd,
        0x0f1bf4ff,
        0x020057f1,
        0xfa0653f0,
        0x03f80535,
-/* 0x07d8: ctx_mmio_pull */
+/* 0x0978: ctx_mmio_pull */
        0x98804e98,
        0x21f4814f,
-       0x0830b68d,
+       0x0830b69d,
        0xf40112b6,
-/* 0x07ea: ctx_mmio_done */
+/* 0x098a: ctx_mmio_done */
        0x0398df1b,
-       0x0023d016,
-       0xf1400080,
-       0xf0010017,
-       0x01fa0613,
-       0xf803f806,
-/* 0x0801: ctx_xfer */
-       0x00f7f100,
-       0x06f4b60c,
-       0xd004e7f0,
-/* 0x080e: ctx_xfer_idle */
-       0xfecf80fe,
-       0x00e4f100,
-       0xf91bf420,
-       0xf40611f4,
-/* 0x081e: ctx_xfer_pre */
-       0xf7f00d02,
-       0x6c21f510,
-       0x1c11f406,
-/* 0x0828: ctx_xfer_pre_load */
-       0xf502f7f0,
-       0xf5062b21,
-       0xf5063a21,
-       0xbd064c21,
-       0x2b21f5f4,
-       0x8c21f506,
-/* 0x0841: ctx_xfer_exec */
-       0x16019806,
-       0x041427f1,
-       0xd00624b6,
-       0xe7f10020,
-       0xe3f0a500,
-       0x021fb941,
-       0xb68d21f4,
-       0xfcf004e0,
-       0x022cf001,
-       0xfd0124b6,
-       0x21f405f2,
-       0xfc17f18d,
-       0x0213f04a,
-       0xd00c27f0,
-       0x21f50012,
-       0x27f10215,
-       0x23f047fc,
-       0x0020d002,
+       0x0007f116,
+       0x0203f081,
+       0xbd0003d0,
+       0x40008004,
+       0x010017f1,
+       0xfa0613f0,
+       0x03f80601,
+/* 0x09aa: ctx_xfer */
+       0xe7f000f8,
+       0x0007f104,
+       0x0303f002,
+       0xbd000ed0,
+/* 0x09b9: ctx_xfer_idle */
+       0x00e7f104,
+       0x03e3f000,
+       0xf100eecf,
+       0xf42000e4,
+       0x11f4f21b,
+       0x0d02f406,
+/* 0x09d0: ctx_xfer_pre */
+       0xf510f7f0,
+       0xf407de21,
+/* 0x09da: ctx_xfer_pre_load */
+       0xf7f01c11,
+       0x7f21f502,
+       0x9121f507,
+       0xa621f507,
+       0xf5f4bd07,
+       0xf5077f21,
+/* 0x09f3: ctx_xfer_exec */
+       0x98082421,
+       0x24bd1601,
+       0x050007f1,
+       0xd00103f0,
+       0x04bd0002,
+       0xf1021fb9,
+       0xf0a500e7,
+       0x21f441e3,
+       0x01fcf09d,
+       0xb6022cf0,
+       0xf2fd0124,
+       0x02ffb905,
+       0xa504e7f1,
+       0xf441e3f0,
+       0x21f59d21,
+       0x24bd026a,
+       0x47fc07f1,
+       0xd00203f0,
+       0x04bd0002,
        0xb6012cf0,
-       0x12d00320,
-       0x01acf000,
-       0xf006a5f0,
-       0x0c9800b7,
-       0x010d9800,
-       0xf500e7f0,
-       0xf0016621,
-       0x21f508a7,
-       0x21f50109,
-       0x01f40215,
-       0x0ca7f022,
-       0xf1c921f4,
-       0xb60a1017,
-       0x27f00614,
-       0x0012d005,
-/* 0x08c8: ctx_xfer_post_save_wait */
-       0xfd0012cf,
-       0x1bf40522,
-       0x2e02f4fa,
-/* 0x08d4: ctx_xfer_post */
-       0xf502f7f0,
-       0xbd062b21,
-       0x6c21f5f4,
-       0x3421f506,
-       0x3a21f502,
-       0xf5f4bd06,
-       0xf4062b21,
-       0x01981011,
-       0x0511fd40,
-       0xf5070bf4,
-/* 0x08ff: ctx_xfer_no_post_mmio */
-/* 0x08ff: ctx_xfer_done */
-       0xf807b721,
-       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,
+       0x07f10320,
+       0x03f04afc,
+       0x0002d002,
+       0xacf004bd,
+       0x06a5f001,
+       0x9800b7f0,
+       0x0d98000c,
+       0x00e7f001,
+       0x016f21f5,
+       0xf508a7f0,
+       0xf5011021,
+       0xf4025e21,
+       0xa7f01301,
+       0xd021f40c,
+       0xf505f7f0,
+       0xf4080621,
+/* 0x0a82: ctx_xfer_post */
+       0xf7f02e02,
+       0x7f21f502,
+       0xf5f4bd07,
+       0xf507de21,
+       0xf5027f21,
+       0xbd079121,
+       0x7f21f5f4,
+       0x1011f407,
+       0xfd400198,
+       0x0bf40511,
+       0x5521f507,
+/* 0x0aad: ctx_xfer_no_post_mmio */
+/* 0x0aad: ctx_xfer_done */
+       0x0000f809,
        0x00000000,
        0x00000000,
        0x00000000,
index 33a5a82eccbd6e8114f55d8d8766d22929474d80..6ffe28307dbd6e420a019d0e7dd4ac891f531fd7 100644 (file)
 #define GF117 0xd7
 #define GK100 0xe0
 #define GK110 0xf0
+#define GK208 0x108
 
+#define NV_PGRAPH_FECS_INTR_ACK                                        0x409004
+#define NV_PGRAPH_FECS_INTR                                            0x409008
+#define NV_PGRAPH_FECS_INTR_FWMTHD                                   0x00000400
+#define NV_PGRAPH_FECS_INTR_CHSW                                     0x00000100
+#define NV_PGRAPH_FECS_INTR_FIFO                                     0x00000004
+#define NV_PGRAPH_FECS_INTR_MODE                                       0x40900c
+#define NV_PGRAPH_FECS_INTR_MODE_FIFO                                0x00000004
+#define NV_PGRAPH_FECS_INTR_MODE_FIFO_LEVEL                          0x00000004
+#define NV_PGRAPH_FECS_INTR_MODE_FIFO_EDGE                           0x00000000
+#define NV_PGRAPH_FECS_INTR_EN_SET                                     0x409010
+#define NV_PGRAPH_FECS_INTR_EN_SET_FIFO                              0x00000004
+#define NV_PGRAPH_FECS_INTR_ROUTE                                      0x40901c
+#define NV_PGRAPH_FECS_ACCESS                                          0x409048
+#define NV_PGRAPH_FECS_ACCESS_FIFO                                   0x00000002
+#define NV_PGRAPH_FECS_FIFO_DATA                                       0x409064
+#define NV_PGRAPH_FECS_FIFO_CMD                                        0x409068
+#define NV_PGRAPH_FECS_FIFO_ACK                                        0x409074
+#define NV_PGRAPH_FECS_CAPS                                            0x409108
 #define NV_PGRAPH_FECS_SIGNAL                                          0x409400
+#define NV_PGRAPH_FECS_IROUTE                                          0x409404
+#define NV_PGRAPH_FECS_BAR_MASK0                                       0x40940c
+#define NV_PGRAPH_FECS_BAR_MASK1                                       0x409410
+#define NV_PGRAPH_FECS_BAR                                             0x409414
+#define NV_PGRAPH_FECS_BAR_SET                                         0x409418
+#define NV_PGRAPH_FECS_RED_SWITCH                                      0x409614
+#define NV_PGRAPH_FECS_RED_SWITCH_ENABLE_ROP                         0x00000400
+#define NV_PGRAPH_FECS_RED_SWITCH_ENABLE_GPC                         0x00000200
+#define NV_PGRAPH_FECS_RED_SWITCH_ENABLE_MAIN                        0x00000100
+#define NV_PGRAPH_FECS_RED_SWITCH_POWER_ROP                          0x00000040
+#define NV_PGRAPH_FECS_RED_SWITCH_POWER_GPC                          0x00000020
+#define NV_PGRAPH_FECS_RED_SWITCH_POWER_MAIN                         0x00000010
+#define NV_PGRAPH_FECS_RED_SWITCH_PAUSE_GPC                          0x00000002
+#define NV_PGRAPH_FECS_RED_SWITCH_PAUSE_MAIN                         0x00000001
+#define NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE                               0x409700
+#define NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE                               0x409704
+#define NV_PGRAPH_FECS_MMCTX_LOAD_COUNT                                0x40974c
+#define NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE                               0x409700
+#define NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE                               0x409704
+#define NV_PGRAPH_FECS_MMCTX_BASE                                      0x409710
+#define NV_PGRAPH_FECS_MMCTX_CTRL                                      0x409714
+#define NV_PGRAPH_FECS_MMCTX_MULTI_STRIDE                              0x409718
+#define NV_PGRAPH_FECS_MMCTX_MULTI_MASK                                0x40971c
+#define NV_PGRAPH_FECS_MMCTX_QUEUE                                     0x409720
+#define NV_PGRAPH_FECS_MMIO_CTRL                                       0x409728
+#define NV_PGRAPH_FECS_MMIO_RDVAL                                      0x40972c
+#define NV_PGRAPH_FECS_MMIO_WRVAL                                      0x409730
+#define NV_PGRAPH_FECS_MMCTX_LOAD_COUNT                                0x40974c
 #if CHIPSET < GK110
 #define NV_PGRAPH_FECS_CC_SCRATCH_VAL(n)                    ((n) * 4 + 0x409800)
 #define NV_PGRAPH_FECS_CC_SCRATCH_SET(n)                    ((n) * 4 + 0x409820)
 #define NV_PGRAPH_FECS_CC_SCRATCH_CLR(n)                    ((n) * 4 + 0x409840)
+#define NV_PGRAPH_FECS_UNK86C                                          0x40986c
 #else
 #define NV_PGRAPH_FECS_CC_SCRATCH_VAL(n)                    ((n) * 4 + 0x409800)
 #define NV_PGRAPH_FECS_CC_SCRATCH_CLR(n)                    ((n) * 4 + 0x409840)
+#define NV_PGRAPH_FECS_UNK86C                                          0x40988c
 #define NV_PGRAPH_FECS_CC_SCRATCH_SET(n)                    ((n) * 4 + 0x4098c0)
 #endif
+#define NV_PGRAPH_FECS_STRANDS_CNT                                     0x409880
+#define NV_PGRAPH_FECS_STRAND_SAVE_SWBASE                              0x409908
+#define NV_PGRAPH_FECS_STRAND_LOAD_SWBASE                              0x40990c
+#define NV_PGRAPH_FECS_STRAND_WORDS                                    0x409910
+#define NV_PGRAPH_FECS_STRAND_DATA                                     0x409918
+#define NV_PGRAPH_FECS_STRAND_SELECT                                   0x40991c
+#define NV_PGRAPH_FECS_STRAND_CMD                                      0x409928
+#define NV_PGRAPH_FECS_STRAND_CMD_SEEK                               0x00000001
+#define NV_PGRAPH_FECS_STRAND_CMD_GET_INFO                           0x00000002
+#define NV_PGRAPH_FECS_STRAND_CMD_SAVE                               0x00000003
+#define NV_PGRAPH_FECS_STRAND_CMD_LOAD                               0x00000004
+#define NV_PGRAPH_FECS_STRAND_CMD_ACTIVATE_FILTER                    0x0000000a
+#define NV_PGRAPH_FECS_STRAND_CMD_DEACTIVATE_FILTER                  0x0000000b
+#define NV_PGRAPH_FECS_STRAND_CMD_ENABLE                             0x0000000c
+#define NV_PGRAPH_FECS_STRAND_CMD_DISABLE                            0x0000000d
+#define NV_PGRAPH_FECS_STRAND_FILTER                                   0x40993c
+#define NV_PGRAPH_FECS_MEM_BASE                                        0x409a04
+#define NV_PGRAPH_FECS_MEM_CHAN                                        0x409a0c
+#define NV_PGRAPH_FECS_MEM_CMD                                         0x409a10
+#define NV_PGRAPH_FECS_MEM_CMD_LOAD_CHAN                             0x00000007
+#define NV_PGRAPH_FECS_MEM_TARGET                                      0x409a20
+#define NV_PGRAPH_FECS_MEM_TARGET_UNK31                              0x80000000
+#define NV_PGRAPH_FECS_MEM_TARGET_AS                                 0x0000001f
+#define NV_PGRAPH_FECS_MEM_TARGET_AS_VM                              0x00000001
+#define NV_PGRAPH_FECS_MEM_TARGET_AS_VRAM                            0x00000002
+#define NV_PGRAPH_FECS_CHAN_ADDR                                       0x409b00
+#define NV_PGRAPH_FECS_CHAN_NEXT                                       0x409b04
+#define NV_PGRAPH_FECS_CHSW                                            0x409b0c
+#define NV_PGRAPH_FECS_CHSW_ACK                                      0x00000001
 #define NV_PGRAPH_FECS_INTR_UP_SET                                     0x409c1c
+#define NV_PGRAPH_FECS_INTR_UP_EN                                      0x409c24
 
+#define NV_PGRAPH_GPCX_GPCCS_INTR_ACK                                  0x41a004
+#define NV_PGRAPH_GPCX_GPCCS_INTR                                      0x41a008
+#define NV_PGRAPH_GPCX_GPCCS_INTR_FIFO                               0x00000004
+#define NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET                               0x41a010
+#define NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO                        0x00000004
+#define NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE                                0x41a01c
+#define NV_PGRAPH_GPCX_GPCCS_ACCESS                                    0x41a048
+#define NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO                             0x00000002
+#define NV_PGRAPH_GPCX_GPCCS_FIFO_DATA                                 0x41a064
+#define NV_PGRAPH_GPCX_GPCCS_FIFO_CMD                                  0x41a068
+#define NV_PGRAPH_GPCX_GPCCS_FIFO_ACK                                  0x41a074
+#define NV_PGRAPH_GPCX_GPCCS_UNITS                                     0x41a608
+#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH                                0x41a614
+#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11                        0x00000800
+#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE                       0x00000200
+#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER                        0x00000020
+#define NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_PAUSE                        0x00000002
+#define NV_PGRAPH_GPCX_GPCCS_MYINDEX                                   0x41a618
+#define NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE                         0x41a700
+#define NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE                         0x41a704
+#define NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT                          0x41a74c
 #if CHIPSET < GK110
 #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(n)              ((n) * 4 + 0x41a800)
 #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(n)              ((n) * 4 + 0x41a820)
 #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_CLR(n)              ((n) * 4 + 0x41a840)
+#define NV_PGRAPH_GPCX_GPCCS_UNK86C                                    0x41a86c
 #else
 #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(n)              ((n) * 4 + 0x41a800)
 #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_CLR(n)              ((n) * 4 + 0x41a840)
+#define NV_PGRAPH_GPCX_GPCCS_UNK86C                                    0x41a88c
 #define NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(n)              ((n) * 4 + 0x41a8c0)
 #endif
+#define NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT                             0x41a91c
+#define NV_PGRAPH_GPCX_GPCCS_STRAND_CMD                                0x41a928
+#define NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE                         0x00000003
+#define NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_LOAD                         0x00000004
+#define NV_PGRAPH_GPCX_GPCCS_MEM_BASE                                  0x41aa04
 
 #define mmctx_data(r,c) .b32 (((c - 1) << 26) | r)
 #define queue_init      .skip 72 // (2 * 4) + ((8 * 4) * 2)
 #define T_LCHAN   8
 #define T_LCTXH   9
 
-#define nv_mkmm(rv,r) /*
-*/     movw rv  ((r) & 0x0000fffc) /*
-*/     sethi rv ((r) & 0x00ff0000)
+#if CHIPSET < GK208
+#define imm32(reg,val) /*
+*/     movw reg  ((val) & 0x0000ffff) /*
+*/     sethi reg ((val) & 0xffff0000)
+#else
+#define imm32(reg,val) /*
+*/     mov reg (val)
+#endif
+
 #define nv_mkio(rv,r,i) /*
-*/     nv_mkmm(rv, (((r) & 0xffc) << 6) | ((i) << 2))
+*/     imm32(rv, (((r) & 0xffc) << 6) | ((i) << 2))
+
+#define hash #
+#define fn(a) a
+#if CHIPSET < GK208
+#define call(a) call fn(hash)a
+#else
+#define call(a) lcall fn(hash)a
+#endif
 
 #define nv_iord(rv,r,i) /*
 */     nv_mkio(rv,r,i) /*
 */     iord rv I[rv]
+
 #define nv_iowr(r,i,rv) /*
 */     nv_mkio($r0,r,i) /*
 */     iowr I[$r0] rv /*
 */     clear b32 $r0
 
+#define nv_rd32(reg,addr) /*
+*/     imm32($r14, addr) /*
+*/     call(nv_rd32) /*
+*/     mov b32 reg $r15
+
+#define nv_wr32(addr,reg) /*
+*/     mov b32 $r15 reg /*
+*/     imm32($r14, addr) /*
+*/     call(nv_wr32)
+
 #define trace_set(bit) /*
 */     clear b32 $r9 /*
 */     bset $r9 bit /*
 */     nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(7), 0, $r9)
+
 #define trace_clr(bit) /*
 */     clear b32 $r9 /*
 */     bset $r9 bit /*
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c
new file mode 100644 (file)
index 0000000..e1af65e
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * 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 <bskeggs@redhat.com>
+ */
+
+#include "nvc0.h"
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nouveau_oclass
+nv108_graph_sclass[] = {
+       { 0x902d, &nouveau_object_ofuncs },
+       { 0xa140, &nouveau_object_ofuncs },
+       { 0xa197, &nouveau_object_ofuncs },
+       { 0xa1c0, &nouveau_object_ofuncs },
+       {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static struct nvc0_graph_init
+nv108_graph_init_regs[] = {
+       { 0x400080,   1, 0x04, 0x003083c2 },
+       { 0x400088,   1, 0x04, 0x0001bfe7 },
+       { 0x40008c,   1, 0x04, 0x00000000 },
+       { 0x400090,   1, 0x04, 0x00000030 },
+       { 0x40013c,   1, 0x04, 0x003901f7 },
+       { 0x400140,   1, 0x04, 0x00000100 },
+       { 0x400144,   1, 0x04, 0x00000000 },
+       { 0x400148,   1, 0x04, 0x00000110 },
+       { 0x400138,   1, 0x04, 0x00000000 },
+       { 0x400130,   2, 0x04, 0x00000000 },
+       { 0x400124,   1, 0x04, 0x00000002 },
+       {}
+};
+
+struct nvc0_graph_init
+nv108_graph_init_unk58xx[] = {
+       { 0x405844,   1, 0x04, 0x00ffffff },
+       { 0x405850,   1, 0x04, 0x00000000 },
+       { 0x405900,   1, 0x04, 0x00000000 },
+       { 0x405908,   1, 0x04, 0x00000000 },
+       { 0x405928,   1, 0x04, 0x00000000 },
+       { 0x40592c,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_graph_init_gpc[] = {
+       { 0x418408,   1, 0x04, 0x00000000 },
+       { 0x4184a0,   3, 0x04, 0x00000000 },
+       { 0x418604,   1, 0x04, 0x00000000 },
+       { 0x418680,   1, 0x04, 0x00000000 },
+       { 0x418714,   1, 0x04, 0x00000000 },
+       { 0x418384,   2, 0x04, 0x00000000 },
+       { 0x418814,   3, 0x04, 0x00000000 },
+       { 0x418b04,   1, 0x04, 0x00000000 },
+       { 0x4188c8,   2, 0x04, 0x00000000 },
+       { 0x4188d0,   1, 0x04, 0x00010000 },
+       { 0x4188d4,   1, 0x04, 0x00000201 },
+       { 0x418910,   1, 0x04, 0x00010001 },
+       { 0x418914,   1, 0x04, 0x00000301 },
+       { 0x418918,   1, 0x04, 0x00800000 },
+       { 0x418980,   1, 0x04, 0x77777770 },
+       { 0x418984,   3, 0x04, 0x77777777 },
+       { 0x418c04,   1, 0x04, 0x00000000 },
+       { 0x418c64,   2, 0x04, 0x00000000 },
+       { 0x418c88,   1, 0x04, 0x00000000 },
+       { 0x418cb4,   2, 0x04, 0x00000000 },
+       { 0x418d00,   1, 0x04, 0x00000000 },
+       { 0x418d28,   2, 0x04, 0x00000000 },
+       { 0x418f00,   1, 0x04, 0x00000400 },
+       { 0x418f08,   1, 0x04, 0x00000000 },
+       { 0x418f20,   2, 0x04, 0x00000000 },
+       { 0x418e00,   1, 0x04, 0x00000000 },
+       { 0x418e08,   1, 0x04, 0x00000000 },
+       { 0x418e1c,   2, 0x04, 0x00000000 },
+       { 0x41900c,   1, 0x04, 0x00000000 },
+       { 0x419018,   1, 0x04, 0x00000000 },
+       {}
+};
+
+static struct nvc0_graph_init
+nv108_graph_init_tpc[] = {
+       { 0x419d0c,   1, 0x04, 0x00000000 },
+       { 0x419d10,   1, 0x04, 0x00000014 },
+       { 0x419ab0,   1, 0x04, 0x00000000 },
+       { 0x419ac8,   1, 0x04, 0x00000000 },
+       { 0x419ab8,   1, 0x04, 0x000000e7 },
+       { 0x419abc,   2, 0x04, 0x00000000 },
+       { 0x419ab4,   1, 0x04, 0x00000000 },
+       { 0x419aa8,   2, 0x04, 0x00000000 },
+       { 0x41980c,   1, 0x04, 0x00000010 },
+       { 0x419844,   1, 0x04, 0x00000000 },
+       { 0x419850,   1, 0x04, 0x00000004 },
+       { 0x419854,   2, 0x04, 0x00000000 },
+       { 0x419c98,   1, 0x04, 0x00000000 },
+       { 0x419ca8,   1, 0x04, 0x00000000 },
+       { 0x419cb0,   1, 0x04, 0x01000000 },
+       { 0x419cb4,   1, 0x04, 0x00000000 },
+       { 0x419cb8,   1, 0x04, 0x00b08bea },
+       { 0x419c84,   1, 0x04, 0x00010384 },
+       { 0x419cbc,   1, 0x04, 0x281b3646 },
+       { 0x419cc0,   2, 0x04, 0x00000000 },
+       { 0x419c80,   1, 0x04, 0x00000230 },
+       { 0x419ccc,   2, 0x04, 0x00000000 },
+       { 0x419c0c,   1, 0x04, 0x00000000 },
+       { 0x419e00,   1, 0x04, 0x00000080 },
+       { 0x419ea0,   1, 0x04, 0x00000000 },
+       { 0x419ee4,   1, 0x04, 0x00000000 },
+       { 0x419ea4,   1, 0x04, 0x00000100 },
+       { 0x419ea8,   1, 0x04, 0x00000000 },
+       { 0x419eb4,   1, 0x04, 0x00000000 },
+       { 0x419ebc,   2, 0x04, 0x00000000 },
+       { 0x419edc,   1, 0x04, 0x00000000 },
+       { 0x419f00,   1, 0x04, 0x00000000 },
+       { 0x419ed0,   1, 0x04, 0x00003234 },
+       { 0x419f74,   1, 0x04, 0x00015555 },
+       { 0x419f80,   4, 0x04, 0x00000000 },
+       {}
+};
+
+static int
+nv108_graph_fini(struct nouveau_object *object, bool suspend)
+{
+       struct nvc0_graph_priv *priv = (void *)object;
+       static const struct {
+               u32 addr;
+               u32 data;
+       } magic[] = {
+               { 0x020520, 0xfffffffc },
+               { 0x020524, 0xfffffffe },
+               { 0x020524, 0xfffffffc },
+               { 0x020524, 0xfffffff8 },
+               { 0x020524, 0xffffffe0 },
+               { 0x020530, 0xfffffffe },
+               { 0x02052c, 0xfffffffa },
+               { 0x02052c, 0xfffffff0 },
+               { 0x02052c, 0xffffffc0 },
+               { 0x02052c, 0xffffff00 },
+               { 0x02052c, 0xfffffc00 },
+               { 0x02052c, 0xfffcfc00 },
+               { 0x02052c, 0xfff0fc00 },
+               { 0x02052c, 0xff80fc00 },
+               { 0x020528, 0xfffffffe },
+               { 0x020528, 0xfffffffc },
+       };
+       int i;
+
+       nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
+       nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
+       for (i = 0; i < ARRAY_SIZE(magic); i++) {
+               nv_wr32(priv, magic[i].addr, magic[i].data);
+               nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
+       }
+
+       return nouveau_graph_fini(&priv->base, suspend);
+}
+
+static struct nvc0_graph_init *
+nv108_graph_init_mmio[] = {
+       nv108_graph_init_regs,
+       nvf0_graph_init_unk40xx,
+       nvc0_graph_init_unk44xx,
+       nvc0_graph_init_unk78xx,
+       nvc0_graph_init_unk60xx,
+       nvd9_graph_init_unk64xx,
+       nv108_graph_init_unk58xx,
+       nvc0_graph_init_unk80xx,
+       nvf0_graph_init_unk70xx,
+       nvf0_graph_init_unk5bxx,
+       nv108_graph_init_gpc,
+       nv108_graph_init_tpc,
+       nve4_graph_init_unk,
+       nve4_graph_init_unk88xx,
+       NULL
+};
+
+#include "fuc/hubnv108.fuc5.h"
+
+static struct nvc0_graph_ucode
+nv108_graph_fecs_ucode = {
+       .code.data = nv108_grhub_code,
+       .code.size = sizeof(nv108_grhub_code),
+       .data.data = nv108_grhub_data,
+       .data.size = sizeof(nv108_grhub_data),
+};
+
+#include "fuc/gpcnv108.fuc5.h"
+
+static struct nvc0_graph_ucode
+nv108_graph_gpccs_ucode = {
+       .code.data = nv108_grgpc_code,
+       .code.size = sizeof(nv108_grgpc_code),
+       .data.data = nv108_grgpc_data,
+       .data.size = sizeof(nv108_grgpc_data),
+};
+
+struct nouveau_oclass *
+nv108_graph_oclass = &(struct nvc0_graph_oclass) {
+       .base.handle = NV_ENGINE(GR, 0x08),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nvc0_graph_ctor,
+               .dtor = nvc0_graph_dtor,
+               .init = nve4_graph_init,
+               .fini = nv108_graph_fini,
+       },
+       .cclass = &nv108_grctx_oclass,
+       .sclass =  nv108_graph_sclass,
+       .mmio = nv108_graph_init_mmio,
+       .fecs.ucode = &nv108_graph_fecs_ucode,
+       .gpccs.ucode = &nv108_graph_gpccs_ucode,
+}.base;
index 03de5175dd9f8bcdb1a2ad48c18de965cf31a3c1..30ed19c52e05ca0cd6a1e759a8fc426f61f246a7 100644 (file)
@@ -304,12 +304,28 @@ nv84_graph_tlb_flush(struct nouveau_engine *engine)
        return timeout ? -EBUSY : 0;
 }
 
-static const struct nouveau_enum nv50_mp_exec_error_names[] = {
-       { 3, "STACK_UNDERFLOW", NULL },
-       { 4, "QUADON_ACTIVE", NULL },
-       { 8, "TIMEOUT", NULL },
-       { 0x10, "INVALID_OPCODE", NULL },
-       { 0x40, "BREAKPOINT", NULL },
+static const struct nouveau_bitfield nv50_mp_exec_errors[] = {
+       { 0x01, "STACK_UNDERFLOW" },
+       { 0x02, "STACK_MISMATCH" },
+       { 0x04, "QUADON_ACTIVE" },
+       { 0x08, "TIMEOUT" },
+       { 0x10, "INVALID_OPCODE" },
+       { 0x20, "PM_OVERFLOW" },
+       { 0x40, "BREAKPOINT" },
+       {}
+};
+
+static const struct nouveau_bitfield nv50_mpc_traps[] = {
+       { 0x0000001, "LOCAL_LIMIT_READ" },
+       { 0x0000010, "LOCAL_LIMIT_WRITE" },
+       { 0x0000040, "STACK_LIMIT" },
+       { 0x0000100, "GLOBAL_LIMIT_READ" },
+       { 0x0001000, "GLOBAL_LIMIT_WRITE" },
+       { 0x0010000, "MP0" },
+       { 0x0020000, "MP1" },
+       { 0x0040000, "GLOBAL_LIMIT_RED" },
+       { 0x0400000, "GLOBAL_LIMIT_ATOM" },
+       { 0x4000000, "MP2" },
        {}
 };
 
@@ -396,6 +412,60 @@ static const struct nouveau_bitfield nv50_graph_intr_name[] = {
        {}
 };
 
+static const struct nouveau_bitfield nv50_graph_trap_prop[] = {
+       { 0x00000004, "SURF_WIDTH_OVERRUN" },
+       { 0x00000008, "SURF_HEIGHT_OVERRUN" },
+       { 0x00000010, "DST2D_FAULT" },
+       { 0x00000020, "ZETA_FAULT" },
+       { 0x00000040, "RT_FAULT" },
+       { 0x00000080, "CUDA_FAULT" },
+       { 0x00000100, "DST2D_STORAGE_TYPE_MISMATCH" },
+       { 0x00000200, "ZETA_STORAGE_TYPE_MISMATCH" },
+       { 0x00000400, "RT_STORAGE_TYPE_MISMATCH" },
+       { 0x00000800, "DST2D_LINEAR_MISMATCH" },
+       { 0x00001000, "RT_LINEAR_MISMATCH" },
+       {}
+};
+
+static void
+nv50_priv_prop_trap(struct nv50_graph_priv *priv,
+                   u32 ustatus_addr, u32 ustatus, u32 tp)
+{
+       u32 e0c = nv_rd32(priv, ustatus_addr + 0x04);
+       u32 e10 = nv_rd32(priv, ustatus_addr + 0x08);
+       u32 e14 = nv_rd32(priv, ustatus_addr + 0x0c);
+       u32 e18 = nv_rd32(priv, ustatus_addr + 0x10);
+       u32 e1c = nv_rd32(priv, ustatus_addr + 0x14);
+       u32 e20 = nv_rd32(priv, ustatus_addr + 0x18);
+       u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c);
+
+       /* CUDA memory: l[], g[] or stack. */
+       if (ustatus & 0x00000080) {
+               if (e18 & 0x80000000) {
+                       /* g[] read fault? */
+                       nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n",
+                                        tp, e14, e10 | ((e18 >> 24) & 0x1f));
+                       e18 &= ~0x1f000000;
+               } else if (e18 & 0xc) {
+                       /* g[] write fault? */
+                       nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n",
+                                tp, e14, e10 | ((e18 >> 7) & 0x1f));
+                       e18 &= ~0x00000f80;
+               } else {
+                       nv_error(priv, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n",
+                                tp, e14, e10);
+               }
+               ustatus &= ~0x00000080;
+       }
+       if (ustatus) {
+               nv_error(priv, "TRAP_PROP - TP %d -", tp);
+               nouveau_bitfield_print(nv50_graph_trap_prop, ustatus);
+               pr_cont(" - Address %02x%08x\n", e14, e10);
+       }
+       nv_error(priv, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+                tp, e0c, e18, e1c, e20, e24);
+}
+
 static void
 nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display)
 {
@@ -420,8 +490,8 @@ nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display)
                        oplow = nv_rd32(priv, addr + 0x70);
                        ophigh = nv_rd32(priv, addr + 0x74);
                        nv_error(priv, "TRAP_MP_EXEC - "
-                                       "TP %d MP %d: ", tpid, i);
-                       nouveau_enum_print(nv50_mp_exec_error_names, status);
+                                       "TP %d MP %d:", tpid, i);
+                       nouveau_bitfield_print(nv50_mp_exec_errors, status);
                        pr_cont(" at %06x warp %d, opcode %08x %08x\n",
                                        pc&0xffffff, pc >> 24,
                                        oplow, ophigh);
@@ -468,60 +538,19 @@ nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
                                nv50_priv_mp_trap(priv, i, display);
                                ustatus &= ~0x04030000;
                        }
-                       break;
-               case 8: /* TPDMA error */
-                       {
-                       u32 e0c = nv_rd32(priv, ustatus_addr + 4);
-                       u32 e10 = nv_rd32(priv, ustatus_addr + 8);
-                       u32 e14 = nv_rd32(priv, ustatus_addr + 0xc);
-                       u32 e18 = nv_rd32(priv, ustatus_addr + 0x10);
-                       u32 e1c = nv_rd32(priv, ustatus_addr + 0x14);
-                       u32 e20 = nv_rd32(priv, ustatus_addr + 0x18);
-                       u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c);
-                       /* 2d engine destination */
-                       if (ustatus & 0x00000010) {
-                               if (display) {
-                                       nv_error(priv, "TRAP_TPDMA_2D - TP %d - Unknown fault at address %02x%08x\n",
-                                                       i, e14, e10);
-                                       nv_error(priv, "TRAP_TPDMA_2D - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
-                                                       i, e0c, e18, e1c, e20, e24);
-                               }
-                               ustatus &= ~0x00000010;
-                       }
-                       /* Render target */
-                       if (ustatus & 0x00000040) {
-                               if (display) {
-                                       nv_error(priv, "TRAP_TPDMA_RT - TP %d - Unknown fault at address %02x%08x\n",
-                                                       i, e14, e10);
-                                       nv_error(priv, "TRAP_TPDMA_RT - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
-                                                       i, e0c, e18, e1c, e20, e24);
-                               }
-                               ustatus &= ~0x00000040;
-                       }
-                       /* CUDA memory: l[], g[] or stack. */
-                       if (ustatus & 0x00000080) {
-                               if (display) {
-                                       if (e18 & 0x80000000) {
-                                               /* g[] read fault? */
-                                               nv_error(priv, "TRAP_TPDMA - TP %d - Global read fault at address %02x%08x\n",
-                                                               i, e14, e10 | ((e18 >> 24) & 0x1f));
-                                               e18 &= ~0x1f000000;
-                                       } else if (e18 & 0xc) {
-                                               /* g[] write fault? */
-                                               nv_error(priv, "TRAP_TPDMA - TP %d - Global write fault at address %02x%08x\n",
-                                                               i, e14, e10 | ((e18 >> 7) & 0x1f));
-                                               e18 &= ~0x00000f80;
-                                       } else {
-                                               nv_error(priv, "TRAP_TPDMA - TP %d - Unknown CUDA fault at address %02x%08x\n",
-                                                               i, e14, e10);
-                                       }
-                                       nv_error(priv, "TRAP_TPDMA - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
-                                                       i, e0c, e18, e1c, e20, e24);
-                               }
-                               ustatus &= ~0x00000080;
-                       }
+                       if (ustatus && display) {
+                               nv_error("%s - TP%d:", name, i);
+                               nouveau_bitfield_print(nv50_mpc_traps, ustatus);
+                               pr_cont("\n");
+                               ustatus = 0;
                        }
                        break;
+               case 8: /* PROP error */
+                       if (display)
+                               nv50_priv_prop_trap(
+                                               priv, ustatus_addr, ustatus, i);
+                       ustatus = 0;
+                       break;
                }
                if (ustatus) {
                        if (display)
@@ -727,11 +756,11 @@ nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
                status &= ~0x080;
        }
 
-       /* TPDMA:  Handles TP-initiated uncached memory accesses:
+       /* PROP:  Handles TP-initiated uncached memory accesses:
         * l[], g[], stack, 2d surfaces, render targets. */
        if (status & 0x100) {
                nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display,
-                                   "TRAP_TPDMA");
+                                   "TRAP_PROP");
                nv_wr32(priv, 0x400108, 0x100);
                status &= ~0x100;
        }
@@ -760,7 +789,7 @@ nv50_graph_intr(struct nouveau_subdev *subdev)
        u32 mthd = (addr & 0x00001ffc);
        u32 data = nv_rd32(priv, 0x400708);
        u32 class = nv_rd32(priv, 0x400814);
-       u32 show = stat;
+       u32 show = stat, show_bitfield = stat;
        int chid;
 
        engctx = nouveau_engctx_get(engine, inst);
@@ -778,21 +807,26 @@ nv50_graph_intr(struct nouveau_subdev *subdev)
                nv_error(priv, "DATA_ERROR ");
                nouveau_enum_print(nv50_data_error_names, ecode);
                pr_cont("\n");
+               show_bitfield &= ~0x00100000;
        }
 
        if (stat & 0x00200000) {
                if (!nv50_graph_trap_handler(priv, show, chid, (u64)inst << 12,
                                engctx))
                        show &= ~0x00200000;
+               show_bitfield &= ~0x00200000;
        }
 
        nv_wr32(priv, 0x400100, stat);
        nv_wr32(priv, 0x400500, 0x00010001);
 
        if (show) {
-               nv_error(priv, "%s", "");
-               nouveau_bitfield_print(nv50_graph_intr_name, show);
-               pr_cont("\n");
+               show &= show_bitfield;
+               if (show) {
+                       nv_error(priv, "%s", "");
+                       nouveau_bitfield_print(nv50_graph_intr_name, show);
+                       pr_cont("\n");
+               }
                nv_error(priv,
                         "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
                         chid, (u64)inst << 12, nouveau_client_name(engctx),
index 5c8a63dc506aafcfbbe5088ede75ed635d0ba8a4..a73ab209ea88c85121fe3580e9daa189b29de46e 100644 (file)
@@ -901,6 +901,9 @@ nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
                }
 
                return 0;
+       } else
+       if (!oclass->fecs.ucode) {
+               return -ENOSYS;
        }
 
        /* load HUB microcode */
index ea17a80ad7fce3d7bcee48013ac6ba8c65acc4c7..b0ab6de270b2ea9d148b483b8249bc11efa27496 100644 (file)
@@ -205,6 +205,11 @@ extern struct nvc0_graph_init nve4_graph_init_regs[];
 extern struct nvc0_graph_init nve4_graph_init_unk[];
 extern struct nvc0_graph_init nve4_graph_init_unk88xx[];
 
+extern struct nvc0_graph_init nvf0_graph_init_unk40xx[];
+extern struct nvc0_graph_init nvf0_graph_init_unk70xx[];
+extern struct nvc0_graph_init nvf0_graph_init_unk5bxx[];
+extern struct nvc0_graph_init nvf0_graph_init_tpc[];
+
 int  nvc0_grctx_generate(struct nvc0_graph_priv *);
 void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
 void nvc0_grctx_generate_mods(struct nvc0_graph_priv *, struct nvc0_grctx *);
@@ -266,6 +271,11 @@ extern struct nvc0_graph_init nve4_grctx_init_unk80xx[];
 extern struct nvc0_graph_init nve4_grctx_init_unk90xx[];
 
 extern struct nouveau_oclass *nvf0_grctx_oclass;
+extern struct nvc0_graph_init nvf0_grctx_init_unk44xx[];
+extern struct nvc0_graph_init nvf0_grctx_init_unk5bxx[];
+extern struct nvc0_graph_init nvf0_grctx_init_unk60xx[];
+
+extern struct nouveau_oclass *nv108_grctx_oclass;
 
 #define mmio_data(s,a,p) do {                                                  \
        info->buffer[info->buffer_nr] = round_up(info->addr, (a));             \
index 2f0ac78322345a0d5dd997f5dc3d83327ba4b809..b1acb9939d95cfe460cea8e9aa2475d85256c20f 100644 (file)
@@ -41,7 +41,7 @@ nvf0_graph_sclass[] = {
  * PGRAPH engine/subdev functions
  ******************************************************************************/
 
-static struct nvc0_graph_init
+struct nvc0_graph_init
 nvf0_graph_init_unk40xx[] = {
        { 0x40415c,   1, 0x04, 0x00000000 },
        { 0x404170,   1, 0x04, 0x00000000 },
@@ -60,7 +60,7 @@ nvf0_graph_init_unk58xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
+struct nvc0_graph_init
 nvf0_graph_init_unk70xx[] = {
        { 0x407010,   1, 0x04, 0x00000000 },
        { 0x407040,   1, 0x04, 0x80440424 },
@@ -68,7 +68,7 @@ nvf0_graph_init_unk70xx[] = {
        {}
 };
 
-static struct nvc0_graph_init
+struct nvc0_graph_init
 nvf0_graph_init_unk5bxx[] = {
        { 0x405b44,   1, 0x04, 0x00000000 },
        { 0x405b50,   1, 0x04, 0x00000000 },
@@ -114,7 +114,7 @@ nvf0_graph_init_gpc[] = {
        {}
 };
 
-static struct nvc0_graph_init
+struct nvc0_graph_init
 nvf0_graph_init_tpc[] = {
        { 0x419d0c,   1, 0x04, 0x00000000 },
        { 0x419d10,   1, 0x04, 0x00000014 },
@@ -243,6 +243,6 @@ nvf0_graph_oclass = &(struct nvc0_graph_oclass) {
        .cclass = &nvf0_grctx_oclass,
        .sclass =  nvf0_graph_sclass,
        .mmio = nvf0_graph_init_mmio,
-       .fecs.ucode = 0 ? &nvf0_graph_fecs_ucode : NULL,
+       .fecs.ucode = &nvf0_graph_fecs_ucode,
        .gpccs.ucode = &nvf0_graph_gpccs_ucode,
 }.base;
index 560c3593dae75e365a647d3e4858d65be85c39e6..e71a4325e670f69c4fce0893b973760a9522185a 100644 (file)
@@ -230,9 +230,26 @@ struct nve0_channel_ind_class {
 
 #define NV04_DISP_CLASS                                              0x00000046
 
+#define NV04_DISP_MTHD                                               0x00000000
+#define NV04_DISP_MTHD_HEAD                                          0x00000001
+
+#define NV04_DISP_SCANOUTPOS                                         0x00000000
+
 struct nv04_display_class {
 };
 
+struct nv04_display_scanoutpos {
+       s64 time[2];
+       u32 vblanks;
+       u32 vblanke;
+       u32 vtotal;
+       u32 vline;
+       u32 hblanks;
+       u32 hblanke;
+       u32 htotal;
+       u32 hline;
+};
+
 /* 5070: NV50_DISP
  * 8270: NV84_DISP
  * 8370: NVA0_DISP
@@ -252,6 +269,11 @@ struct nv04_display_class {
 #define NVE0_DISP_CLASS                                              0x00009170
 #define NVF0_DISP_CLASS                                              0x00009270
 
+#define NV50_DISP_MTHD                                               0x00000000
+#define NV50_DISP_MTHD_HEAD                                          0x00000003
+
+#define NV50_DISP_SCANOUTPOS                                         0x00000000
+
 #define NV50_DISP_SOR_MTHD                                           0x00010000
 #define NV50_DISP_SOR_MTHD_TYPE                                      0x0000f000
 #define NV50_DISP_SOR_MTHD_HEAD                                      0x00000018
index ac2881d1776ac1a071371a84f379ea57ea8ee856..7b8ea221b00dc7bf0d88021fc5443ae059401cbb 100644 (file)
@@ -38,7 +38,8 @@ enum nv_subdev_type {
        NVDEV_SUBDEV_THERM,
        NVDEV_SUBDEV_CLOCK,
 
-       NVDEV_ENGINE_DMAOBJ,
+       NVDEV_ENGINE_FIRST,
+       NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST,
        NVDEV_ENGINE_FIFO,
        NVDEV_ENGINE_SW,
        NVDEV_ENGINE_GR,
@@ -70,6 +71,7 @@ struct nouveau_device {
        const char *dbgopt;
        const char *name;
        const char *cname;
+       u64 disable_mask;
 
        enum {
                NV_04    = 0x04,
index 8c32cf4d83c78bb39773cd11233e59941da52699..26b6b2bb11121e28d4de88f08d4f308ab02fed7a 100644 (file)
@@ -109,6 +109,7 @@ extern struct nouveau_oclass *nv50_fifo_oclass;
 extern struct nouveau_oclass *nv84_fifo_oclass;
 extern struct nouveau_oclass *nvc0_fifo_oclass;
 extern struct nouveau_oclass *nve0_fifo_oclass;
+extern struct nouveau_oclass *nv108_fifo_oclass;
 
 void nv04_fifo_intr(struct nouveau_subdev *);
 int  nv04_fifo_context_attach(struct nouveau_object *, struct nouveau_object *);
index 8e1b52312ddc5cb2675696223ea8344548452ef1..97705618de979e9fe1f810ca3ee5f557d5dd19e2 100644 (file)
@@ -69,6 +69,7 @@ extern struct nouveau_oclass *nvd7_graph_oclass;
 extern struct nouveau_oclass *nvd9_graph_oclass;
 extern struct nouveau_oclass *nve4_graph_oclass;
 extern struct nouveau_oclass *nvf0_graph_oclass;
+extern struct nouveau_oclass *nv108_graph_oclass;
 
 extern const struct nouveau_bitfield nv04_graph_nsource[];
 extern struct nouveau_ofuncs nv04_graph_ofuncs;
index 4f4ff4502c3d2f284e2e6424abe05a923fbc6ff7..9faa98e67ad8c9057273eff0a7fc0f145799abf8 100644 (file)
@@ -4,8 +4,7 @@
 #include <core/subdev.h>
 #include <core/device.h>
 
-#include <subdev/fb.h>
-
+struct nouveau_mem;
 struct nouveau_vma;
 
 struct nouveau_bar {
@@ -29,27 +28,7 @@ nouveau_bar(void *obj)
        return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_BAR];
 }
 
-#define nouveau_bar_create(p,e,o,d)                                            \
-       nouveau_bar_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_bar_init(p)                                                    \
-       nouveau_subdev_init(&(p)->base)
-#define nouveau_bar_fini(p,s)                                                  \
-       nouveau_subdev_fini(&(p)->base, (s))
-
-int nouveau_bar_create_(struct nouveau_object *, struct nouveau_object *,
-                       struct nouveau_oclass *, int, void **);
-void nouveau_bar_destroy(struct nouveau_bar *);
-
-void _nouveau_bar_dtor(struct nouveau_object *);
-#define _nouveau_bar_init _nouveau_subdev_init
-#define _nouveau_bar_fini _nouveau_subdev_fini
-
 extern struct nouveau_oclass nv50_bar_oclass;
 extern struct nouveau_oclass nvc0_bar_oclass;
 
-int nouveau_bar_alloc(struct nouveau_bar *, struct nouveau_object *,
-                     struct nouveau_mem *, struct nouveau_object **);
-
-void nv84_bar_flush(struct nouveau_bar *);
-
 #endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h
new file mode 100644 (file)
index 0000000..c5e6d1e
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __NVBIOS_RAMCFG_H__
+#define __NVBIOS_RAMCFG_H__
+
+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 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[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;
+};
+
+u8 nvbios_ramcfg_count(struct nouveau_bios *);
+u8 nvbios_ramcfg_index(struct nouveau_bios *);
+
+#endif
index bc15e03208773cea8a16ce3a62a84e4cea702ec3..5bdf8e4db40a137df8b00f4a0183424929ad828c 100644 (file)
@@ -1,11 +1,25 @@
 #ifndef __NVBIOS_RAMMAP_H__
 #define __NVBIOS_RAMMAP_H__
 
-u16 nvbios_rammap_table(struct nouveau_bios *, u8 *ver, u8 *hdr,
-                       u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-u16 nvbios_rammap_entry(struct nouveau_bios *, int idx,
-                       u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_rammap_match(struct nouveau_bios *, u16 khz,
-                       u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+struct nvbios_ramcfg;
+
+u32 nvbios_rammapTe(struct nouveau_bios *, u8 *ver, u8 *hdr,
+                   u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+
+u32 nvbios_rammapEe(struct nouveau_bios *, int idx,
+                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+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 *);
+
+u32 nvbios_rammapSe(struct nouveau_bios *, u32 data,
+                   u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+                   u8 *ver, u8 *hdr);
+u32 nvbios_rammapSp(struct nouveau_bios *, u32 data,
+                   u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+                   u8 *ver, u8 *hdr,
+                   struct nvbios_ramcfg *);
 
 #endif
index 963694b5422492ea17526f88ef14ce5e30b70554..76d914b67ab5cc9c0a435d5fc77654cbbfb884e3 100644 (file)
@@ -1,8 +1,14 @@
 #ifndef __NVBIOS_TIMING_H__
 #define __NVBIOS_TIMING_H__
 
-u16 nvbios_timing_table(struct nouveau_bios *,
-                       u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_timing_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
+struct nvbios_ramcfg;
+
+u16 nvbios_timingTe(struct nouveau_bios *,
+                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+u16 nvbios_timingEe(struct nouveau_bios *, int idx,
+                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_timingEp(struct nouveau_bios *, int idx,
+                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+                   struct nvbios_ramcfg *);
 
 #endif
index 685c9b12ee4cff48a682f373b7dbd94d5ea0bb24..ed1ac68c38b354a58211c386e1c9bc450b8501ab 100644 (file)
@@ -9,7 +9,6 @@ struct nouveau_devinit {
        bool post;
        void (*meminit)(struct nouveau_devinit *);
        int  (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
-
 };
 
 static inline struct nouveau_devinit *
@@ -18,32 +17,16 @@ nouveau_devinit(void *obj)
        return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_DEVINIT];
 }
 
-#define nouveau_devinit_create(p,e,o,d)                                        \
-       nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_devinit_destroy(p)                                             \
-       nouveau_subdev_destroy(&(p)->base)
-#define nouveau_devinit_init(p) ({                                             \
-       struct nouveau_devinit *d = (p);                                       \
-       _nouveau_devinit_init(nv_object(d));                                   \
-})
-#define nouveau_devinit_fini(p,s) ({                                           \
-       struct nouveau_devinit *d = (p);                                       \
-       _nouveau_devinit_fini(nv_object(d), (s));                              \
-})
-
-int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *,
-                           struct nouveau_oclass *, int, void **);
-#define _nouveau_devinit_dtor _nouveau_subdev_dtor
-int _nouveau_devinit_init(struct nouveau_object *);
-int _nouveau_devinit_fini(struct nouveau_object *, bool suspend);
-
-extern struct nouveau_oclass nv04_devinit_oclass;
-extern struct nouveau_oclass nv05_devinit_oclass;
-extern struct nouveau_oclass nv10_devinit_oclass;
-extern struct nouveau_oclass nv1a_devinit_oclass;
-extern struct nouveau_oclass nv20_devinit_oclass;
-extern struct nouveau_oclass nv50_devinit_oclass;
-extern struct nouveau_oclass nva3_devinit_oclass;
-extern struct nouveau_oclass nvc0_devinit_oclass;
+extern struct nouveau_oclass *nv04_devinit_oclass;
+extern struct nouveau_oclass *nv05_devinit_oclass;
+extern struct nouveau_oclass *nv10_devinit_oclass;
+extern struct nouveau_oclass *nv1a_devinit_oclass;
+extern struct nouveau_oclass *nv20_devinit_oclass;
+extern struct nouveau_oclass *nv50_devinit_oclass;
+extern struct nouveau_oclass *nv84_devinit_oclass;
+extern struct nouveau_oclass *nv98_devinit_oclass;
+extern struct nouveau_oclass *nva3_devinit_oclass;
+extern struct nouveau_oclass *nvaf_devinit_oclass;
+extern struct nouveau_oclass *nvc0_devinit_oclass;
 
 #endif
index d89dbdf39b0db501159a873eeb5ada0612a3ba35..d7ecafbae1ca1c1b0a43192673fbf5ae582ffa60 100644 (file)
@@ -106,6 +106,13 @@ extern struct nouveau_oclass *nvaf_fb_oclass;
 extern struct nouveau_oclass *nvc0_fb_oclass;
 extern struct nouveau_oclass *nve0_fb_oclass;
 
+#include <subdev/bios/ramcfg.h>
+
+struct nouveau_ram_data {
+       struct nvbios_ramcfg bios;
+       u32 freq;
+};
+
 struct nouveau_ram {
        struct nouveau_object base;
        enum {
@@ -142,6 +149,12 @@ struct nouveau_ram {
        } rammap, ramcfg, timing;
        u32 freq;
        u32 mr[16];
+       u32 mr1_nuts;
+
+       struct nouveau_ram_data *next;
+       struct nouveau_ram_data former;
+       struct nouveau_ram_data xition;
+       struct nouveau_ram_data target;
 };
 
 #endif
index 4aca33887aaa639e4ad738065bfa775319d75afc..c1df26f3230c17f8fe6ff2a270b95cbafb441c6f 100644 (file)
@@ -23,21 +23,6 @@ nv_memobj(void *obj)
        return obj;
 }
 
-#define nouveau_instobj_create(p,e,o,d)                                        \
-       nouveau_instobj_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_instobj_init(p)                                                \
-       nouveau_object_init(&(p)->base)
-#define nouveau_instobj_fini(p,s)                                              \
-       nouveau_object_fini(&(p)->base, (s))
-
-int  nouveau_instobj_create_(struct nouveau_object *, struct nouveau_object *,
-                            struct nouveau_oclass *, int, void **);
-void nouveau_instobj_destroy(struct nouveau_instobj *);
-
-void _nouveau_instobj_dtor(struct nouveau_object *);
-#define _nouveau_instobj_init nouveau_object_init
-#define _nouveau_instobj_fini nouveau_object_fini
-
 struct nouveau_instmem {
        struct nouveau_subdev base;
        struct list_head list;
@@ -60,21 +45,8 @@ nouveau_instmem(void *obj)
        return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_INSTMEM];
 }
 
-#define nouveau_instmem_create(p,e,o,d)                                        \
-       nouveau_instmem_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_instmem_destroy(p)                                             \
-       nouveau_subdev_destroy(&(p)->base)
-int nouveau_instmem_create_(struct nouveau_object *, struct nouveau_object *,
-                           struct nouveau_oclass *, int, void **);
-int nouveau_instmem_init(struct nouveau_instmem *);
-int nouveau_instmem_fini(struct nouveau_instmem *, bool);
-
-#define _nouveau_instmem_dtor _nouveau_subdev_dtor
-int _nouveau_instmem_init(struct nouveau_object *);
-int _nouveau_instmem_fini(struct nouveau_object *, bool);
-
-extern struct nouveau_oclass nv04_instmem_oclass;
-extern struct nouveau_oclass nv40_instmem_oclass;
-extern struct nouveau_oclass nv50_instmem_oclass;
+extern struct nouveau_oclass *nv04_instmem_oclass;
+extern struct nouveau_oclass *nv40_instmem_oclass;
+extern struct nouveau_oclass *nv50_instmem_oclass;
 
 #endif
index fcf57fa309bfd54bbcbba86bdfc53ef5fcc481f6..c9509039f94b4b57bff45b718651bbdfd663012c 100644 (file)
@@ -131,9 +131,5 @@ void nouveau_vm_map(struct nouveau_vma *, struct nouveau_mem *);
 void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_mem *);
 void nouveau_vm_unmap(struct nouveau_vma *);
 void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length);
-void nouveau_vm_map_sg(struct nouveau_vma *, u64 offset, u64 length,
-                      struct nouveau_mem *);
-void nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length,
-                    struct nouveau_mem *mem);
 
 #endif
index d70ba342aa2e8f46c5de87c406b223d39ed98194..7098ddd546788c3adca970af4afc1a5a8d122d1a 100644 (file)
  */
 
 #include <core/object.h>
-#include <subdev/bar.h>
+
+#include <subdev/fb.h>
+#include <subdev/vm.h>
+
+#include "priv.h"
 
 struct nouveau_barobj {
        struct nouveau_object base;
index 160d27f3c7b4732fc67a069a415681295a0d8dd4..090d594a21b36ee9633462db5f0ee838547b1557 100644 (file)
 #include <core/gpuobj.h>
 
 #include <subdev/timer.h>
-#include <subdev/bar.h>
 #include <subdev/fb.h>
 #include <subdev/vm.h>
 
+#include "priv.h"
+
 struct nv50_bar_priv {
        struct nouveau_bar base;
        spinlock_t lock;
index b2ec7411eb2eb7cb43e5434016cad756159c69d6..bac5e754de35acdf838b571bf1d6e25eb8b5faec 100644 (file)
 #include <core/gpuobj.h>
 
 #include <subdev/timer.h>
-#include <subdev/bar.h>
 #include <subdev/fb.h>
 #include <subdev/vm.h>
 
+#include "priv.h"
+
 struct nvc0_bar_priv {
        struct nouveau_bar base;
        spinlock_t lock;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h
new file mode 100644 (file)
index 0000000..ffad8f3
--- /dev/null
@@ -0,0 +1,26 @@
+#ifndef __NVKM_BAR_PRIV_H__
+#define __NVKM_BAR_PRIV_H__
+
+#include <subdev/bar.h>
+
+#define nouveau_bar_create(p,e,o,d)                                            \
+       nouveau_bar_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_bar_init(p)                                                    \
+       nouveau_subdev_init(&(p)->base)
+#define nouveau_bar_fini(p,s)                                                  \
+       nouveau_subdev_fini(&(p)->base, (s))
+
+int nouveau_bar_create_(struct nouveau_object *, struct nouveau_object *,
+                       struct nouveau_oclass *, int, void **);
+void nouveau_bar_destroy(struct nouveau_bar *);
+
+void _nouveau_bar_dtor(struct nouveau_object *);
+#define _nouveau_bar_init _nouveau_subdev_init
+#define _nouveau_bar_fini _nouveau_subdev_fini
+
+int  nouveau_bar_alloc(struct nouveau_bar *, struct nouveau_object *,
+                      struct nouveau_mem *, struct nouveau_object **);
+
+void nv84_bar_flush(struct nouveau_bar *);
+
+#endif
index df1b1b42309337cb14c79b503497e49bf80ee49b..de201baeb053aea79a6632289a865de94fc5dc07 100644 (file)
@@ -9,6 +9,7 @@
 #include <subdev/bios/dp.h>
 #include <subdev/bios/gpio.h>
 #include <subdev/bios/init.h>
+#include <subdev/bios/ramcfg.h>
 #include <subdev/devinit.h>
 #include <subdev/i2c.h>
 #include <subdev/vga.h>
@@ -391,43 +392,14 @@ init_unknown_script(struct nouveau_bios *bios)
        return 0x0000;
 }
 
-static u16
-init_ram_restrict_table(struct nvbios_init *init)
-{
-       struct nouveau_bios *bios = init->bios;
-       struct bit_entry bit_M;
-       u16 data = 0x0000;
-
-       if (!bit_entry(bios, 'M', &bit_M)) {
-               if (bit_M.version == 1 && bit_M.length >= 5)
-                       data = nv_ro16(bios, bit_M.offset + 3);
-               if (bit_M.version == 2 && bit_M.length >= 3)
-                       data = nv_ro16(bios, bit_M.offset + 1);
-       }
-
-       if (data == 0x0000)
-               warn("ram restrict table not found\n");
-       return data;
-}
-
 static u8
 init_ram_restrict_group_count(struct nvbios_init *init)
 {
-       struct nouveau_bios *bios = init->bios;
-       struct bit_entry bit_M;
-
-       if (!bit_entry(bios, 'M', &bit_M)) {
-               if (bit_M.version == 1 && bit_M.length >= 5)
-                       return nv_ro08(bios, bit_M.offset + 2);
-               if (bit_M.version == 2 && bit_M.length >= 3)
-                       return nv_ro08(bios, bit_M.offset + 0);
-       }
-
-       return 0x00;
+       return nvbios_ramcfg_count(init->bios);
 }
 
 static u8
-init_ram_restrict_strap(struct nvbios_init *init)
+init_ram_restrict(struct nvbios_init *init)
 {
        /* This appears to be the behaviour of the VBIOS parser, and *is*
         * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to
@@ -438,18 +410,8 @@ init_ram_restrict_strap(struct nvbios_init *init)
         * in case *not* re-reading the strap causes similar breakage.
         */
        if (!init->ramcfg || init->bios->version.major < 0x70)
-               init->ramcfg = init_rd32(init, 0x101000);
-       return (init->ramcfg & 0x00000003c) >> 2;
-}
-
-static u8
-init_ram_restrict(struct nvbios_init *init)
-{
-       u8  strap = init_ram_restrict_strap(init);
-       u16 table = init_ram_restrict_table(init);
-       if (table)
-               return nv_ro08(init->bios, table + strap);
-       return 0x00;
+               init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->bios);
+       return (init->ramcfg & 0x7fffffff);
 }
 
 static u8
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c
new file mode 100644 (file)
index 0000000..991aedd
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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 <bskeggs@redhat.com>
+ */
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/ramcfg.h>
+
+static u8
+nvbios_ramcfg_strap(struct nouveau_bios *bios)
+{
+       return (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
+}
+
+u8
+nvbios_ramcfg_count(struct nouveau_bios *bios)
+{
+       struct bit_entry bit_M;
+
+       if (!bit_entry(bios, 'M', &bit_M)) {
+               if (bit_M.version == 1 && bit_M.length >= 5)
+                       return nv_ro08(bios, bit_M.offset + 2);
+               if (bit_M.version == 2 && bit_M.length >= 3)
+                       return nv_ro08(bios, bit_M.offset + 0);
+       }
+
+       return 0x00;
+}
+
+u8
+nvbios_ramcfg_index(struct nouveau_bios *bios)
+{
+       u8 strap = nvbios_ramcfg_strap(bios);
+       u32 xlat = 0x00000000;
+       struct bit_entry bit_M;
+
+       if (!bit_entry(bios, 'M', &bit_M)) {
+               if (bit_M.version == 1 && bit_M.length >= 5)
+                       xlat = nv_ro16(bios, bit_M.offset + 3);
+               if (bit_M.version == 2 && bit_M.length >= 3)
+                       xlat = nv_ro16(bios, bit_M.offset + 1);
+       }
+
+       if (xlat)
+               strap = nv_ro08(bios, xlat + strap);
+       return strap;
+}
index 916fa9d302b7f2fd108617844db25ddb565e4b5d..1811b2cb047276ead557d6d1025568667a1fbc24 100644 (file)
 
 #include <subdev/bios.h>
 #include <subdev/bios/bit.h>
+#include <subdev/bios/ramcfg.h>
 #include <subdev/bios/rammap.h>
 
-u16
-nvbios_rammap_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr,
-                   u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+u32
+nvbios_rammapTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr,
+               u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
 {
        struct bit_entry bit_P;
        u16 rammap = 0x0000;
@@ -57,12 +58,12 @@ nvbios_rammap_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr,
        return 0x0000;
 }
 
-u16
-nvbios_rammap_entry(struct nouveau_bios *bios, int idx,
-                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+u32
+nvbios_rammapEe(struct nouveau_bios *bios, int idx,
+               u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
 {
        u8  snr, ssz;
-       u16 rammap = nvbios_rammap_table(bios, ver, hdr, cnt, len, &snr, &ssz);
+       u16 rammap = nvbios_rammapTe(bios, ver, hdr, cnt, len, &snr, &ssz);
        if (rammap && idx < *cnt) {
                rammap = rammap + *hdr + (idx * (*len + (snr * ssz)));
                *hdr = *len;
@@ -73,16 +74,100 @@ nvbios_rammap_entry(struct nouveau_bios *bios, int idx,
        return 0x0000;
 }
 
-u16
-nvbios_rammap_match(struct nouveau_bios *bios, u16 khz,
-                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+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_rammap_entry(bios, idx++, ver, hdr, cnt, len))) {
+       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,
+               u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+               struct nvbios_ramcfg *p)
+{
+       u32 data = nvbios_rammapEm(bios, khz, ver, hdr, cnt, len);
+       memset(p, 0x00, sizeof(*p));
+       switch (!!data * *ver) {
+       case 0x11:
+               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;
+               p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2;
+               break;
+       default:
+               data = 0;
+               break;
+       }
+       return data;
+}
+
+u32
+nvbios_rammapSe(struct nouveau_bios *bios, u32 data,
+               u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+               u8 *ver, u8 *hdr)
+{
+       if (idx < ecnt) {
+               data = data + ehdr + (idx * elen);
+               *ver = ever;
+               *hdr = elen;
+               return data;
+       }
+       return 0;
+}
+
+u32
+nvbios_rammapSp(struct nouveau_bios *bios, u32 data,
+               u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+               u8 *ver, u8 *hdr, struct nvbios_ramcfg *p)
+{
+       data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr);
+       switch (!!data * *ver) {
+       case 0x11:
+               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;
+               p->ramcfg_11_01_08 = (nv_ro08(bios, data + 0x01) & 0x08) >> 3;
+               p->ramcfg_11_01_10 = (nv_ro08(bios, data + 0x01) & 0x10) >> 4;
+               p->ramcfg_11_01_20 = (nv_ro08(bios, data + 0x01) & 0x20) >> 5;
+               p->ramcfg_11_01_40 = (nv_ro08(bios, data + 0x01) & 0x40) >> 6;
+               p->ramcfg_11_01_80 = (nv_ro08(bios, data + 0x01) & 0x80) >> 7;
+               p->ramcfg_11_02_03 = (nv_ro08(bios, data + 0x02) & 0x03) >> 0;
+               p->ramcfg_11_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
+               p->ramcfg_11_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
+               p->ramcfg_11_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
+               p->ramcfg_11_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+               p->ramcfg_11_02_80 = (nv_ro08(bios, data + 0x02) & 0x80) >> 7;
+               p->ramcfg_11_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
+               p->ramcfg_11_03_30 = (nv_ro08(bios, data + 0x03) & 0x30) >> 4;
+               p->ramcfg_11_03_c0 = (nv_ro08(bios, data + 0x03) & 0xc0) >> 6;
+               p->ramcfg_11_03_f0 = (nv_ro08(bios, data + 0x03) & 0xf0) >> 4;
+               p->ramcfg_11_04    = (nv_ro08(bios, data + 0x04) & 0xff) >> 0;
+               p->ramcfg_11_06    = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
+               p->ramcfg_11_07_02 = (nv_ro08(bios, data + 0x07) & 0x02) >> 1;
+               p->ramcfg_11_07_04 = (nv_ro08(bios, data + 0x07) & 0x04) >> 2;
+               p->ramcfg_11_07_08 = (nv_ro08(bios, data + 0x07) & 0x08) >> 3;
+               p->ramcfg_11_07_10 = (nv_ro08(bios, data + 0x07) & 0x10) >> 4;
+               p->ramcfg_11_07_40 = (nv_ro08(bios, data + 0x07) & 0x40) >> 6;
+               p->ramcfg_11_07_80 = (nv_ro08(bios, data + 0x07) & 0x80) >> 7;
+               p->ramcfg_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
+               p->ramcfg_11_08_02 = (nv_ro08(bios, data + 0x08) & 0x02) >> 1;
+               p->ramcfg_11_08_04 = (nv_ro08(bios, data + 0x08) & 0x04) >> 2;
+               p->ramcfg_11_08_08 = (nv_ro08(bios, data + 0x08) & 0x08) >> 3;
+               p->ramcfg_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
+               p->ramcfg_11_08_20 = (nv_ro08(bios, data + 0x08) & 0x20) >> 5;
+               p->ramcfg_11_09    = (nv_ro08(bios, data + 0x09) & 0xff) >> 0;
+               break;
+       default:
+               data = 0;
+               break;
+       }
+       return data;
+}
index 151c2d6aaee872f1398fcca6aab7ae7b48a928d7..350d44ab2ba24b9e56a9dbf178a86497159cc326 100644 (file)
 
 #include <subdev/bios.h>
 #include <subdev/bios/bit.h>
+#include <subdev/bios/ramcfg.h>
 #include <subdev/bios/timing.h>
 
 u16
-nvbios_timing_table(struct nouveau_bios *bios,
-                   u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+nvbios_timingTe(struct nouveau_bios *bios,
+               u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
 {
        struct bit_entry bit_P;
        u16 timing = 0x0000;
@@ -47,11 +48,15 @@ nvbios_timing_table(struct nouveau_bios *bios,
                                *hdr = nv_ro08(bios, timing + 1);
                                *cnt = nv_ro08(bios, timing + 2);
                                *len = nv_ro08(bios, timing + 3);
+                               *snr = 0;
+                               *ssz = 0;
                                return timing;
                        case 0x20:
                                *hdr = nv_ro08(bios, timing + 1);
-                               *cnt = nv_ro08(bios, timing + 3);
+                               *cnt = nv_ro08(bios, timing + 5);
                                *len = nv_ro08(bios, timing + 2);
+                               *snr = nv_ro08(bios, timing + 4);
+                               *ssz = nv_ro08(bios, timing + 3);
                                return timing;
                        default:
                                break;
@@ -63,11 +68,60 @@ nvbios_timing_table(struct nouveau_bios *bios,
 }
 
 u16
-nvbios_timing_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
+nvbios_timingEe(struct nouveau_bios *bios, int idx,
+               u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
 {
-       u8  hdr, cnt;
-       u16 timing = nvbios_timing_table(bios, ver, &hdr, &cnt, len);
-       if (timing && idx < cnt)
-               return timing + hdr + (idx * *len);
+       u8  snr, ssz;
+       u16 timing = nvbios_timingTe(bios, ver, hdr, cnt, len, &snr, &ssz);
+       if (timing && idx < *cnt) {
+               timing += *hdr + idx * (*len + (snr * ssz));
+               *hdr = *len;
+               *cnt = snr;
+               *len = ssz;
+               return timing;
+       }
        return 0x0000;
 }
+
+u16
+nvbios_timingEp(struct nouveau_bios *bios, int idx,
+               u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+               struct nvbios_ramcfg *p)
+{
+       u16 data = nvbios_timingEe(bios, idx, ver, hdr, cnt, len), temp;
+       switch (!!data * *ver) {
+       case 0x20:
+               p->timing[0] = nv_ro32(bios, data + 0x00);
+               p->timing[1] = nv_ro32(bios, data + 0x04);
+               p->timing[2] = nv_ro32(bios, data + 0x08);
+               p->timing[3] = nv_ro32(bios, data + 0x0c);
+               p->timing[4] = nv_ro32(bios, data + 0x10);
+               p->timing[5] = nv_ro32(bios, data + 0x14);
+               p->timing[6] = nv_ro32(bios, data + 0x18);
+               p->timing[7] = nv_ro32(bios, data + 0x1c);
+               p->timing[8] = nv_ro32(bios, data + 0x20);
+               p->timing[9] = nv_ro32(bios, data + 0x24);
+               p->timing[10] = nv_ro32(bios, data + 0x28);
+               p->timing_20_2e_03 = (nv_ro08(bios, data + 0x2e) & 0x03) >> 0;
+               p->timing_20_2e_30 = (nv_ro08(bios, data + 0x2e) & 0x30) >> 4;
+               p->timing_20_2e_c0 = (nv_ro08(bios, data + 0x2e) & 0xc0) >> 6;
+               p->timing_20_2f_03 = (nv_ro08(bios, data + 0x2f) & 0x03) >> 0;
+               temp = nv_ro16(bios, data + 0x2c);
+               p->timing_20_2c_003f = (temp & 0x003f) >> 0;
+               p->timing_20_2c_1fc0 = (temp & 0x1fc0) >> 6;
+               p->timing_20_30_07 = (nv_ro08(bios, data + 0x30) & 0x07) >> 0;
+               p->timing_20_30_f8 = (nv_ro08(bios, data + 0x30) & 0xf8) >> 3;
+               temp = nv_ro16(bios, data + 0x31);
+               p->timing_20_31_0007 = (temp & 0x0007) >> 0;
+               p->timing_20_31_0078 = (temp & 0x0078) >> 3;
+               p->timing_20_31_0780 = (temp & 0x0780) >> 7;
+               p->timing_20_31_0800 = (temp & 0x0800) >> 11;
+               p->timing_20_31_7000 = (temp & 0x7000) >> 12;
+               p->timing_20_31_8000 = (temp & 0x8000) >> 15;
+               break;
+       default:
+               data = 0;
+               break;
+       }
+       return data;
+}
index e2938a21b06fe8a7ac255e9abe106ce1533dc448..dd62baead39c54c9a906939576553b59bf9355a2 100644 (file)
@@ -182,9 +182,12 @@ nouveau_pstate_prog(struct nouveau_clock *clk, int pstatei)
        clk->pstate = pstatei;
 
        if (pfb->ram->calc) {
-               ret = pfb->ram->calc(pfb, pstate->base.domain[nv_clk_src_mem]);
-               if (ret == 0)
-                       ret = pfb->ram->prog(pfb);
+               int khz = pstate->base.domain[nv_clk_src_mem];
+               do {
+                       ret = pfb->ram->calc(pfb, khz);
+                       if (ret == 0)
+                               ret = pfb->ram->prog(pfb);
+               } while (ret > 0);
                pfb->ram->tidy(pfb);
        }
 
index 30c1f3a4158e3de87fd2bfb24592b9ea685b2d88..b74db6cfc4e21ee8f811a08e54da3dfdc7f824a1 100644 (file)
@@ -25,7 +25,7 @@
 #include <subdev/bios.h>
 #include <subdev/bios/pll.h>
 #include <subdev/clock.h>
-#include <subdev/devinit/priv.h>
+#include <subdev/devinit/nv04.h>
 
 #include "pll.h"
 
index 4c62e84b96f5f7a4aa65d5e8d37bd25d12b120eb..d3c37c96f0e7eaeed97c08749bc23611642705db 100644 (file)
@@ -457,7 +457,7 @@ nve0_domain[] = {
        { nv_clk_src_gpc    , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 },
        { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
        { nv_clk_src_rop    , 0x02, NVKM_CLK_DOM_FLAG_CORE },
-       { nv_clk_src_mem    , 0x03, 0, "memory", 1000 },
+       { nv_clk_src_mem    , 0x03, 0, "memory", 500 },
        { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE },
        { nv_clk_src_hubk01 , 0x05 },
        { nv_clk_src_vdec   , 0x06 },
index 79c81d3d9bacee32ec45f36dee8b73cee3ac2953..8fa34e8152c20b6ae90f2ca020f6c49a077f2cdd 100644 (file)
 
 #include <core/option.h>
 
-#include <subdev/devinit.h>
 #include <subdev/bios.h>
 #include <subdev/bios/init.h>
+#include <subdev/vga.h>
+
+#include "priv.h"
 
 int
 _nouveau_devinit_fini(struct nouveau_object *object, bool suspend)
@@ -37,18 +39,41 @@ _nouveau_devinit_fini(struct nouveau_object *object, bool suspend)
        if (suspend)
                devinit->post = true;
 
+       /* unlock the extended vga crtc regs */
+       nv_lockvgac(devinit, false);
+
        return nouveau_subdev_fini(&devinit->base, suspend);
 }
 
 int
 _nouveau_devinit_init(struct nouveau_object *object)
 {
+       struct nouveau_devinit_impl *impl = (void *)object->oclass;
        struct nouveau_devinit *devinit = (void *)object;
-       int ret = nouveau_subdev_init(&devinit->base);
+       int ret;
+
+       ret = nouveau_subdev_init(&devinit->base);
+       if (ret)
+               return ret;
+
+       ret = nvbios_init(&devinit->base, devinit->post);
        if (ret)
                return ret;
 
-       return nvbios_init(&devinit->base, devinit->post);
+       if (impl->disable)
+               nv_device(devinit)->disable_mask |= impl->disable(devinit);
+       return 0;
+}
+
+void
+_nouveau_devinit_dtor(struct nouveau_object *object)
+{
+       struct nouveau_devinit *devinit = (void *)object;
+
+       /* lock crtc regs */
+       nv_lockvgac(devinit, true);
+
+       nouveau_subdev_destroy(&devinit->base);
 }
 
 int
@@ -57,6 +82,7 @@ nouveau_devinit_create_(struct nouveau_object *parent,
                        struct nouveau_oclass *oclass,
                        int size, void **pobject)
 {
+       struct nouveau_devinit_impl *impl = (void *)oclass;
        struct nouveau_device *device = nv_device(parent);
        struct nouveau_devinit *devinit;
        int ret;
@@ -68,5 +94,7 @@ nouveau_devinit_create_(struct nouveau_object *parent,
                return ret;
 
        devinit->post = nouveau_boolopt(device->cfgopt, "NvForcePost", false);
+       devinit->meminit = impl->meminit;
+       devinit->pll_set = impl->pll_set;
        return 0;
 }
index 27c8235f1a85d08a3128dd3266416461ba08a9a7..7037eae46e445bd5d3278dfc70119dac180cadbb 100644 (file)
 #include <subdev/vga.h>
 
 #include "fbmem.h"
-#include "priv.h"
-
-struct nv04_devinit_priv {
-       struct nouveau_devinit base;
-       int owner;
-};
+#include "nv04.h"
 
 static void
 nv04_devinit_meminit(struct nouveau_devinit *devinit)
@@ -393,17 +388,21 @@ int
 nv04_devinit_fini(struct nouveau_object *object, bool suspend)
 {
        struct nv04_devinit_priv *priv = (void *)object;
+       int ret;
 
        /* make i2c busses accessible */
        nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
 
-       /* unlock extended vga crtc regs, and unslave crtcs */
-       nv_lockvgac(priv, false);
+       ret = nouveau_devinit_fini(&priv->base, suspend);
+       if (ret)
+               return ret;
+
+       /* unslave crtcs */
        if (priv->owner < 0)
                priv->owner = nv_rdvgaowner(priv);
        nv_wrvgaowner(priv, 0);
 
-       return nouveau_devinit_fini(&priv->base, suspend);
+       return 0;
 }
 
 int
@@ -431,14 +430,13 @@ nv04_devinit_dtor(struct nouveau_object *object)
 {
        struct nv04_devinit_priv *priv = (void *)object;
 
-       /* restore vga owner saved at first init, and lock crtc regs  */
+       /* restore vga owner saved at first init */
        nv_wrvgaowner(priv, priv->owner);
-       nv_lockvgac(priv, true);
 
        nouveau_devinit_destroy(&priv->base);
 }
 
-static int
+int
 nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                  struct nouveau_oclass *oclass, void *data, u32 size,
                  struct nouveau_object **pobject)
@@ -451,19 +449,19 @@ nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       priv->base.meminit = nv04_devinit_meminit;
-       priv->base.pll_set = nv04_devinit_pll_set;
        priv->owner = -1;
        return 0;
 }
 
-struct nouveau_oclass
-nv04_devinit_oclass = {
-       .handle = NV_SUBDEV(DEVINIT, 0x04),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv04_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x04),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv04_devinit_ctor,
                .dtor = nv04_devinit_dtor,
                .init = nv04_devinit_init,
                .fini = nv04_devinit_fini,
        },
-};
+       .meminit = nv04_devinit_meminit,
+       .pll_set = nv04_devinit_pll_set,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h
new file mode 100644 (file)
index 0000000..23470a5
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __NVKM_DEVINIT_NV04_H__
+#define __NVKM_DEVINIT_NV04_H__
+
+#include "priv.h"
+
+struct nv04_devinit_priv {
+       struct nouveau_devinit base;
+       u8 owner;
+};
+
+int  nv04_devinit_ctor(struct nouveau_object *, struct nouveau_object *,
+                      struct nouveau_oclass *, void *, u32,
+                      struct nouveau_object **);
+void nv04_devinit_dtor(struct nouveau_object *);
+int  nv04_devinit_init(struct nouveau_object *);
+int  nv04_devinit_fini(struct nouveau_object *, bool);
+int  nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32);
+
+void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
+void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
+void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
+
+#endif
index b1912a8a8942129b6292323faed5aa11475bfe3e..98b7e6780dc7f4826c4eb946419d0ceb6cfb5d84 100644 (file)
 #include <subdev/vga.h>
 
 #include "fbmem.h"
-#include "priv.h"
-
-struct nv05_devinit_priv {
-       struct nouveau_devinit base;
-       u8 owner;
-};
+#include "nv04.h"
 
 static void
 nv05_devinit_meminit(struct nouveau_devinit *devinit)
@@ -49,7 +44,7 @@ nv05_devinit_meminit(struct nouveau_devinit *devinit)
                { 0x06, 0x00 },
                { 0x00, 0x00 }
        };
-       struct nv05_devinit_priv *priv = (void *)devinit;
+       struct nv04_devinit_priv *priv = (void *)devinit;
        struct nouveau_bios *bios = nouveau_bios(priv);
        struct io_mapping *fb;
        u32 patt = 0xdeadbeef;
@@ -130,31 +125,15 @@ out:
        fbmem_fini(fb);
 }
 
-static int
-nv05_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-                 struct nouveau_oclass *oclass, void *data, u32 size,
-                 struct nouveau_object **pobject)
-{
-       struct nv05_devinit_priv *priv;
-       int ret;
-
-       ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.meminit = nv05_devinit_meminit;
-       priv->base.pll_set = nv04_devinit_pll_set;
-       return 0;
-}
-
-struct nouveau_oclass
-nv05_devinit_oclass = {
-       .handle = NV_SUBDEV(DEVINIT, 0x05),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv05_devinit_ctor,
+struct nouveau_oclass *
+nv05_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x05),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_devinit_ctor,
                .dtor = nv04_devinit_dtor,
                .init = nv04_devinit_init,
                .fini = nv04_devinit_fini,
        },
-};
+       .meminit = nv05_devinit_meminit,
+       .pll_set = nv04_devinit_pll_set,
+}.base;
index 8d274dba1ef17a363af4d4c33c3cea4451025159..32b3d2131a7f0d14b0e37e8b9888e2b38cf937c5 100644 (file)
 #include <subdev/vga.h>
 
 #include "fbmem.h"
-#include "priv.h"
-
-struct nv10_devinit_priv {
-       struct nouveau_devinit base;
-       u8 owner;
-};
+#include "nv04.h"
 
 static void
 nv10_devinit_meminit(struct nouveau_devinit *devinit)
 {
-       struct nv10_devinit_priv *priv = (void *)devinit;
+       struct nv04_devinit_priv *priv = (void *)devinit;
        static const int mem_width[] = { 0x10, 0x00, 0x20 };
        int mem_width_count;
        uint32_t patt = 0xdeadbeef;
@@ -101,31 +96,15 @@ amount_found:
        fbmem_fini(fb);
 }
 
-static int
-nv10_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-                 struct nouveau_oclass *oclass, void *data, u32 size,
-                 struct nouveau_object **pobject)
-{
-       struct nv10_devinit_priv *priv;
-       int ret;
-
-       ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.meminit = nv10_devinit_meminit;
-       priv->base.pll_set = nv04_devinit_pll_set;
-       return 0;
-}
-
-struct nouveau_oclass
-nv10_devinit_oclass = {
-       .handle = NV_SUBDEV(DEVINIT, 0x10),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv10_devinit_ctor,
+struct nouveau_oclass *
+nv10_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x10),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_devinit_ctor,
                .dtor = nv04_devinit_dtor,
                .init = nv04_devinit_init,
                .fini = nv04_devinit_fini,
        },
-};
+       .meminit = nv10_devinit_meminit,
+       .pll_set = nv04_devinit_pll_set,
+}.base;
index e9743cdabe757df66b92509f295d9c800a6ae919..526d0c6faacd3d2623f1dae3aa2cd1b92087a00e 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include "priv.h"
+#include "nv04.h"
 
-struct nv1a_devinit_priv {
-       struct nouveau_devinit base;
-       u8 owner;
-};
-
-static int
-nv1a_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-                 struct nouveau_oclass *oclass, void *data, u32 size,
-                 struct nouveau_object **pobject)
-{
-       struct nv1a_devinit_priv *priv;
-       int ret;
-
-       ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.pll_set = nv04_devinit_pll_set;
-       return 0;
-}
-
-struct nouveau_oclass
-nv1a_devinit_oclass = {
-       .handle = NV_SUBDEV(DEVINIT, 0x1a),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv1a_devinit_ctor,
+struct nouveau_oclass *
+nv1a_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x1a),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_devinit_ctor,
                .dtor = nv04_devinit_dtor,
                .init = nv04_devinit_init,
                .fini = nv04_devinit_fini,
        },
-};
+       .pll_set = nv04_devinit_pll_set,
+}.base;
index 6cc6080d3bc01e4e9e461bb5c323f82e48a60908..4689ba303b0bd6620ec080fcfe9fa3defad2f3ff 100644 (file)
  *
  */
 
-#include "priv.h"
+#include "nv04.h"
 #include "fbmem.h"
 
-struct nv20_devinit_priv {
-       struct nouveau_devinit base;
-       u8 owner;
-};
-
 static void
 nv20_devinit_meminit(struct nouveau_devinit *devinit)
 {
-       struct nv20_devinit_priv *priv = (void *)devinit;
+       struct nv04_devinit_priv *priv = (void *)devinit;
        struct nouveau_device *device = nv_device(priv);
        uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900);
        uint32_t amount, off;
@@ -65,31 +60,15 @@ nv20_devinit_meminit(struct nouveau_devinit *devinit)
        fbmem_fini(fb);
 }
 
-static int
-nv20_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-                 struct nouveau_oclass *oclass, void *data, u32 size,
-                 struct nouveau_object **pobject)
-{
-       struct nv20_devinit_priv *priv;
-       int ret;
-
-       ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
-
-       priv->base.meminit = nv20_devinit_meminit;
-       priv->base.pll_set = nv04_devinit_pll_set;
-       return 0;
-}
-
-struct nouveau_oclass
-nv20_devinit_oclass = {
-       .handle = NV_SUBDEV(DEVINIT, 0x20),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nv20_devinit_ctor,
+struct nouveau_oclass *
+nv20_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x20),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv04_devinit_ctor,
                .dtor = nv04_devinit_dtor,
                .init = nv04_devinit_init,
                .fini = nv04_devinit_fini,
        },
-};
+       .meminit = nv20_devinit_meminit,
+       .pll_set = nv04_devinit_pll_set,
+}.base;
index 6df72247c477b5a7c96214fe28a0d7a40be82696..b46c62a1d5d86a9a44a0db88932dacbca6a10598 100644 (file)
@@ -28,9 +28,9 @@
 #include <subdev/bios/init.h>
 #include <subdev/vga.h>
 
-#include "priv.h"
+#include "nv50.h"
 
-static int
+int
 nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
 {
        struct nv50_devinit_priv *priv = (void *)devinit;
@@ -74,6 +74,19 @@ nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
        return 0;
 }
 
+static u64
+nv50_devinit_disable(struct nouveau_devinit *devinit)
+{
+       struct nv50_devinit_priv *priv = (void *)devinit;
+       u32 r001540 = nv_rd32(priv, 0x001540);
+       u64 disable = 0ULL;
+
+       if (!(r001540 & 0x40000000))
+               disable |= (1ULL << NVDEV_ENGINE_MPEG);
+
+       return disable;
+}
+
 int
 nv50_devinit_init(struct nouveau_object *object)
 {
@@ -120,7 +133,7 @@ nv50_devinit_init(struct nouveau_object *object)
        return 0;
 }
 
-static int
+int
 nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                  struct nouveau_oclass *oclass, void *data, u32 size,
                  struct nouveau_object **pobject)
@@ -133,17 +146,18 @@ nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       priv->base.pll_set = nv50_devinit_pll_set;
        return 0;
 }
 
-struct nouveau_oclass
-nv50_devinit_oclass = {
-       .handle = NV_SUBDEV(DEVINIT, 0x50),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv50_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x50),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv50_devinit_ctor,
                .dtor = _nouveau_devinit_dtor,
                .init = nv50_devinit_init,
                .fini = _nouveau_devinit_fini,
        },
-};
+       .pll_set = nv50_devinit_pll_set,
+       .disable = nv50_devinit_disable,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h
new file mode 100644 (file)
index 0000000..141c27e
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef __NVKM_DEVINIT_NV50_H__
+#define __NVKM_DEVINIT_NV50_H__
+
+#include "priv.h"
+
+struct nv50_devinit_priv {
+       struct nouveau_devinit base;
+};
+
+int  nv50_devinit_ctor(struct nouveau_object *, struct nouveau_object *,
+                      struct nouveau_oclass *, void *, u32,
+                      struct nouveau_object **);
+int  nv50_devinit_init(struct nouveau_object *);
+int  nv50_devinit_pll_set(struct nouveau_devinit *, u32, u32);
+
+int  nva3_devinit_pll_set(struct nouveau_devinit *, u32, u32);
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c
new file mode 100644 (file)
index 0000000..7874225
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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 "nv50.h"
+
+static u64
+nv84_devinit_disable(struct nouveau_devinit *devinit)
+{
+       struct nv50_devinit_priv *priv = (void *)devinit;
+       u32 r001540 = nv_rd32(priv, 0x001540);
+       u32 r00154c = nv_rd32(priv, 0x00154c);
+       u64 disable = 0ULL;
+
+       if (!(r001540 & 0x40000000)) {
+               disable |= (1ULL << NVDEV_ENGINE_MPEG);
+               disable |= (1ULL << NVDEV_ENGINE_VP);
+               disable |= (1ULL << NVDEV_ENGINE_BSP);
+               disable |= (1ULL << NVDEV_ENGINE_CRYPT);
+       }
+
+       if (!(r00154c & 0x00000004))
+               disable |= (1ULL << NVDEV_ENGINE_DISP);
+       if (!(r00154c & 0x00000020))
+               disable |= (1ULL << NVDEV_ENGINE_BSP);
+       if (!(r00154c & 0x00000040))
+               disable |= (1ULL << NVDEV_ENGINE_CRYPT);
+
+       return disable;
+}
+
+struct nouveau_oclass *
+nv84_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x84),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_devinit_ctor,
+               .dtor = _nouveau_devinit_dtor,
+               .init = nv50_devinit_init,
+               .fini = _nouveau_devinit_fini,
+       },
+       .pll_set = nv50_devinit_pll_set,
+       .disable = nv84_devinit_disable,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c
new file mode 100644 (file)
index 0000000..2b0e963
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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 "nv50.h"
+
+static u64
+nv98_devinit_disable(struct nouveau_devinit *devinit)
+{
+       struct nv50_devinit_priv *priv = (void *)devinit;
+       u32 r001540 = nv_rd32(priv, 0x001540);
+       u32 r00154c = nv_rd32(priv, 0x00154c);
+       u64 disable = 0ULL;
+
+       if (!(r001540 & 0x40000000)) {
+               disable |= (1ULL << NVDEV_ENGINE_VP);
+               disable |= (1ULL << NVDEV_ENGINE_BSP);
+               disable |= (1ULL << NVDEV_ENGINE_PPP);
+       }
+
+       if (!(r00154c & 0x00000004))
+               disable |= (1ULL << NVDEV_ENGINE_DISP);
+       if (!(r00154c & 0x00000020))
+               disable |= (1ULL << NVDEV_ENGINE_BSP);
+       if (!(r00154c & 0x00000040))
+               disable |= (1ULL << NVDEV_ENGINE_CRYPT);
+
+       return disable;
+}
+
+struct nouveau_oclass *
+nv98_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0x98),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_devinit_ctor,
+               .dtor = _nouveau_devinit_dtor,
+               .init = nv50_devinit_init,
+               .fini = _nouveau_devinit_fini,
+       },
+       .pll_set = nv50_devinit_pll_set,
+       .disable = nv98_devinit_disable,
+}.base;
index 76a68b29014119f57c909c4770777016e8838250..6dedf1dad7f7bce5b71d33dd01111cac7324621b 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include "priv.h"
+#include "nv50.h"
 
-static int
+int
 nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
 {
-       struct nva3_devinit_priv *priv = (void *)devinit;
+       struct nv50_devinit_priv *priv = (void *)devinit;
        struct nouveau_bios *bios = nouveau_bios(priv);
        struct nvbios_pll info;
        int N, fN, M, P;
@@ -58,30 +58,38 @@ nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
        return ret;
 }
 
-static int
-nva3_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-                 struct nouveau_oclass *oclass, void *data, u32 size,
-                 struct nouveau_object **pobject)
+static u64
+nva3_devinit_disable(struct nouveau_devinit *devinit)
 {
-       struct nv50_devinit_priv *priv;
-       int ret;
+       struct nv50_devinit_priv *priv = (void *)devinit;
+       u32 r001540 = nv_rd32(priv, 0x001540);
+       u32 r00154c = nv_rd32(priv, 0x00154c);
+       u64 disable = 0ULL;
 
-       ret = nouveau_devinit_create(parent, engine, oclass, &priv);
-       *pobject = nv_object(priv);
-       if (ret)
-               return ret;
+       if (!(r001540 & 0x40000000)) {
+               disable |= (1ULL << NVDEV_ENGINE_VP);
+               disable |= (1ULL << NVDEV_ENGINE_PPP);
+       }
+
+       if (!(r00154c & 0x00000004))
+               disable |= (1ULL << NVDEV_ENGINE_DISP);
+       if (!(r00154c & 0x00000020))
+               disable |= (1ULL << NVDEV_ENGINE_BSP);
+       if (!(r00154c & 0x00000200))
+               disable |= (1ULL << NVDEV_ENGINE_COPY0);
 
-       priv->base.pll_set = nva3_devinit_pll_set;
-       return 0;
+       return disable;
 }
 
-struct nouveau_oclass
-nva3_devinit_oclass = {
-       .handle = NV_SUBDEV(DEVINIT, 0xa3),
-       .ofuncs = &(struct nouveau_ofuncs) {
-               .ctor = nva3_devinit_ctor,
+struct nouveau_oclass *
+nva3_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0xa3),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_devinit_ctor,
                .dtor = _nouveau_devinit_dtor,
                .init = nv50_devinit_init,
                .fini = _nouveau_devinit_fini,
        },
-};
+       .pll_set = nva3_devinit_pll_set,
+       .disable = nva3_devinit_disable,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c
new file mode 100644 (file)
index 0000000..4fc68d2
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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 "nv50.h"
+
+static u64
+nvaf_devinit_disable(struct nouveau_devinit *devinit)
+{
+       struct nv50_devinit_priv *priv = (void *)devinit;
+       u32 r001540 = nv_rd32(priv, 0x001540);
+       u32 r00154c = nv_rd32(priv, 0x00154c);
+       u64 disable = 0;
+
+       if (!(r001540 & 0x40000000)) {
+               disable |= (1ULL << NVDEV_ENGINE_VP);
+               disable |= (1ULL << NVDEV_ENGINE_PPP);
+       }
+
+       if (!(r00154c & 0x00000004))
+               disable |= (1ULL << NVDEV_ENGINE_DISP);
+       if (!(r00154c & 0x00000020))
+               disable |= (1ULL << NVDEV_ENGINE_BSP);
+       if (!(r00154c & 0x00000040))
+               disable |= (1ULL << NVDEV_ENGINE_VIC);
+       if (!(r00154c & 0x00000200))
+               disable |= (1ULL << NVDEV_ENGINE_COPY0);
+
+       return disable;
+}
+
+struct nouveau_oclass *
+nvaf_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0xaf),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
+               .ctor = nv50_devinit_ctor,
+               .dtor = _nouveau_devinit_dtor,
+               .init = nv50_devinit_init,
+               .fini = _nouveau_devinit_fini,
+       },
+       .pll_set = nva3_devinit_pll_set,
+       .disable = nvaf_devinit_disable,
+}.base;
index 19e265bf4574a0ad04086bd99d6fa0c2dd9912f9..fa7e63766b1b19ae47b8557c4581b77cb0ff0a22 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include "priv.h"
+#include "nv50.h"
 
 static int
 nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
 {
-       struct nvc0_devinit_priv *priv = (void *)devinit;
+       struct nv50_devinit_priv *priv = (void *)devinit;
        struct nouveau_bios *bios = nouveau_bios(priv);
        struct nvbios_pll info;
        int N, fN, M, P;
@@ -59,6 +59,33 @@ nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
        return ret;
 }
 
+static u64
+nvc0_devinit_disable(struct nouveau_devinit *devinit)
+{
+       struct nv50_devinit_priv *priv = (void *)devinit;
+       u32 r022500 = nv_rd32(priv, 0x022500);
+       u64 disable = 0ULL;
+
+       if (r022500 & 0x00000001)
+               disable |= (1ULL << NVDEV_ENGINE_DISP);
+
+       if (r022500 & 0x00000002) {
+               disable |= (1ULL << NVDEV_ENGINE_VP);
+               disable |= (1ULL << NVDEV_ENGINE_PPP);
+       }
+
+       if (r022500 & 0x00000004)
+               disable |= (1ULL << NVDEV_ENGINE_BSP);
+       if (r022500 & 0x00000008)
+               disable |= (1ULL << NVDEV_ENGINE_VENC);
+       if (r022500 & 0x00000100)
+               disable |= (1ULL << NVDEV_ENGINE_COPY0);
+       if (r022500 & 0x00000200)
+               disable |= (1ULL << NVDEV_ENGINE_COPY1);
+
+       return disable;
+}
+
 static int
 nvc0_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                  struct nouveau_oclass *oclass, void *data, u32 size,
@@ -72,19 +99,20 @@ nvc0_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        if (ret)
                return ret;
 
-       priv->base.pll_set = nvc0_devinit_pll_set;
        if (nv_rd32(priv, 0x022500) & 0x00000001)
                priv->base.post = true;
        return 0;
 }
 
-struct nouveau_oclass
-nvc0_devinit_oclass = {
-       .handle = NV_SUBDEV(DEVINIT, 0xc0),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nvc0_devinit_oclass = &(struct nouveau_devinit_impl) {
+       .base.handle = NV_SUBDEV(DEVINIT, 0xc0),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nvc0_devinit_ctor,
                .dtor = _nouveau_devinit_dtor,
                .init = nv50_devinit_init,
                .fini = _nouveau_devinit_fini,
        },
-};
+       .pll_set = nvc0_devinit_pll_set,
+       .disable = nvc0_devinit_disable,
+}.base;
index 7d622e2b01712508259e1f4436e0284543da7435..822a2fbf44a5b3d601d5c79eedb7b2af68654d86 100644 (file)
@@ -6,20 +6,32 @@
 #include <subdev/clock/pll.h>
 #include <subdev/devinit.h>
 
-void nv04_devinit_dtor(struct nouveau_object *);
-int  nv04_devinit_init(struct nouveau_object *);
-int  nv04_devinit_fini(struct nouveau_object *, bool);
-int  nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32);
-
-void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
-void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
-void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
-
-
-struct nv50_devinit_priv {
-       struct nouveau_devinit base;
+struct nouveau_devinit_impl {
+       struct nouveau_oclass base;
+       void (*meminit)(struct nouveau_devinit *);
+       int  (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
+       u64  (*disable)(struct nouveau_devinit *);
 };
 
-int  nv50_devinit_init(struct nouveau_object *);
+#define nouveau_devinit_create(p,e,o,d)                                        \
+       nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_devinit_destroy(p) ({                                          \
+       struct nouveau_devinit *d = (p);                                       \
+       _nouveau_devinit_dtor(nv_object(d));                                   \
+})
+#define nouveau_devinit_init(p) ({                                             \
+       struct nouveau_devinit *d = (p);                                       \
+       _nouveau_devinit_init(nv_object(d));                                   \
+})
+#define nouveau_devinit_fini(p,s) ({                                           \
+       struct nouveau_devinit *d = (p);                                       \
+       _nouveau_devinit_fini(nv_object(d), (s));                              \
+})
+
+int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *,
+                           struct nouveau_oclass *, int, void **);
+void _nouveau_devinit_dtor(struct nouveau_object *);
+int _nouveau_devinit_init(struct nouveau_object *);
+int _nouveau_devinit_fini(struct nouveau_object *, bool suspend);
 
 #endif
index 34f9605ffee61321d381d6c3ed7e552f8918c51b..66fe959b4f7431dd2cc1b9ce6520263560fb769f 100644 (file)
 #include <subdev/bios.h>
 #include "priv.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
+
 int
-nouveau_gddr5_calc(struct nouveau_ram *ram)
+nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts)
 {
-       struct nouveau_bios *bios = nouveau_bios(ram);
-       int pd, lf, xd, vh, vr, vo;
-       int WL, CL, WR, at, dt, ds;
+       int pd, lf, xd, vh, vr, vo, l3;
+       int WL, CL, WR, at[2], dt, ds;
        int rq = ram->freq < 1000000; /* XXX */
 
-       switch (!!ram->ramcfg.data * ram->ramcfg.version) {
+       switch (ram->ramcfg.version) {
        case 0x11:
-               pd =  (nv_ro08(bios, ram->ramcfg.data + 0x01) & 0x80) >> 7;
-               lf =  (nv_ro08(bios, ram->ramcfg.data + 0x01) & 0x40) >> 6;
-               xd = !(nv_ro08(bios, ram->ramcfg.data + 0x01) & 0x20);
-               vh =  (nv_ro08(bios, ram->ramcfg.data + 0x02) & 0x10) >> 4;
-               vr =  (nv_ro08(bios, ram->ramcfg.data + 0x02) & 0x04) >> 2;
-               vo =   nv_ro08(bios, ram->ramcfg.data + 0x06) & 0xff;
+               pd =  ram->next->bios.ramcfg_11_01_80;
+               lf =  ram->next->bios.ramcfg_11_01_40;
+               xd = !ram->next->bios.ramcfg_11_01_20;
+               vh =  ram->next->bios.ramcfg_11_02_10;
+               vr =  ram->next->bios.ramcfg_11_02_04;
+               vo =  ram->next->bios.ramcfg_11_06;
+               l3 = !ram->next->bios.ramcfg_11_07_02;
                break;
        default:
                return -ENOSYS;
        }
 
-       switch (!!ram->timing.data * ram->timing.version) {
+       switch (ram->timing.version) {
        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;
-               at = (nv_ro08(bios, ram->timing.data + 0x2e) & 0xc0) >> 6;
-               dt =  nv_ro08(bios, ram->timing.data + 0x2e) & 0x03;
-               ds =  nv_ro08(bios, ram->timing.data + 0x2f) & 0x03;
+               WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
+               CL = (ram->next->bios.timing[1] & 0x0000001f);
+               WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+               at[0] = ram->next->bios.timing_20_2e_c0;
+               at[1] = ram->next->bios.timing_20_2e_30;
+               dt =  ram->next->bios.timing_20_2e_03;
+               ds =  ram->next->bios.timing_20_2f_03;
                break;
        default:
                return -ENOSYS;
@@ -71,13 +80,25 @@ nouveau_gddr5_calc(struct nouveau_ram *ram)
 
        ram->mr[1] &= ~0x0bf;
        ram->mr[1] |= (xd & 0x01) << 7;
-       ram->mr[1] |= (at & 0x03) << 4;
+       ram->mr[1] |= (at[0] & 0x03) << 4;
        ram->mr[1] |= (dt & 0x03) << 2;
        ram->mr[1] |= (ds & 0x03) << 0;
 
+       /* this seems wrong, alternate field used for the broadcast
+        * on nuts vs non-nuts configs..  meh, it matches for now.
+        */
+       ram->mr1_nuts = ram->mr[1];
+       if (nuts) {
+               ram->mr[1] &= ~0x030;
+               ram->mr[1] |= (at[1] & 0x03) << 4;
+       }
+
        ram->mr[3] &= ~0x020;
        ram->mr[3] |= (rq & 0x01) << 5;
 
+       ram->mr[5] &= ~0x004;
+       ram->mr[5] |= (l3 << 2);
+
        if (!vo)
                vo = (ram->mr[6] & 0xff0) >> 4;
        if (ram->mr[6] & 0x001)
@@ -86,11 +107,16 @@ nouveau_gddr5_calc(struct nouveau_ram *ram)
        ram->mr[6] |= (vo & 0xff) << 4;
        ram->mr[6] |= (pd & 0x01) << 0;
 
-       if (!(ram->mr[7] & 0x100))
-               vr = 0; /* binary driver does this.. bug? */
-       ram->mr[7] &= ~0x188;
-       ram->mr[7] |= (vr & 0x01) << 8;
+       if (NOTE00(vr)) {
+               ram->mr[7] &= ~0x300;
+               ram->mr[7] |= (vr & 0x03) << 8;
+       }
+       ram->mr[7] &= ~0x088;
        ram->mr[7] |= (vh & 0x01) << 7;
        ram->mr[7] |= (lf & 0x01) << 3;
+
+       ram->mr[8] &= ~0x003;
+       ram->mr[8] |= (WR & 0x10) >> 3;
+       ram->mr[8] |= (CL & 0x10) >> 4;
        return 0;
 }
index e5fc37c4caac841977a99e4530059ebd6235b36f..45470e1f0385f4682a654e0c37cb27212d3ba8eb 100644 (file)
@@ -33,6 +33,21 @@ nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
        return likely((nvc0_pte_storage_type_map[memtype] != 0xff));
 }
 
+static void
+nvc0_fb_intr(struct nouveau_subdev *subdev)
+{
+       struct nvc0_fb_priv *priv = (void *)subdev;
+       u32 intr = nv_rd32(priv, 0x000100);
+       if (intr & 0x08000000) {
+               nv_debug(priv, "PFFB intr\n");
+               intr &= ~0x08000000;
+       }
+       if (intr & 0x00002000) {
+               nv_debug(priv, "PBFB intr\n");
+               intr &= ~0x00002000;
+       }
+}
+
 int
 nvc0_fb_init(struct nouveau_object *object)
 {
@@ -86,6 +101,7 @@ nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                        return -EFAULT;
        }
 
+       nv_subdev(priv)->intr = nvc0_fb_intr;
        return 0;
 }
 
index 493125214e88696db12ff1786f88be701e108225..edaf95dee61285d81d468060cd2b284b4da89cc0 100644 (file)
@@ -34,7 +34,7 @@ extern struct nouveau_oclass nvc0_ram_oclass;
 extern struct nouveau_oclass nve0_ram_oclass;
 
 int nouveau_sddr3_calc(struct nouveau_ram *ram);
-int nouveau_gddr5_calc(struct nouveau_ram *ram);
+int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
 
 #define nouveau_fb_create(p,e,c,d)                                             \
        nouveau_fb_create_((p), (e), (c), sizeof(**d), (void **)d)
index 76762a17d89cfe46a7b794e510fb83225c4aced7..c7fdb3a9e88b06cdcfa3151abf5ae7331c04e409 100644 (file)
@@ -70,13 +70,11 @@ nv50_ram_calc(struct nouveau_fb *pfb, u32 freq)
        struct nv50_ramseq *hwsq = &ram->hwsq;
        struct nvbios_perfE perfE;
        struct nvbios_pll mpll;
-       struct bit_entry M;
        struct {
                u32 data;
                u8  size;
        } ramcfg, timing;
-       u8  ver, hdr, cnt, strap;
-       u32 data;
+       u8  ver, hdr, cnt, len, strap;
        int N1, M1, N2, M2, P;
        int ret, i;
 
@@ -93,16 +91,7 @@ nv50_ram_calc(struct nouveau_fb *pfb, u32 freq)
        } while (perfE.memory < freq);
 
        /* locate specific data set for the attached memory */
-       if (bit_entry(bios, 'M', &M) || M.version != 1 || M.length < 5) {
-               nv_error(pfb, "invalid/missing memory table\n");
-               return -EINVAL;
-       }
-
-       strap = (nv_rd32(pfb, 0x101000) & 0x0000003c) >> 2;
-       data = nv_ro16(bios, M.offset + 3);
-       if (data)
-               strap = nv_ro08(bios, data + strap);
-
+       strap = nvbios_ramcfg_index(bios);
        if (strap >= cnt) {
                nv_error(pfb, "invalid ramcfg strap\n");
                return -EINVAL;
@@ -113,7 +102,8 @@ nv50_ram_calc(struct nouveau_fb *pfb, u32 freq)
        /* lookup memory timings, if bios says they're present */
        strap = nv_ro08(bios, ramcfg.data + 0x01);
        if (strap != 0xff) {
-               timing.data = nvbios_timing_entry(bios, strap, &ver, &hdr);
+               timing.data = nvbios_timingEe(bios, strap, &ver, &hdr,
+                                            &cnt, &len);
                if (!timing.data || ver != 0x10 || hdr < 0x12) {
                        nv_error(pfb, "invalid/missing timing entry "
                                 "%02x %04x %02x %02x\n",
index f6292cd9207cf354384738c50a135bea9e0ec562..f4ae8aa46a255948df24c3e4d2f4e259ed583d53 100644 (file)
@@ -79,8 +79,7 @@ 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;
-       struct bit_entry M;
-       u8  ver, cnt, strap;
+       u8  ver, cnt, len, strap;
        u32 data;
        struct {
                u32 data;
@@ -91,24 +90,15 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
        int ret;
 
        /* lookup memory config data relevant to the target frequency */
-       rammap.data = nvbios_rammap_match(bios, freq / 1000, &ver, &rammap.size,
-                                        &cnt, &ramcfg.size);
+       rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
+                                    &cnt, &ramcfg.size);
        if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
                nv_error(pfb, "invalid/missing rammap entry\n");
                return -EINVAL;
        }
 
        /* locate specific data set for the attached memory */
-       if (bit_entry(bios, 'M', &M) || M.version != 2 || M.length < 3) {
-               nv_error(pfb, "invalid/missing memory table\n");
-               return -EINVAL;
-       }
-
-       strap = (nv_rd32(pfb, 0x101000) & 0x0000003c) >> 2;
-       data = nv_ro16(bios, M.offset + 1);
-       if (data)
-               strap = nv_ro08(bios, data + strap);
-
+       strap = nvbios_ramcfg_index(bios);
        if (strap >= cnt) {
                nv_error(pfb, "invalid ramcfg strap\n");
                return -EINVAL;
@@ -123,8 +113,8 @@ nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
        /* lookup memory timings, if bios says they're present */
        strap = nv_ro08(bios, ramcfg.data + 0x01);
        if (strap != 0xff) {
-               timing.data = nvbios_timing_entry(bios, strap, &ver,
-                                                &timing.size);
+               timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
+                                            &cnt, &len);
                if (!timing.data || ver != 0x10 || timing.size < 0x19) {
                        nv_error(pfb, "invalid/missing timing entry\n");
                        return -EINVAL;
index f464547c6bab70c714626672bfbb015d7512d1a3..0391b824ee767d7629e333c56965366bc15347fd 100644 (file)
@@ -23,7 +23,6 @@
  */
 
 #include <subdev/bios.h>
-#include <subdev/bios/bit.h>
 #include <subdev/bios/pll.h>
 #include <subdev/bios/rammap.h>
 #include <subdev/bios/timing.h>
@@ -134,9 +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 bit_entry M;
-       u8  ver, cnt, strap;
-       u32 data;
+       u8  ver, cnt, len, strap;
        struct {
                u32 data;
                u8  size;
@@ -147,24 +144,15 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
        int ret;
 
        /* lookup memory config data relevant to the target frequency */
-       rammap.data = nvbios_rammap_match(bios, freq / 1000, &ver, &rammap.size,
-                                        &cnt, &ramcfg.size);
+       rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
+                                    &cnt, &ramcfg.size);
        if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
                nv_error(pfb, "invalid/missing rammap entry\n");
                return -EINVAL;
        }
 
        /* locate specific data set for the attached memory */
-       if (bit_entry(bios, 'M', &M) || M.version != 2 || M.length < 3) {
-               nv_error(pfb, "invalid/missing memory table\n");
-               return -EINVAL;
-       }
-
-       strap = (nv_rd32(pfb, 0x101000) & 0x0000003c) >> 2;
-       data = nv_ro16(bios, M.offset + 1);
-       if (data)
-               strap = nv_ro08(bios, data + strap);
-
+       strap = nvbios_ramcfg_index(bios);
        if (strap >= cnt) {
                nv_error(pfb, "invalid ramcfg strap\n");
                return -EINVAL;
@@ -179,8 +167,8 @@ nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
        /* lookup memory timings, if bios says they're present */
        strap = nv_ro08(bios, ramcfg.data + 0x01);
        if (strap != 0xff) {
-               timing.data = nvbios_timing_entry(bios, strap, &ver,
-                                                &timing.size);
+               timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
+                                            &cnt, &len);
                if (!timing.data || ver != 0x10 || timing.size < 0x19) {
                        nv_error(pfb, "invalid/missing timing entry\n");
                        return -EINVAL;
index bc86cfd084f66c106c4a46980212a59cdde47dad..3257c522a0219026e5147d37725b1f6a30fcac21 100644 (file)
@@ -25,7 +25,6 @@
 #include <subdev/gpio.h>
 
 #include <subdev/bios.h>
-#include <subdev/bios/bit.h>
 #include <subdev/bios/pll.h>
 #include <subdev/bios/init.h>
 #include <subdev/bios/rammap.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;
 
@@ -104,7 +111,9 @@ struct nve0_ramfuc {
        struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */
 
        struct ramfuc_reg r_0x62c000;
+
        struct ramfuc_reg r_0x10f200;
+
        struct ramfuc_reg r_0x10f210;
        struct ramfuc_reg r_0x10f310;
        struct ramfuc_reg r_0x10f314;
@@ -118,12 +127,17 @@ struct nve0_ramfuc {
        struct ramfuc_reg r_0x10f65c;
        struct ramfuc_reg r_0x10f6bc;
        struct ramfuc_reg r_0x100710;
-       struct ramfuc_reg r_0x10f750;
+       struct ramfuc_reg r_0x100750;
 };
 
 struct nve0_ram {
        struct nouveau_ram base;
        struct nve0_ramfuc fuc;
+
+       u32 parts;
+       u32 pmask;
+       u32 pnuts;
+
        int from;
        int mode;
        int N1, fN1, M1, P1;
@@ -134,17 +148,17 @@ struct nve0_ram {
  * GDDR5
  ******************************************************************************/
 static void
-train(struct nve0_ramfuc *fuc, u32 magic)
+nve0_ram_train(struct nve0_ramfuc *fuc, u32 mask, u32 data)
 {
        struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
-       struct nouveau_fb *pfb = nouveau_fb(ram);
-       const int mc = nv_rd32(pfb, 0x02243c);
-       int i;
-
-       ram_mask(fuc, 0x10f910, 0xbc0e0000, magic);
-       ram_mask(fuc, 0x10f914, 0xbc0e0000, magic);
-       for (i = 0; i < mc; i++) {
-               const u32 addr = 0x110974 + (i * 0x1000);
+       u32 addr = 0x110974, i;
+
+       ram_mask(fuc, 0x10f910, mask, data);
+       ram_mask(fuc, 0x10f914, mask, data);
+
+       for (i = 0; (data & 0x80000000) && i < ram->parts; addr += 0x1000, i++) {
+               if (ram->pmask & (1 << i))
+                       continue;
                ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
        }
 }
@@ -199,12 +213,12 @@ r1373f4_init(struct nve0_ramfuc *fuc)
 }
 
 static void
-r1373f4_fini(struct nve0_ramfuc *fuc, u32 ramcfg)
+r1373f4_fini(struct nve0_ramfuc *fuc)
 {
        struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
-       struct nouveau_bios *bios = nouveau_bios(ram);
-       u8 v0 = (nv_ro08(bios, ramcfg + 0x03) & 0xc0) >> 6;
-       u8 v1 = (nv_ro08(bios, ramcfg + 0x03) & 0x30) >> 4;
+       struct nouveau_ram_data *next = ram->base.next;
+       u8 v0 = next->bios.ramcfg_11_03_c0;
+       u8 v1 = next->bios.ramcfg_11_03_30;
        u32 tmp;
 
        tmp = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
@@ -220,25 +234,46 @@ r1373f4_fini(struct nve0_ramfuc *fuc, u32 ramcfg)
        ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4);
 }
 
+static void
+nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg,
+             u32 _mask, u32 _data, u32 _copy)
+{
+       struct nve0_fb_priv *priv = (void *)nouveau_fb(ram);
+       struct ramfuc *fuc = &ram->fuc.base;
+       u32 addr = 0x110000 + (reg->addr[0] & 0xfff);
+       u32 mask = _mask | _copy;
+       u32 data = (_data & _mask) | (reg->data & _copy);
+       u32 i;
+
+       for (i = 0; i < 16; i++, addr += 0x1000) {
+               if (ram->pnuts & (1 << i)) {
+                       u32 prev = nv_rd32(priv, addr);
+                       u32 next = (prev & ~mask) | data;
+                       nouveau_memx_wr32(fuc->memx, addr, next);
+               }
+       }
+}
+#define ram_nuts(s,r,m,d,c)                                                    \
+       nve0_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c))
+
 static int
 nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
 {
-       struct nouveau_bios *bios = nouveau_bios(pfb);
        struct nve0_ram *ram = (void *)pfb->ram;
        struct nve0_ramfuc *fuc = &ram->fuc;
-       const u32 rammap = ram->base.rammap.data;
-       const u32 ramcfg = ram->base.ramcfg.data;
-       const u32 timing = ram->base.timing.data;
-       int vc = !(nv_ro08(bios, ramcfg + 0x02) & 0x08);
-       int mv = 1; /*XXX*/
+       struct nouveau_ram_data *next = ram->base.next;
+       int vc = !(next->bios.ramcfg_11_02_08);
+       int mv = !(next->bios.ramcfg_11_02_04);
        u32 mask, data;
 
        ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
        ram_wr32(fuc, 0x62c000, 0x0f0f0000);
 
        /* MR1: turn termination on early, for some reason.. */
-       if ((ram->base.mr[1] & 0x03c) != 0x030)
+       if ((ram->base.mr[1] & 0x03c) != 0x030) {
                ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c);
+               ram_nuts(ram, mr[1], 0x03c, ram->base.mr1_nuts & 0x03c, 0x000);
+       }
 
        if (vc == 1 && ram_have(fuc, gpio2E)) {
                u32 temp  = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
@@ -250,8 +285,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
 
        ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
 
-       ram_mask(fuc, 0x10f914, 0x01020000, 0x000c0000);
-       ram_mask(fuc, 0x10f910, 0x01020000, 0x000c0000);
+       nve0_ram_train(fuc, 0x01020000, 0x000c0000);
 
        ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
        ram_nsec(fuc, 1000);
@@ -280,28 +314,28 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
 
        if (1) {
                data |= 0x800807e0;
-               switch (nv_ro08(bios, ramcfg + 0x03) & 0xc0) {
-               case 0xc0: data &= ~0x00000040; break;
-               case 0x80: data &= ~0x00000100; break;
-               case 0x40: data &= ~0x80000000; break;
-               case 0x00: data &= ~0x00000400; break;
+               switch (next->bios.ramcfg_11_03_c0) {
+               case 3: data &= ~0x00000040; break;
+               case 2: data &= ~0x00000100; break;
+               case 1: data &= ~0x80000000; break;
+               case 0: data &= ~0x00000400; break;
                }
 
-               switch (nv_ro08(bios, ramcfg + 0x03) & 0x30) {
-               case 0x30: data &= ~0x00000020; break;
-               case 0x20: data &= ~0x00000080; break;
-               case 0x10: data &= ~0x00080000; break;
-               case 0x00: data &= ~0x00000200; break;
+               switch (next->bios.ramcfg_11_03_30) {
+               case 3: data &= ~0x00000020; break;
+               case 2: data &= ~0x00000080; break;
+               case 1: data &= ~0x00080000; break;
+               case 0: data &= ~0x00000200; break;
                }
        }
 
-       if (nv_ro08(bios, ramcfg + 0x02) & 0x80)
+       if (next->bios.ramcfg_11_02_80)
                mask |= 0x03000000;
-       if (nv_ro08(bios, ramcfg + 0x02) & 0x40)
+       if (next->bios.ramcfg_11_02_40)
                mask |= 0x00002000;
-       if (nv_ro08(bios, ramcfg + 0x07) & 0x10)
+       if (next->bios.ramcfg_11_07_10)
                mask |= 0x00004000;
-       if (nv_ro08(bios, ramcfg + 0x07) & 0x08)
+       if (next->bios.ramcfg_11_07_08)
                mask |= 0x00000003;
        else {
                mask |= 0x34000000;
@@ -314,18 +348,18 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
 
        if (ram->from == 2 && ram->mode != 2) {
                ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
-               ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000);
+               ram_mask(fuc, 0x10f200, 0x18008000, 0x00008000);
                ram_mask(fuc, 0x10f800, 0x00000000, 0x00000004);
                ram_mask(fuc, 0x10f830, 0x00008000, 0x01040010);
                ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
                r1373f4_init(fuc);
                ram_mask(fuc, 0x1373f0, 0x00000002, 0x00000001);
-               r1373f4_fini(fuc, ramcfg);
+               r1373f4_fini(fuc);
                ram_mask(fuc, 0x10f830, 0x00c00000, 0x00240001);
        } else
        if (ram->from != 2 && ram->mode != 2) {
                r1373f4_init(fuc);
-               r1373f4_fini(fuc, ramcfg);
+               r1373f4_fini(fuc);
        }
 
        if (ram_have(fuc, gpioMV)) {
@@ -336,49 +370,54 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
                }
        }
 
-       if ( (nv_ro08(bios, ramcfg + 0x02) & 0x40) ||
-            (nv_ro08(bios, ramcfg + 0x07) & 0x10)) {
+       if ( (next->bios.ramcfg_11_02_40) ||
+            (next->bios.ramcfg_11_07_10)) {
                ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
                ram_nsec(fuc, 20000);
        }
 
        if (ram->from != 2 && ram->mode == 2) {
+               if (0 /*XXX: Titan */)
+                       ram_mask(fuc, 0x10f200, 0x18000000, 0x18000000);
                ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
                ram_mask(fuc, 0x1373f0, 0x00000000, 0x00000002);
                ram_mask(fuc, 0x10f830, 0x00800001, 0x00408010);
                r1373f4_init(fuc);
-               r1373f4_fini(fuc, ramcfg);
+               r1373f4_fini(fuc);
                ram_mask(fuc, 0x10f808, 0x00000000, 0x00080000);
                ram_mask(fuc, 0x10f200, 0x00808000, 0x00800000);
        } else
        if (ram->from == 2 && ram->mode == 2) {
                ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
                r1373f4_init(fuc);
-               r1373f4_fini(fuc, ramcfg);
+               r1373f4_fini(fuc);
        }
 
        if (ram->mode != 2) /*XXX*/ {
-               if (nv_ro08(bios, ramcfg + 0x07) & 0x40)
+               if (next->bios.ramcfg_11_07_40)
                        ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
        }
 
-       data = (nv_ro08(bios, rammap + 0x11) & 0x0c) >> 2;
-       ram_wr32(fuc, 0x10f65c, 0x00000011 * data);
-       ram_wr32(fuc, 0x10f6b8, 0x01010101 * nv_ro08(bios, ramcfg + 0x09));
-       ram_wr32(fuc, 0x10f6bc, 0x01010101 * nv_ro08(bios, ramcfg + 0x09));
+       ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
+       ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
+       ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
 
-       data = nv_ro08(bios, ramcfg + 0x04);
-       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08)) {
-               ram_wr32(fuc, 0x10f698, 0x01010101 * data);
-               ram_wr32(fuc, 0x10f69c, 0x01010101 * data);
+       if (!next->bios.ramcfg_11_07_08 && !next->bios.ramcfg_11_07_04) {
+               ram_wr32(fuc, 0x10f698, 0x01010101 * next->bios.ramcfg_11_04);
+               ram_wr32(fuc, 0x10f69c, 0x01010101 * next->bios.ramcfg_11_04);
+       } else
+       if (!next->bios.ramcfg_11_07_08) {
+               ram_wr32(fuc, 0x10f698, 0x00000000);
+               ram_wr32(fuc, 0x10f69c, 0x00000000);
        }
 
        if (ram->mode != 2) {
-               u32 temp = ram_rd32(fuc, 0x10f694) & ~0xff00ff00;
-               ram_wr32(fuc, 0x10f694, temp | (0x01000100 * data));
+               u32 data = 0x01000100 * next->bios.ramcfg_11_04;
+               ram_nuke(fuc, 0x10f694);
+               ram_mask(fuc, 0x10f694, 0xff00ff00, data);
        }
 
-       if (ram->mode == 2 && (nv_ro08(bios, ramcfg + 0x08) & 0x10))
+       if (ram->mode == 2 && (next->bios.ramcfg_11_08_10))
                data = 0x00000080;
        else
                data = 0x00000000;
@@ -386,19 +425,19 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
 
        mask = 0x00070000;
        data = 0x00000000;
-       if (!(nv_ro08(bios, ramcfg + 0x02) & 0x80))
+       if (!(next->bios.ramcfg_11_02_80))
                data |= 0x03000000;
-       if (!(nv_ro08(bios, ramcfg + 0x02) & 0x40))
+       if (!(next->bios.ramcfg_11_02_40))
                data |= 0x00002000;
-       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x10))
+       if (!(next->bios.ramcfg_11_07_10))
                data |= 0x00004000;
-       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08))
+       if (!(next->bios.ramcfg_11_07_08))
                data |= 0x00000003;
        else
                data |= 0x74000000;
        ram_mask(fuc, 0x10f824, mask, data);
 
-       if (nv_ro08(bios, ramcfg + 0x01) & 0x08)
+       if (next->bios.ramcfg_11_01_08)
                data = 0x00000000;
        else
                data = 0x00001000;
@@ -409,61 +448,90 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
                ram_mask(fuc, 0x10f670, 0x80000000, 0x00000000);
        }
 
-       if (nv_ro08(bios, ramcfg + 0x08) & 0x01)
+       if (next->bios.ramcfg_11_08_01)
                data = 0x00100000;
        else
                data = 0x00000000;
        ram_mask(fuc, 0x10f82c, 0x00100000, data);
 
        data = 0x00000000;
-       if (nv_ro08(bios, ramcfg + 0x08) & 0x08)
+       if (next->bios.ramcfg_11_08_08)
                data |= 0x00002000;
-       if (nv_ro08(bios, ramcfg + 0x08) & 0x04)
+       if (next->bios.ramcfg_11_08_04)
                data |= 0x00001000;
-       if (nv_ro08(bios, ramcfg + 0x08) & 0x02)
+       if (next->bios.ramcfg_11_08_02)
                data |= 0x00004000;
        ram_mask(fuc, 0x10f830, 0x00007000, data);
 
        /* PFB timing */
-       ram_mask(fuc, 0x10f248, 0xffffffff, nv_ro32(bios, timing + 0x28));
-       ram_mask(fuc, 0x10f290, 0xffffffff, nv_ro32(bios, timing + 0x00));
-       ram_mask(fuc, 0x10f294, 0xffffffff, nv_ro32(bios, timing + 0x04));
-       ram_mask(fuc, 0x10f298, 0xffffffff, nv_ro32(bios, timing + 0x08));
-       ram_mask(fuc, 0x10f29c, 0xffffffff, nv_ro32(bios, timing + 0x0c));
-       ram_mask(fuc, 0x10f2a0, 0xffffffff, nv_ro32(bios, timing + 0x10));
-       ram_mask(fuc, 0x10f2a4, 0xffffffff, nv_ro32(bios, timing + 0x14));
-       ram_mask(fuc, 0x10f2a8, 0xffffffff, nv_ro32(bios, timing + 0x18));
-       ram_mask(fuc, 0x10f2ac, 0xffffffff, nv_ro32(bios, timing + 0x1c));
-       ram_mask(fuc, 0x10f2cc, 0xffffffff, nv_ro32(bios, timing + 0x20));
-       ram_mask(fuc, 0x10f2e8, 0xffffffff, nv_ro32(bios, timing + 0x24));
-
-       data = (nv_ro08(bios, ramcfg + 0x02) & 0x03) << 8;
-       if (nv_ro08(bios, ramcfg + 0x01) & 0x10)
-               data |= 0x70000000;
-       ram_mask(fuc, 0x10f604, 0x70000300, data);
-
-       data = (nv_ro08(bios, timing + 0x30) & 0x07) << 28;
-       if (nv_ro08(bios, ramcfg + 0x01) & 0x01)
-               data |= 0x00000100;
-       ram_mask(fuc, 0x10f614, 0x70000000, data);
-
-       data = (nv_ro08(bios, timing + 0x30) & 0x07) << 28;
-       if (nv_ro08(bios, ramcfg + 0x01) & 0x02)
-               data |= 0x00000100;
-       ram_mask(fuc, 0x10f610, 0x70000000, data);
+       ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
+       ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
+       ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
+       ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
+       ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
+       ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
+       ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
+       ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
+       ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
+       ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
+       ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
+
+       data = mask = 0x00000000;
+       if (NOTE00(ramcfg_08_20)) {
+               if (next->bios.ramcfg_11_08_20)
+                       data |= 0x01000000;
+               mask |= 0x01000000;
+       }
+       ram_mask(fuc, 0x10f200, mask, data);
+
+       data = mask = 0x00000000;
+       if (NOTE00(ramcfg_02_03 != 0)) {
+               data |= (next->bios.ramcfg_11_02_03) << 8;
+               mask |= 0x00000300;
+       }
+       if (NOTE00(ramcfg_01_10)) {
+               if (next->bios.ramcfg_11_01_10)
+                       data |= 0x70000000;
+               mask |= 0x70000000;
+       }
+       ram_mask(fuc, 0x10f604, mask, data);
+
+       data = mask = 0x00000000;
+       if (NOTE00(timing_30_07 != 0)) {
+               data |= (next->bios.timing_20_30_07) << 28;
+               mask |= 0x70000000;
+       }
+       if (NOTE00(ramcfg_01_01)) {
+               if (next->bios.ramcfg_11_01_01)
+                       data |= 0x00000100;
+               mask |= 0x00000100;
+       }
+       ram_mask(fuc, 0x10f614, mask, data);
+
+       data = mask = 0x00000000;
+       if (NOTE00(timing_30_07 != 0)) {
+               data |= (next->bios.timing_20_30_07) << 28;
+               mask |= 0x70000000;
+       }
+       if (NOTE00(ramcfg_01_02)) {
+               if (next->bios.ramcfg_11_01_02)
+                       data |= 0x00000100;
+               mask |= 0x00000100;
+       }
+       ram_mask(fuc, 0x10f610, mask, data);
 
        mask = 0x33f00000;
        data = 0x00000000;
-       if (!(nv_ro08(bios, ramcfg + 0x01) & 0x04))
+       if (!(next->bios.ramcfg_11_01_04))
                data |= 0x20200000;
-       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x80))
+       if (!(next->bios.ramcfg_11_07_80))
                data |= 0x12800000;
        /*XXX: see note above about there probably being some condition
         *     for the 10f824 stuff that uses ramcfg 3...
         */
-       if ( (nv_ro08(bios, ramcfg + 0x03) & 0xf0)) {
-               if (nv_ro08(bios, rammap + 0x08) & 0x0c) {
-                       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x80))
+       if ( (next->bios.ramcfg_11_03_f0)) {
+               if (next->bios.rammap_11_08_0c) {
+                       if (!(next->bios.ramcfg_11_07_80))
                                mask |= 0x00000020;
                        else
                                data |= 0x00000020;
@@ -476,49 +544,53 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
 
        ram_mask(fuc, 0x10f808, mask, data);
 
-       data = nv_ro08(bios, ramcfg + 0x03) & 0x0f;
-       ram_wr32(fuc, 0x10f870, 0x11111111 * data);
+       ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
 
-       data = nv_ro08(bios, ramcfg + 0x02) & 0x03;
-       if (nv_ro08(bios, ramcfg + 0x01) & 0x10)
-               data |= 0x00000004;
-       if ((nv_rd32(bios, 0x100770) & 0x00000004) != (data & 0x00000004)) {
-               ram_wr32(fuc, 0x10f750, 0x04000009);
+       data = mask = 0x00000000;
+       if (NOTE00(ramcfg_02_03 != 0)) {
+               data |= next->bios.ramcfg_11_02_03;
+               mask |= 0x00000003;
+       }
+       if (NOTE00(ramcfg_01_10)) {
+               if (next->bios.ramcfg_11_01_10)
+                       data |= 0x00000004;
+               mask |= 0x00000004;
+       }
+
+       if ((ram_mask(fuc, 0x100770, mask, data) & mask & 4) != (data & 4)) {
+               ram_mask(fuc, 0x100750, 0x00000008, 0x00000008);
                ram_wr32(fuc, 0x100710, 0x00000000);
                ram_wait(fuc, 0x100710, 0x80000000, 0x80000000, 200000);
        }
-       ram_mask(fuc, 0x100770, 0x00000007, data);
 
-       data = (nv_ro08(bios, timing + 0x30) & 0x07) << 8;
-       if (nv_ro08(bios, ramcfg + 0x01) & 0x01)
+       data = (next->bios.timing_20_30_07) << 8;
+       if (next->bios.ramcfg_11_01_01)
                data |= 0x80000000;
        ram_mask(fuc, 0x100778, 0x00000700, data);
 
-       data = nv_ro16(bios, timing + 0x2c);
-       ram_mask(fuc, 0x10f250, 0x000003f0, (data & 0x003f) <<  4);
-       ram_mask(fuc, 0x10f24c, 0x7f000000, (data & 0x1fc0) << 18);
-
-       data = nv_ro08(bios, timing + 0x30);
-       ram_mask(fuc, 0x10f224, 0x001f0000, (data & 0xf8) << 13);
+       ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
+       data = (next->bios.timing[10] & 0x7f000000) >> 24;
+       if (data < next->bios.timing_20_2c_1fc0)
+               data = next->bios.timing_20_2c_1fc0;
+       ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
+       ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16);
 
-       data = nv_ro16(bios, timing + 0x31);
-       ram_mask(fuc, 0x10fec4, 0x041e0f07, (data & 0x0800) << 15 |
-                                           (data & 0x0780) << 10 |
-                                           (data & 0x0078) <<  5 |
-                                           (data & 0x0007));
-       ram_mask(fuc, 0x10fec8, 0x00000027, (data & 0x8000) >> 10 |
-                                           (data & 0x7000) >> 12);
+       ram_mask(fuc, 0x10fec4, 0x041e0f07, next->bios.timing_20_31_0800 << 26 |
+                                           next->bios.timing_20_31_0780 << 17 |
+                                           next->bios.timing_20_31_0078 << 8 |
+                                           next->bios.timing_20_31_0007);
+       ram_mask(fuc, 0x10fec8, 0x00000027, next->bios.timing_20_31_8000 << 5 |
+                                           next->bios.timing_20_31_7000);
 
        ram_wr32(fuc, 0x10f090, 0x4000007e);
-       ram_nsec(fuc, 1000);
+       ram_nsec(fuc, 2000);
        ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
        ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
-       ram_nsec(fuc, 2000);
        ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
 
-       if ((nv_ro08(bios, ramcfg + 0x08) & 0x10) && (ram->mode == 2) /*XXX*/) {
+       if ((next->bios.ramcfg_11_08_10) && (ram->mode == 2) /*XXX*/) {
                u32 temp = ram_mask(fuc, 0x10f294, 0xff000000, 0x24000000);
-               train(fuc, 0xa4010000); /*XXX*/
+               nve0_ram_train(fuc, 0xbc0e0000, 0xa4010000); /*XXX*/
                ram_nsec(fuc, 1000);
                ram_wr32(fuc, 0x10f294, temp);
        }
@@ -528,7 +600,7 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        ram_mask(fuc, mr[8], 0xfff, ram->base.mr[8]);
        ram_nsec(fuc, 1000);
        ram_mask(fuc, mr[1], 0xfff, ram->base.mr[1]);
-       ram_mask(fuc, mr[5], 0xfff, ram->base.mr[5]);
+       ram_mask(fuc, mr[5], 0xfff, ram->base.mr[5] & ~0x004); /* LP3 later */
        ram_mask(fuc, mr[6], 0xfff, ram->base.mr[6]);
        ram_mask(fuc, mr[7], 0xfff, ram->base.mr[7]);
 
@@ -544,12 +616,13 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
        ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
        ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
        ram_nsec(fuc, 1000);
+       ram_nuts(ram, 0x10f200, 0x18808800, 0x00000000, 0x18808800);
 
        data  = ram_rd32(fuc, 0x10f978);
        data &= ~0x00046144;
        data |=  0x0000000b;
-       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08)) {
-               if (!(nv_ro08(bios, ramcfg + 0x07) & 0x04))
+       if (!(next->bios.ramcfg_11_07_08)) {
+               if (!(next->bios.ramcfg_11_07_04))
                        data |= 0x0000200c;
                else
                        data |= 0x00000000;
@@ -563,44 +636,43 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
                ram_wr32(fuc, 0x10f830, data);
        }
 
-       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08)) {
+       if (!(next->bios.ramcfg_11_07_08)) {
                data = 0x88020000;
-               if ( (nv_ro08(bios, ramcfg + 0x07) & 0x04))
+               if ( (next->bios.ramcfg_11_07_04))
                        data |= 0x10000000;
-               if (!(nv_ro08(bios, rammap + 0x08) & 0x10))
+               if (!(next->bios.rammap_11_08_10))
                        data |= 0x00080000;
        } else {
                data = 0xa40e0000;
        }
-       train(fuc, data);
-       ram_nsec(fuc, 1000);
+       nve0_ram_train(fuc, 0xbc0f0000, data);
+       if (1) /* XXX: not always? */
+               ram_nsec(fuc, 1000);
 
        if (ram->mode == 2) { /*XXX*/
                ram_mask(fuc, 0x10f800, 0x00000004, 0x00000004);
        }
 
-       /* MR5: (re)enable LP3 if necessary
-        * XXX: need to find the switch, keeping off for now
-        */
-       ram_mask(fuc, mr[5], 0x00000004, 0x00000000);
+       /* LP3 */
+       if (ram_mask(fuc, mr[5], 0x004, ram->base.mr[5]) != ram->base.mr[5])
+               ram_nsec(fuc, 1000);
 
        if (ram->mode != 2) {
                ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
                ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
        }
 
-       if (nv_ro08(bios, ramcfg + 0x07) & 0x02) {
-               ram_mask(fuc, 0x10f910, 0x80020000, 0x01000000);
-               ram_mask(fuc, 0x10f914, 0x80020000, 0x01000000);
-       }
+       if (next->bios.ramcfg_11_07_02)
+               nve0_ram_train(fuc, 0x80020000, 0x01000000);
 
        ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
 
-       if (nv_ro08(bios, rammap + 0x08) & 0x01)
+       if (next->bios.rammap_11_08_01)
                data = 0x00000800;
        else
                data = 0x00000000;
        ram_mask(fuc, 0x10f200, 0x00000800, data);
+       ram_nuts(ram, 0x10f200, 0x18808800, data, 0x18808800);
        return 0;
 }
 
@@ -611,17 +683,14 @@ nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
 static int
 nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
 {
-       struct nouveau_bios *bios = nouveau_bios(pfb);
        struct nve0_ram *ram = (void *)pfb->ram;
        struct nve0_ramfuc *fuc = &ram->fuc;
        const u32 rcoef = ((  ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
        const u32 runk0 = ram->fN1 << 16;
        const u32 runk1 = ram->fN1;
-       const u32 rammap = ram->base.rammap.data;
-       const u32 ramcfg = ram->base.ramcfg.data;
-       const u32 timing = ram->base.timing.data;
-       int vc = !(nv_ro08(bios, ramcfg + 0x02) & 0x08);
-       int mv = 1; /*XXX*/
+       struct nouveau_ram_data *next = ram->base.next;
+       int vc = !(next->bios.ramcfg_11_02_08);
+       int mv = !(next->bios.ramcfg_11_02_04);
        u32 mask, data;
 
        ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
@@ -636,7 +705,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
        }
 
        ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
-       if ((nv_ro08(bios, ramcfg + 0x03) & 0xf0))
+       if ((next->bios.ramcfg_11_03_f0))
                ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000);
 
        ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
@@ -661,28 +730,28 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
        if (1) {
                mask |= 0x800807e0;
                data |= 0x800807e0;
-               switch (nv_ro08(bios, ramcfg + 0x03) & 0xc0) {
-               case 0xc0: data &= ~0x00000040; break;
-               case 0x80: data &= ~0x00000100; break;
-               case 0x40: data &= ~0x80000000; break;
-               case 0x00: data &= ~0x00000400; break;
+               switch (next->bios.ramcfg_11_03_c0) {
+               case 3: data &= ~0x00000040; break;
+               case 2: data &= ~0x00000100; break;
+               case 1: data &= ~0x80000000; break;
+               case 0: data &= ~0x00000400; break;
                }
 
-               switch (nv_ro08(bios, ramcfg + 0x03) & 0x30) {
-               case 0x30: data &= ~0x00000020; break;
-               case 0x20: data &= ~0x00000080; break;
-               case 0x10: data &= ~0x00080000; break;
-               case 0x00: data &= ~0x00000200; break;
+               switch (next->bios.ramcfg_11_03_30) {
+               case 3: data &= ~0x00000020; break;
+               case 2: data &= ~0x00000080; break;
+               case 1: data &= ~0x00080000; break;
+               case 0: data &= ~0x00000200; break;
                }
        }
 
-       if (nv_ro08(bios, ramcfg + 0x02) & 0x80)
+       if (next->bios.ramcfg_11_02_80)
                mask |= 0x03000000;
-       if (nv_ro08(bios, ramcfg + 0x02) & 0x40)
+       if (next->bios.ramcfg_11_02_40)
                mask |= 0x00002000;
-       if (nv_ro08(bios, ramcfg + 0x07) & 0x10)
+       if (next->bios.ramcfg_11_07_10)
                mask |= 0x00004000;
-       if (nv_ro08(bios, ramcfg + 0x07) & 0x08)
+       if (next->bios.ramcfg_11_07_08)
                mask |= 0x00000003;
        else
                mask |= 0x14000000;
@@ -692,7 +761,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
 
        ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
        data  = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
-       data |= (nv_ro08(bios, ramcfg + 0x03) & 0x30) << 12;
+       data |= (next->bios.ramcfg_11_03_30) << 12;
        ram_wr32(fuc, 0x1373ec, data);
        ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
        ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
@@ -724,68 +793,67 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
                }
        }
 
-       if ( (nv_ro08(bios, ramcfg + 0x02) & 0x40) ||
-            (nv_ro08(bios, ramcfg + 0x07) & 0x10)) {
+       if ( (next->bios.ramcfg_11_02_40) ||
+            (next->bios.ramcfg_11_07_10)) {
                ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
                ram_nsec(fuc, 20000);
        }
 
        if (ram->mode != 2) /*XXX*/ {
-               if (nv_ro08(bios, ramcfg + 0x07) & 0x40)
+               if (next->bios.ramcfg_11_07_40)
                        ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
        }
 
-       data = (nv_ro08(bios, rammap + 0x11) & 0x0c) >> 2;
-       ram_wr32(fuc, 0x10f65c, 0x00000011 * data);
-       ram_wr32(fuc, 0x10f6b8, 0x01010101 * nv_ro08(bios, ramcfg + 0x09));
-       ram_wr32(fuc, 0x10f6bc, 0x01010101 * nv_ro08(bios, ramcfg + 0x09));
+       ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
+       ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
+       ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
 
        mask = 0x00010000;
        data = 0x00000000;
-       if (!(nv_ro08(bios, ramcfg + 0x02) & 0x80))
+       if (!(next->bios.ramcfg_11_02_80))
                data |= 0x03000000;
-       if (!(nv_ro08(bios, ramcfg + 0x02) & 0x40))
+       if (!(next->bios.ramcfg_11_02_40))
                data |= 0x00002000;
-       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x10))
+       if (!(next->bios.ramcfg_11_07_10))
                data |= 0x00004000;
-       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x08))
+       if (!(next->bios.ramcfg_11_07_08))
                data |= 0x00000003;
        else
                data |= 0x14000000;
        ram_mask(fuc, 0x10f824, mask, data);
        ram_nsec(fuc, 1000);
 
-       if (nv_ro08(bios, ramcfg + 0x08) & 0x01)
+       if (next->bios.ramcfg_11_08_01)
                data = 0x00100000;
        else
                data = 0x00000000;
        ram_mask(fuc, 0x10f82c, 0x00100000, data);
 
        /* PFB timing */
-       ram_mask(fuc, 0x10f248, 0xffffffff, nv_ro32(bios, timing + 0x28));
-       ram_mask(fuc, 0x10f290, 0xffffffff, nv_ro32(bios, timing + 0x00));
-       ram_mask(fuc, 0x10f294, 0xffffffff, nv_ro32(bios, timing + 0x04));
-       ram_mask(fuc, 0x10f298, 0xffffffff, nv_ro32(bios, timing + 0x08));
-       ram_mask(fuc, 0x10f29c, 0xffffffff, nv_ro32(bios, timing + 0x0c));
-       ram_mask(fuc, 0x10f2a0, 0xffffffff, nv_ro32(bios, timing + 0x10));
-       ram_mask(fuc, 0x10f2a4, 0xffffffff, nv_ro32(bios, timing + 0x14));
-       ram_mask(fuc, 0x10f2a8, 0xffffffff, nv_ro32(bios, timing + 0x18));
-       ram_mask(fuc, 0x10f2ac, 0xffffffff, nv_ro32(bios, timing + 0x1c));
-       ram_mask(fuc, 0x10f2cc, 0xffffffff, nv_ro32(bios, timing + 0x20));
-       ram_mask(fuc, 0x10f2e8, 0xffffffff, nv_ro32(bios, timing + 0x24));
+       ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
+       ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
+       ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
+       ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
+       ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
+       ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
+       ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
+       ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
+       ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
+       ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
+       ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
 
        mask = 0x33f00000;
        data = 0x00000000;
-       if (!(nv_ro08(bios, ramcfg + 0x01) & 0x04))
+       if (!(next->bios.ramcfg_11_01_04))
                data |= 0x20200000;
-       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x80))
+       if (!(next->bios.ramcfg_11_07_80))
                data |= 0x12800000;
        /*XXX: see note above about there probably being some condition
         *     for the 10f824 stuff that uses ramcfg 3...
         */
-       if ( (nv_ro08(bios, ramcfg + 0x03) & 0xf0)) {
-               if (nv_ro08(bios, rammap + 0x08) & 0x0c) {
-                       if (!(nv_ro08(bios, ramcfg + 0x07) & 0x80))
+       if ( (next->bios.ramcfg_11_03_f0)) {
+               if (next->bios.rammap_11_08_0c) {
+                       if (!(next->bios.ramcfg_11_07_80))
                                mask |= 0x00000020;
                        else
                                data |= 0x00000020;
@@ -799,21 +867,16 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
 
        ram_mask(fuc, 0x10f808, mask, data);
 
-       data = nv_ro08(bios, ramcfg + 0x03) & 0x0f;
-       ram_wr32(fuc, 0x10f870, 0x11111111 * data);
+       ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
 
-       data = nv_ro16(bios, timing + 0x2c);
-       ram_mask(fuc, 0x10f250, 0x000003f0, (data & 0x003f) <<  4);
+       ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
 
-       if (((nv_ro32(bios, timing + 0x2c) & 0x00001fc0) >>  6) >
-           ((nv_ro32(bios, timing + 0x28) & 0x7f000000) >> 24))
-               data = (nv_ro32(bios, timing + 0x2c) & 0x00001fc0) >>  6;
-       else
-               data = (nv_ro32(bios, timing + 0x28) & 0x1f000000) >> 24;
+       data = (next->bios.timing[10] & 0x7f000000) >> 24;
+       if (data < next->bios.timing_20_2c_1fc0)
+               data = next->bios.timing_20_2c_1fc0;
        ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
 
-       data = nv_ro08(bios, timing + 0x30);
-       ram_mask(fuc, 0x10f224, 0x001f0000, (data & 0xf8) << 13);
+       ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8);
 
        ram_wr32(fuc, 0x10f090, 0x4000007f);
        ram_nsec(fuc, 1000);
@@ -855,7 +918,7 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
 
        ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
 
-       if (nv_ro08(bios, rammap + 0x08) & 0x01)
+       if (next->bios.rammap_11_08_01)
                data = 0x00000800;
        else
                data = 0x00000000;
@@ -868,21 +931,18 @@ nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
  ******************************************************************************/
 
 static int
-nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
+nve0_ram_calc_data(struct nouveau_fb *pfb, u32 freq,
+                  struct nouveau_ram_data *data)
 {
        struct nouveau_bios *bios = nouveau_bios(pfb);
        struct nve0_ram *ram = (void *)pfb->ram;
-       struct nve0_ramfuc *fuc = &ram->fuc;
-       struct bit_entry M;
-       int ret, refclk, strap, i;
-       u32 data;
-       u8  cnt;
+       u8 strap, cnt, len;
 
        /* lookup memory config data relevant to the target frequency */
-       ram->base.rammap.data = nvbios_rammap_match(bios, freq / 1000,
-                                                  &ram->base.rammap.version,
-                                                  &ram->base.rammap.size, &cnt,
-                                                  &ram->base.ramcfg.size);
+       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");
@@ -890,24 +950,13 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
        }
 
        /* locate specific data set for the attached memory */
-       if (bit_entry(bios, 'M', &M) || M.version != 2 || M.length < 3) {
-               nv_error(pfb, "invalid/missing memory table\n");
-               return -EINVAL;
-       }
-
-       strap = (nv_rd32(pfb, 0x101000) & 0x0000003c) >> 2;
-       data = nv_ro16(bios, M.offset + 1);
-       if (data)
-               strap = nv_ro08(bios, data + strap);
-
-       if (strap >= cnt) {
-               nv_error(pfb, "invalid ramcfg strap\n");
-               return -EINVAL;
-       }
-
-       ram->base.ramcfg.version = ram->base.rammap.version;
-       ram->base.ramcfg.data = ram->base.rammap.data + ram->base.rammap.size +
-                              (ram->base.ramcfg.size * strap);
+       ram->base.ramcfg.data = nvbios_rammapSp(bios, ram->base.rammap.data,
+                                               ram->base.rammap.version,
+                                               ram->base.rammap.size, cnt, len,
+                                               nvbios_ramcfg_index(bios),
+                                               &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");
@@ -918,9 +967,9 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
        strap = nv_ro08(bios, ram->base.ramcfg.data + 0x00);
        if (strap != 0xff) {
                ram->base.timing.data =
-                       nvbios_timing_entry(bios, strap,
-                                          &ram->base.timing.version,
-                                          &ram->base.timing.size);
+                       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) {
@@ -931,11 +980,23 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
                ram->base.timing.data = 0;
        }
 
+       data->freq = freq;
+       return 0;
+}
+
+static int
+nve0_ram_calc_xits(struct nouveau_fb *pfb, struct nouveau_ram_data *next)
+{
+       struct nve0_ram *ram = (void *)pfb->ram;
+       struct nve0_ramfuc *fuc = &ram->fuc;
+       int refclk, i;
+       int ret;
+
        ret = ram_init(fuc, pfb);
        if (ret)
                return ret;
 
-       ram->mode = (freq > fuc->refpll.vco1.max_freq) ? 2 : 1;
+       ram->mode = (next->freq > fuc->refpll.vco1.max_freq) ? 2 : 1;
        ram->from = ram_rd32(fuc, 0x1373f4) & 0x0000000f;
 
        /* XXX: this is *not* what nvidia do.  on fermi nvidia generally
@@ -946,7 +1007,7 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
         * so far, i've seen very weird values being chosen by nvidia on
         * kepler boards, no idea how/why they're chosen.
         */
-       refclk = freq;
+       refclk = next->freq;
        if (ram->mode == 2)
                refclk = fuc->mempll.refclk;
 
@@ -968,7 +1029,7 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
                fuc->mempll.min_p = 1;
                fuc->mempll.max_p = 2;
 
-               ret = nva3_pll_calc(nv_subdev(pfb), &fuc->mempll, freq,
+               ret = nva3_pll_calc(nv_subdev(pfb), &fuc->mempll, next->freq,
                                   &ram->N2, NULL, &ram->M2, &ram->P2);
                if (ret <= 0) {
                        nv_error(pfb, "unable to calc mempll\n");
@@ -980,17 +1041,18 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
                if (ram_have(fuc, mr[i]))
                        ram->base.mr[i] = ram_rd32(fuc, mr[i]);
        }
+       ram->base.freq = next->freq;
 
        switch (ram->base.type) {
        case NV_MEM_TYPE_DDR3:
                ret = nouveau_sddr3_calc(&ram->base);
                if (ret == 0)
-                       ret = nve0_ram_calc_sddr3(pfb, freq);
+                       ret = nve0_ram_calc_sddr3(pfb, next->freq);
                break;
        case NV_MEM_TYPE_GDDR5:
-               ret = nouveau_gddr5_calc(&ram->base);
+               ret = nouveau_gddr5_calc(&ram->base, ram->pnuts != 0);
                if (ret == 0)
-                       ret = nve0_ram_calc_gddr5(pfb, freq);
+                       ret = nve0_ram_calc_gddr5(pfb, next->freq);
                break;
        default:
                ret = -ENOSYS;
@@ -1000,6 +1062,48 @@ nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
        return ret;
 }
 
+static int
+nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
+{
+       struct nouveau_clock *clk = nouveau_clock(pfb);
+       struct nve0_ram *ram = (void *)pfb->ram;
+       struct nouveau_ram_data *xits = &ram->base.xition;
+       struct nouveau_ram_data *copy;
+       int ret;
+
+       if (ram->base.next == NULL) {
+               ret = nve0_ram_calc_data(pfb, clk->read(clk, nv_clk_src_mem),
+                                       &ram->base.former);
+               if (ret)
+                       return ret;
+
+               ret = nve0_ram_calc_data(pfb, freq, &ram->base.target);
+               if (ret)
+                       return ret;
+
+               if (ram->base.target.freq < ram->base.former.freq) {
+                       *xits = ram->base.target;
+                       copy = &ram->base.former;
+               } else {
+                       *xits = ram->base.former;
+                       copy = &ram->base.target;
+               }
+
+               xits->bios.ramcfg_11_02_04 = copy->bios.ramcfg_11_02_04;
+               xits->bios.ramcfg_11_02_03 = copy->bios.ramcfg_11_02_03;
+               xits->bios.timing_20_30_07 = copy->bios.timing_20_30_07;
+
+               ram->base.next = &ram->base.target;
+               if (memcmp(xits, &ram->base.former, sizeof(xits->bios)))
+                       ram->base.next = &ram->base.xition;
+       } else {
+               BUG_ON(ram->base.next != &ram->base.xition);
+               ram->base.next = &ram->base.target;
+       }
+
+       return nve0_ram_calc_xits(pfb, ram->base.next);
+}
+
 static int
 nve0_ram_prog(struct nouveau_fb *pfb)
 {
@@ -1007,7 +1111,7 @@ nve0_ram_prog(struct nouveau_fb *pfb)
        struct nve0_ram *ram = (void *)pfb->ram;
        struct nve0_ramfuc *fuc = &ram->fuc;
        ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", false));
-       return 0;
+       return (ram->base.next == &ram->base.xition);
 }
 
 static void
@@ -1015,6 +1119,7 @@ nve0_ram_tidy(struct nouveau_fb *pfb)
 {
        struct nve0_ram *ram = (void *)pfb->ram;
        struct nve0_ramfuc *fuc = &ram->fuc;
+       ram->base.next = NULL;
        ram_exec(fuc, false);
 }
 
@@ -1055,7 +1160,7 @@ nve0_ram_init(struct nouveau_object *object)
         * binary driver skips the one that's already been setup by
         * the init tables.
         */
-       data = nvbios_rammap_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
+       data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
        if (!data || hdr < 0x15)
                return -EINVAL;
 
@@ -1073,6 +1178,7 @@ nve0_ram_init(struct nouveau_object *object)
                data += 4;
        }
        nv_wr32(pfb, 0x10f65c, save);
+       nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000);
 
        switch (ram->base.type) {
        case NV_MEM_TYPE_GDDR5:
@@ -1117,7 +1223,8 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        struct nouveau_gpio *gpio = nouveau_gpio(pfb);
        struct dcb_gpio_func func;
        struct nve0_ram *ram;
-       int ret;
+       int ret, i;
+       u32 tmp;
 
        ret = nvc0_ram_create(parent, engine, oclass, &ram);
        *pobject = nv_object(ram);
@@ -1136,6 +1243,25 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                break;
        }
 
+       /* calculate a mask of differently configured memory partitions,
+        * because, of course reclocking wasn't complicated enough
+        * already without having to treat some of them differently to
+        * the others....
+        */
+       ram->parts = nv_rd32(pfb, 0x022438);
+       ram->pmask = nv_rd32(pfb, 0x022554);
+       ram->pnuts = 0;
+       for (i = 0, tmp = 0; i < ram->parts; i++) {
+               if (!(ram->pmask & (1 << i))) {
+                       u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000));
+                       if (tmp && tmp != cfg1) {
+                               ram->pnuts |= (1 << i);
+                               continue;
+                       }
+                       tmp = cfg1;
+               }
+       }
+
        // parse bios data for both pll's
        ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
        if (ret) {
@@ -1248,7 +1374,7 @@ nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        ram->fuc.r_0x10f65c = ramfuc_reg(0x10f65c);
        ram->fuc.r_0x10f6bc = ramfuc_reg(0x10f6bc);
        ram->fuc.r_0x100710 = ramfuc_reg(0x100710);
-       ram->fuc.r_0x10f750 = ramfuc_reg(0x10f750);
+       ram->fuc.r_0x100750 = ramfuc_reg(0x100750);
        return 0;
 }
 
index 6565f3dbbe04e7e04c0721ad49f3523688f8b729..14706d9842ca6d1428298982e247f1887f11cff6 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/instmem.h>
+#include "priv.h"
+
+/******************************************************************************
+ * instmem object base implementation
+ *****************************************************************************/
+
+void
+_nouveau_instobj_dtor(struct nouveau_object *object)
+{
+       struct nouveau_instmem *imem = (void *)object->engine;
+       struct nouveau_instobj *iobj = (void *)object;
+
+       mutex_lock(&nv_subdev(imem)->mutex);
+       list_del(&iobj->head);
+       mutex_unlock(&nv_subdev(imem)->mutex);
+
+       return nouveau_object_destroy(&iobj->base);
+}
 
 int
 nouveau_instobj_create_(struct nouveau_object *parent,
@@ -46,73 +63,26 @@ nouveau_instobj_create_(struct nouveau_object *parent,
        return 0;
 }
 
-void
-nouveau_instobj_destroy(struct nouveau_instobj *iobj)
-{
-       struct nouveau_subdev *subdev = nv_subdev(iobj->base.engine);
+/******************************************************************************
+ * instmem subdev base implementation
+ *****************************************************************************/
 
-       mutex_lock(&subdev->mutex);
-       list_del(&iobj->head);
-       mutex_unlock(&subdev->mutex);
-
-       return nouveau_object_destroy(&iobj->base);
-}
-
-void
-_nouveau_instobj_dtor(struct nouveau_object *object)
+static int
+nouveau_instmem_alloc(struct nouveau_instmem *imem,
+                     struct nouveau_object *parent, u32 size, u32 align,
+                     struct nouveau_object **pobject)
 {
-       struct nouveau_instobj *iobj = (void *)object;
-       return nouveau_instobj_destroy(iobj);
+       struct nouveau_object *engine = nv_object(imem);
+       struct nouveau_instmem_impl *impl = (void *)engine->oclass;
+       struct nouveau_instobj_args args = { .size = size, .align = align };
+       return nouveau_object_ctor(parent, engine, impl->instobj, &args,
+                                  sizeof(args), pobject);
 }
 
 int
-nouveau_instmem_create_(struct nouveau_object *parent,
-                       struct nouveau_object *engine,
-                       struct nouveau_oclass *oclass,
-                       int length, void **pobject)
-{
-       struct nouveau_instmem *imem;
-       int ret;
-
-       ret = nouveau_subdev_create_(parent, engine, oclass, 0,
-                                    "INSTMEM", "instmem", length, pobject);
-       imem = *pobject;
-       if (ret)
-               return ret;
-
-       INIT_LIST_HEAD(&imem->list);
-       return 0;
-}
-
-int
-nouveau_instmem_init(struct nouveau_instmem *imem)
-{
-       struct nouveau_instobj *iobj;
-       int ret, i;
-
-       ret = nouveau_subdev_init(&imem->base);
-       if (ret)
-               return ret;
-
-       mutex_lock(&imem->base.mutex);
-
-       list_for_each_entry(iobj, &imem->list, head) {
-               if (iobj->suspend) {
-                       for (i = 0; i < iobj->size; i += 4)
-                               nv_wo32(iobj, i, iobj->suspend[i / 4]);
-                       vfree(iobj->suspend);
-                       iobj->suspend = NULL;
-               }
-       }
-
-       mutex_unlock(&imem->base.mutex);
-
-       return 0;
-}
-
-int
-nouveau_instmem_fini(struct nouveau_instmem *imem, bool suspend)
+_nouveau_instmem_fini(struct nouveau_object *object, bool suspend)
 {
+       struct nouveau_instmem *imem = (void *)object;
        struct nouveau_instobj *iobj;
        int i, ret = 0;
 
@@ -143,12 +113,45 @@ int
 _nouveau_instmem_init(struct nouveau_object *object)
 {
        struct nouveau_instmem *imem = (void *)object;
-       return nouveau_instmem_init(imem);
+       struct nouveau_instobj *iobj;
+       int ret, i;
+
+       ret = nouveau_subdev_init(&imem->base);
+       if (ret)
+               return ret;
+
+       mutex_lock(&imem->base.mutex);
+
+       list_for_each_entry(iobj, &imem->list, head) {
+               if (iobj->suspend) {
+                       for (i = 0; i < iobj->size; i += 4)
+                               nv_wo32(iobj, i, iobj->suspend[i / 4]);
+                       vfree(iobj->suspend);
+                       iobj->suspend = NULL;
+               }
+       }
+
+       mutex_unlock(&imem->base.mutex);
+
+       return 0;
 }
 
 int
-_nouveau_instmem_fini(struct nouveau_object *object, bool suspend)
+nouveau_instmem_create_(struct nouveau_object *parent,
+                       struct nouveau_object *engine,
+                       struct nouveau_oclass *oclass,
+                       int length, void **pobject)
 {
-       struct nouveau_instmem *imem = (void *)object;
-       return nouveau_instmem_fini(imem, suspend);
+       struct nouveau_instmem *imem;
+       int ret;
+
+       ret = nouveau_subdev_create_(parent, engine, oclass, 0,
+                                    "INSTMEM", "instmem", length, pobject);
+       imem = *pobject;
+       if (ret)
+               return ret;
+
+       INIT_LIST_HEAD(&imem->list);
+       imem->alloc = nouveau_instmem_alloc;
+       return 0;
 }
index 795393d7b2f56826c0be783c320867bd14d4336b..7b64befee48fbb5b30b306c980ae53bd077c3368 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/fb.h>
-
 #include "nv04.h"
 
+/******************************************************************************
+ * instmem object implementation
+ *****************************************************************************/
+
+static u32
+nv04_instobj_rd32(struct nouveau_object *object, u64 addr)
+{
+       struct nv04_instobj_priv *node = (void *)object;
+       return nv_ro32(object->engine, node->mem->offset + addr);
+}
+
+static void
+nv04_instobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
+{
+       struct nv04_instobj_priv *node = (void *)object;
+       nv_wo32(object->engine, node->mem->offset + addr, data);
+}
+
+static void
+nv04_instobj_dtor(struct nouveau_object *object)
+{
+       struct nv04_instmem_priv *priv = (void *)object->engine;
+       struct nv04_instobj_priv *node = (void *)object;
+       nouveau_mm_free(&priv->heap, &node->mem);
+       nouveau_instobj_destroy(&node->base);
+}
+
 static int
 nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                  struct nouveau_oclass *oclass, void *data, u32 size,
@@ -33,18 +58,19 @@ nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 {
        struct nv04_instmem_priv *priv = (void *)engine;
        struct nv04_instobj_priv *node;
-       int ret, align;
+       struct nouveau_instobj_args *args = data;
+       int ret;
 
-       align = (unsigned long)data;
-       if (!align)
-               align = 1;
+       if (!args->align)
+               args->align = 1;
 
        ret = nouveau_instobj_create(parent, engine, oclass, &node);
        *pobject = nv_object(node);
        if (ret)
                return ret;
 
-       ret = nouveau_mm_head(&priv->heap, 1, size, size, align, &node->mem);
+       ret = nouveau_mm_head(&priv->heap, 1, args->size, args->size,
+                             args->align, &node->mem);
        if (ret)
                return ret;
 
@@ -53,32 +79,9 @@ nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-static void
-nv04_instobj_dtor(struct nouveau_object *object)
-{
-       struct nv04_instmem_priv *priv = (void *)object->engine;
-       struct nv04_instobj_priv *node = (void *)object;
-       nouveau_mm_free(&priv->heap, &node->mem);
-       nouveau_instobj_destroy(&node->base);
-}
-
-static u32
-nv04_instobj_rd32(struct nouveau_object *object, u64 addr)
-{
-       struct nv04_instobj_priv *node = (void *)object;
-       return nv_ro32(object->engine, node->mem->offset + addr);
-}
-
-static void
-nv04_instobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-       struct nv04_instobj_priv *node = (void *)object;
-       nv_wo32(object->engine, node->mem->offset + addr, data);
-}
-
-static struct nouveau_oclass
+struct nouveau_instobj_impl
 nv04_instobj_oclass = {
-       .ofuncs = &(struct nouveau_ofuncs) {
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv04_instobj_ctor,
                .dtor = nv04_instobj_dtor,
                .init = _nouveau_instobj_init,
@@ -88,19 +91,34 @@ nv04_instobj_oclass = {
        },
 };
 
-int
-nv04_instmem_alloc(struct nouveau_instmem *imem, struct nouveau_object *parent,
-                  u32 size, u32 align, struct nouveau_object **pobject)
+/******************************************************************************
+ * instmem subdev implementation
+ *****************************************************************************/
+
+static u32
+nv04_instmem_rd32(struct nouveau_object *object, u64 addr)
 {
-       struct nouveau_object *engine = nv_object(imem);
-       int ret;
+       return nv_rd32(object, 0x700000 + addr);
+}
 
-       ret = nouveau_object_ctor(parent, engine, &nv04_instobj_oclass,
-                                 (void *)(unsigned long)align, size, pobject);
-       if (ret)
-               return ret;
+static void
+nv04_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
+{
+       return nv_wr32(object, 0x700000 + addr, data);
+}
 
-       return 0;
+void
+nv04_instmem_dtor(struct nouveau_object *object)
+{
+       struct nv04_instmem_priv *priv = (void *)object;
+       nouveau_gpuobj_ref(NULL, &priv->ramfc);
+       nouveau_gpuobj_ref(NULL, &priv->ramro);
+       nouveau_ramht_ref(NULL, &priv->ramht);
+       nouveau_gpuobj_ref(NULL, &priv->vbios);
+       nouveau_mm_fini(&priv->heap);
+       if (priv->iomem)
+               iounmap(priv->iomem);
+       nouveau_instmem_destroy(&priv->base);
 }
 
 static int
@@ -118,7 +136,6 @@ nv04_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
 
        /* PRAMIN aperture maps over the end of VRAM, reserve it */
        priv->base.reserved = 512 * 1024;
-       priv->base.alloc    = nv04_instmem_alloc;
 
        ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1);
        if (ret)
@@ -150,36 +167,10 @@ nv04_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-void
-nv04_instmem_dtor(struct nouveau_object *object)
-{
-       struct nv04_instmem_priv *priv = (void *)object;
-       nouveau_gpuobj_ref(NULL, &priv->ramfc);
-       nouveau_gpuobj_ref(NULL, &priv->ramro);
-       nouveau_ramht_ref(NULL, &priv->ramht);
-       nouveau_gpuobj_ref(NULL, &priv->vbios);
-       nouveau_mm_fini(&priv->heap);
-       if (priv->iomem)
-               iounmap(priv->iomem);
-       nouveau_instmem_destroy(&priv->base);
-}
-
-static u32
-nv04_instmem_rd32(struct nouveau_object *object, u64 addr)
-{
-       return nv_rd32(object, 0x700000 + addr);
-}
-
-static void
-nv04_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-       return nv_wr32(object, 0x700000 + addr, data);
-}
-
-struct nouveau_oclass
-nv04_instmem_oclass = {
-       .handle = NV_SUBDEV(INSTMEM, 0x04),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv04_instmem_oclass = &(struct nouveau_instmem_impl) {
+       .base.handle = NV_SUBDEV(INSTMEM, 0x04),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv04_instmem_ctor,
                .dtor = nv04_instmem_dtor,
                .init = _nouveau_instmem_init,
@@ -187,4 +178,5 @@ nv04_instmem_oclass = {
                .rd32 = nv04_instmem_rd32,
                .wr32 = nv04_instmem_wr32,
        },
-};
+       .instobj = &nv04_instobj_oclass.base,
+}.base;
index b15b61310236608e88a1bc2b89f58b70f3705f48..095fbc6fc099a852bfee334dea9aba389448adcb 100644 (file)
@@ -5,7 +5,9 @@
 #include <core/ramht.h>
 #include <core/mm.h>
 
-#include <subdev/instmem.h>
+#include "priv.h"
+
+extern struct nouveau_instobj_impl nv04_instobj_oclass;
 
 struct nv04_instmem_priv {
        struct nouveau_instmem base;
index b10a143787a7af95af24475f78fa52de7c7a641f..ec0b9661d614ced3dec026e3460d3eeb07905f2e 100644 (file)
 
 #include "nv04.h"
 
+/******************************************************************************
+ * instmem subdev implementation
+ *****************************************************************************/
+
+static u32
+nv40_instmem_rd32(struct nouveau_object *object, u64 addr)
+{
+       struct nv04_instmem_priv *priv = (void *)object;
+       return ioread32_native(priv->iomem + addr);
+}
+
+static void
+nv40_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
+{
+       struct nv04_instmem_priv *priv = (void *)object;
+       iowrite32_native(data, priv->iomem + addr);
+}
+
 static int
 nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                  struct nouveau_oclass *oclass, void *data, u32 size,
@@ -69,7 +87,6 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        priv->base.reserved += 512 * 1024;      /* object storage */
 
        priv->base.reserved = round_up(priv->base.reserved, 4096);
-       priv->base.alloc    = nv04_instmem_alloc;
 
        ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1);
        if (ret)
@@ -106,24 +123,10 @@ nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
        return 0;
 }
 
-static u32
-nv40_instmem_rd32(struct nouveau_object *object, u64 addr)
-{
-       struct nv04_instmem_priv *priv = (void *)object;
-       return ioread32_native(priv->iomem + addr);
-}
-
-static void
-nv40_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
-       struct nv04_instmem_priv *priv = (void *)object;
-       iowrite32_native(data, priv->iomem + addr);
-}
-
-struct nouveau_oclass
-nv40_instmem_oclass = {
-       .handle = NV_SUBDEV(INSTMEM, 0x40),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv40_instmem_oclass = &(struct nouveau_instmem_impl) {
+       .base.handle = NV_SUBDEV(INSTMEM, 0x40),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv40_instmem_ctor,
                .dtor = nv04_instmem_dtor,
                .init = _nouveau_instmem_init,
@@ -131,4 +134,5 @@ nv40_instmem_oclass = {
                .rd32 = nv40_instmem_rd32,
                .wr32 = nv40_instmem_wr32,
        },
-};
+       .instobj = &nv04_instobj_oclass.base,
+}.base;
index 97bc5dff93e7aa224643c0cb5422faa15adb9e36..7cb3b098a08d030d7d315a1642ebf6a167033ffe 100644 (file)
  * Authors: Ben Skeggs
  */
 
-#include <subdev/instmem.h>
 #include <subdev/fb.h>
-
 #include <core/mm.h>
 
+#include "priv.h"
+
 struct nv50_instmem_priv {
        struct nouveau_instmem base;
        spinlock_t lock;
@@ -38,42 +38,9 @@ struct nv50_instobj_priv {
        struct nouveau_mem *mem;
 };
 
-static int
-nv50_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
-                 struct nouveau_oclass *oclass, void *data, u32 size,
-                 struct nouveau_object **pobject)
-{
-       struct nouveau_fb *pfb = nouveau_fb(parent);
-       struct nv50_instobj_priv *node;
-       u32 align = (unsigned long)data;
-       int ret;
-
-       size  = max((size  + 4095) & ~4095, (u32)4096);
-       align = max((align + 4095) & ~4095, (u32)4096);
-
-       ret = nouveau_instobj_create(parent, engine, oclass, &node);
-       *pobject = nv_object(node);
-       if (ret)
-               return ret;
-
-       ret = pfb->ram->get(pfb, size, align, 0, 0x800, &node->mem);
-       if (ret)
-               return ret;
-
-       node->base.addr = node->mem->offset;
-       node->base.size = node->mem->size << 12;
-       node->mem->page_shift = 12;
-       return 0;
-}
-
-static void
-nv50_instobj_dtor(struct nouveau_object *object)
-{
-       struct nv50_instobj_priv *node = (void *)object;
-       struct nouveau_fb *pfb = nouveau_fb(object);
-       pfb->ram->put(pfb, &node->mem);
-       nouveau_instobj_destroy(&node->base);
-}
+/******************************************************************************
+ * instmem object implementation
+ *****************************************************************************/
 
 static u32
 nv50_instobj_rd32(struct nouveau_object *object, u64 offset)
@@ -113,9 +80,46 @@ nv50_instobj_wr32(struct nouveau_object *object, u64 offset, u32 data)
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static struct nouveau_oclass
+static void
+nv50_instobj_dtor(struct nouveau_object *object)
+{
+       struct nv50_instobj_priv *node = (void *)object;
+       struct nouveau_fb *pfb = nouveau_fb(object);
+       pfb->ram->put(pfb, &node->mem);
+       nouveau_instobj_destroy(&node->base);
+}
+
+static int
+nv50_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
+                 struct nouveau_oclass *oclass, void *data, u32 size,
+                 struct nouveau_object **pobject)
+{
+       struct nouveau_fb *pfb = nouveau_fb(parent);
+       struct nouveau_instobj_args *args = data;
+       struct nv50_instobj_priv *node;
+       int ret;
+
+       args->size  = max((args->size  + 4095) & ~4095, (u32)4096);
+       args->align = max((args->align + 4095) & ~4095, (u32)4096);
+
+       ret = nouveau_instobj_create(parent, engine, oclass, &node);
+       *pobject = nv_object(node);
+       if (ret)
+               return ret;
+
+       ret = pfb->ram->get(pfb, args->size, args->align, 0, 0x800, &node->mem);
+       if (ret)
+               return ret;
+
+       node->base.addr = node->mem->offset;
+       node->base.size = node->mem->size << 12;
+       node->mem->page_shift = 12;
+       return 0;
+}
+
+static struct nouveau_instobj_impl
 nv50_instobj_oclass = {
-       .ofuncs = &(struct nouveau_ofuncs) {
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv50_instobj_ctor,
                .dtor = nv50_instobj_dtor,
                .init = _nouveau_instobj_init,
@@ -125,13 +129,16 @@ nv50_instobj_oclass = {
        },
 };
 
+/******************************************************************************
+ * instmem subdev implementation
+ *****************************************************************************/
+
 static int
-nv50_instmem_alloc(struct nouveau_instmem *imem, struct nouveau_object *parent,
-                  u32 size, u32 align, struct nouveau_object **pobject)
+nv50_instmem_fini(struct nouveau_object *object, bool suspend)
 {
-       struct nouveau_object *engine = nv_object(imem);
-       return nouveau_object_ctor(parent, engine, &nv50_instobj_oclass,
-                                  (void *)(unsigned long)align, size, pobject);
+       struct nv50_instmem_priv *priv = (void *)object;
+       priv->addr = ~0ULL;
+       return nouveau_instmem_fini(&priv->base, suspend);
 }
 
 static int
@@ -148,25 +155,17 @@ nv50_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
                return ret;
 
        spin_lock_init(&priv->lock);
-       priv->base.alloc = nv50_instmem_alloc;
        return 0;
 }
 
-static int
-nv50_instmem_fini(struct nouveau_object *object, bool suspend)
-{
-       struct nv50_instmem_priv *priv = (void *)object;
-       priv->addr = ~0ULL;
-       return nouveau_instmem_fini(&priv->base, suspend);
-}
-
-struct nouveau_oclass
-nv50_instmem_oclass = {
-       .handle = NV_SUBDEV(INSTMEM, 0x50),
-       .ofuncs = &(struct nouveau_ofuncs) {
+struct nouveau_oclass *
+nv50_instmem_oclass = &(struct nouveau_instmem_impl) {
+       .base.handle = NV_SUBDEV(INSTMEM, 0x50),
+       .base.ofuncs = &(struct nouveau_ofuncs) {
                .ctor = nv50_instmem_ctor,
                .dtor = _nouveau_instmem_dtor,
                .init = _nouveau_instmem_init,
                .fini = nv50_instmem_fini,
        },
-};
+       .instobj = &nv50_instobj_oclass.base,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h
new file mode 100644 (file)
index 0000000..8d67ded
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef __NVKM_INSTMEM_PRIV_H__
+#define __NVKM_INSTMEM_PRIV_H__
+
+#include <subdev/instmem.h>
+
+struct nouveau_instobj_impl {
+       struct nouveau_oclass base;
+};
+
+struct nouveau_instobj_args {
+       u32 size;
+       u32 align;
+};
+
+#define nouveau_instobj_create(p,e,o,d)                                        \
+       nouveau_instobj_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_instobj_destroy(p) ({                                          \
+       struct nouveau_instobj *iobj = (p);                                    \
+       _nouveau_instobj_dtor(nv_object(iobj));                                \
+})
+#define nouveau_instobj_init(p)                                                \
+       nouveau_object_init(&(p)->base)
+#define nouveau_instobj_fini(p,s)                                              \
+       nouveau_object_fini(&(p)->base, (s))
+
+int  nouveau_instobj_create_(struct nouveau_object *, struct nouveau_object *,
+                            struct nouveau_oclass *, int, void **);
+void _nouveau_instobj_dtor(struct nouveau_object *);
+#define _nouveau_instobj_init nouveau_object_init
+#define _nouveau_instobj_fini nouveau_object_fini
+
+struct nouveau_instmem_impl {
+       struct nouveau_oclass base;
+       struct nouveau_oclass *instobj;
+};
+
+#define nouveau_instmem_create(p,e,o,d)                                        \
+       nouveau_instmem_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nouveau_instmem_destroy(p)                                             \
+       nouveau_subdev_destroy(&(p)->base)
+#define nouveau_instmem_init(p) ({                                             \
+       struct nouveau_instmem *imem = (p);                                    \
+       _nouveau_instmem_init(nv_object(imem));                                \
+})
+#define nouveau_instmem_fini(p,s) ({                                           \
+       struct nouveau_instmem *imem = (p);                                    \
+       _nouveau_instmem_fini(nv_object(imem), (s));                           \
+})
+
+int nouveau_instmem_create_(struct nouveau_object *, struct nouveau_object *,
+                           struct nouveau_oclass *, int, void **);
+#define _nouveau_instmem_dtor _nouveau_subdev_dtor
+int _nouveau_instmem_init(struct nouveau_object *);
+int _nouveau_instmem_fini(struct nouveau_object *, bool);
+
+#endif
index c02b4763a2d50e40db65cf2a8a247f2e8374cd3f..34472d3170974ca8e6207afe0a347f332130d6bd 100644 (file)
@@ -32,6 +32,7 @@ nvc0_mc_intr[] = {
        { 0x00000080, NVDEV_ENGINE_COPY2 },
        { 0x00000100, NVDEV_ENGINE_FIFO },
        { 0x00001000, NVDEV_ENGINE_GR },
+       { 0x00002000, NVDEV_SUBDEV_FB },
        { 0x00008000, NVDEV_ENGINE_BSP },
        { 0x00040000, NVDEV_SUBDEV_THERM },
        { 0x00020000, NVDEV_ENGINE_VP },
@@ -40,6 +41,7 @@ nvc0_mc_intr[] = {
        { 0x01000000, NVDEV_SUBDEV_PWR },
        { 0x02000000, NVDEV_SUBDEV_LTCG },
        { 0x04000000, NVDEV_ENGINE_DISP },
+       { 0x08000000, NVDEV_SUBDEV_FB },
        { 0x10000000, NVDEV_SUBDEV_BUS },
        { 0x40000000, NVDEV_SUBDEV_IBUS },
        { 0x80000000, NVDEV_ENGINE_SW },
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc
new file mode 100644 (file)
index 0000000..757dda7
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * 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
+ */
+
+#define T_TIMEOUT  2200000
+#define T_RISEFALL 1000
+#define T_HOLD     5000
+
+#ifdef INCLUDE_PROC
+process(PROC_I2C_, #i2c_init, #i2c_recv)
+#endif
+
+/******************************************************************************
+ * I2C_ data segment
+ *****************************************************************************/
+#ifdef INCLUDE_DATA
+i2c_scl_map:
+.b32 NV_PPWR_OUTPUT_I2C_0_SCL
+.b32 NV_PPWR_OUTPUT_I2C_1_SCL
+.b32 NV_PPWR_OUTPUT_I2C_2_SCL
+.b32 NV_PPWR_OUTPUT_I2C_3_SCL
+.b32 NV_PPWR_OUTPUT_I2C_4_SCL
+.b32 NV_PPWR_OUTPUT_I2C_5_SCL
+.b32 NV_PPWR_OUTPUT_I2C_6_SCL
+.b32 NV_PPWR_OUTPUT_I2C_7_SCL
+.b32 NV_PPWR_OUTPUT_I2C_8_SCL
+.b32 NV_PPWR_OUTPUT_I2C_9_SCL
+i2c_sda_map:
+.b32 NV_PPWR_OUTPUT_I2C_0_SDA
+.b32 NV_PPWR_OUTPUT_I2C_1_SDA
+.b32 NV_PPWR_OUTPUT_I2C_2_SDA
+.b32 NV_PPWR_OUTPUT_I2C_3_SDA
+.b32 NV_PPWR_OUTPUT_I2C_4_SDA
+.b32 NV_PPWR_OUTPUT_I2C_5_SDA
+.b32 NV_PPWR_OUTPUT_I2C_6_SDA
+.b32 NV_PPWR_OUTPUT_I2C_7_SDA
+.b32 NV_PPWR_OUTPUT_I2C_8_SDA
+.b32 NV_PPWR_OUTPUT_I2C_9_SDA
+#if NVKM_PPWR_CHIPSET < GF119
+i2c_ctrl:
+.b32 0x00e138
+.b32 0x00e150
+.b32 0x00e168
+.b32 0x00e180
+.b32 0x00e254
+.b32 0x00e274
+.b32 0x00e764
+.b32 0x00e780
+.b32 0x00e79c
+.b32 0x00e7b8
+#endif
+#endif
+
+/******************************************************************************
+ * I2C_ code segment
+ *****************************************************************************/
+#ifdef INCLUDE_CODE
+
+// $r3  - value
+// $r2  - sda line
+// $r1  - scl line
+// $r0  - zero
+i2c_drive_scl:
+       cmp b32 $r3 0
+       bra e #i2c_drive_scl_lo
+       nv_iowr(NV_PPWR_OUTPUT_SET, $r1)
+       ret
+       i2c_drive_scl_lo:
+       nv_iowr(NV_PPWR_OUTPUT_CLR, $r1)
+       ret
+
+i2c_drive_sda:
+       cmp b32 $r3 0
+       bra e #i2c_drive_sda_lo
+       nv_iowr(NV_PPWR_OUTPUT_SET, $r2)
+       ret
+       i2c_drive_sda_lo:
+       nv_iowr(NV_PPWR_OUTPUT_CLR, $r2)
+       ret
+
+i2c_sense_scl:
+       bclr $flags $p1
+       nv_iord($r3, NV_PPWR_INPUT)
+       and $r3 $r1
+       bra z #i2c_sense_scl_done
+               bset $flags $p1
+       i2c_sense_scl_done:
+       ret
+
+i2c_sense_sda:
+       bclr $flags $p1
+       nv_iord($r3, NV_PPWR_INPUT)
+       and $r3 $r2
+       bra z #i2c_sense_sda_done
+               bset $flags $p1
+       i2c_sense_sda_done:
+       ret
+
+#define i2c_drive_scl(v) /*
+*/     mov $r3 (v) /*
+*/     call(i2c_drive_scl)
+#define i2c_drive_sda(v) /*
+*/     mov $r3 (v) /*
+*/     call(i2c_drive_sda)
+#define i2c_sense_scl() /*
+*/     call(i2c_sense_scl)
+#define i2c_sense_sda() /*
+*/     call(i2c_sense_sda)
+#define i2c_delay(v) /*
+*/     mov $r14 (v) /*
+*/     call(nsec)
+
+#define i2c_trace_init() /*
+*/     imm32($r6, 0x10000000) /*
+*/     sub b32 $r7 $r6 1 /*
+*/
+#define i2c_trace_down() /*
+*/     shr b32 $r6 4 /*
+*/     push $r5 /*
+*/     shl b32 $r5 $r6 4 /*
+*/     sub b32 $r5 $r6 /*
+*/     not b32 $r5 /*
+*/     and $r7 $r5 /*
+*/     pop $r5 /*
+*/
+#define i2c_trace_exit() /*
+*/     shl b32 $r6 4 /*
+*/
+#define i2c_trace_next() /*
+*/     add b32 $r7 $r6 /*
+*/
+#define i2c_trace_call(func) /*
+*/     i2c_trace_next() /*
+*/     i2c_trace_down() /*
+*/     call(func) /*
+*/     i2c_trace_exit() /*
+*/
+
+i2c_raise_scl:
+       push $r4
+       mov $r4 (T_TIMEOUT / T_RISEFALL)
+       i2c_drive_scl(1)
+       i2c_raise_scl_wait:
+               i2c_delay(T_RISEFALL)
+               i2c_sense_scl()
+               bra $p1 #i2c_raise_scl_done
+               sub b32 $r4 1
+               bra nz #i2c_raise_scl_wait
+       i2c_raise_scl_done:
+       pop $r4
+       ret
+
+i2c_start:
+       i2c_sense_scl()
+       bra not $p1 #i2c_start_rep
+       i2c_sense_sda()
+       bra not $p1 #i2c_start_rep
+       bra #i2c_start_send
+       i2c_start_rep:
+               i2c_drive_scl(0)
+               i2c_drive_sda(1)
+               i2c_trace_call(i2c_raise_scl)
+               bra not $p1 #i2c_start_out
+       i2c_start_send:
+       i2c_drive_sda(0)
+       i2c_delay(T_HOLD)
+       i2c_drive_scl(0)
+       i2c_delay(T_HOLD)
+       i2c_start_out:
+       ret
+
+i2c_stop:
+       i2c_drive_scl(0)
+       i2c_drive_sda(0)
+       i2c_delay(T_RISEFALL)
+       i2c_drive_scl(1)
+       i2c_delay(T_HOLD)
+       i2c_drive_sda(1)
+       i2c_delay(T_HOLD)
+       ret
+
+// $r3  - value
+// $r2  - sda line
+// $r1  - scl line
+// $r0  - zero
+i2c_bitw:
+       call(i2c_drive_sda)
+       i2c_delay(T_RISEFALL)
+       i2c_trace_call(i2c_raise_scl)
+       bra not $p1 #i2c_bitw_out
+       i2c_delay(T_HOLD)
+       i2c_drive_scl(0)
+       i2c_delay(T_HOLD)
+       i2c_bitw_out:
+       ret
+
+// $r3  - value (out)
+// $r2  - sda line
+// $r1  - scl line
+// $r0  - zero
+i2c_bitr:
+       i2c_drive_sda(1)
+       i2c_delay(T_RISEFALL)
+       i2c_trace_call(i2c_raise_scl)
+       bra not $p1 #i2c_bitr_done
+       i2c_sense_sda()
+       i2c_drive_scl(0)
+       i2c_delay(T_HOLD)
+       xbit $r3 $flags $p1
+       bset $flags $p1
+       i2c_bitr_done:
+       ret
+
+i2c_get_byte:
+       mov $r5 0
+       mov $r4 8
+       i2c_get_byte_next:
+               shl b32 $r5 1
+               i2c_trace_call(i2c_bitr)
+               bra not $p1 #i2c_get_byte_done
+               or $r5 $r3
+               sub b32 $r4 1
+               bra nz #i2c_get_byte_next
+       mov $r3 1
+       i2c_trace_call(i2c_bitw)
+       i2c_get_byte_done:
+       ret
+
+i2c_put_byte:
+       mov $r4 8
+       i2c_put_byte_next:
+               sub b32 $r4 1
+               xbit $r3 $r5 $r4
+               i2c_trace_call(i2c_bitw)
+               bra not $p1 #i2c_put_byte_done
+               cmp b32 $r4 0
+               bra ne #i2c_put_byte_next
+       i2c_trace_call(i2c_bitr)
+       bra not $p1 #i2c_put_byte_done
+       i2c_trace_next()
+       cmp b32 $r3 1
+       bra ne #i2c_put_byte_done
+       bclr $flags $p1 // nack
+       i2c_put_byte_done:
+       ret
+
+i2c_addr:
+       i2c_trace_call(i2c_start)
+       bra not $p1 #i2c_addr_done
+       extr $r3 $r12 I2C__MSG_DATA0_ADDR
+       shl b32 $r3 1
+       or $r5 $r3
+       i2c_trace_call(i2c_put_byte)
+       i2c_addr_done:
+       ret
+
+i2c_acquire_addr:
+       extr $r14 $r12 I2C__MSG_DATA0_PORT
+#if NVKM_PPWR_CHIPSET < GF119
+       shl b32 $r14 2
+       add b32 $r14 #i2c_ctrl
+       ld b32 $r14 D[$r14]
+#else
+       shl b32 $r14 5
+       add b32 $r14 0x00d014
+#endif
+       ret
+
+i2c_acquire:
+       call(i2c_acquire_addr)
+       call(rd32)
+       bset $r13 3
+       call(wr32)
+       ret
+
+i2c_release:
+       call(i2c_acquire_addr)
+       call(rd32)
+       bclr $r13 3
+       call(wr32)
+       ret
+
+// description
+//
+// $r15 - current (i2c)
+// $r14 - sender process name
+// $r13 - message
+// $r12 - data0
+// $r11 - data1
+// $r0  - zero
+i2c_recv:
+       bclr $flags $p1
+       extr $r1 $r12 I2C__MSG_DATA0_PORT
+       shl b32 $r1 2
+       cmp b32 $r1 (#i2c_sda_map - #i2c_scl_map)
+       bra ge #i2c_recv_done
+       add b32 $r3 $r1 #i2c_sda_map
+       ld b32 $r2 D[$r3]
+       add b32 $r3 $r1 #i2c_scl_map
+       ld b32 $r1 D[$r3]
+
+       bset $flags $p2
+       push $r13
+       push $r14
+
+       push $r13
+       i2c_trace_init()
+       i2c_trace_call(i2c_acquire)
+       pop $r13
+
+       cmp b32 $r13 I2C__MSG_RD08
+       bra ne #i2c_recv_not_rd08
+               mov $r5 0
+               i2c_trace_call(i2c_addr)
+               bra not $p1 #i2c_recv_done
+               extr $r5 $r12 I2C__MSG_DATA0_RD08_REG
+               i2c_trace_call(i2c_put_byte)
+               bra not $p1 #i2c_recv_done
+               mov $r5 1
+               i2c_trace_call(i2c_addr)
+               bra not $p1 #i2c_recv_done
+               i2c_trace_call(i2c_get_byte)
+               bra not $p1 #i2c_recv_done
+               ins $r11 $r5 I2C__MSG_DATA1_RD08_VAL
+               i2c_trace_call(i2c_stop)
+               mov b32 $r11 $r5
+               clear b32 $r7
+               bra #i2c_recv_done
+
+       i2c_recv_not_rd08:
+       cmp b32 $r13 I2C__MSG_WR08
+       bra ne #i2c_recv_not_wr08
+               mov $r5 0
+               call(i2c_addr)
+               bra not $p1 #i2c_recv_done
+               extr $r5 $r12 I2C__MSG_DATA0_WR08_REG
+               call(i2c_put_byte)
+               bra not $p1 #i2c_recv_done
+               mov $r5 0
+               call(i2c_addr)
+               bra not $p1 #i2c_recv_done
+               extr $r5 $r11 I2C__MSG_DATA1_WR08_VAL
+               call(i2c_put_byte)
+               bra not $p1 #i2c_recv_done
+               call(i2c_stop)
+               clear b32 $r7
+               extr $r5 $r12 I2C__MSG_DATA0_WR08_SYNC
+               bra nz #i2c_recv_done
+               bclr $flags $p2
+               bra #i2c_recv_done
+
+       i2c_recv_not_wr08:
+
+       i2c_recv_done:
+       extr $r14 $r12 I2C__MSG_DATA0_PORT
+       call(i2c_release)
+
+       pop $r14
+       pop $r13
+       bra not $p2 #i2c_recv_exit
+       mov b32 $r12 $r7
+       call(send)
+
+       i2c_recv_exit:
+       ret
+
+// description
+//
+// $r15 - current (i2c)
+// $r0  - zero
+i2c_init:
+       ret
+#endif
index 0a7b05fa5c1112ab4f172ca39a5d66fd1de7ead2..8f29badd785f16f9cd37cff7adf19d03f1aafc44 100644 (file)
@@ -51,12 +51,12 @@ time_next: .b32 0
 // $r0  - zero
 rd32:
        nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
-       mov $r14 NV_PPWR_MMIO_CTRL_OP_RD
-       sethi $r14 NV_PPWR_MMIO_CTRL_TRIGGER
-       nv_iowr(NV_PPWR_MMIO_CTRL, $r14)
+       mov $r13 NV_PPWR_MMIO_CTRL_OP_RD
+       sethi $r13 NV_PPWR_MMIO_CTRL_TRIGGER
+       nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
        rd32_wait:
-               nv_iord($r14, NV_PPWR_MMIO_CTRL)
-               and $r14 NV_PPWR_MMIO_CTRL_STATUS
+               nv_iord($r13, NV_PPWR_MMIO_CTRL)
+               and $r13 NV_PPWR_MMIO_CTRL_STATUS
                bra nz #rd32_wait
        nv_iord($r13, NV_PPWR_MMIO_DATA)
        ret
@@ -70,23 +70,25 @@ rd32:
 wr32:
        nv_iowr(NV_PPWR_MMIO_ADDR, $r14)
        nv_iowr(NV_PPWR_MMIO_DATA, $r13)
-       mov $r14 NV_PPWR_MMIO_CTRL_OP_WR
-       or $r14 NV_PPWR_MMIO_CTRL_MASK_B32_0
-       sethi $r14 NV_PPWR_MMIO_CTRL_TRIGGER
+       mov $r13 NV_PPWR_MMIO_CTRL_OP_WR
+       or $r13 NV_PPWR_MMIO_CTRL_MASK_B32_0
+       sethi $r13 NV_PPWR_MMIO_CTRL_TRIGGER
 
 #ifdef NVKM_FALCON_MMIO_TRAP
-       mov $r8 NV_PPWR_INTR_TRIGGER_USER1
-       nv_iowr(NV_PPWR_INTR_TRIGGER, $r8)
+       push $r13
+       mov $r13 NV_PPWR_INTR_TRIGGER_USER1
+       nv_iowr(NV_PPWR_INTR_TRIGGER, $r13)
        wr32_host:
-               nv_iord($r8, NV_PPWR_INTR)
-               and $r8 NV_PPWR_INTR_USER1
+               nv_iord($r13, NV_PPWR_INTR)
+               and $r13 NV_PPWR_INTR_USER1
                bra nz #wr32_host
+       pop $r13
 #endif
 
-       nv_iowr(NV_PPWR_MMIO_CTRL, $r14)
+       nv_iowr(NV_PPWR_MMIO_CTRL, $r13)
        wr32_wait:
-               nv_iord($r14, NV_PPWR_MMIO_CTRL)
-               and $r14 NV_PPWR_MMIO_CTRL_STATUS
+               nv_iord($r13, NV_PPWR_MMIO_CTRL)
+               and $r13 NV_PPWR_MMIO_CTRL_STATUS
                bra nz #wr32_wait
        ret
 
index 2a74ea90760430624d6bb369b02e5a575ad75c5d..e2a63ac5422b8180e4e21cd77e622f688900e4ad 100644 (file)
 #define NV_PPWR_MMIO_CTRL_OP_WR                                      0x00000002
 #define NV_PPWR_OUTPUT                                                   0x07c0
 #define NV_PPWR_OUTPUT_FB_PAUSE                                      0x00000004
+#if NVKM_PPWR_CHIPSET < GF119
+#define NV_PPWR_OUTPUT_I2C_3_SCL                                     0x00000100
+#define NV_PPWR_OUTPUT_I2C_3_SDA                                     0x00000200
+#define NV_PPWR_OUTPUT_I2C_0_SCL                                     0x00001000
+#define NV_PPWR_OUTPUT_I2C_0_SDA                                     0x00002000
+#define NV_PPWR_OUTPUT_I2C_1_SCL                                     0x00004000
+#define NV_PPWR_OUTPUT_I2C_1_SDA                                     0x00008000
+#define NV_PPWR_OUTPUT_I2C_2_SCL                                     0x00010000
+#define NV_PPWR_OUTPUT_I2C_2_SDA                                     0x00020000
+#define NV_PPWR_OUTPUT_I2C_4_SCL                                     0x00040000
+#define NV_PPWR_OUTPUT_I2C_4_SDA                                     0x00080000
+#define NV_PPWR_OUTPUT_I2C_5_SCL                                     0x00100000
+#define NV_PPWR_OUTPUT_I2C_5_SDA                                     0x00200000
+#define NV_PPWR_OUTPUT_I2C_6_SCL                                     0x00400000
+#define NV_PPWR_OUTPUT_I2C_6_SDA                                     0x00800000
+#define NV_PPWR_OUTPUT_I2C_7_SCL                                     0x01000000
+#define NV_PPWR_OUTPUT_I2C_7_SDA                                     0x02000000
+#define NV_PPWR_OUTPUT_I2C_8_SCL                                     0x04000000
+#define NV_PPWR_OUTPUT_I2C_8_SDA                                     0x08000000
+#define NV_PPWR_OUTPUT_I2C_9_SCL                                     0x10000000
+#define NV_PPWR_OUTPUT_I2C_9_SDA                                     0x20000000
+#else
+#define NV_PPWR_OUTPUT_I2C_0_SCL                                     0x00000400
+#define NV_PPWR_OUTPUT_I2C_1_SCL                                     0x00000800
+#define NV_PPWR_OUTPUT_I2C_2_SCL                                     0x00001000
+#define NV_PPWR_OUTPUT_I2C_3_SCL                                     0x00002000
+#define NV_PPWR_OUTPUT_I2C_4_SCL                                     0x00004000
+#define NV_PPWR_OUTPUT_I2C_5_SCL                                     0x00008000
+#define NV_PPWR_OUTPUT_I2C_6_SCL                                     0x00010000
+#define NV_PPWR_OUTPUT_I2C_7_SCL                                     0x00020000
+#define NV_PPWR_OUTPUT_I2C_8_SCL                                     0x00040000
+#define NV_PPWR_OUTPUT_I2C_9_SCL                                     0x00080000
+#define NV_PPWR_OUTPUT_I2C_0_SDA                                     0x00100000
+#define NV_PPWR_OUTPUT_I2C_1_SDA                                     0x00200000
+#define NV_PPWR_OUTPUT_I2C_2_SDA                                     0x00400000
+#define NV_PPWR_OUTPUT_I2C_3_SDA                                     0x00800000
+#define NV_PPWR_OUTPUT_I2C_4_SDA                                     0x01000000
+#define NV_PPWR_OUTPUT_I2C_5_SDA                                     0x02000000
+#define NV_PPWR_OUTPUT_I2C_6_SDA                                     0x04000000
+#define NV_PPWR_OUTPUT_I2C_7_SDA                                     0x08000000
+#define NV_PPWR_OUTPUT_I2C_8_SDA                                     0x10000000
+#define NV_PPWR_OUTPUT_I2C_9_SDA                                     0x20000000
+#endif
+#define NV_PPWR_INPUT                                                    0x07c4
 #define NV_PPWR_OUTPUT_SET                                               0x07e0
 #define NV_PPWR_OUTPUT_SET_FB_PAUSE                                  0x00000004
 #define NV_PPWR_OUTPUT_CLR                                               0x07e4
 */     .b32 0 /*
 */     .skip 64
 
+#if NV_PPWR_CHIPSET < GK208
+#define imm32(reg,val) /*
+*/     movw reg  ((val) & 0x0000ffff) /*
+*/     sethi reg ((val) & 0xffff0000)
+#else
+#define imm32(reg,val) /*
+*/     mov reg (val)
+#endif
+
 #ifndef NVKM_FALCON_UNSHIFTED_IO
 #define nv_iord(reg,ior) /*
 */     mov reg ior /*
index 947be536daefcb6031723f3d5e8eb2638c29eb47..17a8a383d91a91929c2eebad9ef1f531861c6800 100644 (file)
@@ -37,6 +37,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_PROC
@@ -46,6 +47,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_DATA
@@ -57,6 +59,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_CODE
index 9342e2d7d3b7909b94f5cc02ead4c80d1e9e3e9b..4bd43a99fdccbe3d2cde12233644f18bda7561c0 100644 (file)
@@ -89,16 +89,9 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x54534554,
-       0x00000494,
-       0x00000475,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x5f433249,
+       0x00000877,
+       0x0000071e,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -111,16 +104,6 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x454c4449,
-       0x0000049f,
-       0x0000049d,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -128,17 +111,16 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+       0x54534554,
+       0x00000898,
+       0x00000879,
        0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0210: proc_list_tail */
-/* 0x0210: time_prev */
        0x00000000,
-/* 0x0214: time_next */
        0x00000000,
-/* 0x0218: fifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -151,6 +133,9 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+       0x454c4449,
+       0x000008a3,
+       0x000008a1,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -170,9 +155,12 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
        0x00000000,
-/* 0x0298: rfifo_queue */
+/* 0x026c: time_next */
        0x00000000,
+/* 0x0270: fifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -204,31 +192,8 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0318: memx_func_head */
-       0x00010000,
-       0x00000000,
-       0x000003a9,
-/* 0x0324: memx_func_next */
-       0x00000001,
-       0x00000000,
-       0x000003c7,
-       0x00000002,
-       0x00000002,
-       0x000003df,
-       0x00040003,
-       0x00000000,
-       0x00000407,
-       0x00010004,
-       0x00000000,
-       0x00000421,
-/* 0x0354: memx_func_tail */
-/* 0x0354: memx_data_head */
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
        0x00000000,
+/* 0x02f0: rfifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -261,10 +226,25 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+/* 0x0370: memx_func_head */
+       0x00010000,
        0x00000000,
+       0x000003a9,
+/* 0x037c: memx_func_next */
+       0x00000001,
        0x00000000,
+       0x000003c7,
+       0x00000002,
+       0x00000002,
+       0x000003df,
+       0x00040003,
        0x00000000,
+       0x00000407,
+       0x00010004,
        0x00000000,
+       0x00000421,
+/* 0x03ac: memx_func_tail */
+/* 0x03ac: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -735,7 +715,6 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0b54: memx_data_tail */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -778,6 +757,29 @@ uint32_t nv108_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+/* 0x0bac: memx_data_tail */
+/* 0x0bac: i2c_scl_map */
+       0x00000400,
+       0x00000800,
+       0x00001000,
+       0x00002000,
+       0x00004000,
+       0x00008000,
+       0x00010000,
+       0x00020000,
+       0x00040000,
+       0x00080000,
+/* 0x0bd4: i2c_sda_map */
+       0x00100000,
+       0x00200000,
+       0x00400000,
+       0x00800000,
+       0x01000000,
+       0x02000000,
+       0x04000000,
+       0x08000000,
+       0x10000000,
+       0x20000000,
        0x00000000,
 };
 
@@ -786,13 +788,13 @@ uint32_t nv108_pwr_code[] = {
 /* 0x0004: rd32 */
        0xf607a040,
        0x04bd000e,
-       0xe3f0010e,
+       0xd3f0010d,
        0x07ac4001,
-       0xbd000ef6,
+       0xbd000df6,
 /* 0x0019: rd32_wait */
-       0x07ac4e04,
-       0xf100eecf,
-       0xf47000e4,
+       0x07ac4d04,
+       0xf100ddcf,
+       0xf47000d4,
        0xa44df61b,
        0x00ddcf07,
 /* 0x002e: wr32 */
@@ -800,14 +802,14 @@ uint32_t nv108_pwr_code[] = {
        0x000ef607,
        0xa44004bd,
        0x000df607,
-       0x020e04bd,
-       0xf0f0e5f0,
-       0xac4001e3,
-       0x000ef607,
+       0x020d04bd,
+       0xf0f0d5f0,
+       0xac4001d3,
+       0x000df607,
 /* 0x004e: wr32_wait */
-       0xac4e04bd,
-       0x00eecf07,
-       0x7000e4f1,
+       0xac4d04bd,
+       0x00ddcf07,
+       0x7000d4f1,
        0xf8f61bf4,
 /* 0x005d: nsec */
        0xcf2c0800,
@@ -832,20 +834,20 @@ uint32_t nv108_pwr_code[] = {
        0x03e99800,
        0xf40096b0,
        0x0a98280b,
-       0x029abb84,
+       0x029abb9a,
        0x0d0e1cf4,
        0x01de7e01,
        0xf494bd00,
 /* 0x00b2: intr_watchdog_next_time */
        0x0a98140e,
-       0x00a6b085,
+       0x00a6b09b,
        0xa6080bf4,
        0x061cf49a,
 /* 0x00c0: intr_watchdog_next_time_set */
 /* 0x00c3: intr_watchdog_next_proc */
-       0xb58509b5,
+       0xb59b09b5,
        0xe0b603e9,
-       0x10e6b158,
+       0x68e6b158,
        0xc81bf402,
 /* 0x00d2: intr */
        0x00f900f8,
@@ -862,15 +864,15 @@ uint32_t nv108_pwr_code[] = {
        0x080804bd,
        0xc40088cf,
        0x0bf40289,
-       0x8500b51f,
+       0x9b00b51f,
        0x957e580e,
        0x09980000,
-       0x0096b085,
+       0x0096b09b,
        0x000d0bf4,
        0x0009f634,
        0x09b504bd,
 /* 0x0125: intr_skip_watchdog */
-       0x0089e484,
+       0x0089e49a,
        0x360bf408,
        0xcf068849,
        0x9ac40099,
@@ -918,7 +920,7 @@ uint32_t nv108_pwr_code[] = {
 /* 0x01c6: timer_reset */
        0x3400161e,
        0xbd000ef6,
-       0x840eb504,
+       0x9a0eb504,
 /* 0x01d0: timer_enable */
        0x38000108,
        0xbd0008f6,
@@ -949,7 +951,7 @@ uint32_t nv108_pwr_code[] = {
        0xa6008a98,
        0x100bf4ae,
        0xb15880b6,
-       0xf4021086,
+       0xf4026886,
        0x32f4f11b,
 /* 0x0239: find_done */
        0xfc8eb201,
@@ -1009,7 +1011,7 @@ uint32_t nv108_pwr_code[] = {
        0x0bf412a6,
        0x071ec42e,
        0xb704ee94,
-       0x980218e0,
+       0x980270e0,
        0xec9803eb,
        0x01ed9802,
        0x7e00ee98,
@@ -1031,7 +1033,7 @@ uint32_t nv108_pwr_code[] = {
        0xf412a608,
        0x23c4ef0b,
        0x0434b607,
-       0x029830b7,
+       0x02f030b7,
        0xb5033bb5,
        0x3db5023c,
        0x003eb501,
@@ -1044,11 +1046,11 @@ uint32_t nv108_pwr_code[] = {
 /* 0x0379: host_init */
        0x00804100,
        0xf11014b6,
-       0x40021815,
+       0x40027015,
        0x01f604d0,
        0x4104bd00,
        0x14b60080,
-       0x9815f110,
+       0xf015f110,
        0x04dc4002,
        0xbd0001f6,
        0x40010104,
@@ -1101,13 +1103,13 @@ uint32_t nv108_pwr_code[] = {
        0x001398b2,
        0x950410b6,
        0x30f01034,
-       0xc835980c,
+       0xde35980c,
        0x12a655f9,
        0xfced1ef4,
        0x7ee0fcd0,
        0xf800023f,
 /* 0x0455: memx_info */
-       0x03544c00,
+       0x03ac4c00,
        0x7e08004b,
        0xf800023f,
 /* 0x0461: memx_recv */
@@ -1119,7 +1121,301 @@ uint32_t nv108_pwr_code[] = {
 /* 0x0471: perf_recv */
 /* 0x0473: perf_init */
        0xf800f800,
-/* 0x0475: test_recv */
+/* 0x0475: i2c_drive_scl */
+       0x0036b000,
+       0x400d0bf4,
+       0x01f607e0,
+       0xf804bd00,
+/* 0x0485: i2c_drive_scl_lo */
+       0x07e44000,
+       0xbd0001f6,
+/* 0x048f: i2c_drive_sda */
+       0xb000f804,
+       0x0bf40036,
+       0x07e0400d,
+       0xbd0002f6,
+/* 0x049f: i2c_drive_sda_lo */
+       0x4000f804,
+       0x02f607e4,
+       0xf804bd00,
+/* 0x04a9: i2c_sense_scl */
+       0x0132f400,
+       0xcf07c443,
+       0x31fd0033,
+       0x060bf404,
+/* 0x04bb: i2c_sense_scl_done */
+       0xf80131f4,
+/* 0x04bd: i2c_sense_sda */
+       0x0132f400,
+       0xcf07c443,
+       0x32fd0033,
+       0x060bf404,
+/* 0x04cf: i2c_sense_sda_done */
+       0xf80131f4,
+/* 0x04d1: i2c_raise_scl */
+       0x4440f900,
+       0x01030898,
+       0x0004757e,
+/* 0x04dc: i2c_raise_scl_wait */
+       0x7e03e84e,
+       0x7e00005d,
+       0xf40004a9,
+       0x42b60901,
+       0xef1bf401,
+/* 0x04f0: i2c_raise_scl_done */
+       0x00f840fc,
+/* 0x04f4: i2c_start */
+       0x0004a97e,
+       0x7e0d11f4,
+       0xf40004bd,
+       0x0ef40611,
+/* 0x0505: i2c_start_rep */
+       0x7e00032e,
+       0x03000475,
+       0x048f7e01,
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0xd17e50fc,
+       0x64b60004,
+       0x1d11f404,
+/* 0x0530: i2c_start_send */
+       0x8f7e0003,
+       0x884e0004,
+       0x005d7e13,
+       0x7e000300,
+       0x4e000475,
+       0x5d7e1388,
+/* 0x054a: i2c_start_out */
+       0x00f80000,
+/* 0x054c: i2c_stop */
+       0x757e0003,
+       0x00030004,
+       0x00048f7e,
+       0x7e03e84e,
+       0x0300005d,
+       0x04757e01,
+       0x13884e00,
+       0x00005d7e,
+       0x8f7e0103,
+       0x884e0004,
+       0x005d7e13,
+/* 0x057b: i2c_bitw */
+       0x7e00f800,
+       0x4e00048f,
+       0x5d7e03e8,
+       0x76bb0000,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0x7e50fc04,
+       0xb60004d1,
+       0x11f40464,
+       0x13884e17,
+       0x00005d7e,
+       0x757e0003,
+       0x884e0004,
+       0x005d7e13,
+/* 0x05b9: i2c_bitw_out */
+/* 0x05bb: i2c_bitr */
+       0x0300f800,
+       0x048f7e01,
+       0x03e84e00,
+       0x00005d7e,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x04d17e50,
+       0x0464b600,
+       0x7e1a11f4,
+       0x030004bd,
+       0x04757e00,
+       0x13884e00,
+       0x00005d7e,
+       0xf4013cf0,
+/* 0x05fe: i2c_bitr_done */
+       0x00f80131,
+/* 0x0600: i2c_get_byte */
+       0x08040005,
+/* 0x0604: i2c_get_byte_next */
+       0xbb0154b6,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x0005bb7e,
+       0xf40464b6,
+       0x53fd2a11,
+       0x0142b605,
+       0x03d81bf4,
+       0x0076bb01,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x7b7e50fc,
+       0x64b60005,
+/* 0x064d: i2c_get_byte_done */
+/* 0x064f: i2c_put_byte */
+       0x0400f804,
+/* 0x0651: i2c_put_byte_next */
+       0x0142b608,
+       0xbb3854ff,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x00057b7e,
+       0xf40464b6,
+       0x46b03411,
+       0xd81bf400,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x05bb7e50,
+       0x0464b600,
+       0xbb0f11f4,
+       0x36b00076,
+       0x061bf401,
+/* 0x06a7: i2c_put_byte_done */
+       0xf80132f4,
+/* 0x06a9: i2c_addr */
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0xf47e50fc,
+       0x64b60004,
+       0x2911f404,
+       0x012ec3e7,
+       0xfd0134b6,
+       0x76bb0553,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0x7e50fc04,
+       0xb600064f,
+/* 0x06ee: i2c_addr_done */
+       0x00f80464,
+/* 0x06f0: i2c_acquire_addr */
+       0xb6f8cec7,
+       0xe0b705e4,
+       0x00f8d014,
+/* 0x06fc: i2c_acquire */
+       0x0006f07e,
+       0x0000047e,
+       0x7e03d9f0,
+       0xf800002e,
+/* 0x070d: i2c_release */
+       0x06f07e00,
+       0x00047e00,
+       0x03daf000,
+       0x00002e7e,
+/* 0x071e: i2c_recv */
+       0x32f400f8,
+       0xf8c1c701,
+       0xb00214b6,
+       0x1ff52816,
+       0x13b80137,
+       0x98000bd4,
+       0x13b80032,
+       0x98000bac,
+       0x31f40031,
+       0xf9d0f902,
+       0xf1d0f9e0,
+       0xf1000067,
+       0x92100063,
+       0x76bb0167,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0x7e50fc04,
+       0xb60006fc,
+       0xd0fc0464,
+       0xf500d6b0,
+       0x0500b01b,
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0xa97e50fc,
+       0x64b60006,
+       0xcc11f504,
+       0xe0c5c700,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x064f7e50,
+       0x0464b600,
+       0x00a911f5,
+       0x76bb0105,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0x7e50fc04,
+       0xb60006a9,
+       0x11f50464,
+       0x76bb0087,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0x7e50fc04,
+       0xb6000600,
+       0x11f40464,
+       0xe05bcb67,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x054c7e50,
+       0x0464b600,
+       0x74bd5bb2,
+/* 0x0823: i2c_recv_not_rd08 */
+       0xb0410ef4,
+       0x1bf401d6,
+       0x7e00053b,
+       0xf40006a9,
+       0xc5c73211,
+       0x064f7ee0,
+       0x2811f400,
+       0xa97e0005,
+       0x11f40006,
+       0xe0b5c71f,
+       0x00064f7e,
+       0x7e1511f4,
+       0xbd00054c,
+       0x08c5c774,
+       0xf4091bf4,
+       0x0ef40232,
+/* 0x0861: i2c_recv_not_wr08 */
+/* 0x0861: i2c_recv_done */
+       0xf8cec703,
+       0x00070d7e,
+       0xd0fce0fc,
+       0xb20912f4,
+       0x023f7e7c,
+/* 0x0875: i2c_recv_exit */
+/* 0x0877: i2c_init */
+       0xf800f800,
+/* 0x0879: test_recv */
        0x04584100,
        0xb60011cf,
        0x58400110,
@@ -1128,26 +1424,26 @@ uint32_t nv108_pwr_code[] = {
        0xe3f1d900,
        0x967e134f,
        0x00f80001,
-/* 0x0494: test_init */
+/* 0x0898: test_init */
        0x7e08004e,
        0xf8000196,
-/* 0x049d: idle_recv */
-/* 0x049f: idle */
+/* 0x08a1: idle_recv */
+/* 0x08a3: idle */
        0xf400f800,
        0x54410031,
        0x0011cf04,
        0x400110b6,
        0x01f60454,
-/* 0x04b3: idle_loop */
+/* 0x08b7: idle_loop */
        0x0104bd00,
        0x0232f458,
-/* 0x04b8: idle_proc */
-/* 0x04b8: idle_proc_exec */
+/* 0x08bc: idle_proc */
+/* 0x08bc: idle_proc_exec */
        0x1eb210f9,
        0x0002487e,
        0x11f410fc,
        0x0231f409,
-/* 0x04cb: idle_proc_next */
+/* 0x08cf: idle_proc_next */
        0xb6f00ef4,
        0x1fa65810,
        0xf4e81bf4,
@@ -1161,5 +1457,4 @@ uint32_t nv108_pwr_code[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x00000000,
 };
index 6fde0b89e5aa641de3add5489a98dea4e25c61bc..6744fcc0615160e657227285a70fc2c201bb7cb9 100644 (file)
@@ -37,6 +37,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_PROC
@@ -46,6 +47,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_DATA
@@ -57,6 +59,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_CODE
index 0fa4d7dcd407bb5bdb7802dcd4a6382c6bb84803..5a73fa620978aa0b300f87f80e6a1c049a2aa094 100644 (file)
@@ -89,9 +89,31 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+       0x5f433249,
+       0x00000982,
+       0x00000825,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x54534554,
-       0x0000057b,
-       0x00000554,
+       0x000009ab,
+       0x00000984,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +134,8 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x00000587,
-       0x00000585,
+       0x000009b7,
+       0x000009b5,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -133,12 +155,12 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0210: proc_list_tail */
-/* 0x0210: time_prev */
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
        0x00000000,
-/* 0x0214: time_next */
+/* 0x026c: time_next */
        0x00000000,
-/* 0x0218: fifo_queue */
+/* 0x0270: fifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -171,7 +193,7 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0298: rfifo_queue */
+/* 0x02f0: rfifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -204,11 +226,11 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0318: memx_func_head */
+/* 0x0370: memx_func_head */
        0x00010000,
        0x00000000,
        0x0000046f,
-/* 0x0324: memx_func_next */
+/* 0x037c: memx_func_next */
        0x00000001,
        0x00000000,
        0x00000496,
@@ -221,8 +243,18 @@ uint32_t nva3_pwr_data[] = {
        0x00010004,
        0x00000000,
        0x000004fc,
-/* 0x0354: memx_func_tail */
-/* 0x0354: memx_data_head */
+/* 0x03ac: memx_func_tail */
+/* 0x03ac: memx_data_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -725,6 +757,42 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+/* 0x0bac: memx_data_tail */
+/* 0x0bac: i2c_scl_map */
+       0x00001000,
+       0x00004000,
+       0x00010000,
+       0x00000100,
+       0x00040000,
+       0x00100000,
+       0x00400000,
+       0x01000000,
+       0x04000000,
+       0x10000000,
+/* 0x0bd4: i2c_sda_map */
+       0x00002000,
+       0x00008000,
+       0x00020000,
+       0x00000200,
+       0x00080000,
+       0x00200000,
+       0x00800000,
+       0x02000000,
+       0x08000000,
+       0x20000000,
+/* 0x0bfc: i2c_ctrl */
+       0x0000e138,
+       0x0000e150,
+       0x0000e168,
+       0x0000e180,
+       0x0000e254,
+       0x0000e274,
+       0x0000e764,
+       0x0000e780,
+       0x0000e79c,
+       0x0000e7b8,
+       0x00000000,
+       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -735,7 +803,6 @@ uint32_t nva3_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0b54: memx_data_tail */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -787,15 +854,15 @@ uint32_t nva3_pwr_code[] = {
        0x07a007f1,
        0xd00604b6,
        0x04bd000e,
-       0xf001e7f0,
-       0x07f101e3,
+       0xf001d7f0,
+       0x07f101d3,
        0x04b607ac,
-       0x000ed006,
+       0x000dd006,
 /* 0x0022: rd32_wait */
-       0xe7f104bd,
-       0xe4b607ac,
-       0x00eecf06,
-       0x7000e4f1,
+       0xd7f104bd,
+       0xd4b607ac,
+       0x00ddcf06,
+       0x7000d4f1,
        0xf1f21bf4,
        0xb607a4d7,
        0xddcf06d4,
@@ -807,15 +874,15 @@ uint32_t nva3_pwr_code[] = {
        0xb607a407,
        0x0dd00604,
        0xf004bd00,
-       0xe5f002e7,
-       0x01e3f0f0,
+       0xd5f002d7,
+       0x01d3f0f0,
        0x07ac07f1,
        0xd00604b6,
-       0x04bd000e,
+       0x04bd000d,
 /* 0x006c: wr32_wait */
-       0x07ace7f1,
-       0xcf06e4b6,
-       0xe4f100ee,
+       0x07acd7f1,
+       0xcf06d4b6,
+       0xd4f100dd,
        0x1bf47000,
 /* 0x007f: nsec */
        0xf000f8f2,
@@ -845,21 +912,21 @@ uint32_t nva3_pwr_code[] = {
        0x9800f8df,
        0x96b003e9,
        0x2a0bf400,
-       0xbb840a98,
+       0xbb9a0a98,
        0x1cf4029a,
        0x01d7f00f,
        0x025421f5,
        0x0ef494bd,
 /* 0x00e9: intr_watchdog_next_time */
-       0x850a9815,
+       0x9b0a9815,
        0xf400a6b0,
        0x9ab8090b,
        0x061cf406,
 /* 0x00f8: intr_watchdog_next_time_set */
 /* 0x00fb: intr_watchdog_next_proc */
-       0x80850980,
+       0x809b0980,
        0xe0b603e9,
-       0x10e6b158,
+       0x68e6b158,
        0xc61bf402,
 /* 0x010a: intr */
        0x00f900f8,
@@ -880,15 +947,15 @@ uint32_t nva3_pwr_code[] = {
        0x0088cf06,
        0xf40289c4,
        0x0080230b,
-       0x58e7f085,
+       0x58e7f09b,
        0x98cb21f4,
-       0x96b08509,
+       0x96b09b09,
        0x110bf400,
        0xb63407f0,
        0x09d00604,
        0x8004bd00,
 /* 0x016e: intr_skip_watchdog */
-       0x89e48409,
+       0x89e49a09,
        0x0bf40800,
        0x8897f148,
        0x0694b606,
@@ -948,7 +1015,7 @@ uint32_t nva3_pwr_code[] = {
        0x000ed006,
        0x0e8004bd,
 /* 0x0241: timer_enable */
-       0x0187f084,
+       0x0187f09a,
        0xb63807f0,
        0x08d00604,
 /* 0x024f: timer_done */
@@ -979,7 +1046,7 @@ uint32_t nva3_pwr_code[] = {
        0xb8008a98,
        0x0bf406ae,
        0x5880b610,
-       0x021086b1,
+       0x026886b1,
        0xf4f01bf4,
 /* 0x02b2: find_done */
        0x8eb90132,
@@ -1049,7 +1116,7 @@ uint32_t nva3_pwr_code[] = {
        0x320bf406,
        0x94071ec4,
        0xe0b704ee,
-       0xeb980218,
+       0xeb980270,
        0x02ec9803,
        0x9801ed98,
        0x21f500ee,
@@ -1075,7 +1142,7 @@ uint32_t nva3_pwr_code[] = {
        0xe60bf406,
        0xb60723c4,
        0x30b70434,
-       0x3b800298,
+       0x3b8002f0,
        0x023c8003,
        0x80013d80,
        0x20b6003e,
@@ -1090,13 +1157,13 @@ uint32_t nva3_pwr_code[] = {
 /* 0x0430: host_init */
        0x008017f1,
        0xf11014b6,
-       0xf1021815,
+       0xf1027015,
        0xb604d007,
        0x01d00604,
        0xf104bd00,
        0xb6008017,
        0x15f11014,
-       0x07f10298,
+       0x07f102f0,
        0x04b604dc,
        0x0001d006,
        0x17f004bd,
@@ -1156,14 +1223,14 @@ uint32_t nva3_pwr_code[] = {
        0x00139802,
        0x950410b6,
        0x30f01034,
-       0xc835980c,
+       0xde35980c,
        0x12b855f9,
        0xec1ef406,
        0xe0fcd0fc,
        0x02b921f5,
 /* 0x0532: memx_info */
        0xc7f100f8,
-       0xb7f10354,
+       0xb7f103ac,
        0x21f50800,
        0x00f802b9,
 /* 0x0540: memx_recv */
@@ -1175,7 +1242,312 @@ uint32_t nva3_pwr_code[] = {
 /* 0x0550: perf_recv */
 /* 0x0552: perf_init */
        0x00f800f8,
-/* 0x0554: test_recv */
+/* 0x0554: i2c_drive_scl */
+       0xf40036b0,
+       0x07f1110b,
+       0x04b607e0,
+       0x0001d006,
+       0x00f804bd,
+/* 0x0568: i2c_drive_scl_lo */
+       0x07e407f1,
+       0xd00604b6,
+       0x04bd0001,
+/* 0x0576: i2c_drive_sda */
+       0x36b000f8,
+       0x110bf400,
+       0x07e007f1,
+       0xd00604b6,
+       0x04bd0002,
+/* 0x058a: i2c_drive_sda_lo */
+       0x07f100f8,
+       0x04b607e4,
+       0x0002d006,
+       0x00f804bd,
+/* 0x0598: i2c_sense_scl */
+       0xf10132f4,
+       0xb607c437,
+       0x33cf0634,
+       0x0431fd00,
+       0xf4060bf4,
+/* 0x05ae: i2c_sense_scl_done */
+       0x00f80131,
+/* 0x05b0: i2c_sense_sda */
+       0xf10132f4,
+       0xb607c437,
+       0x33cf0634,
+       0x0432fd00,
+       0xf4060bf4,
+/* 0x05c6: i2c_sense_sda_done */
+       0x00f80131,
+/* 0x05c8: i2c_raise_scl */
+       0x47f140f9,
+       0x37f00898,
+       0x5421f501,
+/* 0x05d5: i2c_raise_scl_wait */
+       0xe8e7f105,
+       0x7f21f403,
+       0x059821f5,
+       0xb60901f4,
+       0x1bf40142,
+/* 0x05e9: i2c_raise_scl_done */
+       0xf840fcef,
+/* 0x05ed: i2c_start */
+       0x9821f500,
+       0x0d11f405,
+       0x05b021f5,
+       0xf40611f4,
+/* 0x05fe: i2c_start_rep */
+       0x37f0300e,
+       0x5421f500,
+       0x0137f005,
+       0x057621f5,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xc821f550,
+       0x0464b605,
+/* 0x062b: i2c_start_send */
+       0xf01f11f4,
+       0x21f50037,
+       0xe7f10576,
+       0x21f41388,
+       0x0037f07f,
+       0x055421f5,
+       0x1388e7f1,
+/* 0x0647: i2c_start_out */
+       0xf87f21f4,
+/* 0x0649: i2c_stop */
+       0x0037f000,
+       0x055421f5,
+       0xf50037f0,
+       0xf1057621,
+       0xf403e8e7,
+       0x37f07f21,
+       0x5421f501,
+       0x88e7f105,
+       0x7f21f413,
+       0xf50137f0,
+       0xf1057621,
+       0xf41388e7,
+       0x00f87f21,
+/* 0x067c: i2c_bitw */
+       0x057621f5,
+       0x03e8e7f1,
+       0xbb7f21f4,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x05c821f5,
+       0xf40464b6,
+       0xe7f11811,
+       0x21f41388,
+       0x0037f07f,
+       0x055421f5,
+       0x1388e7f1,
+/* 0x06bb: i2c_bitw_out */
+       0xf87f21f4,
+/* 0x06bd: i2c_bitr */
+       0x0137f000,
+       0x057621f5,
+       0x03e8e7f1,
+       0xbb7f21f4,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x05c821f5,
+       0xf40464b6,
+       0x21f51b11,
+       0x37f005b0,
+       0x5421f500,
+       0x88e7f105,
+       0x7f21f413,
+       0xf4013cf0,
+/* 0x0702: i2c_bitr_done */
+       0x00f80131,
+/* 0x0704: i2c_get_byte */
+       0xf00057f0,
+/* 0x070a: i2c_get_byte_next */
+       0x54b60847,
+       0x0076bb01,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b606bd,
+       0x2b11f404,
+       0xb60553fd,
+       0x1bf40142,
+       0x0137f0d8,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x7c21f550,
+       0x0464b606,
+/* 0x0754: i2c_get_byte_done */
+/* 0x0756: i2c_put_byte */
+       0x47f000f8,
+/* 0x0759: i2c_put_byte_next */
+       0x0142b608,
+       0xbb3854ff,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x067c21f5,
+       0xf40464b6,
+       0x46b03411,
+       0xd81bf400,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xbd21f550,
+       0x0464b606,
+       0xbb0f11f4,
+       0x36b00076,
+       0x061bf401,
+/* 0x07af: i2c_put_byte_done */
+       0xf80132f4,
+/* 0x07b1: i2c_addr */
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b605ed,
+       0x2911f404,
+       0x012ec3e7,
+       0xfd0134b6,
+       0x76bb0553,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb6075621,
+/* 0x07f6: i2c_addr_done */
+       0x00f80464,
+/* 0x07f8: i2c_acquire_addr */
+       0xb6f8cec7,
+       0xe0b702e4,
+       0xee980bfc,
+/* 0x0807: i2c_acquire */
+       0xf500f800,
+       0xf407f821,
+       0xd9f00421,
+       0x3f21f403,
+/* 0x0816: i2c_release */
+       0x21f500f8,
+       0x21f407f8,
+       0x03daf004,
+       0xf83f21f4,
+/* 0x0825: i2c_recv */
+       0x0132f400,
+       0xb6f8c1c7,
+       0x16b00214,
+       0x3a1ff528,
+       0xd413a001,
+       0x0032980b,
+       0x0bac13a0,
+       0xf4003198,
+       0xd0f90231,
+       0xd0f9e0f9,
+       0x000067f1,
+       0x100063f1,
+       0xbb016792,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x080721f5,
+       0xfc0464b6,
+       0x00d6b0d0,
+       0x00b31bf5,
+       0xbb0057f0,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x07b121f5,
+       0xf50464b6,
+       0xc700d011,
+       0x76bbe0c5,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb6075621,
+       0x11f50464,
+       0x57f000ad,
+       0x0076bb01,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b607b1,
+       0x8a11f504,
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b60704,
+       0x6a11f404,
+       0xbbe05bcb,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x064921f5,
+       0xb90464b6,
+       0x74bd025b,
+/* 0x092b: i2c_recv_not_rd08 */
+       0xb0430ef4,
+       0x1bf401d6,
+       0x0057f03d,
+       0x07b121f5,
+       0xc73311f4,
+       0x21f5e0c5,
+       0x11f40756,
+       0x0057f029,
+       0x07b121f5,
+       0xc71f11f4,
+       0x21f5e0b5,
+       0x11f40756,
+       0x4921f515,
+       0xc774bd06,
+       0x1bf408c5,
+       0x0232f409,
+/* 0x096b: i2c_recv_not_wr08 */
+/* 0x096b: i2c_recv_done */
+       0xc7030ef4,
+       0x21f5f8ce,
+       0xe0fc0816,
+       0x12f4d0fc,
+       0x027cb90a,
+       0x02b921f5,
+/* 0x0980: i2c_recv_exit */
+/* 0x0982: i2c_init */
+       0x00f800f8,
+/* 0x0984: test_recv */
        0x05d817f1,
        0xcf0614b6,
        0x10b60011,
@@ -1185,12 +1557,12 @@ uint32_t nva3_pwr_code[] = {
        0x00e7f104,
        0x4fe3f1d9,
        0xf521f513,
-/* 0x057b: test_init */
+/* 0x09ab: test_init */
        0xf100f801,
        0xf50800e7,
        0xf801f521,
-/* 0x0585: idle_recv */
-/* 0x0587: idle */
+/* 0x09b5: idle_recv */
+/* 0x09b7: idle */
        0xf400f800,
        0x17f10031,
        0x14b605d4,
@@ -1198,32 +1570,20 @@ uint32_t nva3_pwr_code[] = {
        0xf10110b6,
        0xb605d407,
        0x01d00604,
-/* 0x05a3: idle_loop */
+/* 0x09d3: idle_loop */
        0xf004bd00,
        0x32f45817,
-/* 0x05a9: idle_proc */
-/* 0x05a9: idle_proc_exec */
+/* 0x09d9: idle_proc */
+/* 0x09d9: idle_proc_exec */
        0xb910f902,
        0x21f5021e,
        0x10fc02c2,
        0xf40911f4,
        0x0ef40231,
-/* 0x05bd: idle_proc_next */
+/* 0x09ed: idle_proc_next */
        0x5810b6ef,
        0xf4061fb8,
        0x02f4e61b,
        0x0028f4dd,
        0x00bb0ef4,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
 };
index eaa64da68e3604b1537753cc314388311dd48514..48f79434a4491f30c61f95755d43c37097f73249 100644 (file)
@@ -37,6 +37,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_PROC
@@ -46,6 +47,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_DATA
@@ -57,6 +59,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_CODE
index 82c8e8b889178dd34e0eef6cf6a39fdd0d7a800d..4dba00d2dd1a6f579d19c4571964440ccbf077b5 100644 (file)
@@ -89,9 +89,31 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+       0x5f433249,
+       0x00000982,
+       0x00000825,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x54534554,
-       0x0000057b,
-       0x00000554,
+       0x000009ab,
+       0x00000984,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -112,8 +134,8 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x454c4449,
-       0x00000587,
-       0x00000585,
+       0x000009b7,
+       0x000009b5,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -133,12 +155,12 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0210: proc_list_tail */
-/* 0x0210: time_prev */
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
        0x00000000,
-/* 0x0214: time_next */
+/* 0x026c: time_next */
        0x00000000,
-/* 0x0218: fifo_queue */
+/* 0x0270: fifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -171,7 +193,7 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0298: rfifo_queue */
+/* 0x02f0: rfifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -204,11 +226,11 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0318: memx_func_head */
+/* 0x0370: memx_func_head */
        0x00010000,
        0x00000000,
        0x0000046f,
-/* 0x0324: memx_func_next */
+/* 0x037c: memx_func_next */
        0x00000001,
        0x00000000,
        0x00000496,
@@ -221,8 +243,18 @@ uint32_t nvc0_pwr_data[] = {
        0x00010004,
        0x00000000,
        0x000004fc,
-/* 0x0354: memx_func_tail */
-/* 0x0354: memx_data_head */
+/* 0x03ac: memx_func_tail */
+/* 0x03ac: memx_data_head */
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
+       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -725,6 +757,42 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+/* 0x0bac: memx_data_tail */
+/* 0x0bac: i2c_scl_map */
+       0x00001000,
+       0x00004000,
+       0x00010000,
+       0x00000100,
+       0x00040000,
+       0x00100000,
+       0x00400000,
+       0x01000000,
+       0x04000000,
+       0x10000000,
+/* 0x0bd4: i2c_sda_map */
+       0x00002000,
+       0x00008000,
+       0x00020000,
+       0x00000200,
+       0x00080000,
+       0x00200000,
+       0x00800000,
+       0x02000000,
+       0x08000000,
+       0x20000000,
+/* 0x0bfc: i2c_ctrl */
+       0x0000e138,
+       0x0000e150,
+       0x0000e168,
+       0x0000e180,
+       0x0000e254,
+       0x0000e274,
+       0x0000e764,
+       0x0000e780,
+       0x0000e79c,
+       0x0000e7b8,
+       0x00000000,
+       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -735,7 +803,6 @@ uint32_t nvc0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0b54: memx_data_tail */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -787,15 +854,15 @@ uint32_t nvc0_pwr_code[] = {
        0x07a007f1,
        0xd00604b6,
        0x04bd000e,
-       0xf001e7f0,
-       0x07f101e3,
+       0xf001d7f0,
+       0x07f101d3,
        0x04b607ac,
-       0x000ed006,
+       0x000dd006,
 /* 0x0022: rd32_wait */
-       0xe7f104bd,
-       0xe4b607ac,
-       0x00eecf06,
-       0x7000e4f1,
+       0xd7f104bd,
+       0xd4b607ac,
+       0x00ddcf06,
+       0x7000d4f1,
        0xf1f21bf4,
        0xb607a4d7,
        0xddcf06d4,
@@ -807,15 +874,15 @@ uint32_t nvc0_pwr_code[] = {
        0xb607a407,
        0x0dd00604,
        0xf004bd00,
-       0xe5f002e7,
-       0x01e3f0f0,
+       0xd5f002d7,
+       0x01d3f0f0,
        0x07ac07f1,
        0xd00604b6,
-       0x04bd000e,
+       0x04bd000d,
 /* 0x006c: wr32_wait */
-       0x07ace7f1,
-       0xcf06e4b6,
-       0xe4f100ee,
+       0x07acd7f1,
+       0xcf06d4b6,
+       0xd4f100dd,
        0x1bf47000,
 /* 0x007f: nsec */
        0xf000f8f2,
@@ -845,21 +912,21 @@ uint32_t nvc0_pwr_code[] = {
        0x9800f8df,
        0x96b003e9,
        0x2a0bf400,
-       0xbb840a98,
+       0xbb9a0a98,
        0x1cf4029a,
        0x01d7f00f,
        0x025421f5,
        0x0ef494bd,
 /* 0x00e9: intr_watchdog_next_time */
-       0x850a9815,
+       0x9b0a9815,
        0xf400a6b0,
        0x9ab8090b,
        0x061cf406,
 /* 0x00f8: intr_watchdog_next_time_set */
 /* 0x00fb: intr_watchdog_next_proc */
-       0x80850980,
+       0x809b0980,
        0xe0b603e9,
-       0x10e6b158,
+       0x68e6b158,
        0xc61bf402,
 /* 0x010a: intr */
        0x00f900f8,
@@ -880,15 +947,15 @@ uint32_t nvc0_pwr_code[] = {
        0x0088cf06,
        0xf40289c4,
        0x0080230b,
-       0x58e7f085,
+       0x58e7f09b,
        0x98cb21f4,
-       0x96b08509,
+       0x96b09b09,
        0x110bf400,
        0xb63407f0,
        0x09d00604,
        0x8004bd00,
 /* 0x016e: intr_skip_watchdog */
-       0x89e48409,
+       0x89e49a09,
        0x0bf40800,
        0x8897f148,
        0x0694b606,
@@ -948,7 +1015,7 @@ uint32_t nvc0_pwr_code[] = {
        0x000ed006,
        0x0e8004bd,
 /* 0x0241: timer_enable */
-       0x0187f084,
+       0x0187f09a,
        0xb63807f0,
        0x08d00604,
 /* 0x024f: timer_done */
@@ -979,7 +1046,7 @@ uint32_t nvc0_pwr_code[] = {
        0xb8008a98,
        0x0bf406ae,
        0x5880b610,
-       0x021086b1,
+       0x026886b1,
        0xf4f01bf4,
 /* 0x02b2: find_done */
        0x8eb90132,
@@ -1049,7 +1116,7 @@ uint32_t nvc0_pwr_code[] = {
        0x320bf406,
        0x94071ec4,
        0xe0b704ee,
-       0xeb980218,
+       0xeb980270,
        0x02ec9803,
        0x9801ed98,
        0x21f500ee,
@@ -1075,7 +1142,7 @@ uint32_t nvc0_pwr_code[] = {
        0xe60bf406,
        0xb60723c4,
        0x30b70434,
-       0x3b800298,
+       0x3b8002f0,
        0x023c8003,
        0x80013d80,
        0x20b6003e,
@@ -1090,13 +1157,13 @@ uint32_t nvc0_pwr_code[] = {
 /* 0x0430: host_init */
        0x008017f1,
        0xf11014b6,
-       0xf1021815,
+       0xf1027015,
        0xb604d007,
        0x01d00604,
        0xf104bd00,
        0xb6008017,
        0x15f11014,
-       0x07f10298,
+       0x07f102f0,
        0x04b604dc,
        0x0001d006,
        0x17f004bd,
@@ -1156,14 +1223,14 @@ uint32_t nvc0_pwr_code[] = {
        0x00139802,
        0x950410b6,
        0x30f01034,
-       0xc835980c,
+       0xde35980c,
        0x12b855f9,
        0xec1ef406,
        0xe0fcd0fc,
        0x02b921f5,
 /* 0x0532: memx_info */
        0xc7f100f8,
-       0xb7f10354,
+       0xb7f103ac,
        0x21f50800,
        0x00f802b9,
 /* 0x0540: memx_recv */
@@ -1175,7 +1242,312 @@ uint32_t nvc0_pwr_code[] = {
 /* 0x0550: perf_recv */
 /* 0x0552: perf_init */
        0x00f800f8,
-/* 0x0554: test_recv */
+/* 0x0554: i2c_drive_scl */
+       0xf40036b0,
+       0x07f1110b,
+       0x04b607e0,
+       0x0001d006,
+       0x00f804bd,
+/* 0x0568: i2c_drive_scl_lo */
+       0x07e407f1,
+       0xd00604b6,
+       0x04bd0001,
+/* 0x0576: i2c_drive_sda */
+       0x36b000f8,
+       0x110bf400,
+       0x07e007f1,
+       0xd00604b6,
+       0x04bd0002,
+/* 0x058a: i2c_drive_sda_lo */
+       0x07f100f8,
+       0x04b607e4,
+       0x0002d006,
+       0x00f804bd,
+/* 0x0598: i2c_sense_scl */
+       0xf10132f4,
+       0xb607c437,
+       0x33cf0634,
+       0x0431fd00,
+       0xf4060bf4,
+/* 0x05ae: i2c_sense_scl_done */
+       0x00f80131,
+/* 0x05b0: i2c_sense_sda */
+       0xf10132f4,
+       0xb607c437,
+       0x33cf0634,
+       0x0432fd00,
+       0xf4060bf4,
+/* 0x05c6: i2c_sense_sda_done */
+       0x00f80131,
+/* 0x05c8: i2c_raise_scl */
+       0x47f140f9,
+       0x37f00898,
+       0x5421f501,
+/* 0x05d5: i2c_raise_scl_wait */
+       0xe8e7f105,
+       0x7f21f403,
+       0x059821f5,
+       0xb60901f4,
+       0x1bf40142,
+/* 0x05e9: i2c_raise_scl_done */
+       0xf840fcef,
+/* 0x05ed: i2c_start */
+       0x9821f500,
+       0x0d11f405,
+       0x05b021f5,
+       0xf40611f4,
+/* 0x05fe: i2c_start_rep */
+       0x37f0300e,
+       0x5421f500,
+       0x0137f005,
+       0x057621f5,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xc821f550,
+       0x0464b605,
+/* 0x062b: i2c_start_send */
+       0xf01f11f4,
+       0x21f50037,
+       0xe7f10576,
+       0x21f41388,
+       0x0037f07f,
+       0x055421f5,
+       0x1388e7f1,
+/* 0x0647: i2c_start_out */
+       0xf87f21f4,
+/* 0x0649: i2c_stop */
+       0x0037f000,
+       0x055421f5,
+       0xf50037f0,
+       0xf1057621,
+       0xf403e8e7,
+       0x37f07f21,
+       0x5421f501,
+       0x88e7f105,
+       0x7f21f413,
+       0xf50137f0,
+       0xf1057621,
+       0xf41388e7,
+       0x00f87f21,
+/* 0x067c: i2c_bitw */
+       0x057621f5,
+       0x03e8e7f1,
+       0xbb7f21f4,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x05c821f5,
+       0xf40464b6,
+       0xe7f11811,
+       0x21f41388,
+       0x0037f07f,
+       0x055421f5,
+       0x1388e7f1,
+/* 0x06bb: i2c_bitw_out */
+       0xf87f21f4,
+/* 0x06bd: i2c_bitr */
+       0x0137f000,
+       0x057621f5,
+       0x03e8e7f1,
+       0xbb7f21f4,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x05c821f5,
+       0xf40464b6,
+       0x21f51b11,
+       0x37f005b0,
+       0x5421f500,
+       0x88e7f105,
+       0x7f21f413,
+       0xf4013cf0,
+/* 0x0702: i2c_bitr_done */
+       0x00f80131,
+/* 0x0704: i2c_get_byte */
+       0xf00057f0,
+/* 0x070a: i2c_get_byte_next */
+       0x54b60847,
+       0x0076bb01,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b606bd,
+       0x2b11f404,
+       0xb60553fd,
+       0x1bf40142,
+       0x0137f0d8,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x7c21f550,
+       0x0464b606,
+/* 0x0754: i2c_get_byte_done */
+/* 0x0756: i2c_put_byte */
+       0x47f000f8,
+/* 0x0759: i2c_put_byte_next */
+       0x0142b608,
+       0xbb3854ff,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x067c21f5,
+       0xf40464b6,
+       0x46b03411,
+       0xd81bf400,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xbd21f550,
+       0x0464b606,
+       0xbb0f11f4,
+       0x36b00076,
+       0x061bf401,
+/* 0x07af: i2c_put_byte_done */
+       0xf80132f4,
+/* 0x07b1: i2c_addr */
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b605ed,
+       0x2911f404,
+       0x012ec3e7,
+       0xfd0134b6,
+       0x76bb0553,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb6075621,
+/* 0x07f6: i2c_addr_done */
+       0x00f80464,
+/* 0x07f8: i2c_acquire_addr */
+       0xb6f8cec7,
+       0xe0b702e4,
+       0xee980bfc,
+/* 0x0807: i2c_acquire */
+       0xf500f800,
+       0xf407f821,
+       0xd9f00421,
+       0x3f21f403,
+/* 0x0816: i2c_release */
+       0x21f500f8,
+       0x21f407f8,
+       0x03daf004,
+       0xf83f21f4,
+/* 0x0825: i2c_recv */
+       0x0132f400,
+       0xb6f8c1c7,
+       0x16b00214,
+       0x3a1ff528,
+       0xd413a001,
+       0x0032980b,
+       0x0bac13a0,
+       0xf4003198,
+       0xd0f90231,
+       0xd0f9e0f9,
+       0x000067f1,
+       0x100063f1,
+       0xbb016792,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x080721f5,
+       0xfc0464b6,
+       0x00d6b0d0,
+       0x00b31bf5,
+       0xbb0057f0,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x07b121f5,
+       0xf50464b6,
+       0xc700d011,
+       0x76bbe0c5,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb6075621,
+       0x11f50464,
+       0x57f000ad,
+       0x0076bb01,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b607b1,
+       0x8a11f504,
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b60704,
+       0x6a11f404,
+       0xbbe05bcb,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x064921f5,
+       0xb90464b6,
+       0x74bd025b,
+/* 0x092b: i2c_recv_not_rd08 */
+       0xb0430ef4,
+       0x1bf401d6,
+       0x0057f03d,
+       0x07b121f5,
+       0xc73311f4,
+       0x21f5e0c5,
+       0x11f40756,
+       0x0057f029,
+       0x07b121f5,
+       0xc71f11f4,
+       0x21f5e0b5,
+       0x11f40756,
+       0x4921f515,
+       0xc774bd06,
+       0x1bf408c5,
+       0x0232f409,
+/* 0x096b: i2c_recv_not_wr08 */
+/* 0x096b: i2c_recv_done */
+       0xc7030ef4,
+       0x21f5f8ce,
+       0xe0fc0816,
+       0x12f4d0fc,
+       0x027cb90a,
+       0x02b921f5,
+/* 0x0980: i2c_recv_exit */
+/* 0x0982: i2c_init */
+       0x00f800f8,
+/* 0x0984: test_recv */
        0x05d817f1,
        0xcf0614b6,
        0x10b60011,
@@ -1185,12 +1557,12 @@ uint32_t nvc0_pwr_code[] = {
        0x00e7f104,
        0x4fe3f1d9,
        0xf521f513,
-/* 0x057b: test_init */
+/* 0x09ab: test_init */
        0xf100f801,
        0xf50800e7,
        0xf801f521,
-/* 0x0585: idle_recv */
-/* 0x0587: idle */
+/* 0x09b5: idle_recv */
+/* 0x09b7: idle */
        0xf400f800,
        0x17f10031,
        0x14b605d4,
@@ -1198,32 +1570,20 @@ uint32_t nvc0_pwr_code[] = {
        0xf10110b6,
        0xb605d407,
        0x01d00604,
-/* 0x05a3: idle_loop */
+/* 0x09d3: idle_loop */
        0xf004bd00,
        0x32f45817,
-/* 0x05a9: idle_proc */
-/* 0x05a9: idle_proc_exec */
+/* 0x09d9: idle_proc */
+/* 0x09d9: idle_proc_exec */
        0xb910f902,
        0x21f5021e,
        0x10fc02c2,
        0xf40911f4,
        0x0ef40231,
-/* 0x05bd: idle_proc_next */
+/* 0x09ed: idle_proc_next */
        0x5810b6ef,
        0xf4061fb8,
        0x02f4e61b,
        0x0028f4dd,
        0x00bb0ef4,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
 };
index 32d65ea254dd85c9b89677855d527c63d2b85654..8a89dfe41ce1ba8ddf7b808ef5534e5eefd418a9 100644 (file)
@@ -37,6 +37,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_PROC
@@ -46,6 +47,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_DATA
@@ -57,6 +59,7 @@
 #include "host.fuc"
 #include "memx.fuc"
 #include "perf.fuc"
+#include "i2c_.fuc"
 #include "test.fuc"
 #include "idle.fuc"
 #undef INCLUDE_CODE
index ce65e2a4b789b4cfef72c9ee196bc0a69c20b906..5e24c6bc041d6aefbe8de51933ed4c30e0af3fcc 100644 (file)
@@ -89,33 +89,13 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-       0x54534554,
-       0x000004eb,
-       0x000004ca,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+       0x5f433249,
+       0x000008e3,
+       0x00000786,
        0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
-       0x454c4449,
-       0x000004f7,
-       0x000004f5,
-       0x00000000,
-       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -131,14 +111,13 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+       0x54534554,
+       0x00000906,
+       0x000008e5,
        0x00000000,
        0x00000000,
-/* 0x0210: proc_list_tail */
-/* 0x0210: time_prev */
        0x00000000,
-/* 0x0214: time_next */
        0x00000000,
-/* 0x0218: fifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -154,6 +133,9 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+       0x454c4449,
+       0x00000912,
+       0x00000910,
        0x00000000,
        0x00000000,
        0x00000000,
@@ -171,11 +153,14 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0298: rfifo_queue */
        0x00000000,
        0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
        0x00000000,
+/* 0x026c: time_next */
        0x00000000,
+/* 0x0270: fifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -204,31 +189,11 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0318: memx_func_head */
-       0x00010000,
-       0x00000000,
-       0x000003f4,
-/* 0x0324: memx_func_next */
-       0x00000001,
-       0x00000000,
-       0x00000415,
-       0x00000002,
-       0x00000002,
-       0x00000430,
-       0x00040003,
-       0x00000000,
-       0x00000458,
-       0x00010004,
-       0x00000000,
-       0x00000472,
-/* 0x0354: memx_func_tail */
-/* 0x0354: memx_data_head */
-       0x00000000,
-       0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
        0x00000000,
+/* 0x02f0: rfifo_queue */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -261,10 +226,25 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+/* 0x0370: memx_func_head */
+       0x00010000,
        0x00000000,
+       0x000003f4,
+/* 0x037c: memx_func_next */
+       0x00000001,
        0x00000000,
+       0x00000415,
+       0x00000002,
+       0x00000002,
+       0x00000430,
+       0x00040003,
        0x00000000,
+       0x00000458,
+       0x00010004,
        0x00000000,
+       0x00000472,
+/* 0x03ac: memx_func_tail */
+/* 0x03ac: memx_data_head */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -735,7 +715,6 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
-/* 0x0b54: memx_data_tail */
        0x00000000,
        0x00000000,
        0x00000000,
@@ -778,6 +757,29 @@ uint32_t nvd0_pwr_data[] = {
        0x00000000,
        0x00000000,
        0x00000000,
+/* 0x0bac: memx_data_tail */
+/* 0x0bac: i2c_scl_map */
+       0x00000400,
+       0x00000800,
+       0x00001000,
+       0x00002000,
+       0x00004000,
+       0x00008000,
+       0x00010000,
+       0x00020000,
+       0x00040000,
+       0x00080000,
+/* 0x0bd4: i2c_sda_map */
+       0x00100000,
+       0x00200000,
+       0x00400000,
+       0x00800000,
+       0x01000000,
+       0x02000000,
+       0x04000000,
+       0x08000000,
+       0x10000000,
+       0x20000000,
        0x00000000,
 };
 
@@ -786,14 +788,14 @@ uint32_t nvd0_pwr_code[] = {
 /* 0x0004: rd32 */
        0x07a007f1,
        0xbd000ed0,
-       0x01e7f004,
-       0xf101e3f0,
+       0x01d7f004,
+       0xf101d3f0,
        0xd007ac07,
-       0x04bd000e,
+       0x04bd000d,
 /* 0x001c: rd32_wait */
-       0x07ace7f1,
-       0xf100eecf,
-       0xf47000e4,
+       0x07acd7f1,
+       0xf100ddcf,
+       0xf47000d4,
        0xd7f1f51b,
        0xddcf07a4,
 /* 0x0033: wr32 */
@@ -802,14 +804,14 @@ uint32_t nvd0_pwr_code[] = {
        0x04bd000e,
        0x07a407f1,
        0xbd000dd0,
-       0x02e7f004,
-       0xf0f0e5f0,
-       0x07f101e3,
-       0x0ed007ac,
+       0x02d7f004,
+       0xf0f0d5f0,
+       0x07f101d3,
+       0x0dd007ac,
 /* 0x0057: wr32_wait */
        0xf104bd00,
-       0xcf07ace7,
-       0xe4f100ee,
+       0xcf07acd7,
+       0xd4f100dd,
        0x1bf47000,
 /* 0x0067: nsec */
        0xf000f8f5,
@@ -836,21 +838,21 @@ uint32_t nvd0_pwr_code[] = {
        0x9800f8e2,
        0x96b003e9,
        0x2a0bf400,
-       0xbb840a98,
+       0xbb9a0a98,
        0x1cf4029a,
        0x01d7f00f,
        0x020621f5,
        0x0ef494bd,
 /* 0x00c5: intr_watchdog_next_time */
-       0x850a9815,
+       0x9b0a9815,
        0xf400a6b0,
        0x9ab8090b,
        0x061cf406,
 /* 0x00d4: intr_watchdog_next_time_set */
 /* 0x00d7: intr_watchdog_next_proc */
-       0x80850980,
+       0x809b0980,
        0xe0b603e9,
-       0x10e6b158,
+       0x68e6b158,
        0xc61bf402,
 /* 0x00e6: intr */
        0x00f900f8,
@@ -868,15 +870,15 @@ uint32_t nvd0_pwr_code[] = {
        0x0887f004,
        0xc40088cf,
        0x0bf40289,
-       0x85008020,
+       0x9b008020,
        0xf458e7f0,
        0x0998a721,
-       0x0096b085,
+       0x0096b09b,
        0xf00e0bf4,
        0x09d03407,
        0x8004bd00,
 /* 0x013e: intr_skip_watchdog */
-       0x89e48409,
+       0x89e49a09,
        0x0bf40800,
        0x8897f13c,
        0x0099cf06,
@@ -929,7 +931,7 @@ uint32_t nvd0_pwr_code[] = {
        0x0ed03407,
        0x8004bd00,
 /* 0x01f6: timer_enable */
-       0x87f0840e,
+       0x87f09a0e,
        0x3807f001,
        0xbd0008d0,
 /* 0x0201: timer_done */
@@ -960,7 +962,7 @@ uint32_t nvd0_pwr_code[] = {
        0x06aeb800,
        0xb6100bf4,
        0x86b15880,
-       0x1bf40210,
+       0x1bf40268,
        0x0132f4f0,
 /* 0x0264: find_done */
        0xfc028eb9,
@@ -1024,7 +1026,7 @@ uint32_t nvd0_pwr_code[] = {
        0x0bf40612,
        0x071ec42f,
        0xb704ee94,
-       0x980218e0,
+       0x980270e0,
        0xec9803eb,
        0x01ed9802,
        0xf500ee98,
@@ -1048,7 +1050,7 @@ uint32_t nvd0_pwr_code[] = {
        0xec0bf406,
        0xb60723c4,
        0x30b70434,
-       0x3b800298,
+       0x3b8002f0,
        0x023c8003,
        0x80013d80,
        0x20b6003e,
@@ -1061,12 +1063,12 @@ uint32_t nvd0_pwr_code[] = {
 /* 0x03be: host_init */
        0x17f100f8,
        0x14b60080,
-       0x1815f110,
+       0x7015f110,
        0xd007f102,
        0x0001d004,
        0x17f104bd,
        0x14b60080,
-       0x9815f110,
+       0xf015f110,
        0xdc07f102,
        0x0001d004,
        0x17f004bd,
@@ -1122,13 +1124,13 @@ uint32_t nvd0_pwr_code[] = {
        0x10b60013,
        0x10349504,
        0x980c30f0,
-       0x55f9c835,
+       0x55f9de35,
        0xf40612b8,
        0xd0fcec1e,
        0x21f5e0fc,
        0x00f8026b,
 /* 0x04a8: memx_info */
-       0x0354c7f1,
+       0x03acc7f1,
        0x0800b7f1,
        0x026b21f5,
 /* 0x04b6: memx_recv */
@@ -1140,49 +1142,342 @@ uint32_t nvd0_pwr_code[] = {
 /* 0x04c6: perf_recv */
        0x00f800f8,
 /* 0x04c8: perf_init */
-/* 0x04ca: test_recv */
-       0x17f100f8,
-       0x11cf05d8,
-       0x0110b600,
-       0x05d807f1,
+/* 0x04ca: i2c_drive_scl */
+       0x36b000f8,
+       0x0e0bf400,
+       0x07e007f1,
        0xbd0001d0,
-       0x00e7f104,
-       0x4fe3f1d9,
-       0xb621f513,
-/* 0x04eb: test_init */
-       0xf100f801,
-       0xf50800e7,
-       0xf801b621,
-/* 0x04f5: idle_recv */
-/* 0x04f7: idle */
-       0xf400f800,
-       0x17f10031,
-       0x11cf05d4,
-       0x0110b600,
-       0x05d407f1,
-       0xbd0001d0,
-/* 0x050d: idle_loop */
-       0x5817f004,
-/* 0x0513: idle_proc */
-/* 0x0513: idle_proc_exec */
-       0xf90232f4,
-       0x021eb910,
-       0x027421f5,
-       0x11f410fc,
-       0x0231f409,
-/* 0x0527: idle_proc_next */
-       0xb6ef0ef4,
-       0x1fb85810,
-       0xe61bf406,
-       0xf4dd02f4,
-       0x0ef40028,
-       0x000000c1,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000000,
+/* 0x04db: i2c_drive_scl_lo */
+       0xf100f804,
+       0xd007e407,
+       0x04bd0001,
+/* 0x04e6: i2c_drive_sda */
+       0x36b000f8,
+       0x0e0bf400,
+       0x07e007f1,
+       0xbd0002d0,
+/* 0x04f7: i2c_drive_sda_lo */
+       0xf100f804,
+       0xd007e407,
+       0x04bd0002,
+/* 0x0502: i2c_sense_scl */
+       0x32f400f8,
+       0xc437f101,
+       0x0033cf07,
+       0xf40431fd,
+       0x31f4060b,
+/* 0x0515: i2c_sense_scl_done */
+/* 0x0517: i2c_sense_sda */
+       0xf400f801,
+       0x37f10132,
+       0x33cf07c4,
+       0x0432fd00,
+       0xf4060bf4,
+/* 0x052a: i2c_sense_sda_done */
+       0x00f80131,
+/* 0x052c: i2c_raise_scl */
+       0x47f140f9,
+       0x37f00898,
+       0xca21f501,
+/* 0x0539: i2c_raise_scl_wait */
+       0xe8e7f104,
+       0x6721f403,
+       0x050221f5,
+       0xb60901f4,
+       0x1bf40142,
+/* 0x054d: i2c_raise_scl_done */
+       0xf840fcef,
+/* 0x0551: i2c_start */
+       0x0221f500,
+       0x0d11f405,
+       0x051721f5,
+       0xf40611f4,
+/* 0x0562: i2c_start_rep */
+       0x37f0300e,
+       0xca21f500,
+       0x0137f004,
+       0x04e621f5,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x2c21f550,
+       0x0464b605,
+/* 0x058f: i2c_start_send */
+       0xf01f11f4,
+       0x21f50037,
+       0xe7f104e6,
+       0x21f41388,
+       0x0037f067,
+       0x04ca21f5,
+       0x1388e7f1,
+/* 0x05ab: i2c_start_out */
+       0xf86721f4,
+/* 0x05ad: i2c_stop */
+       0x0037f000,
+       0x04ca21f5,
+       0xf50037f0,
+       0xf104e621,
+       0xf403e8e7,
+       0x37f06721,
+       0xca21f501,
+       0x88e7f104,
+       0x6721f413,
+       0xf50137f0,
+       0xf104e621,
+       0xf41388e7,
+       0x00f86721,
+/* 0x05e0: i2c_bitw */
+       0x04e621f5,
+       0x03e8e7f1,
+       0xbb6721f4,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x052c21f5,
+       0xf40464b6,
+       0xe7f11811,
+       0x21f41388,
+       0x0037f067,
+       0x04ca21f5,
+       0x1388e7f1,
+/* 0x061f: i2c_bitw_out */
+       0xf86721f4,
+/* 0x0621: i2c_bitr */
+       0x0137f000,
+       0x04e621f5,
+       0x03e8e7f1,
+       0xbb6721f4,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x052c21f5,
+       0xf40464b6,
+       0x21f51b11,
+       0x37f00517,
+       0xca21f500,
+       0x88e7f104,
+       0x6721f413,
+       0xf4013cf0,
+/* 0x0666: i2c_bitr_done */
+       0x00f80131,
+/* 0x0668: i2c_get_byte */
+       0xf00057f0,
+/* 0x066e: i2c_get_byte_next */
+       0x54b60847,
+       0x0076bb01,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b60621,
+       0x2b11f404,
+       0xb60553fd,
+       0x1bf40142,
+       0x0137f0d8,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xe021f550,
+       0x0464b605,
+/* 0x06b8: i2c_get_byte_done */
+/* 0x06ba: i2c_put_byte */
+       0x47f000f8,
+/* 0x06bd: i2c_put_byte_next */
+       0x0142b608,
+       0xbb3854ff,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x05e021f5,
+       0xf40464b6,
+       0x46b03411,
+       0xd81bf400,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x2121f550,
+       0x0464b606,
+       0xbb0f11f4,
+       0x36b00076,
+       0x061bf401,
+/* 0x0713: i2c_put_byte_done */
+       0xf80132f4,
+/* 0x0715: i2c_addr */
+       0x0076bb00,
+       0xf90465b6,
+       0x04659450,
+       0xbd0256bb,
+       0x0475fd50,
+       0x21f550fc,
+       0x64b60551,
+       0x2911f404,
+       0x012ec3e7,
+       0xfd0134b6,
+       0x76bb0553,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb606ba21,
+/* 0x075a: i2c_addr_done */
+       0x00f80464,
+/* 0x075c: i2c_acquire_addr */
+       0xb6f8cec7,
+       0xe0b705e4,
+       0x00f8d014,
+/* 0x0768: i2c_acquire */
+       0x075c21f5,
+       0xf00421f4,
+       0x21f403d9,
+/* 0x0777: i2c_release */
+       0xf500f833,
+       0xf4075c21,
+       0xdaf00421,
+       0x3321f403,
+/* 0x0786: i2c_recv */
+       0x32f400f8,
+       0xf8c1c701,
+       0xb00214b6,
+       0x1ff52816,
+       0x13a0013a,
+       0x32980bd4,
+       0xac13a000,
+       0x0031980b,
+       0xf90231f4,
+       0xf9e0f9d0,
+       0x0067f1d0,
+       0x0063f100,
+       0x01679210,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x6821f550,
+       0x0464b607,
+       0xd6b0d0fc,
+       0xb31bf500,
+       0x0057f000,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0x1521f550,
+       0x0464b607,
+       0x00d011f5,
+       0xbbe0c5c7,
+       0x65b60076,
+       0x9450f904,
+       0x56bb0465,
+       0xfd50bd02,
+       0x50fc0475,
+       0x06ba21f5,
+       0xf50464b6,
+       0xf000ad11,
+       0x76bb0157,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb6071521,
+       0x11f50464,
+       0x76bb008a,
+       0x0465b600,
+       0x659450f9,
+       0x0256bb04,
+       0x75fd50bd,
+       0xf550fc04,
+       0xb6066821,
+       0x11f40464,
+       0xe05bcb6a,
+       0xb60076bb,
+       0x50f90465,
+       0xbb046594,
+       0x50bd0256,
+       0xfc0475fd,
+       0xad21f550,
+       0x0464b605,
+       0xbd025bb9,
+       0x430ef474,
+/* 0x088c: i2c_recv_not_rd08 */
+       0xf401d6b0,
+       0x57f03d1b,
+       0x1521f500,
+       0x3311f407,
+       0xf5e0c5c7,
+       0xf406ba21,
+       0x57f02911,
+       0x1521f500,
+       0x1f11f407,
+       0xf5e0b5c7,
+       0xf406ba21,
+       0x21f51511,
+       0x74bd05ad,
+       0xf408c5c7,
+       0x32f4091b,
+       0x030ef402,
+/* 0x08cc: i2c_recv_not_wr08 */
+/* 0x08cc: i2c_recv_done */
+       0xf5f8cec7,
+       0xfc077721,
+       0xf4d0fce0,
+       0x7cb90a12,
+       0x6b21f502,
+/* 0x08e1: i2c_recv_exit */
+/* 0x08e3: i2c_init */
+       0xf800f802,
+/* 0x08e5: test_recv */
+       0xd817f100,
+       0x0011cf05,
+       0xf10110b6,
+       0xd005d807,
+       0x04bd0001,
+       0xd900e7f1,
+       0x134fe3f1,
+       0x01b621f5,
+/* 0x0906: test_init */
+       0xe7f100f8,
+       0x21f50800,
+       0x00f801b6,
+/* 0x0910: idle_recv */
+/* 0x0912: idle */
+       0x31f400f8,
+       0xd417f100,
+       0x0011cf05,
+       0xf10110b6,
+       0xd005d407,
+       0x04bd0001,
+/* 0x0928: idle_loop */
+       0xf45817f0,
+/* 0x092e: idle_proc */
+/* 0x092e: idle_proc_exec */
+       0x10f90232,
+       0xf5021eb9,
+       0xfc027421,
+       0x0911f410,
+       0xf40231f4,
+/* 0x0942: idle_proc_next */
+       0x10b6ef0e,
+       0x061fb858,
+       0xf4e61bf4,
+       0x28f4dd02,
+       0xc10ef400,
        0x00000000,
        0x00000000,
        0x00000000,
index 5fb0cccc6c64b593dbe1d2728a4011e793744f21..574acfa44c8c78f327dcd9d59cc7e1b6e9b2bc1f 100644 (file)
@@ -7,6 +7,7 @@
 #define PROC_HOST 0x54534f48
 #define PROC_MEMX 0x584d454d
 #define PROC_PERF 0x46524550
+#define PROC_I2C_ 0x5f433249
 #define PROC_TEST 0x54534554
 
 /* KERN: message identifiers */
 #define MEMX_WAIT   3
 #define MEMX_DELAY  4
 
+/* I2C_: message identifiers */
+#define I2C__MSG_RD08 0
+#define I2C__MSG_WR08 1
+
+#define I2C__MSG_DATA0_PORT 24:31
+#define I2C__MSG_DATA0_ADDR 14:23
+
+#define I2C__MSG_DATA0_RD08_PORT I2C__MSG_DATA0_PORT
+#define I2C__MSG_DATA0_RD08_ADDR I2C__MSG_DATA0_ADDR
+#define I2C__MSG_DATA0_RD08_REG 0:7
+#define I2C__MSG_DATA1_RD08_VAL 0:7
+
+#define I2C__MSG_DATA0_WR08_PORT I2C__MSG_DATA0_PORT
+#define I2C__MSG_DATA0_WR08_ADDR I2C__MSG_DATA0_ADDR
+#define I2C__MSG_DATA0_WR08_SYNC 8:8
+#define I2C__MSG_DATA0_WR08_REG 0:7
+#define I2C__MSG_DATA1_WR08_VAL 0:7
+
 #endif
index ef3133e7575c8eaf937520cf750bd51effcd7505..7dd680ff2f6f63683f34e39a1d7821f3c73c140c 100644 (file)
@@ -72,13 +72,7 @@ nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_mem *node)
        vmm->flush(vm);
 }
 
-void
-nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node)
-{
-       nouveau_vm_map_at(vma, 0, node);
-}
-
-void
+static void
 nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length,
                        struct nouveau_mem *mem)
 {
@@ -136,7 +130,7 @@ finish:
        vmm->flush(vm);
 }
 
-void
+static void
 nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length,
                  struct nouveau_mem *mem)
 {
@@ -174,6 +168,18 @@ nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length,
        vmm->flush(vm);
 }
 
+void
+nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node)
+{
+       if (node->sg)
+               nouveau_vm_map_sg_table(vma, 0, node->size << 12, node);
+       else
+       if (node->pages)
+               nouveau_vm_map_sg(vma, 0, node->size << 12, node);
+       else
+               nouveau_vm_map_at(vma, 0, node);
+}
+
 void
 nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length)
 {
index b13ff0fc42de4b2dcaf175e4a1ec3a126f04732c..2f1ed61f7c8c9e39d44c1528410eb4aaeb83fe17 100644 (file)
@@ -77,11 +77,6 @@ nv04_display_create(struct drm_device *dev)
 
        nouveau_hw_save_vga_fonts(dev, 1);
 
-       ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE, 0xd1500000,
-                                NV04_DISP_CLASS, NULL, 0, &disp->core);
-       if (ret)
-               return ret;
-
        nv04_crtc_create(dev, 0);
        if (nv_two_heads(dev))
                nv04_crtc_create(dev, 1);
index 56a28db040004fe6ecfebb6b3b69c8feda6a85f5..4245fc3dab70e5ce06964cc70296ef4e6929a9b8 100644 (file)
@@ -80,7 +80,6 @@ struct nv04_display {
        struct nv04_mode_state saved_reg;
        uint32_t saved_vga_font[4][16384];
        uint32_t dac_users[4];
-       struct nouveau_object *core;
        struct nouveau_bo *image[2];
 };
 
index 32e7064b819b6df4f9e5847beba7a826eaaed726..ab03f7719d2d3af06687ea0b1e840290094ad8dd 100644 (file)
@@ -55,9 +55,12 @@ struct nouveau_plane {
        int hue;
        int saturation;
        int iturbt_709;
+
+       void (*set_params)(struct nouveau_plane *);
 };
 
 static uint32_t formats[] = {
+       DRM_FORMAT_YUYV,
        DRM_FORMAT_UYVY,
        DRM_FORMAT_NV12,
 };
@@ -140,10 +143,10 @@ nv10_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
        nv_wr32(dev, NV_PVIDEO_POINT_OUT(flip), crtc_y << 16 | crtc_x);
        nv_wr32(dev, NV_PVIDEO_SIZE_OUT(flip), crtc_h << 16 | crtc_w);
 
-       if (fb->pixel_format == DRM_FORMAT_NV12) {
+       if (fb->pixel_format != DRM_FORMAT_UYVY)
                format |= NV_PVIDEO_FORMAT_COLOR_LE_CR8YB8CB8YA8;
+       if (fb->pixel_format == DRM_FORMAT_NV12)
                format |= NV_PVIDEO_FORMAT_PLANAR;
-       }
        if (nv_plane->iturbt_709)
                format |= NV_PVIDEO_FORMAT_MATRIX_ITURBT709;
        if (nv_plane->colorkey & (1 << 24))
@@ -182,9 +185,9 @@ nv10_disable_plane(struct drm_plane *plane)
 }
 
 static void
-nv10_destroy_plane(struct drm_plane *plane)
+nv_destroy_plane(struct drm_plane *plane)
 {
-       nv10_disable_plane(plane);
+       plane->funcs->disable_plane(plane);
        drm_plane_cleanup(plane);
        kfree(plane);
 }
@@ -217,9 +220,9 @@ nv10_set_params(struct nouveau_plane *plane)
 }
 
 static int
-nv10_set_property(struct drm_plane *plane,
-                 struct drm_property *property,
-                 uint64_t value)
+nv_set_property(struct drm_plane *plane,
+               struct drm_property *property,
+               uint64_t value)
 {
        struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
 
@@ -238,15 +241,16 @@ nv10_set_property(struct drm_plane *plane,
        else
                return -EINVAL;
 
-       nv10_set_params(nv_plane);
+       if (nv_plane->set_params)
+               nv_plane->set_params(nv_plane);
        return 0;
 }
 
 static const struct drm_plane_funcs nv10_plane_funcs = {
        .update_plane = nv10_update_plane,
        .disable_plane = nv10_disable_plane,
-       .set_property = nv10_set_property,
-       .destroy = nv10_destroy_plane,
+       .set_property = nv_set_property,
+       .destroy = nv_destroy_plane,
 };
 
 static void
@@ -266,7 +270,7 @@ nv10_overlay_init(struct drm_device *device)
        case 0x15:
        case 0x1a:
        case 0x20:
-               num_formats = 1;
+               num_formats = 2;
                break;
        }
 
@@ -321,8 +325,159 @@ nv10_overlay_init(struct drm_device *device)
        drm_object_attach_property(&plane->base.base,
                                   plane->props.iturbt_709, plane->iturbt_709);
 
+       plane->set_params = nv10_set_params;
        nv10_set_params(plane);
-       nv_wr32(dev, NV_PVIDEO_STOP, 1);
+       nv10_disable_plane(&plane->base);
+       return;
+cleanup:
+       drm_plane_cleanup(&plane->base);
+err:
+       kfree(plane);
+       nv_error(dev, "Failed to create plane\n");
+}
+
+static int
+nv04_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+                 struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+                 unsigned int crtc_w, unsigned int crtc_h,
+                 uint32_t src_x, uint32_t src_y,
+                 uint32_t src_w, uint32_t src_h)
+{
+       struct nouveau_device *dev = nouveau_dev(plane->dev);
+       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+       struct nouveau_framebuffer *nv_fb = nouveau_framebuffer(fb);
+       struct nouveau_bo *cur = nv_plane->cur;
+       uint32_t overlay = 1;
+       int brightness = (nv_plane->brightness - 512) * 62 / 512;
+       int pitch, ret, i;
+
+       /* Source parameters given in 16.16 fixed point, ignore fractional. */
+       src_x >>= 16;
+       src_y >>= 16;
+       src_w >>= 16;
+       src_h >>= 16;
+
+       pitch = ALIGN(src_w * 4, 0x100);
+
+       if (pitch > 0xffff)
+               return -ERANGE;
+
+       /* TODO: Compute an offset? Not sure how to do this for YUYV. */
+       if (src_x != 0 || src_y != 0)
+               return -ERANGE;
+
+       if (crtc_w < src_w || crtc_h < src_h)
+               return -ERANGE;
+
+       ret = nouveau_bo_pin(nv_fb->nvbo, TTM_PL_FLAG_VRAM);
+       if (ret)
+               return ret;
+
+       nv_plane->cur = nv_fb->nvbo;
+
+       nv_wr32(dev, NV_PVIDEO_OE_STATE, 0);
+       nv_wr32(dev, NV_PVIDEO_SU_STATE, 0);
+       nv_wr32(dev, NV_PVIDEO_RM_STATE, 0);
+
+       for (i = 0; i < 2; i++) {
+               nv_wr32(dev, NV_PVIDEO_BUFF0_START_ADDRESS + 4 * i,
+                       nv_fb->nvbo->bo.offset);
+               nv_wr32(dev, NV_PVIDEO_BUFF0_PITCH_LENGTH + 4 * i, pitch);
+               nv_wr32(dev, NV_PVIDEO_BUFF0_OFFSET + 4 * i, 0);
+       }
+       nv_wr32(dev, NV_PVIDEO_WINDOW_START, crtc_y << 16 | crtc_x);
+       nv_wr32(dev, NV_PVIDEO_WINDOW_SIZE, crtc_h << 16 | crtc_w);
+       nv_wr32(dev, NV_PVIDEO_STEP_SIZE,
+               (uint32_t)(((src_h - 1) << 11) / (crtc_h - 1)) << 16 | (uint32_t)(((src_w - 1) << 11) / (crtc_w - 1)));
+
+       /* It should be possible to convert hue/contrast to this */
+       nv_wr32(dev, NV_PVIDEO_RED_CSC_OFFSET, 0x69 - brightness);
+       nv_wr32(dev, NV_PVIDEO_GREEN_CSC_OFFSET, 0x3e + brightness);
+       nv_wr32(dev, NV_PVIDEO_BLUE_CSC_OFFSET, 0x89 - brightness);
+       nv_wr32(dev, NV_PVIDEO_CSC_ADJUST, 0);
+
+       nv_wr32(dev, NV_PVIDEO_CONTROL_Y, 0x001); /* (BLUR_ON, LINE_HALF) */
+       nv_wr32(dev, NV_PVIDEO_CONTROL_X, 0x111); /* (WEIGHT_HEAVY, SHARPENING_ON, SMOOTHING_ON) */
+
+       nv_wr32(dev, NV_PVIDEO_FIFO_BURST_LENGTH, 0x03);
+       nv_wr32(dev, NV_PVIDEO_FIFO_THRES_SIZE, 0x38);
+
+       nv_wr32(dev, NV_PVIDEO_KEY, nv_plane->colorkey);
+
+       if (nv_plane->colorkey & (1 << 24))
+               overlay |= 0x10;
+       if (fb->pixel_format == DRM_FORMAT_YUYV)
+               overlay |= 0x100;
+
+       nv_wr32(dev, NV_PVIDEO_OVERLAY, overlay);
+
+       nv_wr32(dev, NV_PVIDEO_SU_STATE, nv_rd32(dev, NV_PVIDEO_SU_STATE) ^ (1 << 16));
+
+       if (cur)
+               nouveau_bo_unpin(cur);
+
+       return 0;
+}
+
+static int
+nv04_disable_plane(struct drm_plane *plane)
+{
+       struct nouveau_device *dev = nouveau_dev(plane->dev);
+       struct nouveau_plane *nv_plane = (struct nouveau_plane *)plane;
+
+       nv_mask(dev, NV_PVIDEO_OVERLAY, 1, 0);
+       nv_wr32(dev, NV_PVIDEO_OE_STATE, 0);
+       nv_wr32(dev, NV_PVIDEO_SU_STATE, 0);
+       nv_wr32(dev, NV_PVIDEO_RM_STATE, 0);
+       if (nv_plane->cur) {
+               nouveau_bo_unpin(nv_plane->cur);
+               nv_plane->cur = NULL;
+       }
+
+       return 0;
+}
+
+static const struct drm_plane_funcs nv04_plane_funcs = {
+       .update_plane = nv04_update_plane,
+       .disable_plane = nv04_disable_plane,
+       .set_property = nv_set_property,
+       .destroy = nv_destroy_plane,
+};
+
+static void
+nv04_overlay_init(struct drm_device *device)
+{
+       struct nouveau_device *dev = nouveau_dev(device);
+       struct nouveau_plane *plane = kzalloc(sizeof(struct nouveau_plane), GFP_KERNEL);
+       int ret;
+
+       if (!plane)
+               return;
+
+       ret = drm_plane_init(device, &plane->base, 1 /* single crtc */,
+                            &nv04_plane_funcs,
+                            formats, 2, false);
+       if (ret)
+               goto err;
+
+       /* Set up the plane properties */
+       plane->props.colorkey = drm_property_create_range(
+                       device, 0, "colorkey", 0, 0x01ffffff);
+       plane->props.brightness = drm_property_create_range(
+                       device, 0, "brightness", 0, 1024);
+       if (!plane->props.colorkey ||
+           !plane->props.brightness)
+               goto cleanup;
+
+       plane->colorkey = 0;
+       drm_object_attach_property(&plane->base.base,
+                                  plane->props.colorkey, plane->colorkey);
+
+       plane->brightness = 512;
+       drm_object_attach_property(&plane->base.base,
+                                  plane->props.brightness, plane->brightness);
+
+       nv04_disable_plane(&plane->base);
        return;
 cleanup:
        drm_plane_cleanup(&plane->base);
@@ -335,6 +490,8 @@ void
 nouveau_overlay_init(struct drm_device *device)
 {
        struct nouveau_device *dev = nouveau_dev(device);
-       if (dev->chipset >= 0x10 && dev->chipset <= 0x40)
+       if (dev->chipset < 0x10)
+               nv04_overlay_init(device);
+       else if (dev->chipset <= 0x40)
                nv10_overlay_init(device);
 }
index 3c149617cfcbaabb49a0253fd405fe52930bc0af..4ef83df2b246fb335dc8ce05bafead80ed7ac180 100644 (file)
@@ -61,6 +61,7 @@ bool nouveau_is_v1_dsm(void) {
 #define NOUVEAU_DSM_HAS_MUX 0x1
 #define NOUVEAU_DSM_HAS_OPT 0x2
 
+#ifdef CONFIG_VGA_SWITCHEROO
 static const char nouveau_dsm_muid[] = {
        0xA0, 0xA0, 0x95, 0x9D, 0x60, 0x00, 0x48, 0x4D,
        0xB3, 0x4D, 0x7E, 0x5F, 0xEA, 0x12, 0x9F, 0xD4,
@@ -326,6 +327,11 @@ void nouveau_unregister_dsm_handler(void)
        if (nouveau_dsm_priv.optimus_detected || nouveau_dsm_priv.dsm_detected)
                vga_switcheroo_unregister_handler();
 }
+#else
+void nouveau_register_dsm_handler(void) {}
+void nouveau_unregister_dsm_handler(void) {}
+void nouveau_switcheroo_optimus_dsm(void) {}
+#endif
 
 /* retrieve the ROM in 4k blocks */
 static int nouveau_rom_call(acpi_handle rom_handle, uint8_t *bios,
index c0fde6b9393cb24fa602e838fdf145657d059d05..488686d490c0c7a96ba016e0f55a4beffcda6e4f 100644 (file)
@@ -560,28 +560,6 @@ nouveau_bo_evict_flags(struct ttm_buffer_object *bo, struct ttm_placement *pl)
 }
 
 
-/* GPU-assisted copy using NV_MEMORY_TO_MEMORY_FORMAT, can access
- * TTM_PL_{VRAM,TT} directly.
- */
-
-static int
-nouveau_bo_move_accel_cleanup(struct nouveau_channel *chan,
-                             struct nouveau_bo *nvbo, bool evict,
-                             bool no_wait_gpu, struct ttm_mem_reg *new_mem)
-{
-       struct nouveau_fence *fence = NULL;
-       int ret;
-
-       ret = nouveau_fence_new(chan, false, &fence);
-       if (ret)
-               return ret;
-
-       ret = ttm_bo_move_accel_cleanup(&nvbo->bo, fence, evict,
-                                       no_wait_gpu, new_mem);
-       nouveau_fence_unref(&fence);
-       return ret;
-}
-
 static int
 nve0_bo_move_init(struct nouveau_channel *chan, u32 handle)
 {
@@ -798,25 +776,25 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
                  struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
 {
        struct nouveau_mem *node = old_mem->mm_node;
-       struct nouveau_bo *nvbo = nouveau_bo(bo);
        u64 length = (new_mem->num_pages << PAGE_SHIFT);
        u64 src_offset = node->vma[0].offset;
        u64 dst_offset = node->vma[1].offset;
+       int src_tiled = !!node->memtype;
+       int dst_tiled = !!((struct nouveau_mem *)new_mem->mm_node)->memtype;
        int ret;
 
        while (length) {
                u32 amount, stride, height;
 
+               ret = RING_SPACE(chan, 18 + 6 * (src_tiled + dst_tiled));
+               if (ret)
+                       return ret;
+
                amount  = min(length, (u64)(4 * 1024 * 1024));
                stride  = 16 * 4;
                height  = amount / stride;
 
-               if (old_mem->mem_type == TTM_PL_VRAM &&
-                   nouveau_bo_tile_layout(nvbo)) {
-                       ret = RING_SPACE(chan, 8);
-                       if (ret)
-                               return ret;
-
+               if (src_tiled) {
                        BEGIN_NV04(chan, NvSubCopy, 0x0200, 7);
                        OUT_RING  (chan, 0);
                        OUT_RING  (chan, 0);
@@ -826,19 +804,10 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
                        OUT_RING  (chan, 0);
                        OUT_RING  (chan, 0);
                } else {
-                       ret = RING_SPACE(chan, 2);
-                       if (ret)
-                               return ret;
-
                        BEGIN_NV04(chan, NvSubCopy, 0x0200, 1);
                        OUT_RING  (chan, 1);
                }
-               if (new_mem->mem_type == TTM_PL_VRAM &&
-                   nouveau_bo_tile_layout(nvbo)) {
-                       ret = RING_SPACE(chan, 8);
-                       if (ret)
-                               return ret;
-
+               if (dst_tiled) {
                        BEGIN_NV04(chan, NvSubCopy, 0x021c, 7);
                        OUT_RING  (chan, 0);
                        OUT_RING  (chan, 0);
@@ -848,18 +817,10 @@ nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
                        OUT_RING  (chan, 0);
                        OUT_RING  (chan, 0);
                } else {
-                       ret = RING_SPACE(chan, 2);
-                       if (ret)
-                               return ret;
-
                        BEGIN_NV04(chan, NvSubCopy, 0x021c, 1);
                        OUT_RING  (chan, 1);
                }
 
-               ret = RING_SPACE(chan, 14);
-               if (ret)
-                       return ret;
-
                BEGIN_NV04(chan, NvSubCopy, 0x0238, 2);
                OUT_RING  (chan, upper_32_bits(src_offset));
                OUT_RING  (chan, upper_32_bits(dst_offset));
@@ -953,23 +914,28 @@ nv04_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
 }
 
 static int
-nouveau_vma_getmap(struct nouveau_channel *chan, struct nouveau_bo *nvbo,
-                  struct ttm_mem_reg *mem, struct nouveau_vma *vma)
+nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo,
+                    struct ttm_mem_reg *mem)
 {
-       struct nouveau_mem *node = mem->mm_node;
+       struct nouveau_mem *old_node = bo->mem.mm_node;
+       struct nouveau_mem *new_node = mem->mm_node;
+       u64 size = (u64)mem->num_pages << PAGE_SHIFT;
        int ret;
 
-       ret = nouveau_vm_get(nv_client(chan->cli)->vm, mem->num_pages <<
-                            PAGE_SHIFT, node->page_shift,
-                            NV_MEM_ACCESS_RW, vma);
+       ret = nouveau_vm_get(nv_client(drm)->vm, size, old_node->page_shift,
+                            NV_MEM_ACCESS_RW, &old_node->vma[0]);
        if (ret)
                return ret;
 
-       if (mem->mem_type == TTM_PL_VRAM)
-               nouveau_vm_map(vma, node);
-       else
-               nouveau_vm_map_sg(vma, 0, mem->num_pages << PAGE_SHIFT, node);
+       ret = nouveau_vm_get(nv_client(drm)->vm, size, new_node->page_shift,
+                            NV_MEM_ACCESS_RW, &old_node->vma[1]);
+       if (ret) {
+               nouveau_vm_put(&old_node->vma[0]);
+               return ret;
+       }
 
+       nouveau_vm_map(&old_node->vma[0], old_node);
+       nouveau_vm_map(&old_node->vma[1], new_node);
        return 0;
 }
 
@@ -979,35 +945,34 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
 {
        struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
        struct nouveau_channel *chan = drm->ttm.chan;
-       struct nouveau_bo *nvbo = nouveau_bo(bo);
-       struct ttm_mem_reg *old_mem = &bo->mem;
+       struct nouveau_fence *fence;
        int ret;
 
-       mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING);
-
        /* create temporary vmas for the transfer and attach them to the
         * old nouveau_mem node, these will get cleaned up after ttm has
         * destroyed the ttm_mem_reg
         */
        if (nv_device(drm->device)->card_type >= NV_50) {
-               struct nouveau_mem *node = old_mem->mm_node;
-
-               ret = nouveau_vma_getmap(chan, nvbo, old_mem, &node->vma[0]);
-               if (ret)
-                       goto out;
-
-               ret = nouveau_vma_getmap(chan, nvbo, new_mem, &node->vma[1]);
+               ret = nouveau_bo_move_prep(drm, bo, new_mem);
                if (ret)
-                       goto out;
+                       return ret;
        }
 
-       ret = drm->ttm.move(chan, bo, &bo->mem, new_mem);
+       mutex_lock_nested(&chan->cli->mutex, SINGLE_DEPTH_NESTING);
+       ret = nouveau_fence_sync(bo->sync_obj, chan);
        if (ret == 0) {
-               ret = nouveau_bo_move_accel_cleanup(chan, nvbo, evict,
-                                                   no_wait_gpu, new_mem);
+               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,
+                                                               evict,
+                                                               no_wait_gpu,
+                                                               new_mem);
+                               nouveau_fence_unref(&fence);
+                       }
+               }
        }
-
-out:
        mutex_unlock(&chan->cli->mutex);
        return ret;
 }
@@ -1147,19 +1112,10 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
                return;
 
        list_for_each_entry(vma, &nvbo->vma_list, head) {
-               if (new_mem && new_mem->mem_type == TTM_PL_VRAM) {
+               if (new_mem && new_mem->mem_type != TTM_PL_SYSTEM &&
+                             (new_mem->mem_type == TTM_PL_VRAM ||
+                              nvbo->page_shift != vma->vm->vmm->lpg_shift)) {
                        nouveau_vm_map(vma, new_mem->mm_node);
-               } else
-               if (new_mem && new_mem->mem_type == TTM_PL_TT &&
-                   nvbo->page_shift == vma->vm->vmm->spg_shift) {
-                       if (((struct nouveau_mem *)new_mem->mm_node)->sg)
-                               nouveau_vm_map_sg_table(vma, 0, new_mem->
-                                                 num_pages << PAGE_SHIFT,
-                                                 new_mem->mm_node);
-                       else
-                               nouveau_vm_map_sg(vma, 0, new_mem->
-                                                 num_pages << PAGE_SHIFT,
-                                                 new_mem->mm_node);
                } else {
                        nouveau_vm_unmap(vma);
                }
@@ -1224,28 +1180,27 @@ nouveau_bo_move(struct ttm_buffer_object *bo, bool evict, bool intr,
                goto out;
        }
 
-       /* CPU copy if we have no accelerated method available */
-       if (!drm->ttm.move) {
-               ret = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
-               goto out;
-       }
-
        /* Hardware assisted copy. */
-       if (new_mem->mem_type == TTM_PL_SYSTEM)
-               ret = nouveau_bo_move_flipd(bo, evict, intr,
-                                           no_wait_gpu, new_mem);
-       else if (old_mem->mem_type == TTM_PL_SYSTEM)
-               ret = nouveau_bo_move_flips(bo, evict, intr,
-                                           no_wait_gpu, new_mem);
-       else
-               ret = nouveau_bo_move_m2mf(bo, evict, intr,
-                                          no_wait_gpu, new_mem);
-
-       if (!ret)
-               goto out;
+       if (drm->ttm.move) {
+               if (new_mem->mem_type == TTM_PL_SYSTEM)
+                       ret = nouveau_bo_move_flipd(bo, evict, intr,
+                                                   no_wait_gpu, new_mem);
+               else if (old_mem->mem_type == TTM_PL_SYSTEM)
+                       ret = nouveau_bo_move_flips(bo, evict, intr,
+                                                   no_wait_gpu, new_mem);
+               else
+                       ret = nouveau_bo_move_m2mf(bo, evict, intr,
+                                                  no_wait_gpu, new_mem);
+               if (!ret)
+                       goto out;
+       }
 
        /* Fallback to software copy. */
-       ret = ttm_bo_move_memcpy(bo, evict, no_wait_gpu, new_mem);
+       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);
 
 out:
        if (nv_device(drm->device)->card_type < NV_50) {
@@ -1271,6 +1226,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
 {
        struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
        struct nouveau_drm *drm = nouveau_bdev(bdev);
+       struct nouveau_mem *node = mem->mm_node;
        struct drm_device *dev = drm->dev;
        int ret;
 
@@ -1293,14 +1249,16 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
                        mem->bus.is_iomem = !dev->agp->cant_use_aperture;
                }
 #endif
-               break;
+               if (!node->memtype)
+                       /* untiled */
+                       break;
+               /* fallthrough, tiled memory */
        case TTM_PL_VRAM:
                mem->bus.offset = mem->start << PAGE_SHIFT;
                mem->bus.base = pci_resource_start(dev->pdev, 1);
                mem->bus.is_iomem = true;
                if (nv_device(drm->device)->card_type >= NV_50) {
                        struct nouveau_bar *bar = nouveau_bar(drm->device);
-                       struct nouveau_mem *node = mem->mm_node;
 
                        ret = bar->umap(bar, node, NV_MEM_ACCESS_RW,
                                        &node->bar_vma);
@@ -1336,6 +1294,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
        struct nouveau_bo *nvbo = nouveau_bo(bo);
        struct nouveau_device *device = nv_device(drm->device);
        u32 mappable = pci_resource_len(device->pdev, 1) >> PAGE_SHIFT;
+       int ret;
 
        /* as long as the bo isn't in vram, and isn't tiled, we've got
         * nothing to do here.
@@ -1344,10 +1303,20 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
                if (nv_device(drm->device)->card_type < NV_50 ||
                    !nouveau_bo_tile_layout(nvbo))
                        return 0;
+
+               if (bo->mem.mem_type == TTM_PL_SYSTEM) {
+                       nouveau_bo_placement_set(nvbo, TTM_PL_TT, 0);
+
+                       ret = nouveau_bo_validate(nvbo, false, false);
+                       if (ret)
+                               return ret;
+               }
+               return 0;
        }
 
        /* make sure bo is in mappable vram */
-       if (bo->mem.start + bo->mem.num_pages < mappable)
+       if (nv_device(drm->device)->card_type >= NV_50 ||
+           bo->mem.start + bo->mem.num_pages < mappable)
                return 0;
 
 
@@ -1535,7 +1504,6 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm,
                   struct nouveau_vma *vma)
 {
        const u32 size = nvbo->bo.mem.num_pages << PAGE_SHIFT;
-       struct nouveau_mem *node = nvbo->bo.mem.mm_node;
        int ret;
 
        ret = nouveau_vm_get(vm, size, nvbo->page_shift,
@@ -1543,15 +1511,10 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm,
        if (ret)
                return ret;
 
-       if (nvbo->bo.mem.mem_type == TTM_PL_VRAM)
+       if ( nvbo->bo.mem.mem_type != TTM_PL_SYSTEM &&
+           (nvbo->bo.mem.mem_type == TTM_PL_VRAM ||
+            nvbo->page_shift != vma->vm->vmm->lpg_shift))
                nouveau_vm_map(vma, nvbo->bo.mem.mm_node);
-       else if (nvbo->bo.mem.mem_type == TTM_PL_TT &&
-                nvbo->page_shift == vma->vm->vmm->spg_shift) {
-               if (node->sg)
-                       nouveau_vm_map_sg_table(vma, 0, size, node);
-               else
-                       nouveau_vm_map_sg(vma, 0, size, node);
-       }
 
        list_add_tail(&vma->head, &nvbo->vma_list);
        vma->refcount = 1;
index 25ea82f8def3cb883a06aef6e9da59ea4cbffaf7..24011596af434276bbe1b9a82a26252229c20c5a 100644 (file)
@@ -68,20 +68,100 @@ nouveau_display_vblank_disable(struct drm_device *dev, int head)
                nouveau_event_put(disp->vblank[head]);
 }
 
+static inline int
+calc(int blanks, int blanke, int total, int line)
+{
+       if (blanke >= blanks) {
+               if (line >= blanks)
+                       line -= total;
+       } else {
+               if (line >= blanks)
+                       line -= total;
+               line -= blanke + 1;
+       }
+       return line;
+}
+
+int
+nouveau_display_scanoutpos_head(struct drm_crtc *crtc, int *vpos, int *hpos,
+                               ktime_t *stime, ktime_t *etime)
+{
+       const u32 mthd = NV04_DISP_SCANOUTPOS + nouveau_crtc(crtc)->index;
+       struct nouveau_display *disp = nouveau_display(crtc->dev);
+       struct nv04_display_scanoutpos args;
+       int ret, retry = 1;
+
+       do {
+               ret = nv_exec(disp->core, mthd, &args, sizeof(args));
+               if (ret != 0)
+                       return 0;
+
+               if (args.vline) {
+                       ret |= DRM_SCANOUTPOS_ACCURATE;
+                       ret |= DRM_SCANOUTPOS_VALID;
+                       break;
+               }
+
+               if (retry) ndelay(crtc->linedur_ns);
+       } while (retry--);
+
+       *hpos = calc(args.hblanks, args.hblanke, args.htotal, args.hline);
+       *vpos = calc(args.vblanks, args.vblanke, args.vtotal, args.vline);
+       if (stime) *stime = ns_to_ktime(args.time[0]);
+       if (etime) *etime = ns_to_ktime(args.time[1]);
+
+       if (*vpos < 0)
+               ret |= DRM_SCANOUTPOS_INVBL;
+       return ret;
+}
+
+int
+nouveau_display_scanoutpos(struct drm_device *dev, int head, unsigned int flags,
+                          int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
+{
+       struct drm_crtc *crtc;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (nouveau_crtc(crtc)->index == head) {
+                       return nouveau_display_scanoutpos_head(crtc, vpos, hpos,
+                                                              stime, etime);
+               }
+       }
+
+       return 0;
+}
+
+int
+nouveau_display_vblstamp(struct drm_device *dev, int head, int *max_error,
+                        struct timeval *time, unsigned flags)
+{
+       struct drm_crtc *crtc;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (nouveau_crtc(crtc)->index == head) {
+                       return drm_calc_vbltimestamp_from_scanoutpos(dev,
+                                       head, max_error, time, flags, crtc,
+                                       &crtc->hwmode);
+               }
+       }
+
+       return -EINVAL;
+}
+
 static void
 nouveau_display_vblank_fini(struct drm_device *dev)
 {
        struct nouveau_display *disp = nouveau_display(dev);
        int i;
 
+       drm_vblank_cleanup(dev);
+
        if (disp->vblank) {
                for (i = 0; i < dev->mode_config.num_crtc; i++)
                        nouveau_event_ref(NULL, &disp->vblank[i]);
                kfree(disp->vblank);
                disp->vblank = NULL;
        }
-
-       drm_vblank_cleanup(dev);
 }
 
 static int
@@ -407,10 +487,31 @@ nouveau_display_create(struct drm_device *dev)
        drm_kms_helper_poll_disable(dev);
 
        if (drm->vbios.dcb.entries) {
-               if (nv_device(drm->device)->card_type < NV_50)
-                       ret = nv04_display_create(dev);
-               else
-                       ret = nv50_display_create(dev);
+               static const u16 oclass[] = {
+                       NVF0_DISP_CLASS,
+                       NVE0_DISP_CLASS,
+                       NVD0_DISP_CLASS,
+                       NVA3_DISP_CLASS,
+                       NV94_DISP_CLASS,
+                       NVA0_DISP_CLASS,
+                       NV84_DISP_CLASS,
+                       NV50_DISP_CLASS,
+                       NV04_DISP_CLASS,
+               };
+               int i;
+
+               for (i = 0, ret = -ENODEV; ret && i < ARRAY_SIZE(oclass); i++) {
+                       ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE,
+                                                NVDRM_DISPLAY, oclass[i],
+                                                NULL, 0, &disp->core);
+               }
+
+               if (ret == 0) {
+                       if (nv_mclass(disp->core) < NV50_DISP_CLASS)
+                               ret = nv04_display_create(dev);
+                       else
+                               ret = nv50_display_create(dev);
+               }
        } else {
                ret = 0;
        }
@@ -439,6 +540,7 @@ void
 nouveau_display_destroy(struct drm_device *dev)
 {
        struct nouveau_display *disp = nouveau_display(dev);
+       struct nouveau_drm *drm = nouveau_drm(dev);
 
        nouveau_backlight_exit(dev);
        nouveau_display_vblank_fini(dev);
@@ -449,6 +551,8 @@ nouveau_display_destroy(struct drm_device *dev)
        if (disp->dtor)
                disp->dtor(dev);
 
+       nouveau_object_del(nv_object(drm), NVDRM_DEVICE, NVDRM_DISPLAY);
+
        nouveau_drm(dev)->display = NULL;
        kfree(disp);
 }
@@ -603,6 +707,14 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        if (!s)
                return -ENOMEM;
 
+       if (new_bo != old_bo) {
+               ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
+               if (ret)
+                       goto fail_free;
+       }
+
+       mutex_lock(&chan->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);
@@ -610,15 +722,8 @@ nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
        ret = nouveau_fence_sync(fence, chan);
        nouveau_fence_unref(&fence);
        if (ret)
-               goto fail_free;
-
-       if (new_bo != old_bo) {
-               ret = nouveau_bo_pin(new_bo, TTM_PL_FLAG_VRAM);
-               if (ret)
-                       goto fail_free;
-       }
+               goto fail_unpin;
 
-       mutex_lock(&chan->cli->mutex);
        ret = ttm_bo_reserve(&old_bo->bo, true, false, false, NULL);
        if (ret)
                goto fail_unpin;
index 8bc8bab90e8d34462f0b484a90710a9094247216..a71cf77e55b24eb19c48df69086cb758ab2a9db6 100644 (file)
@@ -36,6 +36,7 @@ struct nouveau_display {
        int  (*init)(struct drm_device *);
        void (*fini)(struct drm_device *);
 
+       struct nouveau_object *core;
        struct nouveau_eventh **vblank;
 
        struct drm_property *dithering_mode;
@@ -63,6 +64,10 @@ void nouveau_display_repin(struct drm_device *dev);
 void nouveau_display_resume(struct drm_device *dev);
 int  nouveau_display_vblank_enable(struct drm_device *, int);
 void nouveau_display_vblank_disable(struct drm_device *, int);
+int  nouveau_display_scanoutpos(struct drm_device *, int, unsigned int,
+                               int *, int *, ktime_t *, ktime_t *);
+int  nouveau_display_vblstamp(struct drm_device *, int, int *,
+                             struct timeval *, unsigned);
 
 int  nouveau_crtc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
                            struct drm_pending_vblank_event *event,
index 40f91e1e58422f0cdd7db3f607cde397966a7e8d..c177272152e24b7fb525891b8308668abfbeb460 100644 (file)
@@ -100,7 +100,7 @@ nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo,
 
        chan->dma.ib_put = (chan->dma.ib_put + 1) & chan->dma.ib_max;
 
-       DRM_MEMORYBARRIER();
+       mb();
        /* Flush writes. */
        nouveau_bo_rd32(pb, 0);
 
index 984004d66a6d313d1934230bc654c091a77b5f8f..dc0e0c5cadb48753d0c814f4b24586620053fb10 100644 (file)
@@ -155,7 +155,7 @@ BEGIN_IMC0(struct nouveau_channel *chan, int subc, int mthd, u16 data)
 }
 
 #define WRITE_PUT(val) do {                                                    \
-       DRM_MEMORYBARRIER();                                                   \
+       mb();                                                   \
        nouveau_bo_rd32(chan->push.buffer, 0);                                 \
        nv_wo32(chan->object, chan->user_put, ((val) << 2) + chan->push.vma.offset);  \
 } while (0)
index 98a22e6e27a11f73045fdbab161452309f2416ab..78c8e7146d56b2c5f7d189e372e542f4d9b43717 100644 (file)
@@ -503,19 +503,21 @@ nouveau_do_suspend(struct drm_device *dev)
        if (drm->cechan) {
                ret = nouveau_channel_idle(drm->cechan);
                if (ret)
-                       return ret;
+                       goto fail_display;
        }
 
        if (drm->channel) {
                ret = nouveau_channel_idle(drm->channel);
                if (ret)
-                       return ret;
+                       goto fail_display;
        }
 
        NV_INFO(drm, "suspending client object trees...\n");
        if (drm->fence && nouveau_fence(drm)->suspend) {
-               if (!nouveau_fence(drm)->suspend(drm))
-                       return -ENOMEM;
+               if (!nouveau_fence(drm)->suspend(drm)) {
+                       ret = -ENOMEM;
+                       goto fail_display;
+               }
        }
 
        list_for_each_entry(cli, &drm->clients, head) {
@@ -537,6 +539,10 @@ fail_client:
                nouveau_client_init(&cli->base);
        }
 
+       if (drm->fence && nouveau_fence(drm)->resume)
+               nouveau_fence(drm)->resume(drm);
+
+fail_display:
        if (dev->mode_config.num_crtc) {
                NV_INFO(drm, "resuming display...\n");
                nouveau_display_resume(dev);
@@ -798,6 +804,8 @@ driver = {
        .get_vblank_counter = drm_vblank_count,
        .enable_vblank = nouveau_display_vblank_enable,
        .disable_vblank = nouveau_display_vblank_disable,
+       .get_scanout_position = nouveau_display_scanoutpos,
+       .get_vblank_timestamp = nouveau_display_vblstamp,
 
        .ioctls = nouveau_ioctls,
        .num_ioctls = ARRAY_SIZE(nouveau_ioctls),
index 4b0fb6c66be918857bc6529b3a7c5a7c7a49a498..23ca7a517246feda3e7dfae782683c88c2bc64a5 100644 (file)
@@ -54,6 +54,7 @@ enum nouveau_drm_handle {
        NVDRM_CLIENT  = 0xffffffff,
        NVDRM_DEVICE  = 0xdddddddd,
        NVDRM_CONTROL = 0xdddddddc,
+       NVDRM_DISPLAY = 0xd1500000,
        NVDRM_PUSH    = 0xbbbb0000, /* |= client chid */
        NVDRM_CHAN    = 0xcccc0000, /* |= client chid */
        NVDRM_NVSW    = 0x55550000,
index 40cf52e6d6d21ffb818f70b2b01be3b5f5e02b95..90074d620e31265bdcc70d4b7285fc9be077fee8 100644 (file)
@@ -143,7 +143,7 @@ nouveau_fence_emit(struct nouveau_fence *fence, struct nouveau_channel *chan)
        int ret;
 
        fence->channel  = chan;
-       fence->timeout  = jiffies + (15 * DRM_HZ);
+       fence->timeout  = jiffies + (15 * HZ);
        fence->sequence = ++fctx->sequence;
 
        ret = fctx->emit(fence);
index 78a27f8ad7d97be653a63506bb60bd9c7b518252..27c3fd89e8ceb657595d188a8a3ff16cadde0edc 100644 (file)
@@ -463,12 +463,6 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli,
        list_for_each_entry(nvbo, list, entry) {
                struct drm_nouveau_gem_pushbuf_bo *b = &pbbo[nvbo->pbbo_index];
 
-               ret = validate_sync(chan, nvbo);
-               if (unlikely(ret)) {
-                       NV_ERROR(cli, "fail pre-validate sync\n");
-                       return ret;
-               }
-
                ret = nouveau_gem_set_domain(&nvbo->gem, b->read_domains,
                                             b->write_domains,
                                             b->valid_domains);
@@ -506,7 +500,7 @@ validate_list(struct nouveau_channel *chan, struct nouveau_cli *cli,
                        b->presumed.valid = 0;
                        relocs++;
 
-                       if (DRM_COPY_TO_USER(&upbbo[nvbo->pbbo_index].presumed,
+                       if (copy_to_user(&upbbo[nvbo->pbbo_index].presumed,
                                             &b->presumed, sizeof(b->presumed)))
                                return -EFAULT;
                }
@@ -593,7 +587,7 @@ u_memcpya(uint64_t user, unsigned nmemb, unsigned size)
        if (!mem)
                return ERR_PTR(-ENOMEM);
 
-       if (DRM_COPY_FROM_USER(mem, userptr, size)) {
+       if (copy_from_user(mem, userptr, size)) {
                u_free(mem);
                return ERR_PTR(-EFAULT);
        }
index 0843ebc910d4d6062ce94023f70dde1f1cc00ea0..a4d22e5eb176ef342023fdf0e581c564139139ed 100644 (file)
@@ -31,16 +31,17 @@ nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
 {
        struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
        struct nouveau_mem *node = mem->mm_node;
-       u64 size = mem->num_pages << 12;
 
        if (ttm->sg) {
-               node->sg = ttm->sg;
-               nouveau_vm_map_sg_table(&node->vma[0], 0, size, node);
+               node->sg    = ttm->sg;
+               node->pages = NULL;
        } else {
+               node->sg    = NULL;
                node->pages = nvbe->ttm.dma_address;
-               nouveau_vm_map_sg(&node->vma[0], 0, size, node);
        }
+       node->size = (mem->num_pages << PAGE_SHIFT) >> 12;
 
+       nouveau_vm_map(&node->vma[0], node);
        nvbe->node = node;
        return 0;
 }
@@ -67,9 +68,13 @@ nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
 
        /* noop: bound in move_notify() */
        if (ttm->sg) {
-               node->sg = ttm->sg;
-       } else
+               node->sg    = ttm->sg;
+               node->pages = NULL;
+       } else {
+               node->sg    = NULL;
                node->pages = nvbe->ttm.dma_address;
+       }
+       node->size = (mem->num_pages << PAGE_SHIFT) >> 12;
        return 0;
 }
 
index 19e3757291fba09434de033622fd4f5f6b35ea8c..d45d50da978f07870fb2bfc703ef509b4a2482f9 100644 (file)
@@ -171,6 +171,7 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
        node = kzalloc(sizeof(*node), GFP_KERNEL);
        if (!node)
                return -ENOMEM;
+
        node->page_shift = 12;
 
        switch (nv_device(drm->device)->card_type) {
index 4e384a2f99c3627ea0fc6e31f5f0e34ac95e71e8..2dccafc6e9db573814e43acff007c36c2c0da97b 100644 (file)
@@ -1035,6 +1035,7 @@ static bool
 nv50_crtc_mode_fixup(struct drm_crtc *crtc, const struct drm_display_mode *mode,
                     struct drm_display_mode *adjusted_mode)
 {
+       drm_mode_set_crtcinfo(adjusted_mode, CRTC_INTERLACE_HALVE_V);
        return true;
 }
 
@@ -2199,16 +2200,6 @@ nv50_display_destroy(struct drm_device *dev)
 int
 nv50_display_create(struct drm_device *dev)
 {
-       static const u16 oclass[] = {
-               NVF0_DISP_CLASS,
-               NVE0_DISP_CLASS,
-               NVD0_DISP_CLASS,
-               NVA3_DISP_CLASS,
-               NV94_DISP_CLASS,
-               NVA0_DISP_CLASS,
-               NV84_DISP_CLASS,
-               NV50_DISP_CLASS,
-       };
        struct nouveau_device *device = nouveau_dev(dev);
        struct nouveau_drm *drm = nouveau_drm(dev);
        struct dcb_table *dcb = &drm->vbios.dcb;
@@ -2225,6 +2216,7 @@ nv50_display_create(struct drm_device *dev)
        nouveau_display(dev)->dtor = nv50_display_destroy;
        nouveau_display(dev)->init = nv50_display_init;
        nouveau_display(dev)->fini = nv50_display_fini;
+       disp->core = nouveau_display(dev)->core;
 
        /* small shared memory area we use for notifiers and semaphores */
        ret = nouveau_bo_new(dev, 4096, 0x1000, TTM_PL_FLAG_VRAM,
@@ -2240,17 +2232,6 @@ nv50_display_create(struct drm_device *dev)
                        nouveau_bo_ref(NULL, &disp->sync);
        }
 
-       if (ret)
-               goto out;
-
-       /* attempt to allocate a supported evo display class */
-       ret = -ENODEV;
-       for (i = 0; ret && i < ARRAY_SIZE(oclass); i++) {
-               ret = nouveau_object_new(nv_object(drm), NVDRM_DEVICE,
-                                        0xd1500000, oclass[i], NULL, 0,
-                                        &disp->core);
-       }
-
        if (ret)
                goto out;
 
index 0fd2eb139f6e402cd6856d5996ee4faf6affa950..4313bb0a49a62a70039e1bd952a402e2ac54221e 100644 (file)
@@ -411,7 +411,7 @@ static void omap_crtc_error_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
        struct drm_crtc *crtc = &omap_crtc->base;
        DRM_ERROR("%s: errors: %08x\n", omap_crtc->name, irqstatus);
        /* avoid getting in a flood, unregister the irq until next vblank */
-       omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
+       __omap_irq_unregister(crtc->dev, &omap_crtc->error_irq);
 }
 
 static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
@@ -421,13 +421,13 @@ static void omap_crtc_apply_irq(struct omap_drm_irq *irq, uint32_t irqstatus)
        struct drm_crtc *crtc = &omap_crtc->base;
 
        if (!omap_crtc->error_irq.registered)
-               omap_irq_register(crtc->dev, &omap_crtc->error_irq);
+               __omap_irq_register(crtc->dev, &omap_crtc->error_irq);
 
        if (!dispc_mgr_go_busy(omap_crtc->channel)) {
                struct omap_drm_private *priv =
                                crtc->dev->dev_private;
                DBG("%s: apply done", omap_crtc->name);
-               omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
+               __omap_irq_unregister(crtc->dev, &omap_crtc->apply_irq);
                queue_work(priv->wq, &omap_crtc->apply_work);
        }
 }
@@ -623,6 +623,11 @@ void omap_crtc_pre_init(void)
        dss_install_mgr_ops(&mgr_ops);
 }
 
+void omap_crtc_pre_uninit(void)
+{
+       dss_uninstall_mgr_ops();
+}
+
 /* initialize crtc */
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
                struct drm_plane *plane, enum omap_channel channel, int id)
index c27f59da7f2935f0fe3a1908b9a73c9a4c6b7529..d4c04d69fc4df62a62352db72cd035ae6e5e53d1 100644 (file)
@@ -48,7 +48,7 @@ static int mm_show(struct seq_file *m, void *arg)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
-       return drm_mm_dump_table(m, dev->mm_private);
+       return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);
 }
 
 static int fb_show(struct seq_file *m, void *arg)
index 701c4c10e08b5858a5e083d05329af23c076669e..f926b4caf44989be904451c277049152cfc9b9ad 100644 (file)
@@ -969,12 +969,21 @@ static const struct dev_pm_ops omap_dmm_pm_ops = {
 };
 #endif
 
+#if defined(CONFIG_OF)
+static const struct of_device_id dmm_of_match[] = {
+       { .compatible = "ti,omap4-dmm", },
+       { .compatible = "ti,omap5-dmm", },
+       {},
+};
+#endif
+
 struct platform_driver omap_dmm_driver = {
        .probe = omap_dmm_probe,
        .remove = omap_dmm_remove,
        .driver = {
                .owner = THIS_MODULE,
                .name = DMM_DRIVER_NAME,
+               .of_match_table = of_match_ptr(dmm_of_match),
 #ifdef CONFIG_PM
                .pm = &omap_dmm_pm_ops,
 #endif
index e7fa3cd9674389e1cac2de91816ce6b0013b2a1b..bf39fcc49e0f181ddcbf340632fa4f77c8b1bb10 100644 (file)
@@ -86,6 +86,47 @@ static bool channel_used(struct drm_device *dev, enum omap_channel channel)
 
        return false;
 }
+static void omap_disconnect_dssdevs(void)
+{
+       struct omap_dss_device *dssdev = NULL;
+
+       for_each_dss_dev(dssdev)
+               dssdev->driver->disconnect(dssdev);
+}
+
+static int omap_connect_dssdevs(void)
+{
+       int r;
+       struct omap_dss_device *dssdev = NULL;
+       bool no_displays = true;
+
+       for_each_dss_dev(dssdev) {
+               r = dssdev->driver->connect(dssdev);
+               if (r == -EPROBE_DEFER) {
+                       omap_dss_put_device(dssdev);
+                       goto cleanup;
+               } else if (r) {
+                       dev_warn(dssdev->dev, "could not connect display: %s\n",
+                               dssdev->name);
+               } else {
+                       no_displays = false;
+               }
+       }
+
+       if (no_displays)
+               return -EPROBE_DEFER;
+
+       return 0;
+
+cleanup:
+       /*
+        * if we are deferring probe, we disconnect the devices we previously
+        * connected
+        */
+       omap_disconnect_dssdevs();
+
+       return r;
+}
 
 static int omap_modeset_init(struct drm_device *dev)
 {
@@ -95,9 +136,6 @@ static int omap_modeset_init(struct drm_device *dev)
        int num_mgrs = dss_feat_get_num_mgrs();
        int num_crtcs;
        int i, id = 0;
-       int r;
-
-       omap_crtc_pre_init();
 
        drm_mode_config_init(dev);
 
@@ -119,26 +157,8 @@ static int omap_modeset_init(struct drm_device *dev)
                enum omap_channel channel;
                struct omap_overlay_manager *mgr;
 
-               if (!dssdev->driver) {
-                       dev_warn(dev->dev, "%s has no driver.. skipping it\n",
-                                       dssdev->name);
-                       continue;
-               }
-
-               if (!(dssdev->driver->get_timings ||
-                                       dssdev->driver->read_edid)) {
-                       dev_warn(dev->dev, "%s driver does not support "
-                               "get_timings or read_edid.. skipping it!\n",
-                               dssdev->name);
-                       continue;
-               }
-
-               r = dssdev->driver->connect(dssdev);
-               if (r) {
-                       dev_err(dev->dev, "could not connect display: %s\n",
-                                       dssdev->name);
+               if (!omapdss_device_is_connected(dssdev))
                        continue;
-               }
 
                encoder = omap_encoder_init(dev, dssdev);
 
@@ -497,16 +517,16 @@ static int dev_unload(struct drm_device *dev)
        DBG("unload: dev=%p", dev);
 
        drm_kms_helper_poll_fini(dev);
-       drm_vblank_cleanup(dev);
-       omap_drm_irq_uninstall(dev);
 
        omap_fbdev_free(dev);
        omap_modeset_free(dev);
        omap_gem_deinit(dev);
 
-       flush_workqueue(priv->wq);
        destroy_workqueue(priv->wq);
 
+       drm_vblank_cleanup(dev);
+       omap_drm_irq_uninstall(dev);
+
        kfree(dev->dev_private);
        dev->dev_private = NULL;
 
@@ -655,9 +675,19 @@ static void pdev_shutdown(struct platform_device *device)
 
 static int pdev_probe(struct platform_device *device)
 {
+       int r;
+
        if (omapdss_is_initialized() == false)
                return -EPROBE_DEFER;
 
+       omap_crtc_pre_init();
+
+       r = omap_connect_dssdevs();
+       if (r) {
+               omap_crtc_pre_uninit();
+               return r;
+       }
+
        DBG("%s", device->name);
        return drm_platform_init(&omap_drm_driver, device);
 }
@@ -665,9 +695,11 @@ static int pdev_probe(struct platform_device *device)
 static int pdev_remove(struct platform_device *device)
 {
        DBG("");
-       drm_platform_exit(&omap_drm_driver, device);
 
-       platform_driver_unregister(&omap_dmm_driver);
+       omap_disconnect_dssdevs();
+       omap_crtc_pre_uninit();
+
+       drm_put_dev(platform_get_drvdata(device));
        return 0;
 }
 
index 07847693cf494caababe5780bae717ef393c8af1..428b2981fd685f3e42b3ec4d0a63021a94fdaf15 100644 (file)
@@ -141,10 +141,12 @@ int omap_gem_resume(struct device *dev);
 
 int omap_irq_enable_vblank(struct drm_device *dev, int crtc_id);
 void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id);
-irqreturn_t omap_irq_handler(DRM_IRQ_ARGS);
+irqreturn_t omap_irq_handler(int irq, void *arg);
 void omap_irq_preinstall(struct drm_device *dev);
 int omap_irq_postinstall(struct drm_device *dev);
 void omap_irq_uninstall(struct drm_device *dev);
+void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);
+void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
 void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq);
 void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq);
 int omap_drm_irq_uninstall(struct drm_device *dev);
@@ -158,6 +160,7 @@ enum omap_channel omap_crtc_channel(struct drm_crtc *crtc);
 int omap_crtc_apply(struct drm_crtc *crtc,
                struct omap_drm_apply *apply);
 void omap_crtc_pre_init(void);
+void omap_crtc_pre_uninit(void);
 struct drm_crtc *omap_crtc_init(struct drm_device *dev,
                struct drm_plane *plane, enum omap_channel channel, int id);
 
index 6a12e899235bfe480dda3fd1bf80876bc6c805aa..5290a88c681db3e6cd2d4a9e4fa32c0e50230153 100644 (file)
@@ -51,6 +51,9 @@ struct omap_dss_device *omap_encoder_get_dssdev(struct drm_encoder *encoder)
 static void omap_encoder_destroy(struct drm_encoder *encoder)
 {
        struct omap_encoder *omap_encoder = to_omap_encoder(encoder);
+
+       omap_encoder_set_enabled(encoder, false);
+
        drm_encoder_cleanup(encoder);
        kfree(omap_encoder);
 }
index f2b8f0668c0c1701887e8b6c4a8ccb3b3bf1952b..f466c4aaee9464c7ca4c16d684a4e7d4bfec5584 100644 (file)
@@ -123,12 +123,16 @@ static int omap_framebuffer_dirty(struct drm_framebuffer *fb,
 {
        int i;
 
+       drm_modeset_lock_all(fb->dev);
+
        for (i = 0; i < num_clips; i++) {
                omap_framebuffer_flush(fb, clips[i].x1, clips[i].y1,
                                        clips[i].x2 - clips[i].x1,
                                        clips[i].y2 - clips[i].y1);
        }
 
+       drm_modeset_unlock_all(fb->dev);
+
        return 0;
 }
 
index cb858600185f8051c7f92997e5e7e8ad7d8a6173..f035d2bceae7db358427c689b3a1fdd6cde28334 100644 (file)
@@ -45,12 +45,11 @@ static void omap_irq_update(struct drm_device *dev)
        dispc_read_irqenable();        /* flush posted write */
 }
 
-void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
+void __omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
 {
        struct omap_drm_private *priv = dev->dev_private;
        unsigned long flags;
 
-       dispc_runtime_get();
        spin_lock_irqsave(&list_lock, flags);
 
        if (!WARN_ON(irq->registered)) {
@@ -60,14 +59,21 @@ void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
        }
 
        spin_unlock_irqrestore(&list_lock, flags);
+}
+
+void omap_irq_register(struct drm_device *dev, struct omap_drm_irq *irq)
+{
+       dispc_runtime_get();
+
+       __omap_irq_register(dev, irq);
+
        dispc_runtime_put();
 }
 
-void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
+void __omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
 {
        unsigned long flags;
 
-       dispc_runtime_get();
        spin_lock_irqsave(&list_lock, flags);
 
        if (!WARN_ON(!irq->registered)) {
@@ -77,6 +83,14 @@ void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
        }
 
        spin_unlock_irqrestore(&list_lock, flags);
+}
+
+void omap_irq_unregister(struct drm_device *dev, struct omap_drm_irq *irq)
+{
+       dispc_runtime_get();
+
+       __omap_irq_unregister(dev, irq);
+
        dispc_runtime_put();
 }
 
@@ -173,7 +187,7 @@ void omap_irq_disable_vblank(struct drm_device *dev, int crtc_id)
        dispc_runtime_put();
 }
 
-irqreturn_t omap_irq_handler(DRM_IRQ_ARGS)
+irqreturn_t omap_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        struct omap_drm_private *priv = dev->dev_private;
@@ -308,7 +322,7 @@ int omap_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++) {
-                       DRM_WAKEUP(&dev->vblank[i].queue);
+                       wake_up(&dev->vblank[i].queue);
                        dev->vblank[i].enabled = false;
                        dev->vblank[i].last =
                                dev->driver->get_vblank_counter(dev, i);
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
new file mode 100644 (file)
index 0000000..3e0f13d
--- /dev/null
@@ -0,0 +1,19 @@
+config DRM_PANEL
+       bool
+       depends on DRM
+       help
+         Panel registration and lookup framework.
+
+menu "Display Panels"
+       depends on DRM_PANEL
+
+config DRM_PANEL_SIMPLE
+       tristate "support for simple panels"
+       depends on OF
+       help
+         DRM panel driver for dumb panels that need at most a regulator and
+         a GPIO to be powered up. Optionally a backlight can be attached so
+         that it can be automatically turned off when the panel goes into a
+         low power state.
+
+endmenu
diff --git a/drivers/gpu/drm/panel/Makefile b/drivers/gpu/drm/panel/Makefile
new file mode 100644 (file)
index 0000000..af9dfa2
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
new file mode 100644 (file)
index 0000000..59d52ca
--- /dev/null
@@ -0,0 +1,548 @@
+/*
+ * Copyright (C) 2013, NVIDIA Corporation.  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 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/backlight.h>
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+struct panel_desc {
+       const struct drm_display_mode *modes;
+       unsigned int num_modes;
+
+       struct {
+               unsigned int width;
+               unsigned int height;
+       } size;
+};
+
+/* TODO: convert to gpiod_*() API once it's been merged */
+#define GPIO_ACTIVE_LOW        (1 << 0)
+
+struct panel_simple {
+       struct drm_panel base;
+       bool enabled;
+
+       const struct panel_desc *desc;
+
+       struct backlight_device *backlight;
+       struct regulator *supply;
+       struct i2c_adapter *ddc;
+
+       unsigned long enable_gpio_flags;
+       int enable_gpio;
+};
+
+static inline struct panel_simple *to_panel_simple(struct drm_panel *panel)
+{
+       return container_of(panel, struct panel_simple, base);
+}
+
+static int panel_simple_get_fixed_modes(struct panel_simple *panel)
+{
+       struct drm_connector *connector = panel->base.connector;
+       struct drm_device *drm = panel->base.drm;
+       struct drm_display_mode *mode;
+       unsigned int i, num = 0;
+
+       if (!panel->desc)
+               return 0;
+
+       for (i = 0; i < panel->desc->num_modes; i++) {
+               const struct drm_display_mode *m = &panel->desc->modes[i];
+
+               mode = drm_mode_duplicate(drm, m);
+               if (!mode) {
+                       dev_err(drm->dev, "failed to add mode %ux%u@%u\n",
+                               m->hdisplay, m->vdisplay, m->vrefresh);
+                       continue;
+               }
+
+               drm_mode_set_name(mode);
+
+               drm_mode_probed_add(connector, mode);
+               num++;
+       }
+
+       connector->display_info.width_mm = panel->desc->size.width;
+       connector->display_info.height_mm = panel->desc->size.height;
+
+       return num;
+}
+
+static int panel_simple_disable(struct drm_panel *panel)
+{
+       struct panel_simple *p = to_panel_simple(panel);
+
+       if (!p->enabled)
+               return 0;
+
+       if (p->backlight) {
+               p->backlight->props.power = FB_BLANK_POWERDOWN;
+               backlight_update_status(p->backlight);
+       }
+
+       if (gpio_is_valid(p->enable_gpio)) {
+               if (p->enable_gpio_flags & GPIO_ACTIVE_LOW)
+                       gpio_set_value(p->enable_gpio, 1);
+               else
+                       gpio_set_value(p->enable_gpio, 0);
+       }
+
+       regulator_disable(p->supply);
+       p->enabled = false;
+
+       return 0;
+}
+
+static int panel_simple_enable(struct drm_panel *panel)
+{
+       struct panel_simple *p = to_panel_simple(panel);
+       int err;
+
+       if (p->enabled)
+               return 0;
+
+       err = regulator_enable(p->supply);
+       if (err < 0) {
+               dev_err(panel->dev, "failed to enable supply: %d\n", err);
+               return err;
+       }
+
+       if (gpio_is_valid(p->enable_gpio)) {
+               if (p->enable_gpio_flags & GPIO_ACTIVE_LOW)
+                       gpio_set_value(p->enable_gpio, 0);
+               else
+                       gpio_set_value(p->enable_gpio, 1);
+       }
+
+       if (p->backlight) {
+               p->backlight->props.power = FB_BLANK_UNBLANK;
+               backlight_update_status(p->backlight);
+       }
+
+       p->enabled = true;
+
+       return 0;
+}
+
+static int panel_simple_get_modes(struct drm_panel *panel)
+{
+       struct panel_simple *p = to_panel_simple(panel);
+       int num = 0;
+
+       /* probe EDID if a DDC bus is available */
+       if (p->ddc) {
+               struct edid *edid = drm_get_edid(panel->connector, p->ddc);
+               drm_mode_connector_update_edid_property(panel->connector, edid);
+               if (edid) {
+                       num += drm_add_edid_modes(panel->connector, edid);
+                       kfree(edid);
+               }
+       }
+
+       /* add hard-coded panel modes */
+       num += panel_simple_get_fixed_modes(p);
+
+       return num;
+}
+
+static const struct drm_panel_funcs panel_simple_funcs = {
+       .disable = panel_simple_disable,
+       .enable = panel_simple_enable,
+       .get_modes = panel_simple_get_modes,
+};
+
+static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
+{
+       struct device_node *backlight, *ddc;
+       struct panel_simple *panel;
+       enum of_gpio_flags flags;
+       int err;
+
+       panel = devm_kzalloc(dev, sizeof(*panel), GFP_KERNEL);
+       if (!panel)
+               return -ENOMEM;
+
+       panel->enabled = false;
+       panel->desc = desc;
+
+       panel->supply = devm_regulator_get(dev, "power");
+       if (IS_ERR(panel->supply))
+               return PTR_ERR(panel->supply);
+
+       panel->enable_gpio = of_get_named_gpio_flags(dev->of_node,
+                                                    "enable-gpios", 0,
+                                                    &flags);
+       if (gpio_is_valid(panel->enable_gpio)) {
+               unsigned int value;
+
+               if (flags & OF_GPIO_ACTIVE_LOW)
+                       panel->enable_gpio_flags |= GPIO_ACTIVE_LOW;
+
+               err = gpio_request(panel->enable_gpio, "enable");
+               if (err < 0) {
+                       dev_err(dev, "failed to request GPIO#%u: %d\n",
+                               panel->enable_gpio, err);
+                       return err;
+               }
+
+               value = (panel->enable_gpio_flags & GPIO_ACTIVE_LOW) != 0;
+
+               err = gpio_direction_output(panel->enable_gpio, value);
+               if (err < 0) {
+                       dev_err(dev, "failed to setup GPIO%u: %d\n",
+                               panel->enable_gpio, err);
+                       goto free_gpio;
+               }
+       }
+
+       backlight = of_parse_phandle(dev->of_node, "backlight", 0);
+       if (backlight) {
+               panel->backlight = of_find_backlight_by_node(backlight);
+               of_node_put(backlight);
+
+               if (!panel->backlight) {
+                       err = -EPROBE_DEFER;
+                       goto free_gpio;
+               }
+       }
+
+       ddc = of_parse_phandle(dev->of_node, "ddc-i2c-bus", 0);
+       if (ddc) {
+               panel->ddc = of_find_i2c_adapter_by_node(ddc);
+               of_node_put(ddc);
+
+               if (!panel->ddc) {
+                       err = -EPROBE_DEFER;
+                       goto free_backlight;
+               }
+       }
+
+       drm_panel_init(&panel->base);
+       panel->base.dev = dev;
+       panel->base.funcs = &panel_simple_funcs;
+
+       err = drm_panel_add(&panel->base);
+       if (err < 0)
+               goto free_ddc;
+
+       dev_set_drvdata(dev, panel);
+
+       return 0;
+
+free_ddc:
+       if (panel->ddc)
+               put_device(&panel->ddc->dev);
+free_backlight:
+       if (panel->backlight)
+               put_device(&panel->backlight->dev);
+free_gpio:
+       if (gpio_is_valid(panel->enable_gpio))
+               gpio_free(panel->enable_gpio);
+
+       return err;
+}
+
+static int panel_simple_remove(struct device *dev)
+{
+       struct panel_simple *panel = dev_get_drvdata(dev);
+
+       drm_panel_detach(&panel->base);
+       drm_panel_remove(&panel->base);
+
+       panel_simple_disable(&panel->base);
+
+       if (panel->ddc)
+               put_device(&panel->ddc->dev);
+
+       if (panel->backlight)
+               put_device(&panel->backlight->dev);
+
+       if (gpio_is_valid(panel->enable_gpio))
+               gpio_free(panel->enable_gpio);
+
+       regulator_disable(panel->supply);
+
+       return 0;
+}
+
+static const struct drm_display_mode auo_b101aw03_mode = {
+       .clock = 51450,
+       .hdisplay = 1024,
+       .hsync_start = 1024 + 156,
+       .hsync_end = 1024 + 156 + 8,
+       .htotal = 1024 + 156 + 8 + 156,
+       .vdisplay = 600,
+       .vsync_start = 600 + 16,
+       .vsync_end = 600 + 16 + 6,
+       .vtotal = 600 + 16 + 6 + 16,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc auo_b101aw03 = {
+       .modes = &auo_b101aw03_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 223,
+               .height = 125,
+       },
+};
+
+static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
+       .clock = 72070,
+       .hdisplay = 1366,
+       .hsync_start = 1366 + 58,
+       .hsync_end = 1366 + 58 + 58,
+       .htotal = 1366 + 58 + 58 + 58,
+       .vdisplay = 768,
+       .vsync_start = 768 + 4,
+       .vsync_end = 768 + 4 + 4,
+       .vtotal = 768 + 4 + 4 + 4,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc chunghwa_claa101wa01a = {
+       .modes = &chunghwa_claa101wa01a_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 220,
+               .height = 120,
+       },
+};
+
+static const struct drm_display_mode chunghwa_claa101wb01_mode = {
+       .clock = 69300,
+       .hdisplay = 1366,
+       .hsync_start = 1366 + 48,
+       .hsync_end = 1366 + 48 + 32,
+       .htotal = 1366 + 48 + 32 + 20,
+       .vdisplay = 768,
+       .vsync_start = 768 + 16,
+       .vsync_end = 768 + 16 + 8,
+       .vtotal = 768 + 16 + 8 + 16,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc chunghwa_claa101wb01 = {
+       .modes = &chunghwa_claa101wb01_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 223,
+               .height = 125,
+       },
+};
+
+static const struct drm_display_mode samsung_ltn101nt05_mode = {
+       .clock = 54030,
+       .hdisplay = 1024,
+       .hsync_start = 1024 + 24,
+       .hsync_end = 1024 + 24 + 136,
+       .htotal = 1024 + 24 + 136 + 160,
+       .vdisplay = 600,
+       .vsync_start = 600 + 3,
+       .vsync_end = 600 + 3 + 6,
+       .vtotal = 600 + 3 + 6 + 61,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc samsung_ltn101nt05 = {
+       .modes = &samsung_ltn101nt05_mode,
+       .num_modes = 1,
+       .size = {
+               .width = 1024,
+               .height = 600,
+       },
+};
+
+static const struct of_device_id platform_of_match[] = {
+       {
+               .compatible = "auo,b101aw03",
+               .data = &auo_b101aw03,
+       }, {
+               .compatible = "chunghwa,claa101wa01a",
+               .data = &chunghwa_claa101wa01a
+       }, {
+               .compatible = "chunghwa,claa101wb01",
+               .data = &chunghwa_claa101wb01
+       }, {
+               .compatible = "samsung,ltn101nt05",
+               .data = &samsung_ltn101nt05,
+       }, {
+               .compatible = "simple-panel",
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, platform_of_match);
+
+static int panel_simple_platform_probe(struct platform_device *pdev)
+{
+       const struct of_device_id *id;
+
+       id = of_match_node(platform_of_match, pdev->dev.of_node);
+       if (!id)
+               return -ENODEV;
+
+       return panel_simple_probe(&pdev->dev, id->data);
+}
+
+static int panel_simple_platform_remove(struct platform_device *pdev)
+{
+       return panel_simple_remove(&pdev->dev);
+}
+
+static struct platform_driver panel_simple_platform_driver = {
+       .driver = {
+               .name = "panel-simple",
+               .owner = THIS_MODULE,
+               .of_match_table = platform_of_match,
+       },
+       .probe = panel_simple_platform_probe,
+       .remove = panel_simple_platform_remove,
+};
+
+struct panel_desc_dsi {
+       struct panel_desc desc;
+
+       enum mipi_dsi_pixel_format format;
+       unsigned int lanes;
+};
+
+static const struct drm_display_mode panasonic_vvx10f004b00_mode = {
+       .clock = 157200,
+       .hdisplay = 1920,
+       .hsync_start = 1920 + 154,
+       .hsync_end = 1920 + 154 + 16,
+       .htotal = 1920 + 154 + 16 + 32,
+       .vdisplay = 1200,
+       .vsync_start = 1200 + 17,
+       .vsync_end = 1200 + 17 + 2,
+       .vtotal = 1200 + 17 + 2 + 16,
+       .vrefresh = 60,
+};
+
+static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
+       .desc = {
+               .modes = &panasonic_vvx10f004b00_mode,
+               .num_modes = 1,
+               .size = {
+                       .width = 217,
+                       .height = 136,
+               },
+       },
+       .format = MIPI_DSI_FMT_RGB888,
+       .lanes = 4,
+};
+
+static const struct of_device_id dsi_of_match[] = {
+       {
+               .compatible = "panasonic,vvx10f004b00",
+               .data = &panasonic_vvx10f004b00
+       }, {
+               /* sentinel */
+       }
+};
+MODULE_DEVICE_TABLE(of, dsi_of_match);
+
+static int panel_simple_dsi_probe(struct mipi_dsi_device *dsi)
+{
+       const struct panel_desc_dsi *desc;
+       const struct of_device_id *id;
+       int err;
+
+       id = of_match_node(dsi_of_match, dsi->dev.of_node);
+       if (!id)
+               return -ENODEV;
+
+       desc = id->data;
+
+       err = panel_simple_probe(&dsi->dev, &desc->desc);
+       if (err < 0)
+               return err;
+
+       dsi->format = desc->format;
+       dsi->lanes = desc->lanes;
+
+       return mipi_dsi_attach(dsi);
+}
+
+static int panel_simple_dsi_remove(struct mipi_dsi_device *dsi)
+{
+       int err;
+
+       err = mipi_dsi_detach(dsi);
+       if (err < 0)
+               dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
+
+       return panel_simple_remove(&dsi->dev);
+}
+
+static struct mipi_dsi_driver panel_simple_dsi_driver = {
+       .driver = {
+               .name = "panel-simple-dsi",
+               .owner = THIS_MODULE,
+               .of_match_table = dsi_of_match,
+       },
+       .probe = panel_simple_dsi_probe,
+       .remove = panel_simple_dsi_remove,
+};
+
+static int __init panel_simple_init(void)
+{
+       int err;
+
+       err = platform_driver_register(&panel_simple_platform_driver);
+       if (err < 0)
+               return err;
+
+       if (IS_ENABLED(CONFIG_DRM_MIPI_DSI)) {
+               err = mipi_dsi_driver_register(&panel_simple_dsi_driver);
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+module_init(panel_simple_init);
+
+static void __exit panel_simple_exit(void)
+{
+       if (IS_ENABLED(CONFIG_DRM_MIPI_DSI))
+               mipi_dsi_driver_unregister(&panel_simple_dsi_driver);
+
+       platform_driver_unregister(&panel_simple_platform_driver);
+}
+module_exit(panel_simple_exit);
+
+MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
+MODULE_DESCRIPTION("DRM Driver for Simple Panels");
+MODULE_LICENSE("GPL and additional rights");
index d70aafb83307d2a085afdbba6a2d4762309667ea..798bde2e5881db484fd3797013aa11a04f11c902 100644 (file)
@@ -399,10 +399,14 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
        struct qxl_bo *qobj;
        int inc = 1;
 
+       drm_modeset_lock_all(fb->dev);
+
        qobj = gem_to_qxl_bo(qxl_fb->obj);
        /* if we aren't primary surface ignore this */
-       if (!qobj->is_primary)
+       if (!qobj->is_primary) {
+               drm_modeset_unlock_all(fb->dev);
                return 0;
+       }
 
        if (!num_clips) {
                num_clips = 1;
@@ -417,6 +421,9 @@ static int qxl_framebuffer_surface_dirty(struct drm_framebuffer *fb,
 
        qxl_draw_dirty_fb(qdev, qxl_fb, qobj, flags, color,
                          clips, num_clips, inc);
+
+       drm_modeset_unlock_all(fb->dev);
+
        return 0;
 }
 
index 7bda32f68d3b50e528c21c3bba29a3b2018d1df1..36ed40ba773f8149d88eacef4c0633614e09eb83 100644 (file)
@@ -534,7 +534,7 @@ void qxl_debugfs_takedown(struct drm_minor *minor);
 
 /* qxl_irq.c */
 int qxl_irq_init(struct qxl_device *qdev);
-irqreturn_t qxl_irq_handler(DRM_IRQ_ARGS);
+irqreturn_t qxl_irq_handler(int irq, void *arg);
 
 /* qxl_fb.c */
 int qxl_fb_init(struct qxl_device *qdev);
index 7b95c75e9626ae1324dea48b310d3052f0c00d2d..0bb86e6d41b44cc4c1641e72da6e67e754994798 100644 (file)
@@ -200,7 +200,7 @@ static int qxl_process_single_command(struct qxl_device *qdev,
        for (i = 0; i < cmd->relocs_num; ++i) {
                struct drm_qxl_reloc reloc;
 
-               if (DRM_COPY_FROM_USER(&reloc,
+               if (copy_from_user(&reloc,
                                       &((struct drm_qxl_reloc *)(uintptr_t)cmd->relocs)[i],
                                       sizeof(reloc))) {
                        ret = -EFAULT;
@@ -297,7 +297,7 @@ static int qxl_execbuffer_ioctl(struct drm_device *dev, void *data,
                struct drm_qxl_command *commands =
                        (struct drm_qxl_command *)(uintptr_t)execbuffer->commands;
 
-               if (DRM_COPY_FROM_USER(&user_cmd, &commands[cmd_num],
+               if (copy_from_user(&user_cmd, &commands[cmd_num],
                                       sizeof(user_cmd)))
                        return -EFAULT;
 
index 21393dc4700a09697b7551d274b18a96ff5938ab..28f84b4fce32fab576d4bd71d324bceaf93c0682 100644 (file)
@@ -25,7 +25,7 @@
 
 #include "qxl_drv.h"
 
-irqreturn_t qxl_irq_handler(DRM_IRQ_ARGS)
+irqreturn_t qxl_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        struct qxl_device *qdev = (struct qxl_device *)dev->dev_private;
index e5ca498be920a86be9507c94858637aeb0b3c4c6..fd88eb4a3f79d1be5b5478ef04a3c77dde2dbb71 100644 (file)
@@ -115,7 +115,7 @@ static void qxl_gc_work(struct work_struct *work)
        qxl_garbage_collect(qdev);
 }
 
-int qxl_device_init(struct qxl_device *qdev,
+static int qxl_device_init(struct qxl_device *qdev,
                    struct drm_device *ddev,
                    struct pci_dev *pdev,
                    unsigned long flags)
index c451257f08fb51ea4b2c5346339237032705f955..59459fe4e8c57b9c367887daa945324ac7f4eb34 100644 (file)
@@ -892,10 +892,10 @@ static int r128_cce_get_buffers(struct drm_device *dev,
 
                buf->file_priv = file_priv;
 
-               if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
+               if (copy_to_user(&d->request_indices[i], &buf->idx,
                                     sizeof(buf->idx)))
                        return -EFAULT;
-               if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
+               if (copy_to_user(&d->request_sizes[i], &buf->total,
                                     sizeof(buf->total)))
                        return -EFAULT;
 
index 56eb5e3f54399ae9197e62cd5cfadcf094b7fb1b..5bf3f5ff805d941b74e05ab26f5119b8f154c057 100644 (file)
@@ -154,7 +154,7 @@ extern int r128_do_cleanup_cce(struct drm_device *dev);
 extern int r128_enable_vblank(struct drm_device *dev, int crtc);
 extern void r128_disable_vblank(struct drm_device *dev, int crtc);
 extern u32 r128_get_vblank_counter(struct drm_device *dev, int crtc);
-extern irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS);
+extern irqreturn_t r128_driver_irq_handler(int irq, void *arg);
 extern void r128_driver_irq_preinstall(struct drm_device *dev);
 extern int r128_driver_irq_postinstall(struct drm_device *dev);
 extern void r128_driver_irq_uninstall(struct drm_device *dev);
@@ -514,7 +514,7 @@ do {                                                                        \
        if (R128_VERBOSE)                                               \
                DRM_INFO("COMMIT_RING() tail=0x%06x\n",                 \
                         dev_priv->ring.tail);                          \
-       DRM_MEMORYBARRIER();                                            \
+       mb();                                           \
        R128_WRITE(R128_PM4_BUFFER_DL_WPTR, dev_priv->ring.tail);       \
        R128_READ(R128_PM4_BUFFER_DL_WPTR);                             \
 } while (0)
index a954c548201ece8f733a933885c3830e32de1788..b0d0fd3e437676cb306a55df7fa82cba49bcdda1 100644 (file)
@@ -33,6 +33,7 @@
 
 #include <drm/drmP.h>
 #include <drm/r128_drm.h>
+#include "r128_drv.h"
 
 typedef struct drm_r128_init32 {
        int func;
index 2ea4f09d2691d7f69f0a084677c9821f1e0afd69..c2ae496babb7374da8381c688f15883ebc533bc0 100644 (file)
@@ -44,7 +44,7 @@ u32 r128_get_vblank_counter(struct drm_device *dev, int crtc)
        return atomic_read(&dev_priv->vbl_received);
 }
 
-irqreturn_t r128_driver_irq_handler(DRM_IRQ_ARGS)
+irqreturn_t r128_driver_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        drm_r128_private_t *dev_priv = (drm_r128_private_t *) dev->dev_private;
index 01dd9aef9f0e9046116d570d52de96b3bf4a121b..e806dacd452f7b9cc8c93d20308db93ea0ef0da6 100644 (file)
@@ -895,31 +895,22 @@ static int r128_cce_dispatch_write_span(struct drm_device *dev,
        if (count > 4096 || count <= 0)
                return -EMSGSIZE;
 
-       if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x)))
+       if (copy_from_user(&x, depth->x, sizeof(x)))
                return -EFAULT;
-       if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y)))
+       if (copy_from_user(&y, depth->y, sizeof(y)))
                return -EFAULT;
 
        buffer_size = depth->n * sizeof(u32);
-       buffer = kmalloc(buffer_size, GFP_KERNEL);
-       if (buffer == NULL)
-               return -ENOMEM;
-       if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
-               kfree(buffer);
-               return -EFAULT;
-       }
+       buffer = memdup_user(depth->buffer, buffer_size);
+       if (IS_ERR(buffer))
+               return PTR_ERR(buffer);
 
        mask_size = depth->n * sizeof(u8);
        if (depth->mask) {
-               mask = kmalloc(mask_size, GFP_KERNEL);
-               if (mask == NULL) {
+               mask = memdup_user(depth->mask, mask_size);
+               if (IS_ERR(mask)) {
                        kfree(buffer);
-                       return -ENOMEM;
-               }
-               if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
-                       kfree(buffer);
-                       kfree(mask);
-                       return -EFAULT;
+                       return PTR_ERR(mask);
                }
 
                for (i = 0; i < count; i++, x++) {
@@ -999,46 +990,33 @@ static int r128_cce_dispatch_write_pixels(struct drm_device *dev,
                kfree(x);
                return -ENOMEM;
        }
-       if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
+       if (copy_from_user(x, depth->x, xbuf_size)) {
                kfree(x);
                kfree(y);
                return -EFAULT;
        }
-       if (DRM_COPY_FROM_USER(y, depth->y, xbuf_size)) {
+       if (copy_from_user(y, depth->y, xbuf_size)) {
                kfree(x);
                kfree(y);
                return -EFAULT;
        }
 
        buffer_size = depth->n * sizeof(u32);
-       buffer = kmalloc(buffer_size, GFP_KERNEL);
-       if (buffer == NULL) {
-               kfree(x);
-               kfree(y);
-               return -ENOMEM;
-       }
-       if (DRM_COPY_FROM_USER(buffer, depth->buffer, buffer_size)) {
+       buffer = memdup_user(depth->buffer, buffer_size);
+       if (IS_ERR(buffer)) {
                kfree(x);
                kfree(y);
-               kfree(buffer);
-               return -EFAULT;
+               return PTR_ERR(buffer);
        }
 
        if (depth->mask) {
                mask_size = depth->n * sizeof(u8);
-               mask = kmalloc(mask_size, GFP_KERNEL);
-               if (mask == NULL) {
-                       kfree(x);
-                       kfree(y);
-                       kfree(buffer);
-                       return -ENOMEM;
-               }
-               if (DRM_COPY_FROM_USER(mask, depth->mask, mask_size)) {
+               mask = memdup_user(depth->mask, mask_size);
+               if (IS_ERR(mask)) {
                        kfree(x);
                        kfree(y);
                        kfree(buffer);
-                       kfree(mask);
-                       return -EFAULT;
+                       return PTR_ERR(mask);
                }
 
                for (i = 0; i < count; i++) {
@@ -1107,9 +1085,9 @@ static int r128_cce_dispatch_read_span(struct drm_device *dev,
        if (count > 4096 || count <= 0)
                return -EMSGSIZE;
 
-       if (DRM_COPY_FROM_USER(&x, depth->x, sizeof(x)))
+       if (copy_from_user(&x, depth->x, sizeof(x)))
                return -EFAULT;
-       if (DRM_COPY_FROM_USER(&y, depth->y, sizeof(y)))
+       if (copy_from_user(&y, depth->y, sizeof(y)))
                return -EFAULT;
 
        BEGIN_RING(7);
@@ -1162,12 +1140,12 @@ static int r128_cce_dispatch_read_pixels(struct drm_device *dev,
                kfree(x);
                return -ENOMEM;
        }
-       if (DRM_COPY_FROM_USER(x, depth->x, xbuf_size)) {
+       if (copy_from_user(x, depth->x, xbuf_size)) {
                kfree(x);
                kfree(y);
                return -EFAULT;
        }
-       if (DRM_COPY_FROM_USER(y, depth->y, ybuf_size)) {
+       if (copy_from_user(y, depth->y, ybuf_size)) {
                kfree(x);
                kfree(y);
                return -EFAULT;
@@ -1524,7 +1502,7 @@ static int r128_cce_stipple(struct drm_device *dev, void *data, struct drm_file
 
        DEV_INIT_TEST_WITH_RETURN(dev_priv);
 
-       if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
+       if (copy_from_user(&mask, stipple->mask, 32 * sizeof(u32)))
                return -EFAULT;
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -1622,7 +1600,7 @@ static int r128_getparam(struct drm_device *dev, void *data, struct drm_file *fi
                return -EINVAL;
        }
 
-       if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
+       if (copy_to_user(param->value, &value, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
                return -EFAULT;
        }
index 0b9621c9aeea3b25da6bad8b121bfc3c3236ddcc..a9338c85630fe0548336e8c8c492361ce797dd5a 100644 (file)
@@ -209,6 +209,16 @@ static void atombios_enable_crtc_memreq(struct drm_crtc *crtc, int state)
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
 }
 
+static const u32 vga_control_regs[6] =
+{
+       AVIVO_D1VGA_CONTROL,
+       AVIVO_D2VGA_CONTROL,
+       EVERGREEN_D3VGA_CONTROL,
+       EVERGREEN_D4VGA_CONTROL,
+       EVERGREEN_D5VGA_CONTROL,
+       EVERGREEN_D6VGA_CONTROL,
+};
+
 static void atombios_blank_crtc(struct drm_crtc *crtc, int state)
 {
        struct radeon_crtc *radeon_crtc = to_radeon_crtc(crtc);
@@ -216,13 +226,23 @@ static void atombios_blank_crtc(struct drm_crtc *crtc, int state)
        struct radeon_device *rdev = dev->dev_private;
        int index = GetIndexIntoMasterTable(COMMAND, BlankCRTC);
        BLANK_CRTC_PS_ALLOCATION args;
+       u32 vga_control = 0;
 
        memset(&args, 0, sizeof(args));
 
+       if (ASIC_IS_DCE8(rdev)) {
+               vga_control = RREG32(vga_control_regs[radeon_crtc->crtc_id]);
+               WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control | 1);
+       }
+
        args.ucCRTC = radeon_crtc->crtc_id;
        args.ucBlanking = state;
 
        atom_execute_table(rdev->mode_info.atom_context, index, (uint32_t *)&args);
+
+       if (ASIC_IS_DCE8(rdev)) {
+               WREG32(vga_control_regs[radeon_crtc->crtc_id], vga_control);
+       }
 }
 
 static void atombios_powergate_crtc(struct drm_crtc *crtc, int state)
@@ -423,7 +443,17 @@ static void atombios_crtc_program_ss(struct radeon_device *rdev,
        int index = GetIndexIntoMasterTable(COMMAND, EnableSpreadSpectrumOnPPLL);
        union atom_enable_ss args;
 
-       if (!enable) {
+       if (enable) {
+               /* Don't mess with SS if percentage is 0 or external ss.
+                * SS is already disabled previously, and disabling it
+                * again can cause display problems if the pll is already
+                * programmed.
+                */
+               if (ss->percentage == 0)
+                       return;
+               if (ss->type & ATOM_EXTERNAL_SS_MASK)
+                       return;
+       } else {
                for (i = 0; i < rdev->num_crtc; i++) {
                        if (rdev->mode_info.crtcs[i] &&
                            rdev->mode_info.crtcs[i]->enabled &&
@@ -459,8 +489,6 @@ static void atombios_crtc_program_ss(struct radeon_device *rdev,
                args.v3.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
                args.v3.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                args.v3.ucEnable = enable;
-               if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE61(rdev))
-                       args.v3.ucEnable = ATOM_DISABLE;
        } else if (ASIC_IS_DCE4(rdev)) {
                args.v2.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
                args.v2.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
@@ -480,8 +508,6 @@ static void atombios_crtc_program_ss(struct radeon_device *rdev,
                args.v2.usSpreadSpectrumAmount = cpu_to_le16(ss->amount);
                args.v2.usSpreadSpectrumStep = cpu_to_le16(ss->step);
                args.v2.ucEnable = enable;
-               if ((ss->percentage == 0) || (ss->type & ATOM_EXTERNAL_SS_MASK) || ASIC_IS_DCE41(rdev))
-                       args.v2.ucEnable = ATOM_DISABLE;
        } else if (ASIC_IS_DCE3(rdev)) {
                args.v1.usSpreadSpectrumPercentage = cpu_to_le16(ss->percentage);
                args.v1.ucSpreadSpectrumType = ss->type & ATOM_SS_CENTRE_SPREAD_MODE_MASK;
@@ -503,8 +529,7 @@ static void atombios_crtc_program_ss(struct radeon_device *rdev,
                args.lvds_ss_2.ucSpreadSpectrumRange = ss->range;
                args.lvds_ss_2.ucEnable = enable;
        } else {
-               if ((enable == ATOM_DISABLE) || (ss->percentage == 0) ||
-                   (ss->type & ATOM_EXTERNAL_SS_MASK)) {
+               if (enable == ATOM_DISABLE) {
                        atombios_disable_ss(rdev, pll_id);
                        return;
                }
@@ -938,11 +963,14 @@ static bool atombios_crtc_prepare_pll(struct drm_crtc *crtc, struct drm_display_
                                                        radeon_atombios_get_ppll_ss_info(rdev,
                                                                                         &radeon_crtc->ss,
                                                                                         ATOM_DP_SS_ID1);
-                               } else
+                               } else {
                                        radeon_crtc->ss_enabled =
                                                radeon_atombios_get_ppll_ss_info(rdev,
                                                                                 &radeon_crtc->ss,
                                                                                 ATOM_DP_SS_ID1);
+                               }
+                               /* disable spread spectrum on DCE3 DP */
+                               radeon_crtc->ss_enabled = false;
                        }
                        break;
                case ATOM_ENCODER_MODE_LVDS:
@@ -1039,15 +1067,17 @@ static void atombios_crtc_set_pll(struct drm_crtc *crtc, struct drm_display_mode
                /* calculate ss amount and step size */
                if (ASIC_IS_DCE4(rdev)) {
                        u32 step_size;
-                       u32 amount = (((fb_div * 10) + frac_fb_div) * radeon_crtc->ss.percentage) / 10000;
+                       u32 amount = (((fb_div * 10) + frac_fb_div) *
+                                     (u32)radeon_crtc->ss.percentage) /
+                               (100 * (u32)radeon_crtc->ss.percentage_divider);
                        radeon_crtc->ss.amount = (amount / 10) & ATOM_PPLL_SS_AMOUNT_V2_FBDIV_MASK;
                        radeon_crtc->ss.amount |= ((amount - (amount / 10)) << ATOM_PPLL_SS_AMOUNT_V2_NFRAC_SHIFT) &
                                ATOM_PPLL_SS_AMOUNT_V2_NFRAC_MASK;
                        if (radeon_crtc->ss.type & ATOM_PPLL_SS_TYPE_V2_CENTRE_SPREAD)
-                               step_size = (4 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) /
+                               step_size = (4 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) /
                                        (125 * 25 * pll->reference_freq / 100);
                        else
-                               step_size = (2 * amount * ref_div * (radeon_crtc->ss.rate * 2048)) /
+                               step_size = (2 * amount * ref_div * ((u32)radeon_crtc->ss.rate * 2048)) /
                                        (125 * 25 * pll->reference_freq / 100);
                        radeon_crtc->ss.step = step_size;
                }
index fb3ae07a14692601a912b1cbea37ae7ff13bcc62..4ad7643fce5fe9bdb8a479727400ae173475bb37 100644 (file)
@@ -157,21 +157,22 @@ static int radeon_dp_aux_native_write(struct radeon_connector *radeon_connector,
 
        msg[0] = address;
        msg[1] = address >> 8;
-       msg[2] = AUX_NATIVE_WRITE << 4;
+       msg[2] = DP_AUX_NATIVE_WRITE << 4;
        msg[3] = (msg_bytes << 4) | (send_bytes - 1);
        memcpy(&msg[4], send, send_bytes);
 
-       for (retry = 0; retry < 4; retry++) {
+       for (retry = 0; retry < 7; retry++) {
                ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
                                            msg, msg_bytes, NULL, 0, delay, &ack);
                if (ret == -EBUSY)
                        continue;
                else if (ret < 0)
                        return ret;
-               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+               ack >>= 4;
+               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
                        return send_bytes;
-               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
-                       udelay(400);
+               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
+                       usleep_range(400, 500);
                else
                        return -EIO;
        }
@@ -191,20 +192,21 @@ static int radeon_dp_aux_native_read(struct radeon_connector *radeon_connector,
 
        msg[0] = address;
        msg[1] = address >> 8;
-       msg[2] = AUX_NATIVE_READ << 4;
+       msg[2] = DP_AUX_NATIVE_READ << 4;
        msg[3] = (msg_bytes << 4) | (recv_bytes - 1);
 
-       for (retry = 0; retry < 4; retry++) {
+       for (retry = 0; retry < 7; retry++) {
                ret = radeon_process_aux_ch(dig_connector->dp_i2c_bus,
                                            msg, msg_bytes, recv, recv_bytes, delay, &ack);
                if (ret == -EBUSY)
                        continue;
                else if (ret < 0)
                        return ret;
-               if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_ACK)
+               ack >>= 4;
+               if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_ACK)
                        return ret;
-               else if ((ack & AUX_NATIVE_REPLY_MASK) == AUX_NATIVE_REPLY_DEFER)
-                       udelay(400);
+               else if ((ack & DP_AUX_NATIVE_REPLY_MASK) == DP_AUX_NATIVE_REPLY_DEFER)
+                       usleep_range(400, 500);
                else if (ret == 0)
                        return -EPROTO;
                else
@@ -246,12 +248,12 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
 
        /* Set up the command byte */
        if (mode & MODE_I2C_READ)
-               msg[2] = AUX_I2C_READ << 4;
+               msg[2] = DP_AUX_I2C_READ << 4;
        else
-               msg[2] = AUX_I2C_WRITE << 4;
+               msg[2] = DP_AUX_I2C_WRITE << 4;
 
        if (!(mode & MODE_I2C_STOP))
-               msg[2] |= AUX_I2C_MOT << 4;
+               msg[2] |= DP_AUX_I2C_MOT << 4;
 
        msg[0] = address;
        msg[1] = address >> 8;
@@ -272,7 +274,7 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                break;
        }
 
-       for (retry = 0; retry < 4; retry++) {
+       for (retry = 0; retry < 7; retry++) {
                ret = radeon_process_aux_ch(auxch,
                                            msg, msg_bytes, reply, reply_bytes, 0, &ack);
                if (ret == -EBUSY)
@@ -282,35 +284,35 @@ int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                        return ret;
                }
 
-               switch (ack & AUX_NATIVE_REPLY_MASK) {
-               case AUX_NATIVE_REPLY_ACK:
+               switch ((ack >> 4) & DP_AUX_NATIVE_REPLY_MASK) {
+               case DP_AUX_NATIVE_REPLY_ACK:
                        /* I2C-over-AUX Reply field is only valid
                         * when paired with AUX ACK.
                         */
                        break;
-               case AUX_NATIVE_REPLY_NACK:
+               case DP_AUX_NATIVE_REPLY_NACK:
                        DRM_DEBUG_KMS("aux_ch native nack\n");
                        return -EREMOTEIO;
-               case AUX_NATIVE_REPLY_DEFER:
+               case DP_AUX_NATIVE_REPLY_DEFER:
                        DRM_DEBUG_KMS("aux_ch native defer\n");
-                       udelay(400);
+                       usleep_range(500, 600);
                        continue;
                default:
                        DRM_ERROR("aux_ch invalid native reply 0x%02x\n", ack);
                        return -EREMOTEIO;
                }
 
-               switch (ack & AUX_I2C_REPLY_MASK) {
-               case AUX_I2C_REPLY_ACK:
+               switch ((ack >> 4) & DP_AUX_I2C_REPLY_MASK) {
+               case DP_AUX_I2C_REPLY_ACK:
                        if (mode == MODE_I2C_READ)
                                *read_byte = reply[0];
                        return ret;
-               case AUX_I2C_REPLY_NACK:
+               case DP_AUX_I2C_REPLY_NACK:
                        DRM_DEBUG_KMS("aux_i2c nack\n");
                        return -EREMOTEIO;
-               case AUX_I2C_REPLY_DEFER:
+               case DP_AUX_I2C_REPLY_DEFER:
                        DRM_DEBUG_KMS("aux_i2c defer\n");
-                       udelay(400);
+                       usleep_range(400, 500);
                        break;
                default:
                        DRM_ERROR("aux_i2c invalid reply 0x%02x\n", ack);
@@ -671,9 +673,11 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
        u8 tmp;
 
        /* power up the sink */
-       if (dp_info->dpcd[0] >= 0x11)
+       if (dp_info->dpcd[0] >= 0x11) {
                radeon_write_dpcd_reg(dp_info->radeon_connector,
                                      DP_SET_POWER, DP_SET_POWER_D0);
+               usleep_range(1000, 2000);
+       }
 
        /* possibly enable downspread on the sink */
        if (dp_info->dpcd[3] & 0x1)
index f685035dbe39a7d7ad48e63a9b4ca2ea717701fe..b5162c3b6111a1845834fe1b63d3e1f17642d501 100644 (file)
@@ -27,8 +27,6 @@
 #include "radeon.h"
 #include "atom.h"
 
-extern void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);
-
 #define TARGET_HW_I2C_CLOCK 50
 
 /* these are a limitation of ProcessI2cChannelTransaction not the hw */
index 9b6950d9b3c09cc193010a50bdd521939464d539..0fbd36f3d4e9da34b65bc5f8ed302dc143b2d3c7 100644 (file)
@@ -49,6 +49,7 @@ struct rv7xx_ps *rv770_get_ps(struct radeon_ps *rps);
 struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
 struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
 
+extern int ni_mc_load_microcode(struct radeon_device *rdev);
 
 //********* BARTS **************//
 static const u32 barts_cgcg_cgls_default[] =
@@ -2510,21 +2511,6 @@ int btc_dpm_enable(struct radeon_device *rdev)
        if (eg_pi->ls_clock_gating)
                btc_ls_clock_gating_enable(rdev, true);
 
-       if (rdev->irq.installed &&
-           r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
-               PPSMC_Result result;
-
-               ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
-               if (ret)
-                       return ret;
-               rdev->irq.dpm_thermal = true;
-               radeon_irq_set(rdev);
-               result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
-
-               if (result != PPSMC_Result_OK)
-                       DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
-       }
-
        rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
 
        btc_init_stutter_mode(rdev);
@@ -2576,7 +2562,11 @@ void btc_dpm_disable(struct radeon_device *rdev)
 void btc_dpm_setup_asic(struct radeon_device *rdev)
 {
        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       int r;
 
+       r = ni_mc_load_microcode(rdev);
+       if (r)
+               DRM_ERROR("Failed to load MC firmware!\n");
        rv770_get_memory_type(rdev);
        rv740_read_clock_registers(rdev);
        btc_read_arb_registers(rdev);
index 1ed47997635803d9e69bba8b3bd0202ecbc04b0e..8d49104ca6c254efa86f4287059323be28ba3f29 100644 (file)
@@ -171,8 +171,7 @@ extern void si_trim_voltage_table_to_fit_state_table(struct radeon_device *rdev,
                                                     struct atom_voltage_table *voltage_table);
 extern void cik_enter_rlc_safe_mode(struct radeon_device *rdev);
 extern void cik_exit_rlc_safe_mode(struct radeon_device *rdev);
-extern void cik_update_cg(struct radeon_device *rdev,
-                         u32 block, bool enable);
+extern int ci_mc_load_microcode(struct radeon_device *rdev);
 
 static int ci_get_std_voltage_value_sidd(struct radeon_device *rdev,
                                         struct atom_voltage_table_entry *voltage_table,
@@ -4503,8 +4502,8 @@ static void ci_get_memory_type(struct radeon_device *rdev)
 
 }
 
-void ci_update_current_ps(struct radeon_device *rdev,
-                         struct radeon_ps *rps)
+static void ci_update_current_ps(struct radeon_device *rdev,
+                                struct radeon_ps *rps)
 {
        struct ci_ps *new_ps = ci_get_ps(rps);
        struct ci_power_info *pi = ci_get_pi(rdev);
@@ -4514,8 +4513,8 @@ void ci_update_current_ps(struct radeon_device *rdev,
        pi->current_rps.ps_priv = &pi->current_ps;
 }
 
-void ci_update_requested_ps(struct radeon_device *rdev,
-                           struct radeon_ps *rps)
+static void ci_update_requested_ps(struct radeon_device *rdev,
+                                  struct radeon_ps *rps)
 {
        struct ci_ps *new_ps = ci_get_ps(rps);
        struct ci_power_info *pi = ci_get_pi(rdev);
@@ -4549,6 +4548,11 @@ void ci_dpm_post_set_power_state(struct radeon_device *rdev)
 
 void ci_dpm_setup_asic(struct radeon_device *rdev)
 {
+       int r;
+
+       r = ci_mc_load_microcode(rdev);
+       if (r)
+               DRM_ERROR("Failed to load MC firmware!\n");
        ci_read_clock_registers(rdev);
        ci_get_memory_type(rdev);
        ci_enable_acpi_power_management(rdev);
@@ -4561,13 +4565,6 @@ int ci_dpm_enable(struct radeon_device *rdev)
        struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
        int ret;
 
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_MC |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_BIF |
-                            RADEON_CG_BLOCK_UVD |
-                            RADEON_CG_BLOCK_HDP), false);
-
        if (ci_is_smc_running(rdev))
                return -EINVAL;
        if (pi->voltage_control != CISLANDS_VOLTAGE_CONTROL_NONE) {
@@ -4665,6 +4662,18 @@ int ci_dpm_enable(struct radeon_device *rdev)
                DRM_ERROR("ci_enable_power_containment failed\n");
                return ret;
        }
+
+       ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+       ci_update_current_ps(rdev, boot_ps);
+
+       return 0;
+}
+
+int ci_dpm_late_enable(struct radeon_device *rdev)
+{
+       int ret;
+
        if (rdev->irq.installed &&
            r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
 #if 0
@@ -4685,19 +4694,8 @@ int ci_dpm_enable(struct radeon_device *rdev)
 #endif
        }
 
-       ci_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
-
        ci_dpm_powergate_uvd(rdev, true);
 
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_MC |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_BIF |
-                            RADEON_CG_BLOCK_UVD |
-                            RADEON_CG_BLOCK_HDP), true);
-
-       ci_update_current_ps(rdev, boot_ps);
-
        return 0;
 }
 
@@ -4706,12 +4704,6 @@ void ci_dpm_disable(struct radeon_device *rdev)
        struct ci_power_info *pi = ci_get_pi(rdev);
        struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_MC |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_UVD |
-                            RADEON_CG_BLOCK_HDP), false);
-
        ci_dpm_powergate_uvd(rdev, false);
 
        if (!ci_is_smc_running(rdev))
@@ -4742,13 +4734,6 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)
        struct radeon_ps *old_ps = &pi->current_rps;
        int ret;
 
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_MC |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_BIF |
-                            RADEON_CG_BLOCK_UVD |
-                            RADEON_CG_BLOCK_HDP), false);
-
        ci_find_dpm_states_clocks_in_dpm_table(rdev, new_ps);
        if (pi->pcie_performance_request)
                ci_request_link_speed_change_before_state_change(rdev, new_ps, old_ps);
@@ -4804,13 +4789,6 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)
        if (pi->pcie_performance_request)
                ci_notify_link_speed_change_after_state_change(rdev, new_ps, old_ps);
 
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_MC |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_BIF |
-                            RADEON_CG_BLOCK_UVD |
-                            RADEON_CG_BLOCK_HDP), true);
-
        return 0;
 }
 
@@ -5023,8 +5001,8 @@ static int ci_parse_power_table(struct radeon_device *rdev)
        return 0;
 }
 
-int ci_get_vbios_boot_values(struct radeon_device *rdev,
-                            struct ci_vbios_boot_state *boot_state)
+static int ci_get_vbios_boot_values(struct radeon_device *rdev,
+                                   struct ci_vbios_boot_state *boot_state)
 {
        struct radeon_mode_info *mode_info = &rdev->mode_info;
        int index = GetIndexIntoMasterTable(DATA, FirmwareInfo);
index 9c745dd22438953106715feceb974cb620c7db02..8debc9d473625d642243b5a1923b6725eb534387 100644 (file)
@@ -28,6 +28,7 @@
 #include "cikd.h"
 #include "ppsmc.h"
 #include "radeon_ucode.h"
+#include "ci_dpm.h"
 
 static int ci_set_smc_sram_address(struct radeon_device *rdev,
                                   u32 smc_address, u32 limit)
index e950fabd7f5e474ab3e60371f669e31805077785..e6419ca7cd375d6958ebcd339fb68a004c56cd1a 100644 (file)
@@ -1697,7 +1697,7 @@ static void cik_srbm_select(struct radeon_device *rdev,
  * Load the GDDR MC ucode into the hw (CIK).
  * Returns 0 on success, error on failure.
  */
-static int ci_mc_load_microcode(struct radeon_device *rdev)
+int ci_mc_load_microcode(struct radeon_device *rdev)
 {
        const __be32 *fw_data;
        u32 running, blackout = 0;
@@ -3486,6 +3486,51 @@ int cik_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
        return r;
 }
 
+/**
+ * cik_hdp_flush_cp_ring_emit - emit an hdp flush on the cp
+ *
+ * @rdev: radeon_device pointer
+ * @ridx: radeon ring index
+ *
+ * Emits an hdp flush on the cp.
+ */
+static void cik_hdp_flush_cp_ring_emit(struct radeon_device *rdev,
+                                      int ridx)
+{
+       struct radeon_ring *ring = &rdev->ring[ridx];
+       u32 ref_and_mask;
+
+       switch (ring->idx) {
+       case CAYMAN_RING_TYPE_CP1_INDEX:
+       case CAYMAN_RING_TYPE_CP2_INDEX:
+       default:
+               switch (ring->me) {
+               case 0:
+                       ref_and_mask = CP2 << ring->pipe;
+                       break;
+               case 1:
+                       ref_and_mask = CP6 << ring->pipe;
+                       break;
+               default:
+                       return;
+               }
+               break;
+       case RADEON_RING_TYPE_GFX_INDEX:
+               ref_and_mask = CP0;
+               break;
+       }
+
+       radeon_ring_write(ring, PACKET3(PACKET3_WAIT_REG_MEM, 5));
+       radeon_ring_write(ring, (WAIT_REG_MEM_OPERATION(1) | /* write, wait, write */
+                                WAIT_REG_MEM_FUNCTION(3) |  /* == */
+                                WAIT_REG_MEM_ENGINE(1)));   /* pfp */
+       radeon_ring_write(ring, GPU_HDP_FLUSH_REQ >> 2);
+       radeon_ring_write(ring, GPU_HDP_FLUSH_DONE >> 2);
+       radeon_ring_write(ring, ref_and_mask);
+       radeon_ring_write(ring, ref_and_mask);
+       radeon_ring_write(ring, 0x20); /* poll interval */
+}
+
 /**
  * cik_fence_gfx_ring_emit - emit a fence on the gfx ring
  *
@@ -3512,15 +3557,7 @@ void cik_fence_gfx_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, fence->seq);
        radeon_ring_write(ring, 0);
        /* HDP flush */
-       /* We should be using the new WAIT_REG_MEM special op packet here
-        * but it causes the CP to hang
-        */
-       radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
-       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
-                                WRITE_DATA_DST_SEL(0)));
-       radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
-       radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, 0);
+       cik_hdp_flush_cp_ring_emit(rdev, fence->ring);
 }
 
 /**
@@ -3550,15 +3587,7 @@ void cik_fence_compute_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, fence->seq);
        radeon_ring_write(ring, 0);
        /* HDP flush */
-       /* We should be using the new WAIT_REG_MEM special op packet here
-        * but it causes the CP to hang
-        */
-       radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
-       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
-                                WRITE_DATA_DST_SEL(0)));
-       radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
-       radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, 0);
+       cik_hdp_flush_cp_ring_emit(rdev, fence->ring);
 }
 
 bool cik_semaphore_ring_emit(struct radeon_device *rdev,
@@ -3566,8 +3595,6 @@ bool cik_semaphore_ring_emit(struct radeon_device *rdev,
                             struct radeon_semaphore *semaphore,
                             bool emit_wait)
 {
-/* TODO: figure out why semaphore cause lockups */
-#if 0
        uint64_t addr = semaphore->gpu_addr;
        unsigned sel = emit_wait ? PACKET3_SEM_SEL_WAIT : PACKET3_SEM_SEL_SIGNAL;
 
@@ -3576,9 +3603,6 @@ bool cik_semaphore_ring_emit(struct radeon_device *rdev,
        radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) | sel);
 
        return true;
-#else
-       return false;
-#endif
 }
 
 /**
@@ -3816,6 +3840,8 @@ static void cik_cp_gfx_enable(struct radeon_device *rdev, bool enable)
        if (enable)
                WREG32(CP_ME_CNTL, 0);
        else {
+               if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
+                       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
                WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT));
                rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
        }
@@ -4014,18 +4040,50 @@ static int cik_cp_gfx_resume(struct radeon_device *rdev)
                rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
                return r;
        }
+
+       if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+
        return 0;
 }
 
-u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
-                             struct radeon_ring *ring)
+u32 cik_gfx_get_rptr(struct radeon_device *rdev,
+                    struct radeon_ring *ring)
 {
        u32 rptr;
 
+       if (rdev->wb.enabled)
+               rptr = rdev->wb.wb[ring->rptr_offs/4];
+       else
+               rptr = RREG32(CP_RB0_RPTR);
+
+       return rptr;
+}
+
+u32 cik_gfx_get_wptr(struct radeon_device *rdev,
+                    struct radeon_ring *ring)
+{
+       u32 wptr;
+
+       wptr = RREG32(CP_RB0_WPTR);
+
+       return wptr;
+}
 
+void cik_gfx_set_wptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring)
+{
+       WREG32(CP_RB0_WPTR, ring->wptr);
+       (void)RREG32(CP_RB0_WPTR);
+}
+
+u32 cik_compute_get_rptr(struct radeon_device *rdev,
+                        struct radeon_ring *ring)
+{
+       u32 rptr;
 
        if (rdev->wb.enabled) {
-               rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
+               rptr = rdev->wb.wb[ring->rptr_offs/4];
        } else {
                mutex_lock(&rdev->srbm_mutex);
                cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
@@ -4037,13 +4095,14 @@ u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
        return rptr;
 }
 
-u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
-                             struct radeon_ring *ring)
+u32 cik_compute_get_wptr(struct radeon_device *rdev,
+                        struct radeon_ring *ring)
 {
        u32 wptr;
 
        if (rdev->wb.enabled) {
-               wptr = le32_to_cpu(rdev->wb.wb[ring->wptr_offs/4]);
+               /* XXX check if swapping is necessary on BE */
+               wptr = rdev->wb.wb[ring->wptr_offs/4];
        } else {
                mutex_lock(&rdev->srbm_mutex);
                cik_srbm_select(rdev, ring->me, ring->pipe, ring->queue, 0);
@@ -4055,10 +4114,11 @@ u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
        return wptr;
 }
 
-void cik_compute_ring_set_wptr(struct radeon_device *rdev,
-                              struct radeon_ring *ring)
+void cik_compute_set_wptr(struct radeon_device *rdev,
+                         struct radeon_ring *ring)
 {
-       rdev->wb.wb[ring->wptr_offs/4] = cpu_to_le32(ring->wptr);
+       /* XXX check if swapping is necessary on BE */
+       rdev->wb.wb[ring->wptr_offs/4] = ring->wptr;
        WDOORBELL32(ring->doorbell_index, ring->wptr);
 }
 
@@ -4852,6 +4912,160 @@ static void cik_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
        cik_print_gpu_status_regs(rdev);
 }
 
+struct kv_reset_save_regs {
+       u32 gmcon_reng_execute;
+       u32 gmcon_misc;
+       u32 gmcon_misc3;
+};
+
+static void kv_save_regs_for_reset(struct radeon_device *rdev,
+                                  struct kv_reset_save_regs *save)
+{
+       save->gmcon_reng_execute = RREG32(GMCON_RENG_EXECUTE);
+       save->gmcon_misc = RREG32(GMCON_MISC);
+       save->gmcon_misc3 = RREG32(GMCON_MISC3);
+
+       WREG32(GMCON_RENG_EXECUTE, save->gmcon_reng_execute & ~RENG_EXECUTE_ON_PWR_UP);
+       WREG32(GMCON_MISC, save->gmcon_misc & ~(RENG_EXECUTE_ON_REG_UPDATE |
+                                               STCTRL_STUTTER_EN));
+}
+
+static void kv_restore_regs_for_reset(struct radeon_device *rdev,
+                                     struct kv_reset_save_regs *save)
+{
+       int i;
+
+       WREG32(GMCON_PGFSM_WRITE, 0);
+       WREG32(GMCON_PGFSM_CONFIG, 0x200010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0);
+       WREG32(GMCON_PGFSM_CONFIG, 0x300010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0x210000);
+       WREG32(GMCON_PGFSM_CONFIG, 0xa00010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0x21003);
+       WREG32(GMCON_PGFSM_CONFIG, 0xb00010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0x2b00);
+       WREG32(GMCON_PGFSM_CONFIG, 0xc00010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0);
+       WREG32(GMCON_PGFSM_CONFIG, 0xd00010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0x420000);
+       WREG32(GMCON_PGFSM_CONFIG, 0x100010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0x120202);
+       WREG32(GMCON_PGFSM_CONFIG, 0x500010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0x3e3e36);
+       WREG32(GMCON_PGFSM_CONFIG, 0x600010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0x373f3e);
+       WREG32(GMCON_PGFSM_CONFIG, 0x700010ff);
+
+       for (i = 0; i < 5; i++)
+               WREG32(GMCON_PGFSM_WRITE, 0);
+
+       WREG32(GMCON_PGFSM_WRITE, 0x3e1332);
+       WREG32(GMCON_PGFSM_CONFIG, 0xe00010ff);
+
+       WREG32(GMCON_MISC3, save->gmcon_misc3);
+       WREG32(GMCON_MISC, save->gmcon_misc);
+       WREG32(GMCON_RENG_EXECUTE, save->gmcon_reng_execute);
+}
+
+static void cik_gpu_pci_config_reset(struct radeon_device *rdev)
+{
+       struct evergreen_mc_save save;
+       struct kv_reset_save_regs kv_save = { 0 };
+       u32 tmp, i;
+
+       dev_info(rdev->dev, "GPU pci config reset\n");
+
+       /* disable dpm? */
+
+       /* disable cg/pg */
+       cik_fini_pg(rdev);
+       cik_fini_cg(rdev);
+
+       /* Disable GFX parsing/prefetching */
+       WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+
+       /* Disable MEC parsing/prefetching */
+       WREG32(CP_MEC_CNTL, MEC_ME1_HALT | MEC_ME2_HALT);
+
+       /* sdma0 */
+       tmp = RREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET);
+       tmp |= SDMA_HALT;
+       WREG32(SDMA0_ME_CNTL + SDMA0_REGISTER_OFFSET, tmp);
+       /* sdma1 */
+       tmp = RREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET);
+       tmp |= SDMA_HALT;
+       WREG32(SDMA0_ME_CNTL + SDMA1_REGISTER_OFFSET, tmp);
+       /* XXX other engines? */
+
+       /* halt the rlc, disable cp internal ints */
+       cik_rlc_stop(rdev);
+
+       udelay(50);
+
+       /* disable mem access */
+       evergreen_mc_stop(rdev, &save);
+       if (evergreen_mc_wait_for_idle(rdev)) {
+               dev_warn(rdev->dev, "Wait for MC idle timed out !\n");
+       }
+
+       if (rdev->flags & RADEON_IS_IGP)
+               kv_save_regs_for_reset(rdev, &kv_save);
+
+       /* disable BM */
+       pci_clear_master(rdev->pdev);
+       /* reset */
+       radeon_pci_config_reset(rdev);
+
+       udelay(100);
+
+       /* wait for asic to come out of reset */
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               if (RREG32(CONFIG_MEMSIZE) != 0xffffffff)
+                       break;
+               udelay(1);
+       }
+
+       /* does asic init need to be run first??? */
+       if (rdev->flags & RADEON_IS_IGP)
+               kv_restore_regs_for_reset(rdev, &kv_save);
+}
+
 /**
  * cik_asic_reset - soft reset GPU
  *
@@ -4870,10 +5084,17 @@ int cik_asic_reset(struct radeon_device *rdev)
        if (reset_mask)
                r600_set_bios_scratch_engine_hung(rdev, true);
 
+       /* try soft reset */
        cik_gpu_soft_reset(rdev, reset_mask);
 
        reset_mask = cik_gpu_check_soft_reset(rdev);
 
+       /* try pci config reset */
+       if (reset_mask && radeon_hard_reset)
+               cik_gpu_pci_config_reset(rdev);
+
+       reset_mask = cik_gpu_check_soft_reset(rdev);
+
        if (!reset_mask)
                r600_set_bios_scratch_engine_hung(rdev, false);
 
@@ -5138,20 +5359,6 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
                                WRITE_PROTECTION_FAULT_ENABLE_INTERRUPT |
                                WRITE_PROTECTION_FAULT_ENABLE_DEFAULT);
 
-       /* TC cache setup ??? */
-       WREG32(TC_CFG_L1_LOAD_POLICY0, 0);
-       WREG32(TC_CFG_L1_LOAD_POLICY1, 0);
-       WREG32(TC_CFG_L1_STORE_POLICY, 0);
-
-       WREG32(TC_CFG_L2_LOAD_POLICY0, 0);
-       WREG32(TC_CFG_L2_LOAD_POLICY1, 0);
-       WREG32(TC_CFG_L2_STORE_POLICY0, 0);
-       WREG32(TC_CFG_L2_STORE_POLICY1, 0);
-       WREG32(TC_CFG_L2_ATOMIC_POLICY, 0);
-
-       WREG32(TC_CFG_L1_VOLATILE, 0);
-       WREG32(TC_CFG_L2_VOLATILE, 0);
-
        if (rdev->family == CHIP_KAVERI) {
                u32 tmp = RREG32(CHUB_CONTROL);
                tmp &= ~BYPASS_VM;
@@ -5367,16 +5574,7 @@ void cik_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm)
        radeon_ring_write(ring, VMID(0));
 
        /* HDP flush */
-       /* We should be using the WAIT_REG_MEM packet here like in
-        * cik_fence_ring_emit(), but it causes the CP to hang in this
-        * context...
-        */
-       radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
-       radeon_ring_write(ring, (WRITE_DATA_ENGINE_SEL(0) |
-                                WRITE_DATA_DST_SEL(0)));
-       radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
-       radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, 0);
+       cik_hdp_flush_cp_ring_emit(rdev, ridx);
 
        /* bits 0-15 are the VM contexts0-15 */
        radeon_ring_write(ring, PACKET3(PACKET3_WRITE_DATA, 3));
@@ -7503,26 +7701,7 @@ static int cik_startup(struct radeon_device *rdev)
 
        cik_mc_program(rdev);
 
-       if (rdev->flags & RADEON_IS_IGP) {
-               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
-                   !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
-                       r = cik_init_microcode(rdev);
-                       if (r) {
-                               DRM_ERROR("Failed to load firmware!\n");
-                               return r;
-                       }
-               }
-       } else {
-               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
-                   !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw ||
-                   !rdev->mc_fw) {
-                       r = cik_init_microcode(rdev);
-                       if (r) {
-                               DRM_ERROR("Failed to load firmware!\n");
-                               return r;
-                       }
-               }
-
+       if (!(rdev->flags & RADEON_IS_IGP) && !rdev->pm.dpm_enabled) {
                r = ci_mc_load_microcode(rdev);
                if (r) {
                        DRM_ERROR("Failed to load MC firmware!\n");
@@ -7627,7 +7806,6 @@ static int cik_startup(struct radeon_device *rdev)
 
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
-                            CP_RB0_RPTR, CP_RB0_WPTR,
                             PACKET3(PACKET3_NOP, 0x3FFF));
        if (r)
                return r;
@@ -7636,7 +7814,6 @@ static int cik_startup(struct radeon_device *rdev)
        /* type-2 packets are deprecated on MEC, use type-3 instead */
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
-                            CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
                             PACKET3(PACKET3_NOP, 0x3FFF));
        if (r)
                return r;
@@ -7648,7 +7825,6 @@ static int cik_startup(struct radeon_device *rdev)
        /* type-2 packets are deprecated on MEC, use type-3 instead */
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
-                            CP_HQD_PQ_RPTR, CP_HQD_PQ_WPTR,
                             PACKET3(PACKET3_NOP, 0x3FFF));
        if (r)
                return r;
@@ -7660,16 +7836,12 @@ static int cik_startup(struct radeon_device *rdev)
 
        ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
-                            SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET,
-                            SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET,
                             SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
        if (r)
                return r;
 
        ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
-                            SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET,
-                            SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET,
                             SDMA_PACKET(SDMA_OPCODE_NOP, 0, 0));
        if (r)
                return r;
@@ -7685,7 +7857,6 @@ static int cik_startup(struct radeon_device *rdev)
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
        if (ring->ring_size) {
                r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-                                    UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                     RADEON_CP_PACKET2);
                if (!r)
                        r = uvd_v1_0_init(rdev);
@@ -7731,6 +7902,8 @@ int cik_resume(struct radeon_device *rdev)
        /* init golden registers */
        cik_init_golden_registers(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = cik_startup(rdev);
        if (r) {
@@ -7754,6 +7927,7 @@ int cik_resume(struct radeon_device *rdev)
  */
 int cik_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        dce6_audio_fini(rdev);
        radeon_vm_manager_fini(rdev);
        cik_cp_enable(rdev, false);
@@ -7835,6 +8009,30 @@ int cik_init(struct radeon_device *rdev)
        if (r)
                return r;
 
+       if (rdev->flags & RADEON_IS_IGP) {
+               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+                   !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw) {
+                       r = cik_init_microcode(rdev);
+                       if (r) {
+                               DRM_ERROR("Failed to load firmware!\n");
+                               return r;
+                       }
+               }
+       } else {
+               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+                   !rdev->mec_fw || !rdev->sdma_fw || !rdev->rlc_fw ||
+                   !rdev->mc_fw) {
+                       r = cik_init_microcode(rdev);
+                       if (r) {
+                               DRM_ERROR("Failed to load firmware!\n");
+                               return r;
+                       }
+               }
+       }
+
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        ring->ring_obj = NULL;
        r600_ring_init(rdev, ring, 1024 * 1024);
@@ -7915,6 +8113,7 @@ int cik_init(struct radeon_device *rdev)
  */
 void cik_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        cik_cp_fini(rdev);
        cik_sdma_fini(rdev);
        cik_fini_pg(rdev);
index d08b83c6267b4cde4ff5ce0ad71754c1e5e446a1..1ecb3f1070e35c6ed3516e5f325eeeb61bc795b2 100644 (file)
@@ -51,6 +51,75 @@ u32 cik_gpu_check_soft_reset(struct radeon_device *rdev);
  * buffers.
  */
 
+/**
+ * cik_sdma_get_rptr - get the current read pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon ring pointer
+ *
+ * Get the current rptr from the hardware (CIK+).
+ */
+uint32_t cik_sdma_get_rptr(struct radeon_device *rdev,
+                          struct radeon_ring *ring)
+{
+       u32 rptr, reg;
+
+       if (rdev->wb.enabled) {
+               rptr = rdev->wb.wb[ring->rptr_offs/4];
+       } else {
+               if (ring->idx == R600_RING_TYPE_DMA_INDEX)
+                       reg = SDMA0_GFX_RB_RPTR + SDMA0_REGISTER_OFFSET;
+               else
+                       reg = SDMA0_GFX_RB_RPTR + SDMA1_REGISTER_OFFSET;
+
+               rptr = RREG32(reg);
+       }
+
+       return (rptr & 0x3fffc) >> 2;
+}
+
+/**
+ * cik_sdma_get_wptr - get the current write pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon ring pointer
+ *
+ * Get the current wptr from the hardware (CIK+).
+ */
+uint32_t cik_sdma_get_wptr(struct radeon_device *rdev,
+                          struct radeon_ring *ring)
+{
+       u32 reg;
+
+       if (ring->idx == R600_RING_TYPE_DMA_INDEX)
+               reg = SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET;
+       else
+               reg = SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET;
+
+       return (RREG32(reg) & 0x3fffc) >> 2;
+}
+
+/**
+ * cik_sdma_set_wptr - commit the write pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon ring pointer
+ *
+ * Write the wptr back to the hardware (CIK+).
+ */
+void cik_sdma_set_wptr(struct radeon_device *rdev,
+                      struct radeon_ring *ring)
+{
+       u32 reg;
+
+       if (ring->idx == R600_RING_TYPE_DMA_INDEX)
+               reg = SDMA0_GFX_RB_WPTR + SDMA0_REGISTER_OFFSET;
+       else
+               reg = SDMA0_GFX_RB_WPTR + SDMA1_REGISTER_OFFSET;
+
+       WREG32(reg, (ring->wptr << 2) & 0x3fffc);
+}
+
 /**
  * cik_sdma_ring_ib_execute - Schedule an IB on the DMA engine
  *
@@ -87,6 +156,35 @@ void cik_sdma_ring_ib_execute(struct radeon_device *rdev,
 
 }
 
+/**
+ * cik_sdma_hdp_flush_ring_emit - emit an hdp flush on the DMA ring
+ *
+ * @rdev: radeon_device pointer
+ * @ridx: radeon ring index
+ *
+ * Emit an hdp flush packet on the requested DMA ring.
+ */
+static void cik_sdma_hdp_flush_ring_emit(struct radeon_device *rdev,
+                                        int ridx)
+{
+       struct radeon_ring *ring = &rdev->ring[ridx];
+       u32 extra_bits = (SDMA_POLL_REG_MEM_EXTRA_OP(1) |
+                         SDMA_POLL_REG_MEM_EXTRA_FUNC(3)); /* == */
+       u32 ref_and_mask;
+
+       if (ridx == R600_RING_TYPE_DMA_INDEX)
+               ref_and_mask = SDMA0;
+       else
+               ref_and_mask = SDMA1;
+
+       radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_POLL_REG_MEM, 0, extra_bits));
+       radeon_ring_write(ring, GPU_HDP_FLUSH_DONE);
+       radeon_ring_write(ring, GPU_HDP_FLUSH_REQ);
+       radeon_ring_write(ring, ref_and_mask); /* reference */
+       radeon_ring_write(ring, ref_and_mask); /* mask */
+       radeon_ring_write(ring, (0xfff << 16) | 10); /* retry count, poll interval */
+}
+
 /**
  * cik_sdma_fence_ring_emit - emit a fence on the DMA ring
  *
@@ -111,12 +209,7 @@ void cik_sdma_fence_ring_emit(struct radeon_device *rdev,
        /* generate an interrupt */
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_TRAP, 0, 0));
        /* flush HDP */
-       /* We should be using the new POLL_REG_MEM special op packet here
-        * but it causes sDMA to hang sometimes
-        */
-       radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
-       radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
-       radeon_ring_write(ring, 0);
+       cik_sdma_hdp_flush_ring_emit(rdev, fence->ring);
 }
 
 /**
@@ -157,7 +250,9 @@ static void cik_sdma_gfx_stop(struct radeon_device *rdev)
        u32 rb_cntl, reg_offset;
        int i;
 
-       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+       if ((rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) ||
+           (rdev->asic->copy.copy_ring_index == CAYMAN_RING_TYPE_DMA1_INDEX))
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
 
        for (i = 0; i < 2; i++) {
                if (i == 0)
@@ -288,7 +383,9 @@ static int cik_sdma_gfx_resume(struct radeon_device *rdev)
                }
        }
 
-       radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+       if ((rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) ||
+           (rdev->asic->copy.copy_ring_index == CAYMAN_RING_TYPE_DMA1_INDEX))
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
 
        return 0;
 }
@@ -747,12 +844,7 @@ void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm
        radeon_ring_write(ring, VMID(0));
 
        /* flush HDP */
-       /* We should be using the new POLL_REG_MEM special op packet here
-        * but it causes sDMA to hang sometimes
-        */
-       radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
-       radeon_ring_write(ring, HDP_MEM_COHERENCY_FLUSH_CNTL >> 2);
-       radeon_ring_write(ring, 0);
+       cik_sdma_hdp_flush_ring_emit(rdev, ridx);
 
        /* flush TLB */
        radeon_ring_write(ring, SDMA_PACKET(SDMA_OPCODE_SRBM_WRITE, 0, 0xf000));
index 5964af5e5b2d8823c4626cad40bfd2abf385fb40..98bae9d7b74d1b3fe82ab41bc5f631d7e4acfc86 100644 (file)
 
 #define ATC_MISC_CG                                    0x3350
 
+#define GMCON_RENG_EXECUTE                             0x3508
+#define        RENG_EXECUTE_ON_PWR_UP                  (1 << 0)
+#define GMCON_MISC                                     0x350c
+#define        RENG_EXECUTE_ON_REG_UPDATE              (1 << 11)
+#define        STCTRL_STUTTER_EN                       (1 << 16)
+
+#define GMCON_PGFSM_CONFIG                             0x3538
+#define GMCON_PGFSM_WRITE                              0x353c
+#define GMCON_PGFSM_READ                               0x3540
+#define GMCON_MISC3                                    0x3544
+
 #define MC_SEQ_CNTL_3                                     0x3600
 #       define CAC_EN                                     (1 << 31)
 #define MC_SEQ_G5PDX_CTRL                                 0x3604
index 920e1e4a52c52c1edefd84e727a0fc13c2dde39b..cf783fc0ef21920f7d0e50156bddbd9c24299150 100644 (file)
@@ -1905,21 +1905,6 @@ int cypress_dpm_enable(struct radeon_device *rdev)
        if (pi->mg_clock_gating)
                cypress_mg_clock_gating_enable(rdev, true);
 
-       if (rdev->irq.installed &&
-           r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
-               PPSMC_Result result;
-
-               ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
-               if (ret)
-                       return ret;
-               rdev->irq.dpm_thermal = true;
-               radeon_irq_set(rdev);
-               result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
-
-               if (result != PPSMC_Result_OK)
-                       DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
-       }
-
        rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
 
        return 0;
index 9702e55e924e8327740869eb34ed455dcd908db3..f2b9e21ce4da063a03004c4705a3662b2e78c437 100644 (file)
@@ -146,6 +146,7 @@ extern u32 si_get_csb_size(struct radeon_device *rdev);
 extern void si_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer);
 extern u32 cik_get_csb_size(struct radeon_device *rdev);
 extern void cik_get_csb_buffer(struct radeon_device *rdev, volatile u32 *buffer);
+extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev);
 
 static const u32 evergreen_golden_registers[] =
 {
@@ -3867,6 +3868,48 @@ static void evergreen_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
        evergreen_print_gpu_status_regs(rdev);
 }
 
+void evergreen_gpu_pci_config_reset(struct radeon_device *rdev)
+{
+       struct evergreen_mc_save save;
+       u32 tmp, i;
+
+       dev_info(rdev->dev, "GPU pci config reset\n");
+
+       /* disable dpm? */
+
+       /* Disable CP parsing/prefetching */
+       WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT);
+       udelay(50);
+       /* Disable DMA */
+       tmp = RREG32(DMA_RB_CNTL);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL, tmp);
+       /* XXX other engines? */
+
+       /* halt the rlc */
+       r600_rlc_stop(rdev);
+
+       udelay(50);
+
+       /* set mclk/sclk to bypass */
+       rv770_set_clk_bypass_mode(rdev);
+       /* disable BM */
+       pci_clear_master(rdev->pdev);
+       /* disable mem access */
+       evergreen_mc_stop(rdev, &save);
+       if (evergreen_mc_wait_for_idle(rdev)) {
+               dev_warn(rdev->dev, "Wait for MC idle timed out !\n");
+       }
+       /* reset */
+       radeon_pci_config_reset(rdev);
+       /* wait for asic to come out of reset */
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               if (RREG32(CONFIG_MEMSIZE) != 0xffffffff)
+                       break;
+               udelay(1);
+       }
+}
+
 int evergreen_asic_reset(struct radeon_device *rdev)
 {
        u32 reset_mask;
@@ -3876,10 +3919,17 @@ int evergreen_asic_reset(struct radeon_device *rdev)
        if (reset_mask)
                r600_set_bios_scratch_engine_hung(rdev, true);
 
+       /* try soft reset */
        evergreen_gpu_soft_reset(rdev, reset_mask);
 
        reset_mask = evergreen_gpu_check_soft_reset(rdev);
 
+       /* try pci config reset */
+       if (reset_mask && radeon_hard_reset)
+               evergreen_gpu_pci_config_reset(rdev);
+
+       reset_mask = evergreen_gpu_check_soft_reset(rdev);
+
        if (!reset_mask)
                r600_set_bios_scratch_engine_hung(rdev, false);
 
@@ -4298,8 +4348,8 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)
                WREG32(GRPH_INT_CONTROL + EVERGREEN_CRTC5_REGISTER_OFFSET, 0);
        }
 
-       /* only one DAC on DCE6 */
-       if (!ASIC_IS_DCE6(rdev))
+       /* only one DAC on DCE5 */
+       if (!ASIC_IS_DCE5(rdev))
                WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
        WREG32(DACB_AUTODETECT_INT_CONTROL, 0);
 
@@ -5109,27 +5159,12 @@ static int evergreen_startup(struct radeon_device *rdev)
 
        evergreen_mc_program(rdev);
 
-       if (ASIC_IS_DCE5(rdev)) {
-               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
-                       r = ni_init_microcode(rdev);
-                       if (r) {
-                               DRM_ERROR("Failed to load firmware!\n");
-                               return r;
-                       }
-               }
+       if (ASIC_IS_DCE5(rdev) && !rdev->pm.dpm_enabled) {
                r = ni_mc_load_microcode(rdev);
                if (r) {
                        DRM_ERROR("Failed to load MC firmware!\n");
                        return r;
                }
-       } else {
-               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
-                       r = r600_init_microcode(rdev);
-                       if (r) {
-                               DRM_ERROR("Failed to load firmware!\n");
-                               return r;
-                       }
-               }
        }
 
        if (rdev->flags & RADEON_IS_AGP) {
@@ -5199,14 +5234,12 @@ static int evergreen_startup(struct radeon_device *rdev)
 
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
-                            R600_CP_RB_RPTR, R600_CP_RB_WPTR,
                             RADEON_CP_PACKET2);
        if (r)
                return r;
 
        ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
-                            DMA_RB_RPTR, DMA_RB_WPTR,
                             DMA_PACKET(DMA_PACKET_NOP, 0, 0));
        if (r)
                return r;
@@ -5224,7 +5257,6 @@ static int evergreen_startup(struct radeon_device *rdev)
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
        if (ring->ring_size) {
                r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-                                    UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                     RADEON_CP_PACKET2);
                if (!r)
                        r = uvd_v1_0_init(rdev);
@@ -5267,6 +5299,8 @@ int evergreen_resume(struct radeon_device *rdev)
        /* init golden registers */
        evergreen_init_golden_registers(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = evergreen_startup(rdev);
        if (r) {
@@ -5281,6 +5315,7 @@ int evergreen_resume(struct radeon_device *rdev)
 
 int evergreen_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r600_audio_fini(rdev);
        uvd_v1_0_fini(rdev);
        radeon_uvd_suspend(rdev);
@@ -5357,6 +5392,27 @@ int evergreen_init(struct radeon_device *rdev)
        if (r)
                return r;
 
+       if (ASIC_IS_DCE5(rdev)) {
+               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
+                       r = ni_init_microcode(rdev);
+                       if (r) {
+                               DRM_ERROR("Failed to load firmware!\n");
+                               return r;
+                       }
+               }
+       } else {
+               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
+                       r = r600_init_microcode(rdev);
+                       if (r) {
+                               DRM_ERROR("Failed to load firmware!\n");
+                               return r;
+                       }
+               }
+       }
+
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
        r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
 
@@ -5409,6 +5465,7 @@ int evergreen_init(struct radeon_device *rdev)
 
 void evergreen_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r600_audio_fini(rdev);
        r700_cp_fini(rdev);
        r600_dma_fini(rdev);
index eb8ac315f92faa3cbd58468b6bf9ba360a8c0986..c7cac07f139b2106041208179d124d8ff5ba20b0 100644 (file)
@@ -967,7 +967,10 @@ static int evergreen_cs_track_check(struct radeon_cs_parser *p)
        if (track->cb_dirty) {
                tmp = track->cb_target_mask;
                for (i = 0; i < 8; i++) {
-                       if ((tmp >> (i * 4)) & 0xF) {
+                       u32 format = G_028C70_FORMAT(track->cb_color_info[i]);
+
+                       if (format != V_028C70_COLOR_INVALID &&
+                           (tmp >> (i * 4)) & 0xF) {
                                /* at least one component is enabled */
                                if (track->cb_color_bo[i] == NULL) {
                                        dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
index 8a4e641f0e3c3712cfbcb543372fde5707e6cce5..a0f63ff5a5e97cb47100abce14bc249083c61479 100644 (file)
@@ -33,6 +33,7 @@
 #define EVERGREEN_PIF_PHY0_DATA                         0xc
 #define EVERGREEN_PIF_PHY1_INDEX                        0x10
 #define EVERGREEN_PIF_PHY1_DATA                         0x14
+#define EVERGREEN_MM_INDEX_HI                           0x18
 
 #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS               0x310
 #define EVERGREEN_VGA_MEMORY_BASE_ADDRESS_HIGH          0x324
index 17f990798992dae5d6335726a8f3b4c259659f89..f9c7963b3ee6b38730cdf6d422c2b612f0d1c904 100644 (file)
 #define        CG_SPLL_FUNC_CNTL_2                             0x604
 #define                SCLK_MUX_SEL(x)                         ((x) << 0)
 #define                SCLK_MUX_SEL_MASK                       (0x1ff << 0)
+#define                SCLK_MUX_UPDATE                         (1 << 26)
 #define        CG_SPLL_FUNC_CNTL_3                             0x608
 #define                SPLL_FB_DIV(x)                          ((x) << 0)
 #define                SPLL_FB_DIV_MASK                        (0x3ffffff << 0)
 #define                SPLL_DITHEN                             (1 << 28)
+#define        CG_SPLL_STATUS                                  0x60c
+#define                SPLL_CHG_STATUS                         (1 << 1)
 
 #define MPLL_CNTL_MODE                                  0x61c
+#       define MPLL_MCLK_SEL                            (1 << 11)
 #       define SS_SSEN                                  (1 << 24)
 #       define SS_DSMODE_EN                             (1 << 25)
 
index b41905573cd2a431862b3684f4d43ad445ecd15d..b6e01d5d2cced24edc67e773c84cba33a6d5fef8 100644 (file)
@@ -1126,11 +1126,6 @@ int kv_dpm_enable(struct radeon_device *rdev)
        struct kv_power_info *pi = kv_get_pi(rdev);
        int ret;
 
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_BIF |
-                            RADEON_CG_BLOCK_HDP), false);
-
        ret = kv_process_firmware_header(rdev);
        if (ret) {
                DRM_ERROR("kv_process_firmware_header failed\n");
@@ -1215,6 +1210,21 @@ int kv_dpm_enable(struct radeon_device *rdev)
 
        kv_reset_acp_boot_level(rdev);
 
+       ret = kv_smc_bapm_enable(rdev, false);
+       if (ret) {
+               DRM_ERROR("kv_smc_bapm_enable failed\n");
+               return ret;
+       }
+
+       kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+
+       return ret;
+}
+
+int kv_dpm_late_enable(struct radeon_device *rdev)
+{
+       int ret;
+
        if (rdev->irq.installed &&
            r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
                ret = kv_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
@@ -1226,35 +1236,17 @@ int kv_dpm_enable(struct radeon_device *rdev)
                radeon_irq_set(rdev);
        }
 
-       ret = kv_smc_bapm_enable(rdev, false);
-       if (ret) {
-               DRM_ERROR("kv_smc_bapm_enable failed\n");
-               return ret;
-       }
-
        /* powerdown unused blocks for now */
        kv_dpm_powergate_acp(rdev, true);
        kv_dpm_powergate_samu(rdev, true);
        kv_dpm_powergate_vce(rdev, true);
        kv_dpm_powergate_uvd(rdev, true);
 
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_BIF |
-                            RADEON_CG_BLOCK_HDP), true);
-
-       kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
-
        return ret;
 }
 
 void kv_dpm_disable(struct radeon_device *rdev)
 {
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_BIF |
-                            RADEON_CG_BLOCK_HDP), false);
-
        kv_smc_bapm_enable(rdev, false);
 
        /* powerup blocks */
@@ -1779,11 +1771,6 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)
        /*struct radeon_ps *old_ps = &pi->current_rps;*/
        int ret;
 
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_BIF |
-                            RADEON_CG_BLOCK_HDP), false);
-
        if (pi->bapm_enable) {
                ret = kv_smc_bapm_enable(rdev, rdev->pm.dpm.ac_power);
                if (ret) {
@@ -1849,11 +1836,6 @@ int kv_dpm_set_power_state(struct radeon_device *rdev)
                }
        }
 
-       cik_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                            RADEON_CG_BLOCK_SDMA |
-                            RADEON_CG_BLOCK_BIF |
-                            RADEON_CG_BLOCK_HDP), true);
-
        return 0;
 }
 
index f59a9e9fccf8a803ce6097e4e185d8824ad5f714..ea932ac66fc6647da43a8cf775b60ade25d478de 100644 (file)
@@ -174,6 +174,7 @@ extern void evergreen_pcie_gen2_enable(struct radeon_device *rdev);
 extern void evergreen_program_aspm(struct radeon_device *rdev);
 extern void sumo_rlc_fini(struct radeon_device *rdev);
 extern int sumo_rlc_init(struct radeon_device *rdev);
+extern void evergreen_gpu_pci_config_reset(struct radeon_device *rdev);
 
 /* Firmware Names */
 MODULE_FIRMWARE("radeon/BARTS_pfp.bin");
@@ -1330,13 +1331,12 @@ void cayman_fence_ring_emit(struct radeon_device *rdev,
 {
        struct radeon_ring *ring = &rdev->ring[fence->ring];
        u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
+       u32 cp_coher_cntl = PACKET3_FULL_CACHE_ENA | PACKET3_TC_ACTION_ENA |
+               PACKET3_SH_ACTION_ENA;
 
        /* flush read cache over gart for this vmid */
-       radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
-       radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2);
-       radeon_ring_write(ring, 0);
        radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
-       radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | PACKET3_SH_ACTION_ENA);
+       radeon_ring_write(ring, PACKET3_ENGINE_ME | cp_coher_cntl);
        radeon_ring_write(ring, 0xFFFFFFFF);
        radeon_ring_write(ring, 0);
        radeon_ring_write(ring, 10); /* poll interval */
@@ -1352,6 +1352,8 @@ void cayman_fence_ring_emit(struct radeon_device *rdev,
 void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
 {
        struct radeon_ring *ring = &rdev->ring[ib->ring];
+       u32 cp_coher_cntl = PACKET3_FULL_CACHE_ENA | PACKET3_TC_ACTION_ENA |
+               PACKET3_SH_ACTION_ENA;
 
        /* set to DX10/11 mode */
        radeon_ring_write(ring, PACKET3(PACKET3_MODE_CONTROL, 0));
@@ -1376,14 +1378,11 @@ void cayman_ring_ib_execute(struct radeon_device *rdev, struct radeon_ib *ib)
                          (ib->vm ? (ib->vm->id << 24) : 0));
 
        /* flush read cache over gart for this vmid */
-       radeon_ring_write(ring, PACKET3(PACKET3_SET_CONFIG_REG, 1));
-       radeon_ring_write(ring, (CP_COHER_CNTL2 - PACKET3_SET_CONFIG_REG_START) >> 2);
-       radeon_ring_write(ring, ib->vm ? ib->vm->id : 0);
        radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
-       radeon_ring_write(ring, PACKET3_TC_ACTION_ENA | PACKET3_SH_ACTION_ENA);
+       radeon_ring_write(ring, PACKET3_ENGINE_ME | cp_coher_cntl);
        radeon_ring_write(ring, 0xFFFFFFFF);
        radeon_ring_write(ring, 0);
-       radeon_ring_write(ring, 10); /* poll interval */
+       radeon_ring_write(ring, ((ib->vm ? ib->vm->id : 0) << 24) | 10); /* poll interval */
 }
 
 static void cayman_cp_enable(struct radeon_device *rdev, bool enable)
@@ -1391,13 +1390,63 @@ static void cayman_cp_enable(struct radeon_device *rdev, bool enable)
        if (enable)
                WREG32(CP_ME_CNTL, 0);
        else {
-               radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+               if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
+                       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
                WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));
                WREG32(SCRATCH_UMSK, 0);
                rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
        }
 }
 
+u32 cayman_gfx_get_rptr(struct radeon_device *rdev,
+                       struct radeon_ring *ring)
+{
+       u32 rptr;
+
+       if (rdev->wb.enabled)
+               rptr = rdev->wb.wb[ring->rptr_offs/4];
+       else {
+               if (ring->idx == RADEON_RING_TYPE_GFX_INDEX)
+                       rptr = RREG32(CP_RB0_RPTR);
+               else if (ring->idx == CAYMAN_RING_TYPE_CP1_INDEX)
+                       rptr = RREG32(CP_RB1_RPTR);
+               else
+                       rptr = RREG32(CP_RB2_RPTR);
+       }
+
+       return rptr;
+}
+
+u32 cayman_gfx_get_wptr(struct radeon_device *rdev,
+                       struct radeon_ring *ring)
+{
+       u32 wptr;
+
+       if (ring->idx == RADEON_RING_TYPE_GFX_INDEX)
+               wptr = RREG32(CP_RB0_WPTR);
+       else if (ring->idx == CAYMAN_RING_TYPE_CP1_INDEX)
+               wptr = RREG32(CP_RB1_WPTR);
+       else
+               wptr = RREG32(CP_RB2_WPTR);
+
+       return wptr;
+}
+
+void cayman_gfx_set_wptr(struct radeon_device *rdev,
+                        struct radeon_ring *ring)
+{
+       if (ring->idx == RADEON_RING_TYPE_GFX_INDEX) {
+               WREG32(CP_RB0_WPTR, ring->wptr);
+               (void)RREG32(CP_RB0_WPTR);
+       } else if (ring->idx == CAYMAN_RING_TYPE_CP1_INDEX) {
+               WREG32(CP_RB1_WPTR, ring->wptr);
+               (void)RREG32(CP_RB1_WPTR);
+       } else {
+               WREG32(CP_RB2_WPTR, ring->wptr);
+               (void)RREG32(CP_RB2_WPTR);
+       }
+}
+
 static int cayman_cp_load_microcode(struct radeon_device *rdev)
 {
        const __be32 *fw_data;
@@ -1526,6 +1575,16 @@ static int cayman_cp_resume(struct radeon_device *rdev)
                CP_RB1_BASE,
                CP_RB2_BASE
        };
+       static const unsigned cp_rb_rptr[] = {
+               CP_RB0_RPTR,
+               CP_RB1_RPTR,
+               CP_RB2_RPTR
+       };
+       static const unsigned cp_rb_wptr[] = {
+               CP_RB0_WPTR,
+               CP_RB1_WPTR,
+               CP_RB2_WPTR
+       };
        struct radeon_ring *ring;
        int i, r;
 
@@ -1584,8 +1643,8 @@ static int cayman_cp_resume(struct radeon_device *rdev)
                WREG32_P(cp_rb_cntl[i], RB_RPTR_WR_ENA, ~RB_RPTR_WR_ENA);
 
                ring->rptr = ring->wptr = 0;
-               WREG32(ring->rptr_reg, ring->rptr);
-               WREG32(ring->wptr_reg, ring->wptr);
+               WREG32(cp_rb_rptr[i], ring->rptr);
+               WREG32(cp_rb_wptr[i], ring->wptr);
 
                mdelay(1);
                WREG32_P(cp_rb_cntl[i], 0, ~RB_RPTR_WR_ENA);
@@ -1605,6 +1664,9 @@ static int cayman_cp_resume(struct radeon_device *rdev)
                return r;
        }
 
+       if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+
        return 0;
 }
 
@@ -1831,8 +1893,10 @@ int cayman_asic_reset(struct radeon_device *rdev)
 
        reset_mask = cayman_gpu_check_soft_reset(rdev);
 
-       if (!reset_mask)
-               r600_set_bios_scratch_engine_hung(rdev, false);
+       if (reset_mask)
+               evergreen_gpu_pci_config_reset(rdev);
+
+       r600_set_bios_scratch_engine_hung(rdev, false);
 
        return 0;
 }
@@ -1878,23 +1942,7 @@ static int cayman_startup(struct radeon_device *rdev)
 
        evergreen_mc_program(rdev);
 
-       if (rdev->flags & RADEON_IS_IGP) {
-               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
-                       r = ni_init_microcode(rdev);
-                       if (r) {
-                               DRM_ERROR("Failed to load firmware!\n");
-                               return r;
-                       }
-               }
-       } else {
-               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
-                       r = ni_init_microcode(rdev);
-                       if (r) {
-                               DRM_ERROR("Failed to load firmware!\n");
-                               return r;
-                       }
-               }
-
+       if (!(rdev->flags & RADEON_IS_IGP) && !rdev->pm.dpm_enabled) {
                r = ni_mc_load_microcode(rdev);
                if (r) {
                        DRM_ERROR("Failed to load MC firmware!\n");
@@ -1981,23 +2029,18 @@ static int cayman_startup(struct radeon_device *rdev)
        evergreen_irq_set(rdev);
 
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
-                            CP_RB0_RPTR, CP_RB0_WPTR,
                             RADEON_CP_PACKET2);
        if (r)
                return r;
 
        ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
-                            DMA_RB_RPTR + DMA0_REGISTER_OFFSET,
-                            DMA_RB_WPTR + DMA0_REGISTER_OFFSET,
                             DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
        if (r)
                return r;
 
        ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
-                            DMA_RB_RPTR + DMA1_REGISTER_OFFSET,
-                            DMA_RB_WPTR + DMA1_REGISTER_OFFSET,
                             DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
        if (r)
                return r;
@@ -2016,7 +2059,6 @@ static int cayman_startup(struct radeon_device *rdev)
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
        if (ring->ring_size) {
                r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-                                    UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                     RADEON_CP_PACKET2);
                if (!r)
                        r = uvd_v1_0_init(rdev);
@@ -2063,6 +2105,8 @@ int cayman_resume(struct radeon_device *rdev)
        /* init golden registers */
        ni_init_golden_registers(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = cayman_startup(rdev);
        if (r) {
@@ -2075,6 +2119,7 @@ int cayman_resume(struct radeon_device *rdev)
 
 int cayman_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        if (ASIC_IS_DCE6(rdev))
                dce6_audio_fini(rdev);
        else
@@ -2145,6 +2190,27 @@ int cayman_init(struct radeon_device *rdev)
        if (r)
                return r;
 
+       if (rdev->flags & RADEON_IS_IGP) {
+               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
+                       r = ni_init_microcode(rdev);
+                       if (r) {
+                               DRM_ERROR("Failed to load firmware!\n");
+                               return r;
+                       }
+               }
+       } else {
+               if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw || !rdev->mc_fw) {
+                       r = ni_init_microcode(rdev);
+                       if (r) {
+                               DRM_ERROR("Failed to load firmware!\n");
+                               return r;
+                       }
+               }
+       }
+
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        ring->ring_obj = NULL;
        r600_ring_init(rdev, ring, 1024 * 1024);
 
@@ -2204,6 +2270,7 @@ int cayman_init(struct radeon_device *rdev)
 
 void cayman_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        cayman_cp_fini(rdev);
        cayman_dma_fini(rdev);
        r600_irq_fini(rdev);
index bdeb65ed365831db35a94a0ffae523f3c8e419dd..7cf96b15377fa8f66bfbd048b08a6f1959ea68b5 100644 (file)
@@ -42,6 +42,75 @@ u32 cayman_gpu_check_soft_reset(struct radeon_device *rdev);
  * Cayman and newer support two asynchronous DMA engines.
  */
 
+/**
+ * cayman_dma_get_rptr - get the current read pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon ring pointer
+ *
+ * Get the current rptr from the hardware (cayman+).
+ */
+uint32_t cayman_dma_get_rptr(struct radeon_device *rdev,
+                            struct radeon_ring *ring)
+{
+       u32 rptr, reg;
+
+       if (rdev->wb.enabled) {
+               rptr = rdev->wb.wb[ring->rptr_offs/4];
+       } else {
+               if (ring->idx == R600_RING_TYPE_DMA_INDEX)
+                       reg = DMA_RB_RPTR + DMA0_REGISTER_OFFSET;
+               else
+                       reg = DMA_RB_RPTR + DMA1_REGISTER_OFFSET;
+
+               rptr = RREG32(reg);
+       }
+
+       return (rptr & 0x3fffc) >> 2;
+}
+
+/**
+ * cayman_dma_get_wptr - get the current write pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon ring pointer
+ *
+ * Get the current wptr from the hardware (cayman+).
+ */
+uint32_t cayman_dma_get_wptr(struct radeon_device *rdev,
+                          struct radeon_ring *ring)
+{
+       u32 reg;
+
+       if (ring->idx == R600_RING_TYPE_DMA_INDEX)
+               reg = DMA_RB_WPTR + DMA0_REGISTER_OFFSET;
+       else
+               reg = DMA_RB_WPTR + DMA1_REGISTER_OFFSET;
+
+       return (RREG32(reg) & 0x3fffc) >> 2;
+}
+
+/**
+ * cayman_dma_set_wptr - commit the write pointer
+ *
+ * @rdev: radeon_device pointer
+ * @ring: radeon ring pointer
+ *
+ * Write the wptr back to the hardware (cayman+).
+ */
+void cayman_dma_set_wptr(struct radeon_device *rdev,
+                        struct radeon_ring *ring)
+{
+       u32 reg;
+
+       if (ring->idx == R600_RING_TYPE_DMA_INDEX)
+               reg = DMA_RB_WPTR + DMA0_REGISTER_OFFSET;
+       else
+               reg = DMA_RB_WPTR + DMA1_REGISTER_OFFSET;
+
+       WREG32(reg, (ring->wptr << 2) & 0x3fffc);
+}
+
 /**
  * cayman_dma_ring_ib_execute - Schedule an IB on the DMA engine
  *
@@ -88,7 +157,9 @@ void cayman_dma_stop(struct radeon_device *rdev)
 {
        u32 rb_cntl;
 
-       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+       if ((rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) ||
+           (rdev->asic->copy.copy_ring_index == CAYMAN_RING_TYPE_DMA1_INDEX))
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
 
        /* dma0 */
        rb_cntl = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET);
@@ -190,7 +261,9 @@ int cayman_dma_resume(struct radeon_device *rdev)
                }
        }
 
-       radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+       if ((rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX) ||
+           (rdev->asic->copy.copy_ring_index == CAYMAN_RING_TYPE_DMA1_INDEX))
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
 
        return 0;
 }
index 49c4d48f54d616b49b7af261d8fa2d71586ab8fd..c351226ecb31b0d9fa2d94a32ac23d504d61952b 100644 (file)
@@ -720,6 +720,8 @@ static const u32 cayman_sysls_enable[] =
 struct rv7xx_power_info *rv770_get_pi(struct radeon_device *rdev);
 struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
 
+extern int ni_mc_load_microcode(struct radeon_device *rdev);
+
 struct ni_power_info *ni_get_pi(struct radeon_device *rdev)
 {
         struct ni_power_info *pi = rdev->pm.dpm.priv;
@@ -3565,7 +3567,11 @@ void ni_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
 void ni_dpm_setup_asic(struct radeon_device *rdev)
 {
        struct evergreen_power_info *eg_pi = evergreen_get_pi(rdev);
+       int r;
 
+       r = ni_mc_load_microcode(rdev);
+       if (r)
+               DRM_ERROR("Failed to load MC firmware!\n");
        ni_read_clock_registers(rdev);
        btc_read_arb_registers(rdev);
        rv770_get_memory_type(rdev);
@@ -3710,21 +3716,6 @@ int ni_dpm_enable(struct radeon_device *rdev)
        if (eg_pi->ls_clock_gating)
                ni_ls_clockgating_enable(rdev, true);
 
-       if (rdev->irq.installed &&
-           r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
-               PPSMC_Result result;
-
-               ret = rv770_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, 0xff * 1000);
-               if (ret)
-                       return ret;
-               rdev->irq.dpm_thermal = true;
-               radeon_irq_set(rdev);
-               result = rv770_send_msg_to_smc(rdev, PPSMC_MSG_EnableThermalInterrupt);
-
-               if (result != PPSMC_Result_OK)
-                       DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
-       }
-
        rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
 
        ni_update_current_ps(rdev, boot_ps);
index 22421bc80c0d0d0d33c8b87ef9922c3cf982fc15..d996033c243ee14f4509220a707edf50f9dbe489 100644 (file)
 #              define PACKET3_DB_ACTION_ENA        (1 << 26)
 #              define PACKET3_SH_ACTION_ENA        (1 << 27)
 #              define PACKET3_SX_ACTION_ENA        (1 << 28)
+#              define PACKET3_ENGINE_ME            (1 << 31)
 #define        PACKET3_ME_INITIALIZE                           0x44
 #define                PACKET3_ME_INITIALIZE_DEVICE_ID(x) ((x) << 16)
 #define        PACKET3_COND_WRITE                              0x45
index da43ab3288332faf705a3e673663c5fe7fbc30b3..2d532996c69795cc129cb4ac6c60a4dfc4b70808 100644 (file)
@@ -23,7 +23,7 @@
 #ifndef _PPTABLE_H
 #define _PPTABLE_H
 
-#pragma pack(push, 1)
+#pragma pack(1)
 
 typedef struct _ATOM_PPLIB_THERMALCONTROLLER
 
@@ -677,6 +677,6 @@ typedef struct _ATOM_PPLIB_PPM_Table
       ULONG  ulTjmax;
 } ATOM_PPLIB_PPM_Table;
 
-#pragma pack(pop)
+#pragma pack()
 
 #endif
index 10abc4d5a6cc396a85bb32d4b7d094b748757f99..ef024ce3f7ccfd39b1be47be9840a401b588b1dc 100644 (file)
@@ -1050,6 +1050,36 @@ static int r100_cp_init_microcode(struct radeon_device *rdev)
        return err;
 }
 
+u32 r100_gfx_get_rptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring)
+{
+       u32 rptr;
+
+       if (rdev->wb.enabled)
+               rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
+       else
+               rptr = RREG32(RADEON_CP_RB_RPTR);
+
+       return rptr;
+}
+
+u32 r100_gfx_get_wptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring)
+{
+       u32 wptr;
+
+       wptr = RREG32(RADEON_CP_RB_WPTR);
+
+       return wptr;
+}
+
+void r100_gfx_set_wptr(struct radeon_device *rdev,
+                      struct radeon_ring *ring)
+{
+       WREG32(RADEON_CP_RB_WPTR, ring->wptr);
+       (void)RREG32(RADEON_CP_RB_WPTR);
+}
+
 static void r100_cp_load_microcode(struct radeon_device *rdev)
 {
        const __be32 *fw_data;
@@ -1102,7 +1132,6 @@ int r100_cp_init(struct radeon_device *rdev, unsigned ring_size)
        ring_size = (1 << (rb_bufsz + 1)) * 4;
        r100_cp_load_microcode(rdev);
        r = radeon_ring_init(rdev, ring, ring_size, RADEON_WB_CP_RPTR_OFFSET,
-                            RADEON_CP_RB_RPTR, RADEON_CP_RB_WPTR,
                             RADEON_CP_PACKET2);
        if (r) {
                return r;
@@ -3913,6 +3942,8 @@ int r100_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = r100_startup(rdev);
        if (r) {
@@ -3923,6 +3954,7 @@ int r100_resume(struct radeon_device *rdev)
 
 int r100_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r100_cp_disable(rdev);
        radeon_wb_disable(rdev);
        r100_irq_disable(rdev);
@@ -3933,6 +3965,7 @@ int r100_suspend(struct radeon_device *rdev)
 
 void r100_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r100_cp_fini(rdev);
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
@@ -4039,6 +4072,9 @@ int r100_init(struct radeon_device *rdev)
        }
        r100_set_safe_registers(rdev);
 
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->accel_working = true;
        r = r100_startup(rdev);
        if (r) {
index d8dd269b9159fcc0dfbed98cf8c3c2037742e671..7c63ef840e86abaf04f216201b32ee2f40323b9b 100644 (file)
@@ -1430,6 +1430,8 @@ int r300_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = r300_startup(rdev);
        if (r) {
@@ -1440,6 +1442,7 @@ int r300_resume(struct radeon_device *rdev)
 
 int r300_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r100_cp_disable(rdev);
        radeon_wb_disable(rdev);
        r100_irq_disable(rdev);
@@ -1452,6 +1455,7 @@ int r300_suspend(struct radeon_device *rdev)
 
 void r300_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r100_cp_fini(rdev);
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
@@ -1538,6 +1542,9 @@ int r300_init(struct radeon_device *rdev)
        }
        r300_set_reg_safe(rdev);
 
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->accel_working = true;
        r = r300_startup(rdev);
        if (r) {
index 60170ea5e3a228c0483c18f0fd1652b30ec7760b..84b1d5367a11f6950026337f76117bbb8edda0bb 100644 (file)
@@ -75,7 +75,7 @@ static int r300_emit_cliprects(drm_radeon_private_t *dev_priv,
                OUT_RING(CP_PACKET0(R300_RE_CLIPRECT_TL_0, nr * 2 - 1));
 
                for (i = 0; i < nr; ++i) {
-                       if (DRM_COPY_FROM_USER
+                       if (copy_from_user
                            (&box, &cmdbuf->boxes[n + i], sizeof(box))) {
                                DRM_ERROR("copy cliprect faulted\n");
                                return -EFAULT;
@@ -928,12 +928,12 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
                buf_idx = drm_buffer_pointer_to_dword(cmdbuf->buffer, 0);
                *buf_idx *= 2; /* 8 bytes per buf */
 
-               if (DRM_COPY_TO_USER(ref_age_base + *buf_idx,
+               if (copy_to_user(ref_age_base + *buf_idx,
                                &dev_priv->scratch_ages[header.scratch.reg],
                                sizeof(u32)))
                        return -EINVAL;
 
-               if (DRM_COPY_FROM_USER(&h_pending,
+               if (copy_from_user(&h_pending,
                                ref_age_base + *buf_idx + 1,
                                sizeof(u32)))
                        return -EINVAL;
@@ -943,7 +943,7 @@ static int r300_scratch(drm_radeon_private_t *dev_priv,
 
                h_pending--;
 
-               if (DRM_COPY_TO_USER(ref_age_base + *buf_idx + 1,
+               if (copy_to_user(ref_age_base + *buf_idx + 1,
                                        &h_pending,
                                        sizeof(u32)))
                        return -EINVAL;
index 6edf2b3a52b4d7e4ba82cc063048ffb73733a984..3768aab2710b3943261312c4fcc5184b4f18a6fb 100644 (file)
@@ -325,6 +325,8 @@ int r420_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = r420_startup(rdev);
        if (r) {
@@ -335,6 +337,7 @@ int r420_resume(struct radeon_device *rdev)
 
 int r420_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r420_cp_errata_fini(rdev);
        r100_cp_disable(rdev);
        radeon_wb_disable(rdev);
@@ -348,6 +351,7 @@ int r420_suspend(struct radeon_device *rdev)
 
 void r420_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r100_cp_fini(rdev);
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
@@ -444,6 +448,9 @@ int r420_init(struct radeon_device *rdev)
        }
        r420_set_reg_safe(rdev);
 
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->accel_working = true;
        r = r420_startup(rdev);
        if (r) {
index e1aece73b370c1ec9d6d9f86273caad0cbb14d36..e209eb75024f9dc1c441518cbe8f8d70a41844f5 100644 (file)
@@ -240,6 +240,8 @@ int r520_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = r520_startup(rdev);
        if (r) {
@@ -312,6 +314,9 @@ int r520_init(struct radeon_device *rdev)
                return r;
        rv515_set_safe_registers(rdev);
 
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->accel_working = true;
        r = r520_startup(rdev);
        if (r) {
index 9ad06732a78bc6d079914a6ce15e92b7e273b265..56140b4e5bb2e9fa7fc72339cc29f88b398aff1c 100644 (file)
@@ -105,6 +105,7 @@ void r600_fini(struct radeon_device *rdev);
 void r600_irq_disable(struct radeon_device *rdev);
 static void r600_pcie_gen2_enable(struct radeon_device *rdev);
 extern int evergreen_rlc_resume(struct radeon_device *rdev);
+extern void rv770_set_clk_bypass_mode(struct radeon_device *rdev);
 
 /**
  * r600_get_xclk - get the xclk
@@ -1644,6 +1645,67 @@ static void r600_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
        r600_print_gpu_status_regs(rdev);
 }
 
+static void r600_gpu_pci_config_reset(struct radeon_device *rdev)
+{
+       struct rv515_mc_save save;
+       u32 tmp, i;
+
+       dev_info(rdev->dev, "GPU pci config reset\n");
+
+       /* disable dpm? */
+
+       /* Disable CP parsing/prefetching */
+       if (rdev->family >= CHIP_RV770)
+               WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1) | S_0086D8_CP_PFP_HALT(1));
+       else
+               WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
+
+       /* disable the RLC */
+       WREG32(RLC_CNTL, 0);
+
+       /* Disable DMA */
+       tmp = RREG32(DMA_RB_CNTL);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL, tmp);
+
+       mdelay(50);
+
+       /* set mclk/sclk to bypass */
+       if (rdev->family >= CHIP_RV770)
+               rv770_set_clk_bypass_mode(rdev);
+       /* disable BM */
+       pci_clear_master(rdev->pdev);
+       /* disable mem access */
+       rv515_mc_stop(rdev, &save);
+       if (r600_mc_wait_for_idle(rdev)) {
+               dev_warn(rdev->dev, "Wait for MC idle timedout !\n");
+       }
+
+       /* BIF reset workaround.  Not sure if this is needed on 6xx */
+       tmp = RREG32(BUS_CNTL);
+       tmp |= VGA_COHE_SPEC_TIMER_DIS;
+       WREG32(BUS_CNTL, tmp);
+
+       tmp = RREG32(BIF_SCRATCH0);
+
+       /* reset */
+       radeon_pci_config_reset(rdev);
+       mdelay(1);
+
+       /* BIF reset workaround.  Not sure if this is needed on 6xx */
+       tmp = SOFT_RESET_BIF;
+       WREG32(SRBM_SOFT_RESET, tmp);
+       mdelay(1);
+       WREG32(SRBM_SOFT_RESET, 0);
+
+       /* wait for asic to come out of reset */
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               if (RREG32(CONFIG_MEMSIZE) != 0xffffffff)
+                       break;
+               udelay(1);
+       }
+}
+
 int r600_asic_reset(struct radeon_device *rdev)
 {
        u32 reset_mask;
@@ -1653,10 +1715,17 @@ int r600_asic_reset(struct radeon_device *rdev)
        if (reset_mask)
                r600_set_bios_scratch_engine_hung(rdev, true);
 
+       /* try soft reset */
        r600_gpu_soft_reset(rdev, reset_mask);
 
        reset_mask = r600_gpu_check_soft_reset(rdev);
 
+       /* try pci config reset */
+       if (reset_mask && radeon_hard_reset)
+               r600_gpu_pci_config_reset(rdev);
+
+       reset_mask = r600_gpu_check_soft_reset(rdev);
+
        if (!reset_mask)
                r600_set_bios_scratch_engine_hung(rdev, false);
 
@@ -2185,7 +2254,8 @@ void r600_pciep_wreg(struct radeon_device *rdev, u32 reg, u32 v)
  */
 void r600_cp_stop(struct radeon_device *rdev)
 {
-       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+       if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
        WREG32(R_0086D8_CP_ME_CNTL, S_0086D8_CP_ME_HALT(1));
        WREG32(SCRATCH_UMSK, 0);
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
@@ -2382,6 +2452,36 @@ out:
        return err;
 }
 
+u32 r600_gfx_get_rptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring)
+{
+       u32 rptr;
+
+       if (rdev->wb.enabled)
+               rptr = rdev->wb.wb[ring->rptr_offs/4];
+       else
+               rptr = RREG32(R600_CP_RB_RPTR);
+
+       return rptr;
+}
+
+u32 r600_gfx_get_wptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring)
+{
+       u32 wptr;
+
+       wptr = RREG32(R600_CP_RB_WPTR);
+
+       return wptr;
+}
+
+void r600_gfx_set_wptr(struct radeon_device *rdev,
+                      struct radeon_ring *ring)
+{
+       WREG32(R600_CP_RB_WPTR, ring->wptr);
+       (void)RREG32(R600_CP_RB_WPTR);
+}
+
 static int r600_cp_load_microcode(struct radeon_device *rdev)
 {
        const __be32 *fw_data;
@@ -2513,6 +2613,10 @@ int r600_cp_resume(struct radeon_device *rdev)
                ring->ready = false;
                return r;
        }
+
+       if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+
        return 0;
 }
 
@@ -2607,14 +2711,17 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
                          struct radeon_fence *fence)
 {
        struct radeon_ring *ring = &rdev->ring[fence->ring];
+       u32 cp_coher_cntl = PACKET3_TC_ACTION_ENA | PACKET3_VC_ACTION_ENA |
+               PACKET3_SH_ACTION_ENA;
+
+       if (rdev->family >= CHIP_RV770)
+               cp_coher_cntl |= PACKET3_FULL_CACHE_ENA;
 
        if (rdev->wb.use_event) {
                u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
                /* flush read cache over gart */
                radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
-               radeon_ring_write(ring, PACKET3_TC_ACTION_ENA |
-                                       PACKET3_VC_ACTION_ENA |
-                                       PACKET3_SH_ACTION_ENA);
+               radeon_ring_write(ring, cp_coher_cntl);
                radeon_ring_write(ring, 0xFFFFFFFF);
                radeon_ring_write(ring, 0);
                radeon_ring_write(ring, 10); /* poll interval */
@@ -2628,9 +2735,7 @@ void r600_fence_ring_emit(struct radeon_device *rdev,
        } else {
                /* flush read cache over gart */
                radeon_ring_write(ring, PACKET3(PACKET3_SURFACE_SYNC, 3));
-               radeon_ring_write(ring, PACKET3_TC_ACTION_ENA |
-                                       PACKET3_VC_ACTION_ENA |
-                                       PACKET3_SH_ACTION_ENA);
+               radeon_ring_write(ring, cp_coher_cntl);
                radeon_ring_write(ring, 0xFFFFFFFF);
                radeon_ring_write(ring, 0);
                radeon_ring_write(ring, 10); /* poll interval */
@@ -2775,14 +2880,6 @@ static int r600_startup(struct radeon_device *rdev)
 
        r600_mc_program(rdev);
 
-       if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
-               r = r600_init_microcode(rdev);
-               if (r) {
-                       DRM_ERROR("Failed to load firmware!\n");
-                       return r;
-               }
-       }
-
        if (rdev->flags & RADEON_IS_AGP) {
                r600_agp_enable(rdev);
        } else {
@@ -2803,12 +2900,6 @@ static int r600_startup(struct radeon_device *rdev)
                return r;
        }
 
-       r = radeon_fence_driver_start_ring(rdev, R600_RING_TYPE_DMA_INDEX);
-       if (r) {
-               dev_err(rdev->dev, "failed initializing DMA fences (%d).\n", r);
-               return r;
-       }
-
        /* Enable IRQ */
        if (!rdev->irq.installed) {
                r = radeon_irq_kms_init(rdev);
@@ -2826,18 +2917,10 @@ static int r600_startup(struct radeon_device *rdev)
 
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
-                            R600_CP_RB_RPTR, R600_CP_RB_WPTR,
                             RADEON_CP_PACKET2);
        if (r)
                return r;
 
-       ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
-       r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
-                            DMA_RB_RPTR, DMA_RB_WPTR,
-                            DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
-       if (r)
-               return r;
-
        r = r600_cp_load_microcode(rdev);
        if (r)
                return r;
@@ -2845,10 +2928,6 @@ static int r600_startup(struct radeon_device *rdev)
        if (r)
                return r;
 
-       r = r600_dma_resume(rdev);
-       if (r)
-               return r;
-
        r = radeon_ib_pool_init(rdev);
        if (r) {
                dev_err(rdev->dev, "IB initialization failed (%d).\n", r);
@@ -2889,6 +2968,8 @@ int r600_resume(struct radeon_device *rdev)
        /* post card */
        atom_asic_init(rdev->mode_info.atom_context);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = r600_startup(rdev);
        if (r) {
@@ -2902,9 +2983,9 @@ int r600_resume(struct radeon_device *rdev)
 
 int r600_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r600_audio_fini(rdev);
        r600_cp_stop(rdev);
-       r600_dma_stop(rdev);
        r600_irq_suspend(rdev);
        radeon_wb_disable(rdev);
        r600_pcie_gart_disable(rdev);
@@ -2970,12 +3051,20 @@ int r600_init(struct radeon_device *rdev)
        if (r)
                return r;
 
+       if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
+               r = r600_init_microcode(rdev);
+               if (r) {
+                       DRM_ERROR("Failed to load firmware!\n");
+                       return r;
+               }
+       }
+
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
        r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
 
-       rdev->ring[R600_RING_TYPE_DMA_INDEX].ring_obj = NULL;
-       r600_ring_init(rdev, &rdev->ring[R600_RING_TYPE_DMA_INDEX], 64 * 1024);
-
        rdev->ih.ring_obj = NULL;
        r600_ih_ring_init(rdev, 64 * 1024);
 
@@ -2988,7 +3077,6 @@ int r600_init(struct radeon_device *rdev)
        if (r) {
                dev_err(rdev->dev, "disabling GPU acceleration\n");
                r600_cp_fini(rdev);
-               r600_dma_fini(rdev);
                r600_irq_fini(rdev);
                radeon_wb_fini(rdev);
                radeon_ib_pool_fini(rdev);
@@ -3002,9 +3090,9 @@ int r600_init(struct radeon_device *rdev)
 
 void r600_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r600_audio_fini(rdev);
        r600_cp_fini(rdev);
-       r600_dma_fini(rdev);
        r600_irq_fini(rdev);
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
index d8eb48bff0ed204e9c52538342a11dcd1bd5b8ff..8c9b7e26533c6c81635a9dafa20e7cecb164b167 100644 (file)
@@ -2515,7 +2515,7 @@ int r600_cp_dispatch_texture(struct drm_device *dev,
                buf = radeon_freelist_get(dev);
                if (!buf) {
                        DRM_DEBUG("EAGAIN\n");
-                       if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
+                       if (copy_to_user(tex->image, image, sizeof(*image)))
                                return -EFAULT;
                        return -EAGAIN;
                }
@@ -2528,7 +2528,7 @@ int r600_cp_dispatch_texture(struct drm_device *dev,
                buffer =
                    (u32 *) ((char *)dev->agp_buffer_map->handle + buf->offset);
 
-               if (DRM_COPY_FROM_USER(buffer, data, pass_size)) {
+               if (copy_from_user(buffer, data, pass_size)) {
                        DRM_ERROR("EFAULT on pad, %d bytes\n", pass_size);
                        return -EFAULT;
                }
index 5dceea6f71ae450cf925b0d7e119783c801d6ebd..7b399dc5fd5492d1e53dcaa5b5be728164dc85b2 100644 (file)
@@ -749,7 +749,10 @@ static int r600_cs_track_check(struct radeon_cs_parser *p)
                }
 
                for (i = 0; i < 8; i++) {
-                       if ((tmp >> (i * 4)) & 0xF) {
+                       u32 format = G_0280A0_FORMAT(track->cb_color_info[i]);
+
+                       if (format != V_0280A0_COLOR_INVALID &&
+                           (tmp >> (i * 4)) & 0xF) {
                                /* at least one component is enabled */
                                if (track->cb_color_bo[i] == NULL) {
                                        dev_warn(p->dev, "%s:%d mask 0x%08X | 0x%08X no cb for %d\n",
@@ -2386,7 +2389,7 @@ int r600_cs_legacy(struct drm_device *dev, void *data, struct drm_file *filp,
        ib_chunk = &parser.chunks[parser.chunk_ib_idx];
        parser.ib.length_dw = ib_chunk->length_dw;
        *l = parser.ib.length_dw;
-       if (DRM_COPY_FROM_USER(ib, ib_chunk->user_ptr, ib_chunk->length_dw * 4)) {
+       if (copy_from_user(ib, ib_chunk->user_ptr, ib_chunk->length_dw * 4)) {
                r = -EFAULT;
                r600_cs_parser_fini(&parser, r);
                return r;
index 7844d15c139fcb97247880d596ab4354d4bea8d5..b2d4c91e6272e4fb9dfbfbf669a55705c920eee2 100644 (file)
@@ -51,7 +51,14 @@ u32 r600_gpu_check_soft_reset(struct radeon_device *rdev);
 uint32_t r600_dma_get_rptr(struct radeon_device *rdev,
                           struct radeon_ring *ring)
 {
-       return (radeon_ring_generic_get_rptr(rdev, ring) & 0x3fffc) >> 2;
+       u32 rptr;
+
+       if (rdev->wb.enabled)
+               rptr = rdev->wb.wb[ring->rptr_offs/4];
+       else
+               rptr = RREG32(DMA_RB_RPTR);
+
+       return (rptr & 0x3fffc) >> 2;
 }
 
 /**
@@ -65,7 +72,7 @@ uint32_t r600_dma_get_rptr(struct radeon_device *rdev,
 uint32_t r600_dma_get_wptr(struct radeon_device *rdev,
                           struct radeon_ring *ring)
 {
-       return (RREG32(ring->wptr_reg) & 0x3fffc) >> 2;
+       return (RREG32(DMA_RB_WPTR) & 0x3fffc) >> 2;
 }
 
 /**
@@ -79,7 +86,7 @@ uint32_t r600_dma_get_wptr(struct radeon_device *rdev,
 void r600_dma_set_wptr(struct radeon_device *rdev,
                       struct radeon_ring *ring)
 {
-       WREG32(ring->wptr_reg, (ring->wptr << 2) & 0x3fffc);
+       WREG32(DMA_RB_WPTR, (ring->wptr << 2) & 0x3fffc);
 }
 
 /**
@@ -93,7 +100,8 @@ void r600_dma_stop(struct radeon_device *rdev)
 {
        u32 rb_cntl = RREG32(DMA_RB_CNTL);
 
-       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+       if (rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX)
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
 
        rb_cntl &= ~DMA_RB_ENABLE;
        WREG32(DMA_RB_CNTL, rb_cntl);
@@ -180,7 +188,8 @@ int r600_dma_resume(struct radeon_device *rdev)
                return r;
        }
 
-       radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+       if (rdev->asic->copy.copy_ring_index == R600_RING_TYPE_DMA_INDEX)
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
 
        return 0;
 }
index 5513d8f06252e13e11e27e9d21d5aecae775b5a8..e4cc9b314ce974fe5caacf91a000cb9a76a584d6 100644 (file)
@@ -729,8 +729,8 @@ bool r600_is_uvd_state(u32 class, u32 class2)
        return false;
 }
 
-int r600_set_thermal_temperature_range(struct radeon_device *rdev,
-                                      int min_temp, int max_temp)
+static int r600_set_thermal_temperature_range(struct radeon_device *rdev,
+                                             int min_temp, int max_temp)
 {
        int low_temp = 0 * 1000;
        int high_temp = 255 * 1000;
@@ -777,6 +777,22 @@ bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor)
        }
 }
 
+int r600_dpm_late_enable(struct radeon_device *rdev)
+{
+       int ret;
+
+       if (rdev->irq.installed &&
+           r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
+               ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
+               if (ret)
+                       return ret;
+               rdev->irq.dpm_thermal = true;
+               radeon_irq_set(rdev);
+       }
+
+       return 0;
+}
+
 union power_info {
        struct _ATOM_POWERPLAY_INFO info;
        struct _ATOM_POWERPLAY_INFO_V2 info_2;
index 1000bf9719f2449af5d15a153b147f19c6af25e4..07eab2b04e81b5db420a6ee96152c8b8e94e4092 100644 (file)
@@ -213,8 +213,6 @@ void r600_wait_for_power_level(struct radeon_device *rdev,
 void r600_start_dpm(struct radeon_device *rdev);
 void r600_stop_dpm(struct radeon_device *rdev);
 
-int r600_set_thermal_temperature_range(struct radeon_device *rdev,
-                                      int min_temp, int max_temp);
 bool r600_is_internal_thermal_sensor(enum radeon_int_thermal_type sensor);
 
 int r600_parse_extended_power_table(struct radeon_device *rdev);
index b7d3ecba43e34d3b559ee072800101532150c631..3016fc14f502c49a61c2343c3b2ca877d2590109 100644 (file)
@@ -250,7 +250,7 @@ static void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
                 value, ~HDMI0_AUDIO_TEST_EN);
 }
 
-void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+static void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
 {
        struct drm_device *dev = encoder->dev;
        struct radeon_device *rdev = dev->dev_private;
index ebe38724a9765765041eaa245fc7994c4fec01fb..37455f65107f7fc8c0d2ff8a6a14d5abe43c13af 100644 (file)
 #define RLC_UCODE_DATA                                    0x3f30
 
 #define SRBM_SOFT_RESET                                   0xe60
+#       define SOFT_RESET_BIF                             (1 << 1)
 #       define SOFT_RESET_DMA                             (1 << 12)
 #       define SOFT_RESET_RLC                             (1 << 13)
 #       define SOFT_RESET_UVD                             (1 << 18)
 #       define RV770_SOFT_RESET_DMA                       (1 << 20)
 
+#define BIF_SCRATCH0                                      0x5438
+
+#define BUS_CNTL                                          0x5420
+#       define BIOS_ROM_DIS                               (1 << 1)
+#       define VGA_COHE_SPEC_TIMER_DIS                    (1 << 9)
+
 #define CP_INT_CNTL                                       0xc124
 #       define CNTX_BUSY_INT_ENABLE                       (1 << 19)
 #       define CNTX_EMPTY_INT_ENABLE                      (1 << 20)
 #              define PACKET3_CP_DMA_CMD_DAIC      (1 << 29)
 #define        PACKET3_SURFACE_SYNC                            0x43
 #              define PACKET3_CB0_DEST_BASE_ENA    (1 << 6)
+#              define PACKET3_FULL_CACHE_ENA       (1 << 20) /* r7xx+ only */
 #              define PACKET3_TC_ACTION_ENA        (1 << 23)
 #              define PACKET3_VC_ACTION_ENA        (1 << 24)
 #              define PACKET3_CB_ACTION_ENA        (1 << 25)
index 45e1f447bc794c677a8e83830fd318585c2d7f7e..4a8ac1cd6b4c65582690e035e026aa6f1b125e00 100644 (file)
@@ -99,6 +99,7 @@ extern int radeon_fastfb;
 extern int radeon_dpm;
 extern int radeon_aspm;
 extern int radeon_runtime_pm;
+extern int radeon_hard_reset;
 
 /*
  * Copy from radeon_drv.h so we don't have to include both and have conflicting
@@ -139,6 +140,9 @@ extern int radeon_runtime_pm;
 #define RADEON_VA_RESERVED_SIZE                        (8 << 20)
 #define RADEON_IB_VM_MAX_SIZE                  (64 << 10)
 
+/* hard reset data */
+#define RADEON_ASIC_RESET_DATA                  0x39d5e86b
+
 /* reset flags */
 #define RADEON_RESET_GFX                       (1 << 0)
 #define RADEON_RESET_COMPUTE                   (1 << 1)
@@ -252,6 +256,7 @@ struct radeon_clock {
  * Power management
  */
 int radeon_pm_init(struct radeon_device *rdev);
+int radeon_pm_late_init(struct radeon_device *rdev);
 void radeon_pm_fini(struct radeon_device *rdev);
 void radeon_pm_compute_clocks(struct radeon_device *rdev);
 void radeon_pm_suspend(struct radeon_device *rdev);
@@ -413,6 +418,11 @@ struct radeon_mman {
        struct ttm_bo_device            bdev;
        bool                            mem_global_referenced;
        bool                            initialized;
+
+#if defined(CONFIG_DEBUG_FS)
+       struct dentry                   *vram;
+       struct dentry                   *gtt;
+#endif
 };
 
 /* bo virtual address in a specific vm */
@@ -779,13 +789,11 @@ struct radeon_ring {
        volatile uint32_t       *ring;
        unsigned                rptr;
        unsigned                rptr_offs;
-       unsigned                rptr_reg;
        unsigned                rptr_save_reg;
        u64                     next_rptr_gpu_addr;
        volatile u32            *next_rptr_cpu_addr;
        unsigned                wptr;
        unsigned                wptr_old;
-       unsigned                wptr_reg;
        unsigned                ring_size;
        unsigned                ring_free_dw;
        int                     count_dw;
@@ -859,6 +867,8 @@ struct radeon_vm {
        struct radeon_fence             *fence;
        /* last flush or NULL if we still need to flush */
        struct radeon_fence             *last_flush;
+       /* last use of vmid */
+       struct radeon_fence             *last_id_use;
 };
 
 struct radeon_vm_manager {
@@ -949,7 +959,7 @@ unsigned radeon_ring_backup(struct radeon_device *rdev, struct radeon_ring *ring
 int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring,
                        unsigned size, uint32_t *data);
 int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *cp, unsigned ring_size,
-                    unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, u32 nop);
+                    unsigned rptr_offs, u32 nop);
 void radeon_ring_fini(struct radeon_device *rdev, struct radeon_ring *cp);
 
 
@@ -1775,6 +1785,7 @@ struct radeon_asic {
                int (*init)(struct radeon_device *rdev);
                void (*setup_asic)(struct radeon_device *rdev);
                int (*enable)(struct radeon_device *rdev);
+               int (*late_enable)(struct radeon_device *rdev);
                void (*disable)(struct radeon_device *rdev);
                int (*pre_set_power_state)(struct radeon_device *rdev);
                int (*set_power_state)(struct radeon_device *rdev);
@@ -2650,6 +2661,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 #define radeon_dpm_init(rdev) rdev->asic->dpm.init((rdev))
 #define radeon_dpm_setup_asic(rdev) rdev->asic->dpm.setup_asic((rdev))
 #define radeon_dpm_enable(rdev) rdev->asic->dpm.enable((rdev))
+#define radeon_dpm_late_enable(rdev) rdev->asic->dpm.late_enable((rdev))
 #define radeon_dpm_disable(rdev) rdev->asic->dpm.disable((rdev))
 #define radeon_dpm_pre_set_power_state(rdev) rdev->asic->dpm.pre_set_power_state((rdev))
 #define radeon_dpm_set_power_state(rdev) rdev->asic->dpm.set_power_state((rdev))
@@ -2668,6 +2680,7 @@ void radeon_ring_write(struct radeon_ring *ring, uint32_t v);
 /* Common functions */
 /* AGP */
 extern int radeon_gpu_reset(struct radeon_device *rdev);
+extern void radeon_pci_config_reset(struct radeon_device *rdev);
 extern void r600_set_bios_scratch_engine_hung(struct radeon_device *rdev, bool hung);
 extern void radeon_agp_disable(struct radeon_device *rdev);
 extern int radeon_modeset_init(struct radeon_device *rdev);
index c0425bb6223a99fae5eab07a069ab73ace19eec7..f74db43346fd86f4658e11cc62e6e08134127936 100644 (file)
@@ -182,9 +182,9 @@ static struct radeon_asic_ring r100_gfx_ring = {
        .ring_test = &r100_ring_test,
        .ib_test = &r100_ib_test,
        .is_lockup = &r100_gpu_is_lockup,
-       .get_rptr = &radeon_ring_generic_get_rptr,
-       .get_wptr = &radeon_ring_generic_get_wptr,
-       .set_wptr = &radeon_ring_generic_set_wptr,
+       .get_rptr = &r100_gfx_get_rptr,
+       .get_wptr = &r100_gfx_get_wptr,
+       .set_wptr = &r100_gfx_set_wptr,
 };
 
 static struct radeon_asic r100_asic = {
@@ -330,9 +330,9 @@ static struct radeon_asic_ring r300_gfx_ring = {
        .ring_test = &r100_ring_test,
        .ib_test = &r100_ib_test,
        .is_lockup = &r100_gpu_is_lockup,
-       .get_rptr = &radeon_ring_generic_get_rptr,
-       .get_wptr = &radeon_ring_generic_get_wptr,
-       .set_wptr = &radeon_ring_generic_set_wptr,
+       .get_rptr = &r100_gfx_get_rptr,
+       .get_wptr = &r100_gfx_get_wptr,
+       .set_wptr = &r100_gfx_set_wptr,
 };
 
 static struct radeon_asic r300_asic = {
@@ -883,9 +883,9 @@ static struct radeon_asic_ring r600_gfx_ring = {
        .ring_test = &r600_ring_test,
        .ib_test = &r600_ib_test,
        .is_lockup = &r600_gfx_is_lockup,
-       .get_rptr = &radeon_ring_generic_get_rptr,
-       .get_wptr = &radeon_ring_generic_get_wptr,
-       .set_wptr = &radeon_ring_generic_set_wptr,
+       .get_rptr = &r600_gfx_get_rptr,
+       .get_wptr = &r600_gfx_get_wptr,
+       .set_wptr = &r600_gfx_set_wptr,
 };
 
 static struct radeon_asic_ring r600_dma_ring = {
@@ -1045,6 +1045,7 @@ static struct radeon_asic rv6xx_asic = {
                .init = &rv6xx_dpm_init,
                .setup_asic = &rv6xx_setup_asic,
                .enable = &rv6xx_dpm_enable,
+               .late_enable = &r600_dpm_late_enable,
                .disable = &rv6xx_dpm_disable,
                .pre_set_power_state = &r600_dpm_pre_set_power_state,
                .set_power_state = &rv6xx_dpm_set_power_state,
@@ -1135,6 +1136,7 @@ static struct radeon_asic rs780_asic = {
                .init = &rs780_dpm_init,
                .setup_asic = &rs780_dpm_setup_asic,
                .enable = &rs780_dpm_enable,
+               .late_enable = &r600_dpm_late_enable,
                .disable = &rs780_dpm_disable,
                .pre_set_power_state = &r600_dpm_pre_set_power_state,
                .set_power_state = &rs780_dpm_set_power_state,
@@ -1239,6 +1241,7 @@ static struct radeon_asic rv770_asic = {
                .init = &rv770_dpm_init,
                .setup_asic = &rv770_dpm_setup_asic,
                .enable = &rv770_dpm_enable,
+               .late_enable = &rv770_dpm_late_enable,
                .disable = &rv770_dpm_disable,
                .pre_set_power_state = &r600_dpm_pre_set_power_state,
                .set_power_state = &rv770_dpm_set_power_state,
@@ -1267,9 +1270,9 @@ static struct radeon_asic_ring evergreen_gfx_ring = {
        .ring_test = &r600_ring_test,
        .ib_test = &r600_ib_test,
        .is_lockup = &evergreen_gfx_is_lockup,
-       .get_rptr = &radeon_ring_generic_get_rptr,
-       .get_wptr = &radeon_ring_generic_get_wptr,
-       .set_wptr = &radeon_ring_generic_set_wptr,
+       .get_rptr = &r600_gfx_get_rptr,
+       .get_wptr = &r600_gfx_get_wptr,
+       .set_wptr = &r600_gfx_set_wptr,
 };
 
 static struct radeon_asic_ring evergreen_dma_ring = {
@@ -1357,6 +1360,7 @@ static struct radeon_asic evergreen_asic = {
                .init = &cypress_dpm_init,
                .setup_asic = &cypress_dpm_setup_asic,
                .enable = &cypress_dpm_enable,
+               .late_enable = &rv770_dpm_late_enable,
                .disable = &cypress_dpm_disable,
                .pre_set_power_state = &r600_dpm_pre_set_power_state,
                .set_power_state = &cypress_dpm_set_power_state,
@@ -1449,6 +1453,7 @@ static struct radeon_asic sumo_asic = {
                .init = &sumo_dpm_init,
                .setup_asic = &sumo_dpm_setup_asic,
                .enable = &sumo_dpm_enable,
+               .late_enable = &sumo_dpm_late_enable,
                .disable = &sumo_dpm_disable,
                .pre_set_power_state = &sumo_dpm_pre_set_power_state,
                .set_power_state = &sumo_dpm_set_power_state,
@@ -1540,6 +1545,7 @@ static struct radeon_asic btc_asic = {
                .init = &btc_dpm_init,
                .setup_asic = &btc_dpm_setup_asic,
                .enable = &btc_dpm_enable,
+               .late_enable = &rv770_dpm_late_enable,
                .disable = &btc_dpm_disable,
                .pre_set_power_state = &btc_dpm_pre_set_power_state,
                .set_power_state = &btc_dpm_set_power_state,
@@ -1570,9 +1576,9 @@ static struct radeon_asic_ring cayman_gfx_ring = {
        .ib_test = &r600_ib_test,
        .is_lockup = &cayman_gfx_is_lockup,
        .vm_flush = &cayman_vm_flush,
-       .get_rptr = &radeon_ring_generic_get_rptr,
-       .get_wptr = &radeon_ring_generic_get_wptr,
-       .set_wptr = &radeon_ring_generic_set_wptr,
+       .get_rptr = &cayman_gfx_get_rptr,
+       .get_wptr = &cayman_gfx_get_wptr,
+       .set_wptr = &cayman_gfx_set_wptr,
 };
 
 static struct radeon_asic_ring cayman_dma_ring = {
@@ -1585,9 +1591,9 @@ static struct radeon_asic_ring cayman_dma_ring = {
        .ib_test = &r600_dma_ib_test,
        .is_lockup = &cayman_dma_is_lockup,
        .vm_flush = &cayman_dma_vm_flush,
-       .get_rptr = &r600_dma_get_rptr,
-       .get_wptr = &r600_dma_get_wptr,
-       .set_wptr = &r600_dma_set_wptr
+       .get_rptr = &cayman_dma_get_rptr,
+       .get_wptr = &cayman_dma_get_wptr,
+       .set_wptr = &cayman_dma_set_wptr
 };
 
 static struct radeon_asic_ring cayman_uvd_ring = {
@@ -1683,6 +1689,7 @@ static struct radeon_asic cayman_asic = {
                .init = &ni_dpm_init,
                .setup_asic = &ni_dpm_setup_asic,
                .enable = &ni_dpm_enable,
+               .late_enable = &rv770_dpm_late_enable,
                .disable = &ni_dpm_disable,
                .pre_set_power_state = &ni_dpm_pre_set_power_state,
                .set_power_state = &ni_dpm_set_power_state,
@@ -1783,6 +1790,7 @@ static struct radeon_asic trinity_asic = {
                .init = &trinity_dpm_init,
                .setup_asic = &trinity_dpm_setup_asic,
                .enable = &trinity_dpm_enable,
+               .late_enable = &trinity_dpm_late_enable,
                .disable = &trinity_dpm_disable,
                .pre_set_power_state = &trinity_dpm_pre_set_power_state,
                .set_power_state = &trinity_dpm_set_power_state,
@@ -1813,9 +1821,9 @@ static struct radeon_asic_ring si_gfx_ring = {
        .ib_test = &r600_ib_test,
        .is_lockup = &si_gfx_is_lockup,
        .vm_flush = &si_vm_flush,
-       .get_rptr = &radeon_ring_generic_get_rptr,
-       .get_wptr = &radeon_ring_generic_get_wptr,
-       .set_wptr = &radeon_ring_generic_set_wptr,
+       .get_rptr = &cayman_gfx_get_rptr,
+       .get_wptr = &cayman_gfx_get_wptr,
+       .set_wptr = &cayman_gfx_set_wptr,
 };
 
 static struct radeon_asic_ring si_dma_ring = {
@@ -1828,9 +1836,9 @@ static struct radeon_asic_ring si_dma_ring = {
        .ib_test = &r600_dma_ib_test,
        .is_lockup = &si_dma_is_lockup,
        .vm_flush = &si_dma_vm_flush,
-       .get_rptr = &r600_dma_get_rptr,
-       .get_wptr = &r600_dma_get_wptr,
-       .set_wptr = &r600_dma_set_wptr,
+       .get_rptr = &cayman_dma_get_rptr,
+       .get_wptr = &cayman_dma_get_wptr,
+       .set_wptr = &cayman_dma_set_wptr,
 };
 
 static struct radeon_asic si_asic = {
@@ -1913,6 +1921,7 @@ static struct radeon_asic si_asic = {
                .init = &si_dpm_init,
                .setup_asic = &si_dpm_setup_asic,
                .enable = &si_dpm_enable,
+               .late_enable = &si_dpm_late_enable,
                .disable = &si_dpm_disable,
                .pre_set_power_state = &si_dpm_pre_set_power_state,
                .set_power_state = &si_dpm_set_power_state,
@@ -1943,9 +1952,9 @@ static struct radeon_asic_ring ci_gfx_ring = {
        .ib_test = &cik_ib_test,
        .is_lockup = &cik_gfx_is_lockup,
        .vm_flush = &cik_vm_flush,
-       .get_rptr = &radeon_ring_generic_get_rptr,
-       .get_wptr = &radeon_ring_generic_get_wptr,
-       .set_wptr = &radeon_ring_generic_set_wptr,
+       .get_rptr = &cik_gfx_get_rptr,
+       .get_wptr = &cik_gfx_get_wptr,
+       .set_wptr = &cik_gfx_set_wptr,
 };
 
 static struct radeon_asic_ring ci_cp_ring = {
@@ -1958,9 +1967,9 @@ static struct radeon_asic_ring ci_cp_ring = {
        .ib_test = &cik_ib_test,
        .is_lockup = &cik_gfx_is_lockup,
        .vm_flush = &cik_vm_flush,
-       .get_rptr = &cik_compute_ring_get_rptr,
-       .get_wptr = &cik_compute_ring_get_wptr,
-       .set_wptr = &cik_compute_ring_set_wptr,
+       .get_rptr = &cik_compute_get_rptr,
+       .get_wptr = &cik_compute_get_wptr,
+       .set_wptr = &cik_compute_set_wptr,
 };
 
 static struct radeon_asic_ring ci_dma_ring = {
@@ -1973,9 +1982,9 @@ static struct radeon_asic_ring ci_dma_ring = {
        .ib_test = &cik_sdma_ib_test,
        .is_lockup = &cik_sdma_is_lockup,
        .vm_flush = &cik_dma_vm_flush,
-       .get_rptr = &r600_dma_get_rptr,
-       .get_wptr = &r600_dma_get_wptr,
-       .set_wptr = &r600_dma_set_wptr,
+       .get_rptr = &cik_sdma_get_rptr,
+       .get_wptr = &cik_sdma_get_wptr,
+       .set_wptr = &cik_sdma_set_wptr,
 };
 
 static struct radeon_asic ci_asic = {
@@ -2058,6 +2067,7 @@ static struct radeon_asic ci_asic = {
                .init = &ci_dpm_init,
                .setup_asic = &ci_dpm_setup_asic,
                .enable = &ci_dpm_enable,
+               .late_enable = &ci_dpm_late_enable,
                .disable = &ci_dpm_disable,
                .pre_set_power_state = &ci_dpm_pre_set_power_state,
                .set_power_state = &ci_dpm_set_power_state,
@@ -2159,6 +2169,7 @@ static struct radeon_asic kv_asic = {
                .init = &kv_dpm_init,
                .setup_asic = &kv_dpm_setup_asic,
                .enable = &kv_dpm_enable,
+               .late_enable = &kv_dpm_late_enable,
                .disable = &kv_dpm_disable,
                .pre_set_power_state = &kv_dpm_pre_set_power_state,
                .set_power_state = &kv_dpm_set_power_state,
@@ -2449,7 +2460,7 @@ int radeon_asic_init(struct radeon_device *rdev)
                        rdev->cg_flags =
                                RADEON_CG_SUPPORT_GFX_MGCG |
                                RADEON_CG_SUPPORT_GFX_MGLS |
-                               /*RADEON_CG_SUPPORT_GFX_CGCG |*/
+                               RADEON_CG_SUPPORT_GFX_CGCG |
                                RADEON_CG_SUPPORT_GFX_CGLS |
                                RADEON_CG_SUPPORT_GFX_CGTS |
                                RADEON_CG_SUPPORT_GFX_CGTS_LS |
@@ -2468,7 +2479,7 @@ int radeon_asic_init(struct radeon_device *rdev)
                        rdev->cg_flags =
                                RADEON_CG_SUPPORT_GFX_MGCG |
                                RADEON_CG_SUPPORT_GFX_MGLS |
-                               /*RADEON_CG_SUPPORT_GFX_CGCG |*/
+                               RADEON_CG_SUPPORT_GFX_CGCG |
                                RADEON_CG_SUPPORT_GFX_CGLS |
                                RADEON_CG_SUPPORT_GFX_CGTS |
                                RADEON_CG_SUPPORT_GFX_CP_LS |
@@ -2493,7 +2504,7 @@ int radeon_asic_init(struct radeon_device *rdev)
                        rdev->cg_flags =
                                RADEON_CG_SUPPORT_GFX_MGCG |
                                RADEON_CG_SUPPORT_GFX_MGLS |
-                               /*RADEON_CG_SUPPORT_GFX_CGCG |*/
+                               RADEON_CG_SUPPORT_GFX_CGCG |
                                RADEON_CG_SUPPORT_GFX_CGLS |
                                RADEON_CG_SUPPORT_GFX_CGTS |
                                RADEON_CG_SUPPORT_GFX_CGTS_LS |
@@ -2521,7 +2532,7 @@ int radeon_asic_init(struct radeon_device *rdev)
                        rdev->cg_flags =
                                RADEON_CG_SUPPORT_GFX_MGCG |
                                RADEON_CG_SUPPORT_GFX_MGLS |
-                               /*RADEON_CG_SUPPORT_GFX_CGCG |*/
+                               RADEON_CG_SUPPORT_GFX_CGCG |
                                RADEON_CG_SUPPORT_GFX_CGLS |
                                RADEON_CG_SUPPORT_GFX_CGTS |
                                RADEON_CG_SUPPORT_GFX_CGTS_LS |
index c9fd97b58076bd366e57e7916f93de5435c58c52..b3bc433eed4c3bd832424051306a845461c90aa8 100644 (file)
@@ -47,13 +47,6 @@ u8 atombios_get_backlight_level(struct radeon_encoder *radeon_encoder);
 void radeon_legacy_set_backlight_level(struct radeon_encoder *radeon_encoder, u8 level);
 u8 radeon_legacy_get_backlight_level(struct radeon_encoder *radeon_encoder);
 
-u32 radeon_ring_generic_get_rptr(struct radeon_device *rdev,
-                                struct radeon_ring *ring);
-u32 radeon_ring_generic_get_wptr(struct radeon_device *rdev,
-                                struct radeon_ring *ring);
-void radeon_ring_generic_set_wptr(struct radeon_device *rdev,
-                                 struct radeon_ring *ring);
-
 /*
  * r100,rv100,rs100,rv200,rs200
  */
@@ -148,6 +141,13 @@ extern void r100_post_page_flip(struct radeon_device *rdev, int crtc);
 extern void r100_wait_for_vblank(struct radeon_device *rdev, int crtc);
 extern int r100_mc_wait_for_idle(struct radeon_device *rdev);
 
+u32 r100_gfx_get_rptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring);
+u32 r100_gfx_get_wptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring);
+void r100_gfx_set_wptr(struct radeon_device *rdev,
+                      struct radeon_ring *ring);
+
 /*
  * r200,rv250,rs300,rv280
  */
@@ -368,6 +368,12 @@ int r600_mc_wait_for_idle(struct radeon_device *rdev);
 int r600_pcie_gart_init(struct radeon_device *rdev);
 void r600_scratch_init(struct radeon_device *rdev);
 int r600_init_microcode(struct radeon_device *rdev);
+u32 r600_gfx_get_rptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring);
+u32 r600_gfx_get_wptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring);
+void r600_gfx_set_wptr(struct radeon_device *rdev,
+                      struct radeon_ring *ring);
 /* r600 irq */
 int r600_irq_process(struct radeon_device *rdev);
 int r600_irq_init(struct radeon_device *rdev);
@@ -392,6 +398,7 @@ int rv6xx_get_temp(struct radeon_device *rdev);
 int r600_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
 int r600_dpm_pre_set_power_state(struct radeon_device *rdev);
 void r600_dpm_post_set_power_state(struct radeon_device *rdev);
+int r600_dpm_late_enable(struct radeon_device *rdev);
 /* r600 dma */
 uint32_t r600_dma_get_rptr(struct radeon_device *rdev,
                           struct radeon_ring *ring);
@@ -454,6 +461,7 @@ int rv770_get_temp(struct radeon_device *rdev);
 /* rv7xx pm */
 int rv770_dpm_init(struct radeon_device *rdev);
 int rv770_dpm_enable(struct radeon_device *rdev);
+int rv770_dpm_late_enable(struct radeon_device *rdev);
 void rv770_dpm_disable(struct radeon_device *rdev);
 int rv770_dpm_set_power_state(struct radeon_device *rdev);
 void rv770_dpm_setup_asic(struct radeon_device *rdev);
@@ -545,6 +553,7 @@ u32 btc_dpm_get_mclk(struct radeon_device *rdev, bool low);
 bool btc_dpm_vblank_too_short(struct radeon_device *rdev);
 int sumo_dpm_init(struct radeon_device *rdev);
 int sumo_dpm_enable(struct radeon_device *rdev);
+int sumo_dpm_late_enable(struct radeon_device *rdev);
 void sumo_dpm_disable(struct radeon_device *rdev);
 int sumo_dpm_pre_set_power_state(struct radeon_device *rdev);
 int sumo_dpm_set_power_state(struct radeon_device *rdev);
@@ -591,6 +600,19 @@ void cayman_dma_vm_set_page(struct radeon_device *rdev,
 
 void cayman_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
 
+u32 cayman_gfx_get_rptr(struct radeon_device *rdev,
+                       struct radeon_ring *ring);
+u32 cayman_gfx_get_wptr(struct radeon_device *rdev,
+                       struct radeon_ring *ring);
+void cayman_gfx_set_wptr(struct radeon_device *rdev,
+                        struct radeon_ring *ring);
+uint32_t cayman_dma_get_rptr(struct radeon_device *rdev,
+                            struct radeon_ring *ring);
+uint32_t cayman_dma_get_wptr(struct radeon_device *rdev,
+                            struct radeon_ring *ring);
+void cayman_dma_set_wptr(struct radeon_device *rdev,
+                        struct radeon_ring *ring);
+
 int ni_dpm_init(struct radeon_device *rdev);
 void ni_dpm_setup_asic(struct radeon_device *rdev);
 int ni_dpm_enable(struct radeon_device *rdev);
@@ -610,6 +632,7 @@ int ni_dpm_force_performance_level(struct radeon_device *rdev,
 bool ni_dpm_vblank_too_short(struct radeon_device *rdev);
 int trinity_dpm_init(struct radeon_device *rdev);
 int trinity_dpm_enable(struct radeon_device *rdev);
+int trinity_dpm_late_enable(struct radeon_device *rdev);
 void trinity_dpm_disable(struct radeon_device *rdev);
 int trinity_dpm_pre_set_power_state(struct radeon_device *rdev);
 int trinity_dpm_set_power_state(struct radeon_device *rdev);
@@ -669,6 +692,7 @@ int si_get_temp(struct radeon_device *rdev);
 int si_dpm_init(struct radeon_device *rdev);
 void si_dpm_setup_asic(struct radeon_device *rdev);
 int si_dpm_enable(struct radeon_device *rdev);
+int si_dpm_late_enable(struct radeon_device *rdev);
 void si_dpm_disable(struct radeon_device *rdev);
 int si_dpm_pre_set_power_state(struct radeon_device *rdev);
 int si_dpm_set_power_state(struct radeon_device *rdev);
@@ -739,17 +763,30 @@ void cik_sdma_vm_set_page(struct radeon_device *rdev,
                          uint32_t incr, uint32_t flags);
 void cik_dma_vm_flush(struct radeon_device *rdev, int ridx, struct radeon_vm *vm);
 int cik_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib);
-u32 cik_compute_ring_get_rptr(struct radeon_device *rdev,
-                             struct radeon_ring *ring);
-u32 cik_compute_ring_get_wptr(struct radeon_device *rdev,
-                             struct radeon_ring *ring);
-void cik_compute_ring_set_wptr(struct radeon_device *rdev,
-                              struct radeon_ring *ring);
+u32 cik_gfx_get_rptr(struct radeon_device *rdev,
+                    struct radeon_ring *ring);
+u32 cik_gfx_get_wptr(struct radeon_device *rdev,
+                    struct radeon_ring *ring);
+void cik_gfx_set_wptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring);
+u32 cik_compute_get_rptr(struct radeon_device *rdev,
+                        struct radeon_ring *ring);
+u32 cik_compute_get_wptr(struct radeon_device *rdev,
+                        struct radeon_ring *ring);
+void cik_compute_set_wptr(struct radeon_device *rdev,
+                         struct radeon_ring *ring);
+u32 cik_sdma_get_rptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring);
+u32 cik_sdma_get_wptr(struct radeon_device *rdev,
+                     struct radeon_ring *ring);
+void cik_sdma_set_wptr(struct radeon_device *rdev,
+                      struct radeon_ring *ring);
 int ci_get_temp(struct radeon_device *rdev);
 int kv_get_temp(struct radeon_device *rdev);
 
 int ci_dpm_init(struct radeon_device *rdev);
 int ci_dpm_enable(struct radeon_device *rdev);
+int ci_dpm_late_enable(struct radeon_device *rdev);
 void ci_dpm_disable(struct radeon_device *rdev);
 int ci_dpm_pre_set_power_state(struct radeon_device *rdev);
 int ci_dpm_set_power_state(struct radeon_device *rdev);
@@ -770,6 +807,7 @@ void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
 
 int kv_dpm_init(struct radeon_device *rdev);
 int kv_dpm_enable(struct radeon_device *rdev);
+int kv_dpm_late_enable(struct radeon_device *rdev);
 void kv_dpm_disable(struct radeon_device *rdev);
 int kv_dpm_pre_set_power_state(struct radeon_device *rdev);
 int kv_dpm_set_power_state(struct radeon_device *rdev);
index 5c39bf7c3d88668bad65ef9667de82a0a145f196..30844814c25a3c931a286b6823b54c88a0bbf348 100644 (file)
 #include "atom.h"
 #include "atom-bits.h"
 
-/* from radeon_encoder.c */
-extern uint32_t
-radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device,
-                       uint8_t dac);
-extern void radeon_link_encoder_connector(struct drm_device *dev);
 extern void
 radeon_add_atom_encoder(struct drm_device *dev, uint32_t encoder_enum,
                        uint32_t supported_device, u16 caps);
 
-/* from radeon_connector.c */
-extern void
-radeon_add_atom_connector(struct drm_device *dev,
-                         uint32_t connector_id,
-                         uint32_t supported_device,
-                         int connector_type,
-                         struct radeon_i2c_bus_rec *i2c_bus,
-                         uint32_t igp_lane_info,
-                         uint16_t connector_object_id,
-                         struct radeon_hpd *hpd,
-                         struct radeon_router *router);
-
 /* from radeon_legacy_encoder.c */
 extern void
 radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum,
@@ -1528,6 +1511,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                                le16_to_cpu(ss_assign->v1.usSpreadSpectrumPercentage);
                                        ss->type = ss_assign->v1.ucSpreadSpectrumMode;
                                        ss->rate = le16_to_cpu(ss_assign->v1.usSpreadRateInKhz);
+                                       ss->percentage_divider = 100;
                                        return true;
                                }
                                ss_assign = (union asic_ss_assignment *)
@@ -1545,6 +1529,7 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                                le16_to_cpu(ss_assign->v2.usSpreadSpectrumPercentage);
                                        ss->type = ss_assign->v2.ucSpreadSpectrumMode;
                                        ss->rate = le16_to_cpu(ss_assign->v2.usSpreadRateIn10Hz);
+                                       ss->percentage_divider = 100;
                                        if ((crev == 2) &&
                                            ((id == ASIC_INTERNAL_ENGINE_SS) ||
                                             (id == ASIC_INTERNAL_MEMORY_SS)))
@@ -1566,6 +1551,11 @@ bool radeon_atombios_get_asic_ss_info(struct radeon_device *rdev,
                                                le16_to_cpu(ss_assign->v3.usSpreadSpectrumPercentage);
                                        ss->type = ss_assign->v3.ucSpreadSpectrumMode;
                                        ss->rate = le16_to_cpu(ss_assign->v3.usSpreadRateIn10Hz);
+                                       if (ss_assign->v3.ucSpreadSpectrumMode &
+                                           SS_MODE_V3_PERCENTAGE_DIV_BY_1000_MASK)
+                                               ss->percentage_divider = 1000;
+                                       else
+                                               ss->percentage_divider = 100;
                                        if ((id == ASIC_INTERNAL_ENGINE_SS) ||
                                            (id == ASIC_INTERNAL_MEMORY_SS))
                                                ss->rate /= 100;
@@ -1809,7 +1799,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
                if (misc & ATOM_DOUBLE_CLOCK_MODE)
                        mode->flags |= DRM_MODE_FLAG_DBLSCAN;
 
-               mode->clock = le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
+               mode->crtc_clock = mode->clock =
+                       le16_to_cpu(tv_info->aModeTimings[index].usPixelClock) * 10;
 
                if (index == 1) {
                        /* PAL timings appear to have wrong values for totals */
@@ -1852,7 +1843,8 @@ bool radeon_atom_get_tv_timings(struct radeon_device *rdev, int index,
                if (misc & ATOM_DOUBLE_CLOCK_MODE)
                        mode->flags |= DRM_MODE_FLAG_DBLSCAN;
 
-               mode->clock = le16_to_cpu(dtd_timings->usPixClk) * 10;
+               mode->crtc_clock = mode->clock =
+                       le16_to_cpu(dtd_timings->usPixClk) * 10;
                break;
        }
        return true;
@@ -3884,16 +3876,18 @@ int radeon_atom_init_mc_reg_table(struct radeon_device *rdev,
                                                        ((u8 *)format + sizeof(ATOM_INIT_REG_INDEX_FORMAT));
                                        }
                                        reg_table->last = i;
-                                       while ((*(u32 *)reg_data != END_OF_REG_DATA_BLOCK) &&
+                                       while ((le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK) &&
                                               (num_ranges < VBIOS_MAX_AC_TIMING_ENTRIES)) {
-                                               t_mem_id = (u8)((*(u32 *)reg_data & MEM_ID_MASK) >> MEM_ID_SHIFT);
+                                               t_mem_id = (u8)((le32_to_cpu(*(u32 *)reg_data) & MEM_ID_MASK)
+                                                               >> MEM_ID_SHIFT);
                                                if (module_index == t_mem_id) {
                                                        reg_table->mc_reg_table_entry[num_ranges].mclk_max =
-                                                               (u32)((*(u32 *)reg_data & CLOCK_RANGE_MASK) >> CLOCK_RANGE_SHIFT);
+                                                               (u32)((le32_to_cpu(*(u32 *)reg_data) & CLOCK_RANGE_MASK)
+                                                                     >> CLOCK_RANGE_SHIFT);
                                                        for (i = 0, j = 1; i < reg_table->last; i++) {
                                                                if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_FROM_TABLE) {
                                                                        reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
-                                                                               (u32)*((u32 *)reg_data + j);
+                                                                               (u32)le32_to_cpu(*((u32 *)reg_data + j));
                                                                        j++;
                                                                } else if ((reg_table->mc_reg_address[i].pre_reg_data & LOW_NIBBLE_MASK) == DATA_EQU_PREV) {
                                                                        reg_table->mc_reg_table_entry[num_ranges].mc_data[i] =
@@ -3905,7 +3899,7 @@ int radeon_atom_init_mc_reg_table(struct radeon_device *rdev,
                                                reg_data = (ATOM_MEMORY_SETTING_DATA_BLOCK *)
                                                        ((u8 *)reg_data + le16_to_cpu(reg_block->usRegDataBlkSize));
                                        }
-                                       if (*(u32 *)reg_data != END_OF_REG_DATA_BLOCK)
+                                       if (le32_to_cpu(*(u32 *)reg_data) != END_OF_REG_DATA_BLOCK)
                                                return -EINVAL;
                                        reg_table->num_entries = num_ranges;
                                } else
@@ -3944,6 +3938,10 @@ void radeon_atom_initialize_bios_scratch_regs(struct drm_device *dev)
        /* tell the bios not to handle mode switching */
        bios_6_scratch |= ATOM_S6_ACC_BLOCK_DISPLAY_SWITCH;
 
+       /* clear the vbios dpms state */
+       if (ASIC_IS_DCE4(rdev))
+               bios_2_scratch &= ~ATOM_S2_DEVICE_DPMS_STATE;
+
        if (rdev->family >= CHIP_R600) {
                WREG32(R600_BIOS_2_SCRATCH, bios_2_scratch);
                WREG32(R600_BIOS_6_SCRATCH, bios_6_scratch);
index 68ce360560190af6505856452658e450d3f6878a..6651177110f08cd5afb9088f4849ad3f987f5a1b 100644 (file)
 #include <asm/pci-bridge.h>
 #endif /* CONFIG_PPC_PMAC */
 
-/* from radeon_encoder.c */
-extern uint32_t
-radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device,
-                       uint8_t dac);
-extern void radeon_link_encoder_connector(struct drm_device *dev);
-
-/* from radeon_connector.c */
-extern void
-radeon_add_legacy_connector(struct drm_device *dev,
-                           uint32_t connector_id,
-                           uint32_t supported_device,
-                           int connector_type,
-                           struct radeon_i2c_bus_rec *i2c_bus,
-                           uint16_t connector_object_id,
-                           struct radeon_hpd *hpd);
-
 /* from radeon_legacy_encoder.c */
 extern void
 radeon_add_legacy_encoder(struct drm_device *dev, uint32_t encoder_enum,
index 20a768ac89a8e6532b33cbb3114928afc98749b7..82d4f865546ed9024b4078d67bfdd947f08a1060 100644 (file)
 
 #include <linux/pm_runtime.h>
 
-extern void
-radeon_combios_connected_scratch_regs(struct drm_connector *connector,
-                                     struct drm_encoder *encoder,
-                                     bool connected);
-extern void
-radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
-                                      struct drm_encoder *encoder,
-                                      bool connected);
-
 void radeon_connector_hotplug(struct drm_connector *connector)
 {
        struct drm_device *dev = connector->dev;
index 3cae2bbc1854d73dda35f13f0b8cfc3201dc2c25..bb0d5c3a8311bf0dc274c2b47930078d7e657852 100644 (file)
@@ -2020,10 +2020,10 @@ static int radeon_cp_get_buffers(struct drm_device *dev,
 
                buf->file_priv = file_priv;
 
-               if (DRM_COPY_TO_USER(&d->request_indices[i], &buf->idx,
+               if (copy_to_user(&d->request_indices[i], &buf->idx,
                                     sizeof(buf->idx)))
                        return -EFAULT;
-               if (DRM_COPY_TO_USER(&d->request_sizes[i], &buf->total,
+               if (copy_to_user(&d->request_sizes[i], &buf->total,
                                     sizeof(buf->total)))
                        return -EFAULT;
 
@@ -2228,7 +2228,7 @@ void radeon_commit_ring(drm_radeon_private_t *dev_priv)
 
        dev_priv->ring.tail &= dev_priv->ring.tail_mask;
 
-       DRM_MEMORYBARRIER();
+       mb();
        GET_RING_HEAD( dev_priv );
 
        if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_R600) {
index 0b366169d64de55c52e4c2d9c26d1c3b9db19b2d..dfb5a1db87d4a8651fd3a9bf7494d14287af7803 100644 (file)
@@ -138,7 +138,7 @@ static int radeon_cs_get_ring(struct radeon_cs_parser *p, u32 ring, s32 priority
                                p->ring = R600_RING_TYPE_DMA_INDEX;
                        else
                                p->ring = CAYMAN_RING_TYPE_DMA1_INDEX;
-               } else if (p->rdev->family >= CHIP_R600) {
+               } else if (p->rdev->family >= CHIP_RV770) {
                        p->ring = R600_RING_TYPE_DMA_INDEX;
                } else {
                        return -EINVAL;
@@ -192,7 +192,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
                return -ENOMEM;
        }
        chunk_array_ptr = (uint64_t *)(unsigned long)(cs->chunks);
-       if (DRM_COPY_FROM_USER(p->chunks_array, chunk_array_ptr,
+       if (copy_from_user(p->chunks_array, chunk_array_ptr,
                               sizeof(uint64_t)*cs->num_chunks)) {
                return -EFAULT;
        }
@@ -208,7 +208,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
                uint32_t __user *cdata;
 
                chunk_ptr = (void __user*)(unsigned long)p->chunks_array[i];
-               if (DRM_COPY_FROM_USER(&user_chunk, chunk_ptr,
+               if (copy_from_user(&user_chunk, chunk_ptr,
                                       sizeof(struct drm_radeon_cs_chunk))) {
                        return -EFAULT;
                }
@@ -252,7 +252,7 @@ int radeon_cs_parser_init(struct radeon_cs_parser *p, void *data)
                if (p->chunks[i].kdata == NULL) {
                        return -ENOMEM;
                }
-               if (DRM_COPY_FROM_USER(p->chunks[i].kdata, cdata, size)) {
+               if (copy_from_user(p->chunks[i].kdata, cdata, size)) {
                        return -EFAULT;
                }
                if (p->chunks[i].chunk_id == RADEON_CHUNK_ID_FLAGS) {
@@ -472,7 +472,7 @@ static int radeon_cs_ib_fill(struct radeon_device *rdev, struct radeon_cs_parser
                        }
                        parser->const_ib.is_const_ib = true;
                        parser->const_ib.length_dw = ib_chunk->length_dw;
-                       if (DRM_COPY_FROM_USER(parser->const_ib.ptr,
+                       if (copy_from_user(parser->const_ib.ptr,
                                               ib_chunk->user_ptr,
                                               ib_chunk->length_dw * 4))
                                return -EFAULT;
@@ -495,7 +495,7 @@ static int radeon_cs_ib_fill(struct radeon_device *rdev, struct radeon_cs_parser
        parser->ib.length_dw = ib_chunk->length_dw;
        if (ib_chunk->kdata)
                memcpy(parser->ib.ptr, ib_chunk->kdata, ib_chunk->length_dw * 4);
-       else if (DRM_COPY_FROM_USER(parser->ib.ptr, ib_chunk->user_ptr, ib_chunk->length_dw * 4))
+       else if (copy_from_user(parser->ib.ptr, ib_chunk->user_ptr, ib_chunk->length_dw * 4))
                return -EFAULT;
        return 0;
 }
index 39b033b441d2a6f76e8d021df7085568538887b3..b012cbbc3ed5a9b892b433eff0ee5f3134a130de 100644 (file)
@@ -144,6 +144,11 @@ void radeon_program_register_sequence(struct radeon_device *rdev,
        }
 }
 
+void radeon_pci_config_reset(struct radeon_device *rdev)
+{
+       pci_write_config_dword(rdev->pdev, 0x7c, RADEON_ASIC_RESET_DATA);
+}
+
 /**
  * radeon_surface_init - Clear GPU surface registers.
  *
@@ -249,7 +254,7 @@ void radeon_scratch_free(struct radeon_device *rdev, uint32_t reg)
  * Init doorbell driver information (CIK)
  * Returns 0 on success, error on failure.
  */
-int radeon_doorbell_init(struct radeon_device *rdev)
+static int radeon_doorbell_init(struct radeon_device *rdev)
 {
        /* doorbell bar mapping */
        rdev->doorbell.base = pci_resource_start(rdev->pdev, 2);
@@ -278,7 +283,7 @@ int radeon_doorbell_init(struct radeon_device *rdev)
  *
  * Tear down doorbell driver information (CIK)
  */
-void radeon_doorbell_fini(struct radeon_device *rdev)
+static void radeon_doorbell_fini(struct radeon_device *rdev)
 {
        iounmap(rdev->doorbell.ptr);
        rdev->doorbell.ptr = NULL;
@@ -1330,6 +1335,7 @@ int radeon_device_init(struct radeon_device *rdev,
                if (r)
                        return r;
        }
+
        if ((radeon_testing & 1)) {
                if (rdev->accel_working)
                        radeon_test_moves(rdev);
@@ -1455,7 +1461,6 @@ int radeon_suspend_kms(struct drm_device *dev, bool suspend, bool fbcon)
 
        radeon_save_bios_scratch_regs(rdev);
 
-       radeon_pm_suspend(rdev);
        radeon_suspend(rdev);
        radeon_hpd_fini(rdev);
        /* evict remaining vram memory */
@@ -1516,14 +1521,22 @@ int radeon_resume_kms(struct drm_device *dev, bool resume, bool fbcon)
        if (r)
                DRM_ERROR("ib ring test failed (%d).\n", r);
 
-       radeon_pm_resume(rdev);
+       if (rdev->pm.dpm_enabled) {
+               /* do dpm late init */
+               r = radeon_pm_late_init(rdev);
+               if (r) {
+                       rdev->pm.dpm_enabled = false;
+                       DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
+               }
+       }
+
        radeon_restore_bios_scratch_regs(rdev);
 
        if (fbcon) {
                radeon_fbdev_set_suspend(rdev, 0);
                console_unlock();
        }
-       
+
        /* init dig PHYs, disp eng pll */
        if (rdev->is_atom_bios) {
                radeon_atom_encoder_init(rdev);
index 7b253815a3237153b668d660e9ef7d56642597ec..d680608f6f5bc9a80e879b4f24769f8a9ffb1e8c 100644 (file)
@@ -306,7 +306,7 @@ void radeon_crtc_handle_flip(struct radeon_device *rdev, int crtc_id)
         * to complete in this vblank?
         */
        if (update_pending &&
-           (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id,
+           (DRM_SCANOUTPOS_VALID & radeon_get_crtc_scanoutpos(rdev->ddev, crtc_id, 0,
                                                               &vpos, &hpos, NULL, NULL)) &&
            ((vpos >= (99 * rdev->mode_info.crtcs[crtc_id]->base.hwmode.crtc_vdisplay)/100) ||
             (vpos < 0 && !ASIC_IS_AVIVO(rdev)))) {
@@ -1464,12 +1464,22 @@ int radeon_modeset_init(struct radeon_device *rdev)
        /* setup afmt */
        radeon_afmt_init(rdev);
 
-       /* Initialize power management */
-       radeon_pm_init(rdev);
-
        radeon_fbdev_init(rdev);
        drm_kms_helper_poll_init(rdev->ddev);
 
+       if (rdev->pm.dpm_enabled) {
+               /* do dpm late init */
+               ret = radeon_pm_late_init(rdev);
+               if (ret) {
+                       rdev->pm.dpm_enabled = false;
+                       DRM_ERROR("radeon_pm_late_init failed, disabling dpm\n");
+               }
+               /* set the dpm state for PX since there won't be
+                * a modeset to call this.
+                */
+               radeon_pm_compute_clocks(rdev);
+       }
+
        return 0;
 }
 
@@ -1477,7 +1487,6 @@ void radeon_modeset_fini(struct radeon_device *rdev)
 {
        radeon_fbdev_fini(rdev);
        kfree(rdev->mode_info.bios_hardcoded_edid);
-       radeon_pm_fini(rdev);
 
        if (rdev->mode_info.mode_config_initialized) {
                radeon_afmt_fini(rdev);
@@ -1601,6 +1610,7 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
  *
  * \param dev Device to query.
  * \param crtc Crtc to query.
+ * \param flags Flags from caller (DRM_CALLED_FROM_VBLIRQ or 0).
  * \param *vpos Location where vertical scanout position should be stored.
  * \param *hpos Location where horizontal scanout position should go.
  * \param *stime Target location for timestamp taken immediately before
@@ -1622,8 +1632,8 @@ bool radeon_crtc_scaling_mode_fixup(struct drm_crtc *crtc,
  * unknown small number of scanlines wrt. real scanout position.
  *
  */
-int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int *hpos,
-                              ktime_t *stime, ktime_t *etime)
+int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, unsigned int flags,
+                              int *vpos, int *hpos, ktime_t *stime, ktime_t *etime)
 {
        u32 stat_crtc = 0, vbl = 0, position = 0;
        int vbl_start, vbl_end, vtotal, ret = 0;
@@ -1765,5 +1775,27 @@ int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc, int *vpos, int
        if (in_vbl)
                ret |= DRM_SCANOUTPOS_INVBL;
 
+       /* Is vpos outside nominal vblank area, but less than
+        * 1/100 of a frame height away from start of vblank?
+        * If so, assume this isn't a massively delayed vblank
+        * interrupt, but a vblank interrupt that fired a few
+        * microseconds before true start of vblank. Compensate
+        * by adding a full frame duration to the final timestamp.
+        * Happens, e.g., on ATI R500, R600.
+        *
+        * We only do this if DRM_CALLED_FROM_VBLIRQ.
+        */
+       if ((flags & DRM_CALLED_FROM_VBLIRQ) && !in_vbl) {
+               vbl_start = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vdisplay;
+               vtotal = rdev->mode_info.crtcs[crtc]->base.hwmode.crtc_vtotal;
+
+               if (vbl_start - *vpos < vtotal / 100) {
+                       *vpos -= vtotal;
+
+                       /* Signal this correction as "applied". */
+                       ret |= 0x8;
+               }
+       }
+
        return ret;
 }
index db39ea36bf22fc396da63e5a157adf42e752e712..ec8c388eec176e8c36e343ff4182634d3708bc84 100644 (file)
@@ -102,13 +102,14 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
 void radeon_driver_irq_preinstall_kms(struct drm_device *dev);
 int radeon_driver_irq_postinstall_kms(struct drm_device *dev);
 void radeon_driver_irq_uninstall_kms(struct drm_device *dev);
-irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS);
+irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg);
 void radeon_gem_object_free(struct drm_gem_object *obj);
 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);
 extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
+                                     unsigned int flags,
                                      int *vpos, int *hpos, ktime_t *stime,
                                      ktime_t *etime);
 extern const struct drm_ioctl_desc radeon_ioctls_kms[];
@@ -168,6 +169,7 @@ int radeon_fastfb = 0;
 int radeon_dpm = -1;
 int radeon_aspm = -1;
 int radeon_runtime_pm = -1;
+int radeon_hard_reset = 0;
 
 MODULE_PARM_DESC(no_wb, "Disable AGP writeback for scratch registers");
 module_param_named(no_wb, radeon_no_wb, int, 0444);
@@ -232,6 +234,9 @@ module_param_named(aspm, radeon_aspm, int, 0444);
 MODULE_PARM_DESC(runpm, "PX runtime pm (1 = force enable, 0 = disable, -1 = PX only default)");
 module_param_named(runpm, radeon_runtime_pm, int, 0444);
 
+MODULE_PARM_DESC(hard_reset, "PCI config reset (1 = force enable, 0 = disable (default))");
+module_param_named(hard_reset, radeon_hard_reset, int, 0444);
+
 static struct pci_device_id pciidlist[] = {
        radeon_PCI_IDS
 };
@@ -400,6 +405,9 @@ static int radeon_pmops_runtime_suspend(struct device *dev)
        if (radeon_runtime_pm == 0)
                return -EINVAL;
 
+       if (radeon_runtime_pm == -1 && !radeon_is_px())
+               return -EINVAL;
+
        drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
        drm_kms_helper_poll_disable(drm_dev);
        vga_switcheroo_set_dynamic_switch(pdev, VGA_SWITCHEROO_OFF);
@@ -422,6 +430,9 @@ static int radeon_pmops_runtime_resume(struct device *dev)
        if (radeon_runtime_pm == 0)
                return -EINVAL;
 
+       if (radeon_runtime_pm == -1 && !radeon_is_px())
+               return -EINVAL;
+
        drm_dev->switch_power_state = DRM_SWITCH_POWER_CHANGING;
 
        pci_set_power_state(pdev, PCI_D0);
index 00e0d449021c343015540ea3baf1028b85a10090..dafd812e45710b0ffed36c33f3e37de20ec64733 100644 (file)
@@ -405,7 +405,7 @@ extern void radeon_do_release(struct drm_device * dev);
 extern u32 radeon_get_vblank_counter(struct drm_device *dev, int crtc);
 extern int radeon_enable_vblank(struct drm_device *dev, int crtc);
 extern void radeon_disable_vblank(struct drm_device *dev, int crtc);
-extern irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS);
+extern irqreturn_t radeon_driver_irq_handler(int irq, void *arg);
 extern void radeon_driver_irq_preinstall(struct drm_device * dev);
 extern int radeon_driver_irq_postinstall(struct drm_device *dev);
 extern void radeon_driver_irq_uninstall(struct drm_device * dev);
index d3a86e43c0123715e0cf765a738e6664f42ab6e0..c37cb79a9489aadd38a84b2f59a6aed7e56333a5 100644 (file)
@@ -121,7 +121,7 @@ int radeon_fence_emit(struct radeon_device *rdev,
        (*fence)->seq = ++rdev->fence_drv[ring].sync_seq[ring];
        (*fence)->ring = ring;
        radeon_fence_ring_emit(rdev, ring, *fence);
-       trace_radeon_fence_emit(rdev->ddev, (*fence)->seq);
+       trace_radeon_fence_emit(rdev->ddev, ring, (*fence)->seq);
        return 0;
 }
 
@@ -313,7 +313,7 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
                                continue;
 
                        last_seq[i] = atomic64_read(&rdev->fence_drv[i].last_seq);
-                       trace_radeon_fence_wait_begin(rdev->ddev, target_seq[i]);
+                       trace_radeon_fence_wait_begin(rdev->ddev, i, target_seq[i]);
                        radeon_irq_kms_sw_irq_get(rdev, i);
                }
 
@@ -332,7 +332,7 @@ static int radeon_fence_wait_seq(struct radeon_device *rdev, u64 *target_seq,
                                continue;
 
                        radeon_irq_kms_sw_irq_put(rdev, i);
-                       trace_radeon_fence_wait_end(rdev->ddev, target_seq[i]);
+                       trace_radeon_fence_wait_end(rdev->ddev, i, target_seq[i]);
                }
 
                if (unlikely(r < 0))
@@ -841,6 +841,8 @@ static int radeon_debugfs_fence_info(struct seq_file *m, void *data)
                if (!rdev->fence_drv[i].initialized)
                        continue;
 
+               radeon_fence_process(rdev, i);
+
                seq_printf(m, "--- ring %d ---\n", i);
                seq_printf(m, "Last signaled fence 0x%016llx\n",
                           (unsigned long long)atomic64_read(&rdev->fence_drv[i].last_seq));
index 96e440061bdbf5b65a6213047f62bbeb89aea77f..a8f9b463bf2a4767d9ed35d150bafffbfa1dfe07 100644 (file)
@@ -713,7 +713,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
        unsigned i;
 
        /* check if the id is still valid */
-       if (vm->fence && vm->fence == rdev->vm_manager.active[vm->id])
+       if (vm->last_id_use && vm->last_id_use == rdev->vm_manager.active[vm->id])
                return NULL;
 
        /* we definately need to flush */
@@ -726,6 +726,7 @@ struct radeon_fence *radeon_vm_grab_id(struct radeon_device *rdev,
                if (fence == NULL) {
                        /* found a free one */
                        vm->id = i;
+                       trace_radeon_vm_grab_id(vm->id, ring);
                        return NULL;
                }
 
@@ -769,6 +770,9 @@ void radeon_vm_fence(struct radeon_device *rdev,
 
        radeon_fence_unref(&vm->fence);
        vm->fence = radeon_fence_ref(fence);
+
+       radeon_fence_unref(&vm->last_id_use);
+       vm->last_id_use = radeon_fence_ref(fence);
 }
 
 /**
@@ -1303,6 +1307,8 @@ void radeon_vm_init(struct radeon_device *rdev, struct radeon_vm *vm)
 {
        vm->id = 0;
        vm->fence = NULL;
+       vm->last_flush = NULL;
+       vm->last_id_use = NULL;
        mutex_init(&vm->mutex);
        INIT_LIST_HEAD(&vm->list);
        INIT_LIST_HEAD(&vm->va);
@@ -1341,5 +1347,6 @@ void radeon_vm_fini(struct radeon_device *rdev, struct radeon_vm *vm)
        }
        radeon_fence_unref(&vm->fence);
        radeon_fence_unref(&vm->last_flush);
+       radeon_fence_unref(&vm->last_id_use);
        mutex_unlock(&vm->mutex);
 }
index 805c5e566b9a1f29539a4cf1148183056dc90579..b96c819024b3cdb7b2ea8f387c1e267a563ed8df 100644 (file)
@@ -86,7 +86,7 @@ retry:
        return 0;
 }
 
-int radeon_gem_set_domain(struct drm_gem_object *gobj,
+static int radeon_gem_set_domain(struct drm_gem_object *gobj,
                          uint32_t rdomain, uint32_t wdomain)
 {
        struct radeon_bo *robj;
index fc60b74ee304dd779d98db03b3ec60c58767ed9a..e24ca6ab96decdf94c3e86a097d949f2705a1f7c 100644 (file)
@@ -1020,6 +1020,9 @@ void radeon_i2c_destroy(struct radeon_i2c_chan *i2c)
 /* Add the default buses */
 void radeon_i2c_init(struct radeon_device *rdev)
 {
+       if (radeon_hw_i2c)
+               DRM_INFO("hw_i2c forced on, you may experience display detection problems!\n");
+
        if (rdev->is_atom_bios)
                radeon_atombios_i2c_init(rdev);
        else
index 8d68e972789a343f08186c3a4560d7c18db24999..244b19bab2e72406648ef1b2eae8ef7965bfcf01 100644 (file)
@@ -181,7 +181,7 @@ static u32 radeon_acknowledge_irqs(drm_radeon_private_t *dev_priv, u32 *r500_dis
  * tied to dma at all, this is just a hangover from dri prehistory.
  */
 
-irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
+irqreturn_t radeon_driver_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        drm_radeon_private_t *dev_priv =
@@ -203,7 +203,7 @@ irqreturn_t radeon_driver_irq_handler(DRM_IRQ_ARGS)
 
        /* SW interrupt */
        if (stat & RADEON_SW_INT_TEST)
-               DRM_WAKEUP(&dev_priv->swi_queue);
+               wake_up(&dev_priv->swi_queue);
 
        /* VBLANK interrupt */
        if ((dev_priv->flags & RADEON_FAMILY_MASK) >= CHIP_RS600) {
@@ -249,7 +249,7 @@ static int radeon_wait_irq(struct drm_device * dev, int swi_nr)
 
        dev_priv->stats.boxes |= RADEON_BOX_WAIT_IDLE;
 
-       DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * DRM_HZ,
+       DRM_WAIT_ON(ret, dev_priv->swi_queue, 3 * HZ,
                    RADEON_READ(RADEON_LAST_SWI_REG) >= swi_nr);
 
        return ret;
@@ -302,7 +302,7 @@ int radeon_irq_emit(struct drm_device *dev, void *data, struct drm_file *file_pr
 
        result = radeon_emit_irq(dev);
 
-       if (DRM_COPY_TO_USER(emit->irq_seq, &result, sizeof(int))) {
+       if (copy_to_user(emit->irq_seq, &result, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
                return -EFAULT;
        }
@@ -354,7 +354,7 @@ int radeon_driver_irq_postinstall(struct drm_device *dev)
            (drm_radeon_private_t *) dev->dev_private;
 
        atomic_set(&dev_priv->swi_emitted, 0);
-       DRM_INIT_WAITQUEUE(&dev_priv->swi_queue);
+       init_waitqueue_head(&dev_priv->swi_queue);
 
        dev->max_vblank_count = 0x001fffff;
 
index ec6240b00469a18c471e181d59c4670b2e05069d..089c9ffb0aa95e8e47c964f190b07e0e8fe93c32 100644 (file)
 /**
  * radeon_driver_irq_handler_kms - irq handler for KMS
  *
- * @DRM_IRQ_ARGS: args
+ * @int irq, void *arg: args
  *
  * This is the irq handler for the radeon KMS driver (all asics).
  * radeon_irq_process is a macro that points to the per-asic
  * irq handler callback.
  */
-irqreturn_t radeon_driver_irq_handler_kms(DRM_IRQ_ARGS)
+irqreturn_t radeon_driver_irq_handler_kms(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        struct radeon_device *rdev = dev->dev_private;
index 21d593c0ecaf4e7e0ec85ab9b7bf53fafd0f2a87..114d1672d616d0b5d7b85ab5d739da66f2db823e 100644 (file)
@@ -191,7 +191,7 @@ static void radeon_set_filp_rights(struct drm_device *dev,
  * etc. (all asics).
  * Returns 0 on success, -EINVAL on failure.
  */
-int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
+static int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
 {
        struct radeon_device *rdev = dev->dev_private;
        struct drm_radeon_info *info = data;
@@ -223,7 +223,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                        *value = rdev->accel_working;
                break;
        case RADEON_INFO_CRTC_FROM_ID:
-               if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) {
+               if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {
                        DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
                        return -EFAULT;
                }
@@ -269,7 +269,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                 *
                 * When returning, the value is 1 if filp owns hyper-z access,
                 * 0 otherwise. */
-               if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) {
+               if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {
                        DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
                        return -EFAULT;
                }
@@ -281,7 +281,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                break;
        case RADEON_INFO_WANT_CMASK:
                /* The same logic as Hyper-Z. */
-               if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) {
+               if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {
                        DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
                        return -EFAULT;
                }
@@ -417,7 +417,7 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                *value = rdev->fastfb_working;
                break;
        case RADEON_INFO_RING_WORKING:
-               if (DRM_COPY_FROM_USER(value, value_ptr, sizeof(uint32_t))) {
+               if (copy_from_user(value, value_ptr, sizeof(uint32_t))) {
                        DRM_ERROR("copy_from_user %s:%u\n", __func__, __LINE__);
                        return -EFAULT;
                }
@@ -470,11 +470,18 @@ int radeon_info_ioctl(struct drm_device *dev, void *data, struct drm_file *filp)
                        DRM_DEBUG_KMS("BACKEND_ENABLED_MASK is si+ only!\n");
                }
                break;
+       case RADEON_INFO_MAX_SCLK:
+               if ((rdev->pm.pm_method == PM_METHOD_DPM) &&
+                   rdev->pm.dpm_enabled)
+                       *value = rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk * 10;
+               else
+                       *value = rdev->pm.default_sclk * 10;
+               break;
        default:
                DRM_DEBUG_KMS("Invalid request %d\n", info->request);
                return -EINVAL;
        }
-       if (DRM_COPY_TO_USER(value_ptr, (char*)value, value_size)) {
+       if (copy_to_user(value_ptr, (char*)value, value_size)) {
                DRM_ERROR("copy_to_user %s:%u\n", __func__, __LINE__);
                return -EFAULT;
        }
@@ -712,11 +719,12 @@ int radeon_get_vblank_timestamp_kms(struct drm_device *dev, int crtc,
        /* Helper routine in DRM core does all the work: */
        return drm_calc_vbltimestamp_from_scanoutpos(dev, crtc, max_error,
                                                     vblank_time, flags,
-                                                    drmcrtc);
+                                                    drmcrtc, &drmcrtc->hwmode);
 }
 
 #define KMS_INVALID_IOCTL(name)                                                \
-int name(struct drm_device *dev, void *data, struct drm_file *file_priv)\
+static int name(struct drm_device *dev, void *data, struct drm_file    \
+               *file_priv)                                             \
 {                                                                      \
        DRM_ERROR("invalid ioctl with kms %s\n", __func__);             \
        return -EINVAL;                                                 \
index d54d2d7c9031a7ff957fec87b1d58c0ed927e6a5..146d253f1131a4780e889893b3e566336548b3f7 100644 (file)
@@ -243,7 +243,7 @@ int radeon_mem_alloc(struct drm_device *dev, void *data, struct drm_file *file_p
        if (!block)
                return -ENOMEM;
 
-       if (DRM_COPY_TO_USER(alloc->region_offset, &block->start,
+       if (copy_to_user(alloc->region_offset, &block->start,
                             sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
                return -EFAULT;
index 3f0dd664af90d6815b2edea895662936cc1982e4..402dbe32c23483afb3524d3397e3ce1b7c3cc281 100644 (file)
@@ -291,6 +291,7 @@ struct radeon_tv_regs {
 
 struct radeon_atom_ss {
        uint16_t percentage;
+       uint16_t percentage_divider;
        uint8_t type;
        uint16_t step;
        uint8_t delay;
@@ -624,6 +625,30 @@ struct atom_voltage_table
        struct atom_voltage_table_entry entries[MAX_VOLTAGE_ENTRIES];
 };
 
+
+extern void
+radeon_add_atom_connector(struct drm_device *dev,
+                         uint32_t connector_id,
+                         uint32_t supported_device,
+                         int connector_type,
+                         struct radeon_i2c_bus_rec *i2c_bus,
+                         uint32_t igp_lane_info,
+                         uint16_t connector_object_id,
+                         struct radeon_hpd *hpd,
+                         struct radeon_router *router);
+extern void
+radeon_add_legacy_connector(struct drm_device *dev,
+                           uint32_t connector_id,
+                           uint32_t supported_device,
+                           int connector_type,
+                           struct radeon_i2c_bus_rec *i2c_bus,
+                           uint16_t connector_object_id,
+                           struct radeon_hpd *hpd);
+extern uint32_t
+radeon_get_encoder_enum(struct drm_device *dev, uint32_t supported_device,
+                       uint8_t dac);
+extern void radeon_link_encoder_connector(struct drm_device *dev);
+
 extern enum radeon_tv_std
 radeon_combios_get_tv_info(struct radeon_device *rdev);
 extern enum radeon_tv_std
@@ -631,6 +656,15 @@ radeon_atombios_get_tv_info(struct radeon_device *rdev);
 extern void radeon_atombios_get_default_voltages(struct radeon_device *rdev,
                                                 u16 *vddc, u16 *vddci, u16 *mvdd);
 
+extern void
+radeon_combios_connected_scratch_regs(struct drm_connector *connector,
+                                     struct drm_encoder *encoder,
+                                     bool connected);
+extern void
+radeon_atombios_connected_scratch_regs(struct drm_connector *connector,
+                                      struct drm_encoder *encoder,
+                                      bool connected);
+
 extern struct drm_connector *
 radeon_get_connector_for_encoder(struct drm_encoder *encoder);
 extern struct drm_connector *
@@ -666,6 +700,7 @@ extern void radeon_atom_ext_encoder_setup_ddc(struct drm_encoder *encoder);
 extern struct drm_encoder *radeon_get_external_encoder(struct drm_encoder *encoder);
 extern int radeon_dp_i2c_aux_ch(struct i2c_adapter *adapter, int mode,
                                u8 write_byte, u8 *read_byte);
+void radeon_atom_copy_swap(u8 *dst, u8 *src, u8 num_bytes, bool to_le);
 
 extern void radeon_i2c_init(struct radeon_device *rdev);
 extern void radeon_i2c_fini(struct radeon_device *rdev);
@@ -766,6 +801,7 @@ extern int radeon_crtc_cursor_move(struct drm_crtc *crtc,
                                   int x, int y);
 
 extern int radeon_get_crtc_scanoutpos(struct drm_device *dev, int crtc,
+                                     unsigned int flags,
                                      int *vpos, int *hpos, ktime_t *stime,
                                      ktime_t *etime);
 
index c0fa4aa9ceea8ad8d22c7485b28f4bf045a3a7dd..08595cf90b0139ee0da24f4ac3725e30dcbf9d68 100644 (file)
@@ -46,7 +46,7 @@ static void radeon_bo_clear_surface_reg(struct radeon_bo *bo);
  * function are calling it.
  */
 
-void radeon_bo_clear_va(struct radeon_bo *bo)
+static void radeon_bo_clear_va(struct radeon_bo *bo)
 {
        struct radeon_bo_va *bo_va, *tmp;
 
index 984097b907ef5ee67c8e59faf4198ccf8add5f1b..8e8153e471c20a6b0dba28b38ce36bcd78f41a7b 100644 (file)
@@ -924,6 +924,10 @@ void radeon_dpm_enable_uvd(struct radeon_device *rdev, bool enable)
 
        if (rdev->asic->dpm.powergate_uvd) {
                mutex_lock(&rdev->pm.mutex);
+               /* don't powergate anything if we
+                  have active but pause streams */
+               enable |= rdev->pm.dpm.sd > 0;
+               enable |= rdev->pm.dpm.hd > 0;
                /* enable/disable UVD */
                radeon_dpm_powergate_uvd(rdev, !enable);
                mutex_unlock(&rdev->pm.mutex);
@@ -1010,8 +1014,10 @@ static void radeon_pm_resume_old(struct radeon_device *rdev)
        rdev->pm.current_clock_mode_index = 0;
        rdev->pm.current_sclk = rdev->pm.default_sclk;
        rdev->pm.current_mclk = rdev->pm.default_mclk;
-       rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
-       rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci;
+       if (rdev->pm.power_state) {
+               rdev->pm.current_vddc = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.voltage;
+               rdev->pm.current_vddci = rdev->pm.power_state[rdev->pm.default_power_state_index].clock_info[0].voltage.vddci;
+       }
        if (rdev->pm.pm_method == PM_METHOD_DYNPM
            && rdev->pm.dynpm_state == DYNPM_STATE_SUSPENDED) {
                rdev->pm.dynpm_state = DYNPM_STATE_ACTIVE;
@@ -1032,25 +1038,27 @@ static void radeon_pm_resume_dpm(struct radeon_device *rdev)
        radeon_dpm_setup_asic(rdev);
        ret = radeon_dpm_enable(rdev);
        mutex_unlock(&rdev->pm.mutex);
-       if (ret) {
-               DRM_ERROR("radeon: dpm resume failed\n");
-               if ((rdev->family >= CHIP_BARTS) &&
-                   (rdev->family <= CHIP_CAYMAN) &&
-                   rdev->mc_fw) {
-                       if (rdev->pm.default_vddc)
-                               radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
-                                                       SET_VOLTAGE_TYPE_ASIC_VDDC);
-                       if (rdev->pm.default_vddci)
-                               radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
-                                                       SET_VOLTAGE_TYPE_ASIC_VDDCI);
-                       if (rdev->pm.default_sclk)
-                               radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
-                       if (rdev->pm.default_mclk)
-                               radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
-               }
-       } else {
-               rdev->pm.dpm_enabled = true;
-               radeon_pm_compute_clocks(rdev);
+       if (ret)
+               goto dpm_resume_fail;
+       rdev->pm.dpm_enabled = true;
+       radeon_pm_compute_clocks(rdev);
+       return;
+
+dpm_resume_fail:
+       DRM_ERROR("radeon: dpm resume failed\n");
+       if ((rdev->family >= CHIP_BARTS) &&
+           (rdev->family <= CHIP_CAYMAN) &&
+           rdev->mc_fw) {
+               if (rdev->pm.default_vddc)
+                       radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
+                                               SET_VOLTAGE_TYPE_ASIC_VDDC);
+               if (rdev->pm.default_vddci)
+                       radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
+                                               SET_VOLTAGE_TYPE_ASIC_VDDCI);
+               if (rdev->pm.default_sclk)
+                       radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
+               if (rdev->pm.default_mclk)
+                       radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
        }
 }
 
@@ -1170,51 +1178,50 @@ static int radeon_pm_init_dpm(struct radeon_device *rdev)
        radeon_dpm_setup_asic(rdev);
        ret = radeon_dpm_enable(rdev);
        mutex_unlock(&rdev->pm.mutex);
-       if (ret) {
-               rdev->pm.dpm_enabled = false;
-               if ((rdev->family >= CHIP_BARTS) &&
-                   (rdev->family <= CHIP_CAYMAN) &&
-                   rdev->mc_fw) {
-                       if (rdev->pm.default_vddc)
-                               radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
-                                                       SET_VOLTAGE_TYPE_ASIC_VDDC);
-                       if (rdev->pm.default_vddci)
-                               radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
-                                                       SET_VOLTAGE_TYPE_ASIC_VDDCI);
-                       if (rdev->pm.default_sclk)
-                               radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
-                       if (rdev->pm.default_mclk)
-                               radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
-               }
-               DRM_ERROR("radeon: dpm initialization failed\n");
-               return ret;
-       }
+       if (ret)
+               goto dpm_failed;
        rdev->pm.dpm_enabled = true;
-       radeon_pm_compute_clocks(rdev);
 
-       if (rdev->pm.num_power_states > 1) {
-               ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state);
-               if (ret)
-                       DRM_ERROR("failed to create device file for dpm state\n");
-               ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
-               if (ret)
-                       DRM_ERROR("failed to create device file for dpm state\n");
-               /* XXX: these are noops for dpm but are here for backwards compat */
-               ret = device_create_file(rdev->dev, &dev_attr_power_profile);
-               if (ret)
-                       DRM_ERROR("failed to create device file for power profile\n");
-               ret = device_create_file(rdev->dev, &dev_attr_power_method);
-               if (ret)
-                       DRM_ERROR("failed to create device file for power method\n");
-
-               if (radeon_debugfs_pm_init(rdev)) {
-                       DRM_ERROR("Failed to register debugfs file for dpm!\n");
-               }
+       ret = device_create_file(rdev->dev, &dev_attr_power_dpm_state);
+       if (ret)
+               DRM_ERROR("failed to create device file for dpm state\n");
+       ret = device_create_file(rdev->dev, &dev_attr_power_dpm_force_performance_level);
+       if (ret)
+               DRM_ERROR("failed to create device file for dpm state\n");
+       /* XXX: these are noops for dpm but are here for backwards compat */
+       ret = device_create_file(rdev->dev, &dev_attr_power_profile);
+       if (ret)
+               DRM_ERROR("failed to create device file for power profile\n");
+       ret = device_create_file(rdev->dev, &dev_attr_power_method);
+       if (ret)
+               DRM_ERROR("failed to create device file for power method\n");
 
-               DRM_INFO("radeon: dpm initialized\n");
+       if (radeon_debugfs_pm_init(rdev)) {
+               DRM_ERROR("Failed to register debugfs file for dpm!\n");
        }
 
+       DRM_INFO("radeon: dpm initialized\n");
+
        return 0;
+
+dpm_failed:
+       rdev->pm.dpm_enabled = false;
+       if ((rdev->family >= CHIP_BARTS) &&
+           (rdev->family <= CHIP_CAYMAN) &&
+           rdev->mc_fw) {
+               if (rdev->pm.default_vddc)
+                       radeon_atom_set_voltage(rdev, rdev->pm.default_vddc,
+                                               SET_VOLTAGE_TYPE_ASIC_VDDC);
+               if (rdev->pm.default_vddci)
+                       radeon_atom_set_voltage(rdev, rdev->pm.default_vddci,
+                                               SET_VOLTAGE_TYPE_ASIC_VDDCI);
+               if (rdev->pm.default_sclk)
+                       radeon_set_engine_clock(rdev, rdev->pm.default_sclk);
+               if (rdev->pm.default_mclk)
+                       radeon_set_memory_clock(rdev, rdev->pm.default_mclk);
+       }
+       DRM_ERROR("radeon: dpm initialization failed\n");
+       return ret;
 }
 
 int radeon_pm_init(struct radeon_device *rdev)
@@ -1228,11 +1235,10 @@ int radeon_pm_init(struct radeon_device *rdev)
        case CHIP_RV670:
        case CHIP_RS780:
        case CHIP_RS880:
+       case CHIP_BARTS:
+       case CHIP_TURKS:
+       case CHIP_CAICOS:
        case CHIP_CAYMAN:
-       case CHIP_BONAIRE:
-       case CHIP_KABINI:
-       case CHIP_KAVERI:
-       case CHIP_HAWAII:
                /* DPM requires the RLC, RV770+ dGPU requires SMC */
                if (!rdev->rlc_fw)
                        rdev->pm.pm_method = PM_METHOD_PROFILE;
@@ -1257,15 +1263,16 @@ int radeon_pm_init(struct radeon_device *rdev)
        case CHIP_PALM:
        case CHIP_SUMO:
        case CHIP_SUMO2:
-       case CHIP_BARTS:
-       case CHIP_TURKS:
-       case CHIP_CAICOS:
        case CHIP_ARUBA:
        case CHIP_TAHITI:
        case CHIP_PITCAIRN:
        case CHIP_VERDE:
        case CHIP_OLAND:
        case CHIP_HAINAN:
+       case CHIP_BONAIRE:
+       case CHIP_KABINI:
+       case CHIP_KAVERI:
+       case CHIP_HAWAII:
                /* DPM requires the RLC, RV770+ dGPU requires SMC */
                if (!rdev->rlc_fw)
                        rdev->pm.pm_method = PM_METHOD_PROFILE;
@@ -1290,6 +1297,18 @@ int radeon_pm_init(struct radeon_device *rdev)
                return radeon_pm_init_old(rdev);
 }
 
+int radeon_pm_late_init(struct radeon_device *rdev)
+{
+       int ret = 0;
+
+       if (rdev->pm.pm_method == PM_METHOD_DPM) {
+               mutex_lock(&rdev->pm.mutex);
+               ret = radeon_dpm_late_enable(rdev);
+               mutex_unlock(&rdev->pm.mutex);
+       }
+       return ret;
+}
+
 static void radeon_pm_fini_old(struct radeon_device *rdev)
 {
        if (rdev->pm.num_power_states > 1) {
@@ -1420,6 +1439,9 @@ static void radeon_pm_compute_clocks_dpm(struct radeon_device *rdev)
        struct drm_crtc *crtc;
        struct radeon_crtc *radeon_crtc;
 
+       if (!rdev->pm.dpm_enabled)
+               return;
+
        mutex_lock(&rdev->pm.mutex);
 
        /* update active crtc counts */
@@ -1464,7 +1486,7 @@ static bool radeon_pm_in_vbl(struct radeon_device *rdev)
         */
        for (crtc = 0; (crtc < rdev->num_crtc) && in_vbl; crtc++) {
                if (rdev->pm.active_crtcs & (1 << crtc)) {
-                       vbl_status = radeon_get_crtc_scanoutpos(rdev->ddev, crtc, &vpos, &hpos, NULL, NULL);
+                       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))
                                in_vbl = false;
index 9214403ae173c146573cf8c4441a6a71cf052665..1b783f0e6d3ad084b0a62629a4b5d67c9e92453f 100644 (file)
@@ -332,36 +332,6 @@ bool radeon_ring_supports_scratch_reg(struct radeon_device *rdev,
        }
 }
 
-u32 radeon_ring_generic_get_rptr(struct radeon_device *rdev,
-                                struct radeon_ring *ring)
-{
-       u32 rptr;
-
-       if (rdev->wb.enabled)
-               rptr = le32_to_cpu(rdev->wb.wb[ring->rptr_offs/4]);
-       else
-               rptr = RREG32(ring->rptr_reg);
-
-       return rptr;
-}
-
-u32 radeon_ring_generic_get_wptr(struct radeon_device *rdev,
-                                struct radeon_ring *ring)
-{
-       u32 wptr;
-
-       wptr = RREG32(ring->wptr_reg);
-
-       return wptr;
-}
-
-void radeon_ring_generic_set_wptr(struct radeon_device *rdev,
-                                 struct radeon_ring *ring)
-{
-       WREG32(ring->wptr_reg, ring->wptr);
-       (void)RREG32(ring->wptr_reg);
-}
-
 /**
  * radeon_ring_free_size - update the free size
  *
@@ -463,7 +433,7 @@ void radeon_ring_commit(struct radeon_device *rdev, struct radeon_ring *ring)
        while (ring->wptr & ring->align_mask) {
                radeon_ring_write(ring, ring->nop);
        }
-       DRM_MEMORYBARRIER();
+       mb();
        radeon_ring_set_wptr(rdev, ring);
 }
 
@@ -689,22 +659,18 @@ int radeon_ring_restore(struct radeon_device *rdev, struct radeon_ring *ring,
  * @ring: radeon_ring structure holding ring information
  * @ring_size: size of the ring
  * @rptr_offs: offset of the rptr writeback location in the WB buffer
- * @rptr_reg: MMIO offset of the rptr register
- * @wptr_reg: MMIO offset of the wptr register
  * @nop: nop packet for this ring
  *
  * Initialize the driver information for the selected ring (all asics).
  * Returns 0 on success, error on failure.
  */
 int radeon_ring_init(struct radeon_device *rdev, struct radeon_ring *ring, unsigned ring_size,
-                    unsigned rptr_offs, unsigned rptr_reg, unsigned wptr_reg, u32 nop)
+                    unsigned rptr_offs, u32 nop)
 {
        int r;
 
        ring->ring_size = ring_size;
        ring->rptr_offs = rptr_offs;
-       ring->rptr_reg = rptr_reg;
-       ring->wptr_reg = wptr_reg;
        ring->nop = nop;
        /* Allocate ring buffer */
        if (ring->ring_obj == NULL) {
@@ -790,34 +756,54 @@ static int radeon_debugfs_ring_info(struct seq_file *m, void *data)
        struct radeon_device *rdev = dev->dev_private;
        int ridx = *(int*)node->info_ent->data;
        struct radeon_ring *ring = &rdev->ring[ridx];
+
+       uint32_t rptr, wptr, rptr_next;
        unsigned count, i, j;
-       u32 tmp;
 
        radeon_ring_free_size(rdev, ring);
        count = (ring->ring_size / 4) - ring->ring_free_dw;
-       tmp = radeon_ring_get_wptr(rdev, ring);
-       seq_printf(m, "wptr(0x%04x): 0x%08x [%5d]\n", ring->wptr_reg, tmp, tmp);
-       tmp = radeon_ring_get_rptr(rdev, ring);
-       seq_printf(m, "rptr(0x%04x): 0x%08x [%5d]\n", ring->rptr_reg, tmp, tmp);
+
+       wptr = radeon_ring_get_wptr(rdev, ring);
+       seq_printf(m, "wptr: 0x%08x [%5d]\n",
+                  wptr, wptr);
+
+       rptr = radeon_ring_get_rptr(rdev, ring);
+       seq_printf(m, "rptr: 0x%08x [%5d]\n",
+                  rptr, rptr);
+
        if (ring->rptr_save_reg) {
-               seq_printf(m, "rptr next(0x%04x): 0x%08x\n", ring->rptr_save_reg,
-                          RREG32(ring->rptr_save_reg));
-       }
-       seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n", ring->wptr, ring->wptr);
-       seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n", ring->rptr, ring->rptr);
-       seq_printf(m, "last semaphore signal addr : 0x%016llx\n", ring->last_semaphore_signal_addr);
-       seq_printf(m, "last semaphore wait addr   : 0x%016llx\n", ring->last_semaphore_wait_addr);
+               rptr_next = RREG32(ring->rptr_save_reg);
+               seq_printf(m, "rptr next(0x%04x): 0x%08x [%5d]\n",
+                          ring->rptr_save_reg, rptr_next, rptr_next);
+       } else
+               rptr_next = ~0;
+
+       seq_printf(m, "driver's copy of the wptr: 0x%08x [%5d]\n",
+                  ring->wptr, ring->wptr);
+       seq_printf(m, "driver's copy of the rptr: 0x%08x [%5d]\n",
+                  ring->rptr, ring->rptr);
+       seq_printf(m, "last semaphore signal addr : 0x%016llx\n",
+                  ring->last_semaphore_signal_addr);
+       seq_printf(m, "last semaphore wait addr   : 0x%016llx\n",
+                  ring->last_semaphore_wait_addr);
        seq_printf(m, "%u free dwords in ring\n", ring->ring_free_dw);
        seq_printf(m, "%u dwords in ring\n", count);
+
+       if (!ring->ready)
+               return 0;
+
        /* print 8 dw before current rptr as often it's the last executed
         * packet that is the root issue
         */
-       i = (ring->rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask;
-       if (ring->ready) {
-               for (j = 0; j <= (count + 32); j++) {
-                       seq_printf(m, "r[%5d]=0x%08x\n", i, ring->ring[i]);
-                       i = (i + 1) & ring->ptr_mask;
-               }
+       i = (rptr + ring->ptr_mask + 1 - 32) & ring->ptr_mask;
+       for (j = 0; j <= (count + 32); j++) {
+               seq_printf(m, "r[%5d]=0x%08x", i, ring->ring[i]);
+               if (rptr == i)
+                       seq_puts(m, " *");
+               if (rptr_next == i)
+                       seq_puts(m, " #");
+               seq_puts(m, "\n");
+               i = (i + 1) & ring->ptr_mask;
        }
        return 0;
 }
index f0bac68254b79a5dd31cfdc14ce80a98bca91065..c0625805cdd769b826d0605141f6cc80ce80ad72 100644 (file)
@@ -402,13 +402,15 @@ void radeon_sa_bo_dump_debug_info(struct radeon_sa_manager *sa_manager,
 
        spin_lock(&sa_manager->wq.lock);
        list_for_each_entry(i, &sa_manager->olist, olist) {
+               uint64_t soffset = i->soffset + sa_manager->gpu_addr;
+               uint64_t eoffset = i->eoffset + sa_manager->gpu_addr;
                if (&i->olist == sa_manager->hole) {
                        seq_printf(m, ">");
                } else {
                        seq_printf(m, " ");
                }
-               seq_printf(m, "[0x%08x 0x%08x] size %8d",
-                          i->soffset, i->eoffset, i->eoffset - i->soffset);
+               seq_printf(m, "[0x%010llx 0x%010llx] size %8lld",
+                          soffset, eoffset, eoffset - soffset);
                if (i->fence) {
                        seq_printf(m, " protected by 0x%016llx on ring %d",
                                   i->fence->seq, i->fence->ring);
index 4d20910899d4c7ed8ad85f29788bfd35cc359fb5..956ab7f14e1650607c8dd09f1b9c96daaee3169a 100644 (file)
@@ -1810,7 +1810,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,
                }
                if (!buf) {
                        DRM_DEBUG("EAGAIN\n");
-                       if (DRM_COPY_TO_USER(tex->image, image, sizeof(*image)))
+                       if (copy_to_user(tex->image, image, sizeof(*image)))
                                return -EFAULT;
                        return -EAGAIN;
                }
@@ -1823,7 +1823,7 @@ static int radeon_cp_dispatch_texture(struct drm_device * dev,
 
 #define RADEON_COPY_MT(_buf, _data, _width) \
        do { \
-               if (DRM_COPY_FROM_USER(_buf, _data, (_width))) {\
+               if (copy_from_user(_buf, _data, (_width))) {\
                        DRM_ERROR("EFAULT on pad, %d bytes\n", (_width)); \
                        return -EFAULT; \
                } \
@@ -2168,7 +2168,7 @@ static int radeon_cp_clear(struct drm_device *dev, void *data, struct drm_file *
        if (sarea_priv->nbox > RADEON_NR_SAREA_CLIPRECTS)
                sarea_priv->nbox = RADEON_NR_SAREA_CLIPRECTS;
 
-       if (DRM_COPY_FROM_USER(&depth_boxes, clear->depth_boxes,
+       if (copy_from_user(&depth_boxes, clear->depth_boxes,
                               sarea_priv->nbox * sizeof(depth_boxes[0])))
                return -EFAULT;
 
@@ -2436,7 +2436,7 @@ static int radeon_cp_texture(struct drm_device *dev, void *data, struct drm_file
                return -EINVAL;
        }
 
-       if (DRM_COPY_FROM_USER(&image,
+       if (copy_from_user(&image,
                               (drm_radeon_tex_image_t __user *) tex->image,
                               sizeof(image)))
                return -EFAULT;
@@ -2460,7 +2460,7 @@ static int radeon_cp_stipple(struct drm_device *dev, void *data, struct drm_file
 
        LOCK_TEST_WITH_RETURN(dev, file_priv);
 
-       if (DRM_COPY_FROM_USER(&mask, stipple->mask, 32 * sizeof(u32)))
+       if (copy_from_user(&mask, stipple->mask, 32 * sizeof(u32)))
                return -EFAULT;
 
        RING_SPACE_TEST_WITH_RETURN(dev_priv);
@@ -2585,13 +2585,13 @@ static int radeon_cp_vertex2(struct drm_device *dev, void *data, struct drm_file
                drm_radeon_prim_t prim;
                drm_radeon_tcl_prim_t tclprim;
 
-               if (DRM_COPY_FROM_USER(&prim, &vertex->prim[i], sizeof(prim)))
+               if (copy_from_user(&prim, &vertex->prim[i], sizeof(prim)))
                        return -EFAULT;
 
                if (prim.stateidx != laststate) {
                        drm_radeon_state_t state;
 
-                       if (DRM_COPY_FROM_USER(&state,
+                       if (copy_from_user(&state,
                                               &vertex->state[prim.stateidx],
                                               sizeof(state)))
                                return -EFAULT;
@@ -2799,7 +2799,7 @@ static int radeon_emit_packet3_cliprect(struct drm_device *dev,
 
        do {
                if (i < cmdbuf->nbox) {
-                       if (DRM_COPY_FROM_USER(&box, &boxes[i], sizeof(box)))
+                       if (copy_from_user(&box, &boxes[i], sizeof(box)))
                                return -EFAULT;
                        /* FIXME The second and subsequent times round
                         * this loop, send a WAIT_UNTIL_3D_IDLE before
@@ -3116,7 +3116,7 @@ static int radeon_cp_getparam(struct drm_device *dev, void *data, struct drm_fil
                return -EINVAL;
        }
 
-       if (DRM_COPY_TO_USER(param->value, &value, sizeof(int))) {
+       if (copy_to_user(param->value, &value, sizeof(int))) {
                DRM_ERROR("copy_to_user\n");
                return -EFAULT;
        }
index 0473257d407886e175f77347078b2de54c61cfc3..f749f2c3bbdb838a63bdcd6598409387de3c790b 100644 (file)
@@ -106,42 +106,45 @@ TRACE_EVENT(radeon_vm_set_page,
 
 DECLARE_EVENT_CLASS(radeon_fence_request,
 
-           TP_PROTO(struct drm_device *dev, u32 seqno),
+           TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
 
-           TP_ARGS(dev, seqno),
+           TP_ARGS(dev, ring, seqno),
 
            TP_STRUCT__entry(
                             __field(u32, dev)
+                            __field(int, ring)
                             __field(u32, seqno)
                             ),
 
            TP_fast_assign(
                           __entry->dev = dev->primary->index;
+                          __entry->ring = ring;
                           __entry->seqno = seqno;
                           ),
 
-           TP_printk("dev=%u, seqno=%u", __entry->dev, __entry->seqno)
+           TP_printk("dev=%u, ring=%d, seqno=%u",
+                     __entry->dev, __entry->ring, __entry->seqno)
 );
 
 DEFINE_EVENT(radeon_fence_request, radeon_fence_emit,
 
-           TP_PROTO(struct drm_device *dev, u32 seqno),
+           TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
 
-           TP_ARGS(dev, seqno)
+           TP_ARGS(dev, ring, seqno)
 );
 
 DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_begin,
 
-           TP_PROTO(struct drm_device *dev, u32 seqno),
+           TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
 
-           TP_ARGS(dev, seqno)
+           TP_ARGS(dev, ring, seqno)
 );
 
 DEFINE_EVENT(radeon_fence_request, radeon_fence_wait_end,
 
-           TP_PROTO(struct drm_device *dev, u32 seqno),
+           TP_PROTO(struct drm_device *dev, int ring, u32 seqno),
 
-           TP_ARGS(dev, seqno)
+           TP_ARGS(dev, ring, seqno)
 );
 
 DECLARE_EVENT_CLASS(radeon_semaphore_request,
index 71245d6f34a20c0f64a6eff3057eb6d7ae37f388..77f5b0c3edb8d8b1f4835620d626c3981171c7a6 100644 (file)
 #include <linux/seq_file.h>
 #include <linux/slab.h>
 #include <linux/swiotlb.h>
+#include <linux/debugfs.h>
 #include "radeon_reg.h"
 #include "radeon.h"
 
 #define DRM_FILE_PAGE_OFFSET (0x100000000ULL >> PAGE_SHIFT)
 
 static int radeon_ttm_debugfs_init(struct radeon_device *rdev);
+static void radeon_ttm_debugfs_fini(struct radeon_device *rdev);
 
 static struct radeon_device *radeon_get_rdev(struct ttm_bo_device *bdev)
 {
@@ -142,7 +144,7 @@ static int radeon_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->flags = TTM_MEMTYPE_FLAG_MAPPABLE | TTM_MEMTYPE_FLAG_CMA;
 #if __OS_HAS_AGP
                if (rdev->flags & RADEON_IS_AGP) {
-                       if (!(drm_core_has_AGP(rdev->ddev) && rdev->ddev->agp)) {
+                       if (!rdev->ddev->agp) {
                                DRM_ERROR("AGP is not enabled for memory type %u\n",
                                          (unsigned)type);
                                return -EINVAL;
@@ -753,6 +755,7 @@ void radeon_ttm_fini(struct radeon_device *rdev)
 
        if (!rdev->mman.initialized)
                return;
+       radeon_ttm_debugfs_fini(rdev);
        if (rdev->stollen_vga_memory) {
                r = radeon_bo_reserve(rdev->stollen_vga_memory, false);
                if (r == 0) {
@@ -832,16 +835,15 @@ int radeon_mmap(struct file *filp, struct vm_area_struct *vma)
        return 0;
 }
 
-
-#define RADEON_DEBUGFS_MEM_TYPES 2
-
 #if defined(CONFIG_DEBUG_FS)
+
 static int radeon_mm_dump_table(struct seq_file *m, void *data)
 {
        struct drm_info_node *node = (struct drm_info_node *)m->private;
-       struct drm_mm *mm = (struct drm_mm *)node->info_ent->data;
+       unsigned ttm_pl = *(int *)node->info_ent->data;
        struct drm_device *dev = node->minor->dev;
        struct radeon_device *rdev = dev->dev_private;
+       struct drm_mm *mm = (struct drm_mm *)rdev->mman.bdev.man[ttm_pl].priv;
        int ret;
        struct ttm_bo_global *glob = rdev->mman.bdev.glob;
 
@@ -850,46 +852,169 @@ static int radeon_mm_dump_table(struct seq_file *m, void *data)
        spin_unlock(&glob->lru_lock);
        return ret;
 }
+
+static int ttm_pl_vram = TTM_PL_VRAM;
+static int ttm_pl_tt = TTM_PL_TT;
+
+static struct drm_info_list radeon_ttm_debugfs_list[] = {
+       {"radeon_vram_mm", radeon_mm_dump_table, 0, &ttm_pl_vram},
+       {"radeon_gtt_mm", radeon_mm_dump_table, 0, &ttm_pl_tt},
+       {"ttm_page_pool", ttm_page_alloc_debugfs, 0, NULL},
+#ifdef CONFIG_SWIOTLB
+       {"ttm_dma_page_pool", ttm_dma_page_alloc_debugfs, 0, NULL}
 #endif
+};
 
-static int radeon_ttm_debugfs_init(struct radeon_device *rdev)
+static int radeon_ttm_vram_open(struct inode *inode, struct file *filep)
 {
-#if defined(CONFIG_DEBUG_FS)
-       static struct drm_info_list radeon_mem_types_list[RADEON_DEBUGFS_MEM_TYPES+2];
-       static char radeon_mem_types_names[RADEON_DEBUGFS_MEM_TYPES+2][32];
-       unsigned i;
+       struct radeon_device *rdev = inode->i_private;
+       i_size_write(inode, rdev->mc.mc_vram_size);
+       filep->private_data = inode->i_private;
+       return 0;
+}
 
-       for (i = 0; i < RADEON_DEBUGFS_MEM_TYPES; i++) {
-               if (i == 0)
-                       sprintf(radeon_mem_types_names[i], "radeon_vram_mm");
-               else
-                       sprintf(radeon_mem_types_names[i], "radeon_gtt_mm");
-               radeon_mem_types_list[i].name = radeon_mem_types_names[i];
-               radeon_mem_types_list[i].show = &radeon_mm_dump_table;
-               radeon_mem_types_list[i].driver_features = 0;
-               if (i == 0)
-                       radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_VRAM].priv;
-               else
-                       radeon_mem_types_list[i].data = rdev->mman.bdev.man[TTM_PL_TT].priv;
+static ssize_t radeon_ttm_vram_read(struct file *f, char __user *buf,
+                                   size_t size, loff_t *pos)
+{
+       struct radeon_device *rdev = f->private_data;
+       ssize_t result = 0;
+       int r;
 
+       if (size & 0x3 || *pos & 0x3)
+               return -EINVAL;
+
+       while (size) {
+               unsigned long flags;
+               uint32_t value;
+
+               if (*pos >= rdev->mc.mc_vram_size)
+                       return result;
+
+               spin_lock_irqsave(&rdev->mmio_idx_lock, flags);
+               WREG32(RADEON_MM_INDEX, ((uint32_t)*pos) | 0x80000000);
+               if (rdev->family >= CHIP_CEDAR)
+                       WREG32(EVERGREEN_MM_INDEX_HI, *pos >> 31);
+               value = RREG32(RADEON_MM_DATA);
+               spin_unlock_irqrestore(&rdev->mmio_idx_lock, flags);
+
+               r = put_user(value, (uint32_t *)buf);
+               if (r)
+                       return r;
+
+               result += 4;
+               buf += 4;
+               *pos += 4;
+               size -= 4;
        }
-       /* Add ttm page pool to debugfs */
-       sprintf(radeon_mem_types_names[i], "ttm_page_pool");
-       radeon_mem_types_list[i].name = radeon_mem_types_names[i];
-       radeon_mem_types_list[i].show = &ttm_page_alloc_debugfs;
-       radeon_mem_types_list[i].driver_features = 0;
-       radeon_mem_types_list[i++].data = NULL;
-#ifdef CONFIG_SWIOTLB
-       if (swiotlb_nr_tbl()) {
-               sprintf(radeon_mem_types_names[i], "ttm_dma_page_pool");
-               radeon_mem_types_list[i].name = radeon_mem_types_names[i];
-               radeon_mem_types_list[i].show = &ttm_dma_page_alloc_debugfs;
-               radeon_mem_types_list[i].driver_features = 0;
-               radeon_mem_types_list[i++].data = NULL;
+
+       return result;
+}
+
+static const struct file_operations radeon_ttm_vram_fops = {
+       .owner = THIS_MODULE,
+       .open = radeon_ttm_vram_open,
+       .read = radeon_ttm_vram_read,
+       .llseek = default_llseek
+};
+
+static int radeon_ttm_gtt_open(struct inode *inode, struct file *filep)
+{
+       struct radeon_device *rdev = inode->i_private;
+       i_size_write(inode, rdev->mc.gtt_size);
+       filep->private_data = inode->i_private;
+       return 0;
+}
+
+static ssize_t radeon_ttm_gtt_read(struct file *f, char __user *buf,
+                                  size_t size, loff_t *pos)
+{
+       struct radeon_device *rdev = f->private_data;
+       ssize_t result = 0;
+       int r;
+
+       while (size) {
+               loff_t p = *pos / PAGE_SIZE;
+               unsigned off = *pos & ~PAGE_MASK;
+               ssize_t cur_size = min(size, PAGE_SIZE - off);
+               struct page *page;
+               void *ptr;
+
+               if (p >= rdev->gart.num_cpu_pages)
+                       return result;
+
+               page = rdev->gart.pages[p];
+               if (page) {
+                       ptr = kmap(page);
+                       ptr += off;
+
+                       r = copy_to_user(buf, ptr, cur_size);
+                       kunmap(rdev->gart.pages[p]);
+               } else
+                       r = clear_user(buf, cur_size);
+
+               if (r)
+                       return -EFAULT;
+
+               result += cur_size;
+               buf += cur_size;
+               *pos += cur_size;
+               size -= cur_size;
        }
+
+       return result;
+}
+
+static const struct file_operations radeon_ttm_gtt_fops = {
+       .owner = THIS_MODULE,
+       .open = radeon_ttm_gtt_open,
+       .read = radeon_ttm_gtt_read,
+       .llseek = default_llseek
+};
+
 #endif
-       return radeon_debugfs_add_files(rdev, radeon_mem_types_list, i);
 
+static int radeon_ttm_debugfs_init(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+       unsigned count;
+
+       struct drm_minor *minor = rdev->ddev->primary;
+       struct dentry *ent, *root = minor->debugfs_root;
+
+       ent = debugfs_create_file("radeon_vram", S_IFREG | S_IRUGO, root,
+                                 rdev, &radeon_ttm_vram_fops);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+       rdev->mman.vram = ent;
+
+       ent = debugfs_create_file("radeon_gtt", S_IFREG | S_IRUGO, root,
+                                 rdev, &radeon_ttm_gtt_fops);
+       if (IS_ERR(ent))
+               return PTR_ERR(ent);
+       rdev->mman.gtt = ent;
+
+       count = ARRAY_SIZE(radeon_ttm_debugfs_list);
+
+#ifdef CONFIG_SWIOTLB
+       if (!swiotlb_nr_tbl())
+               --count;
 #endif
+
+       return radeon_debugfs_add_files(rdev, radeon_ttm_debugfs_list, count);
+#else
+
        return 0;
+#endif
+}
+
+static void radeon_ttm_debugfs_fini(struct radeon_device *rdev)
+{
+#if defined(CONFIG_DEBUG_FS)
+
+       debugfs_remove(rdev->mman.vram);
+       rdev->mman.vram = NULL;
+
+       debugfs_remove(rdev->mman.gtt);
+       rdev->mman.gtt = NULL;
+#endif
 }
index b9c0529b4a2e1e9d8f69e51f6742d023492a0040..6781fee1eaadc21a68e50de696dd353be0a3e9e5 100644 (file)
@@ -91,6 +91,7 @@ int radeon_uvd_init(struct radeon_device *rdev)
        case CHIP_VERDE:
        case CHIP_PITCAIRN:
        case CHIP_ARUBA:
+       case CHIP_OLAND:
                fw_name = FIRMWARE_TAHITI;
                break;
 
@@ -778,6 +779,8 @@ static void radeon_uvd_idle_work_handler(struct work_struct *work)
 
        if (radeon_fence_count_emitted(rdev, R600_RING_TYPE_UVD_INDEX) == 0) {
                if ((rdev->pm.pm_method == PM_METHOD_DPM) && rdev->pm.dpm_enabled) {
+                       radeon_uvd_count_handles(rdev, &rdev->pm.dpm.sd,
+                                                &rdev->pm.dpm.hd);
                        radeon_dpm_enable_uvd(rdev, false);
                } else {
                        radeon_set_uvd_clocks(rdev, 0, 0);
index 9566b5940a5ae723f90dfa11427e3f09bac233b3..b5c2369cda2fe28ca043fe91f4fcfe12fc227fc6 100644 (file)
@@ -474,6 +474,8 @@ int rs400_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = rs400_startup(rdev);
        if (r) {
@@ -484,6 +486,7 @@ int rs400_resume(struct radeon_device *rdev)
 
 int rs400_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r100_cp_disable(rdev);
        radeon_wb_disable(rdev);
        r100_irq_disable(rdev);
@@ -493,6 +496,7 @@ int rs400_suspend(struct radeon_device *rdev)
 
 void rs400_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r100_cp_fini(rdev);
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
@@ -560,6 +564,9 @@ int rs400_init(struct radeon_device *rdev)
                return r;
        r300_set_reg_safe(rdev);
 
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->accel_working = true;
        r = rs400_startup(rdev);
        if (r) {
index 76cc8d3aafec461d0b41668f25500f2a4753dbc3..fdcde7693032c28cc30008b494fd573fd82e58f3 100644 (file)
@@ -1048,6 +1048,8 @@ int rs600_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = rs600_startup(rdev);
        if (r) {
@@ -1058,6 +1060,7 @@ int rs600_resume(struct radeon_device *rdev)
 
 int rs600_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r600_audio_fini(rdev);
        r100_cp_disable(rdev);
        radeon_wb_disable(rdev);
@@ -1068,6 +1071,7 @@ int rs600_suspend(struct radeon_device *rdev)
 
 void rs600_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r600_audio_fini(rdev);
        r100_cp_fini(rdev);
        radeon_wb_fini(rdev);
@@ -1136,6 +1140,9 @@ int rs600_init(struct radeon_device *rdev)
                return r;
        rs600_set_safe_registers(rdev);
 
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->accel_working = true;
        r = rs600_startup(rdev);
        if (r) {
index e7dab069cccf48a05e19cfd7caf27bd65d38c53d..35950738bd5e449465e0e5062d096e3e8ae9ff0e 100644 (file)
@@ -756,6 +756,8 @@ int rs690_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = rs690_startup(rdev);
        if (r) {
@@ -766,6 +768,7 @@ int rs690_resume(struct radeon_device *rdev)
 
 int rs690_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r600_audio_fini(rdev);
        r100_cp_disable(rdev);
        radeon_wb_disable(rdev);
@@ -776,6 +779,7 @@ int rs690_suspend(struct radeon_device *rdev)
 
 void rs690_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r600_audio_fini(rdev);
        r100_cp_fini(rdev);
        radeon_wb_fini(rdev);
@@ -845,6 +849,9 @@ int rs690_init(struct radeon_device *rdev)
                return r;
        rs600_set_safe_registers(rdev);
 
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->accel_working = true;
        r = rs690_startup(rdev);
        if (r) {
index 6af8505cf4d2db624ee64811ba4575158d90e974..8512085b0aefe0139c6ffabdc69114510ae3e2f3 100644 (file)
@@ -623,14 +623,6 @@ int rs780_dpm_enable(struct radeon_device *rdev)
        if (pi->gfx_clock_gating)
                r600_gfx_clockgating_enable(rdev, true);
 
-       if (rdev->irq.installed && (rdev->pm.int_thermal_type == THERMAL_TYPE_RV6XX)) {
-               ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
-               if (ret)
-                       return ret;
-               rdev->irq.dpm_thermal = true;
-               radeon_irq_set(rdev);
-       }
-
        return 0;
 }
 
index 5d1c316115efa31ab7b029de44db66e399322e71..98e8138ff77945ecdba447bdcb94310c30dcb1c7 100644 (file)
@@ -586,6 +586,8 @@ int rv515_resume(struct radeon_device *rdev)
        /* Initialize surface registers */
        radeon_surface_init(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r =  rv515_startup(rdev);
        if (r) {
@@ -596,6 +598,7 @@ int rv515_resume(struct radeon_device *rdev)
 
 int rv515_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r100_cp_disable(rdev);
        radeon_wb_disable(rdev);
        rs600_irq_disable(rdev);
@@ -612,6 +615,7 @@ void rv515_set_safe_registers(struct radeon_device *rdev)
 
 void rv515_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r100_cp_fini(rdev);
        radeon_wb_fini(rdev);
        radeon_ib_pool_fini(rdev);
@@ -685,6 +689,9 @@ int rv515_init(struct radeon_device *rdev)
                return r;
        rv515_set_safe_registers(rdev);
 
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->accel_working = true;
        r = rv515_startup(rdev);
        if (r) {
index 26633a0252522051bc5a504357d93bd9b6257c67..bebf31c4d841ccaa07b86d9bae96c7abb5c223be 100644 (file)
@@ -1546,7 +1546,6 @@ int rv6xx_dpm_enable(struct radeon_device *rdev)
 {
        struct rv6xx_power_info *pi = rv6xx_get_pi(rdev);
        struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
-       int ret;
 
        if (r600_dynamicpm_enabled(rdev))
                return -EINVAL;
@@ -1594,15 +1593,6 @@ int rv6xx_dpm_enable(struct radeon_device *rdev)
        r600_power_level_enable(rdev, R600_POWER_LEVEL_MEDIUM, true);
        r600_power_level_enable(rdev, R600_POWER_LEVEL_HIGH, true);
 
-       if (rdev->irq.installed &&
-           r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
-               ret = r600_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
-               if (ret)
-                       return ret;
-               rdev->irq.dpm_thermal = true;
-               radeon_irq_set(rdev);
-       }
-
        rv6xx_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
 
        r600_start_dpm(rdev);
index 9f5846743c9e0a26dbcf76662250bfb957f6ced1..6c772e58c7845e7d4170287d3e583afd64c5a3e8 100644 (file)
@@ -1071,7 +1071,8 @@ static void rv770_mc_program(struct radeon_device *rdev)
  */
 void r700_cp_stop(struct radeon_device *rdev)
 {
-       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+       if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
        WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT));
        WREG32(SCRATCH_UMSK, 0);
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
@@ -1123,6 +1124,35 @@ void r700_cp_fini(struct radeon_device *rdev)
        radeon_scratch_free(rdev, ring->rptr_save_reg);
 }
 
+void rv770_set_clk_bypass_mode(struct radeon_device *rdev)
+{
+       u32 tmp, i;
+
+       if (rdev->flags & RADEON_IS_IGP)
+               return;
+
+       tmp = RREG32(CG_SPLL_FUNC_CNTL_2);
+       tmp &= SCLK_MUX_SEL_MASK;
+       tmp |= SCLK_MUX_SEL(1) | SCLK_MUX_UPDATE;
+       WREG32(CG_SPLL_FUNC_CNTL_2, tmp);
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               if (RREG32(CG_SPLL_STATUS) & SPLL_CHG_STATUS)
+                       break;
+               udelay(1);
+       }
+
+       tmp &= ~SCLK_MUX_UPDATE;
+       WREG32(CG_SPLL_FUNC_CNTL_2, tmp);
+
+       tmp = RREG32(MPLL_CNTL_MODE);
+       if ((rdev->family == CHIP_RV710) || (rdev->family == CHIP_RV730))
+               tmp &= ~RV730_MPLL_MCLK_SEL;
+       else
+               tmp &= ~MPLL_MCLK_SEL;
+       WREG32(MPLL_CNTL_MODE, tmp);
+}
+
 /*
  * Core functions
  */
@@ -1665,14 +1695,6 @@ static int rv770_startup(struct radeon_device *rdev)
 
        rv770_mc_program(rdev);
 
-       if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
-               r = r600_init_microcode(rdev);
-               if (r) {
-                       DRM_ERROR("Failed to load firmware!\n");
-                       return r;
-               }
-       }
-
        if (rdev->flags & RADEON_IS_AGP) {
                rv770_agp_enable(rdev);
        } else {
@@ -1728,14 +1750,12 @@ static int rv770_startup(struct radeon_device *rdev)
 
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
-                            R600_CP_RB_RPTR, R600_CP_RB_WPTR,
                             RADEON_CP_PACKET2);
        if (r)
                return r;
 
        ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
-                            DMA_RB_RPTR, DMA_RB_WPTR,
                             DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0));
        if (r)
                return r;
@@ -1754,7 +1774,6 @@ static int rv770_startup(struct radeon_device *rdev)
        ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
        if (ring->ring_size) {
                r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-                                    UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                     RADEON_CP_PACKET2);
                if (!r)
                        r = uvd_v1_0_init(rdev);
@@ -1792,6 +1811,8 @@ int rv770_resume(struct radeon_device *rdev)
        /* init golden registers */
        rv770_init_golden_registers(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = rv770_startup(rdev);
        if (r) {
@@ -1806,6 +1827,7 @@ int rv770_resume(struct radeon_device *rdev)
 
 int rv770_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        r600_audio_fini(rdev);
        uvd_v1_0_fini(rdev);
        radeon_uvd_suspend(rdev);
@@ -1876,6 +1898,17 @@ int rv770_init(struct radeon_device *rdev)
        if (r)
                return r;
 
+       if (!rdev->me_fw || !rdev->pfp_fw || !rdev->rlc_fw) {
+               r = r600_init_microcode(rdev);
+               if (r) {
+                       DRM_ERROR("Failed to load firmware!\n");
+                       return r;
+               }
+       }
+
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ring_obj = NULL;
        r600_ring_init(rdev, &rdev->ring[RADEON_RING_TYPE_GFX_INDEX], 1024 * 1024);
 
@@ -1915,6 +1948,7 @@ int rv770_init(struct radeon_device *rdev)
 
 void rv770_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        r700_cp_fini(rdev);
        r600_dma_fini(rdev);
        r600_irq_fini(rdev);
index 374499db20c7e59b55d956b066a30bdc42b4f71f..80c595aba359b53c4f748feae3aeab9d207f5db8 100644 (file)
@@ -1863,8 +1863,8 @@ void rv770_enable_auto_throttle_source(struct radeon_device *rdev,
        }
 }
 
-int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
-                                       int min_temp, int max_temp)
+static int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
+                                              int min_temp, int max_temp)
 {
        int low_temp = 0 * 1000;
        int high_temp = 255 * 1000;
@@ -1966,6 +1966,15 @@ int rv770_dpm_enable(struct radeon_device *rdev)
        if (pi->mg_clock_gating)
                rv770_mg_clock_gating_enable(rdev, true);
 
+       rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+       return 0;
+}
+
+int rv770_dpm_late_enable(struct radeon_device *rdev)
+{
+       int ret;
+
        if (rdev->irq.installed &&
            r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
                PPSMC_Result result;
@@ -1981,8 +1990,6 @@ int rv770_dpm_enable(struct radeon_device *rdev)
                        DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
        }
 
-       rv770_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
-
        return 0;
 }
 
@@ -2244,14 +2251,12 @@ static void rv7xx_parse_pplib_clock_info(struct radeon_device *rdev,
                pl->vddci = vddci;
        }
 
-       if (rdev->family >= CHIP_BARTS) {
-               if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
-                   ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
-                       rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
-                       rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
-                       rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
-                       rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
-               }
+       if ((rps->class & ATOM_PPLIB_CLASSIFICATION_UI_MASK) ==
+           ATOM_PPLIB_CLASSIFICATION_UI_PERFORMANCE) {
+               rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.sclk = pl->sclk;
+               rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.mclk = pl->mclk;
+               rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddc = pl->vddc;
+               rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac.vddci = pl->vddci;
        }
 }
 
@@ -2531,6 +2536,12 @@ bool rv770_dpm_vblank_too_short(struct radeon_device *rdev)
            (rdev->pdev->subsystem_device == 0x1c42))
                switch_limit = 200;
 
+       /* RV770 */
+       /* mclk switching doesn't seem to work reliably on desktop RV770s */
+       if ((rdev->family == CHIP_RV770) &&
+           !(rdev->flags & RADEON_IS_MOBILITY))
+               switch_limit = 0xffffffff; /* disable mclk switching */
+
        if (vblank_time < switch_limit)
                return true;
        else
index 9244effc6b59e2e69c6882b0d4dc35dd2517379c..f776634840c9782bde2e9228007720448aa469d1 100644 (file)
@@ -283,8 +283,4 @@ int rv770_read_smc_soft_register(struct radeon_device *rdev,
 int rv770_write_smc_soft_register(struct radeon_device *rdev,
                                  u16 reg_offset, u32 value);
 
-/* thermal */
-int rv770_set_thermal_temperature_range(struct radeon_device *rdev,
-                                       int min_temp, int max_temp);
-
 #endif
index 1ae277152cc7f0c66f7babbcb0cdfcec5ab04f71..3cf1e2921545f9a980569925088d720e347505d1 100644 (file)
 #define        CG_SPLL_FUNC_CNTL_2                             0x604
 #define                SCLK_MUX_SEL(x)                         ((x) << 0)
 #define                SCLK_MUX_SEL_MASK                       (0x1ff << 0)
+#define                SCLK_MUX_UPDATE                         (1 << 26)
 #define        CG_SPLL_FUNC_CNTL_3                             0x608
 #define                SPLL_FB_DIV(x)                          ((x) << 0)
 #define                SPLL_FB_DIV_MASK                        (0x3ffffff << 0)
 #define                SPLL_DITHEN                             (1 << 28)
+#define        CG_SPLL_STATUS                                  0x60c
+#define                SPLL_CHG_STATUS                         (1 << 1)
 
 #define        SPLL_CNTL_MODE                                  0x610
 #define                SPLL_DIV_SYNC                           (1 << 5)
 
+#define MPLL_CNTL_MODE                                  0x61c
+#       define MPLL_MCLK_SEL                            (1 << 11)
+#       define RV730_MPLL_MCLK_SEL                      (1 << 25)
+
 #define        MPLL_AD_FUNC_CNTL                               0x624
 #define                CLKF(x)                                 ((x) << 0)
 #define                CLKF_MASK                               (0x7f << 0)
index 85e1edfaa3bed0814e262378ae0a7558834936d3..09ec4f6c53bb2202dec2e9c039a3877593d2c4fe 100644 (file)
@@ -80,6 +80,8 @@ extern void evergreen_print_gpu_status_regs(struct radeon_device *rdev);
 extern bool evergreen_is_display_hung(struct radeon_device *rdev);
 static void si_enable_gui_idle_interrupt(struct radeon_device *rdev,
                                         bool enable);
+static void si_init_pg(struct radeon_device *rdev);
+static void si_init_cg(struct radeon_device *rdev);
 static void si_fini_pg(struct radeon_device *rdev);
 static void si_fini_cg(struct radeon_device *rdev);
 static void si_rlc_stop(struct radeon_device *rdev);
@@ -1460,7 +1462,7 @@ static const u32 hainan_io_mc_regs[TAHITI_IO_MC_REGS_SIZE][2] = {
 };
 
 /* ucode loading */
-static int si_mc_load_microcode(struct radeon_device *rdev)
+int si_mc_load_microcode(struct radeon_device *rdev)
 {
        const __be32 *fw_data;
        u32 running, blackout = 0;
@@ -3247,7 +3249,8 @@ static void si_cp_enable(struct radeon_device *rdev, bool enable)
        if (enable)
                WREG32(CP_ME_CNTL, 0);
        else {
-               radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
+               if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
+                       radeon_ttm_set_active_vram_size(rdev, rdev->mc.visible_vram_size);
                WREG32(CP_ME_CNTL, (CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT));
                WREG32(SCRATCH_UMSK, 0);
                rdev->ring[RADEON_RING_TYPE_GFX_INDEX].ready = false;
@@ -3508,6 +3511,9 @@ static int si_cp_resume(struct radeon_device *rdev)
 
        si_enable_gui_idle_interrupt(rdev, true);
 
+       if (rdev->asic->copy.copy_ring_index == RADEON_RING_TYPE_GFX_INDEX)
+               radeon_ttm_set_active_vram_size(rdev, rdev->mc.real_vram_size);
+
        return 0;
 }
 
@@ -3724,6 +3730,106 @@ static void si_gpu_soft_reset(struct radeon_device *rdev, u32 reset_mask)
        evergreen_print_gpu_status_regs(rdev);
 }
 
+static void si_set_clk_bypass_mode(struct radeon_device *rdev)
+{
+       u32 tmp, i;
+
+       tmp = RREG32(CG_SPLL_FUNC_CNTL);
+       tmp |= SPLL_BYPASS_EN;
+       WREG32(CG_SPLL_FUNC_CNTL, tmp);
+
+       tmp = RREG32(CG_SPLL_FUNC_CNTL_2);
+       tmp |= SPLL_CTLREQ_CHG;
+       WREG32(CG_SPLL_FUNC_CNTL_2, tmp);
+
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               if (RREG32(SPLL_STATUS) & SPLL_CHG_STATUS)
+                       break;
+               udelay(1);
+       }
+
+       tmp = RREG32(CG_SPLL_FUNC_CNTL_2);
+       tmp &= ~(SPLL_CTLREQ_CHG | SCLK_MUX_UPDATE);
+       WREG32(CG_SPLL_FUNC_CNTL_2, tmp);
+
+       tmp = RREG32(MPLL_CNTL_MODE);
+       tmp &= ~MPLL_MCLK_SEL;
+       WREG32(MPLL_CNTL_MODE, tmp);
+}
+
+static void si_spll_powerdown(struct radeon_device *rdev)
+{
+       u32 tmp;
+
+       tmp = RREG32(SPLL_CNTL_MODE);
+       tmp |= SPLL_SW_DIR_CONTROL;
+       WREG32(SPLL_CNTL_MODE, tmp);
+
+       tmp = RREG32(CG_SPLL_FUNC_CNTL);
+       tmp |= SPLL_RESET;
+       WREG32(CG_SPLL_FUNC_CNTL, tmp);
+
+       tmp = RREG32(CG_SPLL_FUNC_CNTL);
+       tmp |= SPLL_SLEEP;
+       WREG32(CG_SPLL_FUNC_CNTL, tmp);
+
+       tmp = RREG32(SPLL_CNTL_MODE);
+       tmp &= ~SPLL_SW_DIR_CONTROL;
+       WREG32(SPLL_CNTL_MODE, tmp);
+}
+
+static void si_gpu_pci_config_reset(struct radeon_device *rdev)
+{
+       struct evergreen_mc_save save;
+       u32 tmp, i;
+
+       dev_info(rdev->dev, "GPU pci config reset\n");
+
+       /* disable dpm? */
+
+       /* disable cg/pg */
+       si_fini_pg(rdev);
+       si_fini_cg(rdev);
+
+       /* Disable CP parsing/prefetching */
+       WREG32(CP_ME_CNTL, CP_ME_HALT | CP_PFP_HALT | CP_CE_HALT);
+       /* dma0 */
+       tmp = RREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL + DMA0_REGISTER_OFFSET, tmp);
+       /* dma1 */
+       tmp = RREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET);
+       tmp &= ~DMA_RB_ENABLE;
+       WREG32(DMA_RB_CNTL + DMA1_REGISTER_OFFSET, tmp);
+       /* XXX other engines? */
+
+       /* halt the rlc, disable cp internal ints */
+       si_rlc_stop(rdev);
+
+       udelay(50);
+
+       /* disable mem access */
+       evergreen_mc_stop(rdev, &save);
+       if (evergreen_mc_wait_for_idle(rdev)) {
+               dev_warn(rdev->dev, "Wait for MC idle timed out !\n");
+       }
+
+       /* set mclk/sclk to bypass */
+       si_set_clk_bypass_mode(rdev);
+       /* powerdown spll */
+       si_spll_powerdown(rdev);
+       /* disable BM */
+       pci_clear_master(rdev->pdev);
+       /* reset */
+       radeon_pci_config_reset(rdev);
+       /* wait for asic to come out of reset */
+       for (i = 0; i < rdev->usec_timeout; i++) {
+               if (RREG32(CONFIG_MEMSIZE) != 0xffffffff)
+                       break;
+               udelay(1);
+       }
+}
+
 int si_asic_reset(struct radeon_device *rdev)
 {
        u32 reset_mask;
@@ -3733,10 +3839,17 @@ int si_asic_reset(struct radeon_device *rdev)
        if (reset_mask)
                r600_set_bios_scratch_engine_hung(rdev, true);
 
+       /* try soft reset */
        si_gpu_soft_reset(rdev, reset_mask);
 
        reset_mask = si_gpu_check_soft_reset(rdev);
 
+       /* try pci config reset */
+       if (reset_mask && radeon_hard_reset)
+               si_gpu_pci_config_reset(rdev);
+
+       reset_mask = si_gpu_check_soft_reset(rdev);
+
        if (!reset_mask)
                r600_set_bios_scratch_engine_hung(rdev, false);
 
@@ -5212,8 +5325,8 @@ static void si_enable_hdp_ls(struct radeon_device *rdev,
                WREG32(HDP_MEM_POWER_LS, data);
 }
 
-void si_update_cg(struct radeon_device *rdev,
-                 u32 block, bool enable)
+static void si_update_cg(struct radeon_device *rdev,
+                        u32 block, bool enable)
 {
        if (block & RADEON_CG_BLOCK_GFX) {
                si_enable_gui_idle_interrupt(rdev, false);
@@ -5379,6 +5492,9 @@ static void si_init_pg(struct radeon_device *rdev)
                si_init_ao_cu_mask(rdev);
                if (rdev->pg_flags & RADEON_PG_SUPPORT_GFX_PG) {
                        si_init_gfx_cgpg(rdev);
+               } else {
+                       WREG32(RLC_SAVE_AND_RESTORE_BASE, rdev->rlc.save_restore_gpu_addr >> 8);
+                       WREG32(RLC_CLEAR_STATE_RESTORE_BASE, rdev->rlc.clear_state_gpu_addr >> 8);
                }
                si_enable_dma_pg(rdev, true);
                si_enable_gfx_cgpg(rdev, true);
@@ -5566,7 +5682,7 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
        }
 
        if (!ASIC_IS_NODCE(rdev)) {
-               WREG32(DACA_AUTODETECT_INT_CONTROL, 0);
+               WREG32(DAC_AUTODETECT_INT_CONTROL, 0);
 
                tmp = RREG32(DC_HPD1_INT_CONTROL) & DC_HPDx_INT_POLARITY;
                WREG32(DC_HPD1_INT_CONTROL, tmp);
@@ -6324,21 +6440,14 @@ static int si_startup(struct radeon_device *rdev)
 
        si_mc_program(rdev);
 
-       if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
-           !rdev->rlc_fw || !rdev->mc_fw) {
-               r = si_init_microcode(rdev);
+       if (!rdev->pm.dpm_enabled) {
+               r = si_mc_load_microcode(rdev);
                if (r) {
-                       DRM_ERROR("Failed to load firmware!\n");
+                       DRM_ERROR("Failed to load MC firmware!\n");
                        return r;
                }
        }
 
-       r = si_mc_load_microcode(rdev);
-       if (r) {
-               DRM_ERROR("Failed to load MC firmware!\n");
-               return r;
-       }
-
        r = si_pcie_gart_enable(rdev);
        if (r)
                return r;
@@ -6421,37 +6530,30 @@ static int si_startup(struct radeon_device *rdev)
 
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP_RPTR_OFFSET,
-                            CP_RB0_RPTR, CP_RB0_WPTR,
                             RADEON_CP_PACKET2);
        if (r)
                return r;
 
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP1_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP1_RPTR_OFFSET,
-                            CP_RB1_RPTR, CP_RB1_WPTR,
                             RADEON_CP_PACKET2);
        if (r)
                return r;
 
        ring = &rdev->ring[CAYMAN_RING_TYPE_CP2_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, RADEON_WB_CP2_RPTR_OFFSET,
-                            CP_RB2_RPTR, CP_RB2_WPTR,
                             RADEON_CP_PACKET2);
        if (r)
                return r;
 
        ring = &rdev->ring[R600_RING_TYPE_DMA_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, R600_WB_DMA_RPTR_OFFSET,
-                            DMA_RB_RPTR + DMA0_REGISTER_OFFSET,
-                            DMA_RB_WPTR + DMA0_REGISTER_OFFSET,
                             DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0));
        if (r)
                return r;
 
        ring = &rdev->ring[CAYMAN_RING_TYPE_DMA1_INDEX];
        r = radeon_ring_init(rdev, ring, ring->ring_size, CAYMAN_WB_DMA1_RPTR_OFFSET,
-                            DMA_RB_RPTR + DMA1_REGISTER_OFFSET,
-                            DMA_RB_WPTR + DMA1_REGISTER_OFFSET,
                             DMA_PACKET(DMA_PACKET_NOP, 0, 0, 0, 0));
        if (r)
                return r;
@@ -6471,7 +6573,6 @@ static int si_startup(struct radeon_device *rdev)
                ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
                if (ring->ring_size) {
                        r = radeon_ring_init(rdev, ring, ring->ring_size, 0,
-                                            UVD_RBC_RB_RPTR, UVD_RBC_RB_WPTR,
                                             RADEON_CP_PACKET2);
                        if (!r)
                                r = uvd_v1_0_init(rdev);
@@ -6513,6 +6614,8 @@ int si_resume(struct radeon_device *rdev)
        /* init golden registers */
        si_init_golden_registers(rdev);
 
+       radeon_pm_resume(rdev);
+
        rdev->accel_working = true;
        r = si_startup(rdev);
        if (r) {
@@ -6527,6 +6630,7 @@ int si_resume(struct radeon_device *rdev)
 
 int si_suspend(struct radeon_device *rdev)
 {
+       radeon_pm_suspend(rdev);
        dce6_audio_fini(rdev);
        radeon_vm_manager_fini(rdev);
        si_cp_enable(rdev, false);
@@ -6600,6 +6704,18 @@ int si_init(struct radeon_device *rdev)
        if (r)
                return r;
 
+       if (!rdev->me_fw || !rdev->pfp_fw || !rdev->ce_fw ||
+           !rdev->rlc_fw || !rdev->mc_fw) {
+               r = si_init_microcode(rdev);
+               if (r) {
+                       DRM_ERROR("Failed to load firmware!\n");
+                       return r;
+               }
+       }
+
+       /* Initialize power management */
+       radeon_pm_init(rdev);
+
        ring = &rdev->ring[RADEON_RING_TYPE_GFX_INDEX];
        ring->ring_obj = NULL;
        r600_ring_init(rdev, ring, 1024 * 1024);
@@ -6666,6 +6782,7 @@ int si_init(struct radeon_device *rdev)
 
 void si_fini(struct radeon_device *rdev)
 {
+       radeon_pm_fini(rdev);
        si_cp_fini(rdev);
        cayman_dma_fini(rdev);
        si_fini_pg(rdev);
index 0b00c790fb7713d8b4cbddb91c9b319ecc41c3b9..0471501338fbbeb9e7b72ee572b2bda126ab475a 100644 (file)
@@ -1738,6 +1738,8 @@ struct evergreen_power_info *evergreen_get_pi(struct radeon_device *rdev);
 struct ni_power_info *ni_get_pi(struct radeon_device *rdev);
 struct ni_ps *ni_get_ps(struct radeon_ps *rps);
 
+extern int si_mc_load_microcode(struct radeon_device *rdev);
+
 static int si_populate_voltage_value(struct radeon_device *rdev,
                                     const struct atom_voltage_table *table,
                                     u16 value, SISLANDS_SMC_VOLTAGE_VALUE *voltage);
@@ -1753,9 +1755,6 @@ static int si_calculate_sclk_params(struct radeon_device *rdev,
                                    u32 engine_clock,
                                    SISLANDS_SMC_SCLK_VALUE *sclk);
 
-extern void si_update_cg(struct radeon_device *rdev,
-                        u32 block, bool enable);
-
 static struct si_power_info *si_get_pi(struct radeon_device *rdev)
 {
         struct si_power_info *pi = rdev->pm.dpm.priv;
@@ -2396,7 +2395,7 @@ static int si_populate_sq_ramping_values(struct radeon_device *rdev,
        if (SISLANDS_DPM2_SQ_RAMP_STI_SIZE > (STI_SIZE_MASK >> STI_SIZE_SHIFT))
                enable_sq_ramping = false;
 
-       if (NISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
+       if (SISLANDS_DPM2_SQ_RAMP_LTI_RATIO <= (LTI_RATIO_MASK >> LTI_RATIO_SHIFT))
                enable_sq_ramping = false;
 
        for (i = 0; i < state->performance_level_count; i++) {
@@ -3591,10 +3590,9 @@ static void si_program_display_gap(struct radeon_device *rdev)
 
        /* Setting this to false forces the performance state to low if the crtcs are disabled.
         * This can be a problem on PowerXpress systems or if you want to use the card
-        * for offscreen rendering or compute if there are no crtcs enabled.  Set it to
-        * true for now so that performance scales even if the displays are off.
+        * for offscreen rendering or compute if there are no crtcs enabled.
         */
-       si_notify_smc_display_change(rdev, true /*rdev->pm.dpm.new_active_crtc_count > 0*/);
+       si_notify_smc_display_change(rdev, rdev->pm.dpm.new_active_crtc_count > 0);
 }
 
 static void si_enable_spread_spectrum(struct radeon_device *rdev, bool enable)
@@ -5414,7 +5412,7 @@ static void si_populate_mc_reg_addresses(struct radeon_device *rdev,
 
        for (i = 0, j = 0; j < si_pi->mc_reg_table.last; j++) {
                if (si_pi->mc_reg_table.valid_flag & (1 << j)) {
-                       if (i >= SMC_NISLANDS_MC_REGISTER_ARRAY_SIZE)
+                       if (i >= SMC_SISLANDS_MC_REGISTER_ARRAY_SIZE)
                                break;
                        mc_reg_table->address[i].s0 =
                                cpu_to_be16(si_pi->mc_reg_table.mc_reg_address[j].s0);
@@ -5754,6 +5752,11 @@ static void si_set_pcie_lane_width_in_smc(struct radeon_device *rdev,
 
 void si_dpm_setup_asic(struct radeon_device *rdev)
 {
+       int r;
+
+       r = si_mc_load_microcode(rdev);
+       if (r)
+               DRM_ERROR("Failed to load MC firmware!\n");
        rv770_get_memory_type(rdev);
        si_read_clock_registers(rdev);
        si_enable_acpi_power_management(rdev);
@@ -5791,13 +5794,6 @@ int si_dpm_enable(struct radeon_device *rdev)
        struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
        int ret;
 
-       si_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                           RADEON_CG_BLOCK_MC |
-                           RADEON_CG_BLOCK_SDMA |
-                           RADEON_CG_BLOCK_BIF |
-                           RADEON_CG_BLOCK_UVD |
-                           RADEON_CG_BLOCK_HDP), false);
-
        if (si_is_smc_running(rdev))
                return -EINVAL;
        if (pi->voltage_control)
@@ -5900,6 +5896,17 @@ int si_dpm_enable(struct radeon_device *rdev)
        si_enable_sclk_control(rdev, true);
        si_start_dpm(rdev);
 
+       si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
+
+       ni_update_current_ps(rdev, boot_ps);
+
+       return 0;
+}
+
+int si_dpm_late_enable(struct radeon_device *rdev)
+{
+       int ret;
+
        if (rdev->irq.installed &&
            r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
                PPSMC_Result result;
@@ -5915,17 +5922,6 @@ int si_dpm_enable(struct radeon_device *rdev)
                        DRM_DEBUG_KMS("Could not enable thermal interrupts.\n");
        }
 
-       si_enable_auto_throttle_source(rdev, RADEON_DPM_AUTO_THROTTLE_SRC_THERMAL, true);
-
-       si_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                           RADEON_CG_BLOCK_MC |
-                           RADEON_CG_BLOCK_SDMA |
-                           RADEON_CG_BLOCK_BIF |
-                           RADEON_CG_BLOCK_UVD |
-                           RADEON_CG_BLOCK_HDP), true);
-
-       ni_update_current_ps(rdev, boot_ps);
-
        return 0;
 }
 
@@ -5934,13 +5930,6 @@ void si_dpm_disable(struct radeon_device *rdev)
        struct rv7xx_power_info *pi = rv770_get_pi(rdev);
        struct radeon_ps *boot_ps = rdev->pm.dpm.boot_ps;
 
-       si_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                           RADEON_CG_BLOCK_MC |
-                           RADEON_CG_BLOCK_SDMA |
-                           RADEON_CG_BLOCK_BIF |
-                           RADEON_CG_BLOCK_UVD |
-                           RADEON_CG_BLOCK_HDP), false);
-
        if (!si_is_smc_running(rdev))
                return;
        si_disable_ulv(rdev);
@@ -6005,13 +5994,6 @@ int si_dpm_set_power_state(struct radeon_device *rdev)
        struct radeon_ps *old_ps = &eg_pi->current_rps;
        int ret;
 
-       si_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                           RADEON_CG_BLOCK_MC |
-                           RADEON_CG_BLOCK_SDMA |
-                           RADEON_CG_BLOCK_BIF |
-                           RADEON_CG_BLOCK_UVD |
-                           RADEON_CG_BLOCK_HDP), false);
-
        ret = si_disable_ulv(rdev);
        if (ret) {
                DRM_ERROR("si_disable_ulv failed\n");
@@ -6104,13 +6086,6 @@ int si_dpm_set_power_state(struct radeon_device *rdev)
                return ret;
        }
 
-       si_update_cg(rdev, (RADEON_CG_BLOCK_GFX |
-                           RADEON_CG_BLOCK_MC |
-                           RADEON_CG_BLOCK_SDMA |
-                           RADEON_CG_BLOCK_BIF |
-                           RADEON_CG_BLOCK_UVD |
-                           RADEON_CG_BLOCK_HDP), true);
-
        return 0;
 }
 
index d422a1cbf727b375c467bcf78dc417431c7db2fd..e80efcf0c2306e812b4462ab930464bc03c8c5b5 100644 (file)
@@ -28,6 +28,7 @@
 #include "sid.h"
 #include "ppsmc.h"
 #include "radeon_ucode.h"
+#include "sislands_smc.h"
 
 static int si_set_smc_sram_address(struct radeon_device *rdev,
                                   u32 smc_address, u32 limit)
index b322acc48097f632a0fa1ac3204facc3287912f5..9239a6d291280765ef42b2e79e0c02f4719f33f9 100644 (file)
@@ -94,6 +94,8 @@
 #define        CG_SPLL_FUNC_CNTL_2                             0x604
 #define                SCLK_MUX_SEL(x)                         ((x) << 0)
 #define                SCLK_MUX_SEL_MASK                       (0x1ff << 0)
+#define                SPLL_CTLREQ_CHG                         (1 << 23)
+#define                SCLK_MUX_UPDATE                         (1 << 26)
 #define        CG_SPLL_FUNC_CNTL_3                             0x608
 #define                SPLL_FB_DIV(x)                          ((x) << 0)
 #define                SPLL_FB_DIV_MASK                        (0x3ffffff << 0)
 #define                SPLL_DITHEN                             (1 << 28)
 #define        CG_SPLL_FUNC_CNTL_4                             0x60c
 
+#define        SPLL_STATUS                                     0x614
+#define                SPLL_CHG_STATUS                         (1 << 1)
 #define        SPLL_CNTL_MODE                                  0x618
+#define                SPLL_SW_DIR_CONTROL                     (1 << 0)
 #      define SPLL_REFCLK_SEL(x)                       ((x) << 8)
 #      define SPLL_REFCLK_SEL_MASK                     0xFF00
 
 #       define MRDCK0_BYPASS                            (1 << 24)
 #       define MRDCK1_BYPASS                            (1 << 25)
 
+#define        MPLL_CNTL_MODE                                  0x2bb0
+#       define MPLL_MCLK_SEL                            (1 << 11)
 #define        MPLL_FUNC_CNTL                                  0x2bb4
 #define                BWCTRL(x)                               ((x) << 20)
 #define                BWCTRL_MASK                             (0xff << 20)
 #       define GRPH_PFLIP_INT_MASK                      (1 << 0)
 #       define GRPH_PFLIP_INT_TYPE                      (1 << 8)
 
-#define        DACA_AUTODETECT_INT_CONTROL                     0x66c8
+#define        DAC_AUTODETECT_INT_CONTROL                      0x67c8
 
 #define DC_HPD1_INT_STATUS                              0x601c
 #define DC_HPD2_INT_STATUS                              0x6028
index 5578e9837026fec65ac023a71c5ed3400d8d0734..10e945a49479e3e9bb611ec98cb62b409046acf6 100644 (file)
@@ -374,8 +374,6 @@ typedef struct Smc_SIslands_DTE_Configuration Smc_SIslands_DTE_Configuration;
 
 #pragma pack(pop)
 
-int si_set_smc_sram_address(struct radeon_device *rdev,
-                           u32 smc_address, u32 limit);
 int si_copy_bytes_to_smc(struct radeon_device *rdev,
                         u32 smc_start_address,
                         const u8 *src, u32 byte_count, u32 limit);
index 96ea6db8bf575e7a45f6af501e26120f7e996a9a..f121efe12dc5c10a4fd6f1c5283ee7f87e8b0797 100644 (file)
@@ -71,7 +71,7 @@ static const u32 sumo_dtc[SUMO_PM_NUMBER_OF_TC] =
        SUMO_DTC_DFLT_14,
 };
 
-struct sumo_ps *sumo_get_ps(struct radeon_ps *rps)
+static struct sumo_ps *sumo_get_ps(struct radeon_ps *rps)
 {
        struct sumo_ps *ps = rps->ps_priv;
 
@@ -1202,14 +1202,10 @@ static void sumo_update_requested_ps(struct radeon_device *rdev,
 int sumo_dpm_enable(struct radeon_device *rdev)
 {
        struct sumo_power_info *pi = sumo_get_pi(rdev);
-       int ret;
 
        if (sumo_dpm_enabled(rdev))
                return -EINVAL;
 
-       ret = sumo_enable_clock_power_gating(rdev);
-       if (ret)
-               return ret;
        sumo_program_bootup_state(rdev);
        sumo_init_bsp(rdev);
        sumo_reset_am(rdev);
@@ -1233,6 +1229,19 @@ int sumo_dpm_enable(struct radeon_device *rdev)
        if (pi->enable_boost)
                sumo_enable_boost_timer(rdev);
 
+       sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+
+       return 0;
+}
+
+int sumo_dpm_late_enable(struct radeon_device *rdev)
+{
+       int ret;
+
+       ret = sumo_enable_clock_power_gating(rdev);
+       if (ret)
+               return ret;
+
        if (rdev->irq.installed &&
            r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
                ret = sumo_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
@@ -1242,8 +1251,6 @@ int sumo_dpm_enable(struct radeon_device *rdev)
                radeon_irq_set(rdev);
        }
 
-       sumo_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
-
        return 0;
 }
 
index 18abba5b5810b467f23efb012b9eee24e5e3a155..fb081d2ae37477e37b0ec28068c7d45112e19bc0 100644 (file)
@@ -31,7 +31,6 @@
 #define SUMO_SMU_SERVICE_ROUTINE_ALTVDDNB_NOTIFY  27
 #define SUMO_SMU_SERVICE_ROUTINE_GFX_SRV_ID_20  20
 
-struct sumo_ps *sumo_get_ps(struct radeon_ps *rps);
 struct sumo_power_info *sumo_get_pi(struct radeon_device *rdev);
 
 static void sumo_send_msg_to_smu(struct radeon_device *rdev, u32 id)
index d700698a1f224bea67bd585061289e56735072e4..2d447192d6f7356b1f37af690e1242932b23d7bf 100644 (file)
@@ -342,14 +342,14 @@ static void trinity_apply_state_adjust_rules(struct radeon_device *rdev,
                                             struct radeon_ps *new_rps,
                                             struct radeon_ps *old_rps);
 
-struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
+static struct trinity_ps *trinity_get_ps(struct radeon_ps *rps)
 {
        struct trinity_ps *ps = rps->ps_priv;
 
        return ps;
 }
 
-struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
+static struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev)
 {
        struct trinity_power_info *pi = rdev->pm.dpm.priv;
 
@@ -1082,7 +1082,6 @@ void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
 int trinity_dpm_enable(struct radeon_device *rdev)
 {
        struct trinity_power_info *pi = trinity_get_pi(rdev);
-       int ret;
 
        trinity_acquire_mutex(rdev);
 
@@ -1091,7 +1090,6 @@ int trinity_dpm_enable(struct radeon_device *rdev)
                return -EINVAL;
        }
 
-       trinity_enable_clock_power_gating(rdev);
        trinity_program_bootup_state(rdev);
        sumo_program_vc(rdev, 0x00C00033);
        trinity_start_am(rdev);
@@ -1105,6 +1103,18 @@ int trinity_dpm_enable(struct radeon_device *rdev)
        trinity_dpm_bapm_enable(rdev, false);
        trinity_release_mutex(rdev);
 
+       trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+
+       return 0;
+}
+
+int trinity_dpm_late_enable(struct radeon_device *rdev)
+{
+       int ret;
+
+       trinity_acquire_mutex(rdev);
+       trinity_enable_clock_power_gating(rdev);
+
        if (rdev->irq.installed &&
            r600_is_internal_thermal_sensor(rdev->pm.int_thermal_type)) {
                ret = trinity_set_thermal_temperature_range(rdev, R600_TEMP_RANGE_MIN, R600_TEMP_RANGE_MAX);
@@ -1115,8 +1125,7 @@ int trinity_dpm_enable(struct radeon_device *rdev)
                rdev->irq.dpm_thermal = true;
                radeon_irq_set(rdev);
        }
-
-       trinity_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
+       trinity_release_mutex(rdev);
 
        return 0;
 }
index 9672bcbc7312218a357f07ae54393ed511284279..99dd0455334d1a433c880565ee84dd60e14989c9 100644 (file)
@@ -27,9 +27,6 @@
 #include "trinity_dpm.h"
 #include "ppsmc.h"
 
-struct trinity_ps *trinity_get_ps(struct radeon_ps *rps);
-struct trinity_power_info *trinity_get_pi(struct radeon_device *rdev);
-
 static int trinity_notify_message_to_smu(struct radeon_device *rdev, u32 id)
 {
        int i;
index b19ef4951085b06422aa7b2f8b1f634fba086d87..824550db3fed59e2220953e9e9976b8b28443260 100644 (file)
@@ -153,6 +153,7 @@ int uvd_v2_2_resume(struct radeon_device *rdev)
                chip_id = 0x01000015;
                break;
        case CHIP_PITCAIRN:
+       case CHIP_OLAND:
                chip_id = 0x01000016;
                break;
        case CHIP_ARUBA:
index a9d24e4bf79280c90991c155634c0ca8bd87c1d9..fbf4be316d0b675f89be45db4d820952af079287 100644 (file)
@@ -371,7 +371,6 @@ static int rcar_du_crtc_mode_set(struct drm_crtc *crtc,
                goto error;
 
        rcrtc->plane->format = format;
-       rcrtc->plane->pitch = crtc->fb->pitches[0];
 
        rcrtc->plane->src_x = x;
        rcrtc->plane->src_y = y;
@@ -413,7 +412,7 @@ static int rcar_du_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
        rcrtc->plane->src_x = x;
        rcrtc->plane->src_y = y;
 
-       rcar_du_crtc_update_base(to_rcar_crtc(crtc));
+       rcar_du_crtc_update_base(rcrtc);
 
        return 0;
 }
index 0023f9719cf18fda9e2f3232bae5bf178e15de7d..792fd1d20e865df1125294dcfbf626e6a7a16524 100644 (file)
@@ -224,7 +224,9 @@ static int rcar_du_probe(struct platform_device *pdev)
 
 static int rcar_du_remove(struct platform_device *pdev)
 {
-       drm_platform_exit(&rcar_du_driver, pdev);
+       struct rcar_du_device *rcdu = platform_get_drvdata(pdev);
+
+       drm_put_dev(rcdu->ddev);
 
        return 0;
 }
@@ -249,8 +251,8 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = {
 };
 
 static const struct rcar_du_device_info rcar_du_r8a7790_info = {
-       .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_ALIGN_128B
-                 | RCAR_DU_FEATURE_DEFR8,
+       .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
@@ -272,9 +274,29 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
        .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 },
        { }
 };
 
index 65d2d636b002d9fbf32fb2c6391b8df4bc63ff03..e31b735d3f258b69b65ab97320ddfe7440d7d6b9 100644 (file)
@@ -28,8 +28,10 @@ struct rcar_du_device;
 struct rcar_du_lvdsenc;
 
 #define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0)        /* Per-CRTC IRQ and clock */
-#define RCAR_DU_FEATURE_ALIGN_128B     (1 << 1)        /* Align pitches to 128 bytes */
-#define RCAR_DU_FEATURE_DEFR8          (1 << 2)        /* Has DEFR8 register */
+#define RCAR_DU_FEATURE_DEFR8          (1 << 1)        /* Has DEFR8 register */
+
+#define RCAR_DU_QUIRK_ALIGN_128B       (1 << 0)        /* Align pitches to 128 bytes */
+#define RCAR_DU_QUIRK_LVDS_LANES       (1 << 1)        /* LVDS lanes 1 and 3 inverted */
 
 /*
  * struct rcar_du_output_routing - Output routing specification
@@ -48,12 +50,14 @@ struct rcar_du_output_routing {
 /*
  * struct rcar_du_device_info - DU model-specific information
  * @features: device features (RCAR_DU_FEATURE_*)
+ * @quirks: device quirks (RCAR_DU_QUIRK_*)
  * @num_crtcs: total number of CRTCs
  * @routes: array of CRTC to output routes, indexed by output (RCAR_DU_OUTPUT_*)
  * @num_lvds: number of internal LVDS encoders
  */
 struct rcar_du_device_info {
        unsigned int features;
+       unsigned int quirks;
        unsigned int num_crtcs;
        struct rcar_du_output_routing routes[RCAR_DU_OUTPUT_MAX];
        unsigned int num_lvds;
@@ -84,6 +88,12 @@ static inline bool rcar_du_has(struct rcar_du_device *rcdu,
        return rcdu->info->features & feature;
 }
 
+static inline bool rcar_du_needs(struct rcar_du_device *rcdu,
+                                unsigned int quirk)
+{
+       return rcdu->info->quirks & quirk;
+}
+
 static inline u32 rcar_du_read(struct rcar_du_device *rcdu, u32 reg)
 {
        return ioread32(rcdu->mmio + reg);
index b31ac080c4a77ba6554ae281d0fd90754e8d633b..fbeabd9a281f9a71c2e283df478fb7e3428a7655 100644 (file)
@@ -119,7 +119,7 @@ int rcar_du_dumb_create(struct drm_file *file, struct drm_device *dev,
        /* The R8A7779 DU requires a 16 pixels pitch alignment as documented,
         * but the R8A7790 DU seems to require a 128 bytes pitch alignment.
         */
-       if (rcar_du_has(rcdu, RCAR_DU_FEATURE_ALIGN_128B))
+       if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B))
                align = 128;
        else
                align = 16 * args->bpp / 8;
@@ -144,7 +144,7 @@ rcar_du_fb_create(struct drm_device *dev, struct drm_file *file_priv,
                return ERR_PTR(-EINVAL);
        }
 
-       if (rcar_du_has(rcdu, RCAR_DU_FEATURE_ALIGN_128B))
+       if (rcar_du_needs(rcdu, RCAR_DU_QUIRK_ALIGN_128B))
                align = 128;
        else
                align = 16 * format->bpp / 8;
index a0f6a17819252b51c0f201861777b8c73fc30ef1..df30a075d793ce5d97c550c80a2f01ce172fbdc1 100644 (file)
@@ -44,6 +44,7 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
        const struct drm_display_mode *mode = &rcrtc->crtc.mode;
        unsigned int freq = mode->clock;
        u32 lvdcr0;
+       u32 lvdhcr;
        u32 pllcr;
        int ret;
 
@@ -72,15 +73,19 @@ static int rcar_du_lvdsenc_start(struct rcar_du_lvdsenc *lvds,
         * VSYNC -> CTRL1
         * DISP  -> CTRL2
         * 0     -> CTRL3
-        *
-        * Channels 1 and 3 are switched on ES1.
         */
        rcar_lvds_write(lvds, LVDCTRCR, LVDCTRCR_CTR3SEL_ZERO |
                        LVDCTRCR_CTR2SEL_DISP | LVDCTRCR_CTR1SEL_VSYNC |
                        LVDCTRCR_CTR0SEL_HSYNC);
-       rcar_lvds_write(lvds, LVDCHCR,
-                       LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3) |
-                       LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1));
+
+       if (rcar_du_needs(lvds->dev, RCAR_DU_QUIRK_LVDS_LANES))
+               lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 3)
+                      | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 1);
+       else
+               lvdhcr = LVDCHCR_CHSEL_CH(0, 0) | LVDCHCR_CHSEL_CH(1, 1)
+                      | LVDCHCR_CHSEL_CH(2, 2) | LVDCHCR_CHSEL_CH(3, 3);
+
+       rcar_lvds_write(lvds, LVDCHCR, lvdhcr);
 
        /* Select the input, hardcode mode 0, enable LVDS operation and turn
         * bias circuitry on.
@@ -144,18 +149,9 @@ static int rcar_du_lvdsenc_get_resources(struct rcar_du_lvdsenc *lvds,
        sprintf(name, "lvds.%u", lvds->index);
 
        mem = platform_get_resource_byname(pdev, IORESOURCE_MEM, name);
-       if (mem == NULL) {
-               dev_err(&pdev->dev, "failed to get memory resource for %s\n",
-                       name);
-               return -EINVAL;
-       }
-
        lvds->mmio = devm_ioremap_resource(&pdev->dev, mem);
-       if (lvds->mmio == NULL) {
-               dev_err(&pdev->dev, "failed to remap memory resource for %s\n",
-                       name);
-               return -ENOMEM;
-       }
+       if (IS_ERR(lvds->mmio))
+               return PTR_ERR(lvds->mmio);
 
        lvds->clock = devm_clk_get(&pdev->dev, name);
        if (IS_ERR(lvds->clock)) {
index 53000644733f29c25a5db1edb5d24e5090bbc666..3fb69d9ae61bd15fdea9e1801a5e0c69a19d13df 100644 (file)
@@ -104,6 +104,15 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
 {
        struct rcar_du_group *rgrp = plane->group;
        unsigned int index = plane->hwindex;
+       u32 mwr;
+
+       /* Memory pitch (expressed in pixels) */
+       if (plane->format->planes == 2)
+               mwr = plane->pitch;
+       else
+               mwr = plane->pitch * 8 / plane->format->bpp;
+
+       rcar_du_plane_write(rgrp, index, PnMWR, mwr);
 
        /* The Y position is expressed in raster line units and must be doubled
         * for 32bpp formats, according to the R8A7790 datasheet. No mention of
@@ -133,6 +142,8 @@ void rcar_du_plane_compute_base(struct rcar_du_plane *plane,
 {
        struct drm_gem_cma_object *gem;
 
+       plane->pitch = fb->pitches[0];
+
        gem = drm_fb_cma_get_gem_obj(fb, 0);
        plane->dma[0] = gem->paddr + fb->offsets[0];
 
@@ -209,7 +220,6 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
        struct rcar_du_group *rgrp = plane->group;
        u32 ddcr2 = PnDDCR2_CODE;
        u32 ddcr4;
-       u32 mwr;
 
        /* Data format
         *
@@ -240,14 +250,6 @@ static void __rcar_du_plane_setup(struct rcar_du_plane *plane,
        rcar_du_plane_write(rgrp, index, PnDDCR2, ddcr2);
        rcar_du_plane_write(rgrp, index, PnDDCR4, ddcr4);
 
-       /* Memory pitch (expressed in pixels) */
-       if (plane->format->planes == 2)
-               mwr = plane->pitch;
-       else
-               mwr = plane->pitch * 8 / plane->format->bpp;
-
-       rcar_du_plane_write(rgrp, index, PnMWR, mwr);
-
        /* Destination position and size */
        rcar_du_plane_write(rgrp, index, PnDSXR, plane->width);
        rcar_du_plane_write(rgrp, index, PnDSYR, plane->height);
@@ -309,7 +311,6 @@ rcar_du_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
 
        rplane->crtc = crtc;
        rplane->format = format;
-       rplane->pitch = fb->pitches[0];
 
        rplane->src_x = src_x >> 16;
        rplane->src_y = src_y >> 16;
index b17d0710871abc77487973d837dfe212d17eb5df..d2b2df9e26f3692b51d7495b5197b66ad9d6387b 100644 (file)
@@ -49,7 +49,7 @@ savage_bci_wait_fifo_shadow(drm_savage_private_t * dev_priv, unsigned int n)
 #endif
 
        for (i = 0; i < SAVAGE_DEFAULT_USEC_TIMEOUT; i++) {
-               DRM_MEMORYBARRIER();
+               mb();
                status = dev_priv->status_ptr[0];
                if ((status & mask) < threshold)
                        return 0;
@@ -123,7 +123,7 @@ savage_bci_wait_event_shadow(drm_savage_private_t * dev_priv, uint16_t e)
        int i;
 
        for (i = 0; i < SAVAGE_EVENT_USEC_TIMEOUT; i++) {
-               DRM_MEMORYBARRIER();
+               mb();
                status = dev_priv->status_ptr[1];
                if ((((status & 0xffff) - e) & 0xffff) <= 0x7fff ||
                    (status & 0xffff) == 0)
@@ -449,7 +449,7 @@ static void savage_dma_flush(drm_savage_private_t * dev_priv)
                }
        }
 
-       DRM_MEMORYBARRIER();
+       mb();
 
        /* do flush ... */
        phys_addr = dev_priv->cmd_dma->offset +
@@ -990,10 +990,10 @@ static int savage_bci_get_buffers(struct drm_device *dev,
 
                buf->file_priv = file_priv;
 
-               if (DRM_COPY_TO_USER(&d->request_indices[i],
+               if (copy_to_user(&d->request_indices[i],
                                     &buf->idx, sizeof(buf->idx)))
                        return -EFAULT;
-               if (DRM_COPY_TO_USER(&d->request_sizes[i],
+               if (copy_to_user(&d->request_sizes[i],
                                     &buf->total, sizeof(buf->total)))
                        return -EFAULT;
 
index b35e75ed890c0384c48130108858d5e2f95297c3..c01ad0aeaa5806dd034910eff873d48a149fdbc5 100644 (file)
@@ -992,7 +992,7 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_
                if (kcmd_addr == NULL)
                        return -ENOMEM;
 
-               if (DRM_COPY_FROM_USER(kcmd_addr, cmdbuf->cmd_addr,
+               if (copy_from_user(kcmd_addr, cmdbuf->cmd_addr,
                                       cmdbuf->size * 8))
                {
                        kfree(kcmd_addr);
@@ -1007,7 +1007,7 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_
                        goto done;
                }
 
-               if (DRM_COPY_FROM_USER(kvb_addr, cmdbuf->vb_addr,
+               if (copy_from_user(kvb_addr, cmdbuf->vb_addr,
                                       cmdbuf->vb_size)) {
                        ret = -EFAULT;
                        goto done;
@@ -1022,7 +1022,7 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_
                        goto done;
                }
 
-               if (DRM_COPY_FROM_USER(kbox_addr, cmdbuf->box_addr,
+               if (copy_from_user(kbox_addr, cmdbuf->box_addr,
                                       cmdbuf->nbox * sizeof(struct drm_clip_rect))) {
                        ret = -EFAULT;
                        goto done;
@@ -1032,7 +1032,7 @@ int savage_bci_cmdbuf(struct drm_device *dev, void *data, struct drm_file *file_
 
        /* Make sure writes to DMA buffers are finished before sending
         * DMA commands to the graphics hardware. */
-       DRM_MEMORYBARRIER();
+       mb();
 
        /* Coming from user space. Don't know if the Xserver has
         * emitted wait commands. Assuming the worst. */
index 562f9a401cf65996bb5b0fa99982451271537736..0428076f1ce8723d025e64cdea77df33777288b6 100644 (file)
  * Clock management
  */
 
-static void shmob_drm_clk_on(struct shmob_drm_device *sdev)
+static int shmob_drm_clk_on(struct shmob_drm_device *sdev)
 {
-       if (sdev->clock)
-               clk_prepare_enable(sdev->clock);
+       int ret;
+
+       if (sdev->clock) {
+               ret = clk_prepare_enable(sdev->clock);
+               if (ret < 0)
+                       return ret;
+       }
 #if 0
        if (sdev->meram_dev && sdev->meram_dev->pdev)
                pm_runtime_get_sync(&sdev->meram_dev->pdev->dev);
 #endif
+
+       return 0;
 }
 
 static void shmob_drm_clk_off(struct shmob_drm_device *sdev)
@@ -161,6 +168,7 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
        struct drm_device *dev = sdev->ddev;
        struct drm_plane *plane;
        u32 value;
+       int ret;
 
        if (scrtc->started)
                return;
@@ -170,7 +178,9 @@ static void shmob_drm_crtc_start(struct shmob_drm_crtc *scrtc)
                return;
 
        /* Enable clocks before accessing the hardware. */
-       shmob_drm_clk_on(sdev);
+       ret = shmob_drm_clk_on(sdev);
+       if (ret < 0)
+               return;
 
        /* Reset and enable the LCDC. */
        lcdc_write(sdev, LDCNT2R, lcdc_read(sdev, LDCNT2R) | LDCNT2R_BR);
index 015551866b4a0d3c6f9912c361993f99c3b548b1..c839c9c89efbf6f4eb4a37cac2fba654435bd1f9 100644 (file)
@@ -336,7 +336,9 @@ static int shmob_drm_probe(struct platform_device *pdev)
 
 static int shmob_drm_remove(struct platform_device *pdev)
 {
-       drm_platform_exit(&shmob_drm_driver, pdev);
+       struct shmob_drm_device *sdev = platform_get_drvdata(pdev);
+
+       drm_put_dev(sdev->ddev);
 
        return 0;
 }
index 4383b74a3aa46f480ac3c118e3a113812fdff9de..756f787b71439ac42af2b6a723916207165b2382 100644 (file)
@@ -94,7 +94,7 @@ static int sis_driver_open(struct drm_device *dev, struct drm_file *file)
        return 0;
 }
 
-void sis_driver_postclose(struct drm_device *dev, struct drm_file *file)
+static void sis_driver_postclose(struct drm_device *dev, struct drm_file *file)
 {
        struct sis_file_private *file_priv = file->driver_priv;
 
index 01857d836350db00261d96870af2571e2b3e356f..0573be0d293304269f6cd11eb8677002ddf217a6 100644 (file)
@@ -266,7 +266,7 @@ int sis_idle(struct drm_device *dev)
         * because its polling frequency is too low.
         */
 
-       end = jiffies + (DRM_HZ * 3);
+       end = jiffies + (HZ * 3);
 
        for (i = 0; i < 4; ++i) {
                do {
index 8db9b3bce001fd5dd15e4de157a09d1f9b242ff4..354ddb29231f26e67e6ac9ec3a638358b47923c4 100644 (file)
@@ -1,14 +1,12 @@
 config DRM_TEGRA
-       bool "NVIDIA Tegra DRM"
-       depends on ARCH_TEGRA || ARCH_MULTIPLATFORM
+       tristate "NVIDIA Tegra DRM"
+       depends on ARCH_TEGRA || (ARM && COMPILE_TEST)
        depends on DRM
        depends on RESET_CONTROLLER
-       select TEGRA_HOST1X
        select DRM_KMS_HELPER
-       select DRM_KMS_FB_HELPER
-       select FB_SYS_FILLRECT
-       select FB_SYS_COPYAREA
-       select FB_SYS_IMAGEBLIT
+       select DRM_MIPI_DSI
+       select DRM_PANEL
+       select TEGRA_HOST1X
        help
          Choose this option if you have an NVIDIA Tegra SoC.
 
@@ -17,6 +15,18 @@ config DRM_TEGRA
 
 if DRM_TEGRA
 
+config DRM_TEGRA_FBDEV
+       bool "Enable legacy fbdev support"
+       select DRM_KMS_FB_HELPER
+       select FB_SYS_FILLRECT
+       select FB_SYS_COPYAREA
+       select FB_SYS_IMAGEBLIT
+       default y
+       help
+         Choose this option if you have a need for the legacy fbdev support.
+         Note that this support also provides the Linux console on top of
+         the Tegra modesetting driver.
+
 config DRM_TEGRA_DEBUG
        bool "NVIDIA Tegra DRM debug support"
        help
index edc76abd58bb3ba6c67ca6782ecb3999224db6c1..8d220afbd85f94c6599a2ec0015c38ee7c87434b 100644 (file)
@@ -9,6 +9,8 @@ tegra-drm-y := \
        output.o \
        rgb.o \
        hdmi.o \
+       mipi-phy.o \
+       dsi.o \
        gr2d.o \
        gr3d.o
 
index 565f8f7b9a4781d0f9d0b33e1b53b2ecbe2b7eda..e38e5967d77bdc4a4c709cd44744887318cb87bf 100644 (file)
@@ -46,7 +46,6 @@ int drm_host1x_init(struct drm_driver *driver, struct host1x_device *device)
        struct drm_device *drm;
        int ret;
 
-       INIT_LIST_HEAD(&driver->device_list);
        driver->bus = &drm_host1x_bus;
 
        drm = drm_dev_alloc(driver, &device->dev);
index cd7f1e499616891347485bcf6d3da86d6a05ab56..9336006b475d70b7494f1694d8661c07c2cd882a 100644 (file)
 #include "drm.h"
 #include "gem.h"
 
+struct tegra_dc_soc_info {
+       bool supports_interlacing;
+};
+
 struct tegra_plane {
        struct drm_plane base;
        unsigned int index;
@@ -658,19 +662,12 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
        /* program display mode */
        tegra_dc_set_timings(dc, mode);
 
-       value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
-       tegra_dc_writel(dc, value, DC_DISP_DATA_ENABLE_OPTIONS);
-
-       value = tegra_dc_readl(dc, DC_COM_PIN_OUTPUT_POLARITY(1));
-       value &= ~LVS_OUTPUT_POLARITY_LOW;
-       value &= ~LHS_OUTPUT_POLARITY_LOW;
-       tegra_dc_writel(dc, value, DC_COM_PIN_OUTPUT_POLARITY(1));
-
-       value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB |
-               DISP_ORDER_RED_BLUE;
-       tegra_dc_writel(dc, value, DC_DISP_DISP_INTERFACE_CONTROL);
-
-       tegra_dc_writel(dc, 0x00010001, DC_DISP_SHIFT_CLOCK_OPTIONS);
+       /* interlacing isn't supported yet, so disable it */
+       if (dc->soc->supports_interlacing) {
+               value = tegra_dc_readl(dc, DC_DISP_INTERLACE_CONTROL);
+               value &= ~INTERLACE_ENABLE;
+               tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL);
+       }
 
        value = SHIFT_CLK_DIVIDER(div) | PIXEL_CLK_DIVIDER_PCD1;
        tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
@@ -735,10 +732,6 @@ static void tegra_crtc_prepare(struct drm_crtc *crtc)
                PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
        tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
 
-       value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
-       value |= DISP_CTRL_MODE_C_DISPLAY;
-       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
        /* initialize timer */
        value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
                WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
@@ -1107,8 +1100,6 @@ static int tegra_dc_init(struct host1x_client *client)
        struct tegra_dc *dc = host1x_client_to_dc(client);
        int err;
 
-       dc->pipe = tegra->drm->mode_config.num_crtc;
-
        drm_crtc_init(tegra->drm, &dc->base, &tegra_crtc_funcs);
        drm_mode_crtc_set_gamma_size(&dc->base, 256);
        drm_crtc_helper_add(&dc->base, &tegra_crtc_helper_funcs);
@@ -1167,8 +1158,71 @@ static const struct host1x_client_ops dc_client_ops = {
        .exit = tegra_dc_exit,
 };
 
+static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
+       .supports_interlacing = false,
+};
+
+static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
+       .supports_interlacing = false,
+};
+
+static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
+       .supports_interlacing = true,
+};
+
+static const struct of_device_id tegra_dc_of_match[] = {
+       {
+               .compatible = "nvidia,tegra124-dc",
+               .data = &tegra124_dc_soc_info,
+       }, {
+               .compatible = "nvidia,tegra30-dc",
+               .data = &tegra30_dc_soc_info,
+       }, {
+               .compatible = "nvidia,tegra20-dc",
+               .data = &tegra20_dc_soc_info,
+       }, {
+               /* sentinel */
+       }
+};
+
+static int tegra_dc_parse_dt(struct tegra_dc *dc)
+{
+       struct device_node *np;
+       u32 value = 0;
+       int err;
+
+       err = of_property_read_u32(dc->dev->of_node, "nvidia,head", &value);
+       if (err < 0) {
+               dev_err(dc->dev, "missing \"nvidia,head\" property\n");
+
+               /*
+                * If the nvidia,head property isn't present, try to find the
+                * correct head number by looking up the position of this
+                * display controller's node within the device tree. Assuming
+                * that the nodes are ordered properly in the DTS file and
+                * that the translation into a flattened device tree blob
+                * preserves that ordering this will actually yield the right
+                * head number.
+                *
+                * If those assumptions don't hold, this will still work for
+                * cases where only a single display controller is used.
+                */
+               for_each_matching_node(np, tegra_dc_of_match) {
+                       if (np == dc->dev->of_node)
+                               break;
+
+                       value++;
+               }
+       }
+
+       dc->pipe = value;
+
+       return 0;
+}
+
 static int tegra_dc_probe(struct platform_device *pdev)
 {
+       const struct of_device_id *id;
        struct resource *regs;
        struct tegra_dc *dc;
        int err;
@@ -1177,9 +1231,18 @@ static int tegra_dc_probe(struct platform_device *pdev)
        if (!dc)
                return -ENOMEM;
 
+       id = of_match_node(tegra_dc_of_match, pdev->dev.of_node);
+       if (!id)
+               return -ENODEV;
+
        spin_lock_init(&dc->lock);
        INIT_LIST_HEAD(&dc->list);
        dc->dev = &pdev->dev;
+       dc->soc = id->data;
+
+       err = tegra_dc_parse_dt(dc);
+       if (err < 0)
+               return err;
 
        dc->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(dc->clk)) {
@@ -1253,12 +1316,6 @@ static int tegra_dc_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id tegra_dc_of_match[] = {
-       { .compatible = "nvidia,tegra30-dc", },
-       { .compatible = "nvidia,tegra20-dc", },
-       { },
-};
-
 struct platform_driver tegra_dc_driver = {
        .driver = {
                .name = "tegra-dc",
index 91bbda291470c29ce3ba80a70b0e5d541b8c6556..3c2c0ea1cd87a84e1f3414a780788d868f676703 100644 (file)
@@ -28,6 +28,7 @@
 #define DISP_CTRL_MODE_STOP (0 << 5)
 #define DISP_CTRL_MODE_C_DISPLAY (1 << 5)
 #define DISP_CTRL_MODE_NC_DISPLAY (2 << 5)
+#define DISP_CTRL_MODE_MASK (3 << 5)
 #define DC_CMD_SIGNAL_RAISE                    0x033
 #define DC_CMD_DISPLAY_POWER_CONTROL           0x036
 #define PW0_ENABLE (1 <<  0)
 
 #define DC_DISP_DISP_WIN_OPTIONS               0x402
 #define HDMI_ENABLE (1 << 30)
+#define DSI_ENABLE  (1 << 29)
 
 #define DC_DISP_DISP_MEM_HIGH_PRIORITY         0x403
 #define CURSOR_THRESHOLD(x)   (((x) & 0x03) << 24)
 #define DITHER_CONTROL_ERRDIFF (3 << 8)
 
 #define DC_DISP_SHIFT_CLOCK_OPTIONS            0x431
+#define  SC1_H_QUALIFIER_NONE  (1 << 16)
+#define  SC0_H_QUALIFIER_NONE  (1 <<  0)
 
 #define DC_DISP_DATA_ENABLE_OPTIONS            0x432
 #define DE_SELECT_ACTIVE_BLANK  (0 << 0)
 #define DC_DISP_SD_HW_K_VALUES                 0x4dd
 #define DC_DISP_SD_MAN_K_VALUES                        0x4de
 
+#define DC_DISP_INTERLACE_CONTROL              0x4e5
+#define  INTERLACE_STATUS (1 << 2)
+#define  INTERLACE_START  (1 << 1)
+#define  INTERLACE_ENABLE (1 << 0)
+
 #define DC_WIN_CSC_YOF                         0x611
 #define DC_WIN_CSC_KYRGB                       0x612
 #define DC_WIN_CSC_KUR                         0x613
index 07eba596d458d22b63bc9f0a731d6ca3befae036..88a529008ce0e59210e917422b2cfe07570a0d7d 100644 (file)
@@ -104,9 +104,11 @@ static void tegra_drm_context_free(struct tegra_drm_context *context)
 
 static void tegra_drm_lastclose(struct drm_device *drm)
 {
+#ifdef CONFIG_TEGRA_DRM_FBDEV
        struct tegra_drm *tegra = drm->dev_private;
 
        tegra_fbdev_restore_mode(tegra->fbdev);
+#endif
 }
 
 static struct host1x_bo *
@@ -578,7 +580,7 @@ static void tegra_debugfs_cleanup(struct drm_minor *minor)
 #endif
 
 static struct drm_driver tegra_drm_driver = {
-       .driver_features = DRIVER_MODESET | DRIVER_GEM,
+       .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_PRIME,
        .load = tegra_drm_load,
        .unload = tegra_drm_unload,
        .open = tegra_drm_open,
@@ -596,6 +598,12 @@ static struct drm_driver tegra_drm_driver = {
 
        .gem_free_object = tegra_bo_free_object,
        .gem_vm_ops = &tegra_bo_vm_ops,
+
+       .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
+       .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
+       .gem_prime_export = tegra_gem_prime_export,
+       .gem_prime_import = tegra_gem_prime_import,
+
        .dumb_create = tegra_bo_dumb_create,
        .dumb_map_offset = tegra_bo_dumb_map_offset,
        .dumb_destroy = drm_gem_dumb_destroy,
@@ -653,8 +661,10 @@ static const struct of_device_id host1x_drm_subdevs[] = {
        { .compatible = "nvidia,tegra30-hdmi", },
        { .compatible = "nvidia,tegra30-gr2d", },
        { .compatible = "nvidia,tegra30-gr3d", },
+       { .compatible = "nvidia,tegra114-dsi", },
        { .compatible = "nvidia,tegra114-hdmi", },
        { .compatible = "nvidia,tegra114-gr3d", },
+       { .compatible = "nvidia,tegra124-dc", },
        { /* sentinel */ }
 };
 
@@ -677,10 +687,14 @@ static int __init host1x_drm_init(void)
        if (err < 0)
                goto unregister_host1x;
 
-       err = platform_driver_register(&tegra_hdmi_driver);
+       err = platform_driver_register(&tegra_dsi_driver);
        if (err < 0)
                goto unregister_dc;
 
+       err = platform_driver_register(&tegra_hdmi_driver);
+       if (err < 0)
+               goto unregister_dsi;
+
        err = platform_driver_register(&tegra_gr2d_driver);
        if (err < 0)
                goto unregister_hdmi;
@@ -695,6 +709,8 @@ unregister_gr2d:
        platform_driver_unregister(&tegra_gr2d_driver);
 unregister_hdmi:
        platform_driver_unregister(&tegra_hdmi_driver);
+unregister_dsi:
+       platform_driver_unregister(&tegra_dsi_driver);
 unregister_dc:
        platform_driver_unregister(&tegra_dc_driver);
 unregister_host1x:
@@ -708,6 +724,7 @@ static void __exit host1x_drm_exit(void)
        platform_driver_unregister(&tegra_gr3d_driver);
        platform_driver_unregister(&tegra_gr2d_driver);
        platform_driver_unregister(&tegra_hdmi_driver);
+       platform_driver_unregister(&tegra_dsi_driver);
        platform_driver_unregister(&tegra_dc_driver);
        host1x_driver_unregister(&host1x_drm_driver);
 }
index 266aae08a3bd394fff2d9e41e902d2c9e899bba9..bf1cac7658f8d20333ce0cefbac8383e62f98c37 100644 (file)
@@ -27,10 +27,12 @@ struct tegra_fb {
        unsigned int num_planes;
 };
 
+#ifdef CONFIG_DRM_TEGRA_FBDEV
 struct tegra_fbdev {
        struct drm_fb_helper base;
        struct tegra_fb *fb;
 };
+#endif
 
 struct tegra_drm {
        struct drm_device *drm;
@@ -38,7 +40,9 @@ struct tegra_drm {
        struct mutex clients_lock;
        struct list_head clients;
 
+#ifdef CONFIG_DRM_TEGRA_FBDEV
        struct tegra_fbdev *fbdev;
+#endif
 };
 
 struct tegra_drm_client;
@@ -84,6 +88,7 @@ extern int tegra_drm_unregister_client(struct tegra_drm *tegra,
 extern int tegra_drm_init(struct tegra_drm *tegra, struct drm_device *drm);
 extern int tegra_drm_exit(struct tegra_drm *tegra);
 
+struct tegra_dc_soc_info;
 struct tegra_output;
 
 struct tegra_dc {
@@ -109,6 +114,8 @@ struct tegra_dc {
 
        /* page-flip handling */
        struct drm_pending_vblank_event *event;
+
+       const struct tegra_dc_soc_info *soc;
 };
 
 static inline struct tegra_dc *
@@ -177,6 +184,7 @@ struct tegra_output_ops {
 enum tegra_output_type {
        TEGRA_OUTPUT_RGB,
        TEGRA_OUTPUT_HDMI,
+       TEGRA_OUTPUT_DSI,
 };
 
 struct tegra_output {
@@ -186,6 +194,7 @@ struct tegra_output {
        const struct tegra_output_ops *ops;
        enum tegra_output_type type;
 
+       struct drm_panel *panel;
        struct i2c_adapter *ddc;
        const struct edid *edid;
        unsigned int hpd_irq;
@@ -263,9 +272,12 @@ bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer);
 bool tegra_fb_is_tiled(struct drm_framebuffer *framebuffer);
 extern int tegra_drm_fb_init(struct drm_device *drm);
 extern void tegra_drm_fb_exit(struct drm_device *drm);
+#ifdef CONFIG_DRM_TEGRA_FBDEV
 extern void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
+#endif
 
 extern struct platform_driver tegra_dc_driver;
+extern struct platform_driver tegra_dsi_driver;
 extern struct platform_driver tegra_hdmi_driver;
 extern struct platform_driver tegra_gr2d_driver;
 extern struct platform_driver tegra_gr3d_driver;
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
new file mode 100644 (file)
index 0000000..d452faa
--- /dev/null
@@ -0,0 +1,971 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/host1x.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+
+#include <drm/drm_mipi_dsi.h>
+#include <drm/drm_panel.h>
+
+#include <video/mipi_display.h>
+
+#include "dc.h"
+#include "drm.h"
+#include "dsi.h"
+#include "mipi-phy.h"
+
+#define DSI_VIDEO_FIFO_DEPTH (1920 / 4)
+#define DSI_HOST_FIFO_DEPTH 64
+
+struct tegra_dsi {
+       struct host1x_client client;
+       struct tegra_output output;
+       struct device *dev;
+
+       void __iomem *regs;
+
+       struct reset_control *rst;
+       struct clk *clk_parent;
+       struct clk *clk_lp;
+       struct clk *clk;
+
+       struct drm_info_list *debugfs_files;
+       struct drm_minor *minor;
+       struct dentry *debugfs;
+
+       enum mipi_dsi_pixel_format format;
+       unsigned int lanes;
+
+       struct tegra_mipi_device *mipi;
+       struct mipi_dsi_host host;
+};
+
+static inline struct tegra_dsi *
+host1x_client_to_dsi(struct host1x_client *client)
+{
+       return container_of(client, struct tegra_dsi, client);
+}
+
+static inline struct tegra_dsi *host_to_tegra(struct mipi_dsi_host *host)
+{
+       return container_of(host, struct tegra_dsi, host);
+}
+
+static inline struct tegra_dsi *to_dsi(struct tegra_output *output)
+{
+       return container_of(output, struct tegra_dsi, output);
+}
+
+static inline unsigned long tegra_dsi_readl(struct tegra_dsi *dsi,
+                                           unsigned long reg)
+{
+       return readl(dsi->regs + (reg << 2));
+}
+
+static inline void tegra_dsi_writel(struct tegra_dsi *dsi, unsigned long value,
+                                   unsigned long reg)
+{
+       writel(value, dsi->regs + (reg << 2));
+}
+
+static int tegra_dsi_show_regs(struct seq_file *s, void *data)
+{
+       struct drm_info_node *node = s->private;
+       struct tegra_dsi *dsi = node->info_ent->data;
+
+#define DUMP_REG(name)                                         \
+       seq_printf(s, "%-32s %#05x %08lx\n", #name, name,       \
+                  tegra_dsi_readl(dsi, name))
+
+       DUMP_REG(DSI_INCR_SYNCPT);
+       DUMP_REG(DSI_INCR_SYNCPT_CONTROL);
+       DUMP_REG(DSI_INCR_SYNCPT_ERROR);
+       DUMP_REG(DSI_CTXSW);
+       DUMP_REG(DSI_RD_DATA);
+       DUMP_REG(DSI_WR_DATA);
+       DUMP_REG(DSI_POWER_CONTROL);
+       DUMP_REG(DSI_INT_ENABLE);
+       DUMP_REG(DSI_INT_STATUS);
+       DUMP_REG(DSI_INT_MASK);
+       DUMP_REG(DSI_HOST_CONTROL);
+       DUMP_REG(DSI_CONTROL);
+       DUMP_REG(DSI_SOL_DELAY);
+       DUMP_REG(DSI_MAX_THRESHOLD);
+       DUMP_REG(DSI_TRIGGER);
+       DUMP_REG(DSI_TX_CRC);
+       DUMP_REG(DSI_STATUS);
+
+       DUMP_REG(DSI_INIT_SEQ_CONTROL);
+       DUMP_REG(DSI_INIT_SEQ_DATA_0);
+       DUMP_REG(DSI_INIT_SEQ_DATA_1);
+       DUMP_REG(DSI_INIT_SEQ_DATA_2);
+       DUMP_REG(DSI_INIT_SEQ_DATA_3);
+       DUMP_REG(DSI_INIT_SEQ_DATA_4);
+       DUMP_REG(DSI_INIT_SEQ_DATA_5);
+       DUMP_REG(DSI_INIT_SEQ_DATA_6);
+       DUMP_REG(DSI_INIT_SEQ_DATA_7);
+
+       DUMP_REG(DSI_PKT_SEQ_0_LO);
+       DUMP_REG(DSI_PKT_SEQ_0_HI);
+       DUMP_REG(DSI_PKT_SEQ_1_LO);
+       DUMP_REG(DSI_PKT_SEQ_1_HI);
+       DUMP_REG(DSI_PKT_SEQ_2_LO);
+       DUMP_REG(DSI_PKT_SEQ_2_HI);
+       DUMP_REG(DSI_PKT_SEQ_3_LO);
+       DUMP_REG(DSI_PKT_SEQ_3_HI);
+       DUMP_REG(DSI_PKT_SEQ_4_LO);
+       DUMP_REG(DSI_PKT_SEQ_4_HI);
+       DUMP_REG(DSI_PKT_SEQ_5_LO);
+       DUMP_REG(DSI_PKT_SEQ_5_HI);
+
+       DUMP_REG(DSI_DCS_CMDS);
+
+       DUMP_REG(DSI_PKT_LEN_0_1);
+       DUMP_REG(DSI_PKT_LEN_2_3);
+       DUMP_REG(DSI_PKT_LEN_4_5);
+       DUMP_REG(DSI_PKT_LEN_6_7);
+
+       DUMP_REG(DSI_PHY_TIMING_0);
+       DUMP_REG(DSI_PHY_TIMING_1);
+       DUMP_REG(DSI_PHY_TIMING_2);
+       DUMP_REG(DSI_BTA_TIMING);
+
+       DUMP_REG(DSI_TIMEOUT_0);
+       DUMP_REG(DSI_TIMEOUT_1);
+       DUMP_REG(DSI_TO_TALLY);
+
+       DUMP_REG(DSI_PAD_CONTROL_0);
+       DUMP_REG(DSI_PAD_CONTROL_CD);
+       DUMP_REG(DSI_PAD_CD_STATUS);
+       DUMP_REG(DSI_VIDEO_MODE_CONTROL);
+       DUMP_REG(DSI_PAD_CONTROL_1);
+       DUMP_REG(DSI_PAD_CONTROL_2);
+       DUMP_REG(DSI_PAD_CONTROL_3);
+       DUMP_REG(DSI_PAD_CONTROL_4);
+
+       DUMP_REG(DSI_GANGED_MODE_CONTROL);
+       DUMP_REG(DSI_GANGED_MODE_START);
+       DUMP_REG(DSI_GANGED_MODE_SIZE);
+
+       DUMP_REG(DSI_RAW_DATA_BYTE_COUNT);
+       DUMP_REG(DSI_ULTRA_LOW_POWER_CONTROL);
+
+       DUMP_REG(DSI_INIT_SEQ_DATA_8);
+       DUMP_REG(DSI_INIT_SEQ_DATA_9);
+       DUMP_REG(DSI_INIT_SEQ_DATA_10);
+       DUMP_REG(DSI_INIT_SEQ_DATA_11);
+       DUMP_REG(DSI_INIT_SEQ_DATA_12);
+       DUMP_REG(DSI_INIT_SEQ_DATA_13);
+       DUMP_REG(DSI_INIT_SEQ_DATA_14);
+       DUMP_REG(DSI_INIT_SEQ_DATA_15);
+
+#undef DUMP_REG
+
+       return 0;
+}
+
+static struct drm_info_list debugfs_files[] = {
+       { "regs", tegra_dsi_show_regs, 0, NULL },
+};
+
+static int tegra_dsi_debugfs_init(struct tegra_dsi *dsi,
+                                 struct drm_minor *minor)
+{
+       const char *name = dev_name(dsi->dev);
+       unsigned int i;
+       int err;
+
+       dsi->debugfs = debugfs_create_dir(name, minor->debugfs_root);
+       if (!dsi->debugfs)
+               return -ENOMEM;
+
+       dsi->debugfs_files = kmemdup(debugfs_files, sizeof(debugfs_files),
+                                    GFP_KERNEL);
+       if (!dsi->debugfs_files) {
+               err = -ENOMEM;
+               goto remove;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(debugfs_files); i++)
+               dsi->debugfs_files[i].data = dsi;
+
+       err = drm_debugfs_create_files(dsi->debugfs_files,
+                                      ARRAY_SIZE(debugfs_files),
+                                      dsi->debugfs, minor);
+       if (err < 0)
+               goto free;
+
+       dsi->minor = minor;
+
+       return 0;
+
+free:
+       kfree(dsi->debugfs_files);
+       dsi->debugfs_files = NULL;
+remove:
+       debugfs_remove(dsi->debugfs);
+       dsi->debugfs = NULL;
+
+       return err;
+}
+
+static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
+{
+       drm_debugfs_remove_files(dsi->debugfs_files, ARRAY_SIZE(debugfs_files),
+                                dsi->minor);
+       dsi->minor = NULL;
+
+       kfree(dsi->debugfs_files);
+       dsi->debugfs_files = NULL;
+
+       debugfs_remove(dsi->debugfs);
+       dsi->debugfs = NULL;
+
+       return 0;
+}
+
+#define PKT_ID0(id)    ((((id) & 0x3f) <<  3) | (1 <<  9))
+#define PKT_LEN0(len)  (((len) & 0x07) <<  0)
+#define PKT_ID1(id)    ((((id) & 0x3f) << 13) | (1 << 19))
+#define PKT_LEN1(len)  (((len) & 0x07) << 10)
+#define PKT_ID2(id)    ((((id) & 0x3f) << 23) | (1 << 29))
+#define PKT_LEN2(len)  (((len) & 0x07) << 20)
+
+#define PKT_LP         (1 << 30)
+#define NUM_PKT_SEQ    12
+
+/* non-burst mode with sync-end */
+static const u32 pkt_seq_vnb_syne[NUM_PKT_SEQ] = {
+       [ 0] = PKT_ID0(MIPI_DSI_V_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+              PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+              PKT_LP,
+       [ 1] = 0,
+       [ 2] = PKT_ID0(MIPI_DSI_V_SYNC_END) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+              PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+              PKT_LP,
+       [ 3] = 0,
+       [ 4] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+              PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+              PKT_LP,
+       [ 5] = 0,
+       [ 6] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+              PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
+       [ 7] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
+              PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
+              PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
+       [ 8] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+              PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0) |
+              PKT_LP,
+       [ 9] = 0,
+       [10] = PKT_ID0(MIPI_DSI_H_SYNC_START) | PKT_LEN0(0) |
+              PKT_ID1(MIPI_DSI_BLANKING_PACKET) | PKT_LEN1(1) |
+              PKT_ID2(MIPI_DSI_H_SYNC_END) | PKT_LEN2(0),
+       [11] = PKT_ID0(MIPI_DSI_BLANKING_PACKET) | PKT_LEN0(2) |
+              PKT_ID1(MIPI_DSI_PACKED_PIXEL_STREAM_24) | PKT_LEN1(3) |
+              PKT_ID2(MIPI_DSI_BLANKING_PACKET) | PKT_LEN2(4),
+};
+
+static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
+{
+       struct mipi_dphy_timing timing;
+       unsigned long value, period;
+       long rate;
+       int err;
+
+       rate = clk_get_rate(dsi->clk);
+       if (rate < 0)
+               return rate;
+
+       period = DIV_ROUND_CLOSEST(1000000000UL, rate * 2);
+
+       err = mipi_dphy_timing_get_default(&timing, period);
+       if (err < 0)
+               return err;
+
+       err = mipi_dphy_timing_validate(&timing, period);
+       if (err < 0) {
+               dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
+               return err;
+       }
+
+       /*
+        * The D-PHY timing fields below are expressed in byte-clock cycles,
+        * so multiply the period by 8.
+        */
+       period *= 8;
+
+       value = DSI_TIMING_FIELD(timing.hsexit, period, 1) << 24 |
+               DSI_TIMING_FIELD(timing.hstrail, period, 0) << 16 |
+               DSI_TIMING_FIELD(timing.hszero, period, 3) << 8 |
+               DSI_TIMING_FIELD(timing.hsprepare, period, 1);
+       tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
+
+       value = DSI_TIMING_FIELD(timing.clktrail, period, 1) << 24 |
+               DSI_TIMING_FIELD(timing.clkpost, period, 1) << 16 |
+               DSI_TIMING_FIELD(timing.clkzero, period, 1) << 8 |
+               DSI_TIMING_FIELD(timing.lpx, period, 1);
+       tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
+
+       value = DSI_TIMING_FIELD(timing.clkprepare, period, 1) << 16 |
+               DSI_TIMING_FIELD(timing.clkpre, period, 1) << 8 |
+               DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
+       tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
+
+       value = DSI_TIMING_FIELD(timing.taget, period, 1) << 16 |
+               DSI_TIMING_FIELD(timing.tasure, period, 1) << 8 |
+               DSI_TIMING_FIELD(timing.tago, period, 1);
+       tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
+
+       return 0;
+}
+
+static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
+                               unsigned int *mulp, unsigned int *divp)
+{
+       switch (format) {
+       case MIPI_DSI_FMT_RGB666_PACKED:
+       case MIPI_DSI_FMT_RGB888:
+               *mulp = 3;
+               *divp = 1;
+               break;
+
+       case MIPI_DSI_FMT_RGB565:
+               *mulp = 2;
+               *divp = 1;
+               break;
+
+       case MIPI_DSI_FMT_RGB666:
+               *mulp = 9;
+               *divp = 4;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int tegra_output_dsi_enable(struct tegra_output *output)
+{
+       struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
+       struct drm_display_mode *mode = &dc->base.mode;
+       unsigned int hact, hsw, hbp, hfp, i, mul, div;
+       struct tegra_dsi *dsi = to_dsi(output);
+       /* FIXME: don't hardcode this */
+       const u32 *pkt_seq = pkt_seq_vnb_syne;
+       unsigned long value;
+       int err;
+
+       err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
+       if (err < 0)
+               return err;
+
+       err = clk_enable(dsi->clk);
+       if (err < 0)
+               return err;
+
+       reset_control_deassert(dsi->rst);
+
+       value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(dsi->format) |
+               DSI_CONTROL_LANES(dsi->lanes - 1) |
+               DSI_CONTROL_SOURCE(dc->pipe);
+       tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+       tegra_dsi_writel(dsi, DSI_VIDEO_FIFO_DEPTH, DSI_MAX_THRESHOLD);
+
+       value = DSI_HOST_CONTROL_HS | DSI_HOST_CONTROL_CS |
+               DSI_HOST_CONTROL_ECC;
+       tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+
+       value = tegra_dsi_readl(dsi, DSI_CONTROL);
+       value |= DSI_CONTROL_HS_CLK_CTRL;
+       value &= ~DSI_CONTROL_TX_TRIG(3);
+       value &= ~DSI_CONTROL_DCS_ENABLE;
+       value |= DSI_CONTROL_VIDEO_ENABLE;
+       value &= ~DSI_CONTROL_HOST_ENABLE;
+       tegra_dsi_writel(dsi, value, DSI_CONTROL);
+
+       err = tegra_dsi_set_phy_timing(dsi);
+       if (err < 0)
+               return err;
+
+       for (i = 0; i < NUM_PKT_SEQ; i++)
+               tegra_dsi_writel(dsi, pkt_seq[i], DSI_PKT_SEQ_0_LO + i);
+
+       /* horizontal active pixels */
+       hact = mode->hdisplay * mul / div;
+
+       /* horizontal sync width */
+       hsw = (mode->hsync_end - mode->hsync_start) * mul / div;
+       hsw -= 10;
+
+       /* horizontal back porch */
+       hbp = (mode->htotal - mode->hsync_end) * mul / div;
+       hbp -= 14;
+
+       /* horizontal front porch */
+       hfp = (mode->hsync_start  - mode->hdisplay) * mul / div;
+       hfp -= 8;
+
+       tegra_dsi_writel(dsi, hsw << 16 | 0, DSI_PKT_LEN_0_1);
+       tegra_dsi_writel(dsi, hact << 16 | hbp, DSI_PKT_LEN_2_3);
+       tegra_dsi_writel(dsi, hfp, DSI_PKT_LEN_4_5);
+       tegra_dsi_writel(dsi, 0x0f0f << 16, DSI_PKT_LEN_6_7);
+
+       /* set SOL delay */
+       tegra_dsi_writel(dsi, 8 * mul / div, DSI_SOL_DELAY);
+
+       /* enable display controller */
+       value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+       value |= DSI_ENABLE;
+       tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+       value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+       value &= ~DISP_CTRL_MODE_MASK;
+       value |= DISP_CTRL_MODE_C_DISPLAY;
+       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+       value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+       value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+                PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
+       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+
+       tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+
+       /* enable DSI controller */
+       value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+       value |= DSI_POWER_CONTROL_ENABLE;
+       tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+       return 0;
+}
+
+static int tegra_output_dsi_disable(struct tegra_output *output)
+{
+       struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
+       struct tegra_dsi *dsi = to_dsi(output);
+       unsigned long value;
+
+       /* disable DSI controller */
+       value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+       value &= DSI_POWER_CONTROL_ENABLE;
+       tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+       /*
+        * The following accesses registers of the display controller, so make
+        * sure it's only executed when the output is attached to one.
+        */
+       if (dc) {
+               value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+               value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+                          PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
+               tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+
+               value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+               value &= ~DISP_CTRL_MODE_MASK;
+               tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+               value &= ~DSI_ENABLE;
+               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+               tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+               tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+       }
+
+       clk_disable(dsi->clk);
+
+       return 0;
+}
+
+static int tegra_output_dsi_setup_clock(struct tegra_output *output,
+                                       struct clk *clk, unsigned long pclk)
+{
+       struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
+       struct drm_display_mode *mode = &dc->base.mode;
+       unsigned int timeout, mul, div, vrefresh;
+       struct tegra_dsi *dsi = to_dsi(output);
+       unsigned long bclk, plld, value;
+       struct clk *base;
+       int err;
+
+       err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
+       if (err < 0)
+               return err;
+
+       vrefresh = drm_mode_vrefresh(mode);
+
+       pclk = mode->htotal * mode->vtotal * vrefresh;
+       bclk = (pclk * mul) / (div * dsi->lanes);
+       plld = DIV_ROUND_UP(bclk * 8, 1000000);
+       pclk = (plld * 1000000) / 2;
+
+       err = clk_set_parent(clk, dsi->clk_parent);
+       if (err < 0) {
+               dev_err(dsi->dev, "failed to set parent clock: %d\n", err);
+               return err;
+       }
+
+       base = clk_get_parent(dsi->clk_parent);
+
+       /*
+        * This assumes that the parent clock is pll_d_out0 or pll_d2_out
+        * respectively, each of which divides the base pll_d by 2.
+        */
+       err = clk_set_rate(base, pclk * 2);
+       if (err < 0) {
+               dev_err(dsi->dev, "failed to set base clock rate to %lu Hz\n",
+                       pclk * 2);
+               return err;
+       }
+
+       /*
+        * XXX: Move the below somewhere else so that we don't need to have
+        * access to the vrefresh in this function?
+        */
+
+       /* one frame high-speed transmission timeout */
+       timeout = (bclk / vrefresh) / 512;
+       value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
+       tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
+
+       /* 2 ms peripheral timeout for panel */
+       timeout = 2 * bclk / 512 * 1000;
+       value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
+       tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
+
+       value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
+       tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
+
+       return 0;
+}
+
+static int tegra_output_dsi_check_mode(struct tegra_output *output,
+                                      struct drm_display_mode *mode,
+                                      enum drm_mode_status *status)
+{
+       /*
+        * FIXME: For now, always assume that the mode is okay.
+        */
+
+       *status = MODE_OK;
+
+       return 0;
+}
+
+static const struct tegra_output_ops dsi_ops = {
+       .enable = tegra_output_dsi_enable,
+       .disable = tegra_output_dsi_disable,
+       .setup_clock = tegra_output_dsi_setup_clock,
+       .check_mode = tegra_output_dsi_check_mode,
+};
+
+static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
+{
+       unsigned long value;
+
+       value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
+       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
+
+       return 0;
+}
+
+static int tegra_dsi_pad_calibrate(struct tegra_dsi *dsi)
+{
+       unsigned long value;
+
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
+
+       /* start calibration */
+       tegra_dsi_pad_enable(dsi);
+
+       value = DSI_PAD_SLEW_UP(0x7) | DSI_PAD_SLEW_DN(0x7) |
+               DSI_PAD_LP_UP(0x1) | DSI_PAD_LP_DN(0x1) |
+               DSI_PAD_OUT_CLK(0x0);
+       tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_2);
+
+       return tegra_mipi_calibrate(dsi->mipi);
+}
+
+static int tegra_dsi_init(struct host1x_client *client)
+{
+       struct tegra_drm *tegra = dev_get_drvdata(client->parent);
+       struct tegra_dsi *dsi = host1x_client_to_dsi(client);
+       unsigned long value, i;
+       int err;
+
+       dsi->output.type = TEGRA_OUTPUT_DSI;
+       dsi->output.dev = client->dev;
+       dsi->output.ops = &dsi_ops;
+
+       err = tegra_output_init(tegra->drm, &dsi->output);
+       if (err < 0) {
+               dev_err(client->dev, "output setup failed: %d\n", err);
+               return err;
+       }
+
+       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+               err = tegra_dsi_debugfs_init(dsi, tegra->drm->primary);
+               if (err < 0)
+                       dev_err(dsi->dev, "debugfs setup failed: %d\n", err);
+       }
+
+       /*
+        * enable high-speed mode, checksum generation, ECC generation and
+        * disable raw mode
+        */
+       value = tegra_dsi_readl(dsi, DSI_HOST_CONTROL);
+       value |= DSI_HOST_CONTROL_ECC | DSI_HOST_CONTROL_CS |
+                DSI_HOST_CONTROL_HS;
+       value &= ~DSI_HOST_CONTROL_RAW;
+       tegra_dsi_writel(dsi, value, DSI_HOST_CONTROL);
+
+       tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY);
+       tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD);
+
+       tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL);
+
+       for (i = 0; i < 8; i++) {
+               tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i);
+               tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i);
+       }
+
+       for (i = 0; i < 12; i++)
+               tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i);
+
+       tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS);
+
+       err = tegra_dsi_pad_calibrate(dsi);
+       if (err < 0) {
+               dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
+               return err;
+       }
+
+       tegra_dsi_writel(dsi, DSI_POWER_CONTROL_ENABLE, DSI_POWER_CONTROL);
+       usleep_range(300, 1000);
+
+       return 0;
+}
+
+static int tegra_dsi_exit(struct host1x_client *client)
+{
+       struct tegra_dsi *dsi = host1x_client_to_dsi(client);
+       int err;
+
+       if (IS_ENABLED(CONFIG_DEBUG_FS)) {
+               err = tegra_dsi_debugfs_exit(dsi);
+               if (err < 0)
+                       dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err);
+       }
+
+       err = tegra_output_disable(&dsi->output);
+       if (err < 0) {
+               dev_err(client->dev, "output failed to disable: %d\n", err);
+               return err;
+       }
+
+       err = tegra_output_exit(&dsi->output);
+       if (err < 0) {
+               dev_err(client->dev, "output cleanup failed: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static const struct host1x_client_ops dsi_client_ops = {
+       .init = tegra_dsi_init,
+       .exit = tegra_dsi_exit,
+};
+
+static int tegra_dsi_setup_clocks(struct tegra_dsi *dsi)
+{
+       struct clk *parent;
+       int err;
+
+       parent = clk_get_parent(dsi->clk);
+       if (!parent)
+               return -EINVAL;
+
+       err = clk_set_parent(parent, dsi->clk_parent);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static void tegra_dsi_initialize(struct tegra_dsi *dsi)
+{
+       unsigned int i;
+
+       tegra_dsi_writel(dsi, 0, DSI_POWER_CONTROL);
+
+       tegra_dsi_writel(dsi, 0, DSI_INT_ENABLE);
+       tegra_dsi_writel(dsi, 0, DSI_INT_STATUS);
+       tegra_dsi_writel(dsi, 0, DSI_INT_MASK);
+
+       tegra_dsi_writel(dsi, 0, DSI_HOST_CONTROL);
+       tegra_dsi_writel(dsi, 0, DSI_CONTROL);
+
+       tegra_dsi_writel(dsi, 0, DSI_SOL_DELAY);
+       tegra_dsi_writel(dsi, 0, DSI_MAX_THRESHOLD);
+
+       tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_CONTROL);
+
+       for (i = 0; i < 8; i++) {
+               tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_0 + i);
+               tegra_dsi_writel(dsi, 0, DSI_INIT_SEQ_DATA_8 + i);
+       }
+
+       for (i = 0; i < 12; i++)
+               tegra_dsi_writel(dsi, 0, DSI_PKT_SEQ_0_LO + i);
+
+       tegra_dsi_writel(dsi, 0, DSI_DCS_CMDS);
+
+       for (i = 0; i < 4; i++)
+               tegra_dsi_writel(dsi, 0, DSI_PKT_LEN_0_1 + i);
+
+       tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_0);
+       tegra_dsi_writel(dsi, 0x00000000, DSI_PHY_TIMING_1);
+       tegra_dsi_writel(dsi, 0x000000ff, DSI_PHY_TIMING_2);
+       tegra_dsi_writel(dsi, 0x00000000, DSI_BTA_TIMING);
+
+       tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_0);
+       tegra_dsi_writel(dsi, 0, DSI_TIMEOUT_1);
+       tegra_dsi_writel(dsi, 0, DSI_TO_TALLY);
+
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_0);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_CD);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CD_STATUS);
+       tegra_dsi_writel(dsi, 0, DSI_VIDEO_MODE_CONTROL);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_1);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_2);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_3);
+       tegra_dsi_writel(dsi, 0, DSI_PAD_CONTROL_4);
+
+       tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
+       tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_START);
+       tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_SIZE);
+}
+
+static int tegra_dsi_host_attach(struct mipi_dsi_host *host,
+                                struct mipi_dsi_device *device)
+{
+       struct tegra_dsi *dsi = host_to_tegra(host);
+       struct tegra_output *output = &dsi->output;
+
+       dsi->format = device->format;
+       dsi->lanes = device->lanes;
+
+       output->panel = of_drm_find_panel(device->dev.of_node);
+       if (output->panel) {
+               if (output->connector.dev)
+                       drm_helper_hpd_irq_event(output->connector.dev);
+       }
+
+       return 0;
+}
+
+static int tegra_dsi_host_detach(struct mipi_dsi_host *host,
+                                struct mipi_dsi_device *device)
+{
+       struct tegra_dsi *dsi = host_to_tegra(host);
+       struct tegra_output *output = &dsi->output;
+
+       if (output->panel && &device->dev == output->panel->dev) {
+               if (output->connector.dev)
+                       drm_helper_hpd_irq_event(output->connector.dev);
+
+               output->panel = NULL;
+       }
+
+       return 0;
+}
+
+static const struct mipi_dsi_host_ops tegra_dsi_host_ops = {
+       .attach = tegra_dsi_host_attach,
+       .detach = tegra_dsi_host_detach,
+};
+
+static int tegra_dsi_probe(struct platform_device *pdev)
+{
+       struct tegra_dsi *dsi;
+       struct resource *regs;
+       int err;
+
+       dsi = devm_kzalloc(&pdev->dev, sizeof(*dsi), GFP_KERNEL);
+       if (!dsi)
+               return -ENOMEM;
+
+       dsi->output.dev = dsi->dev = &pdev->dev;
+
+       err = tegra_output_probe(&dsi->output);
+       if (err < 0)
+               return err;
+
+       /*
+        * Assume these values by default. When a DSI peripheral driver
+        * attaches to the DSI host, the parameters will be taken from
+        * the attached device.
+        */
+       dsi->format = MIPI_DSI_FMT_RGB888;
+       dsi->lanes = 4;
+
+       dsi->rst = devm_reset_control_get(&pdev->dev, "dsi");
+       if (IS_ERR(dsi->rst))
+               return PTR_ERR(dsi->rst);
+
+       dsi->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(dsi->clk)) {
+               dev_err(&pdev->dev, "cannot get DSI clock\n");
+               return PTR_ERR(dsi->clk);
+       }
+
+       err = clk_prepare_enable(dsi->clk);
+       if (err < 0) {
+               dev_err(&pdev->dev, "cannot enable DSI clock\n");
+               return err;
+       }
+
+       dsi->clk_lp = devm_clk_get(&pdev->dev, "lp");
+       if (IS_ERR(dsi->clk_lp)) {
+               dev_err(&pdev->dev, "cannot get low-power clock\n");
+               return PTR_ERR(dsi->clk_lp);
+       }
+
+       err = clk_prepare_enable(dsi->clk_lp);
+       if (err < 0) {
+               dev_err(&pdev->dev, "cannot enable low-power clock\n");
+               return err;
+       }
+
+       dsi->clk_parent = devm_clk_get(&pdev->dev, "parent");
+       if (IS_ERR(dsi->clk_parent)) {
+               dev_err(&pdev->dev, "cannot get parent clock\n");
+               return PTR_ERR(dsi->clk_parent);
+       }
+
+       err = clk_prepare_enable(dsi->clk_parent);
+       if (err < 0) {
+               dev_err(&pdev->dev, "cannot enable parent clock\n");
+               return err;
+       }
+
+       err = tegra_dsi_setup_clocks(dsi);
+       if (err < 0) {
+               dev_err(&pdev->dev, "cannot setup clocks\n");
+               return err;
+       }
+
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       dsi->regs = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(dsi->regs))
+               return PTR_ERR(dsi->regs);
+
+       tegra_dsi_initialize(dsi);
+
+       dsi->mipi = tegra_mipi_request(&pdev->dev);
+       if (IS_ERR(dsi->mipi))
+               return PTR_ERR(dsi->mipi);
+
+       dsi->host.ops = &tegra_dsi_host_ops;
+       dsi->host.dev = &pdev->dev;
+
+       err = mipi_dsi_host_register(&dsi->host);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to register DSI host: %d\n", err);
+               return err;
+       }
+
+       INIT_LIST_HEAD(&dsi->client.list);
+       dsi->client.ops = &dsi_client_ops;
+       dsi->client.dev = &pdev->dev;
+
+       err = host1x_client_register(&dsi->client);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to register host1x client: %d\n",
+                       err);
+               return err;
+       }
+
+       platform_set_drvdata(pdev, dsi);
+
+       return 0;
+}
+
+static int tegra_dsi_remove(struct platform_device *pdev)
+{
+       struct tegra_dsi *dsi = platform_get_drvdata(pdev);
+       int err;
+
+       err = host1x_client_unregister(&dsi->client);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to unregister host1x client: %d\n",
+                       err);
+               return err;
+       }
+
+       mipi_dsi_host_unregister(&dsi->host);
+       tegra_mipi_free(dsi->mipi);
+
+       clk_disable_unprepare(dsi->clk_parent);
+       clk_disable_unprepare(dsi->clk_lp);
+       clk_disable_unprepare(dsi->clk);
+
+       err = tegra_output_remove(&dsi->output);
+       if (err < 0) {
+               dev_err(&pdev->dev, "failed to remove output: %d\n", err);
+               return err;
+       }
+
+       return 0;
+}
+
+static const struct of_device_id tegra_dsi_of_match[] = {
+       { .compatible = "nvidia,tegra114-dsi", },
+       { },
+};
+
+struct platform_driver tegra_dsi_driver = {
+       .driver = {
+               .name = "tegra-dsi",
+               .of_match_table = tegra_dsi_of_match,
+       },
+       .probe = tegra_dsi_probe,
+       .remove = tegra_dsi_remove,
+};
diff --git a/drivers/gpu/drm/tegra/dsi.h b/drivers/gpu/drm/tegra/dsi.h
new file mode 100644 (file)
index 0000000..00e79c1
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef DRM_TEGRA_DSI_H
+#define DRM_TEGRA_DSI_H
+
+#define DSI_INCR_SYNCPT                        0x00
+#define DSI_INCR_SYNCPT_CONTROL                0x01
+#define DSI_INCR_SYNCPT_ERROR          0x02
+#define DSI_CTXSW                      0x08
+#define DSI_RD_DATA                    0x09
+#define DSI_WR_DATA                    0x0a
+#define DSI_POWER_CONTROL              0x0b
+#define DSI_POWER_CONTROL_ENABLE       (1 << 0)
+#define DSI_INT_ENABLE                 0x0c
+#define DSI_INT_STATUS                 0x0d
+#define DSI_INT_MASK                   0x0e
+#define DSI_HOST_CONTROL               0x0f
+#define DSI_HOST_CONTROL_RAW           (1 << 6)
+#define DSI_HOST_CONTROL_HS            (1 << 5)
+#define DSI_HOST_CONTROL_BTA           (1 << 2)
+#define DSI_HOST_CONTROL_CS            (1 << 1)
+#define DSI_HOST_CONTROL_ECC           (1 << 0)
+#define DSI_CONTROL                    0x10
+#define DSI_CONTROL_HS_CLK_CTRL                (1 << 20)
+#define DSI_CONTROL_CHANNEL(c)         (((c) & 0x3) << 16)
+#define DSI_CONTROL_FORMAT(f)          (((f) & 0x3) << 12)
+#define DSI_CONTROL_TX_TRIG(x)         (((x) & 0x3) <<  8)
+#define DSI_CONTROL_LANES(n)           (((n) & 0x3) <<  4)
+#define DSI_CONTROL_DCS_ENABLE         (1 << 3)
+#define DSI_CONTROL_SOURCE(s)          (((s) & 0x1) <<  2)
+#define DSI_CONTROL_VIDEO_ENABLE       (1 << 1)
+#define DSI_CONTROL_HOST_ENABLE                (1 << 0)
+#define DSI_SOL_DELAY                  0x11
+#define DSI_MAX_THRESHOLD              0x12
+#define DSI_TRIGGER                    0x13
+#define DSI_TX_CRC                     0x14
+#define DSI_STATUS                     0x15
+#define DSI_STATUS_IDLE                        (1 << 10)
+#define DSI_INIT_SEQ_CONTROL           0x1a
+#define DSI_INIT_SEQ_DATA_0            0x1b
+#define DSI_INIT_SEQ_DATA_1            0x1c
+#define DSI_INIT_SEQ_DATA_2            0x1d
+#define DSI_INIT_SEQ_DATA_3            0x1e
+#define DSI_INIT_SEQ_DATA_4            0x1f
+#define DSI_INIT_SEQ_DATA_5            0x20
+#define DSI_INIT_SEQ_DATA_6            0x21
+#define DSI_INIT_SEQ_DATA_7            0x22
+#define DSI_PKT_SEQ_0_LO               0x23
+#define DSI_PKT_SEQ_0_HI               0x24
+#define DSI_PKT_SEQ_1_LO               0x25
+#define DSI_PKT_SEQ_1_HI               0x26
+#define DSI_PKT_SEQ_2_LO               0x27
+#define DSI_PKT_SEQ_2_HI               0x28
+#define DSI_PKT_SEQ_3_LO               0x29
+#define DSI_PKT_SEQ_3_HI               0x2a
+#define DSI_PKT_SEQ_4_LO               0x2b
+#define DSI_PKT_SEQ_4_HI               0x2c
+#define DSI_PKT_SEQ_5_LO               0x2d
+#define DSI_PKT_SEQ_5_HI               0x2e
+#define DSI_DCS_CMDS                   0x33
+#define DSI_PKT_LEN_0_1                        0x34
+#define DSI_PKT_LEN_2_3                        0x35
+#define DSI_PKT_LEN_4_5                        0x36
+#define DSI_PKT_LEN_6_7                        0x37
+#define DSI_PHY_TIMING_0               0x3c
+#define DSI_PHY_TIMING_1               0x3d
+#define DSI_PHY_TIMING_2               0x3e
+#define DSI_BTA_TIMING                 0x3f
+
+#define DSI_TIMING_FIELD(value, period, hwinc) \
+       ((DIV_ROUND_CLOSEST(value, period) - (hwinc)) & 0xff)
+
+#define DSI_TIMEOUT_0                  0x44
+#define DSI_TIMEOUT_LRX(x)             (((x) & 0xffff) << 16)
+#define DSI_TIMEOUT_HTX(x)             (((x) & 0xffff) <<  0)
+#define DSI_TIMEOUT_1                  0x45
+#define DSI_TIMEOUT_PR(x)              (((x) & 0xffff) << 16)
+#define DSI_TIMEOUT_TA(x)              (((x) & 0xffff) <<  0)
+#define DSI_TO_TALLY                   0x46
+#define DSI_TALLY_TA(x)                        (((x) & 0xff) << 16)
+#define DSI_TALLY_LRX(x)               (((x) & 0xff) <<  8)
+#define DSI_TALLY_HTX(x)               (((x) & 0xff) <<  0)
+#define DSI_PAD_CONTROL_0              0x4b
+#define DSI_PAD_CONTROL_VS1_PDIO(x)    (((x) & 0xf) <<  0)
+#define DSI_PAD_CONTROL_VS1_PDIO_CLK   (1 <<  8)
+#define DSI_PAD_CONTROL_VS1_PULLDN(x)  (((x) & 0xf) << 16)
+#define DSI_PAD_CONTROL_VS1_PULLDN_CLK (1 << 24)
+#define DSI_PAD_CONTROL_CD             0x4c
+#define DSI_PAD_CD_STATUS              0x4d
+#define DSI_VIDEO_MODE_CONTROL         0x4e
+#define DSI_PAD_CONTROL_1              0x4f
+#define DSI_PAD_CONTROL_2              0x50
+#define DSI_PAD_OUT_CLK(x)             (((x) & 0x7) <<  0)
+#define DSI_PAD_LP_DN(x)               (((x) & 0x7) <<  4)
+#define DSI_PAD_LP_UP(x)               (((x) & 0x7) <<  8)
+#define DSI_PAD_SLEW_DN(x)             (((x) & 0x7) << 12)
+#define DSI_PAD_SLEW_UP(x)             (((x) & 0x7) << 16)
+#define DSI_PAD_CONTROL_3              0x51
+#define DSI_PAD_CONTROL_4              0x52
+#define DSI_GANGED_MODE_CONTROL                0x53
+#define DSI_GANGED_MODE_START          0x54
+#define DSI_GANGED_MODE_SIZE           0x55
+#define DSI_RAW_DATA_BYTE_COUNT                0x56
+#define DSI_ULTRA_LOW_POWER_CONTROL    0x57
+#define DSI_INIT_SEQ_DATA_8            0x58
+#define DSI_INIT_SEQ_DATA_9            0x59
+#define DSI_INIT_SEQ_DATA_10           0x5a
+#define DSI_INIT_SEQ_DATA_11           0x5b
+#define DSI_INIT_SEQ_DATA_12           0x5c
+#define DSI_INIT_SEQ_DATA_13           0x5d
+#define DSI_INIT_SEQ_DATA_14           0x5e
+#define DSI_INIT_SEQ_DATA_15           0x5f
+
+#endif
index a3835e7de1842b84145e52c40ef15ed21e183323..f7fca09d49211c5afebdc797590c001a88e72d6d 100644 (file)
@@ -18,10 +18,12 @@ static inline struct tegra_fb *to_tegra_fb(struct drm_framebuffer *fb)
        return container_of(fb, struct tegra_fb, base);
 }
 
+#ifdef CONFIG_DRM_TEGRA_FBDEV
 static inline struct tegra_fbdev *to_tegra_fbdev(struct drm_fb_helper *helper)
 {
        return container_of(helper, struct tegra_fbdev, base);
 }
+#endif
 
 struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
                                    unsigned int index)
@@ -98,8 +100,10 @@ static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm,
                return ERR_PTR(-ENOMEM);
 
        fb->planes = kzalloc(num_planes * sizeof(*planes), GFP_KERNEL);
-       if (!fb->planes)
+       if (!fb->planes) {
+               kfree(fb);
                return ERR_PTR(-ENOMEM);
+       }
 
        fb->num_planes = num_planes;
 
@@ -172,6 +176,7 @@ unreference:
        return ERR_PTR(err);
 }
 
+#ifdef CONFIG_DRM_TEGRA_FBDEV
 static struct fb_ops tegra_fb_ops = {
        .owner = THIS_MODULE,
        .fb_fillrect = sys_fillrect,
@@ -339,6 +344,15 @@ static void tegra_fbdev_free(struct tegra_fbdev *fbdev)
        kfree(fbdev);
 }
 
+void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev)
+{
+       if (fbdev) {
+               drm_modeset_lock_all(fbdev->base.dev);
+               drm_fb_helper_restore_fbdev_mode(&fbdev->base);
+               drm_modeset_unlock_all(fbdev->base.dev);
+       }
+}
+
 static void tegra_fb_output_poll_changed(struct drm_device *drm)
 {
        struct tegra_drm *tegra = drm->dev_private;
@@ -346,16 +360,20 @@ static void tegra_fb_output_poll_changed(struct drm_device *drm)
        if (tegra->fbdev)
                drm_fb_helper_hotplug_event(&tegra->fbdev->base);
 }
+#endif
 
 static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
        .fb_create = tegra_fb_create,
+#ifdef CONFIG_DRM_TEGRA_FBDEV
        .output_poll_changed = tegra_fb_output_poll_changed,
+#endif
 };
 
 int tegra_drm_fb_init(struct drm_device *drm)
 {
+#ifdef CONFIG_DRM_TEGRA_FBDEV
        struct tegra_drm *tegra = drm->dev_private;
-       struct tegra_fbdev *fbdev;
+#endif
 
        drm->mode_config.min_width = 0;
        drm->mode_config.min_height = 0;
@@ -365,28 +383,21 @@ int tegra_drm_fb_init(struct drm_device *drm)
 
        drm->mode_config.funcs = &tegra_drm_mode_funcs;
 
-       fbdev = tegra_fbdev_create(drm, 32, drm->mode_config.num_crtc,
-                                  drm->mode_config.num_connector);
-       if (IS_ERR(fbdev))
-               return PTR_ERR(fbdev);
-
-       tegra->fbdev = fbdev;
+#ifdef CONFIG_DRM_TEGRA_FBDEV
+       tegra->fbdev = tegra_fbdev_create(drm, 32, drm->mode_config.num_crtc,
+                                         drm->mode_config.num_connector);
+       if (IS_ERR(tegra->fbdev))
+               return PTR_ERR(tegra->fbdev);
+#endif
 
        return 0;
 }
 
 void tegra_drm_fb_exit(struct drm_device *drm)
 {
+#ifdef CONFIG_DRM_TEGRA_FBDEV
        struct tegra_drm *tegra = drm->dev_private;
 
        tegra_fbdev_free(tegra->fbdev);
-}
-
-void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev)
-{
-       if (fbdev) {
-               drm_modeset_lock_all(fbdev->base.dev);
-               drm_fb_helper_restore_fbdev_mode(&fbdev->base);
-               drm_modeset_unlock_all(fbdev->base.dev);
-       }
+#endif
 }
index 28a9cbc07ab95f3a5873fc9aac0f008180bffca5..ef853e558036d55ce31c7cb4acfdf2479beefb80 100644 (file)
@@ -18,6 +18,7 @@
  * GNU General Public License for more details.
  */
 
+#include <linux/dma-buf.h>
 #include <drm/tegra_drm.h>
 
 #include "gem.h"
@@ -83,7 +84,7 @@ static struct host1x_bo *tegra_bo_get(struct host1x_bo *bo)
        return bo;
 }
 
-const struct host1x_bo_ops tegra_bo_ops = {
+static const struct host1x_bo_ops tegra_bo_ops = {
        .get = tegra_bo_get,
        .put = tegra_bo_put,
        .pin = tegra_bo_pin,
@@ -145,7 +146,6 @@ err_dma:
        kfree(bo);
 
        return ERR_PTR(err);
-
 }
 
 struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file,
@@ -174,13 +174,87 @@ err:
        return ERR_PTR(ret);
 }
 
+struct tegra_bo *tegra_bo_import(struct drm_device *drm, struct dma_buf *buf)
+{
+       struct dma_buf_attachment *attach;
+       struct tegra_bo *bo;
+       ssize_t size;
+       int err;
+
+       bo = kzalloc(sizeof(*bo), GFP_KERNEL);
+       if (!bo)
+               return ERR_PTR(-ENOMEM);
+
+       host1x_bo_init(&bo->base, &tegra_bo_ops);
+       size = round_up(buf->size, PAGE_SIZE);
+
+       err = drm_gem_object_init(drm, &bo->gem, size);
+       if (err < 0)
+               goto free;
+
+       err = drm_gem_create_mmap_offset(&bo->gem);
+       if (err < 0)
+               goto release;
+
+       attach = dma_buf_attach(buf, drm->dev);
+       if (IS_ERR(attach)) {
+               err = PTR_ERR(attach);
+               goto free_mmap;
+       }
+
+       get_dma_buf(buf);
+
+       bo->sgt = dma_buf_map_attachment(attach, DMA_TO_DEVICE);
+       if (!bo->sgt) {
+               err = -ENOMEM;
+               goto detach;
+       }
+
+       if (IS_ERR(bo->sgt)) {
+               err = PTR_ERR(bo->sgt);
+               goto detach;
+       }
+
+       if (bo->sgt->nents > 1) {
+               err = -EINVAL;
+               goto detach;
+       }
+
+       bo->paddr = sg_dma_address(bo->sgt->sgl);
+       bo->gem.import_attach = attach;
+
+       return bo;
+
+detach:
+       if (!IS_ERR_OR_NULL(bo->sgt))
+               dma_buf_unmap_attachment(attach, bo->sgt, DMA_TO_DEVICE);
+
+       dma_buf_detach(buf, attach);
+       dma_buf_put(buf);
+free_mmap:
+       drm_gem_free_mmap_offset(&bo->gem);
+release:
+       drm_gem_object_release(&bo->gem);
+free:
+       kfree(bo);
+
+       return ERR_PTR(err);
+}
+
 void tegra_bo_free_object(struct drm_gem_object *gem)
 {
        struct tegra_bo *bo = to_tegra_bo(gem);
 
+       if (gem->import_attach) {
+               dma_buf_unmap_attachment(gem->import_attach, bo->sgt,
+                                        DMA_TO_DEVICE);
+               drm_prime_gem_destroy(gem, NULL);
+       } else {
+               tegra_bo_destroy(gem->dev, bo);
+       }
+
        drm_gem_free_mmap_offset(gem);
        drm_gem_object_release(gem);
-       tegra_bo_destroy(gem->dev, bo);
 
        kfree(bo);
 }
@@ -256,3 +330,106 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma)
 
        return ret;
 }
+
+static struct sg_table *
+tegra_gem_prime_map_dma_buf(struct dma_buf_attachment *attach,
+                           enum dma_data_direction dir)
+{
+       struct drm_gem_object *gem = attach->dmabuf->priv;
+       struct tegra_bo *bo = to_tegra_bo(gem);
+       struct sg_table *sgt;
+
+       sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+       if (!sgt)
+               return NULL;
+
+       if (sg_alloc_table(sgt, 1, GFP_KERNEL)) {
+               kfree(sgt);
+               return NULL;
+       }
+
+       sg_dma_address(sgt->sgl) = bo->paddr;
+       sg_dma_len(sgt->sgl) = gem->size;
+
+       return sgt;
+}
+
+static void tegra_gem_prime_unmap_dma_buf(struct dma_buf_attachment *attach,
+                                         struct sg_table *sgt,
+                                         enum dma_data_direction dir)
+{
+       sg_free_table(sgt);
+       kfree(sgt);
+}
+
+static void tegra_gem_prime_release(struct dma_buf *buf)
+{
+       drm_gem_dmabuf_release(buf);
+}
+
+static void *tegra_gem_prime_kmap_atomic(struct dma_buf *buf,
+                                        unsigned long page)
+{
+       return NULL;
+}
+
+static void tegra_gem_prime_kunmap_atomic(struct dma_buf *buf,
+                                         unsigned long page,
+                                         void *addr)
+{
+}
+
+static void *tegra_gem_prime_kmap(struct dma_buf *buf, unsigned long page)
+{
+       return NULL;
+}
+
+static void tegra_gem_prime_kunmap(struct dma_buf *buf, unsigned long page,
+                                  void *addr)
+{
+}
+
+static int tegra_gem_prime_mmap(struct dma_buf *buf, struct vm_area_struct *vma)
+{
+       return -EINVAL;
+}
+
+static const struct dma_buf_ops tegra_gem_prime_dmabuf_ops = {
+       .map_dma_buf = tegra_gem_prime_map_dma_buf,
+       .unmap_dma_buf = tegra_gem_prime_unmap_dma_buf,
+       .release = tegra_gem_prime_release,
+       .kmap_atomic = tegra_gem_prime_kmap_atomic,
+       .kunmap_atomic = tegra_gem_prime_kunmap_atomic,
+       .kmap = tegra_gem_prime_kmap,
+       .kunmap = tegra_gem_prime_kunmap,
+       .mmap = tegra_gem_prime_mmap,
+};
+
+struct dma_buf *tegra_gem_prime_export(struct drm_device *drm,
+                                      struct drm_gem_object *gem,
+                                      int flags)
+{
+       return dma_buf_export(gem, &tegra_gem_prime_dmabuf_ops, gem->size,
+                             flags);
+}
+
+struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm,
+                                             struct dma_buf *buf)
+{
+       struct tegra_bo *bo;
+
+       if (buf->ops == &tegra_gem_prime_dmabuf_ops) {
+               struct drm_gem_object *gem = buf->priv;
+
+               if (gem->dev == drm) {
+                       drm_gem_object_reference(gem);
+                       return gem;
+               }
+       }
+
+       bo = tegra_bo_import(drm, buf);
+       if (IS_ERR(bo))
+               return ERR_CAST(bo);
+
+       return &bo->gem;
+}
index 7674000bf47d6696ecec6db7507926144832c772..ffd4f792b410997630e06339a4307d087ab55f2e 100644 (file)
@@ -31,6 +31,7 @@ struct tegra_bo {
        struct drm_gem_object gem;
        struct host1x_bo base;
        unsigned long flags;
+       struct sg_table *sgt;
        dma_addr_t paddr;
        void *vaddr;
 };
@@ -40,8 +41,6 @@ static inline struct tegra_bo *to_tegra_bo(struct drm_gem_object *gem)
        return container_of(gem, struct tegra_bo, gem);
 }
 
-extern const struct host1x_bo_ops tegra_bo_ops;
-
 struct tegra_bo *tegra_bo_create(struct drm_device *drm, unsigned int size,
                                 unsigned long flags);
 struct tegra_bo *tegra_bo_create_with_handle(struct drm_file *file,
@@ -59,4 +58,10 @@ int tegra_drm_mmap(struct file *file, struct vm_area_struct *vma);
 
 extern const struct vm_operations_struct tegra_bo_vm_ops;
 
+struct dma_buf *tegra_gem_prime_export(struct drm_device *drm,
+                                      struct drm_gem_object *gem,
+                                      int flags);
+struct drm_gem_object *tegra_gem_prime_import(struct drm_device *drm,
+                                             struct dma_buf *buf);
+
 #endif
index 7f6253ea5cb5ea264319e98800b6d3783e1becb3..6928015d11a49e9fd6e499aed2ed5f02d6d1730e 100644 (file)
@@ -40,6 +40,7 @@ struct tegra_hdmi {
        struct host1x_client client;
        struct tegra_output output;
        struct device *dev;
+       bool enabled;
 
        struct regulator *vdd;
        struct regulator *pll;
@@ -379,7 +380,7 @@ static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi)
 
                if (f > 96000)
                        delta = 2;
-               else if (f > 480000)
+               else if (f > 48000)
                        delta = 6;
                else
                        delta = 9;
@@ -699,6 +700,9 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
        int retries = 1000;
        int err;
 
+       if (hdmi->enabled)
+               return 0;
+
        hdmi->dvi = !tegra_output_is_hdmi(output);
 
        pclk = mode->clock * 1000;
@@ -839,10 +843,6 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
        value |= SOR_CSTM_ROTCLK(2);
        tegra_hdmi_writel(hdmi, value, HDMI_NV_PDISP_SOR_CSTM);
 
-       tegra_dc_writel(dc, DISP_CTRL_MODE_STOP, DC_CMD_DISPLAY_COMMAND);
-       tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
-       tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
        /* start SOR */
        tegra_hdmi_writel(hdmi,
                          SOR_PWR_NORMAL_STATE_PU |
@@ -892,31 +892,67 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
                          HDMI_NV_PDISP_SOR_STATE1);
        tegra_hdmi_writel(hdmi, 0, HDMI_NV_PDISP_SOR_STATE0);
 
-       tegra_dc_writel(dc, HDMI_ENABLE, DC_DISP_DISP_WIN_OPTIONS);
-
-       value = PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
-               PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
-       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+       value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+       value |= HDMI_ENABLE;
+       tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
 
-       value = DISP_CTRL_MODE_C_DISPLAY;
+       value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+       value &= ~DISP_CTRL_MODE_MASK;
+       value |= DISP_CTRL_MODE_C_DISPLAY;
        tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
 
+       value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+       value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+                PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
+       tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+
        tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
        tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
 
        /* TODO: add HDCP support */
 
+       hdmi->enabled = true;
+
        return 0;
 }
 
 static int tegra_output_hdmi_disable(struct tegra_output *output)
 {
+       struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
        struct tegra_hdmi *hdmi = to_hdmi(output);
+       unsigned long value;
+
+       if (!hdmi->enabled)
+               return 0;
+
+       /*
+        * The following accesses registers of the display controller, so make
+        * sure it's only executed when the output is attached to one.
+        */
+       if (dc) {
+               value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+               value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+                          PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
+               tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+
+               value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+               value &= ~DISP_CTRL_MODE_MASK;
+               tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+               value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+               value &= ~HDMI_ENABLE;
+               tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+               tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+               tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+       }
 
        reset_control_assert(hdmi->rst);
        clk_disable(hdmi->clk);
        regulator_disable(hdmi->pll);
 
+       hdmi->enabled = false;
+
        return 0;
 }
 
@@ -960,7 +996,7 @@ static int tegra_output_hdmi_check_mode(struct tegra_output *output,
        parent = clk_get_parent(hdmi->clk_parent);
 
        err = clk_round_rate(parent, pclk * 4);
-       if (err < 0)
+       if (err <= 0)
                *status = MODE_NOCLOCK;
        else
                *status = MODE_OK;
@@ -1382,9 +1418,6 @@ static int tegra_hdmi_probe(struct platform_device *pdev)
                return err;
 
        regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!regs)
-               return -ENXIO;
-
        hdmi->regs = devm_ioremap_resource(&pdev->dev, regs);
        if (IS_ERR(hdmi->regs))
                return PTR_ERR(hdmi->regs);
diff --git a/drivers/gpu/drm/tegra/mipi-phy.c b/drivers/gpu/drm/tegra/mipi-phy.c
new file mode 100644 (file)
index 0000000..e2c4aed
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/errno.h>
+#include <linux/kernel.h>
+
+#include "mipi-phy.h"
+
+/*
+ * Default D-PHY timings based on MIPI D-PHY specification. Derived from
+ * the valid ranges specified in Section 5.9 of the D-PHY specification
+ * with minor adjustments.
+ */
+int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
+                                unsigned long period)
+{
+       timing->clkmiss = 0;
+       timing->clkpost = 70 + 52 * period;
+       timing->clkpre = 8;
+       timing->clkprepare = 65;
+       timing->clksettle = 95;
+       timing->clktermen = 0;
+       timing->clktrail = 80;
+       timing->clkzero = 260;
+       timing->dtermen = 0;
+       timing->eot = 0;
+       timing->hsexit = 120;
+       timing->hsprepare = 65 + 5 * period;
+       timing->hszero = 145 + 5 * period;
+       timing->hssettle = 85 + 6 * period;
+       timing->hsskip = 40;
+       timing->hstrail = max(8 * period, 60 + 4 * period);
+       timing->init = 100000;
+       timing->lpx = 60;
+       timing->taget = 5 * timing->lpx;
+       timing->tago = 4 * timing->lpx;
+       timing->tasure = 2 * timing->lpx;
+       timing->wakeup = 1000000;
+
+       return 0;
+}
+
+/*
+ * Validate D-PHY timing according to MIPI Alliance Specification for D-PHY,
+ * Section 5.9 "Global Operation Timing Parameters".
+ */
+int mipi_dphy_timing_validate(struct mipi_dphy_timing *timing,
+                             unsigned long period)
+{
+       if (timing->clkmiss > 60)
+               return -EINVAL;
+
+       if (timing->clkpost < (60 + 52 * period))
+               return -EINVAL;
+
+       if (timing->clkpre < 8)
+               return -EINVAL;
+
+       if (timing->clkprepare < 38 || timing->clkprepare > 95)
+               return -EINVAL;
+
+       if (timing->clksettle < 95 || timing->clksettle > 300)
+               return -EINVAL;
+
+       if (timing->clktermen > 38)
+               return -EINVAL;
+
+       if (timing->clktrail < 60)
+               return -EINVAL;
+
+       if (timing->clkprepare + timing->clkzero < 300)
+               return -EINVAL;
+
+       if (timing->dtermen > 35 + 4 * period)
+               return -EINVAL;
+
+       if (timing->eot > 105 + 12 * period)
+               return -EINVAL;
+
+       if (timing->hsexit < 100)
+               return -EINVAL;
+
+       if (timing->hsprepare < 40 + 4 * period ||
+           timing->hsprepare > 85 + 6 * period)
+               return -EINVAL;
+
+       if (timing->hsprepare + timing->hszero < 145 + 10 * period)
+               return -EINVAL;
+
+       if ((timing->hssettle < 85 + 6 * period) ||
+           (timing->hssettle > 145 + 10 * period))
+               return -EINVAL;
+
+       if (timing->hsskip < 40 || timing->hsskip > 55 + 4 * period)
+               return -EINVAL;
+
+       if (timing->hstrail < max(8 * period, 60 + 4 * period))
+               return -EINVAL;
+
+       if (timing->init < 100000)
+               return -EINVAL;
+
+       if (timing->lpx < 50)
+               return -EINVAL;
+
+       if (timing->taget != 5 * timing->lpx)
+               return -EINVAL;
+
+       if (timing->tago != 4 * timing->lpx)
+               return -EINVAL;
+
+       if (timing->tasure < timing->lpx || timing->tasure > 2 * timing->lpx)
+               return -EINVAL;
+
+       if (timing->wakeup < 1000000)
+               return -EINVAL;
+
+       return 0;
+}
diff --git a/drivers/gpu/drm/tegra/mipi-phy.h b/drivers/gpu/drm/tegra/mipi-phy.h
new file mode 100644 (file)
index 0000000..d359169
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#ifndef DRM_TEGRA_MIPI_PHY_H
+#define DRM_TEGRA_MIPI_PHY_H
+
+/*
+ * D-PHY timing parameters
+ *
+ * A detailed description of these parameters can be found in the  MIPI
+ * Alliance Specification for D-PHY, Section 5.9 "Global Operation Timing
+ * Parameters".
+ *
+ * All parameters are specified in nanoseconds.
+ */
+struct mipi_dphy_timing {
+       unsigned int clkmiss;
+       unsigned int clkpost;
+       unsigned int clkpre;
+       unsigned int clkprepare;
+       unsigned int clksettle;
+       unsigned int clktermen;
+       unsigned int clktrail;
+       unsigned int clkzero;
+       unsigned int dtermen;
+       unsigned int eot;
+       unsigned int hsexit;
+       unsigned int hsprepare;
+       unsigned int hszero;
+       unsigned int hssettle;
+       unsigned int hsskip;
+       unsigned int hstrail;
+       unsigned int init;
+       unsigned int lpx;
+       unsigned int taget;
+       unsigned int tago;
+       unsigned int tasure;
+       unsigned int wakeup;
+};
+
+int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
+                                unsigned long period);
+int mipi_dphy_timing_validate(struct mipi_dphy_timing *timing,
+                             unsigned long period);
+
+#endif
index 2cb0065e0578f6d80da0532dad68a31e27a6924d..57cecbd18ca88d210a6e83e61c3f3cff208f26e5 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/of_gpio.h>
 
+#include <drm/drm_panel.h>
 #include "drm.h"
 
 static int tegra_connector_get_modes(struct drm_connector *connector)
@@ -17,6 +18,16 @@ static int tegra_connector_get_modes(struct drm_connector *connector)
        struct edid *edid = NULL;
        int err = 0;
 
+       /*
+        * If the panel provides one or more modes, use them exclusively and
+        * ignore any other means of obtaining a mode.
+        */
+       if (output->panel) {
+               err = output->panel->funcs->get_modes(output->panel);
+               if (err > 0)
+                       return err;
+       }
+
        if (output->edid)
                edid = kmemdup(output->edid, sizeof(*edid), GFP_KERNEL);
        else if (output->ddc)
@@ -72,6 +83,11 @@ tegra_connector_detect(struct drm_connector *connector, bool force)
                else
                        status = connector_status_connected;
        } else {
+               if (!output->panel)
+                       status = connector_status_disconnected;
+               else
+                       status = connector_status_connected;
+
                if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
                        status = connector_status_connected;
        }
@@ -115,6 +131,16 @@ static const struct drm_encoder_funcs encoder_funcs = {
 
 static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode)
 {
+       struct tegra_output *output = encoder_to_output(encoder);
+       struct drm_panel *panel = output->panel;
+
+       if (mode != DRM_MODE_DPMS_ON) {
+               drm_panel_disable(panel);
+               tegra_output_disable(output);
+       } else {
+               tegra_output_enable(output);
+               drm_panel_enable(panel);
+       }
 }
 
 static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder,
@@ -163,14 +189,22 @@ static irqreturn_t hpd_irq(int irq, void *data)
 
 int tegra_output_probe(struct tegra_output *output)
 {
+       struct device_node *ddc, *panel;
        enum of_gpio_flags flags;
-       struct device_node *ddc;
-       size_t size;
-       int err;
+       int err, size;
 
        if (!output->of_node)
                output->of_node = output->dev->of_node;
 
+       panel = of_parse_phandle(output->of_node, "nvidia,panel", 0);
+       if (panel) {
+               output->panel = of_drm_find_panel(panel);
+               if (!output->panel)
+                       return -EPROBE_DEFER;
+
+               of_node_put(panel);
+       }
+
        output->edid = of_get_property(output->of_node, "nvidia,edid", &size);
 
        ddc = of_parse_phandle(output->of_node, "nvidia,ddc-i2c-bus", 0);
@@ -185,9 +219,6 @@ int tegra_output_probe(struct tegra_output *output)
                of_node_put(ddc);
        }
 
-       if (!output->edid && !output->ddc)
-               return -ENODEV;
-
        output->hpd_gpio = of_get_named_gpio_flags(output->of_node,
                                                   "nvidia,hpd-gpio", 0,
                                                   &flags);
@@ -256,6 +287,11 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
                encoder = DRM_MODE_ENCODER_TMDS;
                break;
 
+       case TEGRA_OUTPUT_DSI:
+               connector = DRM_MODE_CONNECTOR_DSI;
+               encoder = DRM_MODE_ENCODER_DSI;
+               break;
+
        default:
                connector = DRM_MODE_CONNECTOR_Unknown;
                encoder = DRM_MODE_ENCODER_NONE;
@@ -267,6 +303,9 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
        drm_connector_helper_add(&output->connector, &connector_helper_funcs);
        output->connector.dpms = DRM_MODE_DPMS_OFF;
 
+       if (output->panel)
+               drm_panel_attach(output->panel, &output->connector);
+
        drm_encoder_init(drm, &output->encoder, &encoder_funcs, encoder);
        drm_encoder_helper_add(&output->encoder, &encoder_helper_funcs);
 
index 3b29018913a5f2bb9da1a2ae2f57ddc89280bbe8..338f7f6561d701d601a92b2f6362782536d03e2e 100644 (file)
@@ -87,15 +87,60 @@ static void tegra_dc_write_regs(struct tegra_dc *dc,
 static int tegra_output_rgb_enable(struct tegra_output *output)
 {
        struct tegra_rgb *rgb = to_rgb(output);
+       unsigned long value;
 
        tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
 
+       value = DE_SELECT_ACTIVE | DE_CONTROL_NORMAL;
+       tegra_dc_writel(rgb->dc, value, DC_DISP_DATA_ENABLE_OPTIONS);
+
+       /* XXX: parameterize? */
+       value = tegra_dc_readl(rgb->dc, DC_COM_PIN_OUTPUT_POLARITY(1));
+       value &= ~LVS_OUTPUT_POLARITY_LOW;
+       value &= ~LHS_OUTPUT_POLARITY_LOW;
+       tegra_dc_writel(rgb->dc, value, DC_COM_PIN_OUTPUT_POLARITY(1));
+
+       /* XXX: parameterize? */
+       value = DISP_DATA_FORMAT_DF1P1C | DISP_ALIGNMENT_MSB |
+               DISP_ORDER_RED_BLUE;
+       tegra_dc_writel(rgb->dc, value, DC_DISP_DISP_INTERFACE_CONTROL);
+
+       /* XXX: parameterize? */
+       value = SC0_H_QUALIFIER_NONE | SC1_H_QUALIFIER_NONE;
+       tegra_dc_writel(rgb->dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);
+
+       value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND);
+       value &= ~DISP_CTRL_MODE_MASK;
+       value |= DISP_CTRL_MODE_C_DISPLAY;
+       tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND);
+
+       value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
+       value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+                PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
+       tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+
+       tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+
        return 0;
 }
 
 static int tegra_output_rgb_disable(struct tegra_output *output)
 {
        struct tegra_rgb *rgb = to_rgb(output);
+       unsigned long value;
+
+       value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
+       value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+                  PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
+       tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
+
+       value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND);
+       value &= ~DISP_CTRL_MODE_MASK;
+       tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND);
+
+       tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
+       tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
 
        tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
 
@@ -213,7 +258,7 @@ int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc)
         * RGB outputs are an exception, so we make sure they can be attached
         * to only their parent display controller.
         */
-       rgb->output.encoder.possible_crtcs = 1 << dc->pipe;
+       rgb->output.encoder.possible_crtcs = drm_crtc_mask(&dc->base);
 
        return 0;
 }
index 116da199b9429a56ba8a7b58efc953369b721344..171a8203892ce16b7767b2fb3fa11fc1995f0fad 100644 (file)
@@ -311,7 +311,7 @@ static void tilcdc_lastclose(struct drm_device *dev)
        drm_fbdev_cma_restore_mode(priv->fbdev);
 }
 
-static irqreturn_t tilcdc_irq(DRM_IRQ_ARGS)
+static irqreturn_t tilcdc_irq(int irq, void *arg)
 {
        struct drm_device *dev = arg;
        struct tilcdc_drm_private *priv = dev->dev_private;
@@ -444,7 +444,7 @@ static int tilcdc_mm_show(struct seq_file *m, void *arg)
 {
        struct drm_info_node *node = (struct drm_info_node *) m->private;
        struct drm_device *dev = node->minor->dev;
-       return drm_mm_dump_table(m, dev->mm_private);
+       return drm_mm_dump_table(m, &dev->vma_offset_manager->vm_addr_space_mm);
 }
 
 static struct drm_info_list tilcdc_debugfs_list[] = {
@@ -594,7 +594,7 @@ static int tilcdc_pdev_probe(struct platform_device *pdev)
 
 static int tilcdc_pdev_remove(struct platform_device *pdev)
 {
-       drm_platform_exit(&tilcdc_driver, pdev);
+       drm_put_dev(platform_get_drvdata(pdev));
 
        return 0;
 }
index 07e02c4bf5a8e0def00e120a14b5ada2d1cfaa97..a066513093880a218d185624589ec07efce66b0b 100644 (file)
@@ -957,7 +957,7 @@ int ttm_bo_mem_space(struct ttm_buffer_object *bo,
 }
 EXPORT_SYMBOL(ttm_bo_mem_space);
 
-int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
+static int ttm_bo_move_buffer(struct ttm_buffer_object *bo,
                        struct ttm_placement *placement,
                        bool interruptible,
                        bool no_wait_gpu)
index 4061521523154e0fbc102623b6a9d348e03d0313..1df856f7856821b31fe96e55dac5bc74bd74ed4b 100644 (file)
@@ -187,7 +187,7 @@ void ttm_mem_io_free_vm(struct ttm_buffer_object *bo)
        }
 }
 
-int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
+static int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
                        void **virtual)
 {
        struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
@@ -219,7 +219,7 @@ int ttm_mem_reg_ioremap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
        return 0;
 }
 
-void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
+static void ttm_mem_reg_iounmap(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem,
                         void *virtual)
 {
        struct ttm_mem_type_manager *man;
@@ -594,7 +594,7 @@ int ttm_bo_kmap(struct ttm_buffer_object *bo,
        if (start_page > bo->num_pages)
                return -EINVAL;
 #if 0
-       if (num_pages > 1 && !DRM_SUSER(DRM_CURPROC))
+       if (num_pages > 1 && !capable(CAP_SYS_ADMIN))
                return -EPERM;
 #endif
        (void) ttm_mem_io_lock(man, false);
index 6440eeac22d250844d2203018258654e54483cd3..801231c9ae483980afe0e93a0af73a7f07123864 100644 (file)
@@ -132,6 +132,15 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                return VM_FAULT_NOPAGE;
        }
 
+       /*
+        * Refuse to fault imported pages. This should be handled
+        * (if at all) by redirecting mmap to the exporter.
+        */
+       if (bo->ttm && (bo->ttm->page_flags & TTM_PAGE_FLAG_SG)) {
+               retval = VM_FAULT_SIGBUS;
+               goto out_unlock;
+       }
+
        if (bdev->driver->fault_reserve_notify) {
                ret = bdev->driver->fault_reserve_notify(bo);
                switch (ret) {
@@ -217,10 +226,17 @@ static int ttm_bo_vm_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
                        } else if (unlikely(!page)) {
                                break;
                        }
+                       page->mapping = vma->vm_file->f_mapping;
+                       page->index = drm_vma_node_start(&bo->vma_node) +
+                               page_offset;
                        pfn = page_to_pfn(page);
                }
 
-               ret = vm_insert_mixed(&cvma, address, pfn);
+               if (vma->vm_flags & VM_MIXEDMAP)
+                       ret = vm_insert_mixed(&cvma, address, pfn);
+               else
+                       ret = vm_insert_pfn(&cvma, address, pfn);
+
                /*
                 * Somebody beat us to this PTE or prefaulting to
                 * an already populated PTE, or prefaulting error.
@@ -250,6 +266,8 @@ static void ttm_bo_vm_open(struct vm_area_struct *vma)
        struct ttm_buffer_object *bo =
            (struct ttm_buffer_object *)vma->vm_private_data;
 
+       WARN_ON(bo->bdev->dev_mapping != vma->vm_file->f_mapping);
+
        (void)ttm_bo_reference(bo);
 }
 
@@ -319,7 +337,14 @@ int ttm_bo_mmap(struct file *filp, struct vm_area_struct *vma,
         */
 
        vma->vm_private_data = bo;
-       vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND | VM_DONTDUMP;
+
+       /*
+        * PFNMAP is faster than MIXEDMAP due to reduced page
+        * administration. So use MIXEDMAP only if private VMA, where
+        * we need to support COW.
+        */
+       vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+       vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
        return 0;
 out_unref:
        ttm_bo_unref(&bo);
@@ -334,7 +359,8 @@ int ttm_fbdev_mmap(struct vm_area_struct *vma, struct ttm_buffer_object *bo)
 
        vma->vm_ops = &ttm_bo_vm_ops;
        vma->vm_private_data = ttm_bo_reference(bo);
-       vma->vm_flags |= VM_IO | VM_MIXEDMAP | VM_DONTEXPAND;
+       vma->vm_flags |= (vma->vm_flags & VM_SHARED) ? VM_PFNMAP : VM_MIXEDMAP;
+       vma->vm_flags |= VM_IO | VM_DONTEXPAND;
        return 0;
 }
 EXPORT_SYMBOL(ttm_fbdev_mmap);
index 3daa9a3930b810c5adaf310a3dbea89e0e73343d..6a954544727f3f13cfa8d9be0b8ff4cbf39d9367 100644 (file)
@@ -186,14 +186,6 @@ int ttm_write_lock(struct ttm_lock *lock, bool interruptible)
 }
 EXPORT_SYMBOL(ttm_write_lock);
 
-void ttm_write_lock_downgrade(struct ttm_lock *lock)
-{
-       spin_lock(&lock->lock);
-       lock->rw = 1;
-       wake_up_all(&lock->queue);
-       spin_unlock(&lock->lock);
-}
-
 static int __ttm_vt_unlock(struct ttm_lock *lock)
 {
        int ret = 0;
index 6fe7b92a82d1f72f465a79d48dd0088337d713fe..37079859afc86e6cef120cd4d8a924388c3f6e3b 100644 (file)
@@ -68,7 +68,7 @@
 
 struct ttm_object_file {
        struct ttm_object_device *tdev;
-       rwlock_t lock;
+       spinlock_t lock;
        struct list_head ref_list;
        struct drm_open_hash ref_hash[TTM_REF_NUM];
        struct kref refcount;
@@ -118,6 +118,7 @@ struct ttm_object_device {
  */
 
 struct ttm_ref_object {
+       struct rcu_head rcu_head;
        struct drm_hash_item hash;
        struct list_head head;
        struct kref kref;
@@ -210,10 +211,9 @@ static void ttm_release_base(struct kref *kref)
         * call_rcu() or ttm_base_object_kfree().
         */
 
-       if (base->refcount_release) {
-               ttm_object_file_unref(&base->tfile);
+       ttm_object_file_unref(&base->tfile);
+       if (base->refcount_release)
                base->refcount_release(&base);
-       }
 }
 
 void ttm_base_object_unref(struct ttm_base_object **p_base)
@@ -229,32 +229,46 @@ EXPORT_SYMBOL(ttm_base_object_unref);
 struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file *tfile,
                                               uint32_t key)
 {
-       struct ttm_object_device *tdev = tfile->tdev;
-       struct ttm_base_object *uninitialized_var(base);
+       struct ttm_base_object *base = NULL;
        struct drm_hash_item *hash;
+       struct drm_open_hash *ht = &tfile->ref_hash[TTM_REF_USAGE];
        int ret;
 
        rcu_read_lock();
-       ret = drm_ht_find_item_rcu(&tdev->object_hash, key, &hash);
+       ret = drm_ht_find_item_rcu(ht, key, &hash);
 
        if (likely(ret == 0)) {
-               base = drm_hash_entry(hash, struct ttm_base_object, hash);
-               ret = kref_get_unless_zero(&base->refcount) ? 0 : -EINVAL;
+               base = drm_hash_entry(hash, struct ttm_ref_object, hash)->obj;
+               if (!kref_get_unless_zero(&base->refcount))
+                       base = NULL;
        }
        rcu_read_unlock();
 
-       if (unlikely(ret != 0))
-               return NULL;
+       return base;
+}
+EXPORT_SYMBOL(ttm_base_object_lookup);
 
-       if (tfile != base->tfile && !base->shareable) {
-               pr_err("Attempted access of non-shareable object\n");
-               ttm_base_object_unref(&base);
-               return NULL;
+struct ttm_base_object *
+ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key)
+{
+       struct ttm_base_object *base = NULL;
+       struct drm_hash_item *hash;
+       struct drm_open_hash *ht = &tdev->object_hash;
+       int ret;
+
+       rcu_read_lock();
+       ret = drm_ht_find_item_rcu(ht, key, &hash);
+
+       if (likely(ret == 0)) {
+               base = drm_hash_entry(hash, struct ttm_base_object, hash);
+               if (!kref_get_unless_zero(&base->refcount))
+                       base = NULL;
        }
+       rcu_read_unlock();
 
        return base;
 }
-EXPORT_SYMBOL(ttm_base_object_lookup);
+EXPORT_SYMBOL(ttm_base_object_lookup_for_ref);
 
 int ttm_ref_object_add(struct ttm_object_file *tfile,
                       struct ttm_base_object *base,
@@ -266,21 +280,25 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
        struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
        int ret = -EINVAL;
 
+       if (base->tfile != tfile && !base->shareable)
+               return -EPERM;
+
        if (existed != NULL)
                *existed = true;
 
        while (ret == -EINVAL) {
-               read_lock(&tfile->lock);
-               ret = drm_ht_find_item(ht, base->hash.key, &hash);
+               rcu_read_lock();
+               ret = drm_ht_find_item_rcu(ht, base->hash.key, &hash);
 
                if (ret == 0) {
                        ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
-                       kref_get(&ref->kref);
-                       read_unlock(&tfile->lock);
-                       break;
+                       if (!kref_get_unless_zero(&ref->kref)) {
+                               rcu_read_unlock();
+                               break;
+                       }
                }
 
-               read_unlock(&tfile->lock);
+               rcu_read_unlock();
                ret = ttm_mem_global_alloc(mem_glob, sizeof(*ref),
                                           false, false);
                if (unlikely(ret != 0))
@@ -297,19 +315,19 @@ int ttm_ref_object_add(struct ttm_object_file *tfile,
                ref->ref_type = ref_type;
                kref_init(&ref->kref);
 
-               write_lock(&tfile->lock);
-               ret = drm_ht_insert_item(ht, &ref->hash);
+               spin_lock(&tfile->lock);
+               ret = drm_ht_insert_item_rcu(ht, &ref->hash);
 
                if (likely(ret == 0)) {
                        list_add_tail(&ref->head, &tfile->ref_list);
                        kref_get(&base->refcount);
-                       write_unlock(&tfile->lock);
+                       spin_unlock(&tfile->lock);
                        if (existed != NULL)
                                *existed = false;
                        break;
                }
 
-               write_unlock(&tfile->lock);
+               spin_unlock(&tfile->lock);
                BUG_ON(ret != -EINVAL);
 
                ttm_mem_global_free(mem_glob, sizeof(*ref));
@@ -330,17 +348,17 @@ static void ttm_ref_object_release(struct kref *kref)
        struct ttm_mem_global *mem_glob = tfile->tdev->mem_glob;
 
        ht = &tfile->ref_hash[ref->ref_type];
-       (void)drm_ht_remove_item(ht, &ref->hash);
+       (void)drm_ht_remove_item_rcu(ht, &ref->hash);
        list_del(&ref->head);
-       write_unlock(&tfile->lock);
+       spin_unlock(&tfile->lock);
 
        if (ref->ref_type != TTM_REF_USAGE && base->ref_obj_release)
                base->ref_obj_release(base, ref->ref_type);
 
        ttm_base_object_unref(&ref->obj);
        ttm_mem_global_free(mem_glob, sizeof(*ref));
-       kfree(ref);
-       write_lock(&tfile->lock);
+       kfree_rcu(ref, rcu_head);
+       spin_lock(&tfile->lock);
 }
 
 int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
@@ -351,15 +369,15 @@ int ttm_ref_object_base_unref(struct ttm_object_file *tfile,
        struct drm_hash_item *hash;
        int ret;
 
-       write_lock(&tfile->lock);
+       spin_lock(&tfile->lock);
        ret = drm_ht_find_item(ht, key, &hash);
        if (unlikely(ret != 0)) {
-               write_unlock(&tfile->lock);
+               spin_unlock(&tfile->lock);
                return -EINVAL;
        }
        ref = drm_hash_entry(hash, struct ttm_ref_object, hash);
        kref_put(&ref->kref, ttm_ref_object_release);
-       write_unlock(&tfile->lock);
+       spin_unlock(&tfile->lock);
        return 0;
 }
 EXPORT_SYMBOL(ttm_ref_object_base_unref);
@@ -372,7 +390,7 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile)
        struct ttm_object_file *tfile = *p_tfile;
 
        *p_tfile = NULL;
-       write_lock(&tfile->lock);
+       spin_lock(&tfile->lock);
 
        /*
         * Since we release the lock within the loop, we have to
@@ -388,7 +406,7 @@ void ttm_object_file_release(struct ttm_object_file **p_tfile)
        for (i = 0; i < TTM_REF_NUM; ++i)
                drm_ht_remove(&tfile->ref_hash[i]);
 
-       write_unlock(&tfile->lock);
+       spin_unlock(&tfile->lock);
        ttm_object_file_unref(&tfile);
 }
 EXPORT_SYMBOL(ttm_object_file_release);
@@ -404,7 +422,7 @@ struct ttm_object_file *ttm_object_file_init(struct ttm_object_device *tdev,
        if (unlikely(tfile == NULL))
                return NULL;
 
-       rwlock_init(&tfile->lock);
+       spin_lock_init(&tfile->lock);
        tfile->tdev = tdev;
        kref_init(&tfile->refcount);
        INIT_LIST_HEAD(&tfile->ref_list);
index 210d50365162d39d8b2048ba3d8c0e567ed95bf9..9af99084b344413dcb07c2a368916bff647fc119 100644 (file)
@@ -170,9 +170,8 @@ void ttm_tt_destroy(struct ttm_tt *ttm)
                ttm_tt_unbind(ttm);
        }
 
-       if (ttm->state == tt_unbound) {
-               ttm->bdev->driver->ttm_tt_unpopulate(ttm);
-       }
+       if (ttm->state == tt_unbound)
+               ttm_tt_unpopulate(ttm);
 
        if (!(ttm->page_flags & TTM_PAGE_FLAG_PERSISTENT_SWAP) &&
            ttm->swap_storage)
@@ -362,7 +361,7 @@ int ttm_tt_swapout(struct ttm_tt *ttm, struct file *persistent_swap_storage)
                page_cache_release(to_page);
        }
 
-       ttm->bdev->driver->ttm_tt_unpopulate(ttm);
+       ttm_tt_unpopulate(ttm);
        ttm->swap_storage = swap_storage;
        ttm->page_flags |= TTM_PAGE_FLAG_SWAPPED;
        if (persistent_swap_storage)
@@ -375,3 +374,23 @@ out_err:
 
        return ret;
 }
+
+static void ttm_tt_clear_mapping(struct ttm_tt *ttm)
+{
+       pgoff_t i;
+       struct page **page = ttm->pages;
+
+       for (i = 0; i < ttm->num_pages; ++i) {
+               (*page)->mapping = NULL;
+               (*page++)->index = 0;
+       }
+}
+
+void ttm_tt_unpopulate(struct ttm_tt *ttm)
+{
+       if (ttm->state == tt_unpopulated)
+               return;
+
+       ttm_tt_clear_mapping(ttm);
+       ttm->bdev->driver->ttm_tt_unpopulate(ttm);
+}
index 97e9d614700f7f6d475b55c7ecae8a513e54afb4..dbadd49e4c4a62bdd32c83473ad3751452e4033d 100644 (file)
@@ -403,15 +403,17 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
        int i;
        int ret = 0;
 
+       drm_modeset_lock_all(fb->dev);
+
        if (!ufb->active_16)
-               return 0;
+               goto unlock;
 
        if (ufb->obj->base.import_attach) {
                ret = dma_buf_begin_cpu_access(ufb->obj->base.import_attach->dmabuf,
                                               0, ufb->obj->base.size,
                                               DMA_FROM_DEVICE);
                if (ret)
-                       return ret;
+                       goto unlock;
        }
 
        for (i = 0; i < num_clips; i++) {
@@ -419,7 +421,7 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
                                  clips[i].x2 - clips[i].x1,
                                  clips[i].y2 - clips[i].y1);
                if (ret)
-                       break;
+                       goto unlock;
        }
 
        if (ufb->obj->base.import_attach) {
@@ -427,6 +429,10 @@ static int udl_user_framebuffer_dirty(struct drm_framebuffer *fb,
                                       0, ufb->obj->base.size,
                                       DMA_FROM_DEVICE);
        }
+
+ unlock:
+       drm_modeset_unlock_all(fb->dev);
+
        return ret;
 }
 
index 652f9b43ec9dcfc1c8a6e383dcc443fa9ef2db94..a18479c6b6dae3dfdbb3d3e6e238f129dc79a3ad 100644 (file)
@@ -60,7 +60,7 @@
        dev_priv->dma_low += 8;                                 \
 }
 
-#define via_flush_write_combine() DRM_MEMORYBARRIER()
+#define via_flush_write_combine() mb()
 
 #define VIA_OUT_RING_QW(w1, w2)        do {            \
        *vb++ = (w1);                           \
@@ -234,13 +234,13 @@ static int via_dma_init(struct drm_device *dev, void *data, struct drm_file *fil
 
        switch (init->func) {
        case VIA_INIT_DMA:
-               if (!DRM_SUSER(DRM_CURPROC))
+               if (!capable(CAP_SYS_ADMIN))
                        retcode = -EPERM;
                else
                        retcode = via_initialize(dev, dev_priv, init);
                break;
        case VIA_CLEANUP_DMA:
-               if (!DRM_SUSER(DRM_CURPROC))
+               if (!capable(CAP_SYS_ADMIN))
                        retcode = -EPERM;
                else
                        retcode = via_dma_cleanup(dev);
@@ -273,7 +273,7 @@ static int via_dispatch_cmdbuffer(struct drm_device *dev, drm_via_cmdbuffer_t *c
        if (cmd->size > VIA_PCI_BUF_SIZE)
                return -ENOMEM;
 
-       if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
+       if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size))
                return -EFAULT;
 
        /*
@@ -346,7 +346,7 @@ static int via_dispatch_pci_cmdbuffer(struct drm_device *dev,
 
        if (cmd->size > VIA_PCI_BUF_SIZE)
                return -ENOMEM;
-       if (DRM_COPY_FROM_USER(dev_priv->pci_buf, cmd->buf, cmd->size))
+       if (copy_from_user(dev_priv->pci_buf, cmd->buf, cmd->size))
                return -EFAULT;
 
        if ((ret =
@@ -543,7 +543,7 @@ static void via_cmdbuf_start(drm_via_private_t *dev_priv)
 
        VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_hi);
        VIA_WRITE(VIA_REG_TRANSPACE, pause_addr_lo);
-       DRM_WRITEMEMORYBARRIER();
+       wmb();
        VIA_WRITE(VIA_REG_TRANSPACE, command | HC_HAGPCMNT_MASK);
        VIA_READ(VIA_REG_TRANSPACE);
 
index 8b0f25904e6db4edf754c9c18ab58077bfb0930e..ba33cf679180498a4ecd29260c16ee0570d2f480 100644 (file)
@@ -217,7 +217,7 @@ via_fire_dmablit(struct drm_device *dev, drm_via_sg_info_t *vsg, int engine)
        VIA_WRITE(VIA_PCI_DMA_MR0  + engine*0x04, VIA_DMA_MR_CM | VIA_DMA_MR_TDIE);
        VIA_WRITE(VIA_PCI_DMA_BCR0 + engine*0x10, 0);
        VIA_WRITE(VIA_PCI_DMA_DPR0 + engine*0x10, vsg->chain_start);
-       DRM_WRITEMEMORYBARRIER();
+       wmb();
        VIA_WRITE(VIA_PCI_DMA_CSR0 + engine*0x04, VIA_DMA_CSR_DE | VIA_DMA_CSR_TS);
        VIA_READ(VIA_PCI_DMA_CSR0 + engine*0x04);
 }
@@ -338,7 +338,7 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
 
                blitq->blits[cur]->aborted = blitq->aborting;
                blitq->done_blit_handle++;
-               DRM_WAKEUP(blitq->blit_queue + cur);
+               wake_up(blitq->blit_queue + cur);
 
                cur++;
                if (cur >= VIA_NUM_BLIT_SLOTS)
@@ -363,7 +363,7 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
 
                via_abort_dmablit(dev, engine);
                blitq->aborting = 1;
-               blitq->end = jiffies + DRM_HZ;
+               blitq->end = jiffies + HZ;
        }
 
        if (!blitq->is_active) {
@@ -372,7 +372,7 @@ via_dmablit_handler(struct drm_device *dev, int engine, int from_irq)
                        blitq->is_active = 1;
                        blitq->cur = cur;
                        blitq->num_outstanding--;
-                       blitq->end = jiffies + DRM_HZ;
+                       blitq->end = jiffies + HZ;
                        if (!timer_pending(&blitq->poll_timer))
                                mod_timer(&blitq->poll_timer, jiffies + 1);
                } else {
@@ -436,7 +436,7 @@ via_dmablit_sync(struct drm_device *dev, uint32_t handle, int engine)
        int ret = 0;
 
        if (via_dmablit_active(blitq, engine, handle, &queue)) {
-               DRM_WAIT_ON(ret, *queue, 3 * DRM_HZ,
+               DRM_WAIT_ON(ret, *queue, 3 * HZ,
                            !via_dmablit_active(blitq, engine, handle, NULL));
        }
        DRM_DEBUG("DMA blit sync handle 0x%x engine %d returned %d\n",
@@ -521,7 +521,7 @@ via_dmablit_workqueue(struct work_struct *work)
 
                spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
 
-               DRM_WAKEUP(&blitq->busy_queue);
+               wake_up(&blitq->busy_queue);
 
                via_free_sg_info(dev->pdev, cur_sg);
                kfree(cur_sg);
@@ -561,8 +561,8 @@ via_init_dmablit(struct drm_device *dev)
                blitq->aborting = 0;
                spin_lock_init(&blitq->blit_lock);
                for (j = 0; j < VIA_NUM_BLIT_SLOTS; ++j)
-                       DRM_INIT_WAITQUEUE(blitq->blit_queue + j);
-               DRM_INIT_WAITQUEUE(&blitq->busy_queue);
+                       init_waitqueue_head(blitq->blit_queue + j);
+               init_waitqueue_head(&blitq->busy_queue);
                INIT_WORK(&blitq->wq, via_dmablit_workqueue);
                setup_timer(&blitq->poll_timer, via_dmablit_timer,
                                (unsigned long)blitq);
@@ -688,7 +688,7 @@ via_dmablit_grab_slot(drm_via_blitq_t *blitq, int engine)
        while (blitq->num_free == 0) {
                spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
 
-               DRM_WAIT_ON(ret, blitq->busy_queue, DRM_HZ, blitq->num_free > 0);
+               DRM_WAIT_ON(ret, blitq->busy_queue, HZ, blitq->num_free > 0);
                if (ret)
                        return (-EINTR == ret) ? -EAGAIN : ret;
 
@@ -713,7 +713,7 @@ via_dmablit_release_slot(drm_via_blitq_t *blitq)
        spin_lock_irqsave(&blitq->blit_lock, irqsave);
        blitq->num_free++;
        spin_unlock_irqrestore(&blitq->blit_lock, irqsave);
-       DRM_WAKEUP(&blitq->busy_queue);
+       wake_up(&blitq->busy_queue);
 }
 
 /*
index 92684a9b7e3414f69cdc76f2d2ef82d286cda734..50abc2adfaee495730337a94b4fc931bcdd40f37 100644 (file)
@@ -46,7 +46,7 @@ static int via_driver_open(struct drm_device *dev, struct drm_file *file)
        return 0;
 }
 
-void via_driver_postclose(struct drm_device *dev, struct drm_file *file)
+static void via_driver_postclose(struct drm_device *dev, struct drm_file *file)
 {
        struct via_file_private *file_priv = file->driver_priv;
 
index a811ef2b505f1b25de22921a55ad8309d6a33d6a..ad0273256beb58b3bd4ff65c3c6b230427543a17 100644 (file)
@@ -138,7 +138,7 @@ extern u32 via_get_vblank_counter(struct drm_device *dev, int crtc);
 extern int via_enable_vblank(struct drm_device *dev, int crtc);
 extern void via_disable_vblank(struct drm_device *dev, int crtc);
 
-extern irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS);
+extern irqreturn_t via_driver_irq_handler(int irq, void *arg);
 extern void via_driver_irq_preinstall(struct drm_device *dev);
 extern int via_driver_irq_postinstall(struct drm_device *dev);
 extern void via_driver_irq_uninstall(struct drm_device *dev);
index ac98964297cfffcf4939817629fbd51d17f32dd7..1319433816d3cd4743c7eadbcf073d8703c6476b 100644 (file)
@@ -104,7 +104,7 @@ u32 via_get_vblank_counter(struct drm_device *dev, int crtc)
        return atomic_read(&dev_priv->vbl_received);
 }
 
-irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
+irqreturn_t via_driver_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *) arg;
        drm_via_private_t *dev_priv = (drm_via_private_t *) dev->dev_private;
@@ -138,7 +138,7 @@ irqreturn_t via_driver_irq_handler(DRM_IRQ_ARGS)
        for (i = 0; i < dev_priv->num_irqs; ++i) {
                if (status & cur_irq->pending_mask) {
                        atomic_inc(&cur_irq->irq_received);
-                       DRM_WAKEUP(&cur_irq->irq_queue);
+                       wake_up(&cur_irq->irq_queue);
                        handled = 1;
                        if (dev_priv->irq_map[drm_via_irq_dma0_td] == i)
                                via_dmablit_handler(dev, 0, 1);
@@ -239,12 +239,12 @@ via_driver_irq_wait(struct drm_device *dev, unsigned int irq, int force_sequence
        cur_irq = dev_priv->via_irqs + real_irq;
 
        if (masks[real_irq][2] && !force_sequence) {
-               DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+               DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ,
                            ((VIA_READ(masks[irq][2]) & masks[irq][3]) ==
                             masks[irq][4]));
                cur_irq_sequence = atomic_read(&cur_irq->irq_received);
        } else {
-               DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * DRM_HZ,
+               DRM_WAIT_ON(ret, cur_irq->irq_queue, 3 * HZ,
                            (((cur_irq_sequence =
                               atomic_read(&cur_irq->irq_received)) -
                              *sequence) <= (1 << 23)));
@@ -287,7 +287,7 @@ void via_driver_irq_preinstall(struct drm_device *dev)
                        atomic_set(&cur_irq->irq_received, 0);
                        cur_irq->enable_mask = dev_priv->irq_masks[i][0];
                        cur_irq->pending_mask = dev_priv->irq_masks[i][1];
-                       DRM_INIT_WAITQUEUE(&cur_irq->irq_queue);
+                       init_waitqueue_head(&cur_irq->irq_queue);
                        dev_priv->irq_enable_mask |= cur_irq->enable_mask;
                        dev_priv->irq_pending_mask |= cur_irq->pending_mask;
                        cur_irq++;
index 6569efa2ff6ea4e82f2e91649dc9fdec0964b107..a9ffbad1cfdd87fe9d4c4bf14ce8902ca07f4f50 100644 (file)
@@ -36,7 +36,7 @@ void via_init_futex(drm_via_private_t *dev_priv)
        DRM_DEBUG("\n");
 
        for (i = 0; i < VIA_NR_XVMC_LOCKS; ++i) {
-               DRM_INIT_WAITQUEUE(&(dev_priv->decoder_queue[i]));
+               init_waitqueue_head(&(dev_priv->decoder_queue[i]));
                XVMCLOCKPTR(dev_priv->sarea_priv, i)->lock = 0;
        }
 }
@@ -58,7 +58,7 @@ void via_release_futex(drm_via_private_t *dev_priv, int context)
                if ((_DRM_LOCKING_CONTEXT(*lock) == context)) {
                        if (_DRM_LOCK_IS_HELD(*lock)
                            && (*lock & _DRM_LOCK_CONT)) {
-                               DRM_WAKEUP(&(dev_priv->decoder_queue[i]));
+                               wake_up(&(dev_priv->decoder_queue[i]));
                        }
                        *lock = 0;
                }
@@ -83,10 +83,10 @@ int via_decoder_futex(struct drm_device *dev, void *data, struct drm_file *file_
        switch (fx->func) {
        case VIA_FUTEX_WAIT:
                DRM_WAIT_ON(ret, dev_priv->decoder_queue[fx->lock],
-                           (fx->ms / 10) * (DRM_HZ / 100), *lock != fx->val);
+                           (fx->ms / 10) * (HZ / 100), *lock != fx->val);
                return ret;
        case VIA_FUTEX_WAKE:
-               DRM_WAKEUP(&(dev_priv->decoder_queue[fx->lock]));
+               wake_up(&(dev_priv->decoder_queue[fx->lock]));
                return 0;
        }
        return 0;
index 9f8b690bcf52c97e24db7c6a515f9be185b30321..458cdf6d81e8b91781af5d1c18d663c133c5f455 100644 (file)
@@ -6,6 +6,6 @@ vmwgfx-y := vmwgfx_execbuf.o vmwgfx_gmr.o vmwgfx_kms.o vmwgfx_drv.o \
            vmwgfx_fifo.o vmwgfx_irq.o vmwgfx_ldu.o vmwgfx_ttm_glue.o \
            vmwgfx_overlay.o vmwgfx_marker.o vmwgfx_gmrid_manager.o \
            vmwgfx_fence.o vmwgfx_dmabuf.o vmwgfx_scrn.o vmwgfx_context.o \
-           vmwgfx_surface.o vmwgfx_prime.o
+           vmwgfx_surface.o vmwgfx_prime.o vmwgfx_mob.o vmwgfx_shader.o
 
 obj-$(CONFIG_DRM_VMWGFX) := vmwgfx.o
index d0e085ee82498679cdde540f2ce87c539fa4856b..d95335cb90bd4f30f7b7cdcf601028611986d802 100644 (file)
@@ -34,6 +34,8 @@
 
 #include "svga_reg.h"
 
+typedef uint32 PPN;
+typedef __le64 PPN64;
 
 /*
  * 3D Hardware Version
@@ -71,6 +73,9 @@ typedef uint32 SVGA3dBool; /* 32-bit Bool definition */
 #define SVGA3D_MAX_CONTEXT_IDS                  256
 #define SVGA3D_MAX_SURFACE_IDS                  (32 * 1024)
 
+#define SVGA3D_NUM_TEXTURE_UNITS                32
+#define SVGA3D_NUM_LIGHTS                       8
+
 /*
  * Surface formats.
  *
@@ -81,6 +86,7 @@ typedef uint32 SVGA3dBool; /* 32-bit Bool definition */
  */
 
 typedef enum SVGA3dSurfaceFormat {
+   SVGA3D_FORMAT_MIN                   = 0,
    SVGA3D_FORMAT_INVALID               = 0,
 
    SVGA3D_X8R8G8B8                     = 1,
@@ -134,12 +140,6 @@ typedef enum SVGA3dSurfaceFormat {
    SVGA3D_RG_S10E5                     = 35,
    SVGA3D_RG_S23E8                     = 36,
 
-   /*
-    * Any surface can be used as a buffer object, but SVGA3D_BUFFER is
-    * the most efficient format to use when creating new surfaces
-    * expressly for index or vertex data.
-    */
-
    SVGA3D_BUFFER                       = 37,
 
    SVGA3D_Z_D24X8                      = 38,
@@ -159,15 +159,114 @@ typedef enum SVGA3dSurfaceFormat {
    /* Video format with alpha */
    SVGA3D_AYUV                         = 45,
 
+   SVGA3D_R32G32B32A32_TYPELESS        = 46,
+   SVGA3D_R32G32B32A32_FLOAT           = 25,
+   SVGA3D_R32G32B32A32_UINT            = 47,
+   SVGA3D_R32G32B32A32_SINT            = 48,
+   SVGA3D_R32G32B32_TYPELESS           = 49,
+   SVGA3D_R32G32B32_FLOAT              = 50,
+   SVGA3D_R32G32B32_UINT               = 51,
+   SVGA3D_R32G32B32_SINT               = 52,
+   SVGA3D_R16G16B16A16_TYPELESS        = 53,
+   SVGA3D_R16G16B16A16_FLOAT           = 24,
+   SVGA3D_R16G16B16A16_UNORM           = 41,
+   SVGA3D_R16G16B16A16_UINT            = 54,
+   SVGA3D_R16G16B16A16_SNORM           = 55,
+   SVGA3D_R16G16B16A16_SINT            = 56,
+   SVGA3D_R32G32_TYPELESS              = 57,
+   SVGA3D_R32G32_FLOAT                 = 36,
+   SVGA3D_R32G32_UINT                  = 58,
+   SVGA3D_R32G32_SINT                  = 59,
+   SVGA3D_R32G8X24_TYPELESS            = 60,
+   SVGA3D_D32_FLOAT_S8X24_UINT         = 61,
+   SVGA3D_R32_FLOAT_X8X24_TYPELESS     = 62,
+   SVGA3D_X32_TYPELESS_G8X24_UINT      = 63,
+   SVGA3D_R10G10B10A2_TYPELESS         = 64,
+   SVGA3D_R10G10B10A2_UNORM            = 26,
+   SVGA3D_R10G10B10A2_UINT             = 65,
+   SVGA3D_R11G11B10_FLOAT              = 66,
+   SVGA3D_R8G8B8A8_TYPELESS            = 67,
+   SVGA3D_R8G8B8A8_UNORM               = 68,
+   SVGA3D_R8G8B8A8_UNORM_SRGB          = 69,
+   SVGA3D_R8G8B8A8_UINT                = 70,
+   SVGA3D_R8G8B8A8_SNORM               = 28,
+   SVGA3D_R8G8B8A8_SINT                = 71,
+   SVGA3D_R16G16_TYPELESS              = 72,
+   SVGA3D_R16G16_FLOAT                 = 35,
+   SVGA3D_R16G16_UNORM                 = 40,
+   SVGA3D_R16G16_UINT                  = 73,
+   SVGA3D_R16G16_SNORM                 = 39,
+   SVGA3D_R16G16_SINT                  = 74,
+   SVGA3D_R32_TYPELESS                 = 75,
+   SVGA3D_D32_FLOAT                    = 76,
+   SVGA3D_R32_FLOAT                    = 34,
+   SVGA3D_R32_UINT                     = 77,
+   SVGA3D_R32_SINT                     = 78,
+   SVGA3D_R24G8_TYPELESS               = 79,
+   SVGA3D_D24_UNORM_S8_UINT            = 80,
+   SVGA3D_R24_UNORM_X8_TYPELESS        = 81,
+   SVGA3D_X24_TYPELESS_G8_UINT         = 82,
+   SVGA3D_R8G8_TYPELESS                = 83,
+   SVGA3D_R8G8_UNORM                   = 84,
+   SVGA3D_R8G8_UINT                    = 85,
+   SVGA3D_R8G8_SNORM                   = 27,
+   SVGA3D_R8G8_SINT                    = 86,
+   SVGA3D_R16_TYPELESS                 = 87,
+   SVGA3D_R16_FLOAT                    = 33,
+   SVGA3D_D16_UNORM                    = 8,
+   SVGA3D_R16_UNORM                    = 88,
+   SVGA3D_R16_UINT                     = 89,
+   SVGA3D_R16_SNORM                    = 90,
+   SVGA3D_R16_SINT                     = 91,
+   SVGA3D_R8_TYPELESS                  = 92,
+   SVGA3D_R8_UNORM                     = 93,
+   SVGA3D_R8_UINT                      = 94,
+   SVGA3D_R8_SNORM                     = 95,
+   SVGA3D_R8_SINT                      = 96,
+   SVGA3D_A8_UNORM                     = 32,
+   SVGA3D_R1_UNORM                     = 97,
+   SVGA3D_R9G9B9E5_SHAREDEXP           = 98,
+   SVGA3D_R8G8_B8G8_UNORM              = 99,
+   SVGA3D_G8R8_G8B8_UNORM              = 100,
+   SVGA3D_BC1_TYPELESS                 = 101,
+   SVGA3D_BC1_UNORM                    = 15,
+   SVGA3D_BC1_UNORM_SRGB               = 102,
+   SVGA3D_BC2_TYPELESS                 = 103,
+   SVGA3D_BC2_UNORM                    = 17,
+   SVGA3D_BC2_UNORM_SRGB               = 104,
+   SVGA3D_BC3_TYPELESS                 = 105,
+   SVGA3D_BC3_UNORM                    = 19,
+   SVGA3D_BC3_UNORM_SRGB               = 106,
+   SVGA3D_BC4_TYPELESS                 = 107,
    SVGA3D_BC4_UNORM                    = 108,
+   SVGA3D_BC4_SNORM                    = 109,
+   SVGA3D_BC5_TYPELESS                 = 110,
    SVGA3D_BC5_UNORM                    = 111,
+   SVGA3D_BC5_SNORM                    = 112,
+   SVGA3D_B5G6R5_UNORM                 = 3,
+   SVGA3D_B5G5R5A1_UNORM               = 5,
+   SVGA3D_B8G8R8A8_UNORM               = 2,
+   SVGA3D_B8G8R8X8_UNORM               = 1,
+   SVGA3D_R10G10B10_XR_BIAS_A2_UNORM   = 113,
+   SVGA3D_B8G8R8A8_TYPELESS            = 114,
+   SVGA3D_B8G8R8A8_UNORM_SRGB          = 115,
+   SVGA3D_B8G8R8X8_TYPELESS            = 116,
+   SVGA3D_B8G8R8X8_UNORM_SRGB          = 117,
 
    /* Advanced D3D9 depth formats. */
    SVGA3D_Z_DF16                       = 118,
    SVGA3D_Z_DF24                       = 119,
    SVGA3D_Z_D24S8_INT                  = 120,
 
-   SVGA3D_FORMAT_MAX
+   /* Planar video formats. */
+   SVGA3D_YV12                         = 121,
+
+   /* Shader constant formats. */
+   SVGA3D_SURFACE_SHADERCONST_FLOAT    = 122,
+   SVGA3D_SURFACE_SHADERCONST_INT      = 123,
+   SVGA3D_SURFACE_SHADERCONST_BOOL     = 124,
+
+   SVGA3D_FORMAT_MAX                   = 125,
 } SVGA3dSurfaceFormat;
 
 typedef uint32 SVGA3dColor; /* a, r, g, b */
@@ -957,15 +1056,21 @@ typedef enum {
 } SVGA3dCubeFace;
 
 typedef enum {
+   SVGA3D_SHADERTYPE_INVALID                    = 0,
+   SVGA3D_SHADERTYPE_MIN                        = 1,
    SVGA3D_SHADERTYPE_VS                         = 1,
    SVGA3D_SHADERTYPE_PS                         = 2,
-   SVGA3D_SHADERTYPE_MAX
+   SVGA3D_SHADERTYPE_MAX                        = 3,
+   SVGA3D_SHADERTYPE_GS                         = 3,
 } SVGA3dShaderType;
 
+#define SVGA3D_NUM_SHADERTYPE (SVGA3D_SHADERTYPE_MAX - SVGA3D_SHADERTYPE_MIN)
+
 typedef enum {
    SVGA3D_CONST_TYPE_FLOAT                      = 0,
    SVGA3D_CONST_TYPE_INT                        = 1,
    SVGA3D_CONST_TYPE_BOOL                       = 2,
+   SVGA3D_CONST_TYPE_MAX
 } SVGA3dShaderConstType;
 
 #define SVGA3D_MAX_SURFACE_FACES                6
@@ -1056,9 +1161,74 @@ typedef enum {
 #define SVGA_3D_CMD_GENERATE_MIPMAPS       SVGA_3D_CMD_BASE + 31
 #define SVGA_3D_CMD_ACTIVATE_SURFACE       SVGA_3D_CMD_BASE + 40
 #define SVGA_3D_CMD_DEACTIVATE_SURFACE     SVGA_3D_CMD_BASE + 41
-#define SVGA_3D_CMD_MAX                    SVGA_3D_CMD_BASE + 42
-
-#define SVGA_3D_CMD_FUTURE_MAX             2000
+#define SVGA_3D_CMD_SCREEN_DMA               1082
+#define SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE 1083
+#define SVGA_3D_CMD_OPEN_CONTEXT_SURFACE     1084
+
+#define SVGA_3D_CMD_LOGICOPS_BITBLT          1085
+#define SVGA_3D_CMD_LOGICOPS_TRANSBLT        1086
+#define SVGA_3D_CMD_LOGICOPS_STRETCHBLT      1087
+#define SVGA_3D_CMD_LOGICOPS_COLORFILL       1088
+#define SVGA_3D_CMD_LOGICOPS_ALPHABLEND      1089
+#define SVGA_3D_CMD_LOGICOPS_CLEARTYPEBLEND  1090
+
+#define SVGA_3D_CMD_SET_OTABLE_BASE          1091
+#define SVGA_3D_CMD_READBACK_OTABLE          1092
+
+#define SVGA_3D_CMD_DEFINE_GB_MOB            1093
+#define SVGA_3D_CMD_DESTROY_GB_MOB           1094
+#define SVGA_3D_CMD_REDEFINE_GB_MOB          1095
+#define SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING    1096
+
+#define SVGA_3D_CMD_DEFINE_GB_SURFACE        1097
+#define SVGA_3D_CMD_DESTROY_GB_SURFACE       1098
+#define SVGA_3D_CMD_BIND_GB_SURFACE          1099
+#define SVGA_3D_CMD_COND_BIND_GB_SURFACE     1100
+#define SVGA_3D_CMD_UPDATE_GB_IMAGE          1101
+#define SVGA_3D_CMD_UPDATE_GB_SURFACE        1102
+#define SVGA_3D_CMD_READBACK_GB_IMAGE        1103
+#define SVGA_3D_CMD_READBACK_GB_SURFACE      1104
+#define SVGA_3D_CMD_INVALIDATE_GB_IMAGE      1105
+#define SVGA_3D_CMD_INVALIDATE_GB_SURFACE    1106
+
+#define SVGA_3D_CMD_DEFINE_GB_CONTEXT        1107
+#define SVGA_3D_CMD_DESTROY_GB_CONTEXT       1108
+#define SVGA_3D_CMD_BIND_GB_CONTEXT          1109
+#define SVGA_3D_CMD_READBACK_GB_CONTEXT      1110
+#define SVGA_3D_CMD_INVALIDATE_GB_CONTEXT    1111
+
+#define SVGA_3D_CMD_DEFINE_GB_SHADER         1112
+#define SVGA_3D_CMD_DESTROY_GB_SHADER        1113
+#define SVGA_3D_CMD_BIND_GB_SHADER           1114
+
+#define SVGA_3D_CMD_SET_OTABLE_BASE64        1115
+
+#define SVGA_3D_CMD_BEGIN_GB_QUERY           1116
+#define SVGA_3D_CMD_END_GB_QUERY             1117
+#define SVGA_3D_CMD_WAIT_FOR_GB_QUERY        1118
+
+#define SVGA_3D_CMD_NOP                      1119
+
+#define SVGA_3D_CMD_ENABLE_GART              1120
+#define SVGA_3D_CMD_DISABLE_GART             1121
+#define SVGA_3D_CMD_MAP_MOB_INTO_GART        1122
+#define SVGA_3D_CMD_UNMAP_GART_RANGE         1123
+
+#define SVGA_3D_CMD_DEFINE_GB_SCREENTARGET   1124
+#define SVGA_3D_CMD_DESTROY_GB_SCREENTARGET  1125
+#define SVGA_3D_CMD_BIND_GB_SCREENTARGET     1126
+#define SVGA_3D_CMD_UPDATE_GB_SCREENTARGET   1127
+
+#define SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL   1128
+#define SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL 1129
+
+#define SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE  1130
+
+#define SVGA_3D_CMD_DEFINE_GB_MOB64          1135
+#define SVGA_3D_CMD_REDEFINE_GB_MOB64        1136
+
+#define SVGA_3D_CMD_MAX                      1142
+#define SVGA_3D_CMD_FUTURE_MAX               3000
 
 /*
  * Common substructures used in multiple FIFO commands:
@@ -1749,6 +1919,495 @@ struct {
 } SVGA3dCmdGenerateMipmaps;             /* SVGA_3D_CMD_GENERATE_MIPMAPS */
 
 
+/*
+ * Guest-backed surface definitions.
+ */
+
+typedef uint32 SVGAMobId;
+
+typedef enum SVGAMobFormat {
+   SVGA3D_MOBFMT_INVALID = SVGA3D_INVALID_ID,
+   SVGA3D_MOBFMT_PTDEPTH_0 = 0,
+   SVGA3D_MOBFMT_PTDEPTH_1 = 1,
+   SVGA3D_MOBFMT_PTDEPTH_2 = 2,
+   SVGA3D_MOBFMT_RANGE     = 3,
+   SVGA3D_MOBFMT_PTDEPTH64_0 = 4,
+   SVGA3D_MOBFMT_PTDEPTH64_1 = 5,
+   SVGA3D_MOBFMT_PTDEPTH64_2 = 6,
+   SVGA3D_MOBFMT_MAX,
+} SVGAMobFormat;
+
+/*
+ * Sizes of opaque types.
+ */
+
+#define SVGA3D_OTABLE_MOB_ENTRY_SIZE 16
+#define SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE 8
+#define SVGA3D_OTABLE_SURFACE_ENTRY_SIZE 64
+#define SVGA3D_OTABLE_SHADER_ENTRY_SIZE 16
+#define SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE 64
+#define SVGA3D_CONTEXT_DATA_SIZE 16384
+
+/*
+ * SVGA3dCmdSetOTableBase --
+ *
+ * This command allows the guest to specify the base PPN of the
+ * specified object table.
+ */
+
+typedef enum {
+   SVGA_OTABLE_MOB           = 0,
+   SVGA_OTABLE_MIN           = 0,
+   SVGA_OTABLE_SURFACE       = 1,
+   SVGA_OTABLE_CONTEXT       = 2,
+   SVGA_OTABLE_SHADER        = 3,
+   SVGA_OTABLE_SCREEN_TARGET = 4,
+   SVGA_OTABLE_DX9_MAX       = 5,
+   SVGA_OTABLE_MAX           = 8
+} SVGAOTableType;
+
+typedef
+struct {
+   SVGAOTableType type;
+   PPN baseAddress;
+   uint32 sizeInBytes;
+   uint32 validSizeInBytes;
+   SVGAMobFormat ptDepth;
+}
+__attribute__((__packed__))
+SVGA3dCmdSetOTableBase;  /* SVGA_3D_CMD_SET_OTABLE_BASE */
+
+typedef
+struct {
+   SVGAOTableType type;
+   PPN64 baseAddress;
+   uint32 sizeInBytes;
+   uint32 validSizeInBytes;
+   SVGAMobFormat ptDepth;
+}
+__attribute__((__packed__))
+SVGA3dCmdSetOTableBase64;  /* SVGA_3D_CMD_SET_OTABLE_BASE64 */
+
+typedef
+struct {
+   SVGAOTableType type;
+}
+__attribute__((__packed__))
+SVGA3dCmdReadbackOTable;  /* SVGA_3D_CMD_READBACK_OTABLE */
+
+/*
+ * Define a memory object (Mob) in the OTable.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBMob {
+   SVGAMobId mobid;
+   SVGAMobFormat ptDepth;
+   PPN base;
+   uint32 sizeInBytes;
+}
+__attribute__((__packed__))
+SVGA3dCmdDefineGBMob;   /* SVGA_3D_CMD_DEFINE_GB_MOB */
+
+
+/*
+ * Destroys an object in the OTable.
+ */
+
+typedef
+struct SVGA3dCmdDestroyGBMob {
+   SVGAMobId mobid;
+}
+__attribute__((__packed__))
+SVGA3dCmdDestroyGBMob;   /* SVGA_3D_CMD_DESTROY_GB_MOB */
+
+/*
+ * Redefine an object in the OTable.
+ */
+
+typedef
+struct SVGA3dCmdRedefineGBMob {
+   SVGAMobId mobid;
+   SVGAMobFormat ptDepth;
+   PPN base;
+   uint32 sizeInBytes;
+}
+__attribute__((__packed__))
+SVGA3dCmdRedefineGBMob;   /* SVGA_3D_CMD_REDEFINE_GB_MOB */
+
+/*
+ * Define a memory object (Mob) in the OTable with a PPN64 base.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBMob64 {
+   SVGAMobId mobid;
+   SVGAMobFormat ptDepth;
+   PPN64 base;
+   uint32 sizeInBytes;
+}
+__attribute__((__packed__))
+SVGA3dCmdDefineGBMob64;   /* SVGA_3D_CMD_DEFINE_GB_MOB64 */
+
+/*
+ * Redefine an object in the OTable with PPN64 base.
+ */
+
+typedef
+struct SVGA3dCmdRedefineGBMob64 {
+   SVGAMobId mobid;
+   SVGAMobFormat ptDepth;
+   PPN64 base;
+   uint32 sizeInBytes;
+}
+__attribute__((__packed__))
+SVGA3dCmdRedefineGBMob64;   /* SVGA_3D_CMD_REDEFINE_GB_MOB64 */
+
+/*
+ * Notification that the page tables have been modified.
+ */
+
+typedef
+struct SVGA3dCmdUpdateGBMobMapping {
+   SVGAMobId mobid;
+}
+__attribute__((__packed__))
+SVGA3dCmdUpdateGBMobMapping;   /* SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING */
+
+/*
+ * Define a guest-backed surface.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBSurface {
+   uint32 sid;
+   SVGA3dSurfaceFlags surfaceFlags;
+   SVGA3dSurfaceFormat format;
+   uint32 numMipLevels;
+   uint32 multisampleCount;
+   SVGA3dTextureFilter autogenFilter;
+   SVGA3dSize size;
+} SVGA3dCmdDefineGBSurface;   /* SVGA_3D_CMD_DEFINE_GB_SURFACE */
+
+/*
+ * Destroy a guest-backed surface.
+ */
+
+typedef
+struct SVGA3dCmdDestroyGBSurface {
+   uint32 sid;
+} SVGA3dCmdDestroyGBSurface;   /* SVGA_3D_CMD_DESTROY_GB_SURFACE */
+
+/*
+ * Bind a guest-backed surface to an object.
+ */
+
+typedef
+struct SVGA3dCmdBindGBSurface {
+   uint32 sid;
+   SVGAMobId mobid;
+} SVGA3dCmdBindGBSurface;   /* SVGA_3D_CMD_BIND_GB_SURFACE */
+
+/*
+ * Conditionally bind a mob to a guest backed surface if testMobid
+ * matches the currently bound mob.  Optionally issue a readback on
+ * the surface while it is still bound to the old mobid if the mobid
+ * is changed by this command.
+ */
+
+#define SVGA3D_COND_BIND_GB_SURFACE_FLAG_READBACK (1 << 0)
+
+typedef
+struct{
+   uint32 sid;
+   SVGAMobId testMobid;
+   SVGAMobId mobid;
+   uint32 flags;
+}
+SVGA3dCmdCondBindGBSurface;          /* SVGA_3D_CMD_COND_BIND_GB_SURFACE */
+
+/*
+ * Update an image in a guest-backed surface.
+ * (Inform the device that the guest-contents have been updated.)
+ */
+
+typedef
+struct SVGA3dCmdUpdateGBImage {
+   SVGA3dSurfaceImageId image;
+   SVGA3dBox box;
+} SVGA3dCmdUpdateGBImage;   /* SVGA_3D_CMD_UPDATE_GB_IMAGE */
+
+/*
+ * Update an entire guest-backed surface.
+ * (Inform the device that the guest-contents have been updated.)
+ */
+
+typedef
+struct SVGA3dCmdUpdateGBSurface {
+   uint32 sid;
+} SVGA3dCmdUpdateGBSurface;   /* SVGA_3D_CMD_UPDATE_GB_SURFACE */
+
+/*
+ * Readback an image in a guest-backed surface.
+ * (Request the device to flush the dirty contents into the guest.)
+ */
+
+typedef
+struct SVGA3dCmdReadbackGBImage {
+   SVGA3dSurfaceImageId image;
+} SVGA3dCmdReadbackGBImage;   /* SVGA_3D_CMD_READBACK_GB_IMAGE*/
+
+/*
+ * Readback an entire guest-backed surface.
+ * (Request the device to flush the dirty contents into the guest.)
+ */
+
+typedef
+struct SVGA3dCmdReadbackGBSurface {
+   uint32 sid;
+} SVGA3dCmdReadbackGBSurface;   /* SVGA_3D_CMD_READBACK_GB_SURFACE */
+
+/*
+ * Readback a sub rect of an image in a guest-backed surface.  After
+ * issuing this command the driver is required to issue an update call
+ * of the same region before issuing any other commands that reference
+ * this surface or rendering is not guaranteed.
+ */
+
+typedef
+struct SVGA3dCmdReadbackGBImagePartial {
+   SVGA3dSurfaceImageId image;
+   SVGA3dBox box;
+   uint32 invertBox;
+}
+SVGA3dCmdReadbackGBImagePartial; /* SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL */
+
+/*
+ * Invalidate an image in a guest-backed surface.
+ * (Notify the device that the contents can be lost.)
+ */
+
+typedef
+struct SVGA3dCmdInvalidateGBImage {
+   SVGA3dSurfaceImageId image;
+} SVGA3dCmdInvalidateGBImage;   /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE */
+
+/*
+ * Invalidate an entire guest-backed surface.
+ * (Notify the device that the contents if all images can be lost.)
+ */
+
+typedef
+struct SVGA3dCmdInvalidateGBSurface {
+   uint32 sid;
+} SVGA3dCmdInvalidateGBSurface; /* SVGA_3D_CMD_INVALIDATE_GB_SURFACE */
+
+/*
+ * Invalidate a sub rect of an image in a guest-backed surface.  After
+ * issuing this command the driver is required to issue an update call
+ * of the same region before issuing any other commands that reference
+ * this surface or rendering is not guaranteed.
+ */
+
+typedef
+struct SVGA3dCmdInvalidateGBImagePartial {
+   SVGA3dSurfaceImageId image;
+   SVGA3dBox box;
+   uint32 invertBox;
+}
+SVGA3dCmdInvalidateGBImagePartial; /* SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL */
+
+/*
+ * Define a guest-backed context.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBContext {
+   uint32 cid;
+} SVGA3dCmdDefineGBContext;   /* SVGA_3D_CMD_DEFINE_GB_CONTEXT */
+
+/*
+ * Destroy a guest-backed context.
+ */
+
+typedef
+struct SVGA3dCmdDestroyGBContext {
+   uint32 cid;
+} SVGA3dCmdDestroyGBContext;   /* SVGA_3D_CMD_DESTROY_GB_CONTEXT */
+
+/*
+ * Bind a guest-backed context.
+ *
+ * validContents should be set to 0 for new contexts,
+ * and 1 if this is an old context which is getting paged
+ * back on to the device.
+ *
+ * For new contexts, it is recommended that the driver
+ * issue commands to initialize all interesting state
+ * prior to rendering.
+ */
+
+typedef
+struct SVGA3dCmdBindGBContext {
+   uint32 cid;
+   SVGAMobId mobid;
+   uint32 validContents;
+} SVGA3dCmdBindGBContext;   /* SVGA_3D_CMD_BIND_GB_CONTEXT */
+
+/*
+ * Readback a guest-backed context.
+ * (Request that the device flush the contents back into guest memory.)
+ */
+
+typedef
+struct SVGA3dCmdReadbackGBContext {
+   uint32 cid;
+} SVGA3dCmdReadbackGBContext;   /* SVGA_3D_CMD_READBACK_GB_CONTEXT */
+
+/*
+ * Invalidate a guest-backed context.
+ */
+typedef
+struct SVGA3dCmdInvalidateGBContext {
+   uint32 cid;
+} SVGA3dCmdInvalidateGBContext;   /* SVGA_3D_CMD_INVALIDATE_GB_CONTEXT */
+
+/*
+ * Define a guest-backed shader.
+ */
+
+typedef
+struct SVGA3dCmdDefineGBShader {
+   uint32 shid;
+   SVGA3dShaderType type;
+   uint32 sizeInBytes;
+} SVGA3dCmdDefineGBShader;   /* SVGA_3D_CMD_DEFINE_GB_SHADER */
+
+/*
+ * Bind a guest-backed shader.
+ */
+
+typedef struct SVGA3dCmdBindGBShader {
+   uint32 shid;
+   SVGAMobId mobid;
+   uint32 offsetInBytes;
+} SVGA3dCmdBindGBShader;   /* SVGA_3D_CMD_BIND_GB_SHADER */
+
+/*
+ * Destroy a guest-backed shader.
+ */
+
+typedef struct SVGA3dCmdDestroyGBShader {
+   uint32 shid;
+} SVGA3dCmdDestroyGBShader;   /* SVGA_3D_CMD_DESTROY_GB_SHADER */
+
+typedef
+struct {
+   uint32                  cid;
+   uint32                  regStart;
+   SVGA3dShaderType        shaderType;
+   SVGA3dShaderConstType   constType;
+
+   /*
+    * Followed by a variable number of shader constants.
+    *
+    * Note that FLOAT and INT constants are 4-dwords in length, while
+    * BOOL constants are 1-dword in length.
+    */
+} SVGA3dCmdSetGBShaderConstInline;
+/* SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dQueryType      type;
+} SVGA3dCmdBeginGBQuery;           /* SVGA_3D_CMD_BEGIN_GB_QUERY */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dQueryType      type;
+   SVGAMobId mobid;
+   uint32 offset;
+} SVGA3dCmdEndGBQuery;                  /* SVGA_3D_CMD_END_GB_QUERY */
+
+
+/*
+ * SVGA_3D_CMD_WAIT_FOR_GB_QUERY --
+ *
+ *    The semantics of this command are identical to the
+ *    SVGA_3D_CMD_WAIT_FOR_QUERY except that the results are written
+ *    to a Mob instead of a GMR.
+ */
+
+typedef
+struct {
+   uint32               cid;
+   SVGA3dQueryType      type;
+   SVGAMobId mobid;
+   uint32 offset;
+} SVGA3dCmdWaitForGBQuery;          /* SVGA_3D_CMD_WAIT_FOR_GB_QUERY */
+
+typedef
+struct {
+   SVGAMobId mobid;
+   uint32 fbOffset;
+   uint32 initalized;
+}
+SVGA3dCmdEnableGart;              /* SVGA_3D_CMD_ENABLE_GART */
+
+typedef
+struct {
+   SVGAMobId mobid;
+   uint32 gartOffset;
+}
+SVGA3dCmdMapMobIntoGart;          /* SVGA_3D_CMD_MAP_MOB_INTO_GART */
+
+
+typedef
+struct {
+   uint32 gartOffset;
+   uint32 numPages;
+}
+SVGA3dCmdUnmapGartRange;          /* SVGA_3D_CMD_UNMAP_GART_RANGE */
+
+
+/*
+ * Screen Targets
+ */
+#define SVGA_STFLAG_PRIMARY (1 << 0)
+
+typedef
+struct {
+   uint32 stid;
+   uint32 width;
+   uint32 height;
+   int32 xRoot;
+   int32 yRoot;
+   uint32 flags;
+}
+SVGA3dCmdDefineGBScreenTarget;    /* SVGA_3D_CMD_DEFINE_GB_SCREENTARGET */
+
+typedef
+struct {
+   uint32 stid;
+}
+SVGA3dCmdDestroyGBScreenTarget;  /* SVGA_3D_CMD_DESTROY_GB_SCREENTARGET */
+
+typedef
+struct {
+   uint32 stid;
+   SVGA3dSurfaceImageId image;
+}
+SVGA3dCmdBindGBScreenTarget;  /* SVGA_3D_CMD_BIND_GB_SCREENTARGET */
+
+typedef
+struct {
+   uint32 stid;
+   SVGA3dBox box;
+}
+SVGA3dCmdUpdateGBScreenTarget;  /* SVGA_3D_CMD_UPDATE_GB_SCREENTARGET */
+
 /*
  * Capability query index.
  *
@@ -1879,10 +2538,41 @@ typedef enum {
    SVGA3D_DEVCAP_SURFACEFMT_BC5_UNORM              = 83,
 
    /*
-    * Don't add new caps into the previous section; the values in this
-    * enumeration must not change. You can put new values right before
-    * SVGA3D_DEVCAP_MAX.
+    * Deprecated.
     */
+   SVGA3D_DEVCAP_VGPU10                            = 84,
+
+   /*
+    * This contains several SVGA_3D_CAPS_VIDEO_DECODE elements
+    * ored together, one for every type of video decoding supported.
+    */
+   SVGA3D_DEVCAP_VIDEO_DECODE                      = 85,
+
+   /*
+    * This contains several SVGA_3D_CAPS_VIDEO_PROCESS elements
+    * ored together, one for every type of video processing supported.
+    */
+   SVGA3D_DEVCAP_VIDEO_PROCESS                     = 86,
+
+   SVGA3D_DEVCAP_LINE_AA                           = 87,  /* boolean */
+   SVGA3D_DEVCAP_LINE_STIPPLE                      = 88,  /* boolean */
+   SVGA3D_DEVCAP_MAX_LINE_WIDTH                    = 89,  /* float */
+   SVGA3D_DEVCAP_MAX_AA_LINE_WIDTH                 = 90,  /* float */
+
+   SVGA3D_DEVCAP_SURFACEFMT_YV12                   = 91,
+
+   /*
+    * Does the host support the SVGA logic ops commands?
+    */
+   SVGA3D_DEVCAP_LOGICOPS                          = 92,
+
+   /*
+    * What support does the host have for screen targets?
+    *
+    * See the SVGA3D_SCREENTARGET_CAP bits below.
+    */
+   SVGA3D_DEVCAP_SCREENTARGETS                     = 93,
+
    SVGA3D_DEVCAP_MAX                                  /* This must be the last index. */
 } SVGA3dDevCapIndex;
 
index 01f63cb49678f6971e5c704bbb67c77cc51df4ed..71defa4d2d7528a247b8e985a7b14cd1197e2a58 100644 (file)
@@ -169,7 +169,10 @@ enum {
    SVGA_REG_TRACES = 45,            /* Enable trace-based updates even when FIFO is on */
    SVGA_REG_GMRS_MAX_PAGES = 46,    /* Maximum number of 4KB pages for all GMRs */
    SVGA_REG_MEMORY_SIZE = 47,       /* Total dedicated device memory excluding FIFO */
-   SVGA_REG_TOP = 48,               /* Must be 1 more than the last register */
+   SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM = 50,   /* Max primary memory */
+   SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB = 51, /* Suggested limit on mob mem */
+   SVGA_REG_DEV_CAP = 52,           /* Write dev cap index, read value */
+   SVGA_REG_TOP = 53,               /* Must be 1 more than the last register */
 
    SVGA_PALETTE_BASE = 1024,        /* Base of SVGA color map */
    /* Next 768 (== 256*3) registers exist for colormap */
@@ -431,7 +434,10 @@ struct SVGASignedPoint {
 #define SVGA_CAP_TRACES             0x00200000
 #define SVGA_CAP_GMR2               0x00400000
 #define SVGA_CAP_SCREEN_OBJECT_2    0x00800000
-
+#define SVGA_CAP_COMMAND_BUFFERS    0x01000000
+#define SVGA_CAP_DEAD1              0x02000000
+#define SVGA_CAP_CMD_BUFFERS_2      0x04000000
+#define SVGA_CAP_GBOBJECTS          0x08000000
 
 /*
  * FIFO register indices.
index 0489c61524826f2e2b673628783393639f0c591e..6327cfc36805f46364402a004ce76cd9bb19ecd5 100644 (file)
@@ -40,6 +40,10 @@ static uint32_t vram_ne_placement_flags = TTM_PL_FLAG_VRAM |
 static uint32_t sys_placement_flags = TTM_PL_FLAG_SYSTEM |
        TTM_PL_FLAG_CACHED;
 
+static uint32_t sys_ne_placement_flags = TTM_PL_FLAG_SYSTEM |
+       TTM_PL_FLAG_CACHED |
+       TTM_PL_FLAG_NO_EVICT;
+
 static uint32_t gmr_placement_flags = VMW_PL_FLAG_GMR |
        TTM_PL_FLAG_CACHED;
 
@@ -47,6 +51,9 @@ static uint32_t gmr_ne_placement_flags = VMW_PL_FLAG_GMR |
        TTM_PL_FLAG_CACHED |
        TTM_PL_FLAG_NO_EVICT;
 
+static uint32_t mob_placement_flags = VMW_PL_FLAG_MOB |
+       TTM_PL_FLAG_CACHED;
+
 struct ttm_placement vmw_vram_placement = {
        .fpfn = 0,
        .lpfn = 0,
@@ -116,16 +123,26 @@ struct ttm_placement vmw_sys_placement = {
        .busy_placement = &sys_placement_flags
 };
 
+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_GMR | TTM_PL_FLAG_CACHED,
+       VMW_PL_FLAG_MOB | TTM_PL_FLAG_CACHED
 };
 
 struct ttm_placement vmw_evictable_placement = {
        .fpfn = 0,
        .lpfn = 0,
-       .num_placement = 3,
+       .num_placement = 4,
        .placement = evictable_placement_flags,
        .num_busy_placement = 1,
        .busy_placement = &sys_placement_flags
@@ -140,10 +157,21 @@ struct ttm_placement vmw_srf_placement = {
        .busy_placement = gmr_vram_placement_flags
 };
 
+struct ttm_placement vmw_mob_placement = {
+       .fpfn = 0,
+       .lpfn = 0,
+       .num_placement = 1,
+       .num_busy_placement = 1,
+       .placement = &mob_placement_flags,
+       .busy_placement = &mob_placement_flags
+};
+
 struct vmw_ttm_tt {
        struct ttm_dma_tt dma_ttm;
        struct vmw_private *dev_priv;
        int gmr_id;
+       struct vmw_mob *mob;
+       int mem_type;
        struct sg_table sgt;
        struct vmw_sg_table vsgt;
        uint64_t sg_alloc_size;
@@ -244,6 +272,7 @@ void vmw_piter_start(struct vmw_piter *viter, const struct vmw_sg_table *vsgt,
                viter->dma_address = &__vmw_piter_dma_addr;
                viter->page = &__vmw_piter_non_sg_page;
                viter->addrs = vsgt->addrs;
+               viter->pages = vsgt->pages;
                break;
        case vmw_dma_map_populate:
        case vmw_dma_map_bind:
@@ -424,6 +453,63 @@ static void vmw_ttm_unmap_dma(struct vmw_ttm_tt *vmw_tt)
        vmw_tt->mapped = false;
 }
 
+
+/**
+ * vmw_bo_map_dma - Make sure buffer object pages are visible to the device
+ *
+ * @bo: Pointer to a struct ttm_buffer_object
+ *
+ * Wrapper around vmw_ttm_map_dma, that takes a TTM buffer object pointer
+ * instead of a pointer to a struct vmw_ttm_backend as argument.
+ * Note that the buffer object must be either pinned or reserved before
+ * calling this function.
+ */
+int vmw_bo_map_dma(struct ttm_buffer_object *bo)
+{
+       struct vmw_ttm_tt *vmw_tt =
+               container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
+
+       return vmw_ttm_map_dma(vmw_tt);
+}
+
+
+/**
+ * vmw_bo_unmap_dma - Make sure buffer object pages are visible to the device
+ *
+ * @bo: Pointer to a struct ttm_buffer_object
+ *
+ * Wrapper around vmw_ttm_unmap_dma, that takes a TTM buffer object pointer
+ * instead of a pointer to a struct vmw_ttm_backend as argument.
+ */
+void vmw_bo_unmap_dma(struct ttm_buffer_object *bo)
+{
+       struct vmw_ttm_tt *vmw_tt =
+               container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
+
+       vmw_ttm_unmap_dma(vmw_tt);
+}
+
+
+/**
+ * vmw_bo_sg_table - Return a struct vmw_sg_table object for a
+ * TTM buffer object
+ *
+ * @bo: Pointer to a struct ttm_buffer_object
+ *
+ * Returns a pointer to a struct vmw_sg_table object. The object should
+ * not be freed after use.
+ * Note that for the device addresses to be valid, the buffer object must
+ * either be reserved or pinned.
+ */
+const struct vmw_sg_table *vmw_bo_sg_table(struct ttm_buffer_object *bo)
+{
+       struct vmw_ttm_tt *vmw_tt =
+               container_of(bo->ttm, struct vmw_ttm_tt, dma_ttm.ttm);
+
+       return &vmw_tt->vsgt;
+}
+
+
 static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
 {
        struct vmw_ttm_tt *vmw_be =
@@ -435,9 +521,27 @@ static int vmw_ttm_bind(struct ttm_tt *ttm, struct ttm_mem_reg *bo_mem)
                return ret;
 
        vmw_be->gmr_id = bo_mem->start;
+       vmw_be->mem_type = bo_mem->mem_type;
+
+       switch (bo_mem->mem_type) {
+       case VMW_PL_GMR:
+               return vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt,
+                                   ttm->num_pages, vmw_be->gmr_id);
+       case VMW_PL_MOB:
+               if (unlikely(vmw_be->mob == NULL)) {
+                       vmw_be->mob =
+                               vmw_mob_create(ttm->num_pages);
+                       if (unlikely(vmw_be->mob == NULL))
+                               return -ENOMEM;
+               }
 
-       return vmw_gmr_bind(vmw_be->dev_priv, &vmw_be->vsgt,
-                           ttm->num_pages, vmw_be->gmr_id);
+               return vmw_mob_bind(vmw_be->dev_priv, vmw_be->mob,
+                                   &vmw_be->vsgt, ttm->num_pages,
+                                   vmw_be->gmr_id);
+       default:
+               BUG();
+       }
+       return 0;
 }
 
 static int vmw_ttm_unbind(struct ttm_tt *ttm)
@@ -445,7 +549,16 @@ static int vmw_ttm_unbind(struct ttm_tt *ttm)
        struct vmw_ttm_tt *vmw_be =
                container_of(ttm, struct vmw_ttm_tt, dma_ttm.ttm);
 
-       vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
+       switch (vmw_be->mem_type) {
+       case VMW_PL_GMR:
+               vmw_gmr_unbind(vmw_be->dev_priv, vmw_be->gmr_id);
+               break;
+       case VMW_PL_MOB:
+               vmw_mob_unbind(vmw_be->dev_priv, vmw_be->mob);
+               break;
+       default:
+               BUG();
+       }
 
        if (vmw_be->dev_priv->map_mode == vmw_dma_map_bind)
                vmw_ttm_unmap_dma(vmw_be);
@@ -453,6 +566,7 @@ static int vmw_ttm_unbind(struct ttm_tt *ttm)
        return 0;
 }
 
+
 static void vmw_ttm_destroy(struct ttm_tt *ttm)
 {
        struct vmw_ttm_tt *vmw_be =
@@ -463,9 +577,14 @@ static void vmw_ttm_destroy(struct ttm_tt *ttm)
                ttm_dma_tt_fini(&vmw_be->dma_ttm);
        else
                ttm_tt_fini(ttm);
+
+       if (vmw_be->mob)
+               vmw_mob_destroy(vmw_be->mob);
+
        kfree(vmw_be);
 }
 
+
 static int vmw_ttm_populate(struct ttm_tt *ttm)
 {
        struct vmw_ttm_tt *vmw_tt =
@@ -500,6 +619,12 @@ static void vmw_ttm_unpopulate(struct ttm_tt *ttm)
        struct vmw_private *dev_priv = vmw_tt->dev_priv;
        struct ttm_mem_global *glob = vmw_mem_glob(dev_priv);
 
+
+       if (vmw_tt->mob) {
+               vmw_mob_destroy(vmw_tt->mob);
+               vmw_tt->mob = NULL;
+       }
+
        vmw_ttm_unmap_dma(vmw_tt);
        if (dev_priv->map_mode == vmw_dma_alloc_coherent) {
                size_t size =
@@ -517,7 +642,7 @@ static struct ttm_backend_func vmw_ttm_func = {
        .destroy = vmw_ttm_destroy,
 };
 
-struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev,
+static struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev,
                                 unsigned long size, uint32_t page_flags,
                                 struct page *dummy_read_page)
 {
@@ -530,6 +655,7 @@ struct ttm_tt *vmw_ttm_tt_create(struct ttm_bo_device *bdev,
 
        vmw_be->dma_ttm.ttm.func = &vmw_ttm_func;
        vmw_be->dev_priv = container_of(bdev, struct vmw_private, bdev);
+       vmw_be->mob = NULL;
 
        if (vmw_be->dev_priv->map_mode == vmw_dma_alloc_coherent)
                ret = ttm_dma_tt_init(&vmw_be->dma_ttm, bdev, size, page_flags,
@@ -546,12 +672,12 @@ out_no_init:
        return NULL;
 }
 
-int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
+static int vmw_invalidate_caches(struct ttm_bo_device *bdev, uint32_t flags)
 {
        return 0;
 }
 
-int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
+static int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                      struct ttm_mem_type_manager *man)
 {
        switch (type) {
@@ -571,6 +697,7 @@ int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
                man->default_caching = TTM_PL_FLAG_CACHED;
                break;
        case VMW_PL_GMR:
+       case VMW_PL_MOB:
                /*
                 * "Guest Memory Regions" is an aperture like feature with
                 *  one slot per bo. There is an upper limit of the number of
@@ -589,7 +716,7 @@ int vmw_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
        return 0;
 }
 
-void vmw_evict_flags(struct ttm_buffer_object *bo,
+static void vmw_evict_flags(struct ttm_buffer_object *bo,
                     struct ttm_placement *placement)
 {
        *placement = vmw_sys_placement;
@@ -618,6 +745,7 @@ static int vmw_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg
        switch (mem->mem_type) {
        case TTM_PL_SYSTEM:
        case VMW_PL_GMR:
+       case VMW_PL_MOB:
                return 0;
        case TTM_PL_VRAM:
                mem->bus.offset = mem->start << PAGE_SHIFT;
@@ -677,6 +805,38 @@ static int vmw_sync_obj_wait(void *sync_obj, bool lazy, bool interruptible)
                                  VMW_FENCE_WAIT_TIMEOUT);
 }
 
+/**
+ * vmw_move_notify - TTM move_notify_callback
+ *
+ * @bo:             The TTM buffer object about to move.
+ * @mem:            The truct ttm_mem_reg indicating to what memory
+ *                  region the move is taking place.
+ *
+ * Calls move_notify for all subsystems needing it.
+ * (currently only resources).
+ */
+static void vmw_move_notify(struct ttm_buffer_object *bo,
+                           struct ttm_mem_reg *mem)
+{
+       vmw_resource_move_notify(bo, mem);
+}
+
+
+/**
+ * vmw_swap_notify - TTM move_notify_callback
+ *
+ * @bo:             The TTM buffer object about to be swapped out.
+ */
+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);
+}
+
+
 struct ttm_bo_driver vmw_bo_driver = {
        .ttm_tt_create = &vmw_ttm_tt_create,
        .ttm_tt_populate = &vmw_ttm_populate,
@@ -691,8 +851,8 @@ struct ttm_bo_driver vmw_bo_driver = {
        .sync_obj_flush = vmw_sync_obj_flush,
        .sync_obj_unref = vmw_sync_obj_unref,
        .sync_obj_ref = vmw_sync_obj_ref,
-       .move_notify = NULL,
-       .swap_notify = NULL,
+       .move_notify = vmw_move_notify,
+       .swap_notify = vmw_swap_notify,
        .fault_reserve_notify = &vmw_ttm_fault_reserve_notify,
        .io_mem_reserve = &vmw_ttm_io_mem_reserve,
        .io_mem_free = &vmw_ttm_io_mem_free,
index 00ae0925aca87e17994288743e079852c0b14dc2..82c41daebc0e35be6fb3629b602a083a6520f6a3 100644 (file)
 struct vmw_user_context {
        struct ttm_base_object base;
        struct vmw_resource res;
+       struct vmw_ctx_binding_state cbs;
 };
 
+
+
+typedef int (*vmw_scrub_func)(struct vmw_ctx_bindinfo *);
+
 static void vmw_user_context_free(struct vmw_resource *res);
 static struct vmw_resource *
 vmw_user_context_base_to_res(struct ttm_base_object *base);
 
+static int vmw_gb_context_create(struct vmw_resource *res);
+static int vmw_gb_context_bind(struct vmw_resource *res,
+                              struct ttm_validate_buffer *val_buf);
+static int vmw_gb_context_unbind(struct vmw_resource *res,
+                                bool readback,
+                                struct ttm_validate_buffer *val_buf);
+static int vmw_gb_context_destroy(struct vmw_resource *res);
+static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi);
+static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi);
+static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi);
+static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs);
 static uint64_t vmw_user_context_size;
 
 static const struct vmw_user_resource_conv user_context_conv = {
@@ -62,6 +78,23 @@ static const struct vmw_res_func vmw_legacy_context_func = {
        .unbind = NULL
 };
 
+static const struct vmw_res_func vmw_gb_context_func = {
+       .res_type = vmw_res_context,
+       .needs_backup = true,
+       .may_evict = true,
+       .type_name = "guest backed contexts",
+       .backup_placement = &vmw_mob_placement,
+       .create = vmw_gb_context_create,
+       .destroy = vmw_gb_context_destroy,
+       .bind = vmw_gb_context_bind,
+       .unbind = vmw_gb_context_unbind
+};
+
+static const vmw_scrub_func vmw_scrub_funcs[vmw_ctx_binding_max] = {
+       [vmw_ctx_binding_shader] = vmw_context_scrub_shader,
+       [vmw_ctx_binding_rt] = vmw_context_scrub_render_target,
+       [vmw_ctx_binding_tex] = vmw_context_scrub_texture };
+
 /**
  * Context management:
  */
@@ -76,6 +109,16 @@ static void vmw_hw_context_destroy(struct vmw_resource *res)
        } *cmd;
 
 
+       if (res->func->destroy == vmw_gb_context_destroy) {
+               mutex_lock(&dev_priv->cmdbuf_mutex);
+               (void) vmw_gb_context_destroy(res);
+               if (dev_priv->pinned_bo != NULL &&
+                   !dev_priv->query_cid_valid)
+                       __vmw_execbuf_release_pinned_bo(dev_priv, NULL);
+               mutex_unlock(&dev_priv->cmdbuf_mutex);
+               return;
+       }
+
        vmw_execbuf_release_pinned_bo(dev_priv);
        cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
        if (unlikely(cmd == NULL)) {
@@ -92,6 +135,33 @@ static void vmw_hw_context_destroy(struct vmw_resource *res)
        vmw_3d_resource_dec(dev_priv, false);
 }
 
+static int vmw_gb_context_init(struct vmw_private *dev_priv,
+                              struct vmw_resource *res,
+                              void (*res_free) (struct vmw_resource *res))
+{
+       int ret;
+       struct vmw_user_context *uctx =
+               container_of(res, struct vmw_user_context, res);
+
+       ret = vmw_resource_init(dev_priv, res, true,
+                               res_free, &vmw_gb_context_func);
+       res->backup_size = SVGA3D_CONTEXT_DATA_SIZE;
+
+       if (unlikely(ret != 0)) {
+               if (res_free)
+                       res_free(res);
+               else
+                       kfree(res);
+               return ret;
+       }
+
+       memset(&uctx->cbs, 0, sizeof(uctx->cbs));
+       INIT_LIST_HEAD(&uctx->cbs.list);
+
+       vmw_resource_activate(res, vmw_hw_context_destroy);
+       return 0;
+}
+
 static int vmw_context_init(struct vmw_private *dev_priv,
                            struct vmw_resource *res,
                            void (*res_free) (struct vmw_resource *res))
@@ -103,6 +173,9 @@ static int vmw_context_init(struct vmw_private *dev_priv,
                SVGA3dCmdDefineContext body;
        } *cmd;
 
+       if (dev_priv->has_mob)
+               return vmw_gb_context_init(dev_priv, res, res_free);
+
        ret = vmw_resource_init(dev_priv, res, false,
                                res_free, &vmw_legacy_context_func);
 
@@ -154,6 +227,184 @@ struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv)
        return (ret == 0) ? res : NULL;
 }
 
+
+static int vmw_gb_context_create(struct vmw_resource *res)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       int ret;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDefineGBContext body;
+       } *cmd;
+
+       if (likely(res->id != -1))
+               return 0;
+
+       ret = vmw_resource_alloc_id(res);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed to allocate a context id.\n");
+               goto out_no_id;
+       }
+
+       if (unlikely(res->id >= VMWGFX_NUM_GB_CONTEXT)) {
+               ret = -EBUSY;
+               goto out_no_fifo;
+       }
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for context "
+                         "creation.\n");
+               ret = -ENOMEM;
+               goto out_no_fifo;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_DEFINE_GB_CONTEXT;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.cid = res->id;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       (void) vmw_3d_resource_inc(dev_priv, false);
+
+       return 0;
+
+out_no_fifo:
+       vmw_resource_release_id(res);
+out_no_id:
+       return ret;
+}
+
+static int vmw_gb_context_bind(struct vmw_resource *res,
+                              struct ttm_validate_buffer *val_buf)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBindGBContext body;
+       } *cmd;
+       struct ttm_buffer_object *bo = val_buf->bo;
+
+       BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for context "
+                         "binding.\n");
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.cid = res->id;
+       cmd->body.mobid = bo->mem.start;
+       cmd->body.validContents = res->backup_dirty;
+       res->backup_dirty = false;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       return 0;
+}
+
+static int vmw_gb_context_unbind(struct vmw_resource *res,
+                                bool readback,
+                                struct ttm_validate_buffer *val_buf)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct ttm_buffer_object *bo = val_buf->bo;
+       struct vmw_fence_obj *fence;
+       struct vmw_user_context *uctx =
+               container_of(res, struct vmw_user_context, res);
+
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdReadbackGBContext body;
+       } *cmd1;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBindGBContext body;
+       } *cmd2;
+       uint32_t submit_size;
+       uint8_t *cmd;
+
+
+       BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
+
+       mutex_lock(&dev_priv->binding_mutex);
+       vmw_context_binding_state_kill(&uctx->cbs);
+
+       submit_size = sizeof(*cmd2) + (readback ? sizeof(*cmd1) : 0);
+
+       cmd = vmw_fifo_reserve(dev_priv, submit_size);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for context "
+                         "unbinding.\n");
+               mutex_unlock(&dev_priv->binding_mutex);
+               return -ENOMEM;
+       }
+
+       cmd2 = (void *) cmd;
+       if (readback) {
+               cmd1 = (void *) cmd;
+               cmd1->header.id = SVGA_3D_CMD_READBACK_GB_CONTEXT;
+               cmd1->header.size = sizeof(cmd1->body);
+               cmd1->body.cid = res->id;
+               cmd2 = (void *) (&cmd1[1]);
+       }
+       cmd2->header.id = SVGA_3D_CMD_BIND_GB_CONTEXT;
+       cmd2->header.size = sizeof(cmd2->body);
+       cmd2->body.cid = res->id;
+       cmd2->body.mobid = SVGA3D_INVALID_ID;
+
+       vmw_fifo_commit(dev_priv, submit_size);
+       mutex_unlock(&dev_priv->binding_mutex);
+
+       /*
+        * Create a fence object and fence the backup buffer.
+        */
+
+       (void) vmw_execbuf_fence_commands(NULL, dev_priv,
+                                         &fence, NULL);
+
+       vmw_fence_single_bo(bo, fence);
+
+       if (likely(fence != NULL))
+               vmw_fence_obj_unreference(&fence);
+
+       return 0;
+}
+
+static int vmw_gb_context_destroy(struct vmw_resource *res)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDestroyGBContext body;
+       } *cmd;
+       struct vmw_user_context *uctx =
+               container_of(res, struct vmw_user_context, res);
+
+       BUG_ON(!list_empty(&uctx->cbs.list));
+
+       if (likely(res->id == -1))
+               return 0;
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for context "
+                         "destruction.\n");
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_DESTROY_GB_CONTEXT;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.cid = res->id;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       if (dev_priv->query_cid == res->id)
+               dev_priv->query_cid_valid = false;
+       vmw_resource_release_id(res);
+       vmw_3d_resource_dec(dev_priv, false);
+
+       return 0;
+}
+
 /**
  * User-space context management:
  */
@@ -272,3 +523,283 @@ out_unlock:
        return ret;
 
 }
+
+/**
+ * vmw_context_scrub_shader - scrub a shader binding from a context.
+ *
+ * @bi: single binding information.
+ */
+static int vmw_context_scrub_shader(struct vmw_ctx_bindinfo *bi)
+{
+       struct vmw_private *dev_priv = bi->ctx->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSetShader body;
+       } *cmd;
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for shader "
+                         "unbinding.\n");
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_SET_SHADER;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.cid = bi->ctx->id;
+       cmd->body.type = bi->i1.shader_type;
+       cmd->body.shid = SVGA3D_INVALID_ID;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       return 0;
+}
+
+/**
+ * vmw_context_scrub_render_target - scrub a render target binding
+ * from a context.
+ *
+ * @bi: single binding information.
+ */
+static int vmw_context_scrub_render_target(struct vmw_ctx_bindinfo *bi)
+{
+       struct vmw_private *dev_priv = bi->ctx->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSetRenderTarget body;
+       } *cmd;
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for render target "
+                         "unbinding.\n");
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_SETRENDERTARGET;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.cid = bi->ctx->id;
+       cmd->body.type = bi->i1.rt_type;
+       cmd->body.target.sid = SVGA3D_INVALID_ID;
+       cmd->body.target.face = 0;
+       cmd->body.target.mipmap = 0;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       return 0;
+}
+
+/**
+ * vmw_context_scrub_texture - scrub a texture binding from a context.
+ *
+ * @bi: single binding information.
+ *
+ * TODO: Possibly complement this function with a function that takes
+ * a list of texture bindings and combines them to a single command.
+ */
+static int vmw_context_scrub_texture(struct vmw_ctx_bindinfo *bi)
+{
+       struct vmw_private *dev_priv = bi->ctx->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               struct {
+                       SVGA3dCmdSetTextureState c;
+                       SVGA3dTextureState s1;
+               } body;
+       } *cmd;
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for texture "
+                         "unbinding.\n");
+               return -ENOMEM;
+       }
+
+
+       cmd->header.id = SVGA_3D_CMD_SETTEXTURESTATE;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.c.cid = bi->ctx->id;
+       cmd->body.s1.stage = bi->i1.texture_stage;
+       cmd->body.s1.name = SVGA3D_TS_BIND_TEXTURE;
+       cmd->body.s1.value = (uint32) SVGA3D_INVALID_ID;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       return 0;
+}
+
+/**
+ * vmw_context_binding_drop: Stop tracking a context binding
+ *
+ * @cb: Pointer to binding tracker storage.
+ *
+ * Stops tracking a context binding, and re-initializes its storage.
+ * Typically used when the context binding is replaced with a binding to
+ * another (or the same, for that matter) resource.
+ */
+static void vmw_context_binding_drop(struct vmw_ctx_binding *cb)
+{
+       list_del(&cb->ctx_list);
+       if (!list_empty(&cb->res_list))
+               list_del(&cb->res_list);
+       cb->bi.ctx = NULL;
+}
+
+/**
+ * vmw_context_binding_add: Start tracking a context binding
+ *
+ * @cbs: Pointer to the context binding state tracker.
+ * @bi: Information about the binding to track.
+ *
+ * Performs basic checks on the binding to make sure arguments are within
+ * bounds and then starts tracking the binding in the context binding
+ * state structure @cbs.
+ */
+int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs,
+                           const struct vmw_ctx_bindinfo *bi)
+{
+       struct vmw_ctx_binding *loc;
+
+       switch (bi->bt) {
+       case vmw_ctx_binding_rt:
+               if (unlikely((unsigned)bi->i1.rt_type >= SVGA3D_RT_MAX)) {
+                       DRM_ERROR("Illegal render target type %u.\n",
+                                 (unsigned) bi->i1.rt_type);
+                       return -EINVAL;
+               }
+               loc = &cbs->render_targets[bi->i1.rt_type];
+               break;
+       case vmw_ctx_binding_tex:
+               if (unlikely((unsigned)bi->i1.texture_stage >=
+                            SVGA3D_NUM_TEXTURE_UNITS)) {
+                       DRM_ERROR("Illegal texture/sampler unit %u.\n",
+                                 (unsigned) bi->i1.texture_stage);
+                       return -EINVAL;
+               }
+               loc = &cbs->texture_units[bi->i1.texture_stage];
+               break;
+       case vmw_ctx_binding_shader:
+               if (unlikely((unsigned)bi->i1.shader_type >=
+                            SVGA3D_SHADERTYPE_MAX)) {
+                       DRM_ERROR("Illegal shader type %u.\n",
+                                 (unsigned) bi->i1.shader_type);
+                       return -EINVAL;
+               }
+               loc = &cbs->shaders[bi->i1.shader_type];
+               break;
+       default:
+               BUG();
+       }
+
+       if (loc->bi.ctx != NULL)
+               vmw_context_binding_drop(loc);
+
+       loc->bi = *bi;
+       list_add_tail(&loc->ctx_list, &cbs->list);
+       INIT_LIST_HEAD(&loc->res_list);
+
+       return 0;
+}
+
+/**
+ * vmw_context_binding_transfer: Transfer a context binding tracking entry.
+ *
+ * @cbs: Pointer to the persistent context binding state tracker.
+ * @bi: Information about the binding to track.
+ *
+ */
+static void vmw_context_binding_transfer(struct vmw_ctx_binding_state *cbs,
+                                        const struct vmw_ctx_bindinfo *bi)
+{
+       struct vmw_ctx_binding *loc;
+
+       switch (bi->bt) {
+       case vmw_ctx_binding_rt:
+               loc = &cbs->render_targets[bi->i1.rt_type];
+               break;
+       case vmw_ctx_binding_tex:
+               loc = &cbs->texture_units[bi->i1.texture_stage];
+               break;
+       case vmw_ctx_binding_shader:
+               loc = &cbs->shaders[bi->i1.shader_type];
+               break;
+       default:
+               BUG();
+       }
+
+       if (loc->bi.ctx != NULL)
+               vmw_context_binding_drop(loc);
+
+       loc->bi = *bi;
+       list_add_tail(&loc->ctx_list, &cbs->list);
+       if (bi->res != NULL)
+               list_add_tail(&loc->res_list, &bi->res->binding_head);
+       else
+               INIT_LIST_HEAD(&loc->res_list);
+}
+
+/**
+ * vmw_context_binding_kill - Kill a binding on the device
+ * and stop tracking it.
+ *
+ * @cb: Pointer to binding tracker storage.
+ *
+ * Emits FIFO commands to scrub a binding represented by @cb.
+ * Then stops tracking the binding and re-initializes its storage.
+ */
+static void vmw_context_binding_kill(struct vmw_ctx_binding *cb)
+{
+       (void) vmw_scrub_funcs[cb->bi.bt](&cb->bi);
+       vmw_context_binding_drop(cb);
+}
+
+/**
+ * vmw_context_binding_state_kill - Kill all bindings associated with a
+ * struct vmw_ctx_binding state structure, and re-initialize the structure.
+ *
+ * @cbs: Pointer to the context binding state tracker.
+ *
+ * Emits commands to scrub all bindings associated with the
+ * context binding state tracker. Then re-initializes the whole structure.
+ */
+static void vmw_context_binding_state_kill(struct vmw_ctx_binding_state *cbs)
+{
+       struct vmw_ctx_binding *entry, *next;
+
+       list_for_each_entry_safe(entry, next, &cbs->list, ctx_list)
+               vmw_context_binding_kill(entry);
+}
+
+/**
+ * vmw_context_binding_res_list_kill - Kill all bindings on a
+ * resource binding list
+ *
+ * @head: list head of resource binding list
+ *
+ * Kills all bindings associated with a specific resource. Typically
+ * called before the resource is destroyed.
+ */
+void vmw_context_binding_res_list_kill(struct list_head *head)
+{
+       struct vmw_ctx_binding *entry, *next;
+
+       list_for_each_entry_safe(entry, next, head, res_list)
+               vmw_context_binding_kill(entry);
+}
+
+/**
+ * vmw_context_binding_state_transfer - Commit staged binding info
+ *
+ * @ctx: Pointer to context to commit the staged binding info to.
+ * @from: Staged binding info built during execbuf.
+ *
+ * Transfers binding info from a temporary structure to the persistent
+ * structure in the context. This can be done once commands
+ */
+void vmw_context_binding_state_transfer(struct vmw_resource *ctx,
+                                       struct vmw_ctx_binding_state *from)
+{
+       struct vmw_user_context *uctx =
+               container_of(ctx, struct vmw_user_context, res);
+       struct vmw_ctx_binding *entry, *next;
+
+       list_for_each_entry_safe(entry, next, &from->list, ctx_list)
+               vmw_context_binding_transfer(&uctx->cbs, &entry->bi);
+}
index d4e54fcc0acd3e778bd74d1488f898798c740c73..a75840211b3c9682da3be63df8a54385de238824 100644 (file)
@@ -290,8 +290,7 @@ void vmw_bo_get_guest_ptr(const struct ttm_buffer_object *bo,
 /**
  * vmw_bo_pin - Pin or unpin a buffer object without moving it.
  *
- * @bo: The buffer object. Must be reserved, and present either in VRAM
- * or GMR memory.
+ * @bo: The buffer object. Must be reserved.
  * @pin: Whether to pin or unpin.
  *
  */
@@ -303,10 +302,9 @@ void vmw_bo_pin(struct ttm_buffer_object *bo, bool pin)
        int ret;
 
        lockdep_assert_held(&bo->resv->lock.base);
-       BUG_ON(old_mem_type != TTM_PL_VRAM &&
-              old_mem_type != VMW_PL_GMR);
 
-       pl_flags = TTM_PL_FLAG_VRAM | VMW_PL_FLAG_GMR | TTM_PL_FLAG_CACHED;
+       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;
 
index c7a549694e59fb2614562627dcb7f167680babcd..9893328f8fdc04750ec78538c4cdb2ba89ddae30 100644 (file)
 #define DRM_IOCTL_VMW_UPDATE_LAYOUT                            \
        DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UPDATE_LAYOUT,       \
                 struct drm_vmw_update_layout_arg)
+#define DRM_IOCTL_VMW_CREATE_SHADER                            \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_CREATE_SHADER,      \
+                struct drm_vmw_shader_create_arg)
+#define DRM_IOCTL_VMW_UNREF_SHADER                             \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_UNREF_SHADER,        \
+                struct drm_vmw_shader_arg)
+#define DRM_IOCTL_VMW_GB_SURFACE_CREATE                                \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_CREATE,  \
+                union drm_vmw_gb_surface_create_arg)
+#define DRM_IOCTL_VMW_GB_SURFACE_REF                           \
+       DRM_IOWR(DRM_COMMAND_BASE + DRM_VMW_GB_SURFACE_REF,     \
+                union drm_vmw_gb_surface_reference_arg)
+#define DRM_IOCTL_VMW_SYNCCPU                                  \
+       DRM_IOW(DRM_COMMAND_BASE + DRM_VMW_SYNCCPU,             \
+                struct drm_vmw_synccpu_arg)
 
 /**
  * The core DRM version of this macro doesn't account for
@@ -177,6 +192,21 @@ static const struct drm_ioctl_desc vmw_ioctls[] = {
        VMW_IOCTL_DEF(VMW_UPDATE_LAYOUT,
                      vmw_kms_update_layout_ioctl,
                      DRM_MASTER | DRM_UNLOCKED),
+       VMW_IOCTL_DEF(VMW_CREATE_SHADER,
+                     vmw_shader_define_ioctl,
+                     DRM_AUTH | DRM_UNLOCKED),
+       VMW_IOCTL_DEF(VMW_UNREF_SHADER,
+                     vmw_shader_destroy_ioctl,
+                     DRM_AUTH | DRM_UNLOCKED),
+       VMW_IOCTL_DEF(VMW_GB_SURFACE_CREATE,
+                     vmw_gb_surface_define_ioctl,
+                     DRM_AUTH | DRM_UNLOCKED),
+       VMW_IOCTL_DEF(VMW_GB_SURFACE_REF,
+                     vmw_gb_surface_reference_ioctl,
+                     DRM_AUTH | DRM_UNLOCKED),
+       VMW_IOCTL_DEF(VMW_SYNCCPU,
+                     vmw_user_dmabuf_synccpu_ioctl,
+                     DRM_AUTH | DRM_UNLOCKED),
 };
 
 static struct pci_device_id vmw_pci_id_list[] = {
@@ -189,6 +219,7 @@ static int enable_fbdev = IS_ENABLED(CONFIG_DRM_VMWGFX_FBCON);
 static int vmw_force_iommu;
 static int vmw_restrict_iommu;
 static int vmw_force_coherent;
+static int vmw_restrict_dma_mask;
 
 static int vmw_probe(struct pci_dev *, const struct pci_device_id *);
 static void vmw_master_init(struct vmw_master *);
@@ -203,6 +234,8 @@ MODULE_PARM_DESC(restrict_iommu, "Try to limit IOMMU usage for TTM pages");
 module_param_named(restrict_iommu, vmw_restrict_iommu, int, 0600);
 MODULE_PARM_DESC(force_coherent, "Force coherent TTM pages");
 module_param_named(force_coherent, vmw_force_coherent, int, 0600);
+MODULE_PARM_DESC(restrict_dma_mask, "Restrict DMA mask to 44 bits with IOMMU");
+module_param_named(restrict_dma_mask, vmw_restrict_dma_mask, int, 0600);
 
 
 static void vmw_print_capabilities(uint32_t capabilities)
@@ -240,38 +273,52 @@ static void vmw_print_capabilities(uint32_t capabilities)
                DRM_INFO("  GMR2.\n");
        if (capabilities & SVGA_CAP_SCREEN_OBJECT_2)
                DRM_INFO("  Screen Object 2.\n");
+       if (capabilities & SVGA_CAP_COMMAND_BUFFERS)
+               DRM_INFO("  Command Buffers.\n");
+       if (capabilities & SVGA_CAP_CMD_BUFFERS_2)
+               DRM_INFO("  Command Buffers 2.\n");
+       if (capabilities & SVGA_CAP_GBOBJECTS)
+               DRM_INFO("  Guest Backed Resources.\n");
 }
 
-
 /**
- * vmw_execbuf_prepare_dummy_query - Initialize a query result structure at
- * the start of a buffer object.
+ * vmw_dummy_query_bo_create - create a bo to hold a dummy query result
  *
- * @dev_priv: The device private structure.
+ * @dev_priv: A device private structure.
  *
- * This function will idle the buffer using an uninterruptible wait, then
- * map the first page and initialize a pending occlusion query result structure,
- * Finally it will unmap the buffer.
+ * This function creates a small buffer object that holds the query
+ * result for dummy queries emitted as query barriers.
+ * The function will then map the first page and initialize a pending
+ * occlusion query result structure, Finally it will unmap the buffer.
+ * No interruptible waits are done within this function.
  *
- * TODO: Since we're only mapping a single page, we should optimize the map
- * to use kmap_atomic / iomap_atomic.
+ * Returns an error if bo creation or initialization fails.
  */
-static void vmw_dummy_query_bo_prepare(struct vmw_private *dev_priv)
+static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv)
 {
+       int ret;
+       struct ttm_buffer_object *bo;
        struct ttm_bo_kmap_obj map;
        volatile SVGA3dQueryResult *result;
        bool dummy;
-       int ret;
-       struct ttm_bo_device *bdev = &dev_priv->bdev;
-       struct ttm_buffer_object *bo = dev_priv->dummy_query_bo;
 
-       ttm_bo_reserve(bo, false, false, false, 0);
-       spin_lock(&bdev->fence_lock);
-       ret = ttm_bo_wait(bo, false, false, false);
-       spin_unlock(&bdev->fence_lock);
+       /*
+        * Create the bo as pinned, so that a tryreserve will
+        * immediately succeed. This is because we're the only
+        * user of the bo currently.
+        */
+       ret = ttm_bo_create(&dev_priv->bdev,
+                           PAGE_SIZE,
+                           ttm_bo_type_device,
+                           &vmw_sys_ne_placement,
+                           0, false, NULL,
+                           &bo);
+
        if (unlikely(ret != 0))
-               (void) vmw_fallback_wait(dev_priv, false, true, 0, false,
-                                        10*HZ);
+               return ret;
+
+       ret = ttm_bo_reserve(bo, false, true, false, 0);
+       BUG_ON(ret != 0);
 
        ret = ttm_bo_kmap(bo, 0, 1, &map);
        if (likely(ret == 0)) {
@@ -280,34 +327,19 @@ static void vmw_dummy_query_bo_prepare(struct vmw_private *dev_priv)
                result->state = SVGA3D_QUERYSTATE_PENDING;
                result->result32 = 0xff;
                ttm_bo_kunmap(&map);
-       } else
-               DRM_ERROR("Dummy query buffer map failed.\n");
+       }
+       vmw_bo_pin(bo, false);
        ttm_bo_unreserve(bo);
-}
 
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Dummy query buffer map failed.\n");
+               ttm_bo_unref(&bo);
+       } else
+               dev_priv->dummy_query_bo = bo;
 
-/**
- * vmw_dummy_query_bo_create - create a bo to hold a dummy query result
- *
- * @dev_priv: A device private structure.
- *
- * This function creates a small buffer object that holds the query
- * result for dummy queries emitted as query barriers.
- * No interruptible waits are done within this function.
- *
- * Returns an error if bo creation fails.
- */
-static int vmw_dummy_query_bo_create(struct vmw_private *dev_priv)
-{
-       return ttm_bo_create(&dev_priv->bdev,
-                            PAGE_SIZE,
-                            ttm_bo_type_device,
-                            &vmw_vram_sys_placement,
-                            0, false, NULL,
-                            &dev_priv->dummy_query_bo);
+       return ret;
 }
 
-
 static int vmw_request_device(struct vmw_private *dev_priv)
 {
        int ret;
@@ -318,14 +350,24 @@ static int vmw_request_device(struct vmw_private *dev_priv)
                return ret;
        }
        vmw_fence_fifo_up(dev_priv->fman);
+       if (dev_priv->has_mob) {
+               ret = vmw_otables_setup(dev_priv);
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("Unable to initialize "
+                                 "guest Memory OBjects.\n");
+                       goto out_no_mob;
+               }
+       }
        ret = vmw_dummy_query_bo_create(dev_priv);
        if (unlikely(ret != 0))
                goto out_no_query_bo;
-       vmw_dummy_query_bo_prepare(dev_priv);
 
        return 0;
 
 out_no_query_bo:
+       if (dev_priv->has_mob)
+               vmw_otables_takedown(dev_priv);
+out_no_mob:
        vmw_fence_fifo_down(dev_priv->fman);
        vmw_fifo_release(dev_priv, &dev_priv->fifo);
        return ret;
@@ -341,10 +383,13 @@ static void vmw_release_device(struct vmw_private *dev_priv)
        BUG_ON(dev_priv->pinned_bo != NULL);
 
        ttm_bo_unref(&dev_priv->dummy_query_bo);
+       if (dev_priv->has_mob)
+               vmw_otables_takedown(dev_priv);
        vmw_fence_fifo_down(dev_priv->fman);
        vmw_fifo_release(dev_priv, &dev_priv->fifo);
 }
 
+
 /**
  * Increase the 3d resource refcount.
  * If the count was prevously zero, initialize the fifo, switching to svga
@@ -510,6 +555,33 @@ out_fixup:
        return 0;
 }
 
+/**
+ * vmw_dma_masks - set required page- and dma masks
+ *
+ * @dev: Pointer to struct drm-device
+ *
+ * With 32-bit we can only handle 32 bit PFNs. Optionally set that
+ * restriction also for 64-bit systems.
+ */
+#ifdef CONFIG_INTEL_IOMMU
+static int vmw_dma_masks(struct vmw_private *dev_priv)
+{
+       struct drm_device *dev = dev_priv->dev;
+
+       if (intel_iommu_enabled &&
+           (sizeof(unsigned long) == 4 || vmw_restrict_dma_mask)) {
+               DRM_INFO("Restricting DMA addresses to 44 bits.\n");
+               return dma_set_mask(dev->dev, DMA_BIT_MASK(44));
+       }
+       return 0;
+}
+#else
+static int vmw_dma_masks(struct vmw_private *dev_priv)
+{
+       return 0;
+}
+#endif
+
 static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 {
        struct vmw_private *dev_priv;
@@ -532,6 +604,7 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        mutex_init(&dev_priv->hw_mutex);
        mutex_init(&dev_priv->cmdbuf_mutex);
        mutex_init(&dev_priv->release_mutex);
+       mutex_init(&dev_priv->binding_mutex);
        rwlock_init(&dev_priv->resource_lock);
 
        for (i = vmw_res_context; i < vmw_res_max; ++i) {
@@ -578,14 +651,9 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
 
        vmw_get_initial_size(dev_priv);
 
-       if (dev_priv->capabilities & SVGA_CAP_GMR) {
-               dev_priv->max_gmr_descriptors =
-                       vmw_read(dev_priv,
-                                SVGA_REG_GMR_MAX_DESCRIPTOR_LENGTH);
+       if (dev_priv->capabilities & SVGA_CAP_GMR2) {
                dev_priv->max_gmr_ids =
                        vmw_read(dev_priv, SVGA_REG_GMR_MAX_IDS);
-       }
-       if (dev_priv->capabilities & SVGA_CAP_GMR2) {
                dev_priv->max_gmr_pages =
                        vmw_read(dev_priv, SVGA_REG_GMRS_MAX_PAGES);
                dev_priv->memory_size =
@@ -598,23 +666,42 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
                 */
                dev_priv->memory_size = 512*1024*1024;
        }
+       dev_priv->max_mob_pages = 0;
+       if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
+               uint64_t mem_size =
+                       vmw_read(dev_priv,
+                                SVGA_REG_SUGGESTED_GBOBJECT_MEM_SIZE_KB);
+
+               dev_priv->max_mob_pages = mem_size * 1024 / PAGE_SIZE;
+               dev_priv->prim_bb_mem =
+                       vmw_read(dev_priv,
+                                SVGA_REG_MAX_PRIMARY_BOUNDING_BOX_MEM);
+       } else
+               dev_priv->prim_bb_mem = dev_priv->vram_size;
+
+       ret = vmw_dma_masks(dev_priv);
+       if (unlikely(ret != 0)) {
+               mutex_unlock(&dev_priv->hw_mutex);
+               goto out_err0;
+       }
+
+       if (unlikely(dev_priv->prim_bb_mem < dev_priv->vram_size))
+               dev_priv->prim_bb_mem = dev_priv->vram_size;
 
        mutex_unlock(&dev_priv->hw_mutex);
 
        vmw_print_capabilities(dev_priv->capabilities);
 
-       if (dev_priv->capabilities & SVGA_CAP_GMR) {
+       if (dev_priv->capabilities & SVGA_CAP_GMR2) {
                DRM_INFO("Max GMR ids is %u\n",
                         (unsigned)dev_priv->max_gmr_ids);
-               DRM_INFO("Max GMR descriptors is %u\n",
-                        (unsigned)dev_priv->max_gmr_descriptors);
-       }
-       if (dev_priv->capabilities & SVGA_CAP_GMR2) {
                DRM_INFO("Max number of GMR pages is %u\n",
                         (unsigned)dev_priv->max_gmr_pages);
                DRM_INFO("Max dedicated hypervisor surface memory is %u kiB\n",
                         (unsigned)dev_priv->memory_size / 1024);
        }
+       DRM_INFO("Maximum display memory size is %u kiB\n",
+                dev_priv->prim_bb_mem / 1024);
        DRM_INFO("VRAM at 0x%08x size is %u kiB\n",
                 dev_priv->vram_start, dev_priv->vram_size / 1024);
        DRM_INFO("MMIO at 0x%08x size is %u kiB\n",
@@ -649,12 +736,22 @@ static int vmw_driver_load(struct drm_device *dev, unsigned long chipset)
        dev_priv->has_gmr = true;
        if (((dev_priv->capabilities & (SVGA_CAP_GMR | SVGA_CAP_GMR2)) == 0) ||
            refuse_dma || ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_GMR,
-                                        dev_priv->max_gmr_ids) != 0) {
+                                        VMW_PL_GMR) != 0) {
                DRM_INFO("No GMR memory available. "
                         "Graphics memory resources are very limited.\n");
                dev_priv->has_gmr = false;
        }
 
+       if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
+               dev_priv->has_mob = true;
+               if (ttm_bo_init_mm(&dev_priv->bdev, VMW_PL_MOB,
+                                  VMW_PL_MOB) != 0) {
+                       DRM_INFO("No MOB memory available. "
+                                "3D will be disabled.\n");
+                       dev_priv->has_mob = false;
+               }
+       }
+
        dev_priv->mmio_mtrr = arch_phys_wc_add(dev_priv->mmio_start,
                                               dev_priv->mmio_size);
 
@@ -757,6 +854,8 @@ out_err4:
        iounmap(dev_priv->mmio_virt);
 out_err3:
        arch_phys_wc_del(dev_priv->mmio_mtrr);
+       if (dev_priv->has_mob)
+               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
        if (dev_priv->has_gmr)
                (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
        (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
@@ -801,6 +900,8 @@ static int vmw_driver_unload(struct drm_device *dev)
        ttm_object_device_release(&dev_priv->tdev);
        iounmap(dev_priv->mmio_virt);
        arch_phys_wc_del(dev_priv->mmio_mtrr);
+       if (dev_priv->has_mob)
+               (void) ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_MOB);
        if (dev_priv->has_gmr)
                (void)ttm_bo_clean_mm(&dev_priv->bdev, VMW_PL_GMR);
        (void)ttm_bo_clean_mm(&dev_priv->bdev, TTM_PL_VRAM);
index 20890ad8408bb5ef377c4ff54c80397c3105efaf..554e7fa330824cc7a2f1d728f4299c19c8ab8fb5 100644 (file)
@@ -40,9 +40,9 @@
 #include <drm/ttm/ttm_module.h>
 #include "vmwgfx_fence.h"
 
-#define VMWGFX_DRIVER_DATE "20120209"
+#define VMWGFX_DRIVER_DATE "20121114"
 #define VMWGFX_DRIVER_MAJOR 2
-#define VMWGFX_DRIVER_MINOR 4
+#define VMWGFX_DRIVER_MINOR 5
 #define VMWGFX_DRIVER_PATCHLEVEL 0
 #define VMWGFX_FILE_PAGE_OFFSET 0x00100000
 #define VMWGFX_FIFO_STATIC_SIZE (1024*1024)
 #define VMWGFX_MAX_VALIDATIONS 2048
 #define VMWGFX_MAX_DISPLAYS 16
 #define VMWGFX_CMD_BOUNCE_INIT_SIZE 32768
+#define VMWGFX_ENABLE_SCREEN_TARGET_OTABLE 0
+
+/*
+ * Perhaps we should have sysfs entries for these.
+ */
+#define VMWGFX_NUM_GB_CONTEXT 256
+#define VMWGFX_NUM_GB_SHADER 20000
+#define VMWGFX_NUM_GB_SURFACE 32768
+#define VMWGFX_NUM_GB_SCREEN_TARGET VMWGFX_MAX_DISPLAYS
+#define VMWGFX_NUM_MOB (VMWGFX_NUM_GB_CONTEXT +\
+                       VMWGFX_NUM_GB_SHADER +\
+                       VMWGFX_NUM_GB_SURFACE +\
+                       VMWGFX_NUM_GB_SCREEN_TARGET)
 
 #define VMW_PL_GMR TTM_PL_PRIV0
 #define VMW_PL_FLAG_GMR TTM_PL_FLAG_PRIV0
+#define VMW_PL_MOB TTM_PL_PRIV1
+#define VMW_PL_FLAG_MOB TTM_PL_FLAG_PRIV1
 
 #define VMW_RES_CONTEXT ttm_driver_type0
 #define VMW_RES_SURFACE ttm_driver_type1
 #define VMW_RES_STREAM ttm_driver_type2
 #define VMW_RES_FENCE ttm_driver_type3
+#define VMW_RES_SHADER ttm_driver_type4
 
 struct vmw_fpriv {
        struct drm_master *locked_master;
@@ -82,6 +98,7 @@ struct vmw_dma_buffer {
 struct vmw_validate_buffer {
        struct ttm_validate_buffer base;
        struct drm_hash_item hash;
+       bool validate_as_mob;
 };
 
 struct vmw_res_func;
@@ -98,6 +115,7 @@ struct vmw_resource {
        const struct vmw_res_func *func;
        struct list_head lru_head; /* Protected by the resource lock */
        struct list_head mob_head; /* Protected by @backup reserved */
+       struct list_head binding_head; /* Protected by binding_mutex */
        void (*res_free) (struct vmw_resource *res);
        void (*hw_destroy) (struct vmw_resource *res);
 };
@@ -106,6 +124,7 @@ enum vmw_res_type {
        vmw_res_context,
        vmw_res_surface,
        vmw_res_stream,
+       vmw_res_shader,
        vmw_res_max
 };
 
@@ -154,6 +173,7 @@ struct vmw_fifo_state {
 };
 
 struct vmw_relocation {
+       SVGAMobId *mob_loc;
        SVGAGuestPtr *location;
        uint32_t index;
 };
@@ -229,6 +249,71 @@ struct vmw_piter {
        struct page *(*page)(struct vmw_piter *);
 };
 
+/*
+ * enum vmw_ctx_binding_type - abstract resource to context binding types
+ */
+enum vmw_ctx_binding_type {
+       vmw_ctx_binding_shader,
+       vmw_ctx_binding_rt,
+       vmw_ctx_binding_tex,
+       vmw_ctx_binding_max
+};
+
+/**
+ * struct vmw_ctx_bindinfo - structure representing a single context binding
+ *
+ * @ctx: Pointer to the context structure. NULL means the binding is not
+ * active.
+ * @res: Non ref-counted pointer to the bound resource.
+ * @bt: The binding type.
+ * @i1: Union of information needed to unbind.
+ */
+struct vmw_ctx_bindinfo {
+       struct vmw_resource *ctx;
+       struct vmw_resource *res;
+       enum vmw_ctx_binding_type bt;
+       union {
+               SVGA3dShaderType shader_type;
+               SVGA3dRenderTargetType rt_type;
+               uint32 texture_stage;
+       } i1;
+};
+
+/**
+ * struct vmw_ctx_binding - structure representing a single context binding
+ *                        - suitable for tracking in a context
+ *
+ * @ctx_list: List head for context.
+ * @res_list: List head for bound resource.
+ * @bi: Binding info
+ */
+struct vmw_ctx_binding {
+       struct list_head ctx_list;
+       struct list_head res_list;
+       struct vmw_ctx_bindinfo bi;
+};
+
+
+/**
+ * struct vmw_ctx_binding_state - context binding state
+ *
+ * @list: linked list of individual bindings.
+ * @render_targets: Render target bindings.
+ * @texture_units: Texture units/samplers bindings.
+ * @shaders: Shader bindings.
+ *
+ * Note that this structure also provides storage space for the individual
+ * struct vmw_ctx_binding objects, so that no dynamic allocation is needed
+ * for individual bindings.
+ *
+ */
+struct vmw_ctx_binding_state {
+       struct list_head list;
+       struct vmw_ctx_binding render_targets[SVGA3D_RT_MAX];
+       struct vmw_ctx_binding texture_units[SVGA3D_NUM_TEXTURE_UNITS];
+       struct vmw_ctx_binding shaders[SVGA3D_SHADERTYPE_MAX];
+};
+
 struct vmw_sw_context{
        struct drm_open_hash res_ht;
        bool res_ht_initialized;
@@ -250,6 +335,7 @@ struct vmw_sw_context{
        struct vmw_resource *last_query_ctx;
        bool needs_post_query_barrier;
        struct vmw_resource *error_resource;
+       struct vmw_ctx_binding_state staged_bindings;
 };
 
 struct vmw_legacy_display;
@@ -281,6 +367,7 @@ struct vmw_private {
        unsigned int io_start;
        uint32_t vram_start;
        uint32_t vram_size;
+       uint32_t prim_bb_mem;
        uint32_t mmio_start;
        uint32_t mmio_size;
        uint32_t fb_max_width;
@@ -290,11 +377,12 @@ struct vmw_private {
        __le32 __iomem *mmio_virt;
        int mmio_mtrr;
        uint32_t capabilities;
-       uint32_t max_gmr_descriptors;
        uint32_t max_gmr_ids;
        uint32_t max_gmr_pages;
+       uint32_t max_mob_pages;
        uint32_t memory_size;
        bool has_gmr;
+       bool has_mob;
        struct mutex hw_mutex;
 
        /*
@@ -370,6 +458,7 @@ struct vmw_private {
 
        struct vmw_sw_context ctx;
        struct mutex cmdbuf_mutex;
+       struct mutex binding_mutex;
 
        /**
         * Operating mode.
@@ -415,6 +504,12 @@ struct vmw_private {
         * DMA mapping stuff.
         */
        enum vmw_dma_map_mode map_mode;
+
+       /*
+        * Guest Backed stuff
+        */
+       struct ttm_buffer_object *otable_bo;
+       struct vmw_otable *otables;
 };
 
 static inline struct vmw_surface *vmw_res_to_srf(struct vmw_resource *res)
@@ -471,23 +566,12 @@ extern void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id);
  * Resource utilities - vmwgfx_resource.c
  */
 struct vmw_user_resource_conv;
-extern const struct vmw_user_resource_conv *user_surface_converter;
-extern const struct vmw_user_resource_conv *user_context_converter;
 
-extern struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv);
 extern void vmw_resource_unreference(struct vmw_resource **p_res);
 extern struct vmw_resource *vmw_resource_reference(struct vmw_resource *res);
 extern int vmw_resource_validate(struct vmw_resource *res);
 extern int vmw_resource_reserve(struct vmw_resource *res, bool no_backup);
 extern bool vmw_resource_needs_backup(const struct vmw_resource *res);
-extern int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
-                                    struct drm_file *file_priv);
-extern int vmw_context_define_ioctl(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv);
-extern int vmw_context_check(struct vmw_private *dev_priv,
-                            struct ttm_object_file *tfile,
-                            int id,
-                            struct vmw_resource **p_res);
 extern int vmw_user_lookup_handle(struct vmw_private *dev_priv,
                                  struct ttm_object_file *tfile,
                                  uint32_t handle,
@@ -499,18 +583,6 @@ extern int vmw_user_resource_lookup_handle(
        uint32_t handle,
        const struct vmw_user_resource_conv *converter,
        struct vmw_resource **p_res);
-extern void vmw_surface_res_free(struct vmw_resource *res);
-extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
-                                    struct drm_file *file_priv);
-extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
-                                   struct drm_file *file_priv);
-extern int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
-                                      struct drm_file *file_priv);
-extern int vmw_surface_check(struct vmw_private *dev_priv,
-                            struct ttm_object_file *tfile,
-                            uint32_t handle, int *id);
-extern int vmw_surface_validate(struct vmw_private *dev_priv,
-                               struct vmw_surface *srf);
 extern void vmw_dmabuf_bo_free(struct ttm_buffer_object *bo);
 extern int vmw_dmabuf_init(struct vmw_private *dev_priv,
                           struct vmw_dma_buffer *vmw_bo,
@@ -519,10 +591,21 @@ extern int vmw_dmabuf_init(struct vmw_private *dev_priv,
                           void (*bo_free) (struct ttm_buffer_object *bo));
 extern int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo,
                                  struct ttm_object_file *tfile);
+extern int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
+                                struct ttm_object_file *tfile,
+                                uint32_t size,
+                                bool shareable,
+                                uint32_t *handle,
+                                struct vmw_dma_buffer **p_dma_buf);
+extern int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
+                                    struct vmw_dma_buffer *dma_buf,
+                                    uint32_t *handle);
 extern int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file_priv);
 extern int vmw_dmabuf_unref_ioctl(struct drm_device *dev, void *data,
                                  struct drm_file *file_priv);
+extern int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data,
+                                        struct drm_file *file_priv);
 extern uint32_t vmw_dmabuf_validate_node(struct ttm_buffer_object *bo,
                                         uint32_t cur_validate_node);
 extern void vmw_dmabuf_validate_clear(struct ttm_buffer_object *bo);
@@ -622,10 +705,16 @@ extern struct ttm_placement vmw_vram_sys_placement;
 extern struct ttm_placement vmw_vram_gmr_placement;
 extern struct ttm_placement vmw_vram_gmr_ne_placement;
 extern struct ttm_placement vmw_sys_placement;
+extern struct ttm_placement vmw_sys_ne_placement;
 extern struct ttm_placement vmw_evictable_placement;
 extern struct ttm_placement vmw_srf_placement;
+extern struct ttm_placement vmw_mob_placement;
 extern struct ttm_bo_driver vmw_bo_driver;
 extern int vmw_dma_quiescent(struct drm_device *dev);
+extern int vmw_bo_map_dma(struct ttm_buffer_object *bo);
+extern void vmw_bo_unmap_dma(struct ttm_buffer_object *bo);
+extern const struct vmw_sg_table *
+vmw_bo_sg_table(struct ttm_buffer_object *bo);
 extern void vmw_piter_start(struct vmw_piter *viter,
                            const struct vmw_sg_table *vsgt,
                            unsigned long p_offs);
@@ -701,7 +790,7 @@ extern void vmw_execbuf_copy_fence_user(struct vmw_private *dev_priv,
  * IRQs and wating - vmwgfx_irq.c
  */
 
-extern irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS);
+extern irqreturn_t vmw_irq_handler(int irq, void *arg);
 extern int vmw_wait_seqno(struct vmw_private *dev_priv, bool lazy,
                             uint32_t seqno, bool interruptible,
                             unsigned long timeout);
@@ -832,6 +921,76 @@ extern int vmw_prime_handle_to_fd(struct drm_device *dev,
                                  uint32_t handle, uint32_t flags,
                                  int *prime_fd);
 
+/*
+ * MemoryOBject management -  vmwgfx_mob.c
+ */
+struct vmw_mob;
+extern int vmw_mob_bind(struct vmw_private *dev_priv, struct vmw_mob *mob,
+                       const struct vmw_sg_table *vsgt,
+                       unsigned long num_data_pages, int32_t mob_id);
+extern void vmw_mob_unbind(struct vmw_private *dev_priv,
+                          struct vmw_mob *mob);
+extern void vmw_mob_destroy(struct vmw_mob *mob);
+extern struct vmw_mob *vmw_mob_create(unsigned long data_pages);
+extern int vmw_otables_setup(struct vmw_private *dev_priv);
+extern void vmw_otables_takedown(struct vmw_private *dev_priv);
+
+/*
+ * Context management - vmwgfx_context.c
+ */
+
+extern const struct vmw_user_resource_conv *user_context_converter;
+
+extern struct vmw_resource *vmw_context_alloc(struct vmw_private *dev_priv);
+
+extern int vmw_context_check(struct vmw_private *dev_priv,
+                            struct ttm_object_file *tfile,
+                            int id,
+                            struct vmw_resource **p_res);
+extern int vmw_context_define_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
+extern int vmw_context_destroy_ioctl(struct drm_device *dev, void *data,
+                                    struct drm_file *file_priv);
+extern int vmw_context_binding_add(struct vmw_ctx_binding_state *cbs,
+                                  const struct vmw_ctx_bindinfo *ci);
+extern void
+vmw_context_binding_state_transfer(struct vmw_resource *res,
+                                  struct vmw_ctx_binding_state *cbs);
+extern void vmw_context_binding_res_list_kill(struct list_head *head);
+
+/*
+ * Surface management - vmwgfx_surface.c
+ */
+
+extern const struct vmw_user_resource_conv *user_surface_converter;
+
+extern void vmw_surface_res_free(struct vmw_resource *res);
+extern int vmw_surface_destroy_ioctl(struct drm_device *dev, void *data,
+                                    struct drm_file *file_priv);
+extern int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
+extern int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
+                                      struct drm_file *file_priv);
+extern int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
+                                      struct drm_file *file_priv);
+extern int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
+                                         struct drm_file *file_priv);
+extern int vmw_surface_check(struct vmw_private *dev_priv,
+                            struct ttm_object_file *tfile,
+                            uint32_t handle, int *id);
+extern int vmw_surface_validate(struct vmw_private *dev_priv,
+                               struct vmw_surface *srf);
+
+/*
+ * Shader management - vmwgfx_shader.c
+ */
+
+extern const struct vmw_user_resource_conv *user_shader_converter;
+
+extern int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
+                                  struct drm_file *file_priv);
+extern int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
+                                   struct drm_file *file_priv);
 
 /**
  * Inline helper functions
index 599f6469a1ebb00c10b3d8047c44882aebd779d8..7a5f1eb55c5a0ad09adf8aa02c92367908c49c24 100644 (file)
@@ -54,6 +54,8 @@ struct vmw_resource_relocation {
  * @res: Ref-counted pointer to the resource.
  * @switch_backup: Boolean whether to switch backup buffer on unreserve.
  * @new_backup: Refcounted pointer to the new backup buffer.
+ * @staged_bindings: If @res is a context, tracks bindings set up during
+ * the command batch. Otherwise NULL.
  * @new_backup_offset: New backup buffer offset if @new_backup is non-NUll.
  * @first_usage: Set to true the first time the resource is referenced in
  * the command stream.
@@ -65,11 +67,31 @@ struct vmw_resource_val_node {
        struct drm_hash_item hash;
        struct vmw_resource *res;
        struct vmw_dma_buffer *new_backup;
+       struct vmw_ctx_binding_state *staged_bindings;
        unsigned long new_backup_offset;
        bool first_usage;
        bool no_buffer_needed;
 };
 
+/**
+ * struct vmw_cmd_entry - Describe a command for the verifier
+ *
+ * @user_allow: Whether allowed from the execbuf ioctl.
+ * @gb_disable: Whether disabled if guest-backed objects are available.
+ * @gb_enable: Whether enabled iff guest-backed objects are available.
+ */
+struct vmw_cmd_entry {
+       int (*func) (struct vmw_private *, struct vmw_sw_context *,
+                    SVGA3dCmdHeader *);
+       bool user_allow;
+       bool gb_disable;
+       bool gb_enable;
+};
+
+#define VMW_CMD_DEF(_cmd, _func, _user_allow, _gb_disable, _gb_enable) \
+       [(_cmd) - SVGA_3D_CMD_BASE] = {(_func), (_user_allow),\
+                                      (_gb_disable), (_gb_enable)}
+
 /**
  * vmw_resource_unreserve - unreserve resources previously reserved for
  * command submission.
@@ -87,6 +109,16 @@ static void vmw_resource_list_unreserve(struct list_head *list,
                struct vmw_dma_buffer *new_backup =
                        backoff ? NULL : val->new_backup;
 
+               /*
+                * Transfer staged context bindings to the
+                * persistent context binding tracker.
+                */
+               if (unlikely(val->staged_bindings)) {
+                       vmw_context_binding_state_transfer
+                               (val->res, val->staged_bindings);
+                       kfree(val->staged_bindings);
+                       val->staged_bindings = NULL;
+               }
                vmw_resource_unreserve(res, new_backup,
                        val->new_backup_offset);
                vmw_dmabuf_unreference(&val->new_backup);
@@ -224,6 +256,7 @@ static int vmw_cmd_ok(struct vmw_private *dev_priv,
  *
  * @sw_context: The software context used for this command submission batch.
  * @bo: The buffer object to add.
+ * @validate_as_mob: Validate this buffer as a MOB.
  * @p_val_node: If non-NULL Will be updated with the validate node number
  * on return.
  *
@@ -232,6 +265,7 @@ static int vmw_cmd_ok(struct vmw_private *dev_priv,
  */
 static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
                                   struct ttm_buffer_object *bo,
+                                  bool validate_as_mob,
                                   uint32_t *p_val_node)
 {
        uint32_t val_node;
@@ -244,6 +278,10 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
                                    &hash) == 0)) {
                vval_buf = container_of(hash, struct vmw_validate_buffer,
                                        hash);
+               if (unlikely(vval_buf->validate_as_mob != validate_as_mob)) {
+                       DRM_ERROR("Inconsistent buffer usage.\n");
+                       return -EINVAL;
+               }
                val_buf = &vval_buf->base;
                val_node = vval_buf - sw_context->val_bufs;
        } else {
@@ -266,6 +304,7 @@ static int vmw_bo_to_validate_list(struct vmw_sw_context *sw_context,
                val_buf->bo = ttm_bo_reference(bo);
                val_buf->reserved = 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;
@@ -302,7 +341,8 @@ static int vmw_resources_reserve(struct vmw_sw_context *sw_context)
                        struct ttm_buffer_object *bo = &res->backup->base;
 
                        ret = vmw_bo_to_validate_list
-                               (sw_context, bo, NULL);
+                               (sw_context, bo,
+                                vmw_resource_needs_backup(res), NULL);
 
                        if (unlikely(ret != 0))
                                return ret;
@@ -362,8 +402,15 @@ static int vmw_cmd_res_check(struct vmw_private *dev_priv,
        struct vmw_resource_val_node *node;
        int ret;
 
-       if (*id == SVGA3D_INVALID_ID)
+       if (*id == SVGA3D_INVALID_ID) {
+               if (p_val)
+                       *p_val = NULL;
+               if (res_type == vmw_res_context) {
+                       DRM_ERROR("Illegal context invalid id.\n");
+                       return -EINVAL;
+               }
                return 0;
+       }
 
        /*
         * Fastpath in case of repeated commands referencing the same
@@ -411,6 +458,18 @@ static int vmw_cmd_res_check(struct vmw_private *dev_priv,
        rcache->node = node;
        if (p_val)
                *p_val = node;
+
+       if (node->first_usage && res_type == vmw_res_context) {
+               node->staged_bindings =
+                       kzalloc(sizeof(*node->staged_bindings), GFP_KERNEL);
+               if (node->staged_bindings == NULL) {
+                       DRM_ERROR("Failed to allocate context binding "
+                                 "information.\n");
+                       goto out_no_reloc;
+               }
+               INIT_LIST_HEAD(&node->staged_bindings->list);
+       }
+
        vmw_resource_unreference(&res);
        return 0;
 
@@ -453,17 +512,35 @@ static int vmw_cmd_set_render_target_check(struct vmw_private *dev_priv,
                SVGA3dCmdHeader header;
                SVGA3dCmdSetRenderTarget body;
        } *cmd;
+       struct vmw_resource_val_node *ctx_node;
+       struct vmw_resource_val_node *res_node;
        int ret;
 
-       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       cmd = container_of(header, struct vmw_sid_cmd, header);
+
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
+                               user_context_converter, &cmd->body.cid,
+                               &ctx_node);
        if (unlikely(ret != 0))
                return ret;
 
-       cmd = container_of(header, struct vmw_sid_cmd, header);
        ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
                                user_surface_converter,
-                               &cmd->body.target.sid, NULL);
-       return ret;
+                               &cmd->body.target.sid, &res_node);
+       if (unlikely(ret != 0))
+               return ret;
+
+       if (dev_priv->has_mob) {
+               struct vmw_ctx_bindinfo bi;
+
+               bi.ctx = ctx_node->res;
+               bi.res = res_node ? res_node->res : NULL;
+               bi.bt = vmw_ctx_binding_rt;
+               bi.i1.rt_type = cmd->body.type;
+               return vmw_context_binding_add(ctx_node->staged_bindings, &bi);
+       }
+
+       return 0;
 }
 
 static int vmw_cmd_surface_copy_check(struct vmw_private *dev_priv,
@@ -519,11 +596,6 @@ static int vmw_cmd_blt_surf_screen_check(struct vmw_private *dev_priv,
 
        cmd = container_of(header, struct vmw_sid_cmd, header);
 
-       if (unlikely(!sw_context->kernel)) {
-               DRM_ERROR("Kernel only SVGA3d command: %u.\n", cmd->header.id);
-               return -EPERM;
-       }
-
        return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
                                 user_surface_converter,
                                 &cmd->body.srcImage.sid, NULL);
@@ -541,11 +613,6 @@ static int vmw_cmd_present_check(struct vmw_private *dev_priv,
 
        cmd = container_of(header, struct vmw_sid_cmd, header);
 
-       if (unlikely(!sw_context->kernel)) {
-               DRM_ERROR("Kernel only SVGA3d command: %u.\n", cmd->header.id);
-               return -EPERM;
-       }
-
        return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
                                 user_surface_converter, &cmd->body.sid,
                                 NULL);
@@ -586,7 +653,7 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
                        sw_context->needs_post_query_barrier = true;
                        ret = vmw_bo_to_validate_list(sw_context,
                                                      sw_context->cur_query_bo,
-                                                     NULL);
+                                                     dev_priv->has_mob, NULL);
                        if (unlikely(ret != 0))
                                return ret;
                }
@@ -594,7 +661,7 @@ static int vmw_query_bo_switch_prepare(struct vmw_private *dev_priv,
 
                ret = vmw_bo_to_validate_list(sw_context,
                                              dev_priv->dummy_query_bo,
-                                             NULL);
+                                             dev_priv->has_mob, NULL);
                if (unlikely(ret != 0))
                        return ret;
 
@@ -671,6 +738,66 @@ static void vmw_query_bo_switch_commit(struct vmw_private *dev_priv,
        }
 }
 
+/**
+ * vmw_translate_mob_pointer - Prepare to translate a user-space buffer
+ * handle to a MOB id.
+ *
+ * @dev_priv: Pointer to a device private structure.
+ * @sw_context: The software context used for this command batch validation.
+ * @id: Pointer to the user-space handle to be translated.
+ * @vmw_bo_p: Points to a location that, on successful return will carry
+ * a reference-counted pointer to the DMA buffer identified by the
+ * user-space handle in @id.
+ *
+ * This function saves information needed to translate a user-space buffer
+ * handle to a MOB id. The translation does not take place immediately, but
+ * during a call to vmw_apply_relocations(). This function builds a relocation
+ * list and a list of buffers to validate. The former needs to be freed using
+ * either vmw_apply_relocations() or vmw_free_relocations(). The latter
+ * needs to be freed using vmw_clear_validations.
+ */
+static int vmw_translate_mob_ptr(struct vmw_private *dev_priv,
+                                struct vmw_sw_context *sw_context,
+                                SVGAMobId *id,
+                                struct vmw_dma_buffer **vmw_bo_p)
+{
+       struct vmw_dma_buffer *vmw_bo = NULL;
+       struct ttm_buffer_object *bo;
+       uint32_t handle = *id;
+       struct vmw_relocation *reloc;
+       int ret;
+
+       ret = vmw_user_dmabuf_lookup(sw_context->tfile, handle, &vmw_bo);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Could not find or use MOB buffer.\n");
+               return -EINVAL;
+       }
+       bo = &vmw_bo->base;
+
+       if (unlikely(sw_context->cur_reloc >= VMWGFX_MAX_RELOCATIONS)) {
+               DRM_ERROR("Max number relocations per submission"
+                         " exceeded\n");
+               ret = -EINVAL;
+               goto out_no_reloc;
+       }
+
+       reloc = &sw_context->relocs[sw_context->cur_reloc++];
+       reloc->mob_loc = id;
+       reloc->location = NULL;
+
+       ret = vmw_bo_to_validate_list(sw_context, bo, true, &reloc->index);
+       if (unlikely(ret != 0))
+               goto out_no_reloc;
+
+       *vmw_bo_p = vmw_bo;
+       return 0;
+
+out_no_reloc:
+       vmw_dmabuf_unreference(&vmw_bo);
+       vmw_bo_p = NULL;
+       return ret;
+}
+
 /**
  * vmw_translate_guest_pointer - Prepare to translate a user-space buffer
  * handle to a valid SVGAGuestPtr
@@ -718,7 +845,7 @@ static int vmw_translate_guest_ptr(struct vmw_private *dev_priv,
        reloc = &sw_context->relocs[sw_context->cur_reloc++];
        reloc->location = ptr;
 
-       ret = vmw_bo_to_validate_list(sw_context, bo, &reloc->index);
+       ret = vmw_bo_to_validate_list(sw_context, bo, false, &reloc->index);
        if (unlikely(ret != 0))
                goto out_no_reloc;
 
@@ -731,6 +858,30 @@ out_no_reloc:
        return ret;
 }
 
+/**
+ * vmw_cmd_begin_gb_query - validate a  SVGA_3D_CMD_BEGIN_GB_QUERY command.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context used for this command submission.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_begin_gb_query(struct vmw_private *dev_priv,
+                                 struct vmw_sw_context *sw_context,
+                                 SVGA3dCmdHeader *header)
+{
+       struct vmw_begin_gb_query_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBeginGBQuery q;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_begin_gb_query_cmd,
+                          header);
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
+                                user_context_converter, &cmd->q.cid,
+                                NULL);
+}
+
 /**
  * vmw_cmd_begin_query - validate a  SVGA_3D_CMD_BEGIN_QUERY command.
  *
@@ -750,11 +901,63 @@ static int vmw_cmd_begin_query(struct vmw_private *dev_priv,
        cmd = container_of(header, struct vmw_begin_query_cmd,
                           header);
 
+       if (unlikely(dev_priv->has_mob)) {
+               struct {
+                       SVGA3dCmdHeader header;
+                       SVGA3dCmdBeginGBQuery q;
+               } gb_cmd;
+
+               BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
+
+               gb_cmd.header.id = SVGA_3D_CMD_BEGIN_GB_QUERY;
+               gb_cmd.header.size = cmd->header.size;
+               gb_cmd.q.cid = cmd->q.cid;
+               gb_cmd.q.type = cmd->q.type;
+
+               memcpy(cmd, &gb_cmd, sizeof(*cmd));
+               return vmw_cmd_begin_gb_query(dev_priv, sw_context, header);
+       }
+
        return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
                                 user_context_converter, &cmd->q.cid,
                                 NULL);
 }
 
+/**
+ * vmw_cmd_end_gb_query - validate a  SVGA_3D_CMD_END_GB_QUERY command.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context used for this command submission.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_end_gb_query(struct vmw_private *dev_priv,
+                               struct vmw_sw_context *sw_context,
+                               SVGA3dCmdHeader *header)
+{
+       struct vmw_dma_buffer *vmw_bo;
+       struct vmw_query_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdEndGBQuery q;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_query_cmd, header);
+       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = vmw_translate_mob_ptr(dev_priv, sw_context,
+                                   &cmd->q.mobid,
+                                   &vmw_bo);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = vmw_query_bo_switch_prepare(dev_priv, &vmw_bo->base, sw_context);
+
+       vmw_dmabuf_unreference(&vmw_bo);
+       return ret;
+}
+
 /**
  * vmw_cmd_end_query - validate a  SVGA_3D_CMD_END_QUERY command.
  *
@@ -774,6 +977,25 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv,
        int ret;
 
        cmd = container_of(header, struct vmw_query_cmd, header);
+       if (dev_priv->has_mob) {
+               struct {
+                       SVGA3dCmdHeader header;
+                       SVGA3dCmdEndGBQuery q;
+               } gb_cmd;
+
+               BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
+
+               gb_cmd.header.id = SVGA_3D_CMD_END_GB_QUERY;
+               gb_cmd.header.size = cmd->header.size;
+               gb_cmd.q.cid = cmd->q.cid;
+               gb_cmd.q.type = cmd->q.type;
+               gb_cmd.q.mobid = cmd->q.guestResult.gmrId;
+               gb_cmd.q.offset = cmd->q.guestResult.offset;
+
+               memcpy(cmd, &gb_cmd, sizeof(*cmd));
+               return vmw_cmd_end_gb_query(dev_priv, sw_context, header);
+       }
+
        ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
        if (unlikely(ret != 0))
                return ret;
@@ -790,7 +1012,40 @@ static int vmw_cmd_end_query(struct vmw_private *dev_priv,
        return ret;
 }
 
-/*
+/**
+ * vmw_cmd_wait_gb_query - validate a  SVGA_3D_CMD_WAIT_GB_QUERY command.
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context used for this command submission.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_wait_gb_query(struct vmw_private *dev_priv,
+                                struct vmw_sw_context *sw_context,
+                                SVGA3dCmdHeader *header)
+{
+       struct vmw_dma_buffer *vmw_bo;
+       struct vmw_query_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdWaitForGBQuery q;
+       } *cmd;
+       int ret;
+
+       cmd = container_of(header, struct vmw_query_cmd, header);
+       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = vmw_translate_mob_ptr(dev_priv, sw_context,
+                                   &cmd->q.mobid,
+                                   &vmw_bo);
+       if (unlikely(ret != 0))
+               return ret;
+
+       vmw_dmabuf_unreference(&vmw_bo);
+       return 0;
+}
+
+/**
  * vmw_cmd_wait_query - validate a  SVGA_3D_CMD_WAIT_QUERY command.
  *
  * @dev_priv: Pointer to a device private struct.
@@ -809,6 +1064,25 @@ static int vmw_cmd_wait_query(struct vmw_private *dev_priv,
        int ret;
 
        cmd = container_of(header, struct vmw_query_cmd, header);
+       if (dev_priv->has_mob) {
+               struct {
+                       SVGA3dCmdHeader header;
+                       SVGA3dCmdWaitForGBQuery q;
+               } gb_cmd;
+
+               BUG_ON(sizeof(gb_cmd) != sizeof(*cmd));
+
+               gb_cmd.header.id = SVGA_3D_CMD_WAIT_FOR_GB_QUERY;
+               gb_cmd.header.size = cmd->header.size;
+               gb_cmd.q.cid = cmd->q.cid;
+               gb_cmd.q.type = cmd->q.type;
+               gb_cmd.q.mobid = cmd->q.guestResult.gmrId;
+               gb_cmd.q.offset = cmd->q.guestResult.offset;
+
+               memcpy(cmd, &gb_cmd, sizeof(*cmd));
+               return vmw_cmd_wait_gb_query(dev_priv, sw_context, header);
+       }
+
        ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
        if (unlikely(ret != 0))
                return ret;
@@ -921,15 +1195,22 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv,
        struct vmw_tex_state_cmd {
                SVGA3dCmdHeader header;
                SVGA3dCmdSetTextureState state;
-       };
+       } *cmd;
 
        SVGA3dTextureState *last_state = (SVGA3dTextureState *)
          ((unsigned long) header + header->size + sizeof(header));
        SVGA3dTextureState *cur_state = (SVGA3dTextureState *)
                ((unsigned long) header + sizeof(struct vmw_tex_state_cmd));
+       struct vmw_resource_val_node *ctx_node;
+       struct vmw_resource_val_node *res_node;
        int ret;
 
-       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       cmd = container_of(header, struct vmw_tex_state_cmd,
+                          header);
+
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
+                               user_context_converter, &cmd->state.cid,
+                               &ctx_node);
        if (unlikely(ret != 0))
                return ret;
 
@@ -939,9 +1220,20 @@ static int vmw_cmd_tex_state(struct vmw_private *dev_priv,
 
                ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
                                        user_surface_converter,
-                                       &cur_state->value, NULL);
+                                       &cur_state->value, &res_node);
                if (unlikely(ret != 0))
                        return ret;
+
+               if (dev_priv->has_mob) {
+                       struct vmw_ctx_bindinfo bi;
+
+                       bi.ctx = ctx_node->res;
+                       bi.res = res_node ? res_node->res : NULL;
+                       bi.bt = vmw_ctx_binding_tex;
+                       bi.i1.texture_stage = cur_state->stage;
+                       vmw_context_binding_add(ctx_node->staged_bindings,
+                                               &bi);
+               }
        }
 
        return 0;
@@ -970,6 +1262,222 @@ static int vmw_cmd_check_define_gmrfb(struct vmw_private *dev_priv,
        return ret;
 }
 
+/**
+ * vmw_cmd_switch_backup - Utility function to handle backup buffer switching
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @res_type: The resource type.
+ * @converter: Information about user-space binding for this resource type.
+ * @res_id: Pointer to the user-space resource handle in the command stream.
+ * @buf_id: Pointer to the user-space backup buffer handle in the command
+ * stream.
+ * @backup_offset: Offset of backup into MOB.
+ *
+ * This function prepares for registering a switch of backup buffers
+ * in the resource metadata just prior to unreserving.
+ */
+static int vmw_cmd_switch_backup(struct vmw_private *dev_priv,
+                                struct vmw_sw_context *sw_context,
+                                enum vmw_res_type res_type,
+                                const struct vmw_user_resource_conv
+                                *converter,
+                                uint32_t *res_id,
+                                uint32_t *buf_id,
+                                unsigned long backup_offset)
+{
+       int ret;
+       struct vmw_dma_buffer *dma_buf;
+       struct vmw_resource_val_node *val_node;
+
+       ret = vmw_cmd_res_check(dev_priv, sw_context, res_type,
+                               converter, res_id, &val_node);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = vmw_translate_mob_ptr(dev_priv, sw_context, buf_id, &dma_buf);
+       if (unlikely(ret != 0))
+               return ret;
+
+       if (val_node->first_usage)
+               val_node->no_buffer_needed = true;
+
+       vmw_dmabuf_unreference(&val_node->new_backup);
+       val_node->new_backup = dma_buf;
+       val_node->new_backup_offset = backup_offset;
+
+       return 0;
+}
+
+/**
+ * vmw_cmd_bind_gb_surface - Validate an SVGA_3D_CMD_BIND_GB_SURFACE
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_bind_gb_surface(struct vmw_private *dev_priv,
+                                  struct vmw_sw_context *sw_context,
+                                  SVGA3dCmdHeader *header)
+{
+       struct vmw_bind_gb_surface_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBindGBSurface body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_bind_gb_surface_cmd, header);
+
+       return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_surface,
+                                    user_surface_converter,
+                                    &cmd->body.sid, &cmd->body.mobid,
+                                    0);
+}
+
+/**
+ * vmw_cmd_update_gb_image - Validate an SVGA_3D_CMD_UPDATE_GB_IMAGE
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_update_gb_image(struct vmw_private *dev_priv,
+                                  struct vmw_sw_context *sw_context,
+                                  SVGA3dCmdHeader *header)
+{
+       struct vmw_gb_surface_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdUpdateGBImage body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_gb_surface_cmd, header);
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->body.image.sid, NULL);
+}
+
+/**
+ * vmw_cmd_update_gb_surface - Validate an SVGA_3D_CMD_UPDATE_GB_SURFACE
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_update_gb_surface(struct vmw_private *dev_priv,
+                                    struct vmw_sw_context *sw_context,
+                                    SVGA3dCmdHeader *header)
+{
+       struct vmw_gb_surface_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdUpdateGBSurface body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_gb_surface_cmd, header);
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->body.sid, NULL);
+}
+
+/**
+ * vmw_cmd_readback_gb_image - Validate an SVGA_3D_CMD_READBACK_GB_IMAGE
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_readback_gb_image(struct vmw_private *dev_priv,
+                                    struct vmw_sw_context *sw_context,
+                                    SVGA3dCmdHeader *header)
+{
+       struct vmw_gb_surface_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdReadbackGBImage body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_gb_surface_cmd, header);
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->body.image.sid, NULL);
+}
+
+/**
+ * vmw_cmd_readback_gb_surface - Validate an SVGA_3D_CMD_READBACK_GB_SURFACE
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_readback_gb_surface(struct vmw_private *dev_priv,
+                                      struct vmw_sw_context *sw_context,
+                                      SVGA3dCmdHeader *header)
+{
+       struct vmw_gb_surface_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdReadbackGBSurface body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_gb_surface_cmd, header);
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->body.sid, NULL);
+}
+
+/**
+ * vmw_cmd_invalidate_gb_image - Validate an SVGA_3D_CMD_INVALIDATE_GB_IMAGE
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_invalidate_gb_image(struct vmw_private *dev_priv,
+                                      struct vmw_sw_context *sw_context,
+                                      SVGA3dCmdHeader *header)
+{
+       struct vmw_gb_surface_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdInvalidateGBImage body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_gb_surface_cmd, header);
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->body.image.sid, NULL);
+}
+
+/**
+ * vmw_cmd_invalidate_gb_surface - Validate an
+ * SVGA_3D_CMD_INVALIDATE_GB_SURFACE command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_invalidate_gb_surface(struct vmw_private *dev_priv,
+                                        struct vmw_sw_context *sw_context,
+                                        SVGA3dCmdHeader *header)
+{
+       struct vmw_gb_surface_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdInvalidateGBSurface body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_gb_surface_cmd, header);
+
+       return vmw_cmd_res_check(dev_priv, sw_context, vmw_res_surface,
+                                user_surface_converter,
+                                &cmd->body.sid, NULL);
+}
+
 /**
  * vmw_cmd_set_shader - Validate an SVGA_3D_CMD_SET_SHADER
  * command
@@ -986,18 +1494,64 @@ static int vmw_cmd_set_shader(struct vmw_private *dev_priv,
                SVGA3dCmdHeader header;
                SVGA3dCmdSetShader body;
        } *cmd;
+       struct vmw_resource_val_node *ctx_node;
        int ret;
 
        cmd = container_of(header, struct vmw_set_shader_cmd,
                           header);
 
-       ret = vmw_cmd_cid_check(dev_priv, sw_context, header);
+       ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_context,
+                               user_context_converter, &cmd->body.cid,
+                               &ctx_node);
        if (unlikely(ret != 0))
                return ret;
 
+       if (dev_priv->has_mob) {
+               struct vmw_ctx_bindinfo bi;
+               struct vmw_resource_val_node *res_node;
+
+               ret = vmw_cmd_res_check(dev_priv, sw_context, vmw_res_shader,
+                                       user_shader_converter,
+                                       &cmd->body.shid, &res_node);
+               if (unlikely(ret != 0))
+                       return ret;
+
+               bi.ctx = ctx_node->res;
+               bi.res = res_node ? res_node->res : NULL;
+               bi.bt = vmw_ctx_binding_shader;
+               bi.i1.shader_type = cmd->body.type;
+               return vmw_context_binding_add(ctx_node->staged_bindings, &bi);
+       }
+
        return 0;
 }
 
+/**
+ * vmw_cmd_bind_gb_shader - Validate an SVGA_3D_CMD_BIND_GB_SHADER
+ * command
+ *
+ * @dev_priv: Pointer to a device private struct.
+ * @sw_context: The software context being used for this batch.
+ * @header: Pointer to the command header in the command stream.
+ */
+static int vmw_cmd_bind_gb_shader(struct vmw_private *dev_priv,
+                                 struct vmw_sw_context *sw_context,
+                                 SVGA3dCmdHeader *header)
+{
+       struct vmw_bind_gb_shader_cmd {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBindGBShader body;
+       } *cmd;
+
+       cmd = container_of(header, struct vmw_bind_gb_shader_cmd,
+                          header);
+
+       return vmw_cmd_switch_backup(dev_priv, sw_context, vmw_res_shader,
+                                    user_shader_converter,
+                                    &cmd->body.shid, &cmd->body.mobid,
+                                    cmd->body.offsetInBytes);
+}
+
 static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
                                struct vmw_sw_context *sw_context,
                                void *buf, uint32_t *size)
@@ -1041,50 +1595,173 @@ static int vmw_cmd_check_not_3d(struct vmw_private *dev_priv,
        return 0;
 }
 
-typedef int (*vmw_cmd_func) (struct vmw_private *,
-                            struct vmw_sw_context *,
-                            SVGA3dCmdHeader *);
-
-#define VMW_CMD_DEF(cmd, func) \
-       [cmd - SVGA_3D_CMD_BASE] = func
-
-static vmw_cmd_func vmw_cmd_funcs[SVGA_3D_CMD_MAX] = {
-       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid),
-       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid),
-       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_COPY, &vmw_cmd_surface_copy_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_STRETCHBLT, &vmw_cmd_stretch_blt_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DMA, &vmw_cmd_dma),
-       VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DEFINE, &vmw_cmd_invalid),
-       VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DESTROY, &vmw_cmd_invalid),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETTRANSFORM, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETZRANGE, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check),
+static const struct vmw_cmd_entry const vmw_cmd_entries[SVGA_3D_CMD_MAX] = {
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DESTROY, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_COPY, &vmw_cmd_surface_copy_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_STRETCHBLT, &vmw_cmd_stretch_blt_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DMA, &vmw_cmd_dma,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DEFINE, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_CONTEXT_DESTROY, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETTRANSFORM, &vmw_cmd_cid_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETZRANGE, &vmw_cmd_cid_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERSTATE, &vmw_cmd_cid_check,
+                   true, false, false),
        VMW_CMD_DEF(SVGA_3D_CMD_SETRENDERTARGET,
-                   &vmw_cmd_set_render_target_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETVIEWPORT, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETCLIPPLANE, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_CLEAR, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_set_shader),
-       VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw),
-       VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_begin_query),
-       VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_end_query),
-       VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_wait_query),
-       VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok),
+                   &vmw_cmd_set_render_target_check, true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETTEXTURESTATE, &vmw_cmd_tex_state,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETMATERIAL, &vmw_cmd_cid_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTDATA, &vmw_cmd_cid_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETLIGHTENABLED, &vmw_cmd_cid_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETVIEWPORT, &vmw_cmd_cid_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETCLIPPLANE, &vmw_cmd_cid_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_CLEAR, &vmw_cmd_cid_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_PRESENT, &vmw_cmd_present_check,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DEFINE, &vmw_cmd_cid_check,
+                   true, true, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SHADER_DESTROY, &vmw_cmd_cid_check,
+                   true, true, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER, &vmw_cmd_set_shader,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SET_SHADER_CONST, &vmw_cmd_cid_check,
+                   true, true, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_DRAW_PRIMITIVES, &vmw_cmd_draw,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SETSCISSORRECT, &vmw_cmd_cid_check,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_QUERY, &vmw_cmd_begin_query,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_END_QUERY, &vmw_cmd_end_query,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_QUERY, &vmw_cmd_wait_query,
+                   true, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_PRESENT_READBACK, &vmw_cmd_ok,
+                   true, false, false),
        VMW_CMD_DEF(SVGA_3D_CMD_BLIT_SURFACE_TO_SCREEN,
-                   &vmw_cmd_blt_surf_screen_check),
-       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE_V2, &vmw_cmd_invalid),
-       VMW_CMD_DEF(SVGA_3D_CMD_GENERATE_MIPMAPS, &vmw_cmd_invalid),
-       VMW_CMD_DEF(SVGA_3D_CMD_ACTIVATE_SURFACE, &vmw_cmd_invalid),
-       VMW_CMD_DEF(SVGA_3D_CMD_DEACTIVATE_SURFACE, &vmw_cmd_invalid),
+                   &vmw_cmd_blt_surf_screen_check, false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SURFACE_DEFINE_V2, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_GENERATE_MIPMAPS, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_ACTIVATE_SURFACE, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_DEACTIVATE_SURFACE, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SCREEN_DMA, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SET_UNITY_SURFACE_COOKIE, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_OPEN_CONTEXT_SURFACE, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_BITBLT, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_TRANSBLT, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_STRETCHBLT, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_COLORFILL, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_ALPHABLEND, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_LOGICOPS_CLEARTYPEBLEND, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_SET_OTABLE_BASE, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_READBACK_OTABLE, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_MOB, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_MOB, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_REDEFINE_GB_MOB, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_MOB_MAPPING, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SURFACE, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SURFACE, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SURFACE, &vmw_cmd_bind_gb_surface,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_COND_BIND_GB_SURFACE, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_IMAGE, &vmw_cmd_update_gb_image,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_SURFACE,
+                   &vmw_cmd_update_gb_surface, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_IMAGE,
+                   &vmw_cmd_readback_gb_image, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_SURFACE,
+                   &vmw_cmd_readback_gb_surface, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE,
+                   &vmw_cmd_invalidate_gb_image, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_SURFACE,
+                   &vmw_cmd_invalidate_gb_surface, true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_CONTEXT, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SHADER, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SHADER, &vmw_cmd_bind_gb_shader,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SHADER, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_SET_OTABLE_BASE64, &vmw_cmd_invalid,
+                   false, false, false),
+       VMW_CMD_DEF(SVGA_3D_CMD_BEGIN_GB_QUERY, &vmw_cmd_begin_gb_query,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_END_GB_QUERY, &vmw_cmd_end_gb_query,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_WAIT_FOR_GB_QUERY, &vmw_cmd_wait_gb_query,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_NOP, &vmw_cmd_ok,
+                   true, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_ENABLE_GART, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DISABLE_GART, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_MAP_MOB_INTO_GART, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_UNMAP_GART_RANGE, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DEFINE_GB_SCREENTARGET, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_DESTROY_GB_SCREENTARGET, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_BIND_GB_SCREENTARGET, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_UPDATE_GB_SCREENTARGET, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_READBACK_GB_IMAGE_PARTIAL, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_INVALIDATE_GB_IMAGE_PARTIAL, &vmw_cmd_invalid,
+                   false, false, true),
+       VMW_CMD_DEF(SVGA_3D_CMD_SET_GB_SHADERCONSTS_INLINE, &vmw_cmd_cid_check,
+                   true, false, true)
 };
 
 static int vmw_cmd_check(struct vmw_private *dev_priv,
@@ -1095,6 +1772,8 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
        uint32_t size_remaining = *size;
        SVGA3dCmdHeader *header = (SVGA3dCmdHeader *) buf;
        int ret;
+       const struct vmw_cmd_entry *entry;
+       bool gb = dev_priv->capabilities & SVGA_CAP_GBOBJECTS;
 
        cmd_id = le32_to_cpu(((uint32_t *)buf)[0]);
        /* Handle any none 3D commands */
@@ -1107,18 +1786,40 @@ static int vmw_cmd_check(struct vmw_private *dev_priv,
 
        cmd_id -= SVGA_3D_CMD_BASE;
        if (unlikely(*size > size_remaining))
-               goto out_err;
+               goto out_invalid;
 
        if (unlikely(cmd_id >= SVGA_3D_CMD_MAX - SVGA_3D_CMD_BASE))
-               goto out_err;
+               goto out_invalid;
+
+       entry = &vmw_cmd_entries[cmd_id];
+       if (unlikely(!entry->user_allow && !sw_context->kernel))
+               goto out_privileged;
 
-       ret = vmw_cmd_funcs[cmd_id](dev_priv, sw_context, header);
+       if (unlikely(entry->gb_disable && gb))
+               goto out_old;
+
+       if (unlikely(entry->gb_enable && !gb))
+               goto out_new;
+
+       ret = entry->func(dev_priv, sw_context, header);
        if (unlikely(ret != 0))
-               goto out_err;
+               goto out_invalid;
 
        return 0;
-out_err:
-       DRM_ERROR("Illegal / Invalid SVGA3D command: %d\n",
+out_invalid:
+       DRM_ERROR("Invalid SVGA3D command: %d\n",
+                 cmd_id + SVGA_3D_CMD_BASE);
+       return -EINVAL;
+out_privileged:
+       DRM_ERROR("Privileged SVGA3D command: %d\n",
+                 cmd_id + SVGA_3D_CMD_BASE);
+       return -EPERM;
+out_old:
+       DRM_ERROR("Deprecated (disallowed) SVGA3D command: %d\n",
+                 cmd_id + SVGA_3D_CMD_BASE);
+       return -EINVAL;
+out_new:
+       DRM_ERROR("SVGA3D command: %d not supported by virtual hardware.\n",
                  cmd_id + SVGA_3D_CMD_BASE);
        return -EINVAL;
 }
@@ -1174,6 +1875,9 @@ static void vmw_apply_relocations(struct vmw_sw_context *sw_context)
                case VMW_PL_GMR:
                        reloc->location->gmrId = bo->mem.start;
                        break;
+               case VMW_PL_MOB:
+                       *reloc->mob_loc = bo->mem.start;
+                       break;
                default:
                        BUG();
                }
@@ -1198,6 +1902,8 @@ static void vmw_resource_list_unreference(struct list_head *list)
        list_for_each_entry_safe(val, val_next, list, head) {
                list_del_init(&val->head);
                vmw_resource_unreference(&val->res);
+               if (unlikely(val->staged_bindings))
+                       kfree(val->staged_bindings);
                kfree(val);
        }
 }
@@ -1224,7 +1930,8 @@ static void vmw_clear_validations(struct vmw_sw_context *sw_context)
 }
 
 static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
-                                     struct ttm_buffer_object *bo)
+                                     struct ttm_buffer_object *bo,
+                                     bool validate_as_mob)
 {
        int ret;
 
@@ -1238,6 +1945,9 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
             dev_priv->dummy_query_bo_pinned))
                return 0;
 
+       if (validate_as_mob)
+               return ttm_bo_validate(bo, &vmw_mob_placement, true, false);
+
        /**
         * Put BO in VRAM if there is space, otherwise as a GMR.
         * If there is no space in VRAM and GMR ids are all used up,
@@ -1259,7 +1969,6 @@ static int vmw_validate_single_buffer(struct vmw_private *dev_priv,
        return ret;
 }
 
-
 static int vmw_validate_buffers(struct vmw_private *dev_priv,
                                struct vmw_sw_context *sw_context)
 {
@@ -1267,7 +1976,8 @@ static int vmw_validate_buffers(struct vmw_private *dev_priv,
        int ret;
 
        list_for_each_entry(entry, &sw_context->validate_nodes, base.head) {
-               ret = vmw_validate_single_buffer(dev_priv, entry->base.bo);
+               ret = vmw_validate_single_buffer(dev_priv, entry->base.bo,
+                                                entry->validate_as_mob);
                if (unlikely(ret != 0))
                        return ret;
        }
@@ -1509,11 +2219,17 @@ int vmw_execbuf_process(struct drm_file *file_priv,
                        goto out_err;
        }
 
+       ret = mutex_lock_interruptible(&dev_priv->binding_mutex);
+       if (unlikely(ret != 0)) {
+               ret = -ERESTARTSYS;
+               goto out_err;
+       }
+
        cmd = vmw_fifo_reserve(dev_priv, command_size);
        if (unlikely(cmd == NULL)) {
                DRM_ERROR("Failed reserving fifo space for commands.\n");
                ret = -ENOMEM;
-               goto out_err;
+               goto out_unlock_binding;
        }
 
        vmw_apply_relocations(sw_context);
@@ -1538,6 +2254,8 @@ int vmw_execbuf_process(struct drm_file *file_priv,
                DRM_ERROR("Fence submission error. Syncing.\n");
 
        vmw_resource_list_unreserve(&sw_context->resource_list, false);
+       mutex_unlock(&dev_priv->binding_mutex);
+
        ttm_eu_fence_buffer_objects(&ticket, &sw_context->validate_nodes,
                                    (void *) fence);
 
@@ -1568,6 +2286,8 @@ int vmw_execbuf_process(struct drm_file *file_priv,
 
        return 0;
 
+out_unlock_binding:
+       mutex_unlock(&dev_priv->binding_mutex);
 out_err:
        vmw_resource_relocations_free(&sw_context->res_relocations);
        vmw_free_relocations(sw_context);
index c62d20e8a6f169cce1173c849b42f160c55a4f39..436b013b42316a06296dd62cb0dda23f5095c075 100644 (file)
@@ -271,7 +271,7 @@ void vmw_fence_obj_unreference(struct vmw_fence_obj **fence_p)
        spin_unlock_irq(&fman->lock);
 }
 
-void vmw_fences_perform_actions(struct vmw_fence_manager *fman,
+static void vmw_fences_perform_actions(struct vmw_fence_manager *fman,
                                struct list_head *list)
 {
        struct vmw_fence_action *action, *next_action;
@@ -897,7 +897,7 @@ static void vmw_event_fence_action_cleanup(struct vmw_fence_action *action)
  * Note that the action callbacks may be executed before this function
  * returns.
  */
-void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
+static void vmw_fence_obj_add_action(struct vmw_fence_obj *fence,
                              struct vmw_fence_action *action)
 {
        struct vmw_fence_manager *fman = fence->fman;
@@ -993,7 +993,7 @@ struct vmw_event_fence_pending {
        struct drm_vmw_event_fence event;
 };
 
-int vmw_event_fence_action_create(struct drm_file *file_priv,
+static int vmw_event_fence_action_create(struct drm_file *file_priv,
                                  struct vmw_fence_obj *fence,
                                  uint32_t flags,
                                  uint64_t user_data,
@@ -1080,7 +1080,8 @@ int vmw_fence_event_ioctl(struct drm_device *dev, void *data,
         */
        if (arg->handle) {
                struct ttm_base_object *base =
-                       ttm_base_object_lookup(vmw_fp->tfile, arg->handle);
+                       ttm_base_object_lookup_for_ref(dev_priv->tdev,
+                                                      arg->handle);
 
                if (unlikely(base == NULL)) {
                        DRM_ERROR("Fence event invalid fence object handle "
index 3eb148667d6382f003969757db0b9dd26555f909..6ccd993e26bf4ead66d0e8d1f1b4b592856d7599 100644 (file)
@@ -35,6 +35,23 @@ bool vmw_fifo_have_3d(struct vmw_private *dev_priv)
        uint32_t fifo_min, hwversion;
        const struct vmw_fifo_state *fifo = &dev_priv->fifo;
 
+       if (!(dev_priv->capabilities & SVGA_CAP_3D))
+               return false;
+
+       if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS) {
+               uint32_t result;
+
+               if (!dev_priv->has_mob)
+                       return false;
+
+               mutex_lock(&dev_priv->hw_mutex);
+               vmw_write(dev_priv, SVGA_REG_DEV_CAP, SVGA3D_DEVCAP_3D);
+               result = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
+               mutex_unlock(&dev_priv->hw_mutex);
+
+               return (result != 0);
+       }
+
        if (!(dev_priv->capabilities & SVGA_CAP_EXTENDED_FIFO))
                return false;
 
@@ -511,24 +528,16 @@ out_err:
 }
 
 /**
- * vmw_fifo_emit_dummy_query - emits a dummy query to the fifo.
+ * vmw_fifo_emit_dummy_legacy_query - emits a dummy query to the fifo using
+ * legacy query commands.
  *
  * @dev_priv: The device private structure.
  * @cid: The hardware context id used for the query.
  *
- * This function is used to emit a dummy occlusion query with
- * no primitives rendered between query begin and query end.
- * It's used to provide a query barrier, in order to know that when
- * this query is finished, all preceding queries are also finished.
- *
- * A Query results structure should have been initialized at the start
- * of the dev_priv->dummy_query_bo buffer object. And that buffer object
- * must also be either reserved or pinned when this function is called.
- *
- * Returns -ENOMEM on failure to reserve fifo space.
+ * See the vmw_fifo_emit_dummy_query documentation.
  */
-int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv,
-                             uint32_t cid)
+static int vmw_fifo_emit_dummy_legacy_query(struct vmw_private *dev_priv,
+                                           uint32_t cid)
 {
        /*
         * A query wait without a preceding query end will
@@ -566,3 +575,75 @@ int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv,
 
        return 0;
 }
+
+/**
+ * vmw_fifo_emit_dummy_gb_query - emits a dummy query to the fifo using
+ * guest-backed resource query commands.
+ *
+ * @dev_priv: The device private structure.
+ * @cid: The hardware context id used for the query.
+ *
+ * See the vmw_fifo_emit_dummy_query documentation.
+ */
+static int vmw_fifo_emit_dummy_gb_query(struct vmw_private *dev_priv,
+                                       uint32_t cid)
+{
+       /*
+        * A query wait without a preceding query end will
+        * actually finish all queries for this cid
+        * without writing to the query result structure.
+        */
+
+       struct ttm_buffer_object *bo = dev_priv->dummy_query_bo;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdWaitForGBQuery body;
+       } *cmd;
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Out of fifo space for dummy query.\n");
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_WAIT_FOR_GB_QUERY;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.cid = cid;
+       cmd->body.type = SVGA3D_QUERYTYPE_OCCLUSION;
+       BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
+       cmd->body.mobid = bo->mem.start;
+       cmd->body.offset = 0;
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       return 0;
+}
+
+
+/**
+ * vmw_fifo_emit_dummy_gb_query - emits a dummy query to the fifo using
+ * appropriate resource query commands.
+ *
+ * @dev_priv: The device private structure.
+ * @cid: The hardware context id used for the query.
+ *
+ * This function is used to emit a dummy occlusion query with
+ * no primitives rendered between query begin and query end.
+ * It's used to provide a query barrier, in order to know that when
+ * this query is finished, all preceding queries are also finished.
+ *
+ * A Query results structure should have been initialized at the start
+ * of the dev_priv->dummy_query_bo buffer object. And that buffer object
+ * must also be either reserved or pinned when this function is called.
+ *
+ * Returns -ENOMEM on failure to reserve fifo space.
+ */
+int vmw_fifo_emit_dummy_query(struct vmw_private *dev_priv,
+                             uint32_t cid)
+{
+       if (dev_priv->has_mob)
+               return vmw_fifo_emit_dummy_gb_query(dev_priv, cid);
+
+       return vmw_fifo_emit_dummy_legacy_query(dev_priv, cid);
+}
index 6ef0b035becbc5959f78ecf7b978629f90ae98e2..61d8d803199fc97085ef7e7ada07e7cbbd89bb5f 100644 (file)
@@ -125,181 +125,27 @@ static void vmw_gmr2_unbind(struct vmw_private *dev_priv,
 }
 
 
-static void vmw_gmr_free_descriptors(struct device *dev, dma_addr_t desc_dma,
-                                    struct list_head *desc_pages)
-{
-       struct page *page, *next;
-       struct svga_guest_mem_descriptor *page_virtual;
-       unsigned int desc_per_page = PAGE_SIZE /
-               sizeof(struct svga_guest_mem_descriptor) - 1;
-
-       if (list_empty(desc_pages))
-               return;
-
-       list_for_each_entry_safe(page, next, desc_pages, lru) {
-               list_del_init(&page->lru);
-
-               if (likely(desc_dma != DMA_ADDR_INVALID)) {
-                       dma_unmap_page(dev, desc_dma, PAGE_SIZE,
-                                      DMA_TO_DEVICE);
-               }
-
-               page_virtual = kmap_atomic(page);
-               desc_dma = (dma_addr_t)
-                       le32_to_cpu(page_virtual[desc_per_page].ppn) <<
-                       PAGE_SHIFT;
-               kunmap_atomic(page_virtual);
-
-               __free_page(page);
-       }
-}
-
-/**
- * FIXME: Adjust to the ttm lowmem / highmem storage to minimize
- * the number of used descriptors.
- *
- */
-
-static int vmw_gmr_build_descriptors(struct device *dev,
-                                    struct list_head *desc_pages,
-                                    struct vmw_piter *iter,
-                                    unsigned long num_pages,
-                                    dma_addr_t *first_dma)
-{
-       struct page *page;
-       struct svga_guest_mem_descriptor *page_virtual = NULL;
-       struct svga_guest_mem_descriptor *desc_virtual = NULL;
-       unsigned int desc_per_page;
-       unsigned long prev_pfn;
-       unsigned long pfn;
-       int ret;
-       dma_addr_t desc_dma;
-
-       desc_per_page = PAGE_SIZE /
-           sizeof(struct svga_guest_mem_descriptor) - 1;
-
-       while (likely(num_pages != 0)) {
-               page = alloc_page(__GFP_HIGHMEM);
-               if (unlikely(page == NULL)) {
-                       ret = -ENOMEM;
-                       goto out_err;
-               }
-
-               list_add_tail(&page->lru, desc_pages);
-               page_virtual = kmap_atomic(page);
-               desc_virtual = page_virtual - 1;
-               prev_pfn = ~(0UL);
-
-               while (likely(num_pages != 0)) {
-                       pfn = vmw_piter_dma_addr(iter) >> PAGE_SHIFT;
-
-                       if (pfn != prev_pfn + 1) {
-
-                               if (desc_virtual - page_virtual ==
-                                   desc_per_page - 1)
-                                       break;
-
-                               (++desc_virtual)->ppn = cpu_to_le32(pfn);
-                               desc_virtual->num_pages = cpu_to_le32(1);
-                       } else {
-                               uint32_t tmp =
-                                   le32_to_cpu(desc_virtual->num_pages);
-                               desc_virtual->num_pages = cpu_to_le32(tmp + 1);
-                       }
-                       prev_pfn = pfn;
-                       --num_pages;
-                       vmw_piter_next(iter);
-               }
-
-               (++desc_virtual)->ppn = DMA_PAGE_INVALID;
-               desc_virtual->num_pages = cpu_to_le32(0);
-               kunmap_atomic(page_virtual);
-       }
-
-       desc_dma = 0;
-       list_for_each_entry_reverse(page, desc_pages, lru) {
-               page_virtual = kmap_atomic(page);
-               page_virtual[desc_per_page].ppn = cpu_to_le32
-                       (desc_dma >> PAGE_SHIFT);
-               kunmap_atomic(page_virtual);
-               desc_dma = dma_map_page(dev, page, 0, PAGE_SIZE,
-                                       DMA_TO_DEVICE);
-
-               if (unlikely(dma_mapping_error(dev, desc_dma)))
-                       goto out_err;
-       }
-       *first_dma = desc_dma;
-
-       return 0;
-out_err:
-       vmw_gmr_free_descriptors(dev, DMA_ADDR_INVALID, desc_pages);
-       return ret;
-}
-
-static void vmw_gmr_fire_descriptors(struct vmw_private *dev_priv,
-                                    int gmr_id, dma_addr_t desc_dma)
-{
-       mutex_lock(&dev_priv->hw_mutex);
-
-       vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id);
-       wmb();
-       vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, desc_dma >> PAGE_SHIFT);
-       mb();
-
-       mutex_unlock(&dev_priv->hw_mutex);
-
-}
-
 int vmw_gmr_bind(struct vmw_private *dev_priv,
                 const struct vmw_sg_table *vsgt,
                 unsigned long num_pages,
                 int gmr_id)
 {
-       struct list_head desc_pages;
-       dma_addr_t desc_dma = 0;
-       struct device *dev = dev_priv->dev->dev;
        struct vmw_piter data_iter;
-       int ret;
 
        vmw_piter_start(&data_iter, vsgt, 0);
 
        if (unlikely(!vmw_piter_next(&data_iter)))
                return 0;
 
-       if (likely(dev_priv->capabilities & SVGA_CAP_GMR2))
-               return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id);
-
-       if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR)))
-               return -EINVAL;
-
-       if (vsgt->num_regions > dev_priv->max_gmr_descriptors)
+       if (unlikely(!(dev_priv->capabilities & SVGA_CAP_GMR2)))
                return -EINVAL;
 
-       INIT_LIST_HEAD(&desc_pages);
-
-       ret = vmw_gmr_build_descriptors(dev, &desc_pages, &data_iter,
-                                       num_pages, &desc_dma);
-       if (unlikely(ret != 0))
-               return ret;
-
-       vmw_gmr_fire_descriptors(dev_priv, gmr_id, desc_dma);
-       vmw_gmr_free_descriptors(dev, desc_dma, &desc_pages);
-
-       return 0;
+       return vmw_gmr2_bind(dev_priv, &data_iter, num_pages, gmr_id);
 }
 
 
 void vmw_gmr_unbind(struct vmw_private *dev_priv, int gmr_id)
 {
-       if (likely(dev_priv->capabilities & SVGA_CAP_GMR2)) {
+       if (likely(dev_priv->capabilities & SVGA_CAP_GMR2))
                vmw_gmr2_unbind(dev_priv, gmr_id);
-               return;
-       }
-
-       mutex_lock(&dev_priv->hw_mutex);
-       vmw_write(dev_priv, SVGA_REG_GMR_ID, gmr_id);
-       wmb();
-       vmw_write(dev_priv, SVGA_REG_GMR_DESCRIPTOR, 0);
-       mb();
-       mutex_unlock(&dev_priv->hw_mutex);
 }
index c5c054ae9056aaea2479eb6a9018013098708ce2..b1273e8e9a6903e2d15d3b153177e9a99c806859 100644 (file)
@@ -125,10 +125,21 @@ static int vmw_gmrid_man_init(struct ttm_mem_type_manager *man,
                return -ENOMEM;
 
        spin_lock_init(&gman->lock);
-       gman->max_gmr_pages = dev_priv->max_gmr_pages;
        gman->used_gmr_pages = 0;
        ida_init(&gman->gmr_ida);
-       gman->max_gmr_ids = p_size;
+
+       switch (p_size) {
+       case VMW_PL_GMR:
+               gman->max_gmr_ids = dev_priv->max_gmr_ids;
+               gman->max_gmr_pages = dev_priv->max_gmr_pages;
+               break;
+       case VMW_PL_MOB:
+               gman->max_gmr_ids = VMWGFX_NUM_MOB;
+               gman->max_gmr_pages = dev_priv->max_mob_pages;
+               break;
+       default:
+               BUG();
+       }
        man->priv = (void *) gman;
        return 0;
 }
index 45d5b5ab6ca9d8788fe80f0fbfd9f164203c026a..116c49736763ee81a4b4d664bfba2ab0a5e3d5cd 100644 (file)
@@ -53,7 +53,7 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
                param->value = dev_priv->fifo.capabilities;
                break;
        case DRM_VMW_PARAM_MAX_FB_SIZE:
-               param->value = dev_priv->vram_size;
+               param->value = dev_priv->prim_bb_mem;
                break;
        case DRM_VMW_PARAM_FIFO_HW_VERSION:
        {
@@ -71,6 +71,17 @@ int vmw_getparam_ioctl(struct drm_device *dev, void *data,
        case DRM_VMW_PARAM_MAX_SURF_MEMORY:
                param->value = dev_priv->memory_size;
                break;
+       case DRM_VMW_PARAM_3D_CAPS_SIZE:
+               if (dev_priv->capabilities & SVGA_CAP_GBOBJECTS)
+                       param->value = SVGA3D_DEVCAP_MAX;
+               else
+                       param->value = (SVGA_FIFO_3D_CAPS_LAST -
+                                       SVGA_FIFO_3D_CAPS + 1);
+               param->value *= sizeof(uint32_t);
+               break;
+       case DRM_VMW_PARAM_MAX_MOB_MEMORY:
+               param->value = dev_priv->max_mob_pages * PAGE_SIZE;
+               break;
        default:
                DRM_ERROR("Illegal vmwgfx get param request: %d\n",
                          param->param);
@@ -92,13 +103,19 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
        void __user *buffer = (void __user *)((unsigned long)(arg->buffer));
        void *bounce;
        int ret;
+       bool gb_objects = !!(dev_priv->capabilities & SVGA_CAP_GBOBJECTS);
 
        if (unlikely(arg->pad64 != 0)) {
                DRM_ERROR("Illegal GET_3D_CAP argument.\n");
                return -EINVAL;
        }
 
-       size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1) << 2;
+       if (gb_objects)
+               size = SVGA3D_DEVCAP_MAX;
+       else
+               size = (SVGA_FIFO_3D_CAPS_LAST - SVGA_FIFO_3D_CAPS + 1);
+
+       size *= sizeof(uint32_t);
 
        if (arg->max_size < size)
                size = arg->max_size;
@@ -109,8 +126,22 @@ int vmw_get_cap_3d_ioctl(struct drm_device *dev, void *data,
                return -ENOMEM;
        }
 
-       fifo_mem = dev_priv->mmio_virt;
-       memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size);
+       if (gb_objects) {
+               int i;
+               uint32_t *bounce32 = (uint32_t *) bounce;
+
+               mutex_lock(&dev_priv->hw_mutex);
+               for (i = 0; i < SVGA3D_DEVCAP_MAX; ++i) {
+                       vmw_write(dev_priv, SVGA_REG_DEV_CAP, i);
+                       *bounce32++ = vmw_read(dev_priv, SVGA_REG_DEV_CAP);
+               }
+               mutex_unlock(&dev_priv->hw_mutex);
+
+       } else {
+
+               fifo_mem = dev_priv->mmio_virt;
+               memcpy_fromio(bounce, &fifo_mem[SVGA_FIFO_3D_CAPS], size);
+       }
 
        ret = copy_to_user(buffer, bounce, size);
        if (ret)
index 4640adbcaf91b9609643895432d858313e56e2e4..0c423766c44119ca923825e879e3d05b7058cc90 100644 (file)
@@ -30,7 +30,7 @@
 
 #define VMW_FENCE_WRAP (1 << 24)
 
-irqreturn_t vmw_irq_handler(DRM_IRQ_ARGS)
+irqreturn_t vmw_irq_handler(int irq, void *arg)
 {
        struct drm_device *dev = (struct drm_device *)arg;
        struct vmw_private *dev_priv = vmw_priv(dev);
index 03f1c203863193621d9941af3051169ea2f79afb..8a650413dea57c8e50212b41f8be00abba3ee8af 100644 (file)
@@ -40,7 +40,7 @@ struct vmw_clip_rect {
  * Clip @num_rects number of @rects against @clip storing the
  * results in @out_rects and the number of passed rects in @out_num.
  */
-void vmw_clip_cliprects(struct drm_clip_rect *rects,
+static void vmw_clip_cliprects(struct drm_clip_rect *rects,
                        int num_rects,
                        struct vmw_clip_rect clip,
                        SVGASignedRect *out_rects,
@@ -423,7 +423,7 @@ struct vmw_framebuffer_surface {
        struct drm_master *master;
 };
 
-void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
+static void vmw_framebuffer_surface_destroy(struct drm_framebuffer *framebuffer)
 {
        struct vmw_framebuffer_surface *vfbs =
                vmw_framebuffer_to_vfbs(framebuffer);
@@ -589,7 +589,7 @@ out_free_tmp:
        return ret;
 }
 
-int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
+static int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                                  struct drm_file *file_priv,
                                  unsigned flags, unsigned color,
                                  struct drm_clip_rect *clips,
@@ -609,9 +609,13 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
        if (!dev_priv->sou_priv)
                return -EINVAL;
 
+       drm_modeset_lock_all(dev_priv->dev);
+
        ret = ttm_read_lock(&vmaster->lock, true);
-       if (unlikely(ret != 0))
+       if (unlikely(ret != 0)) {
+               drm_modeset_unlock_all(dev_priv->dev);
                return ret;
+       }
 
        if (!num_clips) {
                num_clips = 1;
@@ -629,6 +633,9 @@ int vmw_framebuffer_surface_dirty(struct drm_framebuffer *framebuffer,
                                   clips, num_clips, inc, NULL);
 
        ttm_read_unlock(&vmaster->lock);
+
+       drm_modeset_unlock_all(dev_priv->dev);
+
        return 0;
 }
 
@@ -665,9 +672,9 @@ static int vmw_kms_new_framebuffer_surface(struct vmw_private *dev_priv,
 
        if (unlikely(surface->mip_levels[0] != 1 ||
                     surface->num_sizes != 1 ||
-                    surface->sizes[0].width < mode_cmd->width ||
-                    surface->sizes[0].height < mode_cmd->height ||
-                    surface->sizes[0].depth != 1)) {
+                    surface->base_size.width < mode_cmd->width ||
+                    surface->base_size.height < mode_cmd->height ||
+                    surface->base_size.depth != 1)) {
                DRM_ERROR("Incompatible surface dimensions "
                          "for requested mode.\n");
                return -EINVAL;
@@ -754,7 +761,7 @@ struct vmw_framebuffer_dmabuf {
        struct vmw_dma_buffer *buffer;
 };
 
-void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
+static void vmw_framebuffer_dmabuf_destroy(struct drm_framebuffer *framebuffer)
 {
        struct vmw_framebuffer_dmabuf *vfbd =
                vmw_framebuffer_to_vfbd(framebuffer);
@@ -940,7 +947,7 @@ static int do_dmabuf_dirty_sou(struct drm_file *file_priv,
        return ret;
 }
 
-int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
+static int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
                                 struct drm_file *file_priv,
                                 unsigned flags, unsigned color,
                                 struct drm_clip_rect *clips,
@@ -953,9 +960,13 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
        struct drm_clip_rect norect;
        int ret, increment = 1;
 
+       drm_modeset_lock_all(dev_priv->dev);
+
        ret = ttm_read_lock(&vmaster->lock, true);
-       if (unlikely(ret != 0))
+       if (unlikely(ret != 0)) {
+               drm_modeset_unlock_all(dev_priv->dev);
                return ret;
+       }
 
        if (!num_clips) {
                num_clips = 1;
@@ -979,6 +990,9 @@ int vmw_framebuffer_dmabuf_dirty(struct drm_framebuffer *framebuffer,
        }
 
        ttm_read_unlock(&vmaster->lock);
+
+       drm_modeset_unlock_all(dev_priv->dev);
+
        return ret;
 }
 
@@ -1631,7 +1645,7 @@ bool vmw_kms_validate_mode_vram(struct vmw_private *dev_priv,
                                uint32_t pitch,
                                uint32_t height)
 {
-       return ((u64) pitch * (u64) height) < (u64) dev_priv->vram_size;
+       return ((u64) pitch * (u64) height) < (u64) dev_priv->prim_bb_mem;
 }
 
 
@@ -1663,7 +1677,7 @@ void vmw_disable_vblank(struct drm_device *dev, int crtc)
  * Small shared kms functions.
  */
 
-int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
+static int vmw_du_update_layout(struct vmw_private *dev_priv, unsigned num,
                         struct drm_vmw_rect *rects)
 {
        struct drm_device *dev = dev_priv->dev;
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c b/drivers/gpu/drm/vmwgfx/vmwgfx_mob.c
new file mode 100644 (file)
index 0000000..4910e7b
--- /dev/null
@@ -0,0 +1,652 @@
+/**************************************************************************
+ *
+ * Copyright Â© 2012 VMware, Inc., Palo Alto, CA., USA
+ * 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.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_drv.h"
+
+/*
+ * If we set up the screen target otable, screen objects stop working.
+ */
+
+#define VMW_OTABLE_SETUP_SUB ((VMWGFX_ENABLE_SCREEN_TARGET_OTABLE) ? 0 : 1)
+
+#ifdef CONFIG_64BIT
+#define VMW_PPN_SIZE 8
+#define VMW_MOBFMT_PTDEPTH_0 SVGA3D_MOBFMT_PTDEPTH64_0
+#define VMW_MOBFMT_PTDEPTH_1 SVGA3D_MOBFMT_PTDEPTH64_1
+#define VMW_MOBFMT_PTDEPTH_2 SVGA3D_MOBFMT_PTDEPTH64_2
+#else
+#define VMW_PPN_SIZE 4
+#define VMW_MOBFMT_PTDEPTH_0 SVGA3D_MOBFMT_PTDEPTH_0
+#define VMW_MOBFMT_PTDEPTH_1 SVGA3D_MOBFMT_PTDEPTH_1
+#define VMW_MOBFMT_PTDEPTH_2 SVGA3D_MOBFMT_PTDEPTH_2
+#endif
+
+/*
+ * struct vmw_mob - Structure containing page table and metadata for a
+ * Guest Memory OBject.
+ *
+ * @num_pages       Number of pages that make up the page table.
+ * @pt_level        The indirection level of the page table. 0-2.
+ * @pt_root_page    DMA address of the level 0 page of the page table.
+ */
+struct vmw_mob {
+       struct ttm_buffer_object *pt_bo;
+       unsigned long num_pages;
+       unsigned pt_level;
+       dma_addr_t pt_root_page;
+       uint32_t id;
+};
+
+/*
+ * struct vmw_otable - Guest Memory OBject table metadata
+ *
+ * @size:           Size of the table (page-aligned).
+ * @page_table:     Pointer to a struct vmw_mob holding the page table.
+ */
+struct vmw_otable {
+       unsigned long size;
+       struct vmw_mob *page_table;
+};
+
+static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
+                              struct vmw_mob *mob);
+static void vmw_mob_pt_setup(struct vmw_mob *mob,
+                            struct vmw_piter data_iter,
+                            unsigned long num_data_pages);
+
+/*
+ * vmw_setup_otable_base - Issue an object table base setup command to
+ * the device
+ *
+ * @dev_priv:       Pointer to a device private structure
+ * @type:           Type of object table base
+ * @offset          Start of table offset into dev_priv::otable_bo
+ * @otable          Pointer to otable metadata;
+ *
+ * This function returns -ENOMEM if it fails to reserve fifo space,
+ * and may block waiting for fifo space.
+ */
+static int vmw_setup_otable_base(struct vmw_private *dev_priv,
+                                SVGAOTableType type,
+                                unsigned long offset,
+                                struct vmw_otable *otable)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSetOTableBase64 body;
+       } *cmd;
+       struct vmw_mob *mob;
+       const struct vmw_sg_table *vsgt;
+       struct vmw_piter iter;
+       int ret;
+
+       BUG_ON(otable->page_table != NULL);
+
+       vsgt = vmw_bo_sg_table(dev_priv->otable_bo);
+       vmw_piter_start(&iter, vsgt, offset >> PAGE_SHIFT);
+       WARN_ON(!vmw_piter_next(&iter));
+
+       mob = vmw_mob_create(otable->size >> PAGE_SHIFT);
+       if (unlikely(mob == NULL)) {
+               DRM_ERROR("Failed creating OTable page table.\n");
+               return -ENOMEM;
+       }
+
+       if (otable->size <= PAGE_SIZE) {
+               mob->pt_level = VMW_MOBFMT_PTDEPTH_0;
+               mob->pt_root_page = vmw_piter_dma_addr(&iter);
+       } else if (vsgt->num_regions == 1) {
+               mob->pt_level = SVGA3D_MOBFMT_RANGE;
+               mob->pt_root_page = vmw_piter_dma_addr(&iter);
+       } else {
+               ret = vmw_mob_pt_populate(dev_priv, mob);
+               if (unlikely(ret != 0))
+                       goto out_no_populate;
+
+               vmw_mob_pt_setup(mob, iter, otable->size >> PAGE_SHIFT);
+               mob->pt_level += VMW_MOBFMT_PTDEPTH_1 - SVGA3D_MOBFMT_PTDEPTH_1;
+       }
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for OTable setup.\n");
+               goto out_no_fifo;
+       }
+
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE64;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.type = type;
+       cmd->body.baseAddress = cpu_to_le64(mob->pt_root_page >> PAGE_SHIFT);
+       cmd->body.sizeInBytes = otable->size;
+       cmd->body.validSizeInBytes = 0;
+       cmd->body.ptDepth = mob->pt_level;
+
+       /*
+        * The device doesn't support this, But the otable size is
+        * determined at compile-time, so this BUG shouldn't trigger
+        * randomly.
+        */
+       BUG_ON(mob->pt_level == VMW_MOBFMT_PTDEPTH_2);
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       otable->page_table = mob;
+
+       return 0;
+
+out_no_fifo:
+out_no_populate:
+       vmw_mob_destroy(mob);
+       return ret;
+}
+
+/*
+ * vmw_takedown_otable_base - Issue an object table base takedown command
+ * to the device
+ *
+ * @dev_priv:       Pointer to a device private structure
+ * @type:           Type of object table base
+ *
+ */
+static void vmw_takedown_otable_base(struct vmw_private *dev_priv,
+                                    SVGAOTableType type,
+                                    struct vmw_otable *otable)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdSetOTableBase body;
+       } *cmd;
+       struct ttm_buffer_object *bo;
+
+       if (otable->page_table == NULL)
+               return;
+
+       bo = otable->page_table->pt_bo;
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL))
+               DRM_ERROR("Failed reserving FIFO space for OTable setup.\n");
+
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->header.id = SVGA_3D_CMD_SET_OTABLE_BASE;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.type = type;
+       cmd->body.baseAddress = 0;
+       cmd->body.sizeInBytes = 0;
+       cmd->body.validSizeInBytes = 0;
+       cmd->body.ptDepth = SVGA3D_MOBFMT_INVALID;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       if (bo) {
+               int ret;
+
+               ret = ttm_bo_reserve(bo, false, true, false, NULL);
+               BUG_ON(ret != 0);
+
+               vmw_fence_single_bo(bo, NULL);
+               ttm_bo_unreserve(bo);
+       }
+
+       vmw_mob_destroy(otable->page_table);
+       otable->page_table = NULL;
+}
+
+/*
+ * vmw_otables_setup - Set up guest backed memory object tables
+ *
+ * @dev_priv:       Pointer to a device private structure
+ *
+ * Takes care of the device guest backed surface
+ * initialization, by setting up the guest backed memory object tables.
+ * Returns 0 on success and various error codes on failure. A succesful return
+ * means the object tables can be taken down using the vmw_otables_takedown
+ * function.
+ */
+int vmw_otables_setup(struct vmw_private *dev_priv)
+{
+       unsigned long offset;
+       unsigned long bo_size;
+       struct vmw_otable *otables;
+       SVGAOTableType i;
+       int ret;
+
+       otables = kzalloc(SVGA_OTABLE_DX9_MAX * sizeof(*otables),
+                         GFP_KERNEL);
+       if (unlikely(otables == NULL)) {
+               DRM_ERROR("Failed to allocate space for otable "
+                         "metadata.\n");
+               return -ENOMEM;
+       }
+
+       otables[SVGA_OTABLE_MOB].size =
+               VMWGFX_NUM_MOB * SVGA3D_OTABLE_MOB_ENTRY_SIZE;
+       otables[SVGA_OTABLE_SURFACE].size =
+               VMWGFX_NUM_GB_SURFACE * SVGA3D_OTABLE_SURFACE_ENTRY_SIZE;
+       otables[SVGA_OTABLE_CONTEXT].size =
+               VMWGFX_NUM_GB_CONTEXT * SVGA3D_OTABLE_CONTEXT_ENTRY_SIZE;
+       otables[SVGA_OTABLE_SHADER].size =
+               VMWGFX_NUM_GB_SHADER * SVGA3D_OTABLE_SHADER_ENTRY_SIZE;
+       otables[SVGA_OTABLE_SCREEN_TARGET].size =
+               VMWGFX_NUM_GB_SCREEN_TARGET *
+               SVGA3D_OTABLE_SCREEN_TARGET_ENTRY_SIZE;
+
+       bo_size = 0;
+       for (i = 0; i < SVGA_OTABLE_DX9_MAX; ++i) {
+               otables[i].size =
+                       (otables[i].size + PAGE_SIZE - 1) & PAGE_MASK;
+               bo_size += otables[i].size;
+       }
+
+       ret = ttm_bo_create(&dev_priv->bdev, bo_size,
+                           ttm_bo_type_device,
+                           &vmw_sys_ne_placement,
+                           0, false, NULL,
+                           &dev_priv->otable_bo);
+
+       if (unlikely(ret != 0))
+               goto out_no_bo;
+
+       ret = ttm_bo_reserve(dev_priv->otable_bo, false, true, false, NULL);
+       BUG_ON(ret != 0);
+       ret = vmw_bo_driver.ttm_tt_populate(dev_priv->otable_bo->ttm);
+       if (unlikely(ret != 0))
+               goto out_unreserve;
+       ret = vmw_bo_map_dma(dev_priv->otable_bo);
+       if (unlikely(ret != 0))
+               goto out_unreserve;
+
+       ttm_bo_unreserve(dev_priv->otable_bo);
+
+       offset = 0;
+       for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i) {
+               ret = vmw_setup_otable_base(dev_priv, i, offset,
+                                           &otables[i]);
+               if (unlikely(ret != 0))
+                       goto out_no_setup;
+               offset += otables[i].size;
+       }
+
+       dev_priv->otables = otables;
+       return 0;
+
+out_unreserve:
+       ttm_bo_unreserve(dev_priv->otable_bo);
+out_no_setup:
+       for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i)
+               vmw_takedown_otable_base(dev_priv, i, &otables[i]);
+
+       ttm_bo_unref(&dev_priv->otable_bo);
+out_no_bo:
+       kfree(otables);
+       return ret;
+}
+
+
+/*
+ * vmw_otables_takedown - Take down guest backed memory object tables
+ *
+ * @dev_priv:       Pointer to a device private structure
+ *
+ * Take down the Guest Memory Object tables.
+ */
+void vmw_otables_takedown(struct vmw_private *dev_priv)
+{
+       SVGAOTableType i;
+       struct ttm_buffer_object *bo = dev_priv->otable_bo;
+       int ret;
+
+       for (i = 0; i < SVGA_OTABLE_DX9_MAX - VMW_OTABLE_SETUP_SUB; ++i)
+               vmw_takedown_otable_base(dev_priv, i,
+                                        &dev_priv->otables[i]);
+
+       ret = ttm_bo_reserve(bo, false, true, false, NULL);
+       BUG_ON(ret != 0);
+
+       vmw_fence_single_bo(bo, NULL);
+       ttm_bo_unreserve(bo);
+
+       ttm_bo_unref(&dev_priv->otable_bo);
+       kfree(dev_priv->otables);
+       dev_priv->otables = NULL;
+}
+
+
+/*
+ * vmw_mob_calculate_pt_pages - Calculate the number of page table pages
+ * needed for a guest backed memory object.
+ *
+ * @data_pages:  Number of data pages in the memory object buffer.
+ */
+static unsigned long vmw_mob_calculate_pt_pages(unsigned long data_pages)
+{
+       unsigned long data_size = data_pages * PAGE_SIZE;
+       unsigned long tot_size = 0;
+
+       while (likely(data_size > PAGE_SIZE)) {
+               data_size = DIV_ROUND_UP(data_size, PAGE_SIZE);
+               data_size *= VMW_PPN_SIZE;
+               tot_size += (data_size + PAGE_SIZE - 1) & PAGE_MASK;
+       }
+
+       return tot_size >> PAGE_SHIFT;
+}
+
+/*
+ * vmw_mob_create - Create a mob, but don't populate it.
+ *
+ * @data_pages:  Number of data pages of the underlying buffer object.
+ */
+struct vmw_mob *vmw_mob_create(unsigned long data_pages)
+{
+       struct vmw_mob *mob = kzalloc(sizeof(*mob), GFP_KERNEL);
+
+       if (unlikely(mob == NULL))
+               return NULL;
+
+       mob->num_pages = vmw_mob_calculate_pt_pages(data_pages);
+
+       return mob;
+}
+
+/*
+ * vmw_mob_pt_populate - Populate the mob pagetable
+ *
+ * @mob:         Pointer to the mob the pagetable of which we want to
+ *               populate.
+ *
+ * This function allocates memory to be used for the pagetable, and
+ * adjusts TTM memory accounting accordingly. Returns ENOMEM if
+ * memory resources aren't sufficient and may cause TTM buffer objects
+ * to be swapped out by using the TTM memory accounting function.
+ */
+static int vmw_mob_pt_populate(struct vmw_private *dev_priv,
+                              struct vmw_mob *mob)
+{
+       int ret;
+       BUG_ON(mob->pt_bo != NULL);
+
+       ret = ttm_bo_create(&dev_priv->bdev, mob->num_pages * PAGE_SIZE,
+                           ttm_bo_type_device,
+                           &vmw_sys_ne_placement,
+                           0, false, NULL, &mob->pt_bo);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = ttm_bo_reserve(mob->pt_bo, false, true, false, NULL);
+
+       BUG_ON(ret != 0);
+       ret = vmw_bo_driver.ttm_tt_populate(mob->pt_bo->ttm);
+       if (unlikely(ret != 0))
+               goto out_unreserve;
+       ret = vmw_bo_map_dma(mob->pt_bo);
+       if (unlikely(ret != 0))
+               goto out_unreserve;
+
+       ttm_bo_unreserve(mob->pt_bo);
+       
+       return 0;
+
+out_unreserve:
+       ttm_bo_unreserve(mob->pt_bo);
+       ttm_bo_unref(&mob->pt_bo);
+
+       return ret;
+}
+
+/**
+ * vmw_mob_assign_ppn - Assign a value to a page table entry
+ *
+ * @addr: Pointer to pointer to page table entry.
+ * @val: The page table entry
+ *
+ * Assigns a value to a page table entry pointed to by *@addr and increments
+ * *@addr according to the page table entry size.
+ */
+#if (VMW_PPN_SIZE == 8)
+static void vmw_mob_assign_ppn(__le32 **addr, dma_addr_t val)
+{
+       *((__le64 *) *addr) = cpu_to_le64(val >> PAGE_SHIFT);
+       *addr += 2;
+}
+#else
+static void vmw_mob_assign_ppn(__le32 **addr, dma_addr_t val)
+{
+       *(*addr)++ = cpu_to_le32(val >> PAGE_SHIFT);
+}
+#endif
+
+/*
+ * vmw_mob_build_pt - Build a pagetable
+ *
+ * @data_addr:      Array of DMA addresses to the underlying buffer
+ *                  object's data pages.
+ * @num_data_pages: Number of buffer object data pages.
+ * @pt_pages:       Array of page pointers to the page table pages.
+ *
+ * Returns the number of page table pages actually used.
+ * Uses atomic kmaps of highmem pages to avoid TLB thrashing.
+ */
+static unsigned long vmw_mob_build_pt(struct vmw_piter *data_iter,
+                                     unsigned long num_data_pages,
+                                     struct vmw_piter *pt_iter)
+{
+       unsigned long pt_size = num_data_pages * VMW_PPN_SIZE;
+       unsigned long num_pt_pages = DIV_ROUND_UP(pt_size, PAGE_SIZE);
+       unsigned long pt_page;
+       __le32 *addr, *save_addr;
+       unsigned long i;
+       struct page *page;
+
+       for (pt_page = 0; pt_page < num_pt_pages; ++pt_page) {
+               page = vmw_piter_page(pt_iter);
+
+               save_addr = addr = kmap_atomic(page);
+
+               for (i = 0; i < PAGE_SIZE / VMW_PPN_SIZE; ++i) {
+                       vmw_mob_assign_ppn(&addr,
+                                          vmw_piter_dma_addr(data_iter));
+                       if (unlikely(--num_data_pages == 0))
+                               break;
+                       WARN_ON(!vmw_piter_next(data_iter));
+               }
+               kunmap_atomic(save_addr);
+               vmw_piter_next(pt_iter);
+       }
+
+       return num_pt_pages;
+}
+
+/*
+ * vmw_mob_build_pt - Set up a multilevel mob pagetable
+ *
+ * @mob:            Pointer to a mob whose page table needs setting up.
+ * @data_addr       Array of DMA addresses to the buffer object's data
+ *                  pages.
+ * @num_data_pages: Number of buffer object data pages.
+ *
+ * Uses tail recursion to set up a multilevel mob page table.
+ */
+static void vmw_mob_pt_setup(struct vmw_mob *mob,
+                            struct vmw_piter data_iter,
+                            unsigned long num_data_pages)
+{
+       unsigned long num_pt_pages = 0;
+       struct ttm_buffer_object *bo = mob->pt_bo;
+       struct vmw_piter save_pt_iter;
+       struct vmw_piter pt_iter;
+       const struct vmw_sg_table *vsgt;
+       int ret;
+
+       ret = ttm_bo_reserve(bo, false, true, false, NULL);
+       BUG_ON(ret != 0);
+
+       vsgt = vmw_bo_sg_table(bo);
+       vmw_piter_start(&pt_iter, vsgt, 0);
+       BUG_ON(!vmw_piter_next(&pt_iter));
+       mob->pt_level = 0;
+       while (likely(num_data_pages > 1)) {
+               ++mob->pt_level;
+               BUG_ON(mob->pt_level > 2);
+               save_pt_iter = pt_iter;
+               num_pt_pages = vmw_mob_build_pt(&data_iter, num_data_pages,
+                                               &pt_iter);
+               data_iter = save_pt_iter;
+               num_data_pages = num_pt_pages;
+       }
+
+       mob->pt_root_page = vmw_piter_dma_addr(&save_pt_iter);
+       ttm_bo_unreserve(bo);
+}
+
+/*
+ * vmw_mob_destroy - Destroy a mob, unpopulating first if necessary.
+ *
+ * @mob:            Pointer to a mob to destroy.
+ */
+void vmw_mob_destroy(struct vmw_mob *mob)
+{
+       if (mob->pt_bo)
+               ttm_bo_unref(&mob->pt_bo);
+       kfree(mob);
+}
+
+/*
+ * vmw_mob_unbind - Hide a mob from the device.
+ *
+ * @dev_priv:       Pointer to a device private.
+ * @mob_id:         Device id of the mob to unbind.
+ */
+void vmw_mob_unbind(struct vmw_private *dev_priv,
+                   struct vmw_mob *mob)
+{
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDestroyGBMob body;
+       } *cmd;
+       int ret;
+       struct ttm_buffer_object *bo = mob->pt_bo;
+
+       if (bo) {
+               ret = ttm_bo_reserve(bo, false, true, false, NULL);
+               /*
+                * Noone else should be using this buffer.
+                */
+               BUG_ON(ret != 0);
+       }
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for Memory "
+                         "Object unbinding.\n");
+       }
+       cmd->header.id = SVGA_3D_CMD_DESTROY_GB_MOB;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.mobid = mob->id;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       if (bo) {
+               vmw_fence_single_bo(bo, NULL);
+               ttm_bo_unreserve(bo);
+       }
+       vmw_3d_resource_dec(dev_priv, false);
+}
+
+/*
+ * vmw_mob_bind - Make a mob visible to the device after first
+ *                populating it if necessary.
+ *
+ * @dev_priv:       Pointer to a device private.
+ * @mob:            Pointer to the mob we're making visible.
+ * @data_addr:      Array of DMA addresses to the data pages of the underlying
+ *                  buffer object.
+ * @num_data_pages: Number of data pages of the underlying buffer
+ *                  object.
+ * @mob_id:         Device id of the mob to bind
+ *
+ * This function is intended to be interfaced with the ttm_tt backend
+ * code.
+ */
+int vmw_mob_bind(struct vmw_private *dev_priv,
+                struct vmw_mob *mob,
+                const struct vmw_sg_table *vsgt,
+                unsigned long num_data_pages,
+                int32_t mob_id)
+{
+       int ret;
+       bool pt_set_up = false;
+       struct vmw_piter data_iter;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDefineGBMob64 body;
+       } *cmd;
+
+       mob->id = mob_id;
+       vmw_piter_start(&data_iter, vsgt, 0);
+       if (unlikely(!vmw_piter_next(&data_iter)))
+               return 0;
+
+       if (likely(num_data_pages == 1)) {
+               mob->pt_level = VMW_MOBFMT_PTDEPTH_0;
+               mob->pt_root_page = vmw_piter_dma_addr(&data_iter);
+       } else if (vsgt->num_regions == 1) {
+               mob->pt_level = SVGA3D_MOBFMT_RANGE;
+               mob->pt_root_page = vmw_piter_dma_addr(&data_iter);
+       } else if (unlikely(mob->pt_bo == NULL)) {
+               ret = vmw_mob_pt_populate(dev_priv, mob);
+               if (unlikely(ret != 0))
+                       return ret;
+
+               vmw_mob_pt_setup(mob, data_iter, num_data_pages);
+               pt_set_up = true;
+               mob->pt_level += VMW_MOBFMT_PTDEPTH_1 - SVGA3D_MOBFMT_PTDEPTH_1;
+       }
+
+       (void) vmw_3d_resource_inc(dev_priv, false);
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for Memory "
+                         "Object binding.\n");
+               goto out_no_cmd_space;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_DEFINE_GB_MOB64;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.mobid = mob_id;
+       cmd->body.ptDepth = mob->pt_level;
+       cmd->body.base = cpu_to_le64(mob->pt_root_page >> PAGE_SHIFT);
+       cmd->body.sizeInBytes = num_data_pages * PAGE_SIZE;
+
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       return 0;
+
+out_no_cmd_space:
+       vmw_3d_resource_dec(dev_priv, false);
+       if (pt_set_up)
+               ttm_bo_unref(&mob->pt_bo);
+
+       return -ENOMEM;
+}
index 9b5ea2ac7ddff21562aa7ef52a2f96872c623116..6fdd82d42f6549d2af208516ad22b26d45785e28 100644 (file)
@@ -215,6 +215,7 @@ int vmw_resource_init(struct vmw_private *dev_priv, struct vmw_resource *res,
        res->func = func;
        INIT_LIST_HEAD(&res->lru_head);
        INIT_LIST_HEAD(&res->mob_head);
+       INIT_LIST_HEAD(&res->binding_head);
        res->id = -1;
        res->backup = NULL;
        res->backup_offset = 0;
@@ -441,6 +442,21 @@ static void vmw_user_dmabuf_release(struct ttm_base_object **p_base)
        ttm_bo_unref(&bo);
 }
 
+static void vmw_user_dmabuf_ref_obj_release(struct ttm_base_object *base,
+                                           enum ttm_ref_type ref_type)
+{
+       struct vmw_user_dma_buffer *user_bo;
+       user_bo = container_of(base, struct vmw_user_dma_buffer, prime.base);
+
+       switch (ref_type) {
+       case TTM_REF_SYNCCPU_WRITE:
+               ttm_bo_synccpu_write_release(&user_bo->dma.base);
+               break;
+       default:
+               BUG();
+       }
+}
+
 /**
  * vmw_user_dmabuf_alloc - Allocate a user dma buffer
  *
@@ -471,6 +487,8 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
        }
 
        ret = vmw_dmabuf_init(dev_priv, &user_bo->dma, size,
+                             (dev_priv->has_mob) ?
+                             &vmw_sys_placement :
                              &vmw_vram_sys_placement, true,
                              &vmw_user_dmabuf_destroy);
        if (unlikely(ret != 0))
@@ -482,7 +500,8 @@ int vmw_user_dmabuf_alloc(struct vmw_private *dev_priv,
                                    &user_bo->prime,
                                    shareable,
                                    ttm_buffer_type,
-                                   &vmw_user_dmabuf_release, NULL);
+                                   &vmw_user_dmabuf_release,
+                                   &vmw_user_dmabuf_ref_obj_release);
        if (unlikely(ret != 0)) {
                ttm_bo_unref(&tmp);
                goto out_no_base_object;
@@ -515,6 +534,130 @@ int vmw_user_dmabuf_verify_access(struct ttm_buffer_object *bo,
                vmw_user_bo->prime.base.shareable) ? 0 : -EPERM;
 }
 
+/**
+ * vmw_user_dmabuf_synccpu_grab - Grab a struct vmw_user_dma_buffer for cpu
+ * access, idling previous GPU operations on the buffer and optionally
+ * blocking it for further command submissions.
+ *
+ * @user_bo: Pointer to the buffer object being grabbed for CPU access
+ * @tfile: Identifying the caller.
+ * @flags: Flags indicating how the grab should be performed.
+ *
+ * A blocking grab will be automatically released when @tfile is closed.
+ */
+static int vmw_user_dmabuf_synccpu_grab(struct vmw_user_dma_buffer *user_bo,
+                                       struct ttm_object_file *tfile,
+                                       uint32_t flags)
+{
+       struct ttm_buffer_object *bo = &user_bo->dma.base;
+       bool existed;
+       int ret;
+
+       if (flags & drm_vmw_synccpu_allow_cs) {
+               struct ttm_bo_device *bdev = bo->bdev;
+
+               spin_lock(&bdev->fence_lock);
+               ret = ttm_bo_wait(bo, false, true,
+                                 !!(flags & drm_vmw_synccpu_dontblock));
+               spin_unlock(&bdev->fence_lock);
+               return ret;
+       }
+
+       ret = ttm_bo_synccpu_write_grab
+               (bo, !!(flags & drm_vmw_synccpu_dontblock));
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = ttm_ref_object_add(tfile, &user_bo->prime.base,
+                                TTM_REF_SYNCCPU_WRITE, &existed);
+       if (ret != 0 || existed)
+               ttm_bo_synccpu_write_release(&user_bo->dma.base);
+
+       return ret;
+}
+
+/**
+ * vmw_user_dmabuf_synccpu_release - Release a previous grab for CPU access,
+ * and unblock command submission on the buffer if blocked.
+ *
+ * @handle: Handle identifying the buffer object.
+ * @tfile: Identifying the caller.
+ * @flags: Flags indicating the type of release.
+ */
+static int vmw_user_dmabuf_synccpu_release(uint32_t handle,
+                                          struct ttm_object_file *tfile,
+                                          uint32_t flags)
+{
+       if (!(flags & drm_vmw_synccpu_allow_cs))
+               return ttm_ref_object_base_unref(tfile, handle,
+                                                TTM_REF_SYNCCPU_WRITE);
+
+       return 0;
+}
+
+/**
+ * vmw_user_dmabuf_synccpu_release - ioctl function implementing the synccpu
+ * functionality.
+ *
+ * @dev: Identifies the drm device.
+ * @data: Pointer to the ioctl argument.
+ * @file_priv: Identifies the caller.
+ *
+ * This function checks the ioctl arguments for validity and calls the
+ * relevant synccpu functions.
+ */
+int vmw_user_dmabuf_synccpu_ioctl(struct drm_device *dev, void *data,
+                                 struct drm_file *file_priv)
+{
+       struct drm_vmw_synccpu_arg *arg =
+               (struct drm_vmw_synccpu_arg *) data;
+       struct vmw_dma_buffer *dma_buf;
+       struct vmw_user_dma_buffer *user_bo;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       int ret;
+
+       if ((arg->flags & (drm_vmw_synccpu_read | drm_vmw_synccpu_write)) == 0
+           || (arg->flags & ~(drm_vmw_synccpu_read | drm_vmw_synccpu_write |
+                              drm_vmw_synccpu_dontblock |
+                              drm_vmw_synccpu_allow_cs)) != 0) {
+               DRM_ERROR("Illegal synccpu flags.\n");
+               return -EINVAL;
+       }
+
+       switch (arg->op) {
+       case drm_vmw_synccpu_grab:
+               ret = vmw_user_dmabuf_lookup(tfile, arg->handle, &dma_buf);
+               if (unlikely(ret != 0))
+                       return ret;
+
+               user_bo = container_of(dma_buf, struct vmw_user_dma_buffer,
+                                      dma);
+               ret = vmw_user_dmabuf_synccpu_grab(user_bo, tfile, arg->flags);
+               vmw_dmabuf_unreference(&dma_buf);
+               if (unlikely(ret != 0 && ret != -ERESTARTSYS &&
+                            ret != -EBUSY)) {
+                       DRM_ERROR("Failed synccpu grab on handle 0x%08x.\n",
+                                 (unsigned int) arg->handle);
+                       return ret;
+               }
+               break;
+       case drm_vmw_synccpu_release:
+               ret = vmw_user_dmabuf_synccpu_release(arg->handle, tfile,
+                                                     arg->flags);
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("Failed synccpu release on handle 0x%08x.\n",
+                                 (unsigned int) arg->handle);
+                       return ret;
+               }
+               break;
+       default:
+               DRM_ERROR("Invalid synccpu operation.\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
 int vmw_dmabuf_alloc_ioctl(struct drm_device *dev, void *data,
                           struct drm_file *file_priv)
 {
@@ -591,7 +734,8 @@ int vmw_user_dmabuf_lookup(struct ttm_object_file *tfile,
 }
 
 int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
-                             struct vmw_dma_buffer *dma_buf)
+                             struct vmw_dma_buffer *dma_buf,
+                             uint32_t *handle)
 {
        struct vmw_user_dma_buffer *user_bo;
 
@@ -599,6 +743,8 @@ int vmw_user_dmabuf_reference(struct ttm_object_file *tfile,
                return -EINVAL;
 
        user_bo = container_of(dma_buf, struct vmw_user_dma_buffer, dma);
+
+       *handle = user_bo->prime.base.hash.key;
        return ttm_ref_object_add(tfile, &user_bo->prime.base,
                                  TTM_REF_USAGE, NULL);
 }
@@ -1291,11 +1437,54 @@ void vmw_fence_single_bo(struct ttm_buffer_object *bo,
  * @mem:            The truct ttm_mem_reg indicating to what memory
  *                  region the move is taking place.
  *
- * For now does nothing.
+ * Evicts the Guest Backed hardware resource if the backup
+ * buffer is being moved out of MOB memory.
+ * Note that this function should not race with the resource
+ * validation code as long as it accesses only members of struct
+ * resource that remain static while bo::res is !NULL and
+ * while we have @bo reserved. struct resource::backup is *not* a
+ * static member. The resource validation code will take care
+ * to set @bo::res to NULL, while having @bo reserved when the
+ * buffer is no longer bound to the resource, so @bo:res can be
+ * used to determine whether there is a need to unbind and whether
+ * it is safe to unbind.
  */
 void vmw_resource_move_notify(struct ttm_buffer_object *bo,
                              struct ttm_mem_reg *mem)
 {
+       struct vmw_dma_buffer *dma_buf;
+
+       if (mem == NULL)
+               return;
+
+       if (bo->destroy != vmw_dmabuf_bo_free &&
+           bo->destroy != vmw_user_dmabuf_destroy)
+               return;
+
+       dma_buf = container_of(bo, struct vmw_dma_buffer, base);
+
+       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;
+
+               list_for_each_entry_safe(res, n, &dma_buf->res_list, mob_head) {
+
+                       if (unlikely(res->func->unbind == NULL))
+                               continue;
+
+                       (void) res->func->unbind(res, true, &val_buf);
+                       res->backup_dirty = true;
+                       res->res_dirty = false;
+                       list_del_init(&res->mob_head);
+               }
+
+               spin_lock(&bdev->fence_lock);
+               (void) ttm_bo_wait(bo, false, false, false);
+               spin_unlock(&bdev->fence_lock);
+       }
 }
 
 /**
diff --git a/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c b/drivers/gpu/drm/vmwgfx/vmwgfx_shader.c
new file mode 100644 (file)
index 0000000..1457ec4
--- /dev/null
@@ -0,0 +1,441 @@
+/**************************************************************************
+ *
+ * Copyright Â© 2009-2012 VMware, Inc., Palo Alto, CA., USA
+ * 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.
+ *
+ **************************************************************************/
+
+#include "vmwgfx_drv.h"
+#include "vmwgfx_resource_priv.h"
+#include "ttm/ttm_placement.h"
+
+struct vmw_shader {
+       struct vmw_resource res;
+       SVGA3dShaderType type;
+       uint32_t size;
+};
+
+struct vmw_user_shader {
+       struct ttm_base_object base;
+       struct vmw_shader shader;
+};
+
+static void vmw_user_shader_free(struct vmw_resource *res);
+static struct vmw_resource *
+vmw_user_shader_base_to_res(struct ttm_base_object *base);
+
+static int vmw_gb_shader_create(struct vmw_resource *res);
+static int vmw_gb_shader_bind(struct vmw_resource *res,
+                              struct ttm_validate_buffer *val_buf);
+static int vmw_gb_shader_unbind(struct vmw_resource *res,
+                                bool readback,
+                                struct ttm_validate_buffer *val_buf);
+static int vmw_gb_shader_destroy(struct vmw_resource *res);
+
+static uint64_t vmw_user_shader_size;
+
+static const struct vmw_user_resource_conv user_shader_conv = {
+       .object_type = VMW_RES_SHADER,
+       .base_obj_to_res = vmw_user_shader_base_to_res,
+       .res_free = vmw_user_shader_free
+};
+
+const struct vmw_user_resource_conv *user_shader_converter =
+       &user_shader_conv;
+
+
+static const struct vmw_res_func vmw_gb_shader_func = {
+       .res_type = vmw_res_shader,
+       .needs_backup = true,
+       .may_evict = true,
+       .type_name = "guest backed shaders",
+       .backup_placement = &vmw_mob_placement,
+       .create = vmw_gb_shader_create,
+       .destroy = vmw_gb_shader_destroy,
+       .bind = vmw_gb_shader_bind,
+       .unbind = vmw_gb_shader_unbind
+};
+
+/**
+ * Shader management:
+ */
+
+static inline struct vmw_shader *
+vmw_res_to_shader(struct vmw_resource *res)
+{
+       return container_of(res, struct vmw_shader, res);
+}
+
+static void vmw_hw_shader_destroy(struct vmw_resource *res)
+{
+       (void) vmw_gb_shader_destroy(res);
+}
+
+static int vmw_gb_shader_init(struct vmw_private *dev_priv,
+                             struct vmw_resource *res,
+                             uint32_t size,
+                             uint64_t offset,
+                             SVGA3dShaderType type,
+                             struct vmw_dma_buffer *byte_code,
+                             void (*res_free) (struct vmw_resource *res))
+{
+       struct vmw_shader *shader = vmw_res_to_shader(res);
+       int ret;
+
+       ret = vmw_resource_init(dev_priv, res, true,
+                               res_free, &vmw_gb_shader_func);
+
+
+       if (unlikely(ret != 0)) {
+               if (res_free)
+                       res_free(res);
+               else
+                       kfree(res);
+               return ret;
+       }
+
+       res->backup_size = size;
+       if (byte_code) {
+               res->backup = vmw_dmabuf_reference(byte_code);
+               res->backup_offset = offset;
+       }
+       shader->size = size;
+       shader->type = type;
+
+       vmw_resource_activate(res, vmw_hw_shader_destroy);
+       return 0;
+}
+
+static int vmw_gb_shader_create(struct vmw_resource *res)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct vmw_shader *shader = vmw_res_to_shader(res);
+       int ret;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDefineGBShader body;
+       } *cmd;
+
+       if (likely(res->id != -1))
+               return 0;
+
+       ret = vmw_resource_alloc_id(res);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed to allocate a shader id.\n");
+               goto out_no_id;
+       }
+
+       if (unlikely(res->id >= VMWGFX_NUM_GB_SHADER)) {
+               ret = -EBUSY;
+               goto out_no_fifo;
+       }
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for shader "
+                         "creation.\n");
+               ret = -ENOMEM;
+               goto out_no_fifo;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SHADER;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.shid = res->id;
+       cmd->body.type = shader->type;
+       cmd->body.sizeInBytes = shader->size;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       (void) vmw_3d_resource_inc(dev_priv, false);
+
+       return 0;
+
+out_no_fifo:
+       vmw_resource_release_id(res);
+out_no_id:
+       return ret;
+}
+
+static int vmw_gb_shader_bind(struct vmw_resource *res,
+                             struct ttm_validate_buffer *val_buf)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBindGBShader body;
+       } *cmd;
+       struct ttm_buffer_object *bo = val_buf->bo;
+
+       BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for shader "
+                         "binding.\n");
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.shid = res->id;
+       cmd->body.mobid = bo->mem.start;
+       cmd->body.offsetInBytes = 0;
+       res->backup_dirty = false;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       return 0;
+}
+
+static int vmw_gb_shader_unbind(struct vmw_resource *res,
+                               bool readback,
+                               struct ttm_validate_buffer *val_buf)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBindGBShader body;
+       } *cmd;
+       struct vmw_fence_obj *fence;
+
+       BUG_ON(res->backup->base.mem.mem_type != VMW_PL_MOB);
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for shader "
+                         "unbinding.\n");
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_BIND_GB_SHADER;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.shid = res->id;
+       cmd->body.mobid = SVGA3D_INVALID_ID;
+       cmd->body.offsetInBytes = 0;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+
+       /*
+        * Create a fence object and fence the backup buffer.
+        */
+
+       (void) vmw_execbuf_fence_commands(NULL, dev_priv,
+                                         &fence, NULL);
+
+       vmw_fence_single_bo(val_buf->bo, fence);
+
+       if (likely(fence != NULL))
+               vmw_fence_obj_unreference(&fence);
+
+       return 0;
+}
+
+static int vmw_gb_shader_destroy(struct vmw_resource *res)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDestroyGBShader body;
+       } *cmd;
+
+       if (likely(res->id == -1))
+               return 0;
+
+       mutex_lock(&dev_priv->binding_mutex);
+       vmw_context_binding_res_list_kill(&res->binding_head);
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for shader "
+                         "destruction.\n");
+               mutex_unlock(&dev_priv->binding_mutex);
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SHADER;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.shid = res->id;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       mutex_unlock(&dev_priv->binding_mutex);
+       vmw_resource_release_id(res);
+       vmw_3d_resource_dec(dev_priv, false);
+
+       return 0;
+}
+
+/**
+ * User-space shader management:
+ */
+
+static struct vmw_resource *
+vmw_user_shader_base_to_res(struct ttm_base_object *base)
+{
+       return &(container_of(base, struct vmw_user_shader, base)->
+                shader.res);
+}
+
+static void vmw_user_shader_free(struct vmw_resource *res)
+{
+       struct vmw_user_shader *ushader =
+               container_of(res, struct vmw_user_shader, shader.res);
+       struct vmw_private *dev_priv = res->dev_priv;
+
+       ttm_base_object_kfree(ushader, base);
+       ttm_mem_global_free(vmw_mem_glob(dev_priv),
+                           vmw_user_shader_size);
+}
+
+/**
+ * This function is called when user space has no more references on the
+ * base object. It releases the base-object's reference on the resource object.
+ */
+
+static void vmw_user_shader_base_release(struct ttm_base_object **p_base)
+{
+       struct ttm_base_object *base = *p_base;
+       struct vmw_resource *res = vmw_user_shader_base_to_res(base);
+
+       *p_base = NULL;
+       vmw_resource_unreference(&res);
+}
+
+int vmw_shader_destroy_ioctl(struct drm_device *dev, void *data,
+                             struct drm_file *file_priv)
+{
+       struct drm_vmw_shader_arg *arg = (struct drm_vmw_shader_arg *)data;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+
+       return ttm_ref_object_base_unref(tfile, arg->handle,
+                                        TTM_REF_USAGE);
+}
+
+int vmw_shader_define_ioctl(struct drm_device *dev, void *data,
+                            struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_user_shader *ushader;
+       struct vmw_resource *res;
+       struct vmw_resource *tmp;
+       struct drm_vmw_shader_create_arg *arg =
+               (struct drm_vmw_shader_create_arg *)data;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
+       struct vmw_dma_buffer *buffer = NULL;
+       SVGA3dShaderType shader_type;
+       int ret;
+
+       if (arg->buffer_handle != SVGA3D_INVALID_ID) {
+               ret = vmw_user_dmabuf_lookup(tfile, arg->buffer_handle,
+                                            &buffer);
+               if (unlikely(ret != 0)) {
+                       DRM_ERROR("Could not find buffer for shader "
+                                 "creation.\n");
+                       return ret;
+               }
+
+               if ((u64)buffer->base.num_pages * PAGE_SIZE <
+                   (u64)arg->size + (u64)arg->offset) {
+                       DRM_ERROR("Illegal buffer- or shader size.\n");
+                       ret = -EINVAL;
+                       goto out_bad_arg;
+               }
+       }
+
+       switch (arg->shader_type) {
+       case drm_vmw_shader_type_vs:
+               shader_type = SVGA3D_SHADERTYPE_VS;
+               break;
+       case drm_vmw_shader_type_ps:
+               shader_type = SVGA3D_SHADERTYPE_PS;
+               break;
+       case drm_vmw_shader_type_gs:
+               shader_type = SVGA3D_SHADERTYPE_GS;
+               break;
+       default:
+               DRM_ERROR("Illegal shader type.\n");
+               ret = -EINVAL;
+               goto out_bad_arg;
+       }
+
+       /*
+        * Approximate idr memory usage with 128 bytes. It will be limited
+        * by maximum number_of shaders anyway.
+        */
+
+       if (unlikely(vmw_user_shader_size == 0))
+               vmw_user_shader_size = ttm_round_pot(sizeof(*ushader))
+                       + 128;
+
+       ret = ttm_read_lock(&vmaster->lock, true);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
+                                  vmw_user_shader_size,
+                                  false, true);
+       if (unlikely(ret != 0)) {
+               if (ret != -ERESTARTSYS)
+                       DRM_ERROR("Out of graphics memory for shader"
+                                 " creation.\n");
+               goto out_unlock;
+       }
+
+       ushader = kzalloc(sizeof(*ushader), GFP_KERNEL);
+       if (unlikely(ushader == NULL)) {
+               ttm_mem_global_free(vmw_mem_glob(dev_priv),
+                                   vmw_user_shader_size);
+               ret = -ENOMEM;
+               goto out_unlock;
+       }
+
+       res = &ushader->shader.res;
+       ushader->base.shareable = false;
+       ushader->base.tfile = NULL;
+
+       /*
+        * From here on, the destructor takes over resource freeing.
+        */
+
+       ret = vmw_gb_shader_init(dev_priv, res, arg->size,
+                                arg->offset, shader_type, buffer,
+                                vmw_user_shader_free);
+       if (unlikely(ret != 0))
+               goto out_unlock;
+
+       tmp = vmw_resource_reference(res);
+       ret = ttm_base_object_init(tfile, &ushader->base, false,
+                                  VMW_RES_SHADER,
+                                  &vmw_user_shader_base_release, NULL);
+
+       if (unlikely(ret != 0)) {
+               vmw_resource_unreference(&tmp);
+               goto out_err;
+       }
+
+       arg->shader_handle = ushader->base.hash.key;
+out_err:
+       vmw_resource_unreference(&res);
+out_unlock:
+       ttm_read_unlock(&vmaster->lock);
+out_bad_arg:
+       vmw_dmabuf_unreference(&buffer);
+
+       return ret;
+
+}
index 7de2ea8bd55357561913384bfa23196fe3479ec2..979da1c246a543a445257daee03787e794b266a1 100644 (file)
@@ -41,7 +41,6 @@ struct vmw_user_surface {
        struct ttm_prime_object prime;
        struct vmw_surface srf;
        uint32_t size;
-       uint32_t backup_handle;
 };
 
 /**
@@ -68,6 +67,14 @@ static int vmw_legacy_srf_unbind(struct vmw_resource *res,
                                 struct ttm_validate_buffer *val_buf);
 static int vmw_legacy_srf_create(struct vmw_resource *res);
 static int vmw_legacy_srf_destroy(struct vmw_resource *res);
+static int vmw_gb_surface_create(struct vmw_resource *res);
+static int vmw_gb_surface_bind(struct vmw_resource *res,
+                              struct ttm_validate_buffer *val_buf);
+static int vmw_gb_surface_unbind(struct vmw_resource *res,
+                                bool readback,
+                                struct ttm_validate_buffer *val_buf);
+static int vmw_gb_surface_destroy(struct vmw_resource *res);
+
 
 static const struct vmw_user_resource_conv user_surface_conv = {
        .object_type = VMW_RES_SURFACE,
@@ -93,6 +100,18 @@ static const struct vmw_res_func vmw_legacy_surface_func = {
        .unbind = &vmw_legacy_srf_unbind
 };
 
+static const struct vmw_res_func vmw_gb_surface_func = {
+       .res_type = vmw_res_surface,
+       .needs_backup = true,
+       .may_evict = true,
+       .type_name = "guest backed surfaces",
+       .backup_placement = &vmw_mob_placement,
+       .create = vmw_gb_surface_create,
+       .destroy = vmw_gb_surface_destroy,
+       .bind = vmw_gb_surface_bind,
+       .unbind = vmw_gb_surface_unbind
+};
+
 /**
  * struct vmw_surface_dma - SVGA3D DMA command
  */
@@ -291,6 +310,11 @@ static void vmw_hw_surface_destroy(struct vmw_resource *res)
        struct vmw_surface *srf;
        void *cmd;
 
+       if (res->func->destroy == vmw_gb_surface_destroy) {
+               (void) vmw_gb_surface_destroy(res);
+               return;
+       }
+
        if (res->id != -1) {
 
                cmd = vmw_fifo_reserve(dev_priv, vmw_surface_destroy_size());
@@ -549,12 +573,15 @@ static int vmw_surface_init(struct vmw_private *dev_priv,
        struct vmw_resource *res = &srf->res;
 
        BUG_ON(res_free == NULL);
-       (void) vmw_3d_resource_inc(dev_priv, false);
+       if (!dev_priv->has_mob)
+               (void) vmw_3d_resource_inc(dev_priv, false);
        ret = vmw_resource_init(dev_priv, res, true, res_free,
+                               (dev_priv->has_mob) ? &vmw_gb_surface_func :
                                &vmw_legacy_surface_func);
 
        if (unlikely(ret != 0)) {
-               vmw_3d_resource_dec(dev_priv, false);
+               if (!dev_priv->has_mob)
+                       vmw_3d_resource_dec(dev_priv, false);
                res_free(res);
                return ret;
        }
@@ -750,7 +777,7 @@ int vmw_surface_define_ioctl(struct drm_device *dev, void *data,
 
        srf->base_size = *srf->sizes;
        srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;
-       srf->multisample_count = 1;
+       srf->multisample_count = 0;
 
        cur_bo_offset = 0;
        cur_offset = srf->offsets;
@@ -843,6 +870,7 @@ out_unlock:
 int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
                                struct drm_file *file_priv)
 {
+       struct vmw_private *dev_priv = vmw_priv(dev);
        union drm_vmw_surface_reference_arg *arg =
            (union drm_vmw_surface_reference_arg *)data;
        struct drm_vmw_surface_arg *req = &arg->req;
@@ -854,7 +882,7 @@ int vmw_surface_reference_ioctl(struct drm_device *dev, void *data,
        struct ttm_base_object *base;
        int ret = -EINVAL;
 
-       base = ttm_base_object_lookup(tfile, req->sid);
+       base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid);
        if (unlikely(base == NULL)) {
                DRM_ERROR("Could not find surface to reference.\n");
                return -EINVAL;
@@ -893,3 +921,436 @@ out_no_reference:
 
        return ret;
 }
+
+/**
+ * vmw_surface_define_encode - Encode a surface_define command.
+ *
+ * @srf: Pointer to a struct vmw_surface object.
+ * @cmd_space: Pointer to memory area in which the commands should be encoded.
+ */
+static int vmw_gb_surface_create(struct vmw_resource *res)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct vmw_surface *srf = vmw_res_to_srf(res);
+       uint32_t cmd_len, submit_len;
+       int ret;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDefineGBSurface body;
+       } *cmd;
+
+       if (likely(res->id != -1))
+               return 0;
+
+       (void) vmw_3d_resource_inc(dev_priv, false);
+       ret = vmw_resource_alloc_id(res);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Failed to allocate a surface id.\n");
+               goto out_no_id;
+       }
+
+       if (unlikely(res->id >= VMWGFX_NUM_GB_SURFACE)) {
+               ret = -EBUSY;
+               goto out_no_fifo;
+       }
+
+       cmd_len = sizeof(cmd->body);
+       submit_len = sizeof(*cmd);
+       cmd = vmw_fifo_reserve(dev_priv, submit_len);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for surface "
+                         "creation.\n");
+               ret = -ENOMEM;
+               goto out_no_fifo;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_DEFINE_GB_SURFACE;
+       cmd->header.size = cmd_len;
+       cmd->body.sid = srf->res.id;
+       cmd->body.surfaceFlags = srf->flags;
+       cmd->body.format = cpu_to_le32(srf->format);
+       cmd->body.numMipLevels = srf->mip_levels[0];
+       cmd->body.multisampleCount = srf->multisample_count;
+       cmd->body.autogenFilter = srf->autogen_filter;
+       cmd->body.size.width = srf->base_size.width;
+       cmd->body.size.height = srf->base_size.height;
+       cmd->body.size.depth = srf->base_size.depth;
+       vmw_fifo_commit(dev_priv, submit_len);
+
+       return 0;
+
+out_no_fifo:
+       vmw_resource_release_id(res);
+out_no_id:
+       vmw_3d_resource_dec(dev_priv, false);
+       return ret;
+}
+
+
+static int vmw_gb_surface_bind(struct vmw_resource *res,
+                              struct ttm_validate_buffer *val_buf)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBindGBSurface body;
+       } *cmd1;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdUpdateGBSurface body;
+       } *cmd2;
+       uint32_t submit_size;
+       struct ttm_buffer_object *bo = val_buf->bo;
+
+       BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
+
+       submit_size = sizeof(*cmd1) + (res->backup_dirty ? sizeof(*cmd2) : 0);
+
+       cmd1 = vmw_fifo_reserve(dev_priv, submit_size);
+       if (unlikely(cmd1 == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for surface "
+                         "binding.\n");
+               return -ENOMEM;
+       }
+
+       cmd1->header.id = SVGA_3D_CMD_BIND_GB_SURFACE;
+       cmd1->header.size = sizeof(cmd1->body);
+       cmd1->body.sid = res->id;
+       cmd1->body.mobid = bo->mem.start;
+       if (res->backup_dirty) {
+               cmd2 = (void *) &cmd1[1];
+               cmd2->header.id = SVGA_3D_CMD_UPDATE_GB_SURFACE;
+               cmd2->header.size = sizeof(cmd2->body);
+               cmd2->body.sid = res->id;
+               res->backup_dirty = false;
+       }
+       vmw_fifo_commit(dev_priv, submit_size);
+
+       return 0;
+}
+
+static int vmw_gb_surface_unbind(struct vmw_resource *res,
+                                bool readback,
+                                struct ttm_validate_buffer *val_buf)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct ttm_buffer_object *bo = val_buf->bo;
+       struct vmw_fence_obj *fence;
+
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdReadbackGBSurface body;
+       } *cmd1;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdInvalidateGBSurface body;
+       } *cmd2;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdBindGBSurface body;
+       } *cmd3;
+       uint32_t submit_size;
+       uint8_t *cmd;
+
+
+       BUG_ON(bo->mem.mem_type != VMW_PL_MOB);
+
+       submit_size = sizeof(*cmd3) + (readback ? sizeof(*cmd1) : sizeof(*cmd2));
+       cmd = vmw_fifo_reserve(dev_priv, submit_size);
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for surface "
+                         "unbinding.\n");
+               return -ENOMEM;
+       }
+
+       if (readback) {
+               cmd1 = (void *) cmd;
+               cmd1->header.id = SVGA_3D_CMD_READBACK_GB_SURFACE;
+               cmd1->header.size = sizeof(cmd1->body);
+               cmd1->body.sid = res->id;
+               cmd3 = (void *) &cmd1[1];
+       } else {
+               cmd2 = (void *) cmd;
+               cmd2->header.id = SVGA_3D_CMD_INVALIDATE_GB_SURFACE;
+               cmd2->header.size = sizeof(cmd2->body);
+               cmd2->body.sid = res->id;
+               cmd3 = (void *) &cmd2[1];
+       }
+
+       cmd3->header.id = SVGA_3D_CMD_BIND_GB_SURFACE;
+       cmd3->header.size = sizeof(cmd3->body);
+       cmd3->body.sid = res->id;
+       cmd3->body.mobid = SVGA3D_INVALID_ID;
+
+       vmw_fifo_commit(dev_priv, submit_size);
+
+       /*
+        * Create a fence object and fence the backup buffer.
+        */
+
+       (void) vmw_execbuf_fence_commands(NULL, dev_priv,
+                                         &fence, NULL);
+
+       vmw_fence_single_bo(val_buf->bo, fence);
+
+       if (likely(fence != NULL))
+               vmw_fence_obj_unreference(&fence);
+
+       return 0;
+}
+
+static int vmw_gb_surface_destroy(struct vmw_resource *res)
+{
+       struct vmw_private *dev_priv = res->dev_priv;
+       struct {
+               SVGA3dCmdHeader header;
+               SVGA3dCmdDestroyGBSurface body;
+       } *cmd;
+
+       if (likely(res->id == -1))
+               return 0;
+
+       mutex_lock(&dev_priv->binding_mutex);
+       vmw_context_binding_res_list_kill(&res->binding_head);
+
+       cmd = vmw_fifo_reserve(dev_priv, sizeof(*cmd));
+       if (unlikely(cmd == NULL)) {
+               DRM_ERROR("Failed reserving FIFO space for surface "
+                         "destruction.\n");
+               mutex_unlock(&dev_priv->binding_mutex);
+               return -ENOMEM;
+       }
+
+       cmd->header.id = SVGA_3D_CMD_DESTROY_GB_SURFACE;
+       cmd->header.size = sizeof(cmd->body);
+       cmd->body.sid = res->id;
+       vmw_fifo_commit(dev_priv, sizeof(*cmd));
+       mutex_unlock(&dev_priv->binding_mutex);
+       vmw_resource_release_id(res);
+       vmw_3d_resource_dec(dev_priv, false);
+
+       return 0;
+}
+
+/**
+ * vmw_gb_surface_define_ioctl - Ioctl function implementing
+ *                               the user surface define functionality.
+ *
+ * @dev:            Pointer to a struct drm_device.
+ * @data:           Pointer to data copied from / to user-space.
+ * @file_priv:      Pointer to a drm file private structure.
+ */
+int vmw_gb_surface_define_ioctl(struct drm_device *dev, void *data,
+                               struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       struct vmw_user_surface *user_srf;
+       struct vmw_surface *srf;
+       struct vmw_resource *res;
+       struct vmw_resource *tmp;
+       union drm_vmw_gb_surface_create_arg *arg =
+           (union drm_vmw_gb_surface_create_arg *)data;
+       struct drm_vmw_gb_surface_create_req *req = &arg->req;
+       struct drm_vmw_gb_surface_create_rep *rep = &arg->rep;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       int ret;
+       uint32_t size;
+       struct vmw_master *vmaster = vmw_master(file_priv->master);
+       const struct svga3d_surface_desc *desc;
+       uint32_t backup_handle;
+
+       if (unlikely(vmw_user_surface_size == 0))
+               vmw_user_surface_size = ttm_round_pot(sizeof(*user_srf)) +
+                       128;
+
+       size = vmw_user_surface_size + 128;
+
+       desc = svga3dsurface_get_desc(req->format);
+       if (unlikely(desc->block_desc == SVGA3DBLOCKDESC_NONE)) {
+               DRM_ERROR("Invalid surface format for surface creation.\n");
+               return -EINVAL;
+       }
+
+       ret = ttm_read_lock(&vmaster->lock, true);
+       if (unlikely(ret != 0))
+               return ret;
+
+       ret = ttm_mem_global_alloc(vmw_mem_glob(dev_priv),
+                                  size, false, true);
+       if (unlikely(ret != 0)) {
+               if (ret != -ERESTARTSYS)
+                       DRM_ERROR("Out of graphics memory for surface"
+                                 " creation.\n");
+               goto out_unlock;
+       }
+
+       user_srf = kzalloc(sizeof(*user_srf), GFP_KERNEL);
+       if (unlikely(user_srf == NULL)) {
+               ret = -ENOMEM;
+               goto out_no_user_srf;
+       }
+
+       srf = &user_srf->srf;
+       res = &srf->res;
+
+       srf->flags = req->svga3d_flags;
+       srf->format = req->format;
+       srf->scanout = req->drm_surface_flags & drm_vmw_surface_flag_scanout;
+       srf->mip_levels[0] = req->mip_levels;
+       srf->num_sizes = 1;
+       srf->sizes = NULL;
+       srf->offsets = NULL;
+       user_srf->size = size;
+       srf->base_size = req->base_size;
+       srf->autogen_filter = SVGA3D_TEX_FILTER_NONE;
+       srf->multisample_count = req->multisample_count;
+       res->backup_size = svga3dsurface_get_serialized_size
+         (srf->format, srf->base_size, srf->mip_levels[0],
+          srf->flags & SVGA3D_SURFACE_CUBEMAP);
+
+       user_srf->prime.base.shareable = false;
+       user_srf->prime.base.tfile = NULL;
+
+       /**
+        * From this point, the generic resource management functions
+        * destroy the object on failure.
+        */
+
+       ret = vmw_surface_init(dev_priv, srf, vmw_user_surface_free);
+       if (unlikely(ret != 0))
+               goto out_unlock;
+
+       if (req->buffer_handle != SVGA3D_INVALID_ID) {
+               ret = vmw_user_dmabuf_lookup(tfile, req->buffer_handle,
+                                            &res->backup);
+       } else if (req->drm_surface_flags &
+                  drm_vmw_surface_flag_create_buffer)
+               ret = vmw_user_dmabuf_alloc(dev_priv, tfile,
+                                           res->backup_size,
+                                           req->drm_surface_flags &
+                                           drm_vmw_surface_flag_shareable,
+                                           &backup_handle,
+                                           &res->backup);
+
+       if (unlikely(ret != 0)) {
+               vmw_resource_unreference(&res);
+               goto out_unlock;
+       }
+
+       tmp = vmw_resource_reference(&srf->res);
+       ret = ttm_prime_object_init(tfile, res->backup_size, &user_srf->prime,
+                                   req->drm_surface_flags &
+                                   drm_vmw_surface_flag_shareable,
+                                   VMW_RES_SURFACE,
+                                   &vmw_user_surface_base_release, NULL);
+
+       if (unlikely(ret != 0)) {
+               vmw_resource_unreference(&tmp);
+               vmw_resource_unreference(&res);
+               goto out_unlock;
+       }
+
+       rep->handle = user_srf->prime.base.hash.key;
+       rep->backup_size = res->backup_size;
+       if (res->backup) {
+               rep->buffer_map_handle =
+                       drm_vma_node_offset_addr(&res->backup->base.vma_node);
+               rep->buffer_size = res->backup->base.num_pages * PAGE_SIZE;
+               rep->buffer_handle = backup_handle;
+       } else {
+               rep->buffer_map_handle = 0;
+               rep->buffer_size = 0;
+               rep->buffer_handle = SVGA3D_INVALID_ID;
+       }
+
+       vmw_resource_unreference(&res);
+
+       ttm_read_unlock(&vmaster->lock);
+       return 0;
+out_no_user_srf:
+       ttm_mem_global_free(vmw_mem_glob(dev_priv), size);
+out_unlock:
+       ttm_read_unlock(&vmaster->lock);
+       return ret;
+}
+
+/**
+ * vmw_gb_surface_reference_ioctl - Ioctl function implementing
+ *                                  the user surface reference functionality.
+ *
+ * @dev:            Pointer to a struct drm_device.
+ * @data:           Pointer to data copied from / to user-space.
+ * @file_priv:      Pointer to a drm file private structure.
+ */
+int vmw_gb_surface_reference_ioctl(struct drm_device *dev, void *data,
+                                  struct drm_file *file_priv)
+{
+       struct vmw_private *dev_priv = vmw_priv(dev);
+       union drm_vmw_gb_surface_reference_arg *arg =
+           (union drm_vmw_gb_surface_reference_arg *)data;
+       struct drm_vmw_surface_arg *req = &arg->req;
+       struct drm_vmw_gb_surface_ref_rep *rep = &arg->rep;
+       struct ttm_object_file *tfile = vmw_fpriv(file_priv)->tfile;
+       struct vmw_surface *srf;
+       struct vmw_user_surface *user_srf;
+       struct ttm_base_object *base;
+       uint32_t backup_handle;
+       int ret = -EINVAL;
+
+       base = ttm_base_object_lookup_for_ref(dev_priv->tdev, req->sid);
+       if (unlikely(base == NULL)) {
+               DRM_ERROR("Could not find surface to reference.\n");
+               return -EINVAL;
+       }
+
+       if (unlikely(ttm_base_object_type(base) != VMW_RES_SURFACE))
+               goto out_bad_resource;
+
+       user_srf = container_of(base, struct vmw_user_surface, prime.base);
+       srf = &user_srf->srf;
+       if (srf->res.backup == NULL) {
+               DRM_ERROR("Shared GB surface is missing a backup buffer.\n");
+               goto out_bad_resource;
+       }
+
+       ret = ttm_ref_object_add(tfile, &user_srf->prime.base,
+                                TTM_REF_USAGE, NULL);
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Could not add a reference to a GB surface.\n");
+               goto out_bad_resource;
+       }
+
+       mutex_lock(&dev_priv->cmdbuf_mutex); /* Protect res->backup */
+       ret = vmw_user_dmabuf_reference(tfile, srf->res.backup,
+                                       &backup_handle);
+       mutex_unlock(&dev_priv->cmdbuf_mutex);
+
+       if (unlikely(ret != 0)) {
+               DRM_ERROR("Could not add a reference to a GB surface "
+                         "backup buffer.\n");
+               (void) ttm_ref_object_base_unref(vmw_fpriv(file_priv)->tfile,
+                                                req->sid,
+                                                TTM_REF_USAGE);
+               goto out_bad_resource;
+       }
+
+       rep->creq.svga3d_flags = srf->flags;
+       rep->creq.format = srf->format;
+       rep->creq.mip_levels = srf->mip_levels[0];
+       rep->creq.drm_surface_flags = 0;
+       rep->creq.multisample_count = srf->multisample_count;
+       rep->creq.autogen_filter = srf->autogen_filter;
+       rep->creq.buffer_handle = backup_handle;
+       rep->creq.base_size = srf->base_size;
+       rep->crep.handle = user_srf->prime.base.hash.key;
+       rep->crep.backup_size = srf->res.backup_size;
+       rep->crep.buffer_handle = backup_handle;
+       rep->crep.buffer_map_handle =
+               drm_vma_node_offset_addr(&srf->res.backup->base.vma_node);
+       rep->crep.buffer_size = srf->res.backup->base.num_pages * PAGE_SIZE;
+
+out_bad_resource:
+       ttm_base_object_unref(&base);
+
+       return ret;
+}
index 7d6bed2225422fa2413130a606d2b20fd084cfd4..b2fd029d67b308ce60490d61cd908d743a9e520b 100644 (file)
@@ -1,6 +1,6 @@
 config TEGRA_HOST1X
        tristate "NVIDIA Tegra host1x driver"
-       depends on ARCH_TEGRA || ARCH_MULTIPLATFORM
+       depends on ARCH_TEGRA || (ARM && COMPILE_TEST)
        help
          Driver for the NVIDIA Tegra host1x hardware.
 
index afa1e9e4e51265fbdb21698072315786a6b730b7..c1189f0044411810fb2e0e58203421d6ffa302d7 100644 (file)
@@ -7,7 +7,9 @@ host1x-y = \
        channel.o \
        job.o \
        debug.o \
+       mipi.o \
        hw/host1x01.o \
-       hw/host1x02.o
+       hw/host1x02.o \
+       hw/host1x04.o
 
 obj-$(CONFIG_TEGRA_HOST1X) += host1x.o
index 6a929591aa73801df1126433bc514980e80d1465..ccdd2e6da5e3710a205e1b5dc3a9c667a9ed6bcf 100644 (file)
@@ -188,6 +188,7 @@ int host1x_device_init(struct host1x_device *device)
 
        return 0;
 }
+EXPORT_SYMBOL(host1x_device_init);
 
 int host1x_device_exit(struct host1x_device *device)
 {
@@ -213,6 +214,7 @@ int host1x_device_exit(struct host1x_device *device)
 
        return 0;
 }
+EXPORT_SYMBOL(host1x_device_exit);
 
 static int host1x_register_client(struct host1x *host1x,
                                  struct host1x_client *client)
index 83ea51b9f0fce44ea6a5ff96f78c8db49f6b8839..b4ae3affb987bb92ed7dcd1f3317714b260fd61d 100644 (file)
@@ -43,6 +43,7 @@ int host1x_job_submit(struct host1x_job *job)
 
        return host1x_hw_channel_submit(host, job);
 }
+EXPORT_SYMBOL(host1x_job_submit);
 
 struct host1x_channel *host1x_channel_get(struct host1x_channel *channel)
 {
@@ -60,6 +61,7 @@ struct host1x_channel *host1x_channel_get(struct host1x_channel *channel)
 
        return err ? NULL : channel;
 }
+EXPORT_SYMBOL(host1x_channel_get);
 
 void host1x_channel_put(struct host1x_channel *channel)
 {
@@ -76,6 +78,7 @@ void host1x_channel_put(struct host1x_channel *channel)
 
        mutex_unlock(&channel->reflock);
 }
+EXPORT_SYMBOL(host1x_channel_put);
 
 struct host1x_channel *host1x_channel_request(struct device *dev)
 {
@@ -115,6 +118,7 @@ fail:
        mutex_unlock(&host->chlist_mutex);
        return NULL;
 }
+EXPORT_SYMBOL(host1x_channel_request);
 
 void host1x_channel_free(struct host1x_channel *channel)
 {
@@ -124,3 +128,4 @@ void host1x_channel_free(struct host1x_channel *channel)
        list_del(&channel->list);
        kfree(channel);
 }
+EXPORT_SYMBOL(host1x_channel_free);
index 3ec7d77de24ddc846321f159229e3d592bf02a38..ee3d12b51c50a036b89c48c3e60576a2a14acf5b 100644 (file)
@@ -96,7 +96,6 @@ static void show_all(struct host1x *m, struct output *o)
                show_channels(ch, o, true);
 }
 
-#ifdef CONFIG_DEBUG_FS
 static void show_all_no_fifo(struct host1x *host1x, struct output *o)
 {
        struct host1x_channel *ch;
@@ -153,7 +152,7 @@ static const struct file_operations host1x_debug_fops = {
        .release        = single_release,
 };
 
-void host1x_debug_init(struct host1x *host1x)
+static void host1x_debugfs_init(struct host1x *host1x)
 {
        struct dentry *de = debugfs_create_dir("tegra-host1x", NULL);
 
@@ -180,18 +179,22 @@ void host1x_debug_init(struct host1x *host1x)
                           &host1x_debug_force_timeout_channel);
 }
 
-void host1x_debug_deinit(struct host1x *host1x)
+static void host1x_debugfs_exit(struct host1x *host1x)
 {
        debugfs_remove_recursive(host1x->debugfs);
 }
-#else
+
 void host1x_debug_init(struct host1x *host1x)
 {
+       if (IS_ENABLED(CONFIG_DEBUG_FS))
+               host1x_debugfs_init(host1x);
 }
+
 void host1x_debug_deinit(struct host1x *host1x)
 {
+       if (IS_ENABLED(CONFIG_DEBUG_FS))
+               host1x_debugfs_exit(host1x);
 }
-#endif
 
 void host1x_debug_dump(struct host1x *host1x)
 {
index 80da003d63de8d4b754cd37a607441c7c4901574..2529908d304bd851fdd9c2d0b9d71471e5d69b20 100644 (file)
@@ -34,6 +34,7 @@
 #include "debug.h"
 #include "hw/host1x01.h"
 #include "hw/host1x02.h"
+#include "hw/host1x04.h"
 
 void host1x_sync_writel(struct host1x *host1x, u32 v, u32 r)
 {
@@ -77,7 +78,17 @@ static const struct host1x_info host1x02_info = {
        .sync_offset = 0x3000,
 };
 
+static const struct host1x_info host1x04_info = {
+       .nb_channels = 12,
+       .nb_pts = 192,
+       .nb_mlocks = 16,
+       .nb_bases = 64,
+       .init = host1x04_init,
+       .sync_offset = 0x2100,
+};
+
 static struct of_device_id host1x_of_match[] = {
+       { .compatible = "nvidia,tegra124-host1x", .data = &host1x04_info, },
        { .compatible = "nvidia,tegra114-host1x", .data = &host1x02_info, },
        { .compatible = "nvidia,tegra30-host1x", .data = &host1x01_info, },
        { .compatible = "nvidia,tegra20-host1x", .data = &host1x01_info, },
@@ -210,17 +221,26 @@ static int __init tegra_host1x_init(void)
                return err;
 
        err = platform_driver_register(&tegra_host1x_driver);
-       if (err < 0) {
-               host1x_bus_exit();
-               return err;
-       }
+       if (err < 0)
+               goto unregister_bus;
+
+       err = platform_driver_register(&tegra_mipi_driver);
+       if (err < 0)
+               goto unregister_host1x;
 
        return 0;
+
+unregister_host1x:
+       platform_driver_unregister(&tegra_host1x_driver);
+unregister_bus:
+       host1x_bus_exit();
+       return err;
 }
 module_init(tegra_host1x_init);
 
 static void __exit tegra_host1x_exit(void)
 {
+       platform_driver_unregister(&tegra_mipi_driver);
        platform_driver_unregister(&tegra_host1x_driver);
        host1x_bus_exit();
 }
index a61a976e7a421a405d7fe075272228f08e3e3e6d..0b6e8e9629c5330fbc7fadba1a1ae318ae07da12 100644 (file)
@@ -306,4 +306,6 @@ static inline void host1x_hw_show_mlocks(struct host1x *host, struct output *o)
        host->debug_op->show_mlocks(host, o);
 }
 
+extern struct platform_driver tegra_mipi_driver;
+
 #endif
index e98caca0ca42a55b120e1a29085c9d02fc49c046..928946c2144bd17eaa814e1ab9f5449cf17264d8 100644 (file)
@@ -17,8 +17,8 @@
  */
 
 /* include hw specification */
-#include "host1x01.h"
-#include "host1x01_hardware.h"
+#include "host1x02.h"
+#include "host1x02_hardware.h"
 
 /* include code */
 #include "cdma_hw.c"
diff --git a/drivers/gpu/host1x/hw/host1x02_hardware.h b/drivers/gpu/host1x/hw/host1x02_hardware.h
new file mode 100644 (file)
index 0000000..1549018
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Tegra host1x Register Offsets for Tegra114
+ *
+ * Copyright (c) 2010-2013 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST1X_HOST1X02_HARDWARE_H
+#define __HOST1X_HOST1X02_HARDWARE_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#include "hw_host1x02_channel.h"
+#include "hw_host1x02_sync.h"
+#include "hw_host1x02_uclass.h"
+
+static inline u32 host1x_class_host_wait_syncpt(
+       unsigned indx, unsigned threshold)
+{
+       return host1x_uclass_wait_syncpt_indx_f(indx)
+               | host1x_uclass_wait_syncpt_thresh_f(threshold);
+}
+
+static inline u32 host1x_class_host_load_syncpt_base(
+       unsigned indx, unsigned threshold)
+{
+       return host1x_uclass_load_syncpt_base_base_indx_f(indx)
+               | host1x_uclass_load_syncpt_base_value_f(threshold);
+}
+
+static inline u32 host1x_class_host_wait_syncpt_base(
+       unsigned indx, unsigned base_indx, unsigned offset)
+{
+       return host1x_uclass_wait_syncpt_base_indx_f(indx)
+               | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx)
+               | host1x_uclass_wait_syncpt_base_offset_f(offset);
+}
+
+static inline u32 host1x_class_host_incr_syncpt_base(
+       unsigned base_indx, unsigned offset)
+{
+       return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx)
+               | host1x_uclass_incr_syncpt_base_offset_f(offset);
+}
+
+static inline u32 host1x_class_host_incr_syncpt(
+       unsigned cond, unsigned indx)
+{
+       return host1x_uclass_incr_syncpt_cond_f(cond)
+               | host1x_uclass_incr_syncpt_indx_f(indx);
+}
+
+static inline u32 host1x_class_host_indoff_reg_write(
+       unsigned mod_id, unsigned offset, bool auto_inc)
+{
+       u32 v = host1x_uclass_indoff_indbe_f(0xf)
+               | host1x_uclass_indoff_indmodid_f(mod_id)
+               | host1x_uclass_indoff_indroffset_f(offset);
+       if (auto_inc)
+               v |= host1x_uclass_indoff_autoinc_f(1);
+       return v;
+}
+
+static inline u32 host1x_class_host_indoff_reg_read(
+       unsigned mod_id, unsigned offset, bool auto_inc)
+{
+       u32 v = host1x_uclass_indoff_indmodid_f(mod_id)
+               | host1x_uclass_indoff_indroffset_f(offset)
+               | host1x_uclass_indoff_rwn_read_v();
+       if (auto_inc)
+               v |= host1x_uclass_indoff_autoinc_f(1);
+       return v;
+}
+
+/* cdma opcodes */
+static inline u32 host1x_opcode_setclass(
+       unsigned class_id, unsigned offset, unsigned mask)
+{
+       return (0 << 28) | (offset << 16) | (class_id << 6) | mask;
+}
+
+static inline u32 host1x_opcode_incr(unsigned offset, unsigned count)
+{
+       return (1 << 28) | (offset << 16) | count;
+}
+
+static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count)
+{
+       return (2 << 28) | (offset << 16) | count;
+}
+
+static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask)
+{
+       return (3 << 28) | (offset << 16) | mask;
+}
+
+static inline u32 host1x_opcode_imm(unsigned offset, unsigned value)
+{
+       return (4 << 28) | (offset << 16) | value;
+}
+
+static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx)
+{
+       return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(),
+               host1x_class_host_incr_syncpt(cond, indx));
+}
+
+static inline u32 host1x_opcode_restart(unsigned address)
+{
+       return (5 << 28) | (address >> 4);
+}
+
+static inline u32 host1x_opcode_gather(unsigned count)
+{
+       return (6 << 28) | count;
+}
+
+static inline u32 host1x_opcode_gather_nonincr(unsigned offset,        unsigned count)
+{
+       return (6 << 28) | (offset << 16) | BIT(15) | count;
+}
+
+static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count)
+{
+       return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
+}
+
+#define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0)
+
+#endif
diff --git a/drivers/gpu/host1x/hw/host1x04.c b/drivers/gpu/host1x/hw/host1x04.c
new file mode 100644 (file)
index 0000000..8007c70
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Host1x init for Tegra124 SoCs
+ *
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* include hw specification */
+#include "host1x04.h"
+#include "host1x04_hardware.h"
+
+/* include code */
+#include "cdma_hw.c"
+#include "channel_hw.c"
+#include "debug_hw.c"
+#include "intr_hw.c"
+#include "syncpt_hw.c"
+
+#include "../dev.h"
+
+int host1x04_init(struct host1x *host)
+{
+       host->channel_op = &host1x_channel_ops;
+       host->cdma_op = &host1x_cdma_ops;
+       host->cdma_pb_op = &host1x_pushbuffer_ops;
+       host->syncpt_op = &host1x_syncpt_ops;
+       host->intr_op = &host1x_intr_ops;
+       host->debug_op = &host1x_debug_ops;
+
+       return 0;
+}
diff --git a/drivers/gpu/host1x/hw/host1x04.h b/drivers/gpu/host1x/hw/host1x04.h
new file mode 100644 (file)
index 0000000..a9ab749
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * Host1x init for Tegra124 SoCs
+ *
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef HOST1X_HOST1X04_H
+#define HOST1X_HOST1X04_H
+
+struct host1x;
+
+int host1x04_init(struct host1x *host);
+
+#endif
diff --git a/drivers/gpu/host1x/hw/host1x04_hardware.h b/drivers/gpu/host1x/hw/host1x04_hardware.h
new file mode 100644 (file)
index 0000000..de1a381
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Tegra host1x Register Offsets for Tegra124
+ *
+ * Copyright (c) 2010-2013 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __HOST1X_HOST1X04_HARDWARE_H
+#define __HOST1X_HOST1X04_HARDWARE_H
+
+#include <linux/types.h>
+#include <linux/bitops.h>
+
+#include "hw_host1x04_channel.h"
+#include "hw_host1x04_sync.h"
+#include "hw_host1x04_uclass.h"
+
+static inline u32 host1x_class_host_wait_syncpt(
+       unsigned indx, unsigned threshold)
+{
+       return host1x_uclass_wait_syncpt_indx_f(indx)
+               | host1x_uclass_wait_syncpt_thresh_f(threshold);
+}
+
+static inline u32 host1x_class_host_load_syncpt_base(
+       unsigned indx, unsigned threshold)
+{
+       return host1x_uclass_load_syncpt_base_base_indx_f(indx)
+               | host1x_uclass_load_syncpt_base_value_f(threshold);
+}
+
+static inline u32 host1x_class_host_wait_syncpt_base(
+       unsigned indx, unsigned base_indx, unsigned offset)
+{
+       return host1x_uclass_wait_syncpt_base_indx_f(indx)
+               | host1x_uclass_wait_syncpt_base_base_indx_f(base_indx)
+               | host1x_uclass_wait_syncpt_base_offset_f(offset);
+}
+
+static inline u32 host1x_class_host_incr_syncpt_base(
+       unsigned base_indx, unsigned offset)
+{
+       return host1x_uclass_incr_syncpt_base_base_indx_f(base_indx)
+               | host1x_uclass_incr_syncpt_base_offset_f(offset);
+}
+
+static inline u32 host1x_class_host_incr_syncpt(
+       unsigned cond, unsigned indx)
+{
+       return host1x_uclass_incr_syncpt_cond_f(cond)
+               | host1x_uclass_incr_syncpt_indx_f(indx);
+}
+
+static inline u32 host1x_class_host_indoff_reg_write(
+       unsigned mod_id, unsigned offset, bool auto_inc)
+{
+       u32 v = host1x_uclass_indoff_indbe_f(0xf)
+               | host1x_uclass_indoff_indmodid_f(mod_id)
+               | host1x_uclass_indoff_indroffset_f(offset);
+       if (auto_inc)
+               v |= host1x_uclass_indoff_autoinc_f(1);
+       return v;
+}
+
+static inline u32 host1x_class_host_indoff_reg_read(
+       unsigned mod_id, unsigned offset, bool auto_inc)
+{
+       u32 v = host1x_uclass_indoff_indmodid_f(mod_id)
+               | host1x_uclass_indoff_indroffset_f(offset)
+               | host1x_uclass_indoff_rwn_read_v();
+       if (auto_inc)
+               v |= host1x_uclass_indoff_autoinc_f(1);
+       return v;
+}
+
+/* cdma opcodes */
+static inline u32 host1x_opcode_setclass(
+       unsigned class_id, unsigned offset, unsigned mask)
+{
+       return (0 << 28) | (offset << 16) | (class_id << 6) | mask;
+}
+
+static inline u32 host1x_opcode_incr(unsigned offset, unsigned count)
+{
+       return (1 << 28) | (offset << 16) | count;
+}
+
+static inline u32 host1x_opcode_nonincr(unsigned offset, unsigned count)
+{
+       return (2 << 28) | (offset << 16) | count;
+}
+
+static inline u32 host1x_opcode_mask(unsigned offset, unsigned mask)
+{
+       return (3 << 28) | (offset << 16) | mask;
+}
+
+static inline u32 host1x_opcode_imm(unsigned offset, unsigned value)
+{
+       return (4 << 28) | (offset << 16) | value;
+}
+
+static inline u32 host1x_opcode_imm_incr_syncpt(unsigned cond, unsigned indx)
+{
+       return host1x_opcode_imm(host1x_uclass_incr_syncpt_r(),
+               host1x_class_host_incr_syncpt(cond, indx));
+}
+
+static inline u32 host1x_opcode_restart(unsigned address)
+{
+       return (5 << 28) | (address >> 4);
+}
+
+static inline u32 host1x_opcode_gather(unsigned count)
+{
+       return (6 << 28) | count;
+}
+
+static inline u32 host1x_opcode_gather_nonincr(unsigned offset,        unsigned count)
+{
+       return (6 << 28) | (offset << 16) | BIT(15) | count;
+}
+
+static inline u32 host1x_opcode_gather_incr(unsigned offset, unsigned count)
+{
+       return (6 << 28) | (offset << 16) | BIT(15) | BIT(14) | count;
+}
+
+#define HOST1X_OPCODE_NOP host1x_opcode_nonincr(0, 0)
+
+#endif
index a3b3c9874413c1b420632b74df3137da31eaf73c..028e49d9bac9837132f3ccbcb10067a8514dea58 100644 (file)
@@ -111,6 +111,12 @@ static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v)
 }
 #define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
        host1x_uclass_wait_syncpt_base_offset_f(v)
+static inline u32 host1x_uclass_load_syncpt_base_r(void)
+{
+       return 0xb;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE \
+       host1x_uclass_load_syncpt_base_r()
 static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
 {
        return (v & 0xff) << 24;
diff --git a/drivers/gpu/host1x/hw/hw_host1x04_channel.h b/drivers/gpu/host1x/hw/hw_host1x04_channel.h
new file mode 100644 (file)
index 0000000..95e6f96
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ /*
+  * Function naming determines intended use:
+  *
+  *     <x>_r(void) : Returns the offset for register <x>.
+  *
+  *     <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+  *
+  *     <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+  *
+  *     <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+  *         and masked to place it at field <y> of register <x>.  This value
+  *         can be |'d with others to produce a full register value for
+  *         register <x>.
+  *
+  *     <x>_<y>_m(void) : Returns a mask for field <y> of register <x>.  This
+  *         value can be ~'d and then &'d to clear the value of field <y> for
+  *         register <x>.
+  *
+  *     <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+  *         to place it at field <y> of register <x>.  This value can be |'d
+  *         with others to produce a full register value for <x>.
+  *
+  *     <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+  *         <x> value 'r' after being shifted to place its LSB at bit 0.
+  *         This value is suitable for direct comparison with other unshifted
+  *         values appropriate for use in field <y> of register <x>.
+  *
+  *     <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+  *         field <y> of register <x>.  This value is suitable for direct
+  *         comparison with unshifted values appropriate for use in field <y>
+  *         of register <x>.
+  */
+
+#ifndef HOST1X_HW_HOST1X04_CHANNEL_H
+#define HOST1X_HW_HOST1X04_CHANNEL_H
+
+static inline u32 host1x_channel_fifostat_r(void)
+{
+       return 0x0;
+}
+#define HOST1X_CHANNEL_FIFOSTAT \
+       host1x_channel_fifostat_r()
+static inline u32 host1x_channel_fifostat_cfempty_v(u32 r)
+{
+       return (r >> 11) & 0x1;
+}
+#define HOST1X_CHANNEL_FIFOSTAT_CFEMPTY_V(r) \
+       host1x_channel_fifostat_cfempty_v(r)
+static inline u32 host1x_channel_dmastart_r(void)
+{
+       return 0x14;
+}
+#define HOST1X_CHANNEL_DMASTART \
+       host1x_channel_dmastart_r()
+static inline u32 host1x_channel_dmaput_r(void)
+{
+       return 0x18;
+}
+#define HOST1X_CHANNEL_DMAPUT \
+       host1x_channel_dmaput_r()
+static inline u32 host1x_channel_dmaget_r(void)
+{
+       return 0x1c;
+}
+#define HOST1X_CHANNEL_DMAGET \
+       host1x_channel_dmaget_r()
+static inline u32 host1x_channel_dmaend_r(void)
+{
+       return 0x20;
+}
+#define HOST1X_CHANNEL_DMAEND \
+       host1x_channel_dmaend_r()
+static inline u32 host1x_channel_dmactrl_r(void)
+{
+       return 0x24;
+}
+#define HOST1X_CHANNEL_DMACTRL \
+       host1x_channel_dmactrl_r()
+static inline u32 host1x_channel_dmactrl_dmastop(void)
+{
+       return 1 << 0;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMASTOP \
+       host1x_channel_dmactrl_dmastop()
+static inline u32 host1x_channel_dmactrl_dmastop_v(u32 r)
+{
+       return (r >> 0) & 0x1;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMASTOP_V(r) \
+       host1x_channel_dmactrl_dmastop_v(r)
+static inline u32 host1x_channel_dmactrl_dmagetrst(void)
+{
+       return 1 << 1;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMAGETRST \
+       host1x_channel_dmactrl_dmagetrst()
+static inline u32 host1x_channel_dmactrl_dmainitget(void)
+{
+       return 1 << 2;
+}
+#define HOST1X_CHANNEL_DMACTRL_DMAINITGET \
+       host1x_channel_dmactrl_dmainitget()
+
+#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x04_sync.h b/drivers/gpu/host1x/hw/hw_host1x04_sync.h
new file mode 100644 (file)
index 0000000..ef2275b
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ /*
+  * Function naming determines intended use:
+  *
+  *     <x>_r(void) : Returns the offset for register <x>.
+  *
+  *     <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+  *
+  *     <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+  *
+  *     <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+  *         and masked to place it at field <y> of register <x>.  This value
+  *         can be |'d with others to produce a full register value for
+  *         register <x>.
+  *
+  *     <x>_<y>_m(void) : Returns a mask for field <y> of register <x>.  This
+  *         value can be ~'d and then &'d to clear the value of field <y> for
+  *         register <x>.
+  *
+  *     <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+  *         to place it at field <y> of register <x>.  This value can be |'d
+  *         with others to produce a full register value for <x>.
+  *
+  *     <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+  *         <x> value 'r' after being shifted to place its LSB at bit 0.
+  *         This value is suitable for direct comparison with other unshifted
+  *         values appropriate for use in field <y> of register <x>.
+  *
+  *     <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+  *         field <y> of register <x>.  This value is suitable for direct
+  *         comparison with unshifted values appropriate for use in field <y>
+  *         of register <x>.
+  */
+
+#ifndef HOST1X_HW_HOST1X04_SYNC_H
+#define HOST1X_HW_HOST1X04_SYNC_H
+
+#define REGISTER_STRIDE        4
+
+static inline u32 host1x_sync_syncpt_r(unsigned int id)
+{
+       return 0xf80 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT(id) \
+       host1x_sync_syncpt_r(id)
+static inline u32 host1x_sync_syncpt_thresh_cpu0_int_status_r(unsigned int id)
+{
+       return 0xe80 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_THRESH_CPU0_INT_STATUS(id) \
+       host1x_sync_syncpt_thresh_cpu0_int_status_r(id)
+static inline u32 host1x_sync_syncpt_thresh_int_disable_r(unsigned int id)
+{
+       return 0xf00 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_THRESH_INT_DISABLE(id) \
+       host1x_sync_syncpt_thresh_int_disable_r(id)
+static inline u32 host1x_sync_syncpt_thresh_int_enable_cpu0_r(unsigned int id)
+{
+       return 0xf20 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_THRESH_INT_ENABLE_CPU0(id) \
+       host1x_sync_syncpt_thresh_int_enable_cpu0_r(id)
+static inline u32 host1x_sync_cf_setup_r(unsigned int channel)
+{
+       return 0xc00 + channel * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_CF_SETUP(channel) \
+       host1x_sync_cf_setup_r(channel)
+static inline u32 host1x_sync_cf_setup_base_v(u32 r)
+{
+       return (r >> 0) & 0x3ff;
+}
+#define HOST1X_SYNC_CF_SETUP_BASE_V(r) \
+       host1x_sync_cf_setup_base_v(r)
+static inline u32 host1x_sync_cf_setup_limit_v(u32 r)
+{
+       return (r >> 16) & 0x3ff;
+}
+#define HOST1X_SYNC_CF_SETUP_LIMIT_V(r) \
+       host1x_sync_cf_setup_limit_v(r)
+static inline u32 host1x_sync_cmdproc_stop_r(void)
+{
+       return 0xac;
+}
+#define HOST1X_SYNC_CMDPROC_STOP \
+       host1x_sync_cmdproc_stop_r()
+static inline u32 host1x_sync_ch_teardown_r(void)
+{
+       return 0xb0;
+}
+#define HOST1X_SYNC_CH_TEARDOWN \
+       host1x_sync_ch_teardown_r()
+static inline u32 host1x_sync_usec_clk_r(void)
+{
+       return 0x1a4;
+}
+#define HOST1X_SYNC_USEC_CLK \
+       host1x_sync_usec_clk_r()
+static inline u32 host1x_sync_ctxsw_timeout_cfg_r(void)
+{
+       return 0x1a8;
+}
+#define HOST1X_SYNC_CTXSW_TIMEOUT_CFG \
+       host1x_sync_ctxsw_timeout_cfg_r()
+static inline u32 host1x_sync_ip_busy_timeout_r(void)
+{
+       return 0x1bc;
+}
+#define HOST1X_SYNC_IP_BUSY_TIMEOUT \
+       host1x_sync_ip_busy_timeout_r()
+static inline u32 host1x_sync_mlock_owner_r(unsigned int id)
+{
+       return 0x340 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_MLOCK_OWNER(id) \
+       host1x_sync_mlock_owner_r(id)
+static inline u32 host1x_sync_mlock_owner_chid_f(u32 v)
+{
+       return (v & 0xf) << 8;
+}
+#define HOST1X_SYNC_MLOCK_OWNER_CHID_F(v) \
+       host1x_sync_mlock_owner_chid_f(v)
+static inline u32 host1x_sync_mlock_owner_cpu_owns_v(u32 r)
+{
+       return (r >> 1) & 0x1;
+}
+#define HOST1X_SYNC_MLOCK_OWNER_CPU_OWNS_V(r) \
+       host1x_sync_mlock_owner_cpu_owns_v(r)
+static inline u32 host1x_sync_mlock_owner_ch_owns_v(u32 r)
+{
+       return (r >> 0) & 0x1;
+}
+#define HOST1X_SYNC_MLOCK_OWNER_CH_OWNS_V(r) \
+       host1x_sync_mlock_owner_ch_owns_v(r)
+static inline u32 host1x_sync_syncpt_int_thresh_r(unsigned int id)
+{
+       return 0x1380 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_INT_THRESH(id) \
+       host1x_sync_syncpt_int_thresh_r(id)
+static inline u32 host1x_sync_syncpt_base_r(unsigned int id)
+{
+       return 0x600 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_BASE(id) \
+       host1x_sync_syncpt_base_r(id)
+static inline u32 host1x_sync_syncpt_cpu_incr_r(unsigned int id)
+{
+       return 0xf60 + id * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_SYNCPT_CPU_INCR(id) \
+       host1x_sync_syncpt_cpu_incr_r(id)
+static inline u32 host1x_sync_cbread_r(unsigned int channel)
+{
+       return 0xc80 + channel * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_CBREAD(channel) \
+       host1x_sync_cbread_r(channel)
+static inline u32 host1x_sync_cfpeek_ctrl_r(void)
+{
+       return 0x74c;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL \
+       host1x_sync_cfpeek_ctrl_r()
+static inline u32 host1x_sync_cfpeek_ctrl_addr_f(u32 v)
+{
+       return (v & 0x3ff) << 0;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL_ADDR_F(v) \
+       host1x_sync_cfpeek_ctrl_addr_f(v)
+static inline u32 host1x_sync_cfpeek_ctrl_channr_f(u32 v)
+{
+       return (v & 0xf) << 16;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL_CHANNR_F(v) \
+       host1x_sync_cfpeek_ctrl_channr_f(v)
+static inline u32 host1x_sync_cfpeek_ctrl_ena_f(u32 v)
+{
+       return (v & 0x1) << 31;
+}
+#define HOST1X_SYNC_CFPEEK_CTRL_ENA_F(v) \
+       host1x_sync_cfpeek_ctrl_ena_f(v)
+static inline u32 host1x_sync_cfpeek_read_r(void)
+{
+       return 0x750;
+}
+#define HOST1X_SYNC_CFPEEK_READ \
+       host1x_sync_cfpeek_read_r()
+static inline u32 host1x_sync_cfpeek_ptrs_r(void)
+{
+       return 0x754;
+}
+#define HOST1X_SYNC_CFPEEK_PTRS \
+       host1x_sync_cfpeek_ptrs_r()
+static inline u32 host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(u32 r)
+{
+       return (r >> 0) & 0x3ff;
+}
+#define HOST1X_SYNC_CFPEEK_PTRS_CF_RD_PTR_V(r) \
+       host1x_sync_cfpeek_ptrs_cf_rd_ptr_v(r)
+static inline u32 host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(u32 r)
+{
+       return (r >> 16) & 0x3ff;
+}
+#define HOST1X_SYNC_CFPEEK_PTRS_CF_WR_PTR_V(r) \
+       host1x_sync_cfpeek_ptrs_cf_wr_ptr_v(r)
+static inline u32 host1x_sync_cbstat_r(unsigned int channel)
+{
+       return 0xcc0 + channel * REGISTER_STRIDE;
+}
+#define HOST1X_SYNC_CBSTAT(channel) \
+       host1x_sync_cbstat_r(channel)
+static inline u32 host1x_sync_cbstat_cboffset_v(u32 r)
+{
+       return (r >> 0) & 0xffff;
+}
+#define HOST1X_SYNC_CBSTAT_CBOFFSET_V(r) \
+       host1x_sync_cbstat_cboffset_v(r)
+static inline u32 host1x_sync_cbstat_cbclass_v(u32 r)
+{
+       return (r >> 16) & 0x3ff;
+}
+#define HOST1X_SYNC_CBSTAT_CBCLASS_V(r) \
+       host1x_sync_cbstat_cbclass_v(r)
+
+#endif
diff --git a/drivers/gpu/host1x/hw/hw_host1x04_uclass.h b/drivers/gpu/host1x/hw/hw_host1x04_uclass.h
new file mode 100644 (file)
index 0000000..d1460e9
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright (c) 2013 NVIDIA Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ /*
+  * Function naming determines intended use:
+  *
+  *     <x>_r(void) : Returns the offset for register <x>.
+  *
+  *     <x>_w(void) : Returns the word offset for word (4 byte) element <x>.
+  *
+  *     <x>_<y>_s(void) : Returns size of field <y> of register <x> in bits.
+  *
+  *     <x>_<y>_f(u32 v) : Returns a value based on 'v' which has been shifted
+  *         and masked to place it at field <y> of register <x>.  This value
+  *         can be |'d with others to produce a full register value for
+  *         register <x>.
+  *
+  *     <x>_<y>_m(void) : Returns a mask for field <y> of register <x>.  This
+  *         value can be ~'d and then &'d to clear the value of field <y> for
+  *         register <x>.
+  *
+  *     <x>_<y>_<z>_f(void) : Returns the constant value <z> after being shifted
+  *         to place it at field <y> of register <x>.  This value can be |'d
+  *         with others to produce a full register value for <x>.
+  *
+  *     <x>_<y>_v(u32 r) : Returns the value of field <y> from a full register
+  *         <x> value 'r' after being shifted to place its LSB at bit 0.
+  *         This value is suitable for direct comparison with other unshifted
+  *         values appropriate for use in field <y> of register <x>.
+  *
+  *     <x>_<y>_<z>_v(void) : Returns the constant value for <z> defined for
+  *         field <y> of register <x>.  This value is suitable for direct
+  *         comparison with unshifted values appropriate for use in field <y>
+  *         of register <x>.
+  */
+
+#ifndef HOST1X_HW_HOST1X04_UCLASS_H
+#define HOST1X_HW_HOST1X04_UCLASS_H
+
+static inline u32 host1x_uclass_incr_syncpt_r(void)
+{
+       return 0x0;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT \
+       host1x_uclass_incr_syncpt_r()
+static inline u32 host1x_uclass_incr_syncpt_cond_f(u32 v)
+{
+       return (v & 0xff) << 8;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_COND_F(v) \
+       host1x_uclass_incr_syncpt_cond_f(v)
+static inline u32 host1x_uclass_incr_syncpt_indx_f(u32 v)
+{
+       return (v & 0xff) << 0;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_INDX_F(v) \
+       host1x_uclass_incr_syncpt_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_r(void)
+{
+       return 0x8;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT \
+       host1x_uclass_wait_syncpt_r()
+static inline u32 host1x_uclass_wait_syncpt_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_INDX_F(v) \
+       host1x_uclass_wait_syncpt_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_thresh_f(u32 v)
+{
+       return (v & 0xffffff) << 0;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_THRESH_F(v) \
+       host1x_uclass_wait_syncpt_thresh_f(v)
+static inline u32 host1x_uclass_wait_syncpt_base_r(void)
+{
+       return 0x9;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE \
+       host1x_uclass_wait_syncpt_base_r()
+static inline u32 host1x_uclass_wait_syncpt_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_INDX_F(v) \
+       host1x_uclass_wait_syncpt_base_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_base_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 16;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_BASE_INDX_F(v) \
+       host1x_uclass_wait_syncpt_base_base_indx_f(v)
+static inline u32 host1x_uclass_wait_syncpt_base_offset_f(u32 v)
+{
+       return (v & 0xffff) << 0;
+}
+#define HOST1X_UCLASS_WAIT_SYNCPT_BASE_OFFSET_F(v) \
+       host1x_uclass_wait_syncpt_base_offset_f(v)
+static inline u32 host1x_uclass_load_syncpt_base_r(void)
+{
+       return 0xb;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE \
+       host1x_uclass_load_syncpt_base_r()
+static inline u32 host1x_uclass_load_syncpt_base_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_BASE_INDX_F(v) \
+       host1x_uclass_load_syncpt_base_base_indx_f(v)
+static inline u32 host1x_uclass_load_syncpt_base_value_f(u32 v)
+{
+       return (v & 0xffffff) << 0;
+}
+#define HOST1X_UCLASS_LOAD_SYNCPT_BASE_VALUE_F(v) \
+       host1x_uclass_load_syncpt_base_value_f(v)
+static inline u32 host1x_uclass_incr_syncpt_base_base_indx_f(u32 v)
+{
+       return (v & 0xff) << 24;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_BASE_BASE_INDX_F(v) \
+       host1x_uclass_incr_syncpt_base_base_indx_f(v)
+static inline u32 host1x_uclass_incr_syncpt_base_offset_f(u32 v)
+{
+       return (v & 0xffffff) << 0;
+}
+#define HOST1X_UCLASS_INCR_SYNCPT_BASE_OFFSET_F(v) \
+       host1x_uclass_incr_syncpt_base_offset_f(v)
+static inline u32 host1x_uclass_indoff_r(void)
+{
+       return 0x2d;
+}
+#define HOST1X_UCLASS_INDOFF \
+       host1x_uclass_indoff_r()
+static inline u32 host1x_uclass_indoff_indbe_f(u32 v)
+{
+       return (v & 0xf) << 28;
+}
+#define HOST1X_UCLASS_INDOFF_INDBE_F(v) \
+       host1x_uclass_indoff_indbe_f(v)
+static inline u32 host1x_uclass_indoff_autoinc_f(u32 v)
+{
+       return (v & 0x1) << 27;
+}
+#define HOST1X_UCLASS_INDOFF_AUTOINC_F(v) \
+       host1x_uclass_indoff_autoinc_f(v)
+static inline u32 host1x_uclass_indoff_indmodid_f(u32 v)
+{
+       return (v & 0xff) << 18;
+}
+#define HOST1X_UCLASS_INDOFF_INDMODID_F(v) \
+       host1x_uclass_indoff_indmodid_f(v)
+static inline u32 host1x_uclass_indoff_indroffset_f(u32 v)
+{
+       return (v & 0xffff) << 2;
+}
+#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
+       host1x_uclass_indoff_indroffset_f(v)
+static inline u32 host1x_uclass_indoff_rwn_read_v(void)
+{
+       return 1;
+}
+#define HOST1X_UCLASS_INDOFF_INDROFFSET_F(v) \
+       host1x_uclass_indoff_indroffset_f(v)
+
+#endif
index b26dcc83bc1b373400d72c46aad21d04fb97f52f..db9017adfe2bb944f01558f49769f60715995c87 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/io.h>
-#include <asm/mach/irq.h>
 
 #include "../intr.h"
 #include "../dev.h"
index de5ec333ce1adc1974001d01bad56d2544d472d3..1146e3bba6e19bb69cd7f866c149b4aa7202ae46 100644 (file)
@@ -75,12 +75,14 @@ struct host1x_job *host1x_job_alloc(struct host1x_channel *ch,
 
        return job;
 }
+EXPORT_SYMBOL(host1x_job_alloc);
 
 struct host1x_job *host1x_job_get(struct host1x_job *job)
 {
        kref_get(&job->ref);
        return job;
 }
+EXPORT_SYMBOL(host1x_job_get);
 
 static void job_free(struct kref *ref)
 {
@@ -93,6 +95,7 @@ void host1x_job_put(struct host1x_job *job)
 {
        kref_put(&job->ref, job_free);
 }
+EXPORT_SYMBOL(host1x_job_put);
 
 void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo,
                           u32 words, u32 offset)
@@ -104,6 +107,7 @@ void host1x_job_add_gather(struct host1x_job *job, struct host1x_bo *bo,
        cur_gather->offset = offset;
        job->num_gathers++;
 }
+EXPORT_SYMBOL(host1x_job_add_gather);
 
 /*
  * NULL an already satisfied WAIT_SYNCPT host method, by patching its
@@ -560,6 +564,7 @@ out:
 
        return err;
 }
+EXPORT_SYMBOL(host1x_job_pin);
 
 void host1x_job_unpin(struct host1x_job *job)
 {
@@ -577,6 +582,7 @@ void host1x_job_unpin(struct host1x_job *job)
                                      job->gather_copy_mapped,
                                      job->gather_copy);
 }
+EXPORT_SYMBOL(host1x_job_unpin);
 
 /*
  * Debug routine used to dump job entries
diff --git a/drivers/gpu/host1x/mipi.c b/drivers/gpu/host1x/mipi.c
new file mode 100644 (file)
index 0000000..9882ea1
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2013 NVIDIA Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission.  The copyright holders make no representations
+ * about the suitability of this software for any purpose.  It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/host1x.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "dev.h"
+
+#define MIPI_CAL_CTRL                  0x00
+#define MIPI_CAL_CTRL_START            (1 << 0)
+
+#define MIPI_CAL_AUTOCAL_CTRL          0x01
+
+#define MIPI_CAL_STATUS                        0x02
+#define MIPI_CAL_STATUS_DONE           (1 << 16)
+#define MIPI_CAL_STATUS_ACTIVE         (1 <<  0)
+
+#define MIPI_CAL_CONFIG_CSIA           0x05
+#define MIPI_CAL_CONFIG_CSIB           0x06
+#define MIPI_CAL_CONFIG_CSIC           0x07
+#define MIPI_CAL_CONFIG_CSID           0x08
+#define MIPI_CAL_CONFIG_CSIE           0x09
+#define MIPI_CAL_CONFIG_DSIA           0x0e
+#define MIPI_CAL_CONFIG_DSIB           0x0f
+#define MIPI_CAL_CONFIG_DSIC           0x10
+#define MIPI_CAL_CONFIG_DSID           0x11
+
+#define MIPI_CAL_CONFIG_SELECT         (1 << 21)
+#define MIPI_CAL_CONFIG_HSPDOS(x)      (((x) & 0x1f) << 16)
+#define MIPI_CAL_CONFIG_HSPUOS(x)      (((x) & 0x1f) <<  8)
+#define MIPI_CAL_CONFIG_TERMOS(x)      (((x) & 0x1f) <<  0)
+
+#define MIPI_CAL_BIAS_PAD_CFG0         0x16
+#define MIPI_CAL_BIAS_PAD_PDVCLAMP     (1 << 1)
+#define MIPI_CAL_BIAS_PAD_E_VCLAMP_REF (1 << 0)
+
+#define MIPI_CAL_BIAS_PAD_CFG1         0x17
+
+#define MIPI_CAL_BIAS_PAD_CFG2         0x18
+#define MIPI_CAL_BIAS_PAD_PDVREG       (1 << 1)
+
+static const struct module {
+       unsigned long reg;
+} modules[] = {
+       { .reg = MIPI_CAL_CONFIG_CSIA },
+       { .reg = MIPI_CAL_CONFIG_CSIB },
+       { .reg = MIPI_CAL_CONFIG_CSIC },
+       { .reg = MIPI_CAL_CONFIG_CSID },
+       { .reg = MIPI_CAL_CONFIG_CSIE },
+       { .reg = MIPI_CAL_CONFIG_DSIA },
+       { .reg = MIPI_CAL_CONFIG_DSIB },
+       { .reg = MIPI_CAL_CONFIG_DSIC },
+       { .reg = MIPI_CAL_CONFIG_DSID },
+};
+
+struct tegra_mipi {
+       void __iomem *regs;
+       struct mutex lock;
+       struct clk *clk;
+};
+
+struct tegra_mipi_device {
+       struct platform_device *pdev;
+       struct tegra_mipi *mipi;
+       struct device *device;
+       unsigned long pads;
+};
+
+static inline unsigned long tegra_mipi_readl(struct tegra_mipi *mipi,
+                                            unsigned long reg)
+{
+       return readl(mipi->regs + (reg << 2));
+}
+
+static inline void tegra_mipi_writel(struct tegra_mipi *mipi,
+                                    unsigned long value, unsigned long reg)
+{
+       writel(value, mipi->regs + (reg << 2));
+}
+
+struct tegra_mipi_device *tegra_mipi_request(struct device *device)
+{
+       struct device_node *np = device->of_node;
+       struct tegra_mipi_device *dev;
+       struct of_phandle_args args;
+       int err;
+
+       err = of_parse_phandle_with_args(np, "nvidia,mipi-calibrate",
+                                        "#nvidia,mipi-calibrate-cells", 0,
+                                        &args);
+       if (err < 0)
+               return ERR_PTR(err);
+
+       dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+       if (!dev) {
+               of_node_put(args.np);
+               err = -ENOMEM;
+               goto out;
+       }
+
+       dev->pdev = of_find_device_by_node(args.np);
+       if (!dev->pdev) {
+               of_node_put(args.np);
+               err = -ENODEV;
+               goto free;
+       }
+
+       of_node_put(args.np);
+
+       dev->mipi = platform_get_drvdata(dev->pdev);
+       if (!dev->mipi) {
+               err = -EPROBE_DEFER;
+               goto pdev_put;
+       }
+
+       dev->pads = args.args[0];
+       dev->device = device;
+
+       return dev;
+
+pdev_put:
+       platform_device_put(dev->pdev);
+free:
+       kfree(dev);
+out:
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL(tegra_mipi_request);
+
+void tegra_mipi_free(struct tegra_mipi_device *device)
+{
+       platform_device_put(device->pdev);
+       kfree(device);
+}
+EXPORT_SYMBOL(tegra_mipi_free);
+
+static int tegra_mipi_wait(struct tegra_mipi *mipi)
+{
+       unsigned long timeout = jiffies + msecs_to_jiffies(250);
+       unsigned long value;
+
+       while (time_before(jiffies, timeout)) {
+               value = tegra_mipi_readl(mipi, MIPI_CAL_STATUS);
+               if ((value & MIPI_CAL_STATUS_ACTIVE) == 0 &&
+                   (value & MIPI_CAL_STATUS_DONE) != 0)
+                       return 0;
+
+               usleep_range(10, 50);
+       }
+
+       return -ETIMEDOUT;
+}
+
+int tegra_mipi_calibrate(struct tegra_mipi_device *device)
+{
+       unsigned long value;
+       unsigned int i;
+       int err;
+
+       err = clk_enable(device->mipi->clk);
+       if (err < 0)
+               return err;
+
+       mutex_lock(&device->mipi->lock);
+
+       value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG0);
+       value &= ~MIPI_CAL_BIAS_PAD_PDVCLAMP;
+       value |= MIPI_CAL_BIAS_PAD_E_VCLAMP_REF;
+       tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG0);
+
+       value = tegra_mipi_readl(device->mipi, MIPI_CAL_BIAS_PAD_CFG2);
+       value &= ~MIPI_CAL_BIAS_PAD_PDVREG;
+       tegra_mipi_writel(device->mipi, value, MIPI_CAL_BIAS_PAD_CFG2);
+
+       for (i = 0; i < ARRAY_SIZE(modules); i++) {
+               if (device->pads & BIT(i))
+                       value = MIPI_CAL_CONFIG_SELECT |
+                               MIPI_CAL_CONFIG_HSPDOS(0) |
+                               MIPI_CAL_CONFIG_HSPUOS(4) |
+                               MIPI_CAL_CONFIG_TERMOS(5);
+               else
+                       value = 0;
+
+               tegra_mipi_writel(device->mipi, value, modules[i].reg);
+       }
+
+       tegra_mipi_writel(device->mipi, MIPI_CAL_CTRL_START, MIPI_CAL_CTRL);
+
+       err = tegra_mipi_wait(device->mipi);
+
+       mutex_unlock(&device->mipi->lock);
+       clk_disable(device->mipi->clk);
+
+       return err;
+}
+EXPORT_SYMBOL(tegra_mipi_calibrate);
+
+static int tegra_mipi_probe(struct platform_device *pdev)
+{
+       struct tegra_mipi *mipi;
+       struct resource *res;
+       int err;
+
+       mipi = devm_kzalloc(&pdev->dev, sizeof(*mipi), GFP_KERNEL);
+       if (!mipi)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       mipi->regs = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(mipi->regs))
+               return PTR_ERR(mipi->regs);
+
+       mutex_init(&mipi->lock);
+
+       mipi->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(mipi->clk)) {
+               dev_err(&pdev->dev, "failed to get clock\n");
+               return PTR_ERR(mipi->clk);
+       }
+
+       err = clk_prepare(mipi->clk);
+       if (err < 0)
+               return err;
+
+       platform_set_drvdata(pdev, mipi);
+
+       return 0;
+}
+
+static int tegra_mipi_remove(struct platform_device *pdev)
+{
+       struct tegra_mipi *mipi = platform_get_drvdata(pdev);
+
+       clk_unprepare(mipi->clk);
+
+       return 0;
+}
+
+static struct of_device_id tegra_mipi_of_match[] = {
+       { .compatible = "nvidia,tegra114-mipi", },
+       { },
+};
+
+struct platform_driver tegra_mipi_driver = {
+       .driver = {
+               .name = "tegra-mipi",
+               .of_match_table = tegra_mipi_of_match,
+       },
+       .probe = tegra_mipi_probe,
+       .remove = tegra_mipi_remove,
+};
index 159c479829c959d0bd898742f9bcfec54e74020e..bfb09d802abdfe0c9bcba38d879477610d44bbd8 100644 (file)
@@ -93,6 +93,7 @@ u32 host1x_syncpt_id(struct host1x_syncpt *sp)
 {
        return sp->id;
 }
+EXPORT_SYMBOL(host1x_syncpt_id);
 
 /*
  * Updates the value sent to hardware.
@@ -168,6 +169,7 @@ int host1x_syncpt_incr(struct host1x_syncpt *sp)
 {
        return host1x_hw_syncpt_cpu_incr(sp->host, sp);
 }
+EXPORT_SYMBOL(host1x_syncpt_incr);
 
 /*
  * Updated sync point form hardware, and returns true if syncpoint is expired,
@@ -377,6 +379,7 @@ struct host1x_syncpt *host1x_syncpt_request(struct device *dev,
        struct host1x *host = dev_get_drvdata(dev->parent);
        return host1x_syncpt_alloc(host, dev, flags);
 }
+EXPORT_SYMBOL(host1x_syncpt_request);
 
 void host1x_syncpt_free(struct host1x_syncpt *sp)
 {
@@ -390,6 +393,7 @@ void host1x_syncpt_free(struct host1x_syncpt *sp)
        sp->name = NULL;
        sp->client_managed = false;
 }
+EXPORT_SYMBOL(host1x_syncpt_free);
 
 void host1x_syncpt_deinit(struct host1x *host)
 {
@@ -408,6 +412,7 @@ u32 host1x_syncpt_read_max(struct host1x_syncpt *sp)
        smp_rmb();
        return (u32)atomic_read(&sp->max_val);
 }
+EXPORT_SYMBOL(host1x_syncpt_read_max);
 
 /*
  * Read min, which is a shadow of the current sync point value in hardware.
@@ -417,6 +422,7 @@ u32 host1x_syncpt_read_min(struct host1x_syncpt *sp)
        smp_rmb();
        return (u32)atomic_read(&sp->min_val);
 }
+EXPORT_SYMBOL(host1x_syncpt_read_min);
 
 int host1x_syncpt_nb_pts(struct host1x *host)
 {
@@ -439,13 +445,16 @@ struct host1x_syncpt *host1x_syncpt_get(struct host1x *host, u32 id)
                return NULL;
        return host->syncpt + id;
 }
+EXPORT_SYMBOL(host1x_syncpt_get);
 
 struct host1x_syncpt_base *host1x_syncpt_get_base(struct host1x_syncpt *sp)
 {
        return sp ? sp->base : NULL;
 }
+EXPORT_SYMBOL(host1x_syncpt_get_base);
 
 u32 host1x_syncpt_base_id(struct host1x_syncpt_base *base)
 {
        return base->id;
 }
+EXPORT_SYMBOL(host1x_syncpt_base_id);
index 026ab0fc06f75d7671e40fb00bb73c83c815c9e3..3bfac3accd22fa6dc8a9be7a31cf9fd2814d2443 100644 (file)
@@ -2118,6 +2118,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_BERKSHIRE, USB_DEVICE_ID_BERKSHIRE_PCWD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CIDC, 0x0103) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI470X) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL, USB_DEVICE_ID_CYGNAL_RADIO_SI4713) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CM109) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_HIDCOM) },
        { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_ULTRAMOUSE) },
index 92b40c09d91790b3c9cf1bae103d361730eb884a..5a5248f2cc075b73ca68250866bddbc2b46f9bb1 100644 (file)
 #define USB_VENDOR_ID_CYGNAL           0x10c4
 #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X      0x818a
 
+#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713       0x8244
+
 #define USB_VENDOR_ID_CYPRESS          0x04b4
 #define USB_DEVICE_ID_CYPRESS_MOUSE    0x0001
 #define USB_DEVICE_ID_CYPRESS_HIDCOM   0x5500
index cea623c36ae23cc007138371b14ef05e770fe6d0..69ea36f07b4d6b47c2030fe9c82bb8bb3fe866d0 100644 (file)
@@ -209,7 +209,6 @@ static int create_gpadl_header(void *kbuffer, u32 size,
 {
        int i;
        int pagecount;
-       unsigned long long pfn;
        struct vmbus_channel_gpadl_header *gpadl_header;
        struct vmbus_channel_gpadl_body *gpadl_body;
        struct vmbus_channel_msginfo *msgheader;
@@ -219,7 +218,6 @@ static int create_gpadl_header(void *kbuffer, u32 size,
        int pfnsum, pfncount, pfnleft, pfncurr, pfnsize;
 
        pagecount = size >> PAGE_SHIFT;
-       pfn = virt_to_phys(kbuffer) >> PAGE_SHIFT;
 
        /* do we need a gpadl body msg */
        pfnsize = MAX_SIZE_CHANNEL_MESSAGE -
@@ -248,7 +246,8 @@ static int create_gpadl_header(void *kbuffer, u32 size,
                gpadl_header->range[0].byte_offset = 0;
                gpadl_header->range[0].byte_count = size;
                for (i = 0; i < pfncount; i++)
-                       gpadl_header->range[0].pfn_array[i] = pfn+i;
+                       gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys(
+                               kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT;
                *msginfo = msgheader;
                *messagecount = 1;
 
@@ -301,7 +300,9 @@ static int create_gpadl_header(void *kbuffer, u32 size,
                         * so the hypervisor gurantees that this is ok.
                         */
                        for (i = 0; i < pfncurr; i++)
-                               gpadl_body->pfn[i] = pfn + pfnsum + i;
+                               gpadl_body->pfn[i] = slow_virt_to_phys(
+                                       kbuffer + PAGE_SIZE * (pfnsum + i)) >>
+                                       PAGE_SHIFT;
 
                        /* add to msg header */
                        list_add_tail(&msgbody->msglistentry,
@@ -327,7 +328,8 @@ static int create_gpadl_header(void *kbuffer, u32 size,
                gpadl_header->range[0].byte_offset = 0;
                gpadl_header->range[0].byte_count = size;
                for (i = 0; i < pagecount; i++)
-                       gpadl_header->range[0].pfn_array[i] = pfn+i;
+                       gpadl_header->range[0].pfn_array[i] = slow_virt_to_phys(
+                               kbuffer + PAGE_SIZE * i) >> PAGE_SHIFT;
 
                *msginfo = msgheader;
                *messagecount = 1;
@@ -344,7 +346,7 @@ nomem:
  * vmbus_establish_gpadl - Estabish a GPADL for the specified buffer
  *
  * @channel: a channel
- * @kbuffer: from kmalloc
+ * @kbuffer: from kmalloc or vmalloc
  * @size: page-size multiple
  * @gpadl_handle: some funky thing
  */
index 52d548f1dc1ddbccceedab0c7f2bf9e1d53766f2..f6ca3b21aebd989bcdadeb749e4250134dfbe16e 100644 (file)
@@ -573,8 +573,8 @@ config SENSORS_IT87
        help
          If you say yes here you get support for ITE IT8705F, IT8712F,
          IT8716F, IT8718F, IT8720F, IT8721F, IT8726F, IT8728F, IT8758E,
-         IT8771E, IT8772E, IT8782F, and IT8783E/F sensor chips, and the
-         SiS950 clone.
+         IT8771E, IT8772E, IT8782F, IT8783E/F and IT8603E sensor chips,
+         and the SiS950 clone.
 
          This driver can also be built as a module.  If so, the module
          will be called it87.
index 7e16e5d07bc6868c86514dd4ac5c1343c2e4d99b..9ffc4c8ca8b5e293098cf719ffa3c7ce4334aa49 100644 (file)
@@ -2,7 +2,7 @@
  * adm1025.c
  *
  * Copyright (C) 2000       Chen-Yuan Wu <gwu@esoft.com>
- * Copyright (C) 2003-2009  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2009  Jean Delvare <jdelvare@suse.de>
  *
  * The ADM1025 is a sensor chip made by Analog Devices. It reports up to 6
  * voltages (including its own power source) and up to two temperatures
@@ -615,6 +615,6 @@ static struct adm1025_data *adm1025_update_device(struct device *dev)
 
 module_i2c_driver(adm1025_driver);
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("ADM1025 driver");
 MODULE_LICENSE("GPL");
index 9ee5e066423bee462f17dd6fc81979b618b25e20..d19c790e410a8d7a4354cf7a230e56f9bfeadf6d 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Copyright (C) 2006 Corentin LABBE <corentin.labbe@geomatys.fr>
  *
- * Based on LM83 Driver by Jean Delvare <khali@linux-fr.org>
+ * Based on LM83 Driver by Jean Delvare <jdelvare@suse.de>
  *
  * Give only processor, motherboard temperatures and fan tachs
  * Very rare chip please let me know if you use it
index 253ea396106db45e18ae6b1a54022029d5b7afc9..a8a540ca8c3495c93dd3ac7af1af15e6d9dac914 100644 (file)
@@ -4,7 +4,7 @@
  * Based on lm75.c and lm85.c
  * Supports adm1030 / adm1031
  * Copyright (C) 2004 Alexandre d'Alton <alex@alexdalton.org>
- * Reworked by Jean Delvare <khali@linux-fr.org>
+ * Reworked by Jean Delvare <jdelvare@suse.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
index 22d008bbdc1011d16919e70170f2f9d09b394235..3cefd1aeb24f4a6c73f4bffd64fe7fc5b1edea18 100644 (file)
@@ -3,7 +3,7 @@
  * Copyright (C) 2007-2008, Advanced Micro Devices, Inc.
  * Copyright (C) 2008 Jordan Crouse <jordan@cosmicpenguin.net>
  * Copyright (C) 2008 Hans de Goede <hdegoede@redhat.com>
- * Copyright (C) 2009 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2009 Jean Delvare <jdelvare@suse.de>
  *
  * Derived from the lm83 driver by Jean Delvare
  *
index 872d76744e30d1a7d603cc6ca332ab2aa76a965f..fc6f5d54e7f755282025045f843ba62dcff68fa9 100644 (file)
@@ -4,7 +4,7 @@
  * Christian W. Zuckschwerdt  <zany@triq.net>  2000-11-23
  * based on lm75.c by Frodo Looijaard <frodol@dds.nl>
  * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
- * the help of Jean Delvare <khali@linux-fr.org>
+ * the help of Jean Delvare <jdelvare@suse.de>
  *
  * The DS1621 device is a digital temperature/thermometer with 9-bit
  * resolution, a thermal alarm output (Tout), and user-defined minimum
index 82e661e8241b7a15cf8c32ce57a048429704a2cd..f76a74cb6dc4136e683559a17f0633f0f03aa251 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * emc6w201.c - Hardware monitoring driver for the SMSC EMC6W201
- * Copyright (C) 2011  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2011  Jean Delvare <jdelvare@suse.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
@@ -548,6 +548,6 @@ static struct i2c_driver emc6w201_driver = {
 
 module_i2c_driver(emc6w201_driver);
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("SMSC EMC6W201 hardware monitoring driver");
 MODULE_LICENSE("GPL");
index 15b7f5281def34947ee72afb7c3e170573d5693e..1a8aa1265262e392dd246a8aecfd39d9e997e75b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * f71805f.c - driver for the Fintek F71805F/FG and F71872F/FG Super-I/O
  *             chips integrated hardware monitoring features
- * Copyright (C) 2005-2006  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2005-2006  Jean Delvare <jdelvare@suse.de>
  *
  * The F71805F/FG is a LPC Super-I/O chip made by Fintek. It integrates
  * complete hardware monitoring features: voltage, fan and temperature
index 95257a5621d8f4da50f3175de073fed6d84f1456..1e9830513045e5bb0ecf145170904a5b24352e0c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 1998, 1999 Frodo Looijaard <frodol@dds.nl> and
  * Kyosti Malkki <kmalkki@cc.hut.fi>
  * Copyright (C) 2004 Hong-Gunn Chew <hglinux@gunnet.org> and
- * Jean Delvare <khali@linux-fr.org>
+ * Jean Delvare <jdelvare@suse.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
index 29ffa27c60b89b60bf84db948cf56a890772599e..70749fc15a4f4fdf07155a995513b7872b3bc4e6 100644 (file)
@@ -10,7 +10,8 @@
  *  This driver supports only the Environment Controller in the IT8705F and
  *  similar parts.  The other devices are supported by different drivers.
  *
- *  Supports: IT8705F  Super I/O chip w/LPC interface
+ *  Supports: IT8603E  Super I/O chip w/LPC interface
+ *            IT8705F  Super I/O chip w/LPC interface
  *            IT8712F  Super I/O chip w/LPC interface
  *            IT8716F  Super I/O chip w/LPC interface
  *            IT8718F  Super I/O chip w/LPC interface
@@ -26,7 +27,7 @@
  *            Sis950   A clone of the IT8705F
  *
  *  Copyright (C) 2001 Chris Gauthron
- *  Copyright (C) 2005-2010 Jean Delvare <khali@linux-fr.org>
+ *  Copyright (C) 2005-2010 Jean Delvare <jdelvare@suse.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
@@ -64,7 +65,7 @@
 #define DRVNAME "it87"
 
 enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8771,
-            it8772, it8782, it8783 };
+            it8772, it8782, it8783, it8603 };
 
 static unsigned short force_id;
 module_param(force_id, ushort, 0);
@@ -146,6 +147,7 @@ static inline void superio_exit(void)
 #define IT8772E_DEVID 0x8772
 #define IT8782F_DEVID 0x8782
 #define IT8783E_DEVID 0x8783
+#define IT8306E_DEVID 0x8603
 #define IT87_ACT_REG  0x30
 #define IT87_BASE_REG 0x60
 
@@ -315,6 +317,12 @@ static const struct it87_devices it87_devices[] = {
                  | FEAT_TEMP_OLD_PECI,
                .old_peci_mask = 0x4,
        },
+       [it8603] = {
+               .name = "it8603",
+               .features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
+                 | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI,
+               .peci_mask = 0x07,
+       },
 };
 
 #define has_16bit_fans(data)   ((data)->features & FEAT_16BIT_FANS)
@@ -361,7 +369,7 @@ struct it87_data {
        unsigned long last_updated;     /* In jiffies */
 
        u16 in_scaled;          /* Internal voltage sensors are scaled */
-       u8 in[9][3];            /* [nr][0]=in, [1]=min, [2]=max */
+       u8 in[10][3];           /* [nr][0]=in, [1]=min, [2]=max */
        u8 has_fan;             /* Bitfield, fans enabled */
        u16 fan[5][2];          /* Register values, [nr][0]=fan, [1]=min */
        u8 has_temp;            /* Bitfield, temp sensors enabled */
@@ -578,6 +586,7 @@ static SENSOR_DEVICE_ATTR_2(in7_max, S_IRUGO | S_IWUSR, show_in, set_in,
                            7, 2);
 
 static SENSOR_DEVICE_ATTR_2(in8_input, S_IRUGO, show_in, NULL, 8, 0);
+static SENSOR_DEVICE_ATTR_2(in9_input, S_IRUGO, show_in, NULL, 9, 0);
 
 /* 3 temperatures */
 static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
@@ -734,7 +743,7 @@ static int pwm_mode(const struct it87_data *data, int nr)
 {
        int ctrl = data->fan_main_ctrl & (1 << nr);
 
-       if (ctrl == 0)                                  /* Full speed */
+       if (ctrl == 0 && data->type != it8603)          /* Full speed */
                return 0;
        if (data->pwm_ctrl[nr] & 0x80)                  /* Automatic mode */
                return 2;
@@ -929,6 +938,10 @@ static ssize_t set_pwm_enable(struct device *dev,
                        return -EINVAL;
        }
 
+       /* IT8603E does not have on/off mode */
+       if (val == 0 && data->type == it8603)
+               return -EINVAL;
+
        mutex_lock(&data->update_lock);
 
        if (val == 0) {
@@ -948,10 +961,13 @@ static ssize_t set_pwm_enable(struct device *dev,
                else                                    /* Automatic mode */
                        data->pwm_ctrl[nr] = 0x80 | data->pwm_temp_map[nr];
                it87_write_value(data, IT87_REG_PWM(nr), data->pwm_ctrl[nr]);
-               /* set SmartGuardian mode */
-               data->fan_main_ctrl |= (1 << nr);
-               it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
-                                data->fan_main_ctrl);
+
+               if (data->type != it8603) {
+                       /* set SmartGuardian mode */
+                       data->fan_main_ctrl |= (1 << nr);
+                       it87_write_value(data, IT87_REG_FAN_MAIN_CTRL,
+                                        data->fan_main_ctrl);
+               }
        }
 
        mutex_unlock(&data->update_lock);
@@ -1415,6 +1431,8 @@ static ssize_t show_label(struct device *dev, struct device_attribute *attr,
 static SENSOR_DEVICE_ATTR(in3_label, S_IRUGO, show_label, NULL, 0);
 static SENSOR_DEVICE_ATTR(in7_label, S_IRUGO, show_label, NULL, 1);
 static SENSOR_DEVICE_ATTR(in8_label, S_IRUGO, show_label, NULL, 2);
+/* special AVCC3 IT8306E in9 */
+static SENSOR_DEVICE_ATTR(in9_label, S_IRUGO, show_label, NULL, 0);
 
 static ssize_t show_name(struct device *dev, struct device_attribute
                         *devattr, char *buf)
@@ -1424,7 +1442,7 @@ static ssize_t show_name(struct device *dev, struct device_attribute
 }
 static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
 
-static struct attribute *it87_attributes_in[9][5] = {
+static struct attribute *it87_attributes_in[10][5] = {
 {
        &sensor_dev_attr_in0_input.dev_attr.attr,
        &sensor_dev_attr_in0_min.dev_attr.attr,
@@ -1476,9 +1494,12 @@ static struct attribute *it87_attributes_in[9][5] = {
 }, {
        &sensor_dev_attr_in8_input.dev_attr.attr,
        NULL
+}, {
+       &sensor_dev_attr_in9_input.dev_attr.attr,
+       NULL
 } };
 
-static const struct attribute_group it87_group_in[9] = {
+static const struct attribute_group it87_group_in[10] = {
        { .attrs = it87_attributes_in[0] },
        { .attrs = it87_attributes_in[1] },
        { .attrs = it87_attributes_in[2] },
@@ -1488,6 +1509,7 @@ static const struct attribute_group it87_group_in[9] = {
        { .attrs = it87_attributes_in[6] },
        { .attrs = it87_attributes_in[7] },
        { .attrs = it87_attributes_in[8] },
+       { .attrs = it87_attributes_in[9] },
 };
 
 static struct attribute *it87_attributes_temp[3][6] = {
@@ -1546,7 +1568,8 @@ static struct attribute *it87_attributes_in_beep[] = {
        &sensor_dev_attr_in5_beep.dev_attr.attr,
        &sensor_dev_attr_in6_beep.dev_attr.attr,
        &sensor_dev_attr_in7_beep.dev_attr.attr,
-       NULL
+       NULL,
+       NULL,
 };
 
 static struct attribute *it87_attributes_temp_beep[] = {
@@ -1685,6 +1708,7 @@ static struct attribute *it87_attributes_label[] = {
        &sensor_dev_attr_in3_label.dev_attr.attr,
        &sensor_dev_attr_in7_label.dev_attr.attr,
        &sensor_dev_attr_in8_label.dev_attr.attr,
+       &sensor_dev_attr_in9_label.dev_attr.attr,
        NULL
 };
 
@@ -1742,6 +1766,9 @@ static int __init it87_find(unsigned short *address,
        case IT8783E_DEVID:
                sio_data->type = it8783;
                break;
+       case IT8306E_DEVID:
+               sio_data->type = it8603;
+               break;
        case 0xffff:    /* No device at all */
                goto exit;
        default:
@@ -1763,11 +1790,16 @@ static int __init it87_find(unsigned short *address,
 
        err = 0;
        sio_data->revision = superio_inb(DEVREV) & 0x0f;
-       pr_info("Found IT%04xF chip at 0x%x, revision %d\n",
-               chip_type, *address, sio_data->revision);
+       pr_info("Found IT%04x%c chip at 0x%x, revision %d\n", chip_type,
+               chip_type == 0x8771 || chip_type == 0x8772 ||
+               chip_type == 0x8603 ? 'E' : 'F', *address,
+               sio_data->revision);
 
        /* in8 (Vbat) is always internal */
        sio_data->internal = (1 << 2);
+       /* Only the IT8603E has in9 */
+       if (sio_data->type != it8603)
+               sio_data->skip_in |= (1 << 9);
 
        /* Read GPIO config and VID value from LDN 7 (GPIO) */
        if (sio_data->type == it87) {
@@ -1844,7 +1876,38 @@ static int __init it87_find(unsigned short *address,
                        sio_data->internal |= (1 << 1);
 
                sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
+       } else if (sio_data->type == it8603) {
+               int reg27, reg29;
+
+               sio_data->skip_vid = 1; /* No VID */
+               superio_select(GPIO);
 
+               reg27 = superio_inb(IT87_SIO_GPIO3_REG);
+
+               /* Check if fan3 is there or not */
+               if (reg27 & (1 << 6))
+                       sio_data->skip_pwm |= (1 << 2);
+               if (reg27 & (1 << 7))
+                       sio_data->skip_fan |= (1 << 2);
+
+               /* Check if fan2 is there or not */
+               reg29 = superio_inb(IT87_SIO_GPIO5_REG);
+               if (reg29 & (1 << 1))
+                       sio_data->skip_pwm |= (1 << 1);
+               if (reg29 & (1 << 2))
+                       sio_data->skip_fan |= (1 << 1);
+
+               sio_data->skip_in |= (1 << 5); /* No VIN5 */
+               sio_data->skip_in |= (1 << 6); /* No VIN6 */
+
+               /* no fan4 */
+               sio_data->skip_pwm |= (1 << 3);
+               sio_data->skip_fan |= (1 << 3);
+
+               sio_data->internal |= (1 << 1); /* in7 is VSB */
+               sio_data->internal |= (1 << 3); /* in9 is AVCC */
+
+               sio_data->beep_pin = superio_inb(IT87_SIO_BEEP_PIN_REG) & 0x3f;
        } else {
                int reg;
                bool uart6;
@@ -1966,7 +2029,7 @@ static void it87_remove_files(struct device *dev)
        int i;
 
        sysfs_remove_group(&dev->kobj, &it87_group);
-       for (i = 0; i < 9; i++) {
+       for (i = 0; i < 10; i++) {
                if (sio_data->skip_in & (1 << i))
                        continue;
                sysfs_remove_group(&dev->kobj, &it87_group_in[i]);
@@ -2080,6 +2143,8 @@ static int it87_probe(struct platform_device *pdev)
                        data->in_scaled |= (1 << 7);    /* in7 is VSB */
                if (sio_data->internal & (1 << 2))
                        data->in_scaled |= (1 << 8);    /* in8 is Vbat */
+               if (sio_data->internal & (1 << 3))
+                       data->in_scaled |= (1 << 9);    /* in9 is AVCC */
        } else if (sio_data->type == it8782 || sio_data->type == it8783) {
                if (sio_data->internal & (1 << 0))
                        data->in_scaled |= (1 << 3);    /* in3 is VCC5V */
@@ -2102,7 +2167,7 @@ static int it87_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       for (i = 0; i < 9; i++) {
+       for (i = 0; i < 10; i++) {
                if (sio_data->skip_in & (1 << i))
                        continue;
                err = sysfs_create_group(&dev->kobj, &it87_group_in[i]);
@@ -2202,7 +2267,7 @@ static int it87_probe(struct platform_device *pdev)
        }
 
        /* Export labels for internal sensors */
-       for (i = 0; i < 3; i++) {
+       for (i = 0; i < 4; i++) {
                if (!(sio_data->internal & (1 << i)))
                        continue;
                err = sysfs_create_file(&dev->kobj,
@@ -2383,8 +2448,9 @@ static void it87_init_device(struct platform_device *pdev)
        }
        data->has_fan = (data->fan_main_ctrl >> 4) & 0x07;
 
-       /* Set tachometers to 16-bit mode if needed */
-       if (has_16bit_fans(data)) {
+       /* Set tachometers to 16-bit mode if needed, IT8603E (and IT8728F?)
+        * has it by default */
+       if (has_16bit_fans(data) && data->type != it8603) {
                tmp = it87_read_value(data, IT87_REG_FAN_16BIT);
                if (~tmp & 0x07 & data->has_fan) {
                        dev_dbg(&pdev->dev,
@@ -2464,6 +2530,8 @@ static struct it87_data *it87_update_device(struct device *dev)
                }
                /* in8 (battery) has no limit registers */
                data->in[8][0] = it87_read_value(data, IT87_REG_VIN(8));
+               if (data->type == it8603)
+                       data->in[9][0] = it87_read_value(data, 0x2f);
 
                for (i = 0; i < 5; i++) {
                        /* Skip disabled fans */
@@ -2620,7 +2688,7 @@ static void __exit sm_it87_exit(void)
 }
 
 
-MODULE_AUTHOR("Chris Gauthron, Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Chris Gauthron, Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("IT8705F/IT871xF/IT872xF hardware monitoring driver");
 module_param(update_vbat, bool, 0);
 MODULE_PARM_DESC(update_vbat, "Update vbat if set else return powerup value");
index d0def50ea8605218632593c62411aafd976b73b2..b4ad598feb6c8ee10b7eb3b05ddfef38cf75fc9a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lm63.c - driver for the National Semiconductor LM63 temperature sensor
  *          with integrated fan control
- * Copyright (C) 2004-2008  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004-2008  Jean Delvare <jdelvare@suse.de>
  * Based on the lm90 driver.
  *
  * The LM63 is a sensor chip made by National Semiconductor. It measures
@@ -1202,6 +1202,6 @@ static struct i2c_driver lm63_driver = {
 
 module_i2c_driver(lm63_driver);
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("LM63 driver");
 MODULE_LICENSE("GPL");
index a2f3b4a365e4bbafa17385df4fdca298a7ece0e5..9efadfc851bc99e97451963705d738be33591885 100644 (file)
@@ -2,7 +2,7 @@
  * lm78.c - Part of lm_sensors, Linux kernel modules for hardware
  *         monitoring
  * Copyright (c) 1998, 1999  Frodo Looijaard <frodol@dds.nl>
- * Copyright (c) 2007, 2011  Jean Delvare <khali@linux-fr.org>
+ * Copyright (c) 2007, 2011  Jean Delvare <jdelvare@suse.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
@@ -1108,7 +1108,7 @@ static void __exit sm_lm78_exit(void)
        i2c_del_driver(&lm78_driver);
 }
 
-MODULE_AUTHOR("Frodo Looijaard, Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Frodo Looijaard, Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("LM78/LM79 driver");
 MODULE_LICENSE("GPL");
 
index e998034f1f11e35df0c5848309860fe2e9f0fd66..abd270243ba701d2332977eea1e79f485353a4c0 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lm83.c - Part of lm_sensors, Linux kernel modules for hardware
  *          monitoring
- * Copyright (C) 2003-2009  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2009  Jean Delvare <jdelvare@suse.de>
  *
  * Heavily inspired from the lm78, lm75 and adm1021 drivers. The LM83 is
  * a sensor chip made by National Semiconductor. It reports up to four
@@ -427,6 +427,6 @@ static struct lm83_data *lm83_update_device(struct device *dev)
 
 module_i2c_driver(lm83_driver);
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("LM83 driver");
 MODULE_LICENSE("GPL");
index 3894c408fda3cedc1230742cc5c0a9a653227cd5..bed4af358308def4085d603665641b744a17b0f5 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (c) 2002, 2003  Philip Pokorny <ppokorny@penguincomputing.com>
  * Copyright (c) 2003        Margit Schubert-While <margitsw@t-online.de>
  * Copyright (c) 2004        Justin Thiessen <jthiessen@penguincomputing.com>
- * Copyright (C) 2007--2009  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2007--2009  Jean Delvare <jdelvare@suse.de>
  *
  * Chip details at           <http://www.national.com/ds/LM/LM85.pdf>
  *
index 333092ce2465e234c15d415d4a99bb381100f2a3..4c5f20231c1a6a71e0daa66116340dfb701ff8b5 100644 (file)
@@ -5,7 +5,7 @@
  *                          Philip Edelbrock <phil@netroedge.com>
  *                          Stephen Rousset <stephen.rousset@rocketlogix.com>
  *                          Dan Eaton <dan.eaton@rocketlogix.com>
- * Copyright (C) 2004-2008  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004-2008  Jean Delvare <jdelvare@suse.de>
  *
  * Original port to Linux 2.6 by Jeff Oliver.
  *
@@ -1011,6 +1011,6 @@ static struct i2c_driver lm87_driver = {
 
 module_i2c_driver(lm87_driver);
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org> and others");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de> and others");
 MODULE_DESCRIPTION("LM87 driver");
 MODULE_LICENSE("GPL");
index 8b8f3aa49726873b89267ebe45f4e145eab2c7bb..701e952ae52378477d34c84afd99ce4ebb0e1df1 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * lm90.c - Part of lm_sensors, Linux kernel modules for hardware
  *          monitoring
- * Copyright (C) 2003-2010  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2010  Jean Delvare <jdelvare@suse.de>
  *
  * Based on the lm83 driver. The LM90 is a sensor chip made by National
  * Semiconductor. It reports up to two temperatures (its own plus up to
@@ -1679,6 +1679,6 @@ static struct i2c_driver lm90_driver = {
 
 module_i2c_driver(lm90_driver);
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("LM90/ADM1032 driver");
 MODULE_LICENSE("GPL");
index 71626f3c874239eba685e098f65d324707e6f946..9d0e87a4f0cbc1226cbf8efa47d99cf62dbaa4b8 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * lm92 - Hardware monitoring driver
- * Copyright (C) 2005-2008  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2005-2008  Jean Delvare <jdelvare@suse.de>
  *
  * Based on the lm90 driver, with some ideas taken from the lm_sensors
  * lm92 driver as well.
@@ -440,6 +440,6 @@ static struct i2c_driver lm92_driver = {
 
 module_i2c_driver(lm92_driver);
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("LM92/MAX6635 driver");
 MODULE_LICENSE("GPL");
index a6f46058b1be3994d03cc04217f4789a4e1a7633..6f1c6c0dbaf56c1d019375292dfbfeefb4aef25a 100644 (file)
@@ -12,7 +12,7 @@
  *     Copyright (c) 2003       Margit Schubert-While <margitsw@t-online.de>
  *
  * derived in part from w83l785ts.c:
- *     Copyright (c) 2003-2004 Jean Delvare <khali@linux-fr.org>
+ *     Copyright (c) 2003-2004 Jean Delvare <jdelvare@suse.de>
  *
  * Ported to Linux 2.6 by Eric J. Bowersox <ericb@aspsys.com>
  *     Copyright (c) 2005 Aspen Systems, Inc.
index 445e5d40ac82c5760c90dfa7fbcf3f32893ac52c..6638e997f83fbd165ebcf019aba2b2da930b715b 100644 (file)
@@ -2,7 +2,7 @@
  * max1619.c - Part of lm_sensors, Linux kernel modules for hardware
  *             monitoring
  * Copyright (C) 2003-2004 Oleksij Rempel <bug-track@fisher-privat.net>
- *                         Jean Delvare <khali@linux-fr.org>
+ *                         Jean Delvare <jdelvare@suse.de>
  *
  * Based on the lm90 driver. The MAX1619 is a sensor chip made by Maxim.
  * It reports up to two temperatures (its own plus up to
@@ -357,7 +357,6 @@ static struct max1619_data *max1619_update_device(struct device *dev)
 
 module_i2c_driver(max1619_driver);
 
-MODULE_AUTHOR("Oleksij Rempel <bug-track@fisher-privat.net> and "
-       "Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Oleksij Rempel <bug-track@fisher-privat.net>, Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("MAX1619 sensor driver");
 MODULE_LICENSE("GPL");
index 8326fbd601508d354f5a037aabdc5420b1018670..6520bc51d02a0f71faeb2456025f656bdc817b11 100644 (file)
@@ -8,7 +8,7 @@
  *
  *  Based on the max1619 driver.
  *  Copyright (C) 2003-2004 Oleksij Rempel <bug-track@fisher-privat.net>
- *                          Jean Delvare <khali@linux-fr.org>
+ *                          Jean Delvare <jdelvare@suse.de>
  *
  * The MAX6642 is a sensor chip made by Maxim.
  * It reports up to two temperatures (its own plus up to
index 8686e966fa28e20d267ddf597580ff62e4faf231..38d5a63340535567719feb35338712570a2c88d2 100644 (file)
@@ -5,7 +5,7 @@
  * Copyright (C) 2012  Guenter Roeck <linux@roeck-us.net>
  *
  * Derived from w83627ehf driver
- * Copyright (C) 2005-2012  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2005-2012  Jean Delvare <jdelvare@suse.de>
  * Copyright (C) 2006  Yuan Mu (Winbond),
  *                    Rudolf Marek <r.marek@assembler.cz>
  *                    David Hubbard <david.c.hubbard@gmail.com>
index aa615ba73d4bf70f9f627a29a7279d545dae22bb..330fe117e219ff1af15a59d5d2fc4ed11bd79cbc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  pc87360.c - Part of lm_sensors, Linux kernel modules
  *              for hardware monitoring
- *  Copyright (C) 2004, 2007 Jean Delvare <khali@linux-fr.org>
+ *  Copyright (C) 2004, 2007 Jean Delvare <jdelvare@suse.de>
  *
  *  Copied from smsc47m1.c:
  *  Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
@@ -1808,7 +1808,7 @@ static void __exit pc87360_exit(void)
 }
 
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("PC8736x hardware monitor");
 MODULE_LICENSE("GPL");
 
index 6e6ea4437bb6947692ebd5b4fcc55e698a675b3f..d847e0a084e0f605ed4f02cc7091a4caf4631617 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  pc87427.c - hardware monitoring driver for the
  *              National Semiconductor PC87427 Super-I/O chip
- *  Copyright (C) 2006, 2008, 2010  Jean Delvare <khali@linux-fr.org>
+ *  Copyright (C) 2006, 2008, 2010  Jean Delvare <jdelvare@suse.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
@@ -1347,7 +1347,7 @@ static void __exit pc87427_exit(void)
        platform_driver_unregister(&pc87427_driver);
 }
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("PC87427 hardware monitoring driver");
 MODULE_LICENSE("GPL");
 
index 825883d29002ef1b1f212a3dc02210b9511dd352..5740888c62426b3a45b8b8181a78253123944779 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Copyright (C) 2001-2004 Aurelien Jarno <aurelien@aurel32.net>
  * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
- * the help of Jean Delvare <khali@linux-fr.org>
+ * the help of Jean Delvare <jdelvare@suse.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
index e74bd7e620e8140a44a3917ef701ff22223b8a62..3532026e25dafbf1006bff72559f6e0eba00070e 100644 (file)
@@ -6,7 +6,7 @@
  *                          Kyösti Mälkki <kmalkki@cc.hut.fi>, and
  *                          Mark D. Studebaker <mdsxyz123@yahoo.com>
  * Ported to Linux 2.6 by Aurelien Jarno <aurelien@aurel32.net> with
- * the help of Jean Delvare <khali@linux-fr.org>
+ * the help of Jean Delvare <jdelvare@suse.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
index 81348fadf3b67b2deb3ef89a8a1294d344276239..bd89e87bd6ae3297b655609e92f6e1f62c98afbf 100644 (file)
@@ -9,7 +9,7 @@
  *
  * derived in part from smsc47m1.c:
  * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
- * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004 Jean Delvare <jdelvare@suse.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
index 05cb814539cb609d42e7bd9bc84abe178cb6b7a7..23a22c4eee51bb142d858c42e97ddb6b52ed1af8 100644 (file)
@@ -7,7 +7,7 @@
  * Super-I/O chips.
  *
  * Copyright (C) 2002 Mark D. Studebaker <mdsxyz123@yahoo.com>
- * Copyright (C) 2004-2007 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004-2007 Jean Delvare <jdelvare@suse.de>
  * Ported to Linux 2.6 by Gabriele Gorla <gorlik@yahoo.com>
  *                     and Jean Delvare
  *
index 23ff210513d314da9fa09e944e30c4338f9d1313..f0ab61db7a0d4f536c95ef0196674afc97cc70ac 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *  w83627ehf - Driver for the hardware monitoring functionality of
  *             the Winbond W83627EHF Super-I/O chip
- *  Copyright (C) 2005-2012  Jean Delvare <khali@linux-fr.org>
+ *  Copyright (C) 2005-2012  Jean Delvare <jdelvare@suse.de>
  *  Copyright (C) 2006  Yuan Mu (Winbond),
  *                     Rudolf Marek <r.marek@assembler.cz>
  *                     David Hubbard <david.c.hubbard@gmail.com>
@@ -2889,7 +2889,7 @@ static void __exit sensors_w83627ehf_exit(void)
        platform_driver_unregister(&w83627ehf_driver);
 }
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("W83627EHF driver");
 MODULE_LICENSE("GPL");
 
index cb9cd326ecb564147ec64474c14a296b1be764dd..c1726be3654c156ede9bdb965bb04e1d2ad6c926 100644 (file)
@@ -5,7 +5,7 @@
  *                           Philip Edelbrock <phil@netroedge.com>,
  *                           and Mark Studebaker <mdsxyz123@yahoo.com>
  * Ported to 2.6 by Bernhard C. Schrenk <clemy@clemy.org>
- * Copyright (c) 2007 - 1012  Jean Delvare <khali@linux-fr.org>
+ * Copyright (c) 2007 - 1012  Jean Delvare <jdelvare@suse.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
index f9d513949a38a7a47dcb9317c529ef7b5f93a38a..84911616d8c03e872879be61b56a01115cd05713 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (c) 1998 - 2001  Frodo Looijaard <frodol@dds.nl>,
  *                           Philip Edelbrock <phil@netroedge.com>,
  *                           and Mark Studebaker <mdsxyz123@yahoo.com>
- * Copyright (c) 2007 - 2008  Jean Delvare <khali@linux-fr.org>
+ * Copyright (c) 2007 - 2008  Jean Delvare <jdelvare@suse.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
index 908209d24664e5fd206c0bfd53738a2030f1b1b6..21894131190f4b9a3d18f29e619f352d9fcdb279 100644 (file)
@@ -2,7 +2,7 @@
  *  w83795.c - Linux kernel driver for hardware monitoring
  *  Copyright (C) 2008 Nuvoton Technology Corp.
  *                Wei Song
- *  Copyright (C) 2010 Jean Delvare <khali@linux-fr.org>
+ *  Copyright (C) 2010 Jean Delvare <jdelvare@suse.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
@@ -2282,6 +2282,6 @@ static struct i2c_driver w83795_driver = {
 
 module_i2c_driver(w83795_driver);
 
-MODULE_AUTHOR("Wei Song, Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Wei Song, Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("W83795G/ADG hardware monitoring driver");
 MODULE_LICENSE("GPL");
index 39dbe990dc102e5638b157cecb1fd3e4a3720a09..6384b268f59008406a3cd2789fd851978e35acd7 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * w83l785ts.c - Part of lm_sensors, Linux kernel modules for hardware
  *               monitoring
- * Copyright (C) 2003-2009  Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2003-2009  Jean Delvare <jdelvare@suse.de>
  *
  * Inspired from the lm83 driver. The W83L785TS-S is a sensor chip made
  * by Winbond. It reports a single external temperature with a 1 deg
@@ -10,7 +10,7 @@
  *   http://www.winbond-usa.com/products/winbond_products/pdfs/PCIC/W83L785TS-S.pdf
  *
  * Ported to Linux 2.6 by Wolfgang Ziegler <nuppla@gmx.at> and Jean Delvare
- * <khali@linux-fr.org>.
+ * <jdelvare@suse.de>.
  *
  * Thanks to James Bolt <james@evilpenguin.com> for benchmarking the read
  * error handling mechanism.
@@ -299,6 +299,6 @@ static struct w83l785ts_data *w83l785ts_update_device(struct device *dev)
 
 module_i2c_driver(w83l785ts_driver);
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("W83L785TS-S driver");
 MODULE_LICENSE("GPL");
index fad22b0bb5b06fff58eb7f5fd49533fd841a7464..65ef9664d5da884cdec666a81228408e5240b381 100644 (file)
  * ------------------------------------------------------------------------- */
 
 /* With some changes from Frodo Looijaard <frodol@dds.nl>, Kyösti Mälkki
-   <kmalkki@cc.hut.fi> and Jean Delvare <khali@linux-fr.org> */
+   <kmalkki@cc.hut.fi> and Jean Delvare <jdelvare@suse.de> */
 
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/i2c.h>
index f892a424009b8123c3cb0ceb3dae75359cceaef9..8b10f88b13d9bd8c908997d3ebdde7de84718732 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/jiffies.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pca.h>
index 5c2379522aa9fb8d9e8c0e1a6635e4429443289f..34370090b753f616ff56e8a67e8172210b05c2cd 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-pcf.h>
index 6bcdea5856afa7f84e9d2c0534bcdbfa7a696dd1..f5ed03164d86c314942453d244f103d6e9276070 100644 (file)
@@ -152,6 +152,7 @@ config I2C_PIIX4
            ATI SB700/SP5100
            ATI SB800
            AMD Hudson-2
+           AMD ML
            AMD CZ
            Serverworks OSB4
            Serverworks CSB5
index ed9f48d566dba7d4dab71d1217ce792c7dc3005a..9d7be5af2bf2a037ffb93a1e2ca60bc8f0299583 100644 (file)
@@ -12,7 +12,7 @@
  *  On Acorn machines, the following i2c devices are on the bus:
  *     - PCF8583 real time clock & static RAM
  */
-#include <linux/init.h>
+#include <linux/module.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/io.h>
index 3f491815e2c4759a5d0b7d850de20abeafe42381..7d60d3a1f621cf9fa44d66daedd4af0c7c1e0c30 100644 (file)
@@ -58,7 +58,6 @@
 #include <linux/delay.h>
 #include <linux/ioport.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/io.h>
 
index 84ccd9496a5e91934e197f49192cf5a54fc492ef..4611e4754a67071e35275a4411c327cbe59af0ce 100644 (file)
@@ -20,7 +20,6 @@
 #include <linux/delay.h>
 #include <linux/i2c.h>
 #include <linux/pci.h>
-#include <linux/init.h>
 #include <linux/acpi.h>
 
 #define ALI1563_MAX_TIMEOUT    500
index 26bcc6127cee62c1b12749944af43af76ae3b908..4823206a4870d51331ed74ab4b61b3630e12c9f7 100644 (file)
@@ -65,7 +65,6 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/io.h>
 
index 07f01ac853ff6343c6e3ca51e8066770aa189b09..41fc6837fb8b5393f2193873c765d07d87a2e955 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * i2c-amd756-s4882.c - i2c-amd756 extras for the Tyan S4882 motherboard
  *
- * Copyright (C) 2004, 2008 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004, 2008 Jean Delvare <jdelvare@suse.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
@@ -250,7 +250,7 @@ static void __exit amd756_s4882_exit(void)
                       "Physical bus restoration failed\n");
 }
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("S4882 SMBus multiplexing");
 MODULE_LICENSE("GPL");
 
index e13e2aa2d05d9fb379299fdd84635742cf37efba..819d3c1062a75878a4bd56c8762190e7a662e131 100644 (file)
@@ -41,7 +41,6 @@
 #include <linux/stddef.h>
 #include <linux/ioport.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/io.h>
 
index a44e6e77c5a1d1e55dde1a326c67c6ad1cf39dd2..f3d4d79855b5fdc8fb29dc4524422cb1056c96cb 100644 (file)
@@ -13,7 +13,6 @@
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/ioport.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/acpi.h>
index b5b89239d622d015698d638239fe50bd9562f6f9..8762458ca7da1f09d5094f5f0490bd2bb22c3c2b 100644 (file)
@@ -31,7 +31,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
index ce7ffba2b0208f24fa7324c5c7ad283346e2c693..bdf040fd8675c268510d496cc7d89bbbe1a0d8ae 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/io.h>
 #include <linux/i2c.h>
 #include <linux/gpio.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
index 3e5ea2c87a6e19b747f34a80613d892866fba77d..be7f0a20d634d1107a7bb3147b32edf0256546ed 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/errno.h>
 #include <linux/stddef.h>
index ff15ae90aaf54bb5c52585e087954338c0e40a31..e08e458bab0247161e89c9b68c10b8efd3fe255f 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/i2c.h>
 #include <linux/fs.h>
index 044f85b01d062f4485cba00a76f0fe4d8540230c..9fd711c03dd2bd2ff2de7fef34db4da569a1fbdd 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/module.h>
 
 #include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/time.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
index 436b0f254916dbe8d1a8c4e3c32e0c13e1362536..512fcfabc18e34470e81735d83dc91c2145629e4 100644 (file)
@@ -12,7 +12,6 @@
  * of this archive for more details.
  */
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/i2c.h>
 #include <linux/platform_device.h>
index 79c3d9069a487328edc82c33228c84908b401222..e248257fe517a5f62fc909826640d82d4e15a66f 100644 (file)
@@ -27,7 +27,6 @@
 #include <linux/types.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <asm/hydra.h>
 
index 737e298668878f6b0c7d7421374248b596839668..349c2d35e792b81c278edd59832a24c66d5b0caf 100644 (file)
@@ -2,7 +2,7 @@
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
     <mdsxyz123@yahoo.com>
-    Copyright (C) 2007 - 2012  Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2007 - 2012  Jean Delvare <jdelvare@suse.de>
     Copyright (C) 2010         Intel Corporation,
                                David Woodhouse <dwmw2@infradead.org>
 
@@ -1312,8 +1312,7 @@ static void __exit i2c_i801_exit(void)
        pci_unregister_driver(&i801_driver);
 }
 
-MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, "
-             "Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Mark D. Studebaker <mdsxyz123@yahoo.com>, Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("I801 SMBus driver");
 MODULE_LICENSE("GPL");
 
index f7444100f397cc41baeeb117d790e449e567ed6f..274312c96b12e0eecc46b6fb13e484316e5e3c87 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <asm/irq.h>
 #include <linux/io.h>
index dd24aa0424a9c0cc3df4588a32743171146ac812..3d16c2f60a5e17d6681dc5d3fd3a46bd0543269e 100644 (file)
@@ -34,7 +34,6 @@
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
index af213045ab7e21d52570c93fd91060d4d330d847..cf99dbf21fd100a5002aac1a6d98ddb20ab847c9 100644 (file)
@@ -33,7 +33,6 @@
 #include <linux/stddef.h>
 #include <linux/ioport.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/io.h>
 #include <linux/acpi.h>
 
index bb132ea7d2b49e1b0050ff998d0f893b6cdb80af..8ce4f517fc56eedcb01072c01adba455e8dd0a4a 100644 (file)
@@ -62,7 +62,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/pci.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
index b6a741caf4f6566fcfe0c36be0189bbe185272aa..f5391633b53ac69647f4db90cb1379a19a78a01d 100644 (file)
@@ -16,7 +16,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/sched.h>
-#include <linux/init.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
 #include <linux/of_platform.h>
index 2ca268d6140b54bdfe15eb121b6b3080a2d407a0..b170bdffb5de3aa273d27b97b567b13b27cff278 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * i2c-nforce2-s4985.c - i2c-nforce2 extras for the Tyan S4985 motherboard
  *
- * Copyright (C) 2008 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2008 Jean Delvare <jdelvare@suse.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
@@ -245,7 +245,7 @@ static void __exit nforce2_s4985_exit(void)
                       "Physical bus restoration failed\n");
 }
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("S4985 SMBus multiplexing");
 MODULE_LICENSE("GPL");
 
index ac88f4000cc23acfb8fbcdc8bbb63290aa85bb79..0038c451095c6e86d614c13fea0bca8ee298a3fb 100644 (file)
@@ -51,7 +51,6 @@
 #include <linux/kernel.h>
 #include <linux/stddef.h>
 #include <linux/ioport.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/delay.h>
 #include <linux/dmi.h>
index c61f37a10a074e30f2c3c1e368a602a85e7301b9..80e06fa45720e59235ece70499637eceed2a530f 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/err.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
index b929ba271b4705714f846fa07aae3d9116fcada3..81042b08a947669390d61715f285f8702c888f25 100644 (file)
@@ -18,7 +18,6 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/io.h>
 #include <linux/of.h>
index aa9577881925f3d9244cd13508dfb64a733a4657..62f55fe624cb3be72228decd9f03631f85d2e483 100644 (file)
@@ -1,7 +1,7 @@
 /* ------------------------------------------------------------------------ *
  * i2c-parport-light.c I2C bus over parallel port                           *
  * ------------------------------------------------------------------------ *
-   Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
+   Copyright (C) 2003-2010 Jean Delvare <jdelvare@suse.de>
 
    Based on older i2c-velleman.c driver
    Copyright (C) 1995-2000 Simon G. Vogl
@@ -273,7 +273,7 @@ static void __exit i2c_parport_exit(void)
        release_region(base, 3);
 }
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("I2C bus over parallel port (light)");
 MODULE_LICENSE("GPL");
 
index 81d887869620b40fafd3b21c76d85643a6247d0d..a27aae2d6757195039a69cd192dda8774081b194 100644 (file)
@@ -1,7 +1,7 @@
 /* ------------------------------------------------------------------------ *
  * i2c-parport.c I2C bus over parallel port                                 *
  * ------------------------------------------------------------------------ *
-   Copyright (C) 2003-2011 Jean Delvare <khali@linux-fr.org>
+   Copyright (C) 2003-2011 Jean Delvare <jdelvare@suse.de>
 
    Based on older i2c-philips-par.c driver
    Copyright (C) 1995-2000 Simon G. Vogl
@@ -298,7 +298,7 @@ static void __exit i2c_parport_exit(void)
        parport_unregister_driver(&i2c_parport_driver);
 }
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("I2C bus over parallel port");
 MODULE_LICENSE("GPL");
 
index 3fe652302ea7d2286bad2f5d9f0d696395d8a55c..e572f3aac0f79863a98d7c9c134ab6b038c36eec 100644 (file)
@@ -1,7 +1,7 @@
 /* ------------------------------------------------------------------------ *
  * i2c-parport.h I2C bus over parallel port                                 *
  * ------------------------------------------------------------------------ *
-   Copyright (C) 2003-2010 Jean Delvare <khali@linux-fr.org>
+   Copyright (C) 2003-2010 Jean Delvare <jdelvare@suse.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
index 39e2755e3f257c09bd1edd76371130fd8df0ceda..845f12598e7914bf5bf5c8f49036f6acacb017bb 100644 (file)
@@ -12,7 +12,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/jiffies.h>
index a028617b8f13c37a4a8371264a149ba7f6d44540..39dd8ec60dfda4170664c009726aa46d8c5eae42 100644 (file)
@@ -22,7 +22,7 @@
        Intel PIIX4, 440MX
        Serverworks OSB4, CSB5, CSB6, HT-1000, HT-1100
        ATI IXP200, IXP300, IXP400, SB600, SB700/SP5100, SB800
-       AMD Hudson-2, CZ
+       AMD Hudson-2, ML, CZ
        SMSC Victory66
 
    Note: we assume there can only be one device, with one or more
@@ -38,7 +38,6 @@
 #include <linux/ioport.h>
 #include <linux/i2c.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/dmi.h>
 #include <linux/acpi.h>
 #include <linux/io.h>
@@ -208,16 +207,16 @@ static int piix4_setup(struct pci_dev *PIIX4_dev,
                                   "WARNING: SMBus interface has been FORCEFULLY ENABLED!\n");
                } else {
                        dev_err(&PIIX4_dev->dev,
-                               "Host SMBus controller not enabled!\n");
+                               "SMBus Host Controller not enabled!\n");
                        release_region(piix4_smba, SMBIOSIZE);
                        return -ENODEV;
                }
        }
 
        if (((temp & 0x0E) == 8) || ((temp & 0x0E) == 2))
-               dev_dbg(&PIIX4_dev->dev, "Using Interrupt 9 for SMBus.\n");
+               dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus\n");
        else if ((temp & 0x0E) == 0)
-               dev_dbg(&PIIX4_dev->dev, "Using Interrupt SMI# for SMBus.\n");
+               dev_dbg(&PIIX4_dev->dev, "Using SMI# for SMBus\n");
        else
                dev_err(&PIIX4_dev->dev, "Illegal Interrupt configuration "
                        "(or code out of date)!\n");
@@ -235,7 +234,8 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
 {
        unsigned short piix4_smba;
        unsigned short smba_idx = 0xcd6;
-       u8 smba_en_lo, smba_en_hi, i2ccfg, i2ccfg_offset = 0x10, smb_en;
+       u8 smba_en_lo, smba_en_hi, smb_en, smb_en_status;
+       u8 i2ccfg, i2ccfg_offset = 0x10;
 
        /* SB800 and later SMBus does not support forcing address */
        if (force || force_addr) {
@@ -245,7 +245,15 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
        }
 
        /* Determine the address of the SMBus areas */
-       smb_en = (aux) ? 0x28 : 0x2c;
+       if ((PIIX4_dev->vendor == PCI_VENDOR_ID_AMD &&
+            PIIX4_dev->device == PCI_DEVICE_ID_AMD_HUDSON2_SMBUS &&
+            PIIX4_dev->revision >= 0x41) ||
+           (PIIX4_dev->vendor == PCI_VENDOR_ID_AMD &&
+            PIIX4_dev->device == 0x790b &&
+            PIIX4_dev->revision >= 0x49))
+               smb_en = 0x00;
+       else
+               smb_en = (aux) ? 0x28 : 0x2c;
 
        if (!request_region(smba_idx, 2, "smba_idx")) {
                dev_err(&PIIX4_dev->dev, "SMBus base address index region "
@@ -258,13 +266,22 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
        smba_en_hi = inb_p(smba_idx + 1);
        release_region(smba_idx, 2);
 
-       if ((smba_en_lo & 1) == 0) {
+       if (!smb_en) {
+               smb_en_status = smba_en_lo & 0x10;
+               piix4_smba = smba_en_hi << 8;
+               if (aux)
+                       piix4_smba |= 0x20;
+       } else {
+               smb_en_status = smba_en_lo & 0x01;
+               piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
+       }
+
+       if (!smb_en_status) {
                dev_err(&PIIX4_dev->dev,
-                       "Host SMBus controller not enabled!\n");
+                       "SMBus Host Controller not enabled!\n");
                return -ENODEV;
        }
 
-       piix4_smba = ((smba_en_hi << 8) | smba_en_lo) & 0xffe0;
        if (acpi_check_region(piix4_smba, SMBIOSIZE, piix4_driver.name))
                return -ENODEV;
 
@@ -277,7 +294,8 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
        /* Aux SMBus does not support IRQ information */
        if (aux) {
                dev_info(&PIIX4_dev->dev,
-                        "SMBus Host Controller at 0x%x\n", piix4_smba);
+                        "Auxiliary SMBus Host Controller at 0x%x\n",
+                        piix4_smba);
                return piix4_smba;
        }
 
@@ -292,9 +310,9 @@ static int piix4_setup_sb800(struct pci_dev *PIIX4_dev,
        release_region(piix4_smba + i2ccfg_offset, 1);
 
        if (i2ccfg & 1)
-               dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus.\n");
+               dev_dbg(&PIIX4_dev->dev, "Using IRQ for SMBus\n");
        else
-               dev_dbg(&PIIX4_dev->dev, "Using SMI# for SMBus.\n");
+               dev_dbg(&PIIX4_dev->dev, "Using SMI# for SMBus\n");
 
        dev_info(&PIIX4_dev->dev,
                 "SMBus Host Controller at 0x%x, revision %d\n",
index f6389e2c9d02d704163cd7b2f0fc6c23bda1f8ba..8564768fee32eb24d7bfd92aec29d362ffe6cbdc 100644 (file)
@@ -26,7 +26,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/platform_device.h>
 #include <linux/i2c.h>
 #include <linux/interrupt.h>
index 8c87f4a9793be22ef28b8de3c8c7ae3766b25bde..01e967763c2a70ed92e15eb4e134ab84f621d42c 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/device.h>
 #include <linux/platform_device.h>
 #include <linux/of_irq.h>
index ac80199885bef383c1a394ffbdbff335ab529b5d..c83fc3ccdd2b2c5677a977d00462c65d6c334489 100644 (file)
@@ -17,7 +17,6 @@
 #include <linux/types.h>
 #include <linux/delay.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/io.h>
index 2c2fd7c2b116624f737352fb6ea5dee55ff3cad3..0282d4d42805fae9c2a6d68c3213bf0cab18f6f6 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/err.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/i2c.h>
@@ -111,6 +110,7 @@ struct rcar_i2c_priv {
        void __iomem *io;
        struct i2c_adapter adap;
        struct i2c_msg  *msg;
+       struct clk *clk;
 
        spinlock_t lock;
        wait_queue_head_t wait;
@@ -227,18 +227,12 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
                                    u32 bus_speed,
                                    struct device *dev)
 {
-       struct clk *clkp = clk_get(dev, NULL);
        u32 scgd, cdf;
        u32 round, ick;
        u32 scl;
        u32 cdf_width;
        unsigned long rate;
 
-       if (IS_ERR(clkp)) {
-               dev_err(dev, "couldn't get clock\n");
-               return PTR_ERR(clkp);
-       }
-
        switch (priv->devtype) {
        case I2C_RCAR_GEN1:
                cdf_width = 2;
@@ -266,7 +260,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
         * clkp : peripheral_clk
         * F[]  : integer up-valuation
         */
-       rate = clk_get_rate(clkp);
+       rate = clk_get_rate(priv->clk);
        cdf = rate / 20000000;
        if (cdf >= 1 << cdf_width) {
                dev_err(dev, "Input clock %lu too high\n", rate);
@@ -308,7 +302,7 @@ static int rcar_i2c_clock_calculate(struct rcar_i2c_priv *priv,
 
 scgd_find:
        dev_dbg(dev, "clk %d/%d(%lu), round %u, CDF:0x%x, SCGD: 0x%x\n",
-               scl, bus_speed, clk_get_rate(clkp), round, cdf, scgd);
+               scl, bus_speed, clk_get_rate(priv->clk), round, cdf, scgd);
 
        /*
         * keep icccr value
@@ -604,7 +598,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
                 * error handling
                 */
                if (rcar_i2c_flags_has(priv, ID_NACK)) {
-                       ret = -EREMOTEIO;
+                       ret = -ENXIO;
                        break;
                }
 
@@ -623,7 +617,7 @@ static int rcar_i2c_master_xfer(struct i2c_adapter *adap,
 
        pm_runtime_put(dev);
 
-       if (ret < 0)
+       if (ret < 0 && ret != -ENXIO)
                dev_err(dev, "error %d : %x\n", ret, priv->flags);
 
        return ret;
@@ -664,6 +658,12 @@ static int rcar_i2c_probe(struct platform_device *pdev)
                return -ENOMEM;
        }
 
+       priv->clk = devm_clk_get(dev, NULL);
+       if (IS_ERR(priv->clk)) {
+               dev_err(dev, "cannot get clock\n");
+               return PTR_ERR(priv->clk);
+       }
+
        bus_speed = 100000; /* default 100 kHz */
        ret = of_property_read_u32(dev->of_node, "clock-frequency", &bus_speed);
        if (ret < 0 && pdata && pdata->bus_speed)
index 599235514138564ba2db1befc6b711655420cf16..dfc98df7b1b6a72ccc96e1e1b242bcab9770002e 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/stddef.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/acpi.h>
 
index 5e8f136e233f79d5205a5ef65038474721154b16..d76f3d9737ec920564e72184598010e5f581e7a2 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/delay.h>
 #include <linux/err.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/platform_device.h>
index 4fc87e7c94c9472b1df8b44f25e10dd605593805..294c80f21d65163b86e17d27a0101a3b3b921b50 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/slab.h>
index 36a9556d7cfa8e287b4e8a2f819dd7b2768842c9..19b8505d0cdd0b02ebb437dc7ac859fc91d20df1 100644 (file)
@@ -45,7 +45,6 @@
 #include <linux/delay.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/acpi.h>
 #include <linux/io.h>
index b9faf9b6002bce7c09286229fd1680a212f2d11c..f8aa0c29f02b2cdbd8f852da3aa707058e4413ec 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/stddef.h>
 #include <linux/ioport.h>
 #include <linux/i2c.h>
-#include <linux/init.h>
 #include <linux/acpi.h>
 #include <linux/io.h>
 
index 6ffa56e0851777981af053420d69df68fc7c9d1b..057602683553dc132d01e191af875378573909b1 100644 (file)
@@ -3,7 +3,7 @@
  * These devices include an I2C master which can be controlled over the
  * serial port.
  *
- * Copyright (C) 2007 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2007 Jean Delvare <jdelvare@suse.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
@@ -321,7 +321,7 @@ static void __exit taos_exit(void)
        serio_unregister_driver(&taos_drv);
 }
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("TAOS evaluation module driver");
 MODULE_LICENSE("GPL");
 
index be662511c58bf931aef8e57de31905d710952363..49d7f14b9d275074fc3181b7cacabc49fb521055 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/ioport.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/io.h>
index b2d90e105f41c93b6a6013e6e20adcfbb6927864..40d36df678dec750175a4be7e4e424e4d25e9a13 100644 (file)
@@ -2,7 +2,7 @@
     Copyright (c) 1998 - 2002  Frodo Looijaard <frodol@dds.nl>,
     Philip Edelbrock <phil@netroedge.com>, Kyösti Mälkki <kmalkki@cc.hut.fi>,
     Mark D. Studebaker <mdsxyz123@yahoo.com>
-    Copyright (C) 2005 - 2008  Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2005 - 2008  Jean Delvare <jdelvare@suse.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
@@ -503,7 +503,7 @@ static void __exit i2c_vt596_exit(void)
 
 MODULE_AUTHOR("Kyosti Malkki <kmalkki@cc.hut.fi>, "
              "Mark D. Studebaker <mdsxyz123@yahoo.com> and "
-             "Jean Delvare <khali@linux-fr.org>");
+             "Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("vt82c596 SMBus driver");
 MODULE_LICENSE("GPL");
 
index 6f9918f37b91c23f0464d3a7ed4d70ccc6ae4e93..28107502517f19005860861ca9ff17f785295575 100644 (file)
@@ -30,7 +30,6 @@
  */
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/err.h>
 #include <linux/delay.h>
index 7945b05d3ea0415c2fe86c5f578fa90787e20ef1..17f7352eca6bf7fe37ef1bb2c10f2ada6e4aa984 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
-#include <linux/init.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
index ae1258b95d6041cdfbba0194cbe0de0bf1a8d529..8eadf0f47ad7a1a295a9b4486c3bd870ed756e38 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
-#include <linux/init.h>
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/io.h>
index c4c5588ec0fbe3dcafe23ff2af00a813721fb5c5..5fb80b8962a2ad7d8e78dcee01df68cb639d3602 100644 (file)
@@ -21,7 +21,7 @@
 /* With some changes from Kyösti Mälkki <kmalkki@cc.hut.fi>.
    All SMBus-related things are written by Frodo Looijaard <frodol@dds.nl>
    SMBus 2.0 support by Mark Studebaker <mdsxyz123@yahoo.com> and
-   Jean Delvare <khali@linux-fr.org>
+   Jean Delvare <jdelvare@suse.de>
    Mux support by Rodolfo Giometti <giometti@enneenne.com> and
    Michael Lawnick <michael.lawnick.ext@nsn.com>
    OF support is copyright (c) 2008 Jochen Friedrich <jochen@scram.de>
@@ -261,10 +261,9 @@ static int i2c_device_probe(struct device *dev)
 
        acpi_dev_pm_attach(&client->dev, true);
        status = driver->probe(client, i2c_match_id(driver->id_table, client));
-       if (status) {
-               i2c_set_clientdata(client, NULL);
+       if (status)
                acpi_dev_pm_detach(&client->dev, true);
-       }
+
        return status;
 }
 
@@ -272,7 +271,7 @@ static int i2c_device_remove(struct device *dev)
 {
        struct i2c_client       *client = i2c_verify_client(dev);
        struct i2c_driver       *driver;
-       int                     status;
+       int status = 0;
 
        if (!client || !dev->driver)
                return 0;
@@ -281,12 +280,8 @@ static int i2c_device_remove(struct device *dev)
        if (driver->remove) {
                dev_dbg(dev, "remove\n");
                status = driver->remove(client);
-       } else {
-               dev->driver = NULL;
-               status = 0;
        }
-       if (status == 0)
-               i2c_set_clientdata(client, NULL);
+
        acpi_dev_pm_detach(&client->dev, true);
        return status;
 }
index c99b229873665b56656a7cabd95c7dfd6acb3fb1..fc99f0d6b4a5b0d1f11d886e5bdb5abf23073b0f 100644 (file)
@@ -2,7 +2,7 @@
  * i2c-smbus.c - SMBus extensions to the I2C protocol
  *
  * Copyright (C) 2008 David Brownell
- * Copyright (C) 2010 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2010 Jean Delvare <jdelvare@suse.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
@@ -246,6 +246,6 @@ EXPORT_SYMBOL_GPL(i2c_handle_smbus_alert);
 
 module_i2c_driver(smbalert_driver);
 
-MODULE_AUTHOR("Jean Delvare <khali@linux-fr.org>");
+MODULE_AUTHOR("Jean Delvare <jdelvare@suse.de>");
 MODULE_DESCRIPTION("SMBus protocol extensions support");
 MODULE_LICENSE("GPL");
index d0a9c590c3cd4708937c924afe9f6759602948f0..77e4849d2f2ac348ba06dbbc88f6196856758a7f 100644 (file)
@@ -2,7 +2,7 @@
     i2c-stub.c - I2C/SMBus chip emulator
 
     Copyright (c) 2004 Mark M. Hoffman <mhoffman@lightlink.com>
-    Copyright (C) 2007, 2012 Jean Delvare <khali@linux-fr.org>
+    Copyright (C) 2007, 2012 Jean Delvare <jdelvare@suse.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
index c58e093b6032480a316c1725db5f6879842cd2ef..69afffa8f427a0b055c3a13ae1dd9423b27e76da 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/kernel.h>
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/of_gpio.h>
 #include <linux/platform_device.h>
index 8a8c56f4b026d6a22e54941e9959ea633b42c321..d8989c823f50d0baa7c73c09a64e9016821b7f74 100644 (file)
@@ -12,7 +12,6 @@
 #include <linux/i2c-mux.h>
 #include <linux/i2c-mux-gpio.h>
 #include <linux/platform_device.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
index c4f08ad311832ed79da7d02d6606342e696b72c1..cb772775da431e78ba5ecf1a3da9c45fba135a03 100644 (file)
@@ -17,7 +17,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/jiffies.h>
 #include <linux/delay.h>
 #include <linux/slab.h>
index e835304e7b5a0c1305a5997b38dd3c805fd0134d..550bd36aa5d651b7324879df550563ca0c85d53e 100644 (file)
@@ -28,7 +28,7 @@
  * Based on:
  *     i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
  * and
- *     pca9540.c from Jean Delvare <khali@linux-fr.org>.
+ *     pca9540.c from Jean Delvare <jdelvare@suse.de>.
  *
  * This file is licensed under the terms of the GNU General Public
  * License version 2. This program is licensed "as is" without any
@@ -40,7 +40,6 @@
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
 #include <linux/i2c/pca954x.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/of_gpio.h>
 #include <linux/slab.h>
index d7978dc4ad0b075a03b842bc93b52a61c952ae70..4ff0ef3e07a6b9839c4bcb9e48618f859bc7e10d 100644 (file)
@@ -18,7 +18,6 @@
 
 #include <linux/i2c.h>
 #include <linux/i2c-mux.h>
-#include <linux/init.h>
 #include <linux/module.h>
 #include <linux/pinctrl/consumer.h>
 #include <linux/i2c-mux-pinctrl.h>
index 6490a2dea96b01526657615ceb7139d9b1603a55..f079ca2f260b605ae5f20b7f1010d653baad22e2 100644 (file)
@@ -9,7 +9,9 @@
 #include <linux/kernel.h>
 #include <linux/blkdev.h>
 #include <linux/cdrom.h>
+#include <linux/ide.h>
 #include <scsi/scsi.h>
+#include "ide-cd.h"
 
 #ifndef CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS
 void ide_cd_log_error(const char *name, struct request *failed_command,
index a8c2c8f8660a6a312c7d6767f9a0fee14abf79e1..40e683a84ff91b61ebd7487cd6e074528c7d3c67 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <linux/string.h>
+#include <linux/ide.h>
 
 static struct ide_pio_info {
        const char      *name;
index 9804fca6bf0605a074c13f470e4bf6cf8413bd66..2b161be3c1a346e3a7203a7f88a624dac4df1cee 100644 (file)
@@ -47,10 +47,10 @@ static int
 isert_map_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
               struct isert_rdma_wr *wr);
 static void
-isert_unreg_rdma_frwr(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn);
+isert_unreg_rdma(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn);
 static int
-isert_reg_rdma_frwr(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
-                   struct isert_rdma_wr *wr);
+isert_reg_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+              struct isert_rdma_wr *wr);
 
 static void
 isert_qp_event_callback(struct ib_event *e, void *context)
@@ -227,11 +227,11 @@ isert_create_device_ib_res(struct isert_device *device)
 
        /* asign function handlers */
        if (dev_attr->device_cap_flags & IB_DEVICE_MEM_MGT_EXTENSIONS) {
-               device->use_frwr = 1;
-               device->reg_rdma_mem = isert_reg_rdma_frwr;
-               device->unreg_rdma_mem = isert_unreg_rdma_frwr;
+               device->use_fastreg = 1;
+               device->reg_rdma_mem = isert_reg_rdma;
+               device->unreg_rdma_mem = isert_unreg_rdma;
        } else {
-               device->use_frwr = 0;
+               device->use_fastreg = 0;
                device->reg_rdma_mem = isert_map_rdma;
                device->unreg_rdma_mem = isert_unmap_cmd;
        }
@@ -239,9 +239,10 @@ isert_create_device_ib_res(struct isert_device *device)
        device->cqs_used = min_t(int, num_online_cpus(),
                                 device->ib_device->num_comp_vectors);
        device->cqs_used = min(ISERT_MAX_CQ, device->cqs_used);
-       pr_debug("Using %d CQs, device %s supports %d vectors support FRWR %d\n",
+       pr_debug("Using %d CQs, device %s supports %d vectors support "
+                "Fast registration %d\n",
                 device->cqs_used, device->ib_device->name,
-                device->ib_device->num_comp_vectors, device->use_frwr);
+                device->ib_device->num_comp_vectors, device->use_fastreg);
        device->cq_desc = kzalloc(sizeof(struct isert_cq_desc) *
                                device->cqs_used, GFP_KERNEL);
        if (!device->cq_desc) {
@@ -250,13 +251,6 @@ isert_create_device_ib_res(struct isert_device *device)
        }
        cq_desc = device->cq_desc;
 
-       device->dev_pd = ib_alloc_pd(ib_dev);
-       if (IS_ERR(device->dev_pd)) {
-               ret = PTR_ERR(device->dev_pd);
-               pr_err("ib_alloc_pd failed for dev_pd: %d\n", ret);
-               goto out_cq_desc;
-       }
-
        for (i = 0; i < device->cqs_used; i++) {
                cq_desc[i].device = device;
                cq_desc[i].cq_index = i;
@@ -294,13 +288,6 @@ isert_create_device_ib_res(struct isert_device *device)
                        goto out_cq;
        }
 
-       device->dev_mr = ib_get_dma_mr(device->dev_pd, IB_ACCESS_LOCAL_WRITE);
-       if (IS_ERR(device->dev_mr)) {
-               ret = PTR_ERR(device->dev_mr);
-               pr_err("ib_get_dma_mr failed for dev_mr: %d\n", ret);
-               goto out_cq;
-       }
-
        return 0;
 
 out_cq:
@@ -316,9 +303,6 @@ out_cq:
                        ib_destroy_cq(device->dev_tx_cq[j]);
                }
        }
-       ib_dealloc_pd(device->dev_pd);
-
-out_cq_desc:
        kfree(device->cq_desc);
 
        return ret;
@@ -341,8 +325,6 @@ isert_free_device_ib_res(struct isert_device *device)
                device->dev_tx_cq[i] = NULL;
        }
 
-       ib_dereg_mr(device->dev_mr);
-       ib_dealloc_pd(device->dev_pd);
        kfree(device->cq_desc);
 }
 
@@ -398,18 +380,18 @@ isert_device_find_by_ib_dev(struct rdma_cm_id *cma_id)
 }
 
 static void
-isert_conn_free_frwr_pool(struct isert_conn *isert_conn)
+isert_conn_free_fastreg_pool(struct isert_conn *isert_conn)
 {
        struct fast_reg_descriptor *fr_desc, *tmp;
        int i = 0;
 
-       if (list_empty(&isert_conn->conn_frwr_pool))
+       if (list_empty(&isert_conn->conn_fr_pool))
                return;
 
-       pr_debug("Freeing conn %p frwr pool", isert_conn);
+       pr_debug("Freeing conn %p fastreg pool", isert_conn);
 
        list_for_each_entry_safe(fr_desc, tmp,
-                                &isert_conn->conn_frwr_pool, list) {
+                                &isert_conn->conn_fr_pool, list) {
                list_del(&fr_desc->list);
                ib_free_fast_reg_page_list(fr_desc->data_frpl);
                ib_dereg_mr(fr_desc->data_mr);
@@ -417,20 +399,47 @@ isert_conn_free_frwr_pool(struct isert_conn *isert_conn)
                ++i;
        }
 
-       if (i < isert_conn->conn_frwr_pool_size)
+       if (i < isert_conn->conn_fr_pool_size)
                pr_warn("Pool still has %d regions registered\n",
-                       isert_conn->conn_frwr_pool_size - i);
+                       isert_conn->conn_fr_pool_size - i);
+}
+
+static int
+isert_create_fr_desc(struct ib_device *ib_device, struct ib_pd *pd,
+                    struct fast_reg_descriptor *fr_desc)
+{
+       fr_desc->data_frpl = ib_alloc_fast_reg_page_list(ib_device,
+                                                        ISCSI_ISER_SG_TABLESIZE);
+       if (IS_ERR(fr_desc->data_frpl)) {
+               pr_err("Failed to allocate data frpl err=%ld\n",
+                      PTR_ERR(fr_desc->data_frpl));
+               return PTR_ERR(fr_desc->data_frpl);
+       }
+
+       fr_desc->data_mr = ib_alloc_fast_reg_mr(pd, ISCSI_ISER_SG_TABLESIZE);
+       if (IS_ERR(fr_desc->data_mr)) {
+               pr_err("Failed to allocate data frmr err=%ld\n",
+                      PTR_ERR(fr_desc->data_mr));
+               ib_free_fast_reg_page_list(fr_desc->data_frpl);
+               return PTR_ERR(fr_desc->data_mr);
+       }
+       pr_debug("Create fr_desc %p page_list %p\n",
+                fr_desc, fr_desc->data_frpl->page_list);
+
+       fr_desc->valid = true;
+
+       return 0;
 }
 
 static int
-isert_conn_create_frwr_pool(struct isert_conn *isert_conn)
+isert_conn_create_fastreg_pool(struct isert_conn *isert_conn)
 {
        struct fast_reg_descriptor *fr_desc;
        struct isert_device *device = isert_conn->conn_device;
        int i, ret;
 
-       INIT_LIST_HEAD(&isert_conn->conn_frwr_pool);
-       isert_conn->conn_frwr_pool_size = 0;
+       INIT_LIST_HEAD(&isert_conn->conn_fr_pool);
+       isert_conn->conn_fr_pool_size = 0;
        for (i = 0; i < ISCSI_DEF_XMIT_CMDS_MAX; i++) {
                fr_desc = kzalloc(sizeof(*fr_desc), GFP_KERNEL);
                if (!fr_desc) {
@@ -439,40 +448,25 @@ isert_conn_create_frwr_pool(struct isert_conn *isert_conn)
                        goto err;
                }
 
-               fr_desc->data_frpl =
-                       ib_alloc_fast_reg_page_list(device->ib_device,
-                                                   ISCSI_ISER_SG_TABLESIZE);
-               if (IS_ERR(fr_desc->data_frpl)) {
-                       pr_err("Failed to allocate fr_pg_list err=%ld\n",
-                              PTR_ERR(fr_desc->data_frpl));
-                       ret = PTR_ERR(fr_desc->data_frpl);
-                       goto err;
-               }
-
-               fr_desc->data_mr = ib_alloc_fast_reg_mr(device->dev_pd,
-                                       ISCSI_ISER_SG_TABLESIZE);
-               if (IS_ERR(fr_desc->data_mr)) {
-                       pr_err("Failed to allocate frmr err=%ld\n",
-                              PTR_ERR(fr_desc->data_mr));
-                       ret = PTR_ERR(fr_desc->data_mr);
-                       ib_free_fast_reg_page_list(fr_desc->data_frpl);
+               ret = isert_create_fr_desc(device->ib_device,
+                                          isert_conn->conn_pd, fr_desc);
+               if (ret) {
+                       pr_err("Failed to create fastreg descriptor err=%d\n",
+                              ret);
                        goto err;
                }
-               pr_debug("Create fr_desc %p page_list %p\n",
-                        fr_desc, fr_desc->data_frpl->page_list);
 
-               fr_desc->valid = true;
-               list_add_tail(&fr_desc->list, &isert_conn->conn_frwr_pool);
-               isert_conn->conn_frwr_pool_size++;
+               list_add_tail(&fr_desc->list, &isert_conn->conn_fr_pool);
+               isert_conn->conn_fr_pool_size++;
        }
 
-       pr_debug("Creating conn %p frwr pool size=%d",
-                isert_conn, isert_conn->conn_frwr_pool_size);
+       pr_debug("Creating conn %p fastreg pool size=%d",
+                isert_conn, isert_conn->conn_fr_pool_size);
 
        return 0;
 
 err:
-       isert_conn_free_frwr_pool(isert_conn);
+       isert_conn_free_fastreg_pool(isert_conn);
        return ret;
 }
 
@@ -558,14 +552,29 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        }
 
        isert_conn->conn_device = device;
-       isert_conn->conn_pd = device->dev_pd;
-       isert_conn->conn_mr = device->dev_mr;
+       isert_conn->conn_pd = ib_alloc_pd(isert_conn->conn_device->ib_device);
+       if (IS_ERR(isert_conn->conn_pd)) {
+               ret = PTR_ERR(isert_conn->conn_pd);
+               pr_err("ib_alloc_pd failed for conn %p: ret=%d\n",
+                      isert_conn, ret);
+               goto out_pd;
+       }
 
-       if (device->use_frwr) {
-               ret = isert_conn_create_frwr_pool(isert_conn);
+       isert_conn->conn_mr = ib_get_dma_mr(isert_conn->conn_pd,
+                                          IB_ACCESS_LOCAL_WRITE);
+       if (IS_ERR(isert_conn->conn_mr)) {
+               ret = PTR_ERR(isert_conn->conn_mr);
+               pr_err("ib_get_dma_mr failed for conn %p: ret=%d\n",
+                      isert_conn, ret);
+               goto out_mr;
+       }
+
+       if (device->use_fastreg) {
+               ret = isert_conn_create_fastreg_pool(isert_conn);
                if (ret) {
-                       pr_err("Conn: %p failed to create frwr_pool\n", isert_conn);
-                       goto out_frwr;
+                       pr_err("Conn: %p failed to create fastreg pool\n",
+                              isert_conn);
+                       goto out_fastreg;
                }
        }
 
@@ -582,9 +591,13 @@ isert_connect_request(struct rdma_cm_id *cma_id, struct rdma_cm_event *event)
        return 0;
 
 out_conn_dev:
-       if (device->use_frwr)
-               isert_conn_free_frwr_pool(isert_conn);
-out_frwr:
+       if (device->use_fastreg)
+               isert_conn_free_fastreg_pool(isert_conn);
+out_fastreg:
+       ib_dereg_mr(isert_conn->conn_mr);
+out_mr:
+       ib_dealloc_pd(isert_conn->conn_pd);
+out_pd:
        isert_device_try_release(device);
 out_rsp_dma_map:
        ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma,
@@ -608,8 +621,8 @@ isert_connect_release(struct isert_conn *isert_conn)
 
        pr_debug("Entering isert_connect_release(): >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");
 
-       if (device && device->use_frwr)
-               isert_conn_free_frwr_pool(isert_conn);
+       if (device && device->use_fastreg)
+               isert_conn_free_fastreg_pool(isert_conn);
 
        if (isert_conn->conn_qp) {
                cq_index = ((struct isert_cq_desc *)
@@ -623,6 +636,9 @@ isert_connect_release(struct isert_conn *isert_conn)
        isert_free_rx_descriptors(isert_conn);
        rdma_destroy_id(isert_conn->conn_cm_id);
 
+       ib_dereg_mr(isert_conn->conn_mr);
+       ib_dealloc_pd(isert_conn->conn_pd);
+
        if (isert_conn->login_buf) {
                ib_dma_unmap_single(ib_dev, isert_conn->login_rsp_dma,
                                    ISER_RX_LOGIN_SIZE, DMA_TO_DEVICE);
@@ -1024,13 +1040,13 @@ isert_rx_login_req(struct iser_rx_desc *rx_desc, int rx_buflen,
 }
 
 static struct iscsi_cmd
-*isert_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp)
+*isert_allocate_cmd(struct iscsi_conn *conn)
 {
        struct isert_conn *isert_conn = (struct isert_conn *)conn->context;
        struct isert_cmd *isert_cmd;
        struct iscsi_cmd *cmd;
 
-       cmd = iscsit_allocate_cmd(conn, gfp);
+       cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
        if (!cmd) {
                pr_err("Unable to allocate iscsi_cmd + isert_cmd\n");
                return NULL;
@@ -1219,7 +1235,7 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
 
        switch (opcode) {
        case ISCSI_OP_SCSI_CMD:
-               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn);
                if (!cmd)
                        break;
 
@@ -1233,7 +1249,7 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                                        rx_desc, (unsigned char *)hdr);
                break;
        case ISCSI_OP_NOOP_OUT:
-               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn);
                if (!cmd)
                        break;
 
@@ -1246,7 +1262,7 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                                                (unsigned char *)hdr);
                break;
        case ISCSI_OP_SCSI_TMFUNC:
-               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn);
                if (!cmd)
                        break;
 
@@ -1254,7 +1270,7 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                                                (unsigned char *)hdr);
                break;
        case ISCSI_OP_LOGOUT:
-               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn);
                if (!cmd)
                        break;
 
@@ -1265,7 +1281,7 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
                                                    HZ);
                break;
        case ISCSI_OP_TEXT:
-               cmd = isert_allocate_cmd(conn, GFP_KERNEL);
+               cmd = isert_allocate_cmd(conn);
                if (!cmd)
                        break;
 
@@ -1404,25 +1420,25 @@ isert_unmap_cmd(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn)
 }
 
 static void
-isert_unreg_rdma_frwr(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn)
+isert_unreg_rdma(struct isert_cmd *isert_cmd, struct isert_conn *isert_conn)
 {
        struct isert_rdma_wr *wr = &isert_cmd->rdma_wr;
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
        LIST_HEAD(unmap_list);
 
-       pr_debug("unreg_frwr_cmd: %p\n", isert_cmd);
+       pr_debug("unreg_fastreg_cmd: %p\n", isert_cmd);
 
        if (wr->fr_desc) {
-               pr_debug("unreg_frwr_cmd: %p free fr_desc %p\n",
+               pr_debug("unreg_fastreg_cmd: %p free fr_desc %p\n",
                         isert_cmd, wr->fr_desc);
                spin_lock_bh(&isert_conn->conn_lock);
-               list_add_tail(&wr->fr_desc->list, &isert_conn->conn_frwr_pool);
+               list_add_tail(&wr->fr_desc->list, &isert_conn->conn_fr_pool);
                spin_unlock_bh(&isert_conn->conn_lock);
                wr->fr_desc = NULL;
        }
 
        if (wr->sge) {
-               pr_debug("unreg_frwr_cmd: %p unmap_sg op\n", isert_cmd);
+               pr_debug("unreg_fastreg_cmd: %p unmap_sg op\n", isert_cmd);
                ib_dma_unmap_sg(ib_dev, wr->sge, wr->num_sge,
                                (wr->iser_ib_op == ISER_IB_RDMA_WRITE) ?
                                DMA_TO_DEVICE : DMA_FROM_DEVICE);
@@ -2163,26 +2179,22 @@ isert_map_fr_pagelist(struct ib_device *ib_dev,
 
 static int
 isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
-                 struct isert_cmd *isert_cmd, struct isert_conn *isert_conn,
-                 struct ib_sge *ib_sge, u32 offset, unsigned int data_len)
+                 struct isert_conn *isert_conn, struct scatterlist *sg_start,
+                 struct ib_sge *ib_sge, u32 sg_nents, u32 offset,
+                 unsigned int data_len)
 {
-       struct iscsi_cmd *cmd = isert_cmd->iscsi_cmd;
        struct ib_device *ib_dev = isert_conn->conn_cm_id->device;
-       struct scatterlist *sg_start;
-       u32 sg_off, page_off;
        struct ib_send_wr fr_wr, inv_wr;
        struct ib_send_wr *bad_wr, *wr = NULL;
+       int ret, pagelist_len;
+       u32 page_off;
        u8 key;
-       int ret, sg_nents, pagelist_len;
 
-       sg_off = offset / PAGE_SIZE;
-       sg_start = &cmd->se_cmd.t_data_sg[sg_off];
-       sg_nents = min_t(unsigned int, cmd->se_cmd.t_data_nents - sg_off,
-                        ISCSI_ISER_SG_TABLESIZE);
+       sg_nents = min_t(unsigned int, sg_nents, ISCSI_ISER_SG_TABLESIZE);
        page_off = offset % PAGE_SIZE;
 
-       pr_debug("Cmd: %p use fr_desc %p sg_nents %d sg_off %d offset %u\n",
-                isert_cmd, fr_desc, sg_nents, sg_off, offset);
+       pr_debug("Use fr_desc %p sg_nents %d offset %u\n",
+                fr_desc, sg_nents, offset);
 
        pagelist_len = isert_map_fr_pagelist(ib_dev, sg_start, sg_nents,
                                             &fr_desc->data_frpl->page_list[0]);
@@ -2232,8 +2244,8 @@ isert_fast_reg_mr(struct fast_reg_descriptor *fr_desc,
 }
 
 static int
-isert_reg_rdma_frwr(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
-                   struct isert_rdma_wr *wr)
+isert_reg_rdma(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
+              struct isert_rdma_wr *wr)
 {
        struct se_cmd *se_cmd = &cmd->se_cmd;
        struct isert_cmd *isert_cmd = iscsit_priv_cmd(cmd);
@@ -2251,9 +2263,9 @@ isert_reg_rdma_frwr(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
        if (wr->iser_ib_op == ISER_IB_RDMA_WRITE) {
                data_left = se_cmd->data_length;
        } else {
-               sg_off = cmd->write_data_done / PAGE_SIZE;
-               data_left = se_cmd->data_length - cmd->write_data_done;
                offset = cmd->write_data_done;
+               sg_off = offset / PAGE_SIZE;
+               data_left = se_cmd->data_length - cmd->write_data_done;
                isert_cmd->tx_desc.isert_cmd = isert_cmd;
        }
 
@@ -2311,16 +2323,16 @@ isert_reg_rdma_frwr(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
                wr->fr_desc = NULL;
        } else {
                spin_lock_irqsave(&isert_conn->conn_lock, flags);
-               fr_desc = list_first_entry(&isert_conn->conn_frwr_pool,
+               fr_desc = list_first_entry(&isert_conn->conn_fr_pool,
                                           struct fast_reg_descriptor, list);
                list_del(&fr_desc->list);
                spin_unlock_irqrestore(&isert_conn->conn_lock, flags);
                wr->fr_desc = fr_desc;
 
-               ret = isert_fast_reg_mr(fr_desc, isert_cmd, isert_conn,
-                                 ib_sge, offset, data_len);
+               ret = isert_fast_reg_mr(fr_desc, isert_conn, sg_start,
+                                       ib_sge, sg_nents, offset, data_len);
                if (ret) {
-                       list_add_tail(&fr_desc->list, &isert_conn->conn_frwr_pool);
+                       list_add_tail(&fr_desc->list, &isert_conn->conn_fr_pool);
                        goto unmap_sg;
                }
        }
index 691f90ff2d83603541d357d3b4f09e014e93e61a..708a069002f3530e00002c5d1e454c1823119bb4 100644 (file)
@@ -119,9 +119,9 @@ struct isert_conn {
        wait_queue_head_t       conn_wait;
        wait_queue_head_t       conn_wait_comp_err;
        struct kref             conn_kref;
-       struct list_head        conn_frwr_pool;
-       int                     conn_frwr_pool_size;
-       /* lock to protect frwr_pool */
+       struct list_head        conn_fr_pool;
+       int                     conn_fr_pool_size;
+       /* lock to protect fastreg pool */
        spinlock_t              conn_lock;
 #define ISERT_COMP_BATCH_COUNT 8
        int                     conn_comp_batch;
@@ -139,13 +139,11 @@ struct isert_cq_desc {
 };
 
 struct isert_device {
-       int                     use_frwr;
+       int                     use_fastreg;
        int                     cqs_used;
        int                     refcount;
        int                     cq_active_qps[ISERT_MAX_CQ];
        struct ib_device        *ib_device;
-       struct ib_pd            *dev_pd;
-       struct ib_mr            *dev_mr;
        struct ib_cq            *dev_rx_cq[ISERT_MAX_CQ];
        struct ib_cq            *dev_tx_cq[ISERT_MAX_CQ];
        struct isert_cq_desc    *cq_desc;
index 3e7fdbb4916b1c810314acb77fe9f3b0a2c7cdf1..79bbc21c1d01671b6c7d289c3c1ff44db449e4ec 100644 (file)
@@ -207,6 +207,7 @@ config SHMOBILE_IOMMU
        bool "IOMMU for Renesas IPMMU/IPMMUI"
        default n
        depends on ARM
+       depends on SH_MOBILE || COMPILE_TEST
        select IOMMU_API
        select ARM_DMA_USE_IOMMU
        select SHMOBILE_IPMMU
index 72531f008a5e34ea871e7d3d3569a724af695d86..faf0da4bb3a2f84bfd69c911d8de100028b25b7e 100644 (file)
@@ -248,8 +248,8 @@ static bool check_device(struct device *dev)
        if (!dev || !dev->dma_mask)
                return false;
 
-       /* No device or no PCI device */
-       if (dev->bus != &pci_bus_type)
+       /* No PCI device */
+       if (!dev_is_pci(dev))
                return false;
 
        devid = get_device_id(dev);
index e46a88700b6824c735967118281c9f7feb6e41b0..8911850c94445fa5adf3b41de168293e5adf7721 100644 (file)
@@ -24,7 +24,7 @@
  *     - v7/v8 long-descriptor format
  *     - Non-secure access to the SMMU
  *     - 4k and 64k pages, with contiguous pte hints.
- *     - Up to 39-bit addressing
+ *     - Up to 42-bit addressing (dependent on VA_BITS)
  *     - Context fault reporting
  */
 
 #define ARM_SMMU_GR1(smmu)             ((smmu)->base + (smmu)->pagesize)
 
 /* Page table bits */
-#define ARM_SMMU_PTE_PAGE              (((pteval_t)3) << 0)
+#define ARM_SMMU_PTE_XN                        (((pteval_t)3) << 53)
 #define ARM_SMMU_PTE_CONT              (((pteval_t)1) << 52)
 #define ARM_SMMU_PTE_AF                        (((pteval_t)1) << 10)
 #define ARM_SMMU_PTE_SH_NS             (((pteval_t)0) << 8)
 #define ARM_SMMU_PTE_SH_OS             (((pteval_t)2) << 8)
 #define ARM_SMMU_PTE_SH_IS             (((pteval_t)3) << 8)
+#define ARM_SMMU_PTE_PAGE              (((pteval_t)3) << 0)
 
 #if PAGE_SIZE == SZ_4K
 #define ARM_SMMU_PTE_CONT_ENTRIES      16
@@ -1205,7 +1206,7 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
                                   unsigned long pfn, int flags, int stage)
 {
        pte_t *pte, *start;
-       pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF;
+       pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF | ARM_SMMU_PTE_XN;
 
        if (pmd_none(*pmd)) {
                /* Allocate a new set of tables */
@@ -1244,7 +1245,9 @@ static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
        }
 
        /* If no access, create a faulting entry to avoid TLB fills */
-       if (!(flags & (IOMMU_READ | IOMMU_WRITE)))
+       if (flags & IOMMU_EXEC)
+               pteval &= ~ARM_SMMU_PTE_XN;
+       else if (!(flags & (IOMMU_READ | IOMMU_WRITE)))
                pteval &= ~ARM_SMMU_PTE_PAGE;
 
        pteval |= ARM_SMMU_PTE_SH_IS;
@@ -1494,6 +1497,13 @@ static int arm_smmu_add_device(struct device *dev)
 {
        struct arm_smmu_device *child, *parent, *smmu;
        struct arm_smmu_master *master = NULL;
+       struct iommu_group *group;
+       int ret;
+
+       if (dev->archdata.iommu) {
+               dev_warn(dev, "IOMMU driver already assigned to device\n");
+               return -EINVAL;
+       }
 
        spin_lock(&arm_smmu_devices_lock);
        list_for_each_entry(parent, &arm_smmu_devices, list) {
@@ -1526,13 +1536,23 @@ static int arm_smmu_add_device(struct device *dev)
        if (!master)
                return -ENODEV;
 
+       group = iommu_group_alloc();
+       if (IS_ERR(group)) {
+               dev_err(dev, "Failed to allocate IOMMU group\n");
+               return PTR_ERR(group);
+       }
+
+       ret = iommu_group_add_device(group, dev);
+       iommu_group_put(group);
        dev->archdata.iommu = smmu;
-       return 0;
+
+       return ret;
 }
 
 static void arm_smmu_remove_device(struct device *dev)
 {
        dev->archdata.iommu = NULL;
+       iommu_group_remove_device(dev);
 }
 
 static struct iommu_ops arm_smmu_ops = {
@@ -1730,7 +1750,6 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
         * allocation (PTRS_PER_PGD).
         */
 #ifdef CONFIG_64BIT
-       /* Current maximum output size of 39 bits */
        smmu->s1_output_size = min(39UL, size);
 #else
        smmu->s1_output_size = min(32UL, size);
@@ -1745,7 +1764,7 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
        } else {
 #ifdef CONFIG_64BIT
                size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
-               size = min(39, arm_smmu_id_size_to_bits(size));
+               size = min(VA_BITS, arm_smmu_id_size_to_bits(size));
 #else
                size = 32;
 #endif
index 8b452c9676d968ca5650b1ad8ce2128571014ba8..1581565434106027dca83e1e7bae4c640b3febe9 100644 (file)
@@ -52,6 +52,9 @@ LIST_HEAD(dmar_drhd_units);
 struct acpi_table_header * __initdata dmar_tbl;
 static acpi_size dmar_tbl_size;
 
+static int alloc_iommu(struct dmar_drhd_unit *drhd);
+static void free_iommu(struct intel_iommu *iommu);
+
 static void __init dmar_register_drhd_unit(struct dmar_drhd_unit *drhd)
 {
        /*
@@ -100,7 +103,6 @@ static int __init dmar_parse_one_dev_scope(struct acpi_dmar_device_scope *scope,
        if (!pdev) {
                pr_warn("Device scope device [%04x:%02x:%02x.%02x] not found\n",
                        segment, scope->bus, path->device, path->function);
-               *dev = NULL;
                return 0;
        }
        if ((scope->entry_type == ACPI_DMAR_SCOPE_TYPE_ENDPOINT && \
@@ -151,7 +153,7 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
                        ret = dmar_parse_one_dev_scope(scope,
                                &(*devices)[index], segment);
                        if (ret) {
-                               kfree(*devices);
+                               dmar_free_dev_scope(devices, cnt);
                                return ret;
                        }
                        index ++;
@@ -162,6 +164,17 @@ int __init dmar_parse_dev_scope(void *start, void *end, int *cnt,
        return 0;
 }
 
+void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt)
+{
+       if (*devices && *cnt) {
+               while (--*cnt >= 0)
+                       pci_dev_put((*devices)[*cnt]);
+               kfree(*devices);
+               *devices = NULL;
+               *cnt = 0;
+       }
+}
+
 /**
  * dmar_parse_one_drhd - parses exactly one DMA remapping hardware definition
  * structure which uniquely represent one DMA remapping hardware unit
@@ -193,25 +206,28 @@ dmar_parse_one_drhd(struct acpi_dmar_header *header)
        return 0;
 }
 
+static void dmar_free_drhd(struct dmar_drhd_unit *dmaru)
+{
+       if (dmaru->devices && dmaru->devices_cnt)
+               dmar_free_dev_scope(&dmaru->devices, &dmaru->devices_cnt);
+       if (dmaru->iommu)
+               free_iommu(dmaru->iommu);
+       kfree(dmaru);
+}
+
 static int __init dmar_parse_dev(struct dmar_drhd_unit *dmaru)
 {
        struct acpi_dmar_hardware_unit *drhd;
-       int ret = 0;
 
        drhd = (struct acpi_dmar_hardware_unit *) dmaru->hdr;
 
        if (dmaru->include_all)
                return 0;
 
-       ret = dmar_parse_dev_scope((void *)(drhd + 1),
-                               ((void *)drhd) + drhd->header.length,
-                               &dmaru->devices_cnt, &dmaru->devices,
-                               drhd->segment);
-       if (ret) {
-               list_del(&dmaru->list);
-               kfree(dmaru);
-       }
-       return ret;
+       return dmar_parse_dev_scope((void *)(drhd + 1),
+                                   ((void *)drhd) + drhd->header.length,
+                                   &dmaru->devices_cnt, &dmaru->devices,
+                                   drhd->segment);
 }
 
 #ifdef CONFIG_ACPI_NUMA
@@ -423,7 +439,7 @@ dmar_find_matched_drhd_unit(struct pci_dev *dev)
 int __init dmar_dev_scope_init(void)
 {
        static int dmar_dev_scope_initialized;
-       struct dmar_drhd_unit *drhd, *drhd_n;
+       struct dmar_drhd_unit *drhd;
        int ret = -ENODEV;
 
        if (dmar_dev_scope_initialized)
@@ -432,7 +448,7 @@ int __init dmar_dev_scope_init(void)
        if (list_empty(&dmar_drhd_units))
                goto fail;
 
-       list_for_each_entry_safe(drhd, drhd_n, &dmar_drhd_units, list) {
+       list_for_each_entry(drhd, &dmar_drhd_units, list) {
                ret = dmar_parse_dev(drhd);
                if (ret)
                        goto fail;
@@ -456,24 +472,23 @@ int __init dmar_table_init(void)
        static int dmar_table_initialized;
        int ret;
 
-       if (dmar_table_initialized)
-               return 0;
-
-       dmar_table_initialized = 1;
-
-       ret = parse_dmar_table();
-       if (ret) {
-               if (ret != -ENODEV)
-                       pr_info("parse DMAR table failure.\n");
-               return ret;
-       }
+       if (dmar_table_initialized == 0) {
+               ret = parse_dmar_table();
+               if (ret < 0) {
+                       if (ret != -ENODEV)
+                               pr_info("parse DMAR table failure.\n");
+               } else  if (list_empty(&dmar_drhd_units)) {
+                       pr_info("No DMAR devices found\n");
+                       ret = -ENODEV;
+               }
 
-       if (list_empty(&dmar_drhd_units)) {
-               pr_info("No DMAR devices found\n");
-               return -ENODEV;
+               if (ret < 0)
+                       dmar_table_initialized = ret;
+               else
+                       dmar_table_initialized = 1;
        }
 
-       return 0;
+       return dmar_table_initialized < 0 ? dmar_table_initialized : 0;
 }
 
 static void warn_invalid_dmar(u64 addr, const char *message)
@@ -488,7 +503,7 @@ static void warn_invalid_dmar(u64 addr, const char *message)
                dmi_get_system_info(DMI_PRODUCT_VERSION));
 }
 
-int __init check_zero_address(void)
+static int __init check_zero_address(void)
 {
        struct acpi_table_dmar *dmar;
        struct acpi_dmar_header *entry_header;
@@ -546,14 +561,6 @@ int __init detect_intel_iommu(void)
        if (ret)
                ret = check_zero_address();
        {
-               struct acpi_table_dmar *dmar;
-
-               dmar = (struct acpi_table_dmar *) dmar_tbl;
-
-               if (ret && irq_remapping_enabled && cpu_has_x2apic &&
-                   dmar->flags & 0x1)
-                       pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
-
                if (ret && !no_iommu && !iommu_detected && !dmar_disabled) {
                        iommu_detected = 1;
                        /* Make sure ACS will be enabled */
@@ -565,7 +572,7 @@ int __init detect_intel_iommu(void)
                        x86_init.iommu.iommu_init = intel_iommu_init;
 #endif
        }
-       early_acpi_os_unmap_memory(dmar_tbl, dmar_tbl_size);
+       early_acpi_os_unmap_memory((void __iomem *)dmar_tbl, dmar_tbl_size);
        dmar_tbl = NULL;
 
        return ret ? 1 : -ENODEV;
@@ -647,7 +654,7 @@ out:
        return err;
 }
 
-int alloc_iommu(struct dmar_drhd_unit *drhd)
+static int alloc_iommu(struct dmar_drhd_unit *drhd)
 {
        struct intel_iommu *iommu;
        u32 ver, sts;
@@ -721,12 +728,19 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        return err;
 }
 
-void free_iommu(struct intel_iommu *iommu)
+static void free_iommu(struct intel_iommu *iommu)
 {
-       if (!iommu)
-               return;
+       if (iommu->irq) {
+               free_irq(iommu->irq, iommu);
+               irq_set_handler_data(iommu->irq, NULL);
+               destroy_irq(iommu->irq);
+       }
 
-       free_dmar_iommu(iommu);
+       if (iommu->qi) {
+               free_page((unsigned long)iommu->qi->desc);
+               kfree(iommu->qi->desc_status);
+               kfree(iommu->qi);
+       }
 
        if (iommu->reg)
                unmap_iommu(iommu);
@@ -1050,7 +1064,7 @@ int dmar_enable_qi(struct intel_iommu *iommu)
        desc_page = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO, 0);
        if (!desc_page) {
                kfree(qi);
-               iommu->qi = 0;
+               iommu->qi = NULL;
                return -ENOMEM;
        }
 
@@ -1060,7 +1074,7 @@ int dmar_enable_qi(struct intel_iommu *iommu)
        if (!qi->desc_status) {
                free_page((unsigned long) qi->desc);
                kfree(qi);
-               iommu->qi = 0;
+               iommu->qi = NULL;
                return -ENOMEM;
        }
 
@@ -1111,9 +1125,7 @@ static const char *irq_remap_fault_reasons[] =
        "Blocked an interrupt request due to source-id verification failure",
 };
 
-#define MAX_FAULT_REASON_IDX   (ARRAY_SIZE(fault_reason_strings) - 1)
-
-const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
+static const char *dmar_get_fault_reason(u8 fault_reason, int *fault_type)
 {
        if (fault_reason >= 0x20 && (fault_reason - 0x20 <
                                        ARRAY_SIZE(irq_remap_fault_reasons))) {
@@ -1303,15 +1315,14 @@ int dmar_set_interrupt(struct intel_iommu *iommu)
 int __init enable_drhd_fault_handling(void)
 {
        struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
 
        /*
         * Enable fault control interrupt.
         */
-       for_each_drhd_unit(drhd) {
-               int ret;
-               struct intel_iommu *iommu = drhd->iommu;
+       for_each_iommu(iommu, drhd) {
                u32 fault_status;
-               ret = dmar_set_interrupt(iommu);
+               int ret = dmar_set_interrupt(iommu);
 
                if (ret) {
                        pr_err("DRHD %Lx: failed to enable fault, interrupt, ret %d\n",
@@ -1366,4 +1377,22 @@ int __init dmar_ir_support(void)
                return 0;
        return dmar->flags & 0x1;
 }
+
+static int __init dmar_free_unused_resources(void)
+{
+       struct dmar_drhd_unit *dmaru, *dmaru_n;
+
+       /* DMAR units are in use */
+       if (irq_remapping_enabled || intel_iommu_enabled)
+               return 0;
+
+       list_for_each_entry_safe(dmaru, dmaru_n, &dmar_drhd_units, list) {
+               list_del(&dmaru->list);
+               dmar_free_drhd(dmaru);
+       }
+
+       return 0;
+}
+
+late_initcall(dmar_free_unused_resources);
 IOMMU_INIT_POST(detect_intel_iommu);
index c857c30da9791e9a01f9630f293e5a0d1315dc47..93072ba44b1d179dff9a486cd728cf16ea645691 100644 (file)
@@ -691,7 +691,7 @@ static int fsl_pamu_attach_device(struct iommu_domain *domain,
         * Use LIODN of the PCI controller while attaching a
         * PCI device.
         */
-       if (dev->bus == &pci_bus_type) {
+       if (dev_is_pci(dev)) {
                pdev = to_pci_dev(dev);
                pci_ctl = pci_bus_to_host(pdev->bus);
                /*
@@ -729,7 +729,7 @@ static void fsl_pamu_detach_device(struct iommu_domain *domain,
         * Use LIODN of the PCI controller while detaching a
         * PCI device.
         */
-       if (dev->bus == &pci_bus_type) {
+       if (dev_is_pci(dev)) {
                pdev = to_pci_dev(dev);
                pci_ctl = pci_bus_to_host(pdev->bus);
                /*
@@ -1056,7 +1056,7 @@ static int fsl_pamu_add_device(struct device *dev)
         * For platform devices we allocate a separate group for
         * each of the devices.
         */
-       if (dev->bus == &pci_bus_type) {
+       if (dev_is_pci(dev)) {
                pdev = to_pci_dev(dev);
                /* Don't create device groups for virtual PCI bridges */
                if (pdev->subordinate)
index 59779e19315e1c55eef91bdc0dbe067c1ff701c0..a22c86c867faee78544b99b8528e1f4b9fc183c8 100644 (file)
@@ -63,6 +63,7 @@
 #define DEFAULT_DOMAIN_ADDRESS_WIDTH 48
 
 #define MAX_AGAW_WIDTH 64
+#define MAX_AGAW_PFN_WIDTH     (MAX_AGAW_WIDTH - VTD_PAGE_SHIFT)
 
 #define __DOMAIN_MAX_PFN(gaw)  ((((uint64_t)1) << (gaw-VTD_PAGE_SHIFT)) - 1)
 #define __DOMAIN_MAX_ADDR(gaw) ((((uint64_t)1) << gaw) - 1)
@@ -106,12 +107,12 @@ static inline int agaw_to_level(int agaw)
 
 static inline int agaw_to_width(int agaw)
 {
-       return 30 + agaw * LEVEL_STRIDE;
+       return min_t(int, 30 + agaw * LEVEL_STRIDE, MAX_AGAW_WIDTH);
 }
 
 static inline int width_to_agaw(int width)
 {
-       return (width - 30) / LEVEL_STRIDE;
+       return DIV_ROUND_UP(width - 30, LEVEL_STRIDE);
 }
 
 static inline unsigned int level_to_offset_bits(int level)
@@ -141,7 +142,7 @@ static inline unsigned long align_to_level(unsigned long pfn, int level)
 
 static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
 {
-       return  1 << ((lvl - 1) * LEVEL_STRIDE);
+       return  1 << min_t(int, (lvl - 1) * LEVEL_STRIDE, MAX_AGAW_PFN_WIDTH);
 }
 
 /* VT-d pages must always be _smaller_ than MM pages. Otherwise things
@@ -288,26 +289,6 @@ static inline void dma_clear_pte(struct dma_pte *pte)
        pte->val = 0;
 }
 
-static inline void dma_set_pte_readable(struct dma_pte *pte)
-{
-       pte->val |= DMA_PTE_READ;
-}
-
-static inline void dma_set_pte_writable(struct dma_pte *pte)
-{
-       pte->val |= DMA_PTE_WRITE;
-}
-
-static inline void dma_set_pte_snp(struct dma_pte *pte)
-{
-       pte->val |= DMA_PTE_SNP;
-}
-
-static inline void dma_set_pte_prot(struct dma_pte *pte, unsigned long prot)
-{
-       pte->val = (pte->val & ~3) | (prot & 3);
-}
-
 static inline u64 dma_pte_addr(struct dma_pte *pte)
 {
 #ifdef CONFIG_64BIT
@@ -318,11 +299,6 @@ static inline u64 dma_pte_addr(struct dma_pte *pte)
 #endif
 }
 
-static inline void dma_set_pte_pfn(struct dma_pte *pte, unsigned long pfn)
-{
-       pte->val |= (uint64_t)pfn << VTD_PAGE_SHIFT;
-}
-
 static inline bool dma_pte_present(struct dma_pte *pte)
 {
        return (pte->val & 3) != 0;
@@ -406,7 +382,7 @@ struct device_domain_info {
 
 static void flush_unmaps_timeout(unsigned long data);
 
-DEFINE_TIMER(unmap_timer,  flush_unmaps_timeout, 0, 0);
+static DEFINE_TIMER(unmap_timer,  flush_unmaps_timeout, 0, 0);
 
 #define HIGH_WATER_MARK 250
 struct deferred_flush_tables {
@@ -652,9 +628,7 @@ static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
        struct dmar_drhd_unit *drhd = NULL;
        int i;
 
-       for_each_drhd_unit(drhd) {
-               if (drhd->ignored)
-                       continue;
+       for_each_active_drhd_unit(drhd) {
                if (segment != drhd->segment)
                        continue;
 
@@ -865,7 +839,6 @@ static int dma_pte_clear_range(struct dmar_domain *domain,
        int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        unsigned int large_page = 1;
        struct dma_pte *first_pte, *pte;
-       int order;
 
        BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
        BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
@@ -890,8 +863,7 @@ static int dma_pte_clear_range(struct dmar_domain *domain,
 
        } while (start_pfn && start_pfn <= last_pfn);
 
-       order = (large_page - 1) * 9;
-       return order;
+       return min_t(int, (large_page - 1) * 9, MAX_AGAW_PFN_WIDTH);
 }
 
 static void dma_pte_free_level(struct dmar_domain *domain, int level,
@@ -1255,8 +1227,8 @@ static int iommu_init_domains(struct intel_iommu *iommu)
        unsigned long nlongs;
 
        ndomains = cap_ndoms(iommu->cap);
-       pr_debug("IOMMU %d: Number of Domains supported <%ld>\n", iommu->seq_id,
-                       ndomains);
+       pr_debug("IOMMU%d: Number of Domains supported <%ld>\n",
+                iommu->seq_id, ndomains);
        nlongs = BITS_TO_LONGS(ndomains);
 
        spin_lock_init(&iommu->lock);
@@ -1266,13 +1238,17 @@ static int iommu_init_domains(struct intel_iommu *iommu)
         */
        iommu->domain_ids = kcalloc(nlongs, sizeof(unsigned long), GFP_KERNEL);
        if (!iommu->domain_ids) {
-               printk(KERN_ERR "Allocating domain id array failed\n");
+               pr_err("IOMMU%d: allocating domain id array failed\n",
+                      iommu->seq_id);
                return -ENOMEM;
        }
        iommu->domains = kcalloc(ndomains, sizeof(struct dmar_domain *),
                        GFP_KERNEL);
        if (!iommu->domains) {
-               printk(KERN_ERR "Allocating domain array failed\n");
+               pr_err("IOMMU%d: allocating domain array failed\n",
+                      iommu->seq_id);
+               kfree(iommu->domain_ids);
+               iommu->domain_ids = NULL;
                return -ENOMEM;
        }
 
@@ -1289,10 +1265,10 @@ static int iommu_init_domains(struct intel_iommu *iommu)
 static void domain_exit(struct dmar_domain *domain);
 static void vm_domain_exit(struct dmar_domain *domain);
 
-void free_dmar_iommu(struct intel_iommu *iommu)
+static void free_dmar_iommu(struct intel_iommu *iommu)
 {
        struct dmar_domain *domain;
-       int i;
+       int i, count;
        unsigned long flags;
 
        if ((iommu->domains) && (iommu->domain_ids)) {
@@ -1301,28 +1277,24 @@ void free_dmar_iommu(struct intel_iommu *iommu)
                        clear_bit(i, iommu->domain_ids);
 
                        spin_lock_irqsave(&domain->iommu_lock, flags);
-                       if (--domain->iommu_count == 0) {
+                       count = --domain->iommu_count;
+                       spin_unlock_irqrestore(&domain->iommu_lock, flags);
+                       if (count == 0) {
                                if (domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE)
                                        vm_domain_exit(domain);
                                else
                                        domain_exit(domain);
                        }
-                       spin_unlock_irqrestore(&domain->iommu_lock, flags);
                }
        }
 
        if (iommu->gcmd & DMA_GCMD_TE)
                iommu_disable_translation(iommu);
 
-       if (iommu->irq) {
-               irq_set_handler_data(iommu->irq, NULL);
-               /* This will mask the irq */
-               free_irq(iommu->irq, iommu);
-               destroy_irq(iommu->irq);
-       }
-
        kfree(iommu->domains);
        kfree(iommu->domain_ids);
+       iommu->domains = NULL;
+       iommu->domain_ids = NULL;
 
        g_iommus[iommu->seq_id] = NULL;
 
@@ -2245,8 +2217,6 @@ static int __init si_domain_init(int hw)
        if (!si_domain)
                return -EFAULT;
 
-       pr_debug("Identity mapping domain is domain %d\n", si_domain->id);
-
        for_each_active_iommu(iommu, drhd) {
                ret = iommu_attach_domain(si_domain, iommu);
                if (ret) {
@@ -2261,6 +2231,8 @@ static int __init si_domain_init(int hw)
        }
 
        si_domain->flags = DOMAIN_FLAG_STATIC_IDENTITY;
+       pr_debug("IOMMU: identity mapping domain is domain %d\n",
+                si_domain->id);
 
        if (hw)
                return 0;
@@ -2492,11 +2464,7 @@ static int __init init_dmars(void)
                goto error;
        }
 
-       for_each_drhd_unit(drhd) {
-               if (drhd->ignored)
-                       continue;
-
-               iommu = drhd->iommu;
+       for_each_active_iommu(iommu, drhd) {
                g_iommus[iommu->seq_id] = iommu;
 
                ret = iommu_init_domains(iommu);
@@ -2520,12 +2488,7 @@ static int __init init_dmars(void)
        /*
         * Start from the sane iommu hardware state.
         */
-       for_each_drhd_unit(drhd) {
-               if (drhd->ignored)
-                       continue;
-
-               iommu = drhd->iommu;
-
+       for_each_active_iommu(iommu, drhd) {
                /*
                 * If the queued invalidation is already initialized by us
                 * (for example, while enabling interrupt-remapping) then
@@ -2545,12 +2508,7 @@ static int __init init_dmars(void)
                dmar_disable_qi(iommu);
        }
 
-       for_each_drhd_unit(drhd) {
-               if (drhd->ignored)
-                       continue;
-
-               iommu = drhd->iommu;
-
+       for_each_active_iommu(iommu, drhd) {
                if (dmar_enable_qi(iommu)) {
                        /*
                         * Queued Invalidate not enabled, use Register Based
@@ -2633,17 +2591,16 @@ static int __init init_dmars(void)
         *   global invalidate iotlb
         *   enable translation
         */
-       for_each_drhd_unit(drhd) {
+       for_each_iommu(iommu, drhd) {
                if (drhd->ignored) {
                        /*
                         * we always have to disable PMRs or DMA may fail on
                         * this device
                         */
                        if (force_on)
-                               iommu_disable_protect_mem_regions(drhd->iommu);
+                               iommu_disable_protect_mem_regions(iommu);
                        continue;
                }
-               iommu = drhd->iommu;
 
                iommu_flush_write_buffer(iommu);
 
@@ -2665,12 +2622,9 @@ static int __init init_dmars(void)
 
        return 0;
 error:
-       for_each_drhd_unit(drhd) {
-               if (drhd->ignored)
-                       continue;
-               iommu = drhd->iommu;
-               free_iommu(iommu);
-       }
+       for_each_active_iommu(iommu, drhd)
+               free_dmar_iommu(iommu);
+       kfree(deferred_flush);
        kfree(g_iommus);
        return ret;
 }
@@ -2758,7 +2712,7 @@ static int iommu_no_mapping(struct device *dev)
        struct pci_dev *pdev;
        int found;
 
-       if (unlikely(dev->bus != &pci_bus_type))
+       if (unlikely(!dev_is_pci(dev)))
                return 1;
 
        pdev = to_pci_dev(dev);
@@ -3318,9 +3272,9 @@ static void __init init_no_remapping_devices(void)
                }
        }
 
-       for_each_drhd_unit(drhd) {
+       for_each_active_drhd_unit(drhd) {
                int i;
-               if (drhd->ignored || drhd->include_all)
+               if (drhd->include_all)
                        continue;
 
                for (i = 0; i < drhd->devices_cnt; i++)
@@ -3514,18 +3468,12 @@ static int __init
 rmrr_parse_dev(struct dmar_rmrr_unit *rmrru)
 {
        struct acpi_dmar_reserved_memory *rmrr;
-       int ret;
 
        rmrr = (struct acpi_dmar_reserved_memory *) rmrru->hdr;
-       ret = dmar_parse_dev_scope((void *)(rmrr + 1),
-               ((void *)rmrr) + rmrr->header.length,
-               &rmrru->devices_cnt, &rmrru->devices, rmrr->segment);
-
-       if (ret || (rmrru->devices_cnt == 0)) {
-               list_del(&rmrru->list);
-               kfree(rmrru);
-       }
-       return ret;
+       return dmar_parse_dev_scope((void *)(rmrr + 1),
+                                   ((void *)rmrr) + rmrr->header.length,
+                                   &rmrru->devices_cnt, &rmrru->devices,
+                                   rmrr->segment);
 }
 
 static LIST_HEAD(dmar_atsr_units);
@@ -3550,23 +3498,39 @@ int __init dmar_parse_one_atsr(struct acpi_dmar_header *hdr)
 
 static int __init atsr_parse_dev(struct dmar_atsr_unit *atsru)
 {
-       int rc;
        struct acpi_dmar_atsr *atsr;
 
        if (atsru->include_all)
                return 0;
 
        atsr = container_of(atsru->hdr, struct acpi_dmar_atsr, header);
-       rc = dmar_parse_dev_scope((void *)(atsr + 1),
-                               (void *)atsr + atsr->header.length,
-                               &atsru->devices_cnt, &atsru->devices,
-                               atsr->segment);
-       if (rc || !atsru->devices_cnt) {
-               list_del(&atsru->list);
-               kfree(atsru);
+       return dmar_parse_dev_scope((void *)(atsr + 1),
+                                   (void *)atsr + atsr->header.length,
+                                   &atsru->devices_cnt, &atsru->devices,
+                                   atsr->segment);
+}
+
+static void intel_iommu_free_atsr(struct dmar_atsr_unit *atsru)
+{
+       dmar_free_dev_scope(&atsru->devices, &atsru->devices_cnt);
+       kfree(atsru);
+}
+
+static void intel_iommu_free_dmars(void)
+{
+       struct dmar_rmrr_unit *rmrru, *rmrr_n;
+       struct dmar_atsr_unit *atsru, *atsr_n;
+
+       list_for_each_entry_safe(rmrru, rmrr_n, &dmar_rmrr_units, list) {
+               list_del(&rmrru->list);
+               dmar_free_dev_scope(&rmrru->devices, &rmrru->devices_cnt);
+               kfree(rmrru);
        }
 
-       return rc;
+       list_for_each_entry_safe(atsru, atsr_n, &dmar_atsr_units, list) {
+               list_del(&atsru->list);
+               intel_iommu_free_atsr(atsru);
+       }
 }
 
 int dmar_find_matched_atsr_unit(struct pci_dev *dev)
@@ -3610,17 +3574,17 @@ found:
 
 int __init dmar_parse_rmrr_atsr_dev(void)
 {
-       struct dmar_rmrr_unit *rmrr, *rmrr_n;
-       struct dmar_atsr_unit *atsr, *atsr_n;
+       struct dmar_rmrr_unit *rmrr;
+       struct dmar_atsr_unit *atsr;
        int ret = 0;
 
-       list_for_each_entry_safe(rmrr, rmrr_n, &dmar_rmrr_units, list) {
+       list_for_each_entry(rmrr, &dmar_rmrr_units, list) {
                ret = rmrr_parse_dev(rmrr);
                if (ret)
                        return ret;
        }
 
-       list_for_each_entry_safe(atsr, atsr_n, &dmar_atsr_units, list) {
+       list_for_each_entry(atsr, &dmar_atsr_units, list) {
                ret = atsr_parse_dev(atsr);
                if (ret)
                        return ret;
@@ -3667,8 +3631,9 @@ static struct notifier_block device_nb = {
 
 int __init intel_iommu_init(void)
 {
-       int ret = 0;
+       int ret = -ENODEV;
        struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
 
        /* VT-d is required for a TXT/tboot launch, so enforce that */
        force_on = tboot_force_iommu();
@@ -3676,36 +3641,29 @@ int __init intel_iommu_init(void)
        if (dmar_table_init()) {
                if (force_on)
                        panic("tboot: Failed to initialize DMAR table\n");
-               return  -ENODEV;
+               goto out_free_dmar;
        }
 
        /*
         * Disable translation if already enabled prior to OS handover.
         */
-       for_each_drhd_unit(drhd) {
-               struct intel_iommu *iommu;
-
-               if (drhd->ignored)
-                       continue;
-
-               iommu = drhd->iommu;
+       for_each_active_iommu(iommu, drhd)
                if (iommu->gcmd & DMA_GCMD_TE)
                        iommu_disable_translation(iommu);
-       }
 
        if (dmar_dev_scope_init() < 0) {
                if (force_on)
                        panic("tboot: Failed to initialize DMAR device scope\n");
-               return  -ENODEV;
+               goto out_free_dmar;
        }
 
        if (no_iommu || dmar_disabled)
-               return -ENODEV;
+               goto out_free_dmar;
 
        if (iommu_init_mempool()) {
                if (force_on)
                        panic("tboot: Failed to initialize iommu memory\n");
-               return  -ENODEV;
+               goto out_free_dmar;
        }
 
        if (list_empty(&dmar_rmrr_units))
@@ -3717,7 +3675,7 @@ int __init intel_iommu_init(void)
        if (dmar_init_reserved_ranges()) {
                if (force_on)
                        panic("tboot: Failed to reserve iommu ranges\n");
-               return  -ENODEV;
+               goto out_free_mempool;
        }
 
        init_no_remapping_devices();
@@ -3727,9 +3685,7 @@ int __init intel_iommu_init(void)
                if (force_on)
                        panic("tboot: Failed to initialize DMARs\n");
                printk(KERN_ERR "IOMMU: dmar init failed\n");
-               put_iova_domain(&reserved_iova_list);
-               iommu_exit_mempool();
-               return ret;
+               goto out_free_reserved_range;
        }
        printk(KERN_INFO
        "PCI-DMA: Intel(R) Virtualization Technology for Directed I/O\n");
@@ -3749,6 +3705,14 @@ int __init intel_iommu_init(void)
        intel_iommu_enabled = 1;
 
        return 0;
+
+out_free_reserved_range:
+       put_iova_domain(&reserved_iova_list);
+out_free_mempool:
+       iommu_exit_mempool();
+out_free_dmar:
+       intel_iommu_free_dmars();
+       return ret;
 }
 
 static void iommu_detach_dependent_devices(struct intel_iommu *iommu,
@@ -3877,7 +3841,7 @@ static void vm_domain_remove_all_dev_info(struct dmar_domain *domain)
 }
 
 /* domain id for virtual machine, it won't be set in context */
-static unsigned long vm_domid;
+static atomic_t vm_domid = ATOMIC_INIT(0);
 
 static struct dmar_domain *iommu_alloc_vm_domain(void)
 {
@@ -3887,7 +3851,7 @@ static struct dmar_domain *iommu_alloc_vm_domain(void)
        if (!domain)
                return NULL;
 
-       domain->id = vm_domid++;
+       domain->id = atomic_inc_return(&vm_domid);
        domain->nid = -1;
        memset(domain->iommu_bmp, 0, sizeof(domain->iommu_bmp));
        domain->flags = DOMAIN_FLAG_VIRTUAL_MACHINE;
@@ -3934,11 +3898,7 @@ static void iommu_free_vm_domain(struct dmar_domain *domain)
        unsigned long i;
        unsigned long ndomains;
 
-       for_each_drhd_unit(drhd) {
-               if (drhd->ignored)
-                       continue;
-               iommu = drhd->iommu;
-
+       for_each_active_iommu(iommu, drhd) {
                ndomains = cap_ndoms(iommu->cap);
                for_each_set_bit(i, iommu->domain_ids, ndomains) {
                        if (iommu->domains[i] == domain) {
index 0cb7528b30a134416b4343b08a458f80dcb6aecf..ef5f65dbafe92d81c9d6fefa9990b76662347c50 100644 (file)
@@ -40,13 +40,15 @@ static int ir_ioapic_num, ir_hpet_num;
 
 static DEFINE_RAW_SPINLOCK(irq_2_ir_lock);
 
+static int __init parse_ioapics_under_ir(void);
+
 static struct irq_2_iommu *irq_2_iommu(unsigned int irq)
 {
        struct irq_cfg *cfg = irq_get_chip_data(irq);
        return cfg ? &cfg->irq_2_iommu : NULL;
 }
 
-int get_irte(int irq, struct irte *entry)
+static int get_irte(int irq, struct irte *entry)
 {
        struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
        unsigned long flags;
@@ -69,19 +71,13 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
        struct ir_table *table = iommu->ir_table;
        struct irq_2_iommu *irq_iommu = irq_2_iommu(irq);
        struct irq_cfg *cfg = irq_get_chip_data(irq);
-       u16 index, start_index;
        unsigned int mask = 0;
        unsigned long flags;
-       int i;
+       int index;
 
        if (!count || !irq_iommu)
                return -1;
 
-       /*
-        * start the IRTE search from index 0.
-        */
-       index = start_index = 0;
-
        if (count > 1) {
                count = __roundup_pow_of_two(count);
                mask = ilog2(count);
@@ -96,32 +92,17 @@ static int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
        }
 
        raw_spin_lock_irqsave(&irq_2_ir_lock, flags);
-       do {
-               for (i = index; i < index + count; i++)
-                       if  (table->base[i].present)
-                               break;
-               /* empty index found */
-               if (i == index + count)
-                       break;
-
-               index = (index + count) % INTR_REMAP_TABLE_ENTRIES;
-
-               if (index == start_index) {
-                       raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
-                       printk(KERN_ERR "can't allocate an IRTE\n");
-                       return -1;
-               }
-       } while (1);
-
-       for (i = index; i < index + count; i++)
-               table->base[i].present = 1;
-
-       cfg->remapped = 1;
-       irq_iommu->iommu = iommu;
-       irq_iommu->irte_index =  index;
-       irq_iommu->sub_handle = 0;
-       irq_iommu->irte_mask = mask;
-
+       index = bitmap_find_free_region(table->bitmap,
+                                       INTR_REMAP_TABLE_ENTRIES, mask);
+       if (index < 0) {
+               pr_warn("IR%d: can't allocate an IRTE\n", iommu->seq_id);
+       } else {
+               cfg->remapped = 1;
+               irq_iommu->iommu = iommu;
+               irq_iommu->irte_index =  index;
+               irq_iommu->sub_handle = 0;
+               irq_iommu->irte_mask = mask;
+       }
        raw_spin_unlock_irqrestore(&irq_2_ir_lock, flags);
 
        return index;
@@ -254,6 +235,8 @@ static int clear_entries(struct irq_2_iommu *irq_iommu)
                set_64bit(&entry->low, 0);
                set_64bit(&entry->high, 0);
        }
+       bitmap_release_region(iommu->ir_table->bitmap, index,
+                             irq_iommu->irte_mask);
 
        return qi_flush_iec(iommu, index, irq_iommu->irte_mask);
 }
@@ -336,7 +319,7 @@ static int set_ioapic_sid(struct irte *irte, int apic)
                return -1;
        }
 
-       set_irte_sid(irte, 1, 0, sid);
+       set_irte_sid(irte, SVT_VERIFY_SID_SQ, SQ_ALL_16, sid);
 
        return 0;
 }
@@ -453,6 +436,7 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu, int mode)
 {
        struct ir_table *ir_table;
        struct page *pages;
+       unsigned long *bitmap;
 
        ir_table = iommu->ir_table = kzalloc(sizeof(struct ir_table),
                                             GFP_ATOMIC);
@@ -464,13 +448,23 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu, int mode)
                                 INTR_REMAP_PAGE_ORDER);
 
        if (!pages) {
-               printk(KERN_ERR "failed to allocate pages of order %d\n",
-                      INTR_REMAP_PAGE_ORDER);
+               pr_err("IR%d: failed to allocate pages of order %d\n",
+                      iommu->seq_id, INTR_REMAP_PAGE_ORDER);
                kfree(iommu->ir_table);
                return -ENOMEM;
        }
 
+       bitmap = kcalloc(BITS_TO_LONGS(INTR_REMAP_TABLE_ENTRIES),
+                        sizeof(long), GFP_ATOMIC);
+       if (bitmap == NULL) {
+               pr_err("IR%d: failed to allocate bitmap\n", iommu->seq_id);
+               __free_pages(pages, INTR_REMAP_PAGE_ORDER);
+               kfree(ir_table);
+               return -ENOMEM;
+       }
+
        ir_table->base = page_address(pages);
+       ir_table->bitmap = bitmap;
 
        iommu_set_irq_remapping(iommu, mode);
        return 0;
@@ -521,6 +515,7 @@ static int __init dmar_x2apic_optout(void)
 static int __init intel_irq_remapping_supported(void)
 {
        struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
 
        if (disable_irq_remap)
                return 0;
@@ -539,12 +534,9 @@ static int __init intel_irq_remapping_supported(void)
        if (!dmar_ir_support())
                return 0;
 
-       for_each_drhd_unit(drhd) {
-               struct intel_iommu *iommu = drhd->iommu;
-
+       for_each_iommu(iommu, drhd)
                if (!ecap_ir_support(iommu->ecap))
                        return 0;
-       }
 
        return 1;
 }
@@ -552,6 +544,7 @@ static int __init intel_irq_remapping_supported(void)
 static int __init intel_enable_irq_remapping(void)
 {
        struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
        bool x2apic_present;
        int setup = 0;
        int eim = 0;
@@ -564,6 +557,8 @@ static int __init intel_enable_irq_remapping(void)
        }
 
        if (x2apic_present) {
+               pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
+
                eim = !dmar_x2apic_optout();
                if (!eim)
                        printk(KERN_WARNING
@@ -572,9 +567,7 @@ static int __init intel_enable_irq_remapping(void)
                                "Use 'intremap=no_x2apic_optout' to override BIOS request.\n");
        }
 
-       for_each_drhd_unit(drhd) {
-               struct intel_iommu *iommu = drhd->iommu;
-
+       for_each_iommu(iommu, drhd) {
                /*
                 * If the queued invalidation is already initialized,
                 * shouldn't disable it.
@@ -599,9 +592,7 @@ static int __init intel_enable_irq_remapping(void)
        /*
         * check for the Interrupt-remapping support
         */
-       for_each_drhd_unit(drhd) {
-               struct intel_iommu *iommu = drhd->iommu;
-
+       for_each_iommu(iommu, drhd) {
                if (!ecap_ir_support(iommu->ecap))
                        continue;
 
@@ -615,10 +606,8 @@ static int __init intel_enable_irq_remapping(void)
        /*
         * Enable queued invalidation for all the DRHD's.
         */
-       for_each_drhd_unit(drhd) {
-               int ret;
-               struct intel_iommu *iommu = drhd->iommu;
-               ret = dmar_enable_qi(iommu);
+       for_each_iommu(iommu, drhd) {
+               int ret = dmar_enable_qi(iommu);
 
                if (ret) {
                        printk(KERN_ERR "DRHD %Lx: failed to enable queued, "
@@ -631,9 +620,7 @@ static int __init intel_enable_irq_remapping(void)
        /*
         * Setup Interrupt-remapping for all the DRHD's now.
         */
-       for_each_drhd_unit(drhd) {
-               struct intel_iommu *iommu = drhd->iommu;
-
+       for_each_iommu(iommu, drhd) {
                if (!ecap_ir_support(iommu->ecap))
                        continue;
 
@@ -774,22 +761,20 @@ static int ir_parse_ioapic_hpet_scope(struct acpi_dmar_header *header,
  * Finds the assocaition between IOAPIC's and its Interrupt-remapping
  * hardware unit.
  */
-int __init parse_ioapics_under_ir(void)
+static int __init parse_ioapics_under_ir(void)
 {
        struct dmar_drhd_unit *drhd;
+       struct intel_iommu *iommu;
        int ir_supported = 0;
        int ioapic_idx;
 
-       for_each_drhd_unit(drhd) {
-               struct intel_iommu *iommu = drhd->iommu;
-
+       for_each_iommu(iommu, drhd)
                if (ecap_ir_support(iommu->ecap)) {
                        if (ir_parse_ioapic_hpet_scope(drhd->hdr, iommu))
                                return -1;
 
                        ir_supported = 1;
                }
-       }
 
        if (!ir_supported)
                return 0;
@@ -807,7 +792,7 @@ int __init parse_ioapics_under_ir(void)
        return 1;
 }
 
-int __init ir_dev_scope_init(void)
+static int __init ir_dev_scope_init(void)
 {
        if (!irq_remapping_enabled)
                return 0;
index 39f81aeefcd698f6389f0cf12799491be8e2867d..228632c99adbae9080f9abea301c1c7335121f48 100644 (file)
@@ -150,7 +150,7 @@ static int irq_remapping_setup_msi_irqs(struct pci_dev *dev,
                return do_setup_msix_irqs(dev, nvec);
 }
 
-void eoi_ioapic_pin_remapped(int apic, int pin, int vector)
+static void eoi_ioapic_pin_remapped(int apic, int pin, int vector)
 {
        /*
         * Intr-remapping uses pin number as the virtual vector
@@ -295,8 +295,8 @@ int setup_ioapic_remapped_entry(int irq,
                                             vector, attr);
 }
 
-int set_remapped_irq_affinity(struct irq_data *data, const struct cpumask *mask,
-                             bool force)
+static int set_remapped_irq_affinity(struct irq_data *data,
+                                    const struct cpumask *mask, bool force)
 {
        if (!config_enabled(CONFIG_SMP) || !remap_ops ||
            !remap_ops->set_affinity)
index ee249bc959f84bb2bc50eb652ea1b34d449db77a..e550ccb7634e91d312cd9377ff499499d37e38ed 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/export.h>
 #include <linux/limits.h>
 #include <linux/of.h>
+#include <linux/of_iommu.h>
 
 /**
  * of_get_dma_window - Parse *dma-window property and returns 0 if found.
index d572863dfccd47d767aed86cfe9a04e155c0233a..7a3b928fad1c81eadb788d45a281bacaca3f8949 100644 (file)
@@ -380,14 +380,13 @@ int ipmmu_iommu_init(struct shmobile_ipmmu *ipmmu)
                kmem_cache_destroy(l1cache);
                return -ENOMEM;
        }
-       archdata = kmalloc(sizeof(*archdata), GFP_KERNEL);
+       archdata = kzalloc(sizeof(*archdata), GFP_KERNEL);
        if (!archdata) {
                kmem_cache_destroy(l1cache);
                kmem_cache_destroy(l2cache);
                return -ENOMEM;
        }
        spin_lock_init(&archdata->attach_lock);
-       archdata->attached = NULL;
        archdata->ipmmu = ipmmu;
        ipmmu_archdata = archdata;
        bus_set_iommu(&platform_bus_type, &shmobile_iommu_ops);
index 8321f89596c493909ac36c3ce24a7b2bc245884e..e3bc2e19b6dd8f2cd7bd91b30120ecbba477abe3 100644 (file)
@@ -35,12 +35,12 @@ void ipmmu_tlb_flush(struct shmobile_ipmmu *ipmmu)
        if (!ipmmu)
                return;
 
-       mutex_lock(&ipmmu->flush_lock);
+       spin_lock(&ipmmu->flush_lock);
        if (ipmmu->tlb_enabled)
                ipmmu_reg_write(ipmmu, IMCTR1, IMCTR1_FLUSH | IMCTR1_TLBEN);
        else
                ipmmu_reg_write(ipmmu, IMCTR1, IMCTR1_FLUSH);
-       mutex_unlock(&ipmmu->flush_lock);
+       spin_unlock(&ipmmu->flush_lock);
 }
 
 void ipmmu_tlb_set(struct shmobile_ipmmu *ipmmu, unsigned long phys, int size,
@@ -49,7 +49,7 @@ void ipmmu_tlb_set(struct shmobile_ipmmu *ipmmu, unsigned long phys, int size,
        if (!ipmmu)
                return;
 
-       mutex_lock(&ipmmu->flush_lock);
+       spin_lock(&ipmmu->flush_lock);
        switch (size) {
        default:
                ipmmu->tlb_enabled = 0;
@@ -85,7 +85,7 @@ void ipmmu_tlb_set(struct shmobile_ipmmu *ipmmu, unsigned long phys, int size,
        }
        ipmmu_reg_write(ipmmu, IMTTBR, phys);
        ipmmu_reg_write(ipmmu, IMASID, asid);
-       mutex_unlock(&ipmmu->flush_lock);
+       spin_unlock(&ipmmu->flush_lock);
 }
 
 static int ipmmu_probe(struct platform_device *pdev)
@@ -104,7 +104,7 @@ static int ipmmu_probe(struct platform_device *pdev)
                dev_err(&pdev->dev, "cannot allocate device data\n");
                return -ENOMEM;
        }
-       mutex_init(&ipmmu->flush_lock);
+       spin_lock_init(&ipmmu->flush_lock);
        ipmmu->dev = &pdev->dev;
        ipmmu->ipmmu_base = devm_ioremap_nocache(&pdev->dev, res->start,
                                                resource_size(res));
index 4d53684673e1ff1649c0bc1f44a0d819975d9cc6..9524743ca1fba781a695b4a15c950a12fcd87b18 100644 (file)
@@ -14,7 +14,7 @@ struct shmobile_ipmmu {
        struct device *dev;
        void __iomem *ipmmu_base;
        int tlb_enabled;
-       struct mutex flush_lock;
+       spinlock_t flush_lock;
        const char * const *dev_names;
        unsigned int num_dev_names;
 };
index 3c972b2f989335e4df54aa8436cbd99a7f19ba09..e387f41a9cb7667f3542f510b4a954d299e1d316 100644 (file)
@@ -242,18 +242,14 @@ EXPORT_SYMBOL_GPL(led_trigger_unregister);
 void led_trigger_event(struct led_trigger *trig,
                        enum led_brightness brightness)
 {
-       struct list_head *entry;
+       struct led_classdev *led_cdev;
 
        if (!trig)
                return;
 
        read_lock(&trig->leddev_list_lock);
-       list_for_each(entry, &trig->led_cdevs) {
-               struct led_classdev *led_cdev;
-
-               led_cdev = list_entry(entry, struct led_classdev, trig_list);
+       list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list)
                led_set_brightness(led_cdev, brightness);
-       }
        read_unlock(&trig->leddev_list_lock);
 }
 EXPORT_SYMBOL_GPL(led_trigger_event);
@@ -264,16 +260,13 @@ static void led_trigger_blink_setup(struct led_trigger *trig,
                             int oneshot,
                             int invert)
 {
-       struct list_head *entry;
+       struct led_classdev *led_cdev;
 
        if (!trig)
                return;
 
        read_lock(&trig->leddev_list_lock);
-       list_for_each(entry, &trig->led_cdevs) {
-               struct led_classdev *led_cdev;
-
-               led_cdev = list_entry(entry, struct led_classdev, trig_list);
+       list_for_each_entry(led_cdev, &trig->led_cdevs, trig_list) {
                if (oneshot)
                        led_blink_set_oneshot(led_cdev, delay_on, delay_off,
                                              invert);
index a97263e902ffc6b927db6b935cb290902909f21e..2ec34cfcedcee613aebd97bae8c06966b826f404 100644 (file)
@@ -152,12 +152,26 @@ static void lp5521_load_engine(struct lp55xx_chip *chip)
        lp5521_wait_opmode_done();
 }
 
-static void lp5521_stop_engine(struct lp55xx_chip *chip)
+static void lp5521_stop_all_engines(struct lp55xx_chip *chip)
 {
        lp55xx_write(chip, LP5521_REG_OP_MODE, 0);
        lp5521_wait_opmode_done();
 }
 
+static void lp5521_stop_engine(struct lp55xx_chip *chip)
+{
+       enum lp55xx_engine_index idx = chip->engine_idx;
+       u8 mask[] = {
+               [LP55XX_ENGINE_1] = LP5521_MODE_R_M,
+               [LP55XX_ENGINE_2] = LP5521_MODE_G_M,
+               [LP55XX_ENGINE_3] = LP5521_MODE_B_M,
+       };
+
+       lp55xx_update_bits(chip, LP5521_REG_OP_MODE, mask[idx], 0);
+
+       lp5521_wait_opmode_done();
+}
+
 static void lp5521_run_engine(struct lp55xx_chip *chip, bool start)
 {
        int ret;
@@ -564,7 +578,7 @@ static int lp5521_remove(struct i2c_client *client)
        struct lp55xx_led *led = i2c_get_clientdata(client);
        struct lp55xx_chip *chip = led->chip;
 
-       lp5521_stop_engine(chip);
+       lp5521_stop_all_engines(chip);
        lp55xx_unregister_sysfs(chip);
        lp55xx_unregister_leds(led, chip);
        lp55xx_deinit_device(chip);
index 3a0bc886a87a2c88782c9b075f0eba935271ebc2..4ade66a2d9d4758b314c45ed52a222ff0cb0aeca 100644 (file)
@@ -195,12 +195,26 @@ static void lp5523_load_engine_and_select_page(struct lp55xx_chip *chip)
        lp55xx_write(chip, LP5523_REG_PROG_PAGE_SEL, page_sel[idx]);
 }
 
-static void lp5523_stop_engine(struct lp55xx_chip *chip)
+static void lp5523_stop_all_engines(struct lp55xx_chip *chip)
 {
        lp55xx_write(chip, LP5523_REG_OP_MODE, 0);
        lp5523_wait_opmode_done();
 }
 
+static void lp5523_stop_engine(struct lp55xx_chip *chip)
+{
+       enum lp55xx_engine_index idx = chip->engine_idx;
+       u8 mask[] = {
+               [LP55XX_ENGINE_1] = LP5523_MODE_ENG1_M,
+               [LP55XX_ENGINE_2] = LP5523_MODE_ENG2_M,
+               [LP55XX_ENGINE_3] = LP5523_MODE_ENG3_M,
+       };
+
+       lp55xx_update_bits(chip, LP5523_REG_OP_MODE, mask[idx], 0);
+
+       lp5523_wait_opmode_done();
+}
+
 static void lp5523_turn_off_channels(struct lp55xx_chip *chip)
 {
        int i;
@@ -311,7 +325,7 @@ static int lp5523_init_program_engine(struct lp55xx_chip *chip)
        }
 
 out:
-       lp5523_stop_engine(chip);
+       lp5523_stop_all_engines(chip);
        return ret;
 }
 
@@ -782,7 +796,7 @@ static int lp5523_remove(struct i2c_client *client)
        struct lp55xx_led *led = i2c_get_clientdata(client);
        struct lp55xx_chip *chip = led->chip;
 
-       lp5523_stop_engine(chip);
+       lp5523_stop_all_engines(chip);
        lp55xx_unregister_sysfs(chip);
        lp55xx_unregister_leds(led, chip);
        lp55xx_deinit_device(chip);
index 9acc6bb7deef01f153e5c71044ac93be7e983ba9..88317b4f7bf3abf70e4337a12aa682646e8a2e56 100644 (file)
@@ -210,6 +210,7 @@ static void lp55xx_firmware_loaded(const struct firmware *fw, void *context)
 {
        struct lp55xx_chip *chip = context;
        struct device *dev = &chip->cl->dev;
+       enum lp55xx_engine_index idx = chip->engine_idx;
 
        if (!fw) {
                dev_err(dev, "firmware request failed\n");
@@ -219,6 +220,7 @@ static void lp55xx_firmware_loaded(const struct firmware *fw, void *context)
        /* handling firmware data is chip dependent */
        mutex_lock(&chip->lock);
 
+       chip->engines[idx - 1].mode = LP55XX_ENGINE_LOAD;
        chip->fw = fw;
        if (chip->cfg->firmware_cb)
                chip->cfg->firmware_cb(chip);
index fa9b439323bd06d0d126a48a7828e4b47665c6b5..ca87a1b4a0db228896ca19dc410885eaa53eb7f3 100644 (file)
@@ -117,9 +117,7 @@ static void mc13xxx_led_work(struct work_struct *work)
                BUG();
        }
 
-       mc13xxx_lock(led->master);
        mc13xxx_reg_rmw(led->master, reg, mask << shift, value << shift);
-       mc13xxx_unlock(led->master);
 }
 
 static void mc13xxx_led_set(struct led_classdev *led_cdev,
@@ -132,75 +130,6 @@ static void mc13xxx_led_set(struct led_classdev *led_cdev,
        schedule_work(&led->work);
 }
 
-static int __init mc13xxx_led_setup(struct mc13xxx_led *led, int max_current)
-{
-       int shift, mask, reg, ret, bank;
-
-       switch (led->id) {
-       case MC13783_LED_MD:
-               reg = MC13XXX_REG_LED_CONTROL(2);
-               shift = 0;
-               mask = 0x07;
-               break;
-       case MC13783_LED_AD:
-               reg = MC13XXX_REG_LED_CONTROL(2);
-               shift = 3;
-               mask = 0x07;
-               break;
-       case MC13783_LED_KP:
-               reg = MC13XXX_REG_LED_CONTROL(2);
-               shift = 6;
-               mask = 0x07;
-               break;
-       case MC13783_LED_R1:
-       case MC13783_LED_G1:
-       case MC13783_LED_B1:
-       case MC13783_LED_R2:
-       case MC13783_LED_G2:
-       case MC13783_LED_B2:
-       case MC13783_LED_R3:
-       case MC13783_LED_G3:
-       case MC13783_LED_B3:
-               bank = (led->id - MC13783_LED_R1) / 3;
-               reg = MC13XXX_REG_LED_CONTROL(3) + bank;
-               shift = ((led->id - MC13783_LED_R1) - bank * 3) * 2;
-               mask = 0x03;
-               break;
-       case MC13892_LED_MD:
-               reg = MC13XXX_REG_LED_CONTROL(0);
-               shift = 9;
-               mask = 0x07;
-               break;
-       case MC13892_LED_AD:
-               reg = MC13XXX_REG_LED_CONTROL(0);
-               shift = 21;
-               mask = 0x07;
-               break;
-       case MC13892_LED_KP:
-               reg = MC13XXX_REG_LED_CONTROL(1);
-               shift = 9;
-               mask = 0x07;
-               break;
-       case MC13892_LED_R:
-       case MC13892_LED_G:
-       case MC13892_LED_B:
-               bank = (led->id - MC13892_LED_R) / 2;
-               reg = MC13XXX_REG_LED_CONTROL(2) + bank;
-               shift = ((led->id - MC13892_LED_R) - bank * 2) * 12 + 9;
-               mask = 0x07;
-               break;
-       default:
-               BUG();
-       }
-
-       mc13xxx_lock(led->master);
-       ret = mc13xxx_reg_rmw(led->master, reg, mask << shift,
-                             max_current << shift);
-       mc13xxx_unlock(led->master);
-
-       return ret;
-}
-
 static int __init mc13xxx_led_probe(struct platform_device *pdev)
 {
        struct mc13xxx_leds_platform_data *pdata = dev_get_platdata(&pdev->dev);
@@ -233,31 +162,22 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
        leds->num_leds = num_leds;
        platform_set_drvdata(pdev, leds);
 
-       mc13xxx_lock(mcdev);
        for (i = 0; i < devtype->num_regs; i++) {
                reg = pdata->led_control[i];
                WARN_ON(reg >= (1 << 24));
                ret = mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), reg);
                if (ret)
-                       break;
-       }
-       mc13xxx_unlock(mcdev);
-
-       if (ret) {
-               dev_err(&pdev->dev, "Unable to init LED driver\n");
-               return ret;
+                       return ret;
        }
 
        for (i = 0; i < num_leds; i++) {
                const char *name, *trig;
-               char max_current;
 
                ret = -EINVAL;
 
                id = pdata->led[i].id;
                name = pdata->led[i].name;
                trig = pdata->led[i].default_trigger;
-               max_current = pdata->led[i].max_current;
 
                if ((id > devtype->led_max) || (id < devtype->led_min)) {
                        dev_err(&pdev->dev, "Invalid ID %i\n", id);
@@ -280,11 +200,6 @@ static int __init mc13xxx_led_probe(struct platform_device *pdev)
 
                INIT_WORK(&leds->led[i].work, mc13xxx_led_work);
 
-               ret = mc13xxx_led_setup(&leds->led[i], max_current);
-               if (ret) {
-                       dev_err(&pdev->dev, "Unable to setup LED %i\n", id);
-                       break;
-               }
                ret = led_classdev_register(pdev->dev.parent,
                                            &leds->led[i].cdev);
                if (ret) {
@@ -313,10 +228,8 @@ static int mc13xxx_led_remove(struct platform_device *pdev)
                cancel_work_sync(&leds->led[i].work);
        }
 
-       mc13xxx_lock(mcdev);
        for (i = 0; i < leds->devtype->num_regs; i++)
                mc13xxx_reg_write(mcdev, MC13XXX_REG_LED_CONTROL(i), 0);
-       mc13xxx_unlock(mcdev);
 
        return 0;
 }
index b31d8e99c41992c77610fe5ca1694211035ea592..605047428b5ad75e2d67add0edaecb912d35581a 100644 (file)
@@ -66,9 +66,11 @@ static void led_pwm_set(struct led_classdev *led_cdev,
        struct led_pwm_data *led_dat =
                container_of(led_cdev, struct led_pwm_data, cdev);
        unsigned int max = led_dat->cdev.max_brightness;
-       unsigned int period =  led_dat->period;
+       unsigned long long duty =  led_dat->period;
 
-       led_dat->duty = brightness * period / max;
+       duty *= brightness;
+       do_div(duty, max);
+       led_dat->duty = duty;
 
        if (led_dat->can_sleep)
                schedule_work(&led_dat->work);
@@ -85,11 +87,10 @@ static inline size_t sizeof_pwm_leds_priv(int num_leds)
 static int led_pwm_create_of(struct platform_device *pdev,
                             struct led_pwm_priv *priv)
 {
-       struct device_node *node = pdev->dev.of_node;
        struct device_node *child;
        int ret;
 
-       for_each_child_of_node(node, child) {
+       for_each_child_of_node(pdev->dev.of_node, child) {
                struct led_pwm_data *led_dat = &priv->leds[priv->num_leds];
 
                led_dat->cdev.name = of_get_property(child, "label",
index 87cf215af798c97076df857b0609292c1f752cfe..98174e7240ee9f41b8a4d0cddae494ebff99da65 100644 (file)
 #include <linux/gpio.h>
 #include <linux/slab.h>
 #include <linux/module.h>
+#include <linux/platform_data/leds-s3c24xx.h>
 
-#include <mach/hardware.h>
 #include <mach/regs-gpio.h>
 #include <plat/gpio-cfg.h>
-#include <linux/platform_data/leds-s3c24xx.h>
 
 /* our context */
 
index 8cc304f36728a4e217cbf6716f893a3e6f5aed0c..3d9e267a56c428580bfaa074ce08053bd86ae34a 100644 (file)
@@ -4,77 +4,87 @@
  * The TCA6507 is a programmable LED controller that can drive 7
  * separate lines either by holding them low, or by pulsing them
  * with modulated width.
- * The modulation can be varied in a simple pattern to produce a blink or
- * double-blink.
+ * The modulation can be varied in a simple pattern to produce a
+ * blink or double-blink.
  *
- * This driver can configure each line either as a 'GPIO' which is out-only
- * (no pull-up) or as an LED with variable brightness and hardware-assisted
- * blinking.
+ * This driver can configure each line either as a 'GPIO' which is
+ * out-only (pull-up resistor required) or as an LED with variable
+ * brightness and hardware-assisted blinking.
  *
- * Apart from OFF and ON there are three programmable brightness levels which
- * can be programmed from 0 to 15 and indicate how many 500usec intervals in
- * each 8msec that the led is 'on'.  The levels are named MASTER, BANK0 and
- * BANK1.
+ * Apart from OFF and ON there are three programmable brightness
+ * levels which can be programmed from 0 to 15 and indicate how many
+ * 500usec intervals in each 8msec that the led is 'on'.  The levels
+ * are named MASTER, BANK0 and BANK1.
  *
- * There are two different blink rates that can be programmed, each with
- * separate time for rise, on, fall, off and second-off.  Thus if 3 or more
- * different non-trivial rates are required, software must be used for the extra
- * rates. The two different blink rates must align with the two levels BANK0 and
- * BANK1.
- * This driver does not support double-blink so 'second-off' always matches
- * 'off'.
+ * There are two different blink rates that can be programmed, each
+ * with separate time for rise, on, fall, off and second-off.  Thus if
+ * 3 or more different non-trivial rates are required, software must
+ * be used for the extra rates. The two different blink rates must
+ * align with the two levels BANK0 and BANK1.  This driver does not
+ * support double-blink so 'second-off' always matches 'off'.
  *
- * Only 16 different times can be programmed in a roughly logarithmic scale from
- * 64ms to 16320ms.  To be precise the possible times are:
+ * Only 16 different times can be programmed in a roughly logarithmic
+ * scale from 64ms to 16320ms.  To be precise the possible times are:
  *    0, 64, 128, 192, 256, 384, 512, 768,
  *    1024, 1536, 2048, 3072, 4096, 5760, 8128, 16320
  *
- * Times that cannot be closely matched with these must be
- * handled in software.  This driver allows 12.5% error in matching.
+ * Times that cannot be closely matched with these must be handled in
+ * software.  This driver allows 12.5% error in matching.
  *
- * This driver does not allow rise/fall rates to be set explicitly.  When trying
- * to match a given 'on' or 'off' period, an appropriate pair of 'change' and
- * 'hold' times are chosen to get a close match.  If the target delay is even,
- * the 'change' number will be the smaller; if odd, the 'hold' number will be
- * the smaller.
-
- * Choosing pairs of delays with 12.5% errors allows us to match delays in the
- * ranges: 56-72, 112-144, 168-216, 224-27504, 28560-36720.
- * 26% of the achievable sums can be matched by multiple pairings. For example
- * 1536 == 1536+0, 1024+512, or 768+768.  This driver will always choose the
- * pairing with the least maximum - 768+768 in this case.  Other pairings are
- * not available.
+ * This driver does not allow rise/fall rates to be set explicitly.
+ * When trying to match a given 'on' or 'off' period, an appropriate
+ * pair of 'change' and 'hold' times are chosen to get a close match.
+ * If the target delay is even, the 'change' number will be the
+ * smaller; if odd, the 'hold' number will be the smaller.
+
+ * Choosing pairs of delays with 12.5% errors allows us to match
+ * delays in the ranges: 56-72, 112-144, 168-216, 224-27504,
+ * 28560-36720.
+ * 26% of the achievable sums can be matched by multiple pairings.
+ * For example 1536 == 1536+0, 1024+512, or 768+768.
+ * This driver will always choose the pairing with the least
+ * maximum - 768+768 in this case.  Other pairings are not available.
  *
- * Access to the 3 levels and 2 blinks are on a first-come, first-served basis.
- * Access can be shared by multiple leds if they have the same level and
- * either same blink rates, or some don't blink.
- * When a led changes, it relinquishes access and tries again, so it might
- * lose access to hardware blink.
- * If a blink engine cannot be allocated, software blink is used.
- * If the desired brightness cannot be allocated, the closest available non-zero
- * brightness is used.  As 'full' is always available, the worst case would be
- * to have two different blink rates at '1', with Max at '2', then other leds
- * will have to choose between '2' and '16'.  Hopefully this is not likely.
+ * Access to the 3 levels and 2 blinks are on a first-come,
+ * first-served basis.  Access can be shared by multiple leds if they
+ * have the same level and either same blink rates, or some don't
+ * blink.  When a led changes, it relinquishes access and tries again,
+ * so it might lose access to hardware blink.
  *
- * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the brightness
- * and LEDs using the blink.  It can only be reprogrammed when the appropriate
- * counter is zero.  The MASTER level has a single usage count.
+ * If a blink engine cannot be allocated, software blink is used.  If
+ * the desired brightness cannot be allocated, the closest available
+ * non-zero brightness is used.  As 'full' is always available, the
+ * worst case would be to have two different blink rates at '1', with
+ * Max at '2', then other leds will have to choose between '2' and
+ * '16'.  Hopefully this is not likely.
  *
- * Each Led has programmable 'on' and 'off' time as milliseconds.  With each
- * there is a flag saying if it was explicitly requested or defaulted.
- * Similarly the banks know if each time was explicit or a default.  Defaults
- * are permitted to be changed freely - they are not recognised when matching.
+ * Each bank (BANK0 and BANK1) has two usage counts - LEDs using the
+ * brightness and LEDs using the blink.  It can only be reprogrammed
+ * when the appropriate counter is zero.  The MASTER level has a
+ * single usage count.
  *
+ * Each LED has programmable 'on' and 'off' time as milliseconds.
+ * With each there is a flag saying if it was explicitly requested or
+ * defaulted.  Similarly the banks know if each time was explicit or a
+ * default.  Defaults are permitted to be changed freely - they are
+ * not recognised when matching.
  *
- * An led-tca6507 device must be provided with platform data.  This data
- * lists for each output: the name, default trigger, and whether the signal
- * is being used as a GPiO rather than an led.  'struct led_plaform_data'
- * is used for this.  If 'name' is NULL, the output isn't used.  If 'flags'
- * is TCA6507_MAKE_CPIO, the output is a GPO.
- * The "struct led_platform_data" can be embedded in a
- * "struct tca6507_platform_data" which adds a 'gpio_base' for the GPiOs,
- * and a 'setup' callback which is called once the GPiOs are available.
  *
+ * An led-tca6507 device must be provided with platform data or
+ * configured via devicetree.
+ *
+ * The platform-data lists for each output: the name, default trigger,
+ * and whether the signal is being used as a GPIO rather than an LED.
+ * 'struct led_plaform_data' is used for this.  If 'name' is NULL, the
+ * output isn't used.  If 'flags' is TCA6507_MAKE_GPIO, the output is
+ * a GPO.  The "struct led_platform_data" can be embedded in a "struct
+ * tca6507_platform_data" which adds a 'gpio_base' for the GPIOs, and
+ * a 'setup' callback which is called once the GPIOs are available.
+ *
+ * When configured via devicetree there is one child for each output.
+ * The "reg" determines the output number and "compatible" determines
+ * whether it is an LED or a GPIO.  "linux,default-trigger" can set a
+ * default trigger.
  */
 
 #include <linux/module.h>
@@ -192,17 +202,18 @@ MODULE_DEVICE_TABLE(i2c, tca6507_id);
 static int choose_times(int msec, int *c1p, int *c2p)
 {
        /*
-        * Choose two timecodes which add to 'msec' as near as possible.
-        * The first returned is the 'on' or 'off' time.  The second is to be
-        * used as a 'fade-on' or 'fade-off' time.  If 'msec' is even,
-        * the first will not be smaller than the second.  If 'msec' is odd,
-        * the first will not be larger than the second.
-        * If we cannot get a sum within 1/8 of 'msec' fail with -EINVAL,
-        * otherwise return the sum that was achieved, plus 1 if the first is
-        * smaller.
-        * If two possibilities are equally good (e.g. 512+0, 256+256), choose
-        * the first pair so there is more change-time visible (i.e. it is
-        * softer).
+        * Choose two timecodes which add to 'msec' as near as
+        * possible.  The first returned is the 'on' or 'off' time.
+        * The second is to be used as a 'fade-on' or 'fade-off' time.
+        * If 'msec' is even, the first will not be smaller than the
+        * second.  If 'msec' is odd, the first will not be larger
+        * than the second.
+        * If we cannot get a sum within 1/8 of 'msec' fail with
+        * -EINVAL, otherwise return the sum that was achieved, plus 1
+        * if the first is smaller.
+        * If two possibilities are equally good (e.g. 512+0,
+        * 256+256), choose the first pair so there is more
+        * change-time visible (i.e. it is softer).
         */
        int c1, c2;
        int tmax = msec * 9 / 8;
@@ -255,8 +266,8 @@ static int choose_times(int msec, int *c1p, int *c2p)
 }
 
 /*
- * Update the register file with the appropriate 3-bit state for
- * the given led.
+ * Update the register file with the appropriate 3-bit state for the
+ * given led.
  */
 static void set_select(struct tca6507_chip *tca, int led, int val)
 {
@@ -274,9 +285,9 @@ static void set_select(struct tca6507_chip *tca, int led, int val)
        }
 }
 
-/* Update the register file with the appropriate 4-bit code for
- * one bank or other.  This can be used for timers, for levels, or
- * for initialisation.
+/* Update the register file with the appropriate 4-bit code for one
+ * bank or other.  This can be used for timers, for levels, or for
+ * initialization.
  */
 static void set_code(struct tca6507_chip *tca, int reg, int bank, int new)
 {
@@ -309,7 +320,7 @@ static void set_level(struct tca6507_chip *tca, int bank, int level)
        tca->bank[bank].level = level;
 }
 
-/* Record all relevant time code for a given bank */
+/* Record all relevant time codes for a given bank */
 static void set_times(struct tca6507_chip *tca, int bank)
 {
        int c1, c2;
@@ -317,7 +328,8 @@ static void set_times(struct tca6507_chip *tca, int bank)
 
        result = choose_times(tca->bank[bank].ontime, &c1, &c2);
        dev_dbg(&tca->client->dev,
-               "Chose on  times %d(%d) %d(%d) for %dms\n", c1, time_codes[c1],
+               "Chose on  times %d(%d) %d(%d) for %dms\n",
+               c1, time_codes[c1],
                c2, time_codes[c2], tca->bank[bank].ontime);
        set_code(tca, TCA6507_FADE_ON, bank, c2);
        set_code(tca, TCA6507_FULL_ON, bank, c1);
@@ -325,7 +337,8 @@ static void set_times(struct tca6507_chip *tca, int bank)
 
        result = choose_times(tca->bank[bank].offtime, &c1, &c2);
        dev_dbg(&tca->client->dev,
-               "Chose off times %d(%d) %d(%d) for %dms\n", c1, time_codes[c1],
+               "Chose off times %d(%d) %d(%d) for %dms\n",
+               c1, time_codes[c1],
                c2, time_codes[c2], tca->bank[bank].offtime);
        set_code(tca, TCA6507_FADE_OFF, bank, c2);
        set_code(tca, TCA6507_FIRST_OFF, bank, c1);
@@ -373,7 +386,8 @@ static void led_release(struct tca6507_led *led)
 
 static int led_prepare(struct tca6507_led *led)
 {
-       /* Assign this led to a bank, configuring that bank if necessary. */
+       /* Assign this led to a bank, configuring that bank if
+        * necessary. */
        int level = TO_LEVEL(led->led_cdev.brightness);
        struct tca6507_chip *tca = led->chip;
        int c1, c2;
@@ -389,10 +403,10 @@ static int led_prepare(struct tca6507_led *led)
 
        if (led->ontime == 0 || led->offtime == 0) {
                /*
-                * Just set the brightness, choosing first usable bank.
-                * If none perfect, choose best.
-                * Count backwards so we check MASTER bank first
-                * to avoid wasting a timer.
+                * Just set the brightness, choosing first usable
+                * bank.  If none perfect, choose best.  Count
+                * backwards so we check MASTER bank first to avoid
+                * wasting a timer.
                 */
                int best = -1;/* full-on */
                int diff = 15-level;
@@ -433,9 +447,9 @@ static int led_prepare(struct tca6507_led *led)
        }
 
        /*
-        * We have on/off time so we need to try to allocate a timing bank.
-        * First check if times are compatible with hardware and give up if
-        * not.
+        * We have on/off time so we need to try to allocate a timing
+        * bank.  First check if times are compatible with hardware
+        * and give up if not.
         */
        if (choose_times(led->ontime, &c1, &c2) < 0)
                return -EINVAL;
@@ -523,8 +537,8 @@ static int led_assign(struct tca6507_led *led)
        err = led_prepare(led);
        if (err) {
                /*
-                * Can only fail on timer setup.  In that case we need to
-                * re-establish as steady level.
+                * Can only fail on timer setup.  In that case we need
+                * to re-establish as steady level.
                 */
                led->ontime = 0;
                led->offtime = 0;
@@ -594,8 +608,8 @@ static void tca6507_gpio_set_value(struct gpio_chip *gc,
 
        spin_lock_irqsave(&tca->lock, flags);
        /*
-        * 'OFF' is floating high, and 'ON' is pulled down, so it has the
-        * inverse sense of 'val'.
+        * 'OFF' is floating high, and 'ON' is pulled down, so it has
+        * the inverse sense of 'val'.
         */
        set_select(tca, tca->gpio_map[offset],
                   val ? TCA6507_LS_LED_OFF : TCA6507_LS_LED_ON);
@@ -638,6 +652,9 @@ static int tca6507_probe_gpios(struct i2c_client *client,
        tca->gpio.direction_output = tca6507_gpio_direction_output;
        tca->gpio.set = tca6507_gpio_set_value;
        tca->gpio.dev = &client->dev;
+#ifdef CONFIG_OF_GPIO
+       tca->gpio.of_node = of_node_get(client->dev.of_node);
+#endif
        err = gpiochip_add(&tca->gpio);
        if (err) {
                tca->gpio.ngpio = 0;
@@ -682,7 +699,7 @@ tca6507_led_dt_init(struct i2c_client *client)
                return ERR_PTR(-ENODEV);
 
        tca_leds = devm_kzalloc(&client->dev,
-                       sizeof(struct led_info) * count, GFP_KERNEL);
+                       sizeof(struct led_info) * NUM_LEDS, GFP_KERNEL);
        if (!tca_leds)
                return ERR_PTR(-ENOMEM);
 
@@ -695,9 +712,11 @@ tca6507_led_dt_init(struct i2c_client *client)
                        of_get_property(child, "label", NULL) ? : child->name;
                led.default_trigger =
                        of_get_property(child, "linux,default-trigger", NULL);
-
+               led.flags = 0;
+               if (of_property_match_string(child, "compatible", "gpio") >= 0)
+                       led.flags |= TCA6507_MAKE_GPIO;
                ret = of_property_read_u32(child, "reg", &reg);
-               if (ret != 0)
+               if (ret != 0 || reg < 0 || reg >= NUM_LEDS)
                        continue;
 
                tca_leds[reg] = led;
@@ -708,8 +727,10 @@ tca6507_led_dt_init(struct i2c_client *client)
                return ERR_PTR(-ENOMEM);
 
        pdata->leds.leds = tca_leds;
-       pdata->leds.num_leds = count;
-
+       pdata->leds.num_leds = NUM_LEDS;
+#ifdef CONFIG_GPIOLIB
+       pdata->gpio_base = -1;
+#endif
        return pdata;
 }
 
index 9ef32b3df91f060b0b85d399d207faad7c072384..590214ba736c1778181f3a75cccd1aed0d2f71f9 100644 (file)
@@ -133,7 +133,7 @@ static int wf_lm75_probe(struct i2c_client *client,
        lm->inited = 0;
        lm->ds1775 = ds1775;
        lm->i2c = client;
-       lm->sens.name = (char *)name; /* XXX fix constness in structure */
+       lm->sens.name = name;
        lm->sens.ops = &wf_lm75_ops;
        i2c_set_clientdata(client, lm);
 
index 945a25b2f31ea78b82a746d6beff6407341e5db4..87e439b10318de19bcafe544350c0268d444702a 100644 (file)
@@ -95,7 +95,7 @@ static int wf_max6690_probe(struct i2c_client *client,
        }
 
        max->i2c = client;
-       max->sens.name = (char *)name; /* XXX fix constness in structure */
+       max->sens.name = name;
        max->sens.ops = &wf_max6690_ops;
        i2c_set_clientdata(client, max);
 
index 0e9c82523be678eb1604d18a33aa196b724b0ce7..c488b846f831b9605789779310c90380fa3eb039 100644 (file)
@@ -1,7 +1,8 @@
 
 obj-$(CONFIG_BCACHE)   += bcache.o
 
-bcache-y               := alloc.o btree.o bset.o io.o journal.o writeback.o\
-       movinggc.o request.o super.o sysfs.o debug.o util.o trace.o stats.o closure.o
+bcache-y               := alloc.o bset.o btree.o closure.o debug.o extents.o\
+       io.o journal.o movinggc.o request.o stats.o super.o sysfs.o trace.o\
+       util.o writeback.o
 
 CFLAGS_request.o       += -Iblock
index 4c9852d92b0a909d5b103510ae77d55f4bb05ad0..c0d37d0824439f2daff4c049ab82dc6b3c6e646e 100644 (file)
@@ -132,10 +132,16 @@ bool bch_bucket_add_unused(struct cache *ca, struct bucket *b)
 {
        BUG_ON(GC_MARK(b) || GC_SECTORS_USED(b));
 
-       if (fifo_used(&ca->free) > ca->watermark[WATERMARK_MOVINGGC] &&
-           CACHE_REPLACEMENT(&ca->sb) == CACHE_REPLACEMENT_FIFO)
-               return false;
+       if (CACHE_REPLACEMENT(&ca->sb) == CACHE_REPLACEMENT_FIFO) {
+               unsigned i;
+
+               for (i = 0; i < RESERVE_NONE; i++)
+                       if (!fifo_full(&ca->free[i]))
+                               goto add;
 
+               return false;
+       }
+add:
        b->prio = 0;
 
        if (can_inc_bucket_gen(b) &&
@@ -162,8 +168,21 @@ static void invalidate_one_bucket(struct cache *ca, struct bucket *b)
        fifo_push(&ca->free_inc, b - ca->buckets);
 }
 
-#define bucket_prio(b)                         \
-       (((unsigned) (b->prio - ca->set->min_prio)) * GC_SECTORS_USED(b))
+/*
+ * Determines what order we're going to reuse buckets, smallest bucket_prio()
+ * first: we also take into account the number of sectors of live data in that
+ * bucket, and in order for that multiply to make sense we have to scale bucket
+ *
+ * Thus, we scale the bucket priorities so that the bucket with the smallest
+ * prio is worth 1/8th of what INITIAL_PRIO is worth.
+ */
+
+#define bucket_prio(b)                                                 \
+({                                                                     \
+       unsigned min_prio = (INITIAL_PRIO - ca->set->min_prio) / 8;     \
+                                                                       \
+       (b->prio - ca->set->min_prio + min_prio) * GC_SECTORS_USED(b);  \
+})
 
 #define bucket_max_cmp(l, r)   (bucket_prio(l) < bucket_prio(r))
 #define bucket_min_cmp(l, r)   (bucket_prio(l) > bucket_prio(r))
@@ -304,6 +323,21 @@ do {                                                                       \
        __set_current_state(TASK_RUNNING);                              \
 } while (0)
 
+static int bch_allocator_push(struct cache *ca, long bucket)
+{
+       unsigned i;
+
+       /* Prios/gens are actually the most important reserve */
+       if (fifo_push(&ca->free[RESERVE_PRIO], bucket))
+               return true;
+
+       for (i = 0; i < RESERVE_NR; i++)
+               if (fifo_push(&ca->free[i], bucket))
+                       return true;
+
+       return false;
+}
+
 static int bch_allocator_thread(void *arg)
 {
        struct cache *ca = arg;
@@ -336,9 +370,7 @@ static int bch_allocator_thread(void *arg)
                                mutex_lock(&ca->set->bucket_lock);
                        }
 
-                       allocator_wait(ca, !fifo_full(&ca->free));
-
-                       fifo_push(&ca->free, bucket);
+                       allocator_wait(ca, bch_allocator_push(ca, bucket));
                        wake_up(&ca->set->bucket_wait);
                }
 
@@ -365,34 +397,29 @@ static int bch_allocator_thread(void *arg)
        }
 }
 
-long bch_bucket_alloc(struct cache *ca, unsigned watermark, bool wait)
+long bch_bucket_alloc(struct cache *ca, unsigned reserve, bool wait)
 {
        DEFINE_WAIT(w);
        struct bucket *b;
        long r;
 
        /* fastpath */
-       if (fifo_used(&ca->free) > ca->watermark[watermark]) {
-               fifo_pop(&ca->free, r);
+       if (fifo_pop(&ca->free[RESERVE_NONE], r) ||
+           fifo_pop(&ca->free[reserve], r))
                goto out;
-       }
 
        if (!wait)
                return -1;
 
-       while (1) {
-               if (fifo_used(&ca->free) > ca->watermark[watermark]) {
-                       fifo_pop(&ca->free, r);
-                       break;
-               }
-
+       do {
                prepare_to_wait(&ca->set->bucket_wait, &w,
                                TASK_UNINTERRUPTIBLE);
 
                mutex_unlock(&ca->set->bucket_lock);
                schedule();
                mutex_lock(&ca->set->bucket_lock);
-       }
+       } while (!fifo_pop(&ca->free[RESERVE_NONE], r) &&
+                !fifo_pop(&ca->free[reserve], r));
 
        finish_wait(&ca->set->bucket_wait, &w);
 out:
@@ -401,12 +428,14 @@ out:
        if (expensive_debug_checks(ca->set)) {
                size_t iter;
                long i;
+               unsigned j;
 
                for (iter = 0; iter < prio_buckets(ca) * 2; iter++)
                        BUG_ON(ca->prio_buckets[iter] == (uint64_t) r);
 
-               fifo_for_each(i, &ca->free, iter)
-                       BUG_ON(i == r);
+               for (j = 0; j < RESERVE_NR; j++)
+                       fifo_for_each(i, &ca->free[j], iter)
+                               BUG_ON(i == r);
                fifo_for_each(i, &ca->free_inc, iter)
                        BUG_ON(i == r);
                fifo_for_each(i, &ca->unused, iter)
@@ -419,7 +448,7 @@ out:
 
        SET_GC_SECTORS_USED(b, ca->sb.bucket_size);
 
-       if (watermark <= WATERMARK_METADATA) {
+       if (reserve <= RESERVE_PRIO) {
                SET_GC_MARK(b, GC_MARK_METADATA);
                SET_GC_MOVE(b, 0);
                b->prio = BTREE_PRIO;
@@ -445,7 +474,7 @@ void bch_bucket_free(struct cache_set *c, struct bkey *k)
        }
 }
 
-int __bch_bucket_alloc_set(struct cache_set *c, unsigned watermark,
+int __bch_bucket_alloc_set(struct cache_set *c, unsigned reserve,
                           struct bkey *k, int n, bool wait)
 {
        int i;
@@ -459,7 +488,7 @@ int __bch_bucket_alloc_set(struct cache_set *c, unsigned watermark,
 
        for (i = 0; i < n; i++) {
                struct cache *ca = c->cache_by_alloc[i];
-               long b = bch_bucket_alloc(ca, watermark, wait);
+               long b = bch_bucket_alloc(ca, reserve, wait);
 
                if (b == -1)
                        goto err;
@@ -478,12 +507,12 @@ err:
        return -1;
 }
 
-int bch_bucket_alloc_set(struct cache_set *c, unsigned watermark,
+int bch_bucket_alloc_set(struct cache_set *c, unsigned reserve,
                         struct bkey *k, int n, bool wait)
 {
        int ret;
        mutex_lock(&c->bucket_lock);
-       ret = __bch_bucket_alloc_set(c, watermark, k, n, wait);
+       ret = __bch_bucket_alloc_set(c, reserve, k, n, wait);
        mutex_unlock(&c->bucket_lock);
        return ret;
 }
@@ -573,8 +602,8 @@ bool bch_alloc_sectors(struct cache_set *c, struct bkey *k, unsigned sectors,
 
        while (!(b = pick_data_bucket(c, k, write_point, &alloc.key))) {
                unsigned watermark = write_prio
-                       ? WATERMARK_MOVINGGC
-                       : WATERMARK_NONE;
+                       ? RESERVE_MOVINGGC
+                       : RESERVE_NONE;
 
                spin_unlock(&c->data_bucket_lock);
 
@@ -689,7 +718,7 @@ int bch_cache_allocator_init(struct cache *ca)
         * Then 8 for btree allocations
         * Then half for the moving garbage collector
         */
-
+#if 0
        ca->watermark[WATERMARK_PRIO] = 0;
 
        ca->watermark[WATERMARK_METADATA] = prio_buckets(ca);
@@ -699,6 +728,6 @@ int bch_cache_allocator_init(struct cache *ca)
 
        ca->watermark[WATERMARK_NONE] = ca->free.size / 2 +
                ca->watermark[WATERMARK_MOVINGGC];
-
+#endif
        return 0;
 }
index 754f4317748322e7450d69da9591b6b72aff6dc4..0c707e4f4eafc32adcdb3fec5539b2dbe0998a7a 100644 (file)
 #include <linux/types.h>
 #include <linux/workqueue.h>
 
+#include "bset.h"
 #include "util.h"
 #include "closure.h"
 
@@ -280,7 +281,6 @@ struct bcache_device {
        unsigned long           sectors_dirty_last;
        long                    sectors_dirty_derivative;
 
-       mempool_t               *unaligned_bvec;
        struct bio_set          *bio_split;
 
        unsigned                data_csum:1;
@@ -310,7 +310,8 @@ struct cached_dev {
        struct cache_sb         sb;
        struct bio              sb_bio;
        struct bio_vec          sb_bv[1];
-       struct closure_with_waitlist sb_write;
+       struct closure          sb_write;
+       struct semaphore        sb_write_mutex;
 
        /* Refcount on the cache set. Always nonzero when we're caching. */
        atomic_t                count;
@@ -383,12 +384,12 @@ struct cached_dev {
        unsigned                writeback_rate_p_term_inverse;
 };
 
-enum alloc_watermarks {
-       WATERMARK_PRIO,
-       WATERMARK_METADATA,
-       WATERMARK_MOVINGGC,
-       WATERMARK_NONE,
-       WATERMARK_MAX
+enum alloc_reserve {
+       RESERVE_BTREE,
+       RESERVE_PRIO,
+       RESERVE_MOVINGGC,
+       RESERVE_NONE,
+       RESERVE_NR,
 };
 
 struct cache {
@@ -400,8 +401,6 @@ struct cache {
        struct kobject          kobj;
        struct block_device     *bdev;
 
-       unsigned                watermark[WATERMARK_MAX];
-
        struct task_struct      *alloc_thread;
 
        struct closure          prio;
@@ -430,7 +429,7 @@ struct cache {
         * because all the data they contained was overwritten), so we only
         * need to discard them before they can be moved to the free list.
         */
-       DECLARE_FIFO(long, free);
+       DECLARE_FIFO(long, free)[RESERVE_NR];
        DECLARE_FIFO(long, free_inc);
        DECLARE_FIFO(long, unused);
 
@@ -515,7 +514,8 @@ struct cache_set {
        uint64_t                cached_dev_sectors;
        struct closure          caching;
 
-       struct closure_with_waitlist sb_write;
+       struct closure          sb_write;
+       struct semaphore        sb_write_mutex;
 
        mempool_t               *search;
        mempool_t               *bio_meta;
@@ -630,13 +630,15 @@ struct cache_set {
 
 #ifdef CONFIG_BCACHE_DEBUG
        struct btree            *verify_data;
+       struct bset             *verify_ondisk;
        struct mutex            verify_lock;
 #endif
 
        unsigned                nr_uuids;
        struct uuid_entry       *uuids;
        BKEY_PADDED(uuid_bucket);
-       struct closure_with_waitlist uuid_write;
+       struct closure          uuid_write;
+       struct semaphore        uuid_write_mutex;
 
        /*
         * A btree node on disk could have too many bsets for an iterator to fit
@@ -644,13 +646,7 @@ struct cache_set {
         */
        mempool_t               *fill_iter;
 
-       /*
-        * btree_sort() is a merge sort and requires temporary space - single
-        * element mempool
-        */
-       struct mutex            sort_lock;
-       struct bset             *sort;
-       unsigned                sort_crit_factor;
+       struct bset_sort_state  sort;
 
        /* List of buckets we're currently writing data to */
        struct list_head        data_buckets;
@@ -666,7 +662,6 @@ struct cache_set {
        unsigned                congested_read_threshold_us;
        unsigned                congested_write_threshold_us;
 
-       struct time_stats       sort_time;
        struct time_stats       btree_gc_time;
        struct time_stats       btree_split_time;
        struct time_stats       btree_read_time;
@@ -684,9 +679,9 @@ struct cache_set {
        unsigned                error_decay;
 
        unsigned short          journal_delay_ms;
+       bool                    expensive_debug_checks;
        unsigned                verify:1;
        unsigned                key_merging_disabled:1;
-       unsigned                expensive_debug_checks:1;
        unsigned                gc_always_rewrite:1;
        unsigned                shrinker_disabled:1;
        unsigned                copy_gc_enabled:1;
@@ -708,13 +703,8 @@ struct bbio {
        struct bio              bio;
 };
 
-static inline unsigned local_clock_us(void)
-{
-       return local_clock() >> 10;
-}
-
 #define BTREE_PRIO             USHRT_MAX
-#define INITIAL_PRIO           32768
+#define INITIAL_PRIO           32768U
 
 #define btree_bytes(c)         ((c)->btree_pages * PAGE_SIZE)
 #define btree_blocks(b)                                                        \
@@ -727,21 +717,6 @@ static inline unsigned local_clock_us(void)
 #define bucket_bytes(c)                ((c)->sb.bucket_size << 9)
 #define block_bytes(c)         ((c)->sb.block_size << 9)
 
-#define __set_bytes(i, k)      (sizeof(*(i)) + (k) * sizeof(uint64_t))
-#define set_bytes(i)           __set_bytes(i, i->keys)
-
-#define __set_blocks(i, k, c)  DIV_ROUND_UP(__set_bytes(i, k), block_bytes(c))
-#define set_blocks(i, c)       __set_blocks(i, (i)->keys, c)
-
-#define node(i, j)             ((struct bkey *) ((i)->d + (j)))
-#define end(i)                 node(i, (i)->keys)
-
-#define index(i, b)                                                    \
-       ((size_t) (((void *) i - (void *) (b)->sets[0].data) /          \
-                  block_bytes(b->c)))
-
-#define btree_data_space(b)    (PAGE_SIZE << (b)->page_order)
-
 #define prios_per_bucket(c)                            \
        ((bucket_bytes(c) - sizeof(struct prio_set)) /  \
         sizeof(struct bucket_disk))
@@ -784,20 +759,34 @@ static inline struct bucket *PTR_BUCKET(struct cache_set *c,
        return PTR_CACHE(c, k, ptr)->buckets + PTR_BUCKET_NR(c, k, ptr);
 }
 
-/* Btree key macros */
+static inline uint8_t gen_after(uint8_t a, uint8_t b)
+{
+       uint8_t r = a - b;
+       return r > 128U ? 0 : r;
+}
 
-static inline void bkey_init(struct bkey *k)
+static inline uint8_t ptr_stale(struct cache_set *c, const struct bkey *k,
+                               unsigned i)
 {
-       *k = ZERO_KEY;
+       return gen_after(PTR_BUCKET(c, k, i)->gen, PTR_GEN(k, i));
 }
 
+static inline bool ptr_available(struct cache_set *c, const struct bkey *k,
+                                unsigned i)
+{
+       return (PTR_DEV(k, i) < MAX_CACHES_PER_SET) && PTR_CACHE(c, k, i);
+}
+
+/* Btree key macros */
+
 /*
  * This is used for various on disk data structures - cache_sb, prio_set, bset,
  * jset: The checksum is _always_ the first 8 bytes of these structs
  */
 #define csum_set(i)                                                    \
        bch_crc64(((void *) (i)) + sizeof(uint64_t),                    \
-             ((void *) end(i)) - (((void *) (i)) + sizeof(uint64_t)))
+                 ((void *) bset_bkey_last(i)) -                        \
+                 (((void *) (i)) + sizeof(uint64_t)))
 
 /* Error handling macros */
 
@@ -902,7 +891,6 @@ void bch_bbio_endio(struct cache_set *, struct bio *, int, const char *);
 void bch_bbio_free(struct bio *, struct cache_set *);
 struct bio *bch_bbio_alloc(struct cache_set *);
 
-struct bio *bch_bio_split(struct bio *, int, gfp_t, struct bio_set *);
 void bch_generic_make_request(struct bio *, struct bio_split_pool *);
 void __bch_submit_bbio(struct bio *, struct cache_set *);
 void bch_submit_bbio(struct bio *, struct cache_set *, struct bkey *, unsigned);
index 7d388b8bb50e35cf154d7c082ea492a5de08235d..4f6b5940e609b4f53c248bf65762ef8f99c7258c 100644 (file)
  * Copyright 2012 Google, Inc.
  */
 
-#include "bcache.h"
-#include "btree.h"
-#include "debug.h"
+#define pr_fmt(fmt) "bcache: %s() " fmt "\n", __func__
 
+#include "util.h"
+#include "bset.h"
+
+#include <linux/console.h>
 #include <linux/random.h>
 #include <linux/prefetch.h>
 
+#ifdef CONFIG_BCACHE_DEBUG
+
+void bch_dump_bset(struct btree_keys *b, struct bset *i, unsigned set)
+{
+       struct bkey *k, *next;
+
+       for (k = i->start; k < bset_bkey_last(i); k = next) {
+               next = bkey_next(k);
+
+               printk(KERN_ERR "block %u key %zi/%u: ", set,
+                      (uint64_t *) k - i->d, i->keys);
+
+               if (b->ops->key_dump)
+                       b->ops->key_dump(b, k);
+               else
+                       printk("%llu:%llu\n", KEY_INODE(k), KEY_OFFSET(k));
+
+               if (next < bset_bkey_last(i) &&
+                   bkey_cmp(k, b->ops->is_extents ?
+                            &START_KEY(next) : next) > 0)
+                       printk(KERN_ERR "Key skipped backwards\n");
+       }
+}
+
+void bch_dump_bucket(struct btree_keys *b)
+{
+       unsigned i;
+
+       console_lock();
+       for (i = 0; i <= b->nsets; i++)
+               bch_dump_bset(b, b->set[i].data,
+                             bset_sector_offset(b, b->set[i].data));
+       console_unlock();
+}
+
+int __bch_count_data(struct btree_keys *b)
+{
+       unsigned ret = 0;
+       struct btree_iter iter;
+       struct bkey *k;
+
+       if (b->ops->is_extents)
+               for_each_key(b, k, &iter)
+                       ret += KEY_SIZE(k);
+       return ret;
+}
+
+void __bch_check_keys(struct btree_keys *b, const char *fmt, ...)
+{
+       va_list args;
+       struct bkey *k, *p = NULL;
+       struct btree_iter iter;
+       const char *err;
+
+       for_each_key(b, k, &iter) {
+               if (b->ops->is_extents) {
+                       err = "Keys out of order";
+                       if (p && bkey_cmp(&START_KEY(p), &START_KEY(k)) > 0)
+                               goto bug;
+
+                       if (bch_ptr_invalid(b, k))
+                               continue;
+
+                       err =  "Overlapping keys";
+                       if (p && bkey_cmp(p, &START_KEY(k)) > 0)
+                               goto bug;
+               } else {
+                       if (bch_ptr_bad(b, k))
+                               continue;
+
+                       err = "Duplicate keys";
+                       if (p && !bkey_cmp(p, k))
+                               goto bug;
+               }
+               p = k;
+       }
+#if 0
+       err = "Key larger than btree node key";
+       if (p && bkey_cmp(p, &b->key) > 0)
+               goto bug;
+#endif
+       return;
+bug:
+       bch_dump_bucket(b);
+
+       va_start(args, fmt);
+       vprintk(fmt, args);
+       va_end(args);
+
+       panic("bch_check_keys error:  %s:\n", err);
+}
+
+static void bch_btree_iter_next_check(struct btree_iter *iter)
+{
+       struct bkey *k = iter->data->k, *next = bkey_next(k);
+
+       if (next < iter->data->end &&
+           bkey_cmp(k, iter->b->ops->is_extents ?
+                    &START_KEY(next) : next) > 0) {
+               bch_dump_bucket(iter->b);
+               panic("Key skipped backwards\n");
+       }
+}
+
+#else
+
+static inline void bch_btree_iter_next_check(struct btree_iter *iter) {}
+
+#endif
+
 /* Keylists */
 
-int bch_keylist_realloc(struct keylist *l, int nptrs, struct cache_set *c)
+int __bch_keylist_realloc(struct keylist *l, unsigned u64s)
 {
        size_t oldsize = bch_keylist_nkeys(l);
-       size_t newsize = oldsize + 2 + nptrs;
+       size_t newsize = oldsize + u64s;
        uint64_t *old_keys = l->keys_p == l->inline_keys ? NULL : l->keys_p;
        uint64_t *new_keys;
 
-       /* The journalling code doesn't handle the case where the keys to insert
-        * is bigger than an empty write: If we just return -ENOMEM here,
-        * bio_insert() and bio_invalidate() will insert the keys created so far
-        * and finish the rest when the keylist is empty.
-        */
-       if (newsize * sizeof(uint64_t) > block_bytes(c) - sizeof(struct jset))
-               return -ENOMEM;
-
        newsize = roundup_pow_of_two(newsize);
 
        if (newsize <= KEYLIST_INLINE ||
@@ -71,136 +175,6 @@ void bch_keylist_pop_front(struct keylist *l)
                bch_keylist_bytes(l));
 }
 
-/* Pointer validation */
-
-static bool __ptr_invalid(struct cache_set *c, const struct bkey *k)
-{
-       unsigned i;
-
-       for (i = 0; i < KEY_PTRS(k); i++)
-               if (ptr_available(c, k, i)) {
-                       struct cache *ca = PTR_CACHE(c, k, i);
-                       size_t bucket = PTR_BUCKET_NR(c, k, i);
-                       size_t r = bucket_remainder(c, PTR_OFFSET(k, i));
-
-                       if (KEY_SIZE(k) + r > c->sb.bucket_size ||
-                           bucket <  ca->sb.first_bucket ||
-                           bucket >= ca->sb.nbuckets)
-                               return true;
-               }
-
-       return false;
-}
-
-bool bch_btree_ptr_invalid(struct cache_set *c, const struct bkey *k)
-{
-       char buf[80];
-
-       if (!KEY_PTRS(k) || !KEY_SIZE(k) || KEY_DIRTY(k))
-               goto bad;
-
-       if (__ptr_invalid(c, k))
-               goto bad;
-
-       return false;
-bad:
-       bch_bkey_to_text(buf, sizeof(buf), k);
-       cache_bug(c, "spotted btree ptr %s: %s", buf, bch_ptr_status(c, k));
-       return true;
-}
-
-bool bch_extent_ptr_invalid(struct cache_set *c, const struct bkey *k)
-{
-       char buf[80];
-
-       if (!KEY_SIZE(k))
-               return true;
-
-       if (KEY_SIZE(k) > KEY_OFFSET(k))
-               goto bad;
-
-       if (__ptr_invalid(c, k))
-               goto bad;
-
-       return false;
-bad:
-       bch_bkey_to_text(buf, sizeof(buf), k);
-       cache_bug(c, "spotted extent %s: %s", buf, bch_ptr_status(c, k));
-       return true;
-}
-
-static bool ptr_bad_expensive_checks(struct btree *b, const struct bkey *k,
-                                    unsigned ptr)
-{
-       struct bucket *g = PTR_BUCKET(b->c, k, ptr);
-       char buf[80];
-
-       if (mutex_trylock(&b->c->bucket_lock)) {
-               if (b->level) {
-                       if (KEY_DIRTY(k) ||
-                           g->prio != BTREE_PRIO ||
-                           (b->c->gc_mark_valid &&
-                            GC_MARK(g) != GC_MARK_METADATA))
-                               goto err;
-
-               } else {
-                       if (g->prio == BTREE_PRIO)
-                               goto err;
-
-                       if (KEY_DIRTY(k) &&
-                           b->c->gc_mark_valid &&
-                           GC_MARK(g) != GC_MARK_DIRTY)
-                               goto err;
-               }
-               mutex_unlock(&b->c->bucket_lock);
-       }
-
-       return false;
-err:
-       mutex_unlock(&b->c->bucket_lock);
-       bch_bkey_to_text(buf, sizeof(buf), k);
-       btree_bug(b,
-"inconsistent pointer %s: bucket %zu pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
-                 buf, PTR_BUCKET_NR(b->c, k, ptr), atomic_read(&g->pin),
-                 g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
-       return true;
-}
-
-bool bch_ptr_bad(struct btree *b, const struct bkey *k)
-{
-       struct bucket *g;
-       unsigned i, stale;
-
-       if (!bkey_cmp(k, &ZERO_KEY) ||
-           !KEY_PTRS(k) ||
-           bch_ptr_invalid(b, k))
-               return true;
-
-       for (i = 0; i < KEY_PTRS(k); i++) {
-               if (!ptr_available(b->c, k, i))
-                       return true;
-
-               g = PTR_BUCKET(b->c, k, i);
-               stale = ptr_stale(b->c, k, i);
-
-               btree_bug_on(stale > 96, b,
-                            "key too stale: %i, need_gc %u",
-                            stale, b->c->need_gc);
-
-               btree_bug_on(stale && KEY_DIRTY(k) && KEY_SIZE(k),
-                            b, "stale dirty pointer");
-
-               if (stale)
-                       return true;
-
-               if (expensive_debug_checks(b->c) &&
-                   ptr_bad_expensive_checks(b, k, i))
-                       return true;
-       }
-
-       return false;
-}
-
 /* Key/pointer manipulation */
 
 void bch_bkey_copy_single_ptr(struct bkey *dest, const struct bkey *src,
@@ -255,56 +229,138 @@ bool __bch_cut_back(const struct bkey *where, struct bkey *k)
        return true;
 }
 
-static uint64_t merge_chksums(struct bkey *l, struct bkey *r)
+/* Auxiliary search trees */
+
+/* 32 bits total: */
+#define BKEY_MID_BITS          3
+#define BKEY_EXPONENT_BITS     7
+#define BKEY_MANTISSA_BITS     (32 - BKEY_MID_BITS - BKEY_EXPONENT_BITS)
+#define BKEY_MANTISSA_MASK     ((1 << BKEY_MANTISSA_BITS) - 1)
+
+struct bkey_float {
+       unsigned        exponent:BKEY_EXPONENT_BITS;
+       unsigned        m:BKEY_MID_BITS;
+       unsigned        mantissa:BKEY_MANTISSA_BITS;
+} __packed;
+
+/*
+ * BSET_CACHELINE was originally intended to match the hardware cacheline size -
+ * it used to be 64, but I realized the lookup code would touch slightly less
+ * memory if it was 128.
+ *
+ * It definites the number of bytes (in struct bset) per struct bkey_float in
+ * the auxiliar search tree - when we're done searching the bset_float tree we
+ * have this many bytes left that we do a linear search over.
+ *
+ * Since (after level 5) every level of the bset_tree is on a new cacheline,
+ * we're touching one fewer cacheline in the bset tree in exchange for one more
+ * cacheline in the linear search - but the linear search might stop before it
+ * gets to the second cacheline.
+ */
+
+#define BSET_CACHELINE         128
+
+/* Space required for the btree node keys */
+static inline size_t btree_keys_bytes(struct btree_keys *b)
 {
-       return (l->ptr[KEY_PTRS(l)] + r->ptr[KEY_PTRS(r)]) &
-               ~((uint64_t)1 << 63);
+       return PAGE_SIZE << b->page_order;
 }
 
-/* Tries to merge l and r: l should be lower than r
- * Returns true if we were able to merge. If we did merge, l will be the merged
- * key, r will be untouched.
- */
-bool bch_bkey_try_merge(struct btree *b, struct bkey *l, struct bkey *r)
+static inline size_t btree_keys_cachelines(struct btree_keys *b)
 {
-       unsigned i;
+       return btree_keys_bytes(b) / BSET_CACHELINE;
+}
 
-       if (key_merging_disabled(b->c))
-               return false;
+/* Space required for the auxiliary search trees */
+static inline size_t bset_tree_bytes(struct btree_keys *b)
+{
+       return btree_keys_cachelines(b) * sizeof(struct bkey_float);
+}
 
-       if (KEY_PTRS(l) != KEY_PTRS(r) ||
-           KEY_DIRTY(l) != KEY_DIRTY(r) ||
-           bkey_cmp(l, &START_KEY(r)))
-               return false;
+/* Space required for the prev pointers */
+static inline size_t bset_prev_bytes(struct btree_keys *b)
+{
+       return btree_keys_cachelines(b) * sizeof(uint8_t);
+}
 
-       for (i = 0; i < KEY_PTRS(l); i++)
-               if (l->ptr[i] + PTR(0, KEY_SIZE(l), 0) != r->ptr[i] ||
-                   PTR_BUCKET_NR(b->c, l, i) != PTR_BUCKET_NR(b->c, r, i))
-                       return false;
+/* Memory allocation */
 
-       /* Keys with no pointers aren't restricted to one bucket and could
-        * overflow KEY_SIZE
-        */
-       if (KEY_SIZE(l) + KEY_SIZE(r) > USHRT_MAX) {
-               SET_KEY_OFFSET(l, KEY_OFFSET(l) + USHRT_MAX - KEY_SIZE(l));
-               SET_KEY_SIZE(l, USHRT_MAX);
+void bch_btree_keys_free(struct btree_keys *b)
+{
+       struct bset_tree *t = b->set;
 
-               bch_cut_front(l, r);
-               return false;
-       }
+       if (bset_prev_bytes(b) < PAGE_SIZE)
+               kfree(t->prev);
+       else
+               free_pages((unsigned long) t->prev,
+                          get_order(bset_prev_bytes(b)));
 
-       if (KEY_CSUM(l)) {
-               if (KEY_CSUM(r))
-                       l->ptr[KEY_PTRS(l)] = merge_chksums(l, r);
-               else
-                       SET_KEY_CSUM(l, 0);
-       }
+       if (bset_tree_bytes(b) < PAGE_SIZE)
+               kfree(t->tree);
+       else
+               free_pages((unsigned long) t->tree,
+                          get_order(bset_tree_bytes(b)));
 
-       SET_KEY_OFFSET(l, KEY_OFFSET(l) + KEY_SIZE(r));
-       SET_KEY_SIZE(l, KEY_SIZE(l) + KEY_SIZE(r));
+       free_pages((unsigned long) t->data, b->page_order);
 
-       return true;
+       t->prev = NULL;
+       t->tree = NULL;
+       t->data = NULL;
+}
+EXPORT_SYMBOL(bch_btree_keys_free);
+
+int bch_btree_keys_alloc(struct btree_keys *b, unsigned page_order, gfp_t gfp)
+{
+       struct bset_tree *t = b->set;
+
+       BUG_ON(t->data);
+
+       b->page_order = page_order;
+
+       t->data = (void *) __get_free_pages(gfp, b->page_order);
+       if (!t->data)
+               goto err;
+
+       t->tree = bset_tree_bytes(b) < PAGE_SIZE
+               ? kmalloc(bset_tree_bytes(b), gfp)
+               : (void *) __get_free_pages(gfp, get_order(bset_tree_bytes(b)));
+       if (!t->tree)
+               goto err;
+
+       t->prev = bset_prev_bytes(b) < PAGE_SIZE
+               ? kmalloc(bset_prev_bytes(b), gfp)
+               : (void *) __get_free_pages(gfp, get_order(bset_prev_bytes(b)));
+       if (!t->prev)
+               goto err;
+
+       return 0;
+err:
+       bch_btree_keys_free(b);
+       return -ENOMEM;
 }
+EXPORT_SYMBOL(bch_btree_keys_alloc);
+
+void bch_btree_keys_init(struct btree_keys *b, const struct btree_keys_ops *ops,
+                        bool *expensive_debug_checks)
+{
+       unsigned i;
+
+       b->ops = ops;
+       b->expensive_debug_checks = expensive_debug_checks;
+       b->nsets = 0;
+       b->last_set_unwritten = 0;
+
+       /* XXX: shouldn't be needed */
+       for (i = 0; i < MAX_BSETS; i++)
+               b->set[i].size = 0;
+       /*
+        * Second loop starts at 1 because b->keys[0]->data is the memory we
+        * allocated
+        */
+       for (i = 1; i < MAX_BSETS; i++)
+               b->set[i].data = NULL;
+}
+EXPORT_SYMBOL(bch_btree_keys_init);
 
 /* Binary tree stuff for auxiliary search trees */
 
@@ -455,9 +511,11 @@ static unsigned bkey_to_cacheline(struct bset_tree *t, struct bkey *k)
        return ((void *) k - (void *) t->data) / BSET_CACHELINE;
 }
 
-static unsigned bkey_to_cacheline_offset(struct bkey *k)
+static unsigned bkey_to_cacheline_offset(struct bset_tree *t,
+                                        unsigned cacheline,
+                                        struct bkey *k)
 {
-       return ((size_t) k & (BSET_CACHELINE - 1)) / sizeof(uint64_t);
+       return (u64 *) k - (u64 *) cacheline_to_bkey(t, cacheline, 0);
 }
 
 static struct bkey *tree_to_bkey(struct bset_tree *t, unsigned j)
@@ -504,7 +562,7 @@ static void make_bfloat(struct bset_tree *t, unsigned j)
                : tree_to_prev_bkey(t, j >> ffs(j));
 
        struct bkey *r = is_power_of_2(j + 1)
-               ? node(t->data, t->data->keys - bkey_u64s(&t->end))
+               ? bset_bkey_idx(t->data, t->data->keys - bkey_u64s(&t->end))
                : tree_to_bkey(t, j >> (ffz(j) + 1));
 
        BUG_ON(m < l || m > r);
@@ -528,9 +586,9 @@ static void make_bfloat(struct bset_tree *t, unsigned j)
                f->exponent = 127;
 }
 
-static void bset_alloc_tree(struct btree *b, struct bset_tree *t)
+static void bset_alloc_tree(struct btree_keys *b, struct bset_tree *t)
 {
-       if (t != b->sets) {
+       if (t != b->set) {
                unsigned j = roundup(t[-1].size,
                                     64 / sizeof(struct bkey_float));
 
@@ -538,33 +596,54 @@ static void bset_alloc_tree(struct btree *b, struct bset_tree *t)
                t->prev = t[-1].prev + j;
        }
 
-       while (t < b->sets + MAX_BSETS)
+       while (t < b->set + MAX_BSETS)
                t++->size = 0;
 }
 
-static void bset_build_unwritten_tree(struct btree *b)
+static void bch_bset_build_unwritten_tree(struct btree_keys *b)
 {
-       struct bset_tree *t = b->sets + b->nsets;
+       struct bset_tree *t = bset_tree_last(b);
+
+       BUG_ON(b->last_set_unwritten);
+       b->last_set_unwritten = 1;
 
        bset_alloc_tree(b, t);
 
-       if (t->tree != b->sets->tree + bset_tree_space(b)) {
-               t->prev[0] = bkey_to_cacheline_offset(t->data->start);
+       if (t->tree != b->set->tree + btree_keys_cachelines(b)) {
+               t->prev[0] = bkey_to_cacheline_offset(t, 0, t->data->start);
                t->size = 1;
        }
 }
 
-static void bset_build_written_tree(struct btree *b)
+void bch_bset_init_next(struct btree_keys *b, struct bset *i, uint64_t magic)
+{
+       if (i != b->set->data) {
+               b->set[++b->nsets].data = i;
+               i->seq = b->set->data->seq;
+       } else
+               get_random_bytes(&i->seq, sizeof(uint64_t));
+
+       i->magic        = magic;
+       i->version      = 0;
+       i->keys         = 0;
+
+       bch_bset_build_unwritten_tree(b);
+}
+EXPORT_SYMBOL(bch_bset_init_next);
+
+void bch_bset_build_written_tree(struct btree_keys *b)
 {
-       struct bset_tree *t = b->sets + b->nsets;
-       struct bkey *k = t->data->start;
+       struct bset_tree *t = bset_tree_last(b);
+       struct bkey *prev = NULL, *k = t->data->start;
        unsigned j, cacheline = 1;
 
+       b->last_set_unwritten = 0;
+
        bset_alloc_tree(b, t);
 
        t->size = min_t(unsigned,
-                       bkey_to_cacheline(t, end(t->data)),
-                       b->sets->tree + bset_tree_space(b) - t->tree);
+                       bkey_to_cacheline(t, bset_bkey_last(t->data)),
+                       b->set->tree + btree_keys_cachelines(b) - t->tree);
 
        if (t->size < 2) {
                t->size = 0;
@@ -577,16 +656,14 @@ static void bset_build_written_tree(struct btree *b)
        for (j = inorder_next(0, t->size);
             j;
             j = inorder_next(j, t->size)) {
-               while (bkey_to_cacheline(t, k) != cacheline)
-                       k = bkey_next(k);
+               while (bkey_to_cacheline(t, k) < cacheline)
+                       prev = k, k = bkey_next(k);
 
-               t->prev[j] = bkey_u64s(k);
-               k = bkey_next(k);
-               cacheline++;
-               t->tree[j].m = bkey_to_cacheline_offset(k);
+               t->prev[j] = bkey_u64s(prev);
+               t->tree[j].m = bkey_to_cacheline_offset(t, cacheline++, k);
        }
 
-       while (bkey_next(k) != end(t->data))
+       while (bkey_next(k) != bset_bkey_last(t->data))
                k = bkey_next(k);
 
        t->end = *k;
@@ -597,14 +674,17 @@ static void bset_build_written_tree(struct btree *b)
             j = inorder_next(j, t->size))
                make_bfloat(t, j);
 }
+EXPORT_SYMBOL(bch_bset_build_written_tree);
 
-void bch_bset_fix_invalidated_key(struct btree *b, struct bkey *k)
+/* Insert */
+
+void bch_bset_fix_invalidated_key(struct btree_keys *b, struct bkey *k)
 {
        struct bset_tree *t;
        unsigned inorder, j = 1;
 
-       for (t = b->sets; t <= &b->sets[b->nsets]; t++)
-               if (k < end(t->data))
+       for (t = b->set; t <= bset_tree_last(b); t++)
+               if (k < bset_bkey_last(t->data))
                        goto found_set;
 
        BUG();
@@ -617,7 +697,7 @@ found_set:
        if (k == t->data->start)
                goto fix_left;
 
-       if (bkey_next(k) == end(t->data)) {
+       if (bkey_next(k) == bset_bkey_last(t->data)) {
                t->end = *k;
                goto fix_right;
        }
@@ -642,10 +722,12 @@ fix_right:        do {
                        j = j * 2 + 1;
                } while (j < t->size);
 }
+EXPORT_SYMBOL(bch_bset_fix_invalidated_key);
 
-void bch_bset_fix_lookup_table(struct btree *b, struct bkey *k)
+static void bch_bset_fix_lookup_table(struct btree_keys *b,
+                                     struct bset_tree *t,
+                                     struct bkey *k)
 {
-       struct bset_tree *t = &b->sets[b->nsets];
        unsigned shift = bkey_u64s(k);
        unsigned j = bkey_to_cacheline(t, k);
 
@@ -657,8 +739,8 @@ void bch_bset_fix_lookup_table(struct btree *b, struct bkey *k)
         * lookup table for the first key that is strictly greater than k:
         * it's either k's cacheline or the next one
         */
-       if (j < t->size &&
-           table_to_bkey(t, j) <= k)
+       while (j < t->size &&
+              table_to_bkey(t, j) <= k)
                j++;
 
        /* Adjust all the lookup table entries, and find a new key for any that
@@ -673,54 +755,124 @@ void bch_bset_fix_lookup_table(struct btree *b, struct bkey *k)
                        while (k < cacheline_to_bkey(t, j, 0))
                                k = bkey_next(k);
 
-                       t->prev[j] = bkey_to_cacheline_offset(k);
+                       t->prev[j] = bkey_to_cacheline_offset(t, j, k);
                }
        }
 
-       if (t->size == b->sets->tree + bset_tree_space(b) - t->tree)
+       if (t->size == b->set->tree + btree_keys_cachelines(b) - t->tree)
                return;
 
        /* Possibly add a new entry to the end of the lookup table */
 
        for (k = table_to_bkey(t, t->size - 1);
-            k != end(t->data);
+            k != bset_bkey_last(t->data);
             k = bkey_next(k))
                if (t->size == bkey_to_cacheline(t, k)) {
-                       t->prev[t->size] = bkey_to_cacheline_offset(k);
+                       t->prev[t->size] = bkey_to_cacheline_offset(t, t->size, k);
                        t->size++;
                }
 }
 
-void bch_bset_init_next(struct btree *b)
+/*
+ * Tries to merge l and r: l should be lower than r
+ * Returns true if we were able to merge. If we did merge, l will be the merged
+ * key, r will be untouched.
+ */
+bool bch_bkey_try_merge(struct btree_keys *b, struct bkey *l, struct bkey *r)
 {
-       struct bset *i = write_block(b);
+       if (!b->ops->key_merge)
+               return false;
 
-       if (i != b->sets[0].data) {
-               b->sets[++b->nsets].data = i;
-               i->seq = b->sets[0].data->seq;
-       } else
-               get_random_bytes(&i->seq, sizeof(uint64_t));
+       /*
+        * Generic header checks
+        * Assumes left and right are in order
+        * Left and right must be exactly aligned
+        */
+       if (!bch_bkey_equal_header(l, r) ||
+            bkey_cmp(l, &START_KEY(r)))
+               return false;
 
-       i->magic        = bset_magic(&b->c->sb);
-       i->version      = 0;
-       i->keys         = 0;
+       return b->ops->key_merge(b, l, r);
+}
+EXPORT_SYMBOL(bch_bkey_try_merge);
 
-       bset_build_unwritten_tree(b);
+void bch_bset_insert(struct btree_keys *b, struct bkey *where,
+                    struct bkey *insert)
+{
+       struct bset_tree *t = bset_tree_last(b);
+
+       BUG_ON(!b->last_set_unwritten);
+       BUG_ON(bset_byte_offset(b, t->data) +
+              __set_bytes(t->data, t->data->keys + bkey_u64s(insert)) >
+              PAGE_SIZE << b->page_order);
+
+       memmove((uint64_t *) where + bkey_u64s(insert),
+               where,
+               (void *) bset_bkey_last(t->data) - (void *) where);
+
+       t->data->keys += bkey_u64s(insert);
+       bkey_copy(where, insert);
+       bch_bset_fix_lookup_table(b, t, where);
 }
+EXPORT_SYMBOL(bch_bset_insert);
+
+unsigned bch_btree_insert_key(struct btree_keys *b, struct bkey *k,
+                             struct bkey *replace_key)
+{
+       unsigned status = BTREE_INSERT_STATUS_NO_INSERT;
+       struct bset *i = bset_tree_last(b)->data;
+       struct bkey *m, *prev = NULL;
+       struct btree_iter iter;
+
+       BUG_ON(b->ops->is_extents && !KEY_SIZE(k));
+
+       m = bch_btree_iter_init(b, &iter, b->ops->is_extents
+                               ? PRECEDING_KEY(&START_KEY(k))
+                               : PRECEDING_KEY(k));
+
+       if (b->ops->insert_fixup(b, k, &iter, replace_key))
+               return status;
+
+       status = BTREE_INSERT_STATUS_INSERT;
+
+       while (m != bset_bkey_last(i) &&
+              bkey_cmp(k, b->ops->is_extents ? &START_KEY(m) : m) > 0)
+               prev = m, m = bkey_next(m);
+
+       /* prev is in the tree, if we merge we're done */
+       status = BTREE_INSERT_STATUS_BACK_MERGE;
+       if (prev &&
+           bch_bkey_try_merge(b, prev, k))
+               goto merged;
+#if 0
+       status = BTREE_INSERT_STATUS_OVERWROTE;
+       if (m != bset_bkey_last(i) &&
+           KEY_PTRS(m) == KEY_PTRS(k) && !KEY_SIZE(m))
+               goto copy;
+#endif
+       status = BTREE_INSERT_STATUS_FRONT_MERGE;
+       if (m != bset_bkey_last(i) &&
+           bch_bkey_try_merge(b, k, m))
+               goto copy;
+
+       bch_bset_insert(b, m, k);
+copy:  bkey_copy(m, k);
+merged:
+       return status;
+}
+EXPORT_SYMBOL(bch_btree_insert_key);
+
+/* Lookup */
 
 struct bset_search_iter {
        struct bkey *l, *r;
 };
 
-static struct bset_search_iter bset_search_write_set(struct btree *b,
-                                                    struct bset_tree *t,
+static struct bset_search_iter bset_search_write_set(struct bset_tree *t,
                                                     const struct bkey *search)
 {
        unsigned li = 0, ri = t->size;
 
-       BUG_ON(!b->nsets &&
-              t->size < bkey_to_cacheline(t, end(t->data)));
-
        while (li + 1 != ri) {
                unsigned m = (li + ri) >> 1;
 
@@ -732,12 +884,11 @@ static struct bset_search_iter bset_search_write_set(struct btree *b,
 
        return (struct bset_search_iter) {
                table_to_bkey(t, li),
-               ri < t->size ? table_to_bkey(t, ri) : end(t->data)
+               ri < t->size ? table_to_bkey(t, ri) : bset_bkey_last(t->data)
        };
 }
 
-static struct bset_search_iter bset_search_tree(struct btree *b,
-                                               struct bset_tree *t,
+static struct bset_search_iter bset_search_tree(struct bset_tree *t,
                                                const struct bkey *search)
 {
        struct bkey *l, *r;
@@ -784,7 +935,7 @@ static struct bset_search_iter bset_search_tree(struct btree *b,
                        f = &t->tree[inorder_next(j, t->size)];
                        r = cacheline_to_bkey(t, inorder, f->m);
                } else
-                       r = end(t->data);
+                       r = bset_bkey_last(t->data);
        } else {
                r = cacheline_to_bkey(t, inorder, f->m);
 
@@ -798,7 +949,7 @@ static struct bset_search_iter bset_search_tree(struct btree *b,
        return (struct bset_search_iter) {l, r};
 }
 
-struct bkey *__bch_bset_search(struct btree *b, struct bset_tree *t,
+struct bkey *__bch_bset_search(struct btree_keys *b, struct bset_tree *t,
                               const struct bkey *search)
 {
        struct bset_search_iter i;
@@ -820,7 +971,7 @@ struct bkey *__bch_bset_search(struct btree *b, struct bset_tree *t,
 
        if (unlikely(!t->size)) {
                i.l = t->data->start;
-               i.r = end(t->data);
+               i.r = bset_bkey_last(t->data);
        } else if (bset_written(b, t)) {
                /*
                 * Each node in the auxiliary search tree covers a certain range
@@ -830,23 +981,27 @@ struct bkey *__bch_bset_search(struct btree *b, struct bset_tree *t,
                 */
 
                if (unlikely(bkey_cmp(search, &t->end) >= 0))
-                       return end(t->data);
+                       return bset_bkey_last(t->data);
 
                if (unlikely(bkey_cmp(search, t->data->start) < 0))
                        return t->data->start;
 
-               i = bset_search_tree(b, t, search);
-       } else
-               i = bset_search_write_set(b, t, search);
+               i = bset_search_tree(t, search);
+       } else {
+               BUG_ON(!b->nsets &&
+                      t->size < bkey_to_cacheline(t, bset_bkey_last(t->data)));
 
-       if (expensive_debug_checks(b->c)) {
+               i = bset_search_write_set(t, search);
+       }
+
+       if (btree_keys_expensive_checks(b)) {
                BUG_ON(bset_written(b, t) &&
                       i.l != t->data->start &&
                       bkey_cmp(tree_to_prev_bkey(t,
                          inorder_to_tree(bkey_to_cacheline(t, i.l), t)),
                                search) > 0);
 
-               BUG_ON(i.r != end(t->data) &&
+               BUG_ON(i.r != bset_bkey_last(t->data) &&
                       bkey_cmp(i.r, search) <= 0);
        }
 
@@ -856,22 +1011,17 @@ struct bkey *__bch_bset_search(struct btree *b, struct bset_tree *t,
 
        return i.l;
 }
+EXPORT_SYMBOL(__bch_bset_search);
 
 /* Btree iterator */
 
-/*
- * Returns true if l > r - unless l == r, in which case returns true if l is
- * older than r.
- *
- * Necessary for btree_sort_fixup() - if there are multiple keys that compare
- * equal in different sets, we have to process them newest to oldest.
- */
+typedef bool (btree_iter_cmp_fn)(struct btree_iter_set,
+                                struct btree_iter_set);
+
 static inline bool btree_iter_cmp(struct btree_iter_set l,
                                  struct btree_iter_set r)
 {
-       int64_t c = bkey_cmp(&START_KEY(l.k), &START_KEY(r.k));
-
-       return c ? c > 0 : l.k < r.k;
+       return bkey_cmp(l.k, r.k) > 0;
 }
 
 static inline bool btree_iter_end(struct btree_iter *iter)
@@ -888,8 +1038,10 @@ void bch_btree_iter_push(struct btree_iter *iter, struct bkey *k,
                                 btree_iter_cmp));
 }
 
-struct bkey *__bch_btree_iter_init(struct btree *b, struct btree_iter *iter,
-                                  struct bkey *search, struct bset_tree *start)
+static struct bkey *__bch_btree_iter_init(struct btree_keys *b,
+                                         struct btree_iter *iter,
+                                         struct bkey *search,
+                                         struct bset_tree *start)
 {
        struct bkey *ret = NULL;
        iter->size = ARRAY_SIZE(iter->data);
@@ -899,15 +1051,24 @@ struct bkey *__bch_btree_iter_init(struct btree *b, struct btree_iter *iter,
        iter->b = b;
 #endif
 
-       for (; start <= &b->sets[b->nsets]; start++) {
+       for (; start <= bset_tree_last(b); start++) {
                ret = bch_bset_search(b, start, search);
-               bch_btree_iter_push(iter, ret, end(start->data));
+               bch_btree_iter_push(iter, ret, bset_bkey_last(start->data));
        }
 
        return ret;
 }
 
-struct bkey *bch_btree_iter_next(struct btree_iter *iter)
+struct bkey *bch_btree_iter_init(struct btree_keys *b,
+                                struct btree_iter *iter,
+                                struct bkey *search)
+{
+       return __bch_btree_iter_init(b, iter, search, b->set);
+}
+EXPORT_SYMBOL(bch_btree_iter_init);
+
+static inline struct bkey *__bch_btree_iter_next(struct btree_iter *iter,
+                                                btree_iter_cmp_fn *cmp)
 {
        struct btree_iter_set unused;
        struct bkey *ret = NULL;
@@ -924,16 +1085,23 @@ struct bkey *bch_btree_iter_next(struct btree_iter *iter)
                }
 
                if (iter->data->k == iter->data->end)
-                       heap_pop(iter, unused, btree_iter_cmp);
+                       heap_pop(iter, unused, cmp);
                else
-                       heap_sift(iter, 0, btree_iter_cmp);
+                       heap_sift(iter, 0, cmp);
        }
 
        return ret;
 }
 
+struct bkey *bch_btree_iter_next(struct btree_iter *iter)
+{
+       return __bch_btree_iter_next(iter, btree_iter_cmp);
+
+}
+EXPORT_SYMBOL(bch_btree_iter_next);
+
 struct bkey *bch_btree_iter_next_filter(struct btree_iter *iter,
-                                       struct btree *b, ptr_filter_fn fn)
+                                       struct btree_keys *b, ptr_filter_fn fn)
 {
        struct bkey *ret;
 
@@ -946,70 +1114,58 @@ struct bkey *bch_btree_iter_next_filter(struct btree_iter *iter,
 
 /* Mergesort */
 
-static void sort_key_next(struct btree_iter *iter,
-                         struct btree_iter_set *i)
+void bch_bset_sort_state_free(struct bset_sort_state *state)
 {
-       i->k = bkey_next(i->k);
-
-       if (i->k == i->end)
-               *i = iter->data[--iter->used];
+       if (state->pool)
+               mempool_destroy(state->pool);
 }
 
-static void btree_sort_fixup(struct btree_iter *iter)
+int bch_bset_sort_state_init(struct bset_sort_state *state, unsigned page_order)
 {
-       while (iter->used > 1) {
-               struct btree_iter_set *top = iter->data, *i = top + 1;
+       spin_lock_init(&state->time.lock);
 
-               if (iter->used > 2 &&
-                   btree_iter_cmp(i[0], i[1]))
-                       i++;
+       state->page_order = page_order;
+       state->crit_factor = int_sqrt(1 << page_order);
 
-               if (bkey_cmp(top->k, &START_KEY(i->k)) <= 0)
-                       break;
-
-               if (!KEY_SIZE(i->k)) {
-                       sort_key_next(iter, i);
-                       heap_sift(iter, i - top, btree_iter_cmp);
-                       continue;
-               }
-
-               if (top->k > i->k) {
-                       if (bkey_cmp(top->k, i->k) >= 0)
-                               sort_key_next(iter, i);
-                       else
-                               bch_cut_front(top->k, i->k);
+       state->pool = mempool_create_page_pool(1, page_order);
+       if (!state->pool)
+               return -ENOMEM;
 
-                       heap_sift(iter, i - top, btree_iter_cmp);
-               } else {
-                       /* can't happen because of comparison func */
-                       BUG_ON(!bkey_cmp(&START_KEY(top->k), &START_KEY(i->k)));
-                       bch_cut_back(&START_KEY(i->k), top->k);
-               }
-       }
+       return 0;
 }
+EXPORT_SYMBOL(bch_bset_sort_state_init);
 
-static void btree_mergesort(struct btree *b, struct bset *out,
+static void btree_mergesort(struct btree_keys *b, struct bset *out,
                            struct btree_iter *iter,
                            bool fixup, bool remove_stale)
 {
+       int i;
        struct bkey *k, *last = NULL;
-       bool (*bad)(struct btree *, const struct bkey *) = remove_stale
+       BKEY_PADDED(k) tmp;
+       bool (*bad)(struct btree_keys *, const struct bkey *) = remove_stale
                ? bch_ptr_bad
                : bch_ptr_invalid;
 
+       /* Heapify the iterator, using our comparison function */
+       for (i = iter->used / 2 - 1; i >= 0; --i)
+               heap_sift(iter, i, b->ops->sort_cmp);
+
        while (!btree_iter_end(iter)) {
-               if (fixup && !b->level)
-                       btree_sort_fixup(iter);
+               if (b->ops->sort_fixup && fixup)
+                       k = b->ops->sort_fixup(iter, &tmp.k);
+               else
+                       k = NULL;
+
+               if (!k)
+                       k = __bch_btree_iter_next(iter, b->ops->sort_cmp);
 
-               k = bch_btree_iter_next(iter);
                if (bad(b, k))
                        continue;
 
                if (!last) {
                        last = out->start;
                        bkey_copy(last, k);
-               } else if (b->level ||
-                          !bch_bkey_try_merge(b, last, k)) {
+               } else if (!bch_bkey_try_merge(b, last, k)) {
                        last = bkey_next(last);
                        bkey_copy(last, k);
                }
@@ -1020,27 +1176,27 @@ static void btree_mergesort(struct btree *b, struct bset *out,
        pr_debug("sorted %i keys", out->keys);
 }
 
-static void __btree_sort(struct btree *b, struct btree_iter *iter,
-                        unsigned start, unsigned order, bool fixup)
+static void __btree_sort(struct btree_keys *b, struct btree_iter *iter,
+                        unsigned start, unsigned order, bool fixup,
+                        struct bset_sort_state *state)
 {
        uint64_t start_time;
-       bool remove_stale = !b->written;
+       bool used_mempool = false;
        struct bset *out = (void *) __get_free_pages(__GFP_NOWARN|GFP_NOIO,
                                                     order);
        if (!out) {
-               mutex_lock(&b->c->sort_lock);
-               out = b->c->sort;
-               order = ilog2(bucket_pages(b->c));
+               BUG_ON(order > state->page_order);
+
+               out = page_address(mempool_alloc(state->pool, GFP_NOIO));
+               used_mempool = true;
+               order = state->page_order;
        }
 
        start_time = local_clock();
 
-       btree_mergesort(b, out, iter, fixup, remove_stale);
+       btree_mergesort(b, out, iter, fixup, false);
        b->nsets = start;
 
-       if (!fixup && !start && b->written)
-               bch_btree_verify(b, out);
-
        if (!start && order == b->page_order) {
                /*
                 * Our temporary buffer is the same size as the btree node's
@@ -1048,84 +1204,76 @@ static void __btree_sort(struct btree *b, struct btree_iter *iter,
                 * memcpy()
                 */
 
-               out->magic      = bset_magic(&b->c->sb);
-               out->seq        = b->sets[0].data->seq;
-               out->version    = b->sets[0].data->version;
-               swap(out, b->sets[0].data);
-
-               if (b->c->sort == b->sets[0].data)
-                       b->c->sort = out;
+               out->magic      = b->set->data->magic;
+               out->seq        = b->set->data->seq;
+               out->version    = b->set->data->version;
+               swap(out, b->set->data);
        } else {
-               b->sets[start].data->keys = out->keys;
-               memcpy(b->sets[start].data->start, out->start,
-                      (void *) end(out) - (void *) out->start);
+               b->set[start].data->keys = out->keys;
+               memcpy(b->set[start].data->start, out->start,
+                      (void *) bset_bkey_last(out) - (void *) out->start);
        }
 
-       if (out == b->c->sort)
-               mutex_unlock(&b->c->sort_lock);
+       if (used_mempool)
+               mempool_free(virt_to_page(out), state->pool);
        else
                free_pages((unsigned long) out, order);
 
-       if (b->written)
-               bset_build_written_tree(b);
+       bch_bset_build_written_tree(b);
 
        if (!start)
-               bch_time_stats_update(&b->c->sort_time, start_time);
+               bch_time_stats_update(&state->time, start_time);
 }
 
-void bch_btree_sort_partial(struct btree *b, unsigned start)
+void bch_btree_sort_partial(struct btree_keys *b, unsigned start,
+                           struct bset_sort_state *state)
 {
        size_t order = b->page_order, keys = 0;
        struct btree_iter iter;
        int oldsize = bch_count_data(b);
 
-       __bch_btree_iter_init(b, &iter, NULL, &b->sets[start]);
-
-       BUG_ON(b->sets[b->nsets].data == write_block(b) &&
-              (b->sets[b->nsets].size || b->nsets));
-
+       __bch_btree_iter_init(b, &iter, NULL, &b->set[start]);
 
        if (start) {
                unsigned i;
 
                for (i = start; i <= b->nsets; i++)
-                       keys += b->sets[i].data->keys;
+                       keys += b->set[i].data->keys;
 
-               order = roundup_pow_of_two(__set_bytes(b->sets->data,
-                                                      keys)) / PAGE_SIZE;
-               if (order)
-                       order = ilog2(order);
+               order = get_order(__set_bytes(b->set->data, keys));
        }
 
-       __btree_sort(b, &iter, start, order, false);
+       __btree_sort(b, &iter, start, order, false, state);
 
-       EBUG_ON(b->written && oldsize >= 0 && bch_count_data(b) != oldsize);
+       EBUG_ON(oldsize >= 0 && bch_count_data(b) != oldsize);
 }
+EXPORT_SYMBOL(bch_btree_sort_partial);
 
-void bch_btree_sort_and_fix_extents(struct btree *b, struct btree_iter *iter)
+void bch_btree_sort_and_fix_extents(struct btree_keys *b,
+                                   struct btree_iter *iter,
+                                   struct bset_sort_state *state)
 {
-       BUG_ON(!b->written);
-       __btree_sort(b, iter, 0, b->page_order, true);
+       __btree_sort(b, iter, 0, b->page_order, true, state);
 }
 
-void bch_btree_sort_into(struct btree *b, struct btree *new)
+void bch_btree_sort_into(struct btree_keys *b, struct btree_keys *new,
+                        struct bset_sort_state *state)
 {
        uint64_t start_time = local_clock();
 
        struct btree_iter iter;
        bch_btree_iter_init(b, &iter, NULL);
 
-       btree_mergesort(b, new->sets->data, &iter, false, true);
+       btree_mergesort(b, new->set->data, &iter, false, true);
 
-       bch_time_stats_update(&b->c->sort_time, start_time);
+       bch_time_stats_update(&state->time, start_time);
 
-       bkey_copy_key(&new->key, &b->key);
-       new->sets->size = 0;
+       new->set->size = 0; // XXX: why?
 }
 
 #define SORT_CRIT      (4096 / sizeof(uint64_t))
 
-void bch_btree_sort_lazy(struct btree *b)
+void bch_btree_sort_lazy(struct btree_keys *b, struct bset_sort_state *state)
 {
        unsigned crit = SORT_CRIT;
        int i;
@@ -1134,50 +1282,32 @@ void bch_btree_sort_lazy(struct btree *b)
        if (!b->nsets)
                goto out;
 
-       /* If not a leaf node, always sort */
-       if (b->level) {
-               bch_btree_sort(b);
-               return;
-       }
-
        for (i = b->nsets - 1; i >= 0; --i) {
-               crit *= b->c->sort_crit_factor;
+               crit *= state->crit_factor;
 
-               if (b->sets[i].data->keys < crit) {
-                       bch_btree_sort_partial(b, i);
+               if (b->set[i].data->keys < crit) {
+                       bch_btree_sort_partial(b, i, state);
                        return;
                }
        }
 
        /* Sort if we'd overflow */
        if (b->nsets + 1 == MAX_BSETS) {
-               bch_btree_sort(b);
+               bch_btree_sort(b, state);
                return;
        }
 
 out:
-       bset_build_written_tree(b);
+       bch_bset_build_written_tree(b);
 }
+EXPORT_SYMBOL(bch_btree_sort_lazy);
 
-/* Sysfs stuff */
-
-struct bset_stats {
-       struct btree_op op;
-       size_t nodes;
-       size_t sets_written, sets_unwritten;
-       size_t bytes_written, bytes_unwritten;
-       size_t floats, failed;
-};
-
-static int btree_bset_stats(struct btree_op *op, struct btree *b)
+void bch_btree_keys_stats(struct btree_keys *b, struct bset_stats *stats)
 {
-       struct bset_stats *stats = container_of(op, struct bset_stats, op);
        unsigned i;
 
-       stats->nodes++;
-
        for (i = 0; i <= b->nsets; i++) {
-               struct bset_tree *t = &b->sets[i];
+               struct bset_tree *t = &b->set[i];
                size_t bytes = t->data->keys * sizeof(uint64_t);
                size_t j;
 
@@ -1195,32 +1325,4 @@ static int btree_bset_stats(struct btree_op *op, struct btree *b)
                        stats->bytes_unwritten += bytes;
                }
        }
-
-       return MAP_CONTINUE;
-}
-
-int bch_bset_print_stats(struct cache_set *c, char *buf)
-{
-       struct bset_stats t;
-       int ret;
-
-       memset(&t, 0, sizeof(struct bset_stats));
-       bch_btree_op_init(&t.op, -1);
-
-       ret = bch_btree_map_nodes(&t.op, c, &ZERO_KEY, btree_bset_stats);
-       if (ret < 0)
-               return ret;
-
-       return snprintf(buf, PAGE_SIZE,
-                       "btree nodes:           %zu\n"
-                       "written sets:          %zu\n"
-                       "unwritten sets:                %zu\n"
-                       "written key bytes:     %zu\n"
-                       "unwritten key bytes:   %zu\n"
-                       "floats:                        %zu\n"
-                       "failed:                        %zu\n",
-                       t.nodes,
-                       t.sets_written, t.sets_unwritten,
-                       t.bytes_written, t.bytes_unwritten,
-                       t.floats, t.failed);
 }
index 1d3c24f9fa0e95fbb20c03fcb825559b0736de1b..003260f4ddf6e725417956531e64c9cb33022ae4 100644 (file)
@@ -1,7 +1,11 @@
 #ifndef _BCACHE_BSET_H
 #define _BCACHE_BSET_H
 
-#include <linux/slab.h>
+#include <linux/bcache.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include "util.h" /* for time_stats */
 
 /*
  * BKEYS:
  * first key in that range of bytes again.
  */
 
-/* Btree key comparison/iteration */
+struct btree_keys;
+struct btree_iter;
+struct btree_iter_set;
+struct bkey_float;
 
 #define MAX_BSETS              4U
 
-struct btree_iter {
-       size_t size, used;
-#ifdef CONFIG_BCACHE_DEBUG
-       struct btree *b;
-#endif
-       struct btree_iter_set {
-               struct bkey *k, *end;
-       } data[MAX_BSETS];
-};
-
 struct bset_tree {
        /*
         * We construct a binary tree in an array as if the array
@@ -165,14 +162,14 @@ struct bset_tree {
         */
 
        /* size of the binary tree and prev array */
-       unsigned        size;
+       unsigned                size;
 
        /* function of size - precalculated for to_inorder() */
-       unsigned        extra;
+       unsigned                extra;
 
        /* copy of the last key in the set */
-       struct bkey     end;
-       struct bkey_float *tree;
+       struct bkey             end;
+       struct bkey_float       *tree;
 
        /*
         * The nodes in the bset tree point to specific keys - this
@@ -182,12 +179,219 @@ struct bset_tree {
         * to keep bkey_float to 4 bytes and prev isn't used in the fast
         * path.
         */
-       uint8_t         *prev;
+       uint8_t                 *prev;
 
        /* The actual btree node, with pointers to each sorted set */
-       struct bset     *data;
+       struct bset             *data;
+};
+
+struct btree_keys_ops {
+       bool            (*sort_cmp)(struct btree_iter_set,
+                                   struct btree_iter_set);
+       struct bkey     *(*sort_fixup)(struct btree_iter *, struct bkey *);
+       bool            (*insert_fixup)(struct btree_keys *, struct bkey *,
+                                       struct btree_iter *, struct bkey *);
+       bool            (*key_invalid)(struct btree_keys *,
+                                      const struct bkey *);
+       bool            (*key_bad)(struct btree_keys *, const struct bkey *);
+       bool            (*key_merge)(struct btree_keys *,
+                                    struct bkey *, struct bkey *);
+       void            (*key_to_text)(char *, size_t, const struct bkey *);
+       void            (*key_dump)(struct btree_keys *, const struct bkey *);
+
+       /*
+        * Only used for deciding whether to use START_KEY(k) or just the key
+        * itself in a couple places
+        */
+       bool            is_extents;
+};
+
+struct btree_keys {
+       const struct btree_keys_ops     *ops;
+       uint8_t                 page_order;
+       uint8_t                 nsets;
+       unsigned                last_set_unwritten:1;
+       bool                    *expensive_debug_checks;
+
+       /*
+        * Sets of sorted keys - the real btree node - plus a binary search tree
+        *
+        * set[0] is special; set[0]->tree, set[0]->prev and set[0]->data point
+        * to the memory we have allocated for this btree node. Additionally,
+        * set[0]->data points to the entire btree node as it exists on disk.
+        */
+       struct bset_tree        set[MAX_BSETS];
+};
+
+static inline struct bset_tree *bset_tree_last(struct btree_keys *b)
+{
+       return b->set + b->nsets;
+}
+
+static inline bool bset_written(struct btree_keys *b, struct bset_tree *t)
+{
+       return t <= b->set + b->nsets - b->last_set_unwritten;
+}
+
+static inline bool bkey_written(struct btree_keys *b, struct bkey *k)
+{
+       return !b->last_set_unwritten || k < b->set[b->nsets].data->start;
+}
+
+static inline unsigned bset_byte_offset(struct btree_keys *b, struct bset *i)
+{
+       return ((size_t) i) - ((size_t) b->set->data);
+}
+
+static inline unsigned bset_sector_offset(struct btree_keys *b, struct bset *i)
+{
+       return bset_byte_offset(b, i) >> 9;
+}
+
+#define __set_bytes(i, k)      (sizeof(*(i)) + (k) * sizeof(uint64_t))
+#define set_bytes(i)           __set_bytes(i, i->keys)
+
+#define __set_blocks(i, k, block_bytes)                                \
+       DIV_ROUND_UP(__set_bytes(i, k), block_bytes)
+#define set_blocks(i, block_bytes)                             \
+       __set_blocks(i, (i)->keys, block_bytes)
+
+static inline size_t bch_btree_keys_u64s_remaining(struct btree_keys *b)
+{
+       struct bset_tree *t = bset_tree_last(b);
+
+       BUG_ON((PAGE_SIZE << b->page_order) <
+              (bset_byte_offset(b, t->data) + set_bytes(t->data)));
+
+       if (!b->last_set_unwritten)
+               return 0;
+
+       return ((PAGE_SIZE << b->page_order) -
+               (bset_byte_offset(b, t->data) + set_bytes(t->data))) /
+               sizeof(u64);
+}
+
+static inline struct bset *bset_next_set(struct btree_keys *b,
+                                        unsigned block_bytes)
+{
+       struct bset *i = bset_tree_last(b)->data;
+
+       return ((void *) i) + roundup(set_bytes(i), block_bytes);
+}
+
+void bch_btree_keys_free(struct btree_keys *);
+int bch_btree_keys_alloc(struct btree_keys *, unsigned, gfp_t);
+void bch_btree_keys_init(struct btree_keys *, const struct btree_keys_ops *,
+                        bool *);
+
+void bch_bset_init_next(struct btree_keys *, struct bset *, uint64_t);
+void bch_bset_build_written_tree(struct btree_keys *);
+void bch_bset_fix_invalidated_key(struct btree_keys *, struct bkey *);
+bool bch_bkey_try_merge(struct btree_keys *, struct bkey *, struct bkey *);
+void bch_bset_insert(struct btree_keys *, struct bkey *, struct bkey *);
+unsigned bch_btree_insert_key(struct btree_keys *, struct bkey *,
+                             struct bkey *);
+
+enum {
+       BTREE_INSERT_STATUS_NO_INSERT = 0,
+       BTREE_INSERT_STATUS_INSERT,
+       BTREE_INSERT_STATUS_BACK_MERGE,
+       BTREE_INSERT_STATUS_OVERWROTE,
+       BTREE_INSERT_STATUS_FRONT_MERGE,
 };
 
+/* Btree key iteration */
+
+struct btree_iter {
+       size_t size, used;
+#ifdef CONFIG_BCACHE_DEBUG
+       struct btree_keys *b;
+#endif
+       struct btree_iter_set {
+               struct bkey *k, *end;
+       } data[MAX_BSETS];
+};
+
+typedef bool (*ptr_filter_fn)(struct btree_keys *, const struct bkey *);
+
+struct bkey *bch_btree_iter_next(struct btree_iter *);
+struct bkey *bch_btree_iter_next_filter(struct btree_iter *,
+                                       struct btree_keys *, ptr_filter_fn);
+
+void bch_btree_iter_push(struct btree_iter *, struct bkey *, struct bkey *);
+struct bkey *bch_btree_iter_init(struct btree_keys *, struct btree_iter *,
+                                struct bkey *);
+
+struct bkey *__bch_bset_search(struct btree_keys *, struct bset_tree *,
+                              const struct bkey *);
+
+/*
+ * Returns the first key that is strictly greater than search
+ */
+static inline struct bkey *bch_bset_search(struct btree_keys *b,
+                                          struct bset_tree *t,
+                                          const struct bkey *search)
+{
+       return search ? __bch_bset_search(b, t, search) : t->data->start;
+}
+
+#define for_each_key_filter(b, k, iter, filter)                                \
+       for (bch_btree_iter_init((b), (iter), NULL);                    \
+            ((k) = bch_btree_iter_next_filter((iter), (b), filter));)
+
+#define for_each_key(b, k, iter)                                       \
+       for (bch_btree_iter_init((b), (iter), NULL);                    \
+            ((k) = bch_btree_iter_next(iter));)
+
+/* Sorting */
+
+struct bset_sort_state {
+       mempool_t               *pool;
+
+       unsigned                page_order;
+       unsigned                crit_factor;
+
+       struct time_stats       time;
+};
+
+void bch_bset_sort_state_free(struct bset_sort_state *);
+int bch_bset_sort_state_init(struct bset_sort_state *, unsigned);
+void bch_btree_sort_lazy(struct btree_keys *, struct bset_sort_state *);
+void bch_btree_sort_into(struct btree_keys *, struct btree_keys *,
+                        struct bset_sort_state *);
+void bch_btree_sort_and_fix_extents(struct btree_keys *, struct btree_iter *,
+                                   struct bset_sort_state *);
+void bch_btree_sort_partial(struct btree_keys *, unsigned,
+                           struct bset_sort_state *);
+
+static inline void bch_btree_sort(struct btree_keys *b,
+                                 struct bset_sort_state *state)
+{
+       bch_btree_sort_partial(b, 0, state);
+}
+
+struct bset_stats {
+       size_t sets_written, sets_unwritten;
+       size_t bytes_written, bytes_unwritten;
+       size_t floats, failed;
+};
+
+void bch_btree_keys_stats(struct btree_keys *, struct bset_stats *);
+
+/* Bkey utility code */
+
+#define bset_bkey_last(i)      bkey_idx((struct bkey *) (i)->d, (i)->keys)
+
+static inline struct bkey *bset_bkey_idx(struct bset *i, unsigned idx)
+{
+       return bkey_idx(i->start, idx);
+}
+
+static inline void bkey_init(struct bkey *k)
+{
+       *k = ZERO_KEY;
+}
+
 static __always_inline int64_t bkey_cmp(const struct bkey *l,
                                        const struct bkey *r)
 {
@@ -196,6 +400,62 @@ static __always_inline int64_t bkey_cmp(const struct bkey *l,
                : (int64_t) KEY_OFFSET(l) - (int64_t) KEY_OFFSET(r);
 }
 
+void bch_bkey_copy_single_ptr(struct bkey *, const struct bkey *,
+                             unsigned);
+bool __bch_cut_front(const struct bkey *, struct bkey *);
+bool __bch_cut_back(const struct bkey *, struct bkey *);
+
+static inline bool bch_cut_front(const struct bkey *where, struct bkey *k)
+{
+       BUG_ON(bkey_cmp(where, k) > 0);
+       return __bch_cut_front(where, k);
+}
+
+static inline bool bch_cut_back(const struct bkey *where, struct bkey *k)
+{
+       BUG_ON(bkey_cmp(where, &START_KEY(k)) < 0);
+       return __bch_cut_back(where, k);
+}
+
+#define PRECEDING_KEY(_k)                                      \
+({                                                             \
+       struct bkey *_ret = NULL;                               \
+                                                               \
+       if (KEY_INODE(_k) || KEY_OFFSET(_k)) {                  \
+               _ret = &KEY(KEY_INODE(_k), KEY_OFFSET(_k), 0);  \
+                                                               \
+               if (!_ret->low)                                 \
+                       _ret->high--;                           \
+               _ret->low--;                                    \
+       }                                                       \
+                                                               \
+       _ret;                                                   \
+})
+
+static inline bool bch_ptr_invalid(struct btree_keys *b, const struct bkey *k)
+{
+       return b->ops->key_invalid(b, k);
+}
+
+static inline bool bch_ptr_bad(struct btree_keys *b, const struct bkey *k)
+{
+       return b->ops->key_bad(b, k);
+}
+
+static inline void bch_bkey_to_text(struct btree_keys *b, char *buf,
+                                   size_t size, const struct bkey *k)
+{
+       return b->ops->key_to_text(buf, size, k);
+}
+
+static inline bool bch_bkey_equal_header(const struct bkey *l,
+                                        const struct bkey *r)
+{
+       return (KEY_DIRTY(l) == KEY_DIRTY(r) &&
+               KEY_PTRS(l) == KEY_PTRS(r) &&
+               KEY_CSUM(l) == KEY_CSUM(l));
+}
+
 /* Keylists */
 
 struct keylist {
@@ -257,136 +517,44 @@ static inline size_t bch_keylist_bytes(struct keylist *l)
 
 struct bkey *bch_keylist_pop(struct keylist *);
 void bch_keylist_pop_front(struct keylist *);
-int bch_keylist_realloc(struct keylist *, int, struct cache_set *);
-
-void bch_bkey_copy_single_ptr(struct bkey *, const struct bkey *,
-                             unsigned);
-bool __bch_cut_front(const struct bkey *, struct bkey *);
-bool __bch_cut_back(const struct bkey *, struct bkey *);
+int __bch_keylist_realloc(struct keylist *, unsigned);
 
-static inline bool bch_cut_front(const struct bkey *where, struct bkey *k)
-{
-       BUG_ON(bkey_cmp(where, k) > 0);
-       return __bch_cut_front(where, k);
-}
+/* Debug stuff */
 
-static inline bool bch_cut_back(const struct bkey *where, struct bkey *k)
-{
-       BUG_ON(bkey_cmp(where, &START_KEY(k)) < 0);
-       return __bch_cut_back(where, k);
-}
-
-const char *bch_ptr_status(struct cache_set *, const struct bkey *);
-bool bch_btree_ptr_invalid(struct cache_set *, const struct bkey *);
-bool bch_extent_ptr_invalid(struct cache_set *, const struct bkey *);
-
-bool bch_ptr_bad(struct btree *, const struct bkey *);
-
-static inline uint8_t gen_after(uint8_t a, uint8_t b)
-{
-       uint8_t r = a - b;
-       return r > 128U ? 0 : r;
-}
-
-static inline uint8_t ptr_stale(struct cache_set *c, const struct bkey *k,
-                               unsigned i)
-{
-       return gen_after(PTR_BUCKET(c, k, i)->gen, PTR_GEN(k, i));
-}
-
-static inline bool ptr_available(struct cache_set *c, const struct bkey *k,
-                                unsigned i)
-{
-       return (PTR_DEV(k, i) < MAX_CACHES_PER_SET) && PTR_CACHE(c, k, i);
-}
-
-
-typedef bool (*ptr_filter_fn)(struct btree *, const struct bkey *);
-
-struct bkey *bch_btree_iter_next(struct btree_iter *);
-struct bkey *bch_btree_iter_next_filter(struct btree_iter *,
-                                       struct btree *, ptr_filter_fn);
-
-void bch_btree_iter_push(struct btree_iter *, struct bkey *, struct bkey *);
-struct bkey *__bch_btree_iter_init(struct btree *, struct btree_iter *,
-                                  struct bkey *, struct bset_tree *);
-
-/* 32 bits total: */
-#define BKEY_MID_BITS          3
-#define BKEY_EXPONENT_BITS     7
-#define BKEY_MANTISSA_BITS     22
-#define BKEY_MANTISSA_MASK     ((1 << BKEY_MANTISSA_BITS) - 1)
-
-struct bkey_float {
-       unsigned        exponent:BKEY_EXPONENT_BITS;
-       unsigned        m:BKEY_MID_BITS;
-       unsigned        mantissa:BKEY_MANTISSA_BITS;
-} __packed;
-
-/*
- * BSET_CACHELINE was originally intended to match the hardware cacheline size -
- * it used to be 64, but I realized the lookup code would touch slightly less
- * memory if it was 128.
- *
- * It definites the number of bytes (in struct bset) per struct bkey_float in
- * the auxiliar search tree - when we're done searching the bset_float tree we
- * have this many bytes left that we do a linear search over.
- *
- * Since (after level 5) every level of the bset_tree is on a new cacheline,
- * we're touching one fewer cacheline in the bset tree in exchange for one more
- * cacheline in the linear search - but the linear search might stop before it
- * gets to the second cacheline.
- */
-
-#define BSET_CACHELINE         128
-#define bset_tree_space(b)     (btree_data_space(b) / BSET_CACHELINE)
+#ifdef CONFIG_BCACHE_DEBUG
 
-#define bset_tree_bytes(b)     (bset_tree_space(b) * sizeof(struct bkey_float))
-#define bset_prev_bytes(b)     (bset_tree_space(b) * sizeof(uint8_t))
+int __bch_count_data(struct btree_keys *);
+void __bch_check_keys(struct btree_keys *, const char *, ...);
+void bch_dump_bset(struct btree_keys *, struct bset *, unsigned);
+void bch_dump_bucket(struct btree_keys *);
 
-void bch_bset_init_next(struct btree *);
+#else
 
-void bch_bset_fix_invalidated_key(struct btree *, struct bkey *);
-void bch_bset_fix_lookup_table(struct btree *, struct bkey *);
+static inline int __bch_count_data(struct btree_keys *b) { return -1; }
+static inline void __bch_check_keys(struct btree_keys *b, const char *fmt, ...) {}
+static inline void bch_dump_bucket(struct btree_keys *b) {}
+void bch_dump_bset(struct btree_keys *, struct bset *, unsigned);
 
-struct bkey *__bch_bset_search(struct btree *, struct bset_tree *,
-                          const struct bkey *);
+#endif
 
-/*
- * Returns the first key that is strictly greater than search
- */
-static inline struct bkey *bch_bset_search(struct btree *b, struct bset_tree *t,
-                                          const struct bkey *search)
+static inline bool btree_keys_expensive_checks(struct btree_keys *b)
 {
-       return search ? __bch_bset_search(b, t, search) : t->data->start;
+#ifdef CONFIG_BCACHE_DEBUG
+       return *b->expensive_debug_checks;
+#else
+       return false;
+#endif
 }
 
-#define PRECEDING_KEY(_k)                                      \
-({                                                             \
-       struct bkey *_ret = NULL;                               \
-                                                               \
-       if (KEY_INODE(_k) || KEY_OFFSET(_k)) {                  \
-               _ret = &KEY(KEY_INODE(_k), KEY_OFFSET(_k), 0);  \
-                                                               \
-               if (!_ret->low)                                 \
-                       _ret->high--;                           \
-               _ret->low--;                                    \
-       }                                                       \
-                                                               \
-       _ret;                                                   \
-})
-
-bool bch_bkey_try_merge(struct btree *, struct bkey *, struct bkey *);
-void bch_btree_sort_lazy(struct btree *);
-void bch_btree_sort_into(struct btree *, struct btree *);
-void bch_btree_sort_and_fix_extents(struct btree *, struct btree_iter *);
-void bch_btree_sort_partial(struct btree *, unsigned);
-
-static inline void bch_btree_sort(struct btree *b)
+static inline int bch_count_data(struct btree_keys *b)
 {
-       bch_btree_sort_partial(b, 0);
+       return btree_keys_expensive_checks(b) ? __bch_count_data(b) : -1;
 }
 
-int bch_bset_print_stats(struct cache_set *, char *);
+#define bch_check_keys(b, ...)                                         \
+do {                                                                   \
+       if (btree_keys_expensive_checks(b))                             \
+               __bch_check_keys(b, __VA_ARGS__);                       \
+} while (0)
 
 #endif
index 31bb53fcc67a40806cf73659a596f98297d36128..98cc0a810a366a466253d250baba5c2564e9fab7 100644 (file)
@@ -23,7 +23,7 @@
 #include "bcache.h"
 #include "btree.h"
 #include "debug.h"
-#include "writeback.h"
+#include "extents.h"
 
 #include <linux/slab.h>
 #include <linux/bitops.h>
  * Test module load/unload
  */
 
-enum {
-       BTREE_INSERT_STATUS_INSERT,
-       BTREE_INSERT_STATUS_BACK_MERGE,
-       BTREE_INSERT_STATUS_OVERWROTE,
-       BTREE_INSERT_STATUS_FRONT_MERGE,
-};
-
 #define MAX_NEED_GC            64
 #define MAX_SAVE_PRIO          72
 
@@ -106,14 +99,6 @@ enum {
 
 static struct workqueue_struct *btree_io_wq;
 
-static inline bool should_split(struct btree *b)
-{
-       struct bset *i = write_block(b);
-       return b->written >= btree_blocks(b) ||
-               (b->written + __set_blocks(i, i->keys + 15, b->c)
-                > btree_blocks(b));
-}
-
 #define insert_lock(s, b)      ((b)->level <= (s)->lock)
 
 /*
@@ -167,6 +152,8 @@ static inline bool should_split(struct btree *b)
                        _r = bch_btree_ ## fn(_b, op, ##__VA_ARGS__);   \
                }                                                       \
                rw_unlock(_w, _b);                                      \
+               if (_r == -EINTR)                                       \
+                       schedule();                                     \
                bch_cannibalize_unlock(c);                              \
                if (_r == -ENOSPC) {                                    \
                        wait_event((c)->try_wait,                       \
@@ -175,9 +162,15 @@ static inline bool should_split(struct btree *b)
                }                                                       \
        } while (_r == -EINTR);                                         \
                                                                        \
+       finish_wait(&(c)->bucket_wait, &(op)->wait);                    \
        _r;                                                             \
 })
 
+static inline struct bset *write_block(struct btree *b)
+{
+       return ((void *) btree_bset_first(b)) + b->written * block_bytes(b->c);
+}
+
 /* Btree key manipulation */
 
 void bkey_put(struct cache_set *c, struct bkey *k)
@@ -194,16 +187,16 @@ void bkey_put(struct cache_set *c, struct bkey *k)
 static uint64_t btree_csum_set(struct btree *b, struct bset *i)
 {
        uint64_t crc = b->key.ptr[0];
-       void *data = (void *) i + 8, *end = end(i);
+       void *data = (void *) i + 8, *end = bset_bkey_last(i);
 
        crc = bch_crc64_update(crc, data, end - data);
        return crc ^ 0xffffffffffffffffULL;
 }
 
-static void bch_btree_node_read_done(struct btree *b)
+void bch_btree_node_read_done(struct btree *b)
 {
        const char *err = "bad btree header";
-       struct bset *i = b->sets[0].data;
+       struct bset *i = btree_bset_first(b);
        struct btree_iter *iter;
 
        iter = mempool_alloc(b->c->fill_iter, GFP_NOWAIT);
@@ -211,21 +204,22 @@ static void bch_btree_node_read_done(struct btree *b)
        iter->used = 0;
 
 #ifdef CONFIG_BCACHE_DEBUG
-       iter->b = b;
+       iter->b = &b->keys;
 #endif
 
        if (!i->seq)
                goto err;
 
        for (;
-            b->written < btree_blocks(b) && i->seq == b->sets[0].data->seq;
+            b->written < btree_blocks(b) && i->seq == b->keys.set[0].data->seq;
             i = write_block(b)) {
                err = "unsupported bset version";
                if (i->version > BCACHE_BSET_VERSION)
                        goto err;
 
                err = "bad btree header";
-               if (b->written + set_blocks(i, b->c) > btree_blocks(b))
+               if (b->written + set_blocks(i, block_bytes(b->c)) >
+                   btree_blocks(b))
                        goto err;
 
                err = "bad magic";
@@ -245,39 +239,40 @@ static void bch_btree_node_read_done(struct btree *b)
                }
 
                err = "empty set";
-               if (i != b->sets[0].data && !i->keys)
+               if (i != b->keys.set[0].data && !i->keys)
                        goto err;
 
-               bch_btree_iter_push(iter, i->start, end(i));
+               bch_btree_iter_push(iter, i->start, bset_bkey_last(i));
 
-               b->written += set_blocks(i, b->c);
+               b->written += set_blocks(i, block_bytes(b->c));
        }
 
        err = "corrupted btree";
        for (i = write_block(b);
-            index(i, b) < btree_blocks(b);
+            bset_sector_offset(&b->keys, i) < KEY_SIZE(&b->key);
             i = ((void *) i) + block_bytes(b->c))
-               if (i->seq == b->sets[0].data->seq)
+               if (i->seq == b->keys.set[0].data->seq)
                        goto err;
 
-       bch_btree_sort_and_fix_extents(b, iter);
+       bch_btree_sort_and_fix_extents(&b->keys, iter, &b->c->sort);
 
-       i = b->sets[0].data;
+       i = b->keys.set[0].data;
        err = "short btree key";
-       if (b->sets[0].size &&
-           bkey_cmp(&b->key, &b->sets[0].end) < 0)
+       if (b->keys.set[0].size &&
+           bkey_cmp(&b->key, &b->keys.set[0].end) < 0)
                goto err;
 
        if (b->written < btree_blocks(b))
-               bch_bset_init_next(b);
+               bch_bset_init_next(&b->keys, write_block(b),
+                                  bset_magic(&b->c->sb));
 out:
        mempool_free(iter, b->c->fill_iter);
        return;
 err:
        set_btree_node_io_error(b);
-       bch_cache_set_error(b->c, "%s at bucket %zu, block %zu, %u keys",
+       bch_cache_set_error(b->c, "%s at bucket %zu, block %u, %u keys",
                            err, PTR_BUCKET_NR(b->c, &b->key, 0),
-                           index(i, b), i->keys);
+                           bset_block_offset(b, i), i->keys);
        goto out;
 }
 
@@ -287,7 +282,7 @@ static void btree_node_read_endio(struct bio *bio, int error)
        closure_put(cl);
 }
 
-void bch_btree_node_read(struct btree *b)
+static void bch_btree_node_read(struct btree *b)
 {
        uint64_t start_time = local_clock();
        struct closure cl;
@@ -299,11 +294,11 @@ void bch_btree_node_read(struct btree *b)
 
        bio = bch_bbio_alloc(b->c);
        bio->bi_rw      = REQ_META|READ_SYNC;
-       bio->bi_size    = KEY_SIZE(&b->key) << 9;
+       bio->bi_iter.bi_size = KEY_SIZE(&b->key) << 9;
        bio->bi_end_io  = btree_node_read_endio;
        bio->bi_private = &cl;
 
-       bch_bio_map(bio, b->sets[0].data);
+       bch_bio_map(bio, b->keys.set[0].data);
 
        bch_submit_bbio(bio, b->c, &b->key, 0);
        closure_sync(&cl);
@@ -340,9 +335,16 @@ static void btree_complete_write(struct btree *b, struct btree_write *w)
        w->journal      = NULL;
 }
 
+static void btree_node_write_unlock(struct closure *cl)
+{
+       struct btree *b = container_of(cl, struct btree, io);
+
+       up(&b->io_mutex);
+}
+
 static void __btree_node_write_done(struct closure *cl)
 {
-       struct btree *b = container_of(cl, struct btree, io.cl);
+       struct btree *b = container_of(cl, struct btree, io);
        struct btree_write *w = btree_prev_write(b);
 
        bch_bbio_free(b->bio, b->c);
@@ -353,16 +355,16 @@ static void __btree_node_write_done(struct closure *cl)
                queue_delayed_work(btree_io_wq, &b->work,
                                   msecs_to_jiffies(30000));
 
-       closure_return(cl);
+       closure_return_with_destructor(cl, btree_node_write_unlock);
 }
 
 static void btree_node_write_done(struct closure *cl)
 {
-       struct btree *b = container_of(cl, struct btree, io.cl);
+       struct btree *b = container_of(cl, struct btree, io);
        struct bio_vec *bv;
        int n;
 
-       __bio_for_each_segment(bv, b->bio, n, 0)
+       bio_for_each_segment_all(bv, b->bio, n)
                __free_page(bv->bv_page);
 
        __btree_node_write_done(cl);
@@ -371,7 +373,7 @@ static void btree_node_write_done(struct closure *cl)
 static void btree_node_write_endio(struct bio *bio, int error)
 {
        struct closure *cl = bio->bi_private;
-       struct btree *b = container_of(cl, struct btree, io.cl);
+       struct btree *b = container_of(cl, struct btree, io);
 
        if (error)
                set_btree_node_io_error(b);
@@ -382,8 +384,8 @@ static void btree_node_write_endio(struct bio *bio, int error)
 
 static void do_btree_node_write(struct btree *b)
 {
-       struct closure *cl = &b->io.cl;
-       struct bset *i = b->sets[b->nsets].data;
+       struct closure *cl = &b->io;
+       struct bset *i = btree_bset_last(b);
        BKEY_PADDED(key) k;
 
        i->version      = BCACHE_BSET_VERSION;
@@ -395,7 +397,7 @@ static void do_btree_node_write(struct btree *b)
        b->bio->bi_end_io       = btree_node_write_endio;
        b->bio->bi_private      = cl;
        b->bio->bi_rw           = REQ_META|WRITE_SYNC|REQ_FUA;
-       b->bio->bi_size         = set_blocks(i, b->c) * block_bytes(b->c);
+       b->bio->bi_iter.bi_size = roundup(set_bytes(i), block_bytes(b->c));
        bch_bio_map(b->bio, i);
 
        /*
@@ -414,14 +416,15 @@ static void do_btree_node_write(struct btree *b)
         */
 
        bkey_copy(&k.key, &b->key);
-       SET_PTR_OFFSET(&k.key, 0, PTR_OFFSET(&k.key, 0) + bset_offset(b, i));
+       SET_PTR_OFFSET(&k.key, 0, PTR_OFFSET(&k.key, 0) +
+                      bset_sector_offset(&b->keys, i));
 
        if (!bio_alloc_pages(b->bio, GFP_NOIO)) {
                int j;
                struct bio_vec *bv;
                void *base = (void *) ((unsigned long) i & ~(PAGE_SIZE - 1));
 
-               bio_for_each_segment(bv, b->bio, j)
+               bio_for_each_segment_all(bv, b->bio, j)
                        memcpy(page_address(bv->bv_page),
                               base + j * PAGE_SIZE, PAGE_SIZE);
 
@@ -435,40 +438,54 @@ static void do_btree_node_write(struct btree *b)
                bch_submit_bbio(b->bio, b->c, &k.key, 0);
 
                closure_sync(cl);
-               __btree_node_write_done(cl);
+               continue_at_nobarrier(cl, __btree_node_write_done, NULL);
        }
 }
 
 void bch_btree_node_write(struct btree *b, struct closure *parent)
 {
-       struct bset *i = b->sets[b->nsets].data;
+       struct bset *i = btree_bset_last(b);
 
        trace_bcache_btree_write(b);
 
        BUG_ON(current->bio_list);
        BUG_ON(b->written >= btree_blocks(b));
        BUG_ON(b->written && !i->keys);
-       BUG_ON(b->sets->data->seq != i->seq);
-       bch_check_keys(b, "writing");
+       BUG_ON(btree_bset_first(b)->seq != i->seq);
+       bch_check_keys(&b->keys, "writing");
 
        cancel_delayed_work(&b->work);
 
        /* If caller isn't waiting for write, parent refcount is cache set */
-       closure_lock(&b->io, parent ?: &b->c->cl);
+       down(&b->io_mutex);
+       closure_init(&b->io, parent ?: &b->c->cl);
 
        clear_bit(BTREE_NODE_dirty,      &b->flags);
        change_bit(BTREE_NODE_write_idx, &b->flags);
 
        do_btree_node_write(b);
 
-       b->written += set_blocks(i, b->c);
-       atomic_long_add(set_blocks(i, b->c) * b->c->sb.block_size,
+       atomic_long_add(set_blocks(i, block_bytes(b->c)) * b->c->sb.block_size,
                        &PTR_CACHE(b->c, &b->key, 0)->btree_sectors_written);
 
-       bch_btree_sort_lazy(b);
+       b->written += set_blocks(i, block_bytes(b->c));
+
+       /* If not a leaf node, always sort */
+       if (b->level && b->keys.nsets)
+               bch_btree_sort(&b->keys, &b->c->sort);
+       else
+               bch_btree_sort_lazy(&b->keys, &b->c->sort);
+
+       /*
+        * do verify if there was more than one set initially (i.e. we did a
+        * sort) and we sorted down to a single set:
+        */
+       if (i != b->keys.set->data && !b->keys.nsets)
+               bch_btree_verify(b);
 
        if (b->written < btree_blocks(b))
-               bch_bset_init_next(b);
+               bch_bset_init_next(&b->keys, write_block(b),
+                                  bset_magic(&b->c->sb));
 }
 
 static void bch_btree_node_write_sync(struct btree *b)
@@ -493,7 +510,7 @@ static void btree_node_write_work(struct work_struct *w)
 
 static void bch_btree_leaf_dirty(struct btree *b, atomic_t *journal_ref)
 {
-       struct bset *i = b->sets[b->nsets].data;
+       struct bset *i = btree_bset_last(b);
        struct btree_write *w = btree_current_write(b);
 
        BUG_ON(!b->written);
@@ -528,24 +545,6 @@ static void bch_btree_leaf_dirty(struct btree *b, atomic_t *journal_ref)
  * mca -> memory cache
  */
 
-static void mca_reinit(struct btree *b)
-{
-       unsigned i;
-
-       b->flags        = 0;
-       b->written      = 0;
-       b->nsets        = 0;
-
-       for (i = 0; i < MAX_BSETS; i++)
-               b->sets[i].size = 0;
-       /*
-        * Second loop starts at 1 because b->sets[0]->data is the memory we
-        * allocated
-        */
-       for (i = 1; i < MAX_BSETS; i++)
-               b->sets[i].data = NULL;
-}
-
 #define mca_reserve(c) (((c->root && c->root->level)           \
                          ? c->root->level : 1) * 8 + 16)
 #define mca_can_free(c)                                                \
@@ -553,28 +552,12 @@ static void mca_reinit(struct btree *b)
 
 static void mca_data_free(struct btree *b)
 {
-       struct bset_tree *t = b->sets;
-       BUG_ON(!closure_is_unlocked(&b->io.cl));
+       BUG_ON(b->io_mutex.count != 1);
 
-       if (bset_prev_bytes(b) < PAGE_SIZE)
-               kfree(t->prev);
-       else
-               free_pages((unsigned long) t->prev,
-                          get_order(bset_prev_bytes(b)));
+       bch_btree_keys_free(&b->keys);
 
-       if (bset_tree_bytes(b) < PAGE_SIZE)
-               kfree(t->tree);
-       else
-               free_pages((unsigned long) t->tree,
-                          get_order(bset_tree_bytes(b)));
-
-       free_pages((unsigned long) t->data, b->page_order);
-
-       t->prev = NULL;
-       t->tree = NULL;
-       t->data = NULL;
-       list_move(&b->list, &b->c->btree_cache_freed);
        b->c->bucket_cache_used--;
+       list_move(&b->list, &b->c->btree_cache_freed);
 }
 
 static void mca_bucket_free(struct btree *b)
@@ -593,34 +576,16 @@ static unsigned btree_order(struct bkey *k)
 
 static void mca_data_alloc(struct btree *b, struct bkey *k, gfp_t gfp)
 {
-       struct bset_tree *t = b->sets;
-       BUG_ON(t->data);
-
-       b->page_order = max_t(unsigned,
-                             ilog2(b->c->btree_pages),
-                             btree_order(k));
-
-       t->data = (void *) __get_free_pages(gfp, b->page_order);
-       if (!t->data)
-               goto err;
-
-       t->tree = bset_tree_bytes(b) < PAGE_SIZE
-               ? kmalloc(bset_tree_bytes(b), gfp)
-               : (void *) __get_free_pages(gfp, get_order(bset_tree_bytes(b)));
-       if (!t->tree)
-               goto err;
-
-       t->prev = bset_prev_bytes(b) < PAGE_SIZE
-               ? kmalloc(bset_prev_bytes(b), gfp)
-               : (void *) __get_free_pages(gfp, get_order(bset_prev_bytes(b)));
-       if (!t->prev)
-               goto err;
-
-       list_move(&b->list, &b->c->btree_cache);
-       b->c->bucket_cache_used++;
-       return;
-err:
-       mca_data_free(b);
+       if (!bch_btree_keys_alloc(&b->keys,
+                                 max_t(unsigned,
+                                       ilog2(b->c->btree_pages),
+                                       btree_order(k)),
+                                 gfp)) {
+               b->c->bucket_cache_used++;
+               list_move(&b->list, &b->c->btree_cache);
+       } else {
+               list_move(&b->list, &b->c->btree_cache_freed);
+       }
 }
 
 static struct btree *mca_bucket_alloc(struct cache_set *c,
@@ -635,7 +600,7 @@ static struct btree *mca_bucket_alloc(struct cache_set *c,
        INIT_LIST_HEAD(&b->list);
        INIT_DELAYED_WORK(&b->work, btree_node_write_work);
        b->c = c;
-       closure_init_unlocked(&b->io);
+       sema_init(&b->io_mutex, 1);
 
        mca_data_alloc(b, k, gfp);
        return b;
@@ -651,24 +616,31 @@ static int mca_reap(struct btree *b, unsigned min_order, bool flush)
        if (!down_write_trylock(&b->lock))
                return -ENOMEM;
 
-       BUG_ON(btree_node_dirty(b) && !b->sets[0].data);
+       BUG_ON(btree_node_dirty(b) && !b->keys.set[0].data);
 
-       if (b->page_order < min_order ||
-           (!flush &&
-            (btree_node_dirty(b) ||
-             atomic_read(&b->io.cl.remaining) != -1))) {
-               rw_unlock(true, b);
-               return -ENOMEM;
+       if (b->keys.page_order < min_order)
+               goto out_unlock;
+
+       if (!flush) {
+               if (btree_node_dirty(b))
+                       goto out_unlock;
+
+               if (down_trylock(&b->io_mutex))
+                       goto out_unlock;
+               up(&b->io_mutex);
        }
 
        if (btree_node_dirty(b))
                bch_btree_node_write_sync(b);
 
        /* wait for any in flight btree write */
-       closure_wait_event(&b->io.wait, &cl,
-                          atomic_read(&b->io.cl.remaining) == -1);
+       down(&b->io_mutex);
+       up(&b->io_mutex);
 
        return 0;
+out_unlock:
+       rw_unlock(true, b);
+       return -ENOMEM;
 }
 
 static unsigned long bch_mca_scan(struct shrinker *shrink,
@@ -714,14 +686,10 @@ static unsigned long bch_mca_scan(struct shrinker *shrink,
                }
        }
 
-       /*
-        * Can happen right when we first start up, before we've read in any
-        * btree nodes
-        */
-       if (list_empty(&c->btree_cache))
-               goto out;
-
        for (i = 0; (nr--) && i < c->bucket_cache_used; i++) {
+               if (list_empty(&c->btree_cache))
+                       goto out;
+
                b = list_first_entry(&c->btree_cache, struct btree, list);
                list_rotate_left(&c->btree_cache);
 
@@ -767,6 +735,8 @@ void bch_btree_cache_free(struct cache_set *c)
 #ifdef CONFIG_BCACHE_DEBUG
        if (c->verify_data)
                list_move(&c->verify_data->list, &c->btree_cache);
+
+       free_pages((unsigned long) c->verify_ondisk, ilog2(bucket_pages(c)));
 #endif
 
        list_splice(&c->btree_cache_freeable,
@@ -807,10 +777,13 @@ int bch_btree_cache_alloc(struct cache_set *c)
 #ifdef CONFIG_BCACHE_DEBUG
        mutex_init(&c->verify_lock);
 
+       c->verify_ondisk = (void *)
+               __get_free_pages(GFP_KERNEL, ilog2(bucket_pages(c)));
+
        c->verify_data = mca_bucket_alloc(c, &ZERO_KEY, GFP_KERNEL);
 
        if (c->verify_data &&
-           c->verify_data->sets[0].data)
+           c->verify_data->keys.set->data)
                list_del_init(&c->verify_data->list);
        else
                c->verify_data = NULL;
@@ -908,7 +881,7 @@ static struct btree *mca_alloc(struct cache_set *c, struct bkey *k, int level)
        list_for_each_entry(b, &c->btree_cache_freed, list)
                if (!mca_reap(b, 0, false)) {
                        mca_data_alloc(b, k, __GFP_NOWARN|GFP_NOIO);
-                       if (!b->sets[0].data)
+                       if (!b->keys.set[0].data)
                                goto err;
                        else
                                goto out;
@@ -919,10 +892,10 @@ static struct btree *mca_alloc(struct cache_set *c, struct bkey *k, int level)
                goto err;
 
        BUG_ON(!down_write_trylock(&b->lock));
-       if (!b->sets->data)
+       if (!b->keys.set->data)
                goto err;
 out:
-       BUG_ON(!closure_is_unlocked(&b->io.cl));
+       BUG_ON(b->io_mutex.count != 1);
 
        bkey_copy(&b->key, k);
        list_move(&b->list, &c->btree_cache);
@@ -930,10 +903,17 @@ out:
        hlist_add_head_rcu(&b->hash, mca_hash(c, k));
 
        lock_set_subclass(&b->lock.dep_map, level + 1, _THIS_IP_);
-       b->level        = level;
        b->parent       = (void *) ~0UL;
+       b->flags        = 0;
+       b->written      = 0;
+       b->level        = level;
 
-       mca_reinit(b);
+       if (!b->level)
+               bch_btree_keys_init(&b->keys, &bch_extent_keys_ops,
+                                   &b->c->expensive_debug_checks);
+       else
+               bch_btree_keys_init(&b->keys, &bch_btree_keys_ops,
+                                   &b->c->expensive_debug_checks);
 
        return b;
 err:
@@ -994,13 +974,13 @@ retry:
 
        b->accessed = 1;
 
-       for (; i <= b->nsets && b->sets[i].size; i++) {
-               prefetch(b->sets[i].tree);
-               prefetch(b->sets[i].data);
+       for (; i <= b->keys.nsets && b->keys.set[i].size; i++) {
+               prefetch(b->keys.set[i].tree);
+               prefetch(b->keys.set[i].data);
        }
 
-       for (; i <= b->nsets; i++)
-               prefetch(b->sets[i].data);
+       for (; i <= b->keys.nsets; i++)
+               prefetch(b->keys.set[i].data);
 
        if (btree_node_io_error(b)) {
                rw_unlock(write, b);
@@ -1063,7 +1043,7 @@ struct btree *bch_btree_node_alloc(struct cache_set *c, int level, bool wait)
 
        mutex_lock(&c->bucket_lock);
 retry:
-       if (__bch_bucket_alloc_set(c, WATERMARK_METADATA, &k.key, 1, wait))
+       if (__bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, wait))
                goto err;
 
        bkey_put(c, &k.key);
@@ -1080,7 +1060,7 @@ retry:
        }
 
        b->accessed = 1;
-       bch_bset_init_next(b);
+       bch_bset_init_next(&b->keys, b->keys.set->data, bset_magic(&b->c->sb));
 
        mutex_unlock(&c->bucket_lock);
 
@@ -1098,8 +1078,10 @@ err:
 static struct btree *btree_node_alloc_replacement(struct btree *b, bool wait)
 {
        struct btree *n = bch_btree_node_alloc(b->c, b->level, wait);
-       if (!IS_ERR_OR_NULL(n))
-               bch_btree_sort_into(b, n);
+       if (!IS_ERR_OR_NULL(n)) {
+               bch_btree_sort_into(&b->keys, &n->keys, &b->c->sort);
+               bkey_copy_key(&n->key, &b->key);
+       }
 
        return n;
 }
@@ -1120,6 +1102,28 @@ static void make_btree_freeing_key(struct btree *b, struct bkey *k)
        atomic_inc(&b->c->prio_blocked);
 }
 
+static int btree_check_reserve(struct btree *b, struct btree_op *op)
+{
+       struct cache_set *c = b->c;
+       struct cache *ca;
+       unsigned i, reserve = c->root->level * 2 + 1;
+       int ret = 0;
+
+       mutex_lock(&c->bucket_lock);
+
+       for_each_cache(ca, c, i)
+               if (fifo_used(&ca->free[RESERVE_BTREE]) < reserve) {
+                       if (op)
+                               prepare_to_wait(&c->bucket_wait, &op->wait,
+                                               TASK_UNINTERRUPTIBLE);
+                       ret = -EINTR;
+                       break;
+               }
+
+       mutex_unlock(&c->bucket_lock);
+       return ret;
+}
+
 /* Garbage collection */
 
 uint8_t __bch_btree_mark_key(struct cache_set *c, int level, struct bkey *k)
@@ -1183,11 +1187,11 @@ static bool btree_gc_mark_node(struct btree *b, struct gc_stat *gc)
 
        gc->nodes++;
 
-       for_each_key_filter(b, k, &iter, bch_ptr_invalid) {
+       for_each_key_filter(&b->keys, k, &iter, bch_ptr_invalid) {
                stale = max(stale, btree_mark_key(b, k));
                keys++;
 
-               if (bch_ptr_bad(b, k))
+               if (bch_ptr_bad(&b->keys, k))
                        continue;
 
                gc->key_bytes += bkey_u64s(k);
@@ -1197,9 +1201,9 @@ static bool btree_gc_mark_node(struct btree *b, struct gc_stat *gc)
                gc->data += KEY_SIZE(k);
        }
 
-       for (t = b->sets; t <= &b->sets[b->nsets]; t++)
+       for (t = b->keys.set; t <= &b->keys.set[b->keys.nsets]; t++)
                btree_bug_on(t->size &&
-                            bset_written(b, t) &&
+                            bset_written(&b->keys, t) &&
                             bkey_cmp(&b->key, &t->end) < 0,
                             b, "found short btree key in gc");
 
@@ -1243,7 +1247,8 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
        blocks = btree_default_blocks(b->c) * 2 / 3;
 
        if (nodes < 2 ||
-           __set_blocks(b->sets[0].data, keys, b->c) > blocks * (nodes - 1))
+           __set_blocks(b->keys.set[0].data, keys,
+                        block_bytes(b->c)) > blocks * (nodes - 1))
                return 0;
 
        for (i = 0; i < nodes; i++) {
@@ -1253,18 +1258,19 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
        }
 
        for (i = nodes - 1; i > 0; --i) {
-               struct bset *n1 = new_nodes[i]->sets->data;
-               struct bset *n2 = new_nodes[i - 1]->sets->data;
+               struct bset *n1 = btree_bset_first(new_nodes[i]);
+               struct bset *n2 = btree_bset_first(new_nodes[i - 1]);
                struct bkey *k, *last = NULL;
 
                keys = 0;
 
                if (i > 1) {
                        for (k = n2->start;
-                            k < end(n2);
+                            k < bset_bkey_last(n2);
                             k = bkey_next(k)) {
                                if (__set_blocks(n1, n1->keys + keys +
-                                                bkey_u64s(k), b->c) > blocks)
+                                                bkey_u64s(k),
+                                                block_bytes(b->c)) > blocks)
                                        break;
 
                                last = k;
@@ -1280,7 +1286,8 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
                         * though)
                         */
                        if (__set_blocks(n1, n1->keys + n2->keys,
-                                        b->c) > btree_blocks(new_nodes[i]))
+                                        block_bytes(b->c)) >
+                           btree_blocks(new_nodes[i]))
                                goto out_nocoalesce;
 
                        keys = n2->keys;
@@ -1288,27 +1295,28 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
                        last = &r->b->key;
                }
 
-               BUG_ON(__set_blocks(n1, n1->keys + keys,
-                                   b->c) > btree_blocks(new_nodes[i]));
+               BUG_ON(__set_blocks(n1, n1->keys + keys, block_bytes(b->c)) >
+                      btree_blocks(new_nodes[i]));
 
                if (last)
                        bkey_copy_key(&new_nodes[i]->key, last);
 
-               memcpy(end(n1),
+               memcpy(bset_bkey_last(n1),
                       n2->start,
-                      (void *) node(n2, keys) - (void *) n2->start);
+                      (void *) bset_bkey_idx(n2, keys) - (void *) n2->start);
 
                n1->keys += keys;
                r[i].keys = n1->keys;
 
                memmove(n2->start,
-                       node(n2, keys),
-                       (void *) end(n2) - (void *) node(n2, keys));
+                       bset_bkey_idx(n2, keys),
+                       (void *) bset_bkey_last(n2) -
+                       (void *) bset_bkey_idx(n2, keys));
 
                n2->keys -= keys;
 
-               if (bch_keylist_realloc(keylist,
-                                       KEY_PTRS(&new_nodes[i]->key), b->c))
+               if (__bch_keylist_realloc(keylist,
+                                         bkey_u64s(&new_nodes[i]->key)))
                        goto out_nocoalesce;
 
                bch_btree_node_write(new_nodes[i], &cl);
@@ -1316,7 +1324,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
        }
 
        for (i = 0; i < nodes; i++) {
-               if (bch_keylist_realloc(keylist, KEY_PTRS(&r[i].b->key), b->c))
+               if (__bch_keylist_realloc(keylist, bkey_u64s(&r[i].b->key)))
                        goto out_nocoalesce;
 
                make_btree_freeing_key(r[i].b, keylist->top);
@@ -1324,7 +1332,7 @@ static int btree_gc_coalesce(struct btree *b, struct btree_op *op,
        }
 
        /* We emptied out this node */
-       BUG_ON(new_nodes[0]->sets->data->keys);
+       BUG_ON(btree_bset_first(new_nodes[0])->keys);
        btree_node_free(new_nodes[0]);
        rw_unlock(true, new_nodes[0]);
 
@@ -1370,7 +1378,7 @@ static unsigned btree_gc_count_keys(struct btree *b)
        struct btree_iter iter;
        unsigned ret = 0;
 
-       for_each_key_filter(b, k, &iter, bch_ptr_bad)
+       for_each_key_filter(&b->keys, k, &iter, bch_ptr_bad)
                ret += bkey_u64s(k);
 
        return ret;
@@ -1390,13 +1398,13 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
        struct gc_merge_info *last = r + GC_MERGE_NODES - 1;
 
        bch_keylist_init(&keys);
-       bch_btree_iter_init(b, &iter, &b->c->gc_done);
+       bch_btree_iter_init(&b->keys, &iter, &b->c->gc_done);
 
        for (i = 0; i < GC_MERGE_NODES; i++)
                r[i].b = ERR_PTR(-EINTR);
 
        while (1) {
-               k = bch_btree_iter_next_filter(&iter, b, bch_ptr_bad);
+               k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad);
                if (k) {
                        r->b = bch_btree_node_get(b->c, k, b->level - 1, true);
                        if (IS_ERR(r->b)) {
@@ -1416,7 +1424,8 @@ static int btree_gc_recurse(struct btree *b, struct btree_op *op,
 
                if (!IS_ERR(last->b)) {
                        should_rewrite = btree_gc_mark_node(last->b, gc);
-                       if (should_rewrite) {
+                       if (should_rewrite &&
+                           !btree_check_reserve(b, NULL)) {
                                n = btree_node_alloc_replacement(last->b,
                                                                 false);
 
@@ -1705,7 +1714,7 @@ static int bch_btree_check_recurse(struct btree *b, struct btree_op *op,
        struct bucket *g;
        struct btree_iter iter;
 
-       for_each_key_filter(b, k, &iter, bch_ptr_invalid) {
+       for_each_key_filter(&b->keys, k, &iter, bch_ptr_invalid) {
                for (i = 0; i < KEY_PTRS(k); i++) {
                        if (!ptr_available(b->c, k, i))
                                continue;
@@ -1728,10 +1737,11 @@ static int bch_btree_check_recurse(struct btree *b, struct btree_op *op,
        }
 
        if (b->level) {
-               bch_btree_iter_init(b, &iter, NULL);
+               bch_btree_iter_init(&b->keys, &iter, NULL);
 
                do {
-                       k = bch_btree_iter_next_filter(&iter, b, bch_ptr_bad);
+                       k = bch_btree_iter_next_filter(&iter, &b->keys,
+                                                      bch_ptr_bad);
                        if (k)
                                btree_node_prefetch(b->c, k, b->level - 1);
 
@@ -1774,235 +1784,36 @@ err:
 
 /* Btree insertion */
 
-static void shift_keys(struct btree *b, struct bkey *where, struct bkey *insert)
-{
-       struct bset *i = b->sets[b->nsets].data;
-
-       memmove((uint64_t *) where + bkey_u64s(insert),
-               where,
-               (void *) end(i) - (void *) where);
-
-       i->keys += bkey_u64s(insert);
-       bkey_copy(where, insert);
-       bch_bset_fix_lookup_table(b, where);
-}
-
-static bool fix_overlapping_extents(struct btree *b, struct bkey *insert,
-                                   struct btree_iter *iter,
-                                   struct bkey *replace_key)
+static bool btree_insert_key(struct btree *b, struct bkey *k,
+                            struct bkey *replace_key)
 {
-       void subtract_dirty(struct bkey *k, uint64_t offset, int sectors)
-       {
-               if (KEY_DIRTY(k))
-                       bcache_dev_sectors_dirty_add(b->c, KEY_INODE(k),
-                                                    offset, -sectors);
-       }
-
-       uint64_t old_offset;
-       unsigned old_size, sectors_found = 0;
-
-       while (1) {
-               struct bkey *k = bch_btree_iter_next(iter);
-               if (!k ||
-                   bkey_cmp(&START_KEY(k), insert) >= 0)
-                       break;
-
-               if (bkey_cmp(k, &START_KEY(insert)) <= 0)
-                       continue;
-
-               old_offset = KEY_START(k);
-               old_size = KEY_SIZE(k);
-
-               /*
-                * We might overlap with 0 size extents; we can't skip these
-                * because if they're in the set we're inserting to we have to
-                * adjust them so they don't overlap with the key we're
-                * inserting. But we don't want to check them for replace
-                * operations.
-                */
-
-               if (replace_key && KEY_SIZE(k)) {
-                       /*
-                        * k might have been split since we inserted/found the
-                        * key we're replacing
-                        */
-                       unsigned i;
-                       uint64_t offset = KEY_START(k) -
-                               KEY_START(replace_key);
-
-                       /* But it must be a subset of the replace key */
-                       if (KEY_START(k) < KEY_START(replace_key) ||
-                           KEY_OFFSET(k) > KEY_OFFSET(replace_key))
-                               goto check_failed;
-
-                       /* We didn't find a key that we were supposed to */
-                       if (KEY_START(k) > KEY_START(insert) + sectors_found)
-                               goto check_failed;
-
-                       if (KEY_PTRS(k) != KEY_PTRS(replace_key) ||
-                           KEY_DIRTY(k) != KEY_DIRTY(replace_key))
-                               goto check_failed;
-
-                       /* skip past gen */
-                       offset <<= 8;
-
-                       BUG_ON(!KEY_PTRS(replace_key));
+       unsigned status;
 
-                       for (i = 0; i < KEY_PTRS(replace_key); i++)
-                               if (k->ptr[i] != replace_key->ptr[i] + offset)
-                                       goto check_failed;
-
-                       sectors_found = KEY_OFFSET(k) - KEY_START(insert);
-               }
-
-               if (bkey_cmp(insert, k) < 0 &&
-                   bkey_cmp(&START_KEY(insert), &START_KEY(k)) > 0) {
-                       /*
-                        * We overlapped in the middle of an existing key: that
-                        * means we have to split the old key. But we have to do
-                        * slightly different things depending on whether the
-                        * old key has been written out yet.
-                        */
-
-                       struct bkey *top;
-
-                       subtract_dirty(k, KEY_START(insert), KEY_SIZE(insert));
-
-                       if (bkey_written(b, k)) {
-                               /*
-                                * We insert a new key to cover the top of the
-                                * old key, and the old key is modified in place
-                                * to represent the bottom split.
-                                *
-                                * It's completely arbitrary whether the new key
-                                * is the top or the bottom, but it has to match
-                                * up with what btree_sort_fixup() does - it
-                                * doesn't check for this kind of overlap, it
-                                * depends on us inserting a new key for the top
-                                * here.
-                                */
-                               top = bch_bset_search(b, &b->sets[b->nsets],
-                                                     insert);
-                               shift_keys(b, top, k);
-                       } else {
-                               BKEY_PADDED(key) temp;
-                               bkey_copy(&temp.key, k);
-                               shift_keys(b, k, &temp.key);
-                               top = bkey_next(k);
-                       }
-
-                       bch_cut_front(insert, top);
-                       bch_cut_back(&START_KEY(insert), k);
-                       bch_bset_fix_invalidated_key(b, k);
-                       return false;
-               }
-
-               if (bkey_cmp(insert, k) < 0) {
-                       bch_cut_front(insert, k);
-               } else {
-                       if (bkey_cmp(&START_KEY(insert), &START_KEY(k)) > 0)
-                               old_offset = KEY_START(insert);
-
-                       if (bkey_written(b, k) &&
-                           bkey_cmp(&START_KEY(insert), &START_KEY(k)) <= 0) {
-                               /*
-                                * Completely overwrote, so we don't have to
-                                * invalidate the binary search tree
-                                */
-                               bch_cut_front(k, k);
-                       } else {
-                               __bch_cut_back(&START_KEY(insert), k);
-                               bch_bset_fix_invalidated_key(b, k);
-                       }
-               }
-
-               subtract_dirty(k, old_offset, old_size - KEY_SIZE(k));
-       }
+       BUG_ON(bkey_cmp(k, &b->key) > 0);
 
-check_failed:
-       if (replace_key) {
-               if (!sectors_found) {
-                       return true;
-               } else if (sectors_found < KEY_SIZE(insert)) {
-                       SET_KEY_OFFSET(insert, KEY_OFFSET(insert) -
-                                      (KEY_SIZE(insert) - sectors_found));
-                       SET_KEY_SIZE(insert, sectors_found);
-               }
-       }
+       status = bch_btree_insert_key(&b->keys, k, replace_key);
+       if (status != BTREE_INSERT_STATUS_NO_INSERT) {
+               bch_check_keys(&b->keys, "%u for %s", status,
+                              replace_key ? "replace" : "insert");
 
-       return false;
+               trace_bcache_btree_insert_key(b, k, replace_key != NULL,
+                                             status);
+               return true;
+       } else
+               return false;
 }
 
-static bool btree_insert_key(struct btree *b, struct btree_op *op,
-                            struct bkey *k, struct bkey *replace_key)
+static size_t insert_u64s_remaining(struct btree *b)
 {
-       struct bset *i = b->sets[b->nsets].data;
-       struct bkey *m, *prev;
-       unsigned status = BTREE_INSERT_STATUS_INSERT;
-
-       BUG_ON(bkey_cmp(k, &b->key) > 0);
-       BUG_ON(b->level && !KEY_PTRS(k));
-       BUG_ON(!b->level && !KEY_OFFSET(k));
-
-       if (!b->level) {
-               struct btree_iter iter;
-
-               /*
-                * bset_search() returns the first key that is strictly greater
-                * than the search key - but for back merging, we want to find
-                * the previous key.
-                */
-               prev = NULL;
-               m = bch_btree_iter_init(b, &iter, PRECEDING_KEY(&START_KEY(k)));
+       ssize_t ret = bch_btree_keys_u64s_remaining(&b->keys);
 
-               if (fix_overlapping_extents(b, k, &iter, replace_key)) {
-                       op->insert_collision = true;
-                       return false;
-               }
-
-               if (KEY_DIRTY(k))
-                       bcache_dev_sectors_dirty_add(b->c, KEY_INODE(k),
-                                                    KEY_START(k), KEY_SIZE(k));
-
-               while (m != end(i) &&
-                      bkey_cmp(k, &START_KEY(m)) > 0)
-                       prev = m, m = bkey_next(m);
-
-               if (key_merging_disabled(b->c))
-                       goto insert;
-
-               /* prev is in the tree, if we merge we're done */
-               status = BTREE_INSERT_STATUS_BACK_MERGE;
-               if (prev &&
-                   bch_bkey_try_merge(b, prev, k))
-                       goto merged;
-
-               status = BTREE_INSERT_STATUS_OVERWROTE;
-               if (m != end(i) &&
-                   KEY_PTRS(m) == KEY_PTRS(k) && !KEY_SIZE(m))
-                       goto copy;
-
-               status = BTREE_INSERT_STATUS_FRONT_MERGE;
-               if (m != end(i) &&
-                   bch_bkey_try_merge(b, k, m))
-                       goto copy;
-       } else {
-               BUG_ON(replace_key);
-               m = bch_bset_search(b, &b->sets[b->nsets], k);
-       }
-
-insert:        shift_keys(b, m, k);
-copy:  bkey_copy(m, k);
-merged:
-       bch_check_keys(b, "%u for %s", status,
-                      replace_key ? "replace" : "insert");
-
-       if (b->level && !KEY_OFFSET(k))
-               btree_current_write(b)->prio_blocked++;
-
-       trace_bcache_btree_insert_key(b, k, replace_key != NULL, status);
+       /*
+        * Might land in the middle of an existing extent and have to split it
+        */
+       if (b->keys.ops->is_extents)
+               ret -= KEY_MAX_U64S;
 
-       return true;
+       return max(ret, 0L);
 }
 
 static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op,
@@ -2010,21 +1821,19 @@ static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op,
                                  struct bkey *replace_key)
 {
        bool ret = false;
-       int oldsize = bch_count_data(b);
+       int oldsize = bch_count_data(&b->keys);
 
        while (!bch_keylist_empty(insert_keys)) {
-               struct bset *i = write_block(b);
                struct bkey *k = insert_keys->keys;
 
-               if (b->written + __set_blocks(i, i->keys + bkey_u64s(k), b->c)
-                   > btree_blocks(b))
+               if (bkey_u64s(k) > insert_u64s_remaining(b))
                        break;
 
                if (bkey_cmp(k, &b->key) <= 0) {
                        if (!b->level)
                                bkey_put(b->c, k);
 
-                       ret |= btree_insert_key(b, op, k, replace_key);
+                       ret |= btree_insert_key(b, k, replace_key);
                        bch_keylist_pop_front(insert_keys);
                } else if (bkey_cmp(&START_KEY(k), &b->key) < 0) {
                        BKEY_PADDED(key) temp;
@@ -2033,16 +1842,19 @@ static bool bch_btree_insert_keys(struct btree *b, struct btree_op *op,
                        bch_cut_back(&b->key, &temp.key);
                        bch_cut_front(&b->key, insert_keys->keys);
 
-                       ret |= btree_insert_key(b, op, &temp.key, replace_key);
+                       ret |= btree_insert_key(b, &temp.key, replace_key);
                        break;
                } else {
                        break;
                }
        }
 
+       if (!ret)
+               op->insert_collision = true;
+
        BUG_ON(!bch_keylist_empty(insert_keys) && b->level);
 
-       BUG_ON(bch_count_data(b) < oldsize);
+       BUG_ON(bch_count_data(&b->keys) < oldsize);
        return ret;
 }
 
@@ -2059,16 +1871,21 @@ static int btree_split(struct btree *b, struct btree_op *op,
        closure_init_stack(&cl);
        bch_keylist_init(&parent_keys);
 
+       if (!b->level &&
+           btree_check_reserve(b, op))
+               return -EINTR;
+
        n1 = btree_node_alloc_replacement(b, true);
        if (IS_ERR(n1))
                goto err;
 
-       split = set_blocks(n1->sets[0].data, n1->c) > (btree_blocks(b) * 4) / 5;
+       split = set_blocks(btree_bset_first(n1),
+                          block_bytes(n1->c)) > (btree_blocks(b) * 4) / 5;
 
        if (split) {
                unsigned keys = 0;
 
-               trace_bcache_btree_node_split(b, n1->sets[0].data->keys);
+               trace_bcache_btree_node_split(b, btree_bset_first(n1)->keys);
 
                n2 = bch_btree_node_alloc(b->c, b->level, true);
                if (IS_ERR(n2))
@@ -2087,18 +1904,20 @@ static int btree_split(struct btree *b, struct btree_op *op,
                 * search tree yet
                 */
 
-               while (keys < (n1->sets[0].data->keys * 3) / 5)
-                       keys += bkey_u64s(node(n1->sets[0].data, keys));
+               while (keys < (btree_bset_first(n1)->keys * 3) / 5)
+                       keys += bkey_u64s(bset_bkey_idx(btree_bset_first(n1),
+                                                       keys));
 
-               bkey_copy_key(&n1->key, node(n1->sets[0].data, keys));
-               keys += bkey_u64s(node(n1->sets[0].data, keys));
+               bkey_copy_key(&n1->key,
+                             bset_bkey_idx(btree_bset_first(n1), keys));
+               keys += bkey_u64s(bset_bkey_idx(btree_bset_first(n1), keys));
 
-               n2->sets[0].data->keys = n1->sets[0].data->keys - keys;
-               n1->sets[0].data->keys = keys;
+               btree_bset_first(n2)->keys = btree_bset_first(n1)->keys - keys;
+               btree_bset_first(n1)->keys = keys;
 
-               memcpy(n2->sets[0].data->start,
-                      end(n1->sets[0].data),
-                      n2->sets[0].data->keys * sizeof(uint64_t));
+               memcpy(btree_bset_first(n2)->start,
+                      bset_bkey_last(btree_bset_first(n1)),
+                      btree_bset_first(n2)->keys * sizeof(uint64_t));
 
                bkey_copy_key(&n2->key, &b->key);
 
@@ -2106,7 +1925,7 @@ static int btree_split(struct btree *b, struct btree_op *op,
                bch_btree_node_write(n2, &cl);
                rw_unlock(true, n2);
        } else {
-               trace_bcache_btree_node_compact(b, n1->sets[0].data->keys);
+               trace_bcache_btree_node_compact(b, btree_bset_first(n1)->keys);
 
                bch_btree_insert_keys(n1, op, insert_keys, replace_key);
        }
@@ -2149,18 +1968,21 @@ static int btree_split(struct btree *b, struct btree_op *op,
 
        return 0;
 err_free2:
+       bkey_put(b->c, &n2->key);
        btree_node_free(n2);
        rw_unlock(true, n2);
 err_free1:
+       bkey_put(b->c, &n1->key);
        btree_node_free(n1);
        rw_unlock(true, n1);
 err:
+       WARN(1, "bcache: btree split failed");
+
        if (n3 == ERR_PTR(-EAGAIN) ||
            n2 == ERR_PTR(-EAGAIN) ||
            n1 == ERR_PTR(-EAGAIN))
                return -EAGAIN;
 
-       pr_warn("couldn't split");
        return -ENOMEM;
 }
 
@@ -2171,7 +1993,7 @@ static int bch_btree_insert_node(struct btree *b, struct btree_op *op,
 {
        BUG_ON(b->level && replace_key);
 
-       if (should_split(b)) {
+       if (bch_keylist_nkeys(insert_keys) > insert_u64s_remaining(b)) {
                if (current->bio_list) {
                        op->lock = b->c->root->level + 1;
                        return -EAGAIN;
@@ -2180,11 +2002,13 @@ static int bch_btree_insert_node(struct btree *b, struct btree_op *op,
                        return -EINTR;
                } else {
                        /* Invalidated all iterators */
-                       return btree_split(b, op, insert_keys, replace_key) ?:
-                               -EINTR;
+                       int ret = btree_split(b, op, insert_keys, replace_key);
+
+                       return bch_keylist_empty(insert_keys) ?
+                               0 : ret ?: -EINTR;
                }
        } else {
-               BUG_ON(write_block(b) != b->sets[b->nsets].data);
+               BUG_ON(write_block(b) != btree_bset_last(b));
 
                if (bch_btree_insert_keys(b, op, insert_keys, replace_key)) {
                        if (!b->level)
@@ -2323,9 +2147,9 @@ static int bch_btree_map_nodes_recurse(struct btree *b, struct btree_op *op,
                struct bkey *k;
                struct btree_iter iter;
 
-               bch_btree_iter_init(b, &iter, from);
+               bch_btree_iter_init(&b->keys, &iter, from);
 
-               while ((k = bch_btree_iter_next_filter(&iter, b,
+               while ((k = bch_btree_iter_next_filter(&iter, &b->keys,
                                                       bch_ptr_bad))) {
                        ret = btree(map_nodes_recurse, k, b,
                                    op, from, fn, flags);
@@ -2356,9 +2180,9 @@ static int bch_btree_map_keys_recurse(struct btree *b, struct btree_op *op,
        struct bkey *k;
        struct btree_iter iter;
 
-       bch_btree_iter_init(b, &iter, from);
+       bch_btree_iter_init(&b->keys, &iter, from);
 
-       while ((k = bch_btree_iter_next_filter(&iter, b, bch_ptr_bad))) {
+       while ((k = bch_btree_iter_next_filter(&iter, &b->keys, bch_ptr_bad))) {
                ret = !b->level
                        ? fn(op, b, k)
                        : btree(map_keys_recurse, k, b, op, from, fn, flags);
index 767e755708964ce82f36dc88e28281b5c1b90177..af065e97e55c4186782422db0bae20498fd3cdb8 100644 (file)
@@ -130,20 +130,12 @@ struct btree {
        unsigned long           flags;
        uint16_t                written;        /* would be nice to kill */
        uint8_t                 level;
-       uint8_t                 nsets;
-       uint8_t                 page_order;
-
-       /*
-        * Set of sorted keys - the real btree node - plus a binary search tree
-        *
-        * sets[0] is special; set[0]->tree, set[0]->prev and set[0]->data point
-        * to the memory we have allocated for this btree node. Additionally,
-        * set[0]->data points to the entire btree node as it exists on disk.
-        */
-       struct bset_tree        sets[MAX_BSETS];
+
+       struct btree_keys       keys;
 
        /* For outstanding btree writes, used as a lock - protects write_idx */
-       struct closure_with_waitlist    io;
+       struct closure          io;
+       struct semaphore        io_mutex;
 
        struct list_head        list;
        struct delayed_work     work;
@@ -179,24 +171,19 @@ static inline struct btree_write *btree_prev_write(struct btree *b)
        return b->writes + (btree_node_write_idx(b) ^ 1);
 }
 
-static inline unsigned bset_offset(struct btree *b, struct bset *i)
+static inline struct bset *btree_bset_first(struct btree *b)
 {
-       return (((size_t) i) - ((size_t) b->sets->data)) >> 9;
+       return b->keys.set->data;
 }
 
-static inline struct bset *write_block(struct btree *b)
+static inline struct bset *btree_bset_last(struct btree *b)
 {
-       return ((void *) b->sets[0].data) + b->written * block_bytes(b->c);
+       return bset_tree_last(&b->keys)->data;
 }
 
-static inline bool bset_written(struct btree *b, struct bset_tree *t)
+static inline unsigned bset_block_offset(struct btree *b, struct bset *i)
 {
-       return t->data < write_block(b);
-}
-
-static inline bool bkey_written(struct btree *b, struct bkey *k)
-{
-       return k < write_block(b)->start;
+       return bset_sector_offset(&b->keys, i) >> b->c->block_bits;
 }
 
 static inline void set_gc_sectors(struct cache_set *c)
@@ -204,21 +191,6 @@ static inline void set_gc_sectors(struct cache_set *c)
        atomic_set(&c->sectors_to_gc, c->sb.bucket_size * c->nbuckets / 16);
 }
 
-static inline struct bkey *bch_btree_iter_init(struct btree *b,
-                                              struct btree_iter *iter,
-                                              struct bkey *search)
-{
-       return __bch_btree_iter_init(b, iter, search, b->sets);
-}
-
-static inline bool bch_ptr_invalid(struct btree *b, const struct bkey *k)
-{
-       if (b->level)
-               return bch_btree_ptr_invalid(b->c, k);
-       else
-               return bch_extent_ptr_invalid(b->c, k);
-}
-
 void bkey_put(struct cache_set *c, struct bkey *k);
 
 /* Looping macros */
@@ -229,17 +201,12 @@ void bkey_put(struct cache_set *c, struct bkey *k);
             iter++)                                                    \
                hlist_for_each_entry_rcu((b), (c)->bucket_hash + iter, hash)
 
-#define for_each_key_filter(b, k, iter, filter)                                \
-       for (bch_btree_iter_init((b), (iter), NULL);                    \
-            ((k) = bch_btree_iter_next_filter((iter), b, filter));)
-
-#define for_each_key(b, k, iter)                                       \
-       for (bch_btree_iter_init((b), (iter), NULL);                    \
-            ((k) = bch_btree_iter_next(iter));)
-
 /* Recursing down the btree */
 
 struct btree_op {
+       /* for waiting on btree reserve in btree_split() */
+       wait_queue_t            wait;
+
        /* Btree level at which we start taking write locks */
        short                   lock;
 
@@ -249,6 +216,7 @@ struct btree_op {
 static inline void bch_btree_op_init(struct btree_op *op, int write_lock_level)
 {
        memset(op, 0, sizeof(struct btree_op));
+       init_wait(&op->wait);
        op->lock = write_lock_level;
 }
 
@@ -267,7 +235,7 @@ static inline void rw_unlock(bool w, struct btree *b)
        (w ? up_write : up_read)(&b->lock);
 }
 
-void bch_btree_node_read(struct btree *);
+void bch_btree_node_read_done(struct btree *);
 void bch_btree_node_write(struct btree *, struct closure *);
 
 void bch_btree_set_root(struct btree *);
index dfff2410322e70263ac63e6dbfd9536bd4a5dc54..7a228de95fd7e94fa61acb0758a53d8670770383 100644 (file)
 
 #include "closure.h"
 
-#define CL_FIELD(type, field)                                  \
-       case TYPE_ ## type:                                     \
-       return &container_of(cl, struct type, cl)->field
-
-static struct closure_waitlist *closure_waitlist(struct closure *cl)
-{
-       switch (cl->type) {
-               CL_FIELD(closure_with_waitlist, wait);
-       default:
-               return NULL;
-       }
-}
-
 static inline void closure_put_after_sub(struct closure *cl, int flags)
 {
        int r = flags & CLOSURE_REMAINING_MASK;
@@ -42,17 +29,10 @@ static inline void closure_put_after_sub(struct closure *cl, int flags)
                        closure_queue(cl);
                } else {
                        struct closure *parent = cl->parent;
-                       struct closure_waitlist *wait = closure_waitlist(cl);
                        closure_fn *destructor = cl->fn;
 
                        closure_debug_destroy(cl);
 
-                       smp_mb();
-                       atomic_set(&cl->remaining, -1);
-
-                       if (wait)
-                               closure_wake_up(wait);
-
                        if (destructor)
                                destructor(cl);
 
@@ -69,19 +49,18 @@ void closure_sub(struct closure *cl, int v)
 }
 EXPORT_SYMBOL(closure_sub);
 
+/**
+ * closure_put - decrement a closure's refcount
+ */
 void closure_put(struct closure *cl)
 {
        closure_put_after_sub(cl, atomic_dec_return(&cl->remaining));
 }
 EXPORT_SYMBOL(closure_put);
 
-static void set_waiting(struct closure *cl, unsigned long f)
-{
-#ifdef CONFIG_BCACHE_CLOSURES_DEBUG
-       cl->waiting_on = f;
-#endif
-}
-
+/**
+ * closure_wake_up - wake up all closures on a wait list, without memory barrier
+ */
 void __closure_wake_up(struct closure_waitlist *wait_list)
 {
        struct llist_node *list;
@@ -106,27 +85,34 @@ void __closure_wake_up(struct closure_waitlist *wait_list)
                cl = container_of(reverse, struct closure, list);
                reverse = llist_next(reverse);
 
-               set_waiting(cl, 0);
+               closure_set_waiting(cl, 0);
                closure_sub(cl, CLOSURE_WAITING + 1);
        }
 }
 EXPORT_SYMBOL(__closure_wake_up);
 
-bool closure_wait(struct closure_waitlist *list, struct closure *cl)
+/**
+ * closure_wait - add a closure to a waitlist
+ *
+ * @waitlist will own a ref on @cl, which will be released when
+ * closure_wake_up() is called on @waitlist.
+ *
+ */
+bool closure_wait(struct closure_waitlist *waitlist, struct closure *cl)
 {
        if (atomic_read(&cl->remaining) & CLOSURE_WAITING)
                return false;
 
-       set_waiting(cl, _RET_IP_);
+       closure_set_waiting(cl, _RET_IP_);
        atomic_add(CLOSURE_WAITING + 1, &cl->remaining);
-       llist_add(&cl->list, &list->list);
+       llist_add(&cl->list, &waitlist->list);
 
        return true;
 }
 EXPORT_SYMBOL(closure_wait);
 
 /**
- * closure_sync() - sleep until a closure a closure has nothing left to wait on
+ * closure_sync - sleep until a closure a closure has nothing left to wait on
  *
  * Sleeps until the refcount hits 1 - the thread that's running the closure owns
  * the last refcount.
@@ -148,46 +134,6 @@ void closure_sync(struct closure *cl)
 }
 EXPORT_SYMBOL(closure_sync);
 
-/**
- * closure_trylock() - try to acquire the closure, without waiting
- * @cl:                closure to lock
- *
- * Returns true if the closure was succesfully locked.
- */
-bool closure_trylock(struct closure *cl, struct closure *parent)
-{
-       if (atomic_cmpxchg(&cl->remaining, -1,
-                          CLOSURE_REMAINING_INITIALIZER) != -1)
-               return false;
-
-       smp_mb();
-
-       cl->parent = parent;
-       if (parent)
-               closure_get(parent);
-
-       closure_set_ret_ip(cl);
-       closure_debug_create(cl);
-       return true;
-}
-EXPORT_SYMBOL(closure_trylock);
-
-void __closure_lock(struct closure *cl, struct closure *parent,
-                   struct closure_waitlist *wait_list)
-{
-       struct closure wait;
-       closure_init_stack(&wait);
-
-       while (1) {
-               if (closure_trylock(cl, parent))
-                       return;
-
-               closure_wait_event(wait_list, &wait,
-                                  atomic_read(&cl->remaining) == -1);
-       }
-}
-EXPORT_SYMBOL(__closure_lock);
-
 #ifdef CONFIG_BCACHE_CLOSURES_DEBUG
 
 static LIST_HEAD(closure_list);
index 9762f1be3304f1349cc21f001cfa02d5401470e9..7ef7461912be252d00ce23b79504664e96ffd84f 100644 (file)
  * closure - _always_ use continue_at(). Doing so consistently will help
  * eliminate an entire class of particularly pernicious races.
  *
- * For a closure to wait on an arbitrary event, we need to introduce waitlists:
- *
- * struct closure_waitlist list;
- * closure_wait_event(list, cl, condition);
- * closure_wake_up(wait_list);
- *
- * These work analagously to wait_event() and wake_up() - except that instead of
- * operating on the current thread (for wait_event()) and lists of threads, they
- * operate on an explicit closure and lists of closures.
- *
- * Because it's a closure we can now wait either synchronously or
- * asynchronously. closure_wait_event() returns the current value of the
- * condition, and if it returned false continue_at() or closure_sync() can be
- * used to wait for it to become true.
- *
- * It's useful for waiting on things when you can't sleep in the context in
- * which you must check the condition (perhaps a spinlock held, or you might be
- * beneath generic_make_request() - in which case you can't sleep on IO).
- *
- * closure_wait_event() will wait either synchronously or asynchronously,
- * depending on whether the closure is in blocking mode or not. You can pick a
- * mode explicitly with closure_wait_event_sync() and
- * closure_wait_event_async(), which do just what you might expect.
- *
  * Lastly, you might have a wait list dedicated to a specific event, and have no
  * need for specifying the condition - you just want to wait until someone runs
  * closure_wake_up() on the appropriate wait list. In that case, just use
  * All this implies that a closure should typically be embedded in a particular
  * struct (which its refcount will normally control the lifetime of), and that
  * struct can very much be thought of as a stack frame.
- *
- * Locking:
- *
- * Closures are based on work items but they can be thought of as more like
- * threads - in that like threads and unlike work items they have a well
- * defined lifetime; they are created (with closure_init()) and eventually
- * complete after a continue_at(cl, NULL, NULL).
- *
- * Suppose you've got some larger structure with a closure embedded in it that's
- * used for periodically doing garbage collection. You only want one garbage
- * collection happening at a time, so the natural thing to do is protect it with
- * a lock. However, it's difficult to use a lock protecting a closure correctly
- * because the unlock should come after the last continue_to() (additionally, if
- * you're using the closure asynchronously a mutex won't work since a mutex has
- * to be unlocked by the same process that locked it).
- *
- * So to make it less error prone and more efficient, we also have the ability
- * to use closures as locks:
- *
- * closure_init_unlocked();
- * closure_trylock();
- *
- * That's all we need for trylock() - the last closure_put() implicitly unlocks
- * it for you.  But for closure_lock(), we also need a wait list:
- *
- * struct closure_with_waitlist frobnicator_cl;
- *
- * closure_init_unlocked(&frobnicator_cl);
- * closure_lock(&frobnicator_cl);
- *
- * A closure_with_waitlist embeds a closure and a wait list - much like struct
- * delayed_work embeds a work item and a timer_list. The important thing is, use
- * it exactly like you would a regular closure and closure_put() will magically
- * handle everything for you.
  */
 
 struct closure;
@@ -164,12 +106,6 @@ struct closure_waitlist {
        struct llist_head       list;
 };
 
-enum closure_type {
-       TYPE_closure                            = 0,
-       TYPE_closure_with_waitlist              = 1,
-       MAX_CLOSURE_TYPE                        = 1,
-};
-
 enum closure_state {
        /*
         * CLOSURE_WAITING: Set iff the closure is on a waitlist. Must be set by
@@ -224,8 +160,6 @@ struct closure {
 
        atomic_t                remaining;
 
-       enum closure_type       type;
-
 #ifdef CONFIG_BCACHE_CLOSURES_DEBUG
 #define CLOSURE_MAGIC_DEAD     0xc054dead
 #define CLOSURE_MAGIC_ALIVE    0xc054a11e
@@ -237,34 +171,12 @@ struct closure {
 #endif
 };
 
-struct closure_with_waitlist {
-       struct closure          cl;
-       struct closure_waitlist wait;
-};
-
-extern unsigned invalid_closure_type(void);
-
-#define __CLOSURE_TYPE(cl, _t)                                         \
-         __builtin_types_compatible_p(typeof(cl), struct _t)           \
-               ? TYPE_ ## _t :                                         \
-
-#define __closure_type(cl)                                             \
-(                                                                      \
-       __CLOSURE_TYPE(cl, closure)                                     \
-       __CLOSURE_TYPE(cl, closure_with_waitlist)                       \
-       invalid_closure_type()                                          \
-)
-
 void closure_sub(struct closure *cl, int v);
 void closure_put(struct closure *cl);
 void __closure_wake_up(struct closure_waitlist *list);
 bool closure_wait(struct closure_waitlist *list, struct closure *cl);
 void closure_sync(struct closure *cl);
 
-bool closure_trylock(struct closure *cl, struct closure *parent);
-void __closure_lock(struct closure *cl, struct closure *parent,
-                   struct closure_waitlist *wait_list);
-
 #ifdef CONFIG_BCACHE_CLOSURES_DEBUG
 
 void closure_debug_init(void);
@@ -293,134 +205,97 @@ static inline void closure_set_ret_ip(struct closure *cl)
 #endif
 }
 
-static inline void closure_get(struct closure *cl)
+static inline void closure_set_waiting(struct closure *cl, unsigned long f)
 {
 #ifdef CONFIG_BCACHE_CLOSURES_DEBUG
-       BUG_ON((atomic_inc_return(&cl->remaining) &
-               CLOSURE_REMAINING_MASK) <= 1);
-#else
-       atomic_inc(&cl->remaining);
+       cl->waiting_on = f;
 #endif
 }
 
-static inline void closure_set_stopped(struct closure *cl)
+static inline void __closure_end_sleep(struct closure *cl)
 {
-       atomic_sub(CLOSURE_RUNNING, &cl->remaining);
+       __set_current_state(TASK_RUNNING);
+
+       if (atomic_read(&cl->remaining) & CLOSURE_SLEEPING)
+               atomic_sub(CLOSURE_SLEEPING, &cl->remaining);
 }
 
-static inline bool closure_is_unlocked(struct closure *cl)
+static inline void __closure_start_sleep(struct closure *cl)
 {
-       return atomic_read(&cl->remaining) == -1;
+       closure_set_ip(cl);
+       cl->task = current;
+       set_current_state(TASK_UNINTERRUPTIBLE);
+
+       if (!(atomic_read(&cl->remaining) & CLOSURE_SLEEPING))
+               atomic_add(CLOSURE_SLEEPING, &cl->remaining);
 }
 
-static inline void do_closure_init(struct closure *cl, struct closure *parent,
-                                  bool running)
+static inline void closure_set_stopped(struct closure *cl)
 {
-       cl->parent = parent;
-       if (parent)
-               closure_get(parent);
-
-       if (running) {
-               closure_debug_create(cl);
-               atomic_set(&cl->remaining, CLOSURE_REMAINING_INITIALIZER);
-       } else
-               atomic_set(&cl->remaining, -1);
+       atomic_sub(CLOSURE_RUNNING, &cl->remaining);
+}
 
+static inline void set_closure_fn(struct closure *cl, closure_fn *fn,
+                                 struct workqueue_struct *wq)
+{
+       BUG_ON(object_is_on_stack(cl));
        closure_set_ip(cl);
+       cl->fn = fn;
+       cl->wq = wq;
+       /* between atomic_dec() in closure_put() */
+       smp_mb__before_atomic_dec();
 }
 
-/*
- * Hack to get at the embedded closure if there is one, by doing an unsafe cast:
- * the result of __closure_type() is thrown away, it's used merely for type
- * checking.
- */
-#define __to_internal_closure(cl)                              \
-({                                                             \
-       BUILD_BUG_ON(__closure_type(*cl) > MAX_CLOSURE_TYPE);   \
-       (struct closure *) cl;                                  \
-})
-
-#define closure_init_type(cl, parent, running)                 \
-do {                                                           \
-       struct closure *_cl = __to_internal_closure(cl);        \
-       _cl->type = __closure_type(*(cl));                      \
-       do_closure_init(_cl, parent, running);                  \
-} while (0)
+static inline void closure_queue(struct closure *cl)
+{
+       struct workqueue_struct *wq = cl->wq;
+       if (wq) {
+               INIT_WORK(&cl->work, cl->work.func);
+               BUG_ON(!queue_work(wq, &cl->work));
+       } else
+               cl->fn(cl);
+}
 
 /**
- * __closure_init() - Initialize a closure, skipping the memset()
- *
- * May be used instead of closure_init() when memory has already been zeroed.
+ * closure_get - increment a closure's refcount
  */
-#define __closure_init(cl, parent)                             \
-       closure_init_type(cl, parent, true)
+static inline void closure_get(struct closure *cl)
+{
+#ifdef CONFIG_BCACHE_CLOSURES_DEBUG
+       BUG_ON((atomic_inc_return(&cl->remaining) &
+               CLOSURE_REMAINING_MASK) <= 1);
+#else
+       atomic_inc(&cl->remaining);
+#endif
+}
 
 /**
- * closure_init() - Initialize a closure, setting the refcount to 1
+ * closure_init - Initialize a closure, setting the refcount to 1
  * @cl:                closure to initialize
  * @parent:    parent of the new closure. cl will take a refcount on it for its
  *             lifetime; may be NULL.
  */
-#define closure_init(cl, parent)                               \
-do {                                                           \
-       memset((cl), 0, sizeof(*(cl)));                         \
-       __closure_init(cl, parent);                             \
-} while (0)
-
-static inline void closure_init_stack(struct closure *cl)
+static inline void closure_init(struct closure *cl, struct closure *parent)
 {
        memset(cl, 0, sizeof(struct closure));
-       atomic_set(&cl->remaining, CLOSURE_REMAINING_INITIALIZER|CLOSURE_STACK);
-}
-
-/**
- * closure_init_unlocked() - Initialize a closure but leave it unlocked.
- * @cl:                closure to initialize
- *
- * For when the closure will be used as a lock. The closure may not be used
- * until after a closure_lock() or closure_trylock().
- */
-#define closure_init_unlocked(cl)                              \
-do {                                                           \
-       memset((cl), 0, sizeof(*(cl)));                         \
-       closure_init_type(cl, NULL, false);                     \
-} while (0)
-
-/**
- * closure_lock() - lock and initialize a closure.
- * @cl:                the closure to lock
- * @parent:    the new parent for this closure
- *
- * The closure must be of one of the types that has a waitlist (otherwise we
- * wouldn't be able to sleep on contention).
- *
- * @parent has exactly the same meaning as in closure_init(); if non null, the
- * closure will take a reference on @parent which will be released when it is
- * unlocked.
- */
-#define closure_lock(cl, parent)                               \
-       __closure_lock(__to_internal_closure(cl), parent, &(cl)->wait)
+       cl->parent = parent;
+       if (parent)
+               closure_get(parent);
 
-static inline void __closure_end_sleep(struct closure *cl)
-{
-       __set_current_state(TASK_RUNNING);
+       atomic_set(&cl->remaining, CLOSURE_REMAINING_INITIALIZER);
 
-       if (atomic_read(&cl->remaining) & CLOSURE_SLEEPING)
-               atomic_sub(CLOSURE_SLEEPING, &cl->remaining);
+       closure_debug_create(cl);
+       closure_set_ip(cl);
 }
 
-static inline void __closure_start_sleep(struct closure *cl)
+static inline void closure_init_stack(struct closure *cl)
 {
-       closure_set_ip(cl);
-       cl->task = current;
-       set_current_state(TASK_UNINTERRUPTIBLE);
-
-       if (!(atomic_read(&cl->remaining) & CLOSURE_SLEEPING))
-               atomic_add(CLOSURE_SLEEPING, &cl->remaining);
+       memset(cl, 0, sizeof(struct closure));
+       atomic_set(&cl->remaining, CLOSURE_REMAINING_INITIALIZER|CLOSURE_STACK);
 }
 
 /**
- * closure_wake_up() - wake up all closures on a wait list.
+ * closure_wake_up - wake up all closures on a wait list.
  */
 static inline void closure_wake_up(struct closure_waitlist *list)
 {
@@ -428,69 +303,19 @@ static inline void closure_wake_up(struct closure_waitlist *list)
        __closure_wake_up(list);
 }
 
-/*
- * Wait on an event, synchronously or asynchronously - analogous to wait_event()
- * but for closures.
- *
- * The loop is oddly structured so as to avoid a race; we must check the
- * condition again after we've added ourself to the waitlist. We know if we were
- * already on the waitlist because closure_wait() returns false; thus, we only
- * schedule or break if closure_wait() returns false. If it returns true, we
- * just loop again - rechecking the condition.
- *
- * The __closure_wake_up() is necessary because we may race with the event
- * becoming true; i.e. we see event false -> wait -> recheck condition, but the
- * thread that made the event true may have called closure_wake_up() before we
- * added ourself to the wait list.
- *
- * We have to call closure_sync() at the end instead of just
- * __closure_end_sleep() because a different thread might've called
- * closure_wake_up() before us and gotten preempted before they dropped the
- * refcount on our closure. If this was a stack allocated closure, that would be
- * bad.
+/**
+ * continue_at - jump to another function with barrier
+ *
+ * After @cl is no longer waiting on anything (i.e. all outstanding refs have
+ * been dropped with closure_put()), it will resume execution at @fn running out
+ * of @wq (or, if @wq is NULL, @fn will be called by closure_put() directly).
+ *
+ * NOTE: This macro expands to a return in the calling function!
+ *
+ * This is because after calling continue_at() you no longer have a ref on @cl,
+ * and whatever @cl owns may be freed out from under you - a running closure fn
+ * has a ref on its own closure which continue_at() drops.
  */
-#define closure_wait_event(list, cl, condition)                                \
-({                                                                     \
-       typeof(condition) ret;                                          \
-                                                                       \
-       while (1) {                                                     \
-               ret = (condition);                                      \
-               if (ret) {                                              \
-                       __closure_wake_up(list);                        \
-                       closure_sync(cl);                               \
-                       break;                                          \
-               }                                                       \
-                                                                       \
-               __closure_start_sleep(cl);                              \
-                                                                       \
-               if (!closure_wait(list, cl))                            \
-                       schedule();                                     \
-       }                                                               \
-                                                                       \
-       ret;                                                            \
-})
-
-static inline void closure_queue(struct closure *cl)
-{
-       struct workqueue_struct *wq = cl->wq;
-       if (wq) {
-               INIT_WORK(&cl->work, cl->work.func);
-               BUG_ON(!queue_work(wq, &cl->work));
-       } else
-               cl->fn(cl);
-}
-
-static inline void set_closure_fn(struct closure *cl, closure_fn *fn,
-                                 struct workqueue_struct *wq)
-{
-       BUG_ON(object_is_on_stack(cl));
-       closure_set_ip(cl);
-       cl->fn = fn;
-       cl->wq = wq;
-       /* between atomic_dec() in closure_put() */
-       smp_mb__before_atomic_dec();
-}
-
 #define continue_at(_cl, _fn, _wq)                                     \
 do {                                                                   \
        set_closure_fn(_cl, _fn, _wq);                                  \
@@ -498,8 +323,28 @@ do {                                                                       \
        return;                                                         \
 } while (0)
 
+/**
+ * closure_return - finish execution of a closure
+ *
+ * This is used to indicate that @cl is finished: when all outstanding refs on
+ * @cl have been dropped @cl's ref on its parent closure (as passed to
+ * closure_init()) will be dropped, if one was specified - thus this can be
+ * thought of as returning to the parent closure.
+ */
 #define closure_return(_cl)    continue_at((_cl), NULL, NULL)
 
+/**
+ * continue_at_nobarrier - jump to another function without barrier
+ *
+ * Causes @fn to be executed out of @cl, in @wq context (or called directly if
+ * @wq is NULL).
+ *
+ * NOTE: like continue_at(), this macro expands to a return in the caller!
+ *
+ * The ref the caller of continue_at_nobarrier() had on @cl is now owned by @fn,
+ * thus it's not safe to touch anything protected by @cl after a
+ * continue_at_nobarrier().
+ */
 #define continue_at_nobarrier(_cl, _fn, _wq)                           \
 do {                                                                   \
        set_closure_fn(_cl, _fn, _wq);                                  \
@@ -507,6 +352,15 @@ do {                                                                       \
        return;                                                         \
 } while (0)
 
+/**
+ * closure_return - finish execution of a closure, with destructor
+ *
+ * Works like closure_return(), except @destructor will be called when all
+ * outstanding refs on @cl have been dropped; @destructor may be used to safely
+ * free the memory occupied by @cl, and it is called with the ref on the parent
+ * closure still held - so @destructor could safely return an item to a
+ * freelist protected by @cl's parent.
+ */
 #define closure_return_with_destructor(_cl, _destructor)               \
 do {                                                                   \
        set_closure_fn(_cl, _destructor, NULL);                         \
@@ -514,6 +368,13 @@ do {                                                                       \
        return;                                                         \
 } while (0)
 
+/**
+ * closure_call - execute @fn out of a new, uninitialized closure
+ *
+ * Typically used when running out of one closure, and we want to run @fn
+ * asynchronously out of a new closure - @parent will then wait for @cl to
+ * finish.
+ */
 static inline void closure_call(struct closure *cl, closure_fn fn,
                                struct workqueue_struct *wq,
                                struct closure *parent)
@@ -522,12 +383,4 @@ static inline void closure_call(struct closure *cl, closure_fn fn,
        continue_at_nobarrier(cl, fn, wq);
 }
 
-static inline void closure_trylock_call(struct closure *cl, closure_fn fn,
-                                       struct workqueue_struct *wq,
-                                       struct closure *parent)
-{
-       if (closure_trylock(cl, parent))
-               continue_at_nobarrier(cl, fn, wq);
-}
-
 #endif /* _LINUX_CLOSURE_H */
index 264fcfbd629016aa1ab890cce56de2699c49be70..8b1f1d5c18198f078dea917f40303c98fce1ee94 100644 (file)
@@ -8,6 +8,7 @@
 #include "bcache.h"
 #include "btree.h"
 #include "debug.h"
+#include "extents.h"
 
 #include <linux/console.h>
 #include <linux/debugfs.h>
 
 static struct dentry *debug;
 
-const char *bch_ptr_status(struct cache_set *c, const struct bkey *k)
-{
-       unsigned i;
-
-       for (i = 0; i < KEY_PTRS(k); i++)
-               if (ptr_available(c, k, i)) {
-                       struct cache *ca = PTR_CACHE(c, k, i);
-                       size_t bucket = PTR_BUCKET_NR(c, k, i);
-                       size_t r = bucket_remainder(c, PTR_OFFSET(k, i));
-
-                       if (KEY_SIZE(k) + r > c->sb.bucket_size)
-                               return "bad, length too big";
-                       if (bucket <  ca->sb.first_bucket)
-                               return "bad, short offset";
-                       if (bucket >= ca->sb.nbuckets)
-                               return "bad, offset past end of device";
-                       if (ptr_stale(c, k, i))
-                               return "stale";
-               }
-
-       if (!bkey_cmp(k, &ZERO_KEY))
-               return "bad, null key";
-       if (!KEY_PTRS(k))
-               return "bad, no pointers";
-       if (!KEY_SIZE(k))
-               return "zeroed key";
-       return "";
-}
-
-int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k)
-{
-       unsigned i = 0;
-       char *out = buf, *end = buf + size;
-
-#define p(...) (out += scnprintf(out, end - out, __VA_ARGS__))
-
-       p("%llu:%llu len %llu -> [", KEY_INODE(k), KEY_OFFSET(k), KEY_SIZE(k));
-
-       if (KEY_PTRS(k))
-               while (1) {
-                       p("%llu:%llu gen %llu",
-                         PTR_DEV(k, i), PTR_OFFSET(k, i), PTR_GEN(k, i));
-
-                       if (++i == KEY_PTRS(k))
-                               break;
-
-                       p(", ");
-               }
-
-       p("]");
-
-       if (KEY_DIRTY(k))
-               p(" dirty");
-       if (KEY_CSUM(k))
-               p(" cs%llu %llx", KEY_CSUM(k), k->ptr[1]);
-#undef p
-       return out - buf;
-}
-
 #ifdef CONFIG_BCACHE_DEBUG
 
-static void dump_bset(struct btree *b, struct bset *i)
-{
-       struct bkey *k, *next;
-       unsigned j;
-       char buf[80];
-
-       for (k = i->start; k < end(i); k = next) {
-               next = bkey_next(k);
-
-               bch_bkey_to_text(buf, sizeof(buf), k);
-               printk(KERN_ERR "block %zu key %zi/%u: %s", index(i, b),
-                      (uint64_t *) k - i->d, i->keys, buf);
-
-               for (j = 0; j < KEY_PTRS(k); j++) {
-                       size_t n = PTR_BUCKET_NR(b->c, k, j);
-                       printk(" bucket %zu", n);
-
-                       if (n >= b->c->sb.first_bucket && n < b->c->sb.nbuckets)
-                               printk(" prio %i",
-                                      PTR_BUCKET(b->c, k, j)->prio);
-               }
+#define for_each_written_bset(b, start, i)                             \
+       for (i = (start);                                               \
+            (void *) i < (void *) (start) + (KEY_SIZE(&b->key) << 9) &&\
+            i->seq == (start)->seq;                                    \
+            i = (void *) i + set_blocks(i, block_bytes(b->c)) *        \
+                block_bytes(b->c))
 
-               printk(" %s\n", bch_ptr_status(b->c, k));
-
-               if (next < end(i) &&
-                   bkey_cmp(k, !b->level ? &START_KEY(next) : next) > 0)
-                       printk(KERN_ERR "Key skipped backwards\n");
-       }
-}
-
-static void bch_dump_bucket(struct btree *b)
-{
-       unsigned i;
-
-       console_lock();
-       for (i = 0; i <= b->nsets; i++)
-               dump_bset(b, b->sets[i].data);
-       console_unlock();
-}
-
-void bch_btree_verify(struct btree *b, struct bset *new)
+void bch_btree_verify(struct btree *b)
 {
        struct btree *v = b->c->verify_data;
-       struct closure cl;
-       closure_init_stack(&cl);
+       struct bset *ondisk, *sorted, *inmemory;
+       struct bio *bio;
 
-       if (!b->c->verify)
+       if (!b->c->verify || !b->c->verify_ondisk)
                return;
 
-       closure_wait_event(&b->io.wait, &cl,
-                          atomic_read(&b->io.cl.remaining) == -1);
-
+       down(&b->io_mutex);
        mutex_lock(&b->c->verify_lock);
 
+       ondisk = b->c->verify_ondisk;
+       sorted = b->c->verify_data->keys.set->data;
+       inmemory = b->keys.set->data;
+
        bkey_copy(&v->key, &b->key);
        v->written = 0;
        v->level = b->level;
+       v->keys.ops = b->keys.ops;
+
+       bio = bch_bbio_alloc(b->c);
+       bio->bi_bdev            = PTR_CACHE(b->c, &b->key, 0)->bdev;
+       bio->bi_iter.bi_sector  = PTR_OFFSET(&b->key, 0);
+       bio->bi_iter.bi_size    = KEY_SIZE(&v->key) << 9;
+       bch_bio_map(bio, sorted);
 
-       bch_btree_node_read(v);
-       closure_wait_event(&v->io.wait, &cl,
-                          atomic_read(&b->io.cl.remaining) == -1);
+       submit_bio_wait(REQ_META|READ_SYNC, bio);
+       bch_bbio_free(bio, b->c);
 
-       if (new->keys != v->sets[0].data->keys ||
-           memcmp(new->start,
-                  v->sets[0].data->start,
-                  (void *) end(new) - (void *) new->start)) {
-               unsigned i, j;
+       memcpy(ondisk, sorted, KEY_SIZE(&v->key) << 9);
+
+       bch_btree_node_read_done(v);
+       sorted = v->keys.set->data;
+
+       if (inmemory->keys != sorted->keys ||
+           memcmp(inmemory->start,
+                  sorted->start,
+                  (void *) bset_bkey_last(inmemory) - (void *) inmemory->start)) {
+               struct bset *i;
+               unsigned j;
 
                console_lock();
 
-               printk(KERN_ERR "*** original memory node:\n");
-               for (i = 0; i <= b->nsets; i++)
-                       dump_bset(b, b->sets[i].data);
+               printk(KERN_ERR "*** in memory:\n");
+               bch_dump_bset(&b->keys, inmemory, 0);
 
-               printk(KERN_ERR "*** sorted memory node:\n");
-               dump_bset(b, new);
+               printk(KERN_ERR "*** read back in:\n");
+               bch_dump_bset(&v->keys, sorted, 0);
 
-               printk(KERN_ERR "*** on disk node:\n");
-               dump_bset(v, v->sets[0].data);
+               for_each_written_bset(b, ondisk, i) {
+                       unsigned block = ((void *) i - (void *) ondisk) /
+                               block_bytes(b->c);
+
+                       printk(KERN_ERR "*** on disk block %u:\n", block);
+                       bch_dump_bset(&b->keys, i, block);
+               }
 
-               for (j = 0; j < new->keys; j++)
-                       if (new->d[j] != v->sets[0].data->d[j])
+               printk(KERN_ERR "*** block %zu not written\n",
+                      ((void *) i - (void *) ondisk) / block_bytes(b->c));
+
+               for (j = 0; j < inmemory->keys; j++)
+                       if (inmemory->d[j] != sorted->d[j])
                                break;
 
+               printk(KERN_ERR "b->written %u\n", b->written);
+
                console_unlock();
                panic("verify failed at %u\n", j);
        }
 
        mutex_unlock(&b->c->verify_lock);
+       up(&b->io_mutex);
 }
 
 void bch_data_verify(struct cached_dev *dc, struct bio *bio)
 {
        char name[BDEVNAME_SIZE];
        struct bio *check;
-       struct bio_vec *bv;
+       struct bio_vec bv, *bv2;
+       struct bvec_iter iter;
        int i;
 
        check = bio_clone(bio, GFP_NOIO);
@@ -185,95 +119,27 @@ void bch_data_verify(struct cached_dev *dc, struct bio *bio)
 
        submit_bio_wait(READ_SYNC, check);
 
-       bio_for_each_segment(bv, bio, i) {
-               void *p1 = kmap_atomic(bv->bv_page);
-               void *p2 = page_address(check->bi_io_vec[i].bv_page);
+       bio_for_each_segment(bv, bio, iter) {
+               void *p1 = kmap_atomic(bv.bv_page);
+               void *p2 = page_address(check->bi_io_vec[iter.bi_idx].bv_page);
 
-               cache_set_err_on(memcmp(p1 + bv->bv_offset,
-                                       p2 + bv->bv_offset,
-                                       bv->bv_len),
+               cache_set_err_on(memcmp(p1 + bv.bv_offset,
+                                       p2 + bv.bv_offset,
+                                       bv.bv_len),
                                 dc->disk.c,
                                 "verify failed at dev %s sector %llu",
                                 bdevname(dc->bdev, name),
-                                (uint64_t) bio->bi_sector);
+                                (uint64_t) bio->bi_iter.bi_sector);
 
                kunmap_atomic(p1);
        }
 
-       bio_for_each_segment_all(bv, check, i)
-               __free_page(bv->bv_page);
+       bio_for_each_segment_all(bv2, check, i)
+               __free_page(bv2->bv_page);
 out_put:
        bio_put(check);
 }
 
-int __bch_count_data(struct btree *b)
-{
-       unsigned ret = 0;
-       struct btree_iter iter;
-       struct bkey *k;
-
-       if (!b->level)
-               for_each_key(b, k, &iter)
-                       ret += KEY_SIZE(k);
-       return ret;
-}
-
-void __bch_check_keys(struct btree *b, const char *fmt, ...)
-{
-       va_list args;
-       struct bkey *k, *p = NULL;
-       struct btree_iter iter;
-       const char *err;
-
-       for_each_key(b, k, &iter) {
-               if (!b->level) {
-                       err = "Keys out of order";
-                       if (p && bkey_cmp(&START_KEY(p), &START_KEY(k)) > 0)
-                               goto bug;
-
-                       if (bch_ptr_invalid(b, k))
-                               continue;
-
-                       err =  "Overlapping keys";
-                       if (p && bkey_cmp(p, &START_KEY(k)) > 0)
-                               goto bug;
-               } else {
-                       if (bch_ptr_bad(b, k))
-                               continue;
-
-                       err = "Duplicate keys";
-                       if (p && !bkey_cmp(p, k))
-                               goto bug;
-               }
-               p = k;
-       }
-
-       err = "Key larger than btree node key";
-       if (p && bkey_cmp(p, &b->key) > 0)
-               goto bug;
-
-       return;
-bug:
-       bch_dump_bucket(b);
-
-       va_start(args, fmt);
-       vprintk(fmt, args);
-       va_end(args);
-
-       panic("bcache error: %s:\n", err);
-}
-
-void bch_btree_iter_next_check(struct btree_iter *iter)
-{
-       struct bkey *k = iter->data->k, *next = bkey_next(k);
-
-       if (next < iter->data->end &&
-           bkey_cmp(k, iter->b->level ? next : &START_KEY(next)) > 0) {
-               bch_dump_bucket(iter->b);
-               panic("Key skipped backwards\n");
-       }
-}
-
 #endif
 
 #ifdef CONFIG_DEBUG_FS
@@ -320,7 +186,7 @@ static ssize_t bch_dump_read(struct file *file, char __user *buf,
                if (!w)
                        break;
 
-               bch_bkey_to_text(kbuf, sizeof(kbuf), &w->key);
+               bch_extent_to_text(kbuf, sizeof(kbuf), &w->key);
                i->bytes = snprintf(i->buf, PAGE_SIZE, "%s\n", kbuf);
                bch_keybuf_del(&i->keys, w);
        }
index 2ede60e3187475d114004111ef70c2ebaf4f38af..1f63c195d2476ece1b0c50b6acdddd1a1d92ba8b 100644 (file)
@@ -1,47 +1,30 @@
 #ifndef _BCACHE_DEBUG_H
 #define _BCACHE_DEBUG_H
 
-/* Btree/bkey debug printing */
-
-int bch_bkey_to_text(char *buf, size_t size, const struct bkey *k);
+struct bio;
+struct cached_dev;
+struct cache_set;
 
 #ifdef CONFIG_BCACHE_DEBUG
 
-void bch_btree_verify(struct btree *, struct bset *);
+void bch_btree_verify(struct btree *);
 void bch_data_verify(struct cached_dev *, struct bio *);
-int __bch_count_data(struct btree *);
-void __bch_check_keys(struct btree *, const char *, ...);
-void bch_btree_iter_next_check(struct btree_iter *);
 
-#define EBUG_ON(cond)                  BUG_ON(cond)
 #define expensive_debug_checks(c)      ((c)->expensive_debug_checks)
 #define key_merging_disabled(c)                ((c)->key_merging_disabled)
 #define bypass_torture_test(d)         ((d)->bypass_torture_test)
 
 #else /* DEBUG */
 
-static inline void bch_btree_verify(struct btree *b, struct bset *i) {}
+static inline void bch_btree_verify(struct btree *b) {}
 static inline void bch_data_verify(struct cached_dev *dc, struct bio *bio) {}
-static inline int __bch_count_data(struct btree *b) { return -1; }
-static inline void __bch_check_keys(struct btree *b, const char *fmt, ...) {}
-static inline void bch_btree_iter_next_check(struct btree_iter *iter) {}
 
-#define EBUG_ON(cond)                  do { if (cond); } while (0)
 #define expensive_debug_checks(c)      0
 #define key_merging_disabled(c)                0
 #define bypass_torture_test(d)         0
 
 #endif
 
-#define bch_count_data(b)                                              \
-       (expensive_debug_checks((b)->c) ? __bch_count_data(b) : -1)
-
-#define bch_check_keys(b, ...)                                         \
-do {                                                                   \
-       if (expensive_debug_checks((b)->c))                             \
-               __bch_check_keys(b, __VA_ARGS__);                       \
-} while (0)
-
 #ifdef CONFIG_DEBUG_FS
 void bch_debug_init_cache_set(struct cache_set *);
 #else
diff --git a/drivers/md/bcache/extents.c b/drivers/md/bcache/extents.c
new file mode 100644 (file)
index 0000000..c3ead58
--- /dev/null
@@ -0,0 +1,616 @@
+/*
+ * Copyright (C) 2010 Kent Overstreet <kent.overstreet@gmail.com>
+ *
+ * Uses a block device as cache for other block devices; optimized for SSDs.
+ * All allocation is done in buckets, which should match the erase block size
+ * of the device.
+ *
+ * Buckets containing cached data are kept on a heap sorted by priority;
+ * bucket priority is increased on cache hit, and periodically all the buckets
+ * on the heap have their priority scaled down. This currently is just used as
+ * an LRU but in the future should allow for more intelligent heuristics.
+ *
+ * Buckets have an 8 bit counter; freeing is accomplished by incrementing the
+ * counter. Garbage collection is used to remove stale pointers.
+ *
+ * Indexing is done via a btree; nodes are not necessarily fully sorted, rather
+ * as keys are inserted we only sort the pages that have not yet been written.
+ * When garbage collection is run, we resort the entire node.
+ *
+ * All configuration is done via sysfs; see Documentation/bcache.txt.
+ */
+
+#include "bcache.h"
+#include "btree.h"
+#include "debug.h"
+#include "extents.h"
+#include "writeback.h"
+
+static void sort_key_next(struct btree_iter *iter,
+                         struct btree_iter_set *i)
+{
+       i->k = bkey_next(i->k);
+
+       if (i->k == i->end)
+               *i = iter->data[--iter->used];
+}
+
+static bool bch_key_sort_cmp(struct btree_iter_set l,
+                            struct btree_iter_set r)
+{
+       int64_t c = bkey_cmp(l.k, r.k);
+
+       return c ? c > 0 : l.k < r.k;
+}
+
+static bool __ptr_invalid(struct cache_set *c, const struct bkey *k)
+{
+       unsigned i;
+
+       for (i = 0; i < KEY_PTRS(k); i++)
+               if (ptr_available(c, k, i)) {
+                       struct cache *ca = PTR_CACHE(c, k, i);
+                       size_t bucket = PTR_BUCKET_NR(c, k, i);
+                       size_t r = bucket_remainder(c, PTR_OFFSET(k, i));
+
+                       if (KEY_SIZE(k) + r > c->sb.bucket_size ||
+                           bucket <  ca->sb.first_bucket ||
+                           bucket >= ca->sb.nbuckets)
+                               return true;
+               }
+
+       return false;
+}
+
+/* Common among btree and extent ptrs */
+
+static const char *bch_ptr_status(struct cache_set *c, const struct bkey *k)
+{
+       unsigned i;
+
+       for (i = 0; i < KEY_PTRS(k); i++)
+               if (ptr_available(c, k, i)) {
+                       struct cache *ca = PTR_CACHE(c, k, i);
+                       size_t bucket = PTR_BUCKET_NR(c, k, i);
+                       size_t r = bucket_remainder(c, PTR_OFFSET(k, i));
+
+                       if (KEY_SIZE(k) + r > c->sb.bucket_size)
+                               return "bad, length too big";
+                       if (bucket <  ca->sb.first_bucket)
+                               return "bad, short offset";
+                       if (bucket >= ca->sb.nbuckets)
+                               return "bad, offset past end of device";
+                       if (ptr_stale(c, k, i))
+                               return "stale";
+               }
+
+       if (!bkey_cmp(k, &ZERO_KEY))
+               return "bad, null key";
+       if (!KEY_PTRS(k))
+               return "bad, no pointers";
+       if (!KEY_SIZE(k))
+               return "zeroed key";
+       return "";
+}
+
+void bch_extent_to_text(char *buf, size_t size, const struct bkey *k)
+{
+       unsigned i = 0;
+       char *out = buf, *end = buf + size;
+
+#define p(...) (out += scnprintf(out, end - out, __VA_ARGS__))
+
+       p("%llu:%llu len %llu -> [", KEY_INODE(k), KEY_START(k), KEY_SIZE(k));
+
+       for (i = 0; i < KEY_PTRS(k); i++) {
+               if (i)
+                       p(", ");
+
+               if (PTR_DEV(k, i) == PTR_CHECK_DEV)
+                       p("check dev");
+               else
+                       p("%llu:%llu gen %llu", PTR_DEV(k, i),
+                         PTR_OFFSET(k, i), PTR_GEN(k, i));
+       }
+
+       p("]");
+
+       if (KEY_DIRTY(k))
+               p(" dirty");
+       if (KEY_CSUM(k))
+               p(" cs%llu %llx", KEY_CSUM(k), k->ptr[1]);
+#undef p
+}
+
+static void bch_bkey_dump(struct btree_keys *keys, const struct bkey *k)
+{
+       struct btree *b = container_of(keys, struct btree, keys);
+       unsigned j;
+       char buf[80];
+
+       bch_extent_to_text(buf, sizeof(buf), k);
+       printk(" %s", buf);
+
+       for (j = 0; j < KEY_PTRS(k); j++) {
+               size_t n = PTR_BUCKET_NR(b->c, k, j);
+               printk(" bucket %zu", n);
+
+               if (n >= b->c->sb.first_bucket && n < b->c->sb.nbuckets)
+                       printk(" prio %i",
+                              PTR_BUCKET(b->c, k, j)->prio);
+       }
+
+       printk(" %s\n", bch_ptr_status(b->c, k));
+}
+
+/* Btree ptrs */
+
+bool __bch_btree_ptr_invalid(struct cache_set *c, const struct bkey *k)
+{
+       char buf[80];
+
+       if (!KEY_PTRS(k) || !KEY_SIZE(k) || KEY_DIRTY(k))
+               goto bad;
+
+       if (__ptr_invalid(c, k))
+               goto bad;
+
+       return false;
+bad:
+       bch_extent_to_text(buf, sizeof(buf), k);
+       cache_bug(c, "spotted btree ptr %s: %s", buf, bch_ptr_status(c, k));
+       return true;
+}
+
+static bool bch_btree_ptr_invalid(struct btree_keys *bk, const struct bkey *k)
+{
+       struct btree *b = container_of(bk, struct btree, keys);
+       return __bch_btree_ptr_invalid(b->c, k);
+}
+
+static bool btree_ptr_bad_expensive(struct btree *b, const struct bkey *k)
+{
+       unsigned i;
+       char buf[80];
+       struct bucket *g;
+
+       if (mutex_trylock(&b->c->bucket_lock)) {
+               for (i = 0; i < KEY_PTRS(k); i++)
+                       if (ptr_available(b->c, k, i)) {
+                               g = PTR_BUCKET(b->c, k, i);
+
+                               if (KEY_DIRTY(k) ||
+                                   g->prio != BTREE_PRIO ||
+                                   (b->c->gc_mark_valid &&
+                                    GC_MARK(g) != GC_MARK_METADATA))
+                                       goto err;
+                       }
+
+               mutex_unlock(&b->c->bucket_lock);
+       }
+
+       return false;
+err:
+       mutex_unlock(&b->c->bucket_lock);
+       bch_extent_to_text(buf, sizeof(buf), k);
+       btree_bug(b,
+"inconsistent btree pointer %s: bucket %li pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
+                 buf, PTR_BUCKET_NR(b->c, k, i), atomic_read(&g->pin),
+                 g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
+       return true;
+}
+
+static bool bch_btree_ptr_bad(struct btree_keys *bk, const struct bkey *k)
+{
+       struct btree *b = container_of(bk, struct btree, keys);
+       unsigned i;
+
+       if (!bkey_cmp(k, &ZERO_KEY) ||
+           !KEY_PTRS(k) ||
+           bch_ptr_invalid(bk, k))
+               return true;
+
+       for (i = 0; i < KEY_PTRS(k); i++)
+               if (!ptr_available(b->c, k, i) ||
+                   ptr_stale(b->c, k, i))
+                       return true;
+
+       if (expensive_debug_checks(b->c) &&
+           btree_ptr_bad_expensive(b, k))
+               return true;
+
+       return false;
+}
+
+static bool bch_btree_ptr_insert_fixup(struct btree_keys *bk,
+                                      struct bkey *insert,
+                                      struct btree_iter *iter,
+                                      struct bkey *replace_key)
+{
+       struct btree *b = container_of(bk, struct btree, keys);
+
+       if (!KEY_OFFSET(insert))
+               btree_current_write(b)->prio_blocked++;
+
+       return false;
+}
+
+const struct btree_keys_ops bch_btree_keys_ops = {
+       .sort_cmp       = bch_key_sort_cmp,
+       .insert_fixup   = bch_btree_ptr_insert_fixup,
+       .key_invalid    = bch_btree_ptr_invalid,
+       .key_bad        = bch_btree_ptr_bad,
+       .key_to_text    = bch_extent_to_text,
+       .key_dump       = bch_bkey_dump,
+};
+
+/* Extents */
+
+/*
+ * Returns true if l > r - unless l == r, in which case returns true if l is
+ * older than r.
+ *
+ * Necessary for btree_sort_fixup() - if there are multiple keys that compare
+ * equal in different sets, we have to process them newest to oldest.
+ */
+static bool bch_extent_sort_cmp(struct btree_iter_set l,
+                               struct btree_iter_set r)
+{
+       int64_t c = bkey_cmp(&START_KEY(l.k), &START_KEY(r.k));
+
+       return c ? c > 0 : l.k < r.k;
+}
+
+static struct bkey *bch_extent_sort_fixup(struct btree_iter *iter,
+                                         struct bkey *tmp)
+{
+       while (iter->used > 1) {
+               struct btree_iter_set *top = iter->data, *i = top + 1;
+
+               if (iter->used > 2 &&
+                   bch_extent_sort_cmp(i[0], i[1]))
+                       i++;
+
+               if (bkey_cmp(top->k, &START_KEY(i->k)) <= 0)
+                       break;
+
+               if (!KEY_SIZE(i->k)) {
+                       sort_key_next(iter, i);
+                       heap_sift(iter, i - top, bch_extent_sort_cmp);
+                       continue;
+               }
+
+               if (top->k > i->k) {
+                       if (bkey_cmp(top->k, i->k) >= 0)
+                               sort_key_next(iter, i);
+                       else
+                               bch_cut_front(top->k, i->k);
+
+                       heap_sift(iter, i - top, bch_extent_sort_cmp);
+               } else {
+                       /* can't happen because of comparison func */
+                       BUG_ON(!bkey_cmp(&START_KEY(top->k), &START_KEY(i->k)));
+
+                       if (bkey_cmp(i->k, top->k) < 0) {
+                               bkey_copy(tmp, top->k);
+
+                               bch_cut_back(&START_KEY(i->k), tmp);
+                               bch_cut_front(i->k, top->k);
+                               heap_sift(iter, 0, bch_extent_sort_cmp);
+
+                               return tmp;
+                       } else {
+                               bch_cut_back(&START_KEY(i->k), top->k);
+                       }
+               }
+       }
+
+       return NULL;
+}
+
+static bool bch_extent_insert_fixup(struct btree_keys *b,
+                                   struct bkey *insert,
+                                   struct btree_iter *iter,
+                                   struct bkey *replace_key)
+{
+       struct cache_set *c = container_of(b, struct btree, keys)->c;
+
+       void subtract_dirty(struct bkey *k, uint64_t offset, int sectors)
+       {
+               if (KEY_DIRTY(k))
+                       bcache_dev_sectors_dirty_add(c, KEY_INODE(k),
+                                                    offset, -sectors);
+       }
+
+       uint64_t old_offset;
+       unsigned old_size, sectors_found = 0;
+
+       BUG_ON(!KEY_OFFSET(insert));
+       BUG_ON(!KEY_SIZE(insert));
+
+       while (1) {
+               struct bkey *k = bch_btree_iter_next(iter);
+               if (!k)
+                       break;
+
+               if (bkey_cmp(&START_KEY(k), insert) >= 0) {
+                       if (KEY_SIZE(k))
+                               break;
+                       else
+                               continue;
+               }
+
+               if (bkey_cmp(k, &START_KEY(insert)) <= 0)
+                       continue;
+
+               old_offset = KEY_START(k);
+               old_size = KEY_SIZE(k);
+
+               /*
+                * We might overlap with 0 size extents; we can't skip these
+                * because if they're in the set we're inserting to we have to
+                * adjust them so they don't overlap with the key we're
+                * inserting. But we don't want to check them for replace
+                * operations.
+                */
+
+               if (replace_key && KEY_SIZE(k)) {
+                       /*
+                        * k might have been split since we inserted/found the
+                        * key we're replacing
+                        */
+                       unsigned i;
+                       uint64_t offset = KEY_START(k) -
+                               KEY_START(replace_key);
+
+                       /* But it must be a subset of the replace key */
+                       if (KEY_START(k) < KEY_START(replace_key) ||
+                           KEY_OFFSET(k) > KEY_OFFSET(replace_key))
+                               goto check_failed;
+
+                       /* We didn't find a key that we were supposed to */
+                       if (KEY_START(k) > KEY_START(insert) + sectors_found)
+                               goto check_failed;
+
+                       if (!bch_bkey_equal_header(k, replace_key))
+                               goto check_failed;
+
+                       /* skip past gen */
+                       offset <<= 8;
+
+                       BUG_ON(!KEY_PTRS(replace_key));
+
+                       for (i = 0; i < KEY_PTRS(replace_key); i++)
+                               if (k->ptr[i] != replace_key->ptr[i] + offset)
+                                       goto check_failed;
+
+                       sectors_found = KEY_OFFSET(k) - KEY_START(insert);
+               }
+
+               if (bkey_cmp(insert, k) < 0 &&
+                   bkey_cmp(&START_KEY(insert), &START_KEY(k)) > 0) {
+                       /*
+                        * We overlapped in the middle of an existing key: that
+                        * means we have to split the old key. But we have to do
+                        * slightly different things depending on whether the
+                        * old key has been written out yet.
+                        */
+
+                       struct bkey *top;
+
+                       subtract_dirty(k, KEY_START(insert), KEY_SIZE(insert));
+
+                       if (bkey_written(b, k)) {
+                               /*
+                                * We insert a new key to cover the top of the
+                                * old key, and the old key is modified in place
+                                * to represent the bottom split.
+                                *
+                                * It's completely arbitrary whether the new key
+                                * is the top or the bottom, but it has to match
+                                * up with what btree_sort_fixup() does - it
+                                * doesn't check for this kind of overlap, it
+                                * depends on us inserting a new key for the top
+                                * here.
+                                */
+                               top = bch_bset_search(b, bset_tree_last(b),
+                                                     insert);
+                               bch_bset_insert(b, top, k);
+                       } else {
+                               BKEY_PADDED(key) temp;
+                               bkey_copy(&temp.key, k);
+                               bch_bset_insert(b, k, &temp.key);
+                               top = bkey_next(k);
+                       }
+
+                       bch_cut_front(insert, top);
+                       bch_cut_back(&START_KEY(insert), k);
+                       bch_bset_fix_invalidated_key(b, k);
+                       goto out;
+               }
+
+               if (bkey_cmp(insert, k) < 0) {
+                       bch_cut_front(insert, k);
+               } else {
+                       if (bkey_cmp(&START_KEY(insert), &START_KEY(k)) > 0)
+                               old_offset = KEY_START(insert);
+
+                       if (bkey_written(b, k) &&
+                           bkey_cmp(&START_KEY(insert), &START_KEY(k)) <= 0) {
+                               /*
+                                * Completely overwrote, so we don't have to
+                                * invalidate the binary search tree
+                                */
+                               bch_cut_front(k, k);
+                       } else {
+                               __bch_cut_back(&START_KEY(insert), k);
+                               bch_bset_fix_invalidated_key(b, k);
+                       }
+               }
+
+               subtract_dirty(k, old_offset, old_size - KEY_SIZE(k));
+       }
+
+check_failed:
+       if (replace_key) {
+               if (!sectors_found) {
+                       return true;
+               } else if (sectors_found < KEY_SIZE(insert)) {
+                       SET_KEY_OFFSET(insert, KEY_OFFSET(insert) -
+                                      (KEY_SIZE(insert) - sectors_found));
+                       SET_KEY_SIZE(insert, sectors_found);
+               }
+       }
+out:
+       if (KEY_DIRTY(insert))
+               bcache_dev_sectors_dirty_add(c, KEY_INODE(insert),
+                                            KEY_START(insert),
+                                            KEY_SIZE(insert));
+
+       return false;
+}
+
+static bool bch_extent_invalid(struct btree_keys *bk, const struct bkey *k)
+{
+       struct btree *b = container_of(bk, struct btree, keys);
+       char buf[80];
+
+       if (!KEY_SIZE(k))
+               return true;
+
+       if (KEY_SIZE(k) > KEY_OFFSET(k))
+               goto bad;
+
+       if (__ptr_invalid(b->c, k))
+               goto bad;
+
+       return false;
+bad:
+       bch_extent_to_text(buf, sizeof(buf), k);
+       cache_bug(b->c, "spotted extent %s: %s", buf, bch_ptr_status(b->c, k));
+       return true;
+}
+
+static bool bch_extent_bad_expensive(struct btree *b, const struct bkey *k,
+                                    unsigned ptr)
+{
+       struct bucket *g = PTR_BUCKET(b->c, k, ptr);
+       char buf[80];
+
+       if (mutex_trylock(&b->c->bucket_lock)) {
+               if (b->c->gc_mark_valid &&
+                   ((GC_MARK(g) != GC_MARK_DIRTY &&
+                     KEY_DIRTY(k)) ||
+                    GC_MARK(g) == GC_MARK_METADATA))
+                       goto err;
+
+               if (g->prio == BTREE_PRIO)
+                       goto err;
+
+               mutex_unlock(&b->c->bucket_lock);
+       }
+
+       return false;
+err:
+       mutex_unlock(&b->c->bucket_lock);
+       bch_extent_to_text(buf, sizeof(buf), k);
+       btree_bug(b,
+"inconsistent extent pointer %s:\nbucket %zu pin %i prio %i gen %i last_gc %i mark %llu gc_gen %i",
+                 buf, PTR_BUCKET_NR(b->c, k, ptr), atomic_read(&g->pin),
+                 g->prio, g->gen, g->last_gc, GC_MARK(g), g->gc_gen);
+       return true;
+}
+
+static bool bch_extent_bad(struct btree_keys *bk, const struct bkey *k)
+{
+       struct btree *b = container_of(bk, struct btree, keys);
+       struct bucket *g;
+       unsigned i, stale;
+
+       if (!KEY_PTRS(k) ||
+           bch_extent_invalid(bk, k))
+               return true;
+
+       for (i = 0; i < KEY_PTRS(k); i++)
+               if (!ptr_available(b->c, k, i))
+                       return true;
+
+       if (!expensive_debug_checks(b->c) && KEY_DIRTY(k))
+               return false;
+
+       for (i = 0; i < KEY_PTRS(k); i++) {
+               g = PTR_BUCKET(b->c, k, i);
+               stale = ptr_stale(b->c, k, i);
+
+               btree_bug_on(stale > 96, b,
+                            "key too stale: %i, need_gc %u",
+                            stale, b->c->need_gc);
+
+               btree_bug_on(stale && KEY_DIRTY(k) && KEY_SIZE(k),
+                            b, "stale dirty pointer");
+
+               if (stale)
+                       return true;
+
+               if (expensive_debug_checks(b->c) &&
+                   bch_extent_bad_expensive(b, k, i))
+                       return true;
+       }
+
+       return false;
+}
+
+static uint64_t merge_chksums(struct bkey *l, struct bkey *r)
+{
+       return (l->ptr[KEY_PTRS(l)] + r->ptr[KEY_PTRS(r)]) &
+               ~((uint64_t)1 << 63);
+}
+
+static bool bch_extent_merge(struct btree_keys *bk, struct bkey *l, struct bkey *r)
+{
+       struct btree *b = container_of(bk, struct btree, keys);
+       unsigned i;
+
+       if (key_merging_disabled(b->c))
+               return false;
+
+       for (i = 0; i < KEY_PTRS(l); i++)
+               if (l->ptr[i] + PTR(0, KEY_SIZE(l), 0) != r->ptr[i] ||
+                   PTR_BUCKET_NR(b->c, l, i) != PTR_BUCKET_NR(b->c, r, i))
+                       return false;
+
+       /* Keys with no pointers aren't restricted to one bucket and could
+        * overflow KEY_SIZE
+        */
+       if (KEY_SIZE(l) + KEY_SIZE(r) > USHRT_MAX) {
+               SET_KEY_OFFSET(l, KEY_OFFSET(l) + USHRT_MAX - KEY_SIZE(l));
+               SET_KEY_SIZE(l, USHRT_MAX);
+
+               bch_cut_front(l, r);
+               return false;
+       }
+
+       if (KEY_CSUM(l)) {
+               if (KEY_CSUM(r))
+                       l->ptr[KEY_PTRS(l)] = merge_chksums(l, r);
+               else
+                       SET_KEY_CSUM(l, 0);
+       }
+
+       SET_KEY_OFFSET(l, KEY_OFFSET(l) + KEY_SIZE(r));
+       SET_KEY_SIZE(l, KEY_SIZE(l) + KEY_SIZE(r));
+
+       return true;
+}
+
+const struct btree_keys_ops bch_extent_keys_ops = {
+       .sort_cmp       = bch_extent_sort_cmp,
+       .sort_fixup     = bch_extent_sort_fixup,
+       .insert_fixup   = bch_extent_insert_fixup,
+       .key_invalid    = bch_extent_invalid,
+       .key_bad        = bch_extent_bad,
+       .key_merge      = bch_extent_merge,
+       .key_to_text    = bch_extent_to_text,
+       .key_dump       = bch_bkey_dump,
+       .is_extents     = true,
+};
diff --git a/drivers/md/bcache/extents.h b/drivers/md/bcache/extents.h
new file mode 100644 (file)
index 0000000..e4e2340
--- /dev/null
@@ -0,0 +1,13 @@
+#ifndef _BCACHE_EXTENTS_H
+#define _BCACHE_EXTENTS_H
+
+extern const struct btree_keys_ops bch_btree_keys_ops;
+extern const struct btree_keys_ops bch_extent_keys_ops;
+
+struct bkey;
+struct cache_set;
+
+void bch_extent_to_text(char *, size_t, const struct bkey *);
+bool __bch_btree_ptr_invalid(struct cache_set *, const struct bkey *);
+
+#endif /* _BCACHE_EXTENTS_H */
index 9056632995b1b8a2de9de607c60cd693704c9c65..fa028fa82df41bf509e15d140f9b3b943c5a8c2d 100644 (file)
 
 #include <linux/blkdev.h>
 
-static void bch_bi_idx_hack_endio(struct bio *bio, int error)
-{
-       struct bio *p = bio->bi_private;
-
-       bio_endio(p, error);
-       bio_put(bio);
-}
-
-static void bch_generic_make_request_hack(struct bio *bio)
-{
-       if (bio->bi_idx) {
-               struct bio *clone = bio_alloc(GFP_NOIO, bio_segments(bio));
-
-               memcpy(clone->bi_io_vec,
-                      bio_iovec(bio),
-                      bio_segments(bio) * sizeof(struct bio_vec));
-
-               clone->bi_sector        = bio->bi_sector;
-               clone->bi_bdev          = bio->bi_bdev;
-               clone->bi_rw            = bio->bi_rw;
-               clone->bi_vcnt          = bio_segments(bio);
-               clone->bi_size          = bio->bi_size;
-
-               clone->bi_private       = bio;
-               clone->bi_end_io        = bch_bi_idx_hack_endio;
-
-               bio = clone;
-       }
-
-       /*
-        * Hack, since drivers that clone bios clone up to bi_max_vecs, but our
-        * bios might have had more than that (before we split them per device
-        * limitations).
-        *
-        * To be taken out once immutable bvec stuff is in.
-        */
-       bio->bi_max_vecs = bio->bi_vcnt;
-
-       generic_make_request(bio);
-}
-
-/**
- * bch_bio_split - split a bio
- * @bio:       bio to split
- * @sectors:   number of sectors to split from the front of @bio
- * @gfp:       gfp mask
- * @bs:                bio set to allocate from
- *
- * Allocates and returns a new bio which represents @sectors from the start of
- * @bio, and updates @bio to represent the remaining sectors.
- *
- * If bio_sectors(@bio) was less than or equal to @sectors, returns @bio
- * unchanged.
- *
- * The newly allocated bio will point to @bio's bi_io_vec, if the split was on a
- * bvec boundry; it is the caller's responsibility to ensure that @bio is not
- * freed before the split.
- */
-struct bio *bch_bio_split(struct bio *bio, int sectors,
-                         gfp_t gfp, struct bio_set *bs)
-{
-       unsigned idx = bio->bi_idx, vcnt = 0, nbytes = sectors << 9;
-       struct bio_vec *bv;
-       struct bio *ret = NULL;
-
-       BUG_ON(sectors <= 0);
-
-       if (sectors >= bio_sectors(bio))
-               return bio;
-
-       if (bio->bi_rw & REQ_DISCARD) {
-               ret = bio_alloc_bioset(gfp, 1, bs);
-               if (!ret)
-                       return NULL;
-               idx = 0;
-               goto out;
-       }
-
-       bio_for_each_segment(bv, bio, idx) {
-               vcnt = idx - bio->bi_idx;
-
-               if (!nbytes) {
-                       ret = bio_alloc_bioset(gfp, vcnt, bs);
-                       if (!ret)
-                               return NULL;
-
-                       memcpy(ret->bi_io_vec, bio_iovec(bio),
-                              sizeof(struct bio_vec) * vcnt);
-
-                       break;
-               } else if (nbytes < bv->bv_len) {
-                       ret = bio_alloc_bioset(gfp, ++vcnt, bs);
-                       if (!ret)
-                               return NULL;
-
-                       memcpy(ret->bi_io_vec, bio_iovec(bio),
-                              sizeof(struct bio_vec) * vcnt);
-
-                       ret->bi_io_vec[vcnt - 1].bv_len = nbytes;
-                       bv->bv_offset   += nbytes;
-                       bv->bv_len      -= nbytes;
-                       break;
-               }
-
-               nbytes -= bv->bv_len;
-       }
-out:
-       ret->bi_bdev    = bio->bi_bdev;
-       ret->bi_sector  = bio->bi_sector;
-       ret->bi_size    = sectors << 9;
-       ret->bi_rw      = bio->bi_rw;
-       ret->bi_vcnt    = vcnt;
-       ret->bi_max_vecs = vcnt;
-
-       bio->bi_sector  += sectors;
-       bio->bi_size    -= sectors << 9;
-       bio->bi_idx      = idx;
-
-       if (bio_integrity(bio)) {
-               if (bio_integrity_clone(ret, bio, gfp)) {
-                       bio_put(ret);
-                       return NULL;
-               }
-
-               bio_integrity_trim(ret, 0, bio_sectors(ret));
-               bio_integrity_trim(bio, bio_sectors(ret), bio_sectors(bio));
-       }
-
-       return ret;
-}
-
 static unsigned bch_bio_max_sectors(struct bio *bio)
 {
-       unsigned ret = bio_sectors(bio);
        struct request_queue *q = bdev_get_queue(bio->bi_bdev);
-       unsigned max_segments = min_t(unsigned, BIO_MAX_PAGES,
-                                     queue_max_segments(q));
+       struct bio_vec bv;
+       struct bvec_iter iter;
+       unsigned ret = 0, seg = 0;
 
        if (bio->bi_rw & REQ_DISCARD)
-               return min(ret, q->limits.max_discard_sectors);
-
-       if (bio_segments(bio) > max_segments ||
-           q->merge_bvec_fn) {
-               struct bio_vec *bv;
-               int i, seg = 0;
-
-               ret = 0;
-
-               bio_for_each_segment(bv, bio, i) {
-                       struct bvec_merge_data bvm = {
-                               .bi_bdev        = bio->bi_bdev,
-                               .bi_sector      = bio->bi_sector,
-                               .bi_size        = ret << 9,
-                               .bi_rw          = bio->bi_rw,
-                       };
-
-                       if (seg == max_segments)
-                               break;
+               return min(bio_sectors(bio), q->limits.max_discard_sectors);
+
+       bio_for_each_segment(bv, bio, iter) {
+               struct bvec_merge_data bvm = {
+                       .bi_bdev        = bio->bi_bdev,
+                       .bi_sector      = bio->bi_iter.bi_sector,
+                       .bi_size        = ret << 9,
+                       .bi_rw          = bio->bi_rw,
+               };
+
+               if (seg == min_t(unsigned, BIO_MAX_PAGES,
+                                queue_max_segments(q)))
+                       break;
 
-                       if (q->merge_bvec_fn &&
-                           q->merge_bvec_fn(q, &bvm, bv) < (int) bv->bv_len)
-                               break;
+               if (q->merge_bvec_fn &&
+                   q->merge_bvec_fn(q, &bvm, &bv) < (int) bv.bv_len)
+                       break;
 
-                       seg++;
-                       ret += bv->bv_len >> 9;
-               }
+               seg++;
+               ret += bv.bv_len >> 9;
        }
 
        ret = min(ret, queue_max_sectors(q));
 
        WARN_ON(!ret);
-       ret = max_t(int, ret, bio_iovec(bio)->bv_len >> 9);
+       ret = max_t(int, ret, bio_iovec(bio).bv_len >> 9);
 
        return ret;
 }
@@ -193,7 +55,7 @@ static void bch_bio_submit_split_done(struct closure *cl)
 
        s->bio->bi_end_io = s->bi_end_io;
        s->bio->bi_private = s->bi_private;
-       bio_endio(s->bio, 0);
+       bio_endio_nodec(s->bio, 0);
 
        closure_debug_destroy(&s->cl);
        mempool_free(s, s->p->bio_split_hook);
@@ -232,19 +94,19 @@ void bch_generic_make_request(struct bio *bio, struct bio_split_pool *p)
        bio_get(bio);
 
        do {
-               n = bch_bio_split(bio, bch_bio_max_sectors(bio),
-                                 GFP_NOIO, s->p->bio_split);
+               n = bio_next_split(bio, bch_bio_max_sectors(bio),
+                                  GFP_NOIO, s->p->bio_split);
 
                n->bi_end_io    = bch_bio_submit_split_endio;
                n->bi_private   = &s->cl;
 
                closure_get(&s->cl);
-               bch_generic_make_request_hack(n);
+               generic_make_request(n);
        } while (n != bio);
 
        continue_at(&s->cl, bch_bio_submit_split_done, NULL);
 submit:
-       bch_generic_make_request_hack(bio);
+       generic_make_request(bio);
 }
 
 /* Bios with headers */
@@ -272,8 +134,8 @@ void __bch_submit_bbio(struct bio *bio, struct cache_set *c)
 {
        struct bbio *b = container_of(bio, struct bbio, bio);
 
-       bio->bi_sector  = PTR_OFFSET(&b->key, 0);
-       bio->bi_bdev    = PTR_CACHE(c, &b->key, 0)->bdev;
+       bio->bi_iter.bi_sector  = PTR_OFFSET(&b->key, 0);
+       bio->bi_bdev            = PTR_CACHE(c, &b->key, 0)->bdev;
 
        b->submit_time_us = local_clock_us();
        closure_bio_submit(bio, bio->bi_private, PTR_CACHE(c, &b->key, 0));
index ecdaa671bd50457bf38d1cf9f896ffd1c8352546..18039affc306b539e187b9b57ba3f1c3c3b95e3d 100644 (file)
@@ -44,17 +44,17 @@ static int journal_read_bucket(struct cache *ca, struct list_head *list,
 
        closure_init_stack(&cl);
 
-       pr_debug("reading %llu", (uint64_t) bucket);
+       pr_debug("reading %u", bucket_index);
 
        while (offset < ca->sb.bucket_size) {
 reread:                left = ca->sb.bucket_size - offset;
-               len = min_t(unsigned, left, PAGE_SECTORS * 8);
+               len = min_t(unsigned, left, PAGE_SECTORS << JSET_BITS);
 
                bio_reset(bio);
-               bio->bi_sector  = bucket + offset;
+               bio->bi_iter.bi_sector  = bucket + offset;
                bio->bi_bdev    = ca->bdev;
                bio->bi_rw      = READ;
-               bio->bi_size    = len << 9;
+               bio->bi_iter.bi_size    = len << 9;
 
                bio->bi_end_io  = journal_read_endio;
                bio->bi_private = &cl;
@@ -74,19 +74,28 @@ reread:             left = ca->sb.bucket_size - offset;
                        struct list_head *where;
                        size_t blocks, bytes = set_bytes(j);
 
-                       if (j->magic != jset_magic(&ca->sb))
+                       if (j->magic != jset_magic(&ca->sb)) {
+                               pr_debug("%u: bad magic", bucket_index);
                                return ret;
+                       }
 
-                       if (bytes > left << 9)
+                       if (bytes > left << 9 ||
+                           bytes > PAGE_SIZE << JSET_BITS) {
+                               pr_info("%u: too big, %zu bytes, offset %u",
+                                       bucket_index, bytes, offset);
                                return ret;
+                       }
 
                        if (bytes > len << 9)
                                goto reread;
 
-                       if (j->csum != csum_set(j))
+                       if (j->csum != csum_set(j)) {
+                               pr_info("%u: bad csum, %zu bytes, offset %u",
+                                       bucket_index, bytes, offset);
                                return ret;
+                       }
 
-                       blocks = set_blocks(j, ca->set);
+                       blocks = set_blocks(j, block_bytes(ca->set));
 
                        while (!list_empty(list)) {
                                i = list_first_entry(list,
@@ -275,7 +284,7 @@ void bch_journal_mark(struct cache_set *c, struct list_head *list)
                }
 
                for (k = i->j.start;
-                    k < end(&i->j);
+                    k < bset_bkey_last(&i->j);
                     k = bkey_next(k)) {
                        unsigned j;
 
@@ -313,7 +322,7 @@ int bch_journal_replay(struct cache_set *s, struct list_head *list)
                                 n, i->j.seq - 1, start, end);
 
                for (k = i->j.start;
-                    k < end(&i->j);
+                    k < bset_bkey_last(&i->j);
                     k = bkey_next(k)) {
                        trace_bcache_journal_replay_key(k);
 
@@ -437,13 +446,13 @@ static void do_journal_discard(struct cache *ca)
                atomic_set(&ja->discard_in_flight, DISCARD_IN_FLIGHT);
 
                bio_init(bio);
-               bio->bi_sector          = bucket_to_sector(ca->set,
+               bio->bi_iter.bi_sector  = bucket_to_sector(ca->set,
                                                ca->sb.d[ja->discard_idx]);
                bio->bi_bdev            = ca->bdev;
                bio->bi_rw              = REQ_WRITE|REQ_DISCARD;
                bio->bi_max_vecs        = 1;
                bio->bi_io_vec          = bio->bi_inline_vecs;
-               bio->bi_size            = bucket_bytes(ca);
+               bio->bi_iter.bi_size    = bucket_bytes(ca);
                bio->bi_end_io          = journal_discard_endio;
 
                closure_get(&ca->set->cl);
@@ -555,6 +564,14 @@ static void journal_write_done(struct closure *cl)
        continue_at_nobarrier(cl, journal_write, system_wq);
 }
 
+static void journal_write_unlock(struct closure *cl)
+{
+       struct cache_set *c = container_of(cl, struct cache_set, journal.io);
+
+       c->journal.io_in_flight = 0;
+       spin_unlock(&c->journal.lock);
+}
+
 static void journal_write_unlocked(struct closure *cl)
        __releases(c->journal.lock)
 {
@@ -562,22 +579,15 @@ static void journal_write_unlocked(struct closure *cl)
        struct cache *ca;
        struct journal_write *w = c->journal.cur;
        struct bkey *k = &c->journal.key;
-       unsigned i, sectors = set_blocks(w->data, c) * c->sb.block_size;
+       unsigned i, sectors = set_blocks(w->data, block_bytes(c)) *
+               c->sb.block_size;
 
        struct bio *bio;
        struct bio_list list;
        bio_list_init(&list);
 
        if (!w->need_write) {
-               /*
-                * XXX: have to unlock closure before we unlock journal lock,
-                * else we race with bch_journal(). But this way we race
-                * against cache set unregister. Doh.
-                */
-               set_closure_fn(cl, NULL, NULL);
-               closure_sub(cl, CLOSURE_RUNNING + 1);
-               spin_unlock(&c->journal.lock);
-               return;
+               closure_return_with_destructor(cl, journal_write_unlock);
        } else if (journal_full(&c->journal)) {
                journal_reclaim(c);
                spin_unlock(&c->journal.lock);
@@ -586,7 +596,7 @@ static void journal_write_unlocked(struct closure *cl)
                continue_at(cl, journal_write, system_wq);
        }
 
-       c->journal.blocks_free -= set_blocks(w->data, c);
+       c->journal.blocks_free -= set_blocks(w->data, block_bytes(c));
 
        w->data->btree_level = c->root->level;
 
@@ -608,10 +618,10 @@ static void journal_write_unlocked(struct closure *cl)
                atomic_long_add(sectors, &ca->meta_sectors_written);
 
                bio_reset(bio);
-               bio->bi_sector  = PTR_OFFSET(k, i);
+               bio->bi_iter.bi_sector  = PTR_OFFSET(k, i);
                bio->bi_bdev    = ca->bdev;
                bio->bi_rw      = REQ_WRITE|REQ_SYNC|REQ_META|REQ_FLUSH|REQ_FUA;
-               bio->bi_size    = sectors << 9;
+               bio->bi_iter.bi_size = sectors << 9;
 
                bio->bi_end_io  = journal_write_endio;
                bio->bi_private = w;
@@ -653,10 +663,12 @@ static void journal_try_write(struct cache_set *c)
 
        w->need_write = true;
 
-       if (closure_trylock(cl, &c->cl))
-               journal_write_unlocked(cl);
-       else
+       if (!c->journal.io_in_flight) {
+               c->journal.io_in_flight = 1;
+               closure_call(cl, journal_write_unlocked, NULL, &c->cl);
+       } else {
                spin_unlock(&c->journal.lock);
+       }
 }
 
 static struct journal_write *journal_wait_for_write(struct cache_set *c,
@@ -664,6 +676,7 @@ static struct journal_write *journal_wait_for_write(struct cache_set *c,
 {
        size_t sectors;
        struct closure cl;
+       bool wait = false;
 
        closure_init_stack(&cl);
 
@@ -673,16 +686,19 @@ static struct journal_write *journal_wait_for_write(struct cache_set *c,
                struct journal_write *w = c->journal.cur;
 
                sectors = __set_blocks(w->data, w->data->keys + nkeys,
-                                      c) * c->sb.block_size;
+                                      block_bytes(c)) * c->sb.block_size;
 
                if (sectors <= min_t(size_t,
                                     c->journal.blocks_free * c->sb.block_size,
                                     PAGE_SECTORS << JSET_BITS))
                        return w;
 
-               /* XXX: tracepoint */
+               if (wait)
+                       closure_wait(&c->journal.wait, &cl);
+
                if (!journal_full(&c->journal)) {
-                       trace_bcache_journal_entry_full(c);
+                       if (wait)
+                               trace_bcache_journal_entry_full(c);
 
                        /*
                         * XXX: If we were inserting so many keys that they
@@ -692,12 +708,11 @@ static struct journal_write *journal_wait_for_write(struct cache_set *c,
                         */
                        BUG_ON(!w->data->keys);
 
-                       closure_wait(&w->wait, &cl);
                        journal_try_write(c); /* unlocks */
                } else {
-                       trace_bcache_journal_full(c);
+                       if (wait)
+                               trace_bcache_journal_full(c);
 
-                       closure_wait(&c->journal.wait, &cl);
                        journal_reclaim(c);
                        spin_unlock(&c->journal.lock);
 
@@ -706,6 +721,7 @@ static struct journal_write *journal_wait_for_write(struct cache_set *c,
 
                closure_sync(&cl);
                spin_lock(&c->journal.lock);
+               wait = true;
        }
 }
 
@@ -736,7 +752,7 @@ atomic_t *bch_journal(struct cache_set *c,
 
        w = journal_wait_for_write(c, bch_keylist_nkeys(keys));
 
-       memcpy(end(w->data), keys->keys, bch_keylist_bytes(keys));
+       memcpy(bset_bkey_last(w->data), keys->keys, bch_keylist_bytes(keys));
        w->data->keys += bch_keylist_nkeys(keys);
 
        ret = &fifo_back(&c->journal.pin);
@@ -780,7 +796,6 @@ int bch_journal_alloc(struct cache_set *c)
 {
        struct journal *j = &c->journal;
 
-       closure_init_unlocked(&j->io);
        spin_lock_init(&j->lock);
        INIT_DELAYED_WORK(&j->work, journal_write_work);
 
index a6472fda94b25c00a340bcfefd48b3ac0c762c6e..9180c44650759b61b843ea8fe763a38b62277cd4 100644 (file)
@@ -104,6 +104,7 @@ struct journal {
        /* used when waiting because the journal was full */
        struct closure_waitlist wait;
        struct closure          io;
+       int                     io_in_flight;
        struct delayed_work     work;
 
        /* Number of blocks free in the bucket(s) we're currently writing to */
index f2f0998c4a91872407dd036a54fe72d243885fed..9eb60d102de84532e3a662390b1ba2934b744673 100644 (file)
@@ -86,7 +86,7 @@ static void moving_init(struct moving_io *io)
        bio_get(bio);
        bio_set_prio(bio, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0));
 
-       bio->bi_size            = KEY_SIZE(&io->w->key) << 9;
+       bio->bi_iter.bi_size    = KEY_SIZE(&io->w->key) << 9;
        bio->bi_max_vecs        = DIV_ROUND_UP(KEY_SIZE(&io->w->key),
                                               PAGE_SECTORS);
        bio->bi_private         = &io->cl;
@@ -102,7 +102,7 @@ static void write_moving(struct closure *cl)
        if (!op->error) {
                moving_init(io);
 
-               io->bio.bio.bi_sector = KEY_START(&io->w->key);
+               io->bio.bio.bi_iter.bi_sector = KEY_START(&io->w->key);
                op->write_prio          = 1;
                op->bio                 = &io->bio.bio;
 
@@ -211,7 +211,7 @@ void bch_moving_gc(struct cache_set *c)
        for_each_cache(ca, c, i) {
                unsigned sectors_to_move = 0;
                unsigned reserve_sectors = ca->sb.bucket_size *
-                       min(fifo_used(&ca->free), ca->free.size / 2);
+                       fifo_used(&ca->free[RESERVE_MOVINGGC]);
 
                ca->heap.used = 0;
 
index 61bcfc21d2a0f4972b581a689fd1c3c929f7bd38..72cd213f213f9e806dc9a0360000ffffe6466896 100644 (file)
@@ -197,14 +197,14 @@ static bool verify(struct cached_dev *dc, struct bio *bio)
 
 static void bio_csum(struct bio *bio, struct bkey *k)
 {
-       struct bio_vec *bv;
+       struct bio_vec bv;
+       struct bvec_iter iter;
        uint64_t csum = 0;
-       int i;
 
-       bio_for_each_segment(bv, bio, i) {
-               void *d = kmap(bv->bv_page) + bv->bv_offset;
-               csum = bch_crc64_update(csum, d, bv->bv_len);
-               kunmap(bv->bv_page);
+       bio_for_each_segment(bv, bio, iter) {
+               void *d = kmap(bv.bv_page) + bv.bv_offset;
+               csum = bch_crc64_update(csum, d, bv.bv_len);
+               kunmap(bv.bv_page);
        }
 
        k->ptr[KEY_PTRS(k)] = csum & (~0ULL >> 1);
@@ -254,26 +254,44 @@ static void bch_data_insert_keys(struct closure *cl)
        closure_return(cl);
 }
 
+static int bch_keylist_realloc(struct keylist *l, unsigned u64s,
+                              struct cache_set *c)
+{
+       size_t oldsize = bch_keylist_nkeys(l);
+       size_t newsize = oldsize + u64s;
+
+       /*
+        * The journalling code doesn't handle the case where the keys to insert
+        * is bigger than an empty write: If we just return -ENOMEM here,
+        * bio_insert() and bio_invalidate() will insert the keys created so far
+        * and finish the rest when the keylist is empty.
+        */
+       if (newsize * sizeof(uint64_t) > block_bytes(c) - sizeof(struct jset))
+               return -ENOMEM;
+
+       return __bch_keylist_realloc(l, u64s);
+}
+
 static void bch_data_invalidate(struct closure *cl)
 {
        struct data_insert_op *op = container_of(cl, struct data_insert_op, cl);
        struct bio *bio = op->bio;
 
        pr_debug("invalidating %i sectors from %llu",
-                bio_sectors(bio), (uint64_t) bio->bi_sector);
+                bio_sectors(bio), (uint64_t) bio->bi_iter.bi_sector);
 
        while (bio_sectors(bio)) {
                unsigned sectors = min(bio_sectors(bio),
                                       1U << (KEY_SIZE_BITS - 1));
 
-               if (bch_keylist_realloc(&op->insert_keys, 0, op->c))
+               if (bch_keylist_realloc(&op->insert_keys, 2, op->c))
                        goto out;
 
-               bio->bi_sector  += sectors;
-               bio->bi_size    -= sectors << 9;
+               bio->bi_iter.bi_sector  += sectors;
+               bio->bi_iter.bi_size    -= sectors << 9;
 
                bch_keylist_add(&op->insert_keys,
-                               &KEY(op->inode, bio->bi_sector, sectors));
+                               &KEY(op->inode, bio->bi_iter.bi_sector, sectors));
        }
 
        op->insert_data_done = true;
@@ -356,21 +374,21 @@ static void bch_data_insert_start(struct closure *cl)
 
                /* 1 for the device pointer and 1 for the chksum */
                if (bch_keylist_realloc(&op->insert_keys,
-                                       1 + (op->csum ? 1 : 0),
+                                       3 + (op->csum ? 1 : 0),
                                        op->c))
                        continue_at(cl, bch_data_insert_keys, bcache_wq);
 
                k = op->insert_keys.top;
                bkey_init(k);
                SET_KEY_INODE(k, op->inode);
-               SET_KEY_OFFSET(k, bio->bi_sector);
+               SET_KEY_OFFSET(k, bio->bi_iter.bi_sector);
 
                if (!bch_alloc_sectors(op->c, k, bio_sectors(bio),
                                       op->write_point, op->write_prio,
                                       op->writeback))
                        goto err;
 
-               n = bch_bio_split(bio, KEY_SIZE(k), GFP_NOIO, split);
+               n = bio_next_split(bio, KEY_SIZE(k), GFP_NOIO, split);
 
                n->bi_end_io    = bch_data_insert_endio;
                n->bi_private   = cl;
@@ -521,7 +539,7 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
             (bio->bi_rw & REQ_WRITE)))
                goto skip;
 
-       if (bio->bi_sector & (c->sb.block_size - 1) ||
+       if (bio->bi_iter.bi_sector & (c->sb.block_size - 1) ||
            bio_sectors(bio) & (c->sb.block_size - 1)) {
                pr_debug("skipping unaligned io");
                goto skip;
@@ -545,8 +563,8 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
 
        spin_lock(&dc->io_lock);
 
-       hlist_for_each_entry(i, iohash(dc, bio->bi_sector), hash)
-               if (i->last == bio->bi_sector &&
+       hlist_for_each_entry(i, iohash(dc, bio->bi_iter.bi_sector), hash)
+               if (i->last == bio->bi_iter.bi_sector &&
                    time_before(jiffies, i->jiffies))
                        goto found;
 
@@ -555,8 +573,8 @@ static bool check_should_bypass(struct cached_dev *dc, struct bio *bio)
        add_sequential(task);
        i->sequential = 0;
 found:
-       if (i->sequential + bio->bi_size > i->sequential)
-               i->sequential   += bio->bi_size;
+       if (i->sequential + bio->bi_iter.bi_size > i->sequential)
+               i->sequential   += bio->bi_iter.bi_size;
 
        i->last                  = bio_end_sector(bio);
        i->jiffies               = jiffies + msecs_to_jiffies(5000);
@@ -596,16 +614,13 @@ struct search {
        /* Stack frame for bio_complete */
        struct closure          cl;
 
-       struct bcache_device    *d;
-
        struct bbio             bio;
        struct bio              *orig_bio;
        struct bio              *cache_miss;
+       struct bcache_device    *d;
 
        unsigned                insert_bio_sectors;
-
        unsigned                recoverable:1;
-       unsigned                unaligned_bvec:1;
        unsigned                write:1;
        unsigned                read_dirty_data:1;
 
@@ -630,7 +645,8 @@ static void bch_cache_read_endio(struct bio *bio, int error)
 
        if (error)
                s->iop.error = error;
-       else if (ptr_stale(s->iop.c, &b->key, 0)) {
+       else if (!KEY_DIRTY(&b->key) &&
+                ptr_stale(s->iop.c, &b->key, 0)) {
                atomic_long_inc(&s->iop.c->cache_read_races);
                s->iop.error = -EINTR;
        }
@@ -649,15 +665,15 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k)
        struct bkey *bio_key;
        unsigned ptr;
 
-       if (bkey_cmp(k, &KEY(s->iop.inode, bio->bi_sector, 0)) <= 0)
+       if (bkey_cmp(k, &KEY(s->iop.inode, bio->bi_iter.bi_sector, 0)) <= 0)
                return MAP_CONTINUE;
 
        if (KEY_INODE(k) != s->iop.inode ||
-           KEY_START(k) > bio->bi_sector) {
+           KEY_START(k) > bio->bi_iter.bi_sector) {
                unsigned bio_sectors = bio_sectors(bio);
                unsigned sectors = KEY_INODE(k) == s->iop.inode
                        ? min_t(uint64_t, INT_MAX,
-                               KEY_START(k) - bio->bi_sector)
+                               KEY_START(k) - bio->bi_iter.bi_sector)
                        : INT_MAX;
 
                int ret = s->d->cache_miss(b, s, bio, sectors);
@@ -679,14 +695,14 @@ static int cache_lookup_fn(struct btree_op *op, struct btree *b, struct bkey *k)
        if (KEY_DIRTY(k))
                s->read_dirty_data = true;
 
-       n = bch_bio_split(bio, min_t(uint64_t, INT_MAX,
-                                    KEY_OFFSET(k) - bio->bi_sector),
-                         GFP_NOIO, s->d->bio_split);
+       n = bio_next_split(bio, min_t(uint64_t, INT_MAX,
+                                     KEY_OFFSET(k) - bio->bi_iter.bi_sector),
+                          GFP_NOIO, s->d->bio_split);
 
        bio_key = &container_of(n, struct bbio, bio)->key;
        bch_bkey_copy_single_ptr(bio_key, k, ptr);
 
-       bch_cut_front(&KEY(s->iop.inode, n->bi_sector, 0), bio_key);
+       bch_cut_front(&KEY(s->iop.inode, n->bi_iter.bi_sector, 0), bio_key);
        bch_cut_back(&KEY(s->iop.inode, bio_end_sector(n), 0), bio_key);
 
        n->bi_end_io    = bch_cache_read_endio;
@@ -711,10 +727,13 @@ static void cache_lookup(struct closure *cl)
 {
        struct search *s = container_of(cl, struct search, iop.cl);
        struct bio *bio = &s->bio.bio;
+       int ret;
 
-       int ret = bch_btree_map_keys(&s->op, s->iop.c,
-                                    &KEY(s->iop.inode, bio->bi_sector, 0),
-                                    cache_lookup_fn, MAP_END_KEY);
+       bch_btree_op_init(&s->op, -1);
+
+       ret = bch_btree_map_keys(&s->op, s->iop.c,
+                                &KEY(s->iop.inode, bio->bi_iter.bi_sector, 0),
+                                cache_lookup_fn, MAP_END_KEY);
        if (ret == -EAGAIN)
                continue_at(cl, cache_lookup, bcache_wq);
 
@@ -755,13 +774,15 @@ static void bio_complete(struct search *s)
        }
 }
 
-static void do_bio_hook(struct search *s)
+static void do_bio_hook(struct search *s, struct bio *orig_bio)
 {
        struct bio *bio = &s->bio.bio;
-       memcpy(bio, s->orig_bio, sizeof(struct bio));
 
+       bio_init(bio);
+       __bio_clone_fast(bio, orig_bio);
        bio->bi_end_io          = request_endio;
        bio->bi_private         = &s->cl;
+
        atomic_set(&bio->bi_cnt, 3);
 }
 
@@ -773,43 +794,36 @@ static void search_free(struct closure *cl)
        if (s->iop.bio)
                bio_put(s->iop.bio);
 
-       if (s->unaligned_bvec)
-               mempool_free(s->bio.bio.bi_io_vec, s->d->unaligned_bvec);
-
        closure_debug_destroy(cl);
        mempool_free(s, s->d->c->search);
 }
 
-static struct search *search_alloc(struct bio *bio, struct bcache_device *d)
+static inline struct search *search_alloc(struct bio *bio,
+                                         struct bcache_device *d)
 {
        struct search *s;
-       struct bio_vec *bv;
 
        s = mempool_alloc(d->c->search, GFP_NOIO);
-       memset(s, 0, offsetof(struct search, iop.insert_keys));
 
-       __closure_init(&s->cl, NULL);
+       closure_init(&s->cl, NULL);
+       do_bio_hook(s, bio);
 
-       s->iop.inode            = d->id;
-       s->iop.c                = d->c;
-       s->d                    = d;
-       s->op.lock              = -1;
-       s->iop.write_point      = hash_long((unsigned long) current, 16);
        s->orig_bio             = bio;
-       s->write                = (bio->bi_rw & REQ_WRITE) != 0;
-       s->iop.flush_journal    = (bio->bi_rw & (REQ_FLUSH|REQ_FUA)) != 0;
+       s->cache_miss           = NULL;
+       s->d                    = d;
        s->recoverable          = 1;
+       s->write                = (bio->bi_rw & REQ_WRITE) != 0;
+       s->read_dirty_data      = 0;
        s->start_time           = jiffies;
-       do_bio_hook(s);
 
-       if (bio->bi_size != bio_segments(bio) * PAGE_SIZE) {
-               bv = mempool_alloc(d->unaligned_bvec, GFP_NOIO);
-               memcpy(bv, bio_iovec(bio),
-                      sizeof(struct bio_vec) * bio_segments(bio));
-
-               s->bio.bio.bi_io_vec    = bv;
-               s->unaligned_bvec       = 1;
-       }
+       s->iop.c                = d->c;
+       s->iop.bio              = NULL;
+       s->iop.inode            = d->id;
+       s->iop.write_point      = hash_long((unsigned long) current, 16);
+       s->iop.write_prio       = 0;
+       s->iop.error            = 0;
+       s->iop.flags            = 0;
+       s->iop.flush_journal    = (bio->bi_rw & (REQ_FLUSH|REQ_FUA)) != 0;
 
        return s;
 }
@@ -849,26 +863,13 @@ static void cached_dev_read_error(struct closure *cl)
 {
        struct search *s = container_of(cl, struct search, cl);
        struct bio *bio = &s->bio.bio;
-       struct bio_vec *bv;
-       int i;
 
        if (s->recoverable) {
                /* Retry from the backing device: */
                trace_bcache_read_retry(s->orig_bio);
 
                s->iop.error = 0;
-               bv = s->bio.bio.bi_io_vec;
-               do_bio_hook(s);
-               s->bio.bio.bi_io_vec = bv;
-
-               if (!s->unaligned_bvec)
-                       bio_for_each_segment(bv, s->orig_bio, i)
-                               bv->bv_offset = 0, bv->bv_len = PAGE_SIZE;
-               else
-                       memcpy(s->bio.bio.bi_io_vec,
-                              bio_iovec(s->orig_bio),
-                              sizeof(struct bio_vec) *
-                              bio_segments(s->orig_bio));
+               do_bio_hook(s, s->orig_bio);
 
                /* XXX: invalidate cache */
 
@@ -893,9 +894,9 @@ static void cached_dev_read_done(struct closure *cl)
 
        if (s->iop.bio) {
                bio_reset(s->iop.bio);
-               s->iop.bio->bi_sector = s->cache_miss->bi_sector;
+               s->iop.bio->bi_iter.bi_sector = s->cache_miss->bi_iter.bi_sector;
                s->iop.bio->bi_bdev = s->cache_miss->bi_bdev;
-               s->iop.bio->bi_size = s->insert_bio_sectors << 9;
+               s->iop.bio->bi_iter.bi_size = s->insert_bio_sectors << 9;
                bch_bio_map(s->iop.bio, NULL);
 
                bio_copy_data(s->cache_miss, s->iop.bio);
@@ -904,8 +905,7 @@ static void cached_dev_read_done(struct closure *cl)
                s->cache_miss = NULL;
        }
 
-       if (verify(dc, &s->bio.bio) && s->recoverable &&
-           !s->unaligned_bvec && !s->read_dirty_data)
+       if (verify(dc, &s->bio.bio) && s->recoverable && !s->read_dirty_data)
                bch_data_verify(dc, s->orig_bio);
 
        bio_complete(s);
@@ -945,7 +945,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
        struct bio *miss, *cache_bio;
 
        if (s->cache_miss || s->iop.bypass) {
-               miss = bch_bio_split(bio, sectors, GFP_NOIO, s->d->bio_split);
+               miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split);
                ret = miss == bio ? MAP_DONE : MAP_CONTINUE;
                goto out_submit;
        }
@@ -959,7 +959,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
        s->insert_bio_sectors = min(sectors, bio_sectors(bio) + reada);
 
        s->iop.replace_key = KEY(s->iop.inode,
-                                bio->bi_sector + s->insert_bio_sectors,
+                                bio->bi_iter.bi_sector + s->insert_bio_sectors,
                                 s->insert_bio_sectors);
 
        ret = bch_btree_insert_check_key(b, &s->op, &s->iop.replace_key);
@@ -968,7 +968,7 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
 
        s->iop.replace = true;
 
-       miss = bch_bio_split(bio, sectors, GFP_NOIO, s->d->bio_split);
+       miss = bio_next_split(bio, sectors, GFP_NOIO, s->d->bio_split);
 
        /* btree_search_recurse()'s btree iterator is no good anymore */
        ret = miss == bio ? MAP_DONE : -EINTR;
@@ -979,9 +979,9 @@ static int cached_dev_cache_miss(struct btree *b, struct search *s,
        if (!cache_bio)
                goto out_submit;
 
-       cache_bio->bi_sector    = miss->bi_sector;
-       cache_bio->bi_bdev      = miss->bi_bdev;
-       cache_bio->bi_size      = s->insert_bio_sectors << 9;
+       cache_bio->bi_iter.bi_sector    = miss->bi_iter.bi_sector;
+       cache_bio->bi_bdev              = miss->bi_bdev;
+       cache_bio->bi_iter.bi_size      = s->insert_bio_sectors << 9;
 
        cache_bio->bi_end_io    = request_endio;
        cache_bio->bi_private   = &s->cl;
@@ -1031,7 +1031,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s)
 {
        struct closure *cl = &s->cl;
        struct bio *bio = &s->bio.bio;
-       struct bkey start = KEY(dc->disk.id, bio->bi_sector, 0);
+       struct bkey start = KEY(dc->disk.id, bio->bi_iter.bi_sector, 0);
        struct bkey end = KEY(dc->disk.id, bio_end_sector(bio), 0);
 
        bch_keybuf_check_overlapping(&s->iop.c->moving_gc_keys, &start, &end);
@@ -1087,8 +1087,7 @@ static void cached_dev_write(struct cached_dev *dc, struct search *s)
                        closure_bio_submit(flush, cl, s->d);
                }
        } else {
-               s->iop.bio = bio_clone_bioset(bio, GFP_NOIO,
-                                             dc->disk.bio_split);
+               s->iop.bio = bio_clone_fast(bio, GFP_NOIO, dc->disk.bio_split);
 
                closure_bio_submit(bio, cl, s->d);
        }
@@ -1126,13 +1125,13 @@ static void cached_dev_make_request(struct request_queue *q, struct bio *bio)
        part_stat_unlock();
 
        bio->bi_bdev = dc->bdev;
-       bio->bi_sector += dc->sb.data_offset;
+       bio->bi_iter.bi_sector += dc->sb.data_offset;
 
        if (cached_dev_get(dc)) {
                s = search_alloc(bio, d);
                trace_bcache_request_start(s->d, bio);
 
-               if (!bio->bi_size) {
+               if (!bio->bi_iter.bi_size) {
                        /*
                         * can't call bch_journal_meta from under
                         * generic_make_request
@@ -1204,24 +1203,24 @@ void bch_cached_dev_request_init(struct cached_dev *dc)
 static int flash_dev_cache_miss(struct btree *b, struct search *s,
                                struct bio *bio, unsigned sectors)
 {
-       struct bio_vec *bv;
-       int i;
+       struct bio_vec bv;
+       struct bvec_iter iter;
 
        /* Zero fill bio */
 
-       bio_for_each_segment(bv, bio, i) {
-               unsigned j = min(bv->bv_len >> 9, sectors);
+       bio_for_each_segment(bv, bio, iter) {
+               unsigned j = min(bv.bv_len >> 9, sectors);
 
-               void *p = kmap(bv->bv_page);
-               memset(p + bv->bv_offset, 0, j << 9);
-               kunmap(bv->bv_page);
+               void *p = kmap(bv.bv_page);
+               memset(p + bv.bv_offset, 0, j << 9);
+               kunmap(bv.bv_page);
 
                sectors -= j;
        }
 
-       bio_advance(bio, min(sectors << 9, bio->bi_size));
+       bio_advance(bio, min(sectors << 9, bio->bi_iter.bi_size));
 
-       if (!bio->bi_size)
+       if (!bio->bi_iter.bi_size)
                return MAP_DONE;
 
        return MAP_CONTINUE;
@@ -1255,7 +1254,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio)
 
        trace_bcache_request_start(s->d, bio);
 
-       if (!bio->bi_size) {
+       if (!bio->bi_iter.bi_size) {
                /*
                 * can't call bch_journal_meta from under
                 * generic_make_request
@@ -1265,7 +1264,7 @@ static void flash_dev_make_request(struct request_queue *q, struct bio *bio)
                                      bcache_wq);
        } else if (rw) {
                bch_keybuf_check_overlapping(&s->iop.c->moving_gc_keys,
-                                       &KEY(d->id, bio->bi_sector, 0),
+                                       &KEY(d->id, bio->bi_iter.bi_sector, 0),
                                        &KEY(d->id, bio_end_sector(bio), 0));
 
                s->iop.bypass           = (bio->bi_rw & REQ_DISCARD) != 0;
index 2cd65bf073c24689542d78f0ef316f81ed21ba1c..39f21dbedc38b43ec7bf4818cfca319d27d27433 100644 (file)
@@ -13,17 +13,22 @@ struct data_insert_op {
        uint16_t                write_prio;
        short                   error;
 
-       unsigned                bypass:1;
-       unsigned                writeback:1;
-       unsigned                flush_journal:1;
-       unsigned                csum:1;
+       union {
+               uint16_t        flags;
 
-       unsigned                replace:1;
-       unsigned                replace_collision:1;
+       struct {
+               unsigned        bypass:1;
+               unsigned        writeback:1;
+               unsigned        flush_journal:1;
+               unsigned        csum:1;
 
-       unsigned                insert_data_done:1;
+               unsigned        replace:1;
+               unsigned        replace_collision:1;
+
+               unsigned        insert_data_done:1;
+       };
+       };
 
-       /* Anything past this point won't get zeroed in search_alloc() */
        struct keylist          insert_keys;
        BKEY_PADDED(replace_key);
 };
index c57bfa071a57c58b06fabeb194cbf98f5f4fbf56..24a3a1546caa7a4c8e9c0aa70c9461574f87a591 100644 (file)
@@ -9,6 +9,7 @@
 #include "bcache.h"
 #include "btree.h"
 #include "debug.h"
+#include "extents.h"
 #include "request.h"
 #include "writeback.h"
 
@@ -225,7 +226,7 @@ static void write_bdev_super_endio(struct bio *bio, int error)
        struct cached_dev *dc = bio->bi_private;
        /* XXX: error checking */
 
-       closure_put(&dc->sb_write.cl);
+       closure_put(&dc->sb_write);
 }
 
 static void __write_super(struct cache_sb *sb, struct bio *bio)
@@ -233,9 +234,9 @@ static void __write_super(struct cache_sb *sb, struct bio *bio)
        struct cache_sb *out = page_address(bio->bi_io_vec[0].bv_page);
        unsigned i;
 
-       bio->bi_sector  = SB_SECTOR;
-       bio->bi_rw      = REQ_SYNC|REQ_META;
-       bio->bi_size    = SB_SIZE;
+       bio->bi_iter.bi_sector  = SB_SECTOR;
+       bio->bi_rw              = REQ_SYNC|REQ_META;
+       bio->bi_iter.bi_size    = SB_SIZE;
        bch_bio_map(bio, NULL);
 
        out->offset             = cpu_to_le64(sb->offset);
@@ -263,12 +264,20 @@ static void __write_super(struct cache_sb *sb, struct bio *bio)
        submit_bio(REQ_WRITE, bio);
 }
 
+static void bch_write_bdev_super_unlock(struct closure *cl)
+{
+       struct cached_dev *dc = container_of(cl, struct cached_dev, sb_write);
+
+       up(&dc->sb_write_mutex);
+}
+
 void bch_write_bdev_super(struct cached_dev *dc, struct closure *parent)
 {
-       struct closure *cl = &dc->sb_write.cl;
+       struct closure *cl = &dc->sb_write;
        struct bio *bio = &dc->sb_bio;
 
-       closure_lock(&dc->sb_write, parent);
+       down(&dc->sb_write_mutex);
+       closure_init(cl, parent);
 
        bio_reset(bio);
        bio->bi_bdev    = dc->bdev;
@@ -278,7 +287,7 @@ void bch_write_bdev_super(struct cached_dev *dc, struct closure *parent)
        closure_get(cl);
        __write_super(&dc->sb, bio);
 
-       closure_return(cl);
+       closure_return_with_destructor(cl, bch_write_bdev_super_unlock);
 }
 
 static void write_super_endio(struct bio *bio, int error)
@@ -286,16 +295,24 @@ static void write_super_endio(struct bio *bio, int error)
        struct cache *ca = bio->bi_private;
 
        bch_count_io_errors(ca, error, "writing superblock");
-       closure_put(&ca->set->sb_write.cl);
+       closure_put(&ca->set->sb_write);
+}
+
+static void bcache_write_super_unlock(struct closure *cl)
+{
+       struct cache_set *c = container_of(cl, struct cache_set, sb_write);
+
+       up(&c->sb_write_mutex);
 }
 
 void bcache_write_super(struct cache_set *c)
 {
-       struct closure *cl = &c->sb_write.cl;
+       struct closure *cl = &c->sb_write;
        struct cache *ca;
        unsigned i;
 
-       closure_lock(&c->sb_write, &c->cl);
+       down(&c->sb_write_mutex);
+       closure_init(cl, &c->cl);
 
        c->sb.seq++;
 
@@ -317,7 +334,7 @@ void bcache_write_super(struct cache_set *c)
                __write_super(&ca->sb, bio);
        }
 
-       closure_return(cl);
+       closure_return_with_destructor(cl, bcache_write_super_unlock);
 }
 
 /* UUID io */
@@ -325,29 +342,37 @@ void bcache_write_super(struct cache_set *c)
 static void uuid_endio(struct bio *bio, int error)
 {
        struct closure *cl = bio->bi_private;
-       struct cache_set *c = container_of(cl, struct cache_set, uuid_write.cl);
+       struct cache_set *c = container_of(cl, struct cache_set, uuid_write);
 
        cache_set_err_on(error, c, "accessing uuids");
        bch_bbio_free(bio, c);
        closure_put(cl);
 }
 
+static void uuid_io_unlock(struct closure *cl)
+{
+       struct cache_set *c = container_of(cl, struct cache_set, uuid_write);
+
+       up(&c->uuid_write_mutex);
+}
+
 static void uuid_io(struct cache_set *c, unsigned long rw,
                    struct bkey *k, struct closure *parent)
 {
-       struct closure *cl = &c->uuid_write.cl;
+       struct closure *cl = &c->uuid_write;
        struct uuid_entry *u;
        unsigned i;
        char buf[80];
 
        BUG_ON(!parent);
-       closure_lock(&c->uuid_write, parent);
+       down(&c->uuid_write_mutex);
+       closure_init(cl, parent);
 
        for (i = 0; i < KEY_PTRS(k); i++) {
                struct bio *bio = bch_bbio_alloc(c);
 
                bio->bi_rw      = REQ_SYNC|REQ_META|rw;
-               bio->bi_size    = KEY_SIZE(k) << 9;
+               bio->bi_iter.bi_size = KEY_SIZE(k) << 9;
 
                bio->bi_end_io  = uuid_endio;
                bio->bi_private = cl;
@@ -359,7 +384,7 @@ static void uuid_io(struct cache_set *c, unsigned long rw,
                        break;
        }
 
-       bch_bkey_to_text(buf, sizeof(buf), k);
+       bch_extent_to_text(buf, sizeof(buf), k);
        pr_debug("%s UUIDs at %s", rw & REQ_WRITE ? "wrote" : "read", buf);
 
        for (u = c->uuids; u < c->uuids + c->nr_uuids; u++)
@@ -368,14 +393,14 @@ static void uuid_io(struct cache_set *c, unsigned long rw,
                                 u - c->uuids, u->uuid, u->label,
                                 u->first_reg, u->last_reg, u->invalidated);
 
-       closure_return(cl);
+       closure_return_with_destructor(cl, uuid_io_unlock);
 }
 
 static char *uuid_read(struct cache_set *c, struct jset *j, struct closure *cl)
 {
        struct bkey *k = &j->uuid_bucket;
 
-       if (bch_btree_ptr_invalid(c, k))
+       if (__bch_btree_ptr_invalid(c, k))
                return "bad uuid pointer";
 
        bkey_copy(&c->uuid_bucket, k);
@@ -420,7 +445,7 @@ static int __uuid_write(struct cache_set *c)
 
        lockdep_assert_held(&bch_register_lock);
 
-       if (bch_bucket_alloc_set(c, WATERMARK_METADATA, &k.key, 1, true))
+       if (bch_bucket_alloc_set(c, RESERVE_BTREE, &k.key, 1, true))
                return 1;
 
        SET_KEY_SIZE(&k.key, c->sb.bucket_size);
@@ -503,10 +528,10 @@ static void prio_io(struct cache *ca, uint64_t bucket, unsigned long rw)
 
        closure_init_stack(cl);
 
-       bio->bi_sector  = bucket * ca->sb.bucket_size;
-       bio->bi_bdev    = ca->bdev;
-       bio->bi_rw      = REQ_SYNC|REQ_META|rw;
-       bio->bi_size    = bucket_bytes(ca);
+       bio->bi_iter.bi_sector  = bucket * ca->sb.bucket_size;
+       bio->bi_bdev            = ca->bdev;
+       bio->bi_rw              = REQ_SYNC|REQ_META|rw;
+       bio->bi_iter.bi_size    = bucket_bytes(ca);
 
        bio->bi_end_io  = prio_endio;
        bio->bi_private = ca;
@@ -538,8 +563,8 @@ void bch_prio_write(struct cache *ca)
        atomic_long_add(ca->sb.bucket_size * prio_buckets(ca),
                        &ca->meta_sectors_written);
 
-       pr_debug("free %zu, free_inc %zu, unused %zu", fifo_used(&ca->free),
-                fifo_used(&ca->free_inc), fifo_used(&ca->unused));
+       //pr_debug("free %zu, free_inc %zu, unused %zu", fifo_used(&ca->free),
+       //       fifo_used(&ca->free_inc), fifo_used(&ca->unused));
 
        for (i = prio_buckets(ca) - 1; i >= 0; --i) {
                long bucket;
@@ -558,7 +583,7 @@ void bch_prio_write(struct cache *ca)
                p->magic        = pset_magic(&ca->sb);
                p->csum         = bch_crc64(&p->magic, bucket_bytes(ca) - 8);
 
-               bucket = bch_bucket_alloc(ca, WATERMARK_PRIO, true);
+               bucket = bch_bucket_alloc(ca, RESERVE_PRIO, true);
                BUG_ON(bucket == -1);
 
                mutex_unlock(&ca->set->bucket_lock);
@@ -739,8 +764,6 @@ static void bcache_device_free(struct bcache_device *d)
        }
 
        bio_split_pool_free(&d->bio_split_hook);
-       if (d->unaligned_bvec)
-               mempool_destroy(d->unaligned_bvec);
        if (d->bio_split)
                bioset_free(d->bio_split);
        if (is_vmalloc_addr(d->full_dirty_stripes))
@@ -793,8 +816,6 @@ static int bcache_device_init(struct bcache_device *d, unsigned block_size,
                return minor;
 
        if (!(d->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
-           !(d->unaligned_bvec = mempool_create_kmalloc_pool(1,
-                               sizeof(struct bio_vec) * BIO_MAX_PAGES)) ||
            bio_split_pool_init(&d->bio_split_hook) ||
            !(d->disk = alloc_disk(1))) {
                ida_simple_remove(&bcache_minor, minor);
@@ -1102,7 +1123,7 @@ static int cached_dev_init(struct cached_dev *dc, unsigned block_size)
        set_closure_fn(&dc->disk.cl, cached_dev_flush, system_wq);
        kobject_init(&dc->disk.kobj, &bch_cached_dev_ktype);
        INIT_WORK(&dc->detach, cached_dev_detach_finish);
-       closure_init_unlocked(&dc->sb_write);
+       sema_init(&dc->sb_write_mutex, 1);
        INIT_LIST_HEAD(&dc->io_lru);
        spin_lock_init(&dc->io_lock);
        bch_cache_accounting_init(&dc->accounting, &dc->disk.cl);
@@ -1114,6 +1135,12 @@ static int cached_dev_init(struct cached_dev *dc, unsigned block_size)
                hlist_add_head(&io->hash, dc->io_hash + RECENT_IO);
        }
 
+       dc->disk.stripe_size = q->limits.io_opt >> 9;
+
+       if (dc->disk.stripe_size)
+               dc->partial_stripes_expensive =
+                       q->limits.raid_partial_stripes_expensive;
+
        ret = bcache_device_init(&dc->disk, block_size,
                         dc->bdev->bd_part->nr_sects - dc->sb.data_offset);
        if (ret)
@@ -1325,8 +1352,8 @@ static void cache_set_free(struct closure *cl)
                if (ca)
                        kobject_put(&ca->kobj);
 
+       bch_bset_sort_state_free(&c->sort);
        free_pages((unsigned long) c->uuids, ilog2(bucket_pages(c)));
-       free_pages((unsigned long) c->sort, ilog2(bucket_pages(c)));
 
        if (c->bio_split)
                bioset_free(c->bio_split);
@@ -1451,21 +1478,17 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
        c->block_bits           = ilog2(sb->block_size);
        c->nr_uuids             = bucket_bytes(c) / sizeof(struct uuid_entry);
 
-       c->btree_pages          = c->sb.bucket_size / PAGE_SECTORS;
+       c->btree_pages          = bucket_pages(c);
        if (c->btree_pages > BTREE_MAX_PAGES)
                c->btree_pages = max_t(int, c->btree_pages / 4,
                                       BTREE_MAX_PAGES);
 
-       c->sort_crit_factor = int_sqrt(c->btree_pages);
-
-       closure_init_unlocked(&c->sb_write);
+       sema_init(&c->sb_write_mutex, 1);
        mutex_init(&c->bucket_lock);
        init_waitqueue_head(&c->try_wait);
        init_waitqueue_head(&c->bucket_wait);
-       closure_init_unlocked(&c->uuid_write);
-       mutex_init(&c->sort_lock);
+       sema_init(&c->uuid_write_mutex, 1);
 
-       spin_lock_init(&c->sort_time.lock);
        spin_lock_init(&c->btree_gc_time.lock);
        spin_lock_init(&c->btree_split_time.lock);
        spin_lock_init(&c->btree_read_time.lock);
@@ -1493,11 +1516,11 @@ struct cache_set *bch_cache_set_alloc(struct cache_sb *sb)
                                bucket_pages(c))) ||
            !(c->fill_iter = mempool_create_kmalloc_pool(1, iter_size)) ||
            !(c->bio_split = bioset_create(4, offsetof(struct bbio, bio))) ||
-           !(c->sort = alloc_bucket_pages(GFP_KERNEL, c)) ||
            !(c->uuids = alloc_bucket_pages(GFP_KERNEL, c)) ||
            bch_journal_alloc(c) ||
            bch_btree_cache_alloc(c) ||
-           bch_open_buckets_alloc(c))
+           bch_open_buckets_alloc(c) ||
+           bch_bset_sort_state_init(&c->sort, ilog2(c->btree_pages)))
                goto err;
 
        c->congested_read_threshold_us  = 2000;
@@ -1553,7 +1576,7 @@ static void run_cache_set(struct cache_set *c)
                k = &j->btree_root;
 
                err = "bad btree root";
-               if (bch_btree_ptr_invalid(c, k))
+               if (__bch_btree_ptr_invalid(c, k))
                        goto err;
 
                err = "error reading btree root";
@@ -1747,6 +1770,7 @@ err:
 void bch_cache_release(struct kobject *kobj)
 {
        struct cache *ca = container_of(kobj, struct cache, kobj);
+       unsigned i;
 
        if (ca->set)
                ca->set->cache[ca->sb.nr_this_dev] = NULL;
@@ -1760,7 +1784,9 @@ void bch_cache_release(struct kobject *kobj)
        free_heap(&ca->heap);
        free_fifo(&ca->unused);
        free_fifo(&ca->free_inc);
-       free_fifo(&ca->free);
+
+       for (i = 0; i < RESERVE_NR; i++)
+               free_fifo(&ca->free[i]);
 
        if (ca->sb_bio.bi_inline_vecs[0].bv_page)
                put_page(ca->sb_bio.bi_io_vec[0].bv_page);
@@ -1786,10 +1812,12 @@ static int cache_alloc(struct cache_sb *sb, struct cache *ca)
        ca->journal.bio.bi_max_vecs = 8;
        ca->journal.bio.bi_io_vec = ca->journal.bio.bi_inline_vecs;
 
-       free = roundup_pow_of_two(ca->sb.nbuckets) >> 9;
-       free = max_t(size_t, free, (prio_buckets(ca) + 8) * 2);
+       free = roundup_pow_of_two(ca->sb.nbuckets) >> 10;
 
-       if (!init_fifo(&ca->free,       free, GFP_KERNEL) ||
+       if (!init_fifo(&ca->free[RESERVE_BTREE], 8, GFP_KERNEL) ||
+           !init_fifo(&ca->free[RESERVE_PRIO], prio_buckets(ca), GFP_KERNEL) ||
+           !init_fifo(&ca->free[RESERVE_MOVINGGC], free, GFP_KERNEL) ||
+           !init_fifo(&ca->free[RESERVE_NONE], free, GFP_KERNEL) ||
            !init_fifo(&ca->free_inc,   free << 2, GFP_KERNEL) ||
            !init_fifo(&ca->unused,     free << 2, GFP_KERNEL) ||
            !init_heap(&ca->heap,       free << 3, GFP_KERNEL) ||
@@ -2034,7 +2062,8 @@ static void bcache_exit(void)
                kobject_put(bcache_kobj);
        if (bcache_wq)
                destroy_workqueue(bcache_wq);
-       unregister_blkdev(bcache_major, "bcache");
+       if (bcache_major)
+               unregister_blkdev(bcache_major, "bcache");
        unregister_reboot_notifier(&reboot);
 }
 
index a1f85612f0b3dfc5c90b768aaef48118034c02c7..c6ab69333a6dfde7761e9e2b05c16574f5c52480 100644 (file)
@@ -102,7 +102,6 @@ rw_attribute(bypass_torture_test);
 rw_attribute(key_merging_disabled);
 rw_attribute(gc_always_rewrite);
 rw_attribute(expensive_debug_checks);
-rw_attribute(freelist_percent);
 rw_attribute(cache_replacement_policy);
 rw_attribute(btree_shrinker_disabled);
 rw_attribute(copy_gc_enabled);
@@ -401,6 +400,48 @@ static struct attribute *bch_flash_dev_files[] = {
 };
 KTYPE(bch_flash_dev);
 
+struct bset_stats_op {
+       struct btree_op op;
+       size_t nodes;
+       struct bset_stats stats;
+};
+
+static int btree_bset_stats(struct btree_op *b_op, struct btree *b)
+{
+       struct bset_stats_op *op = container_of(b_op, struct bset_stats_op, op);
+
+       op->nodes++;
+       bch_btree_keys_stats(&b->keys, &op->stats);
+
+       return MAP_CONTINUE;
+}
+
+int bch_bset_print_stats(struct cache_set *c, char *buf)
+{
+       struct bset_stats_op op;
+       int ret;
+
+       memset(&op, 0, sizeof(op));
+       bch_btree_op_init(&op.op, -1);
+
+       ret = bch_btree_map_nodes(&op.op, c, &ZERO_KEY, btree_bset_stats);
+       if (ret < 0)
+               return ret;
+
+       return snprintf(buf, PAGE_SIZE,
+                       "btree nodes:           %zu\n"
+                       "written sets:          %zu\n"
+                       "unwritten sets:                %zu\n"
+                       "written key bytes:     %zu\n"
+                       "unwritten key bytes:   %zu\n"
+                       "floats:                        %zu\n"
+                       "failed:                        %zu\n",
+                       op.nodes,
+                       op.stats.sets_written, op.stats.sets_unwritten,
+                       op.stats.bytes_written, op.stats.bytes_unwritten,
+                       op.stats.floats, op.stats.failed);
+}
+
 SHOW(__bch_cache_set)
 {
        unsigned root_usage(struct cache_set *c)
@@ -419,7 +460,7 @@ lock_root:
                        rw_lock(false, b, b->level);
                } while (b != c->root);
 
-               for_each_key_filter(b, k, &iter, bch_ptr_bad)
+               for_each_key_filter(&b->keys, k, &iter, bch_ptr_bad)
                        bytes += bkey_bytes(k);
 
                rw_unlock(false, b);
@@ -434,7 +475,7 @@ lock_root:
 
                mutex_lock(&c->bucket_lock);
                list_for_each_entry(b, &c->btree_cache, list)
-                       ret += 1 << (b->page_order + PAGE_SHIFT);
+                       ret += 1 << (b->keys.page_order + PAGE_SHIFT);
 
                mutex_unlock(&c->bucket_lock);
                return ret;
@@ -491,7 +532,7 @@ lock_root:
 
        sysfs_print_time_stats(&c->btree_gc_time,       btree_gc, sec, ms);
        sysfs_print_time_stats(&c->btree_split_time,    btree_split, sec, us);
-       sysfs_print_time_stats(&c->sort_time,           btree_sort, ms, us);
+       sysfs_print_time_stats(&c->sort.time,           btree_sort, ms, us);
        sysfs_print_time_stats(&c->btree_read_time,     btree_read, ms, us);
        sysfs_print_time_stats(&c->try_harder_time,     try_harder, ms, us);
 
@@ -711,9 +752,6 @@ SHOW(__bch_cache)
        sysfs_print(io_errors,
                    atomic_read(&ca->io_errors) >> IO_ERROR_SHIFT);
 
-       sysfs_print(freelist_percent, ca->free.size * 100 /
-                   ((size_t) ca->sb.nbuckets));
-
        if (attr == &sysfs_cache_replacement_policy)
                return bch_snprint_string_list(buf, PAGE_SIZE,
                                               cache_replacement_policies,
@@ -820,32 +858,6 @@ STORE(__bch_cache)
                }
        }
 
-       if (attr == &sysfs_freelist_percent) {
-               DECLARE_FIFO(long, free);
-               long i;
-               size_t p = strtoul_or_return(buf);
-
-               p = clamp_t(size_t,
-                           ((size_t) ca->sb.nbuckets * p) / 100,
-                           roundup_pow_of_two(ca->sb.nbuckets) >> 9,
-                           ca->sb.nbuckets / 2);
-
-               if (!init_fifo_exact(&free, p, GFP_KERNEL))
-                       return -ENOMEM;
-
-               mutex_lock(&ca->set->bucket_lock);
-
-               fifo_move(&free, &ca->free);
-               fifo_swap(&free, &ca->free);
-
-               mutex_unlock(&ca->set->bucket_lock);
-
-               while (fifo_pop(&free, i))
-                       atomic_dec(&ca->buckets[i].pin);
-
-               free_fifo(&free);
-       }
-
        if (attr == &sysfs_clear_stats) {
                atomic_long_set(&ca->sectors_written, 0);
                atomic_long_set(&ca->btree_sectors_written, 0);
@@ -869,7 +881,6 @@ static struct attribute *bch_cache_files[] = {
        &sysfs_metadata_written,
        &sysfs_io_errors,
        &sysfs_clear_stats,
-       &sysfs_freelist_percent,
        &sysfs_cache_replacement_policy,
        NULL
 };
index bb37618e76648b7bc3caf99532e4f81b48666dfe..db3ae4c2b2233a4026ebe8a183042eb84d53cdc4 100644 (file)
@@ -224,10 +224,10 @@ uint64_t bch_next_delay(struct bch_ratelimit *d, uint64_t done)
 
 void bch_bio_map(struct bio *bio, void *base)
 {
-       size_t size = bio->bi_size;
+       size_t size = bio->bi_iter.bi_size;
        struct bio_vec *bv = bio->bi_io_vec;
 
-       BUG_ON(!bio->bi_size);
+       BUG_ON(!bio->bi_iter.bi_size);
        BUG_ON(bio->bi_vcnt);
 
        bv->bv_offset = base ? ((unsigned long) base) % PAGE_SIZE : 0;
index 1030c6020e986934e21c94628794e5e342271b49..ac7d0d1f70d7be9ae818a51c6d77c461d770eb4b 100644 (file)
@@ -2,6 +2,7 @@
 #ifndef _BCACHE_UTIL_H
 #define _BCACHE_UTIL_H
 
+#include <linux/blkdev.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
 #include <linux/llist.h>
@@ -17,11 +18,13 @@ struct closure;
 
 #ifdef CONFIG_BCACHE_DEBUG
 
+#define EBUG_ON(cond)                  BUG_ON(cond)
 #define atomic_dec_bug(v)      BUG_ON(atomic_dec_return(v) < 0)
 #define atomic_inc_bug(v, i)   BUG_ON(atomic_inc_return(v) <= i)
 
 #else /* DEBUG */
 
+#define EBUG_ON(cond)                  do { if (cond); } while (0)
 #define atomic_dec_bug(v)      atomic_dec(v)
 #define atomic_inc_bug(v, i)   atomic_inc(v)
 
@@ -391,6 +394,11 @@ struct time_stats {
 
 void bch_time_stats_update(struct time_stats *stats, uint64_t time);
 
+static inline unsigned local_clock_us(void)
+{
+       return local_clock() >> 10;
+}
+
 #define NSEC_PER_ns                    1L
 #define NSEC_PER_us                    NSEC_PER_USEC
 #define NSEC_PER_ms                    NSEC_PER_MSEC
index 6c44fe059c2769a4b2c317f25878596268726f0d..f4300e4c0114a0cc1abc3b90f757a03666d2637b 100644 (file)
@@ -111,7 +111,7 @@ static void dirty_init(struct keybuf_key *w)
        if (!io->dc->writeback_percent)
                bio_set_prio(bio, IOPRIO_PRIO_VALUE(IOPRIO_CLASS_IDLE, 0));
 
-       bio->bi_size            = KEY_SIZE(&w->key) << 9;
+       bio->bi_iter.bi_size    = KEY_SIZE(&w->key) << 9;
        bio->bi_max_vecs        = DIV_ROUND_UP(KEY_SIZE(&w->key), PAGE_SECTORS);
        bio->bi_private         = w;
        bio->bi_io_vec          = bio->bi_inline_vecs;
@@ -184,7 +184,7 @@ static void write_dirty(struct closure *cl)
 
        dirty_init(w);
        io->bio.bi_rw           = WRITE;
-       io->bio.bi_sector       = KEY_START(&w->key);
+       io->bio.bi_iter.bi_sector = KEY_START(&w->key);
        io->bio.bi_bdev         = io->dc->bdev;
        io->bio.bi_end_io       = dirty_endio;
 
@@ -253,7 +253,7 @@ static void read_dirty(struct cached_dev *dc)
                io->dc          = dc;
 
                dirty_init(w);
-               io->bio.bi_sector       = PTR_OFFSET(&w->key, 0);
+               io->bio.bi_iter.bi_sector = PTR_OFFSET(&w->key, 0);
                io->bio.bi_bdev         = PTR_CACHE(dc->disk.c,
                                                    &w->key, 0)->bdev;
                io->bio.bi_rw           = READ;
index c9ddcf4614b9300701c9867033c82bc13cadf472..e2f8598937ac41ff5c7577bc5e65aeb39de95386 100644 (file)
@@ -50,7 +50,7 @@ static inline bool should_writeback(struct cached_dev *dc, struct bio *bio,
                return false;
 
        if (dc->partial_stripes_expensive &&
-           bcache_dev_stripe_dirty(dc, bio->bi_sector,
+           bcache_dev_stripe_dirty(dc, bio->bi_iter.bi_sector,
                                    bio_sectors(bio)))
                return true;
 
index 3a8cfa2645c72f6539170f2ab2d3242bb4a6fa58..dd3646111561512f50728aa915b8a279be1c26ac 100644 (file)
  * original bio state.
  */
 
-struct dm_bio_vec_details {
-#if PAGE_SIZE < 65536
-       __u16 bv_len;
-       __u16 bv_offset;
-#else
-       unsigned bv_len;
-       unsigned bv_offset;
-#endif
-};
-
 struct dm_bio_details {
-       sector_t bi_sector;
        struct block_device *bi_bdev;
-       unsigned int bi_size;
-       unsigned short bi_idx;
        unsigned long bi_flags;
-       struct dm_bio_vec_details bi_io_vec[BIO_MAX_PAGES];
+       struct bvec_iter bi_iter;
 };
 
 static inline void dm_bio_record(struct dm_bio_details *bd, struct bio *bio)
 {
-       unsigned i;
-
-       bd->bi_sector = bio->bi_sector;
        bd->bi_bdev = bio->bi_bdev;
-       bd->bi_size = bio->bi_size;
-       bd->bi_idx = bio->bi_idx;
        bd->bi_flags = bio->bi_flags;
-
-       for (i = 0; i < bio->bi_vcnt; i++) {
-               bd->bi_io_vec[i].bv_len = bio->bi_io_vec[i].bv_len;
-               bd->bi_io_vec[i].bv_offset = bio->bi_io_vec[i].bv_offset;
-       }
+       bd->bi_iter = bio->bi_iter;
 }
 
 static inline void dm_bio_restore(struct dm_bio_details *bd, struct bio *bio)
 {
-       unsigned i;
-
-       bio->bi_sector = bd->bi_sector;
        bio->bi_bdev = bd->bi_bdev;
-       bio->bi_size = bd->bi_size;
-       bio->bi_idx = bd->bi_idx;
        bio->bi_flags = bd->bi_flags;
-
-       for (i = 0; i < bio->bi_vcnt; i++) {
-               bio->bi_io_vec[i].bv_len = bd->bi_io_vec[i].bv_len;
-               bio->bi_io_vec[i].bv_offset = bd->bi_io_vec[i].bv_offset;
-       }
+       bio->bi_iter = bd->bi_iter;
 }
 
 #endif
index 9ed42125514b38d560464e4dd3d741038db06858..66c5d130c8c24c4f3101ce78296460da4487f38b 100644 (file)
@@ -540,7 +540,7 @@ static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block,
        bio_init(&b->bio);
        b->bio.bi_io_vec = b->bio_vec;
        b->bio.bi_max_vecs = DM_BUFIO_INLINE_VECS;
-       b->bio.bi_sector = block << b->c->sectors_per_block_bits;
+       b->bio.bi_iter.bi_sector = block << b->c->sectors_per_block_bits;
        b->bio.bi_bdev = b->c->bdev;
        b->bio.bi_end_io = end_io;
 
index 930e8c3d73e985b1e75769a9894f13ffd32d756a..1e018e986610a57ef9f82a818aa1f70a8c364e30 100644 (file)
@@ -72,7 +72,7 @@ static enum io_pattern iot_pattern(struct io_tracker *t)
 
 static void iot_update_stats(struct io_tracker *t, struct bio *bio)
 {
-       if (bio->bi_sector == from_oblock(t->last_end_oblock) + 1)
+       if (bio->bi_iter.bi_sector == from_oblock(t->last_end_oblock) + 1)
                t->nr_seq_samples++;
        else {
                /*
@@ -87,7 +87,7 @@ static void iot_update_stats(struct io_tracker *t, struct bio *bio)
                t->nr_rand_samples++;
        }
 
-       t->last_end_oblock = to_oblock(bio->bi_sector + bio_sectors(bio) - 1);
+       t->last_end_oblock = to_oblock(bio_end_sector(bio) - 1);
 }
 
 static void iot_check_for_pattern_switch(struct io_tracker *t)
index 09334c275c79e91c7bf4fd41e18e641b2196073a..ffd472e015caa918facaed4f65a621c0f61e58a9 100644 (file)
@@ -85,6 +85,12 @@ static void dm_unhook_bio(struct dm_hook_info *h, struct bio *bio)
 {
        bio->bi_end_io = h->bi_end_io;
        bio->bi_private = h->bi_private;
+
+       /*
+        * Must bump bi_remaining to allow bio to complete with
+        * restored bi_end_io.
+        */
+       atomic_inc(&bio->bi_remaining);
 }
 
 /*----------------------------------------------------------------*/
@@ -664,15 +670,17 @@ static void remap_to_origin(struct cache *cache, struct bio *bio)
 static void remap_to_cache(struct cache *cache, struct bio *bio,
                           dm_cblock_t cblock)
 {
-       sector_t bi_sector = bio->bi_sector;
+       sector_t bi_sector = bio->bi_iter.bi_sector;
 
        bio->bi_bdev = cache->cache_dev->bdev;
        if (!block_size_is_power_of_two(cache))
-               bio->bi_sector = (from_cblock(cblock) * cache->sectors_per_block) +
-                               sector_div(bi_sector, cache->sectors_per_block);
+               bio->bi_iter.bi_sector =
+                       (from_cblock(cblock) * cache->sectors_per_block) +
+                       sector_div(bi_sector, cache->sectors_per_block);
        else
-               bio->bi_sector = (from_cblock(cblock) << cache->sectors_per_block_shift) |
-                               (bi_sector & (cache->sectors_per_block - 1));
+               bio->bi_iter.bi_sector =
+                       (from_cblock(cblock) << cache->sectors_per_block_shift) |
+                       (bi_sector & (cache->sectors_per_block - 1));
 }
 
 static void check_if_tick_bio_needed(struct cache *cache, struct bio *bio)
@@ -712,7 +720,7 @@ static void remap_to_cache_dirty(struct cache *cache, struct bio *bio,
 
 static dm_oblock_t get_bio_block(struct cache *cache, struct bio *bio)
 {
-       sector_t block_nr = bio->bi_sector;
+       sector_t block_nr = bio->bi_iter.bi_sector;
 
        if (!block_size_is_power_of_two(cache))
                (void) sector_div(block_nr, cache->sectors_per_block);
@@ -1027,7 +1035,7 @@ static void issue_overwrite(struct dm_cache_migration *mg, struct bio *bio)
 static bool bio_writes_complete_block(struct cache *cache, struct bio *bio)
 {
        return (bio_data_dir(bio) == WRITE) &&
-               (bio->bi_size == (cache->sectors_per_block << SECTOR_SHIFT));
+               (bio->bi_iter.bi_size == (cache->sectors_per_block << SECTOR_SHIFT));
 }
 
 static void avoid_copy(struct dm_cache_migration *mg)
@@ -1252,7 +1260,7 @@ static void process_flush_bio(struct cache *cache, struct bio *bio)
        size_t pb_data_size = get_per_bio_data_size(cache);
        struct per_bio_data *pb = get_per_bio_data(bio, pb_data_size);
 
-       BUG_ON(bio->bi_size);
+       BUG_ON(bio->bi_iter.bi_size);
        if (!pb->req_nr)
                remap_to_origin(cache, bio);
        else
@@ -1275,9 +1283,9 @@ static void process_flush_bio(struct cache *cache, struct bio *bio)
  */
 static void process_discard_bio(struct cache *cache, struct bio *bio)
 {
-       dm_block_t start_block = dm_sector_div_up(bio->bi_sector,
+       dm_block_t start_block = dm_sector_div_up(bio->bi_iter.bi_sector,
                                                  cache->discard_block_size);
-       dm_block_t end_block = bio->bi_sector + bio_sectors(bio);
+       dm_block_t end_block = bio_end_sector(bio);
        dm_block_t b;
 
        end_block = block_div(end_block, cache->discard_block_size);
index 81b0fa66045204604a979fdc929e723f6c914a5c..784695d22fde1acaaf11acd78c7263438c04648e 100644 (file)
@@ -39,10 +39,8 @@ struct convert_context {
        struct completion restart;
        struct bio *bio_in;
        struct bio *bio_out;
-       unsigned int offset_in;
-       unsigned int offset_out;
-       unsigned int idx_in;
-       unsigned int idx_out;
+       struct bvec_iter iter_in;
+       struct bvec_iter iter_out;
        sector_t cc_sector;
        atomic_t cc_pending;
 };
@@ -826,10 +824,10 @@ static void crypt_convert_init(struct crypt_config *cc,
 {
        ctx->bio_in = bio_in;
        ctx->bio_out = bio_out;
-       ctx->offset_in = 0;
-       ctx->offset_out = 0;
-       ctx->idx_in = bio_in ? bio_in->bi_idx : 0;
-       ctx->idx_out = bio_out ? bio_out->bi_idx : 0;
+       if (bio_in)
+               ctx->iter_in = bio_in->bi_iter;
+       if (bio_out)
+               ctx->iter_out = bio_out->bi_iter;
        ctx->cc_sector = sector + cc->iv_offset;
        init_completion(&ctx->restart);
 }
@@ -857,8 +855,8 @@ static int crypt_convert_block(struct crypt_config *cc,
                               struct convert_context *ctx,
                               struct ablkcipher_request *req)
 {
-       struct bio_vec *bv_in = bio_iovec_idx(ctx->bio_in, ctx->idx_in);
-       struct bio_vec *bv_out = bio_iovec_idx(ctx->bio_out, ctx->idx_out);
+       struct bio_vec bv_in = bio_iter_iovec(ctx->bio_in, ctx->iter_in);
+       struct bio_vec bv_out = bio_iter_iovec(ctx->bio_out, ctx->iter_out);
        struct dm_crypt_request *dmreq;
        u8 *iv;
        int r;
@@ -869,24 +867,15 @@ static int crypt_convert_block(struct crypt_config *cc,
        dmreq->iv_sector = ctx->cc_sector;
        dmreq->ctx = ctx;
        sg_init_table(&dmreq->sg_in, 1);
-       sg_set_page(&dmreq->sg_in, bv_in->bv_page, 1 << SECTOR_SHIFT,
-                   bv_in->bv_offset + ctx->offset_in);
+       sg_set_page(&dmreq->sg_in, bv_in.bv_page, 1 << SECTOR_SHIFT,
+                   bv_in.bv_offset);
 
        sg_init_table(&dmreq->sg_out, 1);
-       sg_set_page(&dmreq->sg_out, bv_out->bv_page, 1 << SECTOR_SHIFT,
-                   bv_out->bv_offset + ctx->offset_out);
+       sg_set_page(&dmreq->sg_out, bv_out.bv_page, 1 << SECTOR_SHIFT,
+                   bv_out.bv_offset);
 
-       ctx->offset_in += 1 << SECTOR_SHIFT;
-       if (ctx->offset_in >= bv_in->bv_len) {
-               ctx->offset_in = 0;
-               ctx->idx_in++;
-       }
-
-       ctx->offset_out += 1 << SECTOR_SHIFT;
-       if (ctx->offset_out >= bv_out->bv_len) {
-               ctx->offset_out = 0;
-               ctx->idx_out++;
-       }
+       bio_advance_iter(ctx->bio_in, &ctx->iter_in, 1 << SECTOR_SHIFT);
+       bio_advance_iter(ctx->bio_out, &ctx->iter_out, 1 << SECTOR_SHIFT);
 
        if (cc->iv_gen_ops) {
                r = cc->iv_gen_ops->generator(cc, iv, dmreq);
@@ -937,8 +926,7 @@ static int crypt_convert(struct crypt_config *cc,
 
        atomic_set(&ctx->cc_pending, 1);
 
-       while(ctx->idx_in < ctx->bio_in->bi_vcnt &&
-             ctx->idx_out < ctx->bio_out->bi_vcnt) {
+       while (ctx->iter_in.bi_size && ctx->iter_out.bi_size) {
 
                crypt_alloc_req(cc, ctx);
 
@@ -1021,7 +1009,7 @@ static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size,
                size -= len;
        }
 
-       if (!clone->bi_size) {
+       if (!clone->bi_iter.bi_size) {
                bio_put(clone);
                return NULL;
        }
@@ -1161,7 +1149,7 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
        crypt_inc_pending(io);
 
        clone_init(io, clone);
-       clone->bi_sector = cc->start + io->sector;
+       clone->bi_iter.bi_sector = cc->start + io->sector;
 
        generic_make_request(clone);
        return 0;
@@ -1207,9 +1195,9 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
        }
 
        /* crypt_convert should have filled the clone bio */
-       BUG_ON(io->ctx.idx_out < clone->bi_vcnt);
+       BUG_ON(io->ctx.iter_out.bi_size);
 
-       clone->bi_sector = cc->start + io->sector;
+       clone->bi_iter.bi_sector = cc->start + io->sector;
 
        if (async)
                kcryptd_queue_io(io);
@@ -1224,7 +1212,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
        struct dm_crypt_io *new_io;
        int crypt_finished;
        unsigned out_of_pages = 0;
-       unsigned remaining = io->base_bio->bi_size;
+       unsigned remaining = io->base_bio->bi_iter.bi_size;
        sector_t sector = io->sector;
        int r;
 
@@ -1246,9 +1234,9 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
                }
 
                io->ctx.bio_out = clone;
-               io->ctx.idx_out = 0;
+               io->ctx.iter_out = clone->bi_iter;
 
-               remaining -= clone->bi_size;
+               remaining -= clone->bi_iter.bi_size;
                sector += bio_sectors(clone);
 
                crypt_inc_pending(io);
@@ -1290,8 +1278,7 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
                        crypt_inc_pending(new_io);
                        crypt_convert_init(cc, &new_io->ctx, NULL,
                                           io->base_bio, sector);
-                       new_io->ctx.idx_in = io->ctx.idx_in;
-                       new_io->ctx.offset_in = io->ctx.offset_in;
+                       new_io->ctx.iter_in = io->ctx.iter_in;
 
                        /*
                         * Fragments after the first use the base_io
@@ -1869,11 +1856,12 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
        if (unlikely(bio->bi_rw & (REQ_FLUSH | REQ_DISCARD))) {
                bio->bi_bdev = cc->dev->bdev;
                if (bio_sectors(bio))
-                       bio->bi_sector = cc->start + dm_target_offset(ti, bio->bi_sector);
+                       bio->bi_iter.bi_sector = cc->start +
+                               dm_target_offset(ti, bio->bi_iter.bi_sector);
                return DM_MAPIO_REMAPPED;
        }
 
-       io = crypt_io_alloc(cc, bio, dm_target_offset(ti, bio->bi_sector));
+       io = crypt_io_alloc(cc, bio, dm_target_offset(ti, bio->bi_iter.bi_sector));
 
        if (bio_data_dir(io->base_bio) == READ) {
                if (kcryptd_io_read(io, GFP_NOWAIT))
index a8a511c053a5d5fda6574933e616719256768d31..42c3a27a14cc3a906b5f892a6206de348b6b58ee 100644 (file)
@@ -277,14 +277,15 @@ static int delay_map(struct dm_target *ti, struct bio *bio)
        if ((bio_data_dir(bio) == WRITE) && (dc->dev_write)) {
                bio->bi_bdev = dc->dev_write->bdev;
                if (bio_sectors(bio))
-                       bio->bi_sector = dc->start_write +
-                                        dm_target_offset(ti, bio->bi_sector);
+                       bio->bi_iter.bi_sector = dc->start_write +
+                               dm_target_offset(ti, bio->bi_iter.bi_sector);
 
                return delay_bio(dc, dc->write_delay, bio);
        }
 
        bio->bi_bdev = dc->dev_read->bdev;
-       bio->bi_sector = dc->start_read + dm_target_offset(ti, bio->bi_sector);
+       bio->bi_iter.bi_sector = dc->start_read +
+               dm_target_offset(ti, bio->bi_iter.bi_sector);
 
        return delay_bio(dc, dc->read_delay, bio);
 }
index c80a0ec5f1269b40be7da133c68c6e789c5e5329..b257e46876d357f831bf1c751010d5b16fa125b8 100644 (file)
@@ -248,7 +248,8 @@ static void flakey_map_bio(struct dm_target *ti, struct bio *bio)
 
        bio->bi_bdev = fc->dev->bdev;
        if (bio_sectors(bio))
-               bio->bi_sector = flakey_map_sector(ti, bio->bi_sector);
+               bio->bi_iter.bi_sector =
+                       flakey_map_sector(ti, bio->bi_iter.bi_sector);
 }
 
 static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
@@ -265,8 +266,8 @@ static void corrupt_bio_data(struct bio *bio, struct flakey_c *fc)
                DMDEBUG("Corrupting data bio=%p by writing %u to byte %u "
                        "(rw=%c bi_rw=%lu bi_sector=%llu cur_bytes=%u)\n",
                        bio, fc->corrupt_bio_value, fc->corrupt_bio_byte,
-                       (bio_data_dir(bio) == WRITE) ? 'w' : 'r',
-                       bio->bi_rw, (unsigned long long)bio->bi_sector, bio_bytes);
+                       (bio_data_dir(bio) == WRITE) ? 'w' : 'r', bio->bi_rw,
+                       (unsigned long long)bio->bi_iter.bi_sector, bio_bytes);
        }
 }
 
index 2a20986a2fec9701cd25e443c990f2b7a8479f9f..b2b8a10e842784de5454e2639474f1a208b4b3f1 100644 (file)
@@ -201,26 +201,29 @@ static void list_dp_init(struct dpages *dp, struct page_list *pl, unsigned offse
 /*
  * Functions for getting the pages from a bvec.
  */
-static void bvec_get_page(struct dpages *dp,
+static void bio_get_page(struct dpages *dp,
                  struct page **p, unsigned long *len, unsigned *offset)
 {
-       struct bio_vec *bvec = (struct bio_vec *) dp->context_ptr;
-       *p = bvec->bv_page;
-       *len = bvec->bv_len;
-       *offset = bvec->bv_offset;
+       struct bio *bio = dp->context_ptr;
+       struct bio_vec bvec = bio_iovec(bio);
+       *p = bvec.bv_page;
+       *len = bvec.bv_len;
+       *offset = bvec.bv_offset;
 }
 
-static void bvec_next_page(struct dpages *dp)
+static void bio_next_page(struct dpages *dp)
 {
-       struct bio_vec *bvec = (struct bio_vec *) dp->context_ptr;
-       dp->context_ptr = bvec + 1;
+       struct bio *bio = dp->context_ptr;
+       struct bio_vec bvec = bio_iovec(bio);
+
+       bio_advance(bio, bvec.bv_len);
 }
 
-static void bvec_dp_init(struct dpages *dp, struct bio_vec *bvec)
+static void bio_dp_init(struct dpages *dp, struct bio *bio)
 {
-       dp->get_page = bvec_get_page;
-       dp->next_page = bvec_next_page;
-       dp->context_ptr = bvec;
+       dp->get_page = bio_get_page;
+       dp->next_page = bio_next_page;
+       dp->context_ptr = bio;
 }
 
 /*
@@ -304,14 +307,14 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                                          dm_sector_div_up(remaining, (PAGE_SIZE >> SECTOR_SHIFT)));
 
                bio = bio_alloc_bioset(GFP_NOIO, num_bvecs, io->client->bios);
-               bio->bi_sector = where->sector + (where->count - remaining);
+               bio->bi_iter.bi_sector = where->sector + (where->count - remaining);
                bio->bi_bdev = where->bdev;
                bio->bi_end_io = endio;
                store_io_and_region_in_bio(bio, io, region);
 
                if (rw & REQ_DISCARD) {
                        num_sectors = min_t(sector_t, q->limits.max_discard_sectors, remaining);
-                       bio->bi_size = num_sectors << SECTOR_SHIFT;
+                       bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
                        remaining -= num_sectors;
                } else if (rw & REQ_WRITE_SAME) {
                        /*
@@ -320,7 +323,7 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
                        dp->get_page(dp, &page, &len, &offset);
                        bio_add_page(bio, page, logical_block_size, offset);
                        num_sectors = min_t(sector_t, q->limits.max_write_same_sectors, remaining);
-                       bio->bi_size = num_sectors << SECTOR_SHIFT;
+                       bio->bi_iter.bi_size = num_sectors << SECTOR_SHIFT;
 
                        offset = 0;
                        remaining -= num_sectors;
@@ -457,8 +460,8 @@ static int dp_init(struct dm_io_request *io_req, struct dpages *dp,
                list_dp_init(dp, io_req->mem.ptr.pl, io_req->mem.offset);
                break;
 
-       case DM_IO_BVEC:
-               bvec_dp_init(dp, io_req->mem.ptr.bvec);
+       case DM_IO_BIO:
+               bio_dp_init(dp, io_req->mem.ptr.bio);
                break;
 
        case DM_IO_VMA:
index 4f99d267340cdb48c3a7b64edcdd4ed9a7fd48ea..53e848c1093936560a9554c9fdacbec2f6dae5bd 100644 (file)
@@ -85,7 +85,8 @@ static void linear_map_bio(struct dm_target *ti, struct bio *bio)
 
        bio->bi_bdev = lc->dev->bdev;
        if (bio_sectors(bio))
-               bio->bi_sector = linear_map_sector(ti, bio->bi_sector);
+               bio->bi_iter.bi_sector =
+                       linear_map_sector(ti, bio->bi_iter.bi_sector);
 }
 
 static int linear_map(struct dm_target *ti, struct bio *bio)
index 9584443c56148608d159ceab1d436fd6bacfda3b..f284e0bfb25fca869855f390f2d8d7a5519a0864 100644 (file)
@@ -432,7 +432,7 @@ static int mirror_available(struct mirror_set *ms, struct bio *bio)
        region_t region = dm_rh_bio_to_region(ms->rh, bio);
 
        if (log->type->in_sync(log, region, 0))
-               return choose_mirror(ms,  bio->bi_sector) ? 1 : 0;
+               return choose_mirror(ms,  bio->bi_iter.bi_sector) ? 1 : 0;
 
        return 0;
 }
@@ -442,15 +442,15 @@ static int mirror_available(struct mirror_set *ms, struct bio *bio)
  */
 static sector_t map_sector(struct mirror *m, struct bio *bio)
 {
-       if (unlikely(!bio->bi_size))
+       if (unlikely(!bio->bi_iter.bi_size))
                return 0;
-       return m->offset + dm_target_offset(m->ms->ti, bio->bi_sector);
+       return m->offset + dm_target_offset(m->ms->ti, bio->bi_iter.bi_sector);
 }
 
 static void map_bio(struct mirror *m, struct bio *bio)
 {
        bio->bi_bdev = m->dev->bdev;
-       bio->bi_sector = map_sector(m, bio);
+       bio->bi_iter.bi_sector = map_sector(m, bio);
 }
 
 static void map_region(struct dm_io_region *io, struct mirror *m,
@@ -526,8 +526,8 @@ static void read_async_bio(struct mirror *m, struct bio *bio)
        struct dm_io_region io;
        struct dm_io_request io_req = {
                .bi_rw = READ,
-               .mem.type = DM_IO_BVEC,
-               .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx,
+               .mem.type = DM_IO_BIO,
+               .mem.ptr.bio = bio,
                .notify.fn = read_callback,
                .notify.context = bio,
                .client = m->ms->io_client,
@@ -559,7 +559,7 @@ static void do_reads(struct mirror_set *ms, struct bio_list *reads)
                 * We can only read balance if the region is in sync.
                 */
                if (likely(region_in_sync(ms, region, 1)))
-                       m = choose_mirror(ms, bio->bi_sector);
+                       m = choose_mirror(ms, bio->bi_iter.bi_sector);
                else if (m && atomic_read(&m->error_count))
                        m = NULL;
 
@@ -629,8 +629,8 @@ static void do_write(struct mirror_set *ms, struct bio *bio)
        struct mirror *m;
        struct dm_io_request io_req = {
                .bi_rw = WRITE | (bio->bi_rw & WRITE_FLUSH_FUA),
-               .mem.type = DM_IO_BVEC,
-               .mem.ptr.bvec = bio->bi_io_vec + bio->bi_idx,
+               .mem.type = DM_IO_BIO,
+               .mem.ptr.bio = bio,
                .notify.fn = write_callback,
                .notify.context = bio,
                .client = ms->io_client,
@@ -1181,7 +1181,7 @@ static int mirror_map(struct dm_target *ti, struct bio *bio)
         * The region is in-sync and we can perform reads directly.
         * Store enough information so we can retry if it fails.
         */
-       m = choose_mirror(ms, bio->bi_sector);
+       m = choose_mirror(ms, bio->bi_iter.bi_sector);
        if (unlikely(!m))
                return -EIO;
 
index 69732e03eb3490d636a0183bd22303742ab65c65..b929fd5f4984bb67fbb62474e24e5af425758770 100644 (file)
@@ -126,7 +126,8 @@ EXPORT_SYMBOL_GPL(dm_rh_region_to_sector);
 
 region_t dm_rh_bio_to_region(struct dm_region_hash *rh, struct bio *bio)
 {
-       return dm_rh_sector_to_region(rh, bio->bi_sector - rh->target_begin);
+       return dm_rh_sector_to_region(rh, bio->bi_iter.bi_sector -
+                                     rh->target_begin);
 }
 EXPORT_SYMBOL_GPL(dm_rh_bio_to_region);
 
index 717718558bd9908469b23bbb9b3cd0223ac243f3..ebddef5237e4b28e6254e486b3267dbccca9864e 100644 (file)
@@ -1438,6 +1438,7 @@ out:
        if (full_bio) {
                full_bio->bi_end_io = pe->full_bio_end_io;
                full_bio->bi_private = pe->full_bio_private;
+               atomic_inc(&full_bio->bi_remaining);
        }
        free_pending_exception(pe);
 
@@ -1619,11 +1620,10 @@ static void remap_exception(struct dm_snapshot *s, struct dm_exception *e,
                            struct bio *bio, chunk_t chunk)
 {
        bio->bi_bdev = s->cow->bdev;
-       bio->bi_sector = chunk_to_sector(s->store,
-                                        dm_chunk_number(e->new_chunk) +
-                                        (chunk - e->old_chunk)) +
-                                        (bio->bi_sector &
-                                         s->store->chunk_mask);
+       bio->bi_iter.bi_sector =
+               chunk_to_sector(s->store, dm_chunk_number(e->new_chunk) +
+                               (chunk - e->old_chunk)) +
+               (bio->bi_iter.bi_sector & s->store->chunk_mask);
 }
 
 static int snapshot_map(struct dm_target *ti, struct bio *bio)
@@ -1641,7 +1641,7 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_REMAPPED;
        }
 
-       chunk = sector_to_chunk(s->store, bio->bi_sector);
+       chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector);
 
        /* Full snapshots are not usable */
        /* To get here the table must be live so s->active is always set. */
@@ -1702,7 +1702,8 @@ static int snapshot_map(struct dm_target *ti, struct bio *bio)
                r = DM_MAPIO_SUBMITTED;
 
                if (!pe->started &&
-                   bio->bi_size == (s->store->chunk_size << SECTOR_SHIFT)) {
+                   bio->bi_iter.bi_size ==
+                   (s->store->chunk_size << SECTOR_SHIFT)) {
                        pe->started = 1;
                        up_write(&s->lock);
                        start_full_bio(pe, bio);
@@ -1758,7 +1759,7 @@ static int snapshot_merge_map(struct dm_target *ti, struct bio *bio)
                return DM_MAPIO_REMAPPED;
        }
 
-       chunk = sector_to_chunk(s->store, bio->bi_sector);
+       chunk = sector_to_chunk(s->store, bio->bi_iter.bi_sector);
 
        down_write(&s->lock);
 
@@ -2095,7 +2096,7 @@ static int do_origin(struct dm_dev *origin, struct bio *bio)
        down_read(&_origins_lock);
        o = __lookup_origin(origin->bdev);
        if (o)
-               r = __origin_write(&o->snapshots, bio->bi_sector, bio);
+               r = __origin_write(&o->snapshots, bio->bi_iter.bi_sector, bio);
        up_read(&_origins_lock);
 
        return r;
index 73c1712dad96d09f2760416852dd0cacd22cbd33..d1600d2aa2e2e6983643ef0ef864195f858d4f9d 100644 (file)
@@ -259,13 +259,15 @@ static int stripe_map_range(struct stripe_c *sc, struct bio *bio,
 {
        sector_t begin, end;
 
-       stripe_map_range_sector(sc, bio->bi_sector, target_stripe, &begin);
+       stripe_map_range_sector(sc, bio->bi_iter.bi_sector,
+                               target_stripe, &begin);
        stripe_map_range_sector(sc, bio_end_sector(bio),
                                target_stripe, &end);
        if (begin < end) {
                bio->bi_bdev = sc->stripe[target_stripe].dev->bdev;
-               bio->bi_sector = begin + sc->stripe[target_stripe].physical_start;
-               bio->bi_size = to_bytes(end - begin);
+               bio->bi_iter.bi_sector = begin +
+                       sc->stripe[target_stripe].physical_start;
+               bio->bi_iter.bi_size = to_bytes(end - begin);
                return DM_MAPIO_REMAPPED;
        } else {
                /* The range doesn't map to the target stripe */
@@ -293,9 +295,10 @@ static int stripe_map(struct dm_target *ti, struct bio *bio)
                return stripe_map_range(sc, bio, target_bio_nr);
        }
 
-       stripe_map_sector(sc, bio->bi_sector, &stripe, &bio->bi_sector);
+       stripe_map_sector(sc, bio->bi_iter.bi_sector,
+                         &stripe, &bio->bi_iter.bi_sector);
 
-       bio->bi_sector += sc->stripe[stripe].physical_start;
+       bio->bi_iter.bi_sector += sc->stripe[stripe].physical_start;
        bio->bi_bdev = sc->stripe[stripe].dev->bdev;
 
        return DM_MAPIO_REMAPPED;
index ff9ac4be47210839369e233d1d1dfc161cbfb852..09a688b3d48ca1445e136544321a54b112b280e1 100644 (file)
@@ -311,11 +311,11 @@ error:
 static int switch_map(struct dm_target *ti, struct bio *bio)
 {
        struct switch_ctx *sctx = ti->private;
-       sector_t offset = dm_target_offset(ti, bio->bi_sector);
+       sector_t offset = dm_target_offset(ti, bio->bi_iter.bi_sector);
        unsigned path_nr = switch_get_path_nr(sctx, offset);
 
        bio->bi_bdev = sctx->path_list[path_nr].dmdev->bdev;
-       bio->bi_sector = sctx->path_list[path_nr].start + offset;
+       bio->bi_iter.bi_sector = sctx->path_list[path_nr].start + offset;
 
        return DM_MAPIO_REMAPPED;
 }
index 726228b33a012f9994fc2f8843b25a0ca46ef966..faaf944597ab7669b90f3ecb85152fbcd16cbe33 100644 (file)
@@ -414,7 +414,7 @@ static bool block_size_is_power_of_two(struct pool *pool)
 static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio)
 {
        struct pool *pool = tc->pool;
-       sector_t block_nr = bio->bi_sector;
+       sector_t block_nr = bio->bi_iter.bi_sector;
 
        if (block_size_is_power_of_two(pool))
                block_nr >>= pool->sectors_per_block_shift;
@@ -427,14 +427,15 @@ static dm_block_t get_bio_block(struct thin_c *tc, struct bio *bio)
 static void remap(struct thin_c *tc, struct bio *bio, dm_block_t block)
 {
        struct pool *pool = tc->pool;
-       sector_t bi_sector = bio->bi_sector;
+       sector_t bi_sector = bio->bi_iter.bi_sector;
 
        bio->bi_bdev = tc->pool_dev->bdev;
        if (block_size_is_power_of_two(pool))
-               bio->bi_sector = (block << pool->sectors_per_block_shift) |
-                               (bi_sector & (pool->sectors_per_block - 1));
+               bio->bi_iter.bi_sector =
+                       (block << pool->sectors_per_block_shift) |
+                       (bi_sector & (pool->sectors_per_block - 1));
        else
-               bio->bi_sector = (block * pool->sectors_per_block) +
+               bio->bi_iter.bi_sector = (block * pool->sectors_per_block) +
                                 sector_div(bi_sector, pool->sectors_per_block);
 }
 
@@ -612,8 +613,10 @@ static void cell_defer_no_holder(struct thin_c *tc, struct dm_bio_prison_cell *c
 
 static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m)
 {
-       if (m->bio)
+       if (m->bio) {
                m->bio->bi_end_io = m->saved_bi_end_io;
+               atomic_inc(&m->bio->bi_remaining);
+       }
        cell_error(m->tc->pool, m->cell);
        list_del(&m->list);
        mempool_free(m, m->tc->pool->mapping_pool);
@@ -627,8 +630,10 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
        int r;
 
        bio = m->bio;
-       if (bio)
+       if (bio) {
                bio->bi_end_io = m->saved_bi_end_io;
+               atomic_inc(&bio->bi_remaining);
+       }
 
        if (m->err) {
                cell_error(pool, m->cell);
@@ -731,7 +736,8 @@ static void process_prepared(struct pool *pool, struct list_head *head,
  */
 static int io_overlaps_block(struct pool *pool, struct bio *bio)
 {
-       return bio->bi_size == (pool->sectors_per_block << SECTOR_SHIFT);
+       return bio->bi_iter.bi_size ==
+               (pool->sectors_per_block << SECTOR_SHIFT);
 }
 
 static int io_overwrites_block(struct pool *pool, struct bio *bio)
@@ -1136,7 +1142,7 @@ static void process_shared_bio(struct thin_c *tc, struct bio *bio,
        if (bio_detain(pool, &key, bio, &cell))
                return;
 
-       if (bio_data_dir(bio) == WRITE && bio->bi_size)
+       if (bio_data_dir(bio) == WRITE && bio->bi_iter.bi_size)
                break_sharing(tc, bio, block, &key, lookup_result, cell);
        else {
                struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
@@ -1159,7 +1165,7 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
        /*
         * Remap empty bios (flushes) immediately, without provisioning.
         */
-       if (!bio->bi_size) {
+       if (!bio->bi_iter.bi_size) {
                inc_all_io_entry(pool, bio);
                cell_defer_no_holder(tc, cell);
 
@@ -1258,7 +1264,7 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
        r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
        switch (r) {
        case 0:
-               if (lookup_result.shared && (rw == WRITE) && bio->bi_size)
+               if (lookup_result.shared && (rw == WRITE) && bio->bi_iter.bi_size)
                        handle_unserviceable_bio(tc->pool, bio);
                else {
                        inc_all_io_entry(tc->pool, bio);
@@ -2939,7 +2945,7 @@ out_unlock:
 
 static int thin_map(struct dm_target *ti, struct bio *bio)
 {
-       bio->bi_sector = dm_target_offset(ti, bio->bi_sector);
+       bio->bi_iter.bi_sector = dm_target_offset(ti, bio->bi_iter.bi_sector);
 
        return thin_bio_map(ti, bio);
 }
index 4b7941db3aff33223481464f24a162d101ab7698..796007a5e0e1a4b6e83b0871c1fca1ef8c0c461f 100644 (file)
@@ -73,15 +73,10 @@ struct dm_verity_io {
        sector_t block;
        unsigned n_blocks;
 
-       /* saved bio vector */
-       struct bio_vec *io_vec;
-       unsigned io_vec_size;
+       struct bvec_iter iter;
 
        struct work_struct work;
 
-       /* A space for short vectors; longer vectors are allocated separately. */
-       struct bio_vec io_vec_inline[DM_VERITY_IO_VEC_INLINE];
-
        /*
         * Three variably-size fields follow this struct:
         *
@@ -284,9 +279,10 @@ release_ret_r:
 static int verity_verify_io(struct dm_verity_io *io)
 {
        struct dm_verity *v = io->v;
+       struct bio *bio = dm_bio_from_per_bio_data(io,
+                                                  v->ti->per_bio_data_size);
        unsigned b;
        int i;
-       unsigned vector = 0, offset = 0;
 
        for (b = 0; b < io->n_blocks; b++) {
                struct shash_desc *desc;
@@ -336,31 +332,22 @@ test_block_hash:
                }
 
                todo = 1 << v->data_dev_block_bits;
-               do {
-                       struct bio_vec *bv;
+               while (io->iter.bi_size) {
                        u8 *page;
-                       unsigned len;
-
-                       BUG_ON(vector >= io->io_vec_size);
-                       bv = &io->io_vec[vector];
-                       page = kmap_atomic(bv->bv_page);
-                       len = bv->bv_len - offset;
-                       if (likely(len >= todo))
-                               len = todo;
-                       r = crypto_shash_update(desc,
-                                       page + bv->bv_offset + offset, len);
+                       struct bio_vec bv = bio_iter_iovec(bio, io->iter);
+
+                       page = kmap_atomic(bv.bv_page);
+                       r = crypto_shash_update(desc, page + bv.bv_offset,
+                                               bv.bv_len);
                        kunmap_atomic(page);
+
                        if (r < 0) {
                                DMERR("crypto_shash_update failed: %d", r);
                                return r;
                        }
-                       offset += len;
-                       if (likely(offset == bv->bv_len)) {
-                               offset = 0;
-                               vector++;
-                       }
-                       todo -= len;
-               } while (todo);
+
+                       bio_advance_iter(bio, &io->iter, bv.bv_len);
+               }
 
                if (!v->version) {
                        r = crypto_shash_update(desc, v->salt, v->salt_size);
@@ -383,8 +370,6 @@ test_block_hash:
                        return -EIO;
                }
        }
-       BUG_ON(vector != io->io_vec_size);
-       BUG_ON(offset);
 
        return 0;
 }
@@ -400,10 +385,7 @@ static void verity_finish_io(struct dm_verity_io *io, int error)
        bio->bi_end_io = io->orig_bi_end_io;
        bio->bi_private = io->orig_bi_private;
 
-       if (io->io_vec != io->io_vec_inline)
-               mempool_free(io->io_vec, v->vec_mempool);
-
-       bio_endio(bio, error);
+       bio_endio_nodec(bio, error);
 }
 
 static void verity_work(struct work_struct *w)
@@ -493,9 +475,9 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
        struct dm_verity_io *io;
 
        bio->bi_bdev = v->data_dev->bdev;
-       bio->bi_sector = verity_map_sector(v, bio->bi_sector);
+       bio->bi_iter.bi_sector = verity_map_sector(v, bio->bi_iter.bi_sector);
 
-       if (((unsigned)bio->bi_sector | bio_sectors(bio)) &
+       if (((unsigned)bio->bi_iter.bi_sector | bio_sectors(bio)) &
            ((1 << (v->data_dev_block_bits - SECTOR_SHIFT)) - 1)) {
                DMERR_LIMIT("unaligned io");
                return -EIO;
@@ -514,18 +496,12 @@ static int verity_map(struct dm_target *ti, struct bio *bio)
        io->v = v;
        io->orig_bi_end_io = bio->bi_end_io;
        io->orig_bi_private = bio->bi_private;
-       io->block = bio->bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
-       io->n_blocks = bio->bi_size >> v->data_dev_block_bits;
+       io->block = bio->bi_iter.bi_sector >> (v->data_dev_block_bits - SECTOR_SHIFT);
+       io->n_blocks = bio->bi_iter.bi_size >> v->data_dev_block_bits;
 
        bio->bi_end_io = verity_end_io;
        bio->bi_private = io;
-       io->io_vec_size = bio_segments(bio);
-       if (io->io_vec_size < DM_VERITY_IO_VEC_INLINE)
-               io->io_vec = io->io_vec_inline;
-       else
-               io->io_vec = mempool_alloc(v->vec_mempool, GFP_NOIO);
-       memcpy(io->io_vec, bio_iovec(bio),
-              io->io_vec_size * sizeof(struct bio_vec));
+       io->iter = bio->bi_iter;
 
        verity_submit_prefetch(v, io);
 
index b49c7628424171f0622ed4446e5c4111b00ba418..8c53b09b9a2c5a3050b22f4fba82af5563f1d59a 100644 (file)
@@ -575,7 +575,7 @@ static void start_io_acct(struct dm_io *io)
                atomic_inc_return(&md->pending[rw]));
 
        if (unlikely(dm_stats_used(&md->stats)))
-               dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_sector,
+               dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_iter.bi_sector,
                                    bio_sectors(bio), false, 0, &io->stats_aux);
 }
 
@@ -593,7 +593,7 @@ static void end_io_acct(struct dm_io *io)
        part_stat_unlock();
 
        if (unlikely(dm_stats_used(&md->stats)))
-               dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_sector,
+               dm_stats_account_io(&md->stats, bio->bi_rw, bio->bi_iter.bi_sector,
                                    bio_sectors(bio), true, duration, &io->stats_aux);
 
        /*
@@ -742,7 +742,7 @@ static void dec_pending(struct dm_io *io, int error)
                if (io_error == DM_ENDIO_REQUEUE)
                        return;
 
-               if ((bio->bi_rw & REQ_FLUSH) && bio->bi_size) {
+               if ((bio->bi_rw & REQ_FLUSH) && bio->bi_iter.bi_size) {
                        /*
                         * Preflush done for flush with data, reissue
                         * without REQ_FLUSH.
@@ -797,7 +797,7 @@ static void end_clone_bio(struct bio *clone, int error)
        struct dm_rq_clone_bio_info *info = clone->bi_private;
        struct dm_rq_target_io *tio = info->tio;
        struct bio *bio = info->orig;
-       unsigned int nr_bytes = info->orig->bi_size;
+       unsigned int nr_bytes = info->orig->bi_iter.bi_size;
 
        bio_put(clone);
 
@@ -1128,7 +1128,7 @@ static void __map_bio(struct dm_target_io *tio)
         * this io.
         */
        atomic_inc(&tio->io->io_count);
-       sector = clone->bi_sector;
+       sector = clone->bi_iter.bi_sector;
        r = ti->type->map(ti, clone);
        if (r == DM_MAPIO_REMAPPED) {
                /* the bio has been remapped so dispatch it */
@@ -1155,76 +1155,32 @@ struct clone_info {
        struct dm_io *io;
        sector_t sector;
        sector_t sector_count;
-       unsigned short idx;
 };
 
 static void bio_setup_sector(struct bio *bio, sector_t sector, sector_t len)
 {
-       bio->bi_sector = sector;
-       bio->bi_size = to_bytes(len);
-}
-
-static void bio_setup_bv(struct bio *bio, unsigned short idx, unsigned short bv_count)
-{
-       bio->bi_idx = idx;
-       bio->bi_vcnt = idx + bv_count;
-       bio->bi_flags &= ~(1 << BIO_SEG_VALID);
-}
-
-static void clone_bio_integrity(struct bio *bio, struct bio *clone,
-                               unsigned short idx, unsigned len, unsigned offset,
-                               unsigned trim)
-{
-       if (!bio_integrity(bio))
-               return;
-
-       bio_integrity_clone(clone, bio, GFP_NOIO);
-
-       if (trim)
-               bio_integrity_trim(clone, bio_sector_offset(bio, idx, offset), len);
-}
-
-/*
- * Creates a little bio that just does part of a bvec.
- */
-static void clone_split_bio(struct dm_target_io *tio, struct bio *bio,
-                           sector_t sector, unsigned short idx,
-                           unsigned offset, unsigned len)
-{
-       struct bio *clone = &tio->clone;
-       struct bio_vec *bv = bio->bi_io_vec + idx;
-
-       *clone->bi_io_vec = *bv;
-
-       bio_setup_sector(clone, sector, len);
-
-       clone->bi_bdev = bio->bi_bdev;
-       clone->bi_rw = bio->bi_rw;
-       clone->bi_vcnt = 1;
-       clone->bi_io_vec->bv_offset = offset;
-       clone->bi_io_vec->bv_len = clone->bi_size;
-       clone->bi_flags |= 1 << BIO_CLONED;
-
-       clone_bio_integrity(bio, clone, idx, len, offset, 1);
+       bio->bi_iter.bi_sector = sector;
+       bio->bi_iter.bi_size = to_bytes(len);
 }
 
 /*
  * Creates a bio that consists of range of complete bvecs.
  */
 static void clone_bio(struct dm_target_io *tio, struct bio *bio,
-                     sector_t sector, unsigned short idx,
-                     unsigned short bv_count, unsigned len)
+                     sector_t sector, unsigned len)
 {
        struct bio *clone = &tio->clone;
-       unsigned trim = 0;
 
-       __bio_clone(clone, bio);
-       bio_setup_sector(clone, sector, len);
-       bio_setup_bv(clone, idx, bv_count);
+       __bio_clone_fast(clone, bio);
+
+       if (bio_integrity(bio))
+               bio_integrity_clone(clone, bio, GFP_NOIO);
+
+       bio_advance(clone, to_bytes(sector - clone->bi_iter.bi_sector));
+       clone->bi_iter.bi_size = to_bytes(len);
 
-       if (idx != bio->bi_idx || clone->bi_size < bio->bi_size)
-               trim = 1;
-       clone_bio_integrity(bio, clone, idx, len, 0, trim);
+       if (bio_integrity(bio))
+               bio_integrity_trim(clone, 0, len);
 }
 
 static struct dm_target_io *alloc_tio(struct clone_info *ci,
@@ -1257,7 +1213,7 @@ static void __clone_and_map_simple_bio(struct clone_info *ci,
         * ci->bio->bi_max_vecs is BIO_INLINE_VECS anyway, for both flush
         * and discard, so no need for concern about wasted bvec allocations.
         */
-        __bio_clone(clone, ci->bio);
+        __bio_clone_fast(clone, ci->bio);
        if (len)
                bio_setup_sector(clone, ci->sector, len);
 
@@ -1286,10 +1242,7 @@ static int __send_empty_flush(struct clone_info *ci)
 }
 
 static void __clone_and_map_data_bio(struct clone_info *ci, struct dm_target *ti,
-                                    sector_t sector, int nr_iovecs,
-                                    unsigned short idx, unsigned short bv_count,
-                                    unsigned offset, unsigned len,
-                                    unsigned split_bvec)
+                                    sector_t sector, unsigned len)
 {
        struct bio *bio = ci->bio;
        struct dm_target_io *tio;
@@ -1303,11 +1256,8 @@ static void __clone_and_map_data_bio(struct clone_info *ci, struct dm_target *ti
                num_target_bios = ti->num_write_bios(ti, bio);
 
        for (target_bio_nr = 0; target_bio_nr < num_target_bios; target_bio_nr++) {
-               tio = alloc_tio(ci, ti, nr_iovecs, target_bio_nr);
-               if (split_bvec)
-                       clone_split_bio(tio, bio, sector, idx, offset, len);
-               else
-                       clone_bio(tio, bio, sector, idx, bv_count, len);
+               tio = alloc_tio(ci, ti, 0, target_bio_nr);
+               clone_bio(tio, bio, sector, len);
                __map_bio(tio);
        }
 }
@@ -1378,60 +1328,6 @@ static int __send_write_same(struct clone_info *ci)
        return __send_changing_extent_only(ci, get_num_write_same_bios, NULL);
 }
 
-/*
- * Find maximum number of sectors / bvecs we can process with a single bio.
- */
-static sector_t __len_within_target(struct clone_info *ci, sector_t max, int *idx)
-{
-       struct bio *bio = ci->bio;
-       sector_t bv_len, total_len = 0;
-
-       for (*idx = ci->idx; max && (*idx < bio->bi_vcnt); (*idx)++) {
-               bv_len = to_sector(bio->bi_io_vec[*idx].bv_len);
-
-               if (bv_len > max)
-                       break;
-
-               max -= bv_len;
-               total_len += bv_len;
-       }
-
-       return total_len;
-}
-
-static int __split_bvec_across_targets(struct clone_info *ci,
-                                      struct dm_target *ti, sector_t max)
-{
-       struct bio *bio = ci->bio;
-       struct bio_vec *bv = bio->bi_io_vec + ci->idx;
-       sector_t remaining = to_sector(bv->bv_len);
-       unsigned offset = 0;
-       sector_t len;
-
-       do {
-               if (offset) {
-                       ti = dm_table_find_target(ci->map, ci->sector);
-                       if (!dm_target_is_valid(ti))
-                               return -EIO;
-
-                       max = max_io_len(ci->sector, ti);
-               }
-
-               len = min(remaining, max);
-
-               __clone_and_map_data_bio(ci, ti, ci->sector, 1, ci->idx, 0,
-                                        bv->bv_offset + offset, len, 1);
-
-               ci->sector += len;
-               ci->sector_count -= len;
-               offset += to_bytes(len);
-       } while (remaining -= len);
-
-       ci->idx++;
-
-       return 0;
-}
-
 /*
  * Select the correct strategy for processing a non-flush bio.
  */
@@ -1439,8 +1335,7 @@ static int __split_and_process_non_flush(struct clone_info *ci)
 {
        struct bio *bio = ci->bio;
        struct dm_target *ti;
-       sector_t len, max;
-       int idx;
+       unsigned len;
 
        if (unlikely(bio->bi_rw & REQ_DISCARD))
                return __send_discard(ci);
@@ -1451,41 +1346,14 @@ static int __split_and_process_non_flush(struct clone_info *ci)
        if (!dm_target_is_valid(ti))
                return -EIO;
 
-       max = max_io_len(ci->sector, ti);
-
-       /*
-        * Optimise for the simple case where we can do all of
-        * the remaining io with a single clone.
-        */
-       if (ci->sector_count <= max) {
-               __clone_and_map_data_bio(ci, ti, ci->sector, bio->bi_max_vecs,
-                                        ci->idx, bio->bi_vcnt - ci->idx, 0,
-                                        ci->sector_count, 0);
-               ci->sector_count = 0;
-               return 0;
-       }
-
-       /*
-        * There are some bvecs that don't span targets.
-        * Do as many of these as possible.
-        */
-       if (to_sector(bio->bi_io_vec[ci->idx].bv_len) <= max) {
-               len = __len_within_target(ci, max, &idx);
-
-               __clone_and_map_data_bio(ci, ti, ci->sector, bio->bi_max_vecs,
-                                        ci->idx, idx - ci->idx, 0, len, 0);
+       len = min_t(sector_t, max_io_len(ci->sector, ti), ci->sector_count);
 
-               ci->sector += len;
-               ci->sector_count -= len;
-               ci->idx = idx;
+       __clone_and_map_data_bio(ci, ti, ci->sector, len);
 
-               return 0;
-       }
+       ci->sector += len;
+       ci->sector_count -= len;
 
-       /*
-        * Handle a bvec that must be split between two or more targets.
-        */
-       return __split_bvec_across_targets(ci, ti, max);
+       return 0;
 }
 
 /*
@@ -1510,8 +1378,7 @@ static void __split_and_process_bio(struct mapped_device *md,
        ci.io->bio = bio;
        ci.io->md = md;
        spin_lock_init(&ci.io->endio_lock);
-       ci.sector = bio->bi_sector;
-       ci.idx = bio->bi_idx;
+       ci.sector = bio->bi_iter.bi_sector;
 
        start_io_acct(ci.io);
 
index 3193aefe982b7b42badf4eba4adc36f89439d70c..e8b4574956c73e500cd634fa0acafad4fad0b93d 100644 (file)
@@ -74,8 +74,8 @@ static void faulty_fail(struct bio *bio, int error)
 {
        struct bio *b = bio->bi_private;
 
-       b->bi_size = bio->bi_size;
-       b->bi_sector = bio->bi_sector;
+       b->bi_iter.bi_size = bio->bi_iter.bi_size;
+       b->bi_iter.bi_sector = bio->bi_iter.bi_sector;
 
        bio_put(bio);
 
@@ -185,26 +185,31 @@ static void make_request(struct mddev *mddev, struct bio *bio)
                        return;
                }
 
-               if (check_sector(conf, bio->bi_sector, bio_end_sector(bio), WRITE))
+               if (check_sector(conf, bio->bi_iter.bi_sector,
+                                bio_end_sector(bio), WRITE))
                        failit = 1;
                if (check_mode(conf, WritePersistent)) {
-                       add_sector(conf, bio->bi_sector, WritePersistent);
+                       add_sector(conf, bio->bi_iter.bi_sector,
+                                  WritePersistent);
                        failit = 1;
                }
                if (check_mode(conf, WriteTransient))
                        failit = 1;
        } else {
                /* read request */
-               if (check_sector(conf, bio->bi_sector, bio_end_sector(bio), READ))
+               if (check_sector(conf, bio->bi_iter.bi_sector,
+                                bio_end_sector(bio), READ))
                        failit = 1;
                if (check_mode(conf, ReadTransient))
                        failit = 1;
                if (check_mode(conf, ReadPersistent)) {
-                       add_sector(conf, bio->bi_sector, ReadPersistent);
+                       add_sector(conf, bio->bi_iter.bi_sector,
+                                  ReadPersistent);
                        failit = 1;
                }
                if (check_mode(conf, ReadFixable)) {
-                       add_sector(conf, bio->bi_sector, ReadFixable);
+                       add_sector(conf, bio->bi_iter.bi_sector,
+                                  ReadFixable);
                        failit = 1;
                }
        }
index f03fabd2b37bacf34a231a0bb034a6d8f2826e68..56f534b4a2d27036b1f820f8bf4bfed56a9b2002 100644 (file)
@@ -288,65 +288,65 @@ static int linear_stop (struct mddev *mddev)
 
 static void linear_make_request(struct mddev *mddev, struct bio *bio)
 {
+       char b[BDEVNAME_SIZE];
        struct dev_info *tmp_dev;
-       sector_t start_sector;
+       struct bio *split;
+       sector_t start_sector, end_sector, data_offset;
 
        if (unlikely(bio->bi_rw & REQ_FLUSH)) {
                md_flush_request(mddev, bio);
                return;
        }
 
-       rcu_read_lock();
-       tmp_dev = which_dev(mddev, bio->bi_sector);
-       start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors;
-
-
-       if (unlikely(bio->bi_sector >= (tmp_dev->end_sector)
-                    || (bio->bi_sector < start_sector))) {
-               char b[BDEVNAME_SIZE];
-
-               printk(KERN_ERR
-                      "md/linear:%s: make_request: Sector %llu out of bounds on "
-                      "dev %s: %llu sectors, offset %llu\n",
-                      mdname(mddev),
-                      (unsigned long long)bio->bi_sector,
-                      bdevname(tmp_dev->rdev->bdev, b),
-                      (unsigned long long)tmp_dev->rdev->sectors,
-                      (unsigned long long)start_sector);
-               rcu_read_unlock();
-               bio_io_error(bio);
-               return;
-       }
-       if (unlikely(bio_end_sector(bio) > tmp_dev->end_sector)) {
-               /* This bio crosses a device boundary, so we have to
-                * split it.
-                */
-               struct bio_pair *bp;
-               sector_t end_sector = tmp_dev->end_sector;
+       do {
+               rcu_read_lock();
 
-               rcu_read_unlock();
-
-               bp = bio_split(bio, end_sector - bio->bi_sector);
+               tmp_dev = which_dev(mddev, bio->bi_iter.bi_sector);
+               start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors;
+               end_sector = tmp_dev->end_sector;
+               data_offset = tmp_dev->rdev->data_offset;
+               bio->bi_bdev = tmp_dev->rdev->bdev;
 
-               linear_make_request(mddev, &bp->bio1);
-               linear_make_request(mddev, &bp->bio2);
-               bio_pair_release(bp);
-               return;
-       }
-                   
-       bio->bi_bdev = tmp_dev->rdev->bdev;
-       bio->bi_sector = bio->bi_sector - start_sector
-               + tmp_dev->rdev->data_offset;
-       rcu_read_unlock();
+               rcu_read_unlock();
 
-       if (unlikely((bio->bi_rw & REQ_DISCARD) &&
-                    !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) {
-               /* Just ignore it */
-               bio_endio(bio, 0);
-               return;
-       }
+               if (unlikely(bio->bi_iter.bi_sector >= end_sector ||
+                            bio->bi_iter.bi_sector < start_sector))
+                       goto out_of_bounds;
+
+               if (unlikely(bio_end_sector(bio) > end_sector)) {
+                       /* This bio crosses a device boundary, so we have to
+                        * split it.
+                        */
+                       split = bio_split(bio, end_sector -
+                                         bio->bi_iter.bi_sector,
+                                         GFP_NOIO, fs_bio_set);
+                       bio_chain(split, bio);
+               } else {
+                       split = bio;
+               }
 
-       generic_make_request(bio);
+               split->bi_iter.bi_sector = split->bi_iter.bi_sector -
+                       start_sector + data_offset;
+
+               if (unlikely((split->bi_rw & REQ_DISCARD) &&
+                        !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) {
+                       /* Just ignore it */
+                       bio_endio(split, 0);
+               } else
+                       generic_make_request(split);
+       } while (split != bio);
+       return;
+
+out_of_bounds:
+       printk(KERN_ERR
+              "md/linear:%s: make_request: Sector %llu out of bounds on "
+              "dev %s: %llu sectors, offset %llu\n",
+              mdname(mddev),
+              (unsigned long long)bio->bi_iter.bi_sector,
+              bdevname(tmp_dev->rdev->bdev, b),
+              (unsigned long long)tmp_dev->rdev->sectors,
+              (unsigned long long)start_sector);
+       bio_io_error(bio);
 }
 
 static void linear_status (struct seq_file *seq, struct mddev *mddev)
index 40c531359a15af61ad9c3ba70506d1863085dffe..4ad5cc4e63e8438ca3c32fea1f40f69ec71657fb 100644 (file)
@@ -393,7 +393,7 @@ static void md_submit_flush_data(struct work_struct *ws)
        struct mddev *mddev = container_of(ws, struct mddev, flush_work);
        struct bio *bio = mddev->flush_bio;
 
-       if (bio->bi_size == 0)
+       if (bio->bi_iter.bi_size == 0)
                /* an empty barrier - all done */
                bio_endio(bio, 0);
        else {
@@ -754,7 +754,7 @@ void md_super_write(struct mddev *mddev, struct md_rdev *rdev,
        struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, mddev);
 
        bio->bi_bdev = rdev->meta_bdev ? rdev->meta_bdev : rdev->bdev;
-       bio->bi_sector = sector;
+       bio->bi_iter.bi_sector = sector;
        bio_add_page(bio, page, size, 0);
        bio->bi_private = rdev;
        bio->bi_end_io = super_written;
@@ -782,18 +782,16 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
        struct bio *bio = bio_alloc_mddev(GFP_NOIO, 1, rdev->mddev);
        int ret;
 
-       rw |= REQ_SYNC;
-
        bio->bi_bdev = (metadata_op && rdev->meta_bdev) ?
                rdev->meta_bdev : rdev->bdev;
        if (metadata_op)
-               bio->bi_sector = sector + rdev->sb_start;
+               bio->bi_iter.bi_sector = sector + rdev->sb_start;
        else if (rdev->mddev->reshape_position != MaxSector &&
                 (rdev->mddev->reshape_backwards ==
                  (sector >= rdev->mddev->reshape_position)))
-               bio->bi_sector = sector + rdev->new_data_offset;
+               bio->bi_iter.bi_sector = sector + rdev->new_data_offset;
        else
-               bio->bi_sector = sector + rdev->data_offset;
+               bio->bi_iter.bi_sector = sector + rdev->data_offset;
        bio_add_page(bio, page, size, 0);
        submit_bio_wait(rw, bio);
 
index 1642eae75a3335d1282a4bf53751802e1aeb52db..849ad39f547b9c1fbb8d993e118261a33b242134 100644 (file)
@@ -100,7 +100,7 @@ static void multipath_end_request(struct bio *bio, int error)
                md_error (mp_bh->mddev, rdev);
                printk(KERN_ERR "multipath: %s: rescheduling sector %llu\n", 
                       bdevname(rdev->bdev,b), 
-                      (unsigned long long)bio->bi_sector);
+                      (unsigned long long)bio->bi_iter.bi_sector);
                multipath_reschedule_retry(mp_bh);
        } else
                multipath_end_bh_io(mp_bh, error);
@@ -132,7 +132,7 @@ static void multipath_make_request(struct mddev *mddev, struct bio * bio)
        multipath = conf->multipaths + mp_bh->path;
 
        mp_bh->bio = *bio;
-       mp_bh->bio.bi_sector += multipath->rdev->data_offset;
+       mp_bh->bio.bi_iter.bi_sector += multipath->rdev->data_offset;
        mp_bh->bio.bi_bdev = multipath->rdev->bdev;
        mp_bh->bio.bi_rw |= REQ_FAILFAST_TRANSPORT;
        mp_bh->bio.bi_end_io = multipath_end_request;
@@ -355,21 +355,22 @@ static void multipathd(struct md_thread *thread)
                spin_unlock_irqrestore(&conf->device_lock, flags);
 
                bio = &mp_bh->bio;
-               bio->bi_sector = mp_bh->master_bio->bi_sector;
+               bio->bi_iter.bi_sector = mp_bh->master_bio->bi_iter.bi_sector;
                
                if ((mp_bh->path = multipath_map (conf))<0) {
                        printk(KERN_ALERT "multipath: %s: unrecoverable IO read"
                                " error for block %llu\n",
                                bdevname(bio->bi_bdev,b),
-                               (unsigned long long)bio->bi_sector);
+                               (unsigned long long)bio->bi_iter.bi_sector);
                        multipath_end_bh_io(mp_bh, -EIO);
                } else {
                        printk(KERN_ERR "multipath: %s: redirecting sector %llu"
                                " to another IO path\n",
                                bdevname(bio->bi_bdev,b),
-                               (unsigned long long)bio->bi_sector);
+                               (unsigned long long)bio->bi_iter.bi_sector);
                        *bio = *(mp_bh->master_bio);
-                       bio->bi_sector += conf->multipaths[mp_bh->path].rdev->data_offset;
+                       bio->bi_iter.bi_sector +=
+                               conf->multipaths[mp_bh->path].rdev->data_offset;
                        bio->bi_bdev = conf->multipaths[mp_bh->path].rdev->bdev;
                        bio->bi_rw |= REQ_FAILFAST_TRANSPORT;
                        bio->bi_end_io = multipath_end_request;
index c4d420b7d2f43d0804e1c1a94d88ca63484b5ec3..407a99e46f6993a770c21fdfff1972b7f64063b6 100644 (file)
@@ -501,10 +501,11 @@ static inline int is_io_in_chunk_boundary(struct mddev *mddev,
                        unsigned int chunk_sects, struct bio *bio)
 {
        if (likely(is_power_of_2(chunk_sects))) {
-               return chunk_sects >= ((bio->bi_sector & (chunk_sects-1))
+               return chunk_sects >=
+                       ((bio->bi_iter.bi_sector & (chunk_sects-1))
                                        + bio_sectors(bio));
        } else{
-               sector_t sector = bio->bi_sector;
+               sector_t sector = bio->bi_iter.bi_sector;
                return chunk_sects >= (sector_div(sector, chunk_sects)
                                                + bio_sectors(bio));
        }
@@ -512,64 +513,44 @@ static inline int is_io_in_chunk_boundary(struct mddev *mddev,
 
 static void raid0_make_request(struct mddev *mddev, struct bio *bio)
 {
-       unsigned int chunk_sects;
-       sector_t sector_offset;
        struct strip_zone *zone;
        struct md_rdev *tmp_dev;
+       struct bio *split;
 
        if (unlikely(bio->bi_rw & REQ_FLUSH)) {
                md_flush_request(mddev, bio);
                return;
        }
 
-       chunk_sects = mddev->chunk_sectors;
-       if (unlikely(!is_io_in_chunk_boundary(mddev, chunk_sects, bio))) {
-               sector_t sector = bio->bi_sector;
-               struct bio_pair *bp;
-               /* Sanity check -- queue functions should prevent this happening */
-               if (bio_segments(bio) > 1)
-                       goto bad_map;
-               /* This is a one page bio that upper layers
-                * refuse to split for us, so we need to split it.
-                */
-               if (likely(is_power_of_2(chunk_sects)))
-                       bp = bio_split(bio, chunk_sects - (sector &
-                                                          (chunk_sects-1)));
-               else
-                       bp = bio_split(bio, chunk_sects -
-                                      sector_div(sector, chunk_sects));
-               raid0_make_request(mddev, &bp->bio1);
-               raid0_make_request(mddev, &bp->bio2);
-               bio_pair_release(bp);
-               return;
-       }
+       do {
+               sector_t sector = bio->bi_iter.bi_sector;
+               unsigned chunk_sects = mddev->chunk_sectors;
 
-       sector_offset = bio->bi_sector;
-       zone = find_zone(mddev->private, &sector_offset);
-       tmp_dev = map_sector(mddev, zone, bio->bi_sector,
-                            &sector_offset);
-       bio->bi_bdev = tmp_dev->bdev;
-       bio->bi_sector = sector_offset + zone->dev_start +
-               tmp_dev->data_offset;
-
-       if (unlikely((bio->bi_rw & REQ_DISCARD) &&
-                    !blk_queue_discard(bdev_get_queue(bio->bi_bdev)))) {
-               /* Just ignore it */
-               bio_endio(bio, 0);
-               return;
-       }
+               unsigned sectors = chunk_sects -
+                       (likely(is_power_of_2(chunk_sects))
+                        ? (sector & (chunk_sects-1))
+                        : sector_div(sector, chunk_sects));
 
-       generic_make_request(bio);
-       return;
-
-bad_map:
-       printk("md/raid0:%s: make_request bug: can't convert block across chunks"
-              " or bigger than %dk %llu %d\n",
-              mdname(mddev), chunk_sects / 2,
-              (unsigned long long)bio->bi_sector, bio_sectors(bio) / 2);
+               if (sectors < bio_sectors(bio)) {
+                       split = bio_split(bio, sectors, GFP_NOIO, fs_bio_set);
+                       bio_chain(split, bio);
+               } else {
+                       split = bio;
+               }
 
-       bio_io_error(bio);
-       return;
+               zone = find_zone(mddev->private, &sector);
+               tmp_dev = map_sector(mddev, zone, sector, &sector);
+               split->bi_bdev = tmp_dev->bdev;
+               split->bi_iter.bi_sector = sector + zone->dev_start +
+                       tmp_dev->data_offset;
+
+               if (unlikely((split->bi_rw & REQ_DISCARD) &&
+                        !blk_queue_discard(bdev_get_queue(split->bi_bdev)))) {
+                       /* Just ignore it */
+                       bio_endio(split, 0);
+               } else
+                       generic_make_request(split);
+       } while (split != bio);
 }
 
 static void raid0_status(struct seq_file *seq, struct mddev *mddev)
index a49cfcc7a343188a5579350886795ce6fef35c4f..fd3a2a14b587da5e3bb5046b0017ed7bd46f67a1 100644 (file)
@@ -229,7 +229,7 @@ static void call_bio_endio(struct r1bio *r1_bio)
        int done;
        struct r1conf *conf = r1_bio->mddev->private;
        sector_t start_next_window = r1_bio->start_next_window;
-       sector_t bi_sector = bio->bi_sector;
+       sector_t bi_sector = bio->bi_iter.bi_sector;
 
        if (bio->bi_phys_segments) {
                unsigned long flags;
@@ -265,9 +265,8 @@ static void raid_end_bio_io(struct r1bio *r1_bio)
        if (!test_and_set_bit(R1BIO_Returned, &r1_bio->state)) {
                pr_debug("raid1: sync end %s on sectors %llu-%llu\n",
                         (bio_data_dir(bio) == WRITE) ? "write" : "read",
-                        (unsigned long long) bio->bi_sector,
-                        (unsigned long long) bio->bi_sector +
-                        bio_sectors(bio) - 1);
+                        (unsigned long long) bio->bi_iter.bi_sector,
+                        (unsigned long long) bio_end_sector(bio) - 1);
 
                call_bio_endio(r1_bio);
        }
@@ -466,9 +465,8 @@ static void raid1_end_write_request(struct bio *bio, int error)
                                struct bio *mbio = r1_bio->master_bio;
                                pr_debug("raid1: behind end write sectors"
                                         " %llu-%llu\n",
-                                        (unsigned long long) mbio->bi_sector,
-                                        (unsigned long long) mbio->bi_sector +
-                                        bio_sectors(mbio) - 1);
+                                        (unsigned long long) mbio->bi_iter.bi_sector,
+                                        (unsigned long long) bio_end_sector(mbio) - 1);
                                call_bio_endio(r1_bio);
                        }
                }
@@ -875,7 +873,7 @@ static bool need_to_wait_for_sync(struct r1conf *conf, struct bio *bio)
                else if ((conf->next_resync - RESYNC_WINDOW_SECTORS
                                >= bio_end_sector(bio)) ||
                         (conf->next_resync + NEXT_NORMALIO_DISTANCE
-                               <= bio->bi_sector))
+                               <= bio->bi_iter.bi_sector))
                        wait = false;
                else
                        wait = true;
@@ -913,14 +911,14 @@ static sector_t wait_barrier(struct r1conf *conf, struct bio *bio)
 
        if (bio && bio_data_dir(bio) == WRITE) {
                if (conf->next_resync + NEXT_NORMALIO_DISTANCE
-                   <= bio->bi_sector) {
+                   <= bio->bi_iter.bi_sector) {
                        if (conf->start_next_window == MaxSector)
                                conf->start_next_window =
                                        conf->next_resync +
                                        NEXT_NORMALIO_DISTANCE;
 
                        if ((conf->start_next_window + NEXT_NORMALIO_DISTANCE)
-                           <= bio->bi_sector)
+                           <= bio->bi_iter.bi_sector)
                                conf->next_window_requests++;
                        else
                                conf->current_window_requests++;
@@ -1027,7 +1025,8 @@ do_sync_io:
                if (bvecs[i].bv_page)
                        put_page(bvecs[i].bv_page);
        kfree(bvecs);
-       pr_debug("%dB behind alloc failed, doing sync I/O\n", bio->bi_size);
+       pr_debug("%dB behind alloc failed, doing sync I/O\n",
+                bio->bi_iter.bi_size);
 }
 
 struct raid1_plug_cb {
@@ -1107,7 +1106,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
 
        if (bio_data_dir(bio) == WRITE &&
            bio_end_sector(bio) > mddev->suspend_lo &&
-           bio->bi_sector < mddev->suspend_hi) {
+           bio->bi_iter.bi_sector < mddev->suspend_hi) {
                /* As the suspend_* range is controlled by
                 * userspace, we want an interruptible
                 * wait.
@@ -1118,7 +1117,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
                        prepare_to_wait(&conf->wait_barrier,
                                        &w, TASK_INTERRUPTIBLE);
                        if (bio_end_sector(bio) <= mddev->suspend_lo ||
-                           bio->bi_sector >= mddev->suspend_hi)
+                           bio->bi_iter.bi_sector >= mddev->suspend_hi)
                                break;
                        schedule();
                }
@@ -1140,7 +1139,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
        r1_bio->sectors = bio_sectors(bio);
        r1_bio->state = 0;
        r1_bio->mddev = mddev;
-       r1_bio->sector = bio->bi_sector;
+       r1_bio->sector = bio->bi_iter.bi_sector;
 
        /* We might need to issue multiple reads to different
         * devices if there are bad blocks around, so we keep
@@ -1180,12 +1179,13 @@ read_again:
                r1_bio->read_disk = rdisk;
 
                read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-               bio_trim(read_bio, r1_bio->sector - bio->bi_sector,
+               bio_trim(read_bio, r1_bio->sector - bio->bi_iter.bi_sector,
                         max_sectors);
 
                r1_bio->bios[rdisk] = read_bio;
 
-               read_bio->bi_sector = r1_bio->sector + mirror->rdev->data_offset;
+               read_bio->bi_iter.bi_sector = r1_bio->sector +
+                       mirror->rdev->data_offset;
                read_bio->bi_bdev = mirror->rdev->bdev;
                read_bio->bi_end_io = raid1_end_read_request;
                read_bio->bi_rw = READ | do_sync;
@@ -1197,7 +1197,7 @@ read_again:
                         */
 
                        sectors_handled = (r1_bio->sector + max_sectors
-                                          - bio->bi_sector);
+                                          - bio->bi_iter.bi_sector);
                        r1_bio->sectors = max_sectors;
                        spin_lock_irq(&conf->device_lock);
                        if (bio->bi_phys_segments == 0)
@@ -1218,7 +1218,8 @@ read_again:
                        r1_bio->sectors = bio_sectors(bio) - sectors_handled;
                        r1_bio->state = 0;
                        r1_bio->mddev = mddev;
-                       r1_bio->sector = bio->bi_sector + sectors_handled;
+                       r1_bio->sector = bio->bi_iter.bi_sector +
+                               sectors_handled;
                        goto read_again;
                } else
                        generic_make_request(read_bio);
@@ -1321,7 +1322,7 @@ read_again:
                        if (r1_bio->bios[j])
                                rdev_dec_pending(conf->mirrors[j].rdev, mddev);
                r1_bio->state = 0;
-               allow_barrier(conf, start_next_window, bio->bi_sector);
+               allow_barrier(conf, start_next_window, bio->bi_iter.bi_sector);
                md_wait_for_blocked_rdev(blocked_rdev, mddev);
                start_next_window = wait_barrier(conf, bio);
                /*
@@ -1348,7 +1349,7 @@ read_again:
                        bio->bi_phys_segments++;
                spin_unlock_irq(&conf->device_lock);
        }
-       sectors_handled = r1_bio->sector + max_sectors - bio->bi_sector;
+       sectors_handled = r1_bio->sector + max_sectors - bio->bi_iter.bi_sector;
 
        atomic_set(&r1_bio->remaining, 1);
        atomic_set(&r1_bio->behind_remaining, 0);
@@ -1360,7 +1361,7 @@ read_again:
                        continue;
 
                mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-               bio_trim(mbio, r1_bio->sector - bio->bi_sector, max_sectors);
+               bio_trim(mbio, r1_bio->sector - bio->bi_iter.bi_sector, max_sectors);
 
                if (first_clone) {
                        /* do behind I/O ?
@@ -1394,7 +1395,7 @@ read_again:
 
                r1_bio->bios[i] = mbio;
 
-               mbio->bi_sector = (r1_bio->sector +
+               mbio->bi_iter.bi_sector = (r1_bio->sector +
                                   conf->mirrors[i].rdev->data_offset);
                mbio->bi_bdev = conf->mirrors[i].rdev->bdev;
                mbio->bi_end_io = raid1_end_write_request;
@@ -1434,7 +1435,7 @@ read_again:
                r1_bio->sectors = bio_sectors(bio) - sectors_handled;
                r1_bio->state = 0;
                r1_bio->mddev = mddev;
-               r1_bio->sector = bio->bi_sector + sectors_handled;
+               r1_bio->sector = bio->bi_iter.bi_sector + sectors_handled;
                goto retry_write;
        }
 
@@ -1958,14 +1959,14 @@ static int process_checks(struct r1bio *r1_bio)
                /* fixup the bio for reuse */
                bio_reset(b);
                b->bi_vcnt = vcnt;
-               b->bi_size = r1_bio->sectors << 9;
-               b->bi_sector = r1_bio->sector +
+               b->bi_iter.bi_size = r1_bio->sectors << 9;
+               b->bi_iter.bi_sector = r1_bio->sector +
                        conf->mirrors[i].rdev->data_offset;
                b->bi_bdev = conf->mirrors[i].rdev->bdev;
                b->bi_end_io = end_sync_read;
                b->bi_private = r1_bio;
 
-               size = b->bi_size;
+               size = b->bi_iter.bi_size;
                for (j = 0; j < vcnt ; j++) {
                        struct bio_vec *bi;
                        bi = &b->bi_io_vec[j];
@@ -2220,11 +2221,11 @@ static int narrow_write_error(struct r1bio *r1_bio, int i)
                }
 
                wbio->bi_rw = WRITE;
-               wbio->bi_sector = r1_bio->sector;
-               wbio->bi_size = r1_bio->sectors << 9;
+               wbio->bi_iter.bi_sector = r1_bio->sector;
+               wbio->bi_iter.bi_size = r1_bio->sectors << 9;
 
                bio_trim(wbio, sector - r1_bio->sector, sectors);
-               wbio->bi_sector += rdev->data_offset;
+               wbio->bi_iter.bi_sector += rdev->data_offset;
                wbio->bi_bdev = rdev->bdev;
                if (submit_bio_wait(WRITE, wbio) == 0)
                        /* failure! */
@@ -2338,7 +2339,8 @@ read_more:
                }
                r1_bio->read_disk = disk;
                bio = bio_clone_mddev(r1_bio->master_bio, GFP_NOIO, mddev);
-               bio_trim(bio, r1_bio->sector - bio->bi_sector, max_sectors);
+               bio_trim(bio, r1_bio->sector - bio->bi_iter.bi_sector,
+                        max_sectors);
                r1_bio->bios[r1_bio->read_disk] = bio;
                rdev = conf->mirrors[disk].rdev;
                printk_ratelimited(KERN_ERR
@@ -2347,7 +2349,7 @@ read_more:
                                   mdname(mddev),
                                   (unsigned long long)r1_bio->sector,
                                   bdevname(rdev->bdev, b));
-               bio->bi_sector = r1_bio->sector + rdev->data_offset;
+               bio->bi_iter.bi_sector = r1_bio->sector + rdev->data_offset;
                bio->bi_bdev = rdev->bdev;
                bio->bi_end_io = raid1_end_read_request;
                bio->bi_rw = READ | do_sync;
@@ -2356,7 +2358,7 @@ read_more:
                        /* Drat - have to split this up more */
                        struct bio *mbio = r1_bio->master_bio;
                        int sectors_handled = (r1_bio->sector + max_sectors
-                                              - mbio->bi_sector);
+                                              - mbio->bi_iter.bi_sector);
                        r1_bio->sectors = max_sectors;
                        spin_lock_irq(&conf->device_lock);
                        if (mbio->bi_phys_segments == 0)
@@ -2374,7 +2376,8 @@ read_more:
                        r1_bio->state = 0;
                        set_bit(R1BIO_ReadError, &r1_bio->state);
                        r1_bio->mddev = mddev;
-                       r1_bio->sector = mbio->bi_sector + sectors_handled;
+                       r1_bio->sector = mbio->bi_iter.bi_sector +
+                               sectors_handled;
 
                        goto read_more;
                } else
@@ -2598,7 +2601,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp
                }
                if (bio->bi_end_io) {
                        atomic_inc(&rdev->nr_pending);
-                       bio->bi_sector = sector_nr + rdev->data_offset;
+                       bio->bi_iter.bi_sector = sector_nr + rdev->data_offset;
                        bio->bi_bdev = rdev->bdev;
                        bio->bi_private = r1_bio;
                }
@@ -2698,7 +2701,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr, int *skipp
                                                        continue;
                                                /* remove last page from this bio */
                                                bio->bi_vcnt--;
-                                               bio->bi_size -= len;
+                                               bio->bi_iter.bi_size -= len;
                                                bio->bi_flags &= ~(1<< BIO_SEG_VALID);
                                        }
                                        goto bio_full;
index 8d39d63281b9b5441b3ec8e524955356c8690871..33fc408e5eacef0a1dce55fd5c0d578fc244b663 100644 (file)
@@ -1152,14 +1152,12 @@ static void raid10_unplug(struct blk_plug_cb *cb, bool from_schedule)
        kfree(plug);
 }
 
-static void make_request(struct mddev *mddev, struct bio * bio)
+static void __make_request(struct mddev *mddev, struct bio *bio)
 {
        struct r10conf *conf = mddev->private;
        struct r10bio *r10_bio;
        struct bio *read_bio;
        int i;
-       sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask);
-       int chunk_sects = chunk_mask + 1;
        const int rw = bio_data_dir(bio);
        const unsigned long do_sync = (bio->bi_rw & REQ_SYNC);
        const unsigned long do_fua = (bio->bi_rw & REQ_FUA);
@@ -1174,88 +1172,27 @@ static void make_request(struct mddev *mddev, struct bio * bio)
        int max_sectors;
        int sectors;
 
-       if (unlikely(bio->bi_rw & REQ_FLUSH)) {
-               md_flush_request(mddev, bio);
-               return;
-       }
-
-       /* If this request crosses a chunk boundary, we need to
-        * split it.  This will only happen for 1 PAGE (or less) requests.
-        */
-       if (unlikely((bio->bi_sector & chunk_mask) + bio_sectors(bio)
-                    > chunk_sects
-                    && (conf->geo.near_copies < conf->geo.raid_disks
-                        || conf->prev.near_copies < conf->prev.raid_disks))) {
-               struct bio_pair *bp;
-               /* Sanity check -- queue functions should prevent this happening */
-               if (bio_segments(bio) > 1)
-                       goto bad_map;
-               /* This is a one page bio that upper layers
-                * refuse to split for us, so we need to split it.
-                */
-               bp = bio_split(bio,
-                              chunk_sects - (bio->bi_sector & (chunk_sects - 1)) );
-
-               /* Each of these 'make_request' calls will call 'wait_barrier'.
-                * If the first succeeds but the second blocks due to the resync
-                * thread raising the barrier, we will deadlock because the
-                * IO to the underlying device will be queued in generic_make_request
-                * and will never complete, so will never reduce nr_pending.
-                * So increment nr_waiting here so no new raise_barriers will
-                * succeed, and so the second wait_barrier cannot block.
-                */
-               spin_lock_irq(&conf->resync_lock);
-               conf->nr_waiting++;
-               spin_unlock_irq(&conf->resync_lock);
-
-               make_request(mddev, &bp->bio1);
-               make_request(mddev, &bp->bio2);
-
-               spin_lock_irq(&conf->resync_lock);
-               conf->nr_waiting--;
-               wake_up(&conf->wait_barrier);
-               spin_unlock_irq(&conf->resync_lock);
-
-               bio_pair_release(bp);
-               return;
-       bad_map:
-               printk("md/raid10:%s: make_request bug: can't convert block across chunks"
-                      " or bigger than %dk %llu %d\n", mdname(mddev), chunk_sects/2,
-                      (unsigned long long)bio->bi_sector, bio_sectors(bio) / 2);
-
-               bio_io_error(bio);
-               return;
-       }
-
-       md_write_start(mddev, bio);
-
-       /*
-        * Register the new request and wait if the reconstruction
-        * thread has put up a bar for new requests.
-        * Continue immediately if no resync is active currently.
-        */
-       wait_barrier(conf);
-
        sectors = bio_sectors(bio);
        while (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
-           bio->bi_sector < conf->reshape_progress &&
-           bio->bi_sector + sectors > conf->reshape_progress) {
+           bio->bi_iter.bi_sector < conf->reshape_progress &&
+           bio->bi_iter.bi_sector + sectors > conf->reshape_progress) {
                /* IO spans the reshape position.  Need to wait for
                 * reshape to pass
                 */
                allow_barrier(conf);
                wait_event(conf->wait_barrier,
-                          conf->reshape_progress <= bio->bi_sector ||
-                          conf->reshape_progress >= bio->bi_sector + sectors);
+                          conf->reshape_progress <= bio->bi_iter.bi_sector ||
+                          conf->reshape_progress >= bio->bi_iter.bi_sector +
+                          sectors);
                wait_barrier(conf);
        }
        if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
            bio_data_dir(bio) == WRITE &&
            (mddev->reshape_backwards
-            ? (bio->bi_sector < conf->reshape_safe &&
-               bio->bi_sector + sectors > conf->reshape_progress)
-            : (bio->bi_sector + sectors > conf->reshape_safe &&
-               bio->bi_sector < conf->reshape_progress))) {
+            ? (bio->bi_iter.bi_sector < conf->reshape_safe &&
+               bio->bi_iter.bi_sector + sectors > conf->reshape_progress)
+            : (bio->bi_iter.bi_sector + sectors > conf->reshape_safe &&
+               bio->bi_iter.bi_sector < conf->reshape_progress))) {
                /* Need to update reshape_position in metadata */
                mddev->reshape_position = conf->reshape_progress;
                set_bit(MD_CHANGE_DEVS, &mddev->flags);
@@ -1273,7 +1210,7 @@ static void make_request(struct mddev *mddev, struct bio * bio)
        r10_bio->sectors = sectors;
 
        r10_bio->mddev = mddev;
-       r10_bio->sector = bio->bi_sector;
+       r10_bio->sector = bio->bi_iter.bi_sector;
        r10_bio->state = 0;
 
        /* We might need to issue multiple reads to different
@@ -1302,13 +1239,13 @@ read_again:
                slot = r10_bio->read_slot;
 
                read_bio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-               bio_trim(read_bio, r10_bio->sector - bio->bi_sector,
+               bio_trim(read_bio, r10_bio->sector - bio->bi_iter.bi_sector,
                         max_sectors);
 
                r10_bio->devs[slot].bio = read_bio;
                r10_bio->devs[slot].rdev = rdev;
 
-               read_bio->bi_sector = r10_bio->devs[slot].addr +
+               read_bio->bi_iter.bi_sector = r10_bio->devs[slot].addr +
                        choose_data_offset(r10_bio, rdev);
                read_bio->bi_bdev = rdev->bdev;
                read_bio->bi_end_io = raid10_end_read_request;
@@ -1320,7 +1257,7 @@ read_again:
                         * need another r10_bio.
                         */
                        sectors_handled = (r10_bio->sector + max_sectors
-                                          - bio->bi_sector);
+                                          - bio->bi_iter.bi_sector);
                        r10_bio->sectors = max_sectors;
                        spin_lock_irq(&conf->device_lock);
                        if (bio->bi_phys_segments == 0)
@@ -1341,7 +1278,8 @@ read_again:
                        r10_bio->sectors = bio_sectors(bio) - sectors_handled;
                        r10_bio->state = 0;
                        r10_bio->mddev = mddev;
-                       r10_bio->sector = bio->bi_sector + sectors_handled;
+                       r10_bio->sector = bio->bi_iter.bi_sector +
+                               sectors_handled;
                        goto read_again;
                } else
                        generic_make_request(read_bio);
@@ -1499,7 +1437,8 @@ retry_write:
                        bio->bi_phys_segments++;
                spin_unlock_irq(&conf->device_lock);
        }
-       sectors_handled = r10_bio->sector + max_sectors - bio->bi_sector;
+       sectors_handled = r10_bio->sector + max_sectors -
+               bio->bi_iter.bi_sector;
 
        atomic_set(&r10_bio->remaining, 1);
        bitmap_startwrite(mddev->bitmap, r10_bio->sector, r10_bio->sectors, 0);
@@ -1510,11 +1449,11 @@ retry_write:
                if (r10_bio->devs[i].bio) {
                        struct md_rdev *rdev = conf->mirrors[d].rdev;
                        mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-                       bio_trim(mbio, r10_bio->sector - bio->bi_sector,
+                       bio_trim(mbio, r10_bio->sector - bio->bi_iter.bi_sector,
                                 max_sectors);
                        r10_bio->devs[i].bio = mbio;
 
-                       mbio->bi_sector = (r10_bio->devs[i].addr+
+                       mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr+
                                           choose_data_offset(r10_bio,
                                                              rdev));
                        mbio->bi_bdev = rdev->bdev;
@@ -1553,11 +1492,11 @@ retry_write:
                                rdev = conf->mirrors[d].rdev;
                        }
                        mbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-                       bio_trim(mbio, r10_bio->sector - bio->bi_sector,
+                       bio_trim(mbio, r10_bio->sector - bio->bi_iter.bi_sector,
                                 max_sectors);
                        r10_bio->devs[i].repl_bio = mbio;
 
-                       mbio->bi_sector = (r10_bio->devs[i].addr +
+                       mbio->bi_iter.bi_sector = (r10_bio->devs[i].addr +
                                           choose_data_offset(
                                                   r10_bio, rdev));
                        mbio->bi_bdev = rdev->bdev;
@@ -1591,11 +1530,57 @@ retry_write:
                r10_bio->sectors = bio_sectors(bio) - sectors_handled;
 
                r10_bio->mddev = mddev;
-               r10_bio->sector = bio->bi_sector + sectors_handled;
+               r10_bio->sector = bio->bi_iter.bi_sector + sectors_handled;
                r10_bio->state = 0;
                goto retry_write;
        }
        one_write_done(r10_bio);
+}
+
+static void make_request(struct mddev *mddev, struct bio *bio)
+{
+       struct r10conf *conf = mddev->private;
+       sector_t chunk_mask = (conf->geo.chunk_mask & conf->prev.chunk_mask);
+       int chunk_sects = chunk_mask + 1;
+
+       struct bio *split;
+
+       if (unlikely(bio->bi_rw & REQ_FLUSH)) {
+               md_flush_request(mddev, bio);
+               return;
+       }
+
+       md_write_start(mddev, bio);
+
+       /*
+        * Register the new request and wait if the reconstruction
+        * thread has put up a bar for new requests.
+        * Continue immediately if no resync is active currently.
+        */
+       wait_barrier(conf);
+
+       do {
+
+               /*
+                * If this request crosses a chunk boundary, we need to split
+                * it.
+                */
+               if (unlikely((bio->bi_iter.bi_sector & chunk_mask) +
+                            bio_sectors(bio) > chunk_sects
+                            && (conf->geo.near_copies < conf->geo.raid_disks
+                                || conf->prev.near_copies <
+                                conf->prev.raid_disks))) {
+                       split = bio_split(bio, chunk_sects -
+                                         (bio->bi_iter.bi_sector &
+                                          (chunk_sects - 1)),
+                                         GFP_NOIO, fs_bio_set);
+                       bio_chain(split, bio);
+               } else {
+                       split = bio;
+               }
+
+               __make_request(mddev, split);
+       } while (split != bio);
 
        /* In case raid10d snuck in to freeze_array */
        wake_up(&conf->wait_barrier);
@@ -2124,10 +2109,10 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
                bio_reset(tbio);
 
                tbio->bi_vcnt = vcnt;
-               tbio->bi_size = r10_bio->sectors << 9;
+               tbio->bi_iter.bi_size = r10_bio->sectors << 9;
                tbio->bi_rw = WRITE;
                tbio->bi_private = r10_bio;
-               tbio->bi_sector = r10_bio->devs[i].addr;
+               tbio->bi_iter.bi_sector = r10_bio->devs[i].addr;
 
                for (j=0; j < vcnt ; j++) {
                        tbio->bi_io_vec[j].bv_offset = 0;
@@ -2144,7 +2129,7 @@ static void sync_request_write(struct mddev *mddev, struct r10bio *r10_bio)
                atomic_inc(&r10_bio->remaining);
                md_sync_acct(conf->mirrors[d].rdev->bdev, bio_sectors(tbio));
 
-               tbio->bi_sector += conf->mirrors[d].rdev->data_offset;
+               tbio->bi_iter.bi_sector += conf->mirrors[d].rdev->data_offset;
                tbio->bi_bdev = conf->mirrors[d].rdev->bdev;
                generic_make_request(tbio);
        }
@@ -2614,8 +2599,8 @@ static int narrow_write_error(struct r10bio *r10_bio, int i)
                        sectors = sect_to_write;
                /* Write at 'sector' for 'sectors' */
                wbio = bio_clone_mddev(bio, GFP_NOIO, mddev);
-               bio_trim(wbio, sector - bio->bi_sector, sectors);
-               wbio->bi_sector = (r10_bio->devs[i].addr+
+               bio_trim(wbio, sector - bio->bi_iter.bi_sector, sectors);
+               wbio->bi_iter.bi_sector = (r10_bio->devs[i].addr+
                                   choose_data_offset(r10_bio, rdev) +
                                   (sector - r10_bio->sector));
                wbio->bi_bdev = rdev->bdev;
@@ -2687,10 +2672,10 @@ read_more:
                (unsigned long long)r10_bio->sector);
        bio = bio_clone_mddev(r10_bio->master_bio,
                              GFP_NOIO, mddev);
-       bio_trim(bio, r10_bio->sector - bio->bi_sector, max_sectors);
+       bio_trim(bio, r10_bio->sector - bio->bi_iter.bi_sector, max_sectors);
        r10_bio->devs[slot].bio = bio;
        r10_bio->devs[slot].rdev = rdev;
-       bio->bi_sector = r10_bio->devs[slot].addr
+       bio->bi_iter.bi_sector = r10_bio->devs[slot].addr
                + choose_data_offset(r10_bio, rdev);
        bio->bi_bdev = rdev->bdev;
        bio->bi_rw = READ | do_sync;
@@ -2701,7 +2686,7 @@ read_more:
                struct bio *mbio = r10_bio->master_bio;
                int sectors_handled =
                        r10_bio->sector + max_sectors
-                       - mbio->bi_sector;
+                       - mbio->bi_iter.bi_sector;
                r10_bio->sectors = max_sectors;
                spin_lock_irq(&conf->device_lock);
                if (mbio->bi_phys_segments == 0)
@@ -2719,7 +2704,7 @@ read_more:
                set_bit(R10BIO_ReadError,
                        &r10_bio->state);
                r10_bio->mddev = mddev;
-               r10_bio->sector = mbio->bi_sector
+               r10_bio->sector = mbio->bi_iter.bi_sector
                        + sectors_handled;
 
                goto read_more;
@@ -3157,7 +3142,8 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                                bio->bi_end_io = end_sync_read;
                                bio->bi_rw = READ;
                                from_addr = r10_bio->devs[j].addr;
-                               bio->bi_sector = from_addr + rdev->data_offset;
+                               bio->bi_iter.bi_sector = from_addr +
+                                       rdev->data_offset;
                                bio->bi_bdev = rdev->bdev;
                                atomic_inc(&rdev->nr_pending);
                                /* and we write to 'i' (if not in_sync) */
@@ -3181,7 +3167,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                                        bio->bi_private = r10_bio;
                                        bio->bi_end_io = end_sync_write;
                                        bio->bi_rw = WRITE;
-                                       bio->bi_sector = to_addr
+                                       bio->bi_iter.bi_sector = to_addr
                                                + rdev->data_offset;
                                        bio->bi_bdev = rdev->bdev;
                                        atomic_inc(&r10_bio->remaining);
@@ -3210,7 +3196,8 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                                bio->bi_private = r10_bio;
                                bio->bi_end_io = end_sync_write;
                                bio->bi_rw = WRITE;
-                               bio->bi_sector = to_addr + rdev->data_offset;
+                               bio->bi_iter.bi_sector = to_addr +
+                                       rdev->data_offset;
                                bio->bi_bdev = rdev->bdev;
                                atomic_inc(&r10_bio->remaining);
                                break;
@@ -3328,7 +3315,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                        bio->bi_private = r10_bio;
                        bio->bi_end_io = end_sync_read;
                        bio->bi_rw = READ;
-                       bio->bi_sector = sector +
+                       bio->bi_iter.bi_sector = sector +
                                conf->mirrors[d].rdev->data_offset;
                        bio->bi_bdev = conf->mirrors[d].rdev->bdev;
                        count++;
@@ -3350,7 +3337,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                        bio->bi_private = r10_bio;
                        bio->bi_end_io = end_sync_write;
                        bio->bi_rw = WRITE;
-                       bio->bi_sector = sector +
+                       bio->bi_iter.bi_sector = sector +
                                conf->mirrors[d].replacement->data_offset;
                        bio->bi_bdev = conf->mirrors[d].replacement->bdev;
                        count++;
@@ -3397,7 +3384,7 @@ static sector_t sync_request(struct mddev *mddev, sector_t sector_nr,
                             bio2 = bio2->bi_next) {
                                /* remove last page from this bio */
                                bio2->bi_vcnt--;
-                               bio2->bi_size -= len;
+                               bio2->bi_iter.bi_size -= len;
                                bio2->bi_flags &= ~(1<< BIO_SEG_VALID);
                        }
                        goto bio_full;
@@ -4418,7 +4405,7 @@ read_more:
        read_bio = bio_alloc_mddev(GFP_KERNEL, RESYNC_PAGES, mddev);
 
        read_bio->bi_bdev = rdev->bdev;
-       read_bio->bi_sector = (r10_bio->devs[r10_bio->read_slot].addr
+       read_bio->bi_iter.bi_sector = (r10_bio->devs[r10_bio->read_slot].addr
                               + rdev->data_offset);
        read_bio->bi_private = r10_bio;
        read_bio->bi_end_io = end_sync_read;
@@ -4426,7 +4413,7 @@ read_more:
        read_bio->bi_flags &= ~(BIO_POOL_MASK - 1);
        read_bio->bi_flags |= 1 << BIO_UPTODATE;
        read_bio->bi_vcnt = 0;
-       read_bio->bi_size = 0;
+       read_bio->bi_iter.bi_size = 0;
        r10_bio->master_bio = read_bio;
        r10_bio->read_slot = r10_bio->devs[r10_bio->read_slot].devnum;
 
@@ -4452,7 +4439,8 @@ read_more:
 
                bio_reset(b);
                b->bi_bdev = rdev2->bdev;
-               b->bi_sector = r10_bio->devs[s/2].addr + rdev2->new_data_offset;
+               b->bi_iter.bi_sector = r10_bio->devs[s/2].addr +
+                       rdev2->new_data_offset;
                b->bi_private = r10_bio;
                b->bi_end_io = end_reshape_write;
                b->bi_rw = WRITE;
@@ -4479,7 +4467,7 @@ read_more:
                             bio2 = bio2->bi_next) {
                                /* Remove last page from this bio */
                                bio2->bi_vcnt--;
-                               bio2->bi_size -= len;
+                               bio2->bi_iter.bi_size -= len;
                                bio2->bi_flags &= ~(1<<BIO_SEG_VALID);
                        }
                        goto bio_full;
index 03f82ab87d9e73eb4fed4ede052c95fa5d891f09..f1feadeb7bb2d1b68a6592d946516e4036c7e939 100644 (file)
@@ -133,7 +133,7 @@ static inline void unlock_all_device_hash_locks_irq(struct r5conf *conf)
 static inline struct bio *r5_next_bio(struct bio *bio, sector_t sector)
 {
        int sectors = bio_sectors(bio);
-       if (bio->bi_sector + sectors < sector + STRIPE_SECTORS)
+       if (bio->bi_iter.bi_sector + sectors < sector + STRIPE_SECTORS)
                return bio->bi_next;
        else
                return NULL;
@@ -225,7 +225,7 @@ static void return_io(struct bio *return_bi)
 
                return_bi = bi->bi_next;
                bi->bi_next = NULL;
-               bi->bi_size = 0;
+               bi->bi_iter.bi_size = 0;
                trace_block_bio_complete(bdev_get_queue(bi->bi_bdev),
                                         bi, 0);
                bio_endio(bi, 0);
@@ -852,10 +852,10 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                                bi->bi_rw, i);
                        atomic_inc(&sh->count);
                        if (use_new_offset(conf, sh))
-                               bi->bi_sector = (sh->sector
+                               bi->bi_iter.bi_sector = (sh->sector
                                                 + rdev->new_data_offset);
                        else
-                               bi->bi_sector = (sh->sector
+                               bi->bi_iter.bi_sector = (sh->sector
                                                 + rdev->data_offset);
                        if (test_bit(R5_ReadNoMerge, &sh->dev[i].flags))
                                bi->bi_rw |= REQ_NOMERGE;
@@ -863,7 +863,7 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                        bi->bi_vcnt = 1;
                        bi->bi_io_vec[0].bv_len = STRIPE_SIZE;
                        bi->bi_io_vec[0].bv_offset = 0;
-                       bi->bi_size = STRIPE_SIZE;
+                       bi->bi_iter.bi_size = STRIPE_SIZE;
                        /*
                         * If this is discard request, set bi_vcnt 0. We don't
                         * want to confuse SCSI because SCSI will replace payload
@@ -899,15 +899,15 @@ static void ops_run_io(struct stripe_head *sh, struct stripe_head_state *s)
                                rbi->bi_rw, i);
                        atomic_inc(&sh->count);
                        if (use_new_offset(conf, sh))
-                               rbi->bi_sector = (sh->sector
+                               rbi->bi_iter.bi_sector = (sh->sector
                                                  + rrdev->new_data_offset);
                        else
-                               rbi->bi_sector = (sh->sector
+                               rbi->bi_iter.bi_sector = (sh->sector
                                                  + rrdev->data_offset);
                        rbi->bi_vcnt = 1;
                        rbi->bi_io_vec[0].bv_len = STRIPE_SIZE;
                        rbi->bi_io_vec[0].bv_offset = 0;
-                       rbi->bi_size = STRIPE_SIZE;
+                       rbi->bi_iter.bi_size = STRIPE_SIZE;
                        /*
                         * If this is discard request, set bi_vcnt 0. We don't
                         * want to confuse SCSI because SCSI will replace payload
@@ -935,24 +935,24 @@ static struct dma_async_tx_descriptor *
 async_copy_data(int frombio, struct bio *bio, struct page *page,
        sector_t sector, struct dma_async_tx_descriptor *tx)
 {
-       struct bio_vec *bvl;
+       struct bio_vec bvl;
+       struct bvec_iter iter;
        struct page *bio_page;
-       int i;
        int page_offset;
        struct async_submit_ctl submit;
        enum async_tx_flags flags = 0;
 
-       if (bio->bi_sector >= sector)
-               page_offset = (signed)(bio->bi_sector - sector) * 512;
+       if (bio->bi_iter.bi_sector >= sector)
+               page_offset = (signed)(bio->bi_iter.bi_sector - sector) * 512;
        else
-               page_offset = (signed)(sector - bio->bi_sector) * -512;
+               page_offset = (signed)(sector - bio->bi_iter.bi_sector) * -512;
 
        if (frombio)
                flags |= ASYNC_TX_FENCE;
        init_async_submit(&submit, flags, tx, NULL, NULL, NULL);
 
-       bio_for_each_segment(bvl, bio, i) {
-               int len = bvl->bv_len;
+       bio_for_each_segment(bvl, bio, iter) {
+               int len = bvl.bv_len;
                int clen;
                int b_offset = 0;
 
@@ -968,8 +968,8 @@ async_copy_data(int frombio, struct bio *bio, struct page *page,
                        clen = len;
 
                if (clen > 0) {
-                       b_offset += bvl->bv_offset;
-                       bio_page = bvl->bv_page;
+                       b_offset += bvl.bv_offset;
+                       bio_page = bvl.bv_page;
                        if (frombio)
                                tx = async_memcpy(page, bio_page, page_offset,
                                                  b_offset, clen, &submit);
@@ -1012,7 +1012,7 @@ static void ops_complete_biofill(void *stripe_head_ref)
                        BUG_ON(!dev->read);
                        rbi = dev->read;
                        dev->read = NULL;
-                       while (rbi && rbi->bi_sector <
+                       while (rbi && rbi->bi_iter.bi_sector <
                                dev->sector + STRIPE_SECTORS) {
                                rbi2 = r5_next_bio(rbi, dev->sector);
                                if (!raid5_dec_bi_active_stripes(rbi)) {
@@ -1048,7 +1048,7 @@ static void ops_run_biofill(struct stripe_head *sh)
                        dev->read = rbi = dev->toread;
                        dev->toread = NULL;
                        spin_unlock_irq(&sh->stripe_lock);
-                       while (rbi && rbi->bi_sector <
+                       while (rbi && rbi->bi_iter.bi_sector <
                                dev->sector + STRIPE_SECTORS) {
                                tx = async_copy_data(0, rbi, dev->page,
                                        dev->sector, tx);
@@ -1390,7 +1390,7 @@ ops_run_biodrain(struct stripe_head *sh, struct dma_async_tx_descriptor *tx)
                        wbi = dev->written = chosen;
                        spin_unlock_irq(&sh->stripe_lock);
 
-                       while (wbi && wbi->bi_sector <
+                       while (wbi && wbi->bi_iter.bi_sector <
                                dev->sector + STRIPE_SECTORS) {
                                if (wbi->bi_rw & REQ_FUA)
                                        set_bit(R5_WantFUA, &dev->flags);
@@ -2615,7 +2615,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
        int firstwrite=0;
 
        pr_debug("adding bi b#%llu to stripe s#%llu\n",
-               (unsigned long long)bi->bi_sector,
+               (unsigned long long)bi->bi_iter.bi_sector,
                (unsigned long long)sh->sector);
 
        /*
@@ -2633,12 +2633,12 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
                        firstwrite = 1;
        } else
                bip = &sh->dev[dd_idx].toread;
-       while (*bip && (*bip)->bi_sector < bi->bi_sector) {
-               if (bio_end_sector(*bip) > bi->bi_sector)
+       while (*bip && (*bip)->bi_iter.bi_sector < bi->bi_iter.bi_sector) {
+               if (bio_end_sector(*bip) > bi->bi_iter.bi_sector)
                        goto overlap;
                bip = & (*bip)->bi_next;
        }
-       if (*bip && (*bip)->bi_sector < bio_end_sector(bi))
+       if (*bip && (*bip)->bi_iter.bi_sector < bio_end_sector(bi))
                goto overlap;
 
        BUG_ON(*bip && bi->bi_next && (*bip) != bi->bi_next);
@@ -2652,7 +2652,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
                sector_t sector = sh->dev[dd_idx].sector;
                for (bi=sh->dev[dd_idx].towrite;
                     sector < sh->dev[dd_idx].sector + STRIPE_SECTORS &&
-                            bi && bi->bi_sector <= sector;
+                            bi && bi->bi_iter.bi_sector <= sector;
                     bi = r5_next_bio(bi, sh->dev[dd_idx].sector)) {
                        if (bio_end_sector(bi) >= sector)
                                sector = bio_end_sector(bi);
@@ -2662,7 +2662,7 @@ static int add_stripe_bio(struct stripe_head *sh, struct bio *bi, int dd_idx, in
        }
 
        pr_debug("added bi b#%llu to stripe s#%llu, disk %d.\n",
-               (unsigned long long)(*bip)->bi_sector,
+               (unsigned long long)(*bip)->bi_iter.bi_sector,
                (unsigned long long)sh->sector, dd_idx);
        spin_unlock_irq(&sh->stripe_lock);
 
@@ -2737,7 +2737,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
                if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
                        wake_up(&conf->wait_for_overlap);
 
-               while (bi && bi->bi_sector <
+               while (bi && bi->bi_iter.bi_sector <
                        sh->dev[i].sector + STRIPE_SECTORS) {
                        struct bio *nextbi = r5_next_bio(bi, sh->dev[i].sector);
                        clear_bit(BIO_UPTODATE, &bi->bi_flags);
@@ -2756,7 +2756,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
                bi = sh->dev[i].written;
                sh->dev[i].written = NULL;
                if (bi) bitmap_end = 1;
-               while (bi && bi->bi_sector <
+               while (bi && bi->bi_iter.bi_sector <
                       sh->dev[i].sector + STRIPE_SECTORS) {
                        struct bio *bi2 = r5_next_bio(bi, sh->dev[i].sector);
                        clear_bit(BIO_UPTODATE, &bi->bi_flags);
@@ -2780,7 +2780,7 @@ handle_failed_stripe(struct r5conf *conf, struct stripe_head *sh,
                        spin_unlock_irq(&sh->stripe_lock);
                        if (test_and_clear_bit(R5_Overlap, &sh->dev[i].flags))
                                wake_up(&conf->wait_for_overlap);
-                       while (bi && bi->bi_sector <
+                       while (bi && bi->bi_iter.bi_sector <
                               sh->dev[i].sector + STRIPE_SECTORS) {
                                struct bio *nextbi =
                                        r5_next_bio(bi, sh->dev[i].sector);
@@ -3004,7 +3004,7 @@ static void handle_stripe_clean_event(struct r5conf *conf,
                                        clear_bit(R5_UPTODATE, &dev->flags);
                                wbi = dev->written;
                                dev->written = NULL;
-                               while (wbi && wbi->bi_sector <
+                               while (wbi && wbi->bi_iter.bi_sector <
                                        dev->sector + STRIPE_SECTORS) {
                                        wbi2 = r5_next_bio(wbi, dev->sector);
                                        if (!raid5_dec_bi_active_stripes(wbi)) {
@@ -4096,7 +4096,7 @@ static int raid5_mergeable_bvec(struct request_queue *q,
 
 static int in_chunk_boundary(struct mddev *mddev, struct bio *bio)
 {
-       sector_t sector = bio->bi_sector + get_start_sect(bio->bi_bdev);
+       sector_t sector = bio->bi_iter.bi_sector + get_start_sect(bio->bi_bdev);
        unsigned int chunk_sectors = mddev->chunk_sectors;
        unsigned int bio_sectors = bio_sectors(bio);
 
@@ -4233,9 +4233,9 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
        /*
         *      compute position
         */
-       align_bi->bi_sector =  raid5_compute_sector(conf, raid_bio->bi_sector,
-                                                   0,
-                                                   &dd_idx, NULL);
+       align_bi->bi_iter.bi_sector =
+               raid5_compute_sector(conf, raid_bio->bi_iter.bi_sector,
+                                    0, &dd_idx, NULL);
 
        end_sector = bio_end_sector(align_bi);
        rcu_read_lock();
@@ -4260,7 +4260,8 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
                align_bi->bi_flags &= ~(1 << BIO_SEG_VALID);
 
                if (!bio_fits_rdev(align_bi) ||
-                   is_badblock(rdev, align_bi->bi_sector, bio_sectors(align_bi),
+                   is_badblock(rdev, align_bi->bi_iter.bi_sector,
+                               bio_sectors(align_bi),
                                &first_bad, &bad_sectors)) {
                        /* too big in some way, or has a known bad block */
                        bio_put(align_bi);
@@ -4269,7 +4270,7 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
                }
 
                /* No reshape active, so we can trust rdev->data_offset */
-               align_bi->bi_sector += rdev->data_offset;
+               align_bi->bi_iter.bi_sector += rdev->data_offset;
 
                spin_lock_irq(&conf->device_lock);
                wait_event_lock_irq(conf->wait_for_stripe,
@@ -4281,7 +4282,7 @@ static int chunk_aligned_read(struct mddev *mddev, struct bio * raid_bio)
                if (mddev->gendisk)
                        trace_block_bio_remap(bdev_get_queue(align_bi->bi_bdev),
                                              align_bi, disk_devt(mddev->gendisk),
-                                             raid_bio->bi_sector);
+                                             raid_bio->bi_iter.bi_sector);
                generic_make_request(align_bi);
                return 1;
        } else {
@@ -4464,8 +4465,8 @@ static void make_discard_request(struct mddev *mddev, struct bio *bi)
                /* Skip discard while reshape is happening */
                return;
 
-       logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
-       last_sector = bi->bi_sector + (bi->bi_size>>9);
+       logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1);
+       last_sector = bi->bi_iter.bi_sector + (bi->bi_iter.bi_size>>9);
 
        bi->bi_next = NULL;
        bi->bi_phys_segments = 1; /* over-loaded to count active stripes */
@@ -4569,7 +4570,7 @@ static void make_request(struct mddev *mddev, struct bio * bi)
                return;
        }
 
-       logical_sector = bi->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
+       logical_sector = bi->bi_iter.bi_sector & ~((sector_t)STRIPE_SECTORS-1);
        last_sector = bio_end_sector(bi);
        bi->bi_next = NULL;
        bi->bi_phys_segments = 1;       /* over-loaded to count active stripes */
@@ -5053,7 +5054,8 @@ static int  retry_aligned_read(struct r5conf *conf, struct bio *raid_bio)
        int remaining;
        int handled = 0;
 
-       logical_sector = raid_bio->bi_sector & ~((sector_t)STRIPE_SECTORS-1);
+       logical_sector = raid_bio->bi_iter.bi_sector &
+               ~((sector_t)STRIPE_SECTORS-1);
        sector = raid5_compute_sector(conf, logical_sector,
                                      0, &dd_idx, NULL);
        last_sector = bio_end_sector(raid_bio);
@@ -6101,6 +6103,7 @@ static int run(struct mddev *mddev)
                blk_queue_io_min(mddev->queue, chunk_size);
                blk_queue_io_opt(mddev->queue, chunk_size *
                                 (conf->raid_disks - conf->max_degraded));
+               mddev->queue->limits.raid_partial_stripes_expensive = 1;
                /*
                 * We can only discard a whole stripe. It doesn't make sense to
                 * discard data disk but write parity disk
index 8270388e2a0d2b703f2d08e2cc95533ff434dc14..1d0758aeb8e424bf77080e9914cb9bcc6619a0f7 100644 (file)
@@ -172,6 +172,9 @@ comment "Media ancillary drivers (tuners, sensors, i2c, frontends)"
 config MEDIA_SUBDRV_AUTOSELECT
        bool "Autoselect ancillary drivers (tuners, sensors, i2c, frontends)"
        depends on MEDIA_ANALOG_TV_SUPPORT || MEDIA_DIGITAL_TV_SUPPORT || MEDIA_CAMERA_SUPPORT
+       depends on HAS_IOMEM
+       select I2C
+       select I2C_MUX
        default y
        help
          By default, a media driver auto-selects all possible ancillary
index 419a2d6b43491d505fd386dd3468064f165ee1ff..f19a2ccd1e4b5e88c753200fc5177d88e7b1e8e9 100644 (file)
 #define USB_PID_AVERMEDIA_A835B_4835                   0x4835
 #define USB_PID_AVERMEDIA_1867                         0x1867
 #define USB_PID_AVERMEDIA_A867                         0xa867
+#define USB_PID_AVERMEDIA_H335                         0x0335
 #define USB_PID_AVERMEDIA_TWINSTAR                     0x0825
 #define USB_PID_TECHNOTREND_CONNECT_S2400               0x3006
 #define USB_PID_TECHNOTREND_CONNECT_S2400_8KEEPROM     0x3009
 #define USB_PID_WINFAST_DTV_DONGLE_H                   0x60f6
 #define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2          0x6f01
 #define USB_PID_WINFAST_DTV_DONGLE_GOLD                        0x6029
+#define USB_PID_WINFAST_DTV_DONGLE_MINID               0x6f0f
 #define USB_PID_GENPIX_8PSK_REV_1_COLD                 0x0200
 #define USB_PID_GENPIX_8PSK_REV_1_WARM                 0x0201
 #define USB_PID_GENPIX_8PSK_REV_2                      0x0202
 #define USB_PID_TERRATEC_DVBS2CI_V2                    0x10ac
 #define USB_PID_TECHNISAT_USB2_HDCI_V1                 0x0001
 #define USB_PID_TECHNISAT_USB2_HDCI_V2                 0x0002
+#define USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI          0x0003
 #define USB_PID_TECHNISAT_AIRSTAR_TELESTICK_2          0x0004
 #define USB_PID_TECHNISAT_USB2_DVB_S2                  0x0500
 #define USB_PID_CPYTO_REDI_PC50A                       0xa803
index bddbab43a2df01a3f243bb5300708c09e7cf4c21..dd12a1ebda823ffeadef699349fedcf2d2997a0a 100644 (file)
@@ -35,6 +35,13 @@ config DVB_STV6110x
        help
          A Silicon tuner that supports DVB-S and DVB-S2 modes
 
+config DVB_M88DS3103
+       tristate "Montage M88DS3103"
+       depends on DVB_CORE && I2C && I2C_MUX
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         Say Y when you want to support this frontend.
+
 comment "Multistandard (cable + terrestrial) frontends"
        depends on DVB_CORE
 
index f9cb43d9aed920816413d95656a83d3dad30a096..0c75a6aafb9d7424e2393accd13e873f7037504d 100644 (file)
@@ -85,6 +85,7 @@ obj-$(CONFIG_DVB_STV6110) += stv6110.o
 obj-$(CONFIG_DVB_STV0900) += stv0900.o
 obj-$(CONFIG_DVB_STV090x) += stv090x.o
 obj-$(CONFIG_DVB_STV6110x) += stv6110x.o
+obj-$(CONFIG_DVB_M88DS3103) += m88ds3103.o
 obj-$(CONFIG_DVB_ISL6423) += isl6423.o
 obj-$(CONFIG_DVB_EC100) += ec100.o
 obj-$(CONFIG_DVB_HD29L2) += hd29l2.o
index 74fbb5d58bed73a28d2c1f7356f0b732b78b67a5..780da58132f11336131ca8c1c6c0dae3481442de 100644 (file)
@@ -96,6 +96,8 @@ static int a8293_set_voltage(struct dvb_frontend *fe,
        if (ret)
                goto err;
 
+       usleep_range(1500, 50000);
+
        return ret;
 err:
        dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
index 476b422ccf1960bbf2cf71d5973fdd64e8680cdc..68f768a5422d063f69b4e33446364f5af699a7a1 100644 (file)
 
 
 enum cmds {
-       CMD_SET_VCO     = 0x10,
-       CMD_TUNEREQUEST = 0x11,
-       CMD_MPEGCONFIG  = 0x13,
-       CMD_TUNERINIT   = 0x14,
-       CMD_LNBSEND     = 0x21, /* Formerly CMD_SEND_DISEQC */
-       CMD_LNBDCLEVEL  = 0x22,
-       CMD_SET_TONE    = 0x23,
-       CMD_UPDFWVERS   = 0x35,
-       CMD_TUNERSLEEP  = 0x36,
+       CMD_SET_VCOFREQ    = 0x10,
+       CMD_TUNEREQUEST    = 0x11,
+       CMD_GLOBAL_MPEGCFG = 0x13,
+       CMD_MPEGCFG        = 0x14,
+       CMD_TUNERINIT      = 0x15,
+       CMD_GET_SRATE      = 0x18,
+       CMD_SET_GOLDCODE   = 0x19,
+       CMD_GET_AGCACC     = 0x1a,
+       CMD_DEMODINIT      = 0x1b,
+       CMD_GETCTLACC      = 0x1c,
+
+       CMD_LNBCONFIG      = 0x20,
+       CMD_LNBSEND        = 0x21,
+       CMD_LNBDCLEVEL     = 0x22,
+       CMD_LNBPCBCONFIG   = 0x23,
+       CMD_LNBSENDTONEBST = 0x24,
+       CMD_LNBUPDREPLY    = 0x25,
+
+       CMD_SET_GPIOMODE   = 0x30,
+       CMD_SET_GPIOEN     = 0x31,
+       CMD_SET_GPIODIR    = 0x32,
+       CMD_SET_GPIOOUT    = 0x33,
+       CMD_ENABLERSCORR   = 0x34,
+       CMD_FWVERSION      = 0x35,
+       CMD_SET_SLEEPMODE  = 0x36,
+       CMD_BERCTRL        = 0x3c,
+       CMD_EVENTCTRL      = 0x3d,
 };
 
 static LIST_HEAD(hybrid_tuner_instance_list);
@@ -619,8 +637,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
        cx24117_writereg(state, 0xf7, 0x0c);
        cx24117_writereg(state, 0xe0, 0x00);
 
-       /* CMD 1B */
-       cmd.args[0] = 0x1b;
+       /* Init demodulator */
+       cmd.args[0] = CMD_DEMODINIT;
        cmd.args[1] = 0x00;
        cmd.args[2] = 0x01;
        cmd.args[3] = 0x00;
@@ -629,8 +647,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
        if (ret != 0)
                goto error;
 
-       /* CMD 10 */
-       cmd.args[0] = CMD_SET_VCO;
+       /* Set VCO frequency */
+       cmd.args[0] = CMD_SET_VCOFREQ;
        cmd.args[1] = 0x06;
        cmd.args[2] = 0x2b;
        cmd.args[3] = 0xd8;
@@ -648,8 +666,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
        if (ret != 0)
                goto error;
 
-       /* CMD 15 */
-       cmd.args[0] = 0x15;
+       /* Tuner init */
+       cmd.args[0] = CMD_TUNERINIT;
        cmd.args[1] = 0x00;
        cmd.args[2] = 0x01;
        cmd.args[3] = 0x00;
@@ -667,8 +685,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
        if (ret != 0)
                goto error;
 
-       /* CMD 13 */
-       cmd.args[0] = CMD_MPEGCONFIG;
+       /* Global MPEG config */
+       cmd.args[0] = CMD_GLOBAL_MPEGCFG;
        cmd.args[1] = 0x00;
        cmd.args[2] = 0x00;
        cmd.args[3] = 0x00;
@@ -679,9 +697,9 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
        if (ret != 0)
                goto error;
 
-       /* CMD 14 */
+       /* MPEG config for each demod */
        for (i = 0; i < 2; i++) {
-               cmd.args[0] = CMD_TUNERINIT;
+               cmd.args[0] = CMD_MPEGCFG;
                cmd.args[1] = (u8) i;
                cmd.args[2] = 0x00;
                cmd.args[3] = 0x05;
@@ -699,8 +717,8 @@ static int cx24117_load_firmware(struct dvb_frontend *fe,
        cx24117_writereg(state, 0xcf, 0x00);
        cx24117_writereg(state, 0xe5, 0x04);
 
-       /* Firmware CMD 35: Get firmware version */
-       cmd.args[0] = CMD_UPDFWVERS;
+       /* Get firmware version */
+       cmd.args[0] = CMD_FWVERSION;
        cmd.len = 2;
        for (i = 0; i < 4; i++) {
                cmd.args[1] = i;
@@ -779,8 +797,8 @@ static int cx24117_read_signal_strength(struct dvb_frontend *fe,
        u8 reg = (state->demod == 0) ?
                CX24117_REG_SSTATUS0 : CX24117_REG_SSTATUS1;
 
-       /* Firmware CMD 1A */
-       cmd.args[0] = 0x1a;
+       /* Read AGC accumulator register */
+       cmd.args[0] = CMD_GET_AGCACC;
        cmd.args[1] = (u8) state->demod;
        cmd.len = 2;
        ret = cx24117_cmd_execute(fe, &cmd);
@@ -899,22 +917,15 @@ static int cx24117_set_voltage(struct dvb_frontend *fe,
                voltage == SEC_VOLTAGE_18 ? "SEC_VOLTAGE_18" :
                "SEC_VOLTAGE_OFF");
 
-       /* CMD 32 */
-       cmd.args[0] = 0x32;
-       cmd.args[1] = reg;
-       cmd.args[2] = reg;
+       /* Prepare a set GPIO logic level CMD */
+       cmd.args[0] = CMD_SET_GPIOOUT;
+       cmd.args[2] = reg; /* mask */
        cmd.len = 3;
-       ret = cx24117_cmd_execute(fe, &cmd);
-       if (ret)
-               return ret;
 
        if ((voltage == SEC_VOLTAGE_13) ||
            (voltage == SEC_VOLTAGE_18)) {
-               /* CMD 33 */
-               cmd.args[0] = 0x33;
+               /* power on LNB */
                cmd.args[1] = reg;
-               cmd.args[2] = reg;
-               cmd.len = 3;
                ret = cx24117_cmd_execute(fe, &cmd);
                if (ret != 0)
                        return ret;
@@ -926,22 +937,22 @@ static int cx24117_set_voltage(struct dvb_frontend *fe,
                /* Wait for voltage/min repeat delay */
                msleep(100);
 
-               /* CMD 22 - CMD_LNBDCLEVEL */
+               /* Set 13V/18V select pin */
                cmd.args[0] = CMD_LNBDCLEVEL;
                cmd.args[1] = state->demod ? 0 : 1;
                cmd.args[2] = (voltage == SEC_VOLTAGE_18 ? 0x01 : 0x00);
                cmd.len = 3;
+               ret = cx24117_cmd_execute(fe, &cmd);
 
                /* Min delay time before DiSEqC send */
                msleep(20);
        } else {
-               cmd.args[0] = 0x33;
+               /* power off LNB */
                cmd.args[1] = 0x00;
-               cmd.args[2] = reg;
-               cmd.len = 3;
+               ret = cx24117_cmd_execute(fe, &cmd);
        }
 
-       return cx24117_cmd_execute(fe, &cmd);
+       return ret;
 }
 
 static int cx24117_set_tone(struct dvb_frontend *fe,
@@ -968,8 +979,7 @@ static int cx24117_set_tone(struct dvb_frontend *fe,
        msleep(20);
 
        /* Set the tone */
-       /* CMD 23 - CMD_SET_TONE */
-       cmd.args[0] = CMD_SET_TONE;
+       cmd.args[0] = CMD_LNBPCBCONFIG;
        cmd.args[1] = (state->demod ? 0 : 1);
        cmd.args[2] = 0x00;
        cmd.args[3] = 0x00;
@@ -1231,8 +1241,8 @@ static int cx24117_initfe(struct dvb_frontend *fe)
 
        mutex_lock(&state->priv->fe_lock);
 
-       /* Firmware CMD 36: Power config */
-       cmd.args[0] = CMD_TUNERSLEEP;
+       /* Set sleep mode off */
+       cmd.args[0] = CMD_SET_SLEEPMODE;
        cmd.args[1] = (state->demod ? 1 : 0);
        cmd.args[2] = 0;
        cmd.len = 3;
@@ -1244,8 +1254,8 @@ static int cx24117_initfe(struct dvb_frontend *fe)
        if (ret != 0)
                goto exit;
 
-       /* CMD 3C */
-       cmd.args[0] = 0x3c;
+       /* Set BER control */
+       cmd.args[0] = CMD_BERCTRL;
        cmd.args[1] = (state->demod ? 1 : 0);
        cmd.args[2] = 0x10;
        cmd.args[3] = 0x10;
@@ -1254,12 +1264,22 @@ static int cx24117_initfe(struct dvb_frontend *fe)
        if (ret != 0)
                goto exit;
 
-       /* CMD 34 */
-       cmd.args[0] = 0x34;
+       /* Set RS correction (enable/disable) */
+       cmd.args[0] = CMD_ENABLERSCORR;
        cmd.args[1] = (state->demod ? 1 : 0);
        cmd.args[2] = CX24117_OCC;
        cmd.len = 3;
        ret = cx24117_cmd_execute_nolock(fe, &cmd);
+       if (ret != 0)
+               goto exit;
+
+       /* Set GPIO direction */
+       /* Set as output - controls LNB power on/off */
+       cmd.args[0] = CMD_SET_GPIODIR;
+       cmd.args[1] = 0x30;
+       cmd.args[2] = 0x30;
+       cmd.len = 3;
+       ret = cx24117_cmd_execute_nolock(fe, &cmd);
 
 exit:
        mutex_unlock(&state->priv->fe_lock);
@@ -1278,8 +1298,8 @@ static int cx24117_sleep(struct dvb_frontend *fe)
        dev_dbg(&state->priv->i2c->dev, "%s() demod%d\n",
                __func__, state->demod);
 
-       /* Firmware CMD 36: Power config */
-       cmd.args[0] = CMD_TUNERSLEEP;
+       /* Set sleep mode on */
+       cmd.args[0] = CMD_SET_SLEEPMODE;
        cmd.args[1] = (state->demod ? 1 : 0);
        cmd.args[2] = 1;
        cmd.len = 3;
@@ -1558,7 +1578,8 @@ static int cx24117_get_frontend(struct dvb_frontend *fe)
 
        u8 buf[0x1f-4];
 
-       cmd.args[0] = 0x1c;
+       /* Read current tune parameters */
+       cmd.args[0] = CMD_GETCTLACC;
        cmd.args[1] = (u8) state->demod;
        cmd.len = 2;
        ret = cx24117_cmd_execute(fe, &cmd);
index 6dbbee453ee15adb0c4d6b97196beefe6e7d9523..1632d78a547928327f8a8da45380c4c299a57a48 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/slab.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
+#include <asm/div64.h>
 
 #include "dvb_math.h"
 
@@ -118,6 +119,12 @@ struct dib8000_state {
        u8 longest_intlv_layer;
        u16 output_mode;
 
+       /* for DVBv5 stats */
+       s64 init_ucb;
+       unsigned long per_jiffies_stats;
+       unsigned long ber_jiffies_stats;
+       unsigned long ber_jiffies_stats_layer[3];
+
 #ifdef DIB8000_AGC_FREEZE
        u16 agc1_max;
        u16 agc1_min;
@@ -157,15 +164,10 @@ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
        return ret;
 }
 
-static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
+static u16 __dib8000_read_word(struct dib8000_state *state, u16 reg)
 {
        u16 ret;
 
-       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
-               dprintk("could not acquire lock");
-               return 0;
-       }
-
        state->i2c_write_buffer[0] = reg >> 8;
        state->i2c_write_buffer[1] = reg & 0xff;
 
@@ -183,6 +185,21 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
                dprintk("i2c read error on %d", reg);
 
        ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
+
+       return ret;
+}
+
+static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
+{
+       u16 ret;
+
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
+       ret = __dib8000_read_word(state, reg);
+
        mutex_unlock(&state->i2c_buffer_lock);
 
        return ret;
@@ -192,8 +209,15 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
 {
        u16 rw[2];
 
-       rw[0] = dib8000_read_word(state, reg + 0);
-       rw[1] = dib8000_read_word(state, reg + 1);
+       if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
+               dprintk("could not acquire lock");
+               return 0;
+       }
+
+       rw[0] = __dib8000_read_word(state, reg + 0);
+       rw[1] = __dib8000_read_word(state, reg + 1);
+
+       mutex_unlock(&state->i2c_buffer_lock);
 
        return ((rw[0] << 16) | (rw[1]));
 }
@@ -787,7 +811,7 @@ int dib8000_update_pll(struct dvb_frontend *fe,
                        dprintk("PLL: Update ratio (prediv: %d, ratio: %d)", state->cfg.pll->pll_prediv, ratio);
                        dib8000_write_word(state, 901, (state->cfg.pll->pll_prediv << 8) | (ratio << 0)); /* only the PLL ratio is updated. */
                }
-}
+       }
 
        return 0;
 }
@@ -966,6 +990,45 @@ static u16 dib8000_identify(struct i2c_device *client)
        return value;
 }
 
+static int dib8000_read_unc_blocks(struct dvb_frontend *fe, u32 *unc);
+
+static void dib8000_reset_stats(struct dvb_frontend *fe)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+       u32 ucb;
+
+       memset(&c->strength, 0, sizeof(c->strength));
+       memset(&c->cnr, 0, sizeof(c->cnr));
+       memset(&c->post_bit_error, 0, sizeof(c->post_bit_error));
+       memset(&c->post_bit_count, 0, sizeof(c->post_bit_count));
+       memset(&c->block_error, 0, sizeof(c->block_error));
+
+       c->strength.len = 1;
+       c->cnr.len = 1;
+       c->block_error.len = 1;
+       c->block_count.len = 1;
+       c->post_bit_error.len = 1;
+       c->post_bit_count.len = 1;
+
+       c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+       c->strength.stat[0].uvalue = 0;
+
+       c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+       c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+       dib8000_read_unc_blocks(fe, &ucb);
+
+       state->init_ucb = -ucb;
+       state->ber_jiffies_stats = 0;
+       state->per_jiffies_stats = 0;
+       memset(&state->ber_jiffies_stats_layer, 0,
+              sizeof(state->ber_jiffies_stats_layer));
+}
+
 static int dib8000_reset(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
@@ -1071,6 +1134,8 @@ static int dib8000_reset(struct dvb_frontend *fe)
 
        dib8000_set_power_mode(state, DIB8000_POWER_INTERFACE_ONLY);
 
+       dib8000_reset_stats(fe);
+
        return 0;
 }
 
@@ -2445,7 +2510,8 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe)
        if (state->revision == 0x8090)
                internal = dib8000_read32(state, 23) / 1000;
 
-       if (state->autosearch_state == AS_SEARCHING_FFT) {
+       if ((state->revision >= 0x8002) &&
+           (state->autosearch_state == AS_SEARCHING_FFT)) {
                dib8000_write_word(state,  37, 0x0065); /* P_ctrl_pha_off_max default values */
                dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */
 
@@ -2481,7 +2547,8 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe)
                dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */
                dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */
                dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */
-       } else if (state->autosearch_state == AS_SEARCHING_GUARD) {
+       } else if ((state->revision >= 0x8002) &&
+                  (state->autosearch_state == AS_SEARCHING_GUARD)) {
                c->transmission_mode = TRANSMISSION_MODE_8K;
                c->guard_interval = GUARD_INTERVAL_1_8;
                c->inversion = 0;
@@ -2583,7 +2650,8 @@ static int dib8000_autosearch_irq(struct dvb_frontend *fe)
        struct dib8000_state *state = fe->demodulator_priv;
        u16 irq_pending = dib8000_read_word(state, 1284);
 
-       if (state->autosearch_state == AS_SEARCHING_FFT) {
+       if ((state->revision >= 0x8002) &&
+           (state->autosearch_state == AS_SEARCHING_FFT)) {
                if (irq_pending & 0x1) {
                        dprintk("dib8000_autosearch_irq: max correlation result available");
                        return 3;
@@ -2853,6 +2921,91 @@ static int dib8090p_init_sdram(struct dib8000_state *state)
        return 0;
 }
 
+/**
+ * is_manual_mode - Check if TMCC should be used for parameters settings
+ * @c: struct dvb_frontend_properties
+ *
+ * By default, TMCC table should be used for parameter settings on most
+ * usercases. However, sometimes it is desirable to lock the demod to
+ * use the manual parameters.
+ *
+ * On manual mode, the current dib8000_tune state machine is very restrict:
+ * It requires that both per-layer and per-transponder parameters to be
+ * properly specified, otherwise the device won't lock.
+ *
+ * Check if all those conditions are properly satisfied before allowing
+ * the device to use the manual frequency lock mode.
+ */
+static int is_manual_mode(struct dtv_frontend_properties *c)
+{
+       int i, n_segs = 0;
+
+       /* Use auto mode on DVB-T compat mode */
+       if (c->delivery_system != SYS_ISDBT)
+               return 0;
+
+       /*
+        * Transmission mode is only detected on auto mode, currently
+        */
+       if (c->transmission_mode == TRANSMISSION_MODE_AUTO) {
+               dprintk("transmission mode auto");
+               return 0;
+       }
+
+       /*
+        * Guard interval is only detected on auto mode, currently
+        */
+       if (c->guard_interval == GUARD_INTERVAL_AUTO) {
+               dprintk("guard interval auto");
+               return 0;
+       }
+
+       /*
+        * If no layer is enabled, assume auto mode, as at least one
+        * layer should be enabled
+        */
+       if (!c->isdbt_layer_enabled) {
+               dprintk("no layer modulation specified");
+               return 0;
+       }
+
+       /*
+        * Check if the per-layer parameters aren't auto and
+        * disable a layer if segment count is 0 or invalid.
+        */
+       for (i = 0; i < 3; i++) {
+               if (!(c->isdbt_layer_enabled & 1 << i))
+                       continue;
+
+               if ((c->layer[i].segment_count > 13) ||
+                   (c->layer[i].segment_count == 0)) {
+                       c->isdbt_layer_enabled &= ~(1 << i);
+                       continue;
+               }
+
+               n_segs += c->layer[i].segment_count;
+
+               if ((c->layer[i].modulation == QAM_AUTO) ||
+                   (c->layer[i].fec == FEC_AUTO)) {
+                       dprintk("layer %c has either modulation or FEC auto",
+                               'A' + i);
+                       return 0;
+               }
+       }
+
+       /*
+        * Userspace specified a wrong number of segments.
+        *      fallback to auto mode.
+        */
+       if (n_segs == 0 || n_segs > 13) {
+               dprintk("number of segments is invalid");
+               return 0;
+       }
+
+       /* Everything looks ok for manual mode */
+       return 1;
+}
+
 static int dib8000_tune(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
@@ -2878,40 +3031,19 @@ static int dib8000_tune(struct dvb_frontend *fe)
 
        switch (*tune_state) {
        case CT_DEMOD_START: /* 30 */
+                       dib8000_reset_stats(fe);
+
                        if (state->revision == 0x8090)
                                dib8090p_init_sdram(state);
                        state->status = FE_STATUS_TUNE_PENDING;
-                       if ((c->delivery_system != SYS_ISDBT) ||
-                                       (c->inversion == INVERSION_AUTO) ||
-                                       (c->transmission_mode == TRANSMISSION_MODE_AUTO) ||
-                                       (c->guard_interval == GUARD_INTERVAL_AUTO) ||
-                                       (((c->isdbt_layer_enabled & (1 << 0)) != 0) &&
-                                        (c->layer[0].segment_count != 0xff) &&
-                                        (c->layer[0].segment_count != 0) &&
-                                        ((c->layer[0].modulation == QAM_AUTO) ||
-                                         (c->layer[0].fec == FEC_AUTO))) ||
-                                       (((c->isdbt_layer_enabled & (1 << 1)) != 0) &&
-                                        (c->layer[1].segment_count != 0xff) &&
-                                        (c->layer[1].segment_count != 0) &&
-                                        ((c->layer[1].modulation == QAM_AUTO) ||
-                                         (c->layer[1].fec == FEC_AUTO))) ||
-                                       (((c->isdbt_layer_enabled & (1 << 2)) != 0) &&
-                                        (c->layer[2].segment_count != 0xff) &&
-                                        (c->layer[2].segment_count != 0) &&
-                                        ((c->layer[2].modulation == QAM_AUTO) ||
-                                         (c->layer[2].fec == FEC_AUTO))) ||
-                                       (((c->layer[0].segment_count == 0) ||
-                                         ((c->isdbt_layer_enabled & (1 << 0)) == 0)) &&
-                                        ((c->layer[1].segment_count == 0) ||
-                                         ((c->isdbt_layer_enabled & (2 << 0)) == 0)) &&
-                                        ((c->layer[2].segment_count == 0) || ((c->isdbt_layer_enabled & (3 << 0)) == 0))))
-                               state->channel_parameters_set = 0; /* auto search */
-                       else
-                               state->channel_parameters_set = 1; /* channel parameters are known */
+                       state->channel_parameters_set = is_manual_mode(c);
+
+                       dprintk("Tuning channel on %s search mode",
+                               state->channel_parameters_set ? "manual" : "auto");
 
                        dib8000_viterbi_state(state, 0); /* force chan dec in restart */
 
-                       /* Layer monit */
+                       /* Layer monitor */
                        dib8000_write_word(state, 285, dib8000_read_word(state, 285) & 0x60);
 
                        dib8000_set_frequency_offset(state);
@@ -3256,15 +3388,27 @@ static int dib8000_sleep(struct dvb_frontend *fe)
        return dib8000_set_adc_state(state, DIBX000_SLOW_ADC_OFF) | dib8000_set_adc_state(state, DIBX000_ADC_OFF);
 }
 
+static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat);
+
 static int dib8000_get_frontend(struct dvb_frontend *fe)
 {
        struct dib8000_state *state = fe->demodulator_priv;
        u16 i, val = 0;
-       fe_status_t stat;
+       fe_status_t stat = 0;
        u8 index_frontend, sub_index_frontend;
 
        fe->dtv_property_cache.bandwidth_hz = 6000000;
 
+       /*
+        * If called to early, get_frontend makes dib8000_tune to either
+        * not lock or not sync. This causes dvbv5-scan/dvbv5-zap to fail.
+        * So, let's just return if frontend 0 has not locked.
+        */
+       dib8000_read_status(fe, &stat);
+       if (!(stat & FE_HAS_SYNC))
+               return 0;
+
+       dprintk("TMCC lock");
        for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
                state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
                if (stat&FE_HAS_SYNC) {
@@ -3335,9 +3479,13 @@ static int dib8000_get_frontend(struct dvb_frontend *fe)
                fe->dtv_property_cache.layer[i].segment_count = val & 0x0F;
                dprintk("dib8000_get_frontend : Layer %d segments = %d ", i, fe->dtv_property_cache.layer[i].segment_count);
 
-               val = dib8000_read_word(state, 499 + i);
-               fe->dtv_property_cache.layer[i].interleaving = val & 0x3;
-               dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ", i, fe->dtv_property_cache.layer[i].interleaving);
+               val = dib8000_read_word(state, 499 + i) & 0x3;
+               /* Interleaving can be 0, 1, 2 or 4 */
+               if (val == 3)
+                       val = 4;
+               fe->dtv_property_cache.layer[i].interleaving = val;
+               dprintk("dib8000_get_frontend : Layer %d time_intlv = %d ",
+                       i, fe->dtv_property_cache.layer[i].interleaving);
 
                val = dib8000_read_word(state, 481 + i);
                switch (val & 0x7) {
@@ -3556,6 +3704,8 @@ static int dib8000_set_frontend(struct dvb_frontend *fe)
        return 0;
 }
 
+static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat);
+
 static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
 {
        struct dib8000_state *state = fe->demodulator_priv;
@@ -3593,6 +3743,7 @@ static int dib8000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
                if (lock & 0x01)
                        *stat |= FE_HAS_VITERBI;
        }
+       dib8000_get_stats(fe, *stat);
 
        return 0;
 }
@@ -3699,6 +3850,357 @@ static int dib8000_read_snr(struct dvb_frontend *fe, u16 * snr)
        return 0;
 }
 
+struct per_layer_regs {
+       u16 lock, ber, per;
+};
+
+static const struct per_layer_regs per_layer_regs[] = {
+       { 554, 560, 562 },
+       { 555, 576, 578 },
+       { 556, 581, 583 },
+};
+
+struct linear_segments {
+       unsigned x;
+       signed y;
+};
+
+/*
+ * Table to estimate signal strength in dBm.
+ * This table was empirically determinated by measuring the signal
+ * strength generated by a DTA-2111 RF generator directly connected into
+ * a dib8076 device (a PixelView PV-D231U stick), using a good quality
+ * 3 meters RC6 cable and good RC6 connectors.
+ * The real value can actually be different on other devices, depending
+ * on several factors, like if LNA is enabled or not, if diversity is
+ * enabled, type of connectors, etc.
+ * Yet, it is better to use this measure in dB than a random non-linear
+ * percentage value, especially for antenna adjustments.
+ * On my tests, the precision of the measure using this table is about
+ * 0.5 dB, with sounds reasonable enough.
+ */
+static struct linear_segments strength_to_db_table[] = {
+       { 55953, 108500 },      /* -22.5 dBm */
+       { 55394, 108000 },
+       { 53834, 107000 },
+       { 52863, 106000 },
+       { 52239, 105000 },
+       { 52012, 104000 },
+       { 51803, 103000 },
+       { 51566, 102000 },
+       { 51356, 101000 },
+       { 51112, 100000 },
+       { 50869,  99000 },
+       { 50600,  98000 },
+       { 50363,  97000 },
+       { 50117,  96000 },      /* -35 dBm */
+       { 49889,  95000 },
+       { 49680,  94000 },
+       { 49493,  93000 },
+       { 49302,  92000 },
+       { 48929,  91000 },
+       { 48416,  90000 },
+       { 48035,  89000 },
+       { 47593,  88000 },
+       { 47282,  87000 },
+       { 46953,  86000 },
+       { 46698,  85000 },
+       { 45617,  84000 },
+       { 44773,  83000 },
+       { 43845,  82000 },
+       { 43020,  81000 },
+       { 42010,  80000 },      /* -51 dBm */
+       {     0,      0 },
+};
+
+static u32 interpolate_value(u32 value, struct linear_segments *segments,
+                            unsigned len)
+{
+       u64 tmp64;
+       u32 dx;
+       s32 dy;
+       int i, ret;
+
+       if (value >= segments[0].x)
+               return segments[0].y;
+       if (value < segments[len-1].x)
+               return segments[len-1].y;
+
+       for (i = 1; i < len - 1; i++) {
+               /* If value is identical, no need to interpolate */
+               if (value == segments[i].x)
+                       return segments[i].y;
+               if (value > segments[i].x)
+                       break;
+       }
+
+       /* Linear interpolation between the two (x,y) points */
+       dy = segments[i - 1].y - segments[i].y;
+       dx = segments[i - 1].x - segments[i].x;
+
+       tmp64 = value - segments[i].x;
+       tmp64 *= dy;
+       do_div(tmp64, dx);
+       ret = segments[i].y + tmp64;
+
+       return ret;
+}
+
+static u32 dib8000_get_time_us(struct dvb_frontend *fe, int layer)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+       int ini_layer, end_layer, i;
+       u64 time_us, tmp64;
+       u32 tmp, denom;
+       int guard, rate_num, rate_denum = 1, bits_per_symbol, nsegs;
+       int interleaving = 0, fft_div;
+
+       if (layer >= 0) {
+               ini_layer = layer;
+               end_layer = layer + 1;
+       } else {
+               ini_layer = 0;
+               end_layer = 3;
+       }
+
+       switch (c->guard_interval) {
+       case GUARD_INTERVAL_1_4:
+               guard = 4;
+               break;
+       case GUARD_INTERVAL_1_8:
+               guard = 8;
+               break;
+       case GUARD_INTERVAL_1_16:
+               guard = 16;
+               break;
+       default:
+       case GUARD_INTERVAL_1_32:
+               guard = 32;
+               break;
+       }
+
+       switch (c->transmission_mode) {
+       case TRANSMISSION_MODE_2K:
+               fft_div = 4;
+               break;
+       case TRANSMISSION_MODE_4K:
+               fft_div = 2;
+               break;
+       default:
+       case TRANSMISSION_MODE_8K:
+               fft_div = 1;
+               break;
+       }
+
+       denom = 0;
+       for (i = ini_layer; i < end_layer; i++) {
+               nsegs = c->layer[i].segment_count;
+               if (nsegs == 0 || nsegs > 13)
+                       continue;
+
+               switch (c->layer[i].modulation) {
+               case DQPSK:
+               case QPSK:
+                       bits_per_symbol = 2;
+                       break;
+               case QAM_16:
+                       bits_per_symbol = 4;
+                       break;
+               default:
+               case QAM_64:
+                       bits_per_symbol = 6;
+                       break;
+               }
+
+               switch (c->layer[i].fec) {
+               case FEC_1_2:
+                       rate_num = 1;
+                       rate_denum = 2;
+                       break;
+               case FEC_2_3:
+                       rate_num = 2;
+                       rate_denum = 3;
+                       break;
+               case FEC_3_4:
+                       rate_num = 3;
+                       rate_denum = 4;
+                       break;
+               case FEC_5_6:
+                       rate_num = 5;
+                       rate_denum = 6;
+                       break;
+               default:
+               case FEC_7_8:
+                       rate_num = 7;
+                       rate_denum = 8;
+                       break;
+               }
+
+               interleaving = c->layer[i].interleaving;
+
+               denom += bits_per_symbol * rate_num * fft_div * nsegs * 384;
+       }
+
+       /* If all goes wrong, wait for 1s for the next stats */
+       if (!denom)
+               return 0;
+
+       /* Estimate the period for the total bit rate */
+       time_us = rate_denum * (1008 * 1562500L);
+       tmp64 = time_us;
+       do_div(tmp64, guard);
+       time_us = time_us + tmp64;
+       time_us += denom / 2;
+       do_div(time_us, denom);
+
+       tmp = 1008 * 96 * interleaving;
+       time_us += tmp + tmp / guard;
+
+       return time_us;
+}
+
+static int dib8000_get_stats(struct dvb_frontend *fe, fe_status_t stat)
+{
+       struct dib8000_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &state->fe[0]->dtv_property_cache;
+       int i;
+       int show_per_stats = 0;
+       u32 time_us = 0, snr, val;
+       u64 blocks;
+       s32 db;
+       u16 strength;
+
+       /* Get Signal strength */
+       dib8000_read_signal_strength(fe, &strength);
+       val = strength;
+       db = interpolate_value(val,
+                              strength_to_db_table,
+                              ARRAY_SIZE(strength_to_db_table)) - 131000;
+       c->strength.stat[0].svalue = db;
+
+       /* UCB/BER/CNR measures require lock */
+       if (!(stat & FE_HAS_LOCK)) {
+               c->cnr.len = 1;
+               c->block_count.len = 1;
+               c->block_error.len = 1;
+               c->post_bit_error.len = 1;
+               c->post_bit_count.len = 1;
+               c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+               return 0;
+       }
+
+       /* Check if time for stats was elapsed */
+       if (time_after(jiffies, state->per_jiffies_stats)) {
+               state->per_jiffies_stats = jiffies + msecs_to_jiffies(1000);
+
+               /* Get SNR */
+               snr = dib8000_get_snr(fe);
+               for (i = 1; i < MAX_NUMBER_OF_FRONTENDS; i++) {
+                       if (state->fe[i])
+                               snr += dib8000_get_snr(state->fe[i]);
+               }
+               snr = snr >> 16;
+
+               if (snr) {
+                       snr = 10 * intlog10(snr);
+                       snr = (1000L * snr) >> 24;
+               } else {
+                       snr = 0;
+               }
+               c->cnr.stat[0].svalue = snr;
+               c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+
+               /* Get UCB measures */
+               dib8000_read_unc_blocks(fe, &val);
+               if (val < state->init_ucb)
+                       state->init_ucb += 0x100000000LL;
+
+               c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->block_error.stat[0].uvalue = val + state->init_ucb;
+
+               /* Estimate the number of packets based on bitrate */
+               if (!time_us)
+                       time_us = dib8000_get_time_us(fe, -1);
+
+               if (time_us) {
+                       blocks = 1250000ULL * 1000000ULL;
+                       do_div(blocks, time_us * 8 * 204);
+                       c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+                       c->block_count.stat[0].uvalue += blocks;
+               }
+
+               show_per_stats = 1;
+       }
+
+       /* Get post-BER measures */
+       if (time_after(jiffies, state->ber_jiffies_stats)) {
+               time_us = dib8000_get_time_us(fe, -1);
+               state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
+
+               dprintk("Next all layers stats available in %u us.", time_us);
+
+               dib8000_read_ber(fe, &val);
+               c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+               c->post_bit_error.stat[0].uvalue += val;
+
+               c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+               c->post_bit_count.stat[0].uvalue += 100000000;
+       }
+
+       if (state->revision < 0x8002)
+               return 0;
+
+       c->block_error.len = 4;
+       c->post_bit_error.len = 4;
+       c->post_bit_count.len = 4;
+
+       for (i = 0; i < 3; i++) {
+               unsigned nsegs = c->layer[i].segment_count;
+
+               if (nsegs == 0 || nsegs > 13)
+                       continue;
+
+               time_us = 0;
+
+               if (time_after(jiffies, state->ber_jiffies_stats_layer[i])) {
+                       time_us = dib8000_get_time_us(fe, i);
+
+                       state->ber_jiffies_stats_layer[i] = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
+                       dprintk("Next layer %c  stats will be available in %u us\n",
+                               'A' + i, time_us);
+
+                       val = dib8000_read_word(state, per_layer_regs[i].ber);
+                       c->post_bit_error.stat[1 + i].scale = FE_SCALE_COUNTER;
+                       c->post_bit_error.stat[1 + i].uvalue += val;
+
+                       c->post_bit_count.stat[1 + i].scale = FE_SCALE_COUNTER;
+                       c->post_bit_count.stat[1 + i].uvalue += 100000000;
+               }
+
+               if (show_per_stats) {
+                       val = dib8000_read_word(state, per_layer_regs[i].per);
+
+                       c->block_error.stat[1 + i].scale = FE_SCALE_COUNTER;
+                       c->block_error.stat[1 + i].uvalue += val;
+
+                       if (!time_us)
+                               time_us = dib8000_get_time_us(fe, i);
+                       if (time_us) {
+                               blocks = 1250000ULL * 1000000ULL;
+                               do_div(blocks, time_us * 8 * 204);
+                               c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+                               c->block_count.stat[0].uvalue += blocks;
+                       }
+               }
+       }
+       return 0;
+}
+
 int dib8000_set_slave_frontend(struct dvb_frontend *fe, struct dvb_frontend *fe_slave)
 {
        struct dib8000_state *state = fe->demodulator_priv;
index f22eb9f13ad54622b4618bb8adaef4ca6ef22704..f6cb3466032778882cfc30925866c4da86910490 100644 (file)
@@ -29,7 +29,6 @@
  *                             A value of 0 (default) or lower indicates that
  *                             the correct number of parameters will be
  *                             automatically detected.
- * @load_firmware_sync:                Force the firmware load to be synchronous.
  *
  * On the *_gpio vars, bit 0 is UIO-1, bit 1 is UIO-2 and bit 2 is
  * UIO-3.
@@ -41,7 +40,6 @@ struct drxk_config {
        bool    parallel_ts;
        bool    dynamic_clk;
        bool    enable_merr_cfg;
-       bool    load_firmware_sync;
 
        bool    antenna_dvbt;
        u16     antenna_gpio;
index bf29a3f0e6f0ca440990f7b8b61e71e9bd02674a..cce94a75b2e1f74c4dc05c0715f6320f130fe988 100644 (file)
@@ -6830,25 +6830,13 @@ struct dvb_frontend *drxk_attach(const struct drxk_config *config,
 
        /* Load firmware and initialize DRX-K */
        if (state->microcode_name) {
-               if (config->load_firmware_sync) {
-                       const struct firmware *fw = NULL;
+               const struct firmware *fw = NULL;
 
-                       status = request_firmware(&fw, state->microcode_name,
-                                                 state->i2c->dev.parent);
-                       if (status < 0)
-                               fw = NULL;
-                       load_firmware_cb(fw, state);
-               } else {
-                       status = request_firmware_nowait(THIS_MODULE, 1,
-                                             state->microcode_name,
-                                             state->i2c->dev.parent,
-                                             GFP_KERNEL,
-                                             state, load_firmware_cb);
-                       if (status < 0) {
-                               pr_err("failed to request a firmware\n");
-                               return NULL;
-                       }
-               }
+               status = request_firmware(&fw, state->microcode_name,
+                                         state->i2c->dev.parent);
+               if (status < 0)
+                       fw = NULL;
+               load_firmware_cb(fw, state);
        } else if (init_drxk(state) < 0)
                goto error;
 
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
new file mode 100644 (file)
index 0000000..b8a7897
--- /dev/null
@@ -0,0 +1,1311 @@
+/*
+ * Montage M88DS3103 demodulator driver
+ *
+ * Copyright (C) 2013 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 "m88ds3103_priv.h"
+
+static struct dvb_frontend_ops m88ds3103_ops;
+
+/* write multiple registers */
+static int m88ds3103_wr_regs(struct m88ds3103_priv *priv,
+               u8 reg, const u8 *val, int len)
+{
+#define MAX_WR_LEN 32
+#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1)
+       int ret;
+       u8 buf[MAX_WR_XFER_LEN];
+       struct i2c_msg msg[1] = {
+               {
+                       .addr = priv->cfg->i2c_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);
+
+       mutex_lock(&priv->i2c_mutex);
+       ret = i2c_transfer(priv->i2c, msg, 1);
+       mutex_unlock(&priv->i2c_mutex);
+       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 m88ds3103_rd_regs(struct m88ds3103_priv *priv,
+               u8 reg, u8 *val, int len)
+{
+#define MAX_RD_LEN 3
+#define MAX_RD_XFER_LEN (MAX_RD_LEN)
+       int ret;
+       u8 buf[MAX_RD_XFER_LEN];
+       struct i2c_msg msg[2] = {
+               {
+                       .addr = priv->cfg->i2c_addr,
+                       .flags = 0,
+                       .len = 1,
+                       .buf = &reg,
+               }, {
+                       .addr = priv->cfg->i2c_addr,
+                       .flags = I2C_M_RD,
+                       .len = len,
+                       .buf = buf,
+               }
+       };
+
+       if (WARN_ON(len > MAX_RD_LEN))
+               return -EINVAL;
+
+       mutex_lock(&priv->i2c_mutex);
+       ret = i2c_transfer(priv->i2c, msg, 2);
+       mutex_unlock(&priv->i2c_mutex);
+       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 m88ds3103_wr_reg(struct m88ds3103_priv *priv, u8 reg, u8 val)
+{
+       return m88ds3103_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+static int m88ds3103_rd_reg(struct m88ds3103_priv *priv, u8 reg, u8 *val)
+{
+       return m88ds3103_rd_regs(priv, reg, val, 1);
+}
+
+/* write single register with mask */
+static int m88ds3103_wr_reg_mask(struct m88ds3103_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 = m88ds3103_rd_regs(priv, reg, &u8tmp, 1);
+               if (ret)
+                       return ret;
+
+               val &= mask;
+               u8tmp &= ~mask;
+               val |= u8tmp;
+       }
+
+       return m88ds3103_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register with mask */
+static int m88ds3103_rd_reg_mask(struct m88ds3103_priv *priv,
+               u8 reg, u8 *val, u8 mask)
+{
+       int ret, i;
+       u8 u8tmp;
+
+       ret = m88ds3103_rd_regs(priv, reg, &u8tmp, 1);
+       if (ret)
+               return ret;
+
+       u8tmp &= mask;
+
+       /* find position of the first bit */
+       for (i = 0; i < 8; i++) {
+               if ((mask >> i) & 0x01)
+                       break;
+       }
+       *val = u8tmp >> i;
+
+       return 0;
+}
+
+/* write reg val table using reg addr auto increment */
+static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv,
+               const struct m88ds3103_reg_val *tab, int tab_len)
+{
+       int ret, i, j;
+       u8 buf[83];
+       dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len);
+
+       if (tab_len > 83) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       for (i = 0, j = 0; i < tab_len; i++, j++) {
+               buf[j] = tab[i].val;
+
+               if (i == tab_len - 1 || tab[i].reg != tab[i + 1].reg - 1 ||
+                               !((j + 1) % (priv->cfg->i2c_wr_max - 1))) {
+                       ret = m88ds3103_wr_regs(priv, tab[i].reg - j, buf, j + 1);
+                       if (ret)
+                               goto err;
+
+                       j = -1;
+               }
+       }
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int m88ds3103_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct m88ds3103_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret;
+       u8 u8tmp;
+
+       *status = 0;
+
+       if (!priv->warm) {
+               ret = -EAGAIN;
+               goto err;
+       }
+
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               ret = m88ds3103_rd_reg_mask(priv, 0xd1, &u8tmp, 0x07);
+               if (ret)
+                       goto err;
+
+               if (u8tmp == 0x07)
+                       *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                                       FE_HAS_VITERBI | FE_HAS_SYNC |
+                                       FE_HAS_LOCK;
+               break;
+       case SYS_DVBS2:
+               ret = m88ds3103_rd_reg_mask(priv, 0x0d, &u8tmp, 0x8f);
+               if (ret)
+                       goto err;
+
+               if (u8tmp == 0x8f)
+                       *status = FE_HAS_SIGNAL | FE_HAS_CARRIER |
+                                       FE_HAS_VITERBI | FE_HAS_SYNC |
+                                       FE_HAS_LOCK;
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
+                               __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       priv->fe_status = *status;
+
+       dev_dbg(&priv->i2c->dev, "%s: lock=%02x status=%02x\n",
+                       __func__, u8tmp, *status);
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int m88ds3103_set_frontend(struct dvb_frontend *fe)
+{
+       struct m88ds3103_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, len;
+       const struct m88ds3103_reg_val *init;
+       u8 u8tmp, u8tmp1, u8tmp2;
+       u8 buf[2];
+       u16 u16tmp, divide_ratio;
+       u32 tuner_frequency, target_mclk, ts_clk;
+       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,
+                       c->modulation, c->frequency, c->symbol_rate,
+                       c->inversion, c->pilot, c->rolloff);
+
+       if (!priv->warm) {
+               ret = -EAGAIN;
+               goto err;
+       }
+
+       /* program tuner */
+       if (fe->ops.tuner_ops.set_params) {
+               ret = fe->ops.tuner_ops.set_params(fe);
+               if (ret)
+                       goto err;
+       }
+
+       if (fe->ops.tuner_ops.get_frequency) {
+               ret = fe->ops.tuner_ops.get_frequency(fe, &tuner_frequency);
+               if (ret)
+                       goto err;
+       }
+
+       /* reset */
+       ret = m88ds3103_wr_reg(priv, 0x07, 0x80);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0x07, 0x00);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0xb2, 0x01);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0x00, 0x01);
+       if (ret)
+               goto err;
+
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals);
+               init = m88ds3103_dvbs_init_reg_vals;
+               target_mclk = 96000;
+               break;
+       case SYS_DVBS2:
+               len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals);
+               init = m88ds3103_dvbs2_init_reg_vals;
+
+               switch (priv->cfg->ts_mode) {
+               case M88DS3103_TS_SERIAL:
+               case M88DS3103_TS_SERIAL_D7:
+                       if (c->symbol_rate < 18000000)
+                               target_mclk = 96000;
+                       else
+                               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;
+                       else if (c->symbol_rate < 28000000)
+                               target_mclk = 144000;
+                       else
+                               target_mclk = 192000;
+                       break;
+               default:
+                       dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n",
+                                       __func__);
+                       ret = -EINVAL;
+                       goto err;
+               }
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
+                               __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* program init table */
+       if (c->delivery_system != priv->delivery_system) {
+               ret = m88ds3103_wr_reg_val_tab(priv, init, len);
+               if (ret)
+                       goto err;
+       }
+
+       u8tmp1 = 0; /* silence compiler warning */
+       switch (priv->cfg->ts_mode) {
+       case M88DS3103_TS_SERIAL:
+               u8tmp1 = 0x00;
+               ts_clk = 0;
+               u8tmp = 0x46;
+               break;
+       case M88DS3103_TS_SERIAL_D7:
+               u8tmp1 = 0x20;
+               ts_clk = 0;
+               u8tmp = 0x46;
+               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;
+               break;
+       case M88DS3103_TS_CI:
+               ts_clk = 6000;
+               u8tmp = 0x43;
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n", __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       /* TS mode */
+       ret = m88ds3103_wr_reg(priv, 0xfd, u8tmp);
+       if (ret)
+               goto err;
+
+       switch (priv->cfg->ts_mode) {
+       case M88DS3103_TS_SERIAL:
+       case M88DS3103_TS_SERIAL_D7:
+               ret = m88ds3103_wr_reg_mask(priv, 0x29, u8tmp1, 0x20);
+               if (ret)
+                       goto err;
+       }
+
+       if (ts_clk) {
+               divide_ratio = DIV_ROUND_UP(target_mclk, ts_clk);
+               u8tmp1 = divide_ratio / 2;
+               u8tmp2 = DIV_ROUND_UP(divide_ratio, 2);
+       } else {
+               divide_ratio = 0;
+               u8tmp1 = 0;
+               u8tmp2 = 0;
+       }
+
+       dev_dbg(&priv->i2c->dev,
+                       "%s: target_mclk=%d ts_clk=%d divide_ratio=%d\n",
+                       __func__, target_mclk, ts_clk, divide_ratio);
+
+       u8tmp1--;
+       u8tmp2--;
+       /* u8tmp1[5:2] => fe[3:0], u8tmp1[1:0] => ea[7:6] */
+       u8tmp1 &= 0x3f;
+       /* u8tmp2[5:0] => ea[5:0] */
+       u8tmp2 &= 0x3f;
+
+       ret = m88ds3103_rd_reg(priv, 0xfe, &u8tmp);
+       if (ret)
+               goto err;
+
+       u8tmp = ((u8tmp  & 0xf0) << 0) | u8tmp1 >> 2;
+       ret = m88ds3103_wr_reg(priv, 0xfe, u8tmp);
+       if (ret)
+               goto err;
+
+       u8tmp = ((u8tmp1 & 0x03) << 6) | u8tmp2 >> 0;
+       ret = m88ds3103_wr_reg(priv, 0xea, u8tmp);
+       if (ret)
+               goto err;
+
+       switch (target_mclk) {
+       case 72000:
+               u8tmp1 = 0x00; /* 0b00 */
+               u8tmp2 = 0x03; /* 0b11 */
+               break;
+       case 96000:
+               u8tmp1 = 0x02; /* 0b10 */
+               u8tmp2 = 0x01; /* 0b01 */
+               break;
+       case 115200:
+               u8tmp1 = 0x01; /* 0b01 */
+               u8tmp2 = 0x01; /* 0b01 */
+               break;
+       case 144000:
+               u8tmp1 = 0x00; /* 0b00 */
+               u8tmp2 = 0x01; /* 0b01 */
+               break;
+       case 192000:
+               u8tmp1 = 0x03; /* 0b11 */
+               u8tmp2 = 0x00; /* 0b00 */
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid target_mclk\n", __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x22, u8tmp1 << 6, 0xc0);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x24, u8tmp2 << 6, 0xc0);
+       if (ret)
+               goto err;
+
+       if (c->symbol_rate <= 3000000)
+               u8tmp = 0x20;
+       else if (c->symbol_rate <= 10000000)
+               u8tmp = 0x10;
+       else
+               u8tmp = 0x06;
+
+       ret = m88ds3103_wr_reg(priv, 0xc3, 0x08);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0xc8, u8tmp);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0xc4, 0x08);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0xc7, 0x00);
+       if (ret)
+               goto err;
+
+       u16tmp = DIV_ROUND_CLOSEST((c->symbol_rate / 1000) << 15, M88DS3103_MCLK_KHZ / 2);
+       buf[0] = (u16tmp >> 0) & 0xff;
+       buf[1] = (u16tmp >> 8) & 0xff;
+       ret = m88ds3103_wr_regs(priv, 0x61, buf, 2);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x4d, priv->cfg->spec_inv << 1, 0x02);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x30, priv->cfg->agc_inv << 4, 0x10);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0x33, priv->cfg->agc);
+       if (ret)
+               goto err;
+
+       dev_dbg(&priv->i2c->dev, "%s: carrier offset=%d\n", __func__,
+                       (tuner_frequency - c->frequency));
+
+       s32tmp = 0x10000 * (tuner_frequency - c->frequency);
+       s32tmp = DIV_ROUND_CLOSEST(s32tmp, M88DS3103_MCLK_KHZ);
+       if (s32tmp < 0)
+               s32tmp += 0x10000;
+
+       buf[0] = (s32tmp >> 0) & 0xff;
+       buf[1] = (s32tmp >> 8) & 0xff;
+       ret = m88ds3103_wr_regs(priv, 0x5e, buf, 2);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0x00, 0x00);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0xb2, 0x00);
+       if (ret)
+               goto err;
+
+       priv->delivery_system = c->delivery_system;
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int m88ds3103_init(struct dvb_frontend *fe)
+{
+       struct m88ds3103_priv *priv = fe->demodulator_priv;
+       int ret, len, remaining;
+       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 */
+       priv->warm = false;
+
+       /* wake up device from sleep */
+       ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x01, 0x01);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x00, 0x01);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x00, 0x10);
+       if (ret)
+               goto err;
+
+       /* reset */
+       ret = m88ds3103_wr_reg(priv, 0x07, 0x60);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0x07, 0x00);
+       if (ret)
+               goto err;
+
+       /* firmware status */
+       ret = m88ds3103_rd_reg(priv, 0xb9, &u8tmp);
+       if (ret)
+               goto err;
+
+       dev_dbg(&priv->i2c->dev, "%s: firmware=%02x\n", __func__, u8tmp);
+
+       if (u8tmp)
+               goto skip_fw_download;
+
+       /* cold state - try to download firmware */
+       dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state\n",
+                       KBUILD_MODNAME, m88ds3103_ops.info.name);
+
+       /* request the firmware, this will block and timeout */
+       ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
+       if (ret) {
+               dev_err(&priv->i2c->dev, "%s: firmare file '%s' not found\n",
+                               KBUILD_MODNAME, fw_file);
+               goto err;
+       }
+
+       dev_info(&priv->i2c->dev, "%s: downloading firmware from file '%s'\n",
+                       KBUILD_MODNAME, fw_file);
+
+       ret = m88ds3103_wr_reg(priv, 0xb2, 0x01);
+       if (ret)
+               goto err;
+
+       for (remaining = fw->size; remaining > 0;
+                       remaining -= (priv->cfg->i2c_wr_max - 1)) {
+               len = remaining;
+               if (len > (priv->cfg->i2c_wr_max - 1))
+                       len = (priv->cfg->i2c_wr_max - 1);
+
+               ret = m88ds3103_wr_regs(priv, 0xb0,
+                               &fw->data[fw->size - remaining], len);
+               if (ret) {
+                       dev_err(&priv->i2c->dev,
+                                       "%s: firmware download failed=%d\n",
+                                       KBUILD_MODNAME, ret);
+                       goto err;
+               }
+       }
+
+       ret = m88ds3103_wr_reg(priv, 0xb2, 0x00);
+       if (ret)
+               goto err;
+
+       release_firmware(fw);
+       fw = NULL;
+
+       ret = m88ds3103_rd_reg(priv, 0xb9, &u8tmp);
+       if (ret)
+               goto err;
+
+       if (!u8tmp) {
+               dev_info(&priv->i2c->dev, "%s: firmware did not run\n",
+                               KBUILD_MODNAME);
+               ret = -EFAULT;
+               goto err;
+       }
+
+       dev_info(&priv->i2c->dev, "%s: found a '%s' in warm state\n",
+                       KBUILD_MODNAME, m88ds3103_ops.info.name);
+       dev_info(&priv->i2c->dev, "%s: firmware version %X.%X\n",
+                       KBUILD_MODNAME, (u8tmp >> 4) & 0xf, (u8tmp >> 0 & 0xf));
+
+skip_fw_download:
+       /* warm state */
+       priv->warm = true;
+
+       return 0;
+err:
+       if (fw)
+               release_firmware(fw);
+
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+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;
+
+       /* TS Hi-Z */
+       ret = m88ds3103_wr_reg_mask(priv, 0x27, 0x00, 0x01);
+       if (ret)
+               goto err;
+
+       /* sleep */
+       ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x00, 0x01);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x01, 0x01);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x10, 0x10);
+       if (ret)
+               goto err;
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int m88ds3103_get_frontend(struct dvb_frontend *fe)
+{
+       struct m88ds3103_priv *priv = fe->demodulator_priv;
+       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)) {
+               ret = -EAGAIN;
+               goto err;
+       }
+
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               ret = m88ds3103_rd_reg(priv, 0xe0, &buf[0]);
+               if (ret)
+                       goto err;
+
+               ret = m88ds3103_rd_reg(priv, 0xe6, &buf[1]);
+               if (ret)
+                       goto err;
+
+               switch ((buf[0] >> 2) & 0x01) {
+               case 0:
+                       c->inversion = INVERSION_OFF;
+                       break;
+               case 1:
+                       c->inversion = INVERSION_ON;
+                       break;
+               default:
+                       dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n",
+                                       __func__);
+               }
+
+               switch ((buf[1] >> 5) & 0x07) {
+               case 0:
+                       c->fec_inner = FEC_7_8;
+                       break;
+               case 1:
+                       c->fec_inner = FEC_5_6;
+                       break;
+               case 2:
+                       c->fec_inner = FEC_3_4;
+                       break;
+               case 3:
+                       c->fec_inner = FEC_2_3;
+                       break;
+               case 4:
+                       c->fec_inner = FEC_1_2;
+                       break;
+               default:
+                       dev_dbg(&priv->i2c->dev, "%s: invalid fec_inner\n",
+                                       __func__);
+               }
+
+               c->modulation = QPSK;
+
+               break;
+       case SYS_DVBS2:
+               ret = m88ds3103_rd_reg(priv, 0x7e, &buf[0]);
+               if (ret)
+                       goto err;
+
+               ret = m88ds3103_rd_reg(priv, 0x89, &buf[1]);
+               if (ret)
+                       goto err;
+
+               ret = m88ds3103_rd_reg(priv, 0xf2, &buf[2]);
+               if (ret)
+                       goto err;
+
+               switch ((buf[0] >> 0) & 0x0f) {
+               case 2:
+                       c->fec_inner = FEC_2_5;
+                       break;
+               case 3:
+                       c->fec_inner = FEC_1_2;
+                       break;
+               case 4:
+                       c->fec_inner = FEC_3_5;
+                       break;
+               case 5:
+                       c->fec_inner = FEC_2_3;
+                       break;
+               case 6:
+                       c->fec_inner = FEC_3_4;
+                       break;
+               case 7:
+                       c->fec_inner = FEC_4_5;
+                       break;
+               case 8:
+                       c->fec_inner = FEC_5_6;
+                       break;
+               case 9:
+                       c->fec_inner = FEC_8_9;
+                       break;
+               case 10:
+                       c->fec_inner = FEC_9_10;
+                       break;
+               default:
+                       dev_dbg(&priv->i2c->dev, "%s: invalid fec_inner\n",
+                                       __func__);
+               }
+
+               switch ((buf[0] >> 5) & 0x01) {
+               case 0:
+                       c->pilot = PILOT_OFF;
+                       break;
+               case 1:
+                       c->pilot = PILOT_ON;
+                       break;
+               default:
+                       dev_dbg(&priv->i2c->dev, "%s: invalid pilot\n",
+                                       __func__);
+               }
+
+               switch ((buf[0] >> 6) & 0x07) {
+               case 0:
+                       c->modulation = QPSK;
+                       break;
+               case 1:
+                       c->modulation = PSK_8;
+                       break;
+               case 2:
+                       c->modulation = APSK_16;
+                       break;
+               case 3:
+                       c->modulation = APSK_32;
+                       break;
+               default:
+                       dev_dbg(&priv->i2c->dev, "%s: invalid modulation\n",
+                                       __func__);
+               }
+
+               switch ((buf[1] >> 7) & 0x01) {
+               case 0:
+                       c->inversion = INVERSION_OFF;
+                       break;
+               case 1:
+                       c->inversion = INVERSION_ON;
+                       break;
+               default:
+                       dev_dbg(&priv->i2c->dev, "%s: invalid inversion\n",
+                                       __func__);
+               }
+
+               switch ((buf[2] >> 0) & 0x03) {
+               case 0:
+                       c->rolloff = ROLLOFF_35;
+                       break;
+               case 1:
+                       c->rolloff = ROLLOFF_25;
+                       break;
+               case 2:
+                       c->rolloff = ROLLOFF_20;
+                       break;
+               default:
+                       dev_dbg(&priv->i2c->dev, "%s: invalid rolloff\n",
+                                       __func__);
+               }
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
+                               __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = m88ds3103_rd_regs(priv, 0x6d, buf, 2);
+       if (ret)
+               goto err;
+
+       c->symbol_rate = 1ull * ((buf[1] << 8) | (buf[0] << 0)) *
+                       M88DS3103_MCLK_KHZ * 1000 / 0x10000;
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int m88ds3103_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct m88ds3103_priv *priv = fe->demodulator_priv;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int ret, i, tmp;
+       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 */
+
+       /* more iterations for more accurate estimation */
+       #define M88DS3103_SNR_ITERATIONS 3
+
+       switch (c->delivery_system) {
+       case SYS_DVBS:
+               tmp = 0;
+
+               for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) {
+                       ret = m88ds3103_rd_reg(priv, 0xff, &buf[0]);
+                       if (ret)
+                               goto err;
+
+                       tmp += buf[0];
+               }
+
+               /* use of one register limits max value to 15 dB */
+               /* SNR(X) dB = 10 * ln(X) / ln(10) dB */
+               tmp = DIV_ROUND_CLOSEST(tmp, 8 * M88DS3103_SNR_ITERATIONS);
+               if (tmp)
+                       *snr = 100ul * intlog2(tmp) / intlog2(10);
+               else
+                       *snr = 0;
+               break;
+       case SYS_DVBS2:
+               noise_tot = 0;
+               signal_tot = 0;
+
+               for (i = 0; i < M88DS3103_SNR_ITERATIONS; i++) {
+                       ret = m88ds3103_rd_regs(priv, 0x8c, buf, 3);
+                       if (ret)
+                               goto err;
+
+                       noise = buf[1] << 6;    /* [13:6] */
+                       noise |= buf[0] & 0x3f; /*  [5:0] */
+                       noise >>= 2;
+                       signal = buf[2] * buf[2];
+                       signal >>= 1;
+
+                       noise_tot += noise;
+                       signal_tot += signal;
+               }
+
+               noise = noise_tot / M88DS3103_SNR_ITERATIONS;
+               signal = signal_tot / M88DS3103_SNR_ITERATIONS;
+
+               /* SNR(X) dB = 10 * log10(X) dB */
+               if (signal > noise) {
+                       tmp = signal / noise;
+                       *snr = 100ul * intlog10(tmp) / (1 << 24);
+               } else {
+                       *snr = 0;
+               }
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
+                               __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+
+static int m88ds3103_set_tone(struct dvb_frontend *fe,
+       fe_sec_tone_mode_t fe_sec_tone_mode)
+{
+       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);
+
+       if (!priv->warm) {
+               ret = -EAGAIN;
+               goto err;
+       }
+
+       switch (fe_sec_tone_mode) {
+       case SEC_TONE_ON:
+               tone = 0;
+               reg_a1_mask = 0x87;
+               break;
+       case SEC_TONE_OFF:
+               tone = 1;
+               reg_a1_mask = 0x00;
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_tone_mode\n",
+                               __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       u8tmp = tone << 7 | priv->cfg->envelope_mode << 5;
+       ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0xe0);
+       if (ret)
+               goto err;
+
+       u8tmp = 1 << 2;
+       ret = m88ds3103_wr_reg_mask(priv, 0xa1, u8tmp, reg_a1_mask);
+       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);
+
+       if (!priv->warm) {
+               ret = -EAGAIN;
+               goto err;
+       }
+
+       if (diseqc_cmd->msg_len < 3 || diseqc_cmd->msg_len > 6) {
+               ret = -EINVAL;
+               goto err;
+       }
+
+       u8tmp = priv->cfg->envelope_mode << 5;
+       ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0xe0);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_regs(priv, 0xa3, diseqc_cmd->msg,
+                       diseqc_cmd->msg_len);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg(priv, 0xa1,
+                       (diseqc_cmd->msg_len - 1) << 3 | 0x07);
+       if (ret)
+               goto err;
+
+       /* DiSEqC message typical period is 54 ms */
+       usleep_range(40000, 60000);
+
+       /* wait DiSEqC TX ready */
+       for (i = 20, u8tmp = 1; i && u8tmp; i--) {
+               usleep_range(5000, 10000);
+
+               ret = m88ds3103_rd_reg_mask(priv, 0xa1, &u8tmp, 0x40);
+               if (ret)
+                       goto err;
+       }
+
+       dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+
+       if (i == 0) {
+               dev_dbg(&priv->i2c->dev, "%s: diseqc tx timeout\n", __func__);
+
+               ret = m88ds3103_wr_reg_mask(priv, 0xa1, 0x40, 0xc0);
+               if (ret)
+                       goto err;
+       }
+
+       ret = m88ds3103_wr_reg_mask(priv, 0xa2, 0x80, 0xc0);
+       if (ret)
+               goto err;
+
+       if (i == 0) {
+               ret = -ETIMEDOUT;
+               goto err;
+       }
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int m88ds3103_diseqc_send_burst(struct dvb_frontend *fe,
+       fe_sec_mini_cmd_t fe_sec_mini_cmd)
+{
+       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);
+
+       if (!priv->warm) {
+               ret = -EAGAIN;
+               goto err;
+       }
+
+       u8tmp = priv->cfg->envelope_mode << 5;
+       ret = m88ds3103_wr_reg_mask(priv, 0xa2, u8tmp, 0xe0);
+       if (ret)
+               goto err;
+
+       switch (fe_sec_mini_cmd) {
+       case SEC_MINI_A:
+               burst = 0x02;
+               break;
+       case SEC_MINI_B:
+               burst = 0x01;
+               break;
+       default:
+               dev_dbg(&priv->i2c->dev, "%s: invalid fe_sec_mini_cmd\n",
+                               __func__);
+               ret = -EINVAL;
+               goto err;
+       }
+
+       ret = m88ds3103_wr_reg(priv, 0xa1, burst);
+       if (ret)
+               goto err;
+
+       /* DiSEqC ToneBurst period is 12.5 ms */
+       usleep_range(11000, 20000);
+
+       /* wait DiSEqC TX ready */
+       for (i = 5, u8tmp = 1; i && u8tmp; i--) {
+               usleep_range(800, 2000);
+
+               ret = m88ds3103_rd_reg_mask(priv, 0xa1, &u8tmp, 0x40);
+               if (ret)
+                       goto err;
+       }
+
+       dev_dbg(&priv->i2c->dev, "%s: loop=%d\n", __func__, i);
+
+       ret = m88ds3103_wr_reg_mask(priv, 0xa2, 0x80, 0xc0);
+       if (ret)
+               goto err;
+
+       if (i == 0) {
+               dev_dbg(&priv->i2c->dev, "%s: diseqc tx timeout\n", __func__);
+               ret = -ETIMEDOUT;
+               goto err;
+       }
+
+       return 0;
+err:
+       dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int m88ds3103_get_tune_settings(struct dvb_frontend *fe,
+       struct dvb_frontend_tune_settings *s)
+{
+       s->min_delay_ms = 3000;
+
+       return 0;
+}
+
+static void m88ds3103_release(struct dvb_frontend *fe)
+{
+       struct m88ds3103_priv *priv = fe->demodulator_priv;
+       i2c_del_mux_adapter(priv->i2c_adapter);
+       kfree(priv);
+}
+
+static int m88ds3103_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
+{
+       struct m88ds3103_priv *priv = mux_priv;
+       int ret;
+       struct i2c_msg gate_open_msg[1] = {
+               {
+                       .addr = priv->cfg->i2c_addr,
+                       .flags = 0,
+                       .len = 2,
+                       .buf = "\x03\x11",
+               }
+       };
+
+       mutex_lock(&priv->i2c_mutex);
+
+       /* open tuner I2C repeater for 1 xfer, closes automatically */
+       ret = __i2c_transfer(priv->i2c, gate_open_msg, 1);
+       if (ret != 1) {
+               dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d\n",
+                               KBUILD_MODNAME, ret);
+               if (ret >= 0)
+                       ret = -EREMOTEIO;
+
+               return ret;
+       }
+
+       return 0;
+}
+
+static int m88ds3103_deselect(struct i2c_adapter *adap, void *mux_priv,
+               u32 chan)
+{
+       struct m88ds3103_priv *priv = mux_priv;
+
+       mutex_unlock(&priv->i2c_mutex);
+
+       return 0;
+}
+
+struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg,
+               struct i2c_adapter *i2c, struct i2c_adapter **tuner_i2c_adapter)
+{
+       int ret;
+       struct m88ds3103_priv *priv;
+       u8 chip_id, u8tmp;
+
+       /* allocate memory for the internal priv */
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               ret = -ENOMEM;
+               dev_err(&i2c->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               goto err;
+       }
+
+       priv->cfg = cfg;
+       priv->i2c = i2c;
+       mutex_init(&priv->i2c_mutex);
+
+       ret = m88ds3103_rd_reg(priv, 0x01, &chip_id);
+       if (ret)
+               goto err;
+
+       dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id);
+
+       switch (chip_id) {
+       case 0xd0:
+               break;
+       default:
+               goto err;
+       }
+
+       switch (priv->cfg->clock_out) {
+       case M88DS3103_CLOCK_OUT_DISABLED:
+               u8tmp = 0x80;
+               break;
+       case M88DS3103_CLOCK_OUT_ENABLED:
+               u8tmp = 0x00;
+               break;
+       case M88DS3103_CLOCK_OUT_ENABLED_DIV2:
+               u8tmp = 0x10;
+               break;
+       default:
+               goto err;
+       }
+
+       ret = m88ds3103_wr_reg(priv, 0x29, u8tmp);
+       if (ret)
+               goto err;
+
+       /* sleep */
+       ret = m88ds3103_wr_reg_mask(priv, 0x08, 0x00, 0x01);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x04, 0x01, 0x01);
+       if (ret)
+               goto err;
+
+       ret = m88ds3103_wr_reg_mask(priv, 0x23, 0x10, 0x10);
+       if (ret)
+               goto err;
+
+       /* create mux i2c adapter for tuner */
+       priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0,
+                       m88ds3103_select, m88ds3103_deselect);
+       if (priv->i2c_adapter == NULL)
+               goto err;
+
+       *tuner_i2c_adapter = priv->i2c_adapter;
+
+       /* create dvb_frontend */
+       memcpy(&priv->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops));
+       priv->fe.demodulator_priv = priv;
+
+       return &priv->fe;
+err:
+       dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
+       kfree(priv);
+       return NULL;
+}
+EXPORT_SYMBOL(m88ds3103_attach);
+
+static struct dvb_frontend_ops m88ds3103_ops = {
+       .delsys = { SYS_DVBS, SYS_DVBS2 },
+       .info = {
+               .name = "Montage M88DS3103",
+               .frequency_min =  950000,
+               .frequency_max = 2150000,
+               .frequency_tolerance = 5000,
+               .symbol_rate_min =  1000000,
+               .symbol_rate_max = 45000000,
+               .caps = FE_CAN_INVERSION_AUTO |
+                       FE_CAN_FEC_1_2 |
+                       FE_CAN_FEC_2_3 |
+                       FE_CAN_FEC_3_4 |
+                       FE_CAN_FEC_4_5 |
+                       FE_CAN_FEC_5_6 |
+                       FE_CAN_FEC_6_7 |
+                       FE_CAN_FEC_7_8 |
+                       FE_CAN_FEC_8_9 |
+                       FE_CAN_FEC_AUTO |
+                       FE_CAN_QPSK |
+                       FE_CAN_RECOVER |
+                       FE_CAN_2G_MODULATION
+       },
+
+       .release = m88ds3103_release,
+
+       .get_tune_settings = m88ds3103_get_tune_settings,
+
+       .init = m88ds3103_init,
+       .sleep = m88ds3103_sleep,
+
+       .set_frontend = m88ds3103_set_frontend,
+       .get_frontend = m88ds3103_get_frontend,
+
+       .read_status = m88ds3103_read_status,
+       .read_snr = m88ds3103_read_snr,
+
+       .diseqc_send_master_cmd = m88ds3103_diseqc_send_master_cmd,
+       .diseqc_send_burst = m88ds3103_diseqc_send_burst,
+
+       .set_tone = m88ds3103_set_tone,
+};
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Montage M88DS3103 DVB-S/S2 demodulator driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(M88DS3103_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/m88ds3103.h b/drivers/media/dvb-frontends/m88ds3103.h
new file mode 100644 (file)
index 0000000..bbb7e3a
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Montage M88DS3103 demodulator driver
+ *
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef M88DS3103_H
+#define M88DS3103_H
+
+#include <linux/dvb/frontend.h>
+
+struct m88ds3103_config {
+       /*
+        * I2C address
+        * Default: none, must set
+        * 0x68, ...
+        */
+       u8 i2c_addr;
+
+       /*
+        * clock
+        * Default: none, must set
+        * 27000000
+        */
+       u32 clock;
+
+       /*
+        * max bytes I2C provider is asked to write at once
+        * Default: none, must set
+        * 33, 65, ...
+        */
+       u16 i2c_wr_max;
+
+       /*
+        * TS output mode
+        * Default: M88DS3103_TS_SERIAL
+        */
+#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 */
+       u8 ts_mode;
+
+       /*
+        * spectrum inversion
+        * Default: 0
+        */
+       u8 spec_inv:1;
+
+       /*
+        * AGC polarity
+        * Default: 0
+        */
+       u8 agc_inv:1;
+
+       /*
+        * clock output
+        * Default: M88DS3103_CLOCK_OUT_DISABLED
+        */
+#define M88DS3103_CLOCK_OUT_DISABLED        0
+#define M88DS3103_CLOCK_OUT_ENABLED         1
+#define M88DS3103_CLOCK_OUT_ENABLED_DIV2    2
+       u8 clock_out;
+
+       /*
+        * DiSEqC envelope mode
+        * Default: 0
+        */
+       u8 envelope_mode:1;
+
+       /*
+        * AGC configuration
+        * Default: none, must set
+        */
+       u8 agc;
+};
+
+/*
+ * Driver implements own I2C-adapter for tuner I2C access. That's since chip
+ * has I2C-gate control which closes gate automatically after I2C transfer.
+ * Using own I2C adapter we can workaround that.
+ */
+
+#if defined(CONFIG_DVB_M88DS3103) || \
+               (defined(CONFIG_DVB_M88DS3103_MODULE) && defined(MODULE))
+extern struct dvb_frontend *m88ds3103_attach(
+               const struct m88ds3103_config *config,
+               struct i2c_adapter *i2c,
+               struct i2c_adapter **tuner_i2c);
+#else
+static inline struct dvb_frontend *m88ds3103_attach(
+               const struct m88ds3103_config *config,
+               struct i2c_adapter *i2c,
+               struct i2c_adapter **tuner_i2c)
+{
+       pr_warn("%s: driver disabled by Kconfig\n", __func__);
+       return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h
new file mode 100644 (file)
index 0000000..84c3c06
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Montage M88DS3103 demodulator driver
+ *
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef M88DS3103_PRIV_H
+#define M88DS3103_PRIV_H
+
+#include "dvb_frontend.h"
+#include "m88ds3103.h"
+#include "dvb_math.h"
+#include <linux/firmware.h>
+#include <linux/i2c-mux.h>
+
+#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
+#define M88DS3103_MCLK_KHZ 96000
+
+struct m88ds3103_priv {
+       struct i2c_adapter *i2c;
+       /* mutex needed due to own tuner I2C adapter */
+       struct mutex i2c_mutex;
+       const struct m88ds3103_config *cfg;
+       struct dvb_frontend fe;
+       fe_delivery_system_t delivery_system;
+       fe_status_t fe_status;
+       bool warm; /* FW running */
+       struct i2c_adapter *i2c_adapter;
+};
+
+struct m88ds3103_reg_val {
+       u8 reg;
+       u8 val;
+};
+
+static const struct m88ds3103_reg_val m88ds3103_dvbs_init_reg_vals[] = {
+       {0x23, 0x07},
+       {0x08, 0x03},
+       {0x0c, 0x02},
+       {0x21, 0x54},
+       {0x25, 0x8a},
+       {0x27, 0x31},
+       {0x30, 0x08},
+       {0x31, 0x40},
+       {0x32, 0x32},
+       {0x35, 0xff},
+       {0x3a, 0x00},
+       {0x37, 0x10},
+       {0x38, 0x10},
+       {0x39, 0x02},
+       {0x42, 0x60},
+       {0x4a, 0x80},
+       {0x4b, 0x04},
+       {0x4d, 0x91},
+       {0x5d, 0xc8},
+       {0x50, 0x36},
+       {0x51, 0x36},
+       {0x52, 0x36},
+       {0x53, 0x36},
+       {0x56, 0x01},
+       {0x63, 0x0f},
+       {0x64, 0x30},
+       {0x65, 0x40},
+       {0x68, 0x26},
+       {0x69, 0x4c},
+       {0x70, 0x20},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0x40},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0x60},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0x80},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0xa0},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0x1f},
+       {0x76, 0x38},
+       {0x77, 0xa6},
+       {0x78, 0x0c},
+       {0x79, 0x80},
+       {0x7f, 0x14},
+       {0x7c, 0x00},
+       {0xae, 0x82},
+       {0x80, 0x64},
+       {0x81, 0x66},
+       {0x82, 0x44},
+       {0x85, 0x04},
+       {0xcd, 0xf4},
+       {0x90, 0x33},
+       {0xa0, 0x44},
+       {0xc0, 0x08},
+       {0xc3, 0x10},
+       {0xc4, 0x08},
+       {0xc5, 0xf0},
+       {0xc6, 0xff},
+       {0xc7, 0x00},
+       {0xc8, 0x1a},
+       {0xc9, 0x80},
+       {0xe0, 0xf8},
+       {0xe6, 0x8b},
+       {0xd0, 0x40},
+       {0xf8, 0x20},
+       {0xfa, 0x0f},
+       {0x00, 0x00},
+       {0xbd, 0x01},
+       {0xb8, 0x00},
+};
+
+static const struct m88ds3103_reg_val m88ds3103_dvbs2_init_reg_vals[] = {
+       {0x23, 0x07},
+       {0x08, 0x07},
+       {0x0c, 0x02},
+       {0x21, 0x54},
+       {0x25, 0x8a},
+       {0x27, 0x31},
+       {0x30, 0x08},
+       {0x32, 0x32},
+       {0x35, 0xff},
+       {0x3a, 0x00},
+       {0x37, 0x10},
+       {0x38, 0x10},
+       {0x39, 0x02},
+       {0x42, 0x60},
+       {0x4a, 0x80},
+       {0x4b, 0x04},
+       {0x4d, 0x91},
+       {0x5d, 0xc8},
+       {0x50, 0x36},
+       {0x51, 0x36},
+       {0x52, 0x36},
+       {0x53, 0x36},
+       {0x56, 0x01},
+       {0x63, 0x0f},
+       {0x64, 0x10},
+       {0x65, 0x20},
+       {0x68, 0x46},
+       {0x69, 0xcd},
+       {0x70, 0x20},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0x40},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0x60},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0x80},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0xa0},
+       {0x71, 0x70},
+       {0x72, 0x04},
+       {0x73, 0x00},
+       {0x70, 0x1f},
+       {0x76, 0x38},
+       {0x77, 0xa6},
+       {0x78, 0x0c},
+       {0x79, 0x80},
+       {0x7f, 0x14},
+       {0x85, 0x08},
+       {0xcd, 0xf4},
+       {0x90, 0x33},
+       {0x86, 0x00},
+       {0x87, 0x0f},
+       {0x89, 0x00},
+       {0x8b, 0x44},
+       {0x8c, 0x66},
+       {0x9d, 0xc1},
+       {0x8a, 0x10},
+       {0xad, 0x40},
+       {0xa0, 0x44},
+       {0xc0, 0x08},
+       {0xc1, 0x10},
+       {0xc2, 0x08},
+       {0xc3, 0x10},
+       {0xc4, 0x08},
+       {0xc5, 0xf0},
+       {0xc6, 0xff},
+       {0xc7, 0x00},
+       {0xc8, 0x1a},
+       {0xc9, 0x80},
+       {0xca, 0x23},
+       {0xcb, 0x24},
+       {0xcc, 0xf4},
+       {0xce, 0x74},
+       {0x00, 0x00},
+       {0xbd, 0x01},
+       {0xb8, 0x00},
+};
+
+#endif
index 4da5272075cb513036cef1c7ada3fd6cf5a0e545..b2351466b0dac0e73b7de1b6ad96698e1ed88c97 100644 (file)
@@ -110,28 +110,94 @@ static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 reg)
        return b1[0];
 }
 
+static u32 m88rs2000_get_mclk(struct dvb_frontend *fe)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       u32 mclk;
+       u8 reg;
+       /* Must not be 0x00 or 0xff */
+       reg = m88rs2000_readreg(state, 0x86);
+       if (!reg || reg == 0xff)
+               return 0;
+
+       reg /= 2;
+       reg += 1;
+
+       mclk = (u32)(reg * RS2000_FE_CRYSTAL_KHZ + 28 / 2) / 28;
+
+       return mclk;
+}
+
+static int m88rs2000_set_carrieroffset(struct dvb_frontend *fe, s16 offset)
+{
+       struct m88rs2000_state *state = fe->demodulator_priv;
+       u32 mclk;
+       s32 tmp;
+       u8 reg;
+       int ret;
+
+       mclk = m88rs2000_get_mclk(fe);
+       if (!mclk)
+               return -EINVAL;
+
+       tmp = (offset * 4096 + (s32)mclk / 2) / (s32)mclk;
+       if (tmp < 0)
+               tmp += 4096;
+
+       /* Carrier Offset */
+       ret = m88rs2000_writereg(state, 0x9c, (u8)(tmp >> 4));
+
+       reg = m88rs2000_readreg(state, 0x9d);
+       reg &= 0xf;
+       reg |= (u8)(tmp & 0xf) << 4;
+
+       ret |= m88rs2000_writereg(state, 0x9d, reg);
+
+       return ret;
+}
+
 static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate)
 {
        struct m88rs2000_state *state = fe->demodulator_priv;
        int ret;
-       u32 temp;
+       u64 temp;
+       u32 mclk;
        u8 b[3];
 
        if ((srate < 1000000) || (srate > 45000000))
                return -EINVAL;
 
+       mclk = m88rs2000_get_mclk(fe);
+       if (!mclk)
+               return -EINVAL;
+
        temp = srate / 1000;
-       temp *= 11831;
-       temp /= 68;
-       temp -= 3;
+       temp *= 1 << 24;
+
+       do_div(temp, mclk);
 
        b[0] = (u8) (temp >> 16) & 0xff;
        b[1] = (u8) (temp >> 8) & 0xff;
        b[2] = (u8) temp & 0xff;
+
        ret = m88rs2000_writereg(state, 0x93, b[2]);
        ret |= m88rs2000_writereg(state, 0x94, b[1]);
        ret |= m88rs2000_writereg(state, 0x95, b[0]);
 
+       if (srate > 10000000)
+               ret |= m88rs2000_writereg(state, 0xa0, 0x20);
+       else
+               ret |= m88rs2000_writereg(state, 0xa0, 0x60);
+
+       ret |= m88rs2000_writereg(state, 0xa1, 0xe0);
+
+       if (srate > 12000000)
+               ret |= m88rs2000_writereg(state, 0xa3, 0x20);
+       else if (srate > 2800000)
+               ret |= m88rs2000_writereg(state, 0xa3, 0x98);
+       else
+               ret |= m88rs2000_writereg(state, 0xa3, 0x90);
+
        deb_info("m88rs2000: m88rs2000_set_symbolrate\n");
        return ret;
 }
@@ -260,8 +326,6 @@ struct inittab m88rs2000_shutdown[] = {
 };
 
 struct inittab fe_reset[] = {
-       {DEMOD_WRITE, 0x00, 0x01},
-       {DEMOD_WRITE, 0xf1, 0xbf},
        {DEMOD_WRITE, 0x00, 0x01},
        {DEMOD_WRITE, 0x20, 0x81},
        {DEMOD_WRITE, 0x21, 0x80},
@@ -305,9 +369,6 @@ struct inittab fe_trigger[] = {
        {DEMOD_WRITE, 0x9b, 0x64},
        {DEMOD_WRITE, 0x9e, 0x00},
        {DEMOD_WRITE, 0x9f, 0xf8},
-       {DEMOD_WRITE, 0xa0, 0x20},
-       {DEMOD_WRITE, 0xa1, 0xe0},
-       {DEMOD_WRITE, 0xa3, 0x38},
        {DEMOD_WRITE, 0x98, 0xff},
        {DEMOD_WRITE, 0xc0, 0x0f},
        {DEMOD_WRITE, 0x89, 0x01},
@@ -408,7 +469,7 @@ static int m88rs2000_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
        *status = 0;
 
-       if ((reg & 0x7) == 0x7) {
+       if ((reg & 0xee) == 0xee) {
                *status = FE_HAS_CARRIER | FE_HAS_SIGNAL | FE_HAS_VITERBI
                        | FE_HAS_SYNC | FE_HAS_LOCK;
                if (state->config->set_ts_params)
@@ -480,33 +541,38 @@ static int m88rs2000_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 static int m88rs2000_set_fec(struct m88rs2000_state *state,
                fe_code_rate_t fec)
 {
-       u16 fec_set;
+       u8 fec_set, reg;
+       int ret;
+
        switch (fec) {
-       /* This is not confirmed kept for reference */
-/*     case FEC_1_2:
-               fec_set = 0x88;
+       case FEC_1_2:
+               fec_set = 0x8;
                break;
        case FEC_2_3:
-               fec_set = 0x68;
+               fec_set = 0x10;
                break;
        case FEC_3_4:
-               fec_set = 0x48;
+               fec_set = 0x20;
                break;
        case FEC_5_6:
-               fec_set = 0x28;
+               fec_set = 0x40;
                break;
        case FEC_7_8:
-               fec_set = 0x18;
-               break; */
+               fec_set = 0x80;
+               break;
        case FEC_AUTO:
        default:
-               fec_set = 0x08;
+               fec_set = 0x0;
        }
-       m88rs2000_writereg(state, 0x76, fec_set);
 
-       return 0;
-}
+       reg = m88rs2000_readreg(state, 0x70);
+       reg &= 0x7;
+       ret = m88rs2000_writereg(state, 0x70, reg | fec_set);
 
+       ret |= m88rs2000_writereg(state, 0x76, 0x8);
+
+       return ret;
+}
 
 static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
 {
@@ -515,18 +581,20 @@ static fe_code_rate_t m88rs2000_get_fec(struct m88rs2000_state *state)
        reg = m88rs2000_readreg(state, 0x76);
        m88rs2000_writereg(state, 0x9a, 0xb0);
 
+       reg &= 0xf0;
+       reg >>= 5;
+
        switch (reg) {
-       case 0x88:
+       case 0x4:
                return FEC_1_2;
-       case 0x68:
+       case 0x3:
                return FEC_2_3;
-       case 0x48:
+       case 0x2:
                return FEC_3_4;
-       case 0x28:
+       case 0x1:
                return FEC_5_6;
-       case 0x18:
+       case 0x0:
                return FEC_7_8;
-       case 0x08:
        default:
                break;
        }
@@ -540,9 +608,8 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
        struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        fe_status_t status;
        int i, ret = 0;
-       s32 tmp;
        u32 tuner_freq;
-       u16 offset = 0;
+       s16 offset = 0;
        u8 reg;
 
        state->no_lock_count = 0;
@@ -567,38 +634,31 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
        if (ret < 0)
                return -ENODEV;
 
-       offset = tuner_freq - c->frequency;
-
-       /* calculate offset assuming 96000kHz*/
-       tmp = offset;
-       tmp *= 65536;
-
-       tmp = (2 * tmp + 96000) / (2 * 96000);
-       if (tmp < 0)
-               tmp += 65536;
+       offset = (s16)((s32)tuner_freq - c->frequency);
 
-       offset = tmp & 0xffff;
+       /* default mclk value 96.4285 * 2 * 1000 = 192857 */
+       if (((c->frequency % 192857) >= (192857 - 3000)) ||
+                               (c->frequency % 192857) <= 3000)
+               ret = m88rs2000_writereg(state, 0x86, 0xc2);
+       else
+               ret = m88rs2000_writereg(state, 0x86, 0xc6);
 
-       ret = m88rs2000_writereg(state, 0x9a, 0x30);
-       /* Unknown usually 0xc6 sometimes 0xc1 */
-       reg = m88rs2000_readreg(state, 0x86);
-       ret |= m88rs2000_writereg(state, 0x86, reg);
-       /* Offset lower nibble always 0 */
-       ret |= m88rs2000_writereg(state, 0x9c, (offset >> 8));
-       ret |= m88rs2000_writereg(state, 0x9d, offset & 0xf0);
+       ret |= m88rs2000_set_carrieroffset(fe, offset);
+       if (ret < 0)
+               return -ENODEV;
 
+       /* Reset demod by symbol rate */
+       if (c->symbol_rate > 27500000)
+               ret = m88rs2000_writereg(state, 0xf1, 0xa4);
+       else
+               ret = m88rs2000_writereg(state, 0xf1, 0xbf);
 
-       /* Reset Demod */
-       ret = m88rs2000_tab_set(state, fe_reset);
+       ret |= m88rs2000_tab_set(state, fe_reset);
        if (ret < 0)
                return -ENODEV;
 
-       /* Unknown */
-       reg = m88rs2000_readreg(state, 0x70);
-       ret = m88rs2000_writereg(state, 0x70, reg);
-
        /* Set FEC */
-       ret |= m88rs2000_set_fec(state, c->fec_inner);
+       ret = m88rs2000_set_fec(state, c->fec_inner);
        ret |= m88rs2000_writereg(state, 0x85, 0x1);
        ret |= m88rs2000_writereg(state, 0x8a, 0xbf);
        ret |= m88rs2000_writereg(state, 0x8d, 0x1e);
@@ -620,7 +680,7 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe)
 
        for (i = 0; i < 25; i++) {
                reg = m88rs2000_readreg(state, 0x8c);
-               if ((reg & 0x7) == 0x7) {
+               if ((reg & 0xee) == 0xee) {
                        status = FE_HAS_LOCK;
                        break;
                }
index 14ce31e76ae69c11ddf9e6de0050d96624cdca48..0a50ea90736bfa62c22d07fc386a6e0c9270b82e 100644 (file)
@@ -53,6 +53,8 @@ static inline struct dvb_frontend *m88rs2000_attach(
 }
 #endif /* CONFIG_DVB_M88RS2000 */
 
+#define RS2000_FE_CRYSTAL_KHZ 27000
+
 enum {
        DEMOD_WRITE = 0x1,
        WRITE_DELAY = 0x10,
index fbca9856313a8b8a0cfb9fe34705c1f350e31a3e..4bf057544607e0762b13332e5da122561fcf4d36 100644 (file)
@@ -40,7 +40,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 /* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE  64
+#define MAX_XFER_SIZE  256
 
 #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw"
 #define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw"
index 842654d333177ad197326b8655b80b54bbdeae23..4aa9c5311cc506c6cca0a61c83b48402ae5fe684 100644 (file)
@@ -555,14 +555,6 @@ config VIDEO_MT9V032
          This is a Video4Linux2 sensor-level driver for the Micron
          MT9V032 752x480 CMOS sensor.
 
-config VIDEO_TCM825X
-       tristate "TCM825x camera sensor support"
-       depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_INT_DEVICE
-       depends on MEDIA_CAMERA_SUPPORT
-       ---help---
-         This is a driver for the Toshiba TCM825x VGA camera sensor.
-         It is used for example in Nokia N800.
-
 config VIDEO_SR030PC30
        tristate "Siliconfile SR030PC30 sensor support"
        depends on I2C && VIDEO_V4L2
@@ -594,6 +586,13 @@ config VIDEO_S5K4ECGX
           This is a V4L2 sensor-level driver for Samsung S5K4ECGX 5M
           camera sensor with an embedded SoC image signal processor.
 
+config VIDEO_S5K5BAF
+       tristate "Samsung S5K5BAF sensor support"
+       depends on I2C && VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+       ---help---
+         This is a V4L2 sensor-level driver for Samsung S5K5BAF 2M
+         camera sensor with an embedded SoC image signal processor.
+
 source "drivers/media/i2c/smiapp/Kconfig"
 
 config VIDEO_S5C73M3
@@ -655,6 +654,18 @@ config VIDEO_UPD64083
          To compile this driver as a module, choose M here: the
          module will be called upd64083.
 
+comment "Audio/Video compression chips"
+
+config VIDEO_SAA6752HS
+       tristate "Philips SAA6752HS MPEG-2 Audio/Video Encoder"
+       depends on VIDEO_V4L2 && I2C
+       ---help---
+         Support for the Philips SAA6752HS MPEG-2 video and MPEG-audio/AC-3
+         audio encoder with multiplexer.
+
+         To compile this driver as a module, choose M here: the
+         module will be called saa6752hs.
+
 comment "Miscellaneous helper chips"
 
 config VIDEO_THS7303
index e03f1776f4f4f416c2bd5a1d0ff63f503e976837..48888ae876fb36f2b83080619f2605f9ae62563d 100644 (file)
@@ -19,6 +19,7 @@ obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
 obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
 obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
 obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
+obj-$(CONFIG_VIDEO_SAA6752HS) += saa6752hs.o
 obj-$(CONFIG_VIDEO_ADV7170) += adv7170.o
 obj-$(CONFIG_VIDEO_ADV7175) += adv7175.o
 obj-$(CONFIG_VIDEO_ADV7180) += adv7180.o
@@ -57,7 +58,6 @@ obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
 obj-$(CONFIG_VIDEO_OV7640) += ov7640.o
 obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
 obj-$(CONFIG_VIDEO_OV9650) += ov9650.o
-obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 obj-$(CONFIG_VIDEO_MT9M032) += mt9m032.o
 obj-$(CONFIG_VIDEO_MT9P031) += mt9p031.o
 obj-$(CONFIG_VIDEO_MT9T001) += mt9t001.o
@@ -67,6 +67,7 @@ obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
 obj-$(CONFIG_VIDEO_NOON010PC30)        += noon010pc30.o
 obj-$(CONFIG_VIDEO_S5K6AA)     += s5k6aa.o
 obj-$(CONFIG_VIDEO_S5K4ECGX)   += s5k4ecgx.o
+obj-$(CONFIG_VIDEO_S5K5BAF)    += s5k5baf.o
 obj-$(CONFIG_VIDEO_S5C73M3)    += s5c73m3/
 obj-$(CONFIG_VIDEO_ADP1653)    += adp1653.o
 obj-$(CONFIG_VIDEO_AS3645A)    += as3645a.o
index b06a7e54ee0d25100f1f01abcac7ddc70e8489df..83225d6a0dd96069f62976ae5255deeee4374005 100644 (file)
@@ -66,11 +66,6 @@ MODULE_LICENSE("GPL");
 **********************************************************************
 */
 
-struct i2c_reg_value {
-       u8 reg;
-       u8 value;
-};
-
 struct ad9389b_state_edid {
        /* total number of blocks */
        u32 blocks;
@@ -143,14 +138,14 @@ static int ad9389b_wr(struct v4l2_subdev *sd, u8 reg, u8 val)
                if (ret == 0)
                        return 0;
        }
-       v4l2_err(sd, "I2C Write Problem\n");
+       v4l2_err(sd, "%s: failed reg 0x%x, val 0x%x\n", __func__, reg, val);
        return ret;
 }
 
 /* To set specific bits in the register, a clear-mask is given (to be AND-ed),
    and then the value-mask (to be OR-ed). */
 static inline void ad9389b_wr_and_or(struct v4l2_subdev *sd, u8 reg,
-                                               u8 clr_mask, u8 val_mask)
+                                    u8 clr_mask, u8 val_mask)
 {
        ad9389b_wr(sd, reg, (ad9389b_rd(sd, reg) & clr_mask) | val_mask);
 }
@@ -321,12 +316,12 @@ static int ad9389b_s_ctrl(struct v4l2_ctrl *ctrl)
        struct ad9389b_state *state = get_ad9389b_state(sd);
 
        v4l2_dbg(1, debug, sd,
-               "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val);
+                "%s: ctrl id: %d, ctrl->val %d\n", __func__, ctrl->id, ctrl->val);
 
        if (state->hdmi_mode_ctrl == ctrl) {
                /* Set HDMI or DVI-D */
                ad9389b_wr_and_or(sd, 0xaf, 0xfd,
-                               ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
+                                 ctrl->val == V4L2_DV_TX_MODE_HDMI ? 0x02 : 0x00);
                return 0;
        }
        if (state->rgb_quantization_range_ctrl == ctrl)
@@ -387,61 +382,57 @@ static int ad9389b_log_status(struct v4l2_subdev *sd)
        v4l2_info(sd, "chip revision %d\n", state->chip_revision);
        v4l2_info(sd, "power %s\n", state->power_on ? "on" : "off");
        v4l2_info(sd, "%s hotplug, %s Rx Sense, %s EDID (%d block(s))\n",
-                       (ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ?
-                                                       "detected" : "no",
-                       (ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ?
-                                                       "detected" : "no",
-                       edid->segments ? "found" : "no", edid->blocks);
-       if (state->have_monitor) {
-               v4l2_info(sd, "%s output %s\n",
-                                 (ad9389b_rd(sd, 0xaf) & 0x02) ?
-                                 "HDMI" : "DVI-D",
-                                 (ad9389b_rd(sd, 0xa1) & 0x3c) ?
-                                 "disabled" : "enabled");
-       }
+                 (ad9389b_rd(sd, 0x42) & MASK_AD9389B_HPD_DETECT) ?
+                 "detected" : "no",
+                 (ad9389b_rd(sd, 0x42) & MASK_AD9389B_MSEN_DETECT) ?
+                 "detected" : "no",
+                 edid->segments ? "found" : "no", edid->blocks);
+       v4l2_info(sd, "%s output %s\n",
+                 (ad9389b_rd(sd, 0xaf) & 0x02) ?
+                 "HDMI" : "DVI-D",
+                 (ad9389b_rd(sd, 0xa1) & 0x3c) ?
+                 "disabled" : "enabled");
        v4l2_info(sd, "ad9389b: %s\n", (ad9389b_rd(sd, 0xb8) & 0x40) ?
-                                       "encrypted" : "no encryption");
+                 "encrypted" : "no encryption");
        v4l2_info(sd, "state: %s, error: %s, detect count: %u, msk/irq: %02x/%02x\n",
-                       states[ad9389b_rd(sd, 0xc8) & 0xf],
-                       errors[ad9389b_rd(sd, 0xc8) >> 4],
-                       state->edid_detect_counter,
-                       ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96));
+                 states[ad9389b_rd(sd, 0xc8) & 0xf],
+                 errors[ad9389b_rd(sd, 0xc8) >> 4],
+                 state->edid_detect_counter,
+                 ad9389b_rd(sd, 0x94), ad9389b_rd(sd, 0x96));
        manual_gear = ad9389b_rd(sd, 0x98) & 0x80;
        v4l2_info(sd, "ad9389b: RGB quantization: %s range\n",
-                       ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full");
+                 ad9389b_rd(sd, 0x3b) & 0x01 ? "limited" : "full");
        v4l2_info(sd, "ad9389b: %s gear %d\n",
                  manual_gear ? "manual" : "automatic",
                  manual_gear ? ((ad9389b_rd(sd, 0x98) & 0x70) >> 4) :
-                               ((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1));
-       if (state->have_monitor) {
-               if (ad9389b_rd(sd, 0xaf) & 0x02) {
-                       /* HDMI only */
-                       u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80;
-                       u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
-                                ad9389b_rd(sd, 0x02) << 8 |
-                                ad9389b_rd(sd, 0x03);
-                       u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2;
-                       u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f;
-                       u32 CTS;
-
-                       if (manual_cts)
-                               CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 |
-                                      ad9389b_rd(sd, 0x08) << 8 |
-                                      ad9389b_rd(sd, 0x09);
-                       else
-                               CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 |
-                                      ad9389b_rd(sd, 0x05) << 8 |
-                                      ad9389b_rd(sd, 0x06);
-                       N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
-                            ad9389b_rd(sd, 0x02) << 8 |
-                            ad9389b_rd(sd, 0x03);
-
-                       v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n",
-                               manual_cts ? "manual" : "automatic", N, CTS);
-
-                       v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n",
-                               vic_detect, vic_sent);
-               }
+                 ((ad9389b_rd(sd, 0x9e) & 0x0e) >> 1));
+       if (ad9389b_rd(sd, 0xaf) & 0x02) {
+               /* HDMI only */
+               u8 manual_cts = ad9389b_rd(sd, 0x0a) & 0x80;
+               u32 N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
+                       ad9389b_rd(sd, 0x02) << 8 |
+                       ad9389b_rd(sd, 0x03);
+               u8 vic_detect = ad9389b_rd(sd, 0x3e) >> 2;
+               u8 vic_sent = ad9389b_rd(sd, 0x3d) & 0x3f;
+               u32 CTS;
+
+               if (manual_cts)
+                       CTS = (ad9389b_rd(sd, 0x07) & 0xf) << 16 |
+                             ad9389b_rd(sd, 0x08) << 8 |
+                             ad9389b_rd(sd, 0x09);
+               else
+                       CTS = (ad9389b_rd(sd, 0x04) & 0xf) << 16 |
+                             ad9389b_rd(sd, 0x05) << 8 |
+                             ad9389b_rd(sd, 0x06);
+               N = (ad9389b_rd(sd, 0x01) & 0xf) << 16 |
+                   ad9389b_rd(sd, 0x02) << 8 |
+                   ad9389b_rd(sd, 0x03);
+
+               v4l2_info(sd, "ad9389b: CTS %s mode: N %d, CTS %d\n",
+                         manual_cts ? "manual" : "automatic", N, CTS);
+
+               v4l2_info(sd, "ad9389b: VIC: detected %d, sent %d\n",
+                         vic_detect, vic_sent);
        }
        if (state->dv_timings.type == V4L2_DV_BT_656_1120)
                v4l2_print_dv_timings(sd->name, "timings: ",
@@ -486,7 +477,7 @@ static int ad9389b_s_power(struct v4l2_subdev *sd, int on)
        }
        if (i > 1)
                v4l2_dbg(1, debug, sd,
-                       "needed %d retries to powerup the ad9389b\n", i);
+                        "needed %d retries to powerup the ad9389b\n", i);
 
        /* Select chip: AD9389B */
        ad9389b_wr_and_or(sd, 0xba, 0xef, 0x10);
@@ -556,14 +547,16 @@ static int ad9389b_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
        irq_status = ad9389b_rd(sd, 0x96);
        /* clear detected interrupts */
        ad9389b_wr(sd, 0x96, irq_status);
+       /* enable interrupts */
+       ad9389b_set_isr(sd, true);
+
+       v4l2_dbg(1, debug, sd, "%s: irq_status 0x%x\n", __func__, irq_status);
 
-       if (irq_status & (MASK_AD9389B_HPD_INT | MASK_AD9389B_MSEN_INT))
+       if (irq_status & (MASK_AD9389B_HPD_INT))
                ad9389b_check_monitor_present_status(sd);
        if (irq_status & MASK_AD9389B_EDID_RDY_INT)
                ad9389b_check_edid_status(sd);
 
-       /* enable interrupts */
-       ad9389b_set_isr(sd, true);
        *handled = true;
        return 0;
 }
@@ -599,7 +592,7 @@ static int ad9389b_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edi
        if (edid->blocks + edid->start_block >= state->edid.segments * 2)
                edid->blocks = state->edid.segments * 2 - edid->start_block;
        memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
-                               128 * edid->blocks);
+              128 * edid->blocks);
        return 0;
 }
 
@@ -612,8 +605,6 @@ static const struct v4l2_subdev_pad_ops ad9389b_pad_ops = {
 /* Enable/disable ad9389b output */
 static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
 {
-       struct ad9389b_state *state = get_ad9389b_state(sd);
-
        v4l2_dbg(1, debug, sd, "%s: %sable\n", __func__, (enable ? "en" : "dis"));
 
        ad9389b_wr_and_or(sd, 0xa1, ~0x3c, (enable ? 0 : 0x3c));
@@ -621,7 +612,6 @@ static int ad9389b_s_stream(struct v4l2_subdev *sd, int enable)
                ad9389b_check_monitor_present_status(sd);
        } else {
                ad9389b_s_power(sd, 0);
-               state->have_monitor = false;
        }
        return 0;
 }
@@ -686,14 +676,14 @@ static int ad9389b_g_dv_timings(struct v4l2_subdev *sd,
 }
 
 static int ad9389b_enum_dv_timings(struct v4l2_subdev *sd,
-                       struct v4l2_enum_dv_timings *timings)
+                                  struct v4l2_enum_dv_timings *timings)
 {
        return v4l2_enum_dv_timings_cap(timings, &ad9389b_timings_cap,
                        NULL, NULL);
 }
 
 static int ad9389b_dv_timings_cap(struct v4l2_subdev *sd,
-                       struct v4l2_dv_timings_cap *cap)
+                                 struct v4l2_dv_timings_cap *cap)
 {
        *cap = ad9389b_timings_cap;
        return 0;
@@ -724,15 +714,15 @@ static int ad9389b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
        u32 N;
 
        switch (freq) {
-       case 32000: N = 4096; break;
-       case 44100: N = 6272; break;
-       case 48000: N = 6144; break;
-       case 88200: N = 12544; break;
-       case 96000: N = 12288; break;
+       case 32000:  N = 4096;  break;
+       case 44100:  N = 6272;  break;
+       case 48000:  N = 6144;  break;
+       case 88200:  N = 12544; break;
+       case 96000:  N = 12288; break;
        case 176400: N = 25088; break;
        case 192000: N = 24576; break;
        default:
-               return -EINVAL;
+            return -EINVAL;
        }
 
        /* Set N (used with CTS to regenerate the audio clock) */
@@ -748,15 +738,15 @@ static int ad9389b_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
        u32 i2s_sf;
 
        switch (freq) {
-       case 32000: i2s_sf = 0x30; break;
-       case 44100: i2s_sf = 0x00; break;
-       case 48000: i2s_sf = 0x20; break;
-       case 88200: i2s_sf = 0x80; break;
-       case 96000: i2s_sf = 0xa0; break;
+       case 32000:  i2s_sf = 0x30; break;
+       case 44100:  i2s_sf = 0x00; break;
+       case 48000:  i2s_sf = 0x20; break;
+       case 88200:  i2s_sf = 0x80; break;
+       case 96000:  i2s_sf = 0xa0; break;
        case 176400: i2s_sf = 0xc0; break;
        case 192000: i2s_sf = 0xe0; break;
        default:
-               return -EINVAL;
+            return -EINVAL;
        }
 
        /* Set sampling frequency for I2S audio to 48 kHz */
@@ -800,7 +790,7 @@ static const struct v4l2_subdev_ops ad9389b_ops = {
 
 /* ----------------------------------------------------------------------- */
 static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd,
-                                                       int segment, u8 *buf)
+                                 int segment, u8 *buf)
 {
        int i, j;
 
@@ -826,8 +816,8 @@ static void ad9389b_dbg_dump_edid(int lvl, int debug, struct v4l2_subdev *sd,
 static void ad9389b_edid_handler(struct work_struct *work)
 {
        struct delayed_work *dwork = to_delayed_work(work);
-       struct ad9389b_state *state = container_of(dwork,
-                       struct ad9389b_state, edid_handler);
+       struct ad9389b_state *state =
+               container_of(dwork, struct ad9389b_state, edid_handler);
        struct v4l2_subdev *sd = &state->sd;
        struct ad9389b_edid_detect ed;
 
@@ -845,11 +835,10 @@ static void ad9389b_edid_handler(struct work_struct *work)
                if (state->edid.read_retries) {
                        state->edid.read_retries--;
                        v4l2_dbg(1, debug, sd, "%s: edid read failed\n", __func__);
-                       state->have_monitor = false;
                        ad9389b_s_power(sd, false);
                        ad9389b_s_power(sd, true);
                        queue_delayed_work(state->work_queue,
-                                       &state->edid_handler, EDID_DELAY);
+                                          &state->edid_handler, EDID_DELAY);
                        return;
                }
        }
@@ -915,49 +904,35 @@ static void ad9389b_notify_monitor_detect(struct v4l2_subdev *sd)
        v4l2_subdev_notify(sd, AD9389B_MONITOR_DETECT, (void *)&mdt);
 }
 
-static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
+static void ad9389b_update_monitor_present_status(struct v4l2_subdev *sd)
 {
        struct ad9389b_state *state = get_ad9389b_state(sd);
        /* read hotplug and rx-sense state */
        u8 status = ad9389b_rd(sd, 0x42);
 
        v4l2_dbg(1, debug, sd, "%s: status: 0x%x%s%s\n",
-                        __func__,
-                        status,
-                        status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "",
-                        status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : "");
+                __func__,
+                status,
+                status & MASK_AD9389B_HPD_DETECT ? ", hotplug" : "",
+                status & MASK_AD9389B_MSEN_DETECT ? ", rx-sense" : "");
 
-       if ((status & MASK_AD9389B_HPD_DETECT) &&
-           ((status & MASK_AD9389B_MSEN_DETECT) || state->edid.segments)) {
-               v4l2_dbg(1, debug, sd,
-                               "%s: hotplug and (rx-sense or edid)\n", __func__);
-               if (!state->have_monitor) {
-                       v4l2_dbg(1, debug, sd, "%s: monitor detected\n", __func__);
-                       state->have_monitor = true;
-                       ad9389b_set_isr(sd, true);
-                       if (!ad9389b_s_power(sd, true)) {
-                               v4l2_dbg(1, debug, sd,
-                                       "%s: monitor detected, powerup failed\n", __func__);
-                               return;
-                       }
-                       ad9389b_setup(sd);
-                       ad9389b_notify_monitor_detect(sd);
-                       state->edid.read_retries = EDID_MAX_RETRIES;
-                       queue_delayed_work(state->work_queue,
-                                       &state->edid_handler, EDID_DELAY);
-               }
-       } else if (status & MASK_AD9389B_HPD_DETECT) {
+       if (status & MASK_AD9389B_HPD_DETECT) {
                v4l2_dbg(1, debug, sd, "%s: hotplug detected\n", __func__);
+               state->have_monitor = true;
+               if (!ad9389b_s_power(sd, true)) {
+                       v4l2_dbg(1, debug, sd,
+                                "%s: monitor detected, powerup failed\n", __func__);
+                       return;
+               }
+               ad9389b_setup(sd);
+               ad9389b_notify_monitor_detect(sd);
                state->edid.read_retries = EDID_MAX_RETRIES;
                queue_delayed_work(state->work_queue,
-                               &state->edid_handler, EDID_DELAY);
+                                  &state->edid_handler, EDID_DELAY);
        } else if (!(status & MASK_AD9389B_HPD_DETECT)) {
                v4l2_dbg(1, debug, sd, "%s: hotplug not detected\n", __func__);
-               if (state->have_monitor) {
-                       v4l2_dbg(1, debug, sd, "%s: monitor not detected\n", __func__);
-                       state->have_monitor = false;
-                       ad9389b_notify_monitor_detect(sd);
-               }
+               state->have_monitor = false;
+               ad9389b_notify_monitor_detect(sd);
                ad9389b_s_power(sd, false);
                memset(&state->edid, 0, sizeof(struct ad9389b_state_edid));
        }
@@ -966,6 +941,35 @@ static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
        v4l2_ctrl_s_ctrl(state->hotplug_ctrl, ad9389b_have_hotplug(sd) ? 0x1 : 0x0);
        v4l2_ctrl_s_ctrl(state->rx_sense_ctrl, ad9389b_have_rx_sense(sd) ? 0x1 : 0x0);
        v4l2_ctrl_s_ctrl(state->have_edid0_ctrl, state->edid.segments ? 0x1 : 0x0);
+
+       /* update with setting from ctrls */
+       ad9389b_s_ctrl(state->rgb_quantization_range_ctrl);
+       ad9389b_s_ctrl(state->hdmi_mode_ctrl);
+}
+
+static void ad9389b_check_monitor_present_status(struct v4l2_subdev *sd)
+{
+       struct ad9389b_state *state = get_ad9389b_state(sd);
+       int retry = 0;
+
+       ad9389b_update_monitor_present_status(sd);
+
+       /*
+        * Rapid toggling of the hotplug may leave the chip powered off,
+        * even if we think it is on. In that case reset and power up again.
+        */
+       while (state->power_on && (ad9389b_rd(sd, 0x41) & 0x40)) {
+               if (++retry > 5) {
+                       v4l2_err(sd, "retried %d times, give up\n", retry);
+                       return;
+               }
+               v4l2_dbg(1, debug, sd, "%s: reset and re-check status (%d)\n", __func__, retry);
+               ad9389b_notify_monitor_detect(sd);
+               cancel_delayed_work_sync(&state->edid_handler);
+               memset(&state->edid, 0, sizeof(struct ad9389b_state_edid));
+               ad9389b_s_power(sd, false);
+               ad9389b_update_monitor_present_status(sd);
+       }
 }
 
 static bool edid_block_verify_crc(u8 *edid_block)
@@ -978,7 +982,7 @@ static bool edid_block_verify_crc(u8 *edid_block)
        return sum == 0;
 }
 
-static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment)
+static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment)
 {
        struct ad9389b_state *state = get_ad9389b_state(sd);
        u32 blocks = state->edid.blocks;
@@ -992,6 +996,25 @@ static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment)
        return false;
 }
 
+static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)
+{
+       static const u8 hdmi_header[] = {
+               0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
+       };
+       struct ad9389b_state *state = get_ad9389b_state(sd);
+       u8 *data = state->edid.data;
+       int i;
+
+       if (segment)
+               return true;
+
+       for (i = 0; i < ARRAY_SIZE(hdmi_header); i++)
+               if (data[i] != hdmi_header[i])
+                       return false;
+
+       return true;
+}
+
 static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
 {
        struct ad9389b_state *state = get_ad9389b_state(sd);
@@ -1000,7 +1023,7 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
        u8 edidRdy = ad9389b_rd(sd, 0xc5);
 
        v4l2_dbg(1, debug, sd, "%s: edid ready (retries: %d)\n",
-                        __func__, EDID_MAX_RETRIES - state->edid.read_retries);
+                __func__, EDID_MAX_RETRIES - state->edid.read_retries);
 
        if (!(edidRdy & MASK_AD9389B_EDID_RDY))
                return false;
@@ -1013,16 +1036,16 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
        v4l2_dbg(1, debug, sd, "%s: got segment %d\n", __func__, segment);
        ad9389b_edid_rd(sd, 256, &state->edid.data[segment * 256]);
        ad9389b_dbg_dump_edid(2, debug, sd, segment,
-                       &state->edid.data[segment * 256]);
+                             &state->edid.data[segment * 256]);
        if (segment == 0) {
                state->edid.blocks = state->edid.data[0x7e] + 1;
                v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n",
-                               __func__, state->edid.blocks);
+                        __func__, state->edid.blocks);
        }
-       if (!edid_segment_verify_crc(sd, segment)) {
+       if (!edid_verify_crc(sd, segment) ||
+           !edid_verify_header(sd, segment)) {
                /* edid crc error, force reread of edid segment */
-               v4l2_err(sd, "%s: edid crc error\n", __func__);
-               state->have_monitor = false;
+               v4l2_err(sd, "%s: edid crc or header error\n", __func__);
                ad9389b_s_power(sd, false);
                ad9389b_s_power(sd, true);
                return false;
@@ -1032,12 +1055,12 @@ static bool ad9389b_check_edid_status(struct v4l2_subdev *sd)
        if (((state->edid.data[0x7e] >> 1) + 1) > state->edid.segments) {
                /* Request next EDID segment */
                v4l2_dbg(1, debug, sd, "%s: request segment %d\n",
-                               __func__, state->edid.segments);
+                        __func__, state->edid.segments);
                ad9389b_wr(sd, 0xc9, 0xf);
                ad9389b_wr(sd, 0xc4, state->edid.segments);
                state->edid.read_retries = EDID_MAX_RETRIES;
                queue_delayed_work(state->work_queue,
-                               &state->edid_handler, EDID_DELAY);
+                                  &state->edid_handler, EDID_DELAY);
                return false;
        }
 
@@ -1081,7 +1104,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
                return -EIO;
 
        v4l_dbg(1, debug, client, "detecting ad9389b client on address 0x%x\n",
-                       client->addr << 1);
+               client->addr << 1);
 
        state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
        if (!state)
@@ -1140,7 +1163,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
                goto err_entity;
        }
        v4l2_dbg(1, debug, sd, "reg 0x41 0x%x, chip version (reg 0x00) 0x%x\n",
-                       ad9389b_rd(sd, 0x41), state->chip_revision);
+                ad9389b_rd(sd, 0x41), state->chip_revision);
 
        state->edid_i2c_client = i2c_new_dummy(client->adapter, (0x7e>>1));
        if (state->edid_i2c_client == NULL) {
@@ -1163,7 +1186,7 @@ static int ad9389b_probe(struct i2c_client *client, const struct i2c_device_id *
        ad9389b_set_isr(sd, true);
 
        v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
-                         client->addr << 1, client->adapter->name);
+                 client->addr << 1, client->adapter->name);
        return 0;
 
 err_unreg:
index 7c8d971f1f613206b1821bfa023ea5326ba48028..ee618942cb8eca1ec3ca2f6c50421e5b492075c7 100644 (file)
@@ -452,6 +452,29 @@ static int adv7511_log_status(struct v4l2_subdev *sd)
                          errors[adv7511_rd(sd, 0xc8) >> 4], state->edid_detect_counter,
                          adv7511_rd(sd, 0x94), adv7511_rd(sd, 0x96));
        v4l2_info(sd, "RGB quantization: %s range\n", adv7511_rd(sd, 0x18) & 0x80 ? "limited" : "full");
+       if (adv7511_rd(sd, 0xaf) & 0x02) {
+               /* HDMI only */
+               u8 manual_cts = adv7511_rd(sd, 0x0a) & 0x80;
+               u32 N = (adv7511_rd(sd, 0x01) & 0xf) << 16 |
+                       adv7511_rd(sd, 0x02) << 8 |
+                       adv7511_rd(sd, 0x03);
+               u8 vic_detect = adv7511_rd(sd, 0x3e) >> 2;
+               u8 vic_sent = adv7511_rd(sd, 0x3d) & 0x3f;
+               u32 CTS;
+
+               if (manual_cts)
+                       CTS = (adv7511_rd(sd, 0x07) & 0xf) << 16 |
+                             adv7511_rd(sd, 0x08) << 8 |
+                             adv7511_rd(sd, 0x09);
+               else
+                       CTS = (adv7511_rd(sd, 0x04) & 0xf) << 16 |
+                             adv7511_rd(sd, 0x05) << 8 |
+                             adv7511_rd(sd, 0x06);
+               v4l2_info(sd, "CTS %s mode: N %d, CTS %d\n",
+                         manual_cts ? "manual" : "automatic", N, CTS);
+               v4l2_info(sd, "VIC: detected %d, sent %d\n",
+                         vic_detect, vic_sent);
+       }
        if (state->dv_timings.type == V4L2_DV_BT_656_1120)
                v4l2_print_dv_timings(sd->name, "timings: ",
                                &state->dv_timings, false);
@@ -942,26 +965,38 @@ static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd)
 
 static bool edid_block_verify_crc(uint8_t *edid_block)
 {
-       int i;
        uint8_t sum = 0;
+       int i;
 
        for (i = 0; i < 128; i++)
-               sum += *(edid_block + i);
-       return (sum == 0);
+               sum += edid_block[i];
+       return sum == 0;
 }
 
-static bool edid_segment_verify_crc(struct v4l2_subdev *sd, u32 segment)
+static bool edid_verify_crc(struct v4l2_subdev *sd, u32 segment)
 {
        struct adv7511_state *state = get_adv7511_state(sd);
        u32 blocks = state->edid.blocks;
        uint8_t *data = state->edid.data;
 
-       if (edid_block_verify_crc(&data[segment * 256])) {
-               if ((segment + 1) * 2 <= blocks)
-                       return edid_block_verify_crc(&data[segment * 256 + 128]);
+       if (!edid_block_verify_crc(&data[segment * 256]))
+               return false;
+       if ((segment + 1) * 2 <= blocks)
+               return edid_block_verify_crc(&data[segment * 256 + 128]);
+       return true;
+}
+
+static bool edid_verify_header(struct v4l2_subdev *sd, u32 segment)
+{
+       static const u8 hdmi_header[] = {
+               0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00
+       };
+       struct adv7511_state *state = get_adv7511_state(sd);
+       u8 *data = state->edid.data;
+
+       if (segment != 0)
                return true;
-       }
-       return false;
+       return !memcmp(data, hdmi_header, sizeof(hdmi_header));
 }
 
 static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
@@ -990,9 +1025,10 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
                        state->edid.blocks = state->edid.data[0x7e] + 1;
                        v4l2_dbg(1, debug, sd, "%s: %d blocks in total\n", __func__, state->edid.blocks);
                }
-               if (!edid_segment_verify_crc(sd, segment)) {
+               if (!edid_verify_crc(sd, segment) ||
+                   !edid_verify_header(sd, segment)) {
                        /* edid crc error, force reread of edid segment */
-                       v4l2_dbg(1, debug, sd, "%s: edid crc error\n", __func__);
+                       v4l2_err(sd, "%s: edid crc or header error\n", __func__);
                        state->have_monitor = false;
                        adv7511_s_power(sd, false);
                        adv7511_s_power(sd, true);
@@ -1038,6 +1074,12 @@ static void adv7511_init_setup(struct v4l2_subdev *sd)
 
        /* clear all interrupts */
        adv7511_wr(sd, 0x96, 0xff);
+       /*
+        * Stop HPD from resetting a lot of registers.
+        * It might leave the chip in a partly un-initialized state,
+        * in particular with regards to hotplug bounces.
+        */
+       adv7511_wr_and_or(sd, 0xd6, 0x3f, 0xc0);
        memset(edid, 0, sizeof(struct adv7511_state_edid));
        state->have_monitor = false;
        adv7511_set_isr(sd, false);
index a324106b9f11e985c0637c16578cd3922ee6f58b..71c8570bd9eafd3dab56faf9b8fdf2453415e193 100644 (file)
@@ -53,8 +53,6 @@ MODULE_LICENSE("GPL");
 /* ADV7604 system clock frequency */
 #define ADV7604_fsc (28636360)
 
-#define DIGITAL_INPUT (state->mode == ADV7604_MODE_HDMI)
-
 /*
  **********************************************************************
  *
@@ -67,17 +65,19 @@ struct adv7604_state {
        struct v4l2_subdev sd;
        struct media_pad pad;
        struct v4l2_ctrl_handler hdl;
-       enum adv7604_mode mode;
+       enum adv7604_input_port selected_input;
        struct v4l2_dv_timings timings;
-       u8 edid[256];
-       unsigned edid_blocks;
+       struct {
+               u8 edid[256];
+               u32 present;
+               unsigned blocks;
+       } edid;
+       u16 spa_port_a[2];
        struct v4l2_fract aspect_ratio;
        u32 rgb_quantization_range;
        struct workqueue_struct *work_queues;
        struct delayed_work delayed_work_enable_hotplug;
-       bool connector_hdmi;
        bool restart_stdi_once;
-       u32 prev_input_status;
 
        /* i2c clients */
        struct i2c_client *i2c_avlink;
@@ -160,6 +160,7 @@ static const struct v4l2_dv_timings adv7604_timings[] = {
        V4L2_DV_BT_DMT_1792X1344P60,
        V4L2_DV_BT_DMT_1856X1392P60,
        V4L2_DV_BT_DMT_1920X1200P60_RB,
+       V4L2_DV_BT_DMT_1366X768P60_RB,
        V4L2_DV_BT_DMT_1366X768P60,
        V4L2_DV_BT_DMT_1920X1080P60,
        { },
@@ -507,57 +508,31 @@ static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val)
        return 0;
 }
 
-static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
-{
-       struct delayed_work *dwork = to_delayed_work(work);
-       struct adv7604_state *state = container_of(dwork, struct adv7604_state,
-                                               delayed_work_enable_hotplug);
-       struct v4l2_subdev *sd = &state->sd;
-
-       v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__);
-
-       v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)1);
-}
-
 static inline int edid_write_block(struct v4l2_subdev *sd,
                                        unsigned len, const u8 *val)
 {
-       struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct adv7604_state *state = to_state(sd);
        int err = 0;
        int i;
 
        v4l2_dbg(2, debug, sd, "%s: write EDID block (%d byte)\n", __func__, len);
 
-       v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)0);
-
-       /* Disables I2C access to internal EDID ram from DDC port */
-       rep_write_and_or(sd, 0x77, 0xf0, 0x0);
-
        for (i = 0; !err && i < len; i += I2C_SMBUS_BLOCK_MAX)
                err = adv_smbus_write_i2c_block_data(state->i2c_edid, i,
                                I2C_SMBUS_BLOCK_MAX, val + i);
-       if (err)
-               return err;
+       return err;
+}
 
-       /* adv7604 calculates the checksums and enables I2C access to internal
-          EDID ram from DDC port. */
-       rep_write_and_or(sd, 0x77, 0xf0, 0x1);
+static void adv7604_delayed_work_enable_hotplug(struct work_struct *work)
+{
+       struct delayed_work *dwork = to_delayed_work(work);
+       struct adv7604_state *state = container_of(dwork, struct adv7604_state,
+                                               delayed_work_enable_hotplug);
+       struct v4l2_subdev *sd = &state->sd;
 
-       for (i = 0; i < 1000; i++) {
-               if (rep_read(sd, 0x7d) & 1)
-                       break;
-               mdelay(1);
-       }
-       if (i == 1000) {
-               v4l_err(client, "error enabling edid\n");
-               return -EIO;
-       }
+       v4l2_dbg(2, debug, sd, "%s: enable hotplug\n", __func__);
 
-       /* enable hotplug after 100 ms */
-       queue_delayed_work(state->work_queues,
-                       &state->delayed_work_enable_hotplug, HZ / 10);
-       return 0;
+       v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present);
 }
 
 static inline int hdmi_read(struct v4l2_subdev *sd, u8 reg)
@@ -574,6 +549,11 @@ static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val)
        return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val);
 }
 
+static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
+{
+       return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val);
+}
+
 static inline int test_read(struct v4l2_subdev *sd, u8 reg)
 {
        struct adv7604_state *state = to_state(sd);
@@ -623,6 +603,26 @@ static inline int vdp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
 
 /* ----------------------------------------------------------------------- */
 
+static inline bool is_analog_input(struct v4l2_subdev *sd)
+{
+       struct adv7604_state *state = to_state(sd);
+
+       return state->selected_input == ADV7604_INPUT_VGA_RGB ||
+              state->selected_input == ADV7604_INPUT_VGA_COMP;
+}
+
+static inline bool is_digital_input(struct v4l2_subdev *sd)
+{
+       struct adv7604_state *state = to_state(sd);
+
+       return state->selected_input == ADV7604_INPUT_HDMI_PORT_A ||
+              state->selected_input == ADV7604_INPUT_HDMI_PORT_B ||
+              state->selected_input == ADV7604_INPUT_HDMI_PORT_C ||
+              state->selected_input == ADV7604_INPUT_HDMI_PORT_D;
+}
+
+/* ----------------------------------------------------------------------- */
+
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static void adv7604_inv_register(struct v4l2_subdev *sd)
 {
@@ -696,45 +696,47 @@ static int adv7604_g_register(struct v4l2_subdev *sd,
 static int adv7604_s_register(struct v4l2_subdev *sd,
                                        const struct v4l2_dbg_register *reg)
 {
+       u8 val = reg->val & 0xff;
+
        switch (reg->reg >> 8) {
        case 0:
-               io_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               io_write(sd, reg->reg & 0xff, val);
                break;
        case 1:
-               avlink_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               avlink_write(sd, reg->reg & 0xff, val);
                break;
        case 2:
-               cec_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               cec_write(sd, reg->reg & 0xff, val);
                break;
        case 3:
-               infoframe_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               infoframe_write(sd, reg->reg & 0xff, val);
                break;
        case 4:
-               esdp_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               esdp_write(sd, reg->reg & 0xff, val);
                break;
        case 5:
-               dpp_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               dpp_write(sd, reg->reg & 0xff, val);
                break;
        case 6:
-               afe_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               afe_write(sd, reg->reg & 0xff, val);
                break;
        case 7:
-               rep_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               rep_write(sd, reg->reg & 0xff, val);
                break;
        case 8:
-               edid_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               edid_write(sd, reg->reg & 0xff, val);
                break;
        case 9:
-               hdmi_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               hdmi_write(sd, reg->reg & 0xff, val);
                break;
        case 0xa:
-               test_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               test_write(sd, reg->reg & 0xff, val);
                break;
        case 0xb:
-               cp_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               cp_write(sd, reg->reg & 0xff, val);
                break;
        case 0xc:
-               vdp_write(sd, reg->reg & 0xff, reg->val & 0xff);
+               vdp_write(sd, reg->reg & 0xff, val);
                break;
        default:
                v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
@@ -748,10 +750,13 @@ static int adv7604_s_register(struct v4l2_subdev *sd,
 static int adv7604_s_detect_tx_5v_ctrl(struct v4l2_subdev *sd)
 {
        struct adv7604_state *state = to_state(sd);
+       u8 reg_io_6f = io_read(sd, 0x6f);
 
-       /* port A only */
        return v4l2_ctrl_s_ctrl(state->detect_tx_5v_ctrl,
-                               ((io_read(sd, 0x6f) & 0x10) >> 4));
+                       ((reg_io_6f & 0x10) >> 4) |
+                       ((reg_io_6f & 0x08) >> 2) |
+                       (reg_io_6f & 0x04) |
+                       ((reg_io_6f & 0x02) << 2));
 }
 
 static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
@@ -759,12 +764,11 @@ static int find_and_set_predefined_video_timings(struct v4l2_subdev *sd,
                const struct adv7604_video_standards *predef_vid_timings,
                const struct v4l2_dv_timings *timings)
 {
-       struct adv7604_state *state = to_state(sd);
        int i;
 
        for (i = 0; predef_vid_timings[i].timings.bt.width; i++) {
                if (!v4l2_match_dv_timings(timings, &predef_vid_timings[i].timings,
-                                       DIGITAL_INPUT ? 250000 : 1000000))
+                                       is_digital_input(sd) ? 250000 : 1000000))
                        continue;
                io_write(sd, 0x00, predef_vid_timings[i].vid_std); /* video std */
                io_write(sd, 0x01, (predef_vid_timings[i].v_freq << 4) +
@@ -799,27 +803,22 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd,
        cp_write(sd, 0xab, 0x00);
        cp_write(sd, 0xac, 0x00);
 
-       switch (state->mode) {
-       case ADV7604_MODE_COMP:
-       case ADV7604_MODE_GR:
+       if (is_analog_input(sd)) {
                err = find_and_set_predefined_video_timings(sd,
                                0x01, adv7604_prim_mode_comp, timings);
                if (err)
                        err = find_and_set_predefined_video_timings(sd,
                                        0x02, adv7604_prim_mode_gr, timings);
-               break;
-       case ADV7604_MODE_HDMI:
+       } else if (is_digital_input(sd)) {
                err = find_and_set_predefined_video_timings(sd,
                                0x05, adv7604_prim_mode_hdmi_comp, timings);
                if (err)
                        err = find_and_set_predefined_video_timings(sd,
                                        0x06, adv7604_prim_mode_hdmi_gr, timings);
-               break;
-       default:
-               v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
-                               __func__, state->mode);
+       } else {
+               v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n",
+                               __func__, state->selected_input);
                err = -1;
-               break;
        }
 
 
@@ -846,9 +845,7 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
 
        v4l2_dbg(2, debug, sd, "%s\n", __func__);
 
-       switch (state->mode) {
-       case ADV7604_MODE_COMP:
-       case ADV7604_MODE_GR:
+       if (is_analog_input(sd)) {
                /* auto graphics */
                io_write(sd, 0x00, 0x07); /* video std */
                io_write(sd, 0x01, 0x02); /* prim mode */
@@ -858,33 +855,28 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
                /* Should only be set in auto-graphics mode [REF_02, p. 91-92] */
                /* setup PLL_DIV_MAN_EN and PLL_DIV_RATIO */
                /* IO-map reg. 0x16 and 0x17 should be written in sequence */
-               if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll)) {
+               if (adv_smbus_write_i2c_block_data(client, 0x16, 2, pll))
                        v4l2_err(sd, "writing to reg 0x16 and 0x17 failed\n");
-                       break;
-               }
 
                /* active video - horizontal timing */
                cp_write(sd, 0xa2, (cp_start_sav >> 4) & 0xff);
                cp_write(sd, 0xa3, ((cp_start_sav & 0x0f) << 4) |
-                                       ((cp_start_eav >> 8) & 0x0f));
+                                  ((cp_start_eav >> 8) & 0x0f));
                cp_write(sd, 0xa4, cp_start_eav & 0xff);
 
                /* active video - vertical timing */
                cp_write(sd, 0xa5, (cp_start_vbi >> 4) & 0xff);
                cp_write(sd, 0xa6, ((cp_start_vbi & 0xf) << 4) |
-                                       ((cp_end_vbi >> 8) & 0xf));
+                                  ((cp_end_vbi >> 8) & 0xf));
                cp_write(sd, 0xa7, cp_end_vbi & 0xff);
-               break;
-       case ADV7604_MODE_HDMI:
+       } else if (is_digital_input(sd)) {
                /* set default prim_mode/vid_std for HDMI
                   according to [REF_03, c. 4.2] */
                io_write(sd, 0x00, 0x02); /* video std */
                io_write(sd, 0x01, 0x06); /* prim mode */
-               break;
-       default:
-               v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
-                               __func__, state->mode);
-               break;
+       } else {
+               v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n",
+                               __func__, state->selected_input);
        }
 
        cp_write(sd, 0x8f, (ch1_fr_ll >> 8) & 0x7);
@@ -893,43 +885,149 @@ static void configure_custom_video_timings(struct v4l2_subdev *sd,
        cp_write(sd, 0xac, (height & 0x0f) << 4);
 }
 
+static void adv7604_set_offset(struct v4l2_subdev *sd, bool auto_offset, u16 offset_a, u16 offset_b, u16 offset_c)
+{
+       struct adv7604_state *state = to_state(sd);
+       u8 offset_buf[4];
+
+       if (auto_offset) {
+               offset_a = 0x3ff;
+               offset_b = 0x3ff;
+               offset_c = 0x3ff;
+       }
+
+       v4l2_dbg(2, debug, sd, "%s: %s offset: a = 0x%x, b = 0x%x, c = 0x%x\n",
+                       __func__, auto_offset ? "Auto" : "Manual",
+                       offset_a, offset_b, offset_c);
+
+       offset_buf[0] = (cp_read(sd, 0x77) & 0xc0) | ((offset_a & 0x3f0) >> 4);
+       offset_buf[1] = ((offset_a & 0x00f) << 4) | ((offset_b & 0x3c0) >> 6);
+       offset_buf[2] = ((offset_b & 0x03f) << 2) | ((offset_c & 0x300) >> 8);
+       offset_buf[3] = offset_c & 0x0ff;
+
+       /* Registers must be written in this order with no i2c access in between */
+       if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x77, 4, offset_buf))
+               v4l2_err(sd, "%s: i2c error writing to CP reg 0x77, 0x78, 0x79, 0x7a\n", __func__);
+}
+
+static void adv7604_set_gain(struct v4l2_subdev *sd, bool auto_gain, u16 gain_a, u16 gain_b, u16 gain_c)
+{
+       struct adv7604_state *state = to_state(sd);
+       u8 gain_buf[4];
+       u8 gain_man = 1;
+       u8 agc_mode_man = 1;
+
+       if (auto_gain) {
+               gain_man = 0;
+               agc_mode_man = 0;
+               gain_a = 0x100;
+               gain_b = 0x100;
+               gain_c = 0x100;
+       }
+
+       v4l2_dbg(2, debug, sd, "%s: %s gain: a = 0x%x, b = 0x%x, c = 0x%x\n",
+                       __func__, auto_gain ? "Auto" : "Manual",
+                       gain_a, gain_b, gain_c);
+
+       gain_buf[0] = ((gain_man << 7) | (agc_mode_man << 6) | ((gain_a & 0x3f0) >> 4));
+       gain_buf[1] = (((gain_a & 0x00f) << 4) | ((gain_b & 0x3c0) >> 6));
+       gain_buf[2] = (((gain_b & 0x03f) << 2) | ((gain_c & 0x300) >> 8));
+       gain_buf[3] = ((gain_c & 0x0ff));
+
+       /* Registers must be written in this order with no i2c access in between */
+       if (adv_smbus_write_i2c_block_data(state->i2c_cp, 0x73, 4, gain_buf))
+               v4l2_err(sd, "%s: i2c error writing to CP reg 0x73, 0x74, 0x75, 0x76\n", __func__);
+}
+
 static void set_rgb_quantization_range(struct v4l2_subdev *sd)
 {
        struct adv7604_state *state = to_state(sd);
+       bool rgb_output = io_read(sd, 0x02) & 0x02;
+       bool hdmi_signal = hdmi_read(sd, 0x05) & 0x80;
+
+       v4l2_dbg(2, debug, sd, "%s: RGB quantization range: %d, RGB out: %d, HDMI: %d\n",
+                       __func__, state->rgb_quantization_range,
+                       rgb_output, hdmi_signal);
+
+       adv7604_set_gain(sd, true, 0x0, 0x0, 0x0);
+       adv7604_set_offset(sd, true, 0x0, 0x0, 0x0);
 
        switch (state->rgb_quantization_range) {
        case V4L2_DV_RGB_RANGE_AUTO:
-               /* automatic */
-               if (DIGITAL_INPUT && !(hdmi_read(sd, 0x05) & 0x80)) {
-                       /* receiving DVI-D signal */
+               if (state->selected_input == ADV7604_INPUT_VGA_RGB) {
+                       /* Receiving analog RGB signal
+                        * Set RGB full range (0-255) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x10);
+                       break;
+               }
+
+               if (state->selected_input == ADV7604_INPUT_VGA_COMP) {
+                       /* Receiving analog YPbPr signal
+                        * Set automode */
+                       io_write_and_or(sd, 0x02, 0x0f, 0xf0);
+                       break;
+               }
+
+               if (hdmi_signal) {
+                       /* Receiving HDMI signal
+                        * Set automode */
+                       io_write_and_or(sd, 0x02, 0x0f, 0xf0);
+                       break;
+               }
 
-                       /* ADV7604 selects RGB limited range regardless of
-                          input format (CE/IT) in automatic mode */
-                       if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
-                               /* RGB limited range (16-235) */
-                               io_write_and_or(sd, 0x02, 0x0f, 0x00);
+               /* Receiving DVI-D signal
+                * ADV7604 selects RGB limited range regardless of
+                * input format (CE/IT) in automatic mode */
+               if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
+                       /* RGB limited range (16-235) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x00);
+               } else {
+                       /* RGB full range (0-255) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x10);
 
+                       if (is_digital_input(sd) && rgb_output) {
+                               adv7604_set_offset(sd, false, 0x40, 0x40, 0x40);
                        } else {
-                               /* RGB full range (0-255) */
-                               io_write_and_or(sd, 0x02, 0x0f, 0x10);
+                               adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
+                               adv7604_set_offset(sd, false, 0x70, 0x70, 0x70);
                        }
-               } else {
-                       /* receiving HDMI or analog signal, set automode */
-                       io_write_and_or(sd, 0x02, 0x0f, 0xf0);
                }
                break;
        case V4L2_DV_RGB_RANGE_LIMITED:
+               if (state->selected_input == ADV7604_INPUT_VGA_COMP) {
+                       /* YCrCb limited range (16-235) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x20);
+                       break;
+               }
+
                /* RGB limited range (16-235) */
                io_write_and_or(sd, 0x02, 0x0f, 0x00);
+
                break;
        case V4L2_DV_RGB_RANGE_FULL:
+               if (state->selected_input == ADV7604_INPUT_VGA_COMP) {
+                       /* YCrCb full range (0-255) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x60);
+                       break;
+               }
+
                /* RGB full range (0-255) */
                io_write_and_or(sd, 0x02, 0x0f, 0x10);
+
+               if (is_analog_input(sd) || hdmi_signal)
+                       break;
+
+               /* Adjust gain/offset for DVI-D signals only */
+               if (rgb_output) {
+                       adv7604_set_offset(sd, false, 0x40, 0x40, 0x40);
+               } else {
+                       adv7604_set_gain(sd, false, 0xe0, 0xe0, 0xe0);
+                       adv7604_set_offset(sd, false, 0x70, 0x70, 0x70);
+               }
                break;
        }
 }
 
-
 static int adv7604_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct v4l2_subdev *sd = to_sd(ctrl);
@@ -983,8 +1081,9 @@ static inline bool no_power(struct v4l2_subdev *sd)
 
 static inline bool no_signal_tmds(struct v4l2_subdev *sd)
 {
-       /* TODO port B, C and D */
-       return !(io_read(sd, 0x6a) & 0x10);
+       struct adv7604_state *state = to_state(sd);
+
+       return !(io_read(sd, 0x6a) & (0x10 >> state->selected_input));
 }
 
 static inline bool no_lock_tmds(struct v4l2_subdev *sd)
@@ -1011,7 +1110,6 @@ static inline bool no_lock_stdi(struct v4l2_subdev *sd)
 
 static inline bool no_signal(struct v4l2_subdev *sd)
 {
-       struct adv7604_state *state = to_state(sd);
        bool ret;
 
        ret = no_power(sd);
@@ -1019,7 +1117,7 @@ static inline bool no_signal(struct v4l2_subdev *sd)
        ret |= no_lock_stdi(sd);
        ret |= no_lock_sspd(sd);
 
-       if (DIGITAL_INPUT) {
+       if (is_digital_input(sd)) {
                ret |= no_lock_tmds(sd);
                ret |= no_signal_tmds(sd);
        }
@@ -1036,13 +1134,11 @@ static inline bool no_lock_cp(struct v4l2_subdev *sd)
 
 static int adv7604_g_input_status(struct v4l2_subdev *sd, u32 *status)
 {
-       struct adv7604_state *state = to_state(sd);
-
        *status = 0;
        *status |= no_power(sd) ? V4L2_IN_ST_NO_POWER : 0;
        *status |= no_signal(sd) ? V4L2_IN_ST_NO_SIGNAL : 0;
        if (no_lock_cp(sd))
-               *status |= DIGITAL_INPUT ? V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK;
+               *status |= is_digital_input(sd) ? V4L2_IN_ST_NO_SYNC : V4L2_IN_ST_NO_H_LOCK;
 
        v4l2_dbg(1, debug, sd, "%s: status = 0x%x\n", __func__, *status);
 
@@ -1157,13 +1253,11 @@ static int adv7604_enum_dv_timings(struct v4l2_subdev *sd,
 static int adv7604_dv_timings_cap(struct v4l2_subdev *sd,
                        struct v4l2_dv_timings_cap *cap)
 {
-       struct adv7604_state *state = to_state(sd);
-
        cap->type = V4L2_DV_BT_656_1120;
        cap->bt.max_width = 1920;
        cap->bt.max_height = 1200;
        cap->bt.min_pixelclock = 25000000;
-       if (DIGITAL_INPUT)
+       if (is_digital_input(sd))
                cap->bt.max_pixelclock = 225000000;
        else
                cap->bt.max_pixelclock = 170000000;
@@ -1179,12 +1273,11 @@ static int adv7604_dv_timings_cap(struct v4l2_subdev *sd,
 static void adv7604_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
                struct v4l2_dv_timings *timings)
 {
-       struct adv7604_state *state = to_state(sd);
        int i;
 
        for (i = 0; adv7604_timings[i].bt.width; i++) {
                if (v4l2_match_dv_timings(timings, &adv7604_timings[i],
-                                       DIGITAL_INPUT ? 250000 : 1000000)) {
+                                       is_digital_input(sd) ? 250000 : 1000000)) {
                        *timings = adv7604_timings[i];
                        break;
                }
@@ -1204,6 +1297,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
        memset(timings, 0, sizeof(struct v4l2_dv_timings));
 
        if (no_signal(sd)) {
+               state->restart_stdi_once = true;
                v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__);
                return -ENOLINK;
        }
@@ -1216,7 +1310,7 @@ static int adv7604_query_dv_timings(struct v4l2_subdev *sd,
        bt->interlaced = stdi.interlaced ?
                V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
 
-       if (DIGITAL_INPUT) {
+       if (is_digital_input(sd)) {
                uint32_t freq;
 
                timings->type = V4L2_DV_BT_656_1120;
@@ -1305,8 +1399,8 @@ found:
                return -ENOLINK;
        }
 
-       if ((!DIGITAL_INPUT && bt->pixelclock > 170000000) ||
-                       (DIGITAL_INPUT && bt->pixelclock > 225000000)) {
+       if ((is_analog_input(sd) && bt->pixelclock > 170000000) ||
+                       (is_digital_input(sd) && bt->pixelclock > 225000000)) {
                v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n",
                                __func__, (u32)bt->pixelclock);
                return -ERANGE;
@@ -1329,10 +1423,15 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
        if (!timings)
                return -EINVAL;
 
+       if (v4l2_match_dv_timings(&state->timings, timings, 0)) {
+               v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
+               return 0;
+       }
+
        bt = &timings->bt;
 
-       if ((!DIGITAL_INPUT && bt->pixelclock > 170000000) ||
-                       (DIGITAL_INPUT && bt->pixelclock > 225000000)) {
+       if ((is_analog_input(sd) && bt->pixelclock > 170000000) ||
+                       (is_digital_input(sd) && bt->pixelclock > 225000000)) {
                v4l2_dbg(1, debug, sd, "%s: pixelclock out of range %d\n",
                                __func__, (u32)bt->pixelclock);
                return -ERANGE;
@@ -1354,7 +1453,6 @@ static int adv7604_s_dv_timings(struct v4l2_subdev *sd,
 
        set_rgb_quantization_range(sd);
 
-
        if (debug > 1)
                v4l2_print_dv_timings(sd->name, "adv7604_s_dv_timings: ",
                                      timings, true);
@@ -1374,30 +1472,24 @@ static void enable_input(struct v4l2_subdev *sd)
 {
        struct adv7604_state *state = to_state(sd);
 
-       switch (state->mode) {
-       case ADV7604_MODE_COMP:
-       case ADV7604_MODE_GR:
-               /* enable */
+       if (is_analog_input(sd)) {
                io_write(sd, 0x15, 0xb0);   /* Disable Tristate of Pins (no audio) */
-               break;
-       case ADV7604_MODE_HDMI:
-               /* enable */
-               hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */
+       } else if (is_digital_input(sd)) {
+               hdmi_write_and_or(sd, 0x00, 0xfc, state->selected_input);
                hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */
                io_write(sd, 0x15, 0xa0);   /* Disable Tristate of Pins */
-               break;
-       default:
-               v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
-                               __func__, state->mode);
-               break;
+               hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */
+       } else {
+               v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n",
+                               __func__, state->selected_input);
        }
 }
 
 static void disable_input(struct v4l2_subdev *sd)
 {
-       /* disable */
+       hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio */
+       msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 7.16.10] */
        io_write(sd, 0x15, 0xbe);   /* Tristate all outputs from video core */
-       hdmi_write(sd, 0x1a, 0x1a); /* Mute audio */
        hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */
 }
 
@@ -1405,9 +1497,7 @@ static void select_input(struct v4l2_subdev *sd)
 {
        struct adv7604_state *state = to_state(sd);
 
-       switch (state->mode) {
-       case ADV7604_MODE_COMP:
-       case ADV7604_MODE_GR:
+       if (is_analog_input(sd)) {
                /* reset ADI recommended settings for HDMI: */
                /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
                hdmi_write(sd, 0x0d, 0x04); /* HDMI filter optimization */
@@ -1433,9 +1523,9 @@ static void select_input(struct v4l2_subdev *sd)
                cp_write(sd, 0x3e, 0x04); /* CP core pre-gain control */
                cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */
                cp_write(sd, 0x40, 0x5c); /* CP core pre-gain control. Graphics mode */
-               break;
+       } else if (is_digital_input(sd)) {
+               hdmi_write(sd, 0x00, state->selected_input & 0x03);
 
-       case ADV7604_MODE_HDMI:
                /* set ADI recommended settings for HDMI: */
                /* "ADV7604 Register Settings Recommendations (rev. 2.5, June 2010)" p. 4. */
                hdmi_write(sd, 0x0d, 0x84); /* HDMI filter optimization */
@@ -1461,12 +1551,9 @@ static void select_input(struct v4l2_subdev *sd)
                cp_write(sd, 0x3e, 0x00); /* CP core pre-gain control */
                cp_write(sd, 0xc3, 0x39); /* CP coast control. Graphics mode */
                cp_write(sd, 0x40, 0x80); /* CP core pre-gain control. Graphics mode */
-
-               break;
-       default:
-               v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
-                               __func__, state->mode);
-               break;
+       } else {
+               v4l2_dbg(2, debug, sd, "%s: Unknown port %d selected\n",
+                               __func__, state->selected_input);
        }
 }
 
@@ -1475,9 +1562,13 @@ static int adv7604_s_routing(struct v4l2_subdev *sd,
 {
        struct adv7604_state *state = to_state(sd);
 
-       v4l2_dbg(2, debug, sd, "%s: input %d", __func__, input);
+       v4l2_dbg(2, debug, sd, "%s: input %d, selected input %d",
+                       __func__, input, state->selected_input);
+
+       if (input == state->selected_input)
+               return 0;
 
-       state->mode = input;
+       state->selected_input = input;
 
        disable_input(sd);
 
@@ -1516,36 +1607,47 @@ static int adv7604_g_mbus_fmt(struct v4l2_subdev *sd,
 
 static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 {
-       struct adv7604_state *state = to_state(sd);
-       u8 fmt_change, fmt_change_digital, tx_5v;
-       u32 input_status;
+       const u8 irq_reg_0x43 = io_read(sd, 0x43);
+       const u8 irq_reg_0x6b = io_read(sd, 0x6b);
+       const u8 irq_reg_0x70 = io_read(sd, 0x70);
+       u8 fmt_change_digital;
+       u8 fmt_change;
+       u8 tx_5v;
+
+       if (irq_reg_0x43)
+               io_write(sd, 0x44, irq_reg_0x43);
+       if (irq_reg_0x70)
+               io_write(sd, 0x71, irq_reg_0x70);
+       if (irq_reg_0x6b)
+               io_write(sd, 0x6c, irq_reg_0x6b);
+
+       v4l2_dbg(2, debug, sd, "%s: ", __func__);
 
        /* format change */
-       fmt_change = io_read(sd, 0x43) & 0x98;
-       if (fmt_change)
-               io_write(sd, 0x44, fmt_change);
-       fmt_change_digital = DIGITAL_INPUT ? (io_read(sd, 0x6b) & 0xc0) : 0;
-       if (fmt_change_digital)
-               io_write(sd, 0x6c, fmt_change_digital);
+       fmt_change = irq_reg_0x43 & 0x98;
+       fmt_change_digital = is_digital_input(sd) ? (irq_reg_0x6b & 0xc0) : 0;
+
        if (fmt_change || fmt_change_digital) {
                v4l2_dbg(1, debug, sd,
                        "%s: fmt_change = 0x%x, fmt_change_digital = 0x%x\n",
                        __func__, fmt_change, fmt_change_digital);
 
-               adv7604_g_input_status(sd, &input_status);
-               if (input_status != state->prev_input_status) {
-                       v4l2_dbg(1, debug, sd,
-                               "%s: input_status = 0x%x, prev_input_status = 0x%x\n",
-                               __func__, input_status, state->prev_input_status);
-                       state->prev_input_status = input_status;
-                       v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL);
-               }
+               v4l2_subdev_notify(sd, ADV7604_FMT_CHANGE, NULL);
 
                if (handled)
                        *handled = true;
        }
+       /* HDMI/DVI mode */
+       if (irq_reg_0x6b & 0x01) {
+               v4l2_dbg(1, debug, sd, "%s: irq %s mode\n", __func__,
+                       (io_read(sd, 0x6a) & 0x01) ? "HDMI" : "DVI");
+               set_rgb_quantization_range(sd);
+               if (handled)
+                       *handled = true;
+       }
+
        /* tx 5v detect */
-       tx_5v = io_read(sd, 0x70) & 0x10;
+       tx_5v = io_read(sd, 0x70) & 0x1e;
        if (tx_5v) {
                v4l2_dbg(1, debug, sd, "%s: tx_5v: 0x%x\n", __func__, tx_5v);
                io_write(sd, 0x71, tx_5v);
@@ -1559,55 +1661,178 @@ static int adv7604_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
 {
        struct adv7604_state *state = to_state(sd);
+       u8 *data = NULL;
 
-       if (edid->pad != 0)
+       if (edid->pad > ADV7604_EDID_PORT_D)
                return -EINVAL;
        if (edid->blocks == 0)
                return -EINVAL;
-       if (edid->start_block >= state->edid_blocks)
+       if (edid->blocks > 2)
+               return -EINVAL;
+       if (edid->start_block > 1)
                return -EINVAL;
-       if (edid->start_block + edid->blocks > state->edid_blocks)
-               edid->blocks = state->edid_blocks - edid->start_block;
+       if (edid->start_block == 1)
+               edid->blocks = 1;
        if (!edid->edid)
                return -EINVAL;
-       memcpy(edid->edid + edid->start_block * 128,
-              state->edid + edid->start_block * 128,
+
+       if (edid->blocks > state->edid.blocks)
+               edid->blocks = state->edid.blocks;
+
+       switch (edid->pad) {
+       case ADV7604_EDID_PORT_A:
+       case ADV7604_EDID_PORT_B:
+       case ADV7604_EDID_PORT_C:
+       case ADV7604_EDID_PORT_D:
+               if (state->edid.present & (1 << edid->pad))
+                       data = state->edid.edid;
+               break;
+       default:
+               return -EINVAL;
+               break;
+       }
+       if (!data)
+               return -ENODATA;
+
+       memcpy(edid->edid,
+              data + edid->start_block * 128,
               edid->blocks * 128);
        return 0;
 }
 
+static int get_edid_spa_location(const u8 *edid)
+{
+       u8 d;
+
+       if ((edid[0x7e] != 1) ||
+           (edid[0x80] != 0x02) ||
+           (edid[0x81] != 0x03)) {
+               return -1;
+       }
+
+       /* search Vendor Specific Data Block (tag 3) */
+       d = edid[0x82] & 0x7f;
+       if (d > 4) {
+               int i = 0x84;
+               int end = 0x80 + d;
+
+               do {
+                       u8 tag = edid[i] >> 5;
+                       u8 len = edid[i] & 0x1f;
+
+                       if ((tag == 3) && (len >= 5))
+                               return i + 4;
+                       i += len + 1;
+               } while (i < end);
+       }
+       return -1;
+}
+
 static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
 {
        struct adv7604_state *state = to_state(sd);
+       int spa_loc;
+       int tmp = 0;
        int err;
+       int i;
 
-       if (edid->pad != 0)
+       if (edid->pad > ADV7604_EDID_PORT_D)
                return -EINVAL;
        if (edid->start_block != 0)
                return -EINVAL;
        if (edid->blocks == 0) {
-               /* Pull down the hotplug pin */
-               v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)0);
-               /* Disables I2C access to internal EDID ram from DDC port */
-               rep_write_and_or(sd, 0x77, 0xf0, 0x0);
-               state->edid_blocks = 0;
+               /* Disable hotplug and I2C access to EDID RAM from DDC port */
+               state->edid.present &= ~(1 << edid->pad);
+               v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&state->edid.present);
+               rep_write_and_or(sd, 0x77, 0xf0, state->edid.present);
+
                /* Fall back to a 16:9 aspect ratio */
                state->aspect_ratio.numerator = 16;
                state->aspect_ratio.denominator = 9;
+
+               if (!state->edid.present)
+                       state->edid.blocks = 0;
+
+               v4l2_dbg(2, debug, sd, "%s: clear EDID pad %d, edid.present = 0x%x\n",
+                               __func__, edid->pad, state->edid.present);
                return 0;
        }
-       if (edid->blocks > 2)
+       if (edid->blocks > 2) {
+               edid->blocks = 2;
                return -E2BIG;
+       }
        if (!edid->edid)
                return -EINVAL;
-       memcpy(state->edid, edid->edid, 128 * edid->blocks);
-       state->edid_blocks = edid->blocks;
+
+       v4l2_dbg(2, debug, sd, "%s: write EDID pad %d, edid.present = 0x%x\n",
+                       __func__, edid->pad, state->edid.present);
+
+       /* Disable hotplug and I2C access to EDID RAM from DDC port */
+       cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
+       v4l2_subdev_notify(sd, ADV7604_HOTPLUG, (void *)&tmp);
+       rep_write_and_or(sd, 0x77, 0xf0, 0x00);
+
+       spa_loc = get_edid_spa_location(edid->edid);
+       if (spa_loc < 0)
+               spa_loc = 0xc0; /* Default value [REF_02, p. 116] */
+
+       switch (edid->pad) {
+       case ADV7604_EDID_PORT_A:
+               state->spa_port_a[0] = edid->edid[spa_loc];
+               state->spa_port_a[1] = edid->edid[spa_loc + 1];
+               break;
+       case ADV7604_EDID_PORT_B:
+               rep_write(sd, 0x70, edid->edid[spa_loc]);
+               rep_write(sd, 0x71, edid->edid[spa_loc + 1]);
+               break;
+       case ADV7604_EDID_PORT_C:
+               rep_write(sd, 0x72, edid->edid[spa_loc]);
+               rep_write(sd, 0x73, edid->edid[spa_loc + 1]);
+               break;
+       case ADV7604_EDID_PORT_D:
+               rep_write(sd, 0x74, edid->edid[spa_loc]);
+               rep_write(sd, 0x75, edid->edid[spa_loc + 1]);
+               break;
+       default:
+               return -EINVAL;
+       }
+       rep_write(sd, 0x76, spa_loc & 0xff);
+       rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40);
+
+       edid->edid[spa_loc] = state->spa_port_a[0];
+       edid->edid[spa_loc + 1] = state->spa_port_a[1];
+
+       memcpy(state->edid.edid, edid->edid, 128 * edid->blocks);
+       state->edid.blocks = edid->blocks;
        state->aspect_ratio = v4l2_calc_aspect_ratio(edid->edid[0x15],
                        edid->edid[0x16]);
-       err = edid_write_block(sd, 128 * edid->blocks, state->edid);
-       if (err < 0)
-               v4l2_err(sd, "error %d writing edid\n", err);
-       return err;
+       state->edid.present |= 1 << edid->pad;
+
+       err = edid_write_block(sd, 128 * edid->blocks, state->edid.edid);
+       if (err < 0) {
+               v4l2_err(sd, "error %d writing edid pad %d\n", err, edid->pad);
+               return err;
+       }
+
+       /* adv7604 calculates the checksums and enables I2C access to internal
+          EDID RAM from DDC port. */
+       rep_write_and_or(sd, 0x77, 0xf0, state->edid.present);
+
+       for (i = 0; i < 1000; i++) {
+               if (rep_read(sd, 0x7d) & state->edid.present)
+                       break;
+               mdelay(1);
+       }
+       if (i == 1000) {
+               v4l2_err(sd, "error enabling edid (0x%x)\n", state->edid.present);
+               return -EIO;
+       }
+
+
+       /* enable hotplug after 100 ms */
+       queue_delayed_work(state->work_queues,
+                       &state->delayed_work_enable_hotplug, HZ / 10);
+       return 0;
 }
 
 /*********** avi info frame CEA-861-E **************/
@@ -1670,7 +1895,7 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
        char *input_color_space_txt[16] = {
                "RGB limited range (16-235)", "RGB full range (0-255)",
                "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)",
-               "XvYCC Bt.601", "XvYCC Bt.709",
+               "xvYCC Bt.601", "xvYCC Bt.709",
                "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)",
                "invalid", "invalid", "invalid", "invalid", "invalid",
                "invalid", "invalid", "automatic"
@@ -1689,16 +1914,20 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
 
        v4l2_info(sd, "-----Chip status-----\n");
        v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on");
-       v4l2_info(sd, "Connector type: %s\n", state->connector_hdmi ?
-                       "HDMI" : (DIGITAL_INPUT ? "DVI-D" : "DVI-A"));
-       v4l2_info(sd, "EDID: %s\n", ((rep_read(sd, 0x7d) & 0x01) &&
-                       (rep_read(sd, 0x77) & 0x01)) ? "enabled" : "disabled ");
+       v4l2_info(sd, "EDID enabled port A: %s, B: %s, C: %s, D: %s\n",
+                       ((rep_read(sd, 0x7d) & 0x01) ? "Yes" : "No"),
+                       ((rep_read(sd, 0x7d) & 0x02) ? "Yes" : "No"),
+                       ((rep_read(sd, 0x7d) & 0x04) ? "Yes" : "No"),
+                       ((rep_read(sd, 0x7d) & 0x08) ? "Yes" : "No"));
        v4l2_info(sd, "CEC: %s\n", !!(cec_read(sd, 0x2a) & 0x01) ?
                        "enabled" : "disabled");
 
        v4l2_info(sd, "-----Signal status-----\n");
-       v4l2_info(sd, "Cable detected (+5V power): %s\n",
-                       (io_read(sd, 0x6f) & 0x10) ? "true" : "false");
+       v4l2_info(sd, "Cable detected (+5V power) port A: %s, B: %s, C: %s, D: %s\n",
+                       ((io_read(sd, 0x6f) & 0x10) ? "Yes" : "No"),
+                       ((io_read(sd, 0x6f) & 0x08) ? "Yes" : "No"),
+                       ((io_read(sd, 0x6f) & 0x04) ? "Yes" : "No"),
+                       ((io_read(sd, 0x6f) & 0x02) ? "Yes" : "No"));
        v4l2_info(sd, "TMDS signal detected: %s\n",
                        no_signal_tmds(sd) ? "false" : "true");
        v4l2_info(sd, "TMDS signal locked: %s\n",
@@ -1744,11 +1973,14 @@ static int adv7604_log_status(struct v4l2_subdev *sd)
        v4l2_info(sd, "Color space conversion: %s\n",
                        csc_coeff_sel_rb[cp_read(sd, 0xfc) >> 4]);
 
-       if (!DIGITAL_INPUT)
+       if (!is_digital_input(sd))
                return 0;
 
        v4l2_info(sd, "-----%s status-----\n", is_hdmi(sd) ? "HDMI" : "DVI-D");
-       v4l2_info(sd, "HDCP encrypted content: %s\n", (hdmi_read(sd, 0x05) & 0x40) ? "true" : "false");
+       v4l2_info(sd, "Digital video port selected: %c\n",
+                       (hdmi_read(sd, 0x00) & 0x03) + 'A');
+       v4l2_info(sd, "HDCP encrypted content: %s\n",
+                       (hdmi_read(sd, 0x05) & 0x40) ? "true" : "false");
        v4l2_info(sd, "HDCP keys read: %s%s\n",
                        (hdmi_read(sd, 0x04) & 0x20) ? "yes" : "no",
                        (hdmi_read(sd, 0x04) & 0x10) ? "ERROR" : "");
@@ -1894,10 +2126,16 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
                                        pdata->replicate_av_codes << 1 |
                                        pdata->invert_cbcr << 0);
 
-       /* TODO from platform data */
        cp_write(sd, 0x69, 0x30);   /* Enable CP CSC */
-       io_write(sd, 0x06, 0xa6);   /* positive VS and HS */
-       io_write(sd, 0x14, 0x7f);   /* Drive strength adjusted to max */
+
+       /* VS, HS polarities */
+       io_write(sd, 0x06, 0xa0 | pdata->inv_vs_pol << 2 | pdata->inv_hs_pol << 1);
+
+       /* Adjust drive strength */
+       io_write(sd, 0x14, 0x40 | pdata->dr_str_data << 4 |
+                               pdata->dr_str_clk << 2 |
+                               pdata->dr_str_sync);
+
        cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01); /* HDMI free run */
        cp_write(sd, 0xf3, 0xdc); /* Low threshold to enter/exit free run mode */
        cp_write(sd, 0xf9, 0x23); /*  STDI ch. 1 - LCVS change threshold -
@@ -1907,6 +2145,11 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
        cp_write(sd, 0xc9, 0x2d); /* use prim_mode and vid_std as free run resolution
                                     for digital formats */
 
+       /* HDMI audio */
+       hdmi_write_and_or(sd, 0x15, 0xfc, 0x03); /* Mute on FIFO over-/underflow [REF_01, c. 1.2.18] */
+       hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */
+       hdmi_write_and_or(sd, 0x68, 0xf9, 0x06); /* FIFO reset on over-/underflow [REF_01, c. 1.2.19] */
+
        /* TODO from platform data */
        afe_write(sd, 0xb5, 0x01);  /* Setting MCLK to 256Fs */
 
@@ -1917,8 +2160,8 @@ static int adv7604_core_init(struct v4l2_subdev *sd)
        io_write(sd, 0x40, 0xc2); /* Configure INT1 */
        io_write(sd, 0x41, 0xd7); /* STDI irq for any change, disable INT2 */
        io_write(sd, 0x46, 0x98); /* Enable SSPD, STDI and CP unlocked interrupts */
-       io_write(sd, 0x6e, 0xc0); /* Enable V_LOCKED and DE_REGEN_LCK interrupts */
-       io_write(sd, 0x73, 0x10); /* Enable CABLE_DET_A_ST (+5v) interrupt */
+       io_write(sd, 0x6e, 0xc1); /* Enable V_LOCKED, DE_REGEN_LCK, HDMI_MODE interrupts */
+       io_write(sd, 0x73, 0x1e); /* Enable CABLE_DET_A_ST (+5v) interrupts */
 
        return v4l2_ctrl_handler_setup(sd->ctrl_handler);
 }
@@ -1964,6 +2207,8 @@ static struct i2c_client *adv7604_dummy_client(struct v4l2_subdev *sd,
 static int adv7604_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
+       static const struct v4l2_dv_timings cea640x480 =
+               V4L2_DV_BT_CEA_640X480P59_94;
        struct adv7604_state *state;
        struct adv7604_platform_data *pdata = client->dev.platform_data;
        struct v4l2_ctrl_handler *hdl;
@@ -1984,19 +2229,19 @@ static int adv7604_probe(struct i2c_client *client,
 
        /* initialize variables */
        state->restart_stdi_once = true;
-       state->prev_input_status = ~0;
+       state->selected_input = ~0;
 
        /* platform data */
        if (!pdata) {
                v4l_err(client, "No platform data!\n");
                return -ENODEV;
        }
-       memcpy(&state->pdata, pdata, sizeof(state->pdata));
+       state->pdata = *pdata;
+       state->timings = cea640x480;
 
        sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &adv7604_ops);
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       state->connector_hdmi = pdata->connector_hdmi;
 
        /* i2c access to adv7604? */
        if (adv_smbus_read_byte_data_check(client, 0xfb, false) != 0x68) {
@@ -2020,7 +2265,7 @@ static int adv7604_probe(struct i2c_client *client,
 
        /* private controls */
        state->detect_tx_5v_ctrl = v4l2_ctrl_new_std(hdl, NULL,
-                       V4L2_CID_DV_RX_POWER_PRESENT, 0, 1, 0, 0);
+                       V4L2_CID_DV_RX_POWER_PRESENT, 0, 0x0f, 0, 0);
        state->rgb_quantization_range_ctrl =
                v4l2_ctrl_new_std_menu(hdl, &adv7604_ctrl_ops,
                        V4L2_CID_DV_RX_RGB_RANGE, V4L2_DV_RGB_RANGE_FULL,
index b154f36740b49151e2b1e0daeaf307c53032f3e7..1effc21e1cdd1bf110d175627009cba22d55c171 100644 (file)
 
 /*
  * References (c = chapter, p = page):
- * REF_01 - Analog devices, ADV7842, Register Settings Recommendations,
- *             Revision 2.5, June 2010
- * REF_02 - Analog devices, Register map documentation, Documentation of
- *             the register maps, Software manual, Rev. F, June 2010
+ * REF_01 - Analog devices, ADV7842,
+ *             Register Settings Recommendations, Rev. 1.9, April 2011
+ * REF_02 - Analog devices, Software User Guide, UG-206,
+ *             ADV7842 I2C Register Maps, Rev. 0, November 2010
+ * REF_03 - Analog devices, Hardware User Guide, UG-214,
+ *             ADV7842 Fast Switching 2:1 HDMI 1.4 Receiver with 3D-Comb
+ *             Decoder and Digitizer , Rev. 0, January 2011
  */
 
 
@@ -61,6 +64,7 @@ MODULE_LICENSE("GPL");
 */
 
 struct adv7842_state {
+       struct adv7842_platform_data pdata;
        struct v4l2_subdev sd;
        struct media_pad pad;
        struct v4l2_ctrl_handler hdl;
@@ -81,7 +85,7 @@ struct adv7842_state {
        bool is_cea_format;
        struct workqueue_struct *work_queues;
        struct delayed_work delayed_work_enable_hotplug;
-       bool connector_hdmi;
+       bool restart_stdi_once;
        bool hdmi_port_a;
 
        /* i2c clients */
@@ -491,6 +495,11 @@ static inline int hdmi_write(struct v4l2_subdev *sd, u8 reg, u8 val)
        return adv_smbus_write_byte_data(state->i2c_hdmi, reg, val);
 }
 
+static inline int hdmi_write_and_or(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
+{
+       return hdmi_write(sd, reg, (hdmi_read(sd, reg) & mask) | val);
+}
+
 static inline int cp_read(struct v4l2_subdev *sd, u8 reg)
 {
        struct adv7842_state *state = to_state(sd);
@@ -532,7 +541,7 @@ static void main_reset(struct v4l2_subdev *sd)
 
        adv_smbus_write_byte_no_check(client, 0xff, 0x80);
 
-       mdelay(2);
+       mdelay(5);
 }
 
 /* ----------------------------------------------------------------------- */
@@ -587,10 +596,10 @@ static void adv7842_delayed_work_enable_hotplug(struct work_struct *work)
        v4l2_dbg(2, debug, sd, "%s: enable hotplug on ports: 0x%x\n",
                        __func__, present);
 
-       if (present & 0x1)
-               mask |= 0x20; /* port A */
-       if (present & 0x2)
-               mask |= 0x10; /* port B */
+       if (present & (0x04 << ADV7842_EDID_PORT_A))
+               mask |= 0x20;
+       if (present & (0x04 << ADV7842_EDID_PORT_B))
+               mask |= 0x10;
        io_write_and_or(sd, 0x20, 0xcf, mask);
 }
 
@@ -679,14 +688,12 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct adv7842_state *state = to_state(sd);
        const u8 *val = state->hdmi_edid.edid;
-       u8 cur_mask = rep_read(sd, 0x77) & 0x0c;
-       u8 mask = port == 0 ? 0x4 : 0x8;
        int spa_loc = edid_spa_location(val);
        int err = 0;
        int i;
 
-       v4l2_dbg(2, debug, sd, "%s: write EDID on port %d (spa at 0x%x)\n",
-                       __func__, port, spa_loc);
+       v4l2_dbg(2, debug, sd, "%s: write EDID on port %c (spa at 0x%x)\n",
+                       __func__, (port == ADV7842_EDID_PORT_A) ? 'A' : 'B', spa_loc);
 
        /* HPA disable on port A and B */
        io_write_and_or(sd, 0x20, 0xcf, 0x00);
@@ -694,6 +701,9 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
        /* Disable I2C access to internal EDID ram from HDMI DDC ports */
        rep_write_and_or(sd, 0x77, 0xf3, 0x00);
 
+       if (!state->hdmi_edid.present)
+               return 0;
+
        /* edid segment pointer '0' for HDMI ports */
        rep_write_and_or(sd, 0x77, 0xef, 0x00);
 
@@ -703,44 +713,32 @@ static int edid_write_hdmi_segment(struct v4l2_subdev *sd, u8 port)
        if (err)
                return err;
 
-       if (spa_loc > 0) {
-               if (port == 0) {
-                       /* port A SPA */
-                       rep_write(sd, 0x72, val[spa_loc]);
-                       rep_write(sd, 0x73, val[spa_loc + 1]);
-               } else {
-                       /* port B SPA */
-                       rep_write(sd, 0x74, val[spa_loc]);
-                       rep_write(sd, 0x75, val[spa_loc + 1]);
-               }
-               rep_write(sd, 0x76, spa_loc);
+       if (spa_loc < 0)
+               spa_loc = 0xc0; /* Default value [REF_02, p. 199] */
+
+       if (port == ADV7842_EDID_PORT_A) {
+               rep_write(sd, 0x72, val[spa_loc]);
+               rep_write(sd, 0x73, val[spa_loc + 1]);
        } else {
-               /* default register values for SPA */
-               if (port == 0) {
-                       /* port A SPA */
-                       rep_write(sd, 0x72, 0);
-                       rep_write(sd, 0x73, 0);
-               } else {
-                       /* port B SPA */
-                       rep_write(sd, 0x74, 0);
-                       rep_write(sd, 0x75, 0);
-               }
-               rep_write(sd, 0x76, 0xc0);
+               rep_write(sd, 0x74, val[spa_loc]);
+               rep_write(sd, 0x75, val[spa_loc + 1]);
        }
-       rep_write_and_or(sd, 0x77, 0xbf, 0x00);
+       rep_write(sd, 0x76, spa_loc & 0xff);
+       rep_write_and_or(sd, 0x77, 0xbf, (spa_loc >> 2) & 0x40);
 
        /* Calculates the checksums and enables I2C access to internal
         * EDID ram from HDMI DDC ports
         */
-       rep_write_and_or(sd, 0x77, 0xf3, mask | cur_mask);
+       rep_write_and_or(sd, 0x77, 0xf3, state->hdmi_edid.present);
 
        for (i = 0; i < 1000; i++) {
-               if (rep_read(sd, 0x7d) & mask)
+               if (rep_read(sd, 0x7d) & state->hdmi_edid.present)
                        break;
                mdelay(1);
        }
        if (i == 1000) {
-               v4l_err(client, "error enabling edid on port %d\n", port);
+               v4l_err(client, "error enabling edid on port %c\n",
+                               (port == ADV7842_EDID_PORT_A) ? 'A' : 'B');
                return -EIO;
        }
 
@@ -927,7 +925,7 @@ static int configure_predefined_video_timings(struct v4l2_subdev *sd,
        cp_write(sd, 0x27, 0x00);
        cp_write(sd, 0x28, 0x00);
        cp_write(sd, 0x29, 0x00);
-       cp_write(sd, 0x8f, 0x00);
+       cp_write(sd, 0x8f, 0x40);
        cp_write(sd, 0x90, 0x00);
        cp_write(sd, 0xa5, 0x00);
        cp_write(sd, 0xa6, 0x00);
@@ -1033,34 +1031,60 @@ static void set_rgb_quantization_range(struct v4l2_subdev *sd)
 {
        struct adv7842_state *state = to_state(sd);
 
+       v4l2_dbg(2, debug, sd, "%s: rgb_quantization_range = %d\n",
+                      __func__, state->rgb_quantization_range);
+
        switch (state->rgb_quantization_range) {
        case V4L2_DV_RGB_RANGE_AUTO:
-               /* automatic */
-               if (is_digital_input(sd) && !(hdmi_read(sd, 0x05) & 0x80)) {
-                       /* receiving DVI-D signal */
-
-                       /* ADV7842 selects RGB limited range regardless of
-                          input format (CE/IT) in automatic mode */
-                       if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
-                               /* RGB limited range (16-235) */
-                               io_write_and_or(sd, 0x02, 0x0f, 0x00);
-
-                       } else {
-                               /* RGB full range (0-255) */
-                               io_write_and_or(sd, 0x02, 0x0f, 0x10);
-                       }
-               } else {
-                       /* receiving HDMI or analog signal, set automode */
+               if (state->mode == ADV7842_MODE_RGB) {
+                       /* Receiving analog RGB signal
+                        * Set RGB full range (0-255) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x10);
+                       break;
+               }
+
+               if (state->mode == ADV7842_MODE_COMP) {
+                       /* Receiving analog YPbPr signal
+                        * Set automode */
                        io_write_and_or(sd, 0x02, 0x0f, 0xf0);
+                       break;
+               }
+
+               if (hdmi_read(sd, 0x05) & 0x80) {
+                       /* Receiving HDMI signal
+                        * Set automode */
+                       io_write_and_or(sd, 0x02, 0x0f, 0xf0);
+                       break;
+               }
+
+               /* Receiving DVI-D signal
+                * ADV7842 selects RGB limited range regardless of
+                * input format (CE/IT) in automatic mode */
+               if (state->timings.bt.standards & V4L2_DV_BT_STD_CEA861) {
+                       /* RGB limited range (16-235) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x00);
+               } else {
+                       /* RGB full range (0-255) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x10);
                }
                break;
        case V4L2_DV_RGB_RANGE_LIMITED:
-               /* RGB limited range (16-235) */
-               io_write_and_or(sd, 0x02, 0x0f, 0x00);
+               if (state->mode == ADV7842_MODE_COMP) {
+                       /* YCrCb limited range (16-235) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x20);
+               } else {
+                       /* RGB limited range (16-235) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x00);
+               }
                break;
        case V4L2_DV_RGB_RANGE_FULL:
-               /* RGB full range (0-255) */
-               io_write_and_or(sd, 0x02, 0x0f, 0x10);
+               if (state->mode == ADV7842_MODE_COMP) {
+                       /* YCrCb full range (0-255) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x60);
+               } else {
+                       /* RGB full range (0-255) */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x10);
+               }
                break;
        }
 }
@@ -1298,7 +1322,7 @@ static int adv7842_dv_timings_cap(struct v4l2_subdev *sd,
 }
 
 /* Fill the optional fields .standards and .flags in struct v4l2_dv_timings
-   if the format is listed in adv7604_timings[] */
+   if the format is listed in adv7842_timings[] */
 static void adv7842_fill_optional_dv_timings_fields(struct v4l2_subdev *sd,
                struct v4l2_dv_timings *timings)
 {
@@ -1314,119 +1338,106 @@ static int adv7842_query_dv_timings(struct v4l2_subdev *sd,
        struct v4l2_bt_timings *bt = &timings->bt;
        struct stdi_readback stdi = { 0 };
 
+       v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
        /* SDP block */
        if (state->mode == ADV7842_MODE_SDP)
                return -ENODATA;
 
        /* read STDI */
        if (read_stdi(sd, &stdi)) {
+               state->restart_stdi_once = true;
                v4l2_dbg(1, debug, sd, "%s: no valid signal\n", __func__);
                return -ENOLINK;
        }
        bt->interlaced = stdi.interlaced ?
                V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
-       bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) |
-               ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0);
-       bt->vsync = stdi.lcvs;
 
        if (is_digital_input(sd)) {
-               bool lock = hdmi_read(sd, 0x04) & 0x02;
-               bool interlaced = hdmi_read(sd, 0x0b) & 0x20;
-               unsigned w = (hdmi_read(sd, 0x07) & 0x1f) * 256 + hdmi_read(sd, 0x08);
-               unsigned h = (hdmi_read(sd, 0x09) & 0x1f) * 256 + hdmi_read(sd, 0x0a);
-               unsigned w_total = (hdmi_read(sd, 0x1e) & 0x3f) * 256 +
-                       hdmi_read(sd, 0x1f);
-               unsigned h_total = ((hdmi_read(sd, 0x26) & 0x3f) * 256 +
-                                   hdmi_read(sd, 0x27)) / 2;
-               unsigned freq = (((hdmi_read(sd, 0x51) << 1) +
-                                       (hdmi_read(sd, 0x52) >> 7)) * 1000000) +
-                       ((hdmi_read(sd, 0x52) & 0x7f) * 1000000) / 128;
-               int i;
+               uint32_t freq;
 
-               if (is_hdmi(sd)) {
-                       /* adjust for deep color mode */
-                       freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0)>>6) * 2 + 8);
-               }
-
-               /* No lock? */
-               if (!lock) {
-                       v4l2_dbg(1, debug, sd, "%s: no lock on TMDS signal\n", __func__);
-                       return -ENOLCK;
-               }
-               /* Interlaced? */
-               if (interlaced) {
-                       v4l2_dbg(1, debug, sd, "%s: interlaced video not supported\n", __func__);
-                       return -ERANGE;
-               }
-
-               for (i = 0; v4l2_dv_timings_presets[i].bt.width; i++) {
-                       const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;
-
-                       if (!v4l2_valid_dv_timings(&v4l2_dv_timings_presets[i],
-                                                  adv7842_get_dv_timings_cap(sd),
-                                                  adv7842_check_dv_timings, NULL))
-                               continue;
-                       if (w_total != htotal(bt) || h_total != vtotal(bt))
-                               continue;
+               timings->type = V4L2_DV_BT_656_1120;
 
-                       if (w != bt->width || h != bt->height)
-                               continue;
+               bt->width = (hdmi_read(sd, 0x07) & 0x0f) * 256 + hdmi_read(sd, 0x08);
+               bt->height = (hdmi_read(sd, 0x09) & 0x0f) * 256 + hdmi_read(sd, 0x0a);
+               freq = (hdmi_read(sd, 0x06) * 1000000) +
+                      ((hdmi_read(sd, 0x3b) & 0x30) >> 4) * 250000;
 
-                       if (abs(freq - bt->pixelclock) > 1000000)
-                               continue;
-                       *timings = v4l2_dv_timings_presets[i];
-                       return 0;
+               if (is_hdmi(sd)) {
+                       /* adjust for deep color mode */
+                       freq = freq * 8 / (((hdmi_read(sd, 0x0b) & 0xc0) >> 5) + 8);
                }
-
-               timings->type = V4L2_DV_BT_656_1120;
-
-               bt->width = w;
-               bt->height = h;
-               bt->interlaced = (hdmi_read(sd, 0x0b) & 0x20) ?
-                       V4L2_DV_INTERLACED : V4L2_DV_PROGRESSIVE;
-               bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ?
-                       V4L2_DV_VSYNC_POS_POL : 0) | ((hdmi_read(sd, 0x05) & 0x20) ?
-                       V4L2_DV_HSYNC_POS_POL : 0);
-               bt->pixelclock = (((hdmi_read(sd, 0x51) << 1) +
-                                  (hdmi_read(sd, 0x52) >> 7)) * 1000000) +
-                                ((hdmi_read(sd, 0x52) & 0x7f) * 1000000) / 128;
-               bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x1f) * 256 +
+               bt->pixelclock = freq;
+               bt->hfrontporch = (hdmi_read(sd, 0x20) & 0x03) * 256 +
                        hdmi_read(sd, 0x21);
-               bt->hsync = (hdmi_read(sd, 0x22) & 0x1f) * 256 +
+               bt->hsync = (hdmi_read(sd, 0x22) & 0x03) * 256 +
                        hdmi_read(sd, 0x23);
-               bt->hbackporch = (hdmi_read(sd, 0x24) & 0x1f) * 256 +
+               bt->hbackporch = (hdmi_read(sd, 0x24) & 0x03) * 256 +
                        hdmi_read(sd, 0x25);
-               bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x3f) * 256 +
-                                  hdmi_read(sd, 0x2b)) / 2;
-               bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x3f) * 256 +
-                                     hdmi_read(sd, 0x2d)) / 2;
-               bt->vsync = ((hdmi_read(sd, 0x2e) & 0x3f) * 256 +
-                            hdmi_read(sd, 0x2f)) / 2;
-               bt->il_vsync = ((hdmi_read(sd, 0x30) & 0x3f) * 256 +
-                               hdmi_read(sd, 0x31)) / 2;
-               bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x3f) * 256 +
-                                 hdmi_read(sd, 0x33)) / 2;
-               bt->il_vbackporch = ((hdmi_read(sd, 0x34) & 0x3f) * 256 +
-                                    hdmi_read(sd, 0x35)) / 2;
-
-               bt->standards = 0;
-               bt->flags = 0;
-       } else {
-               /* Interlaced? */
-               if (stdi.interlaced) {
-                       v4l2_dbg(1, debug, sd, "%s: interlaced video not supported\n", __func__);
-                       return -ERANGE;
+               bt->vfrontporch = ((hdmi_read(sd, 0x2a) & 0x1f) * 256 +
+                       hdmi_read(sd, 0x2b)) / 2;
+               bt->vsync = ((hdmi_read(sd, 0x2e) & 0x1f) * 256 +
+                       hdmi_read(sd, 0x2f)) / 2;
+               bt->vbackporch = ((hdmi_read(sd, 0x32) & 0x1f) * 256 +
+                       hdmi_read(sd, 0x33)) / 2;
+               bt->polarities = ((hdmi_read(sd, 0x05) & 0x10) ? V4L2_DV_VSYNC_POS_POL : 0) |
+                       ((hdmi_read(sd, 0x05) & 0x20) ? V4L2_DV_HSYNC_POS_POL : 0);
+               if (bt->interlaced == V4L2_DV_INTERLACED) {
+                       bt->height += (hdmi_read(sd, 0x0b) & 0x0f) * 256 +
+                                       hdmi_read(sd, 0x0c);
+                       bt->il_vfrontporch = ((hdmi_read(sd, 0x2c) & 0x1f) * 256 +
+                                       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 +
+                                       hdmi_read(sd, 0x35)) / 2;
                }
-
+               adv7842_fill_optional_dv_timings_fields(sd, timings);
+       } else {
+               /* find format
+                * Since LCVS values are inaccurate [REF_03, p. 339-340],
+                * stdi2dv_timings() is called with lcvs +-1 if the first attempt fails.
+                */
+               if (!stdi2dv_timings(sd, &stdi, timings))
+                       goto found;
+               stdi.lcvs += 1;
+               v4l2_dbg(1, debug, sd, "%s: lcvs + 1 = %d\n", __func__, stdi.lcvs);
+               if (!stdi2dv_timings(sd, &stdi, timings))
+                       goto found;
+               stdi.lcvs -= 2;
+               v4l2_dbg(1, debug, sd, "%s: lcvs - 1 = %d\n", __func__, stdi.lcvs);
                if (stdi2dv_timings(sd, &stdi, timings)) {
+                       /*
+                        * The STDI block may measure wrong values, especially
+                        * for lcvs and lcf. If the driver can not find any
+                        * valid timing, the STDI block is restarted to measure
+                        * the video timings again. The function will return an
+                        * error, but the restart of STDI will generate a new
+                        * STDI interrupt and the format detection process will
+                        * restart.
+                        */
+                       if (state->restart_stdi_once) {
+                               v4l2_dbg(1, debug, sd, "%s: restart STDI\n", __func__);
+                               /* TODO restart STDI for Sync Channel 2 */
+                               /* enter one-shot mode */
+                               cp_write_and_or(sd, 0x86, 0xf9, 0x00);
+                               /* trigger STDI restart */
+                               cp_write_and_or(sd, 0x86, 0xf9, 0x04);
+                               /* reset to continuous mode */
+                               cp_write_and_or(sd, 0x86, 0xf9, 0x02);
+                               state->restart_stdi_once = false;
+                               return -ENOLINK;
+                       }
                        v4l2_dbg(1, debug, sd, "%s: format not supported\n", __func__);
                        return -ERANGE;
                }
+               state->restart_stdi_once = true;
        }
+found:
 
        if (debug > 1)
-               v4l2_print_dv_timings(sd->name, "adv7842_query_dv_timings: ",
-                                     timings, true);
+               v4l2_print_dv_timings(sd->name, "adv7842_query_dv_timings:",
+                               timings, true);
        return 0;
 }
 
@@ -1437,9 +1448,16 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd,
        struct v4l2_bt_timings *bt;
        int err;
 
+       v4l2_dbg(1, debug, sd, "%s:\n", __func__);
+
        if (state->mode == ADV7842_MODE_SDP)
                return -ENODATA;
 
+       if (v4l2_match_dv_timings(&state->timings, timings, 0)) {
+               v4l2_dbg(1, debug, sd, "%s: no change\n", __func__);
+               return 0;
+       }
+
        bt = &timings->bt;
 
        if (!v4l2_valid_dv_timings(timings, adv7842_get_dv_timings_cap(sd),
@@ -1450,7 +1468,7 @@ static int adv7842_s_dv_timings(struct v4l2_subdev *sd,
 
        state->timings = *timings;
 
-       cp_write(sd, 0x91, bt->interlaced ? 0x50 : 0x10);
+       cp_write(sd, 0x91, bt->interlaced ? 0x40 : 0x00);
 
        /* Use prim_mode and vid_std when available */
        err = configure_predefined_video_timings(sd, timings);
@@ -1483,18 +1501,18 @@ static int adv7842_g_dv_timings(struct v4l2_subdev *sd,
 static void enable_input(struct v4l2_subdev *sd)
 {
        struct adv7842_state *state = to_state(sd);
+
+       set_rgb_quantization_range(sd);
        switch (state->mode) {
        case ADV7842_MODE_SDP:
        case ADV7842_MODE_COMP:
        case ADV7842_MODE_RGB:
-               /* enable */
                io_write(sd, 0x15, 0xb0);   /* Disable Tristate of Pins (no audio) */
                break;
        case ADV7842_MODE_HDMI:
-               /* enable */
-               hdmi_write(sd, 0x1a, 0x0a); /* Unmute audio */
                hdmi_write(sd, 0x01, 0x00); /* Enable HDMI clock terminators */
                io_write(sd, 0x15, 0xa0);   /* Disable Tristate of Pins */
+               hdmi_write_and_or(sd, 0x1a, 0xef, 0x00); /* Unmute audio */
                break;
        default:
                v4l2_dbg(2, debug, sd, "%s: Unknown mode %d\n",
@@ -1505,9 +1523,9 @@ static void enable_input(struct v4l2_subdev *sd)
 
 static void disable_input(struct v4l2_subdev *sd)
 {
-       /* disable */
+       hdmi_write_and_or(sd, 0x1a, 0xef, 0x10); /* Mute audio [REF_01, c. 2.2.2] */
+       msleep(16); /* 512 samples with >= 32 kHz sample rate [REF_03, c. 8.29] */
        io_write(sd, 0x15, 0xbe);   /* Tristate all outputs from video core */
-       hdmi_write(sd, 0x1a, 0x1a); /* Mute audio */
        hdmi_write(sd, 0x01, 0x78); /* Disable HDMI clock terminators */
 }
 
@@ -1575,9 +1593,6 @@ static void select_input(struct v4l2_subdev *sd,
                afe_write(sd, 0x00, 0x00); /* power up ADC */
                afe_write(sd, 0xc8, 0x00); /* phase control */
 
-               io_write(sd, 0x19, 0x83); /* LLC DLL phase */
-               io_write(sd, 0x33, 0x40); /* LLC DLL enable */
-
                io_write(sd, 0xdd, 0x90); /* Manual 2x output clock */
                /* script says register 0xde, which don't exist in manual */
 
@@ -1611,8 +1626,6 @@ static void select_input(struct v4l2_subdev *sd,
                /* deinterlacer enabled and 3D comb */
                sdp_write_and_or(sd, 0x12, 0xf6, 0x09);
 
-               sdp_write(sd, 0xdd, 0x08); /* free run auto */
-
                break;
 
        case ADV7842_MODE_COMP:
@@ -1627,6 +1640,13 @@ static void select_input(struct v4l2_subdev *sd,
 
                afe_write(sd, 0x00, 0x00); /* power up ADC */
                afe_write(sd, 0xc8, 0x00); /* phase control */
+               if (state->mode == ADV7842_MODE_COMP) {
+                       /* force to YCrCb */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x60);
+               } else {
+                       /* force to RGB */
+                       io_write_and_or(sd, 0x02, 0x0f, 0x10);
+               }
 
                /* set ADI recommended settings for digitizer */
                /* "ADV7842 Register Settings Recommendations
@@ -1722,19 +1742,19 @@ static int adv7842_s_routing(struct v4l2_subdev *sd,
 
        switch (input) {
        case ADV7842_SELECT_HDMI_PORT_A:
-               /* TODO select HDMI_COMP or HDMI_GR */
                state->mode = ADV7842_MODE_HDMI;
                state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P;
                state->hdmi_port_a = true;
                break;
        case ADV7842_SELECT_HDMI_PORT_B:
-               /* TODO select HDMI_COMP or HDMI_GR */
                state->mode = ADV7842_MODE_HDMI;
                state->vid_std_select = ADV7842_HDMI_COMP_VID_STD_HD_1250P;
                state->hdmi_port_a = false;
                break;
        case ADV7842_SELECT_VGA_COMP:
-               v4l2_info(sd, "%s: VGA component: todo\n", __func__);
+               state->mode = ADV7842_MODE_COMP;
+               state->vid_std_select = ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE;
+               break;
        case ADV7842_SELECT_VGA_RGB:
                state->mode = ADV7842_MODE_RGB;
                state->vid_std_select = ADV7842_RGB_VID_STD_AUTO_GRAPH_MODE;
@@ -1814,12 +1834,15 @@ static void adv7842_irq_enable(struct v4l2_subdev *sd, bool enable)
                io_write(sd, 0x78, 0x03);
                /* Enable SDP Standard Detection Change and SDP Video Detected */
                io_write(sd, 0xa0, 0x09);
+               /* Enable HDMI_MODE interrupt */
+               io_write(sd, 0x69, 0x08);
        } else {
                io_write(sd, 0x46, 0x0);
                io_write(sd, 0x5a, 0x0);
                io_write(sd, 0x73, 0x0);
                io_write(sd, 0x78, 0x0);
                io_write(sd, 0xa0, 0x0);
+               io_write(sd, 0x69, 0x0);
        }
 }
 
@@ -1827,11 +1850,9 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
 {
        struct adv7842_state *state = to_state(sd);
        u8 fmt_change_cp, fmt_change_digital, fmt_change_sdp;
-       u8 irq_status[5];
-       u8 irq_cfg = io_read(sd, 0x40);
+       u8 irq_status[6];
 
-       /* disable irq-pin output */
-       io_write(sd, 0x40, irq_cfg | 0x3);
+       adv7842_irq_enable(sd, false);
 
        /* read status */
        irq_status[0] = io_read(sd, 0x43);
@@ -1839,6 +1860,7 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
        irq_status[2] = io_read(sd, 0x70);
        irq_status[3] = io_read(sd, 0x75);
        irq_status[4] = io_read(sd, 0x9d);
+       irq_status[5] = io_read(sd, 0x66);
 
        /* and clear */
        if (irq_status[0])
@@ -1851,10 +1873,14 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
                io_write(sd, 0x76, irq_status[3]);
        if (irq_status[4])
                io_write(sd, 0x9e, irq_status[4]);
+       if (irq_status[5])
+               io_write(sd, 0x67, irq_status[5]);
 
-       v4l2_dbg(1, debug, sd, "%s: irq %x, %x, %x, %x, %x\n", __func__,
+       adv7842_irq_enable(sd, true);
+
+       v4l2_dbg(1, debug, sd, "%s: irq %x, %x, %x, %x, %x, %x\n", __func__,
                 irq_status[0], irq_status[1], irq_status[2],
-                irq_status[3], irq_status[4]);
+                irq_status[3], irq_status[4], irq_status[5]);
 
        /* format change CP */
        fmt_change_cp = irq_status[0] & 0x9c;
@@ -1871,25 +1897,72 @@ static int adv7842_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
        else
                fmt_change_digital = 0;
 
-       /* notify */
+       /* format change */
        if (fmt_change_cp || fmt_change_digital || fmt_change_sdp) {
                v4l2_dbg(1, debug, sd,
                         "%s: fmt_change_cp = 0x%x, fmt_change_digital = 0x%x, fmt_change_sdp = 0x%x\n",
                         __func__, fmt_change_cp, fmt_change_digital,
                         fmt_change_sdp);
                v4l2_subdev_notify(sd, ADV7842_FMT_CHANGE, NULL);
+               if (handled)
+                       *handled = true;
        }
 
-       /* 5v cable detect */
-       if (irq_status[2])
+       /* HDMI/DVI mode */
+       if (irq_status[5] & 0x08) {
+               v4l2_dbg(1, debug, sd, "%s: irq %s mode\n", __func__,
+                        (io_read(sd, 0x65) & 0x08) ? "HDMI" : "DVI");
+               if (handled)
+                       *handled = true;
+       }
+
+       /* tx 5v detect */
+       if (irq_status[2] & 0x3) {
+               v4l2_dbg(1, debug, sd, "%s: irq tx_5v\n", __func__);
                adv7842_s_detect_tx_5v_ctrl(sd);
+               if (handled)
+                       *handled = true;
+       }
+       return 0;
+}
+
+static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *edid)
+{
+       struct adv7842_state *state = to_state(sd);
+       u8 *data = NULL;
 
-       if (handled)
-               *handled = true;
+       if (edid->pad > ADV7842_EDID_PORT_VGA)
+               return -EINVAL;
+       if (edid->blocks == 0)
+               return -EINVAL;
+       if (edid->blocks > 2)
+               return -EINVAL;
+       if (edid->start_block > 1)
+               return -EINVAL;
+       if (edid->start_block == 1)
+               edid->blocks = 1;
+       if (!edid->edid)
+               return -EINVAL;
 
-       /* re-enable irq-pin output */
-       io_write(sd, 0x40, irq_cfg);
+       switch (edid->pad) {
+       case ADV7842_EDID_PORT_A:
+       case ADV7842_EDID_PORT_B:
+               if (state->hdmi_edid.present & (0x04 << edid->pad))
+                       data = state->hdmi_edid.edid;
+               break;
+       case ADV7842_EDID_PORT_VGA:
+               if (state->vga_edid.present)
+                       data = state->vga_edid.edid;
+               break;
+       default:
+               return -EINVAL;
+       }
+       if (!data)
+               return -ENODATA;
 
+       memcpy(edid->edid,
+              data + edid->start_block * 128,
+              edid->blocks * 128);
        return 0;
 }
 
@@ -1898,7 +1971,7 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *e)
        struct adv7842_state *state = to_state(sd);
        int err = 0;
 
-       if (e->pad > 2)
+       if (e->pad > ADV7842_EDID_PORT_VGA)
                return -EINVAL;
        if (e->start_block != 0)
                return -EINVAL;
@@ -1911,20 +1984,25 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_subdev_edid *e)
        state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15],
                        e->edid[0x16]);
 
-       if (e->pad == 2) {
+       switch (e->pad) {
+       case ADV7842_EDID_PORT_VGA:
                memset(&state->vga_edid.edid, 0, 256);
                state->vga_edid.present = e->blocks ? 0x1 : 0x0;
                memcpy(&state->vga_edid.edid, e->edid, 128 * e->blocks);
                err = edid_write_vga_segment(sd);
-       } else {
-               u32 mask = 0x1<<e->pad;
+               break;
+       case ADV7842_EDID_PORT_A:
+       case ADV7842_EDID_PORT_B:
                memset(&state->hdmi_edid.edid, 0, 256);
                if (e->blocks)
-                       state->hdmi_edid.present |= mask;
+                       state->hdmi_edid.present |= 0x04 << e->pad;
                else
-                       state->hdmi_edid.present &= ~mask;
-               memcpy(&state->hdmi_edid.edid, e->edid, 128*e->blocks);
+                       state->hdmi_edid.present &= ~(0x04 << e->pad);
+               memcpy(&state->hdmi_edid.edid, e->edid, 128 * e->blocks);
                err = edid_write_hdmi_segment(sd, e->pad);
+               break;
+       default:
+               return -EINVAL;
        }
        if (err < 0)
                v4l2_err(sd, "error %d writing edid on port %d\n", err, e->pad);
@@ -2156,7 +2234,7 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd)
        static const char * const input_color_space_txt[16] = {
                "RGB limited range (16-235)", "RGB full range (0-255)",
                "YCbCr Bt.601 (16-235)", "YCbCr Bt.709 (16-235)",
-               "XvYCC Bt.601", "XvYCC Bt.709",
+               "xvYCC Bt.601", "xvYCC Bt.709",
                "YCbCr Bt.601 (0-255)", "YCbCr Bt.709 (0-255)",
                "invalid", "invalid", "invalid", "invalid", "invalid",
                "invalid", "invalid", "automatic"
@@ -2175,8 +2253,6 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd)
 
        v4l2_info(sd, "-----Chip status-----\n");
        v4l2_info(sd, "Chip power: %s\n", no_power(sd) ? "off" : "on");
-       v4l2_info(sd, "Connector type: %s\n", state->connector_hdmi ?
-                       "HDMI" : (is_digital_input(sd) ? "DVI-D" : "DVI-A"));
        v4l2_info(sd, "HDMI/DVI-D port selected: %s\n",
                        state->hdmi_port_a ? "A" : "B");
        v4l2_info(sd, "EDID A %s, B %s\n",
@@ -2354,15 +2430,63 @@ static int adv7842_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
        return 0;
 }
 
+static void adv7842_s_sdp_io(struct v4l2_subdev *sd, struct adv7842_sdp_io_sync_adjustment *s)
+{
+       if (s && s->adjust) {
+               sdp_io_write(sd, 0x94, (s->hs_beg >> 8) & 0xf);
+               sdp_io_write(sd, 0x95, s->hs_beg & 0xff);
+               sdp_io_write(sd, 0x96, (s->hs_width >> 8) & 0xf);
+               sdp_io_write(sd, 0x97, s->hs_width & 0xff);
+               sdp_io_write(sd, 0x98, (s->de_beg >> 8) & 0xf);
+               sdp_io_write(sd, 0x99, s->de_beg & 0xff);
+               sdp_io_write(sd, 0x9a, (s->de_end >> 8) & 0xf);
+               sdp_io_write(sd, 0x9b, s->de_end & 0xff);
+               sdp_io_write(sd, 0xa8, s->vs_beg_o);
+               sdp_io_write(sd, 0xa9, s->vs_beg_e);
+               sdp_io_write(sd, 0xaa, s->vs_end_o);
+               sdp_io_write(sd, 0xab, s->vs_end_e);
+               sdp_io_write(sd, 0xac, s->de_v_beg_o);
+               sdp_io_write(sd, 0xad, s->de_v_beg_e);
+               sdp_io_write(sd, 0xae, s->de_v_end_o);
+               sdp_io_write(sd, 0xaf, s->de_v_end_e);
+       } else {
+               /* set to default */
+               sdp_io_write(sd, 0x94, 0x00);
+               sdp_io_write(sd, 0x95, 0x00);
+               sdp_io_write(sd, 0x96, 0x00);
+               sdp_io_write(sd, 0x97, 0x20);
+               sdp_io_write(sd, 0x98, 0x00);
+               sdp_io_write(sd, 0x99, 0x00);
+               sdp_io_write(sd, 0x9a, 0x00);
+               sdp_io_write(sd, 0x9b, 0x00);
+               sdp_io_write(sd, 0xa8, 0x04);
+               sdp_io_write(sd, 0xa9, 0x04);
+               sdp_io_write(sd, 0xaa, 0x04);
+               sdp_io_write(sd, 0xab, 0x04);
+               sdp_io_write(sd, 0xac, 0x04);
+               sdp_io_write(sd, 0xad, 0x04);
+               sdp_io_write(sd, 0xae, 0x04);
+               sdp_io_write(sd, 0xaf, 0x04);
+       }
+}
+
 static int adv7842_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
 {
        struct adv7842_state *state = to_state(sd);
+       struct adv7842_platform_data *pdata = &state->pdata;
 
        v4l2_dbg(1, debug, sd, "%s:\n", __func__);
 
        if (state->mode != ADV7842_MODE_SDP)
                return -ENODATA;
 
+       if (norm & V4L2_STD_625_50)
+               adv7842_s_sdp_io(sd, &pdata->sdp_io_sync_625);
+       else if (norm & V4L2_STD_525_60)
+               adv7842_s_sdp_io(sd, &pdata->sdp_io_sync_525);
+       else
+               adv7842_s_sdp_io(sd, NULL);
+
        if (norm & V4L2_STD_ALL) {
                state->norm = norm;
                return 0;
@@ -2385,9 +2509,10 @@ static int adv7842_g_std(struct v4l2_subdev *sd, v4l2_std_id *norm)
 
 /* ----------------------------------------------------------------------- */
 
-static int adv7842_core_init(struct v4l2_subdev *sd,
-               const struct adv7842_platform_data *pdata)
+static int adv7842_core_init(struct v4l2_subdev *sd)
 {
+       struct adv7842_state *state = to_state(sd);
+       struct adv7842_platform_data *pdata = &state->pdata;
        hdmi_write(sd, 0x48,
                   (pdata->disable_pwrdnb ? 0x80 : 0) |
                   (pdata->disable_cable_det_rst ? 0x40 : 0));
@@ -2400,7 +2525,7 @@ static int adv7842_core_init(struct v4l2_subdev *sd,
 
        /* video format */
        io_write(sd, 0x02,
-                pdata->inp_color_space << 4 |
+                0xf0 |
                 pdata->alt_gamma << 3 |
                 pdata->op_656_range << 2 |
                 pdata->rgb_out << 1 |
@@ -2412,13 +2537,24 @@ static int adv7842_core_init(struct v4l2_subdev *sd,
                        pdata->replicate_av_codes << 1 |
                        pdata->invert_cbcr << 0);
 
+       /* HDMI audio */
+       hdmi_write_and_or(sd, 0x1a, 0xf1, 0x08); /* Wait 1 s before unmute */
+
        /* Drive strength */
-       io_write_and_or(sd, 0x14, 0xc0, pdata->drive_strength.data<<4 |
-                       pdata->drive_strength.clock<<2 |
-                       pdata->drive_strength.sync);
+       io_write_and_or(sd, 0x14, 0xc0,
+                       pdata->dr_str_data << 4 |
+                       pdata->dr_str_clk << 2 |
+                       pdata->dr_str_sync);
 
        /* HDMI free run */
-       cp_write(sd, 0xba, (pdata->hdmi_free_run_mode << 1) | 0x01);
+       cp_write_and_or(sd, 0xba, 0xfc, pdata->hdmi_free_run_enable |
+                                       (pdata->hdmi_free_run_mode << 1));
+
+       /* SPD free run */
+       sdp_write_and_or(sd, 0xdd, 0xf0, pdata->sdp_free_run_force |
+                                        (pdata->sdp_free_run_cbar_en << 1) |
+                                        (pdata->sdp_free_run_man_col_en << 2) |
+                                        (pdata->sdp_free_run_force << 3));
 
        /* TODO from platform data */
        cp_write(sd, 0x69, 0x14);   /* Enable CP CSC */
@@ -2431,18 +2567,6 @@ static int adv7842_core_init(struct v4l2_subdev *sd,
 
        sdp_csc_coeff(sd, &pdata->sdp_csc_coeff);
 
-       if (pdata->sdp_io_sync.adjust) {
-               const struct adv7842_sdp_io_sync_adjustment *s = &pdata->sdp_io_sync;
-               sdp_io_write(sd, 0x94, (s->hs_beg>>8) & 0xf);
-               sdp_io_write(sd, 0x95, s->hs_beg & 0xff);
-               sdp_io_write(sd, 0x96, (s->hs_width>>8) & 0xf);
-               sdp_io_write(sd, 0x97, s->hs_width & 0xff);
-               sdp_io_write(sd, 0x98, (s->de_beg>>8) & 0xf);
-               sdp_io_write(sd, 0x99, s->de_beg & 0xff);
-               sdp_io_write(sd, 0x9a, (s->de_end>>8) & 0xf);
-               sdp_io_write(sd, 0x9b, s->de_end & 0xff);
-       }
-
        /* todo, improve settings for sdram */
        if (pdata->sd_ram_size >= 128) {
                sdp_write(sd, 0x12, 0x0d); /* Frame TBC,3D comb enabled */
@@ -2483,12 +2607,11 @@ static int adv7842_core_init(struct v4l2_subdev *sd,
        io_write_and_or(sd, 0x20, 0xcf, 0x00);
 
        /* LLC */
-       /* Set phase to 16. TODO: get this from platform_data */
-       io_write(sd, 0x19, 0x90);
+       io_write(sd, 0x19, 0x80 | pdata->llc_dll_phase);
        io_write(sd, 0x33, 0x40);
 
        /* interrupts */
-       io_write(sd, 0x40, 0xe2); /* Configure INT1 */
+       io_write(sd, 0x40, 0xf2); /* Configure INT1 */
 
        adv7842_irq_enable(sd, true);
 
@@ -2588,6 +2711,7 @@ static int adv7842_command_ram_test(struct v4l2_subdev *sd)
        struct i2c_client *client = v4l2_get_subdevdata(sd);
        struct adv7842_state *state = to_state(sd);
        struct adv7842_platform_data *pdata = client->dev.platform_data;
+       struct v4l2_dv_timings timings;
        int ret = 0;
 
        if (!pdata)
@@ -2610,7 +2734,7 @@ static int adv7842_command_ram_test(struct v4l2_subdev *sd)
        adv7842_rewrite_i2c_addresses(sd, pdata);
 
        /* and re-init chip and state */
-       adv7842_core_init(sd, pdata);
+       adv7842_core_init(sd);
 
        disable_input(sd);
 
@@ -2618,11 +2742,15 @@ static int adv7842_command_ram_test(struct v4l2_subdev *sd)
 
        enable_input(sd);
 
-       adv7842_s_dv_timings(sd, &state->timings);
-
        edid_write_vga_segment(sd);
-       edid_write_hdmi_segment(sd, 0);
-       edid_write_hdmi_segment(sd, 1);
+       edid_write_hdmi_segment(sd, ADV7842_EDID_PORT_A);
+       edid_write_hdmi_segment(sd, ADV7842_EDID_PORT_B);
+
+       timings = state->timings;
+
+       memset(&state->timings, 0, sizeof(struct v4l2_dv_timings));
+
+       adv7842_s_dv_timings(sd, &timings);
 
        return ret;
 }
@@ -2670,6 +2798,7 @@ static const struct v4l2_subdev_video_ops adv7842_video_ops = {
 };
 
 static const struct v4l2_subdev_pad_ops adv7842_pad_ops = {
+       .get_edid = adv7842_get_edid,
        .set_edid = adv7842_set_edid,
 };
 
@@ -2712,8 +2841,9 @@ static const struct v4l2_ctrl_config adv7842_ctrl_free_run_color = {
 };
 
 
-static void adv7842_unregister_clients(struct adv7842_state *state)
+static void adv7842_unregister_clients(struct v4l2_subdev *sd)
 {
+       struct adv7842_state *state = to_state(sd);
        if (state->i2c_avlink)
                i2c_unregister_device(state->i2c_avlink);
        if (state->i2c_cec)
@@ -2736,21 +2866,79 @@ static void adv7842_unregister_clients(struct adv7842_state *state)
                i2c_unregister_device(state->i2c_cp);
        if (state->i2c_vdp)
                i2c_unregister_device(state->i2c_vdp);
+
+       state->i2c_avlink = NULL;
+       state->i2c_cec = NULL;
+       state->i2c_infoframe = NULL;
+       state->i2c_sdp_io = NULL;
+       state->i2c_sdp = NULL;
+       state->i2c_afe = NULL;
+       state->i2c_repeater = NULL;
+       state->i2c_edid = NULL;
+       state->i2c_hdmi = NULL;
+       state->i2c_cp = NULL;
+       state->i2c_vdp = NULL;
 }
 
-static struct i2c_client *adv7842_dummy_client(struct v4l2_subdev *sd,
+static struct i2c_client *adv7842_dummy_client(struct v4l2_subdev *sd, const char *desc,
                                               u8 addr, u8 io_reg)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
+       struct i2c_client *cp;
 
        io_write(sd, io_reg, addr << 1);
-       return i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1);
+
+       if (addr == 0) {
+               v4l2_err(sd, "no %s i2c addr configured\n", desc);
+               return NULL;
+       }
+
+       cp = i2c_new_dummy(client->adapter, io_read(sd, io_reg) >> 1);
+       if (!cp)
+               v4l2_err(sd, "register %s on i2c addr 0x%x failed\n", desc, addr);
+
+       return cp;
+}
+
+static int adv7842_register_clients(struct v4l2_subdev *sd)
+{
+       struct adv7842_state *state = to_state(sd);
+       struct adv7842_platform_data *pdata = &state->pdata;
+
+       state->i2c_avlink = adv7842_dummy_client(sd, "avlink", pdata->i2c_avlink, 0xf3);
+       state->i2c_cec = adv7842_dummy_client(sd, "cec", pdata->i2c_cec, 0xf4);
+       state->i2c_infoframe = adv7842_dummy_client(sd, "infoframe", pdata->i2c_infoframe, 0xf5);
+       state->i2c_sdp_io = adv7842_dummy_client(sd, "sdp_io", pdata->i2c_sdp_io, 0xf2);
+       state->i2c_sdp = adv7842_dummy_client(sd, "sdp", pdata->i2c_sdp, 0xf1);
+       state->i2c_afe = adv7842_dummy_client(sd, "afe", pdata->i2c_afe, 0xf8);
+       state->i2c_repeater = adv7842_dummy_client(sd, "repeater", pdata->i2c_repeater, 0xf9);
+       state->i2c_edid = adv7842_dummy_client(sd, "edid", pdata->i2c_edid, 0xfa);
+       state->i2c_hdmi = adv7842_dummy_client(sd, "hdmi", pdata->i2c_hdmi, 0xfb);
+       state->i2c_cp = adv7842_dummy_client(sd, "cp", pdata->i2c_cp, 0xfd);
+       state->i2c_vdp = adv7842_dummy_client(sd, "vdp", pdata->i2c_vdp, 0xfe);
+
+       if (!state->i2c_avlink ||
+           !state->i2c_cec ||
+           !state->i2c_infoframe ||
+           !state->i2c_sdp_io ||
+           !state->i2c_sdp ||
+           !state->i2c_afe ||
+           !state->i2c_repeater ||
+           !state->i2c_edid ||
+           !state->i2c_hdmi ||
+           !state->i2c_cp ||
+           !state->i2c_vdp)
+               return -1;
+
+       return 0;
 }
 
 static int adv7842_probe(struct i2c_client *client,
                         const struct i2c_device_id *id)
 {
        struct adv7842_state *state;
+       static const struct v4l2_dv_timings cea640x480 =
+               V4L2_DV_BT_CEA_640X480P59_94;
        struct adv7842_platform_data *pdata = client->dev.platform_data;
        struct v4l2_ctrl_handler *hdl;
        struct v4l2_subdev *sd;
@@ -2775,13 +2963,17 @@ static int adv7842_probe(struct i2c_client *client,
                return -ENOMEM;
        }
 
+       /* platform data */
+       state->pdata = *pdata;
+       state->timings = cea640x480;
+
        sd = &state->sd;
        v4l2_i2c_subdev_init(sd, client, &adv7842_ops);
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
-       state->connector_hdmi = pdata->connector_hdmi;
        state->mode = pdata->mode;
 
-       state->hdmi_port_a = true;
+       state->hdmi_port_a = pdata->input == ADV7842_SELECT_HDMI_PORT_A;
+       state->restart_stdi_once = true;
 
        /* i2c access to adv7842? */
        rev = adv_smbus_read_byte_data_check(client, 0xea, false) << 8 |
@@ -2843,21 +3035,7 @@ static int adv7842_probe(struct i2c_client *client,
                goto err_hdl;
        }
 
-       state->i2c_avlink = adv7842_dummy_client(sd, pdata->i2c_avlink, 0xf3);
-       state->i2c_cec = adv7842_dummy_client(sd, pdata->i2c_cec, 0xf4);
-       state->i2c_infoframe = adv7842_dummy_client(sd, pdata->i2c_infoframe, 0xf5);
-       state->i2c_sdp_io = adv7842_dummy_client(sd, pdata->i2c_sdp_io, 0xf2);
-       state->i2c_sdp = adv7842_dummy_client(sd, pdata->i2c_sdp, 0xf1);
-       state->i2c_afe = adv7842_dummy_client(sd, pdata->i2c_afe, 0xf8);
-       state->i2c_repeater = adv7842_dummy_client(sd, pdata->i2c_repeater, 0xf9);
-       state->i2c_edid = adv7842_dummy_client(sd, pdata->i2c_edid, 0xfa);
-       state->i2c_hdmi = adv7842_dummy_client(sd, pdata->i2c_hdmi, 0xfb);
-       state->i2c_cp = adv7842_dummy_client(sd, pdata->i2c_cp, 0xfd);
-       state->i2c_vdp = adv7842_dummy_client(sd, pdata->i2c_vdp, 0xfe);
-       if (!state->i2c_avlink || !state->i2c_cec || !state->i2c_infoframe ||
-           !state->i2c_sdp_io || !state->i2c_sdp || !state->i2c_afe ||
-           !state->i2c_repeater || !state->i2c_edid || !state->i2c_hdmi ||
-           !state->i2c_cp || !state->i2c_vdp) {
+       if (adv7842_register_clients(sd) < 0) {
                err = -ENOMEM;
                v4l2_err(sd, "failed to create all i2c clients\n");
                goto err_i2c;
@@ -2879,7 +3057,7 @@ static int adv7842_probe(struct i2c_client *client,
        if (err)
                goto err_work_queues;
 
-       err = adv7842_core_init(sd, pdata);
+       err = adv7842_core_init(sd);
        if (err)
                goto err_entity;
 
@@ -2893,7 +3071,7 @@ err_work_queues:
        cancel_delayed_work(&state->delayed_work_enable_hotplug);
        destroy_workqueue(state->work_queues);
 err_i2c:
-       adv7842_unregister_clients(state);
+       adv7842_unregister_clients(sd);
 err_hdl:
        v4l2_ctrl_handler_free(hdl);
        return err;
@@ -2912,7 +3090,7 @@ static int adv7842_remove(struct i2c_client *client)
        destroy_workqueue(state->work_queues);
        v4l2_device_unregister_subdev(sd);
        media_entity_cleanup(&sd->entity);
-       adv7842_unregister_clients(to_state(sd));
+       adv7842_unregister_clients(sd);
        v4l2_ctrl_handler_free(sd->ctrl_handler);
        return 0;
 }
index 3317a9ae3961fcf11dcf4cd97254654af608e1d5..d98ca3aebe235d7ae494ec2381ebe801899f6aa1 100644 (file)
@@ -172,28 +172,28 @@ static int lm3560_flash_brt_ctrl(struct lm3560_flash *flash,
 static int lm3560_get_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
 {
        struct lm3560_flash *flash = to_lm3560_flash(ctrl, led_no);
+       int rval = -EINVAL;
 
        mutex_lock(&flash->lock);
 
        if (ctrl->id == V4L2_CID_FLASH_FAULT) {
-               int rval;
                s32 fault = 0;
                unsigned int reg_val;
                rval = regmap_read(flash->regmap, REG_FLAG, &reg_val);
                if (rval < 0)
-                       return rval;
-               if (rval & FAULT_SHORT_CIRCUIT)
+                       goto out;
+               if (reg_val & FAULT_SHORT_CIRCUIT)
                        fault |= V4L2_FLASH_FAULT_SHORT_CIRCUIT;
-               if (rval & FAULT_OVERTEMP)
+               if (reg_val & FAULT_OVERTEMP)
                        fault |= V4L2_FLASH_FAULT_OVER_TEMPERATURE;
-               if (rval & FAULT_TIMEOUT)
+               if (reg_val & FAULT_TIMEOUT)
                        fault |= V4L2_FLASH_FAULT_TIMEOUT;
                ctrl->cur.val = fault;
-               return 0;
        }
 
+out:
        mutex_unlock(&flash->lock);
-       return -EINVAL;
+       return rval;
 }
 
 static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
@@ -219,15 +219,19 @@ static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
                break;
 
        case V4L2_CID_FLASH_STROBE:
-               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
-                       return -EBUSY;
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
+                       rval = -EBUSY;
+                       goto err_out;
+               }
                flash->led_mode = V4L2_FLASH_LED_MODE_FLASH;
                rval = lm3560_mode_ctrl(flash);
                break;
 
        case V4L2_CID_FLASH_STROBE_STOP:
-               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH)
-                       return -EBUSY;
+               if (flash->led_mode != V4L2_FLASH_LED_MODE_FLASH) {
+                       rval = -EBUSY;
+                       goto err_out;
+               }
                flash->led_mode = V4L2_FLASH_LED_MODE_NONE;
                rval = lm3560_mode_ctrl(flash);
                break;
@@ -247,8 +251,8 @@ static int lm3560_set_ctrl(struct v4l2_ctrl *ctrl, enum lm3560_led_id led_no)
                break;
        }
 
-       mutex_unlock(&flash->lock);
 err_out:
+       mutex_unlock(&flash->lock);
        return rval;
 }
 
@@ -444,14 +448,14 @@ static int lm3560_probe(struct i2c_client *client,
        if (rval < 0)
                return rval;
 
+       i2c_set_clientdata(client, flash);
+
        return 0;
 }
 
 static int lm3560_remove(struct i2c_client *client)
 {
-       struct v4l2_subdev *subdev = i2c_get_clientdata(client);
-       struct lm3560_flash *flash = container_of(subdev, struct lm3560_flash,
-                                                 subdev_led[LM3560_LED_MAX]);
+       struct lm3560_flash *flash = i2c_get_clientdata(client);
        unsigned int i;
 
        for (i = LM3560_LED0; i < LM3560_LED_MAX; i++) {
index 846b15f0bf6458d778ec731442e0e45107db179c..85ec3bacdf1c5e9b881bd726943ab3a6e85a375f 100644 (file)
@@ -459,13 +459,15 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
                          MT9M032_COLUMN_START_MAX);
        rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN,
                         MT9M032_ROW_START_MAX);
-       rect.width = clamp(ALIGN(crop->rect.width, 2), MT9M032_COLUMN_SIZE_MIN,
-                          MT9M032_COLUMN_SIZE_MAX);
-       rect.height = clamp(ALIGN(crop->rect.height, 2), MT9M032_ROW_SIZE_MIN,
-                           MT9M032_ROW_SIZE_MAX);
-
-       rect.width = min(rect.width, MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
-       rect.height = min(rect.height, MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
+       rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+                            MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX);
+       rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+                             MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX);
+
+       rect.width = min_t(unsigned int, rect.width,
+                          MT9M032_PIXEL_ARRAY_WIDTH - rect.left);
+       rect.height = min_t(unsigned int, rect.height,
+                           MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
 
        __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which);
 
index 1c2303d18bf49db242c00ac0cab8a474843c6db1..e5ddf47030fdd23b4aff11088847da08494bbb50 100644 (file)
@@ -519,11 +519,13 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
 
        /* Clamp the width and height to avoid dividing by zero. */
        width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
-                       max(__crop->width / 7, MT9P031_WINDOW_WIDTH_MIN),
+                       max_t(unsigned int, __crop->width / 7,
+                             MT9P031_WINDOW_WIDTH_MIN),
                        __crop->width);
        height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
-                       max(__crop->height / 8, MT9P031_WINDOW_HEIGHT_MIN),
-                       __crop->height);
+                        max_t(unsigned int, __crop->height / 8,
+                              MT9P031_WINDOW_HEIGHT_MIN),
+                        __crop->height);
 
        hratio = DIV_ROUND_CLOSEST(__crop->width, width);
        vratio = DIV_ROUND_CLOSEST(__crop->height, height);
@@ -565,15 +567,17 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev,
                          MT9P031_COLUMN_START_MAX);
        rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN,
                         MT9P031_ROW_START_MAX);
-       rect.width = clamp(ALIGN(crop->rect.width, 2),
-                          MT9P031_WINDOW_WIDTH_MIN,
-                          MT9P031_WINDOW_WIDTH_MAX);
-       rect.height = clamp(ALIGN(crop->rect.height, 2),
-                           MT9P031_WINDOW_HEIGHT_MIN,
-                           MT9P031_WINDOW_HEIGHT_MAX);
-
-       rect.width = min(rect.width, MT9P031_PIXEL_ARRAY_WIDTH - rect.left);
-       rect.height = min(rect.height, MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
+       rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+                            MT9P031_WINDOW_WIDTH_MIN,
+                            MT9P031_WINDOW_WIDTH_MAX);
+       rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+                             MT9P031_WINDOW_HEIGHT_MIN,
+                             MT9P031_WINDOW_HEIGHT_MAX);
+
+       rect.width = min_t(unsigned int, rect.width,
+                          MT9P031_PIXEL_ARRAY_WIDTH - rect.left);
+       rect.height = min_t(unsigned int, rect.height,
+                           MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
 
        __crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which);
 
index 796463466ef07ebd3707821c30c3bb5e0bdae427..d41c70eaf838b0b7ced8acc48c4609c522d0a3bb 100644 (file)
@@ -291,10 +291,12 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
 
        /* Clamp the width and height to avoid dividing by zero. */
        width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
-                       max(__crop->width / 8, MT9T001_WINDOW_HEIGHT_MIN + 1),
+                       max_t(unsigned int, __crop->width / 8,
+                             MT9T001_WINDOW_HEIGHT_MIN + 1),
                        __crop->width);
        height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
-                        max(__crop->height / 8, MT9T001_WINDOW_HEIGHT_MIN + 1),
+                        max_t(unsigned int, __crop->height / 8,
+                              MT9T001_WINDOW_HEIGHT_MIN + 1),
                         __crop->height);
 
        hratio = DIV_ROUND_CLOSEST(__crop->width, width);
@@ -339,15 +341,17 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev,
        rect.top = clamp(ALIGN(crop->rect.top, 2),
                         MT9T001_ROW_START_MIN,
                         MT9T001_ROW_START_MAX);
-       rect.width = clamp(ALIGN(crop->rect.width, 2),
-                          MT9T001_WINDOW_WIDTH_MIN + 1,
-                          MT9T001_WINDOW_WIDTH_MAX + 1);
-       rect.height = clamp(ALIGN(crop->rect.height, 2),
-                           MT9T001_WINDOW_HEIGHT_MIN + 1,
-                           MT9T001_WINDOW_HEIGHT_MAX + 1);
-
-       rect.width = min(rect.width, MT9T001_PIXEL_ARRAY_WIDTH - rect.left);
-       rect.height = min(rect.height, MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
+       rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+                            MT9T001_WINDOW_WIDTH_MIN + 1,
+                            MT9T001_WINDOW_WIDTH_MAX + 1);
+       rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+                             MT9T001_WINDOW_HEIGHT_MIN + 1,
+                             MT9T001_WINDOW_HEIGHT_MAX + 1);
+
+       rect.width = min_t(unsigned int, rect.width,
+                          MT9T001_PIXEL_ARRAY_WIDTH - rect.left);
+       rect.height = min_t(unsigned int, rect.height,
+                           MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
 
        __crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which);
 
index 2c50effaa33449d3430b5d06af570f164ac72f2b..36c504b78f2c6233b711fbe46a7c509aae7f101e 100644 (file)
 #include <media/v4l2-device.h>
 #include <media/v4l2-subdev.h>
 
-#define MT9V032_PIXEL_ARRAY_HEIGHT                     492
-#define MT9V032_PIXEL_ARRAY_WIDTH                      782
+/* The first four rows are black rows. The active area spans 753x481 pixels. */
+#define MT9V032_PIXEL_ARRAY_HEIGHT                     485
+#define MT9V032_PIXEL_ARRAY_WIDTH                      753
 
 #define MT9V032_SYSCLK_FREQ_DEF                                26600000
 
 #define MT9V032_CHIP_VERSION                           0x00
 #define                MT9V032_CHIP_ID_REV1                    0x1311
 #define                MT9V032_CHIP_ID_REV3                    0x1313
+#define                MT9V034_CHIP_ID_REV1                    0X1324
 #define MT9V032_COLUMN_START                           0x01
 #define                MT9V032_COLUMN_START_MIN                1
 #define                MT9V032_COLUMN_START_DEF                1
 #define                MT9V032_WINDOW_WIDTH_MAX                752
 #define MT9V032_HORIZONTAL_BLANKING                    0x05
 #define                MT9V032_HORIZONTAL_BLANKING_MIN         43
+#define                MT9V034_HORIZONTAL_BLANKING_MIN         61
 #define                MT9V032_HORIZONTAL_BLANKING_DEF         94
 #define                MT9V032_HORIZONTAL_BLANKING_MAX         1023
 #define MT9V032_VERTICAL_BLANKING                      0x06
 #define                MT9V032_VERTICAL_BLANKING_MIN           4
+#define                MT9V034_VERTICAL_BLANKING_MIN           2
 #define                MT9V032_VERTICAL_BLANKING_DEF           45
 #define                MT9V032_VERTICAL_BLANKING_MAX           3000
+#define                MT9V034_VERTICAL_BLANKING_MAX           32288
 #define MT9V032_CHIP_CONTROL                           0x07
 #define                MT9V032_CHIP_CONTROL_MASTER_MODE        (1 << 3)
 #define                MT9V032_CHIP_CONTROL_DOUT_ENABLE        (1 << 7)
 #define MT9V032_SHUTTER_WIDTH_CONTROL                  0x0a
 #define MT9V032_TOTAL_SHUTTER_WIDTH                    0x0b
 #define                MT9V032_TOTAL_SHUTTER_WIDTH_MIN         1
+#define                MT9V034_TOTAL_SHUTTER_WIDTH_MIN         0
 #define                MT9V032_TOTAL_SHUTTER_WIDTH_DEF         480
 #define                MT9V032_TOTAL_SHUTTER_WIDTH_MAX         32767
+#define                MT9V034_TOTAL_SHUTTER_WIDTH_MAX         32765
 #define MT9V032_RESET                                  0x0c
 #define MT9V032_READ_MODE                              0x0d
 #define                MT9V032_READ_MODE_ROW_BIN_MASK          (3 << 0)
@@ -81,6 +88,8 @@
 #define                MT9V032_READ_MODE_DARK_COLUMNS          (1 << 6)
 #define                MT9V032_READ_MODE_DARK_ROWS             (1 << 7)
 #define MT9V032_PIXEL_OPERATION_MODE                   0x0f
+#define                MT9V034_PIXEL_OPERATION_MODE_HDR        (1 << 0)
+#define                MT9V034_PIXEL_OPERATION_MODE_COLOR      (1 << 1)
 #define                MT9V032_PIXEL_OPERATION_MODE_COLOR      (1 << 2)
 #define                MT9V032_PIXEL_OPERATION_MODE_HDR        (1 << 6)
 #define MT9V032_ANALOG_GAIN                            0x35
 #define                MT9V032_DARK_AVG_HIGH_THRESH_MASK       (255 << 8)
 #define                MT9V032_DARK_AVG_HIGH_THRESH_SHIFT      8
 #define MT9V032_ROW_NOISE_CORR_CONTROL                 0x70
+#define                MT9V034_ROW_NOISE_CORR_ENABLE           (1 << 0)
+#define                MT9V034_ROW_NOISE_CORR_USE_BLK_AVG      (1 << 1)
 #define                MT9V032_ROW_NOISE_CORR_ENABLE           (1 << 5)
 #define                MT9V032_ROW_NOISE_CORR_USE_BLK_AVG      (1 << 7)
 #define MT9V032_PIXEL_CLOCK                            0x74
+#define MT9V034_PIXEL_CLOCK                            0x72
 #define                MT9V032_PIXEL_CLOCK_INV_LINE            (1 << 0)
 #define                MT9V032_PIXEL_CLOCK_INV_FRAME           (1 << 1)
 #define                MT9V032_PIXEL_CLOCK_XOR_LINE            (1 << 2)
 #define                MT9V032_AGC_ENABLE                      (1 << 1)
 #define MT9V032_THERMAL_INFO                           0xc1
 
+enum mt9v032_model {
+       MT9V032_MODEL_V032_COLOR,
+       MT9V032_MODEL_V032_MONO,
+       MT9V032_MODEL_V034_COLOR,
+       MT9V032_MODEL_V034_MONO,
+};
+
+struct mt9v032_model_version {
+       unsigned int version;
+       const char *name;
+};
+
+struct mt9v032_model_data {
+       unsigned int min_row_time;
+       unsigned int min_hblank;
+       unsigned int min_vblank;
+       unsigned int max_vblank;
+       unsigned int min_shutter;
+       unsigned int max_shutter;
+       unsigned int pclk_reg;
+};
+
+struct mt9v032_model_info {
+       const struct mt9v032_model_data *data;
+       bool color;
+};
+
+static const struct mt9v032_model_version mt9v032_versions[] = {
+       { MT9V032_CHIP_ID_REV1, "MT9V032 rev1/2" },
+       { MT9V032_CHIP_ID_REV3, "MT9V032 rev3" },
+       { MT9V034_CHIP_ID_REV1, "MT9V034 rev1" },
+};
+
+static const struct mt9v032_model_data mt9v032_model_data[] = {
+       {
+               /* MT9V032 revisions 1/2/3 */
+               .min_row_time = 660,
+               .min_hblank = MT9V032_HORIZONTAL_BLANKING_MIN,
+               .min_vblank = MT9V032_VERTICAL_BLANKING_MIN,
+               .max_vblank = MT9V032_VERTICAL_BLANKING_MAX,
+               .min_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
+               .max_shutter = MT9V032_TOTAL_SHUTTER_WIDTH_MAX,
+               .pclk_reg = MT9V032_PIXEL_CLOCK,
+       }, {
+               /* MT9V034 */
+               .min_row_time = 690,
+               .min_hblank = MT9V034_HORIZONTAL_BLANKING_MIN,
+               .min_vblank = MT9V034_VERTICAL_BLANKING_MIN,
+               .max_vblank = MT9V034_VERTICAL_BLANKING_MAX,
+               .min_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MIN,
+               .max_shutter = MT9V034_TOTAL_SHUTTER_WIDTH_MAX,
+               .pclk_reg = MT9V034_PIXEL_CLOCK,
+       },
+};
+
+static const struct mt9v032_model_info mt9v032_models[] = {
+       [MT9V032_MODEL_V032_COLOR] = {
+               .data = &mt9v032_model_data[0],
+               .color = true,
+       },
+       [MT9V032_MODEL_V032_MONO] = {
+               .data = &mt9v032_model_data[0],
+               .color = false,
+       },
+       [MT9V032_MODEL_V034_COLOR] = {
+               .data = &mt9v032_model_data[1],
+               .color = true,
+       },
+       [MT9V032_MODEL_V034_MONO] = {
+               .data = &mt9v032_model_data[1],
+               .color = false,
+       },
+};
+
 struct mt9v032 {
        struct v4l2_subdev subdev;
        struct media_pad pad;
 
        struct v4l2_mbus_framefmt format;
        struct v4l2_rect crop;
+       unsigned int hratio;
+       unsigned int vratio;
 
        struct v4l2_ctrl_handler ctrls;
        struct {
@@ -139,6 +227,8 @@ struct mt9v032 {
        struct clk *clk;
 
        struct mt9v032_platform_data *pdata;
+       const struct mt9v032_model_info *model;
+       const struct mt9v032_model_version *version;
 
        u32 sysclk;
        u16 chip_control;
@@ -210,12 +300,17 @@ mt9v032_update_hblank(struct mt9v032 *mt9v032)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
        struct v4l2_rect *crop = &mt9v032->crop;
+       unsigned int min_hblank = mt9v032->model->data->min_hblank;
+       unsigned int hblank;
 
-       return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING,
-                            max_t(s32, mt9v032->hblank, 660 - crop->width));
-}
+       if (mt9v032->version->version == MT9V034_CHIP_ID_REV1)
+               min_hblank += (mt9v032->hratio - 1) * 10;
+       min_hblank = max_t(unsigned int, (int)mt9v032->model->data->min_row_time - crop->width,
+                          (int)min_hblank);
+       hblank = max_t(unsigned int, mt9v032->hblank, min_hblank);
 
-#define EXT_CLK                25000000
+       return mt9v032_write(client, MT9V032_HORIZONTAL_BLANKING, hblank);
+}
 
 static int mt9v032_power_on(struct mt9v032 *mt9v032)
 {
@@ -259,7 +354,7 @@ static int __mt9v032_set_power(struct mt9v032 *mt9v032, bool on)
 
        /* Configure the pixel clock polarity */
        if (mt9v032->pdata && mt9v032->pdata->clk_pol) {
-               ret = mt9v032_write(client, MT9V032_PIXEL_CLOCK,
+               ret = mt9v032_write(client, mt9v032->model->data->pclk_reg,
                                MT9V032_PIXEL_CLOCK_INV_PXL_CLK);
                if (ret < 0)
                        return ret;
@@ -312,22 +407,20 @@ static int mt9v032_s_stream(struct v4l2_subdev *subdev, int enable)
                       | MT9V032_CHIP_CONTROL_SEQUENTIAL;
        struct i2c_client *client = v4l2_get_subdevdata(subdev);
        struct mt9v032 *mt9v032 = to_mt9v032(subdev);
-       struct v4l2_mbus_framefmt *format = &mt9v032->format;
        struct v4l2_rect *crop = &mt9v032->crop;
-       unsigned int hratio;
-       unsigned int vratio;
+       unsigned int hbin;
+       unsigned int vbin;
        int ret;
 
        if (!enable)
                return mt9v032_set_chip_control(mt9v032, mode, 0);
 
        /* Configure the window size and row/column bin */
-       hratio = DIV_ROUND_CLOSEST(crop->width, format->width);
-       vratio = DIV_ROUND_CLOSEST(crop->height, format->height);
-
+       hbin = fls(mt9v032->hratio) - 1;
+       vbin = fls(mt9v032->vratio) - 1;
        ret = mt9v032_write(client, MT9V032_READ_MODE,
-                   (hratio - 1) << MT9V032_READ_MODE_ROW_BIN_SHIFT |
-                   (vratio - 1) << MT9V032_READ_MODE_COLUMN_BIN_SHIFT);
+                           hbin << MT9V032_READ_MODE_COLUMN_BIN_SHIFT |
+                           vbin << MT9V032_READ_MODE_ROW_BIN_SHIFT);
        if (ret < 0)
                return ret;
 
@@ -370,12 +463,12 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
                                   struct v4l2_subdev_fh *fh,
                                   struct v4l2_subdev_frame_size_enum *fse)
 {
-       if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+       if (fse->index >= 3 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
                return -EINVAL;
 
-       fse->min_width = MT9V032_WINDOW_WIDTH_DEF / fse->index;
+       fse->min_width = MT9V032_WINDOW_WIDTH_DEF / (1 << fse->index);
        fse->max_width = fse->min_width;
-       fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / fse->index;
+       fse->min_height = MT9V032_WINDOW_HEIGHT_DEF / (1 << fse->index);
        fse->max_height = fse->min_height;
 
        return 0;
@@ -392,18 +485,30 @@ static int mt9v032_get_format(struct v4l2_subdev *subdev,
        return 0;
 }
 
-static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032,
-                                        unsigned int hratio)
+static void mt9v032_configure_pixel_rate(struct mt9v032 *mt9v032)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&mt9v032->subdev);
        int ret;
 
        ret = v4l2_ctrl_s_ctrl_int64(mt9v032->pixel_rate,
-                                    mt9v032->sysclk / hratio);
+                                    mt9v032->sysclk / mt9v032->hratio);
        if (ret < 0)
                dev_warn(&client->dev, "failed to set pixel rate (%d)\n", ret);
 }
 
+static unsigned int mt9v032_calc_ratio(unsigned int input, unsigned int output)
+{
+       /* Compute the power-of-two binning factor closest to the input size to
+        * output size ratio. Given that the output size is bounded by input/4
+        * and input, a generic implementation would be an ineffective luxury.
+        */
+       if (output * 3 > input * 2)
+               return 1;
+       if (output * 3 > input)
+               return 2;
+       return 4;
+}
+
 static int mt9v032_set_format(struct v4l2_subdev *subdev,
                              struct v4l2_subdev_fh *fh,
                              struct v4l2_subdev_format *format)
@@ -420,22 +525,28 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
                                        format->which);
 
        /* Clamp the width and height to avoid dividing by zero. */
-       width = clamp_t(unsigned int, ALIGN(format->format.width, 2),
-                       max(__crop->width / 8, MT9V032_WINDOW_WIDTH_MIN),
-                       __crop->width);
-       height = clamp_t(unsigned int, ALIGN(format->format.height, 2),
-                        max(__crop->height / 8, MT9V032_WINDOW_HEIGHT_MIN),
-                        __crop->height);
-
-       hratio = DIV_ROUND_CLOSEST(__crop->width, width);
-       vratio = DIV_ROUND_CLOSEST(__crop->height, height);
+       width = clamp(ALIGN(format->format.width, 2),
+                     max_t(unsigned int, __crop->width / 4,
+                           MT9V032_WINDOW_WIDTH_MIN),
+                     __crop->width);
+       height = clamp(ALIGN(format->format.height, 2),
+                      max_t(unsigned int, __crop->height / 4,
+                            MT9V032_WINDOW_HEIGHT_MIN),
+                      __crop->height);
+
+       hratio = mt9v032_calc_ratio(__crop->width, width);
+       vratio = mt9v032_calc_ratio(__crop->height, height);
 
        __format = __mt9v032_get_pad_format(mt9v032, fh, format->pad,
                                            format->which);
        __format->width = __crop->width / hratio;
        __format->height = __crop->height / vratio;
-       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-               mt9v032_configure_pixel_rate(mt9v032, hratio);
+
+       if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+               mt9v032->hratio = hratio;
+               mt9v032->vratio = vratio;
+               mt9v032_configure_pixel_rate(mt9v032);
+       }
 
        format->format = *__format;
 
@@ -471,15 +582,17 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
        rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1,
                         MT9V032_ROW_START_MIN,
                         MT9V032_ROW_START_MAX);
-       rect.width = clamp(ALIGN(crop->rect.width, 2),
-                          MT9V032_WINDOW_WIDTH_MIN,
-                          MT9V032_WINDOW_WIDTH_MAX);
-       rect.height = clamp(ALIGN(crop->rect.height, 2),
-                           MT9V032_WINDOW_HEIGHT_MIN,
-                           MT9V032_WINDOW_HEIGHT_MAX);
-
-       rect.width = min(rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
-       rect.height = min(rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
+       rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+                            MT9V032_WINDOW_WIDTH_MIN,
+                            MT9V032_WINDOW_WIDTH_MAX);
+       rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+                             MT9V032_WINDOW_HEIGHT_MIN,
+                             MT9V032_WINDOW_HEIGHT_MAX);
+
+       rect.width = min_t(unsigned int,
+                          rect.width, MT9V032_PIXEL_ARRAY_WIDTH - rect.left);
+       rect.height = min_t(unsigned int,
+                           rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
 
        __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
 
@@ -491,8 +604,11 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
                                                    crop->which);
                __format->width = rect.width;
                __format->height = rect.height;
-               if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
-                       mt9v032_configure_pixel_rate(mt9v032, 1);
+               if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+                       mt9v032->hratio = 1;
+                       mt9v032->vratio = 1;
+                       mt9v032_configure_pixel_rate(mt9v032);
+               }
        }
 
        *__crop = rect;
@@ -641,7 +757,8 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
 {
        struct i2c_client *client = v4l2_get_subdevdata(subdev);
        struct mt9v032 *mt9v032 = to_mt9v032(subdev);
-       s32 data;
+       unsigned int i;
+       s32 version;
        int ret;
 
        dev_info(&client->dev, "Probing MT9V032 at address 0x%02x\n",
@@ -654,25 +771,38 @@ static int mt9v032_registered(struct v4l2_subdev *subdev)
        }
 
        /* Read and check the sensor version */
-       data = mt9v032_read(client, MT9V032_CHIP_VERSION);
-       if (data != MT9V032_CHIP_ID_REV1 && data != MT9V032_CHIP_ID_REV3) {
-               dev_err(&client->dev, "MT9V032 not detected, wrong version "
-                               "0x%04x\n", data);
+       version = mt9v032_read(client, MT9V032_CHIP_VERSION);
+       if (version < 0) {
+               dev_err(&client->dev, "Failed reading chip version\n");
+               return version;
+       }
+
+       for (i = 0; i < ARRAY_SIZE(mt9v032_versions); ++i) {
+               if (mt9v032_versions[i].version == version) {
+                       mt9v032->version = &mt9v032_versions[i];
+                       break;
+               }
+       }
+
+       if (mt9v032->version == NULL) {
+               dev_err(&client->dev, "Unsupported chip version 0x%04x\n",
+                       version);
                return -ENODEV;
        }
 
        mt9v032_power_off(mt9v032);
 
-       dev_info(&client->dev, "MT9V032 detected at address 0x%02x\n",
-                       client->addr);
+       dev_info(&client->dev, "%s detected at address 0x%02x\n",
+                mt9v032->version->name, client->addr);
 
-       mt9v032_configure_pixel_rate(mt9v032, 1);
+       mt9v032_configure_pixel_rate(mt9v032);
 
        return ret;
 }
 
 static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
 {
+       struct mt9v032 *mt9v032 = to_mt9v032(subdev);
        struct v4l2_mbus_framefmt *format;
        struct v4l2_rect *crop;
 
@@ -683,7 +813,12 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
        crop->height = MT9V032_WINDOW_HEIGHT_DEF;
 
        format = v4l2_subdev_get_try_format(fh, 0);
-       format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+       if (mt9v032->model->color)
+               format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       else
+               format->code = V4L2_MBUS_FMT_Y10_1X10;
+
        format->width = MT9V032_WINDOW_WIDTH_DEF;
        format->height = MT9V032_WINDOW_HEIGHT_DEF;
        format->field = V4L2_FIELD_NONE;
@@ -755,6 +890,7 @@ static int mt9v032_probe(struct i2c_client *client,
 
        mutex_init(&mt9v032->power_lock);
        mt9v032->pdata = pdata;
+       mt9v032->model = (const void *)did->driver_data;
 
        v4l2_ctrl_handler_init(&mt9v032->ctrls, 10);
 
@@ -767,16 +903,16 @@ static int mt9v032_probe(struct i2c_client *client,
                               V4L2_CID_EXPOSURE_AUTO, V4L2_EXPOSURE_MANUAL, 0,
                               V4L2_EXPOSURE_AUTO);
        v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
-                         V4L2_CID_EXPOSURE, MT9V032_TOTAL_SHUTTER_WIDTH_MIN,
-                         MT9V032_TOTAL_SHUTTER_WIDTH_MAX, 1,
+                         V4L2_CID_EXPOSURE, mt9v032->model->data->min_shutter,
+                         mt9v032->model->data->max_shutter, 1,
                          MT9V032_TOTAL_SHUTTER_WIDTH_DEF);
        v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
-                         V4L2_CID_HBLANK, MT9V032_HORIZONTAL_BLANKING_MIN,
+                         V4L2_CID_HBLANK, mt9v032->model->data->min_hblank,
                          MT9V032_HORIZONTAL_BLANKING_MAX, 1,
                          MT9V032_HORIZONTAL_BLANKING_DEF);
        v4l2_ctrl_new_std(&mt9v032->ctrls, &mt9v032_ctrl_ops,
-                         V4L2_CID_VBLANK, MT9V032_VERTICAL_BLANKING_MIN,
-                         MT9V032_VERTICAL_BLANKING_MAX, 1,
+                         V4L2_CID_VBLANK, mt9v032->model->data->min_vblank,
+                         mt9v032->model->data->max_vblank, 1,
                          MT9V032_VERTICAL_BLANKING_DEF);
        mt9v032->test_pattern = v4l2_ctrl_new_std_menu_items(&mt9v032->ctrls,
                                &mt9v032_ctrl_ops, V4L2_CID_TEST_PATTERN,
@@ -819,12 +955,19 @@ static int mt9v032_probe(struct i2c_client *client,
        mt9v032->crop.width = MT9V032_WINDOW_WIDTH_DEF;
        mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
 
-       mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       if (mt9v032->model->color)
+               mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       else
+               mt9v032->format.code = V4L2_MBUS_FMT_Y10_1X10;
+
        mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
        mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
        mt9v032->format.field = V4L2_FIELD_NONE;
        mt9v032->format.colorspace = V4L2_COLORSPACE_SRGB;
 
+       mt9v032->hratio = 1;
+       mt9v032->vratio = 1;
+
        mt9v032->aec_agc = MT9V032_AEC_ENABLE | MT9V032_AGC_ENABLE;
        mt9v032->hblank = MT9V032_HORIZONTAL_BLANKING_DEF;
        mt9v032->sysclk = MT9V032_SYSCLK_FREQ_DEF;
@@ -855,7 +998,10 @@ static int mt9v032_remove(struct i2c_client *client)
 }
 
 static const struct i2c_device_id mt9v032_id[] = {
-       { "mt9v032", 0 },
+       { "mt9v032", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_COLOR] },
+       { "mt9v032m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V032_MONO] },
+       { "mt9v034", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_COLOR] },
+       { "mt9v034m", (kernel_ulong_t)&mt9v032_models[MT9V032_MODEL_V034_MONO] },
        { }
 };
 MODULE_DEVICE_TABLE(i2c, mt9v032_id);
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
new file mode 100644 (file)
index 0000000..4b83811
--- /dev/null
@@ -0,0 +1,2045 @@
+/*
+ * Driver for Samsung S5K5BAF UXGA 1/5" 2M CMOS Image Sensor
+ * with embedded SoC ISP.
+ *
+ * Copyright (C) 2013, Samsung Electronics Co., Ltd.
+ * Andrzej Hajda <a.hajda@samsung.com>
+ *
+ * Based on S5K6AA driver authored by Sylwester Nawrocki
+ * Copyright (C) 2013, Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/media.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-of.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define S5K5BAF_DRIVER_NAME            "s5k5baf"
+#define S5K5BAF_DEFAULT_MCLK_FREQ      24000000U
+#define S5K5BAF_CLK_NAME               "mclk"
+
+#define S5K5BAF_FW_FILENAME            "s5k5baf-cfg.bin"
+#define S5K5BAF_FW_TAG                 "SF00"
+#define S5K5BAG_FW_TAG_LEN             2
+#define S5K5BAG_FW_MAX_COUNT           16
+
+#define S5K5BAF_CIS_WIDTH              1600
+#define S5K5BAF_CIS_HEIGHT             1200
+#define S5K5BAF_WIN_WIDTH_MIN          8
+#define S5K5BAF_WIN_HEIGHT_MIN         8
+#define S5K5BAF_GAIN_RED_DEF           127
+#define S5K5BAF_GAIN_GREEN_DEF         95
+#define S5K5BAF_GAIN_BLUE_DEF          180
+/* Default number of MIPI CSI-2 data lanes used */
+#define S5K5BAF_DEF_NUM_LANES          1
+
+#define AHB_MSB_ADDR_PTR               0xfcfc
+
+/*
+ * Register interface pages (the most significant word of the address)
+ */
+#define PAGE_IF_HW                     0xd000
+#define PAGE_IF_SW                     0x7000
+
+/*
+ * H/W register Interface (PAGE_IF_HW)
+ */
+#define REG_SW_LOAD_COMPLETE           0x0014
+#define REG_CMDWR_PAGE                 0x0028
+#define REG_CMDWR_ADDR                 0x002a
+#define REG_CMDRD_PAGE                 0x002c
+#define REG_CMDRD_ADDR                 0x002e
+#define REG_CMD_BUF                    0x0f12
+#define REG_SET_HOST_INT               0x1000
+#define REG_CLEAR_HOST_INT             0x1030
+#define REG_PATTERN_SET                        0x3100
+#define REG_PATTERN_WIDTH              0x3118
+#define REG_PATTERN_HEIGHT             0x311a
+#define REG_PATTERN_PARAM              0x311c
+
+/*
+ * S/W register interface (PAGE_IF_SW)
+ */
+
+/* Firmware revision information */
+#define REG_FW_APIVER                  0x012e
+#define  S5K5BAF_FW_APIVER             0x0001
+#define REG_FW_REVISION                        0x0130
+#define REG_FW_SENSOR_ID               0x0152
+
+/* Initialization parameters */
+/* Master clock frequency in KHz */
+#define REG_I_INCLK_FREQ_L             0x01b8
+#define REG_I_INCLK_FREQ_H             0x01ba
+#define  MIN_MCLK_FREQ_KHZ             6000U
+#define  MAX_MCLK_FREQ_KHZ             48000U
+#define REG_I_USE_NPVI_CLOCKS          0x01c6
+#define  NPVI_CLOCKS                   1
+#define REG_I_USE_NMIPI_CLOCKS         0x01c8
+#define  NMIPI_CLOCKS                  1
+#define REG_I_BLOCK_INTERNAL_PLL_CALC  0x01ca
+
+/* Clock configurations, n = 0..2. REG_I_* frequency unit is 4 kHz. */
+#define REG_I_OPCLK_4KHZ(n)            ((n) * 6 + 0x01cc)
+#define REG_I_MIN_OUTRATE_4KHZ(n)      ((n) * 6 + 0x01ce)
+#define REG_I_MAX_OUTRATE_4KHZ(n)      ((n) * 6 + 0x01d0)
+#define  SCLK_PVI_FREQ                 24000
+#define  SCLK_MIPI_FREQ                        48000
+#define  PCLK_MIN_FREQ                 6000
+#define  PCLK_MAX_FREQ                 48000
+#define REG_I_USE_REGS_API             0x01de
+#define REG_I_INIT_PARAMS_UPDATED      0x01e0
+#define REG_I_ERROR_INFO               0x01e2
+
+/* General purpose parameters */
+#define REG_USER_BRIGHTNESS            0x01e4
+#define REG_USER_CONTRAST              0x01e6
+#define REG_USER_SATURATION            0x01e8
+#define REG_USER_SHARPBLUR             0x01ea
+
+#define REG_G_SPEC_EFFECTS             0x01ee
+#define REG_G_ENABLE_PREV              0x01f0
+#define REG_G_ENABLE_PREV_CHG          0x01f2
+#define REG_G_NEW_CFG_SYNC             0x01f8
+#define REG_G_PREVREQ_IN_WIDTH         0x01fa
+#define REG_G_PREVREQ_IN_HEIGHT                0x01fc
+#define REG_G_PREVREQ_IN_XOFFS         0x01fe
+#define REG_G_PREVREQ_IN_YOFFS         0x0200
+#define REG_G_PREVZOOM_IN_WIDTH                0x020a
+#define REG_G_PREVZOOM_IN_HEIGHT       0x020c
+#define REG_G_PREVZOOM_IN_XOFFS                0x020e
+#define REG_G_PREVZOOM_IN_YOFFS                0x0210
+#define REG_G_INPUTS_CHANGE_REQ                0x021a
+#define REG_G_ACTIVE_PREV_CFG          0x021c
+#define REG_G_PREV_CFG_CHG             0x021e
+#define REG_G_PREV_OPEN_AFTER_CH       0x0220
+#define REG_G_PREV_CFG_ERROR           0x0222
+#define  CFG_ERROR_RANGE               0x0b
+#define REG_G_PREV_CFG_BYPASS_CHANGED  0x022a
+#define REG_G_ACTUAL_P_FR_TIME         0x023a
+#define REG_G_ACTUAL_P_OUT_RATE                0x023c
+#define REG_G_ACTUAL_C_FR_TIME         0x023e
+#define REG_G_ACTUAL_C_OUT_RATE                0x0240
+
+/* Preview control section. n = 0...4. */
+#define PREG(n, x)                     ((n) * 0x26 + x)
+#define REG_P_OUT_WIDTH(n)             PREG(n, 0x0242)
+#define REG_P_OUT_HEIGHT(n)            PREG(n, 0x0244)
+#define REG_P_FMT(n)                   PREG(n, 0x0246)
+#define REG_P_MAX_OUT_RATE(n)          PREG(n, 0x0248)
+#define REG_P_MIN_OUT_RATE(n)          PREG(n, 0x024a)
+#define REG_P_PVI_MASK(n)              PREG(n, 0x024c)
+#define  PVI_MASK_MIPI                 0x52
+#define REG_P_CLK_INDEX(n)             PREG(n, 0x024e)
+#define  CLK_PVI_INDEX                 0
+#define  CLK_MIPI_INDEX                        NPVI_CLOCKS
+#define REG_P_FR_RATE_TYPE(n)          PREG(n, 0x0250)
+#define  FR_RATE_DYNAMIC               0
+#define  FR_RATE_FIXED                 1
+#define  FR_RATE_FIXED_ACCURATE                2
+#define REG_P_FR_RATE_Q_TYPE(n)                PREG(n, 0x0252)
+#define  FR_RATE_Q_DYNAMIC             0
+#define  FR_RATE_Q_BEST_FRRATE         1 /* Binning enabled */
+#define  FR_RATE_Q_BEST_QUALITY                2 /* Binning disabled */
+/* Frame period in 0.1 ms units */
+#define REG_P_MAX_FR_TIME(n)           PREG(n, 0x0254)
+#define REG_P_MIN_FR_TIME(n)           PREG(n, 0x0256)
+#define  S5K5BAF_MIN_FR_TIME           333  /* x100 us */
+#define  S5K5BAF_MAX_FR_TIME           6500 /* x100 us */
+/* The below 5 registers are for "device correction" values */
+#define REG_P_SATURATION(n)            PREG(n, 0x0258)
+#define REG_P_SHARP_BLUR(n)            PREG(n, 0x025a)
+#define REG_P_GLAMOUR(n)               PREG(n, 0x025c)
+#define REG_P_COLORTEMP(n)             PREG(n, 0x025e)
+#define REG_P_GAMMA_INDEX(n)           PREG(n, 0x0260)
+#define REG_P_PREV_MIRROR(n)           PREG(n, 0x0262)
+#define REG_P_CAP_MIRROR(n)            PREG(n, 0x0264)
+#define REG_P_CAP_ROTATION(n)          PREG(n, 0x0266)
+
+/* Extended image property controls */
+/* Exposure time in 10 us units */
+#define REG_SF_USR_EXPOSURE_L          0x03bc
+#define REG_SF_USR_EXPOSURE_H          0x03be
+#define REG_SF_USR_EXPOSURE_CHG                0x03c0
+#define REG_SF_USR_TOT_GAIN            0x03c2
+#define REG_SF_USR_TOT_GAIN_CHG                0x03c4
+#define REG_SF_RGAIN                   0x03c6
+#define REG_SF_RGAIN_CHG               0x03c8
+#define REG_SF_GGAIN                   0x03ca
+#define REG_SF_GGAIN_CHG               0x03cc
+#define REG_SF_BGAIN                   0x03ce
+#define REG_SF_BGAIN_CHG               0x03d0
+#define REG_SF_WBGAIN_CHG              0x03d2
+#define REG_SF_FLICKER_QUANT           0x03d4
+#define REG_SF_FLICKER_QUANT_CHG       0x03d6
+
+/* Output interface (parallel/MIPI) setup */
+#define REG_OIF_EN_MIPI_LANES          0x03f2
+#define REG_OIF_EN_PACKETS             0x03f4
+#define  EN_PACKETS_CSI2               0xc3
+#define REG_OIF_CFG_CHG                        0x03f6
+
+/* Auto-algorithms enable mask */
+#define REG_DBG_AUTOALG_EN             0x03f8
+#define  AALG_ALL_EN                   BIT(0)
+#define  AALG_AE_EN                    BIT(1)
+#define  AALG_DIVLEI_EN                        BIT(2)
+#define  AALG_WB_EN                    BIT(3)
+#define  AALG_USE_WB_FOR_ISP           BIT(4)
+#define  AALG_FLICKER_EN               BIT(5)
+#define  AALG_FIT_EN                   BIT(6)
+#define  AALG_WRHW_EN                  BIT(7)
+
+/* Pointers to color correction matrices */
+#define REG_PTR_CCM_HORIZON            0x06d0
+#define REG_PTR_CCM_INCANDESCENT       0x06d4
+#define REG_PTR_CCM_WARM_WHITE         0x06d8
+#define REG_PTR_CCM_COOL_WHITE         0x06dc
+#define REG_PTR_CCM_DL50               0x06e0
+#define REG_PTR_CCM_DL65               0x06e4
+#define REG_PTR_CCM_OUTDOOR            0x06ec
+
+#define REG_ARR_CCM(n)                 (0x2800 + 36 * (n))
+
+static const char * const s5k5baf_supply_names[] = {
+       "vdda",         /* Analog power supply 2.8V (2.6V to 3.0V) */
+       "vddreg",       /* Regulator input power supply 1.8V (1.7V to 1.9V)
+                          or 2.8V (2.6V to 3.0) */
+       "vddio",        /* I/O power supply 1.8V (1.65V to 1.95V)
+                          or 2.8V (2.5V to 3.1V) */
+};
+#define S5K5BAF_NUM_SUPPLIES ARRAY_SIZE(s5k5baf_supply_names)
+
+struct s5k5baf_gpio {
+       int gpio;
+       int level;
+};
+
+enum s5k5baf_gpio_id {
+       STBY,
+       RST,
+       NUM_GPIOS,
+};
+
+#define PAD_CIS 0
+#define PAD_OUT 1
+#define NUM_CIS_PADS 1
+#define NUM_ISP_PADS 2
+
+struct s5k5baf_pixfmt {
+       enum v4l2_mbus_pixelcode code;
+       u32 colorspace;
+       /* REG_P_FMT(x) register value */
+       u16 reg_p_fmt;
+};
+
+struct s5k5baf_ctrls {
+       struct v4l2_ctrl_handler handler;
+       struct { /* Auto / manual white balance cluster */
+               struct v4l2_ctrl *awb;
+               struct v4l2_ctrl *gain_red;
+               struct v4l2_ctrl *gain_blue;
+       };
+       struct { /* Mirror cluster */
+               struct v4l2_ctrl *hflip;
+               struct v4l2_ctrl *vflip;
+       };
+       struct { /* Auto exposure / manual exposure and gain cluster */
+               struct v4l2_ctrl *auto_exp;
+               struct v4l2_ctrl *exposure;
+               struct v4l2_ctrl *gain;
+       };
+};
+
+enum {
+       S5K5BAF_FW_ID_PATCH,
+       S5K5BAF_FW_ID_CCM,
+       S5K5BAF_FW_ID_CIS,
+};
+
+struct s5k5baf_fw {
+       u16 count;
+       struct {
+               u16 id;
+               u16 offset;
+       } seq[0];
+       u16 data[0];
+};
+
+struct s5k5baf {
+       struct s5k5baf_gpio gpios[NUM_GPIOS];
+       enum v4l2_mbus_type bus_type;
+       u8 nlanes;
+       struct regulator_bulk_data supplies[S5K5BAF_NUM_SUPPLIES];
+
+       struct clk *clock;
+       u32 mclk_frequency;
+
+       struct s5k5baf_fw *fw;
+
+       struct v4l2_subdev cis_sd;
+       struct media_pad cis_pad;
+
+       struct v4l2_subdev sd;
+       struct media_pad pads[NUM_ISP_PADS];
+
+       /* protects the struct members below */
+       struct mutex lock;
+
+       int error;
+
+       struct v4l2_rect crop_sink;
+       struct v4l2_rect compose;
+       struct v4l2_rect crop_source;
+       /* index to s5k5baf_formats array */
+       int pixfmt;
+       /* actual frame interval in 100us */
+       u16 fiv;
+       /* requested frame interval in 100us */
+       u16 req_fiv;
+       /* cache for REG_DBG_AUTOALG_EN register */
+       u16 auto_alg;
+
+       struct s5k5baf_ctrls ctrls;
+
+       unsigned int streaming:1;
+       unsigned int apply_cfg:1;
+       unsigned int apply_crop:1;
+       unsigned int valid_auto_alg:1;
+       unsigned int power;
+};
+
+static const struct s5k5baf_pixfmt s5k5baf_formats[] = {
+       { V4L2_MBUS_FMT_VYUY8_2X8,      V4L2_COLORSPACE_JPEG,   5 },
+       /* range 16-240 */
+       { V4L2_MBUS_FMT_VYUY8_2X8,      V4L2_COLORSPACE_REC709, 6 },
+       { V4L2_MBUS_FMT_RGB565_2X8_BE,  V4L2_COLORSPACE_JPEG,   0 },
+};
+
+static struct v4l2_rect s5k5baf_cis_rect = {
+       0, 0, S5K5BAF_CIS_WIDTH, S5K5BAF_CIS_HEIGHT
+};
+
+/* Setfile contains set of I2C command sequences. Each sequence has its ID.
+ * setfile format:
+ *     u8 magic[4];
+ *     u16 count;              number of sequences
+ *     struct {
+ *             u16 id;         sequence id
+ *             u16 offset;     sequence offset in data array
+ *     } seq[count];
+ *     u16 data[*];            array containing sequences
+ *
+ */
+static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw,
+                           size_t count, const u16 *data)
+{
+       struct s5k5baf_fw *f;
+       u16 *d, i, *end;
+       int ret;
+
+       if (count < S5K5BAG_FW_TAG_LEN + 1) {
+               dev_err(dev, "firmware file too short (%zu)\n", count);
+               return -EINVAL;
+       }
+
+       ret = memcmp(data, S5K5BAF_FW_TAG, S5K5BAG_FW_TAG_LEN * sizeof(u16));
+       if (ret != 0) {
+               dev_err(dev, "invalid firmware magic number\n");
+               return -EINVAL;
+       }
+
+       data += S5K5BAG_FW_TAG_LEN;
+       count -= S5K5BAG_FW_TAG_LEN;
+
+       d = devm_kzalloc(dev, count * sizeof(u16), GFP_KERNEL);
+
+       for (i = 0; i < count; ++i)
+               d[i] = le16_to_cpu(data[i]);
+
+       f = (struct s5k5baf_fw *)d;
+       if (count < 1 + 2 * f->count) {
+               dev_err(dev, "invalid firmware header (count=%d size=%zu)\n",
+                       f->count, 2 * (count + S5K5BAG_FW_TAG_LEN));
+               return -EINVAL;
+       }
+       end = d + count;
+       d += 1 + 2 * f->count;
+
+       for (i = 0; i < f->count; ++i) {
+               if (f->seq[i].offset + d <= end)
+                       continue;
+               dev_err(dev, "invalid firmware header (seq=%d)\n", i);
+               return -EINVAL;
+       }
+
+       *fw = f;
+
+       return 0;
+}
+
+static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
+{
+       return &container_of(ctrl->handler, struct s5k5baf, ctrls.handler)->sd;
+}
+
+static inline bool s5k5baf_is_cis_subdev(struct v4l2_subdev *sd)
+{
+       return sd->entity.type == MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+}
+
+static inline struct s5k5baf *to_s5k5baf(struct v4l2_subdev *sd)
+{
+       if (s5k5baf_is_cis_subdev(sd))
+               return container_of(sd, struct s5k5baf, cis_sd);
+       else
+               return container_of(sd, struct s5k5baf, sd);
+}
+
+static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
+       __be16 w, r;
+       struct i2c_msg msg[] = {
+               { .addr = c->addr, .flags = 0,
+                 .len = 2, .buf = (u8 *)&w },
+               { .addr = c->addr, .flags = I2C_M_RD,
+                 .len = 2, .buf = (u8 *)&r },
+       };
+       int ret;
+
+       if (state->error)
+               return 0;
+
+       w = cpu_to_be16(addr);
+       ret = i2c_transfer(c->adapter, msg, 2);
+       r = be16_to_cpu(r);
+
+       v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, r);
+
+       if (ret != 2) {
+               v4l2_err(c, "i2c_read: error during transfer (%d)\n", ret);
+               state->error = ret;
+       }
+       return r;
+}
+
+static void s5k5baf_i2c_write(struct s5k5baf *state, u16 addr, u16 val)
+{
+       u8 buf[4] = { addr >> 8, addr & 0xFF, val >> 8, val & 0xFF };
+       struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
+       int ret;
+
+       if (state->error)
+               return;
+
+       ret = i2c_master_send(c, buf, 4);
+       v4l2_dbg(3, debug, c, "i2c_write: 0x%04x : 0x%04x\n", addr, val);
+
+       if (ret != 4) {
+               v4l2_err(c, "i2c_write: error during transfer (%d)\n", ret);
+               state->error = ret;
+       }
+}
+
+static u16 s5k5baf_read(struct s5k5baf *state, u16 addr)
+{
+       s5k5baf_i2c_write(state, REG_CMDRD_ADDR, addr);
+       return s5k5baf_i2c_read(state, REG_CMD_BUF);
+}
+
+static void s5k5baf_write(struct s5k5baf *state, u16 addr, u16 val)
+{
+       s5k5baf_i2c_write(state, REG_CMDWR_ADDR, addr);
+       s5k5baf_i2c_write(state, REG_CMD_BUF, val);
+}
+
+static void s5k5baf_write_arr_seq(struct s5k5baf *state, u16 addr,
+                                 u16 count, const u16 *seq)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
+       __be16 buf[count + 1];
+       int ret, n;
+
+       s5k5baf_i2c_write(state, REG_CMDWR_ADDR, addr);
+       if (state->error)
+               return;
+
+       buf[0] = __constant_cpu_to_be16(REG_CMD_BUF);
+       for (n = 1; n <= count; ++n)
+               buf[n] = cpu_to_be16(*seq++);
+
+       n *= 2;
+       ret = i2c_master_send(c, (char *)buf, n);
+       v4l2_dbg(3, debug, c, "i2c_write_seq(count=%d): %*ph\n", count,
+                min(2 * count, 64), seq - count);
+
+       if (ret != n) {
+               v4l2_err(c, "i2c_write_seq: error during transfer (%d)\n", ret);
+               state->error = ret;
+       }
+}
+
+#define s5k5baf_write_seq(state, addr, seq...) \
+       s5k5baf_write_arr_seq(state, addr, sizeof((char[]){ seq }), \
+                             (const u16 []){ seq });
+
+/* add items count at the beginning of the list */
+#define NSEQ(seq...) sizeof((char[]){ seq }), seq
+
+/*
+ * s5k5baf_write_nseq() - Writes sequences of values to sensor memory via i2c
+ * @nseq: sequence of u16 words in format:
+ *     (N, address, value[1]...value[N-1])*,0
+ * Ex.:
+ *     u16 seq[] = { NSEQ(0x4000, 1, 1), NSEQ(0x4010, 640, 480), 0 };
+ *     ret = s5k5baf_write_nseq(c, seq);
+ */
+static void s5k5baf_write_nseq(struct s5k5baf *state, const u16 *nseq)
+{
+       int count;
+
+       while ((count = *nseq++)) {
+               u16 addr = *nseq++;
+               --count;
+
+               s5k5baf_write_arr_seq(state, addr, count, nseq);
+               nseq += count;
+       }
+}
+
+static void s5k5baf_synchronize(struct s5k5baf *state, int timeout, u16 addr)
+{
+       unsigned long end = jiffies + msecs_to_jiffies(timeout);
+       u16 reg;
+
+       s5k5baf_write(state, addr, 1);
+       do {
+               reg = s5k5baf_read(state, addr);
+               if (state->error || !reg)
+                       return;
+               usleep_range(5000, 10000);
+       } while (time_is_after_jiffies(end));
+
+       v4l2_err(&state->sd, "timeout on register synchronize (%#x)\n", addr);
+       state->error = -ETIMEDOUT;
+}
+
+static u16 *s5k5baf_fw_get_seq(struct s5k5baf *state, u16 seq_id)
+{
+       struct s5k5baf_fw *fw = state->fw;
+       u16 *data;
+       int i;
+
+       if (fw == NULL)
+               return NULL;
+
+       data = fw->data + 2 * fw->count;
+
+       for (i = 0; i < fw->count; ++i) {
+               if (fw->seq[i].id == seq_id)
+                       return data + fw->seq[i].offset;
+       }
+
+       return NULL;
+}
+
+static void s5k5baf_hw_patch(struct s5k5baf *state)
+{
+       u16 *seq = s5k5baf_fw_get_seq(state, S5K5BAF_FW_ID_PATCH);
+
+       if (seq)
+               s5k5baf_write_nseq(state, seq);
+}
+
+static void s5k5baf_hw_set_clocks(struct s5k5baf *state)
+{
+       unsigned long mclk = state->mclk_frequency / 1000;
+       u16 status;
+       static const u16 nseq_clk_cfg[] = {
+               NSEQ(REG_I_USE_NPVI_CLOCKS,
+                 NPVI_CLOCKS, NMIPI_CLOCKS, 0,
+                 SCLK_PVI_FREQ / 4, PCLK_MIN_FREQ / 4, PCLK_MAX_FREQ / 4,
+                 SCLK_MIPI_FREQ / 4, PCLK_MIN_FREQ / 4, PCLK_MAX_FREQ / 4),
+               NSEQ(REG_I_USE_REGS_API, 1),
+               0
+       };
+
+       s5k5baf_write_seq(state, REG_I_INCLK_FREQ_L, mclk & 0xffff, mclk >> 16);
+       s5k5baf_write_nseq(state, nseq_clk_cfg);
+
+       s5k5baf_synchronize(state, 250, REG_I_INIT_PARAMS_UPDATED);
+       status = s5k5baf_read(state, REG_I_ERROR_INFO);
+       if (!state->error && status) {
+               v4l2_err(&state->sd, "error configuring PLL (%d)\n", status);
+               state->error = -EINVAL;
+       }
+}
+
+/* set custom color correction matrices for various illuminations */
+static void s5k5baf_hw_set_ccm(struct s5k5baf *state)
+{
+       u16 *seq = s5k5baf_fw_get_seq(state, S5K5BAF_FW_ID_CCM);
+
+       if (seq)
+               s5k5baf_write_nseq(state, seq);
+}
+
+/* CIS sensor tuning, based on undocumented android driver code */
+static void s5k5baf_hw_set_cis(struct s5k5baf *state)
+{
+       u16 *seq = s5k5baf_fw_get_seq(state, S5K5BAF_FW_ID_CIS);
+
+       if (!seq)
+               return;
+
+       s5k5baf_i2c_write(state, REG_CMDWR_PAGE, PAGE_IF_HW);
+       s5k5baf_write_nseq(state, seq);
+       s5k5baf_i2c_write(state, REG_CMDWR_PAGE, PAGE_IF_SW);
+}
+
+static void s5k5baf_hw_sync_cfg(struct s5k5baf *state)
+{
+       s5k5baf_write(state, REG_G_PREV_CFG_CHG, 1);
+       if (state->apply_crop) {
+               s5k5baf_write(state, REG_G_INPUTS_CHANGE_REQ, 1);
+               s5k5baf_write(state, REG_G_PREV_CFG_BYPASS_CHANGED, 1);
+       }
+       s5k5baf_synchronize(state, 500, REG_G_NEW_CFG_SYNC);
+}
+/* Set horizontal and vertical image flipping */
+static void s5k5baf_hw_set_mirror(struct s5k5baf *state)
+{
+       u16 flip = state->ctrls.vflip->val | (state->ctrls.vflip->val << 1);
+
+       s5k5baf_write(state, REG_P_PREV_MIRROR(0), flip);
+       if (state->streaming)
+               s5k5baf_hw_sync_cfg(state);
+}
+
+static void s5k5baf_hw_set_alg(struct s5k5baf *state, u16 alg, bool enable)
+{
+       u16 cur_alg, new_alg;
+
+       if (!state->valid_auto_alg)
+               cur_alg = s5k5baf_read(state, REG_DBG_AUTOALG_EN);
+       else
+               cur_alg = state->auto_alg;
+
+       new_alg = enable ? (cur_alg | alg) : (cur_alg & ~alg);
+
+       if (new_alg != cur_alg)
+               s5k5baf_write(state, REG_DBG_AUTOALG_EN, new_alg);
+
+       if (state->error)
+               return;
+
+       state->valid_auto_alg = 1;
+       state->auto_alg = new_alg;
+}
+
+/* Configure auto/manual white balance and R/G/B gains */
+static void s5k5baf_hw_set_awb(struct s5k5baf *state, int awb)
+{
+       struct s5k5baf_ctrls *ctrls = &state->ctrls;
+
+       if (!awb)
+               s5k5baf_write_seq(state, REG_SF_RGAIN,
+                                 ctrls->gain_red->val, 1,
+                                 S5K5BAF_GAIN_GREEN_DEF, 1,
+                                 ctrls->gain_blue->val, 1,
+                                 1);
+
+       s5k5baf_hw_set_alg(state, AALG_WB_EN, awb);
+}
+
+/* Program FW with exposure time, 'exposure' in us units */
+static void s5k5baf_hw_set_user_exposure(struct s5k5baf *state, int exposure)
+{
+       unsigned int time = exposure / 10;
+
+       s5k5baf_write_seq(state, REG_SF_USR_EXPOSURE_L,
+                         time & 0xffff, time >> 16, 1);
+}
+
+static void s5k5baf_hw_set_user_gain(struct s5k5baf *state, int gain)
+{
+       s5k5baf_write_seq(state, REG_SF_USR_TOT_GAIN, gain, 1);
+}
+
+/* Set auto/manual exposure and total gain */
+static void s5k5baf_hw_set_auto_exposure(struct s5k5baf *state, int value)
+{
+       if (value == V4L2_EXPOSURE_AUTO) {
+               s5k5baf_hw_set_alg(state, AALG_AE_EN | AALG_DIVLEI_EN, true);
+       } else {
+               unsigned int exp_time = state->ctrls.exposure->val;
+
+               s5k5baf_hw_set_user_exposure(state, exp_time);
+               s5k5baf_hw_set_user_gain(state, state->ctrls.gain->val);
+               s5k5baf_hw_set_alg(state, AALG_AE_EN | AALG_DIVLEI_EN, false);
+       }
+}
+
+static void s5k5baf_hw_set_anti_flicker(struct s5k5baf *state, int v)
+{
+       if (v == V4L2_CID_POWER_LINE_FREQUENCY_AUTO) {
+               s5k5baf_hw_set_alg(state, AALG_FLICKER_EN, true);
+       } else {
+               /* The V4L2_CID_LINE_FREQUENCY control values match
+                * the register values */
+               s5k5baf_write_seq(state, REG_SF_FLICKER_QUANT, v, 1);
+               s5k5baf_hw_set_alg(state, AALG_FLICKER_EN, false);
+       }
+}
+
+static void s5k5baf_hw_set_colorfx(struct s5k5baf *state, int val)
+{
+       static const u16 colorfx[] = {
+               [V4L2_COLORFX_NONE] = 0,
+               [V4L2_COLORFX_BW] = 1,
+               [V4L2_COLORFX_NEGATIVE] = 2,
+               [V4L2_COLORFX_SEPIA] = 3,
+               [V4L2_COLORFX_SKY_BLUE] = 4,
+               [V4L2_COLORFX_SKETCH] = 5,
+       };
+
+       s5k5baf_write(state, REG_G_SPEC_EFFECTS, colorfx[val]);
+}
+
+static int s5k5baf_find_pixfmt(struct v4l2_mbus_framefmt *mf)
+{
+       int i, c = -1;
+
+       for (i = 0; i < ARRAY_SIZE(s5k5baf_formats); i++) {
+               if (mf->colorspace != s5k5baf_formats[i].colorspace)
+                       continue;
+               if (mf->code == s5k5baf_formats[i].code)
+                       return i;
+               if (c < 0)
+                       c = i;
+       }
+       return (c < 0) ? 0 : c;
+}
+
+static int s5k5baf_clear_error(struct s5k5baf *state)
+{
+       int ret = state->error;
+
+       state->error = 0;
+       return ret;
+}
+
+static int s5k5baf_hw_set_video_bus(struct s5k5baf *state)
+{
+       u16 en_pkts;
+
+       if (state->bus_type == V4L2_MBUS_CSI2)
+               en_pkts = EN_PACKETS_CSI2;
+       else
+               en_pkts = 0;
+
+       s5k5baf_write_seq(state, REG_OIF_EN_MIPI_LANES,
+                         state->nlanes, en_pkts, 1);
+
+       return s5k5baf_clear_error(state);
+}
+
+static u16 s5k5baf_get_cfg_error(struct s5k5baf *state)
+{
+       u16 err = s5k5baf_read(state, REG_G_PREV_CFG_ERROR);
+       if (err)
+               s5k5baf_write(state, REG_G_PREV_CFG_ERROR, 0);
+       return err;
+}
+
+static void s5k5baf_hw_set_fiv(struct s5k5baf *state, u16 fiv)
+{
+       s5k5baf_write(state, REG_P_MAX_FR_TIME(0), fiv);
+       s5k5baf_hw_sync_cfg(state);
+}
+
+static void s5k5baf_hw_find_min_fiv(struct s5k5baf *state)
+{
+       u16 err, fiv;
+       int n;
+
+       fiv = s5k5baf_read(state,  REG_G_ACTUAL_P_FR_TIME);
+       if (state->error)
+               return;
+
+       for (n = 5; n > 0; --n) {
+               s5k5baf_hw_set_fiv(state, fiv);
+               err = s5k5baf_get_cfg_error(state);
+               if (state->error)
+                       return;
+               switch (err) {
+               case CFG_ERROR_RANGE:
+                       ++fiv;
+                       break;
+               case 0:
+                       state->fiv = fiv;
+                       v4l2_info(&state->sd,
+                                 "found valid frame interval: %d00us\n", fiv);
+                       return;
+               default:
+                       v4l2_err(&state->sd,
+                                "error setting frame interval: %d\n", err);
+                       state->error = -EINVAL;
+               }
+       };
+       v4l2_err(&state->sd, "cannot find correct frame interval\n");
+       state->error = -ERANGE;
+}
+
+static void s5k5baf_hw_validate_cfg(struct s5k5baf *state)
+{
+       u16 err;
+
+       err = s5k5baf_get_cfg_error(state);
+       if (state->error)
+               return;
+
+       switch (err) {
+       case 0:
+               state->apply_cfg = 1;
+               return;
+       case CFG_ERROR_RANGE:
+               s5k5baf_hw_find_min_fiv(state);
+               if (!state->error)
+                       state->apply_cfg = 1;
+               return;
+       default:
+               v4l2_err(&state->sd,
+                        "error setting format: %d\n", err);
+               state->error = -EINVAL;
+       }
+}
+
+static void s5k5baf_rescale(struct v4l2_rect *r, const struct v4l2_rect *v,
+                           const struct v4l2_rect *n,
+                           const struct v4l2_rect *d)
+{
+       r->left = v->left * n->width / d->width;
+       r->top = v->top * n->height / d->height;
+       r->width = v->width * n->width / d->width;
+       r->height = v->height * n->height / d->height;
+}
+
+static int s5k5baf_hw_set_crop_rects(struct s5k5baf *state)
+{
+       struct v4l2_rect *p, r;
+       u16 err;
+       int ret;
+
+       p = &state->crop_sink;
+       s5k5baf_write_seq(state, REG_G_PREVREQ_IN_WIDTH, p->width, p->height,
+                         p->left, p->top);
+
+       s5k5baf_rescale(&r, &state->crop_source, &state->crop_sink,
+                       &state->compose);
+       s5k5baf_write_seq(state, REG_G_PREVZOOM_IN_WIDTH, r.width, r.height,
+                         r.left, r.top);
+
+       s5k5baf_synchronize(state, 500, REG_G_INPUTS_CHANGE_REQ);
+       s5k5baf_synchronize(state, 500, REG_G_PREV_CFG_BYPASS_CHANGED);
+       err = s5k5baf_get_cfg_error(state);
+       ret = s5k5baf_clear_error(state);
+       if (ret < 0)
+               return ret;
+
+       switch (err) {
+       case 0:
+               break;
+       case CFG_ERROR_RANGE:
+               /* retry crop with frame interval set to max */
+               s5k5baf_hw_set_fiv(state, S5K5BAF_MAX_FR_TIME);
+               err = s5k5baf_get_cfg_error(state);
+               ret = s5k5baf_clear_error(state);
+               if (ret < 0)
+                       return ret;
+               if (err) {
+                       v4l2_err(&state->sd,
+                                "crop error on max frame interval: %d\n", err);
+                       state->error = -EINVAL;
+               }
+               s5k5baf_hw_set_fiv(state, state->req_fiv);
+               s5k5baf_hw_validate_cfg(state);
+               break;
+       default:
+               v4l2_err(&state->sd, "crop error: %d\n", err);
+               return -EINVAL;
+       }
+
+       if (!state->apply_cfg)
+               return 0;
+
+       p = &state->crop_source;
+       s5k5baf_write_seq(state, REG_P_OUT_WIDTH(0), p->width, p->height);
+       s5k5baf_hw_set_fiv(state, state->req_fiv);
+       s5k5baf_hw_validate_cfg(state);
+
+       return s5k5baf_clear_error(state);
+}
+
+static void s5k5baf_hw_set_config(struct s5k5baf *state)
+{
+       u16 reg_fmt = s5k5baf_formats[state->pixfmt].reg_p_fmt;
+       struct v4l2_rect *r = &state->crop_source;
+
+       s5k5baf_write_seq(state, REG_P_OUT_WIDTH(0),
+                         r->width, r->height, reg_fmt,
+                         PCLK_MAX_FREQ >> 2, PCLK_MIN_FREQ >> 2,
+                         PVI_MASK_MIPI, CLK_MIPI_INDEX,
+                         FR_RATE_FIXED, FR_RATE_Q_DYNAMIC,
+                         state->req_fiv, S5K5BAF_MIN_FR_TIME);
+       s5k5baf_hw_sync_cfg(state);
+       s5k5baf_hw_validate_cfg(state);
+}
+
+
+static void s5k5baf_hw_set_test_pattern(struct s5k5baf *state, int id)
+{
+       s5k5baf_i2c_write(state, REG_PATTERN_WIDTH, 800);
+       s5k5baf_i2c_write(state, REG_PATTERN_HEIGHT, 511);
+       s5k5baf_i2c_write(state, REG_PATTERN_PARAM, 0);
+       s5k5baf_i2c_write(state, REG_PATTERN_SET, id);
+}
+
+static void s5k5baf_gpio_assert(struct s5k5baf *state, int id)
+{
+       struct s5k5baf_gpio *gpio = &state->gpios[id];
+
+       gpio_set_value(gpio->gpio, gpio->level);
+}
+
+static void s5k5baf_gpio_deassert(struct s5k5baf *state, int id)
+{
+       struct s5k5baf_gpio *gpio = &state->gpios[id];
+
+       gpio_set_value(gpio->gpio, !gpio->level);
+}
+
+static int s5k5baf_power_on(struct s5k5baf *state)
+{
+       int ret;
+
+       ret = regulator_bulk_enable(S5K5BAF_NUM_SUPPLIES, state->supplies);
+       if (ret < 0)
+               goto err;
+
+       ret = clk_set_rate(state->clock, state->mclk_frequency);
+       if (ret < 0)
+               goto err_reg_dis;
+
+       ret = clk_prepare_enable(state->clock);
+       if (ret < 0)
+               goto err_reg_dis;
+
+       v4l2_dbg(1, debug, &state->sd, "clock frequency: %ld\n",
+                clk_get_rate(state->clock));
+
+       s5k5baf_gpio_deassert(state, STBY);
+       usleep_range(50, 100);
+       s5k5baf_gpio_deassert(state, RST);
+       return 0;
+
+err_reg_dis:
+       regulator_bulk_disable(S5K5BAF_NUM_SUPPLIES, state->supplies);
+err:
+       v4l2_err(&state->sd, "%s() failed (%d)\n", __func__, ret);
+       return ret;
+}
+
+static int s5k5baf_power_off(struct s5k5baf *state)
+{
+       int ret;
+
+       state->streaming = 0;
+       state->apply_cfg = 0;
+       state->apply_crop = 0;
+
+       s5k5baf_gpio_assert(state, RST);
+       s5k5baf_gpio_assert(state, STBY);
+
+       if (!IS_ERR(state->clock))
+               clk_disable_unprepare(state->clock);
+
+       ret = regulator_bulk_disable(S5K5BAF_NUM_SUPPLIES,
+                                       state->supplies);
+       if (ret < 0)
+               v4l2_err(&state->sd, "failed to disable regulators\n");
+
+       return 0;
+}
+
+static void s5k5baf_hw_init(struct s5k5baf *state)
+{
+       s5k5baf_i2c_write(state, AHB_MSB_ADDR_PTR, PAGE_IF_HW);
+       s5k5baf_i2c_write(state, REG_CLEAR_HOST_INT, 0);
+       s5k5baf_i2c_write(state, REG_SW_LOAD_COMPLETE, 1);
+       s5k5baf_i2c_write(state, REG_CMDRD_PAGE, PAGE_IF_SW);
+       s5k5baf_i2c_write(state, REG_CMDWR_PAGE, PAGE_IF_SW);
+}
+
+/*
+ * V4L2 subdev core and video operations
+ */
+
+static void s5k5baf_initialize_data(struct s5k5baf *state)
+{
+       state->pixfmt = 0;
+       state->req_fiv = 10000 / 15;
+       state->fiv = state->req_fiv;
+       state->valid_auto_alg = 0;
+}
+
+static int s5k5baf_load_setfile(struct s5k5baf *state)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
+       const struct firmware *fw;
+       int ret;
+
+       ret = request_firmware(&fw, S5K5BAF_FW_FILENAME, &c->dev);
+       if (ret < 0) {
+               dev_warn(&c->dev, "firmware file (%s) not loaded\n",
+                        S5K5BAF_FW_FILENAME);
+               return ret;
+       }
+
+       ret = s5k5baf_fw_parse(&c->dev, &state->fw, fw->size / 2,
+                              (u16 *)fw->data);
+
+       release_firmware(fw);
+
+       return ret;
+}
+
+static int s5k5baf_set_power(struct v4l2_subdev *sd, int on)
+{
+       struct s5k5baf *state = to_s5k5baf(sd);
+       int ret = 0;
+
+       mutex_lock(&state->lock);
+
+       if (!on != state->power)
+               goto out;
+
+       if (on) {
+               if (state->fw == NULL)
+                       s5k5baf_load_setfile(state);
+
+               s5k5baf_initialize_data(state);
+               ret = s5k5baf_power_on(state);
+               if (ret < 0)
+                       goto out;
+
+               s5k5baf_hw_init(state);
+               s5k5baf_hw_patch(state);
+               s5k5baf_i2c_write(state, REG_SET_HOST_INT, 1);
+               s5k5baf_hw_set_clocks(state);
+
+               ret = s5k5baf_hw_set_video_bus(state);
+               if (ret < 0)
+                       goto out;
+
+               s5k5baf_hw_set_cis(state);
+               s5k5baf_hw_set_ccm(state);
+
+               ret = s5k5baf_clear_error(state);
+               if (!ret)
+                       state->power++;
+       } else {
+               s5k5baf_power_off(state);
+               state->power--;
+       }
+
+out:
+       mutex_unlock(&state->lock);
+
+       if (!ret && on)
+               ret = v4l2_ctrl_handler_setup(&state->ctrls.handler);
+
+       return ret;
+}
+
+static void s5k5baf_hw_set_stream(struct s5k5baf *state, int enable)
+{
+       s5k5baf_write_seq(state, REG_G_ENABLE_PREV, enable, 1);
+}
+
+static int s5k5baf_s_stream(struct v4l2_subdev *sd, int on)
+{
+       struct s5k5baf *state = to_s5k5baf(sd);
+       int ret;
+
+       mutex_lock(&state->lock);
+
+       if (state->streaming == !!on) {
+               ret = 0;
+               goto out;
+       }
+
+       if (on) {
+               s5k5baf_hw_set_config(state);
+               ret = s5k5baf_hw_set_crop_rects(state);
+               if (ret < 0)
+                       goto out;
+               s5k5baf_hw_set_stream(state, 1);
+               s5k5baf_i2c_write(state, 0xb0cc, 0x000b);
+       } else {
+               s5k5baf_hw_set_stream(state, 0);
+       }
+       ret = s5k5baf_clear_error(state);
+       if (!ret)
+               state->streaming = !state->streaming;
+
+out:
+       mutex_unlock(&state->lock);
+
+       return ret;
+}
+
+static int s5k5baf_g_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *fi)
+{
+       struct s5k5baf *state = to_s5k5baf(sd);
+
+       mutex_lock(&state->lock);
+       fi->interval.numerator = state->fiv;
+       fi->interval.denominator = 10000;
+       mutex_unlock(&state->lock);
+
+       return 0;
+}
+
+static void s5k5baf_set_frame_interval(struct s5k5baf *state,
+                                      struct v4l2_subdev_frame_interval *fi)
+{
+       struct v4l2_fract *i = &fi->interval;
+
+       if (fi->interval.denominator == 0)
+               state->req_fiv = S5K5BAF_MAX_FR_TIME;
+       else
+               state->req_fiv = clamp_t(u32,
+                                        i->numerator * 10000 / i->denominator,
+                                        S5K5BAF_MIN_FR_TIME,
+                                        S5K5BAF_MAX_FR_TIME);
+
+       state->fiv = state->req_fiv;
+       if (state->apply_cfg) {
+               s5k5baf_hw_set_fiv(state, state->req_fiv);
+               s5k5baf_hw_validate_cfg(state);
+       }
+       *i = (struct v4l2_fract){ state->fiv, 10000 };
+       if (state->fiv == state->req_fiv)
+               v4l2_info(&state->sd, "frame interval changed to %d00us\n",
+                         state->fiv);
+}
+
+static int s5k5baf_s_frame_interval(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_frame_interval *fi)
+{
+       struct s5k5baf *state = to_s5k5baf(sd);
+
+       mutex_lock(&state->lock);
+       s5k5baf_set_frame_interval(state, fi);
+       mutex_unlock(&state->lock);
+       return 0;
+}
+
+/*
+ * V4L2 subdev pad level and video operations
+ */
+static int s5k5baf_enum_frame_interval(struct v4l2_subdev *sd,
+                             struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_frame_interval_enum *fie)
+{
+       if (fie->index > S5K5BAF_MAX_FR_TIME - S5K5BAF_MIN_FR_TIME ||
+           fie->pad != PAD_CIS)
+               return -EINVAL;
+
+       v4l_bound_align_image(&fie->width, S5K5BAF_WIN_WIDTH_MIN,
+                             S5K5BAF_CIS_WIDTH, 1,
+                             &fie->height, S5K5BAF_WIN_HEIGHT_MIN,
+                             S5K5BAF_CIS_HEIGHT, 1, 0);
+
+       fie->interval.numerator = S5K5BAF_MIN_FR_TIME + fie->index;
+       fie->interval.denominator = 10000;
+
+       return 0;
+}
+
+static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_fh *fh,
+                                struct v4l2_subdev_mbus_code_enum *code)
+{
+       if (code->pad == PAD_CIS) {
+               if (code->index > 0)
+                       return -EINVAL;
+               code->code = V4L2_MBUS_FMT_FIXED;
+               return 0;
+       }
+
+       if (code->index >= ARRAY_SIZE(s5k5baf_formats))
+               return -EINVAL;
+
+       code->code = s5k5baf_formats[code->index].code;
+       return 0;
+}
+
+static int s5k5baf_enum_frame_size(struct v4l2_subdev *sd,
+                                 struct v4l2_subdev_fh *fh,
+                                 struct v4l2_subdev_frame_size_enum *fse)
+{
+       int i;
+
+       if (fse->index > 0)
+               return -EINVAL;
+
+       if (fse->pad == PAD_CIS) {
+               fse->code = V4L2_MBUS_FMT_FIXED;
+               fse->min_width = S5K5BAF_CIS_WIDTH;
+               fse->max_width = S5K5BAF_CIS_WIDTH;
+               fse->min_height = S5K5BAF_CIS_HEIGHT;
+               fse->max_height = S5K5BAF_CIS_HEIGHT;
+               return 0;
+       }
+
+       i = ARRAY_SIZE(s5k5baf_formats);
+       while (--i)
+               if (fse->code == s5k5baf_formats[i].code)
+                       break;
+       fse->code = s5k5baf_formats[i].code;
+       fse->min_width = S5K5BAF_WIN_WIDTH_MIN;
+       fse->max_width = S5K5BAF_CIS_WIDTH;
+       fse->max_height = S5K5BAF_WIN_HEIGHT_MIN;
+       fse->min_height = S5K5BAF_CIS_HEIGHT;
+
+       return 0;
+}
+
+static void s5k5baf_try_cis_format(struct v4l2_mbus_framefmt *mf)
+{
+       mf->width = S5K5BAF_CIS_WIDTH;
+       mf->height = S5K5BAF_CIS_HEIGHT;
+       mf->code = V4L2_MBUS_FMT_FIXED;
+       mf->colorspace = V4L2_COLORSPACE_JPEG;
+       mf->field = V4L2_FIELD_NONE;
+}
+
+static int s5k5baf_try_isp_format(struct v4l2_mbus_framefmt *mf)
+{
+       int pixfmt;
+
+       v4l_bound_align_image(&mf->width, S5K5BAF_WIN_WIDTH_MIN,
+                             S5K5BAF_CIS_WIDTH, 1,
+                             &mf->height, S5K5BAF_WIN_HEIGHT_MIN,
+                             S5K5BAF_CIS_HEIGHT, 1, 0);
+
+       pixfmt = s5k5baf_find_pixfmt(mf);
+
+       mf->colorspace = s5k5baf_formats[pixfmt].colorspace;
+       mf->code = s5k5baf_formats[pixfmt].code;
+       mf->field = V4L2_FIELD_NONE;
+
+       return pixfmt;
+}
+
+static int s5k5baf_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *fmt)
+{
+       struct s5k5baf *state = to_s5k5baf(sd);
+       const struct s5k5baf_pixfmt *pixfmt;
+       struct v4l2_mbus_framefmt *mf;
+
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               mf = v4l2_subdev_get_try_format(fh, fmt->pad);
+               fmt->format = *mf;
+               return 0;
+       }
+
+       mf = &fmt->format;
+       if (fmt->pad == PAD_CIS) {
+               s5k5baf_try_cis_format(mf);
+               return 0;
+       }
+       mf->field = V4L2_FIELD_NONE;
+       mutex_lock(&state->lock);
+       pixfmt = &s5k5baf_formats[state->pixfmt];
+       mf->width = state->crop_source.width;
+       mf->height = state->crop_source.height;
+       mf->code = pixfmt->code;
+       mf->colorspace = pixfmt->colorspace;
+       mutex_unlock(&state->lock);
+
+       return 0;
+}
+
+static int s5k5baf_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *fmt)
+{
+       struct v4l2_mbus_framefmt *mf = &fmt->format;
+       struct s5k5baf *state = to_s5k5baf(sd);
+       const struct s5k5baf_pixfmt *pixfmt;
+       int ret = 0;
+
+       if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
+               *v4l2_subdev_get_try_format(fh, fmt->pad) = *mf;
+               return 0;
+       }
+
+       if (fmt->pad == PAD_CIS) {
+               s5k5baf_try_cis_format(mf);
+               return 0;
+       }
+
+       mutex_lock(&state->lock);
+
+       if (state->streaming) {
+               mutex_unlock(&state->lock);
+               return -EBUSY;
+       }
+
+       state->pixfmt = s5k5baf_try_isp_format(mf);
+       pixfmt = &s5k5baf_formats[state->pixfmt];
+       mf->code = pixfmt->code;
+       mf->colorspace = pixfmt->colorspace;
+       mf->width = state->crop_source.width;
+       mf->height = state->crop_source.height;
+
+       mutex_unlock(&state->lock);
+       return ret;
+}
+
+enum selection_rect { R_CIS, R_CROP_SINK, R_COMPOSE, R_CROP_SOURCE, R_INVALID };
+
+static enum selection_rect s5k5baf_get_sel_rect(u32 pad, u32 target)
+{
+       switch (target) {
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               return pad ? R_COMPOSE : R_CIS;
+       case V4L2_SEL_TGT_CROP:
+               return pad ? R_CROP_SOURCE : R_CROP_SINK;
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               return pad ? R_INVALID : R_CROP_SINK;
+       case V4L2_SEL_TGT_COMPOSE:
+               return pad ? R_INVALID : R_COMPOSE;
+       default:
+               return R_INVALID;
+       }
+}
+
+static int s5k5baf_is_bound_target(u32 target)
+{
+       return target == V4L2_SEL_TGT_CROP_BOUNDS ||
+               target == V4L2_SEL_TGT_COMPOSE_BOUNDS;
+}
+
+static int s5k5baf_get_selection(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_fh *fh,
+                                struct v4l2_subdev_selection *sel)
+{
+       static enum selection_rect rtype;
+       struct s5k5baf *state = to_s5k5baf(sd);
+
+       rtype = s5k5baf_get_sel_rect(sel->pad, sel->target);
+
+       switch (rtype) {
+       case R_INVALID:
+               return -EINVAL;
+       case R_CIS:
+               sel->r = s5k5baf_cis_rect;
+               return 0;
+       default:
+               break;
+       }
+
+       if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+               if (rtype == R_COMPOSE)
+                       sel->r = *v4l2_subdev_get_try_compose(fh, sel->pad);
+               else
+                       sel->r = *v4l2_subdev_get_try_crop(fh, sel->pad);
+               return 0;
+       }
+
+       mutex_lock(&state->lock);
+       switch (rtype) {
+       case R_CROP_SINK:
+               sel->r = state->crop_sink;
+               break;
+       case R_COMPOSE:
+               sel->r = state->compose;
+               break;
+       case R_CROP_SOURCE:
+               sel->r = state->crop_source;
+               break;
+       default:
+               break;
+       }
+       if (s5k5baf_is_bound_target(sel->target)) {
+               sel->r.left = 0;
+               sel->r.top = 0;
+       }
+       mutex_unlock(&state->lock);
+
+       return 0;
+}
+
+/* bounds range [start, start+len) to [0, max) and aligns to 2 */
+static void s5k5baf_bound_range(u32 *start, u32 *len, u32 max)
+{
+       if (*len > max)
+               *len = max;
+       if (*start + *len > max)
+               *start = max - *len;
+       *start &= ~1;
+       *len &= ~1;
+       if (*len < S5K5BAF_WIN_WIDTH_MIN)
+               *len = S5K5BAF_WIN_WIDTH_MIN;
+}
+
+static void s5k5baf_bound_rect(struct v4l2_rect *r, u32 width, u32 height)
+{
+       s5k5baf_bound_range(&r->left, &r->width, width);
+       s5k5baf_bound_range(&r->top, &r->height, height);
+}
+
+static void s5k5baf_set_rect_and_adjust(struct v4l2_rect **rects,
+                                       enum selection_rect first,
+                                       struct v4l2_rect *v)
+{
+       struct v4l2_rect *r, *br;
+       enum selection_rect i = first;
+
+       *rects[first] = *v;
+       do {
+               r = rects[i];
+               br = rects[i - 1];
+               s5k5baf_bound_rect(r, br->width, br->height);
+       } while (++i != R_INVALID);
+       *v = *rects[first];
+}
+
+static bool s5k5baf_cmp_rect(const struct v4l2_rect *r1,
+                            const struct v4l2_rect *r2)
+{
+       return !memcmp(r1, r2, sizeof(*r1));
+}
+
+static int s5k5baf_set_selection(struct v4l2_subdev *sd,
+                                struct v4l2_subdev_fh *fh,
+                                struct v4l2_subdev_selection *sel)
+{
+       static enum selection_rect rtype;
+       struct s5k5baf *state = to_s5k5baf(sd);
+       struct v4l2_rect **rects;
+       int ret = 0;
+
+       rtype = s5k5baf_get_sel_rect(sel->pad, sel->target);
+       if (rtype == R_INVALID || s5k5baf_is_bound_target(sel->target))
+               return -EINVAL;
+
+       /* allow only scaling on compose */
+       if (rtype == R_COMPOSE) {
+               sel->r.left = 0;
+               sel->r.top = 0;
+       }
+
+       if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
+               rects = (struct v4l2_rect * []) {
+                               &s5k5baf_cis_rect,
+                               v4l2_subdev_get_try_crop(fh, PAD_CIS),
+                               v4l2_subdev_get_try_compose(fh, PAD_CIS),
+                               v4l2_subdev_get_try_crop(fh, PAD_OUT)
+                       };
+               s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
+               return 0;
+       }
+
+       rects = (struct v4l2_rect * []) {
+                       &s5k5baf_cis_rect,
+                       &state->crop_sink,
+                       &state->compose,
+                       &state->crop_source
+               };
+       mutex_lock(&state->lock);
+       if (state->streaming) {
+               /* adjust sel->r to avoid output resolution change */
+               if (rtype < R_CROP_SOURCE) {
+                       if (sel->r.width < state->crop_source.width)
+                               sel->r.width = state->crop_source.width;
+                       if (sel->r.height < state->crop_source.height)
+                               sel->r.height = state->crop_source.height;
+               } else {
+                       sel->r.width = state->crop_source.width;
+                       sel->r.height = state->crop_source.height;
+               }
+       }
+       s5k5baf_set_rect_and_adjust(rects, rtype, &sel->r);
+       if (!s5k5baf_cmp_rect(&state->crop_sink, &s5k5baf_cis_rect) ||
+           !s5k5baf_cmp_rect(&state->compose, &s5k5baf_cis_rect))
+               state->apply_crop = 1;
+       if (state->streaming)
+               ret = s5k5baf_hw_set_crop_rects(state);
+       mutex_unlock(&state->lock);
+
+       return ret;
+}
+
+static const struct v4l2_subdev_pad_ops s5k5baf_cis_pad_ops = {
+       .enum_mbus_code         = s5k5baf_enum_mbus_code,
+       .enum_frame_size        = s5k5baf_enum_frame_size,
+       .get_fmt                = s5k5baf_get_fmt,
+       .set_fmt                = s5k5baf_set_fmt,
+};
+
+static const struct v4l2_subdev_pad_ops s5k5baf_pad_ops = {
+       .enum_mbus_code         = s5k5baf_enum_mbus_code,
+       .enum_frame_size        = s5k5baf_enum_frame_size,
+       .enum_frame_interval    = s5k5baf_enum_frame_interval,
+       .get_fmt                = s5k5baf_get_fmt,
+       .set_fmt                = s5k5baf_set_fmt,
+       .get_selection          = s5k5baf_get_selection,
+       .set_selection          = s5k5baf_set_selection,
+};
+
+static const struct v4l2_subdev_video_ops s5k5baf_video_ops = {
+       .g_frame_interval       = s5k5baf_g_frame_interval,
+       .s_frame_interval       = s5k5baf_s_frame_interval,
+       .s_stream               = s5k5baf_s_stream,
+};
+
+/*
+ * V4L2 subdev controls
+ */
+
+static int s5k5baf_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct v4l2_subdev *sd = ctrl_to_sd(ctrl);
+       struct s5k5baf *state = to_s5k5baf(sd);
+       int ret;
+
+       v4l2_dbg(1, debug, sd, "ctrl: %s, value: %d\n", ctrl->name, ctrl->val);
+
+       mutex_lock(&state->lock);
+
+       if (state->power == 0)
+               goto unlock;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUTO_WHITE_BALANCE:
+               s5k5baf_hw_set_awb(state, ctrl->val);
+               break;
+
+       case V4L2_CID_BRIGHTNESS:
+               s5k5baf_write(state, REG_USER_BRIGHTNESS, ctrl->val);
+               break;
+
+       case V4L2_CID_COLORFX:
+               s5k5baf_hw_set_colorfx(state, ctrl->val);
+               break;
+
+       case V4L2_CID_CONTRAST:
+               s5k5baf_write(state, REG_USER_CONTRAST, ctrl->val);
+               break;
+
+       case V4L2_CID_EXPOSURE_AUTO:
+               s5k5baf_hw_set_auto_exposure(state, ctrl->val);
+               break;
+
+       case V4L2_CID_HFLIP:
+               s5k5baf_hw_set_mirror(state);
+               break;
+
+       case V4L2_CID_POWER_LINE_FREQUENCY:
+               s5k5baf_hw_set_anti_flicker(state, ctrl->val);
+               break;
+
+       case V4L2_CID_SATURATION:
+               s5k5baf_write(state, REG_USER_SATURATION, ctrl->val);
+               break;
+
+       case V4L2_CID_SHARPNESS:
+               s5k5baf_write(state, REG_USER_SHARPBLUR, ctrl->val);
+               break;
+
+       case V4L2_CID_WHITE_BALANCE_TEMPERATURE:
+               s5k5baf_write(state, REG_P_COLORTEMP(0), ctrl->val);
+               if (state->apply_cfg)
+                       s5k5baf_hw_sync_cfg(state);
+               break;
+
+       case V4L2_CID_TEST_PATTERN:
+               s5k5baf_hw_set_test_pattern(state, ctrl->val);
+               break;
+       }
+unlock:
+       ret = s5k5baf_clear_error(state);
+       mutex_unlock(&state->lock);
+       return ret;
+}
+
+static const struct v4l2_ctrl_ops s5k5baf_ctrl_ops = {
+       .s_ctrl = s5k5baf_s_ctrl,
+};
+
+static const char * const s5k5baf_test_pattern_menu[] = {
+       "Disabled",
+       "Blank",
+       "Bars",
+       "Gradients",
+       "Textile",
+       "Textile2",
+       "Squares"
+};
+
+static int s5k5baf_initialize_ctrls(struct s5k5baf *state)
+{
+       const struct v4l2_ctrl_ops *ops = &s5k5baf_ctrl_ops;
+       struct s5k5baf_ctrls *ctrls = &state->ctrls;
+       struct v4l2_ctrl_handler *hdl = &ctrls->handler;
+       int ret;
+
+       ret = v4l2_ctrl_handler_init(hdl, 16);
+       if (ret < 0) {
+               v4l2_err(&state->sd, "cannot init ctrl handler (%d)\n", ret);
+               return ret;
+       }
+
+       /* Auto white balance cluster */
+       ctrls->awb = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_AUTO_WHITE_BALANCE,
+                                      0, 1, 1, 1);
+       ctrls->gain_red = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_RED_BALANCE,
+                                           0, 255, 1, S5K5BAF_GAIN_RED_DEF);
+       ctrls->gain_blue = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BLUE_BALANCE,
+                                            0, 255, 1, S5K5BAF_GAIN_BLUE_DEF);
+       v4l2_ctrl_auto_cluster(3, &ctrls->awb, 0, false);
+
+       ctrls->hflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+       ctrls->vflip = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_cluster(2, &ctrls->hflip);
+
+       ctrls->auto_exp = v4l2_ctrl_new_std_menu(hdl, ops,
+                               V4L2_CID_EXPOSURE_AUTO,
+                               V4L2_EXPOSURE_MANUAL, 0, V4L2_EXPOSURE_AUTO);
+       /* Exposure time: x 1 us */
+       ctrls->exposure = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_EXPOSURE,
+                                           0, 6000000U, 1, 100000U);
+       /* Total gain: 256 <=> 1x */
+       ctrls->gain = v4l2_ctrl_new_std(hdl, ops, V4L2_CID_GAIN,
+                                       0, 256, 1, 256);
+       v4l2_ctrl_auto_cluster(3, &ctrls->auto_exp, 0, false);
+
+       v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_POWER_LINE_FREQUENCY,
+                              V4L2_CID_POWER_LINE_FREQUENCY_AUTO, 0,
+                              V4L2_CID_POWER_LINE_FREQUENCY_AUTO);
+
+       v4l2_ctrl_new_std_menu(hdl, ops, V4L2_CID_COLORFX,
+                              V4L2_COLORFX_SKY_BLUE, ~0x6f, V4L2_COLORFX_NONE);
+
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+                         0, 256, 1, 0);
+
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SATURATION, -127, 127, 1, 0);
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_BRIGHTNESS, -127, 127, 1, 0);
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_CONTRAST, -127, 127, 1, 0);
+       v4l2_ctrl_new_std(hdl, ops, V4L2_CID_SHARPNESS, -127, 127, 1, 0);
+
+       v4l2_ctrl_new_std_menu_items(hdl, ops, V4L2_CID_TEST_PATTERN,
+                                    ARRAY_SIZE(s5k5baf_test_pattern_menu) - 1,
+                                    0, 0, s5k5baf_test_pattern_menu);
+
+       if (hdl->error) {
+               v4l2_err(&state->sd, "error creating controls (%d)\n",
+                        hdl->error);
+               ret = hdl->error;
+               v4l2_ctrl_handler_free(hdl);
+               return ret;
+       }
+
+       state->sd.ctrl_handler = hdl;
+       return 0;
+}
+
+/*
+ * V4L2 subdev internal operations
+ */
+static int s5k5baf_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_mbus_framefmt *mf;
+
+       mf = v4l2_subdev_get_try_format(fh, PAD_CIS);
+       s5k5baf_try_cis_format(mf);
+
+       if (s5k5baf_is_cis_subdev(sd))
+               return 0;
+
+       mf = v4l2_subdev_get_try_format(fh, PAD_OUT);
+       mf->colorspace = s5k5baf_formats[0].colorspace;
+       mf->code = s5k5baf_formats[0].code;
+       mf->width = s5k5baf_cis_rect.width;
+       mf->height = s5k5baf_cis_rect.height;
+       mf->field = V4L2_FIELD_NONE;
+
+       *v4l2_subdev_get_try_crop(fh, PAD_CIS) = s5k5baf_cis_rect;
+       *v4l2_subdev_get_try_compose(fh, PAD_CIS) = s5k5baf_cis_rect;
+       *v4l2_subdev_get_try_crop(fh, PAD_OUT) = s5k5baf_cis_rect;
+
+       return 0;
+}
+
+static int s5k5baf_check_fw_revision(struct s5k5baf *state)
+{
+       u16 api_ver = 0, fw_rev = 0, s_id = 0;
+       int ret;
+
+       api_ver = s5k5baf_read(state, REG_FW_APIVER);
+       fw_rev = s5k5baf_read(state, REG_FW_REVISION) & 0xff;
+       s_id = s5k5baf_read(state, REG_FW_SENSOR_ID);
+       ret = s5k5baf_clear_error(state);
+       if (ret < 0)
+               return ret;
+
+       v4l2_info(&state->sd, "FW API=%#x, revision=%#x sensor_id=%#x\n",
+                 api_ver, fw_rev, s_id);
+
+       if (api_ver != S5K5BAF_FW_APIVER) {
+               v4l2_err(&state->sd, "FW API version not supported\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static int s5k5baf_registered(struct v4l2_subdev *sd)
+{
+       struct s5k5baf *state = to_s5k5baf(sd);
+       int ret;
+
+       ret = v4l2_device_register_subdev(sd->v4l2_dev, &state->cis_sd);
+       if (ret < 0)
+               v4l2_err(sd, "failed to register subdev %s\n",
+                        state->cis_sd.name);
+       else
+               ret = media_entity_create_link(&state->cis_sd.entity, PAD_CIS,
+                                              &state->sd.entity, PAD_CIS,
+                                              MEDIA_LNK_FL_IMMUTABLE |
+                                              MEDIA_LNK_FL_ENABLED);
+       return ret;
+}
+
+static void s5k5baf_unregistered(struct v4l2_subdev *sd)
+{
+       struct s5k5baf *state = to_s5k5baf(sd);
+       v4l2_device_unregister_subdev(&state->cis_sd);
+}
+
+static const struct v4l2_subdev_ops s5k5baf_cis_subdev_ops = {
+       .pad    = &s5k5baf_cis_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops s5k5baf_cis_subdev_internal_ops = {
+       .open = s5k5baf_open,
+};
+
+static const struct v4l2_subdev_internal_ops s5k5baf_subdev_internal_ops = {
+       .registered = s5k5baf_registered,
+       .unregistered = s5k5baf_unregistered,
+       .open = s5k5baf_open,
+};
+
+static const struct v4l2_subdev_core_ops s5k5baf_core_ops = {
+       .s_power = s5k5baf_set_power,
+       .log_status = v4l2_ctrl_subdev_log_status,
+};
+
+static const struct v4l2_subdev_ops s5k5baf_subdev_ops = {
+       .core = &s5k5baf_core_ops,
+       .pad = &s5k5baf_pad_ops,
+       .video = &s5k5baf_video_ops,
+};
+
+static int s5k5baf_configure_gpios(struct s5k5baf *state)
+{
+       static const char const *name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" };
+       struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
+       struct s5k5baf_gpio *g = state->gpios;
+       int ret, i;
+
+       for (i = 0; i < NUM_GPIOS; ++i) {
+               int flags = GPIOF_DIR_OUT;
+               if (g[i].level)
+                       flags |= GPIOF_INIT_HIGH;
+               ret = devm_gpio_request_one(&c->dev, g[i].gpio, flags, name[i]);
+               if (ret < 0) {
+                       v4l2_err(c, "failed to request gpio %s\n", name[i]);
+                       return ret;
+               }
+       }
+       return 0;
+}
+
+static int s5k5baf_parse_gpios(struct s5k5baf_gpio *gpios, struct device *dev)
+{
+       static const char * const names[] = {
+               "stbyn-gpios",
+               "rstn-gpios",
+       };
+       struct device_node *node = dev->of_node;
+       enum of_gpio_flags flags;
+       int ret, i;
+
+       for (i = 0; i < NUM_GPIOS; ++i) {
+               ret = of_get_named_gpio_flags(node, names[i], 0, &flags);
+               if (ret < 0) {
+                       dev_err(dev, "no %s GPIO pin provided\n", names[i]);
+                       return ret;
+               }
+               gpios[i].gpio = ret;
+               gpios[i].level = !(flags & OF_GPIO_ACTIVE_LOW);
+       }
+
+       return 0;
+}
+
+static int s5k5baf_parse_device_node(struct s5k5baf *state, struct device *dev)
+{
+       struct device_node *node = dev->of_node;
+       struct device_node *node_ep;
+       struct v4l2_of_endpoint ep;
+       int ret;
+
+       if (!node) {
+               dev_err(dev, "no device-tree node provided\n");
+               return -EINVAL;
+       }
+
+       ret = of_property_read_u32(node, "clock-frequency",
+                                  &state->mclk_frequency);
+       if (ret < 0) {
+               state->mclk_frequency = S5K5BAF_DEFAULT_MCLK_FREQ;
+               dev_info(dev, "using default %u Hz clock frequency\n",
+                        state->mclk_frequency);
+       }
+
+       ret = s5k5baf_parse_gpios(state->gpios, dev);
+       if (ret < 0)
+               return ret;
+
+       node_ep = v4l2_of_get_next_endpoint(node, NULL);
+       if (!node_ep) {
+               dev_err(dev, "no endpoint defined at node %s\n",
+                       node->full_name);
+               return -EINVAL;
+       }
+
+       v4l2_of_parse_endpoint(node_ep, &ep);
+       of_node_put(node_ep);
+       state->bus_type = ep.bus_type;
+
+       switch (state->bus_type) {
+       case V4L2_MBUS_CSI2:
+               state->nlanes = ep.bus.mipi_csi2.num_data_lanes;
+               break;
+       case V4L2_MBUS_PARALLEL:
+               break;
+       default:
+               dev_err(dev, "unsupported bus in endpoint defined at node %s\n",
+                       node->full_name);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int s5k5baf_configure_subdevs(struct s5k5baf *state,
+                                    struct i2c_client *c)
+{
+       struct v4l2_subdev *sd;
+       int ret;
+
+       sd = &state->cis_sd;
+       v4l2_subdev_init(sd, &s5k5baf_cis_subdev_ops);
+       sd->owner = THIS_MODULE;
+       v4l2_set_subdevdata(sd, state);
+       snprintf(sd->name, sizeof(sd->name), "S5K5BAF-CIS %d-%04x",
+                i2c_adapter_id(c->adapter), c->addr);
+
+       sd->internal_ops = &s5k5baf_cis_subdev_internal_ops;
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       state->cis_pad.flags = MEDIA_PAD_FL_SOURCE;
+       sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV_SENSOR;
+       ret = media_entity_init(&sd->entity, NUM_CIS_PADS, &state->cis_pad, 0);
+       if (ret < 0)
+               goto err;
+
+       sd = &state->sd;
+       v4l2_i2c_subdev_init(sd, c, &s5k5baf_subdev_ops);
+       snprintf(sd->name, sizeof(sd->name), "S5K5BAF-ISP %d-%04x",
+                i2c_adapter_id(c->adapter), c->addr);
+
+       sd->internal_ops = &s5k5baf_subdev_internal_ops;
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       state->pads[PAD_CIS].flags = MEDIA_PAD_FL_SINK;
+       state->pads[PAD_OUT].flags = MEDIA_PAD_FL_SOURCE;
+       sd->entity.type = MEDIA_ENT_T_V4L2_SUBDEV;
+       ret = media_entity_init(&sd->entity, NUM_ISP_PADS, state->pads, 0);
+
+       if (!ret)
+               return 0;
+
+       media_entity_cleanup(&state->cis_sd.entity);
+err:
+       dev_err(&c->dev, "cannot init media entity %s\n", sd->name);
+       return ret;
+}
+
+static int s5k5baf_configure_regulators(struct s5k5baf *state)
+{
+       struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
+       int ret;
+       int i;
+
+       for (i = 0; i < S5K5BAF_NUM_SUPPLIES; i++)
+               state->supplies[i].supply = s5k5baf_supply_names[i];
+
+       ret = devm_regulator_bulk_get(&c->dev, S5K5BAF_NUM_SUPPLIES,
+                                     state->supplies);
+       if (ret < 0)
+               v4l2_err(c, "failed to get regulators\n");
+       return ret;
+}
+
+static int s5k5baf_probe(struct i2c_client *c,
+                       const struct i2c_device_id *id)
+{
+       struct s5k5baf *state;
+       int ret;
+
+       state = devm_kzalloc(&c->dev, sizeof(*state), GFP_KERNEL);
+       if (!state)
+               return -ENOMEM;
+
+       mutex_init(&state->lock);
+       state->crop_sink = s5k5baf_cis_rect;
+       state->compose = s5k5baf_cis_rect;
+       state->crop_source = s5k5baf_cis_rect;
+
+       ret = s5k5baf_parse_device_node(state, &c->dev);
+       if (ret < 0)
+               return ret;
+
+       ret = s5k5baf_configure_subdevs(state, c);
+       if (ret < 0)
+               return ret;
+
+       ret = s5k5baf_configure_gpios(state);
+       if (ret < 0)
+               goto err_me;
+
+       ret = s5k5baf_configure_regulators(state);
+       if (ret < 0)
+               goto err_me;
+
+       state->clock = devm_clk_get(state->sd.dev, S5K5BAF_CLK_NAME);
+       if (IS_ERR(state->clock)) {
+               ret = -EPROBE_DEFER;
+               goto err_me;
+       }
+
+       ret = s5k5baf_power_on(state);
+       if (ret < 0) {
+               ret = -EPROBE_DEFER;
+               goto err_me;
+       }
+       s5k5baf_hw_init(state);
+       ret = s5k5baf_check_fw_revision(state);
+
+       s5k5baf_power_off(state);
+       if (ret < 0)
+               goto err_me;
+
+       ret = s5k5baf_initialize_ctrls(state);
+       if (ret < 0)
+               goto err_me;
+
+       ret = v4l2_async_register_subdev(&state->sd);
+       if (ret < 0)
+               goto err_ctrl;
+
+       return 0;
+
+err_ctrl:
+       v4l2_ctrl_handler_free(state->sd.ctrl_handler);
+err_me:
+       media_entity_cleanup(&state->sd.entity);
+       media_entity_cleanup(&state->cis_sd.entity);
+       return ret;
+}
+
+static int s5k5baf_remove(struct i2c_client *c)
+{
+       struct v4l2_subdev *sd = i2c_get_clientdata(c);
+       struct s5k5baf *state = to_s5k5baf(sd);
+
+       v4l2_async_unregister_subdev(sd);
+       v4l2_ctrl_handler_free(sd->ctrl_handler);
+       media_entity_cleanup(&sd->entity);
+
+       sd = &state->cis_sd;
+       v4l2_device_unregister_subdev(sd);
+       media_entity_cleanup(&sd->entity);
+
+       return 0;
+}
+
+static const struct i2c_device_id s5k5baf_id[] = {
+       { S5K5BAF_DRIVER_NAME, 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, s5k5baf_id);
+
+static const struct of_device_id s5k5baf_of_match[] = {
+       { .compatible = "samsung,s5k5baf" },
+       { }
+};
+MODULE_DEVICE_TABLE(of, s5k5baf_of_match);
+
+static struct i2c_driver s5k5baf_i2c_driver = {
+       .driver = {
+               .of_match_table = s5k5baf_of_match,
+               .name = S5K5BAF_DRIVER_NAME
+       },
+       .probe          = s5k5baf_probe,
+       .remove         = s5k5baf_remove,
+       .id_table       = s5k5baf_id,
+};
+
+module_i2c_driver(s5k5baf_i2c_driver);
+
+MODULE_DESCRIPTION("Samsung S5K5BAF(X) UXGA camera driver");
+MODULE_AUTHOR("Andrzej Hajda <a.hajda@samsung.com>");
+MODULE_LICENSE("GPL v2");
index 70bc72e795d04b30814e32eb599f3b42f1de4328..2960b5a8362a4965c6f5198404ea76a86693d1f8 100644 (file)
@@ -150,14 +150,14 @@ static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
 
 /* ---------------------------------------------------------------------- */
 
-static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
+static bool block_from_buf(struct saa6588 *s, unsigned char *buf)
 {
        int i;
 
        if (s->rd_index == s->wr_index) {
                if (debug > 2)
                        dprintk(PREFIX "Read: buffer empty.\n");
-               return 0;
+               return false;
        }
 
        if (debug > 2) {
@@ -166,8 +166,7 @@ static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
                        dprintk("0x%02x ", s->buffer[i]);
        }
 
-       if (copy_to_user(user_buf, &s->buffer[s->rd_index], 3))
-               return -EFAULT;
+       memcpy(buf, &s->buffer[s->rd_index], 3);
 
        s->rd_index += 3;
        if (s->rd_index >= s->buf_size)
@@ -177,22 +176,22 @@ static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
        if (debug > 2)
                dprintk("%d blocks total.\n", s->block_count);
 
-       return 1;
+       return true;
 }
 
 static void read_from_buf(struct saa6588 *s, struct saa6588_command *a)
 {
-       unsigned long flags;
-
        unsigned char __user *buf_ptr = a->buffer;
-       unsigned int i;
+       unsigned char buf[3];
+       unsigned long flags;
        unsigned int rd_blocks;
+       unsigned int i;
 
        a->result = 0;
        if (!a->buffer)
                return;
 
-       while (!s->data_available_for_read) {
+       while (!a->nonblocking && !s->data_available_for_read) {
                int ret = wait_event_interruptible(s->read_queue,
                                             s->data_available_for_read);
                if (ret == -ERESTARTSYS) {
@@ -201,24 +200,31 @@ static void read_from_buf(struct saa6588 *s, struct saa6588_command *a)
                }
        }
 
-       spin_lock_irqsave(&s->lock, flags);
        rd_blocks = a->block_count;
+       spin_lock_irqsave(&s->lock, flags);
        if (rd_blocks > s->block_count)
                rd_blocks = s->block_count;
+       spin_unlock_irqrestore(&s->lock, flags);
 
-       if (!rd_blocks) {
-               spin_unlock_irqrestore(&s->lock, flags);
+       if (!rd_blocks)
                return;
-       }
 
        for (i = 0; i < rd_blocks; i++) {
-               if (block_to_user_buf(s, buf_ptr)) {
-                       buf_ptr += 3;
-                       a->result++;
-               } else
+               bool got_block;
+
+               spin_lock_irqsave(&s->lock, flags);
+               got_block = block_from_buf(s, buf);
+               spin_unlock_irqrestore(&s->lock, flags);
+               if (!got_block)
                        break;
+               if (copy_to_user(buf_ptr, buf, 3)) {
+                       a->result = -EFAULT;
+                       return;
+               }
+               buf_ptr += 3;
+               a->result += 3;
        }
-       a->result *= 3;
+       spin_lock_irqsave(&s->lock, flags);
        s->data_available_for_read = (s->block_count > 0);
        spin_unlock_irqrestore(&s->lock, flags);
 }
@@ -394,14 +400,11 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
        struct saa6588_command *a = arg;
 
        switch (cmd) {
-               /* --- open() for /dev/radio --- */
-       case SAA6588_CMD_OPEN:
-               a->result = 0;  /* return error if chip doesn't work ??? */
-               break;
                /* --- close() for /dev/radio --- */
        case SAA6588_CMD_CLOSE:
                s->data_available_for_read = 1;
                wake_up_interruptible(&s->read_queue);
+               s->data_available_for_read = 0;
                a->result = 0;
                break;
                /* --- read() for /dev/radio --- */
@@ -411,9 +414,8 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
                /* --- poll() for /dev/radio --- */
        case SAA6588_CMD_POLL:
                a->result = 0;
-               if (s->data_available_for_read) {
+               if (s->data_available_for_read)
                        a->result |= POLLIN | POLLRDNORM;
-               }
                poll_wait(a->instance, &s->read_queue, a->event_list);
                break;
 
similarity index 98%
rename from drivers/media/pci/saa7134/saa6752hs.c
rename to drivers/media/i2c/saa6752hs.c
index 8ac4b1f2322d7e63a6632c640e45497f3355b32e..8272c0b9c5bf6e103294053316ed16fb0c87c317 100644 (file)
 #include <linux/i2c.h>
 #include <linux/types.h>
 #include <linux/videodev2.h>
+#include <linux/init.h>
+#include <linux/crc32.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/v4l2-common.h>
-#include <linux/init.h>
-#include <linux/crc32.h>
 
 #define MPEG_VIDEO_TARGET_BITRATE_MAX  27000
 #define MPEG_VIDEO_MAX_BITRATE_MAX     27000
@@ -124,7 +124,7 @@ static inline struct saa6752hs_state *to_state(struct v4l2_subdev *sd)
 
 /* ---------------------------------------------------------------------- */
 
-static u8 PAT[] = {
+static const u8 PAT[] = {
        0xc2, /* i2c register */
        0x00, /* table number for encoder */
 
@@ -150,7 +150,7 @@ static u8 PAT[] = {
        0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
-static u8 PMT[] = {
+static const u8 PMT[] = {
        0xc2, /* i2c register */
        0x01, /* table number for encoder */
 
@@ -179,7 +179,7 @@ static u8 PMT[] = {
        0x00, 0x00, 0x00, 0x00 /* CRC32 */
 };
 
-static u8 PMT_AC3[] = {
+static const u8 PMT_AC3[] = {
        0xc2, /* i2c register */
        0x01, /* table number for encoder(1) */
        0x47, /* sync */
@@ -212,7 +212,7 @@ static u8 PMT_AC3[] = {
        0xED, 0xDE, 0x2D, 0xF3 /* CRC32 BE */
 };
 
-static struct saa6752hs_mpeg_params param_defaults =
+static const struct saa6752hs_mpeg_params param_defaults =
 {
        .ts_pid_pmt      = 16,
        .ts_pid_video    = 260,
@@ -643,13 +643,6 @@ static const struct v4l2_ctrl_ops saa6752hs_ctrl_ops = {
 
 static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
        .init = saa6752hs_init,
-       .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
-       .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
-       .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
-       .g_ctrl = v4l2_subdev_g_ctrl,
-       .s_ctrl = v4l2_subdev_s_ctrl,
-       .queryctrl = v4l2_subdev_queryctrl,
-       .querymenu = v4l2_subdev_querymenu,
        .s_std = saa6752hs_s_std,
 };
 
index ae66d91bf7136c2e494432cea21d8359654f89a6..8741cae9c9f24aaa8891ec4efd4f8ce757a08da0 100644 (file)
@@ -399,7 +399,6 @@ static void smiapp_update_mbus_formats(struct smiapp_sensor *sensor)
 
        BUG_ON(max(internal_csi_format_idx, csi_format_idx) + pixel_order
               >= ARRAY_SIZE(smiapp_csi_data_formats));
-       BUG_ON(min(internal_csi_format_idx, csi_format_idx) < 0);
 
        dev_dbg(&client->dev, "new pixel order %s\n",
                pixel_order_str[pixel_order]);
@@ -2028,8 +2027,8 @@ static int smiapp_set_crop(struct v4l2_subdev *subdev,
        sel->r.width = min(sel->r.width, src_size->width);
        sel->r.height = min(sel->r.height, src_size->height);
 
-       sel->r.left = min(sel->r.left, src_size->width - sel->r.width);
-       sel->r.top = min(sel->r.top, src_size->height - sel->r.height);
+       sel->r.left = min_t(int, sel->r.left, src_size->width - sel->r.width);
+       sel->r.top = min_t(int, sel->r.top, src_size->height - sel->r.height);
 
        *crops[sel->pad] = sel->r;
 
@@ -2121,8 +2120,8 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev,
 
        sel->r.left = max(0, sel->r.left & ~1);
        sel->r.top = max(0, sel->r.top & ~1);
-       sel->r.width = max(0, SMIAPP_ALIGN_DIM(sel->r.width, sel->flags));
-       sel->r.height = max(0, SMIAPP_ALIGN_DIM(sel->r.height, sel->flags));
+       sel->r.width = SMIAPP_ALIGN_DIM(sel->r.width, sel->flags);
+       sel->r.height = SMIAPP_ALIGN_DIM(sel->r.height, sel->flags);
 
        sel->r.width = max_t(unsigned int,
                             sensor->limits[SMIAPP_LIMIT_MIN_X_OUTPUT_SIZE],
index 6f4056668bbcf513cc7a6abc25e539b949453ee0..ccf59406a17229f7356d1ee8ba90fd03314a88ea 100644 (file)
@@ -208,8 +208,8 @@ struct mt9m111 {
        struct mt9m111_context *ctx;
        struct v4l2_rect rect;  /* cropping rectangle */
        struct v4l2_clk *clk;
-       int width;              /* output */
-       int height;             /* sizes */
+       unsigned int width;     /* output */
+       unsigned int height;    /* sizes */
        struct mutex power_lock; /* lock to protect power_count */
        int power_count;
        const struct mt9m111_datafmt *fmt;
index 89c0b13463b73354b3fa56ce5bcc57b2fe989613..542d2528b3f913767c37db19512303dbed2e76b2 100644 (file)
@@ -58,21 +58,17 @@ static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
        struct i2c_client *c = v4l2_get_subdevdata(sd);
        unsigned char buffer[1];
        int rc;
-
-       buffer[0] = addr;
-
-       rc = i2c_master_send(c, buffer, 1);
-       if (rc < 0) {
-               v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
-               return rc;
-       }
-
-       msleep(10);
-
-       rc = i2c_master_recv(c, buffer, 1);
-       if (rc < 0) {
-               v4l2_err(sd, "i2c i/o error: rc == %d (should be 1)\n", rc);
-               return rc;
+       struct i2c_msg msg[] = {
+               { .addr = c->addr, .flags = 0,
+                 .buf = &addr, .len = 1 },
+               { .addr = c->addr, .flags = I2C_M_RD,
+                 .buf = buffer, .len = 1 }
+       };
+
+       rc = i2c_transfer(c->adapter, msg, 2);
+       if (rc < 0 || rc != 2) {
+               v4l2_err(sd, "i2c i/o error: rc == %d (should be 2)\n", rc);
+               return rc < 0 ? rc : -EIO;
        }
 
        v4l2_dbg(2, debug, sd, "tvp5150: read 0x%02x = 0x%02x\n", addr, buffer[0]);
@@ -867,7 +863,7 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
        struct v4l2_rect rect = a->c;
        struct tvp5150 *decoder = to_tvp5150(sd);
        v4l2_std_id std;
-       int hmax;
+       unsigned int hmax;
 
        v4l2_dbg(1, debug, sd, "%s left=%d, top=%d, width=%d, height=%d\n",
                __func__, rect.left, rect.top, rect.width, rect.height);
@@ -877,9 +873,9 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
 
        /* tvp5150 has some special limits */
        rect.left = clamp(rect.left, 0, TVP5150_MAX_CROP_LEFT);
-       rect.width = clamp(rect.width,
-                          TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
-                          TVP5150_H_MAX - rect.left);
+       rect.width = clamp_t(unsigned int, rect.width,
+                            TVP5150_H_MAX - TVP5150_MAX_CROP_LEFT - rect.left,
+                            TVP5150_H_MAX - rect.left);
        rect.top = clamp(rect.top, 0, TVP5150_MAX_CROP_TOP);
 
        /* Calculate height based on current standard */
@@ -893,9 +889,9 @@ static int tvp5150_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
        else
                hmax = TVP5150_V_MAX_OTHERS;
 
-       rect.height = clamp(rect.height,
-                           hmax - TVP5150_MAX_CROP_TOP - rect.top,
-                           hmax - rect.top);
+       rect.height = clamp_t(unsigned int, rect.height,
+                             hmax - TVP5150_MAX_CROP_TOP - rect.top,
+                             hmax - rect.top);
 
        tvp5150_write(sd, TVP5150_VERT_BLANKING_START, rect.top);
        tvp5150_write(sd, TVP5150_VERT_BLANKING_STOP,
index 25bdd9312fea5a0f1de997632fd02e4e9b6a8ae1..23f4f65fccd7ac19b43bc33fb377bdf0cc9bd8af 100644 (file)
@@ -503,6 +503,7 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
        return &container_of(ctrl->handler, struct vs6624, hdl)->sd;
 }
 
+#ifdef CONFIG_VIDEO_ADV_DEBUG
 static int vs6624_read(struct v4l2_subdev *sd, u16 index)
 {
        struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -515,6 +516,7 @@ static int vs6624_read(struct v4l2_subdev *sd, u16 index)
 
        return buf[0];
 }
+#endif
 
 static int vs6624_write(struct v4l2_subdev *sd, u16 index,
                                u8 value)
index 2c286c307145b6828a7ac8c3b4bfc4f05ae18735..37c334edc7e8c10d3a6430f64a29b1f16088d929 100644 (file)
@@ -235,6 +235,8 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
        media_entity_graph_walk_start(&graph, entity);
 
        while ((entity = media_entity_graph_walk_next(&graph))) {
+               DECLARE_BITMAP(active, entity->num_pads);
+               DECLARE_BITMAP(has_no_links, entity->num_pads);
                unsigned int i;
 
                entity->stream_count++;
@@ -248,21 +250,46 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
                if (!entity->ops || !entity->ops->link_validate)
                        continue;
 
+               bitmap_zero(active, entity->num_pads);
+               bitmap_fill(has_no_links, entity->num_pads);
+
                for (i = 0; i < entity->num_links; i++) {
                        struct media_link *link = &entity->links[i];
-
-                       /* Is this pad part of an enabled link? */
-                       if (!(link->flags & MEDIA_LNK_FL_ENABLED))
-                               continue;
-
-                       /* Are we the sink or not? */
-                       if (link->sink->entity != entity)
+                       struct media_pad *pad = link->sink->entity == entity
+                                               ? link->sink : link->source;
+
+                       /* Mark that a pad is connected by a link. */
+                       bitmap_clear(has_no_links, pad->index, 1);
+
+                       /*
+                        * Pads that either do not need to connect or
+                        * are connected through an enabled link are
+                        * fine.
+                        */
+                       if (!(pad->flags & MEDIA_PAD_FL_MUST_CONNECT) ||
+                           link->flags & MEDIA_LNK_FL_ENABLED)
+                               bitmap_set(active, pad->index, 1);
+
+                       /*
+                        * Link validation will only take place for
+                        * sink ends of the link that are enabled.
+                        */
+                       if (link->sink != pad ||
+                           !(link->flags & MEDIA_LNK_FL_ENABLED))
                                continue;
 
                        ret = entity->ops->link_validate(link);
                        if (ret < 0 && ret != -ENOIOCTLCMD)
                                goto error;
                }
+
+               /* Either no links or validated links are fine. */
+               bitmap_or(active, active, has_no_links, entity->num_pads);
+
+               if (!bitmap_full(active, entity->num_pads)) {
+                       ret = -EPIPE;
+                       goto error;
+               }
        }
 
        mutex_unlock(&mdev->graph_mutex);
index 92a06fd858652acddff2dd65ce07dee560445df1..afcd53bfcf8ec88264c97fd80c75b373e2512810 100644 (file)
@@ -1126,9 +1126,9 @@ bttv_crop_calc_limits(struct bttv_crop *c)
                c->min_scaled_height = 32;
        } else {
                c->min_scaled_width =
-                       (max(48, c->rect.width >> 4) + 3) & ~3;
+                       (max_t(unsigned int, 48, c->rect.width >> 4) + 3) & ~3;
                c->min_scaled_height =
-                       max(32, c->rect.height >> 4);
+                       max_t(unsigned int, 32, c->rect.height >> 4);
        }
 
        c->max_scaled_width  = c->rect.width & ~3;
@@ -2024,7 +2024,7 @@ limit_scaled_size_lock       (struct bttv_fh *               fh,
                /* We cannot scale up. When the scaled image is larger
                   than crop.rect we adjust the crop.rect as required
                   by the V4L2 spec, hence cropcap.bounds are our limit. */
-               max_width = min(b->width, (__s32) MAX_HACTIVE);
+               max_width = min_t(unsigned int, b->width, MAX_HACTIVE);
                max_height = b->height;
 
                /* We cannot capture the same line as video and VBI data.
@@ -3266,7 +3266,9 @@ static ssize_t radio_read(struct file *file, char __user *data,
        struct bttv_fh *fh = file->private_data;
        struct bttv *btv = fh->btv;
        struct saa6588_command cmd;
-       cmd.block_count = count/3;
+
+       cmd.block_count = count / 3;
+       cmd.nonblocking = file->f_flags & O_NONBLOCK;
        cmd.buffer = data;
        cmd.instance = file;
        cmd.result = -ENODEV;
index c1f8cc6f14b21ed74b024dd8c0b4425ed1425cdc..716bdc57fac6fb298a904602675605d21c486d2a 100644 (file)
@@ -327,13 +327,16 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
        struct i2c_client *c;
        u8 eedata[256];
 
+       memset(tv, 0, sizeof(*tv));
+
        c = kzalloc(sizeof(*c), GFP_KERNEL);
+       if (!c)
+               return;
 
        strlcpy(c->name, "cx18 tveeprom tmp", sizeof(c->name));
        c->adapter = &cx->i2c_adap[0];
        c->addr = 0xa0 >> 1;
 
-       memset(tv, 0, sizeof(*tv));
        if (tveeprom_read(c, eedata, sizeof(eedata)))
                goto ret;
 
index 6e91e84d6bf978a139d01c0213cf0597765a96b8..b1e08c3e55cd5561d286700f470adcaf3e182776 100644 (file)
@@ -618,7 +618,7 @@ static int snd_cx25821_pcm(struct cx25821_audio_dev *chip, int device,
  * Only boards with eeprom and byte 1 at eeprom=1 have it
  */
 
-static DEFINE_PCI_DEVICE_TABLE(cx25821_audio_pci_tbl) = {
+static const struct pci_device_id cx25821_audio_pci_tbl[] = {
        {0x14f1, 0x0920, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
        {0,}
 };
index b762c5b2ca100306e1638969c4538ad79a6c03a7..e81173c41e5aaee45fa9168ebb243b486c39b7b7 100644 (file)
@@ -1361,7 +1361,7 @@ static void cx25821_finidev(struct pci_dev *pci_dev)
        kfree(dev);
 }
 
-static DEFINE_PCI_DEVICE_TABLE(cx25821_pci_tbl) = {
+static const struct pci_device_id cx25821_pci_tbl[] = {
        {
                /* CX25821 Athena */
                .vendor = 0x14f1,
index 400eb1c42d3f9529a946017ec3f6dd4fcae3424c..d014206e71762799ad007ce676af13cef333566a 100644 (file)
@@ -931,9 +931,9 @@ error:
  */
 static void cx88_audio_finidev(struct pci_dev *pci)
 {
-       struct cx88_audio_dev *card = pci_get_drvdata(pci);
+       struct snd_card *card = pci_get_drvdata(pci);
 
-       snd_card_free((void *)card);
+       snd_card_free(card);
 
        devno--;
 }
index 15b90d6e9130a79608933308c1773584a30fdb80..7883393571e55df01d907bf9472f93e9739a5884 100644 (file)
@@ -6,6 +6,7 @@ config VIDEO_SAA7134
        select VIDEO_TVEEPROM
        select CRC32
        select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT
+       select VIDEO_SAA6752HS if MEDIA_SUBDRV_AUTOSELECT
        ---help---
          This is a video4linux driver for Philips SAA713x based
          TV cards.
index 35375480ed4d30cb2a57e2c82e1f16c3a23999e6..58de9b085689bc101b01b2641db9e8f91f5a1b1c 100644 (file)
@@ -4,7 +4,7 @@ saa7134-y +=    saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o
 saa7134-y +=   saa7134-video.o
 saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
 
-obj-$(CONFIG_VIDEO_SAA7134) +=  saa6752hs.o saa7134.o saa7134-empress.o
+obj-$(CONFIG_VIDEO_SAA7134) +=  saa7134.o saa7134-empress.o
 
 obj-$(CONFIG_VIDEO_SAA7134_ALSA) += saa7134-alsa.o
 
index 27d7ee709c5895ddd29eb956992c6a9ebc97bff9..1362b4aab47327f95088476d0c45fc0ca48d611e 100644 (file)
@@ -751,6 +751,7 @@ static int saa7134_hwfini(struct saa7134_dev *dev)
        saa7134_input_fini(dev);
        saa7134_vbi_fini(dev);
        saa7134_tvaudio_fini(dev);
+       saa7134_video_fini(dev);
        return 0;
 }
 
@@ -802,7 +803,6 @@ static struct video_device *vdev_init(struct saa7134_dev *dev,
        *vfd = *template;
        vfd->v4l2_dev  = &dev->v4l2_dev;
        vfd->release = video_device_release;
-       vfd->debug   = video_debug;
        snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
                 dev->name, type, saa7134_boards[dev->board].name);
        set_bit(V4L2_FL_USE_FH_PRIO, &vfd->flags);
@@ -1008,13 +1008,13 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
 
        /* load i2c helpers */
        if (card_is_empress(dev)) {
-               struct v4l2_subdev *sd =
+               dev->empress_sd =
                        v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
                                "saa6752hs",
                                saa7134_boards[dev->board].empress_addr, NULL);
 
-               if (sd)
-                       sd->grp_id = GRP_EMPRESS;
+               if (dev->empress_sd)
+                       dev->empress_sd->grp_id = GRP_EMPRESS;
        }
 
        if (saa7134_boards[dev->board].rds_addr) {
@@ -1046,6 +1046,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
                printk(KERN_INFO "%s: Overlay support disabled.\n", dev->name);
 
        dev->video_dev = vdev_init(dev,&saa7134_video_template,"video");
+       dev->video_dev->ctrl_handler = &dev->ctrl_handler;
        err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
                                    video_nr[dev->nr]);
        if (err < 0) {
@@ -1057,6 +1058,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
               dev->name, video_device_node_name(dev->video_dev));
 
        dev->vbi_dev = vdev_init(dev, &saa7134_video_template, "vbi");
+       dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
 
        err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
                                    vbi_nr[dev->nr]);
@@ -1067,6 +1069,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
 
        if (card_has_radio(dev)) {
                dev->radio_dev = vdev_init(dev,&saa7134_radio_template,"radio");
+               dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
                err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
                                            radio_nr[dev->nr]);
                if (err < 0)
index 3022eb2a792503bc065863d6209c38a9d30d5014..0a9047e754b9765de54f6e99ff791d68be0bb305 100644 (file)
 #include <linux/kernel.h>
 #include <linux/delay.h>
 
+#include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
+
 #include "saa7134-reg.h"
 #include "saa7134.h"
 
-#include <media/saa6752hs.h>
-#include <media/v4l2-common.h>
-
 /* ------------------------------------------------------------------ */
 
 MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
@@ -85,52 +85,54 @@ static int ts_open(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
        struct saa7134_dev *dev = video_drvdata(file);
-       int err;
+       struct saa7134_fh *fh;
 
-       dprintk("open dev=%s\n", video_device_node_name(vdev));
-       err = -EBUSY;
-       if (!mutex_trylock(&dev->empress_tsq.vb_lock))
-               return err;
-       if (atomic_read(&dev->empress_users))
-               goto done;
+       /* allocate + initialize per filehandle data */
+       fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+       if (NULL == fh)
+               return -ENOMEM;
+
+       v4l2_fh_init(&fh->fh, vdev);
+       file->private_data = fh;
+       fh->is_empress = true;
+       v4l2_fh_add(&fh->fh);
 
        /* Unmute audio */
        saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
                saa_readb(SAA7134_AUDIO_MUTE_CTRL) & ~(1 << 6));
 
-       atomic_inc(&dev->empress_users);
-       file->private_data = dev;
-       err = 0;
-
-done:
-       mutex_unlock(&dev->empress_tsq.vb_lock);
-       return err;
+       return 0;
 }
 
 static int ts_release(struct file *file)
 {
-       struct saa7134_dev *dev = file->private_data;
+       struct saa7134_dev *dev = video_drvdata(file);
+       struct saa7134_fh *fh = file->private_data;
 
-       videobuf_stop(&dev->empress_tsq);
-       videobuf_mmap_free(&dev->empress_tsq);
+       if (res_check(fh, RESOURCE_EMPRESS)) {
+               videobuf_stop(&dev->empress_tsq);
+               videobuf_mmap_free(&dev->empress_tsq);
 
-       /* stop the encoder */
-       ts_reset_encoder(dev);
+               /* stop the encoder */
+               ts_reset_encoder(dev);
 
-       /* Mute audio */
-       saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
-               saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
-
-       atomic_dec(&dev->empress_users);
+               /* Mute audio */
+               saa_writeb(SAA7134_AUDIO_MUTE_CTRL,
+                               saa_readb(SAA7134_AUDIO_MUTE_CTRL) | (1 << 6));
+       }
 
+       v4l2_fh_del(&fh->fh);
+       v4l2_fh_exit(&fh->fh);
        return 0;
 }
 
 static ssize_t
 ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
-       struct saa7134_dev *dev = file->private_data;
+       struct saa7134_dev *dev = video_drvdata(file);
 
+       if (res_locked(dev, RESOURCE_EMPRESS))
+               return -EBUSY;
        if (!dev->empress_started)
                ts_init_encoder(dev);
 
@@ -142,68 +144,27 @@ ts_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 static unsigned int
 ts_poll(struct file *file, struct poll_table_struct *wait)
 {
-       struct saa7134_dev *dev = file->private_data;
+       unsigned long req_events = poll_requested_events(wait);
+       struct saa7134_dev *dev = video_drvdata(file);
+       struct saa7134_fh *fh = file->private_data;
+       unsigned int rc = 0;
 
-       return videobuf_poll_stream(file, &dev->empress_tsq, wait);
+       if (v4l2_event_pending(&fh->fh))
+               rc = POLLPRI;
+       else if (req_events & POLLPRI)
+               poll_wait(file, &fh->fh.wait, wait);
+       return rc | videobuf_poll_stream(file, &dev->empress_tsq, wait);
 }
 
 
 static int
 ts_mmap(struct file *file, struct vm_area_struct * vma)
 {
-       struct saa7134_dev *dev = file->private_data;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        return videobuf_mmap_mapper(&dev->empress_tsq, vma);
 }
 
-/*
- * This function is _not_ called directly, but from
- * video_generic_ioctl (and maybe others).  userspace
- * copying is done already, arg is a kernel pointer.
- */
-
-static int empress_querycap(struct file *file, void  *priv,
-                                       struct v4l2_capability *cap)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       strcpy(cap->driver, "saa7134");
-       strlcpy(cap->card, saa7134_boards[dev->board].name,
-               sizeof(cap->card));
-       sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
-       cap->capabilities =
-               V4L2_CAP_VIDEO_CAPTURE |
-               V4L2_CAP_READWRITE |
-               V4L2_CAP_STREAMING;
-       return 0;
-}
-
-static int empress_enum_input(struct file *file, void *priv,
-                                       struct v4l2_input *i)
-{
-       if (i->index != 0)
-               return -EINVAL;
-
-       i->type = V4L2_INPUT_TYPE_CAMERA;
-       strcpy(i->name, "CCIR656");
-
-       return 0;
-}
-
-static int empress_g_input(struct file *file, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int empress_s_input(struct file *file, void *priv, unsigned int i)
-{
-       if (i != 0)
-               return -EINVAL;
-
-       return 0;
-}
-
 static int empress_enum_fmt_vid_cap(struct file *file, void  *priv,
                                        struct v4l2_fmtdesc *f)
 {
@@ -219,7 +180,7 @@ static int empress_enum_fmt_vid_cap(struct file *file, void  *priv,
 static int empress_g_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct saa7134_dev *dev = file->private_data;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct v4l2_mbus_framefmt mbus_fmt;
 
        saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt);
@@ -236,7 +197,7 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
 static int empress_s_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct saa7134_dev *dev = file->private_data;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct v4l2_mbus_framefmt mbus_fmt;
 
        v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
@@ -254,7 +215,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
 static int empress_try_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct saa7134_dev *dev = file->private_data;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct v4l2_mbus_framefmt mbus_fmt;
 
        v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
@@ -269,175 +230,6 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
-static int empress_reqbufs(struct file *file, void *priv,
-                                       struct v4l2_requestbuffers *p)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       return videobuf_reqbufs(&dev->empress_tsq, p);
-}
-
-static int empress_querybuf(struct file *file, void *priv,
-                                       struct v4l2_buffer *b)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       return videobuf_querybuf(&dev->empress_tsq, b);
-}
-
-static int empress_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       return videobuf_qbuf(&dev->empress_tsq, b);
-}
-
-static int empress_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       return videobuf_dqbuf(&dev->empress_tsq, b,
-                               file->f_flags & O_NONBLOCK);
-}
-
-static int empress_streamon(struct file *file, void *priv,
-                                       enum v4l2_buf_type type)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       return videobuf_streamon(&dev->empress_tsq);
-}
-
-static int empress_streamoff(struct file *file, void *priv,
-                                       enum v4l2_buf_type type)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       return videobuf_streamoff(&dev->empress_tsq);
-}
-
-static int empress_s_ext_ctrls(struct file *file, void *priv,
-                              struct v4l2_ext_controls *ctrls)
-{
-       struct saa7134_dev *dev = file->private_data;
-       int err;
-
-       /* count == 0 is abused in saa6752hs.c, so that special
-               case is handled here explicitly. */
-       if (ctrls->count == 0)
-               return 0;
-
-       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-
-       err = saa_call_empress(dev, core, s_ext_ctrls, ctrls);
-       ts_init_encoder(dev);
-
-       return err;
-}
-
-static int empress_g_ext_ctrls(struct file *file, void *priv,
-                              struct v4l2_ext_controls *ctrls)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-       return saa_call_empress(dev, core, g_ext_ctrls, ctrls);
-}
-
-static int empress_g_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *c)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       return saa7134_g_ctrl_internal(dev, NULL, c);
-}
-
-static int empress_s_ctrl(struct file *file, void *priv,
-                                       struct v4l2_control *c)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       return saa7134_s_ctrl_internal(dev, NULL, c);
-}
-
-static int empress_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *c)
-{
-       /* Must be sorted from low to high control ID! */
-       static const u32 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,
-               V4L2_CID_HFLIP,
-               0
-       };
-
-       /* Must be sorted from low to high control ID! */
-       static const u32 mpeg_ctrls[] = {
-               V4L2_CID_MPEG_CLASS,
-               V4L2_CID_MPEG_STREAM_TYPE,
-               V4L2_CID_MPEG_STREAM_PID_PMT,
-               V4L2_CID_MPEG_STREAM_PID_AUDIO,
-               V4L2_CID_MPEG_STREAM_PID_VIDEO,
-               V4L2_CID_MPEG_STREAM_PID_PCR,
-               V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
-               V4L2_CID_MPEG_AUDIO_ENCODING,
-               V4L2_CID_MPEG_AUDIO_L2_BITRATE,
-               V4L2_CID_MPEG_VIDEO_ENCODING,
-               V4L2_CID_MPEG_VIDEO_ASPECT,
-               V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
-               V4L2_CID_MPEG_VIDEO_BITRATE,
-               V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
-               0
-       };
-       static const u32 *ctrl_classes[] = {
-               user_ctrls,
-               mpeg_ctrls,
-               NULL
-       };
-       struct saa7134_dev *dev = file->private_data;
-
-       c->id = v4l2_ctrl_next(ctrl_classes, c->id);
-       if (c->id == 0)
-               return -EINVAL;
-       if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS)
-               return v4l2_ctrl_query_fill(c, 0, 0, 0, 0);
-       if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
-               return saa7134_queryctrl(file, priv, c);
-       return saa_call_empress(dev, core, queryctrl, c);
-}
-
-static int empress_querymenu(struct file *file, void *priv,
-                                       struct v4l2_querymenu *c)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
-               return -EINVAL;
-       return saa_call_empress(dev, core, querymenu, c);
-}
-
-static int empress_s_std(struct file *file, void *priv, v4l2_std_id id)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       return saa7134_s_std_internal(dev, NULL, id);
-}
-
-static int empress_g_std(struct file *file, void *priv, v4l2_std_id *id)
-{
-       struct saa7134_dev *dev = file->private_data;
-
-       *id = dev->tvnorm->id;
-       return 0;
-}
-
 static const struct v4l2_file_operations ts_fops =
 {
        .owner    = THIS_MODULE,
@@ -450,28 +242,29 @@ static const struct v4l2_file_operations ts_fops =
 };
 
 static const struct v4l2_ioctl_ops ts_ioctl_ops = {
-       .vidioc_querycap                = empress_querycap,
+       .vidioc_querycap                = saa7134_querycap,
        .vidioc_enum_fmt_vid_cap        = empress_enum_fmt_vid_cap,
        .vidioc_try_fmt_vid_cap         = empress_try_fmt_vid_cap,
        .vidioc_s_fmt_vid_cap           = empress_s_fmt_vid_cap,
        .vidioc_g_fmt_vid_cap           = empress_g_fmt_vid_cap,
-       .vidioc_reqbufs                 = empress_reqbufs,
-       .vidioc_querybuf                = empress_querybuf,
-       .vidioc_qbuf                    = empress_qbuf,
-       .vidioc_dqbuf                   = empress_dqbuf,
-       .vidioc_streamon                = empress_streamon,
-       .vidioc_streamoff               = empress_streamoff,
-       .vidioc_s_ext_ctrls             = empress_s_ext_ctrls,
-       .vidioc_g_ext_ctrls             = empress_g_ext_ctrls,
-       .vidioc_enum_input              = empress_enum_input,
-       .vidioc_g_input                 = empress_g_input,
-       .vidioc_s_input                 = empress_s_input,
-       .vidioc_queryctrl               = empress_queryctrl,
-       .vidioc_querymenu               = empress_querymenu,
-       .vidioc_g_ctrl                  = empress_g_ctrl,
-       .vidioc_s_ctrl                  = empress_s_ctrl,
-       .vidioc_s_std                   = empress_s_std,
-       .vidioc_g_std                   = empress_g_std,
+       .vidioc_reqbufs                 = saa7134_reqbufs,
+       .vidioc_querybuf                = saa7134_querybuf,
+       .vidioc_qbuf                    = saa7134_qbuf,
+       .vidioc_dqbuf                   = saa7134_dqbuf,
+       .vidioc_streamon                = saa7134_streamon,
+       .vidioc_streamoff               = saa7134_streamoff,
+       .vidioc_g_frequency             = saa7134_g_frequency,
+       .vidioc_s_frequency             = saa7134_s_frequency,
+       .vidioc_g_tuner                 = saa7134_g_tuner,
+       .vidioc_s_tuner                 = saa7134_s_tuner,
+       .vidioc_enum_input              = saa7134_enum_input,
+       .vidioc_g_input                 = saa7134_g_input,
+       .vidioc_s_input                 = saa7134_s_input,
+       .vidioc_s_std                   = saa7134_s_std,
+       .vidioc_g_std                   = saa7134_g_std,
+       .vidioc_log_status              = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 };
 
 /* ----------------------------------------------------------- */
@@ -501,9 +294,26 @@ static void empress_signal_change(struct saa7134_dev *dev)
        schedule_work(&dev->empress_workqueue);
 }
 
+static bool empress_ctrl_filter(const struct v4l2_ctrl *ctrl)
+{
+       switch (ctrl->id) {
+       case V4L2_CID_BRIGHTNESS:
+       case V4L2_CID_HUE:
+       case V4L2_CID_CONTRAST:
+       case V4L2_CID_SATURATION:
+       case V4L2_CID_AUDIO_MUTE:
+       case V4L2_CID_AUDIO_VOLUME:
+       case V4L2_CID_PRIVATE_INVERT:
+       case V4L2_CID_PRIVATE_AUTOMUTE:
+               return true;
+       default:
+               return false;
+       }
+}
 
 static int empress_init(struct saa7134_dev *dev)
 {
+       struct v4l2_ctrl_handler *hdl = &dev->empress_ctrl_handler;
        int err;
 
        dprintk("%s: %s\n",dev->name,__func__);
@@ -516,6 +326,16 @@ static int empress_init(struct saa7134_dev *dev)
        snprintf(dev->empress_dev->name, sizeof(dev->empress_dev->name),
                 "%s empress (%s)", dev->name,
                 saa7134_boards[dev->board].name);
+       set_bit(V4L2_FL_USE_FH_PRIO, &dev->empress_dev->flags);
+       v4l2_ctrl_handler_init(hdl, 21);
+       v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler, empress_ctrl_filter);
+       if (dev->empress_sd)
+               v4l2_ctrl_add_handler(hdl, dev->empress_sd->ctrl_handler, NULL);
+       if (hdl->error) {
+               video_device_release(dev->empress_dev);
+               return hdl->error;
+       }
+       dev->empress_dev->ctrl_handler = hdl;
 
        INIT_WORK(&dev->empress_workqueue, empress_signal_update);
 
@@ -551,6 +371,7 @@ static int empress_fini(struct saa7134_dev *dev)
                return 0;
        flush_work(&dev->empress_workqueue);
        video_unregister_device(dev->empress_dev);
+       v4l2_ctrl_handler_free(&dev->empress_ctrl_handler);
        dev->empress_dev = NULL;
        return 0;
 }
index e9aa94b807f11271d5a0b9c61500566fbed4b508..d4da18d049f363943367556b90a251e23dca89fc 100644 (file)
@@ -117,8 +117,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                          struct videobuf_buffer *vb,
                          enum v4l2_field field)
 {
-       struct saa7134_fh *fh   = q->priv_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
        struct saa7134_tvnorm *norm = dev->tvnorm;
        unsigned int lines, llength, size;
@@ -141,7 +140,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                buf->vb.width  = llength;
                buf->vb.height = lines;
                buf->vb.size   = size;
-               buf->pt        = &fh->pt_vbi;
+               buf->pt        = &dev->pt_vbi;
 
                err = videobuf_iolock(q,&buf->vb,NULL);
                if (err)
@@ -166,8 +165,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 static int
 buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
 {
-       struct saa7134_fh *fh   = q->priv_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = q->priv_data;
        int llength,lines;
 
        lines   = dev->tvnorm->vbi_v_stop_0 - dev->tvnorm->vbi_v_start_0 +1;
@@ -181,8 +179,7 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
 
 static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_fh *fh = q->priv_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
 
        saa7134_buffer_queue(dev,&dev->vbi_q,buf);
index fb60da85bc2c039e3ab7a6db22fa1182c4e977bb..eb472b5b26a08e52ac392f436b5ee845a8981d12 100644 (file)
 #include <linux/slab.h>
 #include <linux/sort.h>
 
-#include "saa7134-reg.h"
-#include "saa7134.h"
 #include <media/v4l2-common.h>
+#include <media/v4l2-event.h>
 #include <media/saa6588.h>
 
+#include "saa7134-reg.h"
+#include "saa7134.h"
+
 /* ------------------------------------------------------------------ */
 
 unsigned int video_debug;
@@ -369,117 +371,6 @@ static struct saa7134_tvnorm tvnorms[] = {
 };
 #define TVNORMS ARRAY_SIZE(tvnorms)
 
-#define V4L2_CID_PRIVATE_INVERT      (V4L2_CID_PRIVATE_BASE + 0)
-#define V4L2_CID_PRIVATE_Y_ODD       (V4L2_CID_PRIVATE_BASE + 1)
-#define V4L2_CID_PRIVATE_Y_EVEN      (V4L2_CID_PRIVATE_BASE + 2)
-#define V4L2_CID_PRIVATE_AUTOMUTE    (V4L2_CID_PRIVATE_BASE + 3)
-#define V4L2_CID_PRIVATE_LASTP1      (V4L2_CID_PRIVATE_BASE + 4)
-
-static const struct v4l2_queryctrl no_ctrl = {
-       .name  = "42",
-       .flags = V4L2_CTRL_FLAG_DISABLED,
-};
-static const struct v4l2_queryctrl video_ctrls[] = {
-       /* --- video --- */
-       {
-               .id            = V4L2_CID_BRIGHTNESS,
-               .name          = "Brightness",
-               .minimum       = 0,
-               .maximum       = 255,
-               .step          = 1,
-               .default_value = 128,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_CONTRAST,
-               .name          = "Contrast",
-               .minimum       = 0,
-               .maximum       = 127,
-               .step          = 1,
-               .default_value = 68,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_SATURATION,
-               .name          = "Saturation",
-               .minimum       = 0,
-               .maximum       = 127,
-               .step          = 1,
-               .default_value = 64,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_HUE,
-               .name          = "Hue",
-               .minimum       = -128,
-               .maximum       = 127,
-               .step          = 1,
-               .default_value = 0,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_HFLIP,
-               .name          = "Mirror",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },
-       /* --- audio --- */
-       {
-               .id            = V4L2_CID_AUDIO_MUTE,
-               .name          = "Mute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_AUDIO_VOLUME,
-               .name          = "Volume",
-               .minimum       = -15,
-               .maximum       = 15,
-               .step          = 1,
-               .default_value = 0,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },
-       /* --- private --- */
-       {
-               .id            = V4L2_CID_PRIVATE_INVERT,
-               .name          = "Invert",
-               .minimum       = 0,
-               .maximum       = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       },{
-               .id            = V4L2_CID_PRIVATE_Y_ODD,
-               .name          = "y offset odd field",
-               .minimum       = 0,
-               .maximum       = 128,
-               .step          = 1,
-               .default_value = 0,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_PRIVATE_Y_EVEN,
-               .name          = "y offset even field",
-               .minimum       = 0,
-               .maximum       = 128,
-               .step          = 1,
-               .default_value = 0,
-               .type          = V4L2_CTRL_TYPE_INTEGER,
-       },{
-               .id            = V4L2_CID_PRIVATE_AUTOMUTE,
-               .name          = "automute",
-               .minimum       = 0,
-               .maximum       = 1,
-               .default_value = 1,
-               .type          = V4L2_CTRL_TYPE_BOOLEAN,
-       }
-};
-static const unsigned int CTRLS = ARRAY_SIZE(video_ctrls);
-
-static const struct v4l2_queryctrl* ctrl_by_id(unsigned int id)
-{
-       unsigned int i;
-
-       for (i = 0; i < CTRLS; i++)
-               if (video_ctrls[i].id == id)
-                       return video_ctrls+i;
-       return NULL;
-}
-
 static struct saa7134_format* format_by_fourcc(unsigned int fourcc)
 {
        unsigned int i;
@@ -514,16 +405,6 @@ static int res_get(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int
        return 1;
 }
 
-static int res_check(struct saa7134_fh *fh, unsigned int bit)
-{
-       return (fh->resources & bit);
-}
-
-static int res_locked(struct saa7134_dev *dev, unsigned int bit)
-{
-       return (dev->resources & bit);
-}
-
 static
 void res_free(struct saa7134_dev *dev, struct saa7134_fh *fh, unsigned int bits)
 {
@@ -868,7 +749,7 @@ static int verify_preview(struct saa7134_dev *dev, struct v4l2_window *win, bool
        return 0;
 }
 
-static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
+static int start_preview(struct saa7134_dev *dev)
 {
        unsigned long base,control,bpl;
        int err;
@@ -923,7 +804,7 @@ static int start_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
        return 0;
 }
 
-static int stop_preview(struct saa7134_dev *dev, struct saa7134_fh *fh)
+static int stop_preview(struct saa7134_dev *dev)
 {
        dev->ovenable = 0;
        saa7134_set_dmabits(dev);
@@ -1018,8 +899,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                          struct videobuf_buffer *vb,
                          enum v4l2_field field)
 {
-       struct saa7134_fh *fh = q->priv_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
        unsigned int size;
        int err;
@@ -1057,7 +937,7 @@ static int buffer_prepare(struct videobuf_queue *q,
                buf->vb.size   = size;
                buf->vb.field  = field;
                buf->fmt       = dev->fmt;
-               buf->pt        = &fh->pt_cap;
+               buf->pt        = &dev->pt_cap;
                dev->video_q.curr = NULL;
 
                err = videobuf_iolock(q,&buf->vb,&dev->ovbuf);
@@ -1082,8 +962,7 @@ static int buffer_prepare(struct videobuf_queue *q,
 static int
 buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
 {
-       struct saa7134_fh *fh = q->priv_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = q->priv_data;
 
        *size = dev->fmt->depth * dev->width * dev->height >> 3;
        if (0 == *count)
@@ -1094,10 +973,10 @@ buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
 
 static void buffer_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
 {
-       struct saa7134_fh *fh = q->priv_data;
+       struct saa7134_dev *dev = q->priv_data;
        struct saa7134_buf *buf = container_of(vb,struct saa7134_buf,vb);
 
-       saa7134_buffer_queue(fh->dev,&fh->dev->video_q,buf);
+       saa7134_buffer_queue(dev, &dev->video_q, buf);
 }
 
 static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
@@ -1116,133 +995,56 @@ static struct videobuf_queue_ops video_qops = {
 
 /* ------------------------------------------------------------------ */
 
-int saa7134_g_ctrl_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, struct v4l2_control *c)
+static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-       const struct v4l2_queryctrl* ctrl;
-
-       ctrl = ctrl_by_id(c->id);
-       if (NULL == ctrl)
-               return -EINVAL;
-       switch (c->id) {
-       case V4L2_CID_BRIGHTNESS:
-               c->value = dev->ctl_bright;
-               break;
-       case V4L2_CID_HUE:
-               c->value = dev->ctl_hue;
-               break;
-       case V4L2_CID_CONTRAST:
-               c->value = dev->ctl_contrast;
-               break;
-       case V4L2_CID_SATURATION:
-               c->value = dev->ctl_saturation;
-               break;
-       case V4L2_CID_AUDIO_MUTE:
-               c->value = dev->ctl_mute;
-               break;
-       case V4L2_CID_AUDIO_VOLUME:
-               c->value = dev->ctl_volume;
-               break;
-       case V4L2_CID_PRIVATE_INVERT:
-               c->value = dev->ctl_invert;
-               break;
-       case V4L2_CID_HFLIP:
-               c->value = dev->ctl_mirror;
-               break;
-       case V4L2_CID_PRIVATE_Y_EVEN:
-               c->value = dev->ctl_y_even;
-               break;
-       case V4L2_CID_PRIVATE_Y_ODD:
-               c->value = dev->ctl_y_odd;
-               break;
-       case V4L2_CID_PRIVATE_AUTOMUTE:
-               c->value = dev->ctl_automute;
-               break;
-       default:
-               return -EINVAL;
-       }
-       return 0;
-}
-EXPORT_SYMBOL_GPL(saa7134_g_ctrl_internal);
-
-static int saa7134_g_ctrl(struct file *file, void *priv, struct v4l2_control *c)
-{
-       struct saa7134_fh *fh = priv;
-
-       return saa7134_g_ctrl_internal(fh->dev, fh, c);
-}
-
-int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c)
-{
-       const struct v4l2_queryctrl* ctrl;
+       struct saa7134_dev *dev = container_of(ctrl->handler, struct saa7134_dev, ctrl_handler);
        unsigned long flags;
        int restart_overlay = 0;
-       int err;
 
-       err = -EINVAL;
-
-       mutex_lock(&dev->lock);
-
-       ctrl = ctrl_by_id(c->id);
-       if (NULL == ctrl)
-               goto error;
-
-       dprintk("set_control name=%s val=%d\n",ctrl->name,c->value);
-       switch (ctrl->type) {
-       case V4L2_CTRL_TYPE_BOOLEAN:
-       case V4L2_CTRL_TYPE_MENU:
-       case V4L2_CTRL_TYPE_INTEGER:
-               if (c->value < ctrl->minimum)
-                       c->value = ctrl->minimum;
-               if (c->value > ctrl->maximum)
-                       c->value = ctrl->maximum;
-               break;
-       default:
-               /* nothing */;
-       }
-       switch (c->id) {
+       switch (ctrl->id) {
        case V4L2_CID_BRIGHTNESS:
-               dev->ctl_bright = c->value;
-               saa_writeb(SAA7134_DEC_LUMA_BRIGHT, dev->ctl_bright);
+               dev->ctl_bright = ctrl->val;
+               saa_writeb(SAA7134_DEC_LUMA_BRIGHT, ctrl->val);
                break;
        case V4L2_CID_HUE:
-               dev->ctl_hue = c->value;
-               saa_writeb(SAA7134_DEC_CHROMA_HUE, dev->ctl_hue);
+               dev->ctl_hue = ctrl->val;
+               saa_writeb(SAA7134_DEC_CHROMA_HUE, ctrl->val);
                break;
        case V4L2_CID_CONTRAST:
-               dev->ctl_contrast = c->value;
+               dev->ctl_contrast = ctrl->val;
                saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
                           dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
                break;
        case V4L2_CID_SATURATION:
-               dev->ctl_saturation = c->value;
+               dev->ctl_saturation = ctrl->val;
                saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
                           dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
                break;
        case V4L2_CID_AUDIO_MUTE:
-               dev->ctl_mute = c->value;
+               dev->ctl_mute = ctrl->val;
                saa7134_tvaudio_setmute(dev);
                break;
        case V4L2_CID_AUDIO_VOLUME:
-               dev->ctl_volume = c->value;
+               dev->ctl_volume = ctrl->val;
                saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
                break;
        case V4L2_CID_PRIVATE_INVERT:
-               dev->ctl_invert = c->value;
+               dev->ctl_invert = ctrl->val;
                saa_writeb(SAA7134_DEC_LUMA_CONTRAST,
                           dev->ctl_invert ? -dev->ctl_contrast : dev->ctl_contrast);
                saa_writeb(SAA7134_DEC_CHROMA_SATURATION,
                           dev->ctl_invert ? -dev->ctl_saturation : dev->ctl_saturation);
                break;
        case V4L2_CID_HFLIP:
-               dev->ctl_mirror = c->value;
+               dev->ctl_mirror = ctrl->val;
                restart_overlay = 1;
                break;
        case V4L2_CID_PRIVATE_Y_EVEN:
-               dev->ctl_y_even = c->value;
+               dev->ctl_y_even = ctrl->val;
                restart_overlay = 1;
                break;
        case V4L2_CID_PRIVATE_Y_ODD:
-               dev->ctl_y_odd = c->value;
+               dev->ctl_y_odd = ctrl->val;
                restart_overlay = 1;
                break;
        case V4L2_CID_PRIVATE_AUTOMUTE:
@@ -1252,7 +1054,7 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, str
                tda9887_cfg.tuner = TUNER_TDA9887;
                tda9887_cfg.priv = &dev->tda9887_conf;
 
-               dev->ctl_automute = c->value;
+               dev->ctl_automute = ctrl->val;
                if (dev->tda9887_conf) {
                        if (dev->ctl_automute)
                                dev->tda9887_conf |= TDA9887_AUTOMUTE;
@@ -1264,27 +1066,15 @@ int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, str
                break;
        }
        default:
-               goto error;
+               return -EINVAL;
        }
-       if (restart_overlay && fh && res_check(fh, RESOURCE_OVERLAY)) {
-               spin_lock_irqsave(&dev->slock,flags);
-               stop_preview(dev,fh);
-               start_preview(dev,fh);
-               spin_unlock_irqrestore(&dev->slock,flags);
+       if (restart_overlay && res_locked(dev, RESOURCE_OVERLAY)) {
+               spin_lock_irqsave(&dev->slock, flags);
+               stop_preview(dev);
+               start_preview(dev);
+               spin_unlock_irqrestore(&dev->slock, flags);
        }
-       err = 0;
-
-error:
-       mutex_unlock(&dev->lock);
-       return err;
-}
-EXPORT_SYMBOL_GPL(saa7134_s_ctrl_internal);
-
-static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
-{
-       struct saa7134_fh *fh = f;
-
-       return saa7134_s_ctrl_internal(fh->dev, fh, c);
+       return 0;
 }
 
 /* ------------------------------------------------------------------ */
@@ -1292,15 +1082,16 @@ static int saa7134_s_ctrl(struct file *file, void *f, struct v4l2_control *c)
 static struct videobuf_queue *saa7134_queue(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
+       struct saa7134_dev *dev = video_drvdata(file);
        struct saa7134_fh *fh = file->private_data;
        struct videobuf_queue *q = NULL;
 
        switch (vdev->vfl_type) {
        case VFL_TYPE_GRABBER:
-               q = &fh->cap;
+               q = fh->is_empress ? &dev->empress_tsq : &dev->cap;
                break;
        case VFL_TYPE_VBI:
-               q = &fh->vbi;
+               q = &dev->vbi;
                break;
        default:
                BUG();
@@ -1311,9 +1102,10 @@ static struct videobuf_queue *saa7134_queue(struct file *file)
 static int saa7134_resource(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
+       struct saa7134_fh *fh = file->private_data;
 
        if (vdev->vfl_type == VFL_TYPE_GRABBER)
-               return RESOURCE_VIDEO;
+               return fh->is_empress ? RESOURCE_EMPRESS : RESOURCE_VIDEO;
 
        if (vdev->vfl_type == VFL_TYPE_VBI)
                return RESOURCE_VBI;
@@ -1335,22 +1127,6 @@ static int video_open(struct file *file)
 
        v4l2_fh_init(&fh->fh, vdev);
        file->private_data = fh;
-       fh->dev      = dev;
-
-       videobuf_queue_sg_init(&fh->cap, &video_qops,
-                           &dev->pci->dev, &dev->slock,
-                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
-                           V4L2_FIELD_INTERLACED,
-                           sizeof(struct saa7134_buf),
-                           fh, NULL);
-       videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops,
-                           &dev->pci->dev, &dev->slock,
-                           V4L2_BUF_TYPE_VBI_CAPTURE,
-                           V4L2_FIELD_SEQ_TB,
-                           sizeof(struct saa7134_buf),
-                           fh, NULL);
-       saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
-       saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi);
 
        if (vdev->vfl_type == VFL_TYPE_RADIO) {
                /* switch to radio mode */
@@ -1369,17 +1145,18 @@ static ssize_t
 video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 {
        struct video_device *vdev = video_devdata(file);
+       struct saa7134_dev *dev = video_drvdata(file);
        struct saa7134_fh *fh = file->private_data;
 
        switch (vdev->vfl_type) {
        case VFL_TYPE_GRABBER:
-               if (res_locked(fh->dev,RESOURCE_VIDEO))
+               if (res_locked(dev, RESOURCE_VIDEO))
                        return -EBUSY;
                return videobuf_read_one(saa7134_queue(file),
                                         data, count, ppos,
                                         file->f_flags & O_NONBLOCK);
        case VFL_TYPE_VBI:
-               if (!res_get(fh->dev,fh,RESOURCE_VBI))
+               if (!res_get(dev, fh, RESOURCE_VBI))
                        return -EBUSY;
                return videobuf_read_stream(saa7134_queue(file),
                                            data, count, ppos, 1,
@@ -1394,52 +1171,59 @@ video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
 static unsigned int
 video_poll(struct file *file, struct poll_table_struct *wait)
 {
+       unsigned long req_events = poll_requested_events(wait);
        struct video_device *vdev = video_devdata(file);
+       struct saa7134_dev *dev = video_drvdata(file);
        struct saa7134_fh *fh = file->private_data;
        struct videobuf_buffer *buf = NULL;
        unsigned int rc = 0;
 
+       if (v4l2_event_pending(&fh->fh))
+               rc = POLLPRI;
+       else if (req_events & POLLPRI)
+               poll_wait(file, &fh->fh.wait, wait);
+
        if (vdev->vfl_type == VFL_TYPE_VBI)
-               return videobuf_poll_stream(file, &fh->vbi, wait);
+               return rc | videobuf_poll_stream(file, &dev->vbi, wait);
 
-       if (res_check(fh,RESOURCE_VIDEO)) {
-               mutex_lock(&fh->cap.vb_lock);
-               if (!list_empty(&fh->cap.stream))
-                       buf = list_entry(fh->cap.stream.next, struct videobuf_buffer, stream);
+       if (res_check(fh, RESOURCE_VIDEO)) {
+               mutex_lock(&dev->cap.vb_lock);
+               if (!list_empty(&dev->cap.stream))
+                       buf = list_entry(dev->cap.stream.next, struct videobuf_buffer, stream);
        } else {
-               mutex_lock(&fh->cap.vb_lock);
-               if (UNSET == fh->cap.read_off) {
+               mutex_lock(&dev->cap.vb_lock);
+               if (UNSET == dev->cap.read_off) {
                        /* need to capture a new frame */
-                       if (res_locked(fh->dev,RESOURCE_VIDEO))
+                       if (res_locked(dev, RESOURCE_VIDEO))
                                goto err;
-                       if (0 != fh->cap.ops->buf_prepare(&fh->cap,fh->cap.read_buf,fh->cap.field))
+                       if (0 != dev->cap.ops->buf_prepare(&dev->cap,
+                                       dev->cap.read_buf, dev->cap.field))
                                goto err;
-                       fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
-                       fh->cap.read_off = 0;
+                       dev->cap.ops->buf_queue(&dev->cap, dev->cap.read_buf);
+                       dev->cap.read_off = 0;
                }
-               buf = fh->cap.read_buf;
+               buf = dev->cap.read_buf;
        }
 
        if (!buf)
                goto err;
 
        poll_wait(file, &buf->done, wait);
-       if (buf->state == VIDEOBUF_DONE ||
-           buf->state == VIDEOBUF_ERROR)
-               rc = POLLIN|POLLRDNORM;
-       mutex_unlock(&fh->cap.vb_lock);
+       if (buf->state == VIDEOBUF_DONE || buf->state == VIDEOBUF_ERROR)
+               rc |= POLLIN | POLLRDNORM;
+       mutex_unlock(&dev->cap.vb_lock);
        return rc;
 
 err:
-       mutex_unlock(&fh->cap.vb_lock);
-       return POLLERR;
+       mutex_unlock(&dev->cap.vb_lock);
+       return rc | POLLERR;
 }
 
 static int video_release(struct file *file)
 {
        struct video_device *vdev = video_devdata(file);
-       struct saa7134_fh  *fh  = file->private_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
+       struct saa7134_fh *fh = file->private_data;
        struct saa6588_command cmd;
        unsigned long flags;
 
@@ -1448,26 +1232,28 @@ static int video_release(struct file *file)
        /* turn off overlay */
        if (res_check(fh, RESOURCE_OVERLAY)) {
                spin_lock_irqsave(&dev->slock,flags);
-               stop_preview(dev,fh);
+               stop_preview(dev);
                spin_unlock_irqrestore(&dev->slock,flags);
-               res_free(dev,fh,RESOURCE_OVERLAY);
+               res_free(dev, fh, RESOURCE_OVERLAY);
        }
 
        /* stop video capture */
        if (res_check(fh, RESOURCE_VIDEO)) {
                pm_qos_remove_request(&dev->qos_request);
-               videobuf_streamoff(&fh->cap);
-               res_free(dev,fh,RESOURCE_VIDEO);
+               videobuf_streamoff(&dev->cap);
+               res_free(dev, fh, RESOURCE_VIDEO);
+               videobuf_mmap_free(&dev->cap);
        }
-       if (fh->cap.read_buf) {
-               buffer_release(&fh->cap,fh->cap.read_buf);
-               kfree(fh->cap.read_buf);
+       if (dev->cap.read_buf) {
+               buffer_release(&dev->cap, dev->cap.read_buf);
+               kfree(dev->cap.read_buf);
        }
 
        /* stop vbi capture */
        if (res_check(fh, RESOURCE_VBI)) {
-               videobuf_stop(&fh->vbi);
-               res_free(dev,fh,RESOURCE_VBI);
+               videobuf_stop(&dev->vbi);
+               res_free(dev, fh, RESOURCE_VBI);
+               videobuf_mmap_free(&dev->vbi);
        }
 
        /* ts-capture will not work in planar mode, so turn it off Hac: 04.05*/
@@ -1480,12 +1266,6 @@ static int video_release(struct file *file)
        if (vdev->vfl_type == VFL_TYPE_RADIO)
                saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
 
-       /* free stuff */
-       videobuf_mmap_free(&fh->cap);
-       videobuf_mmap_free(&fh->vbi);
-       saa7134_pgtable_free(dev->pci,&fh->pt_cap);
-       saa7134_pgtable_free(dev->pci,&fh->pt_vbi);
-
        v4l2_fh_del(&fh->fh);
        v4l2_fh_exit(&fh->fh);
        file->private_data = NULL;
@@ -1501,11 +1281,11 @@ static int video_mmap(struct file *file, struct vm_area_struct * vma)
 static ssize_t radio_read(struct file *file, char __user *data,
                         size_t count, loff_t *ppos)
 {
-       struct saa7134_fh *fh = file->private_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct saa6588_command cmd;
 
        cmd.block_count = count/3;
+       cmd.nonblocking = file->f_flags & O_NONBLOCK;
        cmd.buffer = data;
        cmd.instance = file;
        cmd.result = -ENODEV;
@@ -1517,16 +1297,16 @@ static ssize_t radio_read(struct file *file, char __user *data,
 
 static unsigned int radio_poll(struct file *file, poll_table *wait)
 {
-       struct saa7134_fh *fh = file->private_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct saa6588_command cmd;
+       unsigned int rc = v4l2_ctrl_poll(file, wait);
 
        cmd.instance = file;
        cmd.event_list = wait;
-       cmd.result = -ENODEV;
+       cmd.result = 0;
        saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
 
-       return cmd.result;
+       return rc | cmd.result;
 }
 
 /* ------------------------------------------------------------------ */
@@ -1534,8 +1314,7 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
 static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
                                                struct v4l2_format *f)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct saa7134_tvnorm *norm = dev->tvnorm;
 
        memset(&f->fmt.vbi.reserved, 0, sizeof(f->fmt.vbi.reserved));
@@ -1555,12 +1334,11 @@ static int saa7134_try_get_set_fmt_vbi_cap(struct file *file, void *priv,
 static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        f->fmt.pix.width        = dev->width;
        f->fmt.pix.height       = dev->height;
-       f->fmt.pix.field        = fh->cap.field;
+       f->fmt.pix.field        = dev->cap.field;
        f->fmt.pix.pixelformat  = dev->fmt->fourcc;
        f->fmt.pix.bytesperline =
                (f->fmt.pix.width * dev->fmt->depth) >> 3;
@@ -1574,8 +1352,7 @@ static int saa7134_g_fmt_vid_cap(struct file *file, void *priv,
 static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct v4l2_clip __user *clips = f->fmt.win.clips;
        u32 clipcount = f->fmt.win.clipcount;
        int err = 0;
@@ -1607,8 +1384,7 @@ static int saa7134_g_fmt_vid_overlay(struct file *file, void *priv,
 static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
                                                struct v4l2_format *f)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct saa7134_format *fmt;
        enum v4l2_field field;
        unsigned int maxw, maxh;
@@ -1659,8 +1435,7 @@ static int saa7134_try_fmt_vid_cap(struct file *file, void *priv,
 static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv,
                                                struct v4l2_format *f)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        if (saa7134_no_overlay > 0) {
                printk(KERN_ERR "V4L2_BUF_TYPE_VIDEO_OVERLAY: no_overlay\n");
@@ -1675,8 +1450,7 @@ static int saa7134_try_fmt_vid_overlay(struct file *file, void *priv,
 static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        int err;
 
        err = saa7134_try_fmt_vid_cap(file, priv, f);
@@ -1686,15 +1460,14 @@ static int saa7134_s_fmt_vid_cap(struct file *file, void *priv,
        dev->fmt       = format_by_fourcc(f->fmt.pix.pixelformat);
        dev->width     = f->fmt.pix.width;
        dev->height    = f->fmt.pix.height;
-       fh->cap.field = f->fmt.pix.field;
+       dev->cap.field = f->fmt.pix.field;
        return 0;
 }
 
 static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
                                        struct v4l2_format *f)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        int err;
        unsigned long flags;
 
@@ -1719,10 +1492,10 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
                return -EFAULT;
        }
 
-       if (res_check(fh, RESOURCE_OVERLAY)) {
+       if (res_check(priv, RESOURCE_OVERLAY)) {
                spin_lock_irqsave(&dev->slock, flags);
-               stop_preview(dev, fh);
-               start_preview(dev, fh);
+               stop_preview(dev);
+               start_preview(dev);
                spin_unlock_irqrestore(&dev->slock, flags);
        }
 
@@ -1730,26 +1503,9 @@ static int saa7134_s_fmt_vid_overlay(struct file *file, void *priv,
        return 0;
 }
 
-int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c)
-{
-       const struct v4l2_queryctrl *ctrl;
-
-       if ((c->id <  V4L2_CID_BASE ||
-            c->id >= V4L2_CID_LASTP1) &&
-           (c->id <  V4L2_CID_PRIVATE_BASE ||
-            c->id >= V4L2_CID_PRIVATE_LASTP1))
-               return -EINVAL;
-       ctrl = ctrl_by_id(c->id);
-       *c = (NULL != ctrl) ? *ctrl : no_ctrl;
-       return 0;
-}
-EXPORT_SYMBOL_GPL(saa7134_queryctrl);
-
-static int saa7134_enum_input(struct file *file, void *priv,
-                                       struct v4l2_input *i)
+int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        unsigned int n;
 
        n = i->index;
@@ -1769,27 +1525,27 @@ static int saa7134_enum_input(struct file *file, void *priv,
                if (0 != (v1 & 0x40))
                        i->status |= V4L2_IN_ST_NO_H_LOCK;
                if (0 != (v2 & 0x40))
-                       i->status |= V4L2_IN_ST_NO_SYNC;
+                       i->status |= V4L2_IN_ST_NO_SIGNAL;
                if (0 != (v2 & 0x0e))
                        i->status |= V4L2_IN_ST_MACROVISION;
        }
        i->std = SAA7134_NORMS;
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_enum_input);
 
-static int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
+int saa7134_g_input(struct file *file, void *priv, unsigned int *i)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        *i = dev->ctl_input;
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_g_input);
 
-static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
+int saa7134_s_input(struct file *file, void *priv, unsigned int i)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        if (i >= SAA7134_INPUT_MAX)
                return -EINVAL;
@@ -1800,13 +1556,14 @@ static int saa7134_s_input(struct file *file, void *priv, unsigned int i)
        mutex_unlock(&dev->lock);
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_s_input);
 
-static int saa7134_querycap(struct file *file, void  *priv,
+int saa7134_querycap(struct file *file, void *priv,
                                        struct v4l2_capability *cap)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct video_device *vdev = video_devdata(file);
+       struct saa7134_fh *fh = priv;
        u32 radio_caps, video_caps, vbi_caps;
 
        unsigned int tuner_type = dev->tuner_type;
@@ -1825,7 +1582,7 @@ static int saa7134_querycap(struct file *file, void  *priv,
                radio_caps |= V4L2_CAP_RDS_CAPTURE;
 
        video_caps = V4L2_CAP_VIDEO_CAPTURE;
-       if (saa7134_no_overlay <= 0)
+       if (saa7134_no_overlay <= 0 && !fh->is_empress)
                video_caps |= V4L2_CAP_VIDEO_OVERLAY;
 
        vbi_caps = V4L2_CAP_VBI_CAPTURE;
@@ -1851,14 +1608,17 @@ static int saa7134_querycap(struct file *file, void  *priv,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_querycap);
 
-int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id id)
+int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
 {
+       struct saa7134_dev *dev = video_drvdata(file);
+       struct saa7134_fh *fh = priv;
        unsigned long flags;
        unsigned int i;
        v4l2_std_id fixup;
 
-       if (!fh && res_locked(dev, RESOURCE_OVERLAY)) {
+       if (fh->is_empress && res_locked(dev, RESOURCE_OVERLAY)) {
                /* Don't change the std from the mpeg device
                   if overlay is active. */
                return -EBUSY;
@@ -1898,15 +1658,15 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_
        id = tvnorms[i].id;
 
        mutex_lock(&dev->lock);
-       if (fh && res_check(fh, RESOURCE_OVERLAY)) {
+       if (!fh->is_empress && res_check(fh, RESOURCE_OVERLAY)) {
                spin_lock_irqsave(&dev->slock, flags);
-               stop_preview(dev, fh);
+               stop_preview(dev);
                spin_unlock_irqrestore(&dev->slock, flags);
 
                set_tvnorm(dev, &tvnorms[i]);
 
                spin_lock_irqsave(&dev->slock, flags);
-               start_preview(dev, fh);
+               start_preview(dev);
                spin_unlock_irqrestore(&dev->slock, flags);
        } else
                set_tvnorm(dev, &tvnorms[i]);
@@ -1915,29 +1675,21 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_
        mutex_unlock(&dev->lock);
        return 0;
 }
-EXPORT_SYMBOL_GPL(saa7134_s_std_internal);
+EXPORT_SYMBOL_GPL(saa7134_s_std);
 
-static int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id)
+int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id)
 {
-       struct saa7134_fh *fh = priv;
-
-       return saa7134_s_std_internal(fh->dev, fh, id);
-}
-
-static int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id)
-{
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        *id = dev->tvnorm->id;
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_g_std);
 
 static int saa7134_cropcap(struct file *file, void *priv,
                                        struct v4l2_cropcap *cap)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
            cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
@@ -1959,8 +1711,7 @@ static int saa7134_cropcap(struct file *file, void *priv,
 
 static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
 {
-       struct saa7134_fh *fh = f;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
            crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
@@ -1971,22 +1722,17 @@ static int saa7134_g_crop(struct file *file, void *f, struct v4l2_crop *crop)
 
 static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *crop)
 {
-       struct saa7134_fh *fh = f;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct v4l2_rect *b = &dev->crop_bounds;
        struct v4l2_rect *c = &dev->crop_current;
 
        if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
            crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
                return -EINVAL;
-       if (crop->c.height < 0)
-               return -EINVAL;
-       if (crop->c.width < 0)
-               return -EINVAL;
 
-       if (res_locked(fh->dev, RESOURCE_OVERLAY))
+       if (res_locked(dev, RESOURCE_OVERLAY))
                return -EBUSY;
-       if (res_locked(fh->dev, RESOURCE_VIDEO))
+       if (res_locked(dev, RESOURCE_VIDEO))
                return -EBUSY;
 
        *c = crop->c;
@@ -2006,11 +1752,10 @@ static int saa7134_s_crop(struct file *file, void *f, const struct v4l2_crop *cr
        return 0;
 }
 
-static int saa7134_g_tuner(struct file *file, void *priv,
+int saa7134_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *t)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        int n;
 
        if (0 != t->index)
@@ -2037,12 +1782,12 @@ static int saa7134_g_tuner(struct file *file, void *priv,
                t->signal = 0xffff;
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_g_tuner);
 
-static int saa7134_s_tuner(struct file *file, void *priv,
+int saa7134_s_tuner(struct file *file, void *priv,
                                        const struct v4l2_tuner *t)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        int rx, mode;
 
        if (0 != t->index)
@@ -2058,12 +1803,12 @@ static int saa7134_s_tuner(struct file *file, void *priv,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_s_tuner);
 
-static int saa7134_g_frequency(struct file *file, void *priv,
+int saa7134_g_frequency(struct file *file, void *priv,
                                        struct v4l2_frequency *f)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        if (0 != f->tuner)
                return -EINVAL;
@@ -2072,12 +1817,12 @@ static int saa7134_g_frequency(struct file *file, void *priv,
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_g_frequency);
 
-static int saa7134_s_frequency(struct file *file, void *priv,
+int saa7134_s_frequency(struct file *file, void *priv,
                                        const struct v4l2_frequency *f)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        if (0 != f->tuner)
                return -EINVAL;
@@ -2089,6 +1834,7 @@ static int saa7134_s_frequency(struct file *file, void *priv,
        mutex_unlock(&dev->lock);
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_s_frequency);
 
 static int saa7134_enum_fmt_vid_cap(struct file *file, void  *priv,
                                        struct v4l2_fmtdesc *f)
@@ -2126,8 +1872,7 @@ static int saa7134_enum_fmt_vid_overlay(struct file *file, void  *priv,
 static int saa7134_g_fbuf(struct file *file, void *f,
                                struct v4l2_framebuffer *fb)
 {
-       struct saa7134_fh *fh = f;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        *fb = dev->ovbuf;
        fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
@@ -2138,8 +1883,7 @@ static int saa7134_g_fbuf(struct file *file, void *f,
 static int saa7134_s_fbuf(struct file *file, void *f,
                                        const struct v4l2_framebuffer *fb)
 {
-       struct saa7134_fh *fh = f;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        struct saa7134_format *fmt;
 
        if (!capable(CAP_SYS_ADMIN) &&
@@ -2160,10 +1904,9 @@ static int saa7134_s_fbuf(struct file *file, void *f,
        return 0;
 }
 
-static int saa7134_overlay(struct file *file, void *f, unsigned int on)
+static int saa7134_overlay(struct file *file, void *priv, unsigned int on)
 {
-       struct saa7134_fh *fh = f;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        unsigned long flags;
 
        if (on) {
@@ -2172,54 +1915,57 @@ static int saa7134_overlay(struct file *file, void *f, unsigned int on)
                        return -EINVAL;
                }
 
-               if (!res_get(dev, fh, RESOURCE_OVERLAY))
+               if (!res_get(dev, priv, RESOURCE_OVERLAY))
                        return -EBUSY;
                spin_lock_irqsave(&dev->slock, flags);
-               start_preview(dev, fh);
+               start_preview(dev);
                spin_unlock_irqrestore(&dev->slock, flags);
        }
        if (!on) {
-               if (!res_check(fh, RESOURCE_OVERLAY))
+               if (!res_check(priv, RESOURCE_OVERLAY))
                        return -EINVAL;
                spin_lock_irqsave(&dev->slock, flags);
-               stop_preview(dev, fh);
+               stop_preview(dev);
                spin_unlock_irqrestore(&dev->slock, flags);
-               res_free(dev, fh, RESOURCE_OVERLAY);
+               res_free(dev, priv, RESOURCE_OVERLAY);
        }
        return 0;
 }
 
-static int saa7134_reqbufs(struct file *file, void *priv,
+int saa7134_reqbufs(struct file *file, void *priv,
                                        struct v4l2_requestbuffers *p)
 {
        return videobuf_reqbufs(saa7134_queue(file), p);
 }
+EXPORT_SYMBOL_GPL(saa7134_reqbufs);
 
-static int saa7134_querybuf(struct file *file, void *priv,
+int saa7134_querybuf(struct file *file, void *priv,
                                        struct v4l2_buffer *b)
 {
        return videobuf_querybuf(saa7134_queue(file), b);
 }
+EXPORT_SYMBOL_GPL(saa7134_querybuf);
 
-static int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 {
        return videobuf_qbuf(saa7134_queue(file), b);
 }
+EXPORT_SYMBOL_GPL(saa7134_qbuf);
 
-static int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
 {
        return videobuf_dqbuf(saa7134_queue(file), b,
                                file->f_flags & O_NONBLOCK);
 }
+EXPORT_SYMBOL_GPL(saa7134_dqbuf);
 
-static int saa7134_streamon(struct file *file, void *priv,
+int saa7134_streamon(struct file *file, void *priv,
                                        enum v4l2_buf_type type)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
        int res = saa7134_resource(file);
 
-       if (!res_get(dev, fh, res))
+       if (!res_get(dev, priv, res))
                return -EBUSY;
 
        /* The SAA7134 has a 1K FIFO; the datasheet suggests that when
@@ -2229,36 +1975,37 @@ static int saa7134_streamon(struct file *file, void *priv,
         * Unfortunately, I lack register-level documentation to check the
         * Linux FIFO setup and confirm the perfect value.
         */
-       pm_qos_add_request(&dev->qos_request,
-                          PM_QOS_CPU_DMA_LATENCY,
-                          20);
+       if (res != RESOURCE_EMPRESS)
+               pm_qos_add_request(&dev->qos_request,
+                          PM_QOS_CPU_DMA_LATENCY, 20);
 
        return videobuf_streamon(saa7134_queue(file));
 }
+EXPORT_SYMBOL_GPL(saa7134_streamon);
 
-static int saa7134_streamoff(struct file *file, void *priv,
+int saa7134_streamoff(struct file *file, void *priv,
                                        enum v4l2_buf_type type)
 {
+       struct saa7134_dev *dev = video_drvdata(file);
        int err;
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
        int res = saa7134_resource(file);
 
-       pm_qos_remove_request(&dev->qos_request);
+       if (res != RESOURCE_EMPRESS)
+               pm_qos_remove_request(&dev->qos_request);
 
        err = videobuf_streamoff(saa7134_queue(file));
        if (err < 0)
                return err;
-       res_free(dev, fh, res);
+       res_free(dev, priv, res);
        return 0;
 }
+EXPORT_SYMBOL_GPL(saa7134_streamoff);
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 static int vidioc_g_register (struct file *file, void *priv,
                              struct v4l2_dbg_register *reg)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        reg->val = saa_readb(reg->reg & 0xffffff);
        reg->size = 1;
@@ -2268,8 +2015,7 @@ static int vidioc_g_register (struct file *file, void *priv,
 static int vidioc_s_register (struct file *file, void *priv,
                                const struct v4l2_dbg_register *reg)
 {
-       struct saa7134_fh *fh = priv;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        saa_writeb(reg->reg & 0xffffff, reg->val);
        return 0;
@@ -2279,8 +2025,7 @@ static int vidioc_s_register (struct file *file, void *priv,
 static int radio_g_tuner(struct file *file, void *priv,
                                        struct v4l2_tuner *t)
 {
-       struct saa7134_fh *fh = file->private_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        if (0 != t->index)
                return -EINVAL;
@@ -2299,8 +2044,7 @@ static int radio_g_tuner(struct file *file, void *priv,
 static int radio_s_tuner(struct file *file, void *priv,
                                        const struct v4l2_tuner *t)
 {
-       struct saa7134_fh *fh = file->private_data;
-       struct saa7134_dev *dev = fh->dev;
+       struct saa7134_dev *dev = video_drvdata(file);
 
        if (0 != t->index)
                return -EINVAL;
@@ -2309,50 +2053,6 @@ static int radio_s_tuner(struct file *file, void *priv,
        return 0;
 }
 
-static int radio_enum_input(struct file *file, void *priv,
-                                       struct v4l2_input *i)
-{
-       if (i->index != 0)
-               return -EINVAL;
-
-       strcpy(i->name, "Radio");
-       i->type = V4L2_INPUT_TYPE_TUNER;
-
-       return 0;
-}
-
-static int radio_g_input(struct file *filp, void *priv, unsigned int *i)
-{
-       *i = 0;
-       return 0;
-}
-
-static int radio_s_input(struct file *filp, void *priv, unsigned int i)
-{
-       return 0;
-}
-
-static int radio_s_std(struct file *file, void *fh, v4l2_std_id norm)
-{
-       return 0;
-}
-
-static int radio_queryctrl(struct file *file, void *priv,
-                                       struct v4l2_queryctrl *c)
-{
-       const struct v4l2_queryctrl *ctrl;
-
-       if (c->id <  V4L2_CID_BASE ||
-           c->id >= V4L2_CID_LASTP1)
-               return -EINVAL;
-       if (c->id == V4L2_CID_AUDIO_MUTE) {
-               ctrl = ctrl_by_id(c->id);
-               *c = *ctrl;
-       } else
-               *c = no_ctrl;
-       return 0;
-}
-
 static const struct v4l2_file_operations video_fops =
 {
        .owner    = THIS_MODULE,
@@ -2387,9 +2087,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_enum_input              = saa7134_enum_input,
        .vidioc_g_input                 = saa7134_g_input,
        .vidioc_s_input                 = saa7134_s_input,
-       .vidioc_queryctrl               = saa7134_queryctrl,
-       .vidioc_g_ctrl                  = saa7134_g_ctrl,
-       .vidioc_s_ctrl                  = saa7134_s_ctrl,
        .vidioc_streamon                = saa7134_streamon,
        .vidioc_streamoff               = saa7134_streamoff,
        .vidioc_g_tuner                 = saa7134_g_tuner,
@@ -2405,6 +2102,9 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
        .vidioc_g_register              = vidioc_g_register,
        .vidioc_s_register              = vidioc_s_register,
 #endif
+       .vidioc_log_status              = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event         = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event       = v4l2_event_unsubscribe,
 };
 
 static const struct v4l2_file_operations radio_fops = {
@@ -2419,16 +2119,11 @@ static const struct v4l2_file_operations radio_fops = {
 static const struct v4l2_ioctl_ops radio_ioctl_ops = {
        .vidioc_querycap        = saa7134_querycap,
        .vidioc_g_tuner         = radio_g_tuner,
-       .vidioc_enum_input      = radio_enum_input,
        .vidioc_s_tuner         = radio_s_tuner,
-       .vidioc_s_input         = radio_s_input,
-       .vidioc_s_std           = radio_s_std,
-       .vidioc_queryctrl       = radio_queryctrl,
-       .vidioc_g_input         = radio_g_input,
-       .vidioc_g_ctrl          = saa7134_g_ctrl,
-       .vidioc_s_ctrl          = saa7134_s_ctrl,
        .vidioc_g_frequency     = saa7134_g_frequency,
        .vidioc_s_frequency     = saa7134_s_frequency,
+       .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
 
 /* ----------------------------------------------------------- */
@@ -2447,8 +2142,55 @@ struct video_device saa7134_radio_template = {
        .ioctl_ops              = &radio_ioctl_ops,
 };
 
+static const struct v4l2_ctrl_ops saa7134_ctrl_ops = {
+       .s_ctrl = saa7134_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config saa7134_ctrl_invert = {
+       .ops = &saa7134_ctrl_ops,
+       .id = V4L2_CID_PRIVATE_INVERT,
+       .name = "Invert",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .min = 0,
+       .max = 1,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config saa7134_ctrl_y_odd = {
+       .ops = &saa7134_ctrl_ops,
+       .id = V4L2_CID_PRIVATE_Y_ODD,
+       .name = "Y Offset Odd Field",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 0,
+       .max = 128,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config saa7134_ctrl_y_even = {
+       .ops = &saa7134_ctrl_ops,
+       .id = V4L2_CID_PRIVATE_Y_EVEN,
+       .name = "Y Offset Even Field",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 0,
+       .max = 128,
+       .step = 1,
+};
+
+static const struct v4l2_ctrl_config saa7134_ctrl_automute = {
+       .ops = &saa7134_ctrl_ops,
+       .id = V4L2_CID_PRIVATE_AUTOMUTE,
+       .name = "Automute",
+       .type = V4L2_CTRL_TYPE_BOOLEAN,
+       .min = 0,
+       .max = 1,
+       .step = 1,
+       .def = 1,
+};
+
 int saa7134_video_init1(struct saa7134_dev *dev)
 {
+       struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+
        /* sanitycheck insmod options */
        if (gbuffers < 2 || gbuffers > VIDEO_MAX_FRAME)
                gbuffers = 2;
@@ -2456,17 +2198,38 @@ int saa7134_video_init1(struct saa7134_dev *dev)
                gbufsize = gbufsize_max;
        gbufsize = (gbufsize + PAGE_SIZE - 1) & PAGE_MASK;
 
-       /* put some sensible defaults into the data structures ... */
-       dev->ctl_bright     = ctrl_by_id(V4L2_CID_BRIGHTNESS)->default_value;
-       dev->ctl_contrast   = ctrl_by_id(V4L2_CID_CONTRAST)->default_value;
-       dev->ctl_hue        = ctrl_by_id(V4L2_CID_HUE)->default_value;
-       dev->ctl_saturation = ctrl_by_id(V4L2_CID_SATURATION)->default_value;
-       dev->ctl_volume     = ctrl_by_id(V4L2_CID_AUDIO_VOLUME)->default_value;
-       dev->ctl_mute       = 1; // ctrl_by_id(V4L2_CID_AUDIO_MUTE)->default_value;
-       dev->ctl_invert     = ctrl_by_id(V4L2_CID_PRIVATE_INVERT)->default_value;
-       dev->ctl_automute   = ctrl_by_id(V4L2_CID_PRIVATE_AUTOMUTE)->default_value;
-
-       if (dev->tda9887_conf && dev->ctl_automute)
+       v4l2_ctrl_handler_init(hdl, 11);
+       v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+                       V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+       v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+                       V4L2_CID_CONTRAST, 0, 127, 1, 68);
+       v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+                       V4L2_CID_SATURATION, 0, 127, 1, 64);
+       v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+                       V4L2_CID_HUE, -128, 127, 1, 0);
+       v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+                       V4L2_CID_HFLIP, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+                       V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+       v4l2_ctrl_new_std(hdl, &saa7134_ctrl_ops,
+                       V4L2_CID_AUDIO_VOLUME, -15, 15, 1, 0);
+       v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_invert, NULL);
+       v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_y_odd, NULL);
+       v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_y_even, NULL);
+       v4l2_ctrl_new_custom(hdl, &saa7134_ctrl_automute, NULL);
+       if (hdl->error)
+               return hdl->error;
+       if (card_has_radio(dev)) {
+               hdl = &dev->radio_ctrl_handler;
+               v4l2_ctrl_handler_init(hdl, 2);
+               v4l2_ctrl_add_handler(hdl, &dev->ctrl_handler,
+                               v4l2_ctrl_radio_filter);
+               if (hdl->error)
+                       return hdl->error;
+       }
+       dev->ctl_mute       = 1;
+
+       if (dev->tda9887_conf && saa7134_ctrl_automute.def)
                dev->tda9887_conf |= TDA9887_AUTOMUTE;
        dev->automute       = 0;
 
@@ -2489,9 +2252,34 @@ int saa7134_video_init1(struct saa7134_dev *dev)
        if (saa7134_boards[dev->board].video_out)
                saa7134_videoport_init(dev);
 
+       videobuf_queue_sg_init(&dev->cap, &video_qops,
+                           &dev->pci->dev, &dev->slock,
+                           V4L2_BUF_TYPE_VIDEO_CAPTURE,
+                           V4L2_FIELD_INTERLACED,
+                           sizeof(struct saa7134_buf),
+                           dev, NULL);
+       videobuf_queue_sg_init(&dev->vbi, &saa7134_vbi_qops,
+                           &dev->pci->dev, &dev->slock,
+                           V4L2_BUF_TYPE_VBI_CAPTURE,
+                           V4L2_FIELD_SEQ_TB,
+                           sizeof(struct saa7134_buf),
+                           dev, NULL);
+       saa7134_pgtable_alloc(dev->pci, &dev->pt_cap);
+       saa7134_pgtable_alloc(dev->pci, &dev->pt_vbi);
+
        return 0;
 }
 
+void saa7134_video_fini(struct saa7134_dev *dev)
+{
+       /* free stuff */
+       saa7134_pgtable_free(dev->pci, &dev->pt_cap);
+       saa7134_pgtable_free(dev->pci, &dev->pt_vbi);
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       if (card_has_radio(dev))
+               v4l2_ctrl_handler_free(&dev->radio_ctrl_handler);
+}
+
 int saa7134_videoport_init(struct saa7134_dev *dev)
 {
        /* enable video output */
@@ -2533,6 +2321,7 @@ int saa7134_video_init2(struct saa7134_dev *dev)
        /* init video hw */
        set_tvnorm(dev,&tvnorms[0]);
        video_mux(dev,0);
+       v4l2_ctrl_handler_setup(&dev->ctrl_handler);
        saa7134_tvaudio_setmute(dev);
        saa7134_tvaudio_setvolume(dev,dev->ctl_volume);
        return 0;
index 8d1453a48014f6a2e29bfabe77d63ef763fd535a..2474e848f2c03451aa957fc26fc0349120c9bbb3 100644 (file)
@@ -37,6 +37,7 @@
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fh.h>
+#include <media/v4l2-ctrls.h>
 #include <media/tuner.h>
 #include <media/rc-core.h>
 #include <media/ir-kbd-i2c.h>
@@ -410,12 +411,18 @@ struct saa7134_board {
 #define card(dev)             (saa7134_boards[dev->board])
 #define card_in(dev,n)        (saa7134_boards[dev->board].inputs[n])
 
+#define V4L2_CID_PRIVATE_INVERT      (V4L2_CID_USER_SAA7134_BASE + 0)
+#define V4L2_CID_PRIVATE_Y_ODD       (V4L2_CID_USER_SAA7134_BASE + 1)
+#define V4L2_CID_PRIVATE_Y_EVEN      (V4L2_CID_USER_SAA7134_BASE + 2)
+#define V4L2_CID_PRIVATE_AUTOMUTE    (V4L2_CID_USER_SAA7134_BASE + 3)
+
 /* ----------------------------------------------------------- */
 /* device / file handle status                                 */
 
 #define RESOURCE_OVERLAY       1
 #define RESOURCE_VIDEO         2
 #define RESOURCE_VBI           4
+#define RESOURCE_EMPRESS       8
 
 #define INTERLACE_AUTO         0
 #define INTERLACE_ON           1
@@ -470,16 +477,8 @@ struct saa7134_dmaqueue {
 /* video filehandle status */
 struct saa7134_fh {
        struct v4l2_fh             fh;
-       struct saa7134_dev         *dev;
+       bool                       is_empress;
        unsigned int               resources;
-
-       /* video capture */
-       struct videobuf_queue      cap;
-       struct saa7134_pgtable     pt_cap;
-
-       /* vbi capture */
-       struct videobuf_queue      vbi;
-       struct saa7134_pgtable     pt_vbi;
 };
 
 /* dmasound dsp status */
@@ -589,7 +588,11 @@ struct saa7134_dev {
 
        /* video+ts+vbi capture */
        struct saa7134_dmaqueue    video_q;
+       struct videobuf_queue      cap;
+       struct saa7134_pgtable     pt_cap;
        struct saa7134_dmaqueue    vbi_q;
+       struct videobuf_queue      vbi;
+       struct saa7134_pgtable     pt_vbi;
        unsigned int               video_fieldcount;
        unsigned int               vbi_fieldcount;
        struct saa7134_format      *fmt;
@@ -599,6 +602,7 @@ struct saa7134_dev {
        /* various v4l controls */
        struct saa7134_tvnorm      *tvnorm;              /* video */
        struct saa7134_tvaudio     *tvaudio;
+       struct v4l2_ctrl_handler   ctrl_handler;
        unsigned int               ctl_input;
        int                        ctl_bright;
        int                        ctl_contrast;
@@ -626,6 +630,7 @@ struct saa7134_dev {
        int                        last_carrier;
        int                        nosignal;
        unsigned int               insuspend;
+       struct v4l2_ctrl_handler   radio_ctrl_handler;
 
        /* I2C keyboard data */
        struct IR_i2c_init_data    init_data;
@@ -638,10 +643,11 @@ struct saa7134_dev {
 
        /* SAA7134_MPEG_EMPRESS only */
        struct video_device        *empress_dev;
+       struct v4l2_subdev         *empress_sd;
        struct videobuf_queue      empress_tsq;
-       atomic_t                   empress_users;
        struct work_struct         empress_workqueue;
        int                        empress_started;
+       struct v4l2_ctrl_handler   empress_ctrl_handler;
 
 #if IS_ENABLED(CONFIG_VIDEO_SAA7134_DVB)
        /* SAA7134_MPEG_DVB only */
@@ -699,6 +705,16 @@ struct saa7134_dev {
        _rc;                                                            \
 })
 
+static inline int res_check(struct saa7134_fh *fh, unsigned int bit)
+{
+       return fh->resources & bit;
+}
+
+static inline int res_locked(struct saa7134_dev *dev, unsigned int bit)
+{
+       return dev->resources & bit;
+}
+
 /* ----------------------------------------------------------- */
 /* saa7134-core.c                                              */
 
@@ -761,10 +777,31 @@ extern unsigned int video_debug;
 extern struct video_device saa7134_video_template;
 extern struct video_device saa7134_radio_template;
 
-int saa7134_s_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c);
-int saa7134_g_ctrl_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, struct v4l2_control *c);
-int saa7134_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *c);
-int saa7134_s_std_internal(struct saa7134_dev *dev,  struct saa7134_fh *fh, v4l2_std_id id);
+int saa7134_s_std(struct file *file, void *priv, v4l2_std_id id);
+int saa7134_g_std(struct file *file, void *priv, v4l2_std_id *id);
+int saa7134_enum_input(struct file *file, void *priv, struct v4l2_input *i);
+int saa7134_g_input(struct file *file, void *priv, unsigned int *i);
+int saa7134_s_input(struct file *file, void *priv, unsigned int i);
+int saa7134_querycap(struct file *file, void  *priv,
+                                       struct v4l2_capability *cap);
+int saa7134_g_tuner(struct file *file, void *priv,
+                                       struct v4l2_tuner *t);
+int saa7134_s_tuner(struct file *file, void *priv,
+                                       const struct v4l2_tuner *t);
+int saa7134_g_frequency(struct file *file, void *priv,
+                                       struct v4l2_frequency *f);
+int saa7134_s_frequency(struct file *file, void *priv,
+                                       const struct v4l2_frequency *f);
+int saa7134_reqbufs(struct file *file, void *priv,
+                                       struct v4l2_requestbuffers *p);
+int saa7134_querybuf(struct file *file, void *priv,
+                                       struct v4l2_buffer *b);
+int saa7134_qbuf(struct file *file, void *priv, struct v4l2_buffer *b);
+int saa7134_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b);
+int saa7134_streamon(struct file *file, void *priv,
+                                       enum v4l2_buf_type type);
+int saa7134_streamoff(struct file *file, void *priv,
+                                       enum v4l2_buf_type type);
 
 int saa7134_videoport_init(struct saa7134_dev *dev);
 void saa7134_set_tvnorm_hw(struct saa7134_dev *dev);
@@ -773,6 +810,7 @@ int saa7134_video_init1(struct saa7134_dev *dev);
 int saa7134_video_init2(struct saa7134_dev *dev);
 void saa7134_irq_video_signalchange(struct saa7134_dev *dev);
 void saa7134_irq_video_done(struct saa7134_dev *dev, unsigned long status);
+void saa7134_video_fini(struct saa7134_dev *dev);
 
 
 /* ----------------------------------------------------------- */
index 77edc113e48520228b587fb2d092e94f0ccfb54a..e5cfb6cfa18da513e70e7e41d9a06084eedd1555 100644 (file)
@@ -1303,7 +1303,7 @@ static int sta2x11_vip_resume(struct pci_dev *pdev)
 
 #endif
 
-static DEFINE_PCI_DEVICE_TABLE(sta2x11_vip_pci_tbl) = {
+static const struct pci_device_id sta2x11_vip_pci_tbl[] = {
        {PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_VIP)},
        {0,}
 };
index d7f0249e405004139ff1b0e42578170682ef443f..b2a4403940c551e68d00bc8974b89707c4f35d98 100644 (file)
@@ -36,7 +36,8 @@ source "drivers/media/platform/blackfin/Kconfig"
 config VIDEO_SH_VOU
        tristate "SuperH VOU video output driver"
        depends on MEDIA_CAMERA_SUPPORT
-       depends on VIDEO_DEV && ARCH_SHMOBILE && I2C
+       depends on VIDEO_DEV && I2C
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        select VIDEOBUF_DMA_CONTIG
        help
          Support for the Video Output Unit (VOU) on SuperH SoCs.
@@ -90,13 +91,6 @@ config VIDEO_M32R_AR_M64278
          To compile this driver as a module, choose M here: the
          module will be called arv.
 
-config VIDEO_OMAP2
-       tristate "OMAP2 Camera Capture Interface driver"
-       depends on VIDEO_DEV && ARCH_OMAP2 && VIDEO_V4L2_INT_DEVICE
-       select VIDEOBUF_DMA_SG
-       ---help---
-         This is a v4l2 driver for the TI OMAP2 camera capture interface
-
 config VIDEO_OMAP3
        tristate "OMAP 3 Camera support"
        depends on OMAP_IOVMM && VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && ARCH_OMAP3
index 1348ba1faf92ad33d047d8244e2590c77cd99e2c..e5269da91906bd0dea8760e361bb1d599d48b626 100644 (file)
@@ -2,8 +2,6 @@
 # Makefile for the video capture/playback device drivers.
 #
 
-omap2cam-objs  :=      omap24xxcam.o omap24xxcam-dma.o
-
 obj-$(CONFIG_VIDEO_VINO) += indycam.o
 obj-$(CONFIG_VIDEO_VINO) += vino.o
 
@@ -14,7 +12,6 @@ obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
 obj-$(CONFIG_VIDEO_CAFE_CCIC) += marvell-ccic/
 obj-$(CONFIG_VIDEO_MMP_CAMERA) += marvell-ccic/
 
-obj-$(CONFIG_VIDEO_OMAP2)              += omap2cam.o
 obj-$(CONFIG_VIDEO_OMAP3)      += omap3isp/
 
 obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
index eac472b5ae83baf0cdefb0fb2920a1e99b925094..b02aba48882632661962aa52380248409a8457d4 100644 (file)
@@ -347,7 +347,7 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
        /* If buffer queue is empty, return error */
        if (list_empty(&layer->dma_queue)) {
                v4l2_err(&vpbe_dev->v4l2_dev, "buffer queue is empty\n");
-               return -EINVAL;
+               return -ENOBUFS;
        }
        /* Get the next frame from the buffer queue */
        layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
index 52ac5e6c86254d0bd7ba5a4dadee4ba6ca70d08e..735ec47601a9c3241e790315e46efbc437668e56 100644 (file)
@@ -277,7 +277,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
        if (list_empty(&common->dma_queue)) {
                spin_unlock_irqrestore(&common->irqlock, flags);
                vpif_dbg(1, debug, "buffer queue is empty\n");
-               return -EIO;
+               return -ENOBUFS;
        }
 
        /* Get the next frame from the buffer queue */
index c31bcf129a5de08122744d7ad0dae956440a5385..9d115cdc6bdbfdbfc7b1a655346d6a2ad3a13d7e 100644 (file)
@@ -239,7 +239,7 @@ static int vpif_start_streaming(struct vb2_queue *vq, unsigned int count)
        if (list_empty(&common->dma_queue)) {
                spin_unlock_irqrestore(&common->irqlock, flags);
                vpif_err("buffer queue is empty\n");
-               return -EIO;
+               return -ENOBUFS;
        }
 
        /* Get the next frame from the buffer queue */
index d2d3b4b614359e239a540198451fd55b81339353..01ed1ecdff7e671fd46b4f0f3438c3a8f6c60658 100644 (file)
@@ -1,7 +1,7 @@
 
 config VIDEO_SAMSUNG_EXYNOS4_IS
        bool "Samsung S5P/EXYNOS4 SoC series Camera Subsystem driver"
-       depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && PM_RUNTIME
+       depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
        depends on (PLAT_S5P || ARCH_EXYNOS)
        help
          Say Y here to enable camera host interface devices for
index fb27ff7e1e0750e33215b96ee100c9ad569fd9dd..8a712ca91d11bcf46f424778433b3c7c07bbdc78 100644 (file)
@@ -549,7 +549,7 @@ static int fimc_capture_release(struct file *file)
                vc->streaming = false;
        }
 
-       ret = vb2_fop_release(file);
+       ret = _vb2_fop_release(file, NULL);
 
        if (close) {
                clear_bit(ST_CAPT_BUSY, &fimc->state);
index f7915695c9073d37ca10da947c29891b8d0e45d5..a7dfd07e838954b6fb500cc6d1d7991ea5cf0dc5 100644 (file)
@@ -998,36 +998,39 @@ static int fimc_probe(struct platform_device *pdev)
 
        ret = devm_request_irq(dev, res->start, fimc_irq_handler,
                               0, dev_name(dev), fimc);
-       if (ret) {
+       if (ret < 0) {
                dev_err(dev, "failed to install irq (%d)\n", ret);
-               goto err_clk;
+               goto err_sclk;
        }
 
        ret = fimc_initialize_capture_subdev(fimc);
-       if (ret)
-               goto err_clk;
+       if (ret < 0)
+               goto err_sclk;
 
        platform_set_drvdata(pdev, fimc);
        pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(dev);
-       if (ret < 0)
-               goto err_sd;
+
+       if (!pm_runtime_enabled(dev)) {
+               ret = clk_enable(fimc->clock[CLK_GATE]);
+               if (ret < 0)
+                       goto err_sd;
+       }
+
        /* Initialize contiguous memory allocator */
        fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
        if (IS_ERR(fimc->alloc_ctx)) {
                ret = PTR_ERR(fimc->alloc_ctx);
-               goto err_pm;
+               goto err_gclk;
        }
 
        dev_dbg(dev, "FIMC.%d registered successfully\n", fimc->id);
-
-       pm_runtime_put(dev);
        return 0;
-err_pm:
-       pm_runtime_put(dev);
+
+err_gclk:
+       clk_disable(fimc->clock[CLK_GATE]);
 err_sd:
        fimc_unregister_capture_subdev(fimc);
-err_clk:
+err_sclk:
        clk_disable(fimc->clock[CLK_BUS]);
        fimc_clk_put(fimc);
        return ret;
index 3d376faec777d1781434cdbf5526301f50b98271..1790fb4e32eabfc8af8084d452e6483827a3852f 100644 (file)
@@ -481,7 +481,6 @@ struct fimc_ctrls {
  * @flags:             additional flags for image conversion
  * @state:             flags to keep track of user configuration
  * @fimc_dev:          the FIMC device this context applies to
- * @m2m_ctx:           memory-to-memory device context
  * @fh:                        v4l2 file handle
  * @ctrls:             v4l2 controls structure
  */
@@ -502,7 +501,6 @@ struct fimc_ctx {
        u32                     flags;
        u32                     state;
        struct fimc_dev         *fimc_dev;
-       struct v4l2_m2m_ctx     *m2m_ctx;
        struct v4l2_fh          fh;
        struct fimc_ctrls       ctrls;
 };
index f758e2694fa3f1eede8b7155fb10094e72e08a04..2628733c4e104f6e7790a74b40f1add7416a2760 100644 (file)
@@ -33,47 +33,23 @@ void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is)
        mcuctl_write(INTGR0_INTGD(0), is, MCUCTL_REG_INTGR0);
 }
 
-int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is)
-{
-       unsigned int timeout = 2000;
-       u32 cfg, status;
-
-       cfg = mcuctl_read(is, MCUCTL_REG_INTSR0);
-       status = INTSR0_GET_INTSD(0, cfg);
-
-       while (status) {
-               cfg = mcuctl_read(is, MCUCTL_REG_INTSR0);
-               status = INTSR0_GET_INTSD(0, cfg);
-               if (timeout == 0) {
-                       dev_warn(&is->pdev->dev, "%s timeout\n",
-                                __func__);
-                       return -ETIME;
-               }
-               timeout--;
-               udelay(1);
-       }
-       return 0;
-}
-
 int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is)
 {
        unsigned int timeout = 2000;
        u32 cfg, status;
 
-       cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0);
-       status = INTMSR0_GET_INTMSD(0, cfg);
-
-       while (status) {
+       do {
                cfg = mcuctl_read(is, MCUCTL_REG_INTMSR0);
                status = INTMSR0_GET_INTMSD(0, cfg);
-               if (timeout == 0) {
+
+               if (--timeout == 0) {
                        dev_warn(&is->pdev->dev, "%s timeout\n",
                                 __func__);
-                       return -ETIME;
+                       return -ETIMEDOUT;
                }
-               timeout--;
                udelay(1);
-       }
+       } while (status != 0);
+
        return 0;
 }
 
index 5fa2fda46742687e97e7aad2f14a508e6889ecfe..1d9d4ffc6ad59ca8d24fbd0bef0005ece14d1354 100644 (file)
@@ -145,7 +145,6 @@ void fimc_is_fw_clear_irq2(struct fimc_is *is);
 int fimc_is_hw_get_params(struct fimc_is *is, unsigned int num);
 
 void fimc_is_hw_set_intgr0_gd0(struct fimc_is *is);
-int fimc_is_hw_wait_intsr0_intsd0(struct fimc_is *is);
 int fimc_is_hw_wait_intmsr0_intmsd0(struct fimc_is *is);
 void fimc_is_hw_set_sensor_num(struct fimc_is *is);
 void fimc_is_hw_stream_on(struct fimc_is *is);
index 9770fa98d6a16403fcae21e2d38eec6c723e4e68..13a4228952e32809fdcb8903e40db6f51d187316 100644 (file)
@@ -781,6 +781,9 @@ static int fimc_is_debugfs_create(struct fimc_is *is)
        return is->debugfs_entry == NULL ? -EIO : 0;
 }
 
+static int fimc_is_runtime_resume(struct device *dev);
+static int fimc_is_runtime_suspend(struct device *dev);
+
 static int fimc_is_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
@@ -835,14 +838,20 @@ static int fimc_is_probe(struct platform_device *pdev)
        }
        pm_runtime_enable(dev);
 
+       if (!pm_runtime_enabled(dev)) {
+               ret = fimc_is_runtime_resume(dev);
+               if (ret < 0)
+                       goto err_irq;
+       }
+
        ret = pm_runtime_get_sync(dev);
        if (ret < 0)
-               goto err_irq;
+               goto err_pm;
 
        is->alloc_ctx = vb2_dma_contig_init_ctx(dev);
        if (IS_ERR(is->alloc_ctx)) {
                ret = PTR_ERR(is->alloc_ctx);
-               goto err_irq;
+               goto err_pm;
        }
        /*
         * Register FIMC-IS V4L2 subdevs to this driver. The video nodes
@@ -867,10 +876,13 @@ static int fimc_is_probe(struct platform_device *pdev)
 
 err_dfs:
        fimc_is_debugfs_remove(is);
-err_vb:
-       vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
 err_sd:
        fimc_is_unregister_subdevs(is);
+err_vb:
+       vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
+err_pm:
+       if (!pm_runtime_enabled(dev))
+               fimc_is_runtime_suspend(dev);
 err_irq:
        free_irq(is->irq, is);
 err_clk:
@@ -919,10 +931,13 @@ static int fimc_is_suspend(struct device *dev)
 
 static int fimc_is_remove(struct platform_device *pdev)
 {
-       struct fimc_is *is = platform_get_drvdata(pdev);
+       struct device *dev = &pdev->dev;
+       struct fimc_is *is = dev_get_drvdata(dev);
 
-       pm_runtime_disable(&pdev->dev);
-       pm_runtime_set_suspended(&pdev->dev);
+       pm_runtime_disable(dev);
+       pm_runtime_set_suspended(dev);
+       if (!pm_runtime_status_suspended(dev))
+               fimc_is_runtime_suspend(dev);
        free_irq(is->irq, is);
        fimc_is_unregister_subdevs(is);
        vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
index 72a343e3b5e85e62393f8950c3d0e096d09b8909..d0dc7ee0445272eb9d3111b88a33460626f49a6a 100644 (file)
@@ -133,7 +133,7 @@ void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
        int i = ARRAY_SIZE(src_pixfmt_map);
        u32 cfg;
 
-       while (--i >= 0) {
+       while (--i) {
                if (src_pixfmt_map[i][0] == pixelcode)
                        break;
        }
@@ -240,7 +240,7 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
        u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
        int i = ARRAY_SIZE(pixcode);
 
-       while (--i >= 0)
+       while (--i)
                if (pixcode[i][0] == f->fmt->mbus_code)
                        break;
        cfg &= ~FLITE_REG_CIODMAFMT_YCBCR_ORDER_MASK;
index e5798f70d149287a1df8e080c9e0ed766d0a73de..1234734bccf4d3943d047e53a2f54347d73c58c0 100644 (file)
@@ -546,7 +546,7 @@ static int fimc_lite_release(struct file *file)
                mutex_unlock(&entity->parent->graph_mutex);
        }
 
-       vb2_fop_release(file);
+       _vb2_fop_release(file, NULL);
        pm_runtime_put(&fimc->pdev->dev);
        clear_bit(ST_FLITE_SUSPENDED, &fimc->state);
 
@@ -1549,38 +1549,40 @@ static int fimc_lite_probe(struct platform_device *pdev)
                               0, dev_name(dev), fimc);
        if (ret) {
                dev_err(dev, "Failed to install irq (%d)\n", ret);
-               goto err_clk;
+               goto err_clk_put;
        }
 
        /* The video node will be created within the subdev's registered() op */
        ret = fimc_lite_create_capture_subdev(fimc);
        if (ret)
-               goto err_clk;
+               goto err_clk_put;
 
        platform_set_drvdata(pdev, fimc);
        pm_runtime_enable(dev);
-       ret = pm_runtime_get_sync(dev);
-       if (ret < 0)
-               goto err_sd;
+
+       if (!pm_runtime_enabled(dev)) {
+               ret = clk_enable(fimc->clock);
+               if (ret < 0)
+                       goto err_clk_put;
+       }
 
        fimc->alloc_ctx = vb2_dma_contig_init_ctx(dev);
        if (IS_ERR(fimc->alloc_ctx)) {
                ret = PTR_ERR(fimc->alloc_ctx);
-               goto err_pm;
+               goto err_clk_dis;
        }
 
-       pm_runtime_put(dev);
-
        fimc_lite_set_default_config(fimc);
 
        dev_dbg(dev, "FIMC-LITE.%d registered successfully\n",
                fimc->index);
        return 0;
-err_pm:
-       pm_runtime_put(dev);
+
+err_clk_dis:
+       clk_disable(fimc->clock);
 err_sd:
        fimc_lite_unregister_capture_subdev(fimc);
-err_clk:
+err_clk_put:
        fimc_lite_clk_put(fimc);
        return ret;
 }
index 8d33b68c76bac7d9e278785a8c914dddce602197..9da95bd148200d5a4406aa6f80a09bf1364d7c65 100644 (file)
@@ -44,17 +44,17 @@ void fimc_m2m_job_finish(struct fimc_ctx *ctx, int vb_state)
 {
        struct vb2_buffer *src_vb, *dst_vb;
 
-       if (!ctx || !ctx->m2m_ctx)
+       if (!ctx || !ctx->fh.m2m_ctx)
                return;
 
-       src_vb = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-       dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+       src_vb = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 
        if (src_vb && dst_vb) {
                v4l2_m2m_buf_done(src_vb, vb_state);
                v4l2_m2m_buf_done(dst_vb, vb_state);
                v4l2_m2m_job_finish(ctx->fimc_dev->m2m.m2m_dev,
-                                   ctx->m2m_ctx);
+                                   ctx->fh.m2m_ctx);
        }
 }
 
@@ -123,12 +123,12 @@ static void fimc_device_run(void *priv)
                fimc_prepare_dma_offset(ctx, df);
        }
 
-       src_vb = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+       src_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
        ret = fimc_prepare_addr(ctx, src_vb, sf, &sf->paddr);
        if (ret)
                goto dma_unlock;
 
-       dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       dst_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
        ret = fimc_prepare_addr(ctx, dst_vb, df, &df->paddr);
        if (ret)
                goto dma_unlock;
@@ -219,31 +219,15 @@ static int fimc_buf_prepare(struct vb2_buffer *vb)
 static void fimc_buf_queue(struct vb2_buffer *vb)
 {
        struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-
-       dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
-
-       if (ctx->m2m_ctx)
-               v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
-}
-
-static void fimc_lock(struct vb2_queue *vq)
-{
-       struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
-       mutex_lock(&ctx->fimc_dev->lock);
-}
-
-static void fimc_unlock(struct vb2_queue *vq)
-{
-       struct fimc_ctx *ctx = vb2_get_drv_priv(vq);
-       mutex_unlock(&ctx->fimc_dev->lock);
+       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
 }
 
 static struct vb2_ops fimc_qops = {
        .queue_setup     = fimc_queue_setup,
        .buf_prepare     = fimc_buf_prepare,
        .buf_queue       = fimc_buf_queue,
-       .wait_prepare    = fimc_unlock,
-       .wait_finish     = fimc_lock,
+       .wait_prepare    = vb2_ops_wait_prepare,
+       .wait_finish     = vb2_ops_wait_finish,
        .stop_streaming  = stop_streaming,
        .start_streaming = start_streaming,
 };
@@ -385,7 +369,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
        if (ret)
                return ret;
 
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
 
        if (vb2_is_busy(vq)) {
                v4l2_err(&fimc->m2m.vfd, "queue (%d) busy\n", f->type);
@@ -410,56 +394,6 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh,
        return 0;
 }
 
-static int fimc_m2m_reqbufs(struct file *file, void *fh,
-                           struct v4l2_requestbuffers *reqbufs)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(fh);
-       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int fimc_m2m_querybuf(struct file *file, void *fh,
-                            struct v4l2_buffer *buf)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(fh);
-       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int fimc_m2m_qbuf(struct file *file, void *fh,
-                        struct v4l2_buffer *buf)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(fh);
-       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int fimc_m2m_dqbuf(struct file *file, void *fh,
-                         struct v4l2_buffer *buf)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(fh);
-       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int fimc_m2m_expbuf(struct file *file, void *fh,
-                           struct v4l2_exportbuffer *eb)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(fh);
-       return v4l2_m2m_expbuf(file, ctx->m2m_ctx, eb);
-}
-
-
-static int fimc_m2m_streamon(struct file *file, void *fh,
-                            enum v4l2_buf_type type)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(fh);
-       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int fimc_m2m_streamoff(struct file *file, void *fh,
-                           enum v4l2_buf_type type)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(fh);
-       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
 static int fimc_m2m_cropcap(struct file *file, void *fh,
                            struct v4l2_cropcap *cr)
 {
@@ -598,13 +532,13 @@ static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
        .vidioc_try_fmt_vid_out_mplane  = fimc_m2m_try_fmt_mplane,
        .vidioc_s_fmt_vid_cap_mplane    = fimc_m2m_s_fmt_mplane,
        .vidioc_s_fmt_vid_out_mplane    = fimc_m2m_s_fmt_mplane,
-       .vidioc_reqbufs                 = fimc_m2m_reqbufs,
-       .vidioc_querybuf                = fimc_m2m_querybuf,
-       .vidioc_qbuf                    = fimc_m2m_qbuf,
-       .vidioc_dqbuf                   = fimc_m2m_dqbuf,
-       .vidioc_expbuf                  = fimc_m2m_expbuf,
-       .vidioc_streamon                = fimc_m2m_streamon,
-       .vidioc_streamoff               = fimc_m2m_streamoff,
+       .vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
+       .vidioc_qbuf                    = v4l2_m2m_ioctl_qbuf,
+       .vidioc_dqbuf                   = v4l2_m2m_ioctl_dqbuf,
+       .vidioc_expbuf                  = v4l2_m2m_ioctl_expbuf,
+       .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
        .vidioc_g_crop                  = fimc_m2m_g_crop,
        .vidioc_s_crop                  = fimc_m2m_s_crop,
        .vidioc_cropcap                 = fimc_m2m_cropcap
@@ -624,6 +558,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
        src_vq->mem_ops = &vb2_dma_contig_memops;
        src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
        src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock = &ctx->fimc_dev->lock;
 
        ret = vb2_queue_init(src_vq);
        if (ret)
@@ -636,6 +571,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
        dst_vq->mem_ops = &vb2_dma_contig_memops;
        dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
        dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock = &ctx->fimc_dev->lock;
 
        return vb2_queue_init(dst_vq);
 }
@@ -708,9 +644,9 @@ static int fimc_m2m_open(struct file *file)
        ctx->out_path = FIMC_IO_DMA;
        ctx->scaler.enabled = 1;
 
-       ctx->m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
-       if (IS_ERR(ctx->m2m_ctx)) {
-               ret = PTR_ERR(ctx->m2m_ctx);
+       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(fimc->m2m.m2m_dev, ctx, queue_init);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               ret = PTR_ERR(ctx->fh.m2m_ctx);
                goto error_c;
        }
 
@@ -725,7 +661,7 @@ static int fimc_m2m_open(struct file *file)
        return 0;
 
 error_m2m_ctx:
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
 error_c:
        fimc_ctrls_delete(ctx);
 error_fh:
@@ -747,7 +683,7 @@ static int fimc_m2m_release(struct file *file)
 
        mutex_lock(&fimc->lock);
 
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
        fimc_ctrls_delete(ctx);
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
@@ -760,45 +696,13 @@ static int fimc_m2m_release(struct file *file)
        return 0;
 }
 
-static unsigned int fimc_m2m_poll(struct file *file,
-                                 struct poll_table_struct *wait)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
-       struct fimc_dev *fimc = ctx->fimc_dev;
-       int ret;
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
-       ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
-       mutex_unlock(&fimc->lock);
-
-       return ret;
-}
-
-
-static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct fimc_ctx *ctx = fh_to_ctx(file->private_data);
-       struct fimc_dev *fimc = ctx->fimc_dev;
-       int ret;
-
-       if (mutex_lock_interruptible(&fimc->lock))
-               return -ERESTARTSYS;
-
-       ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-       mutex_unlock(&fimc->lock);
-
-       return ret;
-}
-
 static const struct v4l2_file_operations fimc_m2m_fops = {
        .owner          = THIS_MODULE,
        .open           = fimc_m2m_open,
        .release        = fimc_m2m_release,
-       .poll           = fimc_m2m_poll,
+       .poll           = v4l2_m2m_fop_poll,
        .unlocked_ioctl = video_ioctl2,
-       .mmap           = fimc_m2m_mmap,
+       .mmap           = v4l2_m2m_fop_mmap,
 };
 
 static struct v4l2_m2m_ops m2m_ops = {
index 9fc2af6a04466b402c6f931097e28dbdec2ad29c..f3c3591fdc5d6849e4ca884a5caecaf436f0f7d4 100644 (file)
@@ -91,7 +91,7 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
 #define S5PCSIS_INTSRC_ODD_BEFORE      (1 << 29)
 #define S5PCSIS_INTSRC_ODD_AFTER       (1 << 28)
 #define S5PCSIS_INTSRC_ODD             (0x3 << 28)
-#define S5PCSIS_INTSRC_NON_IMAGE_DATA  (0xff << 28)
+#define S5PCSIS_INTSRC_NON_IMAGE_DATA  (0xf << 28)
 #define S5PCSIS_INTSRC_FRAME_START     (1 << 27)
 #define S5PCSIS_INTSRC_FRAME_END       (1 << 26)
 #define S5PCSIS_INTSRC_ERR_SOT_HS      (0xf << 12)
@@ -790,6 +790,7 @@ static int s5pcsis_parse_dt(struct platform_device *pdev,
 #define s5pcsis_parse_dt(pdev, state) (-ENOSYS)
 #endif
 
+static int s5pcsis_pm_resume(struct device *dev, bool runtime);
 static const struct of_device_id s5pcsis_of_match[];
 
 static int s5pcsis_probe(struct platform_device *pdev)
@@ -902,13 +903,21 @@ static int s5pcsis_probe(struct platform_device *pdev)
        /* .. and a pointer to the subdev. */
        platform_set_drvdata(pdev, &state->sd);
        memcpy(state->events, s5pcsis_events, sizeof(state->events));
+
        pm_runtime_enable(dev);
+       if (!pm_runtime_enabled(dev)) {
+               ret = s5pcsis_pm_resume(dev, true);
+               if (ret < 0)
+                       goto e_m_ent;
+       }
 
        dev_info(&pdev->dev, "lanes: %d, hs_settle: %d, wclk: %d, freq: %u\n",
                 state->num_lanes, state->hs_settle, state->wclk_ext,
                 state->clk_frequency);
        return 0;
 
+e_m_ent:
+       media_entity_cleanup(&state->sd.entity);
 e_clkdis:
        clk_disable(state->clock[CSIS_CLK_MUX]);
 e_clkput:
@@ -1014,7 +1023,7 @@ static int s5pcsis_remove(struct platform_device *pdev)
        struct csis_state *state = sd_to_csis_state(sd);
 
        pm_runtime_disable(&pdev->dev);
-       s5pcsis_pm_suspend(&pdev->dev, false);
+       s5pcsis_pm_suspend(&pdev->dev, true);
        clk_disable(state->clock[CSIS_CLK_MUX]);
        pm_runtime_set_suspended(&pdev->dev);
        s5pcsis_clk_put(state);
index 6a232239ee8c71f8c04d3c42c002af2c789fd9a8..dbf0ce38a8e7db1566d5ddde361f51d570fca03d 100644 (file)
@@ -1580,7 +1580,7 @@ static int viu_of_probe(struct platform_device *op)
        }
 
        /* enable VIU clock */
-       clk = devm_clk_get(&op->dev, "viu_clk");
+       clk = devm_clk_get(&op->dev, "ipg");
        if (IS_ERR(clk)) {
                dev_err(&op->dev, "failed to lookup the clock!\n");
                ret = PTR_ERR(clk);
index 65cab70fefcb067e3de0a404d47bd41feaafd38b..6bb86b581a34e43f0fe34cc44f5a2132b1589e7b 100644 (file)
@@ -918,7 +918,7 @@ static int deinterlace_open(struct file *file)
                return ret;
        }
 
-       ctx->xt = kzalloc(sizeof(struct dma_async_tx_descriptor) +
+       ctx->xt = kzalloc(sizeof(struct dma_interleaved_template) +
                                sizeof(struct data_chunk), GFP_KERNEL);
        if (!ctx->xt) {
                kfree(ctx);
index 8df5975b700a01c8f433fb902e1d10e2983de5aa..08e24379b7949af3a71f67123dd8749ce831c7aa 100644 (file)
@@ -177,8 +177,6 @@ struct m2mtest_ctx {
 
        enum v4l2_colorspace    colorspace;
 
-       struct v4l2_m2m_ctx     *m2m_ctx;
-
        /* Source and destination queue data */
        struct m2mtest_q_data   q_data[2];
 };
@@ -342,8 +340,8 @@ static int job_ready(void *priv)
 {
        struct m2mtest_ctx *ctx = priv;
 
-       if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < ctx->translen
-           || v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < ctx->translen) {
+       if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen
+           || v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) {
                dprintk(ctx->dev, "Not enough buffers available\n");
                return 0;
        }
@@ -359,21 +357,6 @@ static void job_abort(void *priv)
        ctx->aborting = 1;
 }
 
-static void m2mtest_lock(void *priv)
-{
-       struct m2mtest_ctx *ctx = priv;
-       struct m2mtest_dev *dev = ctx->dev;
-       mutex_lock(&dev->dev_mutex);
-}
-
-static void m2mtest_unlock(void *priv)
-{
-       struct m2mtest_ctx *ctx = priv;
-       struct m2mtest_dev *dev = ctx->dev;
-       mutex_unlock(&dev->dev_mutex);
-}
-
-
 /* device_run() - prepares and starts the device
  *
  * This simulates all the immediate preparations required before starting
@@ -386,8 +369,8 @@ static void device_run(void *priv)
        struct m2mtest_dev *dev = ctx->dev;
        struct vb2_buffer *src_buf, *dst_buf;
 
-       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 
        device_process(ctx, src_buf, dst_buf);
 
@@ -409,8 +392,8 @@ static void device_isr(unsigned long priv)
                return;
        }
 
-       src_vb = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
-       dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+       src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
+       dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
 
        curr_ctx->num_processed++;
 
@@ -423,7 +406,7 @@ static void device_isr(unsigned long priv)
            || curr_ctx->aborting) {
                dprintk(curr_ctx->dev, "Finishing transaction\n");
                curr_ctx->num_processed = 0;
-               v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->m2m_ctx);
+               v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->fh.m2m_ctx);
        } else {
                device_run(curr_ctx);
        }
@@ -491,7 +474,7 @@ static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
        struct vb2_queue *vq;
        struct m2mtest_q_data *q_data;
 
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
        if (!vq)
                return -EINVAL;
 
@@ -594,7 +577,7 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
        struct m2mtest_q_data *q_data;
        struct vb2_queue *vq;
 
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
        if (!vq)
                return -EINVAL;
 
@@ -648,52 +631,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
        return ret;
 }
 
-static int vidioc_reqbufs(struct file *file, void *priv,
-                         struct v4l2_requestbuffers *reqbufs)
-{
-       struct m2mtest_ctx *ctx = file2ctx(file);
-
-       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-                          struct v4l2_buffer *buf)
-{
-       struct m2mtest_ctx *ctx = file2ctx(file);
-
-       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct m2mtest_ctx *ctx = file2ctx(file);
-
-       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct m2mtest_ctx *ctx = file2ctx(file);
-
-       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_streamon(struct file *file, void *priv,
-                          enum v4l2_buf_type type)
-{
-       struct m2mtest_ctx *ctx = file2ctx(file);
-
-       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
-                           enum v4l2_buf_type type)
-{
-       struct m2mtest_ctx *ctx = file2ctx(file);
-
-       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
 static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct m2mtest_ctx *ctx =
@@ -748,14 +685,14 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
        .vidioc_try_fmt_vid_out = vidioc_try_fmt_vid_out,
        .vidioc_s_fmt_vid_out   = vidioc_s_fmt_vid_out,
 
-       .vidioc_reqbufs         = vidioc_reqbufs,
-       .vidioc_querybuf        = vidioc_querybuf,
+       .vidioc_reqbufs         = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf        = v4l2_m2m_ioctl_querybuf,
+       .vidioc_qbuf            = v4l2_m2m_ioctl_qbuf,
+       .vidioc_dqbuf           = v4l2_m2m_ioctl_dqbuf,
 
-       .vidioc_qbuf            = vidioc_qbuf,
-       .vidioc_dqbuf           = vidioc_dqbuf,
+       .vidioc_streamon        = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff       = v4l2_m2m_ioctl_streamoff,
 
-       .vidioc_streamon        = vidioc_streamon,
-       .vidioc_streamoff       = vidioc_streamoff,
        .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
        .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
 };
@@ -818,27 +755,15 @@ static int m2mtest_buf_prepare(struct vb2_buffer *vb)
 static void m2mtest_buf_queue(struct vb2_buffer *vb)
 {
        struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
-}
-
-static void m2mtest_wait_prepare(struct vb2_queue *q)
-{
-       struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
-       m2mtest_unlock(ctx);
-}
-
-static void m2mtest_wait_finish(struct vb2_queue *q)
-{
-       struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
-       m2mtest_lock(ctx);
+       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
 }
 
 static struct vb2_ops m2mtest_qops = {
        .queue_setup     = m2mtest_queue_setup,
        .buf_prepare     = m2mtest_buf_prepare,
        .buf_queue       = m2mtest_buf_queue,
-       .wait_prepare    = m2mtest_wait_prepare,
-       .wait_finish     = m2mtest_wait_finish,
+       .wait_prepare    = vb2_ops_wait_prepare,
+       .wait_finish     = vb2_ops_wait_finish,
 };
 
 static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
@@ -853,6 +778,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
        src_vq->ops = &m2mtest_qops;
        src_vq->mem_ops = &vb2_vmalloc_memops;
        src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock = &ctx->dev->dev_mutex;
 
        ret = vb2_queue_init(src_vq);
        if (ret)
@@ -865,6 +791,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
        dst_vq->ops = &m2mtest_qops;
        dst_vq->mem_ops = &vb2_vmalloc_memops;
        dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock = &ctx->dev->dev_mutex;
 
        return vb2_queue_init(dst_vq);
 }
@@ -936,10 +863,10 @@ static int m2mtest_open(struct file *file)
        ctx->q_data[V4L2_M2M_DST] = ctx->q_data[V4L2_M2M_SRC];
        ctx->colorspace = V4L2_COLORSPACE_REC709;
 
-       ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
 
-       if (IS_ERR(ctx->m2m_ctx)) {
-               rc = PTR_ERR(ctx->m2m_ctx);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               rc = PTR_ERR(ctx->fh.m2m_ctx);
 
                v4l2_ctrl_handler_free(hdl);
                kfree(ctx);
@@ -949,7 +876,8 @@ static int m2mtest_open(struct file *file)
        v4l2_fh_add(&ctx->fh);
        atomic_inc(&dev->num_inst);
 
-       dprintk(dev, "Created instance %p, m2m_ctx: %p\n", ctx, ctx->m2m_ctx);
+       dprintk(dev, "Created instance: %p, m2m_ctx: %p\n",
+               ctx, ctx->fh.m2m_ctx);
 
 open_unlock:
        mutex_unlock(&dev->dev_mutex);
@@ -967,7 +895,7 @@ static int m2mtest_release(struct file *file)
        v4l2_fh_exit(&ctx->fh);
        v4l2_ctrl_handler_free(&ctx->hdl);
        mutex_lock(&dev->dev_mutex);
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
        mutex_unlock(&dev->dev_mutex);
        kfree(ctx);
 
@@ -976,34 +904,13 @@ static int m2mtest_release(struct file *file)
        return 0;
 }
 
-static unsigned int m2mtest_poll(struct file *file,
-                                struct poll_table_struct *wait)
-{
-       struct m2mtest_ctx *ctx = file2ctx(file);
-
-       return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
-}
-
-static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct m2mtest_dev *dev = video_drvdata(file);
-       struct m2mtest_ctx *ctx = file2ctx(file);
-       int res;
-
-       if (mutex_lock_interruptible(&dev->dev_mutex))
-               return -ERESTARTSYS;
-       res = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-       mutex_unlock(&dev->dev_mutex);
-       return res;
-}
-
 static const struct v4l2_file_operations m2mtest_fops = {
        .owner          = THIS_MODULE,
        .open           = m2mtest_open,
        .release        = m2mtest_release,
-       .poll           = m2mtest_poll,
+       .poll           = v4l2_m2m_fop_poll,
        .unlocked_ioctl = video_ioctl2,
-       .mmap           = m2mtest_mmap,
+       .mmap           = v4l2_m2m_fop_mmap,
 };
 
 static struct video_device m2mtest_videodev = {
@@ -1019,8 +926,6 @@ static struct v4l2_m2m_ops m2m_ops = {
        .device_run     = device_run,
        .job_ready      = job_ready,
        .job_abort      = job_abort,
-       .lock           = m2mtest_lock,
-       .unlock         = m2mtest_unlock,
 };
 
 static int m2mtest_probe(struct platform_device *pdev)
@@ -1133,4 +1038,3 @@ static int __init m2mtest_init(void)
 
 module_init(m2mtest_init);
 module_exit(m2mtest_exit);
-
index fdbdeae3900dd0bb92ea10184239d9bd6c004074..5807185262fef29a20dbb2cd5380da6887b182b7 100644 (file)
@@ -873,15 +873,12 @@ static int isp_pipeline_enable(struct isp_pipeline *pipe,
        unsigned long flags;
        int ret;
 
-       /* If the preview engine crashed it might not respond to read/write
-        * operations on the L4 bus. This would result in a bus fault and a
-        * kernel oops. Refuse to start streaming in that case. This check must
-        * be performed before the loop below to avoid starting entities if the
-        * pipeline won't start anyway (those entities would then likely fail to
-        * stop, making the problem worse).
+       /* Refuse to start streaming if an entity included in the pipeline has
+        * crashed. This check must be performed before the loop below to avoid
+        * starting entities if the pipeline won't start anyway (those entities
+        * would then likely fail to stop, making the problem worse).
         */
-       if ((pipe->entities & isp->crashed) &
-           (1U << isp->isp_prev.subdev.entity.id))
+       if (pipe->entities & isp->crashed)
                return -EIO;
 
        spin_lock_irqsave(&pipe->lock, flags);
@@ -1014,13 +1011,23 @@ static int isp_pipeline_disable(struct isp_pipeline *pipe)
                else
                        ret = 0;
 
+               /* Handle stop failures. An entity that fails to stop can
+                * usually just be restarted. Flag the stop failure nonetheless
+                * to trigger an ISP reset the next time the device is released,
+                * just in case.
+                *
+                * The preview engine is a special case. A failure to stop can
+                * mean a hardware crash. When that happens the preview engine
+                * won't respond to read/write operations on the L4 bus anymore,
+                * resulting in a bus fault and a kernel oops next time it gets
+                * accessed. Mark it as crashed to prevent pipelines including
+                * it from being started.
+                */
                if (ret) {
                        dev_info(isp->dev, "Unable to stop %s\n", subdev->name);
-                       /* If the entity failed to stopped, assume it has
-                        * crashed. Mark it as such, the ISP will be reset when
-                        * applications will release it.
-                        */
-                       isp->crashed |= 1U << subdev->entity.id;
+                       isp->stop_failure = true;
+                       if (subdev == &isp->isp_prev.subdev)
+                               isp->crashed |= 1U << subdev->entity.id;
                        failure = -ETIMEDOUT;
                }
        }
@@ -1056,6 +1063,23 @@ int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
        return ret;
 }
 
+/*
+ * omap3isp_pipeline_cancel_stream - Cancel stream on a pipeline
+ * @pipe: ISP pipeline
+ *
+ * Cancelling a stream mark all buffers on all video nodes in the pipeline as
+ * erroneous and makes sure no new buffer can be queued. This function is called
+ * when a fatal error that prevents any further operation on the pipeline
+ * occurs.
+ */
+void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe)
+{
+       if (pipe->input)
+               omap3isp_video_cancel_stream(pipe->input);
+       if (pipe->output)
+               omap3isp_video_cancel_stream(pipe->output);
+}
+
 /*
  * isp_pipeline_resume - Resume streaming on a pipeline
  * @pipe: ISP pipeline
@@ -1208,6 +1232,7 @@ static int isp_reset(struct isp_device *isp)
                udelay(1);
        }
 
+       isp->stop_failure = false;
        isp->crashed = 0;
        return 0;
 }
@@ -1619,7 +1644,7 @@ void omap3isp_put(struct isp_device *isp)
                /* Reset the ISP if an entity has failed to stop. This is the
                 * only way to recover from such conditions.
                 */
-               if (isp->crashed)
+               if (isp->crashed || isp->stop_failure)
                        isp_reset(isp);
                isp_disable_clocks(isp);
        }
@@ -2130,28 +2155,13 @@ static int isp_map_mem_resource(struct platform_device *pdev,
        /* request the mem region for the camera registers */
 
        mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
-       if (!mem) {
-               dev_err(isp->dev, "no mem resource?\n");
-               return -ENODEV;
-       }
-
-       if (!devm_request_mem_region(isp->dev, mem->start, resource_size(mem),
-                                    pdev->name)) {
-               dev_err(isp->dev,
-                       "cannot reserve camera register I/O region\n");
-               return -ENODEV;
-       }
-       isp->mmio_base_phys[res] = mem->start;
-       isp->mmio_size[res] = resource_size(mem);
 
        /* map the region */
-       isp->mmio_base[res] = devm_ioremap_nocache(isp->dev,
-                                                  isp->mmio_base_phys[res],
-                                                  isp->mmio_size[res]);
-       if (!isp->mmio_base[res]) {
-               dev_err(isp->dev, "cannot map camera register I/O region\n");
-               return -ENODEV;
-       }
+       isp->mmio_base[res] = devm_ioremap_resource(isp->dev, mem);
+       if (IS_ERR(isp->mmio_base[res]))
+               return PTR_ERR(isp->mmio_base[res]);
+
+       isp->mmio_base_phys[res] = mem->start;
 
        return 0;
 }
index d1e857e41731cf3b5c807ff0416ef117ee152ae5..081f5ec5a663c014e1ab270d463ed9b6e63efee0 100644 (file)
@@ -152,9 +152,9 @@ struct isp_xclk {
  *             regions.
  * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
  *                  regions.
- * @mmio_size: Array with ISP register regions size in bytes.
  * @stat_lock: Spinlock for handling statistics
  * @isp_mutex: Mutex for serializing requests to ISP.
+ * @stop_failure: Indicates that an entity failed to stop.
  * @crashed: Bitmask of crashed entities (indexed by entity ID)
  * @has_context: Context has been saved at least once and can be restored.
  * @ref_count: Reference count for handling multiple ISP requests.
@@ -188,11 +188,11 @@ struct isp_device {
 
        void __iomem *mmio_base[OMAP3_ISP_IOMEM_LAST];
        unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_LAST];
-       resource_size_t mmio_size[OMAP3_ISP_IOMEM_LAST];
 
        /* ISP Obj */
        spinlock_t stat_lock;   /* common lock for statistic drivers */
        struct mutex isp_mutex; /* For handling ref_count field */
+       bool stop_failure;
        u32 crashed;
        int has_context;
        int ref_count;
@@ -238,6 +238,7 @@ int omap3isp_module_sync_is_stopping(wait_queue_head_t *wait,
 
 int omap3isp_pipeline_set_stream(struct isp_pipeline *pipe,
                                 enum isp_pipeline_stream_state state);
+void omap3isp_pipeline_cancel_stream(struct isp_pipeline *pipe);
 void omap3isp_configure_bridge(struct isp_device *isp,
                               enum ccdc_input_entity input,
                               const struct isp_parallel_platform_data *pdata,
index 907a205da5a55d977fe39e40c7b612315578e996..5db2c88b9ad8caf810e6de514fef552cb80b929d 100644 (file)
@@ -1516,6 +1516,8 @@ static int ccdc_isr_buffer(struct isp_ccdc_device *ccdc)
 
        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;
        }
 
@@ -2484,7 +2486,8 @@ static int ccdc_init_entities(struct isp_ccdc_device *ccdc)
        v4l2_set_subdevdata(sd, ccdc);
        sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
 
-       pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[CCDC_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+                                   | MEDIA_PAD_FL_MUST_CONNECT;
        pads[CCDC_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
        pads[CCDC_PAD_SOURCE_OF].flags = MEDIA_PAD_FL_SOURCE;
 
index e71651429ddad36523943d4f61c0ca89caaa5bb9..e84fe0543e4719424c3224895ed7b5a218ea8904 100644 (file)
@@ -1076,7 +1076,8 @@ static int ccp2_init_entities(struct isp_ccp2_device *ccp2)
        v4l2_set_subdevdata(sd, ccp2);
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
-       pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[CCP2_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+                                   | MEDIA_PAD_FL_MUST_CONNECT;
        pads[CCP2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
 
        me->ops = &ccp2_media_ops;
index 6db245d84bbbe5f8e27bc9fb1555e2bdf0f20d0d..620560828a48cc9d395bfba0ddbb2c7f017ed84b 100644 (file)
@@ -1245,7 +1245,8 @@ static int csi2_init_entities(struct isp_csi2_device *csi2)
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
        pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
-       pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+                                   | MEDIA_PAD_FL_MUST_CONNECT;
 
        me->ops = &csi2_media_ops;
        ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
index cd8831aebdebdfe80d74bf599dcef02f3db7bbaa..1c776c1186f1b9ff4a4ddbb79b6cb48c88e196f4 100644 (file)
@@ -2283,7 +2283,8 @@ static int preview_init_entities(struct isp_prev_device *prev)
        v4l2_ctrl_handler_setup(&prev->ctrls);
        sd->ctrl_handler = &prev->ctrls;
 
-       pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[PREV_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+                                   | MEDIA_PAD_FL_MUST_CONNECT;
        pads[PREV_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
 
        me->ops = &preview_media_ops;
index e15f01342058579413c5742b366b0a8c5f39ac56..5f0f8fab1d1736440b66c0a3cef3755ce70dfb22 100644 (file)
@@ -553,8 +553,10 @@ static void isp_video_buffer_query(struct isp_video_buffer *buf,
        switch (buf->state) {
        case ISP_BUF_STATE_ERROR:
                vbuf->flags |= V4L2_BUF_FLAG_ERROR;
+               /* Fallthrough */
        case ISP_BUF_STATE_DONE:
                vbuf->flags |= V4L2_BUF_FLAG_DONE;
+               break;
        case ISP_BUF_STATE_QUEUED:
        case ISP_BUF_STATE_ACTIVE:
                vbuf->flags |= V4L2_BUF_FLAG_QUEUED;
index d11fb261d53070a131b4a3fbbd6cd2195bb3f574..0d36b8bc9f9806b1360d0a7482f2fe446fc70e4e 100644 (file)
@@ -1532,6 +1532,20 @@ static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
        return 0;
 }
 
+static int resizer_link_validate(struct v4l2_subdev *sd,
+                                struct media_link *link,
+                                struct v4l2_subdev_format *source_fmt,
+                                struct v4l2_subdev_format *sink_fmt)
+{
+       struct isp_res_device *res = v4l2_get_subdevdata(sd);
+       struct isp_pipeline *pipe = to_isp_pipeline(&sd->entity);
+
+       omap3isp_resizer_max_rate(res, &pipe->max_rate);
+
+       return v4l2_subdev_link_validate_default(sd, link,
+                                                source_fmt, sink_fmt);
+}
+
 /*
  * resizer_init_formats - Initialize formats on all pads
  * @sd: ISP resizer V4L2 subdevice
@@ -1570,6 +1584,7 @@ static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
        .set_fmt = resizer_set_format,
        .get_selection = resizer_get_selection,
        .set_selection = resizer_set_selection,
+       .link_validate = resizer_link_validate,
 };
 
 /* subdev operations */
@@ -1701,7 +1716,8 @@ static int resizer_init_entities(struct isp_res_device *res)
        v4l2_set_subdevdata(sd, res);
        sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 
-       pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[RESZ_PAD_SINK].flags = MEDIA_PAD_FL_SINK
+                                   | MEDIA_PAD_FL_MUST_CONNECT;
        pads[RESZ_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
 
        me->ops = &resizer_media_ops;
index 61e17f9bd8b92148457a45e973aefdb0487dbcec..a75407c3a726217981d40193b89919332a7919bf 100644 (file)
@@ -1067,7 +1067,7 @@ static int isp_stat_init_entities(struct ispstat *stat, const char *name,
        subdev->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
        v4l2_set_subdevdata(subdev, stat);
 
-       stat->pad.flags = MEDIA_PAD_FL_SINK;
+       stat->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
        me->ops = NULL;
 
        return media_entity_init(me, 1, &stat->pad, 0);
index f6304bb074f5edaa598f959515394448d30a3cc9..856fdf55403580c996493b03b811b3c4ef6ac5b0 100644 (file)
@@ -278,55 +278,6 @@ static int isp_video_get_graph_data(struct isp_video *video,
        return 0;
 }
 
-/*
- * Validate a pipeline by checking both ends of all links for format
- * discrepancies.
- *
- * Compute the minimum time per frame value as the maximum of time per frame
- * limits reported by every block in the pipeline.
- *
- * Return 0 if all formats match, or -EPIPE if at least one link is found with
- * different formats on its two ends or if the pipeline doesn't start with a
- * video source (either a subdev with no input pad, or a non-subdev entity).
- */
-static int isp_video_validate_pipeline(struct isp_pipeline *pipe)
-{
-       struct isp_device *isp = pipe->output->isp;
-       struct media_pad *pad;
-       struct v4l2_subdev *subdev;
-
-       subdev = isp_video_remote_subdev(pipe->output, NULL);
-       if (subdev == NULL)
-               return -EPIPE;
-
-       while (1) {
-               /* Retrieve the sink format */
-               pad = &subdev->entity.pads[0];
-               if (!(pad->flags & MEDIA_PAD_FL_SINK))
-                       break;
-
-               /* Update the maximum frame rate */
-               if (subdev == &isp->isp_res.subdev)
-                       omap3isp_resizer_max_rate(&isp->isp_res,
-                                                 &pipe->max_rate);
-
-               /* Retrieve the source format. Return an error if no source
-                * entity can be found, and stop checking the pipeline if the
-                * source entity isn't a subdev.
-                */
-               pad = media_entity_remote_pad(pad);
-               if (pad == NULL)
-                       return -EPIPE;
-
-               if (media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
-                       break;
-
-               subdev = media_entity_to_v4l2_subdev(pad->entity);
-       }
-
-       return 0;
-}
-
 static int
 __isp_video_get_format(struct isp_video *video, struct v4l2_format *format)
 {
@@ -460,6 +411,15 @@ static int isp_video_buffer_prepare(struct isp_video_buffer *buf)
        struct isp_video *video = vfh->video;
        unsigned long addr;
 
+       /* Refuse to prepare the buffer is the video node has registered an
+        * error. We don't need to take any lock here as the operation is
+        * inherently racy. The authoritative check will be performed in the
+        * queue handler, which can't return an error, this check is just a best
+        * effort to notify userspace as early as possible.
+        */
+       if (unlikely(video->error))
+               return -EIO;
+
        addr = ispmmu_vmap(video->isp, buf->sglist, buf->sglen);
        if (IS_ERR_VALUE(addr))
                return -EIO;
@@ -496,6 +456,12 @@ static void isp_video_buffer_queue(struct isp_video_buffer *buf)
        unsigned int empty;
        unsigned int start;
 
+       if (unlikely(video->error)) {
+               buf->state = ISP_BUF_STATE_ERROR;
+               wake_up(&buf->wait);
+               return;
+       }
+
        empty = list_empty(&video->dmaqueue);
        list_add_tail(&buffer->buffer.irqlist, &video->dmaqueue);
 
@@ -617,6 +583,36 @@ struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video)
        return to_isp_buffer(buf);
 }
 
+/*
+ * omap3isp_video_cancel_stream - Cancel stream on a video node
+ * @video: ISP video object
+ *
+ * Cancelling a stream mark all buffers on the video node as erroneous and makes
+ * sure no new buffer can be queued.
+ */
+void omap3isp_video_cancel_stream(struct isp_video *video)
+{
+       struct isp_video_queue *queue = video->queue;
+       unsigned long flags;
+
+       spin_lock_irqsave(&queue->irqlock, flags);
+
+       while (!list_empty(&video->dmaqueue)) {
+               struct isp_video_buffer *buf;
+
+               buf = list_first_entry(&video->dmaqueue,
+                                      struct isp_video_buffer, irqlist);
+               list_del(&buf->irqlist);
+
+               buf->state = ISP_BUF_STATE_ERROR;
+               wake_up(&buf->wait);
+       }
+
+       video->error = true;
+
+       spin_unlock_irqrestore(&queue->irqlock, flags);
+}
+
 /*
  * omap3isp_video_resume - Perform resume operation on the buffers
  * @video: ISP video object
@@ -1051,11 +1047,6 @@ isp_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
        if (ret < 0)
                goto err_check_format;
 
-       /* Validate the pipeline and update its state. */
-       ret = isp_video_validate_pipeline(pipe);
-       if (ret < 0)
-               goto err_check_format;
-
        pipe->error = false;
 
        spin_lock_irqsave(&pipe->lock, flags);
@@ -1159,6 +1150,7 @@ isp_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
        omap3isp_video_queue_streamoff(&vfh->queue);
        video->queue = NULL;
        video->streaming = 0;
+       video->error = false;
 
        if (video->isp->pdata->set_constraints)
                video->isp->pdata->set_constraints(video->isp, false);
@@ -1332,11 +1324,13 @@ int omap3isp_video_init(struct isp_video *video, const char *name)
        switch (video->type) {
        case V4L2_BUF_TYPE_VIDEO_CAPTURE:
                direction = "output";
-               video->pad.flags = MEDIA_PAD_FL_SINK;
+               video->pad.flags = MEDIA_PAD_FL_SINK
+                                  | MEDIA_PAD_FL_MUST_CONNECT;
                break;
        case V4L2_BUF_TYPE_VIDEO_OUTPUT:
                direction = "input";
-               video->pad.flags = MEDIA_PAD_FL_SOURCE;
+               video->pad.flags = MEDIA_PAD_FL_SOURCE
+                                  | MEDIA_PAD_FL_MUST_CONNECT;
                video->video.vfl_dir = VFL_DIR_TX;
                break;
 
index 1ad470ec2b9d5ab5f4cd212f11d0b3d412d93b20..4e194076cc60d611727a6441231f79006dbfadfc 100644 (file)
@@ -178,6 +178,7 @@ struct isp_video {
        /* Pipeline state */
        struct isp_pipeline pipe;
        struct mutex stream_lock;       /* pipeline and stream states */
+       bool error;
 
        /* Video buffers queue */
        struct isp_video_queue *queue;
@@ -207,6 +208,7 @@ int omap3isp_video_register(struct isp_video *video,
                            struct v4l2_device *vdev);
 void omap3isp_video_unregister(struct isp_video *video);
 struct isp_buffer *omap3isp_video_buffer_next(struct isp_video *video);
+void omap3isp_video_cancel_stream(struct isp_video *video);
 void omap3isp_video_resume(struct isp_video *video, int continuous);
 struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
 
index 0b2948376aee9d3715c67d97346d6e775d48ab48..0fcf7d75e841b550d24df8faa9d247ce846d2044 100644 (file)
@@ -136,10 +136,9 @@ static int g2d_buf_prepare(struct vb2_buffer *vb)
 static void g2d_buf_queue(struct vb2_buffer *vb)
 {
        struct g2d_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
-       v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
 }
 
-
 static struct vb2_ops g2d_qops = {
        .queue_setup    = g2d_queue_setup,
        .buf_prepare    = g2d_buf_prepare,
@@ -159,6 +158,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
        src_vq->mem_ops = &vb2_dma_contig_memops;
        src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
        src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock = &ctx->dev->mutex;
 
        ret = vb2_queue_init(src_vq);
        if (ret)
@@ -171,6 +171,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
        dst_vq->mem_ops = &vb2_dma_contig_memops;
        dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
        dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock = &ctx->dev->mutex;
 
        return vb2_queue_init(dst_vq);
 }
@@ -253,9 +254,9 @@ static int g2d_open(struct file *file)
                kfree(ctx);
                return -ERESTARTSYS;
        }
-       ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
-       if (IS_ERR(ctx->m2m_ctx)) {
-               ret = PTR_ERR(ctx->m2m_ctx);
+       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               ret = PTR_ERR(ctx->fh.m2m_ctx);
                mutex_unlock(&dev->mutex);
                kfree(ctx);
                return ret;
@@ -324,7 +325,7 @@ static int vidioc_g_fmt(struct file *file, void *prv, struct v4l2_format *f)
        struct vb2_queue *vq;
        struct g2d_frame *frm;
 
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
        if (!vq)
                return -EINVAL;
        frm = get_frame(ctx, f->type);
@@ -384,7 +385,7 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
        ret = vidioc_try_fmt(file, prv, f);
        if (ret)
                return ret;
-       vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+       vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
        if (vb2_is_busy(vq)) {
                v4l2_err(&dev->v4l2_dev, "queue (%d) bust\n", f->type);
                return -EBUSY;
@@ -410,72 +411,6 @@ static int vidioc_s_fmt(struct file *file, void *prv, struct v4l2_format *f)
        return 0;
 }
 
-static unsigned int g2d_poll(struct file *file, struct poll_table_struct *wait)
-{
-       struct g2d_ctx *ctx = fh2ctx(file->private_data);
-       struct g2d_dev *dev = ctx->dev;
-       unsigned int res;
-
-       mutex_lock(&dev->mutex);
-       res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
-       mutex_unlock(&dev->mutex);
-       return res;
-}
-
-static int g2d_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct g2d_ctx *ctx = fh2ctx(file->private_data);
-       struct g2d_dev *dev = ctx->dev;
-       int ret;
-
-       if (mutex_lock_interruptible(&dev->mutex))
-               return -ERESTARTSYS;
-       ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-       mutex_unlock(&dev->mutex);
-       return ret;
-}
-
-static int vidioc_reqbufs(struct file *file, void *priv,
-                       struct v4l2_requestbuffers *reqbufs)
-{
-       struct g2d_ctx *ctx = priv;
-       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
-                       struct v4l2_buffer *buf)
-{
-       struct g2d_ctx *ctx = priv;
-       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct g2d_ctx *ctx = priv;
-       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct g2d_ctx *ctx = priv;
-       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-
-static int vidioc_streamon(struct file *file, void *priv,
-                                       enum v4l2_buf_type type)
-{
-       struct g2d_ctx *ctx = priv;
-       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
-                                       enum v4l2_buf_type type)
-{
-       struct g2d_ctx *ctx = priv;
-       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
 static int vidioc_cropcap(struct file *file, void *priv,
                                        struct v4l2_cropcap *cr)
 {
@@ -551,20 +486,6 @@ static int vidioc_s_crop(struct file *file, void *prv, const struct v4l2_crop *c
        return 0;
 }
 
-static void g2d_lock(void *prv)
-{
-       struct g2d_ctx *ctx = prv;
-       struct g2d_dev *dev = ctx->dev;
-       mutex_lock(&dev->mutex);
-}
-
-static void g2d_unlock(void *prv)
-{
-       struct g2d_ctx *ctx = prv;
-       struct g2d_dev *dev = ctx->dev;
-       mutex_unlock(&dev->mutex);
-}
-
 static void job_abort(void *prv)
 {
        struct g2d_ctx *ctx = prv;
@@ -589,8 +510,8 @@ static void device_run(void *prv)
 
        dev->curr = ctx;
 
-       src = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-       dst = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
 
        clk_enable(dev->gate);
        g2d_reset(dev);
@@ -631,8 +552,8 @@ static irqreturn_t g2d_isr(int irq, void *prv)
 
        BUG_ON(ctx == NULL);
 
-       src = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
-       dst = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+       src = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+       dst = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
 
        BUG_ON(src == NULL);
        BUG_ON(dst == NULL);
@@ -642,7 +563,7 @@ static irqreturn_t g2d_isr(int irq, void *prv)
 
        v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
        v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
-       v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
+       v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
 
        dev->curr = NULL;
        wake_up(&dev->irq_queue);
@@ -653,9 +574,9 @@ static const struct v4l2_file_operations g2d_fops = {
        .owner          = THIS_MODULE,
        .open           = g2d_open,
        .release        = g2d_release,
-       .poll           = g2d_poll,
+       .poll           = v4l2_m2m_fop_poll,
        .unlocked_ioctl = video_ioctl2,
-       .mmap           = g2d_mmap,
+       .mmap           = v4l2_m2m_fop_mmap,
 };
 
 static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
@@ -671,14 +592,13 @@ static const struct v4l2_ioctl_ops g2d_ioctl_ops = {
        .vidioc_try_fmt_vid_out         = vidioc_try_fmt,
        .vidioc_s_fmt_vid_out           = vidioc_s_fmt,
 
-       .vidioc_reqbufs                 = vidioc_reqbufs,
-       .vidioc_querybuf                = vidioc_querybuf,
-
-       .vidioc_qbuf                    = vidioc_qbuf,
-       .vidioc_dqbuf                   = vidioc_dqbuf,
+       .vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
+       .vidioc_qbuf                    = v4l2_m2m_ioctl_qbuf,
+       .vidioc_dqbuf                   = v4l2_m2m_ioctl_dqbuf,
 
-       .vidioc_streamon                = vidioc_streamon,
-       .vidioc_streamoff               = vidioc_streamoff,
+       .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
 
        .vidioc_g_crop                  = vidioc_g_crop,
        .vidioc_s_crop                  = vidioc_s_crop,
@@ -697,8 +617,6 @@ static struct video_device g2d_videodev = {
 static struct v4l2_m2m_ops g2d_m2m_ops = {
        .device_run     = device_run,
        .job_abort      = job_abort,
-       .lock           = g2d_lock,
-       .unlock         = g2d_unlock,
 };
 
 static const struct of_device_id exynos_g2d_match[];
index 300ca05ba40438f944f2651d2feccd58279eb1c1..b0e52ab7ecdb806b102a51497c2f29303fd5772e 100644 (file)
@@ -57,7 +57,6 @@ struct g2d_frame {
 struct g2d_ctx {
        struct v4l2_fh fh;
        struct g2d_dev          *dev;
-       struct v4l2_m2m_ctx     *m2m_ctx;
        struct g2d_frame        in;
        struct g2d_frame        out;
        struct v4l2_ctrl        *ctrl_hflip;
index d18cb5edd2d53975cea549bd4c696d618fb88c55..a1a9169254c346f96348d871d4d90bff537ae040 100644 (file)
@@ -1,2 +1,2 @@
-s5p-jpeg-objs := jpeg-core.o
+s5p-jpeg-objs := jpeg-core.o jpeg-hw-exynos4.o jpeg-hw-s5p.o
 obj-$(CONFIG_VIDEO_SAMSUNG_S5P_JPEG) += s5p-jpeg.o
index 9b88a46010072fbe3b4aeefa46bbc8ee0f04ea7e..a1c78c870b68b44f660d2b54844ca5a5b13b1c7a 100644 (file)
@@ -1,9 +1,10 @@
 /* linux/drivers/media/platform/s5p-jpeg/jpeg-core.c
  *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
  * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -17,6 +18,7 @@
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 #include <linux/slab.h>
 #include <media/videobuf2-dma-contig.h>
 
 #include "jpeg-core.h"
-#include "jpeg-hw.h"
+#include "jpeg-hw-s5p.h"
+#include "jpeg-hw-exynos4.h"
+#include "jpeg-regs.h"
 
-static struct s5p_jpeg_fmt formats_enc[] = {
+static struct s5p_jpeg_fmt sjpeg_formats[] = {
        {
                .name           = "JPEG JFIF",
                .fourcc         = V4L2_PIX_FMT_JPEG,
+               .flags          = SJPEG_FMT_FLAG_ENC_CAPTURE |
+                                 SJPEG_FMT_FLAG_DEC_OUTPUT |
+                                 SJPEG_FMT_FLAG_S5P |
+                                 SJPEG_FMT_FLAG_EXYNOS4,
+       },
+       {
+               .name           = "YUV 4:2:2 packed, YCbYCr",
+               .fourcc         = V4L2_PIX_FMT_YUYV,
+               .depth          = 16,
                .colplanes      = 1,
-               .types          = MEM2MEM_CAPTURE,
+               .h_align        = 4,
+               .v_align        = 3,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_S5P |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
        },
        {
                .name           = "YUV 4:2:2 packed, YCbYCr",
                .fourcc         = V4L2_PIX_FMT_YUYV,
                .depth          = 16,
                .colplanes      = 1,
-               .types          = MEM2MEM_OUTPUT,
+               .h_align        = 1,
+               .v_align        = 0,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+       },
+       {
+               .name           = "YUV 4:2:2 packed, YCrYCb",
+               .fourcc         = V4L2_PIX_FMT_YVYU,
+               .depth          = 16,
+               .colplanes      = 1,
+               .h_align        = 1,
+               .v_align        = 0,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
        },
        {
                .name           = "RGB565",
                .fourcc         = V4L2_PIX_FMT_RGB565,
                .depth          = 16,
                .colplanes      = 1,
-               .types          = MEM2MEM_OUTPUT,
+               .h_align        = 0,
+               .v_align        = 0,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
        },
-};
-#define NUM_FORMATS_ENC ARRAY_SIZE(formats_enc)
-
-static struct s5p_jpeg_fmt formats_dec[] = {
        {
-               .name           = "YUV 4:2:0 planar, YCbCr",
-               .fourcc         = V4L2_PIX_FMT_YUV420,
-               .depth          = 12,
-               .colplanes      = 3,
-               .h_align        = 4,
-               .v_align        = 4,
-               .types          = MEM2MEM_CAPTURE,
+               .name           = "RGB565",
+               .fourcc         = V4L2_PIX_FMT_RGB565,
+               .depth          = 16,
+               .colplanes      = 1,
+               .h_align        = 0,
+               .v_align        = 0,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_S5P |
+                                 SJPEG_FMT_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
        },
        {
-               .name           = "YUV 4:2:2 packed, YCbYCr",
-               .fourcc         = V4L2_PIX_FMT_YUYV,
-               .depth          = 16,
+               .name           = "ARGB8888, 32 bpp",
+               .fourcc         = V4L2_PIX_FMT_RGB32,
+               .depth          = 32,
                .colplanes      = 1,
+               .h_align        = 0,
+               .v_align        = 0,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+       },
+       {
+               .name           = "YUV 4:4:4 planar, Y/CbCr",
+               .fourcc         = V4L2_PIX_FMT_NV24,
+               .depth          = 24,
+               .colplanes      = 2,
+               .h_align        = 0,
+               .v_align        = 0,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+       },
+       {
+               .name           = "YUV 4:4:4 planar, Y/CrCb",
+               .fourcc         = V4L2_PIX_FMT_NV42,
+               .depth          = 24,
+               .colplanes      = 2,
+               .h_align        = 0,
+               .v_align        = 0,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+       },
+       {
+               .name           = "YUV 4:2:2 planar, Y/CrCb",
+               .fourcc         = V4L2_PIX_FMT_NV61,
+               .depth          = 16,
+               .colplanes      = 2,
+               .h_align        = 1,
+               .v_align        = 0,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+       },
+       {
+               .name           = "YUV 4:2:2 planar, Y/CbCr",
+               .fourcc         = V4L2_PIX_FMT_NV16,
+               .depth          = 16,
+               .colplanes      = 2,
+               .h_align        = 1,
+               .v_align        = 0,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+       },
+       {
+               .name           = "YUV 4:2:0 planar, Y/CbCr",
+               .fourcc         = V4L2_PIX_FMT_NV12,
+               .depth          = 16,
+               .colplanes      = 2,
+               .h_align        = 1,
+               .v_align        = 1,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+       },
+       {
+               .name           = "YUV 4:2:0 planar, Y/CbCr",
+               .fourcc         = V4L2_PIX_FMT_NV12,
+               .depth          = 16,
+               .colplanes      = 4,
                .h_align        = 4,
-               .v_align        = 3,
-               .types          = MEM2MEM_CAPTURE,
+               .v_align        = 1,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_S5P |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
        },
        {
-               .name           = "JPEG JFIF",
-               .fourcc         = V4L2_PIX_FMT_JPEG,
+               .name           = "YUV 4:2:0 planar, Y/CrCb",
+               .fourcc         = V4L2_PIX_FMT_NV21,
+               .depth          = 12,
+               .colplanes      = 2,
+               .h_align        = 1,
+               .v_align        = 1,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+       },
+       {
+               .name           = "YUV 4:2:0 contiguous 3-planar, Y/Cb/Cr",
+               .fourcc         = V4L2_PIX_FMT_YUV420,
+               .depth          = 12,
+               .colplanes      = 3,
+               .h_align        = 1,
+               .v_align        = 1,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+       },
+       {
+               .name           = "Gray",
+               .fourcc         = V4L2_PIX_FMT_GREY,
+               .depth          = 8,
                .colplanes      = 1,
-               .types          = MEM2MEM_OUTPUT,
+               .flags          = SJPEG_FMT_FLAG_ENC_OUTPUT |
+                                 SJPEG_FMT_FLAG_DEC_CAPTURE |
+                                 SJPEG_FMT_FLAG_EXYNOS4 |
+                                 SJPEG_FMT_NON_RGB,
+               .subsampling    = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
        },
 };
-#define NUM_FORMATS_DEC ARRAY_SIZE(formats_dec)
+#define SJPEG_NUM_FORMATS ARRAY_SIZE(sjpeg_formats)
 
 static const unsigned char qtbl_luminance[4][64] = {
-       {/* level 1 - high quality */
-                8,  6,  6,  8, 12, 14, 16, 17,
-                6,  6,  6,  8, 10, 13, 12, 15,
-                6,  6,  7,  8, 13, 14, 18, 24,
-                8,  8,  8, 14, 13, 19, 24, 35,
-               12, 10, 13, 13, 20, 26, 34, 39,
-               14, 13, 14, 19, 26, 34, 39, 39,
-               16, 12, 18, 24, 34, 39, 39, 39,
-               17, 15, 24, 35, 39, 39, 39, 39
+       {/*level 0 - high compression quality */
+               20, 16, 25, 39, 50, 46, 62, 68,
+               16, 18, 23, 38, 38, 53, 65, 68,
+               25, 23, 31, 38, 53, 65, 68, 68,
+               39, 38, 38, 53, 65, 68, 68, 68,
+               50, 38, 53, 65, 68, 68, 68, 68,
+               46, 53, 65, 68, 68, 68, 68, 68,
+               62, 65, 68, 68, 68, 68, 68, 68,
+               68, 68, 68, 68, 68, 68, 68, 68
+       },
+       {/* level 1 */
+               16, 11, 11, 16, 23, 27, 31, 30,
+               11, 12, 12, 15, 20, 23, 23, 30,
+               11, 12, 13, 16, 23, 26, 35, 47,
+               16, 15, 16, 23, 26, 37, 47, 64,
+               23, 20, 23, 26, 39, 51, 64, 64,
+               27, 23, 26, 37, 51, 64, 64, 64,
+               31, 23, 35, 47, 64, 64, 64, 64,
+               30, 30, 47, 64, 64, 64, 64, 64
        },
        {/* level 2 */
                12,  8,  8, 12, 17, 21, 24, 23,
@@ -103,38 +269,38 @@ static const unsigned char qtbl_luminance[4][64] = {
                24, 18, 27, 36, 51, 59, 59, 59,
                23, 23, 36, 53, 59, 59, 59, 59
        },
-       {/* level 3 */
-               16, 11, 11, 16, 23, 27, 31, 30,
-               11, 12, 12, 15, 20, 23, 23, 30,
-               11, 12, 13, 16, 23, 26, 35, 47,
-               16, 15, 16, 23, 26, 37, 47, 64,
-               23, 20, 23, 26, 39, 51, 64, 64,
-               27, 23, 26, 37, 51, 64, 64, 64,
-               31, 23, 35, 47, 64, 64, 64, 64,
-               30, 30, 47, 64, 64, 64, 64, 64
-       },
-       {/*level 4 - low quality */
-               20, 16, 25, 39, 50, 46, 62, 68,
-               16, 18, 23, 38, 38, 53, 65, 68,
-               25, 23, 31, 38, 53, 65, 68, 68,
-               39, 38, 38, 53, 65, 68, 68, 68,
-               50, 38, 53, 65, 68, 68, 68, 68,
-               46, 53, 65, 68, 68, 68, 68, 68,
-               62, 65, 68, 68, 68, 68, 68, 68,
-               68, 68, 68, 68, 68, 68, 68, 68
+       {/* level 3 - low compression quality */
+                8,  6,  6,  8, 12, 14, 16, 17,
+                6,  6,  6,  8, 10, 13, 12, 15,
+                6,  6,  7,  8, 13, 14, 18, 24,
+                8,  8,  8, 14, 13, 19, 24, 35,
+               12, 10, 13, 13, 20, 26, 34, 39,
+               14, 13, 14, 19, 26, 34, 39, 39,
+               16, 12, 18, 24, 34, 39, 39, 39,
+               17, 15, 24, 35, 39, 39, 39, 39
        }
 };
 
 static const unsigned char qtbl_chrominance[4][64] = {
-       {/* level 1 - high quality */
-                9,  8,  9, 11, 14, 17, 19, 24,
-                8, 10,  9, 11, 14, 13, 17, 22,
-                9,  9, 13, 14, 13, 15, 23, 26,
-               11, 11, 14, 14, 15, 20, 26, 33,
-               14, 14, 13, 15, 20, 24, 33, 39,
-               17, 13, 15, 20, 24, 32, 39, 39,
-               19, 17, 23, 26, 33, 39, 39, 39,
-               24, 22, 26, 33, 39, 39, 39, 39
+       {/*level 0 - high compression quality */
+               21, 25, 32, 38, 54, 68, 68, 68,
+               25, 28, 24, 38, 54, 68, 68, 68,
+               32, 24, 32, 43, 66, 68, 68, 68,
+               38, 38, 43, 53, 68, 68, 68, 68,
+               54, 54, 66, 68, 68, 68, 68, 68,
+               68, 68, 68, 68, 68, 68, 68, 68,
+               68, 68, 68, 68, 68, 68, 68, 68,
+               68, 68, 68, 68, 68, 68, 68, 68
+       },
+       {/* level 1 */
+               17, 15, 17, 21, 20, 26, 38, 48,
+               15, 19, 18, 17, 20, 26, 35, 43,
+               17, 18, 20, 22, 26, 30, 46, 53,
+               21, 17, 22, 28, 30, 39, 53, 64,
+               20, 20, 26, 30, 39, 48, 64, 64,
+               26, 26, 30, 39, 48, 63, 64, 64,
+               38, 35, 46, 53, 64, 64, 64, 64,
+               48, 43, 53, 64, 64, 64, 64, 64
        },
        {/* level 2 */
                13, 11, 13, 16, 20, 20, 29, 37,
@@ -146,25 +312,15 @@ static const unsigned char qtbl_chrominance[4][64] = {
                29, 26, 35, 40, 50, 59, 59, 59,
                37, 32, 40, 50, 59, 59, 59, 59
        },
-       {/* level 3 */
-               17, 15, 17, 21, 20, 26, 38, 48,
-               15, 19, 18, 17, 20, 26, 35, 43,
-               17, 18, 20, 22, 26, 30, 46, 53,
-               21, 17, 22, 28, 30, 39, 53, 64,
-               20, 20, 26, 30, 39, 48, 64, 64,
-               26, 26, 30, 39, 48, 63, 64, 64,
-               38, 35, 46, 53, 64, 64, 64, 64,
-               48, 43, 53, 64, 64, 64, 64, 64
-       },
-       {/*level 4 - low quality */
-               21, 25, 32, 38, 54, 68, 68, 68,
-               25, 28, 24, 38, 54, 68, 68, 68,
-               32, 24, 32, 43, 66, 68, 68, 68,
-               38, 38, 43, 53, 68, 68, 68, 68,
-               54, 54, 66, 68, 68, 68, 68, 68,
-               68, 68, 68, 68, 68, 68, 68, 68,
-               68, 68, 68, 68, 68, 68, 68, 68,
-               68, 68, 68, 68, 68, 68, 68, 68
+       {/* level 3 - low compression quality */
+                9,  8,  9, 11, 14, 17, 19, 24,
+                8, 10,  9, 11, 14, 13, 17, 22,
+                9,  9, 13, 14, 13, 15, 23, 26,
+               11, 11, 14, 14, 15, 20, 26, 33,
+               14, 14, 13, 15, 20, 24, 33, 39,
+               17, 13, 15, 20, 24, 32, 39, 39,
+               19, 17, 23, 26, 33, 39, 39, 39,
+               24, 22, 26, 33, 39, 39, 39, 39
        }
 };
 
@@ -202,6 +358,106 @@ static const unsigned char hactblg0[162] = {
        0xf9, 0xfa
 };
 
+/*
+ * Fourcc downgrade schema lookup tables for 422 and 420
+ * chroma subsampling - fourcc on each position maps on the
+ * fourcc from the table fourcc_to_dwngrd_schema_id which allows
+ * to get the most suitable fourcc counterpart for the given
+ * downgraded subsampling property.
+ */
+static const u32 subs422_fourcc_dwngrd_schema[] = {
+       V4L2_PIX_FMT_NV16,
+       V4L2_PIX_FMT_NV61,
+};
+
+static const u32 subs420_fourcc_dwngrd_schema[] = {
+       V4L2_PIX_FMT_NV12,
+       V4L2_PIX_FMT_NV21,
+       V4L2_PIX_FMT_NV12,
+       V4L2_PIX_FMT_NV21,
+       V4L2_PIX_FMT_NV12,
+       V4L2_PIX_FMT_NV21,
+       V4L2_PIX_FMT_GREY,
+       V4L2_PIX_FMT_GREY,
+       V4L2_PIX_FMT_GREY,
+       V4L2_PIX_FMT_GREY,
+};
+
+/*
+ * Lookup table for translation of a fourcc to the position
+ * of its downgraded counterpart in the *fourcc_dwngrd_schema
+ * tables.
+ */
+static const u32 fourcc_to_dwngrd_schema_id[] = {
+       V4L2_PIX_FMT_NV24,
+       V4L2_PIX_FMT_NV42,
+       V4L2_PIX_FMT_NV16,
+       V4L2_PIX_FMT_NV61,
+       V4L2_PIX_FMT_YUYV,
+       V4L2_PIX_FMT_YVYU,
+       V4L2_PIX_FMT_NV12,
+       V4L2_PIX_FMT_NV21,
+       V4L2_PIX_FMT_YUV420,
+       V4L2_PIX_FMT_GREY,
+};
+
+static int s5p_jpeg_get_dwngrd_sch_id_by_fourcc(u32 fourcc)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(fourcc_to_dwngrd_schema_id); ++i) {
+               if (fourcc_to_dwngrd_schema_id[i] == fourcc)
+                       return i;
+       }
+
+       return -EINVAL;
+}
+
+static int s5p_jpeg_adjust_fourcc_to_subsampling(
+                                       enum v4l2_jpeg_chroma_subsampling subs,
+                                       u32 in_fourcc,
+                                       u32 *out_fourcc,
+                                       struct s5p_jpeg_ctx *ctx)
+{
+       int dwngrd_sch_id;
+
+       if (ctx->subsampling != V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
+               dwngrd_sch_id =
+                       s5p_jpeg_get_dwngrd_sch_id_by_fourcc(in_fourcc);
+               if (dwngrd_sch_id < 0)
+                       return -EINVAL;
+       }
+
+       switch (ctx->subsampling) {
+       case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
+               *out_fourcc = V4L2_PIX_FMT_GREY;
+               break;
+       case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
+               if (dwngrd_sch_id >
+                               ARRAY_SIZE(subs420_fourcc_dwngrd_schema) - 1)
+                       return -EINVAL;
+               *out_fourcc = subs420_fourcc_dwngrd_schema[dwngrd_sch_id];
+               break;
+       case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
+               if (dwngrd_sch_id >
+                               ARRAY_SIZE(subs422_fourcc_dwngrd_schema) - 1)
+                       return -EINVAL;
+               *out_fourcc = subs422_fourcc_dwngrd_schema[dwngrd_sch_id];
+               break;
+       default:
+               *out_fourcc = V4L2_PIX_FMT_GREY;
+               break;
+       }
+
+       return 0;
+}
+
+static int exynos4x12_decoded_subsampling[] = {
+       V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY,
+       V4L2_JPEG_CHROMA_SUBSAMPLING_444,
+       V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+       V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+};
+
 static inline struct s5p_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *c)
 {
        return container_of(c->handler, struct s5p_jpeg_ctx, ctrl_handler);
@@ -212,8 +468,24 @@ static inline struct s5p_jpeg_ctx *fh_to_ctx(struct v4l2_fh *fh)
        return container_of(fh, struct s5p_jpeg_ctx, fh);
 }
 
-static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
-                  unsigned long tab, int len)
+static int s5p_jpeg_to_user_subsampling(struct s5p_jpeg_ctx *ctx)
+{
+       WARN_ON(ctx->subsampling > 3);
+
+       if (ctx->jpeg->variant->version == SJPEG_S5P) {
+               if (ctx->subsampling > 2)
+                       return V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
+               return ctx->subsampling;
+       } else {
+               if (ctx->subsampling > 2)
+                       return V4L2_JPEG_CHROMA_SUBSAMPLING_420;
+               return exynos4x12_decoded_subsampling[ctx->subsampling];
+       }
+}
+
+static inline void s5p_jpeg_set_qtbl(void __iomem *regs,
+                                    const unsigned char *qtbl,
+                                    unsigned long tab, int len)
 {
        int i;
 
@@ -221,22 +493,25 @@ static inline void jpeg_set_qtbl(void __iomem *regs, const unsigned char *qtbl,
                writel((unsigned int)qtbl[i], regs + tab + (i * 0x04));
 }
 
-static inline void jpeg_set_qtbl_lum(void __iomem *regs, int quality)
+static inline void s5p_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
 {
        /* this driver fills quantisation table 0 with data for luma */
-       jpeg_set_qtbl(regs, qtbl_luminance[quality], S5P_JPG_QTBL_CONTENT(0),
-                     ARRAY_SIZE(qtbl_luminance[quality]));
+       s5p_jpeg_set_qtbl(regs, qtbl_luminance[quality],
+                         S5P_JPG_QTBL_CONTENT(0),
+                         ARRAY_SIZE(qtbl_luminance[quality]));
 }
 
-static inline void jpeg_set_qtbl_chr(void __iomem *regs, int quality)
+static inline void s5p_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
 {
        /* this driver fills quantisation table 1 with data for chroma */
-       jpeg_set_qtbl(regs, qtbl_chrominance[quality], S5P_JPG_QTBL_CONTENT(1),
-                     ARRAY_SIZE(qtbl_chrominance[quality]));
+       s5p_jpeg_set_qtbl(regs, qtbl_chrominance[quality],
+                         S5P_JPG_QTBL_CONTENT(1),
+                         ARRAY_SIZE(qtbl_chrominance[quality]));
 }
 
-static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
-                  unsigned long tab, int len)
+static inline void s5p_jpeg_set_htbl(void __iomem *regs,
+                                    const unsigned char *htbl,
+                                    unsigned long tab, int len)
 {
        int i;
 
@@ -244,28 +519,84 @@ static inline void jpeg_set_htbl(void __iomem *regs, const unsigned char *htbl,
                writel((unsigned int)htbl[i], regs + tab + (i * 0x04));
 }
 
-static inline void jpeg_set_hdctbl(void __iomem *regs)
+static inline void s5p_jpeg_set_hdctbl(void __iomem *regs)
 {
        /* this driver fills table 0 for this component */
-       jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0), ARRAY_SIZE(hdctbl0));
+       s5p_jpeg_set_htbl(regs, hdctbl0, S5P_JPG_HDCTBL(0),
+                                               ARRAY_SIZE(hdctbl0));
 }
 
-static inline void jpeg_set_hdctblg(void __iomem *regs)
+static inline void s5p_jpeg_set_hdctblg(void __iomem *regs)
 {
        /* this driver fills table 0 for this component */
-       jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0), ARRAY_SIZE(hdctblg0));
+       s5p_jpeg_set_htbl(regs, hdctblg0, S5P_JPG_HDCTBLG(0),
+                                               ARRAY_SIZE(hdctblg0));
 }
 
-static inline void jpeg_set_hactbl(void __iomem *regs)
+static inline void s5p_jpeg_set_hactbl(void __iomem *regs)
 {
        /* this driver fills table 0 for this component */
-       jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0), ARRAY_SIZE(hactbl0));
+       s5p_jpeg_set_htbl(regs, hactbl0, S5P_JPG_HACTBL(0),
+                                               ARRAY_SIZE(hactbl0));
 }
 
-static inline void jpeg_set_hactblg(void __iomem *regs)
+static inline void s5p_jpeg_set_hactblg(void __iomem *regs)
 {
        /* this driver fills table 0 for this component */
-       jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0), ARRAY_SIZE(hactblg0));
+       s5p_jpeg_set_htbl(regs, hactblg0, S5P_JPG_HACTBLG(0),
+                                               ARRAY_SIZE(hactblg0));
+}
+
+static inline void exynos4_jpeg_set_tbl(void __iomem *regs,
+                                       const unsigned char *tbl,
+                                       unsigned long tab, int len)
+{
+       int i;
+       unsigned int dword;
+
+       for (i = 0; i < len; i += 4) {
+               dword = tbl[i] |
+                       (tbl[i + 1] << 8) |
+                       (tbl[i + 2] << 16) |
+                       (tbl[i + 3] << 24);
+               writel(dword, regs + tab + i);
+       }
+}
+
+static inline void exynos4_jpeg_set_qtbl_lum(void __iomem *regs, int quality)
+{
+       /* this driver fills quantisation table 0 with data for luma */
+       exynos4_jpeg_set_tbl(regs, qtbl_luminance[quality],
+                            EXYNOS4_QTBL_CONTENT(0),
+                            ARRAY_SIZE(qtbl_luminance[quality]));
+}
+
+static inline void exynos4_jpeg_set_qtbl_chr(void __iomem *regs, int quality)
+{
+       /* this driver fills quantisation table 1 with data for chroma */
+       exynos4_jpeg_set_tbl(regs, qtbl_chrominance[quality],
+                            EXYNOS4_QTBL_CONTENT(1),
+                            ARRAY_SIZE(qtbl_chrominance[quality]));
+}
+
+void exynos4_jpeg_set_huff_tbl(void __iomem *base)
+{
+       exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCLL,
+                                                       ARRAY_SIZE(hdctbl0));
+       exynos4_jpeg_set_tbl(base, hdctbl0, EXYNOS4_HUFF_TBL_HDCCL,
+                                                       ARRAY_SIZE(hdctbl0));
+       exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCLV,
+                                                       ARRAY_SIZE(hdctblg0));
+       exynos4_jpeg_set_tbl(base, hdctblg0, EXYNOS4_HUFF_TBL_HDCCV,
+                                                       ARRAY_SIZE(hdctblg0));
+       exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACLL,
+                                                       ARRAY_SIZE(hactbl0));
+       exynos4_jpeg_set_tbl(base, hactbl0, EXYNOS4_HUFF_TBL_HACCL,
+                                                       ARRAY_SIZE(hactbl0));
+       exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACLV,
+                                                       ARRAY_SIZE(hactblg0));
+       exynos4_jpeg_set_tbl(base, hactblg0, EXYNOS4_HUFF_TBL_HACCV,
+                                                       ARRAY_SIZE(hactblg0));
 }
 
 /*
@@ -276,8 +607,8 @@ static inline void jpeg_set_hactblg(void __iomem *regs)
 
 static int queue_init(void *priv, struct vb2_queue *src_vq,
                      struct vb2_queue *dst_vq);
-static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
-                                                __u32 pixelformat);
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
+                               __u32 pixelformat, unsigned int fmt_type);
 static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx);
 
 static int s5p_jpeg_open(struct file *file)
@@ -285,7 +616,7 @@ static int s5p_jpeg_open(struct file *file)
        struct s5p_jpeg *jpeg = video_drvdata(file);
        struct video_device *vfd = video_devdata(file);
        struct s5p_jpeg_ctx *ctx;
-       struct s5p_jpeg_fmt *out_fmt;
+       struct s5p_jpeg_fmt *out_fmt, *cap_fmt;
        int ret = 0;
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -306,24 +637,31 @@ static int s5p_jpeg_open(struct file *file)
        ctx->jpeg = jpeg;
        if (vfd == jpeg->vfd_encoder) {
                ctx->mode = S5P_JPEG_ENCODE;
-               out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_RGB565);
+               out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB565,
+                                                       FMT_TYPE_OUTPUT);
+               cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
+                                                       FMT_TYPE_CAPTURE);
        } else {
                ctx->mode = S5P_JPEG_DECODE;
-               out_fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_JPEG);
+               out_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
+                                                       FMT_TYPE_OUTPUT);
+               cap_fmt = s5p_jpeg_find_format(ctx, V4L2_PIX_FMT_YUYV,
+                                                       FMT_TYPE_CAPTURE);
        }
 
-       ret = s5p_jpeg_controls_create(ctx);
-       if (ret < 0)
-               goto error;
-
-       ctx->m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
-       if (IS_ERR(ctx->m2m_ctx)) {
-               ret = PTR_ERR(ctx->m2m_ctx);
+       ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx, queue_init);
+       if (IS_ERR(ctx->fh.m2m_ctx)) {
+               ret = PTR_ERR(ctx->fh.m2m_ctx);
                goto error;
        }
 
        ctx->out_q.fmt = out_fmt;
-       ctx->cap_q.fmt = s5p_jpeg_find_format(ctx->mode, V4L2_PIX_FMT_YUYV);
+       ctx->cap_q.fmt = cap_fmt;
+
+       ret = s5p_jpeg_controls_create(ctx);
+       if (ret < 0)
+               goto error;
+
        mutex_unlock(&jpeg->lock);
        return 0;
 
@@ -342,49 +680,23 @@ static int s5p_jpeg_release(struct file *file)
        struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
 
        mutex_lock(&jpeg->lock);
-       v4l2_m2m_ctx_release(ctx->m2m_ctx);
-       mutex_unlock(&jpeg->lock);
+       v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
        v4l2_ctrl_handler_free(&ctx->ctrl_handler);
        v4l2_fh_del(&ctx->fh);
        v4l2_fh_exit(&ctx->fh);
        kfree(ctx);
-
-       return 0;
-}
-
-static unsigned int s5p_jpeg_poll(struct file *file,
-                                struct poll_table_struct *wait)
-{
-       struct s5p_jpeg *jpeg = video_drvdata(file);
-       struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
-       unsigned int res;
-
-       mutex_lock(&jpeg->lock);
-       res = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
        mutex_unlock(&jpeg->lock);
-       return res;
-}
-
-static int s5p_jpeg_mmap(struct file *file, struct vm_area_struct *vma)
-{
-       struct s5p_jpeg *jpeg = video_drvdata(file);
-       struct s5p_jpeg_ctx *ctx = fh_to_ctx(file->private_data);
-       int ret;
 
-       if (mutex_lock_interruptible(&jpeg->lock))
-               return -ERESTARTSYS;
-       ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
-       mutex_unlock(&jpeg->lock);
-       return ret;
+       return 0;
 }
 
 static const struct v4l2_file_operations s5p_jpeg_fops = {
        .owner          = THIS_MODULE,
        .open           = s5p_jpeg_open,
        .release        = s5p_jpeg_release,
-       .poll           = s5p_jpeg_poll,
+       .poll           = v4l2_m2m_fop_poll,
        .unlocked_ioctl = video_ioctl2,
-       .mmap           = s5p_jpeg_mmap,
+       .mmap           = v4l2_m2m_fop_mmap,
 };
 
 /*
@@ -427,10 +739,11 @@ static void skip(struct s5p_jpeg_buffer *buf, long len)
 }
 
 static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
-                              unsigned long buffer, unsigned long size)
+                              unsigned long buffer, unsigned long size,
+                              struct s5p_jpeg_ctx *ctx)
 {
        int c, components, notfound;
-       unsigned int height, width, word;
+       unsigned int height, width, word, subsampling = 0;
        long length;
        struct s5p_jpeg_buffer jpeg_buffer;
 
@@ -469,7 +782,15 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
                                break;
                        notfound = 0;
 
-                       skip(&jpeg_buffer, components * 3);
+                       if (components == 1) {
+                               subsampling = 0x33;
+                       } else {
+                               skip(&jpeg_buffer, 1);
+                               subsampling = get_byte(&jpeg_buffer);
+                               skip(&jpeg_buffer, 1);
+                       }
+
+                       skip(&jpeg_buffer, components * 2);
                        break;
 
                /* skip payload-less markers */
@@ -491,6 +812,24 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
        result->w = width;
        result->h = height;
        result->size = components;
+
+       switch (subsampling) {
+       case 0x11:
+               ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444;
+               break;
+       case 0x21:
+               ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422;
+               break;
+       case 0x22:
+               ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420;
+               break;
+       case 0x33:
+               ctx->subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
+               break;
+       default:
+               return false;
+       }
+
        return !notfound;
 }
 
@@ -521,13 +860,13 @@ static int s5p_jpeg_querycap(struct file *file, void *priv,
        return 0;
 }
 
-static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
+static int enum_fmt(struct s5p_jpeg_fmt *sjpeg_formats, int n,
                    struct v4l2_fmtdesc *f, u32 type)
 {
        int i, num = 0;
 
        for (i = 0; i < n; ++i) {
-               if (formats[i].types & type) {
+               if (sjpeg_formats[i].flags & type) {
                        /* index-th format of type type found ? */
                        if (num == f->index)
                                break;
@@ -541,8 +880,8 @@ static int enum_fmt(struct s5p_jpeg_fmt *formats, int n,
        if (i >= n)
                return -EINVAL;
 
-       strlcpy(f->description, formats[i].name, sizeof(f->description));
-       f->pixelformat = formats[i].fourcc;
+       strlcpy(f->description, sjpeg_formats[i].name, sizeof(f->description));
+       f->pixelformat = sjpeg_formats[i].fourcc;
 
        return 0;
 }
@@ -553,10 +892,11 @@ static int s5p_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
        struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        if (ctx->mode == S5P_JPEG_ENCODE)
-               return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
-                               MEM2MEM_CAPTURE);
+               return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+                               SJPEG_FMT_FLAG_ENC_CAPTURE);
 
-       return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_CAPTURE);
+       return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+                                       SJPEG_FMT_FLAG_DEC_CAPTURE);
 }
 
 static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
@@ -565,10 +905,11 @@ static int s5p_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
        struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        if (ctx->mode == S5P_JPEG_ENCODE)
-               return enum_fmt(formats_enc, NUM_FORMATS_ENC, f,
-                               MEM2MEM_OUTPUT);
+               return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+                               SJPEG_FMT_FLAG_ENC_OUTPUT);
 
-       return enum_fmt(formats_dec, NUM_FORMATS_DEC, f, MEM2MEM_OUTPUT);
+       return enum_fmt(sjpeg_formats, SJPEG_NUM_FORMATS, f,
+                                       SJPEG_FMT_FLAG_DEC_OUTPUT);
 }
 
 static struct s5p_jpeg_q_data *get_q_data(struct s5p_jpeg_ctx *ctx,
@@ -589,7 +930,7 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
        struct v4l2_pix_format *pix = &f->fmt.pix;
        struct s5p_jpeg_ctx *ct = fh_to_ctx(priv);
 
-       vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
+       vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
        if (!vq)
                return -EINVAL;
 
@@ -615,29 +956,35 @@ static int s5p_jpeg_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
        return 0;
 }
 
-static struct s5p_jpeg_fmt *s5p_jpeg_find_format(unsigned int mode,
-                                                u32 pixelformat)
+static struct s5p_jpeg_fmt *s5p_jpeg_find_format(struct s5p_jpeg_ctx *ctx,
+                               u32 pixelformat, unsigned int fmt_type)
 {
-       unsigned int k;
-       struct s5p_jpeg_fmt *formats;
-       int n;
+       unsigned int k, fmt_flag, ver_flag;
 
-       if (mode == S5P_JPEG_ENCODE) {
-               formats = formats_enc;
-               n = NUM_FORMATS_ENC;
-       } else {
-               formats = formats_dec;
-               n = NUM_FORMATS_DEC;
-       }
+       if (ctx->mode == S5P_JPEG_ENCODE)
+               fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
+                               SJPEG_FMT_FLAG_ENC_OUTPUT :
+                               SJPEG_FMT_FLAG_ENC_CAPTURE;
+       else
+               fmt_flag = (fmt_type == FMT_TYPE_OUTPUT) ?
+                               SJPEG_FMT_FLAG_DEC_OUTPUT :
+                               SJPEG_FMT_FLAG_DEC_CAPTURE;
+
+       if (ctx->jpeg->variant->version == SJPEG_S5P)
+               ver_flag = SJPEG_FMT_FLAG_S5P;
+       else
+               ver_flag = SJPEG_FMT_FLAG_EXYNOS4;
 
-       for (k = 0; k < n; k++) {
-               struct s5p_jpeg_fmt *fmt = &formats[k];
-               if (fmt->fourcc == pixelformat)
+       for (k = 0; k < ARRAY_SIZE(sjpeg_formats); k++) {
+               struct s5p_jpeg_fmt *fmt = &sjpeg_formats[k];
+               if (fmt->fourcc == pixelformat &&
+                   fmt->flags & fmt_flag &&
+                   fmt->flags & ver_flag) {
                        return fmt;
+               }
        }
 
        return NULL;
-
 }
 
 static void jpeg_bound_align_image(u32 *w, unsigned int wmin, unsigned int wmax,
@@ -673,7 +1020,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
 
        /* V4L2 specification suggests the driver corrects the format struct
         * if any of the dimensions is unsupported */
-       if (q_type == MEM2MEM_OUTPUT)
+       if (q_type == FMT_TYPE_OUTPUT)
                jpeg_bound_align_image(&pix->width, S5P_JPEG_MIN_WIDTH,
                                       S5P_JPEG_MAX_WIDTH, 0,
                                       &pix->height, S5P_JPEG_MIN_HEIGHT,
@@ -695,7 +1042,7 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct s5p_jpeg_fmt *fmt,
                        bpl = pix->width; /* planar */
 
                if (fmt->colplanes == 1 && /* packed */
-                   (bpl << 3) * fmt->depth < pix->width)
+                   (bpl << 3) / fmt->depth < pix->width)
                        bpl = (pix->width * fmt->depth) >> 3;
 
                pix->bytesperline = bpl;
@@ -709,17 +1056,41 @@ static int s5p_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
                                  struct v4l2_format *f)
 {
        struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
+       struct v4l2_pix_format *pix = &f->fmt.pix;
        struct s5p_jpeg_fmt *fmt;
+       int ret;
 
-       fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
-       if (!fmt || !(fmt->types & MEM2MEM_CAPTURE)) {
+       fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
+                                               FMT_TYPE_CAPTURE);
+       if (!fmt) {
                v4l2_err(&ctx->jpeg->v4l2_dev,
                         "Fourcc format (0x%08x) invalid.\n",
                         f->fmt.pix.pixelformat);
                return -EINVAL;
        }
 
-       return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_CAPTURE);
+       /*
+        * The exynos4x12 device requires resulting YUV image
+        * subsampling not to be lower than the input jpeg subsampling.
+        * If this requirement is not met then downgrade the requested
+        * capture format to the one with subsampling equal to the input jpeg.
+        */
+       if ((ctx->jpeg->variant->version != SJPEG_S5P) &&
+           (ctx->mode == S5P_JPEG_DECODE) &&
+           (fmt->flags & SJPEG_FMT_NON_RGB) &&
+           (fmt->subsampling < ctx->subsampling)) {
+               ret = s5p_jpeg_adjust_fourcc_to_subsampling(ctx->subsampling,
+                                                           fmt->fourcc,
+                                                           &pix->pixelformat,
+                                                           ctx);
+               if (ret < 0)
+                       pix->pixelformat = V4L2_PIX_FMT_GREY;
+
+               fmt = s5p_jpeg_find_format(ctx, pix->pixelformat,
+                                                       FMT_TYPE_CAPTURE);
+       }
+
+       return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_CAPTURE);
 }
 
 static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
@@ -728,15 +1099,16 @@ static int s5p_jpeg_try_fmt_vid_out(struct file *file, void *priv,
        struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
        struct s5p_jpeg_fmt *fmt;
 
-       fmt = s5p_jpeg_find_format(ctx->mode, f->fmt.pix.pixelformat);
-       if (!fmt || !(fmt->types & MEM2MEM_OUTPUT)) {
+       fmt = s5p_jpeg_find_format(ctx, f->fmt.pix.pixelformat,
+                                               FMT_TYPE_OUTPUT);
+       if (!fmt) {
                v4l2_err(&ctx->jpeg->v4l2_dev,
                         "Fourcc format (0x%08x) invalid.\n",
                         f->fmt.pix.pixelformat);
                return -EINVAL;
        }
 
-       return vidioc_try_fmt(f, fmt, ctx, MEM2MEM_OUTPUT);
+       return vidioc_try_fmt(f, fmt, ctx, FMT_TYPE_OUTPUT);
 }
 
 static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
@@ -744,8 +1116,10 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
        struct vb2_queue *vq;
        struct s5p_jpeg_q_data *q_data = NULL;
        struct v4l2_pix_format *pix = &f->fmt.pix;
+       struct v4l2_ctrl *ctrl_subs;
+       unsigned int f_type;
 
-       vq = v4l2_m2m_get_vq(ct->m2m_ctx, f->type);
+       vq = v4l2_m2m_get_vq(ct->fh.m2m_ctx, f->type);
        if (!vq)
                return -EINVAL;
 
@@ -757,7 +1131,10 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
                return -EBUSY;
        }
 
-       q_data->fmt = s5p_jpeg_find_format(ct->mode, pix->pixelformat);
+       f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
+                       FMT_TYPE_OUTPUT : FMT_TYPE_CAPTURE;
+
+       q_data->fmt = s5p_jpeg_find_format(ct, pix->pixelformat, f_type);
        q_data->w = pix->width;
        q_data->h = pix->height;
        if (q_data->fmt->fourcc != V4L2_PIX_FMT_JPEG)
@@ -765,6 +1142,13 @@ static int s5p_jpeg_s_fmt(struct s5p_jpeg_ctx *ct, struct v4l2_format *f)
        else
                q_data->size = pix->sizeimage;
 
+       if (f_type == FMT_TYPE_OUTPUT) {
+               ctrl_subs = v4l2_ctrl_find(&ct->ctrl_handler,
+                                       V4L2_CID_JPEG_CHROMA_SUBSAMPLING);
+               if (ctrl_subs)
+                       v4l2_ctrl_s_ctrl(ctrl_subs, q_data->fmt->subsampling);
+       }
+
        return 0;
 }
 
@@ -792,60 +1176,14 @@ static int s5p_jpeg_s_fmt_vid_out(struct file *file, void *priv,
        return s5p_jpeg_s_fmt(fh_to_ctx(priv), f);
 }
 
-static int s5p_jpeg_reqbufs(struct file *file, void *priv,
-                         struct v4l2_requestbuffers *reqbufs)
-{
-       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
-       return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int s5p_jpeg_querybuf(struct file *file, void *priv,
-                          struct v4l2_buffer *buf)
-{
-       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
-       return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int s5p_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
-       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
-       return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int s5p_jpeg_dqbuf(struct file *file, void *priv,
-                         struct v4l2_buffer *buf)
-{
-       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
-       return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int s5p_jpeg_streamon(struct file *file, void *priv,
-                          enum v4l2_buf_type type)
-{
-       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
-       return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int s5p_jpeg_streamoff(struct file *file, void *priv,
-                           enum v4l2_buf_type type)
-{
-       struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
-
-       return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
 static int s5p_jpeg_g_selection(struct file *file, void *priv,
                         struct v4l2_selection *s)
 {
        struct s5p_jpeg_ctx *ctx = fh_to_ctx(priv);
 
        if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT &&
-           s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+           s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+           ctx->jpeg->variant->version != SJPEG_S5P)
                return -EINVAL;
 
        /* For JPEG blob active == default == bounds */
@@ -884,12 +1222,7 @@ static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        switch (ctrl->id) {
        case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
                spin_lock_irqsave(&jpeg->slock, flags);
-
-               WARN_ON(ctx->subsampling > S5P_SUBSAMPLING_MODE_GRAY);
-               if (ctx->subsampling > 2)
-                       ctrl->val = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY;
-               else
-                       ctrl->val = ctx->subsampling;
+               ctrl->val = s5p_jpeg_to_user_subsampling(ctx);
                spin_unlock_irqrestore(&jpeg->slock, flags);
                break;
        }
@@ -897,6 +1230,40 @@ static int s5p_jpeg_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
+static int s5p_jpeg_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&ctx->jpeg->slock, flags);
+
+       if (ctrl->id == V4L2_CID_JPEG_CHROMA_SUBSAMPLING) {
+               if (ctx->jpeg->variant->version == SJPEG_S5P)
+                       goto error_free;
+               /*
+                * The exynos4x12 device requires input raw image fourcc
+                * to be V4L2_PIX_FMT_GREY if gray jpeg format
+                * is to be set.
+                */
+               if (ctx->out_q.fmt->fourcc != V4L2_PIX_FMT_GREY &&
+                   ctrl->val == V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY) {
+                       ret = -EINVAL;
+                       goto error_free;
+               }
+               /*
+                * The exynos4x12 device requires resulting jpeg subsampling
+                * not to be lower than the input raw image subsampling.
+                */
+               if (ctx->out_q.fmt->subsampling > ctrl->val)
+                       ctrl->val = ctx->out_q.fmt->subsampling;
+       }
+
+error_free:
+       spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+       return ret;
+}
+
 static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct s5p_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
@@ -906,7 +1273,7 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
 
        switch (ctrl->id) {
        case V4L2_CID_JPEG_COMPRESSION_QUALITY:
-               ctx->compr_quality = S5P_JPEG_COMPR_QUAL_WORST - ctrl->val;
+               ctx->compr_quality = ctrl->val;
                break;
        case V4L2_CID_JPEG_RESTART_INTERVAL:
                ctx->restart_interval = ctrl->val;
@@ -922,6 +1289,7 @@ static int s5p_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
 
 static const struct v4l2_ctrl_ops s5p_jpeg_ctrl_ops = {
        .g_volatile_ctrl        = s5p_jpeg_g_volatile_ctrl,
+       .try_ctrl               = s5p_jpeg_try_ctrl,
        .s_ctrl                 = s5p_jpeg_s_ctrl,
 };
 
@@ -929,18 +1297,20 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
 {
        unsigned int mask = ~0x27; /* 444, 422, 420, GRAY */
        struct v4l2_ctrl *ctrl;
+       int ret;
 
        v4l2_ctrl_handler_init(&ctx->ctrl_handler, 3);
 
        if (ctx->mode == S5P_JPEG_ENCODE) {
                v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
                                  V4L2_CID_JPEG_COMPRESSION_QUALITY,
-                                 0, 3, 1, 3);
+                                 0, 3, 1, S5P_JPEG_COMPR_QUAL_WORST);
 
                v4l2_ctrl_new_std(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
                                  V4L2_CID_JPEG_RESTART_INTERVAL,
                                  0, 3, 0xffff, 0);
-               mask = ~0x06; /* 422, 420 */
+               if (ctx->jpeg->variant->version == SJPEG_S5P)
+                       mask = ~0x06; /* 422, 420 */
        }
 
        ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrl_handler, &s5p_jpeg_ctrl_ops,
@@ -948,13 +1318,24 @@ static int s5p_jpeg_controls_create(struct s5p_jpeg_ctx *ctx)
                                      V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, mask,
                                      V4L2_JPEG_CHROMA_SUBSAMPLING_422);
 
-       if (ctx->ctrl_handler.error)
-               return ctx->ctrl_handler.error;
+       if (ctx->ctrl_handler.error) {
+               ret = ctx->ctrl_handler.error;
+               goto error_free;
+       }
 
        if (ctx->mode == S5P_JPEG_DECODE)
                ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE |
                        V4L2_CTRL_FLAG_READ_ONLY;
-       return 0;
+
+       ret = v4l2_ctrl_handler_setup(&ctx->ctrl_handler);
+       if (ret < 0)
+               goto error_free;
+
+       return ret;
+
+error_free:
+       v4l2_ctrl_handler_free(&ctx->ctrl_handler);
+       return ret;
 }
 
 static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
@@ -972,14 +1353,13 @@ static const struct v4l2_ioctl_ops s5p_jpeg_ioctl_ops = {
        .vidioc_s_fmt_vid_cap           = s5p_jpeg_s_fmt_vid_cap,
        .vidioc_s_fmt_vid_out           = s5p_jpeg_s_fmt_vid_out,
 
-       .vidioc_reqbufs                 = s5p_jpeg_reqbufs,
-       .vidioc_querybuf                = s5p_jpeg_querybuf,
+       .vidioc_reqbufs                 = v4l2_m2m_ioctl_reqbufs,
+       .vidioc_querybuf                = v4l2_m2m_ioctl_querybuf,
+       .vidioc_qbuf                    = v4l2_m2m_ioctl_qbuf,
+       .vidioc_dqbuf                   = v4l2_m2m_ioctl_dqbuf,
 
-       .vidioc_qbuf                    = s5p_jpeg_qbuf,
-       .vidioc_dqbuf                   = s5p_jpeg_dqbuf,
-
-       .vidioc_streamon                = s5p_jpeg_streamon,
-       .vidioc_streamoff               = s5p_jpeg_streamoff,
+       .vidioc_streamon                = v4l2_m2m_ioctl_streamon,
+       .vidioc_streamoff               = v4l2_m2m_ioctl_streamoff,
 
        .vidioc_g_selection             = s5p_jpeg_g_selection,
 };
@@ -995,74 +1375,181 @@ static void s5p_jpeg_device_run(void *priv)
        struct s5p_jpeg_ctx *ctx = priv;
        struct s5p_jpeg *jpeg = ctx->jpeg;
        struct vb2_buffer *src_buf, *dst_buf;
-       unsigned long src_addr, dst_addr;
+       unsigned long src_addr, dst_addr, flags;
+
+       spin_lock_irqsave(&ctx->jpeg->slock, flags);
 
-       src_buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
-       dst_buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+       src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
        src_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
        dst_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
 
-       jpeg_reset(jpeg->regs);
-       jpeg_poweron(jpeg->regs);
-       jpeg_proc_mode(jpeg->regs, ctx->mode);
+       s5p_jpeg_reset(jpeg->regs);
+       s5p_jpeg_poweron(jpeg->regs);
+       s5p_jpeg_proc_mode(jpeg->regs, ctx->mode);
        if (ctx->mode == S5P_JPEG_ENCODE) {
                if (ctx->out_q.fmt->fourcc == V4L2_PIX_FMT_RGB565)
-                       jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_565);
+                       s5p_jpeg_input_raw_mode(jpeg->regs,
+                                                       S5P_JPEG_RAW_IN_565);
                else
-                       jpeg_input_raw_mode(jpeg->regs, S5P_JPEG_RAW_IN_422);
-               jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
-               jpeg_dri(jpeg->regs, ctx->restart_interval);
-               jpeg_x(jpeg->regs, ctx->out_q.w);
-               jpeg_y(jpeg->regs, ctx->out_q.h);
-               jpeg_imgadr(jpeg->regs, src_addr);
-               jpeg_jpgadr(jpeg->regs, dst_addr);
+                       s5p_jpeg_input_raw_mode(jpeg->regs,
+                                                       S5P_JPEG_RAW_IN_422);
+               s5p_jpeg_subsampling_mode(jpeg->regs, ctx->subsampling);
+               s5p_jpeg_dri(jpeg->regs, ctx->restart_interval);
+               s5p_jpeg_x(jpeg->regs, ctx->out_q.w);
+               s5p_jpeg_y(jpeg->regs, ctx->out_q.h);
+               s5p_jpeg_imgadr(jpeg->regs, src_addr);
+               s5p_jpeg_jpgadr(jpeg->regs, dst_addr);
 
                /* ultimately comes from sizeimage from userspace */
-               jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
+               s5p_jpeg_enc_stream_int(jpeg->regs, ctx->cap_q.size);
 
                /* JPEG RGB to YCbCr conversion matrix */
-               jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
-               jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
-               jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
-               jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
-               jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
-               jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
-               jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
-               jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
-               jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
+               s5p_jpeg_coef(jpeg->regs, 1, 1, S5P_JPEG_COEF11);
+               s5p_jpeg_coef(jpeg->regs, 1, 2, S5P_JPEG_COEF12);
+               s5p_jpeg_coef(jpeg->regs, 1, 3, S5P_JPEG_COEF13);
+               s5p_jpeg_coef(jpeg->regs, 2, 1, S5P_JPEG_COEF21);
+               s5p_jpeg_coef(jpeg->regs, 2, 2, S5P_JPEG_COEF22);
+               s5p_jpeg_coef(jpeg->regs, 2, 3, S5P_JPEG_COEF23);
+               s5p_jpeg_coef(jpeg->regs, 3, 1, S5P_JPEG_COEF31);
+               s5p_jpeg_coef(jpeg->regs, 3, 2, S5P_JPEG_COEF32);
+               s5p_jpeg_coef(jpeg->regs, 3, 3, S5P_JPEG_COEF33);
 
                /*
                 * JPEG IP allows storing 4 quantization tables
                 * We fill table 0 for luma and table 1 for chroma
                 */
-               jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
-               jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
+               s5p_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
+               s5p_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
                /* use table 0 for Y */
-               jpeg_qtbl(jpeg->regs, 1, 0);
+               s5p_jpeg_qtbl(jpeg->regs, 1, 0);
                /* use table 1 for Cb and Cr*/
-               jpeg_qtbl(jpeg->regs, 2, 1);
-               jpeg_qtbl(jpeg->regs, 3, 1);
+               s5p_jpeg_qtbl(jpeg->regs, 2, 1);
+               s5p_jpeg_qtbl(jpeg->regs, 3, 1);
 
                /* Y, Cb, Cr use Huffman table 0 */
-               jpeg_htbl_ac(jpeg->regs, 1);
-               jpeg_htbl_dc(jpeg->regs, 1);
-               jpeg_htbl_ac(jpeg->regs, 2);
-               jpeg_htbl_dc(jpeg->regs, 2);
-               jpeg_htbl_ac(jpeg->regs, 3);
-               jpeg_htbl_dc(jpeg->regs, 3);
+               s5p_jpeg_htbl_ac(jpeg->regs, 1);
+               s5p_jpeg_htbl_dc(jpeg->regs, 1);
+               s5p_jpeg_htbl_ac(jpeg->regs, 2);
+               s5p_jpeg_htbl_dc(jpeg->regs, 2);
+               s5p_jpeg_htbl_ac(jpeg->regs, 3);
+               s5p_jpeg_htbl_dc(jpeg->regs, 3);
        } else { /* S5P_JPEG_DECODE */
-               jpeg_rst_int_enable(jpeg->regs, true);
-               jpeg_data_num_int_enable(jpeg->regs, true);
-               jpeg_final_mcu_num_int_enable(jpeg->regs, true);
+               s5p_jpeg_rst_int_enable(jpeg->regs, true);
+               s5p_jpeg_data_num_int_enable(jpeg->regs, true);
+               s5p_jpeg_final_mcu_num_int_enable(jpeg->regs, true);
                if (ctx->cap_q.fmt->fourcc == V4L2_PIX_FMT_YUYV)
-                       jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
+                       s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_422);
                else
-                       jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
-               jpeg_jpgadr(jpeg->regs, src_addr);
-               jpeg_imgadr(jpeg->regs, dst_addr);
+                       s5p_jpeg_outform_raw(jpeg->regs, S5P_JPEG_RAW_OUT_420);
+               s5p_jpeg_jpgadr(jpeg->regs, src_addr);
+               s5p_jpeg_imgadr(jpeg->regs, dst_addr);
        }
 
-       jpeg_start(jpeg->regs);
+       s5p_jpeg_start(jpeg->regs);
+
+       spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
+}
+
+static void exynos4_jpeg_set_img_addr(struct s5p_jpeg_ctx *ctx)
+{
+       struct s5p_jpeg *jpeg = ctx->jpeg;
+       struct s5p_jpeg_fmt *fmt;
+       struct vb2_buffer *vb;
+       struct s5p_jpeg_addr jpeg_addr;
+       u32 pix_size, padding_bytes = 0;
+
+       pix_size = ctx->cap_q.w * ctx->cap_q.h;
+
+       if (ctx->mode == S5P_JPEG_ENCODE) {
+               vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+               fmt = ctx->out_q.fmt;
+               if (ctx->out_q.w % 2 && fmt->h_align > 0)
+                       padding_bytes = ctx->out_q.h;
+       } else {
+               fmt = ctx->cap_q.fmt;
+               vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       }
+
+       jpeg_addr.y = vb2_dma_contig_plane_dma_addr(vb, 0);
+
+       if (fmt->colplanes == 2) {
+               jpeg_addr.cb = jpeg_addr.y + pix_size - padding_bytes;
+       } else if (fmt->colplanes == 3) {
+               jpeg_addr.cb = jpeg_addr.y + pix_size;
+               if (fmt->fourcc == V4L2_PIX_FMT_YUV420)
+                       jpeg_addr.cr = jpeg_addr.cb + pix_size / 4;
+               else
+                       jpeg_addr.cr = jpeg_addr.cb + pix_size / 2;
+       }
+
+       exynos4_jpeg_set_frame_buf_address(jpeg->regs, &jpeg_addr);
+}
+
+static void exynos4_jpeg_set_jpeg_addr(struct s5p_jpeg_ctx *ctx)
+{
+       struct s5p_jpeg *jpeg = ctx->jpeg;
+       struct vb2_buffer *vb;
+       unsigned int jpeg_addr = 0;
+
+       if (ctx->mode == S5P_JPEG_ENCODE)
+               vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+       else
+               vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+
+       jpeg_addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+       exynos4_jpeg_set_stream_buf_address(jpeg->regs, jpeg_addr);
+}
+
+static void exynos4_jpeg_device_run(void *priv)
+{
+       struct s5p_jpeg_ctx *ctx = priv;
+       struct s5p_jpeg *jpeg = ctx->jpeg;
+       unsigned int bitstream_size;
+       unsigned long flags;
+
+       spin_lock_irqsave(&ctx->jpeg->slock, flags);
+
+       if (ctx->mode == S5P_JPEG_ENCODE) {
+               exynos4_jpeg_sw_reset(jpeg->regs);
+               exynos4_jpeg_set_interrupt(jpeg->regs);
+               exynos4_jpeg_set_huf_table_enable(jpeg->regs, 1);
+
+               exynos4_jpeg_set_huff_tbl(jpeg->regs);
+
+               /*
+                * JPEG IP allows storing 4 quantization tables
+                * We fill table 0 for luma and table 1 for chroma
+                */
+               exynos4_jpeg_set_qtbl_lum(jpeg->regs, ctx->compr_quality);
+               exynos4_jpeg_set_qtbl_chr(jpeg->regs, ctx->compr_quality);
+
+               exynos4_jpeg_set_encode_tbl_select(jpeg->regs,
+                                                       ctx->compr_quality);
+               exynos4_jpeg_set_stream_size(jpeg->regs, ctx->cap_q.w,
+                                                       ctx->cap_q.h);
+
+               exynos4_jpeg_set_enc_out_fmt(jpeg->regs, ctx->subsampling);
+               exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->out_q.fmt->fourcc);
+               exynos4_jpeg_set_img_addr(ctx);
+               exynos4_jpeg_set_jpeg_addr(ctx);
+               exynos4_jpeg_set_encode_hoff_cnt(jpeg->regs,
+                                                       ctx->out_q.fmt->fourcc);
+       } else {
+               exynos4_jpeg_sw_reset(jpeg->regs);
+               exynos4_jpeg_set_interrupt(jpeg->regs);
+               exynos4_jpeg_set_img_addr(ctx);
+               exynos4_jpeg_set_jpeg_addr(ctx);
+               exynos4_jpeg_set_img_fmt(jpeg->regs, ctx->cap_q.fmt->fourcc);
+
+               bitstream_size = DIV_ROUND_UP(ctx->out_q.size, 32);
+
+               exynos4_jpeg_set_dec_bitstream_size(jpeg->regs, bitstream_size);
+       }
+
+       exynos4_jpeg_set_enc_dec_mode(jpeg->regs, ctx->mode);
+
+       spin_unlock_irqrestore(&ctx->jpeg->slock, flags);
 }
 
 static int s5p_jpeg_job_ready(void *priv)
@@ -1082,6 +1569,12 @@ static struct v4l2_m2m_ops s5p_jpeg_m2m_ops = {
        .device_run     = s5p_jpeg_device_run,
        .job_ready      = s5p_jpeg_job_ready,
        .job_abort      = s5p_jpeg_job_abort,
+}
+;
+static struct v4l2_m2m_ops exynos_jpeg_m2m_ops = {
+       .device_run     = exynos4_jpeg_device_run,
+       .job_ready      = s5p_jpeg_job_ready,
+       .job_abort      = s5p_jpeg_job_abort,
 };
 
 /*
@@ -1149,7 +1642,7 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
                ctx->hdr_parsed = s5p_jpeg_parse_hdr(&tmp,
                     (unsigned long)vb2_plane_vaddr(vb, 0),
                     min((unsigned long)ctx->out_q.size,
-                        vb2_get_plane_payload(vb, 0)));
+                        vb2_get_plane_payload(vb, 0)), ctx);
                if (!ctx->hdr_parsed) {
                        vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
                        return;
@@ -1162,30 +1655,9 @@ static void s5p_jpeg_buf_queue(struct vb2_buffer *vb)
                q_data = &ctx->cap_q;
                q_data->w = tmp.w;
                q_data->h = tmp.h;
-
-               jpeg_bound_align_image(&q_data->w, S5P_JPEG_MIN_WIDTH,
-                                      S5P_JPEG_MAX_WIDTH, q_data->fmt->h_align,
-                                      &q_data->h, S5P_JPEG_MIN_HEIGHT,
-                                      S5P_JPEG_MAX_HEIGHT, q_data->fmt->v_align
-                                     );
-               q_data->size = q_data->w * q_data->h * q_data->fmt->depth >> 3;
        }
-       if (ctx->m2m_ctx)
-               v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
-}
-
-static void s5p_jpeg_wait_prepare(struct vb2_queue *vq)
-{
-       struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
 
-       mutex_unlock(&ctx->jpeg->lock);
-}
-
-static void s5p_jpeg_wait_finish(struct vb2_queue *vq)
-{
-       struct s5p_jpeg_ctx *ctx = vb2_get_drv_priv(vq);
-
-       mutex_lock(&ctx->jpeg->lock);
+       v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
 }
 
 static int s5p_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
@@ -1211,8 +1683,8 @@ static struct vb2_ops s5p_jpeg_qops = {
        .queue_setup            = s5p_jpeg_queue_setup,
        .buf_prepare            = s5p_jpeg_buf_prepare,
        .buf_queue              = s5p_jpeg_buf_queue,
-       .wait_prepare           = s5p_jpeg_wait_prepare,
-       .wait_finish            = s5p_jpeg_wait_finish,
+       .wait_prepare           = vb2_ops_wait_prepare,
+       .wait_finish            = vb2_ops_wait_finish,
        .start_streaming        = s5p_jpeg_start_streaming,
        .stop_streaming         = s5p_jpeg_stop_streaming,
 };
@@ -1230,6 +1702,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
        src_vq->ops = &s5p_jpeg_qops;
        src_vq->mem_ops = &vb2_dma_contig_memops;
        src_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       src_vq->lock = &ctx->jpeg->lock;
 
        ret = vb2_queue_init(src_vq);
        if (ret)
@@ -1242,6 +1715,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
        dst_vq->ops = &s5p_jpeg_qops;
        dst_vq->mem_ops = &vb2_dma_contig_memops;
        dst_vq->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+       dst_vq->lock = &ctx->jpeg->lock;
 
        return vb2_queue_init(dst_vq);
 }
@@ -1267,26 +1741,27 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
 
        curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
 
-       src_buf = v4l2_m2m_src_buf_remove(curr_ctx->m2m_ctx);
-       dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->m2m_ctx);
+       src_buf = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
+       dst_buf = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
 
        if (curr_ctx->mode == S5P_JPEG_ENCODE)
-               enc_jpeg_too_large = jpeg_enc_stream_stat(jpeg->regs);
-       timer_elapsed = jpeg_timer_stat(jpeg->regs);
-       op_completed = jpeg_result_stat_ok(jpeg->regs);
+               enc_jpeg_too_large = s5p_jpeg_enc_stream_stat(jpeg->regs);
+       timer_elapsed = s5p_jpeg_timer_stat(jpeg->regs);
+       op_completed = s5p_jpeg_result_stat_ok(jpeg->regs);
        if (curr_ctx->mode == S5P_JPEG_DECODE)
-               op_completed = op_completed && jpeg_stream_stat_ok(jpeg->regs);
+               op_completed = op_completed &&
+                                       s5p_jpeg_stream_stat_ok(jpeg->regs);
 
        if (enc_jpeg_too_large) {
                state = VB2_BUF_STATE_ERROR;
-               jpeg_clear_enc_stream_stat(jpeg->regs);
+               s5p_jpeg_clear_enc_stream_stat(jpeg->regs);
        } else if (timer_elapsed) {
                state = VB2_BUF_STATE_ERROR;
-               jpeg_clear_timer_stat(jpeg->regs);
+               s5p_jpeg_clear_timer_stat(jpeg->regs);
        } else if (!op_completed) {
                state = VB2_BUF_STATE_ERROR;
        } else {
-               payload_size = jpeg_compressed_size(jpeg->regs);
+               payload_size = s5p_jpeg_compressed_size(jpeg->regs);
        }
 
        dst_buf->v4l2_buf.timecode = src_buf->v4l2_buf.timecode;
@@ -1296,16 +1771,79 @@ static irqreturn_t s5p_jpeg_irq(int irq, void *dev_id)
        if (curr_ctx->mode == S5P_JPEG_ENCODE)
                vb2_set_plane_payload(dst_buf, 0, payload_size);
        v4l2_m2m_buf_done(dst_buf, state);
-       v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->m2m_ctx);
+       v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
 
-       curr_ctx->subsampling = jpeg_get_subsampling_mode(jpeg->regs);
+       curr_ctx->subsampling = s5p_jpeg_get_subsampling_mode(jpeg->regs);
        spin_unlock(&jpeg->slock);
 
-       jpeg_clear_int(jpeg->regs);
+       s5p_jpeg_clear_int(jpeg->regs);
 
        return IRQ_HANDLED;
 }
 
+static irqreturn_t exynos4_jpeg_irq(int irq, void *priv)
+{
+       unsigned int int_status;
+       struct vb2_buffer *src_vb, *dst_vb;
+       struct s5p_jpeg *jpeg = priv;
+       struct s5p_jpeg_ctx *curr_ctx;
+       unsigned long payload_size = 0;
+
+       spin_lock(&jpeg->slock);
+
+       curr_ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+
+       src_vb = v4l2_m2m_src_buf_remove(curr_ctx->fh.m2m_ctx);
+       dst_vb = v4l2_m2m_dst_buf_remove(curr_ctx->fh.m2m_ctx);
+
+       int_status = exynos4_jpeg_get_int_status(jpeg->regs);
+
+       if (int_status) {
+               switch (int_status & 0x1f) {
+               case 0x1:
+                       jpeg->irq_ret = ERR_PROT;
+                       break;
+               case 0x2:
+                       jpeg->irq_ret = OK_ENC_OR_DEC;
+                       break;
+               case 0x4:
+                       jpeg->irq_ret = ERR_DEC_INVALID_FORMAT;
+                       break;
+               case 0x8:
+                       jpeg->irq_ret = ERR_MULTI_SCAN;
+                       break;
+               case 0x10:
+                       jpeg->irq_ret = ERR_FRAME;
+                       break;
+               default:
+                       jpeg->irq_ret = ERR_UNKNOWN;
+                       break;
+               }
+       } else {
+               jpeg->irq_ret = ERR_UNKNOWN;
+       }
+
+       if (jpeg->irq_ret == OK_ENC_OR_DEC) {
+               if (curr_ctx->mode == S5P_JPEG_ENCODE) {
+                       payload_size = exynos4_jpeg_get_stream_size(jpeg->regs);
+                       vb2_set_plane_payload(dst_vb, 0, payload_size);
+               }
+               v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
+               v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
+       } else {
+               v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_ERROR);
+               v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_ERROR);
+       }
+
+       v4l2_m2m_job_finish(jpeg->m2m_dev, curr_ctx->fh.m2m_ctx);
+       curr_ctx->subsampling = exynos4_jpeg_get_frame_fmt(jpeg->regs);
+
+       spin_unlock(&jpeg->slock);
+       return IRQ_HANDLED;
+}
+
+static void *jpeg_get_drv_data(struct platform_device *pdev);
+
 /*
  * ============================================================================
  * Driver basic infrastructure
@@ -1316,13 +1854,19 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
 {
        struct s5p_jpeg *jpeg;
        struct resource *res;
+       struct v4l2_m2m_ops *samsung_jpeg_m2m_ops;
        int ret;
 
+       if (!pdev->dev.of_node)
+               return -ENODEV;
+
        /* JPEG IP abstraction struct */
        jpeg = devm_kzalloc(&pdev->dev, sizeof(struct s5p_jpeg), GFP_KERNEL);
        if (!jpeg)
                return -ENOMEM;
 
+       jpeg->variant = jpeg_get_drv_data(pdev);
+
        mutex_init(&jpeg->lock);
        spin_lock_init(&jpeg->slock);
        jpeg->dev = &pdev->dev;
@@ -1341,8 +1885,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
                return ret;
        }
 
-       ret = devm_request_irq(&pdev->dev, jpeg->irq, s5p_jpeg_irq, 0,
-                       dev_name(&pdev->dev), jpeg);
+       ret = devm_request_irq(&pdev->dev, jpeg->irq, jpeg->variant->jpeg_irq,
+                               0, dev_name(&pdev->dev), jpeg);
        if (ret) {
                dev_err(&pdev->dev, "cannot claim IRQ %d\n", jpeg->irq);
                return ret;
@@ -1356,7 +1900,6 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
                return ret;
        }
        dev_dbg(&pdev->dev, "clock source %p\n", jpeg->clk);
-       clk_prepare_enable(jpeg->clk);
 
        /* v4l2 device */
        ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
@@ -1365,8 +1908,13 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
                goto clk_get_rollback;
        }
 
+       if (jpeg->variant->version == SJPEG_S5P)
+               samsung_jpeg_m2m_ops = &s5p_jpeg_m2m_ops;
+       else
+               samsung_jpeg_m2m_ops = &exynos_jpeg_m2m_ops;
+
        /* mem2mem device */
-       jpeg->m2m_dev = v4l2_m2m_init(&s5p_jpeg_m2m_ops);
+       jpeg->m2m_dev = v4l2_m2m_init(samsung_jpeg_m2m_ops);
        if (IS_ERR(jpeg->m2m_dev)) {
                v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
                ret = PTR_ERR(jpeg->m2m_dev);
@@ -1387,8 +1935,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto vb2_allocator_rollback;
        }
-       strlcpy(jpeg->vfd_encoder->name, S5P_JPEG_M2M_NAME,
-               sizeof(jpeg->vfd_encoder->name));
+       snprintf(jpeg->vfd_encoder->name, sizeof(jpeg->vfd_encoder->name),
+                               "%s-enc", S5P_JPEG_M2M_NAME);
        jpeg->vfd_encoder->fops         = &s5p_jpeg_fops;
        jpeg->vfd_encoder->ioctl_ops    = &s5p_jpeg_ioctl_ops;
        jpeg->vfd_encoder->minor        = -1;
@@ -1415,8 +1963,8 @@ static int s5p_jpeg_probe(struct platform_device *pdev)
                ret = -ENOMEM;
                goto enc_vdev_register_rollback;
        }
-       strlcpy(jpeg->vfd_decoder->name, S5P_JPEG_M2M_NAME,
-               sizeof(jpeg->vfd_decoder->name));
+       snprintf(jpeg->vfd_decoder->name, sizeof(jpeg->vfd_decoder->name),
+                               "%s-dec", S5P_JPEG_M2M_NAME);
        jpeg->vfd_decoder->fops         = &s5p_jpeg_fops;
        jpeg->vfd_decoder->ioctl_ops    = &s5p_jpeg_ioctl_ops;
        jpeg->vfd_decoder->minor        = -1;
@@ -1464,7 +2012,6 @@ device_register_rollback:
        v4l2_device_unregister(&jpeg->v4l2_dev);
 
 clk_get_rollback:
-       clk_disable_unprepare(jpeg->clk);
        clk_put(jpeg->clk);
 
        return ret;
@@ -1484,7 +2031,9 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
        v4l2_m2m_release(jpeg->m2m_dev);
        v4l2_device_unregister(&jpeg->v4l2_dev);
 
-       clk_disable_unprepare(jpeg->clk);
+       if (!pm_runtime_status_suspended(&pdev->dev))
+               clk_disable_unprepare(jpeg->clk);
+
        clk_put(jpeg->clk);
 
        return 0;
@@ -1492,41 +2041,119 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
 
 static int s5p_jpeg_runtime_suspend(struct device *dev)
 {
+       struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
+
+       clk_disable_unprepare(jpeg->clk);
+
        return 0;
 }
 
 static int s5p_jpeg_runtime_resume(struct device *dev)
 {
        struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
+       unsigned long flags;
+       int ret;
+
+       ret = clk_prepare_enable(jpeg->clk);
+       if (ret < 0)
+               return ret;
+
+       spin_lock_irqsave(&jpeg->slock, flags);
+
        /*
         * JPEG IP allows storing two Huffman tables for each component
-        * We fill table 0 for each component
+        * We fill table 0 for each component and do this here only
+        * for S5PC210 device as Exynos4x12 requires programming its
+        * Huffman tables each time the encoding process is initialized.
         */
-       jpeg_set_hdctbl(jpeg->regs);
-       jpeg_set_hdctblg(jpeg->regs);
-       jpeg_set_hactbl(jpeg->regs);
-       jpeg_set_hactblg(jpeg->regs);
+       if (jpeg->variant->version == SJPEG_S5P) {
+               s5p_jpeg_set_hdctbl(jpeg->regs);
+               s5p_jpeg_set_hdctblg(jpeg->regs);
+               s5p_jpeg_set_hactbl(jpeg->regs);
+               s5p_jpeg_set_hactblg(jpeg->regs);
+       }
+
+       spin_unlock_irqrestore(&jpeg->slock, flags);
+
        return 0;
 }
 
+static int s5p_jpeg_suspend(struct device *dev)
+{
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       return s5p_jpeg_runtime_suspend(dev);
+}
+
+static int s5p_jpeg_resume(struct device *dev)
+{
+       if (pm_runtime_suspended(dev))
+               return 0;
+
+       return s5p_jpeg_runtime_resume(dev);
+}
+
 static const struct dev_pm_ops s5p_jpeg_pm_ops = {
-       .runtime_suspend = s5p_jpeg_runtime_suspend,
-       .runtime_resume  = s5p_jpeg_runtime_resume,
+       SET_SYSTEM_SLEEP_PM_OPS(s5p_jpeg_suspend, s5p_jpeg_resume)
+       SET_RUNTIME_PM_OPS(s5p_jpeg_runtime_suspend, s5p_jpeg_runtime_resume, NULL)
+};
+
+#ifdef CONFIG_OF
+static struct s5p_jpeg_variant s5p_jpeg_drvdata = {
+       .version        = SJPEG_S5P,
+       .jpeg_irq       = s5p_jpeg_irq,
+};
+
+static struct s5p_jpeg_variant exynos4_jpeg_drvdata = {
+       .version        = SJPEG_EXYNOS4,
+       .jpeg_irq       = exynos4_jpeg_irq,
+};
+
+static const struct of_device_id samsung_jpeg_match[] = {
+       {
+               .compatible = "samsung,s5pv210-jpeg",
+               .data = &s5p_jpeg_drvdata,
+       }, {
+               .compatible = "samsung,exynos4210-jpeg",
+               .data = &s5p_jpeg_drvdata,
+       }, {
+               .compatible = "samsung,exynos4212-jpeg",
+               .data = &exynos4_jpeg_drvdata,
+       },
+       {},
 };
 
+MODULE_DEVICE_TABLE(of, samsung_jpeg_match);
+
+static void *jpeg_get_drv_data(struct platform_device *pdev)
+{
+       struct s5p_jpeg_variant *driver_data = NULL;
+       const struct of_device_id *match;
+
+       match = of_match_node(of_match_ptr(samsung_jpeg_match),
+                                        pdev->dev.of_node);
+       if (match)
+               driver_data = (struct s5p_jpeg_variant *)match->data;
+
+       return driver_data;
+}
+#endif
+
 static struct platform_driver s5p_jpeg_driver = {
        .probe = s5p_jpeg_probe,
        .remove = s5p_jpeg_remove,
        .driver = {
-               .owner = THIS_MODULE,
-               .name = S5P_JPEG_M2M_NAME,
-               .pm = &s5p_jpeg_pm_ops,
+               .of_match_table = of_match_ptr(samsung_jpeg_match),
+               .owner          = THIS_MODULE,
+               .name           = S5P_JPEG_M2M_NAME,
+               .pm             = &s5p_jpeg_pm_ops,
        },
 };
 
 module_platform_driver(s5p_jpeg_driver);
 
 MODULE_AUTHOR("Andrzej Pietrasiewicz <andrzej.p@samsung.com>");
+MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
 MODULE_DESCRIPTION("Samsung JPEG codec driver");
 MODULE_LICENSE("GPL");
-
index 8a4013e3aee7717afb9275f36c92f83fde479b30..f482dbf55d5f5a0124c1618bc9b0c8e3831762fe 100644 (file)
@@ -13,6 +13,7 @@
 #ifndef JPEG_CORE_H_
 #define JPEG_CORE_H_
 
+#include <linux/interrupt.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-fh.h>
 #include <media/v4l2-ctrls.h>
 #define DHP                            0xde
 
 /* Flags that indicate a format can be used for capture/output */
-#define MEM2MEM_CAPTURE                        (1 << 0)
-#define MEM2MEM_OUTPUT                 (1 << 1)
+#define SJPEG_FMT_FLAG_ENC_CAPTURE     (1 << 0)
+#define SJPEG_FMT_FLAG_ENC_OUTPUT      (1 << 1)
+#define SJPEG_FMT_FLAG_DEC_CAPTURE     (1 << 2)
+#define SJPEG_FMT_FLAG_DEC_OUTPUT      (1 << 3)
+#define SJPEG_FMT_FLAG_S5P             (1 << 4)
+#define SJPEG_FMT_FLAG_EXYNOS4         (1 << 5)
+#define SJPEG_FMT_RGB                  (1 << 6)
+#define SJPEG_FMT_NON_RGB              (1 << 7)
+
+#define S5P_JPEG_ENCODE                0
+#define S5P_JPEG_DECODE                1
+
+#define FMT_TYPE_OUTPUT                0
+#define FMT_TYPE_CAPTURE       1
+
+#define SJPEG_SUBSAMPLING_444  0x11
+#define SJPEG_SUBSAMPLING_422  0x21
+#define SJPEG_SUBSAMPLING_420  0x22
+
+/* Version numbers */
+
+#define SJPEG_S5P      1
+#define SJPEG_EXYNOS4  2
+
+enum exynos4_jpeg_result {
+       OK_ENC_OR_DEC,
+       ERR_PROT,
+       ERR_DEC_INVALID_FORMAT,
+       ERR_MULTI_SCAN,
+       ERR_FRAME,
+       ERR_UNKNOWN,
+};
+
+enum  exynos4_jpeg_img_quality_level {
+       QUALITY_LEVEL_1 = 0,    /* high */
+       QUALITY_LEVEL_2,
+       QUALITY_LEVEL_3,
+       QUALITY_LEVEL_4,        /* low */
+};
 
 /**
  * struct s5p_jpeg - JPEG IP abstraction
@@ -71,9 +109,16 @@ struct s5p_jpeg {
 
        void __iomem            *regs;
        unsigned int            irq;
+       enum exynos4_jpeg_result irq_ret;
        struct clk              *clk;
        struct device           *dev;
        void                    *alloc_ctx;
+       struct s5p_jpeg_variant *variant;
+};
+
+struct s5p_jpeg_variant {
+       unsigned int    version;
+       irqreturn_t     (*jpeg_irq)(int irq, void *priv);
 };
 
 /**
@@ -84,16 +129,18 @@ struct s5p_jpeg {
  * @colplanes: number of color planes (1 for packed formats)
  * @h_align:   horizontal alignment order (align to 2^h_align)
  * @v_align:   vertical alignment order (align to 2^v_align)
- * @types:     types of queue this format is applicable to
+ * @flags:     flags describing format applicability
  */
 struct s5p_jpeg_fmt {
        char    *name;
        u32     fourcc;
        int     depth;
        int     colplanes;
+       int     memplanes;
        int     h_align;
        int     v_align;
-       u32     types;
+       int     subsampling;
+       u32     flags;
 };
 
 /**
@@ -115,7 +162,6 @@ struct s5p_jpeg_q_data {
  * @jpeg:              JPEG IP device for this context
  * @mode:              compression (encode) operation or decompression (decode)
  * @compr_quality:     destination image quality in compression (encode) mode
- * @m2m_ctx:           mem2mem device context
  * @out_q:             source (output) queue information
  * @cap_fmt:           destination (capture) queue queue information
  * @hdr_parsed:                set if header has been parsed during decompression
@@ -127,7 +173,6 @@ struct s5p_jpeg_ctx {
        unsigned short          compr_quality;
        unsigned short          restart_interval;
        unsigned short          subsampling;
-       struct v4l2_m2m_ctx     *m2m_ctx;
        struct s5p_jpeg_q_data  out_q;
        struct s5p_jpeg_q_data  cap_q;
        struct v4l2_fh          fh;
@@ -147,4 +192,16 @@ struct s5p_jpeg_buffer {
        unsigned long data;
 };
 
+/**
+ * struct s5p_jpeg_addr - JPEG converter physical address set for DMA
+ * @y:   luminance plane physical address
+ * @cb:  Cb plane physical address
+ * @cr:  Cr plane physical address
+ */
+struct s5p_jpeg_addr {
+       u32     y;
+       u32     cb;
+       u32     cr;
+};
+
 #endif /* JPEG_CORE_H */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.c
new file mode 100644 (file)
index 0000000..da8d6a1
--- /dev/null
@@ -0,0 +1,279 @@
+/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * Register interface file for JPEG driver on Exynos4x12.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#include "jpeg-core.h"
+#include "jpeg-hw-exynos4.h"
+#include "jpeg-regs.h"
+
+void exynos4_jpeg_sw_reset(void __iomem *base)
+{
+       unsigned int reg;
+
+       reg = readl(base + EXYNOS4_JPEG_CNTL_REG);
+       writel(reg & ~EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
+
+       ndelay(100000);
+
+       writel(reg | EXYNOS4_SOFT_RESET_HI, base + EXYNOS4_JPEG_CNTL_REG);
+}
+
+void exynos4_jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode)
+{
+       unsigned int reg;
+
+       reg = readl(base + EXYNOS4_JPEG_CNTL_REG);
+       /* set exynos4_jpeg mod register */
+       if (mode == S5P_JPEG_DECODE) {
+               writel((reg & EXYNOS4_ENC_DEC_MODE_MASK) |
+                                       EXYNOS4_DEC_MODE,
+                       base + EXYNOS4_JPEG_CNTL_REG);
+       } else {/* encode */
+               writel((reg & EXYNOS4_ENC_DEC_MODE_MASK) |
+                                       EXYNOS4_ENC_MODE,
+                       base + EXYNOS4_JPEG_CNTL_REG);
+       }
+}
+
+void exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt)
+{
+       unsigned int reg;
+
+       reg = readl(base + EXYNOS4_IMG_FMT_REG) &
+                       EXYNOS4_ENC_IN_FMT_MASK; /* clear except enc format */
+
+       switch (img_fmt) {
+       case V4L2_PIX_FMT_GREY:
+               reg = reg | EXYNOS4_ENC_GRAY_IMG | EXYNOS4_GRAY_IMG_IP;
+               break;
+       case V4L2_PIX_FMT_RGB32:
+               reg = reg | EXYNOS4_ENC_RGB_IMG |
+                               EXYNOS4_RGB_IP_RGB_32BIT_IMG;
+               break;
+       case V4L2_PIX_FMT_RGB565:
+               reg = reg | EXYNOS4_ENC_RGB_IMG |
+                               EXYNOS4_RGB_IP_RGB_16BIT_IMG;
+               break;
+       case V4L2_PIX_FMT_NV24:
+               reg = reg | EXYNOS4_ENC_YUV_444_IMG |
+                               EXYNOS4_YUV_444_IP_YUV_444_2P_IMG |
+                               EXYNOS4_SWAP_CHROMA_CBCR;
+               break;
+       case V4L2_PIX_FMT_NV42:
+               reg = reg | EXYNOS4_ENC_YUV_444_IMG |
+                               EXYNOS4_YUV_444_IP_YUV_444_2P_IMG |
+                               EXYNOS4_SWAP_CHROMA_CRCB;
+               break;
+       case V4L2_PIX_FMT_YUYV:
+               reg = reg | EXYNOS4_DEC_YUV_422_IMG |
+                               EXYNOS4_YUV_422_IP_YUV_422_1P_IMG |
+                               EXYNOS4_SWAP_CHROMA_CBCR;
+               break;
+
+       case V4L2_PIX_FMT_YVYU:
+               reg = reg | EXYNOS4_DEC_YUV_422_IMG |
+                               EXYNOS4_YUV_422_IP_YUV_422_1P_IMG |
+                               EXYNOS4_SWAP_CHROMA_CRCB;
+               break;
+       case V4L2_PIX_FMT_NV16:
+               reg = reg | EXYNOS4_DEC_YUV_422_IMG |
+                               EXYNOS4_YUV_422_IP_YUV_422_2P_IMG |
+                               EXYNOS4_SWAP_CHROMA_CBCR;
+               break;
+       case V4L2_PIX_FMT_NV61:
+               reg = reg | EXYNOS4_DEC_YUV_422_IMG |
+                               EXYNOS4_YUV_422_IP_YUV_422_2P_IMG |
+                               EXYNOS4_SWAP_CHROMA_CRCB;
+               break;
+       case V4L2_PIX_FMT_NV12:
+               reg = reg | EXYNOS4_DEC_YUV_420_IMG |
+                               EXYNOS4_YUV_420_IP_YUV_420_2P_IMG |
+                               EXYNOS4_SWAP_CHROMA_CBCR;
+               break;
+       case V4L2_PIX_FMT_NV21:
+               reg = reg | EXYNOS4_DEC_YUV_420_IMG |
+                               EXYNOS4_YUV_420_IP_YUV_420_2P_IMG |
+                               EXYNOS4_SWAP_CHROMA_CRCB;
+               break;
+       case V4L2_PIX_FMT_YUV420:
+               reg = reg | EXYNOS4_DEC_YUV_420_IMG |
+                               EXYNOS4_YUV_420_IP_YUV_420_3P_IMG |
+                               EXYNOS4_SWAP_CHROMA_CBCR;
+               break;
+       default:
+               break;
+
+       }
+
+       writel(reg, base + EXYNOS4_IMG_FMT_REG);
+}
+
+void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt)
+{
+       unsigned int reg;
+
+       reg = readl(base + EXYNOS4_IMG_FMT_REG) &
+                       ~EXYNOS4_ENC_FMT_MASK; /* clear enc format */
+
+       switch (out_fmt) {
+       case V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY:
+               reg = reg | EXYNOS4_ENC_FMT_GRAY;
+               break;
+
+       case V4L2_JPEG_CHROMA_SUBSAMPLING_444:
+               reg = reg | EXYNOS4_ENC_FMT_YUV_444;
+               break;
+
+       case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
+               reg = reg | EXYNOS4_ENC_FMT_YUV_422;
+               break;
+
+       case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
+               reg = reg | EXYNOS4_ENC_FMT_YUV_420;
+               break;
+
+       default:
+               break;
+       }
+
+       writel(reg, base + EXYNOS4_IMG_FMT_REG);
+}
+
+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);
+}
+
+unsigned int exynos4_jpeg_get_int_status(void __iomem *base)
+{
+       unsigned int    int_status;
+
+       int_status = readl(base + EXYNOS4_INT_STATUS_REG);
+
+       return int_status;
+}
+
+unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base)
+{
+       unsigned int fifo_status;
+
+       fifo_status = readl(base + EXYNOS4_FIFO_STATUS_REG);
+
+       return fifo_status;
+}
+
+void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value)
+{
+       unsigned int    reg;
+
+       reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~EXYNOS4_HUF_TBL_EN;
+
+       if (value == 1)
+               writel(reg | EXYNOS4_HUF_TBL_EN,
+                                       base + EXYNOS4_JPEG_CNTL_REG);
+       else
+               writel(reg | ~EXYNOS4_HUF_TBL_EN,
+                                       base + EXYNOS4_JPEG_CNTL_REG);
+}
+
+void exynos4_jpeg_set_sys_int_enable(void __iomem *base, int value)
+{
+       unsigned int    reg;
+
+       reg = readl(base + EXYNOS4_JPEG_CNTL_REG) & ~(EXYNOS4_SYS_INT_EN);
+
+       if (value == 1)
+               writel(EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
+       else
+               writel(~EXYNOS4_SYS_INT_EN, base + EXYNOS4_JPEG_CNTL_REG);
+}
+
+void exynos4_jpeg_set_stream_buf_address(void __iomem *base,
+                                        unsigned int address)
+{
+       writel(address, base + EXYNOS4_OUT_MEM_BASE_REG);
+}
+
+void exynos4_jpeg_set_stream_size(void __iomem *base,
+               unsigned int x_value, unsigned int y_value)
+{
+       writel(0x0, base + EXYNOS4_JPEG_IMG_SIZE_REG); /* clear */
+       writel(EXYNOS4_X_SIZE(x_value) | EXYNOS4_Y_SIZE(y_value),
+                       base + EXYNOS4_JPEG_IMG_SIZE_REG);
+}
+
+void exynos4_jpeg_set_frame_buf_address(void __iomem *base,
+                               struct s5p_jpeg_addr *exynos4_jpeg_addr)
+{
+       writel(exynos4_jpeg_addr->y, base + EXYNOS4_IMG_BA_PLANE_1_REG);
+       writel(exynos4_jpeg_addr->cb, base + EXYNOS4_IMG_BA_PLANE_2_REG);
+       writel(exynos4_jpeg_addr->cr, base + EXYNOS4_IMG_BA_PLANE_3_REG);
+}
+
+void exynos4_jpeg_set_encode_tbl_select(void __iomem *base,
+               enum exynos4_jpeg_img_quality_level level)
+{
+       unsigned int    reg;
+
+       reg = EXYNOS4_Q_TBL_COMP1_0 | EXYNOS4_Q_TBL_COMP2_1 |
+               EXYNOS4_Q_TBL_COMP3_1 |
+               EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_1 |
+               EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_0 |
+               EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_1;
+
+       writel(reg, base + EXYNOS4_TBL_SEL_REG);
+}
+
+void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt)
+{
+       if (fmt == V4L2_PIX_FMT_GREY)
+               writel(0xd2, base + EXYNOS4_HUFF_CNT_REG);
+       else
+               writel(0x1a2, base + EXYNOS4_HUFF_CNT_REG);
+}
+
+unsigned int exynos4_jpeg_get_stream_size(void __iomem *base)
+{
+       unsigned int size;
+
+       size = readl(base + EXYNOS4_BITSTREAM_SIZE_REG);
+       return size;
+}
+
+void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size)
+{
+       writel(size, base + EXYNOS4_BITSTREAM_SIZE_REG);
+}
+
+void exynos4_jpeg_get_frame_size(void __iomem *base,
+                       unsigned int *width, unsigned int *height)
+{
+       *width = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) &
+                               EXYNOS4_DECODED_SIZE_MASK);
+       *height = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) >> 16) &
+                               EXYNOS4_DECODED_SIZE_MASK;
+}
+
+unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base)
+{
+       return readl(base + EXYNOS4_DECODE_IMG_FMT_REG) &
+                               EXYNOS4_JPEG_DECODED_IMG_FMT_MASK;
+}
+
+void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size)
+{
+       writel(size, base + EXYNOS4_INT_TIMER_COUNT_REG);
+}
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-exynos4.h
new file mode 100644 (file)
index 0000000..c228d28
--- /dev/null
@@ -0,0 +1,42 @@
+/* Copyright (c) 2013 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com/
+ *
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * Header file of the register interface for JPEG driver on Exynos4x12.
+ *
+ * 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 JPEG_HW_EXYNOS4_H_
+#define JPEG_HW_EXYNOS4_H_
+
+void exynos4_jpeg_sw_reset(void __iomem *base);
+void exynos4_jpeg_set_enc_dec_mode(void __iomem *base, unsigned int mode);
+void exynos4_jpeg_set_img_fmt(void __iomem *base, unsigned int img_fmt);
+void exynos4_jpeg_set_enc_out_fmt(void __iomem *base, unsigned int out_fmt);
+void exynos4_jpeg_set_enc_tbl(void __iomem *base);
+void exynos4_jpeg_set_interrupt(void __iomem *base);
+unsigned int exynos4_jpeg_get_int_status(void __iomem *base);
+void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value);
+void exynos4_jpeg_set_sys_int_enable(void __iomem *base, int value);
+void exynos4_jpeg_set_stream_buf_address(void __iomem *base,
+                                        unsigned int address);
+void exynos4_jpeg_set_stream_size(void __iomem *base,
+               unsigned int x_value, unsigned int y_value);
+void exynos4_jpeg_set_frame_buf_address(void __iomem *base,
+                               struct s5p_jpeg_addr *jpeg_addr);
+void exynos4_jpeg_set_encode_tbl_select(void __iomem *base,
+               enum exynos4_jpeg_img_quality_level level);
+void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt);
+void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size);
+unsigned int exynos4_jpeg_get_stream_size(void __iomem *base);
+void exynos4_jpeg_get_frame_size(void __iomem *base,
+                       unsigned int *width, unsigned int *height);
+unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base);
+unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base);
+void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size);
+
+#endif /* JPEG_HW_EXYNOS4_H_ */
similarity index 70%
rename from drivers/media/platform/s5p-jpeg/jpeg-hw.h
rename to drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.c
index b47e887b61381c8f952a99d04935d571c410e308..52407d7907267e520b81bcc540420f1f2ff34544 100644 (file)
@@ -9,27 +9,15 @@
  * it under the terms of the GNU General Public License version 2 as
  * published by the Free Software Foundation.
  */
-#ifndef JPEG_HW_H_
-#define JPEG_HW_H_
 
 #include <linux/io.h>
 #include <linux/videodev2.h>
 
-#include "jpeg-hw.h"
+#include "jpeg-core.h"
 #include "jpeg-regs.h"
+#include "jpeg-hw-s5p.h"
 
-#define S5P_JPEG_MIN_WIDTH             32
-#define S5P_JPEG_MIN_HEIGHT            32
-#define S5P_JPEG_MAX_WIDTH             8192
-#define S5P_JPEG_MAX_HEIGHT            8192
-#define S5P_JPEG_ENCODE                        0
-#define S5P_JPEG_DECODE                        1
-#define S5P_JPEG_RAW_IN_565            0
-#define S5P_JPEG_RAW_IN_422            1
-#define S5P_JPEG_RAW_OUT_422           0
-#define S5P_JPEG_RAW_OUT_420           1
-
-static inline void jpeg_reset(void __iomem *regs)
+void s5p_jpeg_reset(void __iomem *regs)
 {
        unsigned long reg;
 
@@ -42,12 +30,12 @@ static inline void jpeg_reset(void __iomem *regs)
        }
 }
 
-static inline void jpeg_poweron(void __iomem *regs)
+void s5p_jpeg_poweron(void __iomem *regs)
 {
        writel(S5P_POWER_ON, regs + S5P_JPGCLKCON);
 }
 
-static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
+void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
 {
        unsigned long reg, m;
 
@@ -63,7 +51,7 @@ static inline void jpeg_input_raw_mode(void __iomem *regs, unsigned long mode)
        writel(reg, regs + S5P_JPGCMOD);
 }
 
-static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
+void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16)
 {
        unsigned long reg;
 
@@ -75,7 +63,7 @@ static inline void jpeg_input_raw_y16(void __iomem *regs, bool y16)
        writel(reg, regs + S5P_JPGCMOD);
 }
 
-static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
+void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode)
 {
        unsigned long reg, m;
 
@@ -90,7 +78,7 @@ static inline void jpeg_proc_mode(void __iomem *regs, unsigned long mode)
        writel(reg, regs + S5P_JPGMOD);
 }
 
-static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
+void s5p_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
 {
        unsigned long reg, m;
 
@@ -105,12 +93,12 @@ static inline void jpeg_subsampling_mode(void __iomem *regs, unsigned int mode)
        writel(reg, regs + S5P_JPGMOD);
 }
 
-static inline unsigned int jpeg_get_subsampling_mode(void __iomem *regs)
+unsigned int s5p_jpeg_get_subsampling_mode(void __iomem *regs)
 {
        return readl(regs + S5P_JPGMOD) & S5P_SUBSAMPLING_MODE_MASK;
 }
 
-static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
+void s5p_jpeg_dri(void __iomem *regs, unsigned int dri)
 {
        unsigned long reg;
 
@@ -125,7 +113,7 @@ static inline void jpeg_dri(void __iomem *regs, unsigned int dri)
        writel(reg, regs + S5P_JPGDRI_L);
 }
 
-static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
+void s5p_jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
 {
        unsigned long reg;
 
@@ -135,7 +123,7 @@ static inline void jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n)
        writel(reg, regs + S5P_JPG_QTBL);
 }
 
-static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
+void s5p_jpeg_htbl_ac(void __iomem *regs, unsigned int t)
 {
        unsigned long reg;
 
@@ -146,7 +134,7 @@ static inline void jpeg_htbl_ac(void __iomem *regs, unsigned int t)
        writel(reg, regs + S5P_JPG_HTBL);
 }
 
-static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
+void s5p_jpeg_htbl_dc(void __iomem *regs, unsigned int t)
 {
        unsigned long reg;
 
@@ -157,7 +145,7 @@ static inline void jpeg_htbl_dc(void __iomem *regs, unsigned int t)
        writel(reg, regs + S5P_JPG_HTBL);
 }
 
-static inline void jpeg_y(void __iomem *regs, unsigned int y)
+void s5p_jpeg_y(void __iomem *regs, unsigned int y)
 {
        unsigned long reg;
 
@@ -172,7 +160,7 @@ static inline void jpeg_y(void __iomem *regs, unsigned int y)
        writel(reg, regs + S5P_JPGY_L);
 }
 
-static inline void jpeg_x(void __iomem *regs, unsigned int x)
+void s5p_jpeg_x(void __iomem *regs, unsigned int x)
 {
        unsigned long reg;
 
@@ -187,7 +175,7 @@ static inline void jpeg_x(void __iomem *regs, unsigned int x)
        writel(reg, regs + S5P_JPGX_L);
 }
 
-static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
+void s5p_jpeg_rst_int_enable(void __iomem *regs, bool enable)
 {
        unsigned long reg;
 
@@ -198,7 +186,7 @@ static inline void jpeg_rst_int_enable(void __iomem *regs, bool enable)
        writel(reg, regs + S5P_JPGINTSE);
 }
 
-static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
+void s5p_jpeg_data_num_int_enable(void __iomem *regs, bool enable)
 {
        unsigned long reg;
 
@@ -209,7 +197,7 @@ static inline void jpeg_data_num_int_enable(void __iomem *regs, bool enable)
        writel(reg, regs + S5P_JPGINTSE);
 }
 
-static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
+void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
 {
        unsigned long reg;
 
@@ -220,7 +208,7 @@ static inline void jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl)
        writel(reg, regs + S5P_JPGINTSE);
 }
 
-static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
+void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val)
 {
        unsigned long reg;
 
@@ -231,7 +219,7 @@ static inline void jpeg_timer_enable(void __iomem *regs, unsigned long val)
        writel(reg, regs + S5P_JPG_TIMER_SE);
 }
 
-static inline void jpeg_timer_disable(void __iomem *regs)
+void s5p_jpeg_timer_disable(void __iomem *regs)
 {
        unsigned long reg;
 
@@ -240,13 +228,13 @@ static inline void jpeg_timer_disable(void __iomem *regs)
        writel(reg, regs + S5P_JPG_TIMER_SE);
 }
 
-static inline int jpeg_timer_stat(void __iomem *regs)
+int s5p_jpeg_timer_stat(void __iomem *regs)
 {
        return (int)((readl(regs + S5P_JPG_TIMER_ST) & S5P_TIMER_INT_STAT_MASK)
                     >> S5P_TIMER_INT_STAT_SHIFT);
 }
 
-static inline void jpeg_clear_timer_stat(void __iomem *regs)
+void s5p_jpeg_clear_timer_stat(void __iomem *regs)
 {
        unsigned long reg;
 
@@ -255,7 +243,7 @@ static inline void jpeg_clear_timer_stat(void __iomem *regs)
        writel(reg, regs + S5P_JPG_TIMER_SE);
 }
 
-static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
+void s5p_jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
 {
        unsigned long reg;
 
@@ -266,13 +254,13 @@ static inline void jpeg_enc_stream_int(void __iomem *regs, unsigned long size)
        writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
 }
 
-static inline int jpeg_enc_stream_stat(void __iomem *regs)
+int s5p_jpeg_enc_stream_stat(void __iomem *regs)
 {
        return (int)(readl(regs + S5P_JPG_ENC_STREAM_INTST) &
                     S5P_ENC_STREAM_INT_STAT_MASK);
 }
 
-static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
+void s5p_jpeg_clear_enc_stream_stat(void __iomem *regs)
 {
        unsigned long reg;
 
@@ -281,7 +269,7 @@ static inline void jpeg_clear_enc_stream_stat(void __iomem *regs)
        writel(reg, regs + S5P_JPG_ENC_STREAM_INTSE);
 }
 
-static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
+void s5p_jpeg_outform_raw(void __iomem *regs, unsigned long format)
 {
        unsigned long reg, f;
 
@@ -296,17 +284,17 @@ static inline void jpeg_outform_raw(void __iomem *regs, unsigned long format)
        writel(reg, regs + S5P_JPG_OUTFORM);
 }
 
-static inline void jpeg_jpgadr(void __iomem *regs, unsigned long addr)
+void s5p_jpeg_jpgadr(void __iomem *regs, unsigned long addr)
 {
        writel(addr, regs + S5P_JPG_JPGADR);
 }
 
-static inline void jpeg_imgadr(void __iomem *regs, unsigned long addr)
+void s5p_jpeg_imgadr(void __iomem *regs, unsigned long addr)
 {
        writel(addr, regs + S5P_JPG_IMGADR);
 }
 
-static inline void jpeg_coef(void __iomem *regs, unsigned int i,
+void s5p_jpeg_coef(void __iomem *regs, unsigned int i,
                             unsigned int j, unsigned int coef)
 {
        unsigned long reg;
@@ -317,24 +305,24 @@ static inline void jpeg_coef(void __iomem *regs, unsigned int i,
        writel(reg, regs + S5P_JPG_COEF(i));
 }
 
-static inline void jpeg_start(void __iomem *regs)
+void s5p_jpeg_start(void __iomem *regs)
 {
        writel(1, regs + S5P_JSTART);
 }
 
-static inline int jpeg_result_stat_ok(void __iomem *regs)
+int s5p_jpeg_result_stat_ok(void __iomem *regs)
 {
        return (int)((readl(regs + S5P_JPGINTST) & S5P_RESULT_STAT_MASK)
                     >> S5P_RESULT_STAT_SHIFT);
 }
 
-static inline int jpeg_stream_stat_ok(void __iomem *regs)
+int s5p_jpeg_stream_stat_ok(void __iomem *regs)
 {
        return !(int)((readl(regs + S5P_JPGINTST) & S5P_STREAM_STAT_MASK)
                      >> S5P_STREAM_STAT_SHIFT);
 }
 
-static inline void jpeg_clear_int(void __iomem *regs)
+void s5p_jpeg_clear_int(void __iomem *regs)
 {
        unsigned long reg;
 
@@ -343,7 +331,7 @@ static inline void jpeg_clear_int(void __iomem *regs)
        reg = readl(regs + S5P_JPGOPR);
 }
 
-static inline unsigned int jpeg_compressed_size(void __iomem *regs)
+unsigned int s5p_jpeg_compressed_size(void __iomem *regs)
 {
        unsigned long jpeg_size = 0;
 
@@ -353,5 +341,3 @@ static inline unsigned int jpeg_compressed_size(void __iomem *regs)
 
        return (unsigned int)jpeg_size;
 }
-
-#endif /* JPEG_HW_H_ */
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h b/drivers/media/platform/s5p-jpeg/jpeg-hw-s5p.h
new file mode 100644 (file)
index 0000000..c11ebe8
--- /dev/null
@@ -0,0 +1,63 @@
+/* linux/drivers/media/platform/s5p-jpeg/jpeg-hw.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ *             http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef JPEG_HW_S5P_H_
+#define JPEG_HW_S5P_H_
+
+#include <linux/io.h>
+#include <linux/videodev2.h>
+
+#include "jpeg-regs.h"
+
+#define S5P_JPEG_MIN_WIDTH             32
+#define S5P_JPEG_MIN_HEIGHT            32
+#define S5P_JPEG_MAX_WIDTH             8192
+#define S5P_JPEG_MAX_HEIGHT            8192
+#define S5P_JPEG_RAW_IN_565            0
+#define S5P_JPEG_RAW_IN_422            1
+#define S5P_JPEG_RAW_OUT_422           0
+#define S5P_JPEG_RAW_OUT_420           1
+
+void s5p_jpeg_reset(void __iomem *regs);
+void s5p_jpeg_poweron(void __iomem *regs);
+void s5p_jpeg_input_raw_mode(void __iomem *regs, unsigned long mode);
+void s5p_jpeg_input_raw_y16(void __iomem *regs, bool y16);
+void s5p_jpeg_proc_mode(void __iomem *regs, unsigned long mode);
+void s5p_jpeg_subsampling_mode(void __iomem *regs, unsigned int mode);
+unsigned int s5p_jpeg_get_subsampling_mode(void __iomem *regs);
+void s5p_jpeg_dri(void __iomem *regs, unsigned int dri);
+void s5p_jpeg_qtbl(void __iomem *regs, unsigned int t, unsigned int n);
+void s5p_jpeg_htbl_ac(void __iomem *regs, unsigned int t);
+void s5p_jpeg_htbl_dc(void __iomem *regs, unsigned int t);
+void s5p_jpeg_y(void __iomem *regs, unsigned int y);
+void s5p_jpeg_x(void __iomem *regs, unsigned int x);
+void s5p_jpeg_rst_int_enable(void __iomem *regs, bool enable);
+void s5p_jpeg_data_num_int_enable(void __iomem *regs, bool enable);
+void s5p_jpeg_final_mcu_num_int_enable(void __iomem *regs, bool enbl);
+void s5p_jpeg_timer_enable(void __iomem *regs, unsigned long val);
+void s5p_jpeg_timer_disable(void __iomem *regs);
+int s5p_jpeg_timer_stat(void __iomem *regs);
+void s5p_jpeg_clear_timer_stat(void __iomem *regs);
+void s5p_jpeg_enc_stream_int(void __iomem *regs, unsigned long size);
+int s5p_jpeg_enc_stream_stat(void __iomem *regs);
+void s5p_jpeg_clear_enc_stream_stat(void __iomem *regs);
+void s5p_jpeg_outform_raw(void __iomem *regs, unsigned long format);
+void s5p_jpeg_jpgadr(void __iomem *regs, unsigned long addr);
+void s5p_jpeg_imgadr(void __iomem *regs, unsigned long addr);
+void s5p_jpeg_coef(void __iomem *regs, unsigned int i,
+                            unsigned int j, unsigned int coef);
+void s5p_jpeg_start(void __iomem *regs);
+int s5p_jpeg_result_stat_ok(void __iomem *regs);
+int s5p_jpeg_stream_stat_ok(void __iomem *regs);
+void s5p_jpeg_clear_int(void __iomem *regs);
+unsigned int s5p_jpeg_compressed_size(void __iomem *regs);
+
+#endif /* JPEG_HW_S5P_H_ */
index 38e50815668c23e7616a7b15cb39921962005c3c..33f2c7374cfd955c55f31637697bd7af210d657e 100644 (file)
@@ -2,10 +2,11 @@
  *
  * Register definition file for Samsung JPEG codec driver
  *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2013 Samsung Electronics Co., Ltd.
  *             http://www.samsung.com
  *
  * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -15,6 +16,8 @@
 #ifndef JPEG_REGS_H_
 #define JPEG_REGS_H_
 
+/* Register and bit definitions for S5PC210 */
+
 /* JPEG mode register */
 #define S5P_JPGMOD                     0x00
 #define S5P_PROC_MODE_MASK             (0x1 << 3)
 /* JPEG AC Huffman table register */
 #define S5P_JPG_HACTBLG(n)             (0x8c0 + (n) * 0x400)
 
+
+/* Register and bit definitions for Exynos 4x12 */
+
+/* JPEG Codec Control Registers */
+#define EXYNOS4_JPEG_CNTL_REG          0x00
+#define EXYNOS4_INT_EN_REG             0x04
+#define EXYNOS4_INT_TIMER_COUNT_REG    0x08
+#define EXYNOS4_INT_STATUS_REG         0x0c
+#define EXYNOS4_OUT_MEM_BASE_REG               0x10
+#define EXYNOS4_JPEG_IMG_SIZE_REG      0x14
+#define EXYNOS4_IMG_BA_PLANE_1_REG     0x18
+#define EXYNOS4_IMG_SO_PLANE_1_REG     0x1c
+#define EXYNOS4_IMG_PO_PLANE_1_REG     0x20
+#define EXYNOS4_IMG_BA_PLANE_2_REG     0x24
+#define EXYNOS4_IMG_SO_PLANE_2_REG     0x28
+#define EXYNOS4_IMG_PO_PLANE_2_REG     0x2c
+#define EXYNOS4_IMG_BA_PLANE_3_REG     0x30
+#define EXYNOS4_IMG_SO_PLANE_3_REG     0x34
+#define EXYNOS4_IMG_PO_PLANE_3_REG     0x38
+
+#define EXYNOS4_TBL_SEL_REG            0x3c
+
+#define EXYNOS4_IMG_FMT_REG            0x40
+
+#define EXYNOS4_BITSTREAM_SIZE_REG     0x44
+#define EXYNOS4_PADDING_REG            0x48
+#define EXYNOS4_HUFF_CNT_REG           0x4c
+#define EXYNOS4_FIFO_STATUS_REG        0x50
+#define EXYNOS4_DECODE_XY_SIZE_REG     0x54
+#define EXYNOS4_DECODE_IMG_FMT_REG     0x58
+
+#define EXYNOS4_QUAN_TBL_ENTRY_REG     0x100
+#define EXYNOS4_HUFF_TBL_ENTRY_REG     0x200
+
+
+/****************************************************************/
+/* Bit definition part                                         */
+/****************************************************************/
+
+/* JPEG CNTL Register bit */
+#define EXYNOS4_ENC_DEC_MODE_MASK      (0xfffffffc << 0)
+#define EXYNOS4_DEC_MODE                       (1 << 0)
+#define EXYNOS4_ENC_MODE                       (1 << 1)
+#define EXYNOS4_AUTO_RST_MARKER                (1 << 2)
+#define EXYNOS4_RST_INTERVAL_SHIFT     3
+#define EXYNOS4_RST_INTERVAL(x)                (((x) & 0xffff) \
+                                               << EXYNOS4_RST_INTERVAL_SHIFT)
+#define EXYNOS4_HUF_TBL_EN             (1 << 19)
+#define EXYNOS4_HOR_SCALING_SHIFT      20
+#define EXYNOS4_HOR_SCALING_MASK               (3 << EXYNOS4_HOR_SCALING_SHIFT)
+#define EXYNOS4_HOR_SCALING(x)         (((x) & 0x3) \
+                                               << EXYNOS4_HOR_SCALING_SHIFT)
+#define EXYNOS4_VER_SCALING_SHIFT      22
+#define EXYNOS4_VER_SCALING_MASK               (3 << EXYNOS4_VER_SCALING_SHIFT)
+#define EXYNOS4_VER_SCALING(x)         (((x) & 0x3) \
+                                               << EXYNOS4_VER_SCALING_SHIFT)
+#define EXYNOS4_PADDING                        (1 << 27)
+#define EXYNOS4_SYS_INT_EN             (1 << 28)
+#define EXYNOS4_SOFT_RESET_HI          (1 << 29)
+
+/* JPEG INT Register bit */
+#define EXYNOS4_INT_EN_MASK            (0x1f << 0)
+#define EXYNOS4_PROT_ERR_INT_EN                (1 << 0)
+#define EXYNOS4_IMG_COMPLETION_INT_EN  (1 << 1)
+#define EXYNOS4_DEC_INVALID_FORMAT_EN  (1 << 2)
+#define EXYNOS4_MULTI_SCAN_ERROR_EN    (1 << 3)
+#define EXYNOS4_FRAME_ERR_EN           (1 << 4)
+#define EXYNOS4_INT_EN_ALL             (0x1f << 0)
+
+#define EXYNOS4_MOD_REG_PROC_ENC               (0 << 3)
+#define EXYNOS4_MOD_REG_PROC_DEC               (1 << 3)
+
+#define EXYNOS4_MOD_REG_SUBSAMPLE_444  (0 << 0)
+#define EXYNOS4_MOD_REG_SUBSAMPLE_422  (1 << 0)
+#define EXYNOS4_MOD_REG_SUBSAMPLE_420  (2 << 0)
+#define EXYNOS4_MOD_REG_SUBSAMPLE_GRAY (3 << 0)
+
+
+/* JPEG IMAGE SIZE Register bit */
+#define EXYNOS4_X_SIZE_SHIFT           0
+#define EXYNOS4_X_SIZE_MASK            (0xffff << EXYNOS4_X_SIZE_SHIFT)
+#define EXYNOS4_X_SIZE(x)              (((x) & 0xffff) << EXYNOS4_X_SIZE_SHIFT)
+#define EXYNOS4_Y_SIZE_SHIFT           16
+#define EXYNOS4_Y_SIZE_MASK            (0xffff << EXYNOS4_Y_SIZE_SHIFT)
+#define EXYNOS4_Y_SIZE(x)              (((x) & 0xffff) << EXYNOS4_Y_SIZE_SHIFT)
+
+/* JPEG IMAGE FORMAT Register bit */
+#define EXYNOS4_ENC_IN_FMT_MASK                0xffff0000
+#define EXYNOS4_ENC_GRAY_IMG           (0 << 0)
+#define EXYNOS4_ENC_RGB_IMG            (1 << 0)
+#define EXYNOS4_ENC_YUV_444_IMG                (2 << 0)
+#define EXYNOS4_ENC_YUV_422_IMG                (3 << 0)
+#define EXYNOS4_ENC_YUV_440_IMG                (4 << 0)
+
+#define EXYNOS4_DEC_GRAY_IMG           (0 << 0)
+#define EXYNOS4_DEC_RGB_IMG            (1 << 0)
+#define EXYNOS4_DEC_YUV_444_IMG                (2 << 0)
+#define EXYNOS4_DEC_YUV_422_IMG                (3 << 0)
+#define EXYNOS4_DEC_YUV_420_IMG                (4 << 0)
+
+#define EXYNOS4_GRAY_IMG_IP_SHIFT      3
+#define EXYNOS4_GRAY_IMG_IP_MASK               (7 << EXYNOS4_GRAY_IMG_IP_SHIFT)
+#define EXYNOS4_GRAY_IMG_IP            (4 << EXYNOS4_GRAY_IMG_IP_SHIFT)
+
+#define EXYNOS4_RGB_IP_SHIFT           6
+#define EXYNOS4_RGB_IP_MASK            (7 << EXYNOS4_RGB_IP_SHIFT)
+#define EXYNOS4_RGB_IP_RGB_16BIT_IMG   (4 << EXYNOS4_RGB_IP_SHIFT)
+#define EXYNOS4_RGB_IP_RGB_32BIT_IMG   (5 << EXYNOS4_RGB_IP_SHIFT)
+
+#define EXYNOS4_YUV_444_IP_SHIFT                       9
+#define EXYNOS4_YUV_444_IP_MASK                        (7 << EXYNOS4_YUV_444_IP_SHIFT)
+#define EXYNOS4_YUV_444_IP_YUV_444_2P_IMG      (4 << EXYNOS4_YUV_444_IP_SHIFT)
+#define EXYNOS4_YUV_444_IP_YUV_444_3P_IMG      (5 << EXYNOS4_YUV_444_IP_SHIFT)
+
+#define EXYNOS4_YUV_422_IP_SHIFT                       12
+#define EXYNOS4_YUV_422_IP_MASK                        (7 << EXYNOS4_YUV_422_IP_SHIFT)
+#define EXYNOS4_YUV_422_IP_YUV_422_1P_IMG      (4 << EXYNOS4_YUV_422_IP_SHIFT)
+#define EXYNOS4_YUV_422_IP_YUV_422_2P_IMG      (5 << EXYNOS4_YUV_422_IP_SHIFT)
+#define EXYNOS4_YUV_422_IP_YUV_422_3P_IMG      (6 << EXYNOS4_YUV_422_IP_SHIFT)
+
+#define EXYNOS4_YUV_420_IP_SHIFT                       15
+#define EXYNOS4_YUV_420_IP_MASK                        (7 << EXYNOS4_YUV_420_IP_SHIFT)
+#define EXYNOS4_YUV_420_IP_YUV_420_2P_IMG      (4 << EXYNOS4_YUV_420_IP_SHIFT)
+#define EXYNOS4_YUV_420_IP_YUV_420_3P_IMG      (5 << EXYNOS4_YUV_420_IP_SHIFT)
+
+#define EXYNOS4_ENC_FMT_SHIFT                  24
+#define EXYNOS4_ENC_FMT_MASK                   (3 << EXYNOS4_ENC_FMT_SHIFT)
+#define EXYNOS4_ENC_FMT_GRAY                   (0 << EXYNOS4_ENC_FMT_SHIFT)
+#define EXYNOS4_ENC_FMT_YUV_444                        (1 << EXYNOS4_ENC_FMT_SHIFT)
+#define EXYNOS4_ENC_FMT_YUV_422                        (2 << EXYNOS4_ENC_FMT_SHIFT)
+#define EXYNOS4_ENC_FMT_YUV_420                        (3 << EXYNOS4_ENC_FMT_SHIFT)
+
+#define EXYNOS4_JPEG_DECODED_IMG_FMT_MASK      0x03
+
+#define EXYNOS4_SWAP_CHROMA_CRCB                       (1 << 26)
+#define EXYNOS4_SWAP_CHROMA_CBCR                       (0 << 26)
+
+/* JPEG HUFF count Register bit */
+#define EXYNOS4_HUFF_COUNT_MASK                        0xffff
+
+/* JPEG Decoded_img_x_y_size Register bit */
+#define EXYNOS4_DECODED_SIZE_MASK              0x0000ffff
+
+/* JPEG Decoded image format Register bit */
+#define EXYNOS4_DECODED_IMG_FMT_MASK           0x3
+
+/* JPEG TBL SEL Register bit */
+#define EXYNOS4_Q_TBL_COMP1_0          (0 << 0)
+#define EXYNOS4_Q_TBL_COMP1_1          (1 << 0)
+#define EXYNOS4_Q_TBL_COMP1_2          (2 << 0)
+#define EXYNOS4_Q_TBL_COMP1_3          (3 << 0)
+
+#define EXYNOS4_Q_TBL_COMP2_0          (0 << 2)
+#define EXYNOS4_Q_TBL_COMP2_1          (1 << 2)
+#define EXYNOS4_Q_TBL_COMP2_2          (2 << 2)
+#define EXYNOS4_Q_TBL_COMP2_3          (3 << 2)
+
+#define EXYNOS4_Q_TBL_COMP3_0          (0 << 4)
+#define EXYNOS4_Q_TBL_COMP3_1          (1 << 4)
+#define EXYNOS4_Q_TBL_COMP3_2          (2 << 4)
+#define EXYNOS4_Q_TBL_COMP3_3          (3 << 4)
+
+#define EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_0       (0 << 6)
+#define EXYNOS4_HUFF_TBL_COMP1_AC_0_DC_1       (1 << 6)
+#define EXYNOS4_HUFF_TBL_COMP1_AC_1_DC_0       (2 << 6)
+#define EXYNOS4_HUFF_TBL_COMP1_AC_1_DC_1       (3 << 6)
+
+#define EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_0       (0 << 8)
+#define EXYNOS4_HUFF_TBL_COMP2_AC_0_DC_1       (1 << 8)
+#define EXYNOS4_HUFF_TBL_COMP2_AC_1_DC_0       (2 << 8)
+#define EXYNOS4_HUFF_TBL_COMP2_AC_1_DC_1       (3 << 8)
+
+#define EXYNOS4_HUFF_TBL_COMP3_AC_0_DC_0       (0 << 10)
+#define EXYNOS4_HUFF_TBL_COMP3_AC_0_DC_1       (1 << 10)
+#define EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_0       (2 << 10)
+#define EXYNOS4_HUFF_TBL_COMP3_AC_1_DC_1       (3 << 10)
+
+/* JPEG quantizer table register */
+#define EXYNOS4_QTBL_CONTENT(n)        (0x100 + (n) * 0x40)
+
+/* JPEG DC luminance (code length) Huffman table register */
+#define EXYNOS4_HUFF_TBL_HDCLL 0x200
+
+/* JPEG DC luminance (values) Huffman table register */
+#define EXYNOS4_HUFF_TBL_HDCLV 0x210
+
+/* JPEG DC chrominance (code length) Huffman table register */
+#define EXYNOS4_HUFF_TBL_HDCCL 0x220
+
+/* JPEG DC chrominance (values) Huffman table register */
+#define EXYNOS4_HUFF_TBL_HDCCV 0x230
+
+/* JPEG AC luminance (code length) Huffman table register */
+#define EXYNOS4_HUFF_TBL_HACLL 0x240
+
+/* JPEG AC luminance (values) Huffman table register */
+#define EXYNOS4_HUFF_TBL_HACLV 0x250
+
+/* JPEG AC chrominance (code length) Huffman table register */
+#define EXYNOS4_HUFF_TBL_HACCL 0x300
+
+/* JPEG AC chrominance (values) Huffman table register */
+#define EXYNOS4_HUFF_TBL_HACCV 0x310
+
 #endif /* JPEG_REGS_H_ */
 
index e46067a5785307ac7a1381bd8a8babd8e4ec4fc2..e2aac592d29f6a3be2ec81ade46a89cb7e9727ee 100644 (file)
@@ -177,21 +177,6 @@ unlock:
                mutex_unlock(&dev->mfc_mutex);
 }
 
-static enum s5p_mfc_node_type s5p_mfc_get_node_type(struct file *file)
-{
-       struct video_device *vdev = video_devdata(file);
-
-       if (!vdev) {
-               mfc_err("failed to get video_device");
-               return MFCNODE_INVALID;
-       }
-       if (vdev->index == 0)
-               return MFCNODE_DECODER;
-       else if (vdev->index == 1)
-               return MFCNODE_ENCODER;
-       return MFCNODE_INVALID;
-}
-
 static void s5p_mfc_clear_int_flags(struct s5p_mfc_dev *dev)
 {
        mfc_write(dev, 0, S5P_FIMV_RISC_HOST_INT);
@@ -705,6 +690,7 @@ irq_cleanup_hw:
 /* Open an MFC node */
 static int s5p_mfc_open(struct file *file)
 {
+       struct video_device *vdev = video_devdata(file);
        struct s5p_mfc_dev *dev = video_drvdata(file);
        struct s5p_mfc_ctx *ctx = NULL;
        struct vb2_queue *q;
@@ -742,7 +728,7 @@ static int s5p_mfc_open(struct file *file)
        /* Mark context as idle */
        clear_work_bit_irqsave(ctx);
        dev->ctx[ctx->num] = ctx;
-       if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+       if (vdev == dev->vfd_dec) {
                ctx->type = MFCINST_DECODER;
                ctx->c_ops = get_dec_codec_ops();
                s5p_mfc_dec_init(ctx);
@@ -752,7 +738,7 @@ static int s5p_mfc_open(struct file *file)
                        mfc_err("Failed to setup mfc controls\n");
                        goto err_ctrls_setup;
                }
-       } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+       } else if (vdev == dev->vfd_enc) {
                ctx->type = MFCINST_ENCODER;
                ctx->c_ops = get_enc_codec_ops();
                /* only for encoder */
@@ -797,10 +783,10 @@ static int s5p_mfc_open(struct file *file)
        q = &ctx->vq_dst;
        q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
        q->drv_priv = &ctx->fh;
-       if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+       if (vdev == dev->vfd_dec) {
                q->io_modes = VB2_MMAP;
                q->ops = get_dec_queue_ops();
-       } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+       } else if (vdev == dev->vfd_enc) {
                q->io_modes = VB2_MMAP | VB2_USERPTR;
                q->ops = get_enc_queue_ops();
        } else {
@@ -819,10 +805,10 @@ static int s5p_mfc_open(struct file *file)
        q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
        q->io_modes = VB2_MMAP;
        q->drv_priv = &ctx->fh;
-       if (s5p_mfc_get_node_type(file) == MFCNODE_DECODER) {
+       if (vdev == dev->vfd_dec) {
                q->io_modes = VB2_MMAP;
                q->ops = get_dec_queue_ops();
-       } else if (s5p_mfc_get_node_type(file) == MFCNODE_ENCODER) {
+       } else if (vdev == dev->vfd_enc) {
                q->io_modes = VB2_MMAP | VB2_USERPTR;
                q->ops = get_enc_queue_ops();
        } else {
index 6920b546181ae8368cf36ef2250922fac20412ba..f723f1f2f5784e4501e7b39dcb027c507523cb07 100644 (file)
@@ -114,15 +114,6 @@ enum s5p_mfc_fmt_type {
        MFC_FMT_RAW,
 };
 
-/**
- * enum s5p_mfc_node_type - The type of an MFC device node.
- */
-enum s5p_mfc_node_type {
-       MFCNODE_INVALID = -1,
-       MFCNODE_DECODER = 0,
-       MFCNODE_ENCODER = 1,
-};
-
 /**
  * enum s5p_mfc_inst_type - The type of an MFC instance.
  */
@@ -422,6 +413,11 @@ struct s5p_mfc_vp8_enc_params {
        enum v4l2_vp8_golden_frame_sel golden_frame_sel;
        u8 hier_layer;
        u8 hier_layer_qp[3];
+       u8 rc_min_qp;
+       u8 rc_max_qp;
+       u8 rc_frame_qp;
+       u8 rc_p_frame_qp;
+       u8 profile;
 };
 
 /**
index 4ff3b6cd684274a33f14bbce053657db4237f220..91b6e020ddf3ec05d5255574f71be3b2dc86fc23 100644 (file)
@@ -618,6 +618,46 @@ static struct mfc_control controls[] = {
                .default_value = V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV,
                .menu_skip_mask = 0,
        },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_VPX_MAX_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 127,
+               .step = 1,
+               .default_value = 127,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_VPX_MIN_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 11,
+               .step = 1,
+               .default_value = 0,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 127,
+               .step = 1,
+               .default_value = 10,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 127,
+               .step = 1,
+               .default_value = 10,
+       },
+       {
+               .id = V4L2_CID_MPEG_VIDEO_VPX_PROFILE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .minimum = 0,
+               .maximum = 3,
+               .step = 1,
+               .default_value = 0,
+       },
 };
 
 #define NUM_CTRLS ARRAY_SIZE(controls)
@@ -1557,6 +1597,21 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
        case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
                p->codec.vp8.golden_frame_sel = ctrl->val;
                break;
+       case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP:
+               p->codec.vp8.rc_min_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP:
+               p->codec.vp8.rc_max_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP:
+               p->codec.vp8.rc_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP:
+               p->codec.vp8.rc_p_frame_qp = ctrl->val;
+               break;
+       case V4L2_CID_MPEG_VIDEO_VPX_PROFILE:
+               p->codec.vp8.profile = ctrl->val;
+               break;
        default:
                v4l2_err(&dev->v4l2_dev, "Invalid control, id=%d, val=%d\n",
                                                        ctrl->id, ctrl->val);
@@ -1863,7 +1918,7 @@ static int s5p_mfc_start_streaming(struct vb2_queue *q, unsigned int count)
                if (ctx->src_bufs_cnt < ctx->pb_count) {
                        mfc_err("Need minimum %d OUTPUT buffers\n",
                                        ctx->pb_count);
-                       return -EINVAL;
+                       return -ENOBUFS;
                }
        }
 
index 461358c4a7908fa71a3b360ffb61ef2c78ce8853..f6ff2dbf3a1d5d700ad18ab74f4e89be437baf17 100644 (file)
@@ -1197,10 +1197,8 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
        reg |= ((p->num_b_frame & 0x3) << 16);
        WRITEL(reg, S5P_FIMV_E_GOP_CONFIG_V6);
 
-       /* profile & level */
-       reg = 0;
-       /** profile */
-       reg |= (0x1 << 4);
+       /* profile - 0 ~ 3 */
+       reg = p_vp8->profile & 0x3;
        WRITEL(reg, S5P_FIMV_E_PICTURE_PROFILE_V6);
 
        /* rate control config. */
@@ -1218,6 +1216,26 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx)
                WRITEL(reg, S5P_FIMV_E_RC_FRAME_RATE_V6);
        }
 
+       /* frame QP */
+       reg &= ~(0x7F);
+       reg |= p_vp8->rc_frame_qp & 0x7F;
+       WRITEL(reg, S5P_FIMV_E_RC_CONFIG_V6);
+
+       /* other QPs */
+       WRITEL(0x0, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+       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, S5P_FIMV_E_FIXED_PICTURE_QP_V6);
+       }
+
+       /* max QP */
+       reg = ((p_vp8->rc_max_qp & 0x7F) << 8);
+       /* min QP */
+       reg |= p_vp8->rc_min_qp & 0x7F;
+       WRITEL(reg, S5P_FIMV_E_RC_QP_BOUND_V6);
+
        /* vbv buffer size */
        if (p->frame_skip_mode ==
                        V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT) {
index 51805a5e2beb742d1f3372090085c3a3f0097d86..bc08b5f28e447795b4c7d61526666ca551194e26 100644 (file)
@@ -347,19 +347,41 @@ static int mxr_runtime_resume(struct device *dev)
 {
        struct mxr_device *mdev = to_mdev(dev);
        struct mxr_resources *res = &mdev->res;
+       int ret;
 
        mxr_dbg(mdev, "resume - start\n");
        mutex_lock(&mdev->mutex);
        /* turn clocks on */
-       clk_enable(res->mixer);
-       clk_enable(res->vp);
-       clk_enable(res->sclk_mixer);
+       ret = clk_prepare_enable(res->mixer);
+       if (ret < 0) {
+               dev_err(mdev->dev, "clk_prepare_enable(mixer) failed\n");
+               goto fail;
+       }
+       ret = clk_prepare_enable(res->vp);
+       if (ret < 0) {
+               dev_err(mdev->dev, "clk_prepare_enable(vp) failed\n");
+               goto fail_mixer;
+       }
+       ret = clk_prepare_enable(res->sclk_mixer);
+       if (ret < 0) {
+               dev_err(mdev->dev, "clk_prepare_enable(sclk_mixer) failed\n");
+               goto fail_vp;
+       }
        /* apply default configuration */
        mxr_reg_reset(mdev);
        mxr_dbg(mdev, "resume - finished\n");
 
        mutex_unlock(&mdev->mutex);
        return 0;
+
+fail_vp:
+       clk_disable_unprepare(res->vp);
+fail_mixer:
+       clk_disable_unprepare(res->mixer);
+fail:
+       mutex_unlock(&mdev->mutex);
+       dev_err(mdev->dev, "resume failed\n");
+       return ret;
 }
 
 static int mxr_runtime_suspend(struct device *dev)
@@ -369,9 +391,9 @@ static int mxr_runtime_suspend(struct device *dev)
        mxr_dbg(mdev, "suspend - start\n");
        mutex_lock(&mdev->mutex);
        /* turn clocks off */
-       clk_disable(res->sclk_mixer);
-       clk_disable(res->vp);
-       clk_disable(res->mixer);
+       clk_disable_unprepare(res->sclk_mixer);
+       clk_disable_unprepare(res->vp);
+       clk_disable_unprepare(res->mixer);
        mutex_unlock(&mdev->mutex);
        mxr_dbg(mdev, "suspend - finished\n");
        return 0;
index 81b97db111d8506a1c28df84a86ce4181f6ddccb..c5059ba0d733d9f819a6af1b55f57c47c31fe756 100644 (file)
@@ -948,7 +948,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
 
        if (count == 0) {
                mxr_dbg(mdev, "no output buffers queued\n");
-               return -EINVAL;
+               return -ENOBUFS;
        }
 
        /* block any changes in output configuration */
index 0afa90f0f6abfdfd8aee75981c147608b9c1262e..5a7c3796f22e349de4edf608bd5eb8ffee62d0dd 100644 (file)
@@ -55,6 +55,8 @@ struct sdo_device {
        struct clk *dacphy;
        /** clock for control of VPLL */
        struct clk *fout_vpll;
+       /** vpll rate before sdo stream was on */
+       unsigned long vpll_rate;
        /** regulator for SDO IP power */
        struct regulator *vdac;
        /** regulator for SDO plug detection */
@@ -193,17 +195,33 @@ static int sdo_s_power(struct v4l2_subdev *sd, int on)
 
 static int sdo_streamon(struct sdo_device *sdev)
 {
+       int ret;
+
        /* set proper clock for Timing Generator */
-       clk_set_rate(sdev->fout_vpll, 54000000);
+       sdev->vpll_rate = clk_get_rate(sdev->fout_vpll);
+       ret = clk_set_rate(sdev->fout_vpll, 54000000);
+       if (ret < 0) {
+               dev_err(sdev->dev, "Failed to set vpll rate\n");
+               return ret;
+       }
        dev_info(sdev->dev, "fout_vpll.rate = %lu\n",
        clk_get_rate(sdev->fout_vpll));
        /* enable clock in SDO */
        sdo_write_mask(sdev, SDO_CLKCON, ~0, SDO_TVOUT_CLOCK_ON);
-       clk_enable(sdev->dacphy);
+       ret = clk_prepare_enable(sdev->dacphy);
+       if (ret < 0) {
+               dev_err(sdev->dev, "clk_prepare_enable(dacphy) failed\n");
+               goto fail;
+       }
        /* enable DAC */
        sdo_write_mask(sdev, SDO_DAC, ~0, SDO_POWER_ON_DAC);
        sdo_reg_debug(sdev);
        return 0;
+
+fail:
+       sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
+       clk_set_rate(sdev->fout_vpll, sdev->vpll_rate);
+       return ret;
 }
 
 static int sdo_streamoff(struct sdo_device *sdev)
@@ -211,7 +229,7 @@ static int sdo_streamoff(struct sdo_device *sdev)
        int tries;
 
        sdo_write_mask(sdev, SDO_DAC, 0, SDO_POWER_ON_DAC);
-       clk_disable(sdev->dacphy);
+       clk_disable_unprepare(sdev->dacphy);
        sdo_write_mask(sdev, SDO_CLKCON, 0, SDO_TVOUT_CLOCK_ON);
        for (tries = 100; tries; --tries) {
                if (sdo_read(sdev, SDO_CLKCON) & SDO_TVOUT_CLOCK_READY)
@@ -220,6 +238,7 @@ static int sdo_streamoff(struct sdo_device *sdev)
        }
        if (tries == 0)
                dev_err(sdev->dev, "failed to stop streaming\n");
+       clk_set_rate(sdev->fout_vpll, sdev->vpll_rate);
        return tries ? 0 : -EIO;
 }
 
@@ -254,7 +273,7 @@ static int sdo_runtime_suspend(struct device *dev)
        dev_info(dev, "suspend\n");
        regulator_disable(sdev->vdet);
        regulator_disable(sdev->vdac);
-       clk_disable(sdev->sclk_dac);
+       clk_disable_unprepare(sdev->sclk_dac);
        return 0;
 }
 
@@ -266,7 +285,7 @@ static int sdo_runtime_resume(struct device *dev)
 
        dev_info(dev, "resume\n");
 
-       ret = clk_enable(sdev->sclk_dac);
+       ret = clk_prepare_enable(sdev->sclk_dac);
        if (ret < 0)
                return ret;
 
@@ -299,7 +318,7 @@ static int sdo_runtime_resume(struct device *dev)
 vdac_r_dis:
        regulator_disable(sdev->vdac);
 dac_clk_dis:
-       clk_disable(sdev->sclk_dac);
+       clk_disable_unprepare(sdev->sclk_dac);
        return ret;
 }
 
@@ -405,7 +424,11 @@ static int sdo_probe(struct platform_device *pdev)
        }
 
        /* enable gate for dac clock, because mixer uses it */
-       clk_enable(sdev->dac);
+       ret = clk_prepare_enable(sdev->dac);
+       if (ret < 0) {
+               dev_err(dev, "clk_prepare_enable(dac) failed\n");
+               goto fail_fout_vpll;
+       }
 
        /* configure power management */
        pm_runtime_enable(dev);
@@ -444,7 +467,7 @@ static int sdo_remove(struct platform_device *pdev)
        struct sdo_device *sdev = sd_to_sdev(sd);
 
        pm_runtime_disable(&pdev->dev);
-       clk_disable(sdev->dac);
+       clk_disable_unprepare(sdev->dac);
        clk_put(sdev->fout_vpll);
        clk_put(sdev->dacphy);
        clk_put(sdev->dac);
index 4f30341dc2ab239ed4b736292c1b7ccb6d208b5e..e5f1d4c14f2c0c86007a3febc69ce368d3f4f27c 100644 (file)
@@ -286,7 +286,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq,
        vb->size = vb->height * bytes_per_line;
        if (vb->baddr && vb->bsize < vb->size) {
                /* User buffer too small */
-               dev_warn(vq->dev, "User buffer too small: [%u] @ %lx\n",
+               dev_warn(vq->dev, "User buffer too small: [%zu] @ %lx\n",
                         vb->bsize, vb->baddr);
                return -EINVAL;
        }
@@ -302,9 +302,10 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq,
        }
 
        dev_dbg(vou_dev->v4l2_dev.dev,
-               "%s(): fmt #%d, %u bytes per line, phys 0x%x, type %d, state %d\n",
+               "%s(): fmt #%d, %u bytes per line, phys %pad, type %d, state %d\n",
                __func__, vou_dev->pix_idx, bytes_per_line,
-               videobuf_to_dma_contig(vb), vb->memory, vb->state);
+               ({ dma_addr_t addr = videobuf_to_dma_contig(vb); &addr; }),
+               vb->memory, vb->state);
 
        return 0;
 }
@@ -442,7 +443,7 @@ static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev,
                                      int pix_idx, int w_idx, int h_idx)
 {
        struct sh_vou_fmt *fmt = vou_fmt + pix_idx;
-       unsigned int black_left, black_top, width_max, height_max,
+       unsigned int black_left, black_top, width_max,
                frame_in_height, frame_out_height, frame_out_top;
        struct v4l2_rect *rect = &vou_dev->rect;
        struct v4l2_pix_format *pix = &vou_dev->pix;
@@ -450,10 +451,10 @@ static void sh_vou_configure_geometry(struct sh_vou_device *vou_dev,
 
        if (vou_dev->std & V4L2_STD_525_60) {
                width_max = 858;
-               height_max = 262;
+               /* height_max = 262; */
        } else {
                width_max = 864;
-               height_max = 312;
+               /* height_max = 312; */
        }
 
        frame_in_height = pix->height / 2;
@@ -1052,7 +1053,6 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id)
        static unsigned long j;
        struct videobuf_buffer *vb;
        static int cnt;
-       static int side;
        u32 irq_status = sh_vou_reg_a_read(vou_dev, VOUIR), masked;
        u32 vou_status = sh_vou_reg_a_read(vou_dev, VOUSTR);
 
@@ -1080,7 +1080,7 @@ static irqreturn_t sh_vou_isr(int irq, void *dev_id)
                irq_status, masked, vou_status, cnt);
 
        cnt++;
-       side = vou_status & 0x10000;
+       /* side = vou_status & 0x10000; */
 
        /* Clear only set interrupts */
        sh_vou_reg_a_write(vou_dev, VOUIR, masked);
index 1044856325017b61f8c7e29312d7ef0083d2c0bb..4835173d7f80fd651848a9feca1f779face352d3 100644 (file)
 #define MIN_FRAME_RATE                 15
 #define FRAME_INTERVAL_MILLI_SEC       (1000 / MIN_FRAME_RATE)
 
-/* ISI states */
-enum {
-       ISI_STATE_IDLE = 0,
-       ISI_STATE_READY,
-       ISI_STATE_WAIT_SOF,
-};
-
 /* Frame buffer descriptor */
 struct fbd {
        /* Physical address of the frame buffer */
@@ -75,11 +68,6 @@ struct atmel_isi {
        void __iomem                    *regs;
 
        int                             sequence;
-       /* State of the ISI module in capturing mode */
-       int                             state;
-
-       /* Wait queue for waiting for SOF */
-       wait_queue_head_t               vsync_wq;
 
        struct vb2_alloc_ctx            *alloc_ctx;
 
@@ -124,16 +112,16 @@ static int configure_geometry(struct atmel_isi *isi, u32 width,
        case V4L2_MBUS_FMT_Y8_1X8:
                cr = ISI_CFG2_GRAYSCALE;
                break;
-       case V4L2_MBUS_FMT_UYVY8_2X8:
+       case V4L2_MBUS_FMT_VYUY8_2X8:
                cr = ISI_CFG2_YCC_SWAP_MODE_3;
                break;
-       case V4L2_MBUS_FMT_VYUY8_2X8:
+       case V4L2_MBUS_FMT_UYVY8_2X8:
                cr = ISI_CFG2_YCC_SWAP_MODE_2;
                break;
-       case V4L2_MBUS_FMT_YUYV8_2X8:
+       case V4L2_MBUS_FMT_YVYU8_2X8:
                cr = ISI_CFG2_YCC_SWAP_MODE_1;
                break;
-       case V4L2_MBUS_FMT_YVYU8_2X8:
+       case V4L2_MBUS_FMT_YUYV8_2X8:
                cr = ISI_CFG2_YCC_SWAP_DEFAULT;
                break;
        /* RGB, TODO */
@@ -144,6 +132,8 @@ static int configure_geometry(struct atmel_isi *isi, u32 width,
        isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
 
        cfg2 = isi_readl(isi, ISI_CFG2);
+       /* Set YCC swap mode */
+       cfg2 &= ~ISI_CFG2_YCC_SWAP_MODE_MASK;
        cfg2 |= cr;
        /* Set width */
        cfg2 &= ~(ISI_CFG2_IM_HSIZE_MASK);
@@ -207,12 +197,6 @@ static irqreturn_t isi_interrupt(int irq, void *dev_id)
                isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS);
                ret = IRQ_HANDLED;
        } else {
-               if ((pending & ISI_SR_VSYNC) &&
-                               (isi->state == ISI_STATE_IDLE)) {
-                       isi->state = ISI_STATE_READY;
-                       wake_up_interruptible(&isi->vsync_wq);
-                       ret = IRQ_HANDLED;
-               }
                if (likely(pending & ISI_SR_CXFR_DONE))
                        ret = atmel_isi_handle_streaming(isi);
        }
@@ -259,16 +243,6 @@ static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
        struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
        struct atmel_isi *isi = ici->priv;
        unsigned long size;
-       int ret;
-
-       /* Reset ISI */
-       ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET);
-       if (ret < 0) {
-               dev_err(icd->parent, "Reset ISI timed out\n");
-               return ret;
-       }
-       /* Disable all interrupts */
-       isi_writel(isi, ISI_INTDIS, ~0UL);
 
        size = icd->sizeimage;
 
@@ -374,6 +348,7 @@ static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
        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);
 
+       cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK;
        /* Enable linked list */
        cfg1 |= isi->pdata->frate | ISI_CFG1_DISCR;
 
@@ -407,43 +382,27 @@ 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;
 
-       spin_lock_irq(&isi->lock);
-       isi->state = ISI_STATE_IDLE;
-       /* Clear any pending SOF interrupt */
-       sr = isi_readl(isi, ISI_STATUS);
-       /* Enable VSYNC interrupt for SOF */
-       isi_writel(isi, ISI_INTEN, ISI_SR_VSYNC);
-       isi_writel(isi, ISI_CTRL, ISI_CTRL_EN);
-       spin_unlock_irq(&isi->lock);
-
-       dev_dbg(icd->parent, "Waiting for SOF\n");
-       ret = wait_event_interruptible(isi->vsync_wq,
-                                      isi->state != ISI_STATE_IDLE);
-       if (ret)
-               goto err;
-
-       if (isi->state != ISI_STATE_READY) {
-               ret = -EIO;
-               goto err;
+       /* Reset ISI */
+       ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET);
+       if (ret < 0) {
+               dev_err(icd->parent, "Reset ISI timed out\n");
+               return ret;
        }
+       /* Disable all interrupts */
+       isi_writel(isi, ISI_INTDIS, ~0UL);
 
        spin_lock_irq(&isi->lock);
-       isi->state = ISI_STATE_WAIT_SOF;
-       isi_writel(isi, ISI_INTDIS, ISI_SR_VSYNC);
+       /* Clear any pending interrupt */
+       sr = isi_readl(isi, ISI_STATUS);
+
        if (count)
                start_dma(isi, isi->active);
        spin_unlock_irq(&isi->lock);
 
        return 0;
-err:
-       isi->active = NULL;
-       isi->sequence = 0;
-       INIT_LIST_HEAD(&isi->video_buffer_list);
-       return ret;
 }
 
 /* abort streaming and wait for last buffer */
@@ -765,14 +724,16 @@ static int isi_camera_clock_start(struct soc_camera_host *ici)
        struct atmel_isi *isi = ici->priv;
        int ret;
 
-       ret = clk_enable(isi->pclk);
+       ret = clk_prepare_enable(isi->pclk);
        if (ret)
                return ret;
 
-       ret = clk_enable(isi->mck);
-       if (ret) {
-               clk_disable(isi->pclk);
-               return ret;
+       if (!IS_ERR(isi->mck)) {
+               ret = clk_prepare_enable(isi->mck);
+               if (ret) {
+                       clk_disable_unprepare(isi->pclk);
+                       return ret;
+               }
        }
 
        return 0;
@@ -783,8 +744,9 @@ static void isi_camera_clock_stop(struct soc_camera_host *ici)
 {
        struct atmel_isi *isi = ici->priv;
 
-       clk_disable(isi->mck);
-       clk_disable(isi->pclk);
+       if (!IS_ERR(isi->mck))
+               clk_disable_unprepare(isi->mck);
+       clk_disable_unprepare(isi->pclk);
 }
 
 static unsigned int isi_camera_poll(struct file *file, poll_table *pt)
@@ -906,7 +868,6 @@ static int atmel_isi_remove(struct platform_device *pdev)
        struct atmel_isi *isi = container_of(soc_host,
                                        struct atmel_isi, soc_host);
 
-       free_irq(isi->irq, isi);
        soc_camera_host_unregister(soc_host);
        vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
        dma_free_coherent(&pdev->dev,
@@ -914,13 +875,6 @@ static int atmel_isi_remove(struct platform_device *pdev)
                        isi->p_fb_descriptors,
                        isi->fb_descriptors_phys);
 
-       iounmap(isi->regs);
-       clk_unprepare(isi->mck);
-       clk_put(isi->mck);
-       clk_unprepare(isi->pclk);
-       clk_put(isi->pclk);
-       kfree(isi);
-
        return 0;
 }
 
@@ -928,7 +882,6 @@ static int atmel_isi_probe(struct platform_device *pdev)
 {
        unsigned int irq;
        struct atmel_isi *isi;
-       struct clk *pclk;
        struct resource *regs;
        int ret, i;
        struct device *dev = &pdev->dev;
@@ -936,64 +889,50 @@ static int atmel_isi_probe(struct platform_device *pdev)
        struct isi_platform_data *pdata;
 
        pdata = dev->platform_data;
-       if (!pdata || !pdata->data_width_flags || !pdata->mck_hz) {
+       if (!pdata || !pdata->data_width_flags) {
                dev_err(&pdev->dev,
                        "No config available for Atmel ISI\n");
                return -EINVAL;
        }
 
-       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!regs)
-               return -ENXIO;
-
-       pclk = clk_get(&pdev->dev, "isi_clk");
-       if (IS_ERR(pclk))
-               return PTR_ERR(pclk);
-
-       ret = clk_prepare(pclk);
-       if (ret)
-               goto err_clk_prepare_pclk;
-
-       isi = kzalloc(sizeof(struct atmel_isi), GFP_KERNEL);
+       isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL);
        if (!isi) {
-               ret = -ENOMEM;
                dev_err(&pdev->dev, "Can't allocate interface!\n");
-               goto err_alloc_isi;
+               return -ENOMEM;
        }
 
-       isi->pclk = pclk;
+       isi->pclk = devm_clk_get(&pdev->dev, "isi_clk");
+       if (IS_ERR(isi->pclk))
+               return PTR_ERR(isi->pclk);
+
        isi->pdata = pdata;
        isi->active = NULL;
        spin_lock_init(&isi->lock);
-       init_waitqueue_head(&isi->vsync_wq);
        INIT_LIST_HEAD(&isi->video_buffer_list);
        INIT_LIST_HEAD(&isi->dma_desc_head);
 
-       /* Get ISI_MCK, provided by programmable clock or external clock */
-       isi->mck = clk_get(dev, "isi_mck");
-       if (IS_ERR(isi->mck)) {
-               dev_err(dev, "Failed to get isi_mck\n");
-               ret = PTR_ERR(isi->mck);
-               goto err_clk_get;
+       /* ISI_MCK is the sensor master clock. It should be handled by the
+        * sensor driver directly, as the ISI has no use for that clock. Make
+        * the clock optional here while platforms transition to the correct
+        * model.
+        */
+       isi->mck = devm_clk_get(dev, "isi_mck");
+       if (!IS_ERR(isi->mck)) {
+               /* Set ISI_MCK's frequency, it should be faster than pixel
+                * clock.
+                */
+               ret = clk_set_rate(isi->mck, pdata->mck_hz);
+               if (ret < 0)
+                       return ret;
        }
 
-       ret = clk_prepare(isi->mck);
-       if (ret)
-               goto err_clk_prepare_mck;
-
-       /* Set ISI_MCK's frequency, it should be faster than pixel clock */
-       ret = clk_set_rate(isi->mck, pdata->mck_hz);
-       if (ret < 0)
-               goto err_set_mck_rate;
-
        isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev,
                                sizeof(struct fbd) * MAX_BUFFER_NUM,
                                &isi->fb_descriptors_phys,
                                GFP_KERNEL);
        if (!isi->p_fb_descriptors) {
-               ret = -ENOMEM;
                dev_err(&pdev->dev, "Can't allocate descriptors!\n");
-               goto err_alloc_descriptors;
+               return -ENOMEM;
        }
 
        for (i = 0; i < MAX_BUFFER_NUM; i++) {
@@ -1009,9 +948,10 @@ static int atmel_isi_probe(struct platform_device *pdev)
                goto err_alloc_ctx;
        }
 
-       isi->regs = ioremap(regs->start, resource_size(regs));
-       if (!isi->regs) {
-               ret = -ENOMEM;
+       regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       isi->regs = devm_ioremap_resource(&pdev->dev, regs);
+       if (IS_ERR(isi->regs)) {
+               ret = PTR_ERR(isi->regs);
                goto err_ioremap;
        }
 
@@ -1028,7 +968,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
                goto err_req_irq;
        }
 
-       ret = request_irq(irq, isi_interrupt, 0, "isi", isi);
+       ret = devm_request_irq(&pdev->dev, irq, isi_interrupt, 0, "isi", isi);
        if (ret) {
                dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
                goto err_req_irq;
@@ -1050,9 +990,7 @@ static int atmel_isi_probe(struct platform_device *pdev)
        return 0;
 
 err_register_soc_camera_host:
-       free_irq(isi->irq, isi);
 err_req_irq:
-       iounmap(isi->regs);
 err_ioremap:
        vb2_dma_contig_cleanup_ctx(isi->alloc_ctx);
 err_alloc_ctx:
@@ -1060,17 +998,6 @@ err_alloc_ctx:
                        sizeof(struct fbd) * MAX_BUFFER_NUM,
                        isi->p_fb_descriptors,
                        isi->fb_descriptors_phys);
-err_alloc_descriptors:
-err_set_mck_rate:
-       clk_unprepare(isi->mck);
-err_clk_prepare_mck:
-       clk_put(isi->mck);
-err_clk_get:
-       kfree(isi);
-err_alloc_isi:
-       clk_unprepare(pclk);
-err_clk_prepare_pclk:
-       clk_put(pclk);
 
        return ret;
 }
index 45a0276be4e599f15d2fef8f05a67b6e2655e184..d73abca9c6eeda21028dbddcab4410492ec28ae4 100644 (file)
@@ -659,7 +659,7 @@ static int mx2_start_streaming(struct vb2_queue *q, unsigned int count)
        unsigned long flags;
 
        if (count < 2)
-               return -EINVAL;
+               return -ENOBUFS;
 
        spin_lock_irqsave(&pcdev->lock, flags);
 
index 6866bb4fbebc0d553fc27fdb3f72e8d2f6791f9c..3b1c05a72d00cf16ab7a5f070aa09da12b35d00a 100644 (file)
 #define VIN_MAX_HEIGHT         2048
 
 enum chip_id {
-       RCAR_H2,
+       RCAR_GEN2,
        RCAR_H1,
        RCAR_M1,
        RCAR_E1,
@@ -302,7 +302,7 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
                dmr = 0;
                break;
        case V4L2_PIX_FMT_RGB32:
-               if (priv->chip == RCAR_H2 || priv->chip == RCAR_H1 ||
+               if (priv->chip == RCAR_GEN2 || priv->chip == RCAR_H1 ||
                    priv->chip == RCAR_E1) {
                        dmr = VNDMR_EXRGB;
                        break;
@@ -1384,7 +1384,8 @@ static struct soc_camera_host_ops rcar_vin_host_ops = {
 };
 
 static struct platform_device_id rcar_vin_id_table[] = {
-       { "r8a7790-vin",  RCAR_H2 },
+       { "r8a7791-vin",  RCAR_GEN2 },
+       { "r8a7790-vin",  RCAR_GEN2 },
        { "r8a7779-vin",  RCAR_H1 },
        { "r8a7778-vin",  RCAR_M1 },
        { "uPD35004-vin", RCAR_E1 },
index cbd3a34f4f3f60ab37aca08abd275a6ceba18e26..8e74fb7f2a078f2b81396b0dfb4d2c4c281ef801 100644 (file)
@@ -141,8 +141,8 @@ int soc_camera_client_s_crop(struct v4l2_subdev *sd,
         * Popular special case - some cameras can only handle fixed sizes like
         * QVGA, VGA,... Take care to avoid infinite loop.
         */
-       width = max(cam_rect->width, 2);
-       height = max(cam_rect->height, 2);
+       width = max_t(unsigned int, cam_rect->width, 2);
+       height = max_t(unsigned int, cam_rect->height, 2);
 
        /*
         * Loop as long as sensor is not covering the requested rectangle and
index cbf0a806ba1d77e85afe97fd28a5b5049d149186..be680f839e77c9f3d7ab0e7366762093a35e88fe 100644 (file)
@@ -1,5 +1,5 @@
 obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe.o
 
-ti-vpe-y := vpe.o vpdma.o
+ti-vpe-y := vpe.o sc.o csc.o vpdma.o
 
 ccflags-$(CONFIG_VIDEO_TI_VPE_DEBUG) += -DDEBUG
diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c
new file mode 100644 (file)
index 0000000..acfea50
--- /dev/null
@@ -0,0 +1,196 @@
+/*
+ * Color space converter library
+ *
+ * Copyright (c) 2013 Texas Instruments Inc.
+ *
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include "csc.h"
+
+/*
+ * 16 coefficients in the order:
+ * a0, b0, c0, a1, b1, c1, a2, b2, c2, d0, d1, d2
+ * (we may need to pass non-default values from user space later on, we might
+ * need to make the coefficient struct more easy to populate)
+ */
+struct colorspace_coeffs {
+       u16     sd[12];
+       u16     hd[12];
+};
+
+/* VIDEO_RANGE: limited range, GRAPHICS_RANGE: full range */
+#define        CSC_COEFFS_VIDEO_RANGE_Y2R      0
+#define        CSC_COEFFS_GRAPHICS_RANGE_Y2R   1
+#define        CSC_COEFFS_VIDEO_RANGE_R2Y      2
+#define        CSC_COEFFS_GRAPHICS_RANGE_R2Y   3
+
+/* default colorspace coefficients */
+static struct colorspace_coeffs colorspace_coeffs[4] = {
+       [CSC_COEFFS_VIDEO_RANGE_Y2R] = {
+               {
+                       /* SDTV */
+                       0x0400, 0x0000, 0x057D, 0x0400, 0x1EA7, 0x1D35,
+                       0x0400, 0x06EF, 0x1FFE, 0x0D40, 0x0210, 0x0C88,
+               },
+               {
+                       /* HDTV */
+                       0x0400, 0x0000, 0x0629, 0x0400, 0x1F45, 0x1E2B,
+                       0x0400, 0x0742, 0x0000, 0x0CEC, 0x0148, 0x0C60,
+               },
+       },
+       [CSC_COEFFS_GRAPHICS_RANGE_Y2R] = {
+               {
+                       /* SDTV */
+                       0x04A8, 0x1FFE, 0x0662, 0x04A8, 0x1E6F, 0x1CBF,
+                       0x04A8, 0x0812, 0x1FFF, 0x0C84, 0x0220, 0x0BAC,
+               },
+               {
+                       /* HDTV */
+                       0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE,
+                       0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C,
+               },
+       },
+       [CSC_COEFFS_VIDEO_RANGE_R2Y] = {
+               {
+                       /* SDTV */
+                       0x0132, 0x0259, 0x0075, 0x1F50, 0x1EA5, 0x020B,
+                       0x020B, 0x1E4A, 0x1FAB, 0x0000, 0x0200, 0x0200,
+               },
+               {
+                       /* HDTV */
+                       0x00DA, 0x02DC, 0x004A, 0x1F88, 0x1E6C, 0x020C,
+                       0x020C, 0x1E24, 0x1FD0, 0x0000, 0x0200, 0x0200,
+               },
+       },
+       [CSC_COEFFS_GRAPHICS_RANGE_R2Y] = {
+               {
+                       /* SDTV */
+                       0x0107, 0x0204, 0x0064, 0x1F68, 0x1ED6, 0x01C2,
+                       0x01C2, 0x1E87, 0x1FB7, 0x0040, 0x0200, 0x0200,
+               },
+               {
+                       /* HDTV */
+                       0x04A8, 0x0000, 0x072C, 0x04A8, 0x1F26, 0x1DDE,
+                       0x04A8, 0x0873, 0x0000, 0x0C20, 0x0134, 0x0B7C,
+               },
+       },
+};
+
+void csc_dump_regs(struct csc_data *csc)
+{
+       struct device *dev = &csc->pdev->dev;
+
+       u32 read_reg(struct csc_data *csc, int offset)
+       {
+               return ioread32(csc->base + offset);
+       }
+
+#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(csc, CSC_##r))
+
+       DUMPREG(CSC00);
+       DUMPREG(CSC01);
+       DUMPREG(CSC02);
+       DUMPREG(CSC03);
+       DUMPREG(CSC04);
+       DUMPREG(CSC05);
+
+#undef DUMPREG
+}
+
+void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5)
+{
+       *csc_reg5 |= CSC_BYPASS;
+}
+
+/*
+ * set the color space converter coefficient shadow register values
+ */
+void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0,
+               enum v4l2_colorspace src_colorspace,
+               enum v4l2_colorspace dst_colorspace)
+{
+       u32 *csc_reg5 = csc_reg0 + 5;
+       u32 *shadow_csc = csc_reg0;
+       struct colorspace_coeffs *sd_hd_coeffs;
+       u16 *coeff, *end_coeff;
+       enum v4l2_colorspace yuv_colorspace;
+       int sel = 0;
+
+       /*
+        * support only graphics data range(full range) for now, a control ioctl
+        * would be nice here
+        */
+       /* Y2R */
+       if (dst_colorspace == V4L2_COLORSPACE_SRGB &&
+                       (src_colorspace == V4L2_COLORSPACE_SMPTE170M ||
+                       src_colorspace == V4L2_COLORSPACE_REC709)) {
+               /* Y2R */
+               sel = 1;
+               yuv_colorspace = src_colorspace;
+       } else if ((dst_colorspace == V4L2_COLORSPACE_SMPTE170M ||
+                       dst_colorspace == V4L2_COLORSPACE_REC709) &&
+                       src_colorspace == V4L2_COLORSPACE_SRGB) {
+               /* R2Y */
+               sel = 3;
+               yuv_colorspace = dst_colorspace;
+       } else {
+               *csc_reg5 |= CSC_BYPASS;
+               return;
+       }
+
+       sd_hd_coeffs = &colorspace_coeffs[sel];
+
+       /* select between SD or HD coefficients */
+       if (yuv_colorspace == V4L2_COLORSPACE_SMPTE170M)
+               coeff = sd_hd_coeffs->sd;
+       else
+               coeff = sd_hd_coeffs->hd;
+
+       end_coeff = coeff + 12;
+
+       for (; coeff < end_coeff; coeff += 2)
+               *shadow_csc++ = (*(coeff + 1) << 16) | *coeff;
+}
+
+struct csc_data *csc_create(struct platform_device *pdev)
+{
+       struct csc_data *csc;
+
+       dev_dbg(&pdev->dev, "csc_create\n");
+
+       csc = devm_kzalloc(&pdev->dev, sizeof(*csc), GFP_KERNEL);
+       if (!csc) {
+               dev_err(&pdev->dev, "couldn't alloc csc_data\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       csc->pdev = pdev;
+
+       csc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                       "vpe_csc");
+       if (csc->res == NULL) {
+               dev_err(&pdev->dev, "missing platform resources data\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       csc->base = devm_ioremap_resource(&pdev->dev, csc->res);
+       if (!csc->base) {
+               dev_err(&pdev->dev, "failed to ioremap\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return csc;
+}
diff --git a/drivers/media/platform/ti-vpe/csc.h b/drivers/media/platform/ti-vpe/csc.h
new file mode 100644 (file)
index 0000000..1ad2b6d
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2013 Texas Instruments Inc.
+ *
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#ifndef TI_CSC_H
+#define TI_CSC_H
+
+/* VPE color space converter regs */
+#define CSC_CSC00              0x00
+#define CSC_A0_MASK            0x1fff
+#define CSC_A0_SHIFT           0
+#define CSC_B0_MASK            0x1fff
+#define CSC_B0_SHIFT           16
+
+#define CSC_CSC01              0x04
+#define CSC_C0_MASK            0x1fff
+#define CSC_C0_SHIFT           0
+#define CSC_A1_MASK            0x1fff
+#define CSC_A1_SHIFT           16
+
+#define CSC_CSC02              0x08
+#define CSC_B1_MASK            0x1fff
+#define CSC_B1_SHIFT           0
+#define CSC_C1_MASK            0x1fff
+#define CSC_C1_SHIFT           16
+
+#define CSC_CSC03              0x0c
+#define CSC_A2_MASK            0x1fff
+#define CSC_A2_SHIFT           0
+#define CSC_B2_MASK            0x1fff
+#define CSC_B2_SHIFT           16
+
+#define CSC_CSC04              0x10
+#define CSC_C2_MASK            0x1fff
+#define CSC_C2_SHIFT           0
+#define CSC_D0_MASK            0x0fff
+#define CSC_D0_SHIFT           16
+
+#define CSC_CSC05              0x14
+#define CSC_D1_MASK            0x0fff
+#define CSC_D1_SHIFT           0
+#define CSC_D2_MASK            0x0fff
+#define CSC_D2_SHIFT           16
+
+#define CSC_BYPASS             (1 << 28)
+
+struct csc_data {
+       void __iomem            *base;
+       struct resource         *res;
+
+       struct platform_device  *pdev;
+};
+
+void csc_dump_regs(struct csc_data *csc);
+void csc_set_coeff_bypass(struct csc_data *csc, u32 *csc_reg5);
+void csc_set_coeff(struct csc_data *csc, u32 *csc_reg0,
+               enum v4l2_colorspace src_colorspace,
+               enum v4l2_colorspace dst_colorspace);
+struct csc_data *csc_create(struct platform_device *pdev);
+
+#endif
diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c
new file mode 100644 (file)
index 0000000..93f0af5
--- /dev/null
@@ -0,0 +1,311 @@
+/*
+ * Scaler library
+ *
+ * Copyright (c) 2013 Texas Instruments Inc.
+ *
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "sc.h"
+#include "sc_coeff.h"
+
+void sc_dump_regs(struct sc_data *sc)
+{
+       struct device *dev = &sc->pdev->dev;
+
+       u32 read_reg(struct sc_data *sc, int offset)
+       {
+               return ioread32(sc->base + offset);
+       }
+
+#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(sc, CFG_##r))
+
+       DUMPREG(SC0);
+       DUMPREG(SC1);
+       DUMPREG(SC2);
+       DUMPREG(SC3);
+       DUMPREG(SC4);
+       DUMPREG(SC5);
+       DUMPREG(SC6);
+       DUMPREG(SC8);
+       DUMPREG(SC9);
+       DUMPREG(SC10);
+       DUMPREG(SC11);
+       DUMPREG(SC12);
+       DUMPREG(SC13);
+       DUMPREG(SC17);
+       DUMPREG(SC18);
+       DUMPREG(SC19);
+       DUMPREG(SC20);
+       DUMPREG(SC21);
+       DUMPREG(SC22);
+       DUMPREG(SC23);
+       DUMPREG(SC24);
+       DUMPREG(SC25);
+
+#undef DUMPREG
+}
+
+/*
+ * set the horizontal scaler coefficients according to the ratio of output to
+ * input widths, after accounting for up to two levels of decimation
+ */
+void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w,
+               unsigned int dst_w)
+{
+       int sixteenths;
+       int idx;
+       int i, j;
+       u16 *coeff_h = addr;
+       const u16 *cp;
+
+       if (dst_w > src_w) {
+               idx = HS_UP_SCALE;
+       } else {
+               if ((dst_w << 1) < src_w)
+                       dst_w <<= 1;    /* first level decimation */
+               if ((dst_w << 1) < src_w)
+                       dst_w <<= 1;    /* second level decimation */
+
+               if (dst_w == src_w) {
+                       idx = HS_LE_16_16_SCALE;
+               } else {
+                       sixteenths = (dst_w << 4) / src_w;
+                       if (sixteenths < 8)
+                               sixteenths = 8;
+                       idx = HS_LT_9_16_SCALE + sixteenths - 8;
+               }
+       }
+
+       if (idx == sc->hs_index)
+               return;
+
+       cp = scaler_hs_coeffs[idx];
+
+       for (i = 0; i < SC_NUM_PHASES * 2; i++) {
+               for (j = 0; j < SC_H_NUM_TAPS; j++)
+                       *coeff_h++ = *cp++;
+               /*
+                * for each phase, the scaler expects space for 8 coefficients
+                * in it's memory. For the horizontal scaler, we copy the first
+                * 7 coefficients and skip the last slot to move to the next
+                * row to hold coefficients for the next phase
+                */
+               coeff_h += SC_NUM_TAPS_MEM_ALIGN - SC_H_NUM_TAPS;
+       }
+
+       sc->hs_index = idx;
+
+       sc->load_coeff_h = true;
+}
+
+/*
+ * set the vertical scaler coefficients according to the ratio of output to
+ * input heights
+ */
+void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h,
+               unsigned int dst_h)
+{
+       int sixteenths;
+       int idx;
+       int i, j;
+       u16 *coeff_v = addr;
+       const u16 *cp;
+
+       if (dst_h > src_h) {
+               idx = VS_UP_SCALE;
+       } else if (dst_h == src_h) {
+               idx = VS_1_TO_1_SCALE;
+       } else {
+               sixteenths = (dst_h << 4) / src_h;
+               if (sixteenths < 8)
+                       sixteenths = 8;
+               idx = VS_LT_9_16_SCALE + sixteenths - 8;
+       }
+
+       if (idx == sc->vs_index)
+               return;
+
+       cp = scaler_vs_coeffs[idx];
+
+       for (i = 0; i < SC_NUM_PHASES * 2; i++) {
+               for (j = 0; j < SC_V_NUM_TAPS; j++)
+                       *coeff_v++ = *cp++;
+               /*
+                * for the vertical scaler, we copy the first 5 coefficients and
+                * skip the last 3 slots to move to the next row to hold
+                * coefficients for the next phase
+                */
+               coeff_v += SC_NUM_TAPS_MEM_ALIGN - SC_V_NUM_TAPS;
+       }
+
+       sc->vs_index = idx;
+       sc->load_coeff_v = true;
+}
+
+void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8,
+               u32 *sc_reg17, unsigned int src_w, unsigned int src_h,
+               unsigned int dst_w, unsigned int dst_h)
+{
+       struct device *dev = &sc->pdev->dev;
+       u32 val;
+       int dcm_x, dcm_shift;
+       bool use_rav;
+       unsigned long lltmp;
+       u32 lin_acc_inc, lin_acc_inc_u;
+       u32 col_acc_offset;
+       u16 factor = 0;
+       int row_acc_init_rav = 0, row_acc_init_rav_b = 0;
+       u32 row_acc_inc = 0, row_acc_offset = 0, row_acc_offset_b = 0;
+       /*
+        * location of SC register in payload memory with respect to the first
+        * register in the mmr address data block
+        */
+       u32 *sc_reg9 = sc_reg8 + 1;
+       u32 *sc_reg12 = sc_reg8 + 4;
+       u32 *sc_reg13 = sc_reg8 + 5;
+       u32 *sc_reg24 = sc_reg17 + 7;
+
+       val = sc_reg0[0];
+
+       /* clear all the features(they may get enabled elsewhere later) */
+       val &= ~(CFG_SELFGEN_FID | CFG_TRIM | CFG_ENABLE_SIN2_VER_INTP |
+               CFG_INTERLACE_I | CFG_DCM_4X | CFG_DCM_2X | CFG_AUTO_HS |
+               CFG_ENABLE_EV | CFG_USE_RAV | CFG_INVT_FID | CFG_SC_BYPASS |
+               CFG_INTERLACE_O | CFG_Y_PK_EN | CFG_HP_BYPASS | CFG_LINEAR);
+
+       if (src_w == dst_w && src_h == dst_h) {
+               val |= CFG_SC_BYPASS;
+               sc_reg0[0] = val;
+               return;
+       }
+
+       /* we only support linear scaling for now */
+       val |= CFG_LINEAR;
+
+       /* configure horizontal scaler */
+
+       /* enable 2X or 4X decimation */
+       dcm_x = src_w / dst_w;
+       if (dcm_x > 4) {
+               val |= CFG_DCM_4X;
+               dcm_shift = 2;
+       } else if (dcm_x > 2) {
+               val |= CFG_DCM_2X;
+               dcm_shift = 1;
+       } else {
+               dcm_shift = 0;
+       }
+
+       lltmp = dst_w - 1;
+       lin_acc_inc = div64_u64(((u64)(src_w >> dcm_shift) - 1) << 24, lltmp);
+       lin_acc_inc_u = 0;
+       col_acc_offset = 0;
+
+       dev_dbg(dev, "hs config: src_w = %d, dst_w = %d, decimation = %s, lin_acc_inc = %08x\n",
+               src_w, dst_w, dcm_shift == 2 ? "4x" :
+               (dcm_shift == 1 ? "2x" : "none"), lin_acc_inc);
+
+       /* configure vertical scaler */
+
+       /* use RAV for vertical scaler if vertical downscaling is > 4x */
+       if (dst_h < (src_h >> 2)) {
+               use_rav = true;
+               val |= CFG_USE_RAV;
+       } else {
+               use_rav = false;
+       }
+
+       if (use_rav) {
+               /* use RAV */
+               factor = (u16) ((dst_h << 10) / src_h);
+
+               row_acc_init_rav = factor + ((1 + factor) >> 1);
+               if (row_acc_init_rav >= 1024)
+                       row_acc_init_rav -= 1024;
+
+               row_acc_init_rav_b = row_acc_init_rav +
+                               (1 + (row_acc_init_rav >> 1)) -
+                               (1024 >> 1);
+
+               if (row_acc_init_rav_b < 0) {
+                       row_acc_init_rav_b += row_acc_init_rav;
+                       row_acc_init_rav *= 2;
+               }
+
+               dev_dbg(dev, "vs config(RAV): src_h = %d, dst_h = %d, factor = %d, acc_init = %08x, acc_init_b = %08x\n",
+                       src_h, dst_h, factor, row_acc_init_rav,
+                       row_acc_init_rav_b);
+       } else {
+               /* use polyphase */
+               row_acc_inc = ((src_h - 1) << 16) / (dst_h - 1);
+               row_acc_offset = 0;
+               row_acc_offset_b = 0;
+
+               dev_dbg(dev, "vs config(POLY): src_h = %d, dst_h = %d,row_acc_inc = %08x\n",
+                       src_h, dst_h, row_acc_inc);
+       }
+
+
+       sc_reg0[0] = val;
+       sc_reg0[1] = row_acc_inc;
+       sc_reg0[2] = row_acc_offset;
+       sc_reg0[3] = row_acc_offset_b;
+
+       sc_reg0[4] = ((lin_acc_inc_u & CFG_LIN_ACC_INC_U_MASK) <<
+                       CFG_LIN_ACC_INC_U_SHIFT) | (dst_w << CFG_TAR_W_SHIFT) |
+                       (dst_h << CFG_TAR_H_SHIFT);
+
+       sc_reg0[5] = (src_w << CFG_SRC_W_SHIFT) | (src_h << CFG_SRC_H_SHIFT);
+
+       sc_reg0[6] = (row_acc_init_rav_b << CFG_ROW_ACC_INIT_RAV_B_SHIFT) |
+               (row_acc_init_rav << CFG_ROW_ACC_INIT_RAV_SHIFT);
+
+       *sc_reg9 = lin_acc_inc;
+
+       *sc_reg12 = col_acc_offset << CFG_COL_ACC_OFFSET_SHIFT;
+
+       *sc_reg13 = factor;
+
+       *sc_reg24 = (src_w << CFG_ORG_W_SHIFT) | (src_h << CFG_ORG_H_SHIFT);
+}
+
+struct sc_data *sc_create(struct platform_device *pdev)
+{
+       struct sc_data *sc;
+
+       dev_dbg(&pdev->dev, "sc_create\n");
+
+       sc = devm_kzalloc(&pdev->dev, sizeof(*sc), GFP_KERNEL);
+       if (!sc) {
+               dev_err(&pdev->dev, "couldn't alloc sc_data\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       sc->pdev = pdev;
+
+       sc->res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sc");
+       if (!sc->res) {
+               dev_err(&pdev->dev, "missing platform resources data\n");
+               return ERR_PTR(-ENODEV);
+       }
+
+       sc->base = devm_ioremap_resource(&pdev->dev, sc->res);
+       if (!sc->base) {
+               dev_err(&pdev->dev, "failed to ioremap\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       return sc;
+}
diff --git a/drivers/media/platform/ti-vpe/sc.h b/drivers/media/platform/ti-vpe/sc.h
new file mode 100644 (file)
index 0000000..60e411e
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2013 Texas Instruments Inc.
+ *
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+#ifndef TI_SC_H
+#define TI_SC_H
+
+/* Scaler regs */
+#define CFG_SC0                                0x0
+#define CFG_INTERLACE_O                        (1 << 0)
+#define CFG_LINEAR                     (1 << 1)
+#define CFG_SC_BYPASS                  (1 << 2)
+#define CFG_INVT_FID                   (1 << 3)
+#define CFG_USE_RAV                    (1 << 4)
+#define CFG_ENABLE_EV                  (1 << 5)
+#define CFG_AUTO_HS                    (1 << 6)
+#define CFG_DCM_2X                     (1 << 7)
+#define CFG_DCM_4X                     (1 << 8)
+#define CFG_HP_BYPASS                  (1 << 9)
+#define CFG_INTERLACE_I                        (1 << 10)
+#define CFG_ENABLE_SIN2_VER_INTP       (1 << 11)
+#define CFG_Y_PK_EN                    (1 << 14)
+#define CFG_TRIM                       (1 << 15)
+#define CFG_SELFGEN_FID                        (1 << 16)
+
+#define CFG_SC1                                0x4
+#define CFG_ROW_ACC_INC_MASK           0x07ffffff
+#define CFG_ROW_ACC_INC_SHIFT          0
+
+#define CFG_SC2                                0x08
+#define CFG_ROW_ACC_OFFSET_MASK                0x0fffffff
+#define CFG_ROW_ACC_OFFSET_SHIFT       0
+
+#define CFG_SC3                                0x0c
+#define CFG_ROW_ACC_OFFSET_B_MASK      0x0fffffff
+#define CFG_ROW_ACC_OFFSET_B_SHIFT     0
+
+#define CFG_SC4                                0x10
+#define CFG_TAR_H_MASK                 0x07ff
+#define CFG_TAR_H_SHIFT                        0
+#define CFG_TAR_W_MASK                 0x07ff
+#define CFG_TAR_W_SHIFT                        12
+#define CFG_LIN_ACC_INC_U_MASK         0x07
+#define CFG_LIN_ACC_INC_U_SHIFT                24
+#define CFG_NLIN_ACC_INIT_U_MASK       0x07
+#define CFG_NLIN_ACC_INIT_U_SHIFT      28
+
+#define CFG_SC5                                0x14
+#define CFG_SRC_H_MASK                 0x07ff
+#define CFG_SRC_H_SHIFT                        0
+#define CFG_SRC_W_MASK                 0x07ff
+#define CFG_SRC_W_SHIFT                        12
+#define CFG_NLIN_ACC_INC_U_MASK                0x07
+#define CFG_NLIN_ACC_INC_U_SHIFT       24
+
+#define CFG_SC6                                0x18
+#define CFG_ROW_ACC_INIT_RAV_MASK      0x03ff
+#define CFG_ROW_ACC_INIT_RAV_SHIFT     0
+#define CFG_ROW_ACC_INIT_RAV_B_MASK    0x03ff
+#define CFG_ROW_ACC_INIT_RAV_B_SHIFT   10
+
+#define CFG_SC8                                0x20
+#define CFG_NLIN_LEFT_MASK             0x07ff
+#define CFG_NLIN_LEFT_SHIFT            0
+#define CFG_NLIN_RIGHT_MASK            0x07ff
+#define CFG_NLIN_RIGHT_SHIFT           12
+
+#define CFG_SC9                                0x24
+#define CFG_LIN_ACC_INC                        CFG_SC9
+
+#define CFG_SC10                       0x28
+#define CFG_NLIN_ACC_INIT              CFG_SC10
+
+#define CFG_SC11                       0x2c
+#define CFG_NLIN_ACC_INC               CFG_SC11
+
+#define CFG_SC12                       0x30
+#define CFG_COL_ACC_OFFSET_MASK                0x01ffffff
+#define CFG_COL_ACC_OFFSET_SHIFT       0
+
+#define CFG_SC13                       0x34
+#define CFG_SC_FACTOR_RAV_MASK         0xff
+#define CFG_SC_FACTOR_RAV_SHIFT                0
+#define CFG_CHROMA_INTP_THR_MASK       0x03ff
+#define CFG_CHROMA_INTP_THR_SHIFT      12
+#define CFG_DELTA_CHROMA_THR_MASK      0x0f
+#define CFG_DELTA_CHROMA_THR_SHIFT     24
+
+#define CFG_SC17                       0x44
+#define CFG_EV_THR_MASK                        0x03ff
+#define CFG_EV_THR_SHIFT               12
+#define CFG_DELTA_LUMA_THR_MASK                0x0f
+#define CFG_DELTA_LUMA_THR_SHIFT       24
+#define CFG_DELTA_EV_THR_MASK          0x0f
+#define CFG_DELTA_EV_THR_SHIFT         28
+
+#define CFG_SC18                       0x48
+#define CFG_HS_FACTOR_MASK             0x03ff
+#define CFG_HS_FACTOR_SHIFT            0
+#define CFG_CONF_DEFAULT_MASK          0x01ff
+#define CFG_CONF_DEFAULT_SHIFT         16
+
+#define CFG_SC19                       0x4c
+#define CFG_HPF_COEFF0_MASK            0xff
+#define CFG_HPF_COEFF0_SHIFT           0
+#define CFG_HPF_COEFF1_MASK            0xff
+#define CFG_HPF_COEFF1_SHIFT           8
+#define CFG_HPF_COEFF2_MASK            0xff
+#define CFG_HPF_COEFF2_SHIFT           16
+#define CFG_HPF_COEFF3_MASK            0xff
+#define CFG_HPF_COEFF3_SHIFT           23
+
+#define CFG_SC20                       0x50
+#define CFG_HPF_COEFF4_MASK            0xff
+#define CFG_HPF_COEFF4_SHIFT           0
+#define CFG_HPF_COEFF5_MASK            0xff
+#define CFG_HPF_COEFF5_SHIFT           8
+#define CFG_HPF_NORM_SHIFT_MASK                0x07
+#define CFG_HPF_NORM_SHIFT_SHIFT       16
+#define CFG_NL_LIMIT_MASK              0x1ff
+#define CFG_NL_LIMIT_SHIFT             20
+
+#define CFG_SC21                       0x54
+#define CFG_NL_LO_THR_MASK             0x01ff
+#define CFG_NL_LO_THR_SHIFT            0
+#define CFG_NL_LO_SLOPE_MASK           0xff
+#define CFG_NL_LO_SLOPE_SHIFT          16
+
+#define CFG_SC22                       0x58
+#define CFG_NL_HI_THR_MASK             0x01ff
+#define CFG_NL_HI_THR_SHIFT            0
+#define CFG_NL_HI_SLOPE_SH_MASK                0x07
+#define CFG_NL_HI_SLOPE_SH_SHIFT       16
+
+#define CFG_SC23                       0x5c
+#define CFG_GRADIENT_THR_MASK          0x07ff
+#define CFG_GRADIENT_THR_SHIFT         0
+#define CFG_GRADIENT_THR_RANGE_MASK    0x0f
+#define CFG_GRADIENT_THR_RANGE_SHIFT   12
+#define CFG_MIN_GY_THR_MASK            0xff
+#define CFG_MIN_GY_THR_SHIFT           16
+#define CFG_MIN_GY_THR_RANGE_MASK      0x0f
+#define CFG_MIN_GY_THR_RANGE_SHIFT     28
+
+#define CFG_SC24                       0x60
+#define CFG_ORG_H_MASK                 0x07ff
+#define CFG_ORG_H_SHIFT                        0
+#define CFG_ORG_W_MASK                 0x07ff
+#define CFG_ORG_W_SHIFT                        16
+
+#define CFG_SC25                       0x64
+#define CFG_OFF_H_MASK                 0x07ff
+#define CFG_OFF_H_SHIFT                        0
+#define CFG_OFF_W_MASK                 0x07ff
+#define CFG_OFF_W_SHIFT                        16
+
+/* number of phases supported by the polyphase scalers */
+#define SC_NUM_PHASES                  32
+
+/* number of taps used by horizontal polyphase scaler */
+#define SC_H_NUM_TAPS                  7
+
+/* number of taps used by vertical polyphase scaler */
+#define SC_V_NUM_TAPS                  5
+
+/* number of taps expected by the scaler in it's coefficient memory */
+#define SC_NUM_TAPS_MEM_ALIGN          8
+
+/*
+ * coefficient memory size in bytes:
+ * num phases x num sets(luma and chroma) x num taps(aligned) x coeff size
+ */
+#define SC_COEF_SRAM_SIZE      (SC_NUM_PHASES * 2 * SC_NUM_TAPS_MEM_ALIGN * 2)
+
+struct sc_data {
+       void __iomem            *base;
+       struct resource         *res;
+
+       dma_addr_t              loaded_coeff_h; /* loaded h coeffs in SC */
+       dma_addr_t              loaded_coeff_v; /* loaded v coeffs in SC */
+
+       bool                    load_coeff_h;   /* have new h SC coeffs */
+       bool                    load_coeff_v;   /* have new v SC coeffs */
+
+       unsigned int            hs_index;       /* h SC coeffs selector */
+       unsigned int            vs_index;       /* v SC coeffs selector */
+
+       struct platform_device *pdev;
+};
+
+void sc_dump_regs(struct sc_data *sc);
+void sc_set_hs_coeffs(struct sc_data *sc, void *addr, unsigned int src_w,
+               unsigned int dst_w);
+void sc_set_vs_coeffs(struct sc_data *sc, void *addr, unsigned int src_h,
+               unsigned int dst_h);
+void sc_config_scaler(struct sc_data *sc, u32 *sc_reg0, u32 *sc_reg8,
+               u32 *sc_reg17, unsigned int src_w, unsigned int src_h,
+               unsigned int dst_w, unsigned int dst_h);
+struct sc_data *sc_create(struct platform_device *pdev);
+
+#endif
diff --git a/drivers/media/platform/ti-vpe/sc_coeff.h b/drivers/media/platform/ti-vpe/sc_coeff.h
new file mode 100644 (file)
index 0000000..5bfa5c0
--- /dev/null
@@ -0,0 +1,1342 @@
+/*
+ * VPE SC coefs
+ *
+ * Copyright (c) 2013 Texas Instruments Inc.
+ *
+ * David Griego, <dagriego@biglakesoftware.com>
+ * Dale Farnsworth, <dale@farnsworth.org>
+ * Archit Taneja, <archit@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#ifndef __TI_SC_COEFF_H
+#define __TI_SC_COEFF_H
+
+/* horizontal scaler coefficients */
+enum {
+       HS_UP_SCALE = 0,
+       HS_LT_9_16_SCALE,
+       HS_LT_10_16_SCALE,
+       HS_LT_11_16_SCALE,
+       HS_LT_12_16_SCALE,
+       HS_LT_13_16_SCALE,
+       HS_LT_14_16_SCALE,
+       HS_LT_15_16_SCALE,
+       HS_LE_16_16_SCALE,
+};
+
+static const u16 scaler_hs_coeffs[13][SC_NUM_PHASES * 2 * SC_H_NUM_TAPS] = {
+       [HS_UP_SCALE] = {
+               /* Luma */
+               0x001F, 0x1F90, 0x00D2, 0x06FE, 0x00D2, 0x1F90, 0x001F,
+               0x001C, 0x1F9E, 0x009F, 0x06FB, 0x0108, 0x1F82, 0x0022,
+               0x0019, 0x1FAC, 0x006F, 0x06F3, 0x0140, 0x1F74, 0x0025,
+               0x0016, 0x1FB9, 0x0041, 0x06E7, 0x017B, 0x1F66, 0x0028,
+               0x0013, 0x1FC6, 0x0017, 0x06D6, 0x01B7, 0x1F58, 0x002B,
+               0x0010, 0x1FD3, 0x1FEF, 0x06C0, 0x01F6, 0x1F4B, 0x002D,
+               0x000E, 0x1FDF, 0x1FCB, 0x06A5, 0x0235, 0x1F3F, 0x002F,
+               0x000B, 0x1FEA, 0x1FAA, 0x0686, 0x0277, 0x1F33, 0x0031,
+               0x0009, 0x1FF5, 0x1F8C, 0x0663, 0x02B8, 0x1F28, 0x0033,
+               0x0007, 0x1FFF, 0x1F72, 0x063A, 0x02FB, 0x1F1F, 0x0034,
+               0x0005, 0x0008, 0x1F5A, 0x060F, 0x033E, 0x1F17, 0x0035,
+               0x0003, 0x0010, 0x1F46, 0x05E0, 0x0382, 0x1F10, 0x0035,
+               0x0002, 0x0017, 0x1F34, 0x05AF, 0x03C5, 0x1F0B, 0x0034,
+               0x0001, 0x001E, 0x1F26, 0x0579, 0x0407, 0x1F08, 0x0033,
+               0x0000, 0x0023, 0x1F1A, 0x0541, 0x0449, 0x1F07, 0x0032,
+               0x1FFF, 0x0028, 0x1F12, 0x0506, 0x048A, 0x1F08, 0x002F,
+               0x002C, 0x1F0C, 0x04C8, 0x04C8, 0x1F0C, 0x002C, 0x0000,
+               0x002F, 0x1F08, 0x048A, 0x0506, 0x1F12, 0x0028, 0x1FFF,
+               0x0032, 0x1F07, 0x0449, 0x0541, 0x1F1A, 0x0023, 0x0000,
+               0x0033, 0x1F08, 0x0407, 0x0579, 0x1F26, 0x001E, 0x0001,
+               0x0034, 0x1F0B, 0x03C5, 0x05AF, 0x1F34, 0x0017, 0x0002,
+               0x0035, 0x1F10, 0x0382, 0x05E0, 0x1F46, 0x0010, 0x0003,
+               0x0035, 0x1F17, 0x033E, 0x060F, 0x1F5A, 0x0008, 0x0005,
+               0x0034, 0x1F1F, 0x02FB, 0x063A, 0x1F72, 0x1FFF, 0x0007,
+               0x0033, 0x1F28, 0x02B8, 0x0663, 0x1F8C, 0x1FF5, 0x0009,
+               0x0031, 0x1F33, 0x0277, 0x0686, 0x1FAA, 0x1FEA, 0x000B,
+               0x002F, 0x1F3F, 0x0235, 0x06A5, 0x1FCB, 0x1FDF, 0x000E,
+               0x002D, 0x1F4B, 0x01F6, 0x06C0, 0x1FEF, 0x1FD3, 0x0010,
+               0x002B, 0x1F58, 0x01B7, 0x06D6, 0x0017, 0x1FC6, 0x0013,
+               0x0028, 0x1F66, 0x017B, 0x06E7, 0x0041, 0x1FB9, 0x0016,
+               0x0025, 0x1F74, 0x0140, 0x06F3, 0x006F, 0x1FAC, 0x0019,
+               0x0022, 0x1F82, 0x0108, 0x06FB, 0x009F, 0x1F9E, 0x001C,
+               /* Chroma */
+               0x001F, 0x1F90, 0x00D2, 0x06FE, 0x00D2, 0x1F90, 0x001F,
+               0x001C, 0x1F9E, 0x009F, 0x06FB, 0x0108, 0x1F82, 0x0022,
+               0x0019, 0x1FAC, 0x006F, 0x06F3, 0x0140, 0x1F74, 0x0025,
+               0x0016, 0x1FB9, 0x0041, 0x06E7, 0x017B, 0x1F66, 0x0028,
+               0x0013, 0x1FC6, 0x0017, 0x06D6, 0x01B7, 0x1F58, 0x002B,
+               0x0010, 0x1FD3, 0x1FEF, 0x06C0, 0x01F6, 0x1F4B, 0x002D,
+               0x000E, 0x1FDF, 0x1FCB, 0x06A5, 0x0235, 0x1F3F, 0x002F,
+               0x000B, 0x1FEA, 0x1FAA, 0x0686, 0x0277, 0x1F33, 0x0031,
+               0x0009, 0x1FF5, 0x1F8C, 0x0663, 0x02B8, 0x1F28, 0x0033,
+               0x0007, 0x1FFF, 0x1F72, 0x063A, 0x02FB, 0x1F1F, 0x0034,
+               0x0005, 0x0008, 0x1F5A, 0x060F, 0x033E, 0x1F17, 0x0035,
+               0x0003, 0x0010, 0x1F46, 0x05E0, 0x0382, 0x1F10, 0x0035,
+               0x0002, 0x0017, 0x1F34, 0x05AF, 0x03C5, 0x1F0B, 0x0034,
+               0x0001, 0x001E, 0x1F26, 0x0579, 0x0407, 0x1F08, 0x0033,
+               0x0000, 0x0023, 0x1F1A, 0x0541, 0x0449, 0x1F07, 0x0032,
+               0x1FFF, 0x0028, 0x1F12, 0x0506, 0x048A, 0x1F08, 0x002F,
+               0x002C, 0x1F0C, 0x04C8, 0x04C8, 0x1F0C, 0x002C, 0x0000,
+               0x002F, 0x1F08, 0x048A, 0x0506, 0x1F12, 0x0028, 0x1FFF,
+               0x0032, 0x1F07, 0x0449, 0x0541, 0x1F1A, 0x0023, 0x0000,
+               0x0033, 0x1F08, 0x0407, 0x0579, 0x1F26, 0x001E, 0x0001,
+               0x0034, 0x1F0B, 0x03C5, 0x05AF, 0x1F34, 0x0017, 0x0002,
+               0x0035, 0x1F10, 0x0382, 0x05E0, 0x1F46, 0x0010, 0x0003,
+               0x0035, 0x1F17, 0x033E, 0x060F, 0x1F5A, 0x0008, 0x0005,
+               0x0034, 0x1F1F, 0x02FB, 0x063A, 0x1F72, 0x1FFF, 0x0007,
+               0x0033, 0x1F28, 0x02B8, 0x0663, 0x1F8C, 0x1FF5, 0x0009,
+               0x0031, 0x1F33, 0x0277, 0x0686, 0x1FAA, 0x1FEA, 0x000B,
+               0x002F, 0x1F3F, 0x0235, 0x06A5, 0x1FCB, 0x1FDF, 0x000E,
+               0x002D, 0x1F4B, 0x01F6, 0x06C0, 0x1FEF, 0x1FD3, 0x0010,
+               0x002B, 0x1F58, 0x01B7, 0x06D6, 0x0017, 0x1FC6, 0x0013,
+               0x0028, 0x1F66, 0x017B, 0x06E7, 0x0041, 0x1FB9, 0x0016,
+               0x0025, 0x1F74, 0x0140, 0x06F3, 0x006F, 0x1FAC, 0x0019,
+               0x0022, 0x1F82, 0x0108, 0x06FB, 0x009F, 0x1F9E, 0x001C,
+       },
+       [HS_LT_9_16_SCALE] = {
+               /* Luma */
+               0x1FA3, 0x005E, 0x024A, 0x036A, 0x024A, 0x005E, 0x1FA3,
+               0x1FA3, 0x0052, 0x023A, 0x036A, 0x0259, 0x006A, 0x1FA4,
+               0x1FA3, 0x0046, 0x022A, 0x036A, 0x0269, 0x0076, 0x1FA4,
+               0x1FA3, 0x003B, 0x021A, 0x0368, 0x0278, 0x0083, 0x1FA5,
+               0x1FA4, 0x0031, 0x020A, 0x0365, 0x0286, 0x0090, 0x1FA6,
+               0x1FA5, 0x0026, 0x01F9, 0x0362, 0x0294, 0x009E, 0x1FA8,
+               0x1FA6, 0x001C, 0x01E8, 0x035E, 0x02A3, 0x00AB, 0x1FAA,
+               0x1FA7, 0x0013, 0x01D7, 0x035A, 0x02B0, 0x00B9, 0x1FAC,
+               0x1FA9, 0x000A, 0x01C6, 0x0354, 0x02BD, 0x00C7, 0x1FAF,
+               0x1FAA, 0x0001, 0x01B6, 0x034E, 0x02C9, 0x00D6, 0x1FB2,
+               0x1FAC, 0x1FF9, 0x01A5, 0x0347, 0x02D5, 0x00E5, 0x1FB5,
+               0x1FAE, 0x1FF1, 0x0194, 0x0340, 0x02E1, 0x00F3, 0x1FB9,
+               0x1FB0, 0x1FEA, 0x0183, 0x0338, 0x02EC, 0x0102, 0x1FBD,
+               0x1FB2, 0x1FE3, 0x0172, 0x0330, 0x02F6, 0x0112, 0x1FC1,
+               0x1FB4, 0x1FDC, 0x0161, 0x0327, 0x0301, 0x0121, 0x1FC6,
+               0x1FB7, 0x1FD6, 0x0151, 0x031D, 0x030A, 0x0130, 0x1FCB,
+               0x1FD2, 0x0136, 0x02F8, 0x02F8, 0x0136, 0x1FD2, 0x0000,
+               0x1FCB, 0x0130, 0x030A, 0x031D, 0x0151, 0x1FD6, 0x1FB7,
+               0x1FC6, 0x0121, 0x0301, 0x0327, 0x0161, 0x1FDC, 0x1FB4,
+               0x1FC1, 0x0112, 0x02F6, 0x0330, 0x0172, 0x1FE3, 0x1FB2,
+               0x1FBD, 0x0102, 0x02EC, 0x0338, 0x0183, 0x1FEA, 0x1FB0,
+               0x1FB9, 0x00F3, 0x02E1, 0x0340, 0x0194, 0x1FF1, 0x1FAE,
+               0x1FB5, 0x00E5, 0x02D5, 0x0347, 0x01A5, 0x1FF9, 0x1FAC,
+               0x1FB2, 0x00D6, 0x02C9, 0x034E, 0x01B6, 0x0001, 0x1FAA,
+               0x1FAF, 0x00C7, 0x02BD, 0x0354, 0x01C6, 0x000A, 0x1FA9,
+               0x1FAC, 0x00B9, 0x02B0, 0x035A, 0x01D7, 0x0013, 0x1FA7,
+               0x1FAA, 0x00AB, 0x02A3, 0x035E, 0x01E8, 0x001C, 0x1FA6,
+               0x1FA8, 0x009E, 0x0294, 0x0362, 0x01F9, 0x0026, 0x1FA5,
+               0x1FA6, 0x0090, 0x0286, 0x0365, 0x020A, 0x0031, 0x1FA4,
+               0x1FA5, 0x0083, 0x0278, 0x0368, 0x021A, 0x003B, 0x1FA3,
+               0x1FA4, 0x0076, 0x0269, 0x036A, 0x022A, 0x0046, 0x1FA3,
+               0x1FA4, 0x006A, 0x0259, 0x036A, 0x023A, 0x0052, 0x1FA3,
+               /* Chroma */
+               0x1FA3, 0x005E, 0x024A, 0x036A, 0x024A, 0x005E, 0x1FA3,
+               0x1FA3, 0x0052, 0x023A, 0x036A, 0x0259, 0x006A, 0x1FA4,
+               0x1FA3, 0x0046, 0x022A, 0x036A, 0x0269, 0x0076, 0x1FA4,
+               0x1FA3, 0x003B, 0x021A, 0x0368, 0x0278, 0x0083, 0x1FA5,
+               0x1FA4, 0x0031, 0x020A, 0x0365, 0x0286, 0x0090, 0x1FA6,
+               0x1FA5, 0x0026, 0x01F9, 0x0362, 0x0294, 0x009E, 0x1FA8,
+               0x1FA6, 0x001C, 0x01E8, 0x035E, 0x02A3, 0x00AB, 0x1FAA,
+               0x1FA7, 0x0013, 0x01D7, 0x035A, 0x02B0, 0x00B9, 0x1FAC,
+               0x1FA9, 0x000A, 0x01C6, 0x0354, 0x02BD, 0x00C7, 0x1FAF,
+               0x1FAA, 0x0001, 0x01B6, 0x034E, 0x02C9, 0x00D6, 0x1FB2,
+               0x1FAC, 0x1FF9, 0x01A5, 0x0347, 0x02D5, 0x00E5, 0x1FB5,
+               0x1FAE, 0x1FF1, 0x0194, 0x0340, 0x02E1, 0x00F3, 0x1FB9,
+               0x1FB0, 0x1FEA, 0x0183, 0x0338, 0x02EC, 0x0102, 0x1FBD,
+               0x1FB2, 0x1FE3, 0x0172, 0x0330, 0x02F6, 0x0112, 0x1FC1,
+               0x1FB4, 0x1FDC, 0x0161, 0x0327, 0x0301, 0x0121, 0x1FC6,
+               0x1FB7, 0x1FD6, 0x0151, 0x031D, 0x030A, 0x0130, 0x1FCB,
+               0x1FD2, 0x0136, 0x02F8, 0x02F8, 0x0136, 0x1FD2, 0x0000,
+               0x1FCB, 0x0130, 0x030A, 0x031D, 0x0151, 0x1FD6, 0x1FB7,
+               0x1FC6, 0x0121, 0x0301, 0x0327, 0x0161, 0x1FDC, 0x1FB4,
+               0x1FC1, 0x0112, 0x02F6, 0x0330, 0x0172, 0x1FE3, 0x1FB2,
+               0x1FBD, 0x0102, 0x02EC, 0x0338, 0x0183, 0x1FEA, 0x1FB0,
+               0x1FB9, 0x00F3, 0x02E1, 0x0340, 0x0194, 0x1FF1, 0x1FAE,
+               0x1FB5, 0x00E5, 0x02D5, 0x0347, 0x01A5, 0x1FF9, 0x1FAC,
+               0x1FB2, 0x00D6, 0x02C9, 0x034E, 0x01B6, 0x0001, 0x1FAA,
+               0x1FAF, 0x00C7, 0x02BD, 0x0354, 0x01C6, 0x000A, 0x1FA9,
+               0x1FAC, 0x00B9, 0x02B0, 0x035A, 0x01D7, 0x0013, 0x1FA7,
+               0x1FAA, 0x00AB, 0x02A3, 0x035E, 0x01E8, 0x001C, 0x1FA6,
+               0x1FA8, 0x009E, 0x0294, 0x0362, 0x01F9, 0x0026, 0x1FA5,
+               0x1FA6, 0x0090, 0x0286, 0x0365, 0x020A, 0x0031, 0x1FA4,
+               0x1FA5, 0x0083, 0x0278, 0x0368, 0x021A, 0x003B, 0x1FA3,
+               0x1FA4, 0x0076, 0x0269, 0x036A, 0x022A, 0x0046, 0x1FA3,
+               0x1FA4, 0x006A, 0x0259, 0x036A, 0x023A, 0x0052, 0x1FA3,
+       },
+       [HS_LT_10_16_SCALE] = {
+               /* Luma */
+               0x1F8D, 0x000C, 0x026A, 0x03FA, 0x026A, 0x000C, 0x1F8D,
+               0x1F8F, 0x0000, 0x0255, 0x03FA, 0x027F, 0x0019, 0x1F8A,
+               0x1F92, 0x1FF5, 0x023F, 0x03F8, 0x0293, 0x0027, 0x1F88,
+               0x1F95, 0x1FEA, 0x022A, 0x03F6, 0x02A7, 0x0034, 0x1F86,
+               0x1F99, 0x1FDF, 0x0213, 0x03F2, 0x02BB, 0x0043, 0x1F85,
+               0x1F9C, 0x1FD5, 0x01FE, 0x03ED, 0x02CF, 0x0052, 0x1F83,
+               0x1FA0, 0x1FCC, 0x01E8, 0x03E7, 0x02E1, 0x0061, 0x1F83,
+               0x1FA4, 0x1FC3, 0x01D2, 0x03E0, 0x02F4, 0x0071, 0x1F82,
+               0x1FA7, 0x1FBB, 0x01BC, 0x03D9, 0x0306, 0x0081, 0x1F82,
+               0x1FAB, 0x1FB4, 0x01A6, 0x03D0, 0x0317, 0x0092, 0x1F82,
+               0x1FAF, 0x1FAD, 0x0190, 0x03C7, 0x0327, 0x00A3, 0x1F83,
+               0x1FB3, 0x1FA7, 0x017A, 0x03BC, 0x0337, 0x00B5, 0x1F84,
+               0x1FB8, 0x1FA1, 0x0165, 0x03B0, 0x0346, 0x00C7, 0x1F85,
+               0x1FBC, 0x1F9C, 0x0150, 0x03A4, 0x0354, 0x00D9, 0x1F87,
+               0x1FC0, 0x1F98, 0x013A, 0x0397, 0x0361, 0x00EC, 0x1F8A,
+               0x1FC4, 0x1F93, 0x0126, 0x0389, 0x036F, 0x00FE, 0x1F8D,
+               0x1F93, 0x010A, 0x0363, 0x0363, 0x010A, 0x1F93, 0x0000,
+               0x1F8D, 0x00FE, 0x036F, 0x0389, 0x0126, 0x1F93, 0x1FC4,
+               0x1F8A, 0x00EC, 0x0361, 0x0397, 0x013A, 0x1F98, 0x1FC0,
+               0x1F87, 0x00D9, 0x0354, 0x03A4, 0x0150, 0x1F9C, 0x1FBC,
+               0x1F85, 0x00C7, 0x0346, 0x03B0, 0x0165, 0x1FA1, 0x1FB8,
+               0x1F84, 0x00B5, 0x0337, 0x03BC, 0x017A, 0x1FA7, 0x1FB3,
+               0x1F83, 0x00A3, 0x0327, 0x03C7, 0x0190, 0x1FAD, 0x1FAF,
+               0x1F82, 0x0092, 0x0317, 0x03D0, 0x01A6, 0x1FB4, 0x1FAB,
+               0x1F82, 0x0081, 0x0306, 0x03D9, 0x01BC, 0x1FBB, 0x1FA7,
+               0x1F82, 0x0071, 0x02F4, 0x03E0, 0x01D2, 0x1FC3, 0x1FA4,
+               0x1F83, 0x0061, 0x02E1, 0x03E7, 0x01E8, 0x1FCC, 0x1FA0,
+               0x1F83, 0x0052, 0x02CF, 0x03ED, 0x01FE, 0x1FD5, 0x1F9C,
+               0x1F85, 0x0043, 0x02BB, 0x03F2, 0x0213, 0x1FDF, 0x1F99,
+               0x1F86, 0x0034, 0x02A7, 0x03F6, 0x022A, 0x1FEA, 0x1F95,
+               0x1F88, 0x0027, 0x0293, 0x03F8, 0x023F, 0x1FF5, 0x1F92,
+               0x1F8A, 0x0019, 0x027F, 0x03FA, 0x0255, 0x0000, 0x1F8F,
+               /* Chroma */
+               0x1F8D, 0x000C, 0x026A, 0x03FA, 0x026A, 0x000C, 0x1F8D,
+               0x1F8F, 0x0000, 0x0255, 0x03FA, 0x027F, 0x0019, 0x1F8A,
+               0x1F92, 0x1FF5, 0x023F, 0x03F8, 0x0293, 0x0027, 0x1F88,
+               0x1F95, 0x1FEA, 0x022A, 0x03F6, 0x02A7, 0x0034, 0x1F86,
+               0x1F99, 0x1FDF, 0x0213, 0x03F2, 0x02BB, 0x0043, 0x1F85,
+               0x1F9C, 0x1FD5, 0x01FE, 0x03ED, 0x02CF, 0x0052, 0x1F83,
+               0x1FA0, 0x1FCC, 0x01E8, 0x03E7, 0x02E1, 0x0061, 0x1F83,
+               0x1FA4, 0x1FC3, 0x01D2, 0x03E0, 0x02F4, 0x0071, 0x1F82,
+               0x1FA7, 0x1FBB, 0x01BC, 0x03D9, 0x0306, 0x0081, 0x1F82,
+               0x1FAB, 0x1FB4, 0x01A6, 0x03D0, 0x0317, 0x0092, 0x1F82,
+               0x1FAF, 0x1FAD, 0x0190, 0x03C7, 0x0327, 0x00A3, 0x1F83,
+               0x1FB3, 0x1FA7, 0x017A, 0x03BC, 0x0337, 0x00B5, 0x1F84,
+               0x1FB8, 0x1FA1, 0x0165, 0x03B0, 0x0346, 0x00C7, 0x1F85,
+               0x1FBC, 0x1F9C, 0x0150, 0x03A4, 0x0354, 0x00D9, 0x1F87,
+               0x1FC0, 0x1F98, 0x013A, 0x0397, 0x0361, 0x00EC, 0x1F8A,
+               0x1FC4, 0x1F93, 0x0126, 0x0389, 0x036F, 0x00FE, 0x1F8D,
+               0x1F93, 0x010A, 0x0363, 0x0363, 0x010A, 0x1F93, 0x0000,
+               0x1F8D, 0x00FE, 0x036F, 0x0389, 0x0126, 0x1F93, 0x1FC4,
+               0x1F8A, 0x00EC, 0x0361, 0x0397, 0x013A, 0x1F98, 0x1FC0,
+               0x1F87, 0x00D9, 0x0354, 0x03A4, 0x0150, 0x1F9C, 0x1FBC,
+               0x1F85, 0x00C7, 0x0346, 0x03B0, 0x0165, 0x1FA1, 0x1FB8,
+               0x1F84, 0x00B5, 0x0337, 0x03BC, 0x017A, 0x1FA7, 0x1FB3,
+               0x1F83, 0x00A3, 0x0327, 0x03C7, 0x0190, 0x1FAD, 0x1FAF,
+               0x1F82, 0x0092, 0x0317, 0x03D0, 0x01A6, 0x1FB4, 0x1FAB,
+               0x1F82, 0x0081, 0x0306, 0x03D9, 0x01BC, 0x1FBB, 0x1FA7,
+               0x1F82, 0x0071, 0x02F4, 0x03E0, 0x01D2, 0x1FC3, 0x1FA4,
+               0x1F83, 0x0061, 0x02E1, 0x03E7, 0x01E8, 0x1FCC, 0x1FA0,
+               0x1F83, 0x0052, 0x02CF, 0x03ED, 0x01FE, 0x1FD5, 0x1F9C,
+               0x1F85, 0x0043, 0x02BB, 0x03F2, 0x0213, 0x1FDF, 0x1F99,
+               0x1F86, 0x0034, 0x02A7, 0x03F6, 0x022A, 0x1FEA, 0x1F95,
+               0x1F88, 0x0027, 0x0293, 0x03F8, 0x023F, 0x1FF5, 0x1F92,
+               0x1F8A, 0x0019, 0x027F, 0x03FA, 0x0255, 0x0000, 0x1F8F,
+       },
+       [HS_LT_11_16_SCALE] = {
+               /* Luma */
+               0x1F95, 0x1FB5, 0x0272, 0x0488, 0x0272, 0x1FB5, 0x1F95,
+               0x1F9B, 0x1FAA, 0x0257, 0x0486, 0x028D, 0x1FC1, 0x1F90,
+               0x1FA0, 0x1FA0, 0x023C, 0x0485, 0x02A8, 0x1FCD, 0x1F8A,
+               0x1FA6, 0x1F96, 0x0221, 0x0481, 0x02C2, 0x1FDB, 0x1F85,
+               0x1FAC, 0x1F8E, 0x0205, 0x047C, 0x02DC, 0x1FE9, 0x1F80,
+               0x1FB1, 0x1F86, 0x01E9, 0x0476, 0x02F6, 0x1FF8, 0x1F7C,
+               0x1FB7, 0x1F7F, 0x01CE, 0x046E, 0x030F, 0x0008, 0x1F77,
+               0x1FBD, 0x1F79, 0x01B3, 0x0465, 0x0326, 0x0019, 0x1F73,
+               0x1FC3, 0x1F73, 0x0197, 0x045B, 0x033E, 0x002A, 0x1F70,
+               0x1FC8, 0x1F6F, 0x017D, 0x044E, 0x0355, 0x003C, 0x1F6D,
+               0x1FCE, 0x1F6B, 0x0162, 0x0441, 0x036B, 0x004F, 0x1F6A,
+               0x1FD3, 0x1F68, 0x0148, 0x0433, 0x0380, 0x0063, 0x1F67,
+               0x1FD8, 0x1F65, 0x012E, 0x0424, 0x0395, 0x0077, 0x1F65,
+               0x1FDE, 0x1F63, 0x0115, 0x0413, 0x03A8, 0x008B, 0x1F64,
+               0x1FE3, 0x1F62, 0x00FC, 0x0403, 0x03BA, 0x00A0, 0x1F62,
+               0x1FE7, 0x1F62, 0x00E4, 0x03EF, 0x03CC, 0x00B6, 0x1F62,
+               0x1F63, 0x00CA, 0x03D3, 0x03D3, 0x00CA, 0x1F63, 0x0000,
+               0x1F62, 0x00B6, 0x03CC, 0x03EF, 0x00E4, 0x1F62, 0x1FE7,
+               0x1F62, 0x00A0, 0x03BA, 0x0403, 0x00FC, 0x1F62, 0x1FE3,
+               0x1F64, 0x008B, 0x03A8, 0x0413, 0x0115, 0x1F63, 0x1FDE,
+               0x1F65, 0x0077, 0x0395, 0x0424, 0x012E, 0x1F65, 0x1FD8,
+               0x1F67, 0x0063, 0x0380, 0x0433, 0x0148, 0x1F68, 0x1FD3,
+               0x1F6A, 0x004F, 0x036B, 0x0441, 0x0162, 0x1F6B, 0x1FCE,
+               0x1F6D, 0x003C, 0x0355, 0x044E, 0x017D, 0x1F6F, 0x1FC8,
+               0x1F70, 0x002A, 0x033E, 0x045B, 0x0197, 0x1F73, 0x1FC3,
+               0x1F73, 0x0019, 0x0326, 0x0465, 0x01B3, 0x1F79, 0x1FBD,
+               0x1F77, 0x0008, 0x030F, 0x046E, 0x01CE, 0x1F7F, 0x1FB7,
+               0x1F7C, 0x1FF8, 0x02F6, 0x0476, 0x01E9, 0x1F86, 0x1FB1,
+               0x1F80, 0x1FE9, 0x02DC, 0x047C, 0x0205, 0x1F8E, 0x1FAC,
+               0x1F85, 0x1FDB, 0x02C2, 0x0481, 0x0221, 0x1F96, 0x1FA6,
+               0x1F8A, 0x1FCD, 0x02A8, 0x0485, 0x023C, 0x1FA0, 0x1FA0,
+               0x1F90, 0x1FC1, 0x028D, 0x0486, 0x0257, 0x1FAA, 0x1F9B,
+               /* Chroma */
+               0x1F95, 0x1FB5, 0x0272, 0x0488, 0x0272, 0x1FB5, 0x1F95,
+               0x1F9B, 0x1FAA, 0x0257, 0x0486, 0x028D, 0x1FC1, 0x1F90,
+               0x1FA0, 0x1FA0, 0x023C, 0x0485, 0x02A8, 0x1FCD, 0x1F8A,
+               0x1FA6, 0x1F96, 0x0221, 0x0481, 0x02C2, 0x1FDB, 0x1F85,
+               0x1FAC, 0x1F8E, 0x0205, 0x047C, 0x02DC, 0x1FE9, 0x1F80,
+               0x1FB1, 0x1F86, 0x01E9, 0x0476, 0x02F6, 0x1FF8, 0x1F7C,
+               0x1FB7, 0x1F7F, 0x01CE, 0x046E, 0x030F, 0x0008, 0x1F77,
+               0x1FBD, 0x1F79, 0x01B3, 0x0465, 0x0326, 0x0019, 0x1F73,
+               0x1FC3, 0x1F73, 0x0197, 0x045B, 0x033E, 0x002A, 0x1F70,
+               0x1FC8, 0x1F6F, 0x017D, 0x044E, 0x0355, 0x003C, 0x1F6D,
+               0x1FCE, 0x1F6B, 0x0162, 0x0441, 0x036B, 0x004F, 0x1F6A,
+               0x1FD3, 0x1F68, 0x0148, 0x0433, 0x0380, 0x0063, 0x1F67,
+               0x1FD8, 0x1F65, 0x012E, 0x0424, 0x0395, 0x0077, 0x1F65,
+               0x1FDE, 0x1F63, 0x0115, 0x0413, 0x03A8, 0x008B, 0x1F64,
+               0x1FE3, 0x1F62, 0x00FC, 0x0403, 0x03BA, 0x00A0, 0x1F62,
+               0x1FE7, 0x1F62, 0x00E4, 0x03EF, 0x03CC, 0x00B6, 0x1F62,
+               0x1F63, 0x00CA, 0x03D3, 0x03D3, 0x00CA, 0x1F63, 0x0000,
+               0x1F62, 0x00B6, 0x03CC, 0x03EF, 0x00E4, 0x1F62, 0x1FE7,
+               0x1F62, 0x00A0, 0x03BA, 0x0403, 0x00FC, 0x1F62, 0x1FE3,
+               0x1F64, 0x008B, 0x03A8, 0x0413, 0x0115, 0x1F63, 0x1FDE,
+               0x1F65, 0x0077, 0x0395, 0x0424, 0x012E, 0x1F65, 0x1FD8,
+               0x1F67, 0x0063, 0x0380, 0x0433, 0x0148, 0x1F68, 0x1FD3,
+               0x1F6A, 0x004F, 0x036B, 0x0441, 0x0162, 0x1F6B, 0x1FCE,
+               0x1F6D, 0x003C, 0x0355, 0x044E, 0x017D, 0x1F6F, 0x1FC8,
+               0x1F70, 0x002A, 0x033E, 0x045B, 0x0197, 0x1F73, 0x1FC3,
+               0x1F73, 0x0019, 0x0326, 0x0465, 0x01B3, 0x1F79, 0x1FBD,
+               0x1F77, 0x0008, 0x030F, 0x046E, 0x01CE, 0x1F7F, 0x1FB7,
+               0x1F7C, 0x1FF8, 0x02F6, 0x0476, 0x01E9, 0x1F86, 0x1FB1,
+               0x1F80, 0x1FE9, 0x02DC, 0x047C, 0x0205, 0x1F8E, 0x1FAC,
+               0x1F85, 0x1FDB, 0x02C2, 0x0481, 0x0221, 0x1F96, 0x1FA6,
+               0x1F8A, 0x1FCD, 0x02A8, 0x0485, 0x023C, 0x1FA0, 0x1FA0,
+               0x1F90, 0x1FC1, 0x028D, 0x0486, 0x0257, 0x1FAA, 0x1F9B,
+       },
+       [HS_LT_12_16_SCALE] = {
+               /* Luma */
+               0x1FBB, 0x1F65, 0x025E, 0x0504, 0x025E, 0x1F65, 0x1FBB,
+               0x1FC3, 0x1F5D, 0x023C, 0x0503, 0x027F, 0x1F6E, 0x1FB4,
+               0x1FCA, 0x1F56, 0x021B, 0x0501, 0x02A0, 0x1F78, 0x1FAC,
+               0x1FD1, 0x1F50, 0x01FA, 0x04FD, 0x02C0, 0x1F83, 0x1FA5,
+               0x1FD8, 0x1F4B, 0x01D9, 0x04F6, 0x02E1, 0x1F90, 0x1F9D,
+               0x1FDF, 0x1F47, 0x01B8, 0x04EF, 0x0301, 0x1F9D, 0x1F95,
+               0x1FE6, 0x1F43, 0x0198, 0x04E5, 0x0321, 0x1FAB, 0x1F8E,
+               0x1FEC, 0x1F41, 0x0178, 0x04DA, 0x0340, 0x1FBB, 0x1F86,
+               0x1FF2, 0x1F40, 0x0159, 0x04CC, 0x035E, 0x1FCC, 0x1F7F,
+               0x1FF8, 0x1F40, 0x013A, 0x04BE, 0x037B, 0x1FDD, 0x1F78,
+               0x1FFE, 0x1F40, 0x011B, 0x04AD, 0x0398, 0x1FF0, 0x1F72,
+               0x0003, 0x1F41, 0x00FD, 0x049C, 0x03B4, 0x0004, 0x1F6B,
+               0x0008, 0x1F43, 0x00E0, 0x0489, 0x03CE, 0x0019, 0x1F65,
+               0x000D, 0x1F46, 0x00C4, 0x0474, 0x03E8, 0x002E, 0x1F5F,
+               0x0011, 0x1F49, 0x00A9, 0x045E, 0x0400, 0x0045, 0x1F5A,
+               0x0015, 0x1F4D, 0x008E, 0x0447, 0x0418, 0x005C, 0x1F55,
+               0x1F4F, 0x0076, 0x043B, 0x043B, 0x0076, 0x1F4F, 0x0000,
+               0x1F55, 0x005C, 0x0418, 0x0447, 0x008E, 0x1F4D, 0x0015,
+               0x1F5A, 0x0045, 0x0400, 0x045E, 0x00A9, 0x1F49, 0x0011,
+               0x1F5F, 0x002E, 0x03E8, 0x0474, 0x00C4, 0x1F46, 0x000D,
+               0x1F65, 0x0019, 0x03CE, 0x0489, 0x00E0, 0x1F43, 0x0008,
+               0x1F6B, 0x0004, 0x03B4, 0x049C, 0x00FD, 0x1F41, 0x0003,
+               0x1F72, 0x1FF0, 0x0398, 0x04AD, 0x011B, 0x1F40, 0x1FFE,
+               0x1F78, 0x1FDD, 0x037B, 0x04BE, 0x013A, 0x1F40, 0x1FF8,
+               0x1F7F, 0x1FCC, 0x035E, 0x04CC, 0x0159, 0x1F40, 0x1FF2,
+               0x1F86, 0x1FBB, 0x0340, 0x04DA, 0x0178, 0x1F41, 0x1FEC,
+               0x1F8E, 0x1FAB, 0x0321, 0x04E5, 0x0198, 0x1F43, 0x1FE6,
+               0x1F95, 0x1F9D, 0x0301, 0x04EF, 0x01B8, 0x1F47, 0x1FDF,
+               0x1F9D, 0x1F90, 0x02E1, 0x04F6, 0x01D9, 0x1F4B, 0x1FD8,
+               0x1FA5, 0x1F83, 0x02C0, 0x04FD, 0x01FA, 0x1F50, 0x1FD1,
+               0x1FAC, 0x1F78, 0x02A0, 0x0501, 0x021B, 0x1F56, 0x1FCA,
+               0x1FB4, 0x1F6E, 0x027F, 0x0503, 0x023C, 0x1F5D, 0x1FC3,
+               /* Chroma */
+               0x1FBB, 0x1F65, 0x025E, 0x0504, 0x025E, 0x1F65, 0x1FBB,
+               0x1FC3, 0x1F5D, 0x023C, 0x0503, 0x027F, 0x1F6E, 0x1FB4,
+               0x1FCA, 0x1F56, 0x021B, 0x0501, 0x02A0, 0x1F78, 0x1FAC,
+               0x1FD1, 0x1F50, 0x01FA, 0x04FD, 0x02C0, 0x1F83, 0x1FA5,
+               0x1FD8, 0x1F4B, 0x01D9, 0x04F6, 0x02E1, 0x1F90, 0x1F9D,
+               0x1FDF, 0x1F47, 0x01B8, 0x04EF, 0x0301, 0x1F9D, 0x1F95,
+               0x1FE6, 0x1F43, 0x0198, 0x04E5, 0x0321, 0x1FAB, 0x1F8E,
+               0x1FEC, 0x1F41, 0x0178, 0x04DA, 0x0340, 0x1FBB, 0x1F86,
+               0x1FF2, 0x1F40, 0x0159, 0x04CC, 0x035E, 0x1FCC, 0x1F7F,
+               0x1FF8, 0x1F40, 0x013A, 0x04BE, 0x037B, 0x1FDD, 0x1F78,
+               0x1FFE, 0x1F40, 0x011B, 0x04AD, 0x0398, 0x1FF0, 0x1F72,
+               0x0003, 0x1F41, 0x00FD, 0x049C, 0x03B4, 0x0004, 0x1F6B,
+               0x0008, 0x1F43, 0x00E0, 0x0489, 0x03CE, 0x0019, 0x1F65,
+               0x000D, 0x1F46, 0x00C4, 0x0474, 0x03E8, 0x002E, 0x1F5F,
+               0x0011, 0x1F49, 0x00A9, 0x045E, 0x0400, 0x0045, 0x1F5A,
+               0x0015, 0x1F4D, 0x008E, 0x0447, 0x0418, 0x005C, 0x1F55,
+               0x1F4F, 0x0076, 0x043B, 0x043B, 0x0076, 0x1F4F, 0x0000,
+               0x1F55, 0x005C, 0x0418, 0x0447, 0x008E, 0x1F4D, 0x0015,
+               0x1F5A, 0x0045, 0x0400, 0x045E, 0x00A9, 0x1F49, 0x0011,
+               0x1F5F, 0x002E, 0x03E8, 0x0474, 0x00C4, 0x1F46, 0x000D,
+               0x1F65, 0x0019, 0x03CE, 0x0489, 0x00E0, 0x1F43, 0x0008,
+               0x1F6B, 0x0004, 0x03B4, 0x049C, 0x00FD, 0x1F41, 0x0003,
+               0x1F72, 0x1FF0, 0x0398, 0x04AD, 0x011B, 0x1F40, 0x1FFE,
+               0x1F78, 0x1FDD, 0x037B, 0x04BE, 0x013A, 0x1F40, 0x1FF8,
+               0x1F7F, 0x1FCC, 0x035E, 0x04CC, 0x0159, 0x1F40, 0x1FF2,
+               0x1F86, 0x1FBB, 0x0340, 0x04DA, 0x0178, 0x1F41, 0x1FEC,
+               0x1F8E, 0x1FAB, 0x0321, 0x04E5, 0x0198, 0x1F43, 0x1FE6,
+               0x1F95, 0x1F9D, 0x0301, 0x04EF, 0x01B8, 0x1F47, 0x1FDF,
+               0x1F9D, 0x1F90, 0x02E1, 0x04F6, 0x01D9, 0x1F4B, 0x1FD8,
+               0x1FA5, 0x1F83, 0x02C0, 0x04FD, 0x01FA, 0x1F50, 0x1FD1,
+               0x1FAC, 0x1F78, 0x02A0, 0x0501, 0x021B, 0x1F56, 0x1FCA,
+               0x1FB4, 0x1F6E, 0x027F, 0x0503, 0x023C, 0x1F5D, 0x1FC3,
+       },
+       [HS_LT_13_16_SCALE] = {
+               /* Luma */
+               0x1FF4, 0x1F29, 0x022D, 0x056C, 0x022D, 0x1F29, 0x1FF4,
+               0x1FFC, 0x1F26, 0x0206, 0x056A, 0x0254, 0x1F2E, 0x1FEC,
+               0x0003, 0x1F24, 0x01E0, 0x0567, 0x027A, 0x1F34, 0x1FE4,
+               0x000A, 0x1F23, 0x01BA, 0x0561, 0x02A2, 0x1F3B, 0x1FDB,
+               0x0011, 0x1F22, 0x0194, 0x055B, 0x02C9, 0x1F43, 0x1FD2,
+               0x0017, 0x1F23, 0x016F, 0x0551, 0x02F0, 0x1F4D, 0x1FC9,
+               0x001D, 0x1F25, 0x014B, 0x0545, 0x0316, 0x1F58, 0x1FC0,
+               0x0022, 0x1F28, 0x0127, 0x0538, 0x033C, 0x1F65, 0x1FB6,
+               0x0027, 0x1F2C, 0x0104, 0x0528, 0x0361, 0x1F73, 0x1FAD,
+               0x002B, 0x1F30, 0x00E2, 0x0518, 0x0386, 0x1F82, 0x1FA3,
+               0x002F, 0x1F36, 0x00C2, 0x0504, 0x03AA, 0x1F92, 0x1F99,
+               0x0032, 0x1F3C, 0x00A2, 0x04EF, 0x03CD, 0x1FA4, 0x1F90,
+               0x0035, 0x1F42, 0x0083, 0x04D9, 0x03EF, 0x1FB8, 0x1F86,
+               0x0038, 0x1F49, 0x0065, 0x04C0, 0x0410, 0x1FCD, 0x1F7D,
+               0x003A, 0x1F51, 0x0048, 0x04A6, 0x0431, 0x1FE3, 0x1F73,
+               0x003C, 0x1F59, 0x002D, 0x048A, 0x0450, 0x1FFA, 0x1F6A,
+               0x1F5D, 0x0014, 0x048F, 0x048F, 0x0014, 0x1F5D, 0x0000,
+               0x1F6A, 0x1FFA, 0x0450, 0x048A, 0x002D, 0x1F59, 0x003C,
+               0x1F73, 0x1FE3, 0x0431, 0x04A6, 0x0048, 0x1F51, 0x003A,
+               0x1F7D, 0x1FCD, 0x0410, 0x04C0, 0x0065, 0x1F49, 0x0038,
+               0x1F86, 0x1FB8, 0x03EF, 0x04D9, 0x0083, 0x1F42, 0x0035,
+               0x1F90, 0x1FA4, 0x03CD, 0x04EF, 0x00A2, 0x1F3C, 0x0032,
+               0x1F99, 0x1F92, 0x03AA, 0x0504, 0x00C2, 0x1F36, 0x002F,
+               0x1FA3, 0x1F82, 0x0386, 0x0518, 0x00E2, 0x1F30, 0x002B,
+               0x1FAD, 0x1F73, 0x0361, 0x0528, 0x0104, 0x1F2C, 0x0027,
+               0x1FB6, 0x1F65, 0x033C, 0x0538, 0x0127, 0x1F28, 0x0022,
+               0x1FC0, 0x1F58, 0x0316, 0x0545, 0x014B, 0x1F25, 0x001D,
+               0x1FC9, 0x1F4D, 0x02F0, 0x0551, 0x016F, 0x1F23, 0x0017,
+               0x1FD2, 0x1F43, 0x02C9, 0x055B, 0x0194, 0x1F22, 0x0011,
+               0x1FDB, 0x1F3B, 0x02A2, 0x0561, 0x01BA, 0x1F23, 0x000A,
+               0x1FE4, 0x1F34, 0x027A, 0x0567, 0x01E0, 0x1F24, 0x0003,
+               0x1FEC, 0x1F2E, 0x0254, 0x056A, 0x0206, 0x1F26, 0x1FFC,
+               /* Chroma */
+               0x1FF4, 0x1F29, 0x022D, 0x056C, 0x022D, 0x1F29, 0x1FF4,
+               0x1FFC, 0x1F26, 0x0206, 0x056A, 0x0254, 0x1F2E, 0x1FEC,
+               0x0003, 0x1F24, 0x01E0, 0x0567, 0x027A, 0x1F34, 0x1FE4,
+               0x000A, 0x1F23, 0x01BA, 0x0561, 0x02A2, 0x1F3B, 0x1FDB,
+               0x0011, 0x1F22, 0x0194, 0x055B, 0x02C9, 0x1F43, 0x1FD2,
+               0x0017, 0x1F23, 0x016F, 0x0551, 0x02F0, 0x1F4D, 0x1FC9,
+               0x001D, 0x1F25, 0x014B, 0x0545, 0x0316, 0x1F58, 0x1FC0,
+               0x0022, 0x1F28, 0x0127, 0x0538, 0x033C, 0x1F65, 0x1FB6,
+               0x0027, 0x1F2C, 0x0104, 0x0528, 0x0361, 0x1F73, 0x1FAD,
+               0x002B, 0x1F30, 0x00E2, 0x0518, 0x0386, 0x1F82, 0x1FA3,
+               0x002F, 0x1F36, 0x00C2, 0x0504, 0x03AA, 0x1F92, 0x1F99,
+               0x0032, 0x1F3C, 0x00A2, 0x04EF, 0x03CD, 0x1FA4, 0x1F90,
+               0x0035, 0x1F42, 0x0083, 0x04D9, 0x03EF, 0x1FB8, 0x1F86,
+               0x0038, 0x1F49, 0x0065, 0x04C0, 0x0410, 0x1FCD, 0x1F7D,
+               0x003A, 0x1F51, 0x0048, 0x04A6, 0x0431, 0x1FE3, 0x1F73,
+               0x003C, 0x1F59, 0x002D, 0x048A, 0x0450, 0x1FFA, 0x1F6A,
+               0x1F5D, 0x0014, 0x048F, 0x048F, 0x0014, 0x1F5D, 0x0000,
+               0x1F6A, 0x1FFA, 0x0450, 0x048A, 0x002D, 0x1F59, 0x003C,
+               0x1F73, 0x1FE3, 0x0431, 0x04A6, 0x0048, 0x1F51, 0x003A,
+               0x1F7D, 0x1FCD, 0x0410, 0x04C0, 0x0065, 0x1F49, 0x0038,
+               0x1F86, 0x1FB8, 0x03EF, 0x04D9, 0x0083, 0x1F42, 0x0035,
+               0x1F90, 0x1FA4, 0x03CD, 0x04EF, 0x00A2, 0x1F3C, 0x0032,
+               0x1F99, 0x1F92, 0x03AA, 0x0504, 0x00C2, 0x1F36, 0x002F,
+               0x1FA3, 0x1F82, 0x0386, 0x0518, 0x00E2, 0x1F30, 0x002B,
+               0x1FAD, 0x1F73, 0x0361, 0x0528, 0x0104, 0x1F2C, 0x0027,
+               0x1FB6, 0x1F65, 0x033C, 0x0538, 0x0127, 0x1F28, 0x0022,
+               0x1FC0, 0x1F58, 0x0316, 0x0545, 0x014B, 0x1F25, 0x001D,
+               0x1FC9, 0x1F4D, 0x02F0, 0x0551, 0x016F, 0x1F23, 0x0017,
+               0x1FD2, 0x1F43, 0x02C9, 0x055B, 0x0194, 0x1F22, 0x0011,
+               0x1FDB, 0x1F3B, 0x02A2, 0x0561, 0x01BA, 0x1F23, 0x000A,
+               0x1FE4, 0x1F34, 0x027A, 0x0567, 0x01E0, 0x1F24, 0x0003,
+               0x1FEC, 0x1F2E, 0x0254, 0x056A, 0x0206, 0x1F26, 0x1FFC,
+       },
+       [HS_LT_14_16_SCALE] = {
+               /* Luma */
+               0x002F, 0x1F0B, 0x01E7, 0x05BE, 0x01E7, 0x1F0B, 0x002F,
+               0x0035, 0x1F0D, 0x01BC, 0x05BD, 0x0213, 0x1F0A, 0x0028,
+               0x003A, 0x1F11, 0x0191, 0x05BA, 0x023F, 0x1F0A, 0x0021,
+               0x003F, 0x1F15, 0x0167, 0x05B3, 0x026C, 0x1F0C, 0x001A,
+               0x0043, 0x1F1B, 0x013E, 0x05AA, 0x0299, 0x1F0F, 0x0012,
+               0x0046, 0x1F21, 0x0116, 0x05A1, 0x02C6, 0x1F13, 0x0009,
+               0x0049, 0x1F28, 0x00EF, 0x0593, 0x02F4, 0x1F19, 0x0000,
+               0x004C, 0x1F30, 0x00C9, 0x0584, 0x0321, 0x1F20, 0x1FF6,
+               0x004E, 0x1F39, 0x00A4, 0x0572, 0x034D, 0x1F2A, 0x1FEC,
+               0x004F, 0x1F43, 0x0080, 0x055E, 0x037A, 0x1F34, 0x1FE2,
+               0x0050, 0x1F4D, 0x005E, 0x0548, 0x03A5, 0x1F41, 0x1FD7,
+               0x0050, 0x1F57, 0x003D, 0x0531, 0x03D1, 0x1F4F, 0x1FCB,
+               0x0050, 0x1F62, 0x001E, 0x0516, 0x03FB, 0x1F5F, 0x1FC0,
+               0x004F, 0x1F6D, 0x0000, 0x04FA, 0x0425, 0x1F71, 0x1FB4,
+               0x004E, 0x1F79, 0x1FE4, 0x04DC, 0x044D, 0x1F84, 0x1FA8,
+               0x004D, 0x1F84, 0x1FCA, 0x04BC, 0x0474, 0x1F99, 0x1F9C,
+               0x1F8C, 0x1FAE, 0x04C6, 0x04C6, 0x1FAE, 0x1F8C, 0x0000,
+               0x1F9C, 0x1F99, 0x0474, 0x04BC, 0x1FCA, 0x1F84, 0x004D,
+               0x1FA8, 0x1F84, 0x044D, 0x04DC, 0x1FE4, 0x1F79, 0x004E,
+               0x1FB4, 0x1F71, 0x0425, 0x04FA, 0x0000, 0x1F6D, 0x004F,
+               0x1FC0, 0x1F5F, 0x03FB, 0x0516, 0x001E, 0x1F62, 0x0050,
+               0x1FCB, 0x1F4F, 0x03D1, 0x0531, 0x003D, 0x1F57, 0x0050,
+               0x1FD7, 0x1F41, 0x03A5, 0x0548, 0x005E, 0x1F4D, 0x0050,
+               0x1FE2, 0x1F34, 0x037A, 0x055E, 0x0080, 0x1F43, 0x004F,
+               0x1FEC, 0x1F2A, 0x034D, 0x0572, 0x00A4, 0x1F39, 0x004E,
+               0x1FF6, 0x1F20, 0x0321, 0x0584, 0x00C9, 0x1F30, 0x004C,
+               0x0000, 0x1F19, 0x02F4, 0x0593, 0x00EF, 0x1F28, 0x0049,
+               0x0009, 0x1F13, 0x02C6, 0x05A1, 0x0116, 0x1F21, 0x0046,
+               0x0012, 0x1F0F, 0x0299, 0x05AA, 0x013E, 0x1F1B, 0x0043,
+               0x001A, 0x1F0C, 0x026C, 0x05B3, 0x0167, 0x1F15, 0x003F,
+               0x0021, 0x1F0A, 0x023F, 0x05BA, 0x0191, 0x1F11, 0x003A,
+               0x0028, 0x1F0A, 0x0213, 0x05BD, 0x01BC, 0x1F0D, 0x0035,
+               /* Chroma */
+               0x002F, 0x1F0B, 0x01E7, 0x05BE, 0x01E7, 0x1F0B, 0x002F,
+               0x0035, 0x1F0D, 0x01BC, 0x05BD, 0x0213, 0x1F0A, 0x0028,
+               0x003A, 0x1F11, 0x0191, 0x05BA, 0x023F, 0x1F0A, 0x0021,
+               0x003F, 0x1F15, 0x0167, 0x05B3, 0x026C, 0x1F0C, 0x001A,
+               0x0043, 0x1F1B, 0x013E, 0x05AA, 0x0299, 0x1F0F, 0x0012,
+               0x0046, 0x1F21, 0x0116, 0x05A1, 0x02C6, 0x1F13, 0x0009,
+               0x0049, 0x1F28, 0x00EF, 0x0593, 0x02F4, 0x1F19, 0x0000,
+               0x004C, 0x1F30, 0x00C9, 0x0584, 0x0321, 0x1F20, 0x1FF6,
+               0x004E, 0x1F39, 0x00A4, 0x0572, 0x034D, 0x1F2A, 0x1FEC,
+               0x004F, 0x1F43, 0x0080, 0x055E, 0x037A, 0x1F34, 0x1FE2,
+               0x0050, 0x1F4D, 0x005E, 0x0548, 0x03A5, 0x1F41, 0x1FD7,
+               0x0050, 0x1F57, 0x003D, 0x0531, 0x03D1, 0x1F4F, 0x1FCB,
+               0x0050, 0x1F62, 0x001E, 0x0516, 0x03FB, 0x1F5F, 0x1FC0,
+               0x004F, 0x1F6D, 0x0000, 0x04FA, 0x0425, 0x1F71, 0x1FB4,
+               0x004E, 0x1F79, 0x1FE4, 0x04DC, 0x044D, 0x1F84, 0x1FA8,
+               0x004D, 0x1F84, 0x1FCA, 0x04BC, 0x0474, 0x1F99, 0x1F9C,
+               0x1F8C, 0x1FAE, 0x04C6, 0x04C6, 0x1FAE, 0x1F8C, 0x0000,
+               0x1F9C, 0x1F99, 0x0474, 0x04BC, 0x1FCA, 0x1F84, 0x004D,
+               0x1FA8, 0x1F84, 0x044D, 0x04DC, 0x1FE4, 0x1F79, 0x004E,
+               0x1FB4, 0x1F71, 0x0425, 0x04FA, 0x0000, 0x1F6D, 0x004F,
+               0x1FC0, 0x1F5F, 0x03FB, 0x0516, 0x001E, 0x1F62, 0x0050,
+               0x1FCB, 0x1F4F, 0x03D1, 0x0531, 0x003D, 0x1F57, 0x0050,
+               0x1FD7, 0x1F41, 0x03A5, 0x0548, 0x005E, 0x1F4D, 0x0050,
+               0x1FE2, 0x1F34, 0x037A, 0x055E, 0x0080, 0x1F43, 0x004F,
+               0x1FEC, 0x1F2A, 0x034D, 0x0572, 0x00A4, 0x1F39, 0x004E,
+               0x1FF6, 0x1F20, 0x0321, 0x0584, 0x00C9, 0x1F30, 0x004C,
+               0x0000, 0x1F19, 0x02F4, 0x0593, 0x00EF, 0x1F28, 0x0049,
+               0x0009, 0x1F13, 0x02C6, 0x05A1, 0x0116, 0x1F21, 0x0046,
+               0x0012, 0x1F0F, 0x0299, 0x05AA, 0x013E, 0x1F1B, 0x0043,
+               0x001A, 0x1F0C, 0x026C, 0x05B3, 0x0167, 0x1F15, 0x003F,
+               0x0021, 0x1F0A, 0x023F, 0x05BA, 0x0191, 0x1F11, 0x003A,
+               0x0028, 0x1F0A, 0x0213, 0x05BD, 0x01BC, 0x1F0D, 0x0035,
+       },
+       [HS_LT_15_16_SCALE] = {
+               /* Luma */
+               0x005B, 0x1F0A, 0x0195, 0x060C, 0x0195, 0x1F0A, 0x005B,
+               0x005D, 0x1F13, 0x0166, 0x0609, 0x01C6, 0x1F03, 0x0058,
+               0x005F, 0x1F1C, 0x0138, 0x0605, 0x01F7, 0x1EFD, 0x0054,
+               0x0060, 0x1F26, 0x010B, 0x05FF, 0x0229, 0x1EF8, 0x004F,
+               0x0060, 0x1F31, 0x00DF, 0x05F5, 0x025C, 0x1EF5, 0x004A,
+               0x0060, 0x1F3D, 0x00B5, 0x05E8, 0x028F, 0x1EF3, 0x0044,
+               0x005F, 0x1F49, 0x008C, 0x05DA, 0x02C3, 0x1EF2, 0x003D,
+               0x005E, 0x1F56, 0x0065, 0x05C7, 0x02F6, 0x1EF4, 0x0036,
+               0x005C, 0x1F63, 0x003F, 0x05B3, 0x032B, 0x1EF7, 0x002D,
+               0x0059, 0x1F71, 0x001B, 0x059D, 0x035F, 0x1EFB, 0x0024,
+               0x0057, 0x1F7F, 0x1FF9, 0x0583, 0x0392, 0x1F02, 0x001A,
+               0x0053, 0x1F8D, 0x1FD9, 0x0567, 0x03C5, 0x1F0B, 0x0010,
+               0x0050, 0x1F9B, 0x1FBB, 0x0548, 0x03F8, 0x1F15, 0x0005,
+               0x004C, 0x1FA9, 0x1F9E, 0x0528, 0x042A, 0x1F22, 0x1FF9,
+               0x0048, 0x1FB7, 0x1F84, 0x0505, 0x045A, 0x1F31, 0x1FED,
+               0x0043, 0x1FC5, 0x1F6C, 0x04E0, 0x048A, 0x1F42, 0x1FE0,
+               0x1FD1, 0x1F50, 0x04DF, 0x04DF, 0x1F50, 0x1FD1, 0x0000,
+               0x1FE0, 0x1F42, 0x048A, 0x04E0, 0x1F6C, 0x1FC5, 0x0043,
+               0x1FED, 0x1F31, 0x045A, 0x0505, 0x1F84, 0x1FB7, 0x0048,
+               0x1FF9, 0x1F22, 0x042A, 0x0528, 0x1F9E, 0x1FA9, 0x004C,
+               0x0005, 0x1F15, 0x03F8, 0x0548, 0x1FBB, 0x1F9B, 0x0050,
+               0x0010, 0x1F0B, 0x03C5, 0x0567, 0x1FD9, 0x1F8D, 0x0053,
+               0x001A, 0x1F02, 0x0392, 0x0583, 0x1FF9, 0x1F7F, 0x0057,
+               0x0024, 0x1EFB, 0x035F, 0x059D, 0x001B, 0x1F71, 0x0059,
+               0x002D, 0x1EF7, 0x032B, 0x05B3, 0x003F, 0x1F63, 0x005C,
+               0x0036, 0x1EF4, 0x02F6, 0x05C7, 0x0065, 0x1F56, 0x005E,
+               0x003D, 0x1EF2, 0x02C3, 0x05DA, 0x008C, 0x1F49, 0x005F,
+               0x0044, 0x1EF3, 0x028F, 0x05E8, 0x00B5, 0x1F3D, 0x0060,
+               0x004A, 0x1EF5, 0x025C, 0x05F5, 0x00DF, 0x1F31, 0x0060,
+               0x004F, 0x1EF8, 0x0229, 0x05FF, 0x010B, 0x1F26, 0x0060,
+               0x0054, 0x1EFD, 0x01F7, 0x0605, 0x0138, 0x1F1C, 0x005F,
+               0x0058, 0x1F03, 0x01C6, 0x0609, 0x0166, 0x1F13, 0x005D,
+               /* Chroma */
+               0x005B, 0x1F0A, 0x0195, 0x060C, 0x0195, 0x1F0A, 0x005B,
+               0x005D, 0x1F13, 0x0166, 0x0609, 0x01C6, 0x1F03, 0x0058,
+               0x005F, 0x1F1C, 0x0138, 0x0605, 0x01F7, 0x1EFD, 0x0054,
+               0x0060, 0x1F26, 0x010B, 0x05FF, 0x0229, 0x1EF8, 0x004F,
+               0x0060, 0x1F31, 0x00DF, 0x05F5, 0x025C, 0x1EF5, 0x004A,
+               0x0060, 0x1F3D, 0x00B5, 0x05E8, 0x028F, 0x1EF3, 0x0044,
+               0x005F, 0x1F49, 0x008C, 0x05DA, 0x02C3, 0x1EF2, 0x003D,
+               0x005E, 0x1F56, 0x0065, 0x05C7, 0x02F6, 0x1EF4, 0x0036,
+               0x005C, 0x1F63, 0x003F, 0x05B3, 0x032B, 0x1EF7, 0x002D,
+               0x0059, 0x1F71, 0x001B, 0x059D, 0x035F, 0x1EFB, 0x0024,
+               0x0057, 0x1F7F, 0x1FF9, 0x0583, 0x0392, 0x1F02, 0x001A,
+               0x0053, 0x1F8D, 0x1FD9, 0x0567, 0x03C5, 0x1F0B, 0x0010,
+               0x0050, 0x1F9B, 0x1FBB, 0x0548, 0x03F8, 0x1F15, 0x0005,
+               0x004C, 0x1FA9, 0x1F9E, 0x0528, 0x042A, 0x1F22, 0x1FF9,
+               0x0048, 0x1FB7, 0x1F84, 0x0505, 0x045A, 0x1F31, 0x1FED,
+               0x0043, 0x1FC5, 0x1F6C, 0x04E0, 0x048A, 0x1F42, 0x1FE0,
+               0x1FD1, 0x1F50, 0x04DF, 0x04DF, 0x1F50, 0x1FD1, 0x0000,
+               0x1FE0, 0x1F42, 0x048A, 0x04E0, 0x1F6C, 0x1FC5, 0x0043,
+               0x1FED, 0x1F31, 0x045A, 0x0505, 0x1F84, 0x1FB7, 0x0048,
+               0x1FF9, 0x1F22, 0x042A, 0x0528, 0x1F9E, 0x1FA9, 0x004C,
+               0x0005, 0x1F15, 0x03F8, 0x0548, 0x1FBB, 0x1F9B, 0x0050,
+               0x0010, 0x1F0B, 0x03C5, 0x0567, 0x1FD9, 0x1F8D, 0x0053,
+               0x001A, 0x1F02, 0x0392, 0x0583, 0x1FF9, 0x1F7F, 0x0057,
+               0x0024, 0x1EFB, 0x035F, 0x059D, 0x001B, 0x1F71, 0x0059,
+               0x002D, 0x1EF7, 0x032B, 0x05B3, 0x003F, 0x1F63, 0x005C,
+               0x0036, 0x1EF4, 0x02F6, 0x05C7, 0x0065, 0x1F56, 0x005E,
+               0x003D, 0x1EF2, 0x02C3, 0x05DA, 0x008C, 0x1F49, 0x005F,
+               0x0044, 0x1EF3, 0x028F, 0x05E8, 0x00B5, 0x1F3D, 0x0060,
+               0x004A, 0x1EF5, 0x025C, 0x05F5, 0x00DF, 0x1F31, 0x0060,
+               0x004F, 0x1EF8, 0x0229, 0x05FF, 0x010B, 0x1F26, 0x0060,
+               0x0054, 0x1EFD, 0x01F7, 0x0605, 0x0138, 0x1F1C, 0x005F,
+               0x0058, 0x1F03, 0x01C6, 0x0609, 0x0166, 0x1F13, 0x005D,
+       },
+       [HS_LE_16_16_SCALE] = {
+               /* Luma */
+               0x006E, 0x1F24, 0x013E, 0x0660, 0x013E, 0x1F24, 0x006E,
+               0x006C, 0x1F33, 0x010B, 0x065D, 0x0172, 0x1F17, 0x0070,
+               0x0069, 0x1F41, 0x00DA, 0x0659, 0x01A8, 0x1F0B, 0x0070,
+               0x0066, 0x1F51, 0x00AA, 0x0650, 0x01DF, 0x1F00, 0x0070,
+               0x0062, 0x1F61, 0x007D, 0x0644, 0x0217, 0x1EF6, 0x006F,
+               0x005E, 0x1F71, 0x0051, 0x0636, 0x0250, 0x1EED, 0x006D,
+               0x0059, 0x1F81, 0x0028, 0x0624, 0x028A, 0x1EE5, 0x006B,
+               0x0054, 0x1F91, 0x0000, 0x060F, 0x02C5, 0x1EE0, 0x0067,
+               0x004E, 0x1FA2, 0x1FDB, 0x05F6, 0x0300, 0x1EDC, 0x0063,
+               0x0049, 0x1FB2, 0x1FB8, 0x05DB, 0x033B, 0x1EDA, 0x005D,
+               0x0043, 0x1FC3, 0x1F98, 0x05BC, 0x0376, 0x1ED9, 0x0057,
+               0x003D, 0x1FD3, 0x1F7A, 0x059B, 0x03B1, 0x1EDB, 0x004F,
+               0x0036, 0x1FE2, 0x1F5E, 0x0578, 0x03EC, 0x1EDF, 0x0047,
+               0x0030, 0x1FF1, 0x1F45, 0x0551, 0x0426, 0x1EE6, 0x003D,
+               0x002A, 0x0000, 0x1F2E, 0x0528, 0x045F, 0x1EEE, 0x0033,
+               0x0023, 0x000E, 0x1F19, 0x04FD, 0x0498, 0x1EFA, 0x0027,
+               0x001B, 0x1F04, 0x04E1, 0x04E1, 0x1F04, 0x001B, 0x0000,
+               0x0027, 0x1EFA, 0x0498, 0x04FD, 0x1F19, 0x000E, 0x0023,
+               0x0033, 0x1EEE, 0x045F, 0x0528, 0x1F2E, 0x0000, 0x002A,
+               0x003D, 0x1EE6, 0x0426, 0x0551, 0x1F45, 0x1FF1, 0x0030,
+               0x0047, 0x1EDF, 0x03EC, 0x0578, 0x1F5E, 0x1FE2, 0x0036,
+               0x004F, 0x1EDB, 0x03B1, 0x059B, 0x1F7A, 0x1FD3, 0x003D,
+               0x0057, 0x1ED9, 0x0376, 0x05BC, 0x1F98, 0x1FC3, 0x0043,
+               0x005D, 0x1EDA, 0x033B, 0x05DB, 0x1FB8, 0x1FB2, 0x0049,
+               0x0063, 0x1EDC, 0x0300, 0x05F6, 0x1FDB, 0x1FA2, 0x004E,
+               0x0067, 0x1EE0, 0x02C5, 0x060F, 0x0000, 0x1F91, 0x0054,
+               0x006B, 0x1EE5, 0x028A, 0x0624, 0x0028, 0x1F81, 0x0059,
+               0x006D, 0x1EED, 0x0250, 0x0636, 0x0051, 0x1F71, 0x005E,
+               0x006F, 0x1EF6, 0x0217, 0x0644, 0x007D, 0x1F61, 0x0062,
+               0x0070, 0x1F00, 0x01DF, 0x0650, 0x00AA, 0x1F51, 0x0066,
+               0x0070, 0x1F0B, 0x01A8, 0x0659, 0x00DA, 0x1F41, 0x0069,
+               0x0070, 0x1F17, 0x0172, 0x065D, 0x010B, 0x1F33, 0x006C,
+               /* Chroma */
+               0x006E, 0x1F24, 0x013E, 0x0660, 0x013E, 0x1F24, 0x006E,
+               0x006C, 0x1F33, 0x010B, 0x065D, 0x0172, 0x1F17, 0x0070,
+               0x0069, 0x1F41, 0x00DA, 0x0659, 0x01A8, 0x1F0B, 0x0070,
+               0x0066, 0x1F51, 0x00AA, 0x0650, 0x01DF, 0x1F00, 0x0070,
+               0x0062, 0x1F61, 0x007D, 0x0644, 0x0217, 0x1EF6, 0x006F,
+               0x005E, 0x1F71, 0x0051, 0x0636, 0x0250, 0x1EED, 0x006D,
+               0x0059, 0x1F81, 0x0028, 0x0624, 0x028A, 0x1EE5, 0x006B,
+               0x0054, 0x1F91, 0x0000, 0x060F, 0x02C5, 0x1EE0, 0x0067,
+               0x004E, 0x1FA2, 0x1FDB, 0x05F6, 0x0300, 0x1EDC, 0x0063,
+               0x0049, 0x1FB2, 0x1FB8, 0x05DB, 0x033B, 0x1EDA, 0x005D,
+               0x0043, 0x1FC3, 0x1F98, 0x05BC, 0x0376, 0x1ED9, 0x0057,
+               0x003D, 0x1FD3, 0x1F7A, 0x059B, 0x03B1, 0x1EDB, 0x004F,
+               0x0036, 0x1FE2, 0x1F5E, 0x0578, 0x03EC, 0x1EDF, 0x0047,
+               0x0030, 0x1FF1, 0x1F45, 0x0551, 0x0426, 0x1EE6, 0x003D,
+               0x002A, 0x0000, 0x1F2E, 0x0528, 0x045F, 0x1EEE, 0x0033,
+               0x0023, 0x000E, 0x1F19, 0x04FD, 0x0498, 0x1EFA, 0x0027,
+               0x001B, 0x1F04, 0x04E1, 0x04E1, 0x1F04, 0x001B, 0x0000,
+               0x0027, 0x1EFA, 0x0498, 0x04FD, 0x1F19, 0x000E, 0x0023,
+               0x0033, 0x1EEE, 0x045F, 0x0528, 0x1F2E, 0x0000, 0x002A,
+               0x003D, 0x1EE6, 0x0426, 0x0551, 0x1F45, 0x1FF1, 0x0030,
+               0x0047, 0x1EDF, 0x03EC, 0x0578, 0x1F5E, 0x1FE2, 0x0036,
+               0x004F, 0x1EDB, 0x03B1, 0x059B, 0x1F7A, 0x1FD3, 0x003D,
+               0x0057, 0x1ED9, 0x0376, 0x05BC, 0x1F98, 0x1FC3, 0x0043,
+               0x005D, 0x1EDA, 0x033B, 0x05DB, 0x1FB8, 0x1FB2, 0x0049,
+               0x0063, 0x1EDC, 0x0300, 0x05F6, 0x1FDB, 0x1FA2, 0x004E,
+               0x0067, 0x1EE0, 0x02C5, 0x060F, 0x0000, 0x1F91, 0x0054,
+               0x006B, 0x1EE5, 0x028A, 0x0624, 0x0028, 0x1F81, 0x0059,
+               0x006D, 0x1EED, 0x0250, 0x0636, 0x0051, 0x1F71, 0x005E,
+               0x006F, 0x1EF6, 0x0217, 0x0644, 0x007D, 0x1F61, 0x0062,
+               0x0070, 0x1F00, 0x01DF, 0x0650, 0x00AA, 0x1F51, 0x0066,
+               0x0070, 0x1F0B, 0x01A8, 0x0659, 0x00DA, 0x1F41, 0x0069,
+               0x0070, 0x1F17, 0x0172, 0x065D, 0x010B, 0x1F33, 0x006C,
+       },
+};
+
+/* vertical scaler coefficients */
+enum {
+       VS_UP_SCALE = 0,
+       VS_LT_9_16_SCALE,
+       VS_LT_10_16_SCALE,
+       VS_LT_11_16_SCALE,
+       VS_LT_12_16_SCALE,
+       VS_LT_13_16_SCALE,
+       VS_LT_14_16_SCALE,
+       VS_LT_15_16_SCALE,
+       VS_LT_16_16_SCALE,
+       VS_1_TO_1_SCALE,
+};
+
+static const u16 scaler_vs_coeffs[15][SC_NUM_PHASES * 2 * SC_V_NUM_TAPS] = {
+       [VS_UP_SCALE] = {
+               /* Luma */
+               0x1FD1, 0x00B1, 0x06FC, 0x00B1, 0x1FD1,
+               0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9,
+               0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0,
+               0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7,
+               0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE,
+               0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5,
+               0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C,
+               0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93,
+               0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A,
+               0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81,
+               0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79,
+               0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72,
+               0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B,
+               0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66,
+               0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62,
+               0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F,
+               0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000,
+               0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007,
+               0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007,
+               0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006,
+               0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005,
+               0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004,
+               0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002,
+               0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000,
+               0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD,
+               0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9,
+               0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5,
+               0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1,
+               0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB,
+               0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5,
+               0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF,
+               0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8,
+               /* Chroma */
+               0x1FD1, 0x00B1, 0x06FC, 0x00B1, 0x1FD1,
+               0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9,
+               0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0,
+               0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7,
+               0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE,
+               0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5,
+               0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C,
+               0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93,
+               0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A,
+               0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81,
+               0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79,
+               0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72,
+               0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B,
+               0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66,
+               0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62,
+               0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F,
+               0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000,
+               0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007,
+               0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007,
+               0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006,
+               0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005,
+               0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004,
+               0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002,
+               0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000,
+               0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD,
+               0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9,
+               0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5,
+               0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1,
+               0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB,
+               0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5,
+               0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF,
+               0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8,
+       },
+       [VS_LT_9_16_SCALE] = {
+               /* Luma */
+               0x001C, 0x01F6, 0x03DC, 0x01F6, 0x001C,
+               0x0018, 0x01DF, 0x03DB, 0x020C, 0x0022,
+               0x0013, 0x01C9, 0x03D9, 0x0223, 0x0028,
+               0x000F, 0x01B3, 0x03D6, 0x023A, 0x002E,
+               0x000C, 0x019D, 0x03D2, 0x0250, 0x0035,
+               0x0009, 0x0188, 0x03CC, 0x0266, 0x003D,
+               0x0006, 0x0173, 0x03C5, 0x027D, 0x0045,
+               0x0004, 0x015E, 0x03BD, 0x0293, 0x004E,
+               0x0002, 0x014A, 0x03B4, 0x02A8, 0x0058,
+               0x0000, 0x0136, 0x03AA, 0x02BE, 0x0062,
+               0x1FFF, 0x0123, 0x039E, 0x02D3, 0x006D,
+               0x1FFE, 0x0110, 0x0392, 0x02E8, 0x0078,
+               0x1FFD, 0x00FE, 0x0384, 0x02FC, 0x0085,
+               0x1FFD, 0x00ED, 0x0376, 0x030F, 0x0091,
+               0x1FFC, 0x00DC, 0x0367, 0x0322, 0x009F,
+               0x1FFC, 0x00CC, 0x0357, 0x0334, 0x00AD,
+               0x00BC, 0x0344, 0x0344, 0x00BC, 0x0000,
+               0x00AD, 0x0334, 0x0357, 0x00CC, 0x1FFC,
+               0x009F, 0x0322, 0x0367, 0x00DC, 0x1FFC,
+               0x0091, 0x030F, 0x0376, 0x00ED, 0x1FFD,
+               0x0085, 0x02FC, 0x0384, 0x00FE, 0x1FFD,
+               0x0078, 0x02E8, 0x0392, 0x0110, 0x1FFE,
+               0x006D, 0x02D3, 0x039E, 0x0123, 0x1FFF,
+               0x0062, 0x02BE, 0x03AA, 0x0136, 0x0000,
+               0x0058, 0x02A8, 0x03B4, 0x014A, 0x0002,
+               0x004E, 0x0293, 0x03BD, 0x015E, 0x0004,
+               0x0045, 0x027D, 0x03C5, 0x0173, 0x0006,
+               0x003D, 0x0266, 0x03CC, 0x0188, 0x0009,
+               0x0035, 0x0250, 0x03D2, 0x019D, 0x000C,
+               0x002E, 0x023A, 0x03D6, 0x01B3, 0x000F,
+               0x0028, 0x0223, 0x03D9, 0x01C9, 0x0013,
+               0x0022, 0x020C, 0x03DB, 0x01DF, 0x0018,
+               /* Chroma */
+               0x001C, 0x01F6, 0x03DC, 0x01F6, 0x001C,
+               0x0018, 0x01DF, 0x03DB, 0x020C, 0x0022,
+               0x0013, 0x01C9, 0x03D9, 0x0223, 0x0028,
+               0x000F, 0x01B3, 0x03D6, 0x023A, 0x002E,
+               0x000C, 0x019D, 0x03D2, 0x0250, 0x0035,
+               0x0009, 0x0188, 0x03CC, 0x0266, 0x003D,
+               0x0006, 0x0173, 0x03C5, 0x027D, 0x0045,
+               0x0004, 0x015E, 0x03BD, 0x0293, 0x004E,
+               0x0002, 0x014A, 0x03B4, 0x02A8, 0x0058,
+               0x0000, 0x0136, 0x03AA, 0x02BE, 0x0062,
+               0x1FFF, 0x0123, 0x039E, 0x02D3, 0x006D,
+               0x1FFE, 0x0110, 0x0392, 0x02E8, 0x0078,
+               0x1FFD, 0x00FE, 0x0384, 0x02FC, 0x0085,
+               0x1FFD, 0x00ED, 0x0376, 0x030F, 0x0091,
+               0x1FFC, 0x00DC, 0x0367, 0x0322, 0x009F,
+               0x1FFC, 0x00CC, 0x0357, 0x0334, 0x00AD,
+               0x00BC, 0x0344, 0x0344, 0x00BC, 0x0000,
+               0x00AD, 0x0334, 0x0357, 0x00CC, 0x1FFC,
+               0x009F, 0x0322, 0x0367, 0x00DC, 0x1FFC,
+               0x0091, 0x030F, 0x0376, 0x00ED, 0x1FFD,
+               0x0085, 0x02FC, 0x0384, 0x00FE, 0x1FFD,
+               0x0078, 0x02E8, 0x0392, 0x0110, 0x1FFE,
+               0x006D, 0x02D3, 0x039E, 0x0123, 0x1FFF,
+               0x0062, 0x02BE, 0x03AA, 0x0136, 0x0000,
+               0x0058, 0x02A8, 0x03B4, 0x014A, 0x0002,
+               0x004E, 0x0293, 0x03BD, 0x015E, 0x0004,
+               0x0045, 0x027D, 0x03C5, 0x0173, 0x0006,
+               0x003D, 0x0266, 0x03CC, 0x0188, 0x0009,
+               0x0035, 0x0250, 0x03D2, 0x019D, 0x000C,
+               0x002E, 0x023A, 0x03D6, 0x01B3, 0x000F,
+               0x0028, 0x0223, 0x03D9, 0x01C9, 0x0013,
+               0x0022, 0x020C, 0x03DB, 0x01DF, 0x0018,
+       },
+       [VS_LT_10_16_SCALE] = {
+               /* Luma */
+               0x0003, 0x01E9, 0x0428, 0x01E9, 0x0003,
+               0x0000, 0x01D0, 0x0426, 0x0203, 0x0007,
+               0x1FFD, 0x01B7, 0x0424, 0x021C, 0x000C,
+               0x1FFB, 0x019E, 0x0420, 0x0236, 0x0011,
+               0x1FF9, 0x0186, 0x041A, 0x0250, 0x0017,
+               0x1FF7, 0x016E, 0x0414, 0x026A, 0x001D,
+               0x1FF6, 0x0157, 0x040B, 0x0284, 0x0024,
+               0x1FF5, 0x0140, 0x0401, 0x029E, 0x002C,
+               0x1FF4, 0x012A, 0x03F6, 0x02B7, 0x0035,
+               0x1FF4, 0x0115, 0x03E9, 0x02D0, 0x003E,
+               0x1FF4, 0x0100, 0x03DB, 0x02E9, 0x0048,
+               0x1FF4, 0x00EC, 0x03CC, 0x0301, 0x0053,
+               0x1FF4, 0x00D9, 0x03BC, 0x0318, 0x005F,
+               0x1FF5, 0x00C7, 0x03AA, 0x032F, 0x006B,
+               0x1FF6, 0x00B5, 0x0398, 0x0345, 0x0078,
+               0x1FF6, 0x00A5, 0x0384, 0x035B, 0x0086,
+               0x0094, 0x036C, 0x036C, 0x0094, 0x0000,
+               0x0086, 0x035B, 0x0384, 0x00A5, 0x1FF6,
+               0x0078, 0x0345, 0x0398, 0x00B5, 0x1FF6,
+               0x006B, 0x032F, 0x03AA, 0x00C7, 0x1FF5,
+               0x005F, 0x0318, 0x03BC, 0x00D9, 0x1FF4,
+               0x0053, 0x0301, 0x03CC, 0x00EC, 0x1FF4,
+               0x0048, 0x02E9, 0x03DB, 0x0100, 0x1FF4,
+               0x003E, 0x02D0, 0x03E9, 0x0115, 0x1FF4,
+               0x0035, 0x02B7, 0x03F6, 0x012A, 0x1FF4,
+               0x002C, 0x029E, 0x0401, 0x0140, 0x1FF5,
+               0x0024, 0x0284, 0x040B, 0x0157, 0x1FF6,
+               0x001D, 0x026A, 0x0414, 0x016E, 0x1FF7,
+               0x0017, 0x0250, 0x041A, 0x0186, 0x1FF9,
+               0x0011, 0x0236, 0x0420, 0x019E, 0x1FFB,
+               0x000C, 0x021C, 0x0424, 0x01B7, 0x1FFD,
+               0x0007, 0x0203, 0x0426, 0x01D0, 0x0000,
+               /* Chroma */
+               0x0003, 0x01E9, 0x0428, 0x01E9, 0x0003,
+               0x0000, 0x01D0, 0x0426, 0x0203, 0x0007,
+               0x1FFD, 0x01B7, 0x0424, 0x021C, 0x000C,
+               0x1FFB, 0x019E, 0x0420, 0x0236, 0x0011,
+               0x1FF9, 0x0186, 0x041A, 0x0250, 0x0017,
+               0x1FF7, 0x016E, 0x0414, 0x026A, 0x001D,
+               0x1FF6, 0x0157, 0x040B, 0x0284, 0x0024,
+               0x1FF5, 0x0140, 0x0401, 0x029E, 0x002C,
+               0x1FF4, 0x012A, 0x03F6, 0x02B7, 0x0035,
+               0x1FF4, 0x0115, 0x03E9, 0x02D0, 0x003E,
+               0x1FF4, 0x0100, 0x03DB, 0x02E9, 0x0048,
+               0x1FF4, 0x00EC, 0x03CC, 0x0301, 0x0053,
+               0x1FF4, 0x00D9, 0x03BC, 0x0318, 0x005F,
+               0x1FF5, 0x00C7, 0x03AA, 0x032F, 0x006B,
+               0x1FF6, 0x00B5, 0x0398, 0x0345, 0x0078,
+               0x1FF6, 0x00A5, 0x0384, 0x035B, 0x0086,
+               0x0094, 0x036C, 0x036C, 0x0094, 0x0000,
+               0x0086, 0x035B, 0x0384, 0x00A5, 0x1FF6,
+               0x0078, 0x0345, 0x0398, 0x00B5, 0x1FF6,
+               0x006B, 0x032F, 0x03AA, 0x00C7, 0x1FF5,
+               0x005F, 0x0318, 0x03BC, 0x00D9, 0x1FF4,
+               0x0053, 0x0301, 0x03CC, 0x00EC, 0x1FF4,
+               0x0048, 0x02E9, 0x03DB, 0x0100, 0x1FF4,
+               0x003E, 0x02D0, 0x03E9, 0x0115, 0x1FF4,
+               0x0035, 0x02B7, 0x03F6, 0x012A, 0x1FF4,
+               0x002C, 0x029E, 0x0401, 0x0140, 0x1FF5,
+               0x0024, 0x0284, 0x040B, 0x0157, 0x1FF6,
+               0x001D, 0x026A, 0x0414, 0x016E, 0x1FF7,
+               0x0017, 0x0250, 0x041A, 0x0186, 0x1FF9,
+               0x0011, 0x0236, 0x0420, 0x019E, 0x1FFB,
+               0x000C, 0x021C, 0x0424, 0x01B7, 0x1FFD,
+               0x0007, 0x0203, 0x0426, 0x01D0, 0x0000,
+       },
+       [VS_LT_11_16_SCALE] = {
+               /* Luma */
+               0x1FEC, 0x01D6, 0x047C, 0x01D6, 0x1FEC,
+               0x1FEA, 0x01BA, 0x047B, 0x01F3, 0x1FEE,
+               0x1FE9, 0x019D, 0x0478, 0x0211, 0x1FF1,
+               0x1FE8, 0x0182, 0x0473, 0x022E, 0x1FF5,
+               0x1FE8, 0x0167, 0x046C, 0x024C, 0x1FF9,
+               0x1FE8, 0x014D, 0x0464, 0x026A, 0x1FFD,
+               0x1FE8, 0x0134, 0x0459, 0x0288, 0x0003,
+               0x1FE9, 0x011B, 0x044D, 0x02A6, 0x0009,
+               0x1FE9, 0x0104, 0x0440, 0x02C3, 0x0010,
+               0x1FEA, 0x00ED, 0x0430, 0x02E1, 0x0018,
+               0x1FEB, 0x00D7, 0x0420, 0x02FD, 0x0021,
+               0x1FED, 0x00C2, 0x040D, 0x0319, 0x002B,
+               0x1FEE, 0x00AE, 0x03F9, 0x0336, 0x0035,
+               0x1FF0, 0x009C, 0x03E3, 0x0350, 0x0041,
+               0x1FF1, 0x008A, 0x03CD, 0x036B, 0x004D,
+               0x1FF3, 0x0079, 0x03B5, 0x0384, 0x005B,
+               0x0069, 0x0397, 0x0397, 0x0069, 0x0000,
+               0x005B, 0x0384, 0x03B5, 0x0079, 0x1FF3,
+               0x004D, 0x036B, 0x03CD, 0x008A, 0x1FF1,
+               0x0041, 0x0350, 0x03E3, 0x009C, 0x1FF0,
+               0x0035, 0x0336, 0x03F9, 0x00AE, 0x1FEE,
+               0x002B, 0x0319, 0x040D, 0x00C2, 0x1FED,
+               0x0021, 0x02FD, 0x0420, 0x00D7, 0x1FEB,
+               0x0018, 0x02E1, 0x0430, 0x00ED, 0x1FEA,
+               0x0010, 0x02C3, 0x0440, 0x0104, 0x1FE9,
+               0x0009, 0x02A6, 0x044D, 0x011B, 0x1FE9,
+               0x0003, 0x0288, 0x0459, 0x0134, 0x1FE8,
+               0x1FFD, 0x026A, 0x0464, 0x014D, 0x1FE8,
+               0x1FF9, 0x024C, 0x046C, 0x0167, 0x1FE8,
+               0x1FF5, 0x022E, 0x0473, 0x0182, 0x1FE8,
+               0x1FF1, 0x0211, 0x0478, 0x019D, 0x1FE9,
+               0x1FEE, 0x01F3, 0x047B, 0x01BA, 0x1FEA,
+               /* Chroma */
+               0x1FEC, 0x01D6, 0x047C, 0x01D6, 0x1FEC,
+               0x1FEA, 0x01BA, 0x047B, 0x01F3, 0x1FEE,
+               0x1FE9, 0x019D, 0x0478, 0x0211, 0x1FF1,
+               0x1FE8, 0x0182, 0x0473, 0x022E, 0x1FF5,
+               0x1FE8, 0x0167, 0x046C, 0x024C, 0x1FF9,
+               0x1FE8, 0x014D, 0x0464, 0x026A, 0x1FFD,
+               0x1FE8, 0x0134, 0x0459, 0x0288, 0x0003,
+               0x1FE9, 0x011B, 0x044D, 0x02A6, 0x0009,
+               0x1FE9, 0x0104, 0x0440, 0x02C3, 0x0010,
+               0x1FEA, 0x00ED, 0x0430, 0x02E1, 0x0018,
+               0x1FEB, 0x00D7, 0x0420, 0x02FD, 0x0021,
+               0x1FED, 0x00C2, 0x040D, 0x0319, 0x002B,
+               0x1FEE, 0x00AE, 0x03F9, 0x0336, 0x0035,
+               0x1FF0, 0x009C, 0x03E3, 0x0350, 0x0041,
+               0x1FF1, 0x008A, 0x03CD, 0x036B, 0x004D,
+               0x1FF3, 0x0079, 0x03B5, 0x0384, 0x005B,
+               0x0069, 0x0397, 0x0397, 0x0069, 0x0000,
+               0x005B, 0x0384, 0x03B5, 0x0079, 0x1FF3,
+               0x004D, 0x036B, 0x03CD, 0x008A, 0x1FF1,
+               0x0041, 0x0350, 0x03E3, 0x009C, 0x1FF0,
+               0x0035, 0x0336, 0x03F9, 0x00AE, 0x1FEE,
+               0x002B, 0x0319, 0x040D, 0x00C2, 0x1FED,
+               0x0021, 0x02FD, 0x0420, 0x00D7, 0x1FEB,
+               0x0018, 0x02E1, 0x0430, 0x00ED, 0x1FEA,
+               0x0010, 0x02C3, 0x0440, 0x0104, 0x1FE9,
+               0x0009, 0x02A6, 0x044D, 0x011B, 0x1FE9,
+               0x0003, 0x0288, 0x0459, 0x0134, 0x1FE8,
+               0x1FFD, 0x026A, 0x0464, 0x014D, 0x1FE8,
+               0x1FF9, 0x024C, 0x046C, 0x0167, 0x1FE8,
+               0x1FF5, 0x022E, 0x0473, 0x0182, 0x1FE8,
+               0x1FF1, 0x0211, 0x0478, 0x019D, 0x1FE9,
+               0x1FEE, 0x01F3, 0x047B, 0x01BA, 0x1FEA,
+       },
+       [VS_LT_12_16_SCALE] = {
+               /* Luma */
+               0x1FD8, 0x01BC, 0x04D8, 0x01BC, 0x1FD8,
+               0x1FD8, 0x019C, 0x04D8, 0x01DC, 0x1FD8,
+               0x1FD8, 0x017D, 0x04D4, 0x01FE, 0x1FD9,
+               0x1FD9, 0x015E, 0x04CF, 0x0220, 0x1FDA,
+               0x1FDB, 0x0141, 0x04C7, 0x0241, 0x1FDC,
+               0x1FDC, 0x0125, 0x04BC, 0x0264, 0x1FDF,
+               0x1FDE, 0x0109, 0x04B0, 0x0286, 0x1FE3,
+               0x1FE0, 0x00EF, 0x04A1, 0x02A9, 0x1FE7,
+               0x1FE2, 0x00D6, 0x0491, 0x02CB, 0x1FEC,
+               0x1FE4, 0x00BE, 0x047E, 0x02EE, 0x1FF2,
+               0x1FE6, 0x00A7, 0x046A, 0x030F, 0x1FFA,
+               0x1FE9, 0x0092, 0x0453, 0x0330, 0x0002,
+               0x1FEB, 0x007E, 0x043B, 0x0351, 0x000B,
+               0x1FED, 0x006B, 0x0421, 0x0372, 0x0015,
+               0x1FEF, 0x005A, 0x0406, 0x0391, 0x0020,
+               0x1FF1, 0x0049, 0x03EA, 0x03AF, 0x002D,
+               0x003A, 0x03C6, 0x03C6, 0x003A, 0x0000,
+               0x002D, 0x03AF, 0x03EA, 0x0049, 0x1FF1,
+               0x0020, 0x0391, 0x0406, 0x005A, 0x1FEF,
+               0x0015, 0x0372, 0x0421, 0x006B, 0x1FED,
+               0x000B, 0x0351, 0x043B, 0x007E, 0x1FEB,
+               0x0002, 0x0330, 0x0453, 0x0092, 0x1FE9,
+               0x1FFA, 0x030F, 0x046A, 0x00A7, 0x1FE6,
+               0x1FF2, 0x02EE, 0x047E, 0x00BE, 0x1FE4,
+               0x1FEC, 0x02CB, 0x0491, 0x00D6, 0x1FE2,
+               0x1FE7, 0x02A9, 0x04A1, 0x00EF, 0x1FE0,
+               0x1FE3, 0x0286, 0x04B0, 0x0109, 0x1FDE,
+               0x1FDF, 0x0264, 0x04BC, 0x0125, 0x1FDC,
+               0x1FDC, 0x0241, 0x04C7, 0x0141, 0x1FDB,
+               0x1FDA, 0x0220, 0x04CF, 0x015E, 0x1FD9,
+               0x1FD9, 0x01FE, 0x04D4, 0x017D, 0x1FD8,
+               0x1FD8, 0x01DC, 0x04D8, 0x019C, 0x1FD8,
+               /* Chroma */
+               0x1FD8, 0x01BC, 0x04D8, 0x01BC, 0x1FD8,
+               0x1FD8, 0x019C, 0x04D8, 0x01DC, 0x1FD8,
+               0x1FD8, 0x017D, 0x04D4, 0x01FE, 0x1FD9,
+               0x1FD9, 0x015E, 0x04CF, 0x0220, 0x1FDA,
+               0x1FDB, 0x0141, 0x04C7, 0x0241, 0x1FDC,
+               0x1FDC, 0x0125, 0x04BC, 0x0264, 0x1FDF,
+               0x1FDE, 0x0109, 0x04B0, 0x0286, 0x1FE3,
+               0x1FE0, 0x00EF, 0x04A1, 0x02A9, 0x1FE7,
+               0x1FE2, 0x00D6, 0x0491, 0x02CB, 0x1FEC,
+               0x1FE4, 0x00BE, 0x047E, 0x02EE, 0x1FF2,
+               0x1FE6, 0x00A7, 0x046A, 0x030F, 0x1FFA,
+               0x1FE9, 0x0092, 0x0453, 0x0330, 0x0002,
+               0x1FEB, 0x007E, 0x043B, 0x0351, 0x000B,
+               0x1FED, 0x006B, 0x0421, 0x0372, 0x0015,
+               0x1FEF, 0x005A, 0x0406, 0x0391, 0x0020,
+               0x1FF1, 0x0049, 0x03EA, 0x03AF, 0x002D,
+               0x003A, 0x03C6, 0x03C6, 0x003A, 0x0000,
+               0x002D, 0x03AF, 0x03EA, 0x0049, 0x1FF1,
+               0x0020, 0x0391, 0x0406, 0x005A, 0x1FEF,
+               0x0015, 0x0372, 0x0421, 0x006B, 0x1FED,
+               0x000B, 0x0351, 0x043B, 0x007E, 0x1FEB,
+               0x0002, 0x0330, 0x0453, 0x0092, 0x1FE9,
+               0x1FFA, 0x030F, 0x046A, 0x00A7, 0x1FE6,
+               0x1FF2, 0x02EE, 0x047E, 0x00BE, 0x1FE4,
+               0x1FEC, 0x02CB, 0x0491, 0x00D6, 0x1FE2,
+               0x1FE7, 0x02A9, 0x04A1, 0x00EF, 0x1FE0,
+               0x1FE3, 0x0286, 0x04B0, 0x0109, 0x1FDE,
+               0x1FDF, 0x0264, 0x04BC, 0x0125, 0x1FDC,
+               0x1FDC, 0x0241, 0x04C7, 0x0141, 0x1FDB,
+               0x1FDA, 0x0220, 0x04CF, 0x015E, 0x1FD9,
+               0x1FD9, 0x01FE, 0x04D4, 0x017D, 0x1FD8,
+               0x1FD8, 0x01DC, 0x04D8, 0x019C, 0x1FD8,
+       },
+       [VS_LT_13_16_SCALE] = {
+               /* Luma */
+               0x1FC8, 0x0199, 0x053E, 0x0199, 0x1FC8,
+               0x1FCA, 0x0175, 0x053E, 0x01BD, 0x1FC6,
+               0x1FCD, 0x0153, 0x0539, 0x01E2, 0x1FC5,
+               0x1FCF, 0x0132, 0x0532, 0x0209, 0x1FC4,
+               0x1FD2, 0x0112, 0x0529, 0x022F, 0x1FC4,
+               0x1FD5, 0x00F4, 0x051C, 0x0256, 0x1FC5,
+               0x1FD8, 0x00D7, 0x050D, 0x027E, 0x1FC6,
+               0x1FDC, 0x00BB, 0x04FB, 0x02A6, 0x1FC8,
+               0x1FDF, 0x00A1, 0x04E7, 0x02CE, 0x1FCB,
+               0x1FE2, 0x0089, 0x04D1, 0x02F5, 0x1FCF,
+               0x1FE5, 0x0072, 0x04B8, 0x031D, 0x1FD4,
+               0x1FE8, 0x005D, 0x049E, 0x0344, 0x1FD9,
+               0x1FEB, 0x0049, 0x0480, 0x036B, 0x1FE1,
+               0x1FEE, 0x0037, 0x0462, 0x0390, 0x1FE9,
+               0x1FF0, 0x0026, 0x0442, 0x03B6, 0x1FF2,
+               0x1FF2, 0x0017, 0x0420, 0x03DA, 0x1FFD,
+               0x0009, 0x03F7, 0x03F7, 0x0009, 0x0000,
+               0x1FFD, 0x03DA, 0x0420, 0x0017, 0x1FF2,
+               0x1FF2, 0x03B6, 0x0442, 0x0026, 0x1FF0,
+               0x1FE9, 0x0390, 0x0462, 0x0037, 0x1FEE,
+               0x1FE1, 0x036B, 0x0480, 0x0049, 0x1FEB,
+               0x1FD9, 0x0344, 0x049E, 0x005D, 0x1FE8,
+               0x1FD4, 0x031D, 0x04B8, 0x0072, 0x1FE5,
+               0x1FCF, 0x02F5, 0x04D1, 0x0089, 0x1FE2,
+               0x1FCB, 0x02CE, 0x04E7, 0x00A1, 0x1FDF,
+               0x1FC8, 0x02A6, 0x04FB, 0x00BB, 0x1FDC,
+               0x1FC6, 0x027E, 0x050D, 0x00D7, 0x1FD8,
+               0x1FC5, 0x0256, 0x051C, 0x00F4, 0x1FD5,
+               0x1FC4, 0x022F, 0x0529, 0x0112, 0x1FD2,
+               0x1FC4, 0x0209, 0x0532, 0x0132, 0x1FCF,
+               0x1FC5, 0x01E2, 0x0539, 0x0153, 0x1FCD,
+               0x1FC6, 0x01BD, 0x053E, 0x0175, 0x1FCA,
+               /* Chroma */
+               0x1FC8, 0x0199, 0x053E, 0x0199, 0x1FC8,
+               0x1FCA, 0x0175, 0x053E, 0x01BD, 0x1FC6,
+               0x1FCD, 0x0153, 0x0539, 0x01E2, 0x1FC5,
+               0x1FCF, 0x0132, 0x0532, 0x0209, 0x1FC4,
+               0x1FD2, 0x0112, 0x0529, 0x022F, 0x1FC4,
+               0x1FD5, 0x00F4, 0x051C, 0x0256, 0x1FC5,
+               0x1FD8, 0x00D7, 0x050D, 0x027E, 0x1FC6,
+               0x1FDC, 0x00BB, 0x04FB, 0x02A6, 0x1FC8,
+               0x1FDF, 0x00A1, 0x04E7, 0x02CE, 0x1FCB,
+               0x1FE2, 0x0089, 0x04D1, 0x02F5, 0x1FCF,
+               0x1FE5, 0x0072, 0x04B8, 0x031D, 0x1FD4,
+               0x1FE8, 0x005D, 0x049E, 0x0344, 0x1FD9,
+               0x1FEB, 0x0049, 0x0480, 0x036B, 0x1FE1,
+               0x1FEE, 0x0037, 0x0462, 0x0390, 0x1FE9,
+               0x1FF0, 0x0026, 0x0442, 0x03B6, 0x1FF2,
+               0x1FF2, 0x0017, 0x0420, 0x03DA, 0x1FFD,
+               0x0009, 0x03F7, 0x03F7, 0x0009, 0x0000,
+               0x1FFD, 0x03DA, 0x0420, 0x0017, 0x1FF2,
+               0x1FF2, 0x03B6, 0x0442, 0x0026, 0x1FF0,
+               0x1FE9, 0x0390, 0x0462, 0x0037, 0x1FEE,
+               0x1FE1, 0x036B, 0x0480, 0x0049, 0x1FEB,
+               0x1FD9, 0x0344, 0x049E, 0x005D, 0x1FE8,
+               0x1FD4, 0x031D, 0x04B8, 0x0072, 0x1FE5,
+               0x1FCF, 0x02F5, 0x04D1, 0x0089, 0x1FE2,
+               0x1FCB, 0x02CE, 0x04E7, 0x00A1, 0x1FDF,
+               0x1FC8, 0x02A6, 0x04FB, 0x00BB, 0x1FDC,
+               0x1FC6, 0x027E, 0x050D, 0x00D7, 0x1FD8,
+               0x1FC5, 0x0256, 0x051C, 0x00F4, 0x1FD5,
+               0x1FC4, 0x022F, 0x0529, 0x0112, 0x1FD2,
+               0x1FC4, 0x0209, 0x0532, 0x0132, 0x1FCF,
+               0x1FC5, 0x01E2, 0x0539, 0x0153, 0x1FCD,
+               0x1FC6, 0x01BD, 0x053E, 0x0175, 0x1FCA,
+       },
+       [VS_LT_14_16_SCALE] = {
+               /* Luma */
+               0x1FBF, 0x016C, 0x05AA, 0x016C, 0x1FBF,
+               0x1FC3, 0x0146, 0x05A8, 0x0194, 0x1FBB,
+               0x1FC7, 0x0121, 0x05A3, 0x01BD, 0x1FB8,
+               0x1FCB, 0x00FD, 0x059B, 0x01E8, 0x1FB5,
+               0x1FD0, 0x00DC, 0x058F, 0x0213, 0x1FB2,
+               0x1FD4, 0x00BC, 0x0580, 0x0240, 0x1FB0,
+               0x1FD8, 0x009E, 0x056E, 0x026D, 0x1FAF,
+               0x1FDC, 0x0082, 0x055A, 0x029A, 0x1FAE,
+               0x1FE0, 0x0067, 0x0542, 0x02C9, 0x1FAE,
+               0x1FE4, 0x004F, 0x0528, 0x02F6, 0x1FAF,
+               0x1FE8, 0x0038, 0x050A, 0x0325, 0x1FB1,
+               0x1FEB, 0x0024, 0x04EB, 0x0352, 0x1FB4,
+               0x1FEE, 0x0011, 0x04C8, 0x0380, 0x1FB9,
+               0x1FF1, 0x0000, 0x04A4, 0x03AC, 0x1FBF,
+               0x1FF4, 0x1FF1, 0x047D, 0x03D8, 0x1FC6,
+               0x1FF6, 0x1FE4, 0x0455, 0x0403, 0x1FCE,
+               0x1FD8, 0x0428, 0x0428, 0x1FD8, 0x0000,
+               0x1FCE, 0x0403, 0x0455, 0x1FE4, 0x1FF6,
+               0x1FC6, 0x03D8, 0x047D, 0x1FF1, 0x1FF4,
+               0x1FBF, 0x03AC, 0x04A4, 0x0000, 0x1FF1,
+               0x1FB9, 0x0380, 0x04C8, 0x0011, 0x1FEE,
+               0x1FB4, 0x0352, 0x04EB, 0x0024, 0x1FEB,
+               0x1FB1, 0x0325, 0x050A, 0x0038, 0x1FE8,
+               0x1FAF, 0x02F6, 0x0528, 0x004F, 0x1FE4,
+               0x1FAE, 0x02C9, 0x0542, 0x0067, 0x1FE0,
+               0x1FAE, 0x029A, 0x055A, 0x0082, 0x1FDC,
+               0x1FAF, 0x026D, 0x056E, 0x009E, 0x1FD8,
+               0x1FB0, 0x0240, 0x0580, 0x00BC, 0x1FD4,
+               0x1FB2, 0x0213, 0x058F, 0x00DC, 0x1FD0,
+               0x1FB5, 0x01E8, 0x059B, 0x00FD, 0x1FCB,
+               0x1FB8, 0x01BD, 0x05A3, 0x0121, 0x1FC7,
+               0x1FBB, 0x0194, 0x05A8, 0x0146, 0x1FC3,
+               /* Chroma */
+               0x1FBF, 0x016C, 0x05AA, 0x016C, 0x1FBF,
+               0x1FC3, 0x0146, 0x05A8, 0x0194, 0x1FBB,
+               0x1FC7, 0x0121, 0x05A3, 0x01BD, 0x1FB8,
+               0x1FCB, 0x00FD, 0x059B, 0x01E8, 0x1FB5,
+               0x1FD0, 0x00DC, 0x058F, 0x0213, 0x1FB2,
+               0x1FD4, 0x00BC, 0x0580, 0x0240, 0x1FB0,
+               0x1FD8, 0x009E, 0x056E, 0x026D, 0x1FAF,
+               0x1FDC, 0x0082, 0x055A, 0x029A, 0x1FAE,
+               0x1FE0, 0x0067, 0x0542, 0x02C9, 0x1FAE,
+               0x1FE4, 0x004F, 0x0528, 0x02F6, 0x1FAF,
+               0x1FE8, 0x0038, 0x050A, 0x0325, 0x1FB1,
+               0x1FEB, 0x0024, 0x04EB, 0x0352, 0x1FB4,
+               0x1FEE, 0x0011, 0x04C8, 0x0380, 0x1FB9,
+               0x1FF1, 0x0000, 0x04A4, 0x03AC, 0x1FBF,
+               0x1FF4, 0x1FF1, 0x047D, 0x03D8, 0x1FC6,
+               0x1FF6, 0x1FE4, 0x0455, 0x0403, 0x1FCE,
+               0x1FD8, 0x0428, 0x0428, 0x1FD8, 0x0000,
+               0x1FCE, 0x0403, 0x0455, 0x1FE4, 0x1FF6,
+               0x1FC6, 0x03D8, 0x047D, 0x1FF1, 0x1FF4,
+               0x1FBF, 0x03AC, 0x04A4, 0x0000, 0x1FF1,
+               0x1FB9, 0x0380, 0x04C8, 0x0011, 0x1FEE,
+               0x1FB4, 0x0352, 0x04EB, 0x0024, 0x1FEB,
+               0x1FB1, 0x0325, 0x050A, 0x0038, 0x1FE8,
+               0x1FAF, 0x02F6, 0x0528, 0x004F, 0x1FE4,
+               0x1FAE, 0x02C9, 0x0542, 0x0067, 0x1FE0,
+               0x1FAE, 0x029A, 0x055A, 0x0082, 0x1FDC,
+               0x1FAF, 0x026D, 0x056E, 0x009E, 0x1FD8,
+               0x1FB0, 0x0240, 0x0580, 0x00BC, 0x1FD4,
+               0x1FB2, 0x0213, 0x058F, 0x00DC, 0x1FD0,
+               0x1FB5, 0x01E8, 0x059B, 0x00FD, 0x1FCB,
+               0x1FB8, 0x01BD, 0x05A3, 0x0121, 0x1FC7,
+               0x1FBB, 0x0194, 0x05A8, 0x0146, 0x1FC3,
+       },
+       [VS_LT_15_16_SCALE] = {
+               /* Luma */
+               0x1FBD, 0x0136, 0x061A, 0x0136, 0x1FBD,
+               0x1FC3, 0x010D, 0x0617, 0x0161, 0x1FB8,
+               0x1FC9, 0x00E6, 0x0611, 0x018E, 0x1FB2,
+               0x1FCE, 0x00C1, 0x0607, 0x01BD, 0x1FAD,
+               0x1FD4, 0x009E, 0x05F9, 0x01ED, 0x1FA8,
+               0x1FD9, 0x007D, 0x05E8, 0x021F, 0x1FA3,
+               0x1FDE, 0x005E, 0x05D3, 0x0252, 0x1F9F,
+               0x1FE2, 0x0042, 0x05BC, 0x0285, 0x1F9B,
+               0x1FE7, 0x0029, 0x059F, 0x02B9, 0x1F98,
+               0x1FEA, 0x0011, 0x0580, 0x02EF, 0x1F96,
+               0x1FEE, 0x1FFC, 0x055D, 0x0324, 0x1F95,
+               0x1FF1, 0x1FE9, 0x0538, 0x0359, 0x1F95,
+               0x1FF4, 0x1FD8, 0x0510, 0x038E, 0x1F96,
+               0x1FF7, 0x1FC9, 0x04E5, 0x03C2, 0x1F99,
+               0x1FF9, 0x1FBD, 0x04B8, 0x03F5, 0x1F9D,
+               0x1FFB, 0x1FB2, 0x0489, 0x0428, 0x1FA2,
+               0x1FAA, 0x0456, 0x0456, 0x1FAA, 0x0000,
+               0x1FA2, 0x0428, 0x0489, 0x1FB2, 0x1FFB,
+               0x1F9D, 0x03F5, 0x04B8, 0x1FBD, 0x1FF9,
+               0x1F99, 0x03C2, 0x04E5, 0x1FC9, 0x1FF7,
+               0x1F96, 0x038E, 0x0510, 0x1FD8, 0x1FF4,
+               0x1F95, 0x0359, 0x0538, 0x1FE9, 0x1FF1,
+               0x1F95, 0x0324, 0x055D, 0x1FFC, 0x1FEE,
+               0x1F96, 0x02EF, 0x0580, 0x0011, 0x1FEA,
+               0x1F98, 0x02B9, 0x059F, 0x0029, 0x1FE7,
+               0x1F9B, 0x0285, 0x05BC, 0x0042, 0x1FE2,
+               0x1F9F, 0x0252, 0x05D3, 0x005E, 0x1FDE,
+               0x1FA3, 0x021F, 0x05E8, 0x007D, 0x1FD9,
+               0x1FA8, 0x01ED, 0x05F9, 0x009E, 0x1FD4,
+               0x1FAD, 0x01BD, 0x0607, 0x00C1, 0x1FCE,
+               0x1FB2, 0x018E, 0x0611, 0x00E6, 0x1FC9,
+               0x1FB8, 0x0161, 0x0617, 0x010D, 0x1FC3,
+               /* Chroma */
+               0x1FBD, 0x0136, 0x061A, 0x0136, 0x1FBD,
+               0x1FC3, 0x010D, 0x0617, 0x0161, 0x1FB8,
+               0x1FC9, 0x00E6, 0x0611, 0x018E, 0x1FB2,
+               0x1FCE, 0x00C1, 0x0607, 0x01BD, 0x1FAD,
+               0x1FD4, 0x009E, 0x05F9, 0x01ED, 0x1FA8,
+               0x1FD9, 0x007D, 0x05E8, 0x021F, 0x1FA3,
+               0x1FDE, 0x005E, 0x05D3, 0x0252, 0x1F9F,
+               0x1FE2, 0x0042, 0x05BC, 0x0285, 0x1F9B,
+               0x1FE7, 0x0029, 0x059F, 0x02B9, 0x1F98,
+               0x1FEA, 0x0011, 0x0580, 0x02EF, 0x1F96,
+               0x1FEE, 0x1FFC, 0x055D, 0x0324, 0x1F95,
+               0x1FF1, 0x1FE9, 0x0538, 0x0359, 0x1F95,
+               0x1FF4, 0x1FD8, 0x0510, 0x038E, 0x1F96,
+               0x1FF7, 0x1FC9, 0x04E5, 0x03C2, 0x1F99,
+               0x1FF9, 0x1FBD, 0x04B8, 0x03F5, 0x1F9D,
+               0x1FFB, 0x1FB2, 0x0489, 0x0428, 0x1FA2,
+               0x1FAA, 0x0456, 0x0456, 0x1FAA, 0x0000,
+               0x1FA2, 0x0428, 0x0489, 0x1FB2, 0x1FFB,
+               0x1F9D, 0x03F5, 0x04B8, 0x1FBD, 0x1FF9,
+               0x1F99, 0x03C2, 0x04E5, 0x1FC9, 0x1FF7,
+               0x1F96, 0x038E, 0x0510, 0x1FD8, 0x1FF4,
+               0x1F95, 0x0359, 0x0538, 0x1FE9, 0x1FF1,
+               0x1F95, 0x0324, 0x055D, 0x1FFC, 0x1FEE,
+               0x1F96, 0x02EF, 0x0580, 0x0011, 0x1FEA,
+               0x1F98, 0x02B9, 0x059F, 0x0029, 0x1FE7,
+               0x1F9B, 0x0285, 0x05BC, 0x0042, 0x1FE2,
+               0x1F9F, 0x0252, 0x05D3, 0x005E, 0x1FDE,
+               0x1FA3, 0x021F, 0x05E8, 0x007D, 0x1FD9,
+               0x1FA8, 0x01ED, 0x05F9, 0x009E, 0x1FD4,
+               0x1FAD, 0x01BD, 0x0607, 0x00C1, 0x1FCE,
+               0x1FB2, 0x018E, 0x0611, 0x00E6, 0x1FC9,
+               0x1FB8, 0x0161, 0x0617, 0x010D, 0x1FC3,
+       },
+       [VS_LT_16_16_SCALE] = {
+               /* Luma */
+               0x1FC3, 0x00F8, 0x068A, 0x00F8, 0x1FC3,
+               0x1FCA, 0x00CC, 0x0689, 0x0125, 0x1FBC,
+               0x1FD1, 0x00A3, 0x0681, 0x0156, 0x1FB5,
+               0x1FD7, 0x007D, 0x0676, 0x0188, 0x1FAE,
+               0x1FDD, 0x005A, 0x0666, 0x01BD, 0x1FA6,
+               0x1FE3, 0x0039, 0x0652, 0x01F3, 0x1F9F,
+               0x1FE8, 0x001B, 0x0639, 0x022C, 0x1F98,
+               0x1FEC, 0x0000, 0x061D, 0x0265, 0x1F92,
+               0x1FF0, 0x1FE8, 0x05FC, 0x02A0, 0x1F8C,
+               0x1FF4, 0x1FD2, 0x05D7, 0x02DC, 0x1F87,
+               0x1FF7, 0x1FBF, 0x05AF, 0x0319, 0x1F82,
+               0x1FFA, 0x1FAF, 0x0583, 0x0356, 0x1F7E,
+               0x1FFC, 0x1FA1, 0x0554, 0x0393, 0x1F7C,
+               0x1FFE, 0x1F95, 0x0523, 0x03CF, 0x1F7B,
+               0x0000, 0x1F8C, 0x04EE, 0x040B, 0x1F7B,
+               0x0001, 0x1F85, 0x04B8, 0x0446, 0x1F7C,
+               0x1F80, 0x0480, 0x0480, 0x1F80, 0x0000,
+               0x1F7C, 0x0446, 0x04B8, 0x1F85, 0x0001,
+               0x1F7B, 0x040B, 0x04EE, 0x1F8C, 0x0000,
+               0x1F7B, 0x03CF, 0x0523, 0x1F95, 0x1FFE,
+               0x1F7C, 0x0393, 0x0554, 0x1FA1, 0x1FFC,
+               0x1F7E, 0x0356, 0x0583, 0x1FAF, 0x1FFA,
+               0x1F82, 0x0319, 0x05AF, 0x1FBF, 0x1FF7,
+               0x1F87, 0x02DC, 0x05D7, 0x1FD2, 0x1FF4,
+               0x1F8C, 0x02A0, 0x05FC, 0x1FE8, 0x1FF0,
+               0x1F92, 0x0265, 0x061D, 0x0000, 0x1FEC,
+               0x1F98, 0x022C, 0x0639, 0x001B, 0x1FE8,
+               0x1F9F, 0x01F3, 0x0652, 0x0039, 0x1FE3,
+               0x1FA6, 0x01BD, 0x0666, 0x005A, 0x1FDD,
+               0x1FAE, 0x0188, 0x0676, 0x007D, 0x1FD7,
+               0x1FB5, 0x0156, 0x0681, 0x00A3, 0x1FD1,
+               0x1FBC, 0x0125, 0x0689, 0x00CC, 0x1FCA,
+               /* Chroma */
+               0x1FC3, 0x00F8, 0x068A, 0x00F8, 0x1FC3,
+               0x1FCA, 0x00CC, 0x0689, 0x0125, 0x1FBC,
+               0x1FD1, 0x00A3, 0x0681, 0x0156, 0x1FB5,
+               0x1FD7, 0x007D, 0x0676, 0x0188, 0x1FAE,
+               0x1FDD, 0x005A, 0x0666, 0x01BD, 0x1FA6,
+               0x1FE3, 0x0039, 0x0652, 0x01F3, 0x1F9F,
+               0x1FE8, 0x001B, 0x0639, 0x022C, 0x1F98,
+               0x1FEC, 0x0000, 0x061D, 0x0265, 0x1F92,
+               0x1FF0, 0x1FE8, 0x05FC, 0x02A0, 0x1F8C,
+               0x1FF4, 0x1FD2, 0x05D7, 0x02DC, 0x1F87,
+               0x1FF7, 0x1FBF, 0x05AF, 0x0319, 0x1F82,
+               0x1FFA, 0x1FAF, 0x0583, 0x0356, 0x1F7E,
+               0x1FFC, 0x1FA1, 0x0554, 0x0393, 0x1F7C,
+               0x1FFE, 0x1F95, 0x0523, 0x03CF, 0x1F7B,
+               0x0000, 0x1F8C, 0x04EE, 0x040B, 0x1F7B,
+               0x0001, 0x1F85, 0x04B8, 0x0446, 0x1F7C,
+               0x1F80, 0x0480, 0x0480, 0x1F80, 0x0000,
+               0x1F7C, 0x0446, 0x04B8, 0x1F85, 0x0001,
+               0x1F7B, 0x040B, 0x04EE, 0x1F8C, 0x0000,
+               0x1F7B, 0x03CF, 0x0523, 0x1F95, 0x1FFE,
+               0x1F7C, 0x0393, 0x0554, 0x1FA1, 0x1FFC,
+               0x1F7E, 0x0356, 0x0583, 0x1FAF, 0x1FFA,
+               0x1F82, 0x0319, 0x05AF, 0x1FBF, 0x1FF7,
+               0x1F87, 0x02DC, 0x05D7, 0x1FD2, 0x1FF4,
+               0x1F8C, 0x02A0, 0x05FC, 0x1FE8, 0x1FF0,
+               0x1F92, 0x0265, 0x061D, 0x0000, 0x1FEC,
+               0x1F98, 0x022C, 0x0639, 0x001B, 0x1FE8,
+               0x1F9F, 0x01F3, 0x0652, 0x0039, 0x1FE3,
+               0x1FA6, 0x01BD, 0x0666, 0x005A, 0x1FDD,
+               0x1FAE, 0x0188, 0x0676, 0x007D, 0x1FD7,
+               0x1FB5, 0x0156, 0x0681, 0x00A3, 0x1FD1,
+               0x1FBC, 0x0125, 0x0689, 0x00CC, 0x1FCA,
+       },
+       [VS_1_TO_1_SCALE] = {
+               /* Luma */
+               0x0000, 0x0000, 0x0800, 0x0000, 0x0000,
+               0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9,
+               0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0,
+               0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7,
+               0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE,
+               0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5,
+               0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C,
+               0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93,
+               0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A,
+               0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81,
+               0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79,
+               0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72,
+               0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B,
+               0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66,
+               0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62,
+               0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F,
+               0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000,
+               0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007,
+               0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007,
+               0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006,
+               0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005,
+               0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004,
+               0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002,
+               0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000,
+               0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD,
+               0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9,
+               0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5,
+               0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1,
+               0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB,
+               0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5,
+               0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF,
+               0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8,
+               /* Chroma */
+               0x0000, 0x0000, 0x0800, 0x0000, 0x0000,
+               0x1FD8, 0x0085, 0x06F9, 0x00E1, 0x1FC9,
+               0x1FDF, 0x005B, 0x06F2, 0x0114, 0x1FC0,
+               0x1FE5, 0x0035, 0x06E5, 0x014A, 0x1FB7,
+               0x1FEB, 0x0012, 0x06D3, 0x0182, 0x1FAE,
+               0x1FF1, 0x1FF3, 0x06BA, 0x01BD, 0x1FA5,
+               0x1FF5, 0x1FD7, 0x069D, 0x01FB, 0x1F9C,
+               0x1FF9, 0x1FBE, 0x067C, 0x023A, 0x1F93,
+               0x1FFD, 0x1FA8, 0x0656, 0x027B, 0x1F8A,
+               0x0000, 0x1F95, 0x062B, 0x02BF, 0x1F81,
+               0x0002, 0x1F86, 0x05FC, 0x0303, 0x1F79,
+               0x0004, 0x1F79, 0x05CA, 0x0347, 0x1F72,
+               0x0005, 0x1F6F, 0x0594, 0x038D, 0x1F6B,
+               0x0006, 0x1F67, 0x055B, 0x03D2, 0x1F66,
+               0x0007, 0x1F62, 0x051E, 0x0417, 0x1F62,
+               0x0007, 0x1F5F, 0x04DF, 0x045C, 0x1F5F,
+               0x1F5E, 0x04A2, 0x04A2, 0x1F5E, 0x0000,
+               0x1F5F, 0x045C, 0x04DF, 0x1F5F, 0x0007,
+               0x1F62, 0x0417, 0x051E, 0x1F62, 0x0007,
+               0x1F66, 0x03D2, 0x055B, 0x1F67, 0x0006,
+               0x1F6B, 0x038D, 0x0594, 0x1F6F, 0x0005,
+               0x1F72, 0x0347, 0x05CA, 0x1F79, 0x0004,
+               0x1F79, 0x0303, 0x05FC, 0x1F86, 0x0002,
+               0x1F81, 0x02BF, 0x062B, 0x1F95, 0x0000,
+               0x1F8A, 0x027B, 0x0656, 0x1FA8, 0x1FFD,
+               0x1F93, 0x023A, 0x067C, 0x1FBE, 0x1FF9,
+               0x1F9C, 0x01FB, 0x069D, 0x1FD7, 0x1FF5,
+               0x1FA5, 0x01BD, 0x06BA, 0x1FF3, 0x1FF1,
+               0x1FAE, 0x0182, 0x06D3, 0x0012, 0x1FEB,
+               0x1FB7, 0x014A, 0x06E5, 0x0035, 0x1FE5,
+               0x1FC0, 0x0114, 0x06F2, 0x005B, 0x1FDF,
+               0x1FC9, 0x00E1, 0x06F9, 0x0085, 0x1FD8,
+       },
+};
+#endif
index fcbe48a09cf80a09f2be26976b04145eb9093c38..e8175e7938edd2fd09dbcaafa091356538db5b65 100644 (file)
 
 const struct vpdma_data_format vpdma_yuv_fmts[] = {
        [VPDMA_DATA_FMT_Y444] = {
+               .type           = VPDMA_DATA_FMT_TYPE_YUV,
                .data_type      = DATA_TYPE_Y444,
                .depth          = 8,
        },
        [VPDMA_DATA_FMT_Y422] = {
+               .type           = VPDMA_DATA_FMT_TYPE_YUV,
                .data_type      = DATA_TYPE_Y422,
                .depth          = 8,
        },
        [VPDMA_DATA_FMT_Y420] = {
+               .type           = VPDMA_DATA_FMT_TYPE_YUV,
                .data_type      = DATA_TYPE_Y420,
                .depth          = 8,
        },
        [VPDMA_DATA_FMT_C444] = {
+               .type           = VPDMA_DATA_FMT_TYPE_YUV,
                .data_type      = DATA_TYPE_C444,
                .depth          = 8,
        },
        [VPDMA_DATA_FMT_C422] = {
+               .type           = VPDMA_DATA_FMT_TYPE_YUV,
                .data_type      = DATA_TYPE_C422,
                .depth          = 8,
        },
        [VPDMA_DATA_FMT_C420] = {
+               .type           = VPDMA_DATA_FMT_TYPE_YUV,
                .data_type      = DATA_TYPE_C420,
                .depth          = 4,
        },
        [VPDMA_DATA_FMT_YC422] = {
+               .type           = VPDMA_DATA_FMT_TYPE_YUV,
                .data_type      = DATA_TYPE_YC422,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_YC444] = {
+               .type           = VPDMA_DATA_FMT_TYPE_YUV,
                .data_type      = DATA_TYPE_YC444,
                .depth          = 24,
        },
        [VPDMA_DATA_FMT_CY422] = {
+               .type           = VPDMA_DATA_FMT_TYPE_YUV,
                .data_type      = DATA_TYPE_CY422,
                .depth          = 16,
        },
@@ -69,82 +78,102 @@ const struct vpdma_data_format vpdma_yuv_fmts[] = {
 
 const struct vpdma_data_format vpdma_rgb_fmts[] = {
        [VPDMA_DATA_FMT_RGB565] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_RGB16_565,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_ARGB16_1555] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_ARGB_1555,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_ARGB16] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_ARGB_4444,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_RGBA16_5551] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_RGBA_5551,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_RGBA16] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_RGBA_4444,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_ARGB24] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_ARGB24_6666,
                .depth          = 24,
        },
        [VPDMA_DATA_FMT_RGB24] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_RGB24_888,
                .depth          = 24,
        },
        [VPDMA_DATA_FMT_ARGB32] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_ARGB32_8888,
                .depth          = 32,
        },
        [VPDMA_DATA_FMT_RGBA24] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_RGBA24_6666,
                .depth          = 24,
        },
        [VPDMA_DATA_FMT_RGBA32] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_RGBA32_8888,
                .depth          = 32,
        },
        [VPDMA_DATA_FMT_BGR565] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_BGR16_565,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_ABGR16_1555] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_ABGR_1555,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_ABGR16] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_ABGR_4444,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_BGRA16_5551] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_BGRA_5551,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_BGRA16] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_BGRA_4444,
                .depth          = 16,
        },
        [VPDMA_DATA_FMT_ABGR24] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_ABGR24_6666,
                .depth          = 24,
        },
        [VPDMA_DATA_FMT_BGR24] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_BGR24_888,
                .depth          = 24,
        },
        [VPDMA_DATA_FMT_ABGR32] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_ABGR32_8888,
                .depth          = 32,
        },
        [VPDMA_DATA_FMT_BGRA24] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_BGRA24_6666,
                .depth          = 24,
        },
        [VPDMA_DATA_FMT_BGRA32] = {
+               .type           = VPDMA_DATA_FMT_TYPE_RGB,
                .data_type      = DATA_TYPE_BGRA32_8888,
                .depth          = 32,
        },
@@ -152,6 +181,7 @@ const struct vpdma_data_format vpdma_rgb_fmts[] = {
 
 const struct vpdma_data_format vpdma_misc_fmts[] = {
        [VPDMA_DATA_FMT_MV] = {
+               .type           = VPDMA_DATA_FMT_TYPE_MISC,
                .data_type      = DATA_TYPE_MV,
                .depth          = 4,
        },
@@ -599,10 +629,11 @@ void vpdma_add_out_dtd(struct vpdma_desc_list *list, struct v4l2_rect *c_rect,
 
        channel = next_chan = chan_info[chan].num;
 
-       if (fmt->data_type == DATA_TYPE_C420)
+       if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
+                       fmt->data_type == DATA_TYPE_C420)
                depth = 8;
 
-       stride = (depth * c_rect->width) >> 3;
+       stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
        dma_addr += (c_rect->left * depth) >> 3;
 
        dtd = list->next;
@@ -649,13 +680,14 @@ void vpdma_add_in_dtd(struct vpdma_desc_list *list, int frame_width,
 
        channel = next_chan = chan_info[chan].num;
 
-       if (fmt->data_type == DATA_TYPE_C420) {
+       if (fmt->type == VPDMA_DATA_FMT_TYPE_YUV &&
+                       fmt->data_type == DATA_TYPE_C420) {
                height >>= 1;
                frame_height >>= 1;
                depth = 8;
        }
 
-       stride = (depth * c_rect->width) >> 3;
+       stride = ALIGN((depth * c_rect->width) >> 3, VPDMA_STRIDE_ALIGN);
        dma_addr += (c_rect->left * depth) >> 3;
 
        dtd = list->next;
index eaa2a71a5db95d1d21533428e96253e009d1d874..cf40f11b3c8f3dd2bc8397cbf7664cb85e7caff0 100644 (file)
@@ -39,13 +39,23 @@ struct vpdma_data {
        bool ready;
 };
 
+enum vpdma_data_format_type {
+       VPDMA_DATA_FMT_TYPE_YUV,
+       VPDMA_DATA_FMT_TYPE_RGB,
+       VPDMA_DATA_FMT_TYPE_MISC,
+};
+
 struct vpdma_data_format {
+       enum vpdma_data_format_type type;
        int data_type;
        u8 depth;
 };
 
 #define VPDMA_DESC_ALIGN               16      /* 16-byte descriptor alignment */
-
+#define VPDMA_STRIDE_ALIGN             16      /*
+                                                * line stride of source and dest
+                                                * buffers should be 16 byte aligned
+                                                */
 #define VPDMA_DTD_DESC_SIZE            32      /* 8 words */
 #define VPDMA_CFD_CTD_DESC_SIZE                16      /* 4 words */
 
index f0e9a8038c1be6911daec69dd184748af4cdc974..c1a6ce1884f33bfdf6154b6fae3a704bad959426 100644 (file)
@@ -78,7 +78,7 @@
 #define DATA_TYPE_C420                         0x6
 #define DATA_TYPE_YC422                                0x7
 #define DATA_TYPE_YC444                                0x8
-#define DATA_TYPE_CY422                                0x23
+#define DATA_TYPE_CY422                                0x27
 
 #define DATA_TYPE_RGB16_565                    0x0
 #define DATA_TYPE_ARGB_1555                    0x1
index 4e58069e24ff16877f7dc642bf6a99c4838f7715..1296c5386231e25700a0f95e05a6f0a97d72e5fa 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/videodev2.h>
+#include <linux/log2.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ctrls.h>
@@ -42,6 +43,8 @@
 
 #include "vpdma.h"
 #include "vpe_regs.h"
+#include "sc.h"
+#include "csc.h"
 
 #define VPE_MODULE_NAME "vpe"
 
 /* required alignments */
 #define S_ALIGN                0       /* multiple of 1 */
 #define H_ALIGN                1       /* multiple of 2 */
-#define W_ALIGN                1       /* multiple of 2 */
-
-/* multiple of 128 bits, line stride, 16 bytes */
-#define L_ALIGN                4
 
 /* flags that indicate a format can be used for capture/output */
 #define VPE_FMT_TYPE_CAPTURE   (1 << 0)
@@ -268,6 +267,38 @@ static struct vpe_fmt vpe_formats[] = {
                .vpdma_fmt      = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CY422],
                                  },
        },
+       {
+               .name           = "RGB888 packed",
+               .fourcc         = V4L2_PIX_FMT_RGB24,
+               .types          = VPE_FMT_TYPE_CAPTURE,
+               .coplanar       = 0,
+               .vpdma_fmt      = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_RGB24],
+                                 },
+       },
+       {
+               .name           = "ARGB32",
+               .fourcc         = V4L2_PIX_FMT_RGB32,
+               .types          = VPE_FMT_TYPE_CAPTURE,
+               .coplanar       = 0,
+               .vpdma_fmt      = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ARGB32],
+                                 },
+       },
+       {
+               .name           = "BGR888 packed",
+               .fourcc         = V4L2_PIX_FMT_BGR24,
+               .types          = VPE_FMT_TYPE_CAPTURE,
+               .coplanar       = 0,
+               .vpdma_fmt      = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_BGR24],
+                                 },
+       },
+       {
+               .name           = "ABGR32",
+               .fourcc         = V4L2_PIX_FMT_BGR32,
+               .types          = VPE_FMT_TYPE_CAPTURE,
+               .coplanar       = 0,
+               .vpdma_fmt      = { &vpdma_rgb_fmts[VPDMA_DATA_FMT_ABGR32],
+                                 },
+       },
 };
 
 /*
@@ -327,9 +358,12 @@ struct vpe_dev {
 
        int                     irq;
        void __iomem            *base;
+       struct resource         *res;
 
        struct vb2_alloc_ctx    *alloc_ctx;
        struct vpdma_data       *vpdma;         /* vpdma data handle */
+       struct sc_data          *sc;            /* scaler data handle */
+       struct csc_data         *csc;           /* csc data handle */
 };
 
 /*
@@ -356,6 +390,8 @@ struct vpe_ctx {
        void                    *mv_buf[2];             /* virtual addrs of motion vector bufs */
        size_t                  mv_buf_size;            /* current motion vector buffer size */
        struct vpdma_buf        mmr_adb;                /* shadow reg addr/data block */
+       struct vpdma_buf        sc_coeff_h;             /* h coeff buffer */
+       struct vpdma_buf        sc_coeff_v;             /* v coeff buffer */
        struct vpdma_desc_list  desc_list;              /* DMA descriptor list */
 
        bool                    deinterlacing;          /* using de-interlacer */
@@ -438,14 +474,23 @@ struct vpe_mmr_adb {
        u32                     us3_regs[8];
        struct vpdma_adb_hdr    dei_hdr;
        u32                     dei_regs[8];
-       struct vpdma_adb_hdr    sc_hdr;
-       u32                     sc_regs[1];
-       u32                     sc_pad[3];
+       struct vpdma_adb_hdr    sc_hdr0;
+       u32                     sc_regs0[7];
+       u32                     sc_pad0[1];
+       struct vpdma_adb_hdr    sc_hdr8;
+       u32                     sc_regs8[6];
+       u32                     sc_pad8[2];
+       struct vpdma_adb_hdr    sc_hdr17;
+       u32                     sc_regs17[9];
+       u32                     sc_pad17[3];
        struct vpdma_adb_hdr    csc_hdr;
        u32                     csc_regs[6];
        u32                     csc_pad[2];
 };
 
+#define GET_OFFSET_TOP(ctx, obj, reg)  \
+       ((obj)->res->start - ctx->dev->res->start + reg)
+
 #define VPE_SET_MMR_ADB_HDR(ctx, hdr, regs, offset_a)  \
        VPDMA_SET_MMR_ADB_HDR(ctx->mmr_adb, vpe_mmr_adb, hdr, regs, offset_a)
 /*
@@ -458,8 +503,14 @@ static void init_adb_hdrs(struct vpe_ctx *ctx)
        VPE_SET_MMR_ADB_HDR(ctx, us2_hdr, us2_regs, VPE_US2_R0);
        VPE_SET_MMR_ADB_HDR(ctx, us3_hdr, us3_regs, VPE_US3_R0);
        VPE_SET_MMR_ADB_HDR(ctx, dei_hdr, dei_regs, VPE_DEI_FRAME_SIZE);
-       VPE_SET_MMR_ADB_HDR(ctx, sc_hdr, sc_regs, VPE_SC_MP_SC0);
-       VPE_SET_MMR_ADB_HDR(ctx, csc_hdr, csc_regs, VPE_CSC_CSC00);
+       VPE_SET_MMR_ADB_HDR(ctx, sc_hdr0, sc_regs0,
+               GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC0));
+       VPE_SET_MMR_ADB_HDR(ctx, sc_hdr8, sc_regs8,
+               GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC8));
+       VPE_SET_MMR_ADB_HDR(ctx, sc_hdr17, sc_regs17,
+               GET_OFFSET_TOP(ctx, ctx->dev->sc, CFG_SC17));
+       VPE_SET_MMR_ADB_HDR(ctx, csc_hdr, csc_regs,
+               GET_OFFSET_TOP(ctx, ctx->dev->csc, CSC_CSC00));
 };
 
 /*
@@ -670,17 +721,20 @@ static void set_src_registers(struct vpe_ctx *ctx)
 static void set_dst_registers(struct vpe_ctx *ctx)
 {
        struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
+       enum v4l2_colorspace clrspc = ctx->q_data[Q_DATA_DST].colorspace;
        struct vpe_fmt *fmt = ctx->q_data[Q_DATA_DST].fmt;
        u32 val = 0;
 
-       /* select RGB path when color space conversion is supported in future */
-       if (fmt->fourcc == V4L2_PIX_FMT_RGB24)
-               val |= VPE_RGB_OUT_SELECT | VPE_CSC_SRC_DEI_SCALER;
+       if (clrspc == V4L2_COLORSPACE_SRGB)
+               val |= VPE_RGB_OUT_SELECT;
        else if (fmt->fourcc == V4L2_PIX_FMT_NV16)
                val |= VPE_COLOR_SEPARATE_422;
 
-       /* The source of CHR_DS is always the scaler, whether it's used or not */
-       val |= VPE_DS_SRC_DEI_SCALER;
+       /*
+        * the source of CHR_DS and CSC is always the scaler, irrespective of
+        * whether it's used or not
+        */
+       val |= VPE_DS_SRC_DEI_SCALER | VPE_CSC_SRC_DEI_SCALER;
 
        if (fmt->fourcc != V4L2_PIX_FMT_NV12)
                val |= VPE_DS_BYPASS;
@@ -742,28 +796,6 @@ static void set_dei_shadow_registers(struct vpe_ctx *ctx)
        ctx->load_mmrs = true;
 }
 
-static void set_csc_coeff_bypass(struct vpe_ctx *ctx)
-{
-       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
-       u32 *shadow_csc_reg5 = &mmr_adb->csc_regs[5];
-
-       *shadow_csc_reg5 |= VPE_CSC_BYPASS;
-
-       ctx->load_mmrs = true;
-}
-
-static void set_sc_regs_bypass(struct vpe_ctx *ctx)
-{
-       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
-       u32 *sc_reg0 = &mmr_adb->sc_regs[0];
-       u32 val = 0;
-
-       val |= VPE_SC_BYPASS;
-       *sc_reg0 = val;
-
-       ctx->load_mmrs = true;
-}
-
 /*
  * Set the shadow registers whose values are modified when either the
  * source or destination format is changed.
@@ -772,6 +804,11 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
 {
        struct vpe_q_data *s_q_data =  &ctx->q_data[Q_DATA_SRC];
        struct vpe_q_data *d_q_data =  &ctx->q_data[Q_DATA_DST];
+       struct vpe_mmr_adb *mmr_adb = ctx->mmr_adb.addr;
+       unsigned int src_w = s_q_data->c_rect.width;
+       unsigned int src_h = s_q_data->c_rect.height;
+       unsigned int dst_w = d_q_data->c_rect.width;
+       unsigned int dst_h = d_q_data->c_rect.height;
        size_t mv_buf_size;
        int ret;
 
@@ -780,12 +817,23 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
 
        if ((s_q_data->flags & Q_DATA_INTERLACED) &&
                        !(d_q_data->flags & Q_DATA_INTERLACED)) {
+               int bytes_per_line;
                const struct vpdma_data_format *mv =
                        &vpdma_misc_fmts[VPDMA_DATA_FMT_MV];
 
+               /*
+                * we make sure that the source image has a 16 byte aligned
+                * stride, we need to do the same for the motion vector buffer
+                * by aligning it's stride to the next 16 byte boundry. this
+                * extra space will not be used by the de-interlacer, but will
+                * ensure that vpdma operates correctly
+                */
+               bytes_per_line = ALIGN((s_q_data->width * mv->depth) >> 3,
+                                       VPDMA_STRIDE_ALIGN);
+               mv_buf_size = bytes_per_line * s_q_data->height;
+
                ctx->deinterlacing = 1;
-               mv_buf_size =
-                       (s_q_data->width * s_q_data->height * mv->depth) >> 3;
+               src_h <<= 1;
        } else {
                ctx->deinterlacing = 0;
                mv_buf_size = 0;
@@ -799,8 +847,16 @@ static int set_srcdst_params(struct vpe_ctx *ctx)
 
        set_cfg_and_line_modes(ctx);
        set_dei_regs(ctx);
-       set_csc_coeff_bypass(ctx);
-       set_sc_regs_bypass(ctx);
+
+       csc_set_coeff(ctx->dev->csc, &mmr_adb->csc_regs[0],
+               s_q_data->colorspace, d_q_data->colorspace);
+
+       sc_set_hs_coeffs(ctx->dev->sc, ctx->sc_coeff_h.addr, src_w, dst_w);
+       sc_set_vs_coeffs(ctx->dev->sc, ctx->sc_coeff_v.addr, src_h, dst_h);
+
+       sc_config_scaler(ctx->dev->sc, &mmr_adb->sc_regs0[0],
+               &mmr_adb->sc_regs8[0], &mmr_adb->sc_regs17[0],
+               src_w, src_h, dst_w, dst_h);
 
        return 0;
 }
@@ -916,35 +972,10 @@ static void vpe_dump_regs(struct vpe_dev *dev)
        DUMPREG(DEI_FMD_STATUS_R0);
        DUMPREG(DEI_FMD_STATUS_R1);
        DUMPREG(DEI_FMD_STATUS_R2);
-       DUMPREG(SC_MP_SC0);
-       DUMPREG(SC_MP_SC1);
-       DUMPREG(SC_MP_SC2);
-       DUMPREG(SC_MP_SC3);
-       DUMPREG(SC_MP_SC4);
-       DUMPREG(SC_MP_SC5);
-       DUMPREG(SC_MP_SC6);
-       DUMPREG(SC_MP_SC8);
-       DUMPREG(SC_MP_SC9);
-       DUMPREG(SC_MP_SC10);
-       DUMPREG(SC_MP_SC11);
-       DUMPREG(SC_MP_SC12);
-       DUMPREG(SC_MP_SC13);
-       DUMPREG(SC_MP_SC17);
-       DUMPREG(SC_MP_SC18);
-       DUMPREG(SC_MP_SC19);
-       DUMPREG(SC_MP_SC20);
-       DUMPREG(SC_MP_SC21);
-       DUMPREG(SC_MP_SC22);
-       DUMPREG(SC_MP_SC23);
-       DUMPREG(SC_MP_SC24);
-       DUMPREG(SC_MP_SC25);
-       DUMPREG(CSC_CSC00);
-       DUMPREG(CSC_CSC01);
-       DUMPREG(CSC_CSC02);
-       DUMPREG(CSC_CSC03);
-       DUMPREG(CSC_CSC04);
-       DUMPREG(CSC_CSC05);
 #undef DUMPREG
+
+       sc_dump_regs(dev->sc);
+       csc_dump_regs(dev->csc);
 }
 
 static void add_out_dtd(struct vpe_ctx *ctx, int port)
@@ -1053,6 +1084,7 @@ static void disable_irqs(struct vpe_ctx *ctx)
 static void device_run(void *priv)
 {
        struct vpe_ctx *ctx = priv;
+       struct sc_data *sc = ctx->dev->sc;
        struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST];
 
        if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) {
@@ -1075,13 +1107,37 @@ static void device_run(void *priv)
                ctx->load_mmrs = false;
        }
 
+       if (sc->loaded_coeff_h != ctx->sc_coeff_h.dma_addr ||
+                       sc->load_coeff_h) {
+               vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_h);
+               vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT,
+                       &ctx->sc_coeff_h, 0);
+
+               sc->loaded_coeff_h = ctx->sc_coeff_h.dma_addr;
+               sc->load_coeff_h = false;
+       }
+
+       if (sc->loaded_coeff_v != ctx->sc_coeff_v.dma_addr ||
+                       sc->load_coeff_v) {
+               vpdma_map_desc_buf(ctx->dev->vpdma, &ctx->sc_coeff_v);
+               vpdma_add_cfd_block(&ctx->desc_list, CFD_SC_CLIENT,
+                       &ctx->sc_coeff_v, SC_COEF_SRAM_SIZE >> 4);
+
+               sc->loaded_coeff_v = ctx->sc_coeff_v.dma_addr;
+               sc->load_coeff_v = false;
+       }
+
        /* output data descriptors */
        if (ctx->deinterlacing)
                add_out_dtd(ctx, VPE_PORT_MV_OUT);
 
-       add_out_dtd(ctx, VPE_PORT_LUMA_OUT);
-       if (d_q_data->fmt->coplanar)
-               add_out_dtd(ctx, VPE_PORT_CHROMA_OUT);
+       if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) {
+               add_out_dtd(ctx, VPE_PORT_RGB_OUT);
+       } else {
+               add_out_dtd(ctx, VPE_PORT_LUMA_OUT);
+               if (d_q_data->fmt->coplanar)
+                       add_out_dtd(ctx, VPE_PORT_CHROMA_OUT);
+       }
 
        /* input data descriptors */
        if (ctx->deinterlacing) {
@@ -1117,9 +1173,16 @@ static void device_run(void *priv)
        }
 
        /* sync on channel control descriptors for output ports */
-       vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_LUMA_OUT);
-       if (d_q_data->fmt->coplanar)
-               vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_CHROMA_OUT);
+       if (d_q_data->colorspace == V4L2_COLORSPACE_SRGB) {
+               vpdma_add_sync_on_channel_ctd(&ctx->desc_list,
+                       VPE_CHAN_RGB_OUT);
+       } else {
+               vpdma_add_sync_on_channel_ctd(&ctx->desc_list,
+                       VPE_CHAN_LUMA_OUT);
+               if (d_q_data->fmt->coplanar)
+                       vpdma_add_sync_on_channel_ctd(&ctx->desc_list,
+                               VPE_CHAN_CHROMA_OUT);
+       }
 
        if (ctx->deinterlacing)
                vpdma_add_sync_on_channel_ctd(&ctx->desc_list, VPE_CHAN_MV_OUT);
@@ -1198,6 +1261,8 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
 
        vpdma_unmap_desc_buf(dev->vpdma, &ctx->desc_list.buf);
        vpdma_unmap_desc_buf(dev->vpdma, &ctx->mmr_adb);
+       vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_h);
+       vpdma_unmap_desc_buf(dev->vpdma, &ctx->sc_coeff_v);
 
        vpdma_reset_desc_list(&ctx->desc_list);
 
@@ -1352,7 +1417,8 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
 {
        struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp;
        struct v4l2_plane_pix_format *plane_fmt;
-       int i;
+       unsigned int w_align;
+       int i, depth, depth_bytes;
 
        if (!fmt || !(fmt->types & type)) {
                vpe_err(ctx->dev, "Fourcc format (0x%08x) invalid.\n",
@@ -1363,35 +1429,57 @@ static int __vpe_try_fmt(struct vpe_ctx *ctx, struct v4l2_format *f,
        if (pix->field != V4L2_FIELD_NONE && pix->field != V4L2_FIELD_ALTERNATE)
                pix->field = V4L2_FIELD_NONE;
 
-       v4l_bound_align_image(&pix->width, MIN_W, MAX_W, W_ALIGN,
+       depth = fmt->vpdma_fmt[VPE_LUMA]->depth;
+
+       /*
+        * the line stride should 16 byte aligned for VPDMA to work, based on
+        * the bytes per pixel, figure out how much the width should be aligned
+        * to make sure line stride is 16 byte aligned
+        */
+       depth_bytes = depth >> 3;
+
+       if (depth_bytes == 3)
+               /*
+                * if bpp is 3(as in some RGB formats), the pixel width doesn't
+                * really help in ensuring line stride is 16 byte aligned
+                */
+               w_align = 4;
+       else
+               /*
+                * for the remainder bpp(4, 2 and 1), the pixel width alignment
+                * can ensure a line stride alignment of 16 bytes. For example,
+                * if bpp is 2, then the line stride can be 16 byte aligned if
+                * the width is 8 byte aligned
+                */
+               w_align = order_base_2(VPDMA_DESC_ALIGN / depth_bytes);
+
+       v4l_bound_align_image(&pix->width, MIN_W, MAX_W, w_align,
                              &pix->height, MIN_H, MAX_H, H_ALIGN,
                              S_ALIGN);
 
        pix->num_planes = fmt->coplanar ? 2 : 1;
        pix->pixelformat = fmt->fourcc;
 
-       if (type == VPE_FMT_TYPE_CAPTURE) {
-               struct vpe_q_data *s_q_data;
-
-               /* get colorspace from the source queue */
-               s_q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
-
-               pix->colorspace = s_q_data->colorspace;
-       } else {
-               if (!pix->colorspace)
-                       pix->colorspace = V4L2_COLORSPACE_SMPTE240M;
+       if (!pix->colorspace) {
+               if (fmt->fourcc == V4L2_PIX_FMT_RGB24 ||
+                               fmt->fourcc == V4L2_PIX_FMT_BGR24 ||
+                               fmt->fourcc == V4L2_PIX_FMT_RGB32 ||
+                               fmt->fourcc == V4L2_PIX_FMT_BGR32) {
+                       pix->colorspace = V4L2_COLORSPACE_SRGB;
+               } else {
+                       if (pix->height > 1280) /* HD */
+                               pix->colorspace = V4L2_COLORSPACE_REC709;
+                       else                    /* SD */
+                               pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
+               }
        }
 
        for (i = 0; i < pix->num_planes; i++) {
-               int depth;
-
                plane_fmt = &pix->plane_fmt[i];
                depth = fmt->vpdma_fmt[i]->depth;
 
                if (i == VPE_LUMA)
-                       plane_fmt->bytesperline =
-                                       round_up((pix->width * depth) >> 3,
-                                               1 << L_ALIGN);
+                       plane_fmt->bytesperline = (pix->width * depth) >> 3;
                else
                        plane_fmt->bytesperline = pix->width;
 
@@ -1749,6 +1837,14 @@ static int vpe_open(struct file *file)
        if (ret != 0)
                goto free_desc_list;
 
+       ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_h, SC_COEF_SRAM_SIZE);
+       if (ret != 0)
+               goto free_mmr_adb;
+
+       ret = vpdma_alloc_desc_buf(&ctx->sc_coeff_v, SC_COEF_SRAM_SIZE);
+       if (ret != 0)
+               goto free_sc_h;
+
        init_adb_hdrs(ctx);
 
        v4l2_fh_init(&ctx->fh, video_devdata(file));
@@ -1770,7 +1866,7 @@ static int vpe_open(struct file *file)
        s_q_data->height = 1080;
        s_q_data->sizeimage[VPE_LUMA] = (s_q_data->width * s_q_data->height *
                        s_q_data->fmt->vpdma_fmt[VPE_LUMA]->depth) >> 3;
-       s_q_data->colorspace = V4L2_COLORSPACE_SMPTE240M;
+       s_q_data->colorspace = V4L2_COLORSPACE_SMPTE170M;
        s_q_data->field = V4L2_FIELD_NONE;
        s_q_data->c_rect.left = 0;
        s_q_data->c_rect.top = 0;
@@ -1817,6 +1913,10 @@ static int vpe_open(struct file *file)
 exit_fh:
        v4l2_ctrl_handler_free(hdl);
        v4l2_fh_exit(&ctx->fh);
+       vpdma_free_desc_buf(&ctx->sc_coeff_v);
+free_sc_h:
+       vpdma_free_desc_buf(&ctx->sc_coeff_h);
+free_mmr_adb:
        vpdma_free_desc_buf(&ctx->mmr_adb);
 free_desc_list:
        vpdma_free_desc_list(&ctx->desc_list);
@@ -1938,12 +2038,11 @@ static int vpe_probe(struct platform_device *pdev)
 {
        struct vpe_dev *dev;
        struct video_device *vfd;
-       struct resource *res;
        int ret, irq, func;
 
        dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
-       if (IS_ERR(dev))
-               return PTR_ERR(dev);
+       if (!dev)
+               return -ENOMEM;
 
        spin_lock_init(&dev->lock);
 
@@ -1954,16 +2053,17 @@ static int vpe_probe(struct platform_device *pdev)
        atomic_set(&dev->num_instances, 0);
        mutex_init(&dev->dev_mutex);
 
-       res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vpe_top");
+       dev->res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+                       "vpe_top");
        /*
         * HACK: we get resource info from device tree in the form of a list of
         * VPE sub blocks, the driver currently uses only the base of vpe_top
         * for register access, the driver should be changed later to access
         * registers based on the sub block base addresses
         */
-       dev->base = devm_ioremap(&pdev->dev, res->start, SZ_32K);
-       if (IS_ERR(dev->base)) {
-               ret = PTR_ERR(dev->base);
+       dev->base = devm_ioremap(&pdev->dev, dev->res->start, SZ_32K);
+       if (!dev->base) {
+               ret = -ENOMEM;
                goto v4l2_dev_unreg;
        }
 
@@ -2006,9 +2106,23 @@ static int vpe_probe(struct platform_device *pdev)
 
        vpe_top_vpdma_reset(dev);
 
+       dev->sc = sc_create(pdev);
+       if (IS_ERR(dev->sc)) {
+               ret = PTR_ERR(dev->sc);
+               goto runtime_put;
+       }
+
+       dev->csc = csc_create(pdev);
+       if (IS_ERR(dev->csc)) {
+               ret = PTR_ERR(dev->csc);
+               goto runtime_put;
+       }
+
        dev->vpdma = vpdma_create(pdev);
-       if (IS_ERR(dev->vpdma))
+       if (IS_ERR(dev->vpdma)) {
+               ret = PTR_ERR(dev->vpdma);
                goto runtime_put;
+       }
 
        vfd = &dev->vfd;
        *vfd = vpe_videodev;
@@ -2081,18 +2195,7 @@ static struct platform_driver vpe_pdrv = {
        },
 };
 
-static void __exit vpe_exit(void)
-{
-       platform_driver_unregister(&vpe_pdrv);
-}
-
-static int __init vpe_init(void)
-{
-       return platform_driver_register(&vpe_pdrv);
-}
-
-module_init(vpe_init);
-module_exit(vpe_exit);
+module_platform_driver(vpe_pdrv);
 
 MODULE_DESCRIPTION("TI VPE driver");
 MODULE_AUTHOR("Dale Farnsworth, <dale@farnsworth.org>");
index ed214e828398a0f0763059948b3324854aff9621..74283d79eae1f394bfe4ad41c46e75d52bf3d32a 100644 (file)
 #define VPE_FMD_FRAME_DIFF_MASK                0x000fffff
 #define VPE_FMD_FRAME_DIFF_SHIFT       0
 
-/* VPE scaler regs */
-#define VPE_SC_MP_SC0                  0x0700
-#define VPE_INTERLACE_O                        (1 << 0)
-#define VPE_LINEAR                     (1 << 1)
-#define VPE_SC_BYPASS                  (1 << 2)
-#define VPE_INVT_FID                   (1 << 3)
-#define VPE_USE_RAV                    (1 << 4)
-#define VPE_ENABLE_EV                  (1 << 5)
-#define VPE_AUTO_HS                    (1 << 6)
-#define VPE_DCM_2X                     (1 << 7)
-#define VPE_DCM_4X                     (1 << 8)
-#define VPE_HP_BYPASS                  (1 << 9)
-#define VPE_INTERLACE_I                        (1 << 10)
-#define VPE_ENABLE_SIN2_VER_INTP       (1 << 11)
-#define VPE_Y_PK_EN                    (1 << 14)
-#define VPE_TRIM                       (1 << 15)
-#define VPE_SELFGEN_FID                        (1 << 16)
-
-#define VPE_SC_MP_SC1                  0x0704
-#define VPE_ROW_ACC_INC_MASK           0x07ffffff
-#define VPE_ROW_ACC_INC_SHIFT          0
-
-#define VPE_SC_MP_SC2                  0x0708
-#define VPE_ROW_ACC_OFFSET_MASK                0x0fffffff
-#define VPE_ROW_ACC_OFFSET_SHIFT       0
-
-#define VPE_SC_MP_SC3                  0x070c
-#define VPE_ROW_ACC_OFFSET_B_MASK      0x0fffffff
-#define VPE_ROW_ACC_OFFSET_B_SHIFT     0
-
-#define VPE_SC_MP_SC4                  0x0710
-#define VPE_TAR_H_MASK                 0x07ff
-#define VPE_TAR_H_SHIFT                        0
-#define VPE_TAR_W_MASK                 0x07ff
-#define VPE_TAR_W_SHIFT                        12
-#define VPE_LIN_ACC_INC_U_MASK         0x07
-#define VPE_LIN_ACC_INC_U_SHIFT                24
-#define VPE_NLIN_ACC_INIT_U_MASK       0x07
-#define VPE_NLIN_ACC_INIT_U_SHIFT      28
-
-#define VPE_SC_MP_SC5                  0x0714
-#define VPE_SRC_H_MASK                 0x07ff
-#define VPE_SRC_H_SHIFT                        0
-#define VPE_SRC_W_MASK                 0x07ff
-#define VPE_SRC_W_SHIFT                        12
-#define VPE_NLIN_ACC_INC_U_MASK                0x07
-#define VPE_NLIN_ACC_INC_U_SHIFT       24
-
-#define VPE_SC_MP_SC6                  0x0718
-#define VPE_ROW_ACC_INIT_RAV_MASK      0x03ff
-#define VPE_ROW_ACC_INIT_RAV_SHIFT     0
-#define VPE_ROW_ACC_INIT_RAV_B_MASK    0x03ff
-#define VPE_ROW_ACC_INIT_RAV_B_SHIFT   10
-
-#define VPE_SC_MP_SC8                  0x0720
-#define VPE_NLIN_LEFT_MASK             0x07ff
-#define VPE_NLIN_LEFT_SHIFT            0
-#define VPE_NLIN_RIGHT_MASK            0x07ff
-#define VPE_NLIN_RIGHT_SHIFT           12
-
-#define VPE_SC_MP_SC9                  0x0724
-#define VPE_LIN_ACC_INC                        VPE_SC_MP_SC9
-
-#define VPE_SC_MP_SC10                 0x0728
-#define VPE_NLIN_ACC_INIT              VPE_SC_MP_SC10
-
-#define VPE_SC_MP_SC11                 0x072c
-#define VPE_NLIN_ACC_INC               VPE_SC_MP_SC11
-
-#define VPE_SC_MP_SC12                 0x0730
-#define VPE_COL_ACC_OFFSET_MASK                0x01ffffff
-#define VPE_COL_ACC_OFFSET_SHIFT       0
-
-#define VPE_SC_MP_SC13                 0x0734
-#define VPE_SC_FACTOR_RAV_MASK         0x03ff
-#define VPE_SC_FACTOR_RAV_SHIFT                0
-#define VPE_CHROMA_INTP_THR_MASK       0x03ff
-#define VPE_CHROMA_INTP_THR_SHIFT      12
-#define VPE_DELTA_CHROMA_THR_MASK      0x0f
-#define VPE_DELTA_CHROMA_THR_SHIFT     24
-
-#define VPE_SC_MP_SC17                 0x0744
-#define VPE_EV_THR_MASK                        0x03ff
-#define VPE_EV_THR_SHIFT               12
-#define VPE_DELTA_LUMA_THR_MASK                0x0f
-#define VPE_DELTA_LUMA_THR_SHIFT       24
-#define VPE_DELTA_EV_THR_MASK          0x0f
-#define VPE_DELTA_EV_THR_SHIFT         28
-
-#define VPE_SC_MP_SC18                 0x0748
-#define VPE_HS_FACTOR_MASK             0x03ff
-#define VPE_HS_FACTOR_SHIFT            0
-#define VPE_CONF_DEFAULT_MASK          0x01ff
-#define VPE_CONF_DEFAULT_SHIFT         16
-
-#define VPE_SC_MP_SC19                 0x074c
-#define VPE_HPF_COEFF0_MASK            0xff
-#define VPE_HPF_COEFF0_SHIFT           0
-#define VPE_HPF_COEFF1_MASK            0xff
-#define VPE_HPF_COEFF1_SHIFT           8
-#define VPE_HPF_COEFF2_MASK            0xff
-#define VPE_HPF_COEFF2_SHIFT           16
-#define VPE_HPF_COEFF3_MASK            0xff
-#define VPE_HPF_COEFF3_SHIFT           23
-
-#define VPE_SC_MP_SC20                 0x0750
-#define VPE_HPF_COEFF4_MASK            0xff
-#define VPE_HPF_COEFF4_SHIFT           0
-#define VPE_HPF_COEFF5_MASK            0xff
-#define VPE_HPF_COEFF5_SHIFT           8
-#define VPE_HPF_NORM_SHIFT_MASK                0x07
-#define VPE_HPF_NORM_SHIFT_SHIFT       16
-#define VPE_NL_LIMIT_MASK              0x1ff
-#define VPE_NL_LIMIT_SHIFT             20
-
-#define VPE_SC_MP_SC21                 0x0754
-#define VPE_NL_LO_THR_MASK             0x01ff
-#define VPE_NL_LO_THR_SHIFT            0
-#define VPE_NL_LO_SLOPE_MASK           0xff
-#define VPE_NL_LO_SLOPE_SHIFT          16
-
-#define VPE_SC_MP_SC22                 0x0758
-#define VPE_NL_HI_THR_MASK             0x01ff
-#define VPE_NL_HI_THR_SHIFT            0
-#define VPE_NL_HI_SLOPE_SH_MASK                0x07
-#define VPE_NL_HI_SLOPE_SH_SHIFT       16
-
-#define VPE_SC_MP_SC23                 0x075c
-#define VPE_GRADIENT_THR_MASK          0x07ff
-#define VPE_GRADIENT_THR_SHIFT         0
-#define VPE_GRADIENT_THR_RANGE_MASK    0x0f
-#define VPE_GRADIENT_THR_RANGE_SHIFT   12
-#define VPE_MIN_GY_THR_MASK            0xff
-#define VPE_MIN_GY_THR_SHIFT           16
-#define VPE_MIN_GY_THR_RANGE_MASK      0x0f
-#define VPE_MIN_GY_THR_RANGE_SHIFT     28
-
-#define VPE_SC_MP_SC24                 0x0760
-#define VPE_ORG_H_MASK                 0x07ff
-#define VPE_ORG_H_SHIFT                        0
-#define VPE_ORG_W_MASK                 0x07ff
-#define VPE_ORG_W_SHIFT                        16
-
-#define VPE_SC_MP_SC25                 0x0764
-#define VPE_OFF_H_MASK                 0x07ff
-#define VPE_OFF_H_SHIFT                        0
-#define VPE_OFF_W_MASK                 0x07ff
-#define VPE_OFF_W_SHIFT                        16
-
-/* VPE color space converter regs */
-#define VPE_CSC_CSC00                  0x5700
-#define VPE_CSC_A0_MASK                        0x1fff
-#define VPE_CSC_A0_SHIFT               0
-#define VPE_CSC_B0_MASK                        0x1fff
-#define VPE_CSC_B0_SHIFT               16
-
-#define VPE_CSC_CSC01                  0x5704
-#define VPE_CSC_C0_MASK                        0x1fff
-#define VPE_CSC_C0_SHIFT               0
-#define VPE_CSC_A1_MASK                        0x1fff
-#define VPE_CSC_A1_SHIFT               16
-
-#define VPE_CSC_CSC02                  0x5708
-#define VPE_CSC_B1_MASK                        0x1fff
-#define VPE_CSC_B1_SHIFT               0
-#define VPE_CSC_C1_MASK                        0x1fff
-#define VPE_CSC_C1_SHIFT               16
-
-#define VPE_CSC_CSC03                  0x570c
-#define VPE_CSC_A2_MASK                        0x1fff
-#define VPE_CSC_A2_SHIFT               0
-#define VPE_CSC_B2_MASK                        0x1fff
-#define VPE_CSC_B2_SHIFT               16
-
-#define VPE_CSC_CSC04                  0x5710
-#define VPE_CSC_C2_MASK                        0x1fff
-#define VPE_CSC_C2_SHIFT               0
-#define VPE_CSC_D0_MASK                        0x0fff
-#define VPE_CSC_D0_SHIFT               16
-
-#define VPE_CSC_CSC05                  0x5714
-#define VPE_CSC_D1_MASK                        0x0fff
-#define VPE_CSC_D1_SHIFT               0
-#define VPE_CSC_D2_MASK                        0x0fff
-#define VPE_CSC_D2_SHIFT               16
-#define VPE_CSC_BYPASS                 (1 << 28)
-
 #endif
index 4da226169e154f3c15380d232c6293461b818a25..151cecd0ea25a5ac97ab92cb1880729132084dd0 100644 (file)
@@ -1,5 +1,6 @@
 vsp1-y                                 := vsp1_drv.o vsp1_entity.o vsp1_video.o
 vsp1-y                                 += vsp1_rpf.o vsp1_rwpf.o vsp1_wpf.o
-vsp1-y                                 += vsp1_lif.o vsp1_uds.o
+vsp1-y                                 += vsp1_hsit.o vsp1_lif.o vsp1_lut.o
+vsp1-y                                 += vsp1_sru.o vsp1_uds.o
 
 obj-$(CONFIG_VIDEO_RENESAS_VSP1)       += vsp1.o
index d6c6ecd039fff7df6503225de92ab96002a9776c..94d1b02680c57e0b4b544cd5cef90a59485bdc92 100644 (file)
@@ -28,8 +28,11 @@ struct clk;
 struct device;
 
 struct vsp1_platform_data;
+struct vsp1_hsit;
 struct vsp1_lif;
+struct vsp1_lut;
 struct vsp1_rwpf;
+struct vsp1_sru;
 struct vsp1_uds;
 
 #define VPS1_MAX_RPF           5
@@ -47,8 +50,12 @@ struct vsp1_device {
        struct mutex lock;
        int ref_count;
 
+       struct vsp1_hsit *hsi;
+       struct vsp1_hsit *hst;
        struct vsp1_lif *lif;
+       struct vsp1_lut *lut;
        struct vsp1_rwpf *rpf[VPS1_MAX_RPF];
+       struct vsp1_sru *sru;
        struct vsp1_uds *uds[VPS1_MAX_UDS];
        struct vsp1_rwpf *wpf[VPS1_MAX_WPF];
 
index d16bf0f41e247bd69e3af1ebdc31e0309861e0fd..0df0a994e575c4b1e83c121fee0f4dcdec70b46c 100644 (file)
 #include <linux/videodev2.h>
 
 #include "vsp1.h"
+#include "vsp1_hsit.h"
 #include "vsp1_lif.h"
+#include "vsp1_lut.h"
 #include "vsp1_rwpf.h"
+#include "vsp1_sru.h"
 #include "vsp1_uds.h"
 
 /* -----------------------------------------------------------------------------
@@ -152,6 +155,22 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
        }
 
        /* Instantiate all the entities. */
+       vsp1->hsi = vsp1_hsit_create(vsp1, true);
+       if (IS_ERR(vsp1->hsi)) {
+               ret = PTR_ERR(vsp1->hsi);
+               goto done;
+       }
+
+       list_add_tail(&vsp1->hsi->entity.list_dev, &vsp1->entities);
+
+       vsp1->hst = vsp1_hsit_create(vsp1, false);
+       if (IS_ERR(vsp1->hst)) {
+               ret = PTR_ERR(vsp1->hst);
+               goto done;
+       }
+
+       list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
+
        if (vsp1->pdata->features & VSP1_HAS_LIF) {
                vsp1->lif = vsp1_lif_create(vsp1);
                if (IS_ERR(vsp1->lif)) {
@@ -162,6 +181,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
                list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities);
        }
 
+       if (vsp1->pdata->features & VSP1_HAS_LUT) {
+               vsp1->lut = vsp1_lut_create(vsp1);
+               if (IS_ERR(vsp1->lut)) {
+                       ret = PTR_ERR(vsp1->lut);
+                       goto done;
+               }
+
+               list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
+       }
+
        for (i = 0; i < vsp1->pdata->rpf_count; ++i) {
                struct vsp1_rwpf *rpf;
 
@@ -175,6 +204,16 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
                list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
        }
 
+       if (vsp1->pdata->features & VSP1_HAS_SRU) {
+               vsp1->sru = vsp1_sru_create(vsp1);
+               if (IS_ERR(vsp1->sru)) {
+                       ret = PTR_ERR(vsp1->sru);
+                       goto done;
+               }
+
+               list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities);
+       }
+
        for (i = 0; i < vsp1->pdata->uds_count; ++i) {
                struct vsp1_uds *uds;
 
index 9028f9d524f4b3e42e9e5d84243bb29df8023f9f..0226e47df6d94d53358ff310dc46c1d73ac59096 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/gfp.h>
 
 #include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-subdev.h>
 
 #include "vsp1.h"
@@ -122,12 +123,16 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
                unsigned int id;
                unsigned int reg;
        } routes[] = {
+               { VI6_DPR_NODE_HSI, VI6_DPR_HSI_ROUTE },
+               { VI6_DPR_NODE_HST, VI6_DPR_HST_ROUTE },
                { VI6_DPR_NODE_LIF, 0 },
+               { VI6_DPR_NODE_LUT, VI6_DPR_LUT_ROUTE },
                { VI6_DPR_NODE_RPF(0), VI6_DPR_RPF_ROUTE(0) },
                { VI6_DPR_NODE_RPF(1), VI6_DPR_RPF_ROUTE(1) },
                { VI6_DPR_NODE_RPF(2), VI6_DPR_RPF_ROUTE(2) },
                { VI6_DPR_NODE_RPF(3), VI6_DPR_RPF_ROUTE(3) },
                { VI6_DPR_NODE_RPF(4), VI6_DPR_RPF_ROUTE(4) },
+               { VI6_DPR_NODE_SRU, VI6_DPR_SRU_ROUTE },
                { VI6_DPR_NODE_UDS(0), VI6_DPR_UDS_ROUTE(0) },
                { VI6_DPR_NODE_UDS(1), VI6_DPR_UDS_ROUTE(1) },
                { VI6_DPR_NODE_UDS(2), VI6_DPR_UDS_ROUTE(2) },
@@ -177,5 +182,7 @@ int vsp1_entity_init(struct vsp1_device *vsp1, struct vsp1_entity *entity,
 
 void vsp1_entity_destroy(struct vsp1_entity *entity)
 {
+       if (entity->subdev.ctrl_handler)
+               v4l2_ctrl_handler_free(entity->subdev.ctrl_handler);
        media_entity_cleanup(&entity->subdev.entity);
 }
index c4feab2cbb8183b79146b08bb76fc60893f44f06..e152798d7f38e859ccf8fc0d87bd77e5680e91de 100644 (file)
 struct vsp1_device;
 
 enum vsp1_entity_type {
+       VSP1_ENTITY_HSI,
+       VSP1_ENTITY_HST,
        VSP1_ENTITY_LIF,
+       VSP1_ENTITY_LUT,
        VSP1_ENTITY_RPF,
+       VSP1_ENTITY_SRU,
        VSP1_ENTITY_UDS,
        VSP1_ENTITY_WPF,
 };
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
new file mode 100644 (file)
index 0000000..2854853
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * vsp1_hsit.c  --  R-Car VSP1 Hue Saturation value (Inverse) Transform
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/gfp.h>
+
+#include <media/v4l2-subdev.h>
+
+#include "vsp1.h"
+#include "vsp1_hsit.h"
+
+#define HSIT_MIN_SIZE                          4U
+#define HSIT_MAX_SIZE                          8190U
+
+/* -----------------------------------------------------------------------------
+ * Device Access
+ */
+
+static inline u32 vsp1_hsit_read(struct vsp1_hsit *hsit, u32 reg)
+{
+       return vsp1_read(hsit->entity.vsp1, reg);
+}
+
+static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
+{
+       vsp1_write(hsit->entity.vsp1, reg, data);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Core Operations
+ */
+
+static int hsit_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+       struct vsp1_hsit *hsit = to_hsit(subdev);
+
+       if (!enable)
+               return 0;
+
+       if (hsit->inverse)
+               vsp1_hsit_write(hsit, VI6_HSI_CTRL, VI6_HSI_CTRL_EN);
+       else
+               vsp1_hsit_write(hsit, VI6_HST_CTRL, VI6_HST_CTRL_EN);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Pad Operations
+ */
+
+static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct vsp1_hsit *hsit = to_hsit(subdev);
+
+       if (code->index > 0)
+               return -EINVAL;
+
+       if ((code->pad == HSIT_PAD_SINK && !hsit->inverse) |
+           (code->pad == HSIT_PAD_SOURCE && hsit->inverse))
+               code->code = V4L2_MBUS_FMT_ARGB8888_1X32;
+       else
+               code->code = V4L2_MBUS_FMT_AHSV8888_1X32;
+
+       return 0;
+}
+
+static int hsit_enum_frame_size(struct v4l2_subdev *subdev,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct v4l2_mbus_framefmt *format;
+
+       format = v4l2_subdev_get_try_format(fh, fse->pad);
+
+       if (fse->index || fse->code != format->code)
+               return -EINVAL;
+
+       if (fse->pad == HSIT_PAD_SINK) {
+               fse->min_width = HSIT_MIN_SIZE;
+               fse->max_width = HSIT_MAX_SIZE;
+               fse->min_height = HSIT_MIN_SIZE;
+               fse->max_height = HSIT_MAX_SIZE;
+       } else {
+               /* The size on the source pad are fixed and always identical to
+                * the size on the sink pad.
+                */
+               fse->min_width = format->width;
+               fse->max_width = format->width;
+               fse->min_height = format->height;
+               fse->max_height = format->height;
+       }
+
+       return 0;
+}
+
+static int hsit_get_format(struct v4l2_subdev *subdev,
+                          struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct vsp1_hsit *hsit = to_hsit(subdev);
+
+       fmt->format = *vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad,
+                                                 fmt->which);
+
+       return 0;
+}
+
+static int hsit_set_format(struct v4l2_subdev *subdev,
+                          struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct vsp1_hsit *hsit = to_hsit(subdev);
+       struct v4l2_mbus_framefmt *format;
+
+       format = vsp1_entity_get_pad_format(&hsit->entity, fh, fmt->pad,
+                                           fmt->which);
+
+       if (fmt->pad == HSIT_PAD_SOURCE) {
+               /* The HST and HSI output format code and resolution can't be
+                * modified.
+                */
+               fmt->format = *format;
+               return 0;
+       }
+
+       format->code = hsit->inverse ? V4L2_MBUS_FMT_AHSV8888_1X32
+                    : V4L2_MBUS_FMT_ARGB8888_1X32;
+       format->width = clamp_t(unsigned int, fmt->format.width,
+                               HSIT_MIN_SIZE, HSIT_MAX_SIZE);
+       format->height = clamp_t(unsigned int, fmt->format.height,
+                                HSIT_MIN_SIZE, HSIT_MAX_SIZE);
+       format->field = V4L2_FIELD_NONE;
+       format->colorspace = V4L2_COLORSPACE_SRGB;
+
+       fmt->format = *format;
+
+       /* Propagate the format to the source pad. */
+       format = vsp1_entity_get_pad_format(&hsit->entity, fh, HSIT_PAD_SOURCE,
+                                           fmt->which);
+       *format = fmt->format;
+       format->code = hsit->inverse ? V4L2_MBUS_FMT_ARGB8888_1X32
+                    : V4L2_MBUS_FMT_AHSV8888_1X32;
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+
+static struct v4l2_subdev_video_ops hsit_video_ops = {
+       .s_stream = hsit_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops hsit_pad_ops = {
+       .enum_mbus_code = hsit_enum_mbus_code,
+       .enum_frame_size = hsit_enum_frame_size,
+       .get_fmt = hsit_get_format,
+       .set_fmt = hsit_set_format,
+};
+
+static struct v4l2_subdev_ops hsit_ops = {
+       .video  = &hsit_video_ops,
+       .pad    = &hsit_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * Initialization and Cleanup
+ */
+
+struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse)
+{
+       struct v4l2_subdev *subdev;
+       struct vsp1_hsit *hsit;
+       int ret;
+
+       hsit = devm_kzalloc(vsp1->dev, sizeof(*hsit), GFP_KERNEL);
+       if (hsit == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       hsit->inverse = inverse;
+
+       if (inverse) {
+               hsit->entity.type = VSP1_ENTITY_HSI;
+               hsit->entity.id = VI6_DPR_NODE_HSI;
+       } else {
+               hsit->entity.type = VSP1_ENTITY_HST;
+               hsit->entity.id = VI6_DPR_NODE_HST;
+       }
+
+       ret = vsp1_entity_init(vsp1, &hsit->entity, 2);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       /* Initialize the V4L2 subdev. */
+       subdev = &hsit->entity.subdev;
+       v4l2_subdev_init(subdev, &hsit_ops);
+
+       subdev->entity.ops = &vsp1_media_ops;
+       subdev->internal_ops = &vsp1_subdev_internal_ops;
+       snprintf(subdev->name, sizeof(subdev->name), "%s %s",
+                dev_name(vsp1->dev), inverse ? "hsi" : "hst");
+       v4l2_set_subdevdata(subdev, hsit);
+       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       vsp1_entity_init_formats(subdev, NULL);
+
+       return hsit;
+}
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.h b/drivers/media/platform/vsp1/vsp1_hsit.h
new file mode 100644 (file)
index 0000000..82f1c84
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * vsp1_hsit.h  --  R-Car VSP1 Hue Saturation value (Inverse) Transform
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __VSP1_HSIT_H__
+#define __VSP1_HSIT_H__
+
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+
+#include "vsp1_entity.h"
+
+struct vsp1_device;
+
+#define HSIT_PAD_SINK                          0
+#define HSIT_PAD_SOURCE                                1
+
+struct vsp1_hsit {
+       struct vsp1_entity entity;
+       bool inverse;
+};
+
+static inline struct vsp1_hsit *to_hsit(struct v4l2_subdev *subdev)
+{
+       return container_of(subdev, struct vsp1_hsit, entity.subdev);
+}
+
+struct vsp1_hsit *vsp1_hsit_create(struct vsp1_device *vsp1, bool inverse);
+
+#endif /* __VSP1_HSIT_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
new file mode 100644 (file)
index 0000000..4e9dc7c
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * vsp1_lut.c  --  R-Car VSP1 Look-Up Table
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/gfp.h>
+#include <linux/vsp1.h>
+
+#include <media/v4l2-subdev.h>
+
+#include "vsp1.h"
+#include "vsp1_lut.h"
+
+#define LUT_MIN_SIZE                           4U
+#define LUT_MAX_SIZE                           8190U
+
+/* -----------------------------------------------------------------------------
+ * Device Access
+ */
+
+static inline u32 vsp1_lut_read(struct vsp1_lut *lut, u32 reg)
+{
+       return vsp1_read(lut->entity.vsp1, reg);
+}
+
+static inline void vsp1_lut_write(struct vsp1_lut *lut, u32 reg, u32 data)
+{
+       vsp1_write(lut->entity.vsp1, reg, data);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Core Operations
+ */
+
+static void lut_configure(struct vsp1_lut *lut, struct vsp1_lut_config *config)
+{
+       memcpy_toio(lut->entity.vsp1->mmio + VI6_LUT_TABLE, config->lut,
+                   sizeof(config->lut));
+}
+
+static long lut_ioctl(struct v4l2_subdev *subdev, unsigned int cmd, void *arg)
+{
+       struct vsp1_lut *lut = to_lut(subdev);
+
+       switch (cmd) {
+       case VIDIOC_VSP1_LUT_CONFIG:
+               lut_configure(lut, arg);
+               return 0;
+
+       default:
+               return -ENOIOCTLCMD;
+       }
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Video Operations
+ */
+
+static int lut_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+       struct vsp1_lut *lut = to_lut(subdev);
+
+       if (!enable)
+               return 0;
+
+       vsp1_lut_write(lut, VI6_LUT_CTRL, VI6_LUT_CTRL_EN);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Pad Operations
+ */
+
+static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
+                             struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_mbus_code_enum *code)
+{
+       static const unsigned int codes[] = {
+               V4L2_MBUS_FMT_ARGB8888_1X32,
+               V4L2_MBUS_FMT_AHSV8888_1X32,
+               V4L2_MBUS_FMT_AYUV8_1X32,
+       };
+       struct v4l2_mbus_framefmt *format;
+
+       if (code->pad == LUT_PAD_SINK) {
+               if (code->index >= ARRAY_SIZE(codes))
+                       return -EINVAL;
+
+               code->code = codes[code->index];
+       } else {
+               /* The LUT can't perform format conversion, the sink format is
+                * always identical to the source format.
+                */
+               if (code->index)
+                       return -EINVAL;
+
+               format = v4l2_subdev_get_try_format(fh, LUT_PAD_SINK);
+               code->code = format->code;
+       }
+
+       return 0;
+}
+
+static int lut_enum_frame_size(struct v4l2_subdev *subdev,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct v4l2_mbus_framefmt *format;
+
+       format = v4l2_subdev_get_try_format(fh, fse->pad);
+
+       if (fse->index || fse->code != format->code)
+               return -EINVAL;
+
+       if (fse->pad == LUT_PAD_SINK) {
+               fse->min_width = LUT_MIN_SIZE;
+               fse->max_width = LUT_MAX_SIZE;
+               fse->min_height = LUT_MIN_SIZE;
+               fse->max_height = LUT_MAX_SIZE;
+       } else {
+               /* The size on the source pad are fixed and always identical to
+                * the size on the sink pad.
+                */
+               fse->min_width = format->width;
+               fse->max_width = format->width;
+               fse->min_height = format->height;
+               fse->max_height = format->height;
+       }
+
+       return 0;
+}
+
+static int lut_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *fmt)
+{
+       struct vsp1_lut *lut = to_lut(subdev);
+
+       fmt->format = *vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad,
+                                                 fmt->which);
+
+       return 0;
+}
+
+static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *fmt)
+{
+       struct vsp1_lut *lut = to_lut(subdev);
+       struct v4l2_mbus_framefmt *format;
+
+       /* Default to YUV if the requested format is not supported. */
+       if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
+           fmt->format.code != V4L2_MBUS_FMT_AHSV8888_1X32 &&
+           fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32)
+               fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32;
+
+       format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad,
+                                           fmt->which);
+
+       if (fmt->pad == LUT_PAD_SOURCE) {
+               /* The LUT output format can't be modified. */
+               fmt->format = *format;
+               return 0;
+       }
+
+       format->width = clamp_t(unsigned int, fmt->format.width,
+                               LUT_MIN_SIZE, LUT_MAX_SIZE);
+       format->height = clamp_t(unsigned int, fmt->format.height,
+                                LUT_MIN_SIZE, LUT_MAX_SIZE);
+       format->field = V4L2_FIELD_NONE;
+       format->colorspace = V4L2_COLORSPACE_SRGB;
+
+       fmt->format = *format;
+
+       /* Propagate the format to the source pad. */
+       format = vsp1_entity_get_pad_format(&lut->entity, fh, LUT_PAD_SOURCE,
+                                           fmt->which);
+       *format = fmt->format;
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+
+static struct v4l2_subdev_core_ops lut_core_ops = {
+       .ioctl = lut_ioctl,
+};
+
+static struct v4l2_subdev_video_ops lut_video_ops = {
+       .s_stream = lut_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops lut_pad_ops = {
+       .enum_mbus_code = lut_enum_mbus_code,
+       .enum_frame_size = lut_enum_frame_size,
+       .get_fmt = lut_get_format,
+       .set_fmt = lut_set_format,
+};
+
+static struct v4l2_subdev_ops lut_ops = {
+       .core   = &lut_core_ops,
+       .video  = &lut_video_ops,
+       .pad    = &lut_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * Initialization and Cleanup
+ */
+
+struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1)
+{
+       struct v4l2_subdev *subdev;
+       struct vsp1_lut *lut;
+       int ret;
+
+       lut = devm_kzalloc(vsp1->dev, sizeof(*lut), GFP_KERNEL);
+       if (lut == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       lut->entity.type = VSP1_ENTITY_LUT;
+       lut->entity.id = VI6_DPR_NODE_LUT;
+
+       ret = vsp1_entity_init(vsp1, &lut->entity, 2);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       /* Initialize the V4L2 subdev. */
+       subdev = &lut->entity.subdev;
+       v4l2_subdev_init(subdev, &lut_ops);
+
+       subdev->entity.ops = &vsp1_media_ops;
+       subdev->internal_ops = &vsp1_subdev_internal_ops;
+       snprintf(subdev->name, sizeof(subdev->name), "%s lut",
+                dev_name(vsp1->dev));
+       v4l2_set_subdevdata(subdev, lut);
+       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       vsp1_entity_init_formats(subdev, NULL);
+
+       return lut;
+}
diff --git a/drivers/media/platform/vsp1/vsp1_lut.h b/drivers/media/platform/vsp1/vsp1_lut.h
new file mode 100644 (file)
index 0000000..f92ffb8
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * vsp1_lut.h  --  R-Car VSP1 Look-Up Table
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __VSP1_LUT_H__
+#define __VSP1_LUT_H__
+
+#include <media/media-entity.h>
+#include <media/v4l2-subdev.h>
+
+#include "vsp1_entity.h"
+
+struct vsp1_device;
+
+#define LUT_PAD_SINK                           0
+#define LUT_PAD_SOURCE                         1
+
+struct vsp1_lut {
+       struct vsp1_entity entity;
+       u32 lut[256];
+};
+
+static inline struct vsp1_lut *to_lut(struct v4l2_subdev *subdev)
+{
+       return container_of(subdev, struct vsp1_lut, entity.subdev);
+}
+
+struct vsp1_lut *vsp1_lut_create(struct vsp1_device *vsp1);
+
+#endif /* __VSP1_LUT_H__ */
index 1d3304f1365b3fcbfd9fcfc86ed4171ebd09f41d..28650806c20feff950e2064f806fa1f143c343e6 100644 (file)
  */
 
 #define VI6_SRU_CTRL0                  0x2200
+#define VI6_SRU_CTRL0_PARAM0_SHIFT     16
+#define VI6_SRU_CTRL0_PARAM1_SHIFT     8
+#define VI6_SRU_CTRL0_MODE_UPSCALE     (4 << 4)
+#define VI6_SRU_CTRL0_PARAM2           (1 << 3)
+#define VI6_SRU_CTRL0_PARAM3           (1 << 2)
+#define VI6_SRU_CTRL0_PARAM4           (1 << 1)
+#define VI6_SRU_CTRL0_EN               (1 << 0)
+
 #define VI6_SRU_CTRL1                  0x2204
+#define VI6_SRU_CTRL1_PARAM5           0x7ff
+
 #define VI6_SRU_CTRL2                  0x2208
+#define VI6_SRU_CTRL2_PARAM6_SHIFT     16
+#define VI6_SRU_CTRL2_PARAM7_SHIFT     8
+#define VI6_SRU_CTRL2_PARAM8_SHIFT     0
 
 /* -----------------------------------------------------------------------------
  * UDS Control Registers
  */
 
 #define VI6_LUT_CTRL                   0x2800
+#define VI6_LUT_CTRL_EN                        (1 << 0)
 
 /* -----------------------------------------------------------------------------
  * CLU Control Registers
  */
 
 #define VI6_HST_CTRL                   0x2a00
+#define VI6_HST_CTRL_EN                        (1 << 0)
 
 /* -----------------------------------------------------------------------------
  * HSI Control Registers
  */
 
 #define VI6_HSI_CTRL                   0x2b00
+#define VI6_HSI_CTRL_EN                        (1 << 0)
 
 /* -----------------------------------------------------------------------------
  * BRU Control Registers
index 254871d3423e571f052fed3337c3c7151749df88..bce2be5466b9133df3afdf1495fe94f7438a532b 100644 (file)
@@ -47,25 +47,36 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
        struct vsp1_rwpf *rpf = to_rwpf(subdev);
        const struct vsp1_format_info *fmtinfo = rpf->video.fmtinfo;
        const struct v4l2_pix_format_mplane *format = &rpf->video.format;
+       const struct v4l2_rect *crop = &rpf->crop;
        u32 pstride;
        u32 infmt;
 
        if (!enable)
                return 0;
 
-       /* Source size and stride. Cropping isn't supported yet. */
+       /* Source size, stride and crop offsets.
+        *
+        * The crop offsets correspond to the location of the crop rectangle top
+        * left corner in the plane buffer. Only two offsets are needed, as
+        * planes 2 and 3 always have identical strides.
+        */
        vsp1_rpf_write(rpf, VI6_RPF_SRC_BSIZE,
-                      (format->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
-                      (format->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
+                      (crop->width << VI6_RPF_SRC_BSIZE_BHSIZE_SHIFT) |
+                      (crop->height << VI6_RPF_SRC_BSIZE_BVSIZE_SHIFT));
        vsp1_rpf_write(rpf, VI6_RPF_SRC_ESIZE,
-                      (format->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
-                      (format->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
+                      (crop->width << VI6_RPF_SRC_ESIZE_EHSIZE_SHIFT) |
+                      (crop->height << VI6_RPF_SRC_ESIZE_EVSIZE_SHIFT));
 
+       rpf->offsets[0] = crop->top * format->plane_fmt[0].bytesperline
+                       + crop->left * fmtinfo->bpp[0] / 8;
        pstride = format->plane_fmt[0].bytesperline
                << VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
-       if (format->num_planes > 1)
+       if (format->num_planes > 1) {
+               rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
+                               + crop->left * fmtinfo->bpp[1] / 8;
                pstride |= format->plane_fmt[1].bytesperline
                        << VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
+       }
 
        vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
 
@@ -113,6 +124,8 @@ static struct v4l2_subdev_pad_ops rpf_pad_ops = {
        .enum_frame_size = vsp1_rwpf_enum_frame_size,
        .get_fmt = vsp1_rwpf_get_format,
        .set_fmt = vsp1_rwpf_set_format,
+       .get_selection = vsp1_rwpf_get_selection,
+       .set_selection = vsp1_rwpf_set_selection,
 };
 
 static struct v4l2_subdev_ops rpf_ops = {
@@ -129,11 +142,14 @@ static void rpf_vdev_queue(struct vsp1_video *video,
 {
        struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video);
 
-       vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y, buf->addr[0]);
+       vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
+                      buf->addr[0] + rpf->offsets[0]);
        if (buf->buf.num_planes > 1)
-               vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0, buf->addr[1]);
+               vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
+                              buf->addr[1] + rpf->offsets[1]);
        if (buf->buf.num_planes > 2)
-               vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1, buf->addr[2]);
+               vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
+                              buf->addr[2] + rpf->offsets[1]);
 }
 
 static const struct vsp1_video_operations rpf_vdev_ops = {
index 9752d5516cebc995b89071f0cc7fe4fbf169117d..782f770daee5e58fb2757b1589c21d5c61375088 100644 (file)
@@ -71,6 +71,19 @@ int vsp1_rwpf_enum_frame_size(struct v4l2_subdev *subdev,
        return 0;
 }
 
+static struct v4l2_rect *
+vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf, struct v4l2_subdev_fh *fh, u32 which)
+{
+       switch (which) {
+       case V4L2_SUBDEV_FORMAT_TRY:
+               return v4l2_subdev_get_try_crop(fh, RWPF_PAD_SINK);
+       case V4L2_SUBDEV_FORMAT_ACTIVE:
+               return &rwpf->crop;
+       default:
+               return NULL;
+       }
+}
+
 int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
                         struct v4l2_subdev_format *fmt)
 {
@@ -87,6 +100,7 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
 {
        struct vsp1_rwpf *rwpf = to_rwpf(subdev);
        struct v4l2_mbus_framefmt *format;
+       struct v4l2_rect *crop;
 
        /* Default to YUV if the requested format is not supported. */
        if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
@@ -115,6 +129,13 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
 
        fmt->format = *format;
 
+       /* Update the sink crop rectangle. */
+       crop = vsp1_rwpf_get_crop(rwpf, fh, fmt->which);
+       crop->left = 0;
+       crop->top = 0;
+       crop->width = fmt->format.width;
+       crop->height = fmt->format.height;
+
        /* Propagate the format to the source pad. */
        format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
                                            fmt->which);
@@ -122,3 +143,78 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
 
        return 0;
 }
+
+int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_selection *sel)
+{
+       struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+       struct v4l2_mbus_framefmt *format;
+
+       /* Cropping is implemented on the sink pad. */
+       if (sel->pad != RWPF_PAD_SINK)
+               return -EINVAL;
+
+       switch (sel->target) {
+       case V4L2_SEL_TGT_CROP:
+               sel->r = *vsp1_rwpf_get_crop(rwpf, fh, sel->which);
+               break;
+
+       case V4L2_SEL_TGT_CROP_BOUNDS:
+               format = vsp1_entity_get_pad_format(&rwpf->entity, fh,
+                                                   RWPF_PAD_SINK, sel->which);
+               sel->r.left = 0;
+               sel->r.top = 0;
+               sel->r.width = format->width;
+               sel->r.height = format->height;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_selection *sel)
+{
+       struct vsp1_rwpf *rwpf = to_rwpf(subdev);
+       struct v4l2_mbus_framefmt *format;
+       struct v4l2_rect *crop;
+
+       /* Cropping is implemented on the sink pad. */
+       if (sel->pad != RWPF_PAD_SINK)
+               return -EINVAL;
+
+       if (sel->target != V4L2_SEL_TGT_CROP)
+               return -EINVAL;
+
+       /* Make sure the crop rectangle is entirely contained in the image. The
+        * WPF top and left offsets are limited to 255.
+        */
+       format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SINK,
+                                           sel->which);
+       sel->r.left = min_t(unsigned int, sel->r.left, format->width - 2);
+       sel->r.top = min_t(unsigned int, sel->r.top, format->height - 2);
+       if (rwpf->entity.type == VSP1_ENTITY_WPF) {
+               sel->r.left = min_t(unsigned int, sel->r.left, 255);
+               sel->r.top = min_t(unsigned int, sel->r.top, 255);
+       }
+       sel->r.width = min_t(unsigned int, sel->r.width,
+                            format->width - sel->r.left);
+       sel->r.height = min_t(unsigned int, sel->r.height,
+                             format->height - sel->r.top);
+
+       crop = vsp1_rwpf_get_crop(rwpf, fh, sel->which);
+       *crop = sel->r;
+
+       /* Propagate the format to the source pad. */
+       format = vsp1_entity_get_pad_format(&rwpf->entity, fh, RWPF_PAD_SOURCE,
+                                           sel->which);
+       format->width = crop->width;
+       format->height = crop->height;
+
+       return 0;
+}
index c182d85f36b3225e12ac875362311fe0ac415af7..6cbdb547470bb7f49e511e50afcd706a0acaaa72 100644 (file)
@@ -29,6 +29,10 @@ struct vsp1_rwpf {
 
        unsigned int max_width;
        unsigned int max_height;
+
+       struct v4l2_rect crop;
+
+       unsigned int offsets[2];
 };
 
 static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
@@ -49,5 +53,11 @@ int vsp1_rwpf_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
                         struct v4l2_subdev_format *fmt);
 int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
                         struct v4l2_subdev_format *fmt);
+int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_selection *sel);
+int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
+                           struct v4l2_subdev_fh *fh,
+                           struct v4l2_subdev_selection *sel);
 
 #endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
new file mode 100644 (file)
index 0000000..7ab1a0b
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * vsp1_sru.c  --  R-Car VSP1 Super Resolution Unit
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/gfp.h>
+
+#include <media/v4l2-subdev.h>
+
+#include "vsp1.h"
+#include "vsp1_sru.h"
+
+#define SRU_MIN_SIZE                           4U
+#define SRU_MAX_SIZE                           8190U
+
+/* -----------------------------------------------------------------------------
+ * Device Access
+ */
+
+static inline u32 vsp1_sru_read(struct vsp1_sru *sru, u32 reg)
+{
+       return vsp1_read(sru->entity.vsp1, reg);
+}
+
+static inline void vsp1_sru_write(struct vsp1_sru *sru, u32 reg, u32 data)
+{
+       vsp1_write(sru->entity.vsp1, reg, data);
+}
+
+/* -----------------------------------------------------------------------------
+ * Controls
+ */
+
+#define V4L2_CID_VSP1_SRU_INTENSITY            (V4L2_CID_USER_BASE + 1)
+
+static int sru_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+       struct vsp1_sru *sru =
+               container_of(ctrl->handler, struct vsp1_sru, ctrls);
+
+       switch (ctrl->id) {
+       case V4L2_CID_VSP1_SRU_INTENSITY:
+               sru->intensity = ctrl->val;
+               break;
+       }
+
+       return 0;
+}
+
+static const struct v4l2_ctrl_ops sru_ctrl_ops = {
+       .s_ctrl = sru_s_ctrl,
+};
+
+static const struct v4l2_ctrl_config sru_intensity_control = {
+       .ops = &sru_ctrl_ops,
+       .id = V4L2_CID_VSP1_SRU_INTENSITY,
+       .name = "Intensity",
+       .type = V4L2_CTRL_TYPE_INTEGER,
+       .min = 1,
+       .max = 6,
+       .step = 1,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Core Operations
+ */
+
+struct vsp1_sru_param {
+       u32 ctrl0;
+       u32 ctrl2;
+};
+
+#define VI6_SRU_CTRL0_PARAMS(p0, p1)                   \
+       (((p0) << VI6_SRU_CTRL0_PARAM0_SHIFT) |         \
+        ((p1) << VI6_SRU_CTRL0_PARAM1_SHIFT))
+
+#define VI6_SRU_CTRL2_PARAMS(p6, p7, p8)               \
+       (((p6) << VI6_SRU_CTRL2_PARAM6_SHIFT) |         \
+        ((p7) << VI6_SRU_CTRL2_PARAM7_SHIFT) |         \
+        ((p8) << VI6_SRU_CTRL2_PARAM8_SHIFT))
+
+static const struct vsp1_sru_param vsp1_sru_params[] = {
+       {
+               .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN,
+               .ctrl2 = VI6_SRU_CTRL2_PARAMS(24, 40, 255),
+       }, {
+               .ctrl0 = VI6_SRU_CTRL0_PARAMS(256, 4) | VI6_SRU_CTRL0_EN,
+               .ctrl2 = VI6_SRU_CTRL2_PARAMS(8, 16, 255),
+       }, {
+               .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN,
+               .ctrl2 = VI6_SRU_CTRL2_PARAMS(36, 60, 255),
+       }, {
+               .ctrl0 = VI6_SRU_CTRL0_PARAMS(384, 5) | VI6_SRU_CTRL0_EN,
+               .ctrl2 = VI6_SRU_CTRL2_PARAMS(12, 27, 255),
+       }, {
+               .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN,
+               .ctrl2 = VI6_SRU_CTRL2_PARAMS(48, 80, 255),
+       }, {
+               .ctrl0 = VI6_SRU_CTRL0_PARAMS(511, 6) | VI6_SRU_CTRL0_EN,
+               .ctrl2 = VI6_SRU_CTRL2_PARAMS(16, 36, 255),
+       },
+};
+
+static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+       struct vsp1_sru *sru = to_sru(subdev);
+       const struct vsp1_sru_param *param;
+       struct v4l2_mbus_framefmt *input;
+       struct v4l2_mbus_framefmt *output;
+       bool upscale;
+       u32 ctrl0;
+
+       if (!enable)
+               return 0;
+
+       input = &sru->entity.formats[SRU_PAD_SINK];
+       output = &sru->entity.formats[SRU_PAD_SOURCE];
+       upscale = input->width != output->width;
+       param = &vsp1_sru_params[sru->intensity];
+
+       if (input->code == V4L2_MBUS_FMT_ARGB8888_1X32)
+               ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
+                     | VI6_SRU_CTRL0_PARAM4;
+       else
+               ctrl0 = VI6_SRU_CTRL0_PARAM3;
+
+       vsp1_sru_write(sru, VI6_SRU_CTRL0, param->ctrl0 | ctrl0 |
+                      (upscale ? VI6_SRU_CTRL0_MODE_UPSCALE : 0));
+       vsp1_sru_write(sru, VI6_SRU_CTRL1, VI6_SRU_CTRL1_PARAM5);
+       vsp1_sru_write(sru, VI6_SRU_CTRL2, param->ctrl2);
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Pad Operations
+ */
+
+static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
+                             struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_mbus_code_enum *code)
+{
+       static const unsigned int codes[] = {
+               V4L2_MBUS_FMT_ARGB8888_1X32,
+               V4L2_MBUS_FMT_AYUV8_1X32,
+       };
+       struct v4l2_mbus_framefmt *format;
+
+       if (code->pad == SRU_PAD_SINK) {
+               if (code->index >= ARRAY_SIZE(codes))
+                       return -EINVAL;
+
+               code->code = codes[code->index];
+       } else {
+               /* The SRU can't perform format conversion, the sink format is
+                * always identical to the source format.
+                */
+               if (code->index)
+                       return -EINVAL;
+
+               format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK);
+               code->code = format->code;
+       }
+
+       return 0;
+}
+
+static int sru_enum_frame_size(struct v4l2_subdev *subdev,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct v4l2_mbus_framefmt *format;
+
+       format = v4l2_subdev_get_try_format(fh, SRU_PAD_SINK);
+
+       if (fse->index || fse->code != format->code)
+               return -EINVAL;
+
+       if (fse->pad == SRU_PAD_SINK) {
+               fse->min_width = SRU_MIN_SIZE;
+               fse->max_width = SRU_MAX_SIZE;
+               fse->min_height = SRU_MIN_SIZE;
+               fse->max_height = SRU_MAX_SIZE;
+       } else {
+               fse->min_width = format->width;
+               fse->min_height = format->height;
+               if (format->width <= SRU_MAX_SIZE / 2 &&
+                   format->height <= SRU_MAX_SIZE / 2) {
+                       fse->max_width = format->width * 2;
+                       fse->max_height = format->height * 2;
+               } else {
+                       fse->max_width = format->width;
+                       fse->max_height = format->height;
+               }
+       }
+
+       return 0;
+}
+
+static int sru_get_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *fmt)
+{
+       struct vsp1_sru *sru = to_sru(subdev);
+
+       fmt->format = *vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad,
+                                                 fmt->which);
+
+       return 0;
+}
+
+static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh,
+                          unsigned int pad, struct v4l2_mbus_framefmt *fmt,
+                          enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_mbus_framefmt *format;
+       unsigned int input_area;
+       unsigned int output_area;
+
+       switch (pad) {
+       case SRU_PAD_SINK:
+               /* Default to YUV if the requested format is not supported. */
+               if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
+                   fmt->code != V4L2_MBUS_FMT_AYUV8_1X32)
+                       fmt->code = V4L2_MBUS_FMT_AYUV8_1X32;
+
+               fmt->width = clamp(fmt->width, SRU_MIN_SIZE, SRU_MAX_SIZE);
+               fmt->height = clamp(fmt->height, SRU_MIN_SIZE, SRU_MAX_SIZE);
+               break;
+
+       case SRU_PAD_SOURCE:
+               /* The SRU can't perform format conversion. */
+               format = vsp1_entity_get_pad_format(&sru->entity, fh,
+                                                   SRU_PAD_SINK, which);
+               fmt->code = format->code;
+
+               /* We can upscale by 2 in both direction, but not independently.
+                * Compare the input and output rectangles areas (avoiding
+                * integer overflows on the output): if the requested output
+                * area is larger than 1.5^2 the input area upscale by two,
+                * otherwise don't scale.
+                */
+               input_area = format->width * format->height;
+               output_area = min(fmt->width, SRU_MAX_SIZE)
+                           * min(fmt->height, SRU_MAX_SIZE);
+
+               if (fmt->width <= SRU_MAX_SIZE / 2 &&
+                   fmt->height <= SRU_MAX_SIZE / 2 &&
+                   output_area > input_area * 9 / 4) {
+                       fmt->width = format->width * 2;
+                       fmt->height = format->height * 2;
+               } else {
+                       fmt->width = format->width;
+                       fmt->height = format->height;
+               }
+               break;
+       }
+
+       fmt->field = V4L2_FIELD_NONE;
+       fmt->colorspace = V4L2_COLORSPACE_SRGB;
+}
+
+static int sru_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
+                         struct v4l2_subdev_format *fmt)
+{
+       struct vsp1_sru *sru = to_sru(subdev);
+       struct v4l2_mbus_framefmt *format;
+
+       sru_try_format(sru, fh, fmt->pad, &fmt->format, fmt->which);
+
+       format = vsp1_entity_get_pad_format(&sru->entity, fh, fmt->pad,
+                                           fmt->which);
+       *format = fmt->format;
+
+       if (fmt->pad == SRU_PAD_SINK) {
+               /* Propagate the format to the source pad. */
+               format = vsp1_entity_get_pad_format(&sru->entity, fh,
+                                                   SRU_PAD_SOURCE, fmt->which);
+               *format = fmt->format;
+
+               sru_try_format(sru, fh, SRU_PAD_SOURCE, format, fmt->which);
+       }
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdevice Operations
+ */
+
+static struct v4l2_subdev_video_ops sru_video_ops = {
+       .s_stream = sru_s_stream,
+};
+
+static struct v4l2_subdev_pad_ops sru_pad_ops = {
+       .enum_mbus_code = sru_enum_mbus_code,
+       .enum_frame_size = sru_enum_frame_size,
+       .get_fmt = sru_get_format,
+       .set_fmt = sru_set_format,
+};
+
+static struct v4l2_subdev_ops sru_ops = {
+       .video  = &sru_video_ops,
+       .pad    = &sru_pad_ops,
+};
+
+/* -----------------------------------------------------------------------------
+ * Initialization and Cleanup
+ */
+
+struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1)
+{
+       struct v4l2_subdev *subdev;
+       struct vsp1_sru *sru;
+       int ret;
+
+       sru = devm_kzalloc(vsp1->dev, sizeof(*sru), GFP_KERNEL);
+       if (sru == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       sru->entity.type = VSP1_ENTITY_SRU;
+       sru->entity.id = VI6_DPR_NODE_SRU;
+
+       ret = vsp1_entity_init(vsp1, &sru->entity, 2);
+       if (ret < 0)
+               return ERR_PTR(ret);
+
+       /* Initialize the V4L2 subdev. */
+       subdev = &sru->entity.subdev;
+       v4l2_subdev_init(subdev, &sru_ops);
+
+       subdev->entity.ops = &vsp1_media_ops;
+       subdev->internal_ops = &vsp1_subdev_internal_ops;
+       snprintf(subdev->name, sizeof(subdev->name), "%s sru",
+                dev_name(vsp1->dev));
+       v4l2_set_subdevdata(subdev, sru);
+       subdev->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       vsp1_entity_init_formats(subdev, NULL);
+
+       /* Initialize the control handler. */
+       v4l2_ctrl_handler_init(&sru->ctrls, 1);
+       v4l2_ctrl_new_custom(&sru->ctrls, &sru_intensity_control, NULL);
+       v4l2_ctrl_handler_setup(&sru->ctrls);
+       sru->entity.subdev.ctrl_handler = &sru->ctrls;
+
+       return sru;
+}
diff --git a/drivers/media/platform/vsp1/vsp1_sru.h b/drivers/media/platform/vsp1/vsp1_sru.h
new file mode 100644 (file)
index 0000000..381870b
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * vsp1_sru.h  --  R-Car VSP1 Super Resolution Unit
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contact: Laurent Pinchart (laurent.pinchart@ideasonboard.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#ifndef __VSP1_SRU_H__
+#define __VSP1_SRU_H__
+
+#include <media/media-entity.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-subdev.h>
+
+#include "vsp1_entity.h"
+
+struct vsp1_device;
+
+#define SRU_PAD_SINK                           0
+#define SRU_PAD_SOURCE                         1
+
+struct vsp1_sru {
+       struct vsp1_entity entity;
+
+       struct v4l2_ctrl_handler ctrls;
+       unsigned int intensity;
+};
+
+static inline struct vsp1_sru *to_sru(struct v4l2_subdev *subdev)
+{
+       return container_of(subdev, struct vsp1_sru, entity.subdev);
+}
+
+struct vsp1_sru *vsp1_sru_create(struct vsp1_device *vsp1);
+
+#endif /* __VSP1_SRU_H__ */
index 4b0ac07af662c2bca05c6534ecb52bfc15730c74..b4687a834f851c41412b6f9dc6c9e73569e3161d 100644 (file)
@@ -488,11 +488,17 @@ static bool vsp1_pipeline_ready(struct vsp1_pipeline *pipe)
  * This function completes the current buffer by filling its sequence number,
  * time stamp and payload size, and hands it back to the videobuf core.
  *
+ * When operating in DU output mode (deep pipeline to the DU through the LIF),
+ * the VSP1 needs to constantly supply frames to the display. In that case, if
+ * no other buffer is queued, reuse the one that has just been processed instead
+ * of handing it back to the videobuf core.
+ *
  * Return the next queued buffer or NULL if the queue is empty.
  */
 static struct vsp1_video_buffer *
 vsp1_video_complete_buffer(struct vsp1_video *video)
 {
+       struct vsp1_pipeline *pipe = to_vsp1_pipeline(&video->video.entity);
        struct vsp1_video_buffer *next = NULL;
        struct vsp1_video_buffer *done;
        unsigned long flags;
@@ -507,6 +513,13 @@ vsp1_video_complete_buffer(struct vsp1_video *video)
 
        done = list_first_entry(&video->irqqueue,
                                struct vsp1_video_buffer, queue);
+
+       /* In DU output mode reuse the buffer if the list is singular. */
+       if (pipe->lif && list_is_singular(&video->irqqueue)) {
+               spin_unlock_irqrestore(&video->irqlock, flags);
+               return done;
+       }
+
        list_del(&done->queue);
 
        if (!list_empty(&video->irqqueue))
index db4b85ee05fca8c03ccefac3878e4a91fd7034da..7baed81ff0051b7df9799aa47d9aa47f5dde4730 100644 (file)
@@ -48,8 +48,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
        struct vsp1_pipeline *pipe =
                to_vsp1_pipeline(&wpf->entity.subdev.entity);
        struct vsp1_device *vsp1 = wpf->entity.vsp1;
-       const struct v4l2_mbus_framefmt *format =
-               &wpf->entity.formats[RWPF_PAD_SOURCE];
+       const struct v4l2_rect *crop = &wpf->crop;
        unsigned int i;
        u32 srcrpf = 0;
        u32 outfmt = 0;
@@ -68,7 +67,7 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
 
        vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
 
-       /* Destination stride. Cropping isn't supported yet. */
+       /* Destination stride. */
        if (!pipe->lif) {
                struct v4l2_pix_format_mplane *format = &wpf->video.format;
 
@@ -79,10 +78,12 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
                                       format->plane_fmt[1].bytesperline);
        }
 
-       vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP,
-                      format->width << VI6_WPF_SZCLIP_SIZE_SHIFT);
-       vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP,
-                      format->height << VI6_WPF_SZCLIP_SIZE_SHIFT);
+       vsp1_wpf_write(wpf, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
+                      (crop->left << VI6_WPF_SZCLIP_OFST_SHIFT) |
+                      (crop->width << VI6_WPF_SZCLIP_SIZE_SHIFT));
+       vsp1_wpf_write(wpf, VI6_WPF_VSZCLIP, VI6_WPF_SZCLIP_EN |
+                      (crop->top << VI6_WPF_SZCLIP_OFST_SHIFT) |
+                      (crop->height << VI6_WPF_SZCLIP_SIZE_SHIFT));
 
        /* Format */
        if (!pipe->lif) {
@@ -130,6 +131,8 @@ static struct v4l2_subdev_pad_ops wpf_pad_ops = {
        .enum_frame_size = vsp1_rwpf_enum_frame_size,
        .get_fmt = vsp1_rwpf_get_format,
        .set_fmt = vsp1_rwpf_set_format,
+       .get_selection = vsp1_rwpf_get_selection,
+       .set_selection = vsp1_rwpf_set_selection,
 };
 
 static struct v4l2_subdev_ops wpf_ops = {
index 6ecdc39bb366c66cdc5998ef37eca73092edb569..192f36f2f4aa3dd5e2f7eae6fd4ab6e106d51d26 100644 (file)
@@ -21,6 +21,12 @@ config RADIO_SI470X
 
 source "drivers/media/radio/si470x/Kconfig"
 
+config RADIO_SI4713
+       tristate "Silicon Labs Si4713 FM Radio with RDS Transmitter support"
+       depends on VIDEO_V4L2
+
+source "drivers/media/radio/si4713/Kconfig"
+
 config RADIO_SI476X
        tristate "Silicon Laboratories Si476x I2C FM Radio"
        depends on I2C && VIDEO_V4L2
@@ -113,29 +119,6 @@ config RADIO_SHARK2
          To compile this driver as a module, choose M here: the
          module will be called radio-shark2.
 
-config I2C_SI4713
-       tristate "I2C driver for Silicon Labs Si4713 device"
-       depends on I2C && VIDEO_V4L2
-       ---help---
-         Say Y here if you want support to Si4713 I2C device.
-         This device driver supports only i2c bus.
-
-         To compile this driver as a module, choose M here: the
-         module will be called si4713.
-
-config RADIO_SI4713
-       tristate "Silicon Labs Si4713 FM Radio Transmitter support"
-       depends on I2C && VIDEO_V4L2
-       select I2C_SI4713
-       ---help---
-         Say Y here if you want support to Si4713 FM Radio Transmitter.
-         This device can transmit audio through FM. It can transmit
-         RDS and RBDS signals as well. This module is the v4l2 radio
-         interface for the i2c driver of this device.
-
-         To compile this driver as a module, choose M here: the
-         module will be called radio-si4713.
-
 config USB_KEENE
        tristate "Keene FM Transmitter USB support"
        depends on USB && VIDEO_V4L2
@@ -146,6 +129,20 @@ config USB_KEENE
          To compile this driver as a module, choose M here: the
          module will be called radio-keene.
 
+config USB_RAREMONO
+       tristate "Thanko's Raremono AM/FM/SW radio support"
+       depends on USB && VIDEO_V4L2
+       ---help---
+         The 'Thanko's Raremono' device contains the Si4734 chip from Silicon Labs Inc.
+         It is one of the very few or perhaps the only consumer USB radio device
+         to receive the AM/FM/SW bands.
+
+         Say Y here if you want to connect this type of AM/FM/SW receiver
+         to your computer's USB port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-raremono.
+
 config USB_MA901
        tristate "Masterkit MA901 USB FM radio support"
        depends on USB && VIDEO_V4L2
index 3b645601800dc8303e95ae5e25c66c887798bfe4..120e791199b2211e097bd6a2dba1b5f2f50d4b33 100644 (file)
@@ -17,12 +17,11 @@ obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
 obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
 obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
 obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
-obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
-obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
 obj-$(CONFIG_RADIO_SI476X) += radio-si476x.o
 obj-$(CONFIG_RADIO_MIROPCM20) += radio-miropcm20.o
 obj-$(CONFIG_USB_DSBR) += dsbr100.o
 obj-$(CONFIG_RADIO_SI470X) += si470x/
+obj-$(CONFIG_RADIO_SI4713) += si4713/
 obj-$(CONFIG_USB_MR800) += radio-mr800.o
 obj-$(CONFIG_USB_KEENE) += radio-keene.o
 obj-$(CONFIG_USB_MA901) += radio-ma901.o
@@ -33,6 +32,7 @@ obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
 obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o
 obj-$(CONFIG_RADIO_WL128X) += wl128x/
 obj-$(CONFIG_RADIO_TEA575X) += tea575x.o
+obj-$(CONFIG_USB_RAREMONO) += radio-raremono.o
 
 shark2-objs := radio-shark2.o radio-tea5777.o
 
diff --git a/drivers/media/radio/radio-raremono.c b/drivers/media/radio/radio-raremono.c
new file mode 100644 (file)
index 0000000..7b3bdbb
--- /dev/null
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2013 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/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+#include <linux/mutex.h>
+#include <linux/videodev2.h>
+#include <asm/unaligned.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+
+/*
+ * 'Thanko's Raremono' is a Japanese si4734-based AM/FM/SW USB receiver:
+ *
+ * http://www.raremono.jp/product/484.html/
+ *
+ * The USB protocol has been reversed engineered using wireshark, initially
+ * by Dinesh Ram <dinesh.ram@cern.ch> and finished by Hans Verkuil
+ * <hverkuil@xs4all.nl>.
+ *
+ * Sadly the firmware used in this product hides lots of goodies since the
+ * si4734 has more features than are supported by the firmware. Oh well...
+ */
+
+/* driver and module definitions */
+MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
+MODULE_DESCRIPTION("Thanko's Raremono AM/FM/SW Receiver USB driver");
+MODULE_LICENSE("GPL v2");
+
+/*
+ * The Device announces itself as Cygnal Integrated Products, Inc.
+ *
+ * The vendor and product IDs (and in fact all other lsusb information as
+ * well) are identical to the si470x Silicon Labs USB FM Radio Reference
+ * Design board, even though this card has a si4734 device. Clearly the
+ * designer of this product never bothered to change the USB IDs.
+ */
+
+/* USB Device ID List */
+static struct usb_device_id usb_raremono_device_table[] = {
+       {USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_raremono_device_table);
+
+#define BUFFER_LENGTH 64
+
+/* Timeout is set to a high value, could probably be reduced. Need more tests */
+#define USB_TIMEOUT 10000
+
+/* Frequency limits in KHz */
+#define FM_FREQ_RANGE_LOW      64000
+#define FM_FREQ_RANGE_HIGH     108000
+
+#define AM_FREQ_RANGE_LOW      520
+#define AM_FREQ_RANGE_HIGH     1710
+
+#define SW_FREQ_RANGE_LOW      2300
+#define SW_FREQ_RANGE_HIGH     26100
+
+enum { BAND_FM, BAND_AM, BAND_SW };
+
+static const struct v4l2_frequency_band 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 * 16,
+               .rangehigh  = FM_FREQ_RANGE_HIGH * 16,
+               .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 * 16,
+               .rangehigh  = AM_FREQ_RANGE_HIGH * 16,
+               .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 * 16,
+               .rangehigh  = SW_FREQ_RANGE_HIGH * 16,
+               .modulation = V4L2_BAND_MODULATION_AM,
+       },
+};
+
+struct raremono_device {
+       struct usb_device *usbdev;
+       struct usb_interface *intf;
+       struct video_device vdev;
+       struct v4l2_device v4l2_dev;
+       struct mutex lock;
+
+       u8 *buffer;
+       u32 band;
+       unsigned curfreq;
+};
+
+static inline struct raremono_device *to_raremono_dev(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct raremono_device, v4l2_dev);
+}
+
+/* Set frequency. */
+static int raremono_cmd_main(struct raremono_device *radio, unsigned band, unsigned freq)
+{
+       unsigned band_offset;
+       int ret;
+
+       switch (band) {
+       case BAND_FM:
+               band_offset = 1;
+               freq /= 10;
+               break;
+       case BAND_AM:
+               band_offset = 0;
+               break;
+       default:
+               band_offset = 2;
+               break;
+       }
+       radio->buffer[0] = 0x04 + band_offset;
+       radio->buffer[1] = freq >> 8;
+       radio->buffer[2] = freq & 0xff;
+
+       ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+                       HID_REQ_SET_REPORT,
+                       USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+                       0x0300 + radio->buffer[0], 2,
+                       radio->buffer, 3, USB_TIMEOUT);
+
+       if (ret < 0) {
+               dev_warn(radio->v4l2_dev.dev, "%s failed (%d)\n", __func__, ret);
+               return ret;
+       }
+       radio->curfreq = (band == BAND_FM) ? freq * 10 : freq;
+       return 0;
+}
+
+/* Handle unplugging the device.
+ * We call video_unregister_device in any case.
+ * The last function called in this procedure is
+ * usb_raremono_device_release.
+ */
+static void usb_raremono_disconnect(struct usb_interface *intf)
+{
+       struct raremono_device *radio = to_raremono_dev(usb_get_intfdata(intf));
+
+       dev_info(&intf->dev, "Thanko's Raremono disconnected\n");
+
+       mutex_lock(&radio->lock);
+       usb_set_intfdata(intf, NULL);
+       video_unregister_device(&radio->vdev);
+       v4l2_device_disconnect(&radio->v4l2_dev);
+       mutex_unlock(&radio->lock);
+       v4l2_device_put(&radio->v4l2_dev);
+}
+
+/*
+ * Linux Video interface
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *v)
+{
+       struct raremono_device *radio = video_drvdata(file);
+
+       strlcpy(v->driver, "radio-raremono", sizeof(v->driver));
+       strlcpy(v->card, "Thanko's Raremono", sizeof(v->card));
+       usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
+       v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+       v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
+       return 0;
+}
+
+static int vidioc_enum_freq_bands(struct file *file, void *priv,
+               struct v4l2_frequency_band *band)
+{
+       if (band->tuner != 0)
+               return -EINVAL;
+
+       if (band->index >= ARRAY_SIZE(bands))
+               return -EINVAL;
+
+       *band = bands[band->index];
+
+       return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+               struct v4l2_tuner *v)
+{
+       struct raremono_device *radio = video_drvdata(file);
+       int ret;
+
+       if (v->index > 0)
+               return -EINVAL;
+
+       strlcpy(v->name, "AM/FM/SW", sizeof(v->name));
+       v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+               V4L2_TUNER_CAP_FREQ_BANDS;
+       v->rangelow = AM_FREQ_RANGE_LOW * 16;
+       v->rangehigh = FM_FREQ_RANGE_HIGH * 16;
+       v->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
+       v->audmode = (radio->curfreq < FM_FREQ_RANGE_LOW) ?
+               V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO;
+       memset(radio->buffer, 1, BUFFER_LENGTH);
+       ret = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                       1, 0xa1, 0x030d, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
+
+       if (ret < 0) {
+               dev_warn(radio->v4l2_dev.dev, "%s failed (%d)\n", __func__, ret);
+               return ret;
+       }
+       v->signal = ((radio->buffer[1] & 0xf) << 8 | radio->buffer[2]) << 4;
+       return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+                                       const struct v4l2_tuner *v)
+{
+       return v->index ? -EINVAL : 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               const struct v4l2_frequency *f)
+{
+       struct raremono_device *radio = video_drvdata(file);
+       u32 freq = f->frequency;
+       unsigned band;
+
+       if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
+               return -EINVAL;
+
+       if (f->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) * 8)
+               band = BAND_FM;
+       else if (f->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) * 8)
+               band = BAND_AM;
+       else
+               band = BAND_SW;
+
+       freq = clamp_t(u32, f->frequency, bands[band].rangelow, bands[band].rangehigh);
+       return raremono_cmd_main(radio, band, freq / 16);
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *f)
+{
+       struct raremono_device *radio = video_drvdata(file);
+
+       if (f->tuner != 0)
+               return -EINVAL;
+       f->type = V4L2_TUNER_RADIO;
+       f->frequency = radio->curfreq * 16;
+       return 0;
+}
+
+/* File system interface */
+static const struct v4l2_file_operations usb_raremono_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = v4l2_fh_release,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops usb_raremono_ioctl_ops = {
+       .vidioc_querycap = vidioc_querycap,
+       .vidioc_g_tuner = vidioc_g_tuner,
+       .vidioc_s_tuner = vidioc_s_tuner,
+       .vidioc_g_frequency = vidioc_g_frequency,
+       .vidioc_s_frequency = vidioc_s_frequency,
+       .vidioc_enum_freq_bands = vidioc_enum_freq_bands,
+};
+
+/* check if the device is present and register with v4l and usb if it is */
+static int usb_raremono_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       struct raremono_device *radio;
+       int retval = 0;
+
+       radio = devm_kzalloc(&intf->dev, sizeof(struct raremono_device), GFP_KERNEL);
+       if (radio)
+               radio->buffer = devm_kmalloc(&intf->dev, BUFFER_LENGTH, GFP_KERNEL);
+
+       if (!radio || !radio->buffer)
+               return -ENOMEM;
+
+       radio->usbdev = interface_to_usbdev(intf);
+       radio->intf = intf;
+
+       /*
+        * This device uses the same USB IDs as the si470x SiLabs reference
+        * design. So do an additional check: attempt to read the device ID
+        * from the si470x: the lower 12 bits are 0x0242 for the si470x. The
+        * Raremono always returns 0x0800 (the meaning of that is unknown, but
+        * at least it works).
+        *
+        * We use this check to determine which device we are dealing with.
+        */
+       msleep(20);
+       retval = usb_control_msg(radio->usbdev,
+               usb_rcvctrlpipe(radio->usbdev, 0),
+               HID_REQ_GET_REPORT,
+               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+               1, 2,
+               radio->buffer, 3, 500);
+       if (retval != 3 ||
+           (get_unaligned_be16(&radio->buffer[1]) & 0xfff) == 0x0242) {
+               dev_info(&intf->dev, "this is not Thanko's Raremono.\n");
+               return -ENODEV;
+       }
+
+       dev_info(&intf->dev, "Thanko's Raremono connected: (%04X:%04X)\n",
+                       id->idVendor, id->idProduct);
+
+       retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
+       if (retval < 0) {
+               dev_err(&intf->dev, "couldn't register v4l2_device\n");
+               return retval;
+       }
+
+       mutex_init(&radio->lock);
+
+       strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+               sizeof(radio->vdev.name));
+       radio->vdev.v4l2_dev = &radio->v4l2_dev;
+       radio->vdev.fops = &usb_raremono_fops;
+       radio->vdev.ioctl_ops = &usb_raremono_ioctl_ops;
+       radio->vdev.lock = &radio->lock;
+       radio->vdev.release = video_device_release_empty;
+
+       usb_set_intfdata(intf, &radio->v4l2_dev);
+
+       video_set_drvdata(&radio->vdev, radio);
+       set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
+
+       raremono_cmd_main(radio, BAND_FM, 95160);
+
+       retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
+       if (retval == 0) {
+               dev_info(&intf->dev, "V4L2 device registered as %s\n",
+                               video_device_node_name(&radio->vdev));
+               return 0;
+       }
+       dev_err(&intf->dev, "could not register video device\n");
+       v4l2_device_unregister(&radio->v4l2_dev);
+       return retval;
+}
+
+/* USB subsystem interface */
+static struct usb_driver usb_raremono_driver = {
+       .name                   = "radio-raremono",
+       .probe                  = usb_raremono_probe,
+       .disconnect             = usb_raremono_disconnect,
+       .id_table               = usb_raremono_device_table,
+};
+
+module_usb_driver(usb_raremono_driver);
index d6d4d60261d506c5996d748ac011eb3f4cf4261a..07ef40595efda9ccb9e50bda9646d1c6f66b3926 100644 (file)
@@ -137,6 +137,8 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
 /* interrupt out endpoint 2 every 1 millisecond */
 #define UNUSED_REPORT          23
 
+#define MAX_REPORT_SIZE                64
+
 
 
 /**************************************************************************
@@ -208,7 +210,7 @@ MODULE_PARM_DESC(max_rds_errors, "RDS maximum block errors: *1*");
  */
 static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
 {
-       unsigned char *report = (unsigned char *) buf;
+       unsigned char *report = buf;
        int retval;
 
        retval = usb_control_msg(radio->usbdev,
@@ -231,7 +233,7 @@ static int si470x_get_report(struct si470x_device *radio, void *buf, int size)
  */
 static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
 {
-       unsigned char *report = (unsigned char *) buf;
+       unsigned char *report = buf;
        int retval;
 
        retval = usb_control_msg(radio->usbdev,
@@ -254,15 +256,14 @@ static int si470x_set_report(struct si470x_device *radio, void *buf, int size)
  */
 int si470x_get_register(struct si470x_device *radio, int regnr)
 {
-       unsigned char buf[REGISTER_REPORT_SIZE];
        int retval;
 
-       buf[0] = REGISTER_REPORT(regnr);
+       radio->usb_buf[0] = REGISTER_REPORT(regnr);
 
-       retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
+       retval = si470x_get_report(radio, radio->usb_buf, REGISTER_REPORT_SIZE);
 
        if (retval >= 0)
-               radio->registers[regnr] = get_unaligned_be16(&buf[1]);
+               radio->registers[regnr] = get_unaligned_be16(&radio->usb_buf[1]);
 
        return (retval < 0) ? -EINVAL : 0;
 }
@@ -273,13 +274,12 @@ int si470x_get_register(struct si470x_device *radio, int regnr)
  */
 int si470x_set_register(struct si470x_device *radio, int regnr)
 {
-       unsigned char buf[REGISTER_REPORT_SIZE];
        int retval;
 
-       buf[0] = REGISTER_REPORT(regnr);
-       put_unaligned_be16(radio->registers[regnr], &buf[1]);
+       radio->usb_buf[0] = REGISTER_REPORT(regnr);
+       put_unaligned_be16(radio->registers[regnr], &radio->usb_buf[1]);
 
-       retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
+       retval = si470x_set_report(radio, radio->usb_buf, REGISTER_REPORT_SIZE);
 
        return (retval < 0) ? -EINVAL : 0;
 }
@@ -295,18 +295,17 @@ int si470x_set_register(struct si470x_device *radio, int regnr)
  */
 static int si470x_get_all_registers(struct si470x_device *radio)
 {
-       unsigned char buf[ENTIRE_REPORT_SIZE];
        int retval;
        unsigned char regnr;
 
-       buf[0] = ENTIRE_REPORT;
+       radio->usb_buf[0] = ENTIRE_REPORT;
 
-       retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
+       retval = si470x_get_report(radio, radio->usb_buf, ENTIRE_REPORT_SIZE);
 
        if (retval >= 0)
                for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
                        radio->registers[regnr] = get_unaligned_be16(
-                               &buf[regnr * RADIO_REGISTER_SIZE + 1]);
+                               &radio->usb_buf[regnr * RADIO_REGISTER_SIZE + 1]);
 
        return (retval < 0) ? -EINVAL : 0;
 }
@@ -323,14 +322,13 @@ static int si470x_get_all_registers(struct si470x_device *radio)
 static int si470x_set_led_state(struct si470x_device *radio,
                unsigned char led_state)
 {
-       unsigned char buf[LED_REPORT_SIZE];
        int retval;
 
-       buf[0] = LED_REPORT;
-       buf[1] = LED_COMMAND;
-       buf[2] = led_state;
+       radio->usb_buf[0] = LED_REPORT;
+       radio->usb_buf[1] = LED_COMMAND;
+       radio->usb_buf[2] = led_state;
 
-       retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
+       retval = si470x_set_report(radio, radio->usb_buf, LED_REPORT_SIZE);
 
        return (retval < 0) ? -EINVAL : 0;
 }
@@ -346,19 +344,18 @@ static int si470x_set_led_state(struct si470x_device *radio,
  */
 static int si470x_get_scratch_page_versions(struct si470x_device *radio)
 {
-       unsigned char buf[SCRATCH_REPORT_SIZE];
        int retval;
 
-       buf[0] = SCRATCH_REPORT;
+       radio->usb_buf[0] = SCRATCH_REPORT;
 
-       retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
+       retval = si470x_get_report(radio, radio->usb_buf, SCRATCH_REPORT_SIZE);
 
        if (retval < 0)
                dev_warn(&radio->intf->dev, "si470x_get_scratch: "
                        "si470x_get_report returned %d\n", retval);
        else {
-               radio->software_version = buf[1];
-               radio->hardware_version = buf[2];
+               radio->software_version = radio->usb_buf[1];
+               radio->hardware_version = radio->usb_buf[2];
        }
 
        return (retval < 0) ? -EINVAL : 0;
@@ -509,6 +506,7 @@ static void si470x_usb_release(struct v4l2_device *v4l2_dev)
        v4l2_device_unregister(&radio->v4l2_dev);
        kfree(radio->int_in_buffer);
        kfree(radio->buffer);
+       kfree(radio->usb_buf);
        kfree(radio);
 }
 
@@ -593,6 +591,11 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
                retval = -ENOMEM;
                goto err_initial;
        }
+       radio->usb_buf = kmalloc(MAX_REPORT_SIZE, GFP_KERNEL);
+       if (radio->usb_buf == NULL) {
+               retval = -ENOMEM;
+               goto err_radio;
+       }
        radio->usbdev = interface_to_usbdev(intf);
        radio->intf = intf;
        radio->band = 1; /* Default to 76 - 108 MHz */
@@ -612,7 +615,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        if (!radio->int_in_endpoint) {
                dev_info(&intf->dev, "could not find interrupt in endpoint\n");
                retval = -EIO;
-               goto err_radio;
+               goto err_usbbuf;
        }
 
        int_end_size = le16_to_cpu(radio->int_in_endpoint->wMaxPacketSize);
@@ -621,7 +624,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        if (!radio->int_in_buffer) {
                dev_info(&intf->dev, "could not allocate int_in_buffer");
                retval = -ENOMEM;
-               goto err_radio;
+               goto err_usbbuf;
        }
 
        radio->int_in_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -632,6 +635,30 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        }
 
        radio->v4l2_dev.release = si470x_usb_release;
+
+       /*
+        * The si470x SiLabs reference design uses the same USB IDs as
+        * 'Thanko's Raremono' si4734 based receiver. So check here which we
+        * have: attempt to read the device ID from the si470x: the lower 12
+        * bits should be 0x0242 for the si470x.
+        *
+        * We use this check to determine which device we are dealing with.
+        */
+       if (id->idVendor == 0x10c4 && id->idProduct == 0x818a) {
+               retval = usb_control_msg(radio->usbdev,
+                               usb_rcvctrlpipe(radio->usbdev, 0),
+                               HID_REQ_GET_REPORT,
+                               USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+                               1, 2,
+                               radio->usb_buf, 3, 500);
+               if (retval != 3 ||
+                   (get_unaligned_be16(&radio->usb_buf[1]) & 0xfff) != 0x0242) {
+                       dev_info(&intf->dev, "this is not a si470x device.\n");
+                       retval = -ENODEV;
+                       goto err_urb;
+               }
+       }
+
        retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
        if (retval < 0) {
                dev_err(&intf->dev, "couldn't register v4l2_device\n");
@@ -743,6 +770,8 @@ err_urb:
        usb_free_urb(radio->int_in_urb);
 err_intbuffer:
        kfree(radio->int_in_buffer);
+err_usbbuf:
+       kfree(radio->usb_buf);
 err_radio:
        kfree(radio);
 err_initial:
index 467e95575488f02def2c29028c288cd71017a4a8..4b7660470e2f8a6cfbd7f868eaf1312029e08b4c 100644 (file)
@@ -167,6 +167,7 @@ struct si470x_device {
        /* reference to USB and video device */
        struct usb_device *usbdev;
        struct usb_interface *intf;
+       char *usb_buf;
 
        /* Interrupt endpoint handling */
        char *int_in_buffer;
diff --git a/drivers/media/radio/si4713/Kconfig b/drivers/media/radio/si4713/Kconfig
new file mode 100644 (file)
index 0000000..a7c3ba8
--- /dev/null
@@ -0,0 +1,40 @@
+config USB_SI4713
+       tristate "Silicon Labs Si4713 FM Radio Transmitter support with USB"
+       depends on USB && RADIO_SI4713
+       select SI4713
+       ---help---
+         This is a driver for USB devices with the Silicon Labs SI4713
+         chip. Currently these devices are known to work.
+         - 10c4:8244: Silicon Labs FM Transmitter USB device.
+
+         Say Y here if you want to connect this type of radio to your
+         computer's USB port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-usb-si4713.
+
+config PLATFORM_SI4713
+       tristate "Silicon Labs Si4713 FM Radio Transmitter support with I2C"
+       depends on I2C && RADIO_SI4713
+       select SI4713
+       ---help---
+         This is a driver for I2C devices with the Silicon Labs SI4713
+         chip.
+
+         Say Y here if you want to connect this type of radio to your
+         computer's I2C port.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-platform-si4713.
+
+config I2C_SI4713
+       tristate "Silicon Labs Si4713 FM Radio Transmitter support"
+       depends on I2C && RADIO_SI4713
+       ---help---
+         Say Y here if you want support to Si4713 FM Radio Transmitter.
+         This device can transmit audio through FM. It can transmit
+         RDS and RBDS signals as well. This module is the v4l2 radio
+         interface for the i2c driver of this device.
+
+         To compile this driver as a module, choose M here: the
+         module will be called si4713.
diff --git a/drivers/media/radio/si4713/Makefile b/drivers/media/radio/si4713/Makefile
new file mode 100644 (file)
index 0000000..ddaaf92
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile for radios with Silicon Labs Si4713 FM Radio Transmitters
+#
+
+obj-$(CONFIG_I2C_SI4713) += si4713.o
+obj-$(CONFIG_USB_SI4713) += radio-usb-si4713.o
+obj-$(CONFIG_PLATFORM_SI4713) += radio-platform-si4713.o
diff --git a/drivers/media/radio/si4713/radio-usb-si4713.c b/drivers/media/radio/si4713/radio-usb-si4713.c
new file mode 100644 (file)
index 0000000..779855b
--- /dev/null
@@ -0,0 +1,540 @@
+/*
+ * Copyright 2013 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.
+ */
+
+/* kernel includes */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/mutex.h>
+#include <linux/i2c.h>
+/* V4l includes */
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-event.h>
+#include <media/si4713.h>
+
+#include "si4713.h"
+
+/* driver and module definitions */
+MODULE_AUTHOR("Dinesh Ram <dinesh.ram@cern.ch>");
+MODULE_DESCRIPTION("Si4713 FM Transmitter USB driver");
+MODULE_LICENSE("GPL v2");
+
+/* The Device announces itself as Cygnal Integrated Products, Inc. */
+#define USB_SI4713_VENDOR              0x10c4
+#define USB_SI4713_PRODUCT             0x8244
+
+#define BUFFER_LENGTH                  64
+#define USB_TIMEOUT                    1000
+#define USB_RESP_TIMEOUT               50000
+
+/* USB Device ID List */
+static struct usb_device_id usb_si4713_usb_device_table[] = {
+       {USB_DEVICE_AND_INTERFACE_INFO(USB_SI4713_VENDOR, USB_SI4713_PRODUCT,
+                                                       USB_CLASS_HID, 0, 0) },
+       { }                                             /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, usb_si4713_usb_device_table);
+
+struct si4713_usb_device {
+       struct usb_device       *usbdev;
+       struct usb_interface    *intf;
+       struct video_device     vdev;
+       struct v4l2_device      v4l2_dev;
+       struct v4l2_subdev      *v4l2_subdev;
+       struct mutex            lock;
+       struct i2c_adapter      i2c_adapter;
+
+       u8                      *buffer;
+};
+
+static inline struct si4713_usb_device *to_si4713_dev(struct v4l2_device *v4l2_dev)
+{
+       return container_of(v4l2_dev, struct si4713_usb_device, v4l2_dev);
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+                                       struct v4l2_capability *v)
+{
+       struct si4713_usb_device *radio = video_drvdata(file);
+
+       strlcpy(v->driver, "radio-usb-si4713", sizeof(v->driver));
+       strlcpy(v->card, "Si4713 FM Transmitter", sizeof(v->card));
+       usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
+       v->device_caps = V4L2_CAP_MODULATOR | V4L2_CAP_RDS_OUTPUT;
+       v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+       return 0;
+}
+
+static int vidioc_g_modulator(struct file *file, void *priv,
+                               struct v4l2_modulator *vm)
+{
+       struct si4713_usb_device *radio = video_drvdata(file);
+
+       return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_modulator, vm);
+}
+
+static int vidioc_s_modulator(struct file *file, void *priv,
+                               const struct v4l2_modulator *vm)
+{
+       struct si4713_usb_device *radio = video_drvdata(file);
+
+       return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_modulator, vm);
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+                               const struct v4l2_frequency *vf)
+{
+       struct si4713_usb_device *radio = video_drvdata(file);
+
+       return v4l2_subdev_call(radio->v4l2_subdev, tuner, s_frequency, vf);
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+                               struct v4l2_frequency *vf)
+{
+       struct si4713_usb_device *radio = video_drvdata(file);
+
+       return v4l2_subdev_call(radio->v4l2_subdev, tuner, g_frequency, vf);
+}
+
+static const struct v4l2_ioctl_ops usb_si4713_ioctl_ops = {
+       .vidioc_querycap          = vidioc_querycap,
+       .vidioc_g_modulator       = vidioc_g_modulator,
+       .vidioc_s_modulator       = vidioc_s_modulator,
+       .vidioc_g_frequency       = vidioc_g_frequency,
+       .vidioc_s_frequency       = vidioc_s_frequency,
+       .vidioc_log_status        = v4l2_ctrl_log_status,
+       .vidioc_subscribe_event   = v4l2_ctrl_subscribe_event,
+       .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+/* File system interface */
+static const struct v4l2_file_operations usb_si4713_fops = {
+       .owner          = THIS_MODULE,
+       .open           = v4l2_fh_open,
+       .release        = v4l2_fh_release,
+       .poll           = v4l2_ctrl_poll,
+       .unlocked_ioctl = video_ioctl2,
+};
+
+static void usb_si4713_video_device_release(struct v4l2_device *v4l2_dev)
+{
+       struct si4713_usb_device *radio = to_si4713_dev(v4l2_dev);
+       struct i2c_adapter *adapter = &radio->i2c_adapter;
+
+       i2c_del_adapter(adapter);
+       v4l2_device_unregister(&radio->v4l2_dev);
+       kfree(radio->buffer);
+       kfree(radio);
+}
+
+/*
+ * This command sequence emulates the behaviour of the Windows driver.
+ * The structure of these commands was determined by sniffing the
+ * usb traffic of the device during startup.
+ * Most likely, these commands make some queries to the device.
+ * Commands are sent to enquire parameters like the bus mode,
+ * component revision, boot mode, the device serial number etc.
+ *
+ * These commands are necessary to be sent in this order during startup.
+ * The device fails to powerup if these commands are not sent.
+ *
+ * The complete list of startup commands is given in the start_seq table below.
+ */
+static int si4713_send_startup_command(struct si4713_usb_device *radio)
+{
+       unsigned long until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1;
+       u8 *buffer = radio->buffer;
+       int retval;
+
+       /* send the command */
+       retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+                                       0x09, 0x21, 0x033f, 0, radio->buffer,
+                                       BUFFER_LENGTH, USB_TIMEOUT);
+       if (retval < 0)
+               return retval;
+
+       for (;;) {
+               /* receive the response */
+               retval = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
+                               0x01, 0xa1, 0x033f, 0, radio->buffer,
+                               BUFFER_LENGTH, USB_TIMEOUT);
+               if (retval < 0)
+                       return retval;
+               if (!radio->buffer[1]) {
+                       /* USB traffic sniffing showed that some commands require
+                        * additional checks. */
+                       switch (buffer[1]) {
+                       case 0x32:
+                               if (radio->buffer[2] == 0)
+                                       return 0;
+                               break;
+                       case 0x14:
+                       case 0x12:
+                               if (radio->buffer[2] & SI4713_CTS)
+                                       return 0;
+                               break;
+                       case 0x06:
+                               if ((radio->buffer[2] & SI4713_CTS) && radio->buffer[9] == 0x08)
+                                       return 0;
+                               break;
+                       default:
+                               return 0;
+                       }
+               }
+               if (time_is_before_jiffies(until_jiffies))
+                       return -EIO;
+               msleep(3);
+       }
+
+       return retval;
+}
+
+struct si4713_start_seq_table {
+       int len;
+       u8 payload[8];
+};
+
+/*
+ * Some of the startup commands that could be recognized are :
+ * (0x03): Get serial number of the board (Response : CB000-00-00)
+ * (0x06, 0x03, 0x03, 0x08, 0x01, 0x0f) : Get Component revision
+ */
+static struct si4713_start_seq_table start_seq[] = {
+
+       { 1, { 0x03 } },
+       { 2, { 0x32, 0x7f } },
+       { 6, { 0x06, 0x03, 0x03, 0x08, 0x01, 0x0f } },
+       { 2, { 0x14, 0x02 } },
+       { 2, { 0x09, 0x90 } },
+       { 3, { 0x08, 0x90, 0xfa } },
+       { 2, { 0x36, 0x01 } },
+       { 2, { 0x05, 0x03 } },
+       { 7, { 0x06, 0x00, 0x06, 0x0e, 0x01, 0x0f, 0x05 } },
+       { 1, { 0x12 } },
+       /* Commands that are sent after pressing the 'Initialize'
+               button in the windows application */
+       { 1, { 0x03 } },
+       { 1, { 0x01 } },
+       { 2, { 0x09, 0x90 } },
+       { 3, { 0x08, 0x90, 0xfa } },
+       { 1, { 0x34 } },
+       { 2, { 0x35, 0x01 } },
+       { 2, { 0x36, 0x01 } },
+       { 2, { 0x30, 0x09 } },
+       { 4, { 0x30, 0x06, 0x00, 0xe2 } },
+       { 3, { 0x31, 0x01, 0x30 } },
+       { 3, { 0x31, 0x04, 0x09 } },
+       { 2, { 0x05, 0x02 } },
+       { 6, { 0x06, 0x03, 0x03, 0x08, 0x01, 0x0f } },
+};
+
+static int si4713_start_seq(struct si4713_usb_device *radio)
+{
+       int retval = 0;
+       int i;
+
+       radio->buffer[0] = 0x3f;
+
+       for (i = 0; i < ARRAY_SIZE(start_seq); i++) {
+               int len = start_seq[i].len;
+               u8 *payload = start_seq[i].payload;
+
+               memcpy(radio->buffer + 1, payload, len);
+               memset(radio->buffer + len + 1, 0, BUFFER_LENGTH - 1 - len);
+               retval = si4713_send_startup_command(radio);
+       }
+
+       return retval;
+}
+
+static struct i2c_board_info si4713_board_info = {
+       I2C_BOARD_INFO("si4713", SI4713_I2C_ADDR_BUSEN_HIGH),
+};
+
+struct si4713_command_table {
+       int command_id;
+       u8 payload[8];
+};
+
+/*
+ * Structure of a command :
+ *     Byte 1 : 0x3f (always)
+ *     Byte 2 : 0x06 (send a command)
+ *     Byte 3 : Unknown
+ *     Byte 4 : Number of arguments + 1 (for the command byte)
+ *     Byte 5 : Number of response bytes
+ */
+static struct si4713_command_table command_table[] = {
+
+       { SI4713_CMD_POWER_UP,          { 0x00, SI4713_PWUP_NARGS + 1, SI4713_PWUP_NRESP} },
+       { SI4713_CMD_GET_REV,           { 0x03, 0x01, SI4713_GETREV_NRESP } },
+       { SI4713_CMD_POWER_DOWN,        { 0x00, 0x01, SI4713_PWDN_NRESP} },
+       { SI4713_CMD_SET_PROPERTY,      { 0x00, SI4713_SET_PROP_NARGS + 1, SI4713_SET_PROP_NRESP } },
+       { SI4713_CMD_GET_PROPERTY,      { 0x00, SI4713_GET_PROP_NARGS + 1, SI4713_GET_PROP_NRESP } },
+       { SI4713_CMD_TX_TUNE_FREQ,      { 0x03, SI4713_TXFREQ_NARGS + 1, SI4713_TXFREQ_NRESP } },
+       { SI4713_CMD_TX_TUNE_POWER,     { 0x03, SI4713_TXPWR_NARGS + 1, SI4713_TXPWR_NRESP } },
+       { SI4713_CMD_TX_TUNE_MEASURE,   { 0x03, SI4713_TXMEA_NARGS + 1, SI4713_TXMEA_NRESP } },
+       { SI4713_CMD_TX_TUNE_STATUS,    { 0x00, SI4713_TXSTATUS_NARGS + 1, SI4713_TXSTATUS_NRESP } },
+       { SI4713_CMD_TX_ASQ_STATUS,     { 0x03, SI4713_ASQSTATUS_NARGS + 1, SI4713_ASQSTATUS_NRESP } },
+       { SI4713_CMD_GET_INT_STATUS,    { 0x03, 0x01, SI4713_GET_STATUS_NRESP } },
+       { SI4713_CMD_TX_RDS_BUFF,       { 0x03, SI4713_RDSBUFF_NARGS + 1, SI4713_RDSBUFF_NRESP } },
+       { SI4713_CMD_TX_RDS_PS,         { 0x00, SI4713_RDSPS_NARGS + 1, SI4713_RDSPS_NRESP } },
+};
+
+static int send_command(struct si4713_usb_device *radio, u8 *payload, char *data, int len)
+{
+       int retval;
+
+       radio->buffer[0] = 0x3f;
+       radio->buffer[1] = 0x06;
+
+       memcpy(radio->buffer + 2, payload, 3);
+       memcpy(radio->buffer + 5, data, len);
+       memset(radio->buffer + 5 + len, 0, BUFFER_LENGTH - 5 - len);
+
+       /* send the command */
+       retval = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
+                                       0x09, 0x21, 0x033f, 0, radio->buffer,
+                                       BUFFER_LENGTH, USB_TIMEOUT);
+
+       return retval < 0 ? retval : 0;
+}
+
+static int si4713_i2c_read(struct si4713_usb_device *radio, char *data, int len)
+{
+       unsigned long until_jiffies = jiffies + usecs_to_jiffies(USB_RESP_TIMEOUT) + 1;
+       int retval;
+
+       /* receive the response */
+       for (;;) {
+               retval = usb_control_msg(radio->usbdev,
+                                       usb_rcvctrlpipe(radio->usbdev, 0),
+                                       0x01, 0xa1, 0x033f, 0, radio->buffer,
+                                       BUFFER_LENGTH, USB_TIMEOUT);
+               if (retval < 0)
+                       return retval;
+
+               /*
+                * Check that we get a valid reply back (buffer[1] == 0) and
+                * that CTS is set before returning, otherwise we wait and try
+                * again. The i2c driver also does the CTS check, but the timeouts
+                * used there are much too small for this USB driver, so we wait
+                * for it here.
+                */
+               if (radio->buffer[1] == 0 && (radio->buffer[2] & SI4713_CTS)) {
+                       memcpy(data, radio->buffer + 2, len);
+                       return 0;
+               }
+               if (time_is_before_jiffies(until_jiffies)) {
+                       /* Zero the status value, ensuring CTS isn't set */
+                       data[0] = 0;
+                       return 0;
+               }
+               msleep(3);
+       }
+}
+
+static int si4713_i2c_write(struct si4713_usb_device *radio, char *data, int len)
+{
+       int retval = -EINVAL;
+       int i;
+
+       if (len > BUFFER_LENGTH - 5)
+               return -EINVAL;
+
+       for (i = 0; i < ARRAY_SIZE(command_table); i++) {
+               if (data[0] == command_table[i].command_id)
+                       retval = send_command(radio, command_table[i].payload,
+                                               data, len);
+       }
+
+       return retval < 0 ? retval : 0;
+}
+
+static int si4713_transfer(struct i2c_adapter *i2c_adapter,
+                               struct i2c_msg *msgs, int num)
+{
+       struct si4713_usb_device *radio = i2c_get_adapdata(i2c_adapter);
+       int retval = -EINVAL;
+       int i;
+
+       if (num <= 0)
+               return 0;
+
+       for (i = 0; i < num; i++) {
+               if (msgs[i].flags & I2C_M_RD)
+                       retval = si4713_i2c_read(radio, msgs[i].buf, msgs[i].len);
+               else
+                       retval = si4713_i2c_write(radio, msgs[i].buf, msgs[i].len);
+               if (retval)
+                       break;
+       }
+
+       return retval ? retval : num;
+}
+
+static u32 si4713_functionality(struct i2c_adapter *adapter)
+{
+       return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static struct i2c_algorithm si4713_algo = {
+       .master_xfer   = si4713_transfer,
+       .functionality = si4713_functionality,
+};
+
+/* This name value shows up in the sysfs filename associated
+               with this I2C adapter */
+static struct i2c_adapter si4713_i2c_adapter_template = {
+       .name   = "si4713-i2c",
+       .owner  = THIS_MODULE,
+       .algo   = &si4713_algo,
+};
+
+static int si4713_register_i2c_adapter(struct si4713_usb_device *radio)
+{
+       radio->i2c_adapter = si4713_i2c_adapter_template;
+       /* set up sysfs linkage to our parent device */
+       radio->i2c_adapter.dev.parent = &radio->usbdev->dev;
+       i2c_set_adapdata(&radio->i2c_adapter, radio);
+
+       return i2c_add_adapter(&radio->i2c_adapter);
+}
+
+/* check if the device is present and register with v4l and usb if it is */
+static int usb_si4713_probe(struct usb_interface *intf,
+                               const struct usb_device_id *id)
+{
+       struct si4713_usb_device *radio;
+       struct i2c_adapter *adapter;
+       struct v4l2_subdev *sd;
+       int retval = -ENOMEM;
+
+       dev_info(&intf->dev, "Si4713 development board discovered: (%04X:%04X)\n",
+                       id->idVendor, id->idProduct);
+
+       /* Initialize local device structure */
+       radio = kzalloc(sizeof(struct si4713_usb_device), GFP_KERNEL);
+       if (radio)
+               radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL);
+
+       if (!radio || !radio->buffer) {
+               dev_err(&intf->dev, "kmalloc for si4713_usb_device failed\n");
+               kfree(radio);
+               return -ENOMEM;
+       }
+
+       mutex_init(&radio->lock);
+
+       radio->usbdev = interface_to_usbdev(intf);
+       radio->intf = intf;
+       usb_set_intfdata(intf, &radio->v4l2_dev);
+
+       retval = si4713_start_seq(radio);
+       if (retval < 0)
+               goto err_v4l2;
+
+       retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
+       if (retval < 0) {
+               dev_err(&intf->dev, "couldn't register v4l2_device\n");
+               goto err_v4l2;
+       }
+
+       retval = si4713_register_i2c_adapter(radio);
+       if (retval < 0) {
+               dev_err(&intf->dev, "could not register i2c device\n");
+               goto err_i2cdev;
+       }
+
+       adapter = &radio->i2c_adapter;
+       sd = v4l2_i2c_new_subdev_board(&radio->v4l2_dev, adapter,
+                                         &si4713_board_info, NULL);
+       radio->v4l2_subdev = sd;
+       if (!sd) {
+               dev_err(&intf->dev, "cannot get v4l2 subdevice\n");
+               retval = -ENODEV;
+               goto del_adapter;
+       }
+
+       radio->vdev.ctrl_handler = sd->ctrl_handler;
+       radio->v4l2_dev.release = usb_si4713_video_device_release;
+       strlcpy(radio->vdev.name, radio->v4l2_dev.name,
+               sizeof(radio->vdev.name));
+       radio->vdev.v4l2_dev = &radio->v4l2_dev;
+       radio->vdev.fops = &usb_si4713_fops;
+       radio->vdev.ioctl_ops = &usb_si4713_ioctl_ops;
+       radio->vdev.lock = &radio->lock;
+       radio->vdev.release = video_device_release_empty;
+       radio->vdev.vfl_dir = VFL_DIR_TX;
+
+       video_set_drvdata(&radio->vdev, radio);
+       set_bit(V4L2_FL_USE_FH_PRIO, &radio->vdev.flags);
+
+       retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
+       if (retval < 0) {
+               dev_err(&intf->dev, "could not register video device\n");
+               goto del_adapter;
+       }
+
+       dev_info(&intf->dev, "V4L2 device registered as %s\n",
+                       video_device_node_name(&radio->vdev));
+
+       return 0;
+
+del_adapter:
+       i2c_del_adapter(adapter);
+err_i2cdev:
+       v4l2_device_unregister(&radio->v4l2_dev);
+err_v4l2:
+       kfree(radio->buffer);
+       kfree(radio);
+       return retval;
+}
+
+static void usb_si4713_disconnect(struct usb_interface *intf)
+{
+       struct si4713_usb_device *radio = to_si4713_dev(usb_get_intfdata(intf));
+
+       dev_info(&intf->dev, "Si4713 development board now disconnected\n");
+
+       mutex_lock(&radio->lock);
+       usb_set_intfdata(intf, NULL);
+       video_unregister_device(&radio->vdev);
+       v4l2_device_disconnect(&radio->v4l2_dev);
+       mutex_unlock(&radio->lock);
+       v4l2_device_put(&radio->v4l2_dev);
+}
+
+/* USB subsystem interface */
+static struct usb_driver usb_si4713_driver = {
+       .name                   = "radio-usb-si4713",
+       .probe                  = usb_si4713_probe,
+       .disconnect             = usb_si4713_disconnect,
+       .id_table               = usb_si4713_usb_device_table,
+};
+
+module_usb_driver(usb_si4713_driver);
similarity index 86%
rename from drivers/media/radio/si4713-i2c.c
rename to drivers/media/radio/si4713/si4713.c
index 9ec48ccbcf0b2acab93f4eddd6eb31ed4998de34..07d5153811e88b4fc3c12c2136bb46ea35cc42e4 100644 (file)
 #include <linux/i2c.h>
 #include <linux/slab.h>
 #include <linux/gpio.h>
-#include <linux/regulator/consumer.h>
 #include <linux/module.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-common.h>
 
-#include "si4713-i2c.h"
+#include "si4713.h"
 
 /* module parameters */
 static int debug;
@@ -45,23 +44,18 @@ MODULE_AUTHOR("Eduardo Valentin <eduardo.valentin@nokia.com>");
 MODULE_DESCRIPTION("I2C driver for Si4713 FM Radio Transmitter");
 MODULE_VERSION("0.0.1");
 
-static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = {
-       "vio",
-       "vdd",
-};
-
 #define DEFAULT_RDS_PI                 0x00
 #define DEFAULT_RDS_PTY                        0x00
 #define DEFAULT_RDS_DEVIATION          0x00C8
 #define DEFAULT_RDS_PS_REPEAT_COUNT    0x0003
 #define DEFAULT_LIMITER_RTIME          0x1392
 #define DEFAULT_LIMITER_DEV            0x102CA
-#define DEFAULT_PILOT_FREQUENCY        0x4A38
+#define DEFAULT_PILOT_FREQUENCY                0x4A38
 #define DEFAULT_PILOT_DEVIATION                0x1A5E
 #define DEFAULT_ACOMP_ATIME            0x0000
 #define DEFAULT_ACOMP_RTIME            0xF4240L
 #define DEFAULT_ACOMP_GAIN             0x0F
-#define DEFAULT_ACOMP_THRESHOLD        (-0x28)
+#define DEFAULT_ACOMP_THRESHOLD                (-0x28)
 #define DEFAULT_MUTE                   0x01
 #define DEFAULT_POWER_LEVEL            88
 #define DEFAULT_FREQUENCY              8800
@@ -213,6 +207,7 @@ static int si4713_send_command(struct si4713_device *sdev, const u8 command,
                                u8 response[], const int respn, const int usecs)
 {
        struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd);
+       unsigned long until_jiffies;
        u8 data1[MAX_ARGS + 1];
        int err;
 
@@ -228,30 +223,42 @@ static int si4713_send_command(struct si4713_device *sdev, const u8 command,
        if (err != argn + 1) {
                v4l2_err(&sdev->sd, "Error while sending command 0x%02x\n",
                        command);
-               return (err > 0) ? -EIO : err;
+               return err < 0 ? err : -EIO;
        }
 
+       until_jiffies = jiffies + usecs_to_jiffies(usecs) + 1;
+
        /* Wait response from interrupt */
-       if (!wait_for_completion_timeout(&sdev->work,
+       if (client->irq) {
+               if (!wait_for_completion_timeout(&sdev->work,
                                usecs_to_jiffies(usecs) + 1))
-               v4l2_warn(&sdev->sd,
+                       v4l2_warn(&sdev->sd,
                                "(%s) Device took too much time to answer.\n",
                                __func__);
-
-       /* Then get the response */
-       err = i2c_master_recv(client, response, respn);
-       if (err != respn) {
-               v4l2_err(&sdev->sd,
-                       "Error while reading response for command 0x%02x\n",
-                       command);
-               return (err > 0) ? -EIO : err;
        }
 
-       DBG_BUFFER(&sdev->sd, "Response", response, respn);
-       if (check_command_failed(response[0]))
-               return -EBUSY;
+       do {
+               err = i2c_master_recv(client, response, respn);
+               if (err != respn) {
+                       v4l2_err(&sdev->sd,
+                               "Error %d while reading response for command 0x%02x\n",
+                               err, command);
+                       return err < 0 ? err : -EIO;
+               }
 
-       return 0;
+               DBG_BUFFER(&sdev->sd, "Response", response, respn);
+               if (!check_command_failed(response[0]))
+                       return 0;
+
+               if (client->irq)
+                       return -EBUSY;
+               if (usecs <= 1000)
+                       usleep_range(usecs, 1000);
+               else
+                       usleep_range(1000, 2000);
+       } while (time_is_after_jiffies(until_jiffies));
+
+       return -EBUSY;
 }
 
 /*
@@ -265,9 +272,9 @@ static int si4713_read_property(struct si4713_device *sdev, u16 prop, u32 *pv)
        int err;
        u8 val[SI4713_GET_PROP_NRESP];
        /*
-        *      .First byte = 0
-        *      .Second byte = property's MSB
-        *      .Third byte = property's LSB
+        *      .First byte = 0
+        *      .Second byte = property's MSB
+        *      .Third byte = property's LSB
         */
        const u8 args[SI4713_GET_PROP_NARGS] = {
                0x00,
@@ -302,11 +309,11 @@ static int si4713_write_property(struct si4713_device *sdev, u16 prop, u16 val)
        int rval;
        u8 resp[SI4713_SET_PROP_NRESP];
        /*
-        *      .First byte = 0
-        *      .Second byte = property's MSB
-        *      .Third byte = property's LSB
-        *      .Fourth byte = value's MSB
-        *      .Fifth byte = value's LSB
+        *      .First byte = 0
+        *      .Second byte = property's MSB
+        *      .Third byte = property's LSB
+        *      .Fourth byte = value's MSB
+        *      .Fifth byte = value's LSB
         */
        const u8 args[SI4713_SET_PROP_NARGS] = {
                0x00,
@@ -344,31 +351,36 @@ static int si4713_write_property(struct si4713_device *sdev, u16 prop, u16 val)
  */
 static int si4713_powerup(struct si4713_device *sdev)
 {
+       struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd);
        int err;
        u8 resp[SI4713_PWUP_NRESP];
        /*
-        *      .First byte = Enabled interrupts and boot function
-        *      .Second byte = Input operation mode
+        *      .First byte = Enabled interrupts and boot function
+        *      .Second byte = Input operation mode
         */
-       const u8 args[SI4713_PWUP_NARGS] = {
-               SI4713_PWUP_CTSIEN | SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX,
+       u8 args[SI4713_PWUP_NARGS] = {
+               SI4713_PWUP_GPO2OEN | SI4713_PWUP_FUNC_TX,
                SI4713_PWUP_OPMOD_ANALOG,
        };
 
        if (sdev->power_state)
                return 0;
 
-       err = regulator_bulk_enable(ARRAY_SIZE(sdev->supplies),
-                                   sdev->supplies);
-       if (err) {
-               v4l2_err(&sdev->sd, "Failed to enable supplies: %d\n", err);
-               return err;
+       if (sdev->supplies) {
+               err = regulator_bulk_enable(sdev->supplies, sdev->supply_data);
+               if (err) {
+                       v4l2_err(&sdev->sd, "Failed to enable supplies: %d\n", err);
+                       return err;
+               }
        }
        if (gpio_is_valid(sdev->gpio_reset)) {
                udelay(50);
                gpio_set_value(sdev->gpio_reset, 1);
        }
 
+       if (client->irq)
+               args[0] |= SI4713_PWUP_CTSIEN;
+
        err = si4713_send_command(sdev, SI4713_CMD_POWER_UP,
                                        args, ARRAY_SIZE(args),
                                        resp, ARRAY_SIZE(resp),
@@ -380,13 +392,15 @@ static int si4713_powerup(struct si4713_device *sdev)
                v4l2_dbg(1, debug, &sdev->sd, "Device in power up mode\n");
                sdev->power_state = POWER_ON;
 
-               err = si4713_write_property(sdev, SI4713_GPO_IEN,
+               if (client->irq)
+                       err = si4713_write_property(sdev, SI4713_GPO_IEN,
                                                SI4713_STC_INT | SI4713_CTS);
-       } else {
-               if (gpio_is_valid(sdev->gpio_reset))
-                       gpio_set_value(sdev->gpio_reset, 0);
-               err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies),
-                                            sdev->supplies);
+               return err;
+       }
+       if (gpio_is_valid(sdev->gpio_reset))
+               gpio_set_value(sdev->gpio_reset, 0);
+       if (sdev->supplies) {
+               err = regulator_bulk_disable(sdev->supplies, sdev->supply_data);
                if (err)
                        v4l2_err(&sdev->sd,
                                 "Failed to disable supplies: %d\n", err);
@@ -418,11 +432,13 @@ static int si4713_powerdown(struct si4713_device *sdev)
                v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n");
                if (gpio_is_valid(sdev->gpio_reset))
                        gpio_set_value(sdev->gpio_reset, 0);
-               err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies),
-                                            sdev->supplies);
-               if (err)
-                       v4l2_err(&sdev->sd,
-                                "Failed to disable supplies: %d\n", err);
+               if (sdev->supplies) {
+                       err = regulator_bulk_disable(sdev->supplies,
+                                                    sdev->supply_data);
+                       if (err)
+                               v4l2_err(&sdev->sd,
+                                        "Failed to disable supplies: %d\n", err);
+               }
                sdev->power_state = POWER_OFF;
        }
 
@@ -451,7 +467,7 @@ static int si4713_checkrev(struct si4713_device *sdev)
                v4l2_info(&sdev->sd, "chip found @ 0x%02x (%s)\n",
                                client->addr << 1, client->adapter->name);
        } else {
-               v4l2_err(&sdev->sd, "Invalid product number\n");
+               v4l2_err(&sdev->sd, "Invalid product number 0x%X\n", resp[1]);
                rval = -EINVAL;
        }
        return rval;
@@ -465,39 +481,45 @@ static int si4713_checkrev(struct si4713_device *sdev)
  */
 static int si4713_wait_stc(struct si4713_device *sdev, const int usecs)
 {
-       int err;
+       struct i2c_client *client = v4l2_get_subdevdata(&sdev->sd);
        u8 resp[SI4713_GET_STATUS_NRESP];
+       unsigned long start_jiffies = jiffies;
+       int err;
 
-       /* Wait response from STC interrupt */
-       if (!wait_for_completion_timeout(&sdev->work,
-                       usecs_to_jiffies(usecs) + 1))
+       if (client->irq &&
+           !wait_for_completion_timeout(&sdev->work, usecs_to_jiffies(usecs) + 1))
                v4l2_warn(&sdev->sd,
-                       "%s: device took too much time to answer (%d usec).\n",
-                               __func__, usecs);
-
-       /* Clear status bits */
-       err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS,
-                                       NULL, 0,
-                                       resp, ARRAY_SIZE(resp),
-                                       DEFAULT_TIMEOUT);
-
-       if (err < 0)
-               goto exit;
-
-       v4l2_dbg(1, debug, &sdev->sd,
-                       "%s: status bits: 0x%02x\n", __func__, resp[0]);
-
-       if (!(resp[0] & SI4713_STC_INT))
-               err = -EIO;
-
-exit:
-       return err;
+                       "(%s) Device took too much time to answer.\n", __func__);
+
+       for (;;) {
+               /* Clear status bits */
+               err = si4713_send_command(sdev, SI4713_CMD_GET_INT_STATUS,
+                               NULL, 0,
+                               resp, ARRAY_SIZE(resp),
+                               DEFAULT_TIMEOUT);
+               /* The USB device returns errors when it waits for the
+                * STC bit to be set. Hence polling */
+               if (err >= 0) {
+                       v4l2_dbg(1, debug, &sdev->sd,
+                               "%s: status bits: 0x%02x\n", __func__, resp[0]);
+
+                       if (resp[0] & SI4713_STC_INT)
+                               return 0;
+               }
+               if (jiffies_to_usecs(jiffies - start_jiffies) > usecs)
+                       return err < 0 ? err : -EIO;
+               /* We sleep here for 3-4 ms in order to avoid flooding the device
+                * with USB requests. The si4713 USB driver was developed
+                * by reverse engineering the Windows USB driver. The windows
+                * driver also has a ~2.5 ms delay between responses. */
+               usleep_range(3000, 4000);
+       }
 }
 
 /*
  * si4713_tx_tune_freq - Sets the state of the RF carrier and sets the tuning
- *                     frequency between 76 and 108 MHz in 10 kHz units and
- *                     steps of 50 kHz.
+ *                     frequency between 76 and 108 MHz in 10 kHz units and
+ *                     steps of 50 kHz.
  * @sdev: si4713_device structure for the device we are communicating
  * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz)
  */
@@ -506,9 +528,9 @@ static int si4713_tx_tune_freq(struct si4713_device *sdev, u16 frequency)
        int err;
        u8 val[SI4713_TXFREQ_NRESP];
        /*
-        *      .First byte = 0
-        *      .Second byte = frequency's MSB
-        *      .Third byte = frequency's LSB
+        *      .First byte = 0
+        *      .Second byte = frequency's MSB
+        *      .Third byte = frequency's LSB
         */
        const u8 args[SI4713_TXFREQ_NARGS] = {
                0x00,
@@ -535,14 +557,14 @@ static int si4713_tx_tune_freq(struct si4713_device *sdev, u16 frequency)
 }
 
 /*
- * si4713_tx_tune_power - Sets the RF voltage level between 88 and 115 dBuV in
- *                     1 dB units. A value of 0x00 indicates off. The command
- *                     also sets the antenna tuning capacitance. A value of 0
- *                     indicates autotuning, and a value of 1 - 191 indicates
- *                     a manual override, which results in a tuning
- *                     capacitance of 0.25 pF x @antcap.
+ * si4713_tx_tune_power - Sets the RF voltage level between 88 and 120 dBuV in
+ *                     1 dB units. A value of 0x00 indicates off. The command
+ *                     also sets the antenna tuning capacitance. A value of 0
+ *                     indicates autotuning, and a value of 1 - 191 indicates
+ *                     a manual override, which results in a tuning
+ *                     capacitance of 0.25 pF x @antcap.
  * @sdev: si4713_device structure for the device we are communicating
- * @power: tuning power (88 - 115 dBuV, unit/step 1 dB)
+ * @power: tuning power (88 - 120 dBuV, unit/step 1 dB)
  * @antcap: value of antenna tuning capacitor (0 - 191)
  */
 static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power,
@@ -551,21 +573,21 @@ static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power,
        int err;
        u8 val[SI4713_TXPWR_NRESP];
        /*
-        *      .First byte = 0
-        *      .Second byte = 0
-        *      .Third byte = power
-        *      .Fourth byte = antcap
+        *      .First byte = 0
+        *      .Second byte = 0
+        *      .Third byte = power
+        *      .Fourth byte = antcap
         */
-       const u8 args[SI4713_TXPWR_NARGS] = {
+       u8 args[SI4713_TXPWR_NARGS] = {
                0x00,
                0x00,
                power,
                antcap,
        };
 
-       if (((power > 0) && (power < SI4713_MIN_POWER)) ||
-               power > SI4713_MAX_POWER || antcap > SI4713_MAX_ANTCAP)
-               return -EDOM;
+       /* Map power values 1-87 to MIN_POWER (88) */
+       if (power > 0 && power < SI4713_MIN_POWER)
+               args[2] = power = SI4713_MIN_POWER;
 
        err = si4713_send_command(sdev, SI4713_CMD_TX_TUNE_POWER,
                                  args, ARRAY_SIZE(args), val,
@@ -583,12 +605,12 @@ static int si4713_tx_tune_power(struct si4713_device *sdev, u8 power,
 
 /*
  * si4713_tx_tune_measure - Enters receive mode and measures the received noise
- *                     level in units of dBuV on the selected frequency.
- *                     The Frequency must be between 76 and 108 MHz in 10 kHz
- *                     units and steps of 50 kHz. The command also sets the
- *                     antenna tuning capacitance. A value of 0 means
- *                     autotuning, and a value of 1 to 191 indicates manual
- *                     override.
+ *                     level in units of dBuV on the selected frequency.
+ *                     The Frequency must be between 76 and 108 MHz in 10 kHz
+ *                     units and steps of 50 kHz. The command also sets the
+ *                     antenna tuning capacitance. A value of 0 means
+ *                     autotuning, and a value of 1 to 191 indicates manual
+ *                     override.
  * @sdev: si4713_device structure for the device we are communicating
  * @frequency: desired frequency (76 - 108 MHz, unit 10 KHz, step 50 kHz)
  * @antcap: value of antenna tuning capacitor (0 - 191)
@@ -599,10 +621,10 @@ static int si4713_tx_tune_measure(struct si4713_device *sdev, u16 frequency,
        int err;
        u8 val[SI4713_TXMEA_NRESP];
        /*
-        *      .First byte = 0
-        *      .Second byte = frequency's MSB
-        *      .Third byte = frequency's LSB
-        *      .Fourth byte = antcap
+        *      .First byte = 0
+        *      .Second byte = frequency's MSB
+        *      .Third byte = frequency's LSB
+        *      .Fourth byte = antcap
         */
        const u8 args[SI4713_TXMEA_NARGS] = {
                0x00,
@@ -632,11 +654,11 @@ static int si4713_tx_tune_measure(struct si4713_device *sdev, u16 frequency,
 
 /*
  * si4713_tx_tune_status- Returns the status of the tx_tune_freq, tx_tune_mea or
- *                     tx_tune_power commands. This command return the current
- *                     frequency, output voltage in dBuV, the antenna tunning
- *                     capacitance value and the received noise level. The
- *                     command also clears the stcint interrupt bit when the
- *                     first bit of its arguments is high.
+ *                     tx_tune_power commands. This command return the current
+ *                     frequency, output voltage in dBuV, the antenna tunning
+ *                     capacitance value and the received noise level. The
+ *                     command also clears the stcint interrupt bit when the
+ *                     first bit of its arguments is high.
  * @sdev: si4713_device structure for the device we are communicating
  * @intack: 0x01 to clear the seek/tune complete interrupt status indicator.
  * @frequency: returned frequency
@@ -651,7 +673,7 @@ static int si4713_tx_tune_status(struct si4713_device *sdev, u8 intack,
        int err;
        u8 val[SI4713_TXSTATUS_NRESP];
        /*
-        *      .First byte = intack bit
+        *      .First byte = intack bit
         */
        const u8 args[SI4713_TXSTATUS_NARGS] = {
                intack & SI4713_INTACK_MASK,
@@ -812,8 +834,9 @@ static int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name)
        return rval;
 }
 
-static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt)
+static int si4713_set_rds_radio_text(struct si4713_device *sdev, const char *rt)
 {
+       static const char cr[RDS_RADIOTEXT_BLK_SIZE] = { RDS_CARRIAGE_RETURN, 0 };
        int rval = 0, i;
        u16 t_index = 0;
        u8 b_index = 0, cr_inserted = 0;
@@ -837,7 +860,7 @@ static int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt)
                        for (i = 0; i < RDS_RADIOTEXT_BLK_SIZE; i++) {
                                if (!rt[t_index + i] ||
                                    rt[t_index + i] == RDS_CARRIAGE_RETURN) {
-                                       rt[t_index + i] = RDS_CARRIAGE_RETURN;
+                                       rt = cr;
                                        cr_inserted = 1;
                                        break;
                                }
@@ -1024,7 +1047,6 @@ static int si4713_initialize(struct si4713_device *sdev)
        if (rval < 0)
                return rval;
 
-
        sdev->frequency = DEFAULT_FREQUENCY;
        sdev->stereo = 1;
        sdev->tune_rnl = DEFAULT_TUNE_RNL;
@@ -1345,7 +1367,7 @@ static int si4713_probe(struct i2c_client *client,
        struct v4l2_ctrl_handler *hdl;
        int rval, i;
 
-       sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
+       sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
        if (!sdev) {
                dev_err(&client->dev, "Failed to alloc video device.\n");
                rval = -ENOMEM;
@@ -1362,13 +1384,14 @@ static int si4713_probe(struct i2c_client *client,
                }
                sdev->gpio_reset = pdata->gpio_reset;
                gpio_direction_output(sdev->gpio_reset, 0);
+               sdev->supplies = pdata->supplies;
        }
 
-       for (i = 0; i < ARRAY_SIZE(sdev->supplies); i++)
-               sdev->supplies[i].supply = si4713_supply_names[i];
+       for (i = 0; i < sdev->supplies; i++)
+               sdev->supply_data[i].supply = pdata->supply_names[i];
 
-       rval = regulator_bulk_get(&client->dev, ARRAY_SIZE(sdev->supplies),
-                                 sdev->supplies);
+       rval = regulator_bulk_get(&client->dev, sdev->supplies,
+                                 sdev->supply_data);
        if (rval) {
                dev_err(&client->dev, "Cannot get regulators: %d\n", rval);
                goto free_gpio;
@@ -1420,8 +1443,8 @@ static int si4713_probe(struct i2c_client *client,
                        V4L2_CID_AUDIO_COMPRESSION_GAIN, 0, MAX_ACOMP_GAIN, 1,
                        DEFAULT_ACOMP_GAIN);
        sdev->compression_threshold = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
-                       V4L2_CID_AUDIO_COMPRESSION_THRESHOLD, MIN_ACOMP_THRESHOLD,
-                       MAX_ACOMP_THRESHOLD, 1,
+                       V4L2_CID_AUDIO_COMPRESSION_THRESHOLD,
+                       MIN_ACOMP_THRESHOLD, MAX_ACOMP_THRESHOLD, 1,
                        DEFAULT_ACOMP_THRESHOLD);
        sdev->compression_attack_time = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
                        V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME, 0,
@@ -1443,9 +1466,11 @@ static int si4713_probe(struct i2c_client *client,
                        V4L2_CID_TUNE_PREEMPHASIS,
                        V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS);
        sdev->tune_pwr_level = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
-                       V4L2_CID_TUNE_POWER_LEVEL, 0, 120, 1, DEFAULT_POWER_LEVEL);
+                       V4L2_CID_TUNE_POWER_LEVEL, 0, SI4713_MAX_POWER,
+                       1, DEFAULT_POWER_LEVEL);
        sdev->tune_ant_cap = v4l2_ctrl_new_std(hdl, &si4713_ctrl_ops,
-                       V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, 191, 1, 0);
+                       V4L2_CID_TUNE_ANTENNA_CAPACITOR, 0, SI4713_MAX_ANTCAP,
+                       1, 0);
 
        if (hdl->error) {
                rval = hdl->error;
@@ -1481,7 +1506,7 @@ free_irq:
 free_ctrls:
        v4l2_ctrl_handler_free(hdl);
 put_reg:
-       regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
+       regulator_bulk_free(sdev->supplies, sdev->supply_data);
 free_gpio:
        if (gpio_is_valid(sdev->gpio_reset))
                gpio_free(sdev->gpio_reset);
@@ -1505,7 +1530,7 @@ static int si4713_remove(struct i2c_client *client)
 
        v4l2_device_unregister_subdev(sd);
        v4l2_ctrl_handler_free(sd->ctrl_handler);
-       regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
+       regulator_bulk_free(sdev->supplies, sdev->supply_data);
        if (gpio_is_valid(sdev->gpio_reset))
                gpio_free(sdev->gpio_reset);
        kfree(sdev);
similarity index 98%
rename from drivers/media/radio/si4713-i2c.h
rename to drivers/media/radio/si4713/si4713.h
index 25cdea26343b1854003df8bf2651532a751a7257..4837cf6e0e1b060930934ea67e61148a8f9ffe2b 100644 (file)
@@ -15,6 +15,7 @@
 #ifndef SI4713_I2C_H
 #define SI4713_I2C_H
 
+#include <linux/regulator/consumer.h>
 #include <media/v4l2-subdev.h>
 #include <media/v4l2-ctrls.h>
 #include <media/si4713.h>
@@ -226,7 +227,8 @@ struct si4713_device {
                struct v4l2_ctrl *tune_ant_cap;
        };
        struct completion work;
-       struct regulator_bulk_data supplies[SI4713_NUM_SUPPLIES];
+       unsigned supplies;
+       struct regulator_bulk_data supply_data[SI4713_NUM_SUPPLIES];
        int gpio_reset;
        u32 power_state;
        u32 rds_enabled;
index cef06981b7c92118e7ee7c4d2e5e44bc6edbfcd3..7c14060a40b87618abf66f5ec0603e7fce15bb4c 100644 (file)
  *
  */
 
-#include <asm/io.h>
 #include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <asm/io.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-dev.h>
 #include <media/v4l2-fh.h>
index f329485c6629b038ff2aee825edff86c82189328..822b9f47ca729aa6cd769fc262fa98a3fa3616ef 100644 (file)
@@ -1909,10 +1909,8 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
        int ret, i;
 
        idev = input_allocate_device();
-       if (!idev) {
-               dev_err(ictx->dev, "input dev allocation failed\n");
+       if (!idev)
                goto out;
-       }
 
        snprintf(ictx->name_idev, sizeof(ictx->name_idev),
                 "iMON Panel, Knob and Mouse(%04x:%04x)",
@@ -1960,10 +1958,8 @@ static struct input_dev *imon_init_touch(struct imon_context *ictx)
        int ret;
 
        touch = input_allocate_device();
-       if (!touch) {
-               dev_err(ictx->dev, "touchscreen input dev allocation failed\n");
+       if (!touch)
                goto touch_alloc_failed;
-       }
 
        snprintf(ictx->name_touch, sizeof(ictx->name_touch),
                 "iMON USB Touchscreen (%04x:%04x)",
index b1cde8c0422b424141b752263e09b3751194ce5e..0b8c54919010cec79ac916700374f6eca5849f37 100644 (file)
@@ -98,4 +98,5 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
                        rc-videomate-s350.o \
                        rc-videomate-tv-pvr.o \
                        rc-winfast.o \
-                       rc-winfast-usbii-deluxe.o
+                       rc-winfast-usbii-deluxe.o \
+                       rc-su3000.o
diff --git a/drivers/media/rc/keymaps/rc-su3000.c b/drivers/media/rc/keymaps/rc-su3000.c
new file mode 100644 (file)
index 0000000..8dbd3e9
--- /dev/null
@@ -0,0 +1,75 @@
+/* rc-su3000.h - Keytable for Geniatech HDStar Remote Controller
+ *
+ * Copyright (c) 2013 by Evgeny Plehov <Evgeny Plehov@ukr.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table su3000[] = {
+       { 0x25, KEY_POWER },    /* right-bottom Red */
+       { 0x0a, KEY_MUTE },     /* -/-- */
+       { 0x01, KEY_1 },
+       { 0x02, KEY_2 },
+       { 0x03, KEY_3 },
+       { 0x04, KEY_4 },
+       { 0x05, KEY_5 },
+       { 0x06, KEY_6 },
+       { 0x07, KEY_7 },
+       { 0x08, KEY_8 },
+       { 0x09, KEY_9 },
+       { 0x00, KEY_0 },
+       { 0x20, KEY_UP },       /* CH+ */
+       { 0x21, KEY_DOWN },     /* CH+ */
+       { 0x12, KEY_VOLUMEUP }, /* Brightness Up */
+       { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */
+       { 0x1f, KEY_RECORD },
+       { 0x17, KEY_PLAY },
+       { 0x16, KEY_PAUSE },
+       { 0x0b, KEY_STOP },
+       { 0x27, KEY_FASTFORWARD },/* >> */
+       { 0x26, KEY_REWIND },   /* << */
+       { 0x0d, KEY_OK },       /* Mute */
+       { 0x11, KEY_LEFT },     /* VOL- */
+       { 0x10, KEY_RIGHT },    /* VOL+ */
+       { 0x29, KEY_BACK },     /* button under 9 */
+       { 0x2c, KEY_MENU },     /* TTX */
+       { 0x2b, KEY_EPG },      /* EPG */
+       { 0x1e, KEY_RED },      /* OSD */
+       { 0x0e, KEY_GREEN },    /* Window */
+       { 0x2d, KEY_YELLOW },   /* button under << */
+       { 0x0f, KEY_BLUE },     /* bottom yellow button */
+       { 0x14, KEY_AUDIO },    /* Snapshot */
+       { 0x38, KEY_TV },       /* TV/Radio */
+       { 0x0c, KEY_ESC }       /* upper Red button */
+};
+
+static struct rc_map_list su3000_map = {
+       .map = {
+               .scan    = su3000,
+               .size    = ARRAY_SIZE(su3000),
+               .rc_type = RC_TYPE_RC5,
+               .name    = RC_MAP_SU3000,
+       }
+};
+
+static int __init init_rc_map_su3000(void)
+{
+       return rc_map_register(&su3000_map);
+}
+
+static void __exit exit_rc_map_su3000(void)
+{
+       rc_map_unregister(&su3000_map);
+}
+
+module_init(init_rc_map_su3000)
+module_exit(exit_rc_map_su3000)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Evgeny Plehov <Evgeny Plehov@ukr.net>");
index 3c761014d3ce66c50fbe6adec41a384e0887f46d..a25bb1581e4662fa1807ab6bc8b86499ca17a595 100644 (file)
@@ -199,6 +199,7 @@ static bool debug;
 #define VENDOR_TIVO            0x105a
 #define VENDOR_CONEXANT                0x0572
 #define VENDOR_TWISTEDMELON    0x2596
+#define VENDOR_HAUPPAUGE       0x2040
 
 enum mceusb_model_type {
        MCE_GEN2 = 0,           /* Most boards */
@@ -210,6 +211,7 @@ enum mceusb_model_type {
        MULTIFUNCTION,
        TIVO_KIT,
        MCE_GEN2_NO_TX,
+       HAUPPAUGE_CX_HYBRID_TV,
 };
 
 struct mceusb_model {
@@ -258,6 +260,11 @@ static const struct mceusb_model mceusb_model[] = {
                .no_tx = 1, /* tx isn't wired up at all */
                .name = "Conexant Hybrid TV (cx231xx) MCE IR",
        },
+       [HAUPPAUGE_CX_HYBRID_TV] = {
+               .rc_map = RC_MAP_HAUPPAUGE,
+               .no_tx = 1, /* eeprom says it has no tx */
+               .name = "Conexant Hybrid TV (cx231xx) MCE IR no TX",
+       },
        [MULTIFUNCTION] = {
                .mce_gen2 = 1,
                .ir_intfnum = 2,
@@ -399,6 +406,9 @@ static struct usb_device_id mceusb_dev_table[] = {
        { USB_DEVICE(VENDOR_TWISTEDMELON, 0x8016) },
        /* Twisted Melon Inc. - Manta Transceiver */
        { USB_DEVICE(VENDOR_TWISTEDMELON, 0x8042) },
+       /* Hauppauge WINTV-HVR-HVR 930C-HD - based on cx231xx */
+       { USB_DEVICE(VENDOR_HAUPPAUGE, 0xb130),
+         .driver_info = HAUPPAUGE_CX_HYBRID_TV },
        /* Terminating entry */
        { }
 };
index 46da365c9c845bd8f980dd0df81f60fbfe3be338..02e2f38c9c8505121edda2f0e3c46007c887dc8d 100644 (file)
 #include <linux/module.h>
 #include "rc-core-priv.h"
 
+/* Bitmap to store allocated device numbers from 0 to IRRCV_NUM_DEVICES - 1 */
+#define IRRCV_NUM_DEVICES      256
+DECLARE_BITMAP(ir_core_dev_number, IRRCV_NUM_DEVICES);
+
 /* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
 #define IR_TAB_MIN_SIZE        256
 #define IR_TAB_MAX_SIZE        8192
@@ -1065,10 +1069,9 @@ EXPORT_SYMBOL_GPL(rc_free_device);
 int rc_register_device(struct rc_dev *dev)
 {
        static bool raw_init = false; /* raw decoders loaded? */
-       static atomic_t devno = ATOMIC_INIT(0);
        struct rc_map *rc_map;
        const char *path;
-       int rc;
+       int rc, devno;
 
        if (!dev || !dev->map_name)
                return -EINVAL;
@@ -1096,7 +1099,15 @@ int rc_register_device(struct rc_dev *dev)
         */
        mutex_lock(&dev->lock);
 
-       dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1);
+       do {
+               devno = find_first_zero_bit(ir_core_dev_number,
+                                           IRRCV_NUM_DEVICES);
+               /* No free device slots */
+               if (devno >= IRRCV_NUM_DEVICES)
+                       return -ENOMEM;
+       } while (test_and_set_bit(devno, ir_core_dev_number));
+
+       dev->devno = devno;
        dev_set_name(&dev->dev, "rc%ld", dev->devno);
        dev_set_drvdata(&dev->dev, dev);
        rc = device_add(&dev->dev);
@@ -1186,6 +1197,7 @@ out_dev:
        device_del(&dev->dev);
 out_unlock:
        mutex_unlock(&dev->lock);
+       clear_bit(dev->devno, ir_core_dev_number);
        return rc;
 }
 EXPORT_SYMBOL_GPL(rc_register_device);
@@ -1197,6 +1209,8 @@ void rc_unregister_device(struct rc_dev *dev)
 
        del_timer_sync(&dev->timer_keyup);
 
+       clear_bit(dev->devno, ir_core_dev_number);
+
        if (dev->driver_type == RC_DRIVER_IR_RAW)
                ir_raw_event_unregister(dev);
 
index 65120c2d47ad1d34c3a6018b242cf6e0e4c74d0c..8f0cddb9e8f2f4ce0076a9f7a4d4ba0cada0d7b4 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/platform_device.h>
+#include <linux/reset.h>
 #include <media/rc-core.h>
 #include <linux/pinctrl/consumer.h>
 
@@ -28,6 +29,7 @@ struct st_rc_device {
        int                             sample_mult;
        int                             sample_div;
        bool                            rxuhfmode;
+       struct  reset_control           *rstc;
 };
 
 /* Registers */
@@ -161,6 +163,10 @@ static void st_rc_hardware_init(struct st_rc_device *dev)
        unsigned int rx_max_symbol_per = MAX_SYMB_TIME;
        unsigned int rx_sampling_freq_div;
 
+       /* Enable the IP */
+       if (dev->rstc)
+               reset_control_deassert(dev->rstc);
+
        clk_prepare_enable(dev->sys_clock);
        baseclock = clk_get_rate(dev->sys_clock);
 
@@ -271,6 +277,11 @@ static int st_rc_probe(struct platform_device *pdev)
        else
                rc_dev->rx_base = rc_dev->base;
 
+
+       rc_dev->rstc = reset_control_get(dev, NULL);
+       if (IS_ERR(rc_dev->rstc))
+               rc_dev->rstc = NULL;
+
        rc_dev->dev = dev;
        platform_set_drvdata(pdev, rc_dev);
        st_rc_hardware_init(rc_dev);
@@ -338,6 +349,8 @@ static int st_rc_suspend(struct device *dev)
                writel(0x00, rc_dev->rx_base + IRB_RX_EN);
                writel(0x00, rc_dev->rx_base + IRB_RX_INT_EN);
                clk_disable_unprepare(rc_dev->sys_clock);
+               if (rc_dev->rstc)
+                       reset_control_assert(rc_dev->rstc);
        }
 
        return 0;
index 15665debc572437a7e0544dacca3efe16d06ce0a..ba2e365296cf9a0271d50234522b62a8ae194bc1 100644 (file)
@@ -215,6 +215,13 @@ config MEDIA_TUNER_FC2580
        help
          FCI FC2580 silicon tuner driver.
 
+config MEDIA_TUNER_M88TS2022
+       tristate "Montage M88TS2022 silicon tuner"
+       depends on MEDIA_SUPPORT && I2C
+       default m if !MEDIA_SUBDRV_AUTOSELECT
+       help
+         Montage M88TS2022 silicon tuner driver.
+
 config MEDIA_TUNER_TUA9001
        tristate "Infineon TUA 9001 silicon tuner"
        depends on MEDIA_SUPPORT && I2C
index 308f108eadba7cc61e6caeb693aaf2ae6174425d..efe82a904b123ec66d80ca8a930d163ac66b3ba4 100644 (file)
@@ -31,6 +31,7 @@ obj-$(CONFIG_MEDIA_TUNER_TDA18212) += tda18212.o
 obj-$(CONFIG_MEDIA_TUNER_E4000) += e4000.o
 obj-$(CONFIG_MEDIA_TUNER_FC2580) += fc2580.o
 obj-$(CONFIG_MEDIA_TUNER_TUA9001) += tua9001.o
+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
index 72971a8d3c37978ef1c42b6a2523bb4cb8e92f4a..40c1da707d15ce86a094adcc25c7d4765f4ed00c 100644 (file)
@@ -243,8 +243,10 @@ static int e4000_set_params(struct dvb_frontend *fe)
                        break;
        }
 
-       if (i == ARRAY_SIZE(e4000_pll_lut))
+       if (i == ARRAY_SIZE(e4000_pll_lut)) {
+               ret = -EINVAL;
                goto err;
+       }
 
        /*
         * Note: Currently f_vco overflows when c->frequency is 1 073 741 824 Hz
@@ -271,8 +273,10 @@ static int e4000_set_params(struct dvb_frontend *fe)
                        break;
        }
 
-       if (i == ARRAY_SIZE(e400_lna_filter_lut))
+       if (i == ARRAY_SIZE(e400_lna_filter_lut)) {
+               ret = -EINVAL;
                goto err;
+       }
 
        ret = e4000_wr_reg(priv, 0x10, e400_lna_filter_lut[i].val);
        if (ret < 0)
@@ -284,8 +288,10 @@ static int e4000_set_params(struct dvb_frontend *fe)
                        break;
        }
 
-       if (i == ARRAY_SIZE(e4000_if_filter_lut))
+       if (i == ARRAY_SIZE(e4000_if_filter_lut)) {
+               ret = -EINVAL;
                goto err;
+       }
 
        buf[0] = e4000_if_filter_lut[i].reg11_val;
        buf[1] = e4000_if_filter_lut[i].reg12_val;
@@ -300,8 +306,10 @@ static int e4000_set_params(struct dvb_frontend *fe)
                        break;
        }
 
-       if (i == ARRAY_SIZE(e4000_band_lut))
+       if (i == ARRAY_SIZE(e4000_band_lut)) {
+               ret = -EINVAL;
                goto err;
+       }
 
        ret = e4000_wr_reg(priv, 0x07, e4000_band_lut[i].reg07_val);
        if (ret < 0)
diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c
new file mode 100644 (file)
index 0000000..40c42de
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ * Montage M88TS2022 silicon tuner driver
+ *
+ * Copyright (C) 2013 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.
+ *
+ * Some calculations are taken from existing TS2020 driver.
+ */
+
+#include "m88ts2022_priv.h"
+
+/* write multiple registers */
+static int m88ts2022_wr_regs(struct m88ts2022_priv *priv,
+               u8 reg, const u8 *val, int len)
+{
+#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;
+       struct m88ts2022_reg_val reg_vals[] = {
+               {0x51, 0x1f - op},
+               {0x51, 0x1f},
+               {0x50, 0x00 + op},
+               {0x50, 0x00},
+       };
+
+       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);
+
+               for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
+                       ret = m88ts2022_wr_reg(priv, reg_vals[i].reg,
+                                       reg_vals[i].val);
+                       if (ret)
+                               goto err;
+               }
+
+               usleep_range(sleep * 1000, sleep * 10000);
+
+               ret = m88ts2022_rd_reg(priv, reg, &u8tmp);
+               if (ret)
+                       goto err;
+
+               if ((u8tmp & mask) != val)
+                       break;
+       }
+
+       if (reg_val)
+               *reg_val = u8tmp;
+err:
+       return ret;
+}
+
+static int m88ts2022_set_params(struct dvb_frontend *fe)
+{
+       struct m88ts2022_priv *priv = 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 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);
+       /*
+        * 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);
+       div_ref = DIV_ROUND_CLOSEST(f_ref_khz, 2000);
+
+       if (c->symbol_rate < 5000000)
+               frequency_offset_khz = 3000; /* 3 MHz */
+       else
+               frequency_offset_khz = 0;
+
+       frequency_khz = c->frequency + frequency_offset_khz;
+
+       if (frequency_khz < 1103000) {
+               div_out = 4;
+               u8tmp = 0x1b;
+       } else {
+               div_out = 2;
+               u8tmp = 0x0b;
+       }
+
+       buf[0] = u8tmp;
+       buf[1] = 0x40;
+       ret = m88ts2022_wr_regs(priv, 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;
+
+       if (pll_n < 4095)
+               u16tmp = pll_n - 1024;
+       else if (pll_n < 6143)
+               u16tmp = pll_n + 1024;
+       else
+               u16tmp = pll_n + 3072;
+
+       buf[0] = (u16tmp >> 8) & 0x3f;
+       buf[1] = (u16tmp >> 0) & 0xff;
+       buf[2] = div_ref - 8;
+       ret = m88ts2022_wr_regs(priv, 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);
+
+       ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
+       if (ret)
+               goto err;
+
+       u8tmp &= 0x7f;
+       if (u8tmp < 64) {
+               ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x80, 0x80);
+               if (ret)
+                       goto err;
+
+               ret = m88ts2022_wr_reg(priv, 0x11, 0x6f);
+               if (ret)
+                       goto err;
+
+               ret = m88ts2022_cmd(fe, 0x10, 5, 0x15, 0x40, 0x00, NULL);
+               if (ret)
+                       goto err;
+       }
+
+       ret = m88ts2022_rd_reg(priv, 0x14, &u8tmp);
+       if (ret)
+               goto err;
+
+       u8tmp &= 0x1f;
+       if (u8tmp > 19) {
+               ret = m88ts2022_wr_reg_mask(priv, 0x10, 0x00, 0x02);
+               if (ret)
+                       goto err;
+       }
+
+       ret = m88ts2022_cmd(fe, 0x08, 5, 0x3c, 0xff, 0x00, NULL);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_wr_reg(priv, 0x25, 0x00);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_wr_reg(priv, 0x27, 0x70);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_wr_reg(priv, 0x08, 0x0b);
+       if (ret)
+               goto err;
+
+       /* filters */
+       gdiv28 = DIV_ROUND_CLOSEST(f_ref_khz * 1694U, 1000000U);
+
+       ret = m88ts2022_wr_reg(priv, 0x04, gdiv28);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       if (ret)
+               goto err;
+
+       cap_code = u8tmp & 0x3f;
+
+       ret = m88ts2022_wr_reg(priv, 0x41, 0x0d);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       if (ret)
+               goto err;
+
+       u8tmp &= 0x3f;
+       cap_code = (cap_code + u8tmp) / 2;
+       gdiv28 = gdiv28 * 207 / (cap_code * 2 + 151);
+       div_max = gdiv28 * 135 / 100;
+       div_min = gdiv28 * 78 / 100;
+       div_max = clamp_val(div_max, 0U, 63U);
+
+       f_3db_hz = c->symbol_rate * 135UL / 200UL;
+       f_3db_hz +=  2000000U + (frequency_offset_khz * 1000U);
+       f_3db_hz = clamp(f_3db_hz, 7000000U, 40000000U);
+
+#define LPF_COEFF 3200U
+       lpf_gm = DIV_ROUND_CLOSEST(f_3db_hz * gdiv28, LPF_COEFF * f_ref_khz);
+       lpf_gm = clamp_val(lpf_gm, 1U, 23U);
+
+       lpf_mxdiv = DIV_ROUND_CLOSEST(lpf_gm * LPF_COEFF * f_ref_khz, f_3db_hz);
+       if (lpf_mxdiv < div_min)
+               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);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_wr_reg(priv, 0x06, lpf_gm);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       if (ret)
+               goto err;
+
+       cap_code = u8tmp & 0x3f;
+
+       ret = m88ts2022_wr_reg(priv, 0x41, 0x09);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_cmd(fe, 0x04, 2, 0x26, 0xff, 0x00, &u8tmp);
+       if (ret)
+               goto err;
+
+       u8tmp &= 0x3f;
+       cap_code = (cap_code + u8tmp) / 2;
+
+       u8tmp = cap_code | 0x80;
+       ret = m88ts2022_wr_reg(priv, 0x25, u8tmp);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_wr_reg(priv, 0x27, 0x30);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_wr_reg(priv, 0x08, 0x09);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_cmd(fe, 0x01, 20, 0x21, 0xff, 0x00, NULL);
+       if (ret)
+               goto err;
+err:
+       if (ret)
+               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+
+       return ret;
+}
+
+static int m88ts2022_init(struct dvb_frontend *fe)
+{
+       struct m88ts2022_priv *priv = fe->tuner_priv;
+       int ret, i;
+       u8 u8tmp;
+       static const struct m88ts2022_reg_val reg_vals[] = {
+               {0x7d, 0x9d},
+               {0x7c, 0x9a},
+               {0x7a, 0x76},
+               {0x3b, 0x01},
+               {0x63, 0x88},
+               {0x61, 0x85},
+               {0x22, 0x30},
+               {0x30, 0x40},
+               {0x20, 0x23},
+               {0x24, 0x02},
+               {0x12, 0xa0},
+       };
+       dev_dbg(&priv->client->dev, "%s:\n", __func__);
+
+       ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
+       if (ret)
+               goto err;
+
+       ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
+       if (ret)
+               goto err;
+
+       switch (priv->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);
+               if (ret)
+                       goto err;
+               break;
+       case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT:
+               u8tmp = 0x6c;
+               break;
+       default:
+               goto err;
+       }
+
+       ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
+       if (ret)
+               goto err;
+
+       if (priv->cfg.loop_through)
+               u8tmp = 0xec;
+       else
+               u8tmp = 0x6c;
+
+       ret = m88ts2022_wr_reg(priv, 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);
+               if (ret)
+                       goto err;
+       }
+err:
+       if (ret)
+               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static int m88ts2022_sleep(struct dvb_frontend *fe)
+{
+       struct m88ts2022_priv *priv = fe->tuner_priv;
+       int ret;
+       dev_dbg(&priv->client->dev, "%s:\n", __func__);
+
+       ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
+       if (ret)
+               goto err;
+err:
+       if (ret)
+               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, 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__);
+
+       *frequency = priv->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__);
+
+       *frequency = 0; /* Zero-IF */
+       return 0;
+}
+
+static int m88ts2022_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct m88ts2022_priv *priv = fe->tuner_priv;
+       int ret;
+       u8 u8tmp;
+       u16 gain, u16tmp;
+       unsigned int gain1, gain2, gain3;
+
+       ret = m88ts2022_rd_reg(priv, 0x3d, &u8tmp);
+       if (ret)
+               goto err;
+
+       gain1 = (u8tmp >> 0) & 0x1f;
+       gain1 = clamp(gain1, 0U, 15U);
+
+       ret = m88ts2022_rd_reg(priv, 0x21, &u8tmp);
+       if (ret)
+               goto err;
+
+       gain2 = (u8tmp >> 0) & 0x1f;
+       gain2 = clamp(gain2, 2U, 16U);
+
+       ret = m88ts2022_rd_reg(priv, 0x66, &u8tmp);
+       if (ret)
+               goto err;
+
+       gain3 = (u8tmp >> 3) & 0x07;
+       gain3 = clamp(gain3, 0U, 6U);
+
+       gain = gain1 * 265 + gain2 * 338 + gain3 * 285;
+
+       /* scale value to 0x0000-0xffff */
+       u16tmp = (0xffff - gain);
+       u16tmp = clamp_val(u16tmp, 59000U, 61500U);
+
+       *strength = (u16tmp - 59000) * 0xffff / (61500 - 59000);
+err:
+       if (ret)
+               dev_dbg(&priv->client->dev, "%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
+static const struct dvb_tuner_ops m88ts2022_tuner_ops = {
+       .info = {
+               .name          = "Montage M88TS2022",
+               .frequency_min = 950000,
+               .frequency_max = 2150000,
+       },
+
+       .init = m88ts2022_init,
+       .sleep = m88ts2022_sleep,
+       .set_params = m88ts2022_set_params,
+
+       .get_frequency = m88ts2022_get_frequency,
+       .get_if_frequency = m88ts2022_get_if_frequency,
+       .get_rf_strength = m88ts2022_get_rf_strength,
+};
+
+static int m88ts2022_probe(struct i2c_client *client,
+               const struct i2c_device_id *id)
+{
+       struct m88ts2022_config *cfg = client->dev.platform_data;
+       struct dvb_frontend *fe = cfg->fe;
+       struct m88ts2022_priv *priv;
+       int ret;
+       u8 chip_id, u8tmp;
+
+       priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+       if (!priv) {
+               ret = -ENOMEM;
+               dev_err(&client->dev, "%s: kzalloc() failed\n", KBUILD_MODNAME);
+               goto err;
+       }
+
+       memcpy(&priv->cfg, cfg, sizeof(struct m88ts2022_config));
+       priv->client = client;
+
+       /* check if the tuner is there */
+       ret = m88ts2022_rd_reg(priv, 0x00, &u8tmp);
+       if (ret)
+               goto err;
+
+       if ((u8tmp & 0x03) == 0x00) {
+               ret = m88ts2022_wr_reg(priv, 0x00, 0x01);
+               if (ret < 0)
+                       goto err;
+
+               usleep_range(2000, 50000);
+       }
+
+       ret = m88ts2022_wr_reg(priv, 0x00, 0x03);
+       if (ret)
+               goto err;
+
+       usleep_range(2000, 50000);
+
+       ret = m88ts2022_rd_reg(priv, 0x00, &chip_id);
+       if (ret)
+               goto err;
+
+       dev_dbg(&priv->client->dev, "%s: chip_id=%02x\n", __func__, chip_id);
+
+       switch (chip_id) {
+       case 0xc3:
+       case 0x83:
+               break;
+       default:
+               goto err;
+       }
+
+       switch (priv->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);
+               if (ret)
+                       goto err;
+               break;
+       case M88TS2022_CLOCK_OUT_ENABLED_XTALOUT:
+               u8tmp = 0x6c;
+               break;
+       default:
+               goto err;
+       }
+
+       ret = m88ts2022_wr_reg(priv, 0x42, u8tmp);
+       if (ret)
+               goto err;
+
+       if (priv->cfg.loop_through)
+               u8tmp = 0xec;
+       else
+               u8tmp = 0x6c;
+
+       ret = m88ts2022_wr_reg(priv, 0x62, u8tmp);
+       if (ret)
+               goto err;
+
+       /* sleep */
+       ret = m88ts2022_wr_reg(priv, 0x00, 0x00);
+       if (ret)
+               goto err;
+
+       dev_info(&priv->client->dev,
+                       "%s: Montage M88TS2022 successfully identified\n",
+                       KBUILD_MODNAME);
+
+       fe->tuner_priv = priv;
+       memcpy(&fe->ops.tuner_ops, &m88ts2022_tuner_ops,
+                       sizeof(struct dvb_tuner_ops));
+
+       i2c_set_clientdata(client, priv);
+       return 0;
+err:
+       dev_dbg(&client->dev, "%s: failed=%d\n", __func__, ret);
+       kfree(priv);
+       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__);
+
+       memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+       fe->tuner_priv = NULL;
+       kfree(priv);
+
+       return 0;
+}
+
+static const struct i2c_device_id m88ts2022_id[] = {
+       {"m88ts2022", 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, m88ts2022_id);
+
+static struct i2c_driver m88ts2022_driver = {
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "m88ts2022",
+       },
+       .probe          = m88ts2022_probe,
+       .remove         = m88ts2022_remove,
+       .id_table       = m88ts2022_id,
+};
+
+module_i2c_driver(m88ts2022_driver);
+
+MODULE_DESCRIPTION("Montage M88TS2022 silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/m88ts2022.h b/drivers/media/tuners/m88ts2022.h
new file mode 100644 (file)
index 0000000..659fa1b
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Montage M88TS2022 silicon tuner driver
+ *
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef M88TS2022_H
+#define M88TS2022_H
+
+#include "dvb_frontend.h"
+
+struct m88ts2022_config {
+       /*
+        * clock
+        * 16000000 - 32000000
+        */
+       u32 clock;
+
+       /*
+        * RF loop-through
+        */
+       u8 loop_through:1;
+
+       /*
+        * clock output
+        */
+#define M88TS2022_CLOCK_OUT_DISABLED        0
+#define M88TS2022_CLOCK_OUT_ENABLED         1
+#define M88TS2022_CLOCK_OUT_ENABLED_XTALOUT 2
+       u8 clock_out:2;
+
+       /*
+        * clock output divider
+        * 1 - 31
+        */
+       u8 clock_out_div:5;
+
+       /*
+        * pointer to DVB frontend
+        */
+       struct dvb_frontend *fe;
+};
+
+#endif
diff --git a/drivers/media/tuners/m88ts2022_priv.h b/drivers/media/tuners/m88ts2022_priv.h
new file mode 100644 (file)
index 0000000..0363dd8
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Montage M88TS2022 silicon tuner driver
+ *
+ * Copyright (C) 2013 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.
+ */
+
+#ifndef M88TS2022_PRIV_H
+#define M88TS2022_PRIV_H
+
+#include "m88ts2022.h"
+
+struct m88ts2022_priv {
+       struct m88ts2022_config cfg;
+       struct i2c_client *client;
+       struct dvb_frontend *fe;
+       u32 frequency_khz;
+};
+
+struct m88ts2022_reg_val {
+       u8 reg;
+       u8 val;
+};
+
+#endif
index 4be5cf808a40584d949e89fa78e7a90c086a31f5..cca508d4aafb1545037b7972d06d01c346efeb77 100644 (file)
@@ -134,15 +134,6 @@ struct xc2028_data {
        _rc;                                                            \
 })
 
-#define i2c_rcv(priv, buf, size) ({                                    \
-       int _rc;                                                        \
-       _rc = tuner_i2c_xfer_recv(&priv->i2c_props, buf, size);         \
-       if (size != _rc)                                                \
-               tuner_err("i2c input error: rc = %d (should be %d)\n",  \
-                          _rc, (int)size);                             \
-       _rc;                                                            \
-})
-
 #define i2c_send_recv(priv, obuf, osize, ibuf, isize) ({               \
        int _rc;                                                        \
        _rc = tuner_i2c_xfer_send_recv(&priv->i2c_props, obuf, osize,   \
@@ -276,6 +267,7 @@ static int check_device_status(struct xc2028_data *priv)
        case XC2028_WAITING_FIRMWARE:
                return -EAGAIN;
        case XC2028_ACTIVE:
+               return 1;
        case XC2028_SLEEP:
                return 0;
        case XC2028_NODEV:
@@ -718,6 +710,8 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type,
        return 0;
 }
 
+static int xc2028_sleep(struct dvb_frontend *fe);
+
 static int check_firmware(struct dvb_frontend *fe, unsigned int type,
                          v4l2_std_id std, __u16 int_freq)
 {
@@ -890,7 +884,7 @@ read_not_reliable:
        return 0;
 
 fail:
-       priv->state = XC2028_SLEEP;
+       priv->state = XC2028_NO_FIRMWARE;
 
        memset(&priv->cur_fw, 0, sizeof(priv->cur_fw));
        if (retry_count < 8) {
@@ -900,6 +894,9 @@ fail:
                goto retry;
        }
 
+       /* Firmware didn't load. Put the device to sleep */
+       xc2028_sleep(fe);
+
        if (rc == -ENOENT)
                rc = -EINVAL;
        return rc;
@@ -917,6 +914,12 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
        if (rc < 0)
                return rc;
 
+       /* If the device is sleeping, no channel is tuned */
+       if (!rc) {
+               *strength = 0;
+               return 0;
+       }
+
        mutex_lock(&priv->lock);
 
        /* Sync Lock Indicator */
@@ -964,6 +967,12 @@ static int xc2028_get_afc(struct dvb_frontend *fe, s32 *afc)
        if (rc < 0)
                return rc;
 
+       /* If the device is sleeping, no channel is tuned */
+       if (!rc) {
+               *afc = 0;
+               return 0;
+       }
+
        mutex_lock(&priv->lock);
 
        /* Sync Lock Indicator */
@@ -1281,6 +1290,10 @@ static int xc2028_sleep(struct dvb_frontend *fe)
        if (rc < 0)
                return rc;
 
+       /* Device is already in sleep mode */
+       if (!rc)
+               return 0;
+
        /* Avoid firmware reload on slow devices or if PM disabled */
        if (no_poweroff || priv->ctrl.disable_power_mgmt)
                return 0;
@@ -1298,7 +1311,8 @@ static int xc2028_sleep(struct dvb_frontend *fe)
        else
                rc = send_seq(priv, {0x80, XREG_POWER_DOWN, 0x00, 0x00});
 
-       priv->state = XC2028_SLEEP;
+       if (rc >= 0)
+               priv->state = XC2028_SLEEP;
 
        mutex_unlock(&priv->lock);
 
@@ -1366,7 +1380,7 @@ static void load_firmware_cb(const struct firmware *fw,
 
        if (rc < 0)
                return;
-       priv->state = XC2028_SLEEP;
+       priv->state = XC2028_ACTIVE;
 }
 
 static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
index cfe8056b91aa05106497d3de54a95f1982273e29..39d824e2bb69bbf4167c98f05671c05c1a6053f3 100644 (file)
@@ -17,7 +17,6 @@ source "drivers/media/usb/cpia2/Kconfig"
 source "drivers/media/usb/zr364xx/Kconfig"
 source "drivers/media/usb/stkwebcam/Kconfig"
 source "drivers/media/usb/s2255/Kconfig"
-source "drivers/media/usb/sn9c102/Kconfig"
 source "drivers/media/usb/usbtv/Kconfig"
 endif
 
index 0935f47497a6f5af71f78ef819275f2720486183..7ac4b143dce89d24a70624c7987dfb6efcf3bc25 100644 (file)
@@ -10,7 +10,6 @@ obj-$(CONFIG_USB_VIDEO_CLASS) += uvc/
 obj-$(CONFIG_USB_GSPCA)         += gspca/
 obj-$(CONFIG_USB_PWC)           += pwc/
 obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
-obj-$(CONFIG_USB_SN9C102)       += sn9c102/
 obj-$(CONFIG_VIDEO_AU0828) += au0828/
 obj-$(CONFIG_VIDEO_HDPVR)      += hdpvr/
 obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
index bd9d19a73efdf7bb0dd45e74b065d6e07e4e1c52..ab45a6f9dcc9ad1d9490ccb8e080e6815445c6d0 100644 (file)
@@ -173,9 +173,8 @@ static int au0828_usb_probe(struct usb_interface *interface,
        const struct usb_device_id *id)
 {
        int ifnum;
-#ifdef CONFIG_VIDEO_AU0828_V4L2
-       int retval;
-#endif
+       int retval = 0;
+
        struct au0828_dev *dev;
        struct usb_device *usbdev = interface_to_usbdev(interface);
 
@@ -257,7 +256,11 @@ static int au0828_usb_probe(struct usb_interface *interface,
 #endif
 
        /* Digital TV */
-       au0828_dvb_register(dev);
+       retval = au0828_dvb_register(dev);
+       if (retval)
+               pr_err("%s() au0282_dev_register failed\n",
+                      __func__);
+
 
        /* Store the pointer to the au0828_dev so it can be accessed in
           au0828_usb_disconnect */
@@ -268,7 +271,7 @@ static int au0828_usb_probe(struct usb_interface *interface,
 
        mutex_unlock(&dev->lock);
 
-       return 0;
+       return retval;
 }
 
 static struct usb_driver au0828_usb_driver = {
index 9a6f15613a3832d7c17754938098ed7f815458aa..4ae8b10746496e00d4e0396c896583b6bf0cf084 100644 (file)
 #include "mxl5007t.h"
 #include "tda18271.h"
 
+static int preallocate_big_buffers;
+module_param_named(preallocate_big_buffers, preallocate_big_buffers, int, 0644);
+MODULE_PARM_DESC(preallocate_big_buffers, "Preallocate the larger transfer buffers at module load time");
+
 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 
 #define _AU0828_BULKPIPE 0x83
@@ -153,9 +157,13 @@ static int stop_urb_transfer(struct au0828_dev *dev)
 
        dev->urb_streaming = 0;
        for (i = 0; i < URB_COUNT; i++) {
-               usb_kill_urb(dev->urbs[i]);
-               kfree(dev->urbs[i]->transfer_buffer);
-               usb_free_urb(dev->urbs[i]);
+               if (dev->urbs[i]) {
+                       usb_kill_urb(dev->urbs[i]);
+                       if (!preallocate_big_buffers)
+                               kfree(dev->urbs[i]->transfer_buffer);
+
+                       usb_free_urb(dev->urbs[i]);
+               }
        }
 
        return 0;
@@ -181,10 +189,18 @@ static int start_urb_transfer(struct au0828_dev *dev)
 
                purb = dev->urbs[i];
 
-               purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
+               if (preallocate_big_buffers)
+                       purb->transfer_buffer = dev->dig_transfer_buffer[i];
+               else
+                       purb->transfer_buffer = kzalloc(URB_BUFSIZE,
+                                       GFP_KERNEL);
+
                if (!purb->transfer_buffer) {
                        usb_free_urb(purb);
                        dev->urbs[i] = NULL;
+                       printk(KERN_ERR
+                              "%s: failed big buffer allocation, err = %d\n",
+                              __func__, ret);
                        goto err;
                }
 
@@ -217,6 +233,27 @@ err:
        return ret;
 }
 
+static void au0828_start_transport(struct au0828_dev *dev)
+{
+       au0828_write(dev, 0x608, 0x90);
+       au0828_write(dev, 0x609, 0x72);
+       au0828_write(dev, 0x60a, 0x71);
+       au0828_write(dev, 0x60b, 0x01);
+
+}
+
+static void au0828_stop_transport(struct au0828_dev *dev, int full_stop)
+{
+       if (full_stop) {
+               au0828_write(dev, 0x608, 0x00);
+               au0828_write(dev, 0x609, 0x00);
+               au0828_write(dev, 0x60a, 0x00);
+       }
+       au0828_write(dev, 0x60b, 0x00);
+}
+
+
+
 static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
 {
        struct dvb_demux *demux = feed->demux;
@@ -231,13 +268,17 @@ static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
 
        if (dvb) {
                mutex_lock(&dvb->lock);
+               dvb->start_count++;
+               dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
+                       dvb->start_count, dvb->stop_count);
                if (dvb->feeding++ == 0) {
                        /* Start transport */
-                       au0828_write(dev, 0x608, 0x90);
-                       au0828_write(dev, 0x609, 0x72);
-                       au0828_write(dev, 0x60a, 0x71);
-                       au0828_write(dev, 0x60b, 0x01);
+                       au0828_start_transport(dev);
                        ret = start_urb_transfer(dev);
+                       if (ret < 0) {
+                               au0828_stop_transport(dev, 0);
+                               dvb->feeding--; /* We ran out of memory... */
+                       }
                }
                mutex_unlock(&dvb->lock);
        }
@@ -256,10 +297,16 @@ static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
 
        if (dvb) {
                mutex_lock(&dvb->lock);
-               if (--dvb->feeding == 0) {
-                       /* Stop transport */
-                       ret = stop_urb_transfer(dev);
-                       au0828_write(dev, 0x60b, 0x00);
+               dvb->stop_count++;
+               dprintk(1, "%s(), start_count: %d, stop_count: %d\n", __func__,
+                       dvb->start_count, dvb->stop_count);
+               if (dvb->feeding > 0) {
+                       dvb->feeding--;
+                       if (dvb->feeding == 0) {
+                               /* Stop transport */
+                               ret = stop_urb_transfer(dev);
+                               au0828_stop_transport(dev, 0);
+                       }
                }
                mutex_unlock(&dvb->lock);
        }
@@ -282,16 +329,10 @@ static void au0828_restart_dvb_streaming(struct work_struct *work)
 
        /* Stop transport */
        stop_urb_transfer(dev);
-       au0828_write(dev, 0x608, 0x00);
-       au0828_write(dev, 0x609, 0x00);
-       au0828_write(dev, 0x60a, 0x00);
-       au0828_write(dev, 0x60b, 0x00);
+       au0828_stop_transport(dev, 1);
 
        /* Start transport */
-       au0828_write(dev, 0x608, 0x90);
-       au0828_write(dev, 0x609, 0x72);
-       au0828_write(dev, 0x60a, 0x71);
-       au0828_write(dev, 0x60b, 0x01);
+       au0828_start_transport(dev);
        start_urb_transfer(dev);
 
        mutex_unlock(&dvb->lock);
@@ -304,6 +345,23 @@ static int dvb_register(struct au0828_dev *dev)
 
        dprintk(1, "%s()\n", __func__);
 
+       if (preallocate_big_buffers) {
+               int i;
+               for (i = 0; i < URB_COUNT; i++) {
+                       dev->dig_transfer_buffer[i] = kzalloc(URB_BUFSIZE,
+                                       GFP_KERNEL);
+
+                       if (!dev->dig_transfer_buffer[i]) {
+                               result = -ENOMEM;
+
+                               printk(KERN_ERR
+                                      "%s: failed buffer allocation (errno = %d)\n",
+                                      DRIVER_NAME, result);
+                               goto fail_adapter;
+                       }
+               }
+       }
+
        INIT_WORK(&dev->restart_streaming, au0828_restart_dvb_streaming);
 
        /* register adapter */
@@ -375,6 +433,9 @@ static int dvb_register(struct au0828_dev *dev)
 
        /* register network adapter */
        dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+
+       dvb->start_count = 0;
+       dvb->stop_count = 0;
        return 0;
 
 fail_fe_conn:
@@ -391,6 +452,13 @@ fail_frontend:
        dvb_frontend_detach(dvb->frontend);
        dvb_unregister_adapter(&dvb->adapter);
 fail_adapter:
+
+       if (preallocate_big_buffers) {
+               int i;
+               for (i = 0; i < URB_COUNT; i++)
+                       kfree(dev->dig_transfer_buffer[i]);
+       }
+
        return result;
 }
 
@@ -411,6 +479,14 @@ void au0828_dvb_unregister(struct au0828_dev *dev)
        dvb_unregister_frontend(dvb->frontend);
        dvb_frontend_detach(dvb->frontend);
        dvb_unregister_adapter(&dvb->adapter);
+
+       if (preallocate_big_buffers) {
+               int i;
+               for (i = 0; i < URB_COUNT; i++)
+                       kfree(dev->dig_transfer_buffer[i]);
+       }
+
+
 }
 
 /* All the DVB attach calls go here, this function get's modified
index ef1f57f22be74b57ab4630b080e069edd488921d..5439772c15517b3594d0c64a7d3d81a9b62b7fa0 100644 (file)
@@ -102,6 +102,8 @@ struct au0828_dvb {
        struct dmx_frontend fe_mem;
        struct dvb_net net;
        int feeding;
+       int start_count;
+       int stop_count;
 };
 
 enum au0828_stream_state {
@@ -260,6 +262,10 @@ struct au0828_dev {
        /* USB / URB Related */
        int             urb_streaming;
        struct urb      *urbs[URB_COUNT];
+
+       /* Preallocated transfer digital transfer buffers */
+
+       char *dig_transfer_buffer[URB_COUNT];
 };
 
 /* ----------------------------------------------------------- */
index 86feeeaf61c24a458df51f40ad2d3629901437e9..f14c5e89a567b5875c0572590843a052978eeaa9 100644 (file)
@@ -45,6 +45,8 @@ config VIDEO_CX231XX_DVB
        select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
        select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_LGDT3305 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT
 
        ---help---
          This adds support for DVB cards based on the
index 528cce958a82c4a67c91ea0c52841364db36f7d4..2ee03e4ddd868ac1966f0e3e47d804a5e01ed591 100644 (file)
@@ -709,6 +709,8 @@ const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
 
 /* table of devices that work with this driver */
 struct usb_device_id cx231xx_id_table[] = {
+       {USB_DEVICE(0x1D19, 0x6109),
+       .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
        {USB_DEVICE(0x0572, 0x5A3C),
         .driver_info = CX231XX_BOARD_UNKNOWN},
        {USB_DEVICE(0x0572, 0x58A2),
index 96a5a09653994657df3c9602559a3e3102aa9e3a..7c0f797f1057334220f36d9b94b4e7ad963687b8 100644 (file)
@@ -371,9 +371,9 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
        mutex_lock(&dev->i2c_lock);
        for (i = 0; i < num; i++) {
 
-               addr = msgs[i].addr >> 1;
+               addr = msgs[i].addr;
 
-               dprintk2(2, "%s %s addr=%x len=%d:",
+               dprintk2(2, "%s %s addr=0x%x len=%d:",
                         (msgs[i].flags & I2C_M_RD) ? "read" : "write",
                         i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
                if (!msgs[i].len) {
@@ -390,32 +390,41 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
                        rc = cx231xx_i2c_recv_bytes(i2c_adap, &msgs[i]);
                        if (i2c_debug >= 2) {
                                for (byte = 0; byte < msgs[i].len; byte++)
-                                       printk(" %02x", msgs[i].buf[byte]);
+                                       printk(KERN_CONT " %02x", msgs[i].buf[byte]);
                        }
                } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
                           msgs[i].addr == msgs[i + 1].addr
                           && (msgs[i].len <= 2) && (bus->nr < 3)) {
+                       /* write bytes */
+                       if (i2c_debug >= 2) {
+                               for (byte = 0; byte < msgs[i].len; byte++)
+                                       printk(KERN_CONT " %02x", msgs[i].buf[byte]);
+                               printk(KERN_CONT "\n");
+                       }
                        /* read bytes */
+                       dprintk2(2, "plus %s %s addr=0x%x len=%d:",
+                               (msgs[i+1].flags & I2C_M_RD) ? "read" : "write",
+                               i+1 == num - 1 ? "stop" : "nonstop", addr, msgs[i+1].len);
                        rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap,
                                                               &msgs[i],
                                                               &msgs[i + 1]);
                        if (i2c_debug >= 2) {
-                               for (byte = 0; byte < msgs[i].len; byte++)
-                                       printk(" %02x", msgs[i].buf[byte]);
+                               for (byte = 0; byte < msgs[i+1].len; byte++)
+                                       printk(KERN_CONT " %02x", msgs[i+1].buf[byte]);
                        }
                        i++;
                } else {
                        /* write bytes */
                        if (i2c_debug >= 2) {
                                for (byte = 0; byte < msgs[i].len; byte++)
-                                       printk(" %02x", msgs[i].buf[byte]);
+                                       printk(KERN_CONT " %02x", msgs[i].buf[byte]);
                        }
                        rc = cx231xx_i2c_send_bytes(i2c_adap, &msgs[i]);
                }
                if (rc < 0)
                        goto err;
                if (i2c_debug >= 2)
-                       printk("\n");
+                       printk(KERN_CONT "\n");
        }
        mutex_unlock(&dev->i2c_lock);
        return num;
index 90cfa35ef6e62d57bf19a32fe1c2e203a77ed5f0..eeab79bdd2aa90cd257317da152b9fbfbf989d3b 100644 (file)
@@ -442,6 +442,7 @@ static struct cxd2820r_config anysee_cxd2820r_config = {
  * IOD[0] ZL10353 1=enabled
  * IOE[0] tuner 0=enabled
  * tuner is behind ZL10353 I2C-gate
+ * tuner is behind TDA10023 I2C-gate
  *
  * E7 TC VID=1c73 PID=861f HW=18 FW=0.7 AMTCI=0.5 "anysee-E7TC(LP)"
  * PCB: 508TC (rev0.6)
@@ -956,7 +957,7 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
 
                if (fe && adap->fe[1]) {
                        /* attach tuner for 2nd FE */
-                       fe = dvb_attach(dvb_pll_attach, adap->fe[0],
+                       fe = dvb_attach(dvb_pll_attach, adap->fe[1],
                                        (0xc0 >> 1), &d->i2c_adap,
                                        DVB_PLL_SAMSUNG_DTOS403IH102A);
                }
index 44c64ef361bf9dbe0097783e1aa40dacbc842a01..c1051c3477442bc1b98bb0f1ce514d788499057c 100644 (file)
@@ -68,6 +68,19 @@ static struct drxk_config terratec_h7_drxk = {
        .microcode_name = "dvb-usb-terratec-h7-drxk.fw",
 };
 
+static struct drxk_config cablestar_hdci_drxk = {
+       .adr = 0x29,
+       .parallel_ts = true,
+       .dynamic_clk = true,
+       .single_master = true,
+       .enable_merr_cfg = true,
+       .no_i2c_bridge = false,
+       .chunk_size = 64,
+       .mpeg_out_clk_strength = 0x02,
+       .qam_demod_parameter_count = 2,
+       .microcode_name = "dvb-usb-technisat-cablestar-hdci-drxk.fw",
+};
+
 static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
 {
        struct az6007_device_state *st = fe_to_priv(fe);
@@ -630,6 +643,27 @@ static int az6007_frontend_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
+static int az6007_cablestar_hdci_frontend_attach(struct dvb_usb_adapter *adap)
+{
+       struct az6007_device_state *st = adap_to_priv(adap);
+       struct dvb_usb_device *d = adap_to_d(adap);
+
+       pr_debug("attaching demod drxk\n");
+
+       adap->fe[0] = dvb_attach(drxk_attach, &cablestar_hdci_drxk,
+                                &d->i2c_adap);
+       if (!adap->fe[0])
+               return -EINVAL;
+
+       adap->fe[0]->sec_priv = adap;
+       st->gate_ctrl = adap->fe[0]->ops.i2c_gate_ctrl;
+       adap->fe[0]->ops.i2c_gate_ctrl = drxk_gate_ctrl;
+
+       az6007_ci_init(adap);
+
+       return 0;
+}
+
 static int az6007_tuner_attach(struct dvb_usb_adapter *adap)
 {
        struct dvb_usb_device *d = adap_to_d(adap);
@@ -868,6 +902,29 @@ static struct dvb_usb_device_properties az6007_props = {
        }
 };
 
+static struct dvb_usb_device_properties az6007_cablestar_hdci_props = {
+       .driver_name         = KBUILD_MODNAME,
+       .owner               = THIS_MODULE,
+       .firmware            = AZ6007_FIRMWARE,
+
+       .adapter_nr          = adapter_nr,
+       .size_of_priv        = sizeof(struct az6007_device_state),
+       .i2c_algo            = &az6007_i2c_algo,
+       .tuner_attach        = az6007_tuner_attach,
+       .frontend_attach     = az6007_cablestar_hdci_frontend_attach,
+       .streaming_ctrl      = az6007_streaming_ctrl,
+/* ditch get_rc_config as it can't work (TS35 remote, I believe it's rc5) */
+       .get_rc_config       = NULL,
+       .read_mac_address    = az6007_read_mac_addr,
+       .download_firmware   = az6007_download_firmware,
+       .identify_state      = az6007_identify_state,
+       .power_ctrl          = az6007_power_ctrl,
+       .num_adapters        = 1,
+       .adapter             = {
+               { .stream = DVB_USB_STREAM_BULK(0x02, 10, 4096), }
+       }
+};
+
 static struct usb_device_id az6007_usb_table[] = {
        {DVB_USB_DEVICE(USB_VID_AZUREWAVE, USB_PID_AZUREWAVE_6007,
                &az6007_props, "Azurewave 6007", RC_MAP_EMPTY)},
@@ -875,6 +932,8 @@ static struct usb_device_id az6007_usb_table[] = {
                &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
        {DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_H7_2,
                &az6007_props, "Terratec H7", RC_MAP_NEC_TERRATEC_CINERGY_XS)},
+       {DVB_USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_CABLESTAR_HDCI,
+               &az6007_cablestar_hdci_props, "Technisat CableStar Combo HD CI", RC_MAP_EMPTY)},
        {0},
 };
 
index 5c68f3918bc81279717131e15a5084e25e10d1d8..0c2b377704ff18daba836e2af3151a7765982092 100644 (file)
@@ -170,7 +170,7 @@ static int ec168_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 
 error:
        mutex_unlock(&d->i2c_mutex);
-       return i;
+       return ret;
 }
 
 static u32 ec168_i2c_func(struct i2c_adapter *adapter)
index 1cb6899cf797159869f1ee7e24d5f3eab0a9788e..fe95a586dd5d7350a2a30dcf3549fea26c3e2082 100644 (file)
@@ -799,6 +799,9 @@ static const struct usb_device_id it913x_id_table[] = {
        { DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_CTVDIGDUAL_V2,
                &it913x_properties, "Digital Dual TV Receiver CTVDIGDUAL_V2",
                        RC_MAP_IT913X_V1) },
+       { DVB_USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_H335,
+               &it913x_properties, "Avermedia H335",
+                       RC_MAP_IT913X_V2) },
        {}              /* Terminating entry */
 };
 
index ecca03667f9870d865f212bd0a59932aa9d7f00d..fda5c64ba0e8220f0876e56ad3bf0d328361edf5 100644 (file)
@@ -1407,6 +1407,8 @@ static const struct usb_device_id rtl28xxu_id_table[] = {
                &rtl2832u_props, "Dexatek DK DVB-T Dongle", NULL) },
        { DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6680,
                &rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) },
+       { DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_MINID,
+               &rtl2832u_props, "Leadtek Winfast DTV Dongle Mini D", NULL) },
        { DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3,
                &rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) },
        { DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102,
index 20e345d9fe8f3aca89a913f79f3ccb813b7d5ab4..a1c641e18362ad288ebd1972c389831d2abb1db3 100644 (file)
@@ -149,6 +149,7 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                          int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret;
        int i;
 
        if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
@@ -173,7 +174,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        if (1 + msg[i].len > sizeof(ibuf)) {
                                warn("i2c rd: len=%d is too big!\n",
                                     msg[i].len);
-                               return -EOPNOTSUPP;
+                               ret = -EOPNOTSUPP;
+                               goto unlock;
                        }
                        obuf[0] = 0;
                        obuf[1] = msg[i].len;
@@ -193,12 +195,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        if (3 + msg[i].len > sizeof(obuf)) {
                                warn("i2c wr: len=%d is too big!\n",
                                     msg[i].len);
-                               return -EOPNOTSUPP;
+                               ret = -EOPNOTSUPP;
+                               goto unlock;
                        }
                        if (1 + msg[i + 1].len > sizeof(ibuf)) {
                                warn("i2c rd: len=%d is too big!\n",
                                     msg[i + 1].len);
-                               return -EOPNOTSUPP;
+                               ret = -EOPNOTSUPP;
+                               goto unlock;
                        }
                        obuf[0] = msg[i].len;
                        obuf[1] = msg[i+1].len;
@@ -223,7 +227,8 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        if (2 + msg[i].len > sizeof(obuf)) {
                                warn("i2c wr: len=%d is too big!\n",
                                     msg[i].len);
-                               return -EOPNOTSUPP;
+                               ret = -EOPNOTSUPP;
+                               goto unlock;
                        }
                        obuf[0] = msg[i].addr;
                        obuf[1] = msg[i].len;
@@ -237,8 +242,14 @@ static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                }
        }
 
+       if (i == num)
+               ret = num;
+       else
+               ret = -EREMOTEIO;
+
+unlock:
        mutex_unlock(&d->i2c_mutex);
-       return i == num ? num : -EREMOTEIO;
+       return ret;
 }
 
 static u32 cxusb_i2c_func(struct i2c_adapter *adapter)
index c1a63b2a6baa53725342b4ef0b6bc93234207275..ae0f56a32e4d0ba888b09a214492cb2b2f14b244 100644 (file)
@@ -2,7 +2,7 @@
  *     DVBWorld DVB-S 2101, 2102, DVB-S2 2104, DVB-C 3101,
  *     TeVii S600, S630, S650, S660, S480, S421, S632
  *     Prof 1100, 7500,
- *     Geniatech SU3000 Cards
+ *     Geniatech SU3000, T220 Cards
  * Copyright (C) 2008-2012 Igor M. Liplianin (liplianin@me.by)
  *
  *     This program is free software; you can redistribute it and/or modify it
@@ -29,6 +29,8 @@
 #include "stb6100.h"
 #include "stb6100_proc.h"
 #include "m88rs2000.h"
+#include "tda18271.h"
+#include "cxd2820r.h"
 
 /* Max transfer size done by I2C transfer functions */
 #define MAX_XFER_SIZE  64
                "Please see linux/Documentation/dvb/ for more details " \
                "on firmware-problems."
 
-struct rc_map_dvb_usb_table_table {
-       struct rc_map_table *rc_keys;
-       int rc_keys_size;
-};
-
 struct su3000_state {
        u8 initialized;
 };
@@ -129,12 +126,6 @@ module_param_named(debug, dvb_usb_dw2102_debug, int, 0644);
 MODULE_PARM_DESC(debug, "set debugging level (1=info 2=xfer 4=rc(or-able))."
                                                DVB_USB_DEBUG_STATUS);
 
-/* keymaps */
-static int ir_keymap;
-module_param_named(keymap, ir_keymap, int, 0644);
-MODULE_PARM_DESC(keymap, "set keymap 0=default 1=dvbworld 2=tevii 3=tbs  ..."
-                       " 256=none");
-
 /* demod probe */
 static int demod_probe = 1;
 module_param_named(demod, demod_probe, int, 0644);
@@ -301,6 +292,7 @@ static int dw2102_serit_i2c_transfer(struct i2c_adapter *adap,
 static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret;
 
        if (!d)
                return -ENODEV;
@@ -316,7 +308,8 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
                if (2 + msg[1].len > sizeof(ibuf)) {
                        warn("i2c rd: len=%d is too big!\n",
                             msg[1].len);
-                       return -EOPNOTSUPP;
+                       ret = -EOPNOTSUPP;
+                       goto unlock;
                }
 
                obuf[0] = msg[0].addr << 1;
@@ -340,7 +333,8 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
                        if (2 + msg[0].len > sizeof(obuf)) {
                                warn("i2c wr: len=%d is too big!\n",
                                     msg[1].len);
-                               return -EOPNOTSUPP;
+                               ret = -EOPNOTSUPP;
+                               goto unlock;
                        }
 
                        obuf[0] = msg[0].addr << 1;
@@ -357,7 +351,8 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
                        if (2 + msg[0].len > sizeof(obuf)) {
                                warn("i2c wr: len=%d is too big!\n",
                                     msg[1].len);
-                               return -EOPNOTSUPP;
+                               ret = -EOPNOTSUPP;
+                               goto unlock;
                        }
 
                        obuf[0] = msg[0].addr << 1;
@@ -386,15 +381,17 @@ static int dw2102_earda_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg ms
 
                break;
        }
+       ret = num;
 
+unlock:
        mutex_unlock(&d->i2c_mutex);
-       return num;
+       return ret;
 }
 
 static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
-       int len, i, j;
+       int len, i, j, ret;
 
        if (!d)
                return -ENODEV;
@@ -430,7 +427,8 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
                                if (2 + msg[j].len > sizeof(ibuf)) {
                                        warn("i2c rd: len=%d is too big!\n",
                                             msg[j].len);
-                                       return -EOPNOTSUPP;
+                                       ret = -EOPNOTSUPP;
+                                       goto unlock;
                                }
 
                                dw210x_op_rw(d->udev, 0xc3,
@@ -466,7 +464,8 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
                                if (2 + msg[j].len > sizeof(obuf)) {
                                        warn("i2c wr: len=%d is too big!\n",
                                             msg[j].len);
-                                       return -EOPNOTSUPP;
+                                       ret = -EOPNOTSUPP;
+                                       goto unlock;
                                }
 
                                obuf[0] = msg[j].addr << 1;
@@ -481,15 +480,18 @@ static int dw2104_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[], i
                }
 
        }
+       ret = num;
 
+unlock:
        mutex_unlock(&d->i2c_mutex);
-       return num;
+       return ret;
 }
 
 static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                                                int num)
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
+       int ret;
        int i;
 
        if (!d)
@@ -506,7 +508,8 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                if (2 + msg[1].len > sizeof(ibuf)) {
                        warn("i2c rd: len=%d is too big!\n",
                             msg[1].len);
-                       return -EOPNOTSUPP;
+                       ret = -EOPNOTSUPP;
+                       goto unlock;
                }
                obuf[0] = msg[0].addr << 1;
                obuf[1] = msg[0].len;
@@ -530,7 +533,8 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                        if (2 + msg[0].len > sizeof(obuf)) {
                                warn("i2c wr: len=%d is too big!\n",
                                     msg[0].len);
-                               return -EOPNOTSUPP;
+                               ret = -EOPNOTSUPP;
+                               goto unlock;
                        }
                        obuf[0] = msg[0].addr << 1;
                        obuf[1] = msg[0].len;
@@ -556,9 +560,11 @@ static int dw3101_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                msg[i].flags == 0 ? ">>>" : "<<<");
                debug_dump(msg[i].buf, msg[i].len, deb_xfer);
        }
+       ret = num;
 
+unlock:
        mutex_unlock(&d->i2c_mutex);
-       return num;
+       return ret;
 }
 
 static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
@@ -566,7 +572,7 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
 {
        struct dvb_usb_device *d = i2c_get_adapdata(adap);
        struct usb_device *udev;
-       int len, i, j;
+       int len, i, j, ret;
 
        if (!d)
                return -ENODEV;
@@ -618,7 +624,8 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                if (msg[j].len > sizeof(ibuf)) {
                                        warn("i2c rd: len=%d is too big!\n",
                                             msg[j].len);
-                                       return -EOPNOTSUPP;
+                                       ret = -EOPNOTSUPP;
+                                       goto unlock;
                                }
 
                                dw210x_op_rw(d->udev, 0x91, 0, 0,
@@ -652,7 +659,8 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                if (2 + msg[j].len > sizeof(obuf)) {
                                        warn("i2c wr: len=%d is too big!\n",
                                             msg[j].len);
-                                       return -EOPNOTSUPP;
+                                       ret = -EOPNOTSUPP;
+                                       goto unlock;
                                }
 
                                obuf[0] = msg[j + 1].len;
@@ -671,7 +679,8 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                                if (2 + msg[j].len > sizeof(obuf)) {
                                        warn("i2c wr: len=%d is too big!\n",
                                             msg[j].len);
-                                       return -EOPNOTSUPP;
+                                       ret = -EOPNOTSUPP;
+                                       goto unlock;
                                }
                                obuf[0] = msg[j].len + 1;
                                obuf[1] = (msg[j].addr << 1);
@@ -685,9 +694,11 @@ static int s6x0_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
                }
                }
        }
+       ret = num;
 
+unlock:
        mutex_unlock(&d->i2c_mutex);
-       return num;
+       return ret;
 }
 
 static int su3000_i2c_transfer(struct i2c_adapter *adap, struct i2c_msg msg[],
@@ -1095,6 +1106,16 @@ static struct ds3000_config su3000_ds3000_config = {
        .set_lock_led = dw210x_led_ctrl,
 };
 
+static struct cxd2820r_config cxd2820r_config = {
+       .i2c_address = 0x6c, /* (0xd8 >> 1) */
+       .ts_mode = 0x38,
+};
+
+static struct tda18271_config tda18271_config = {
+       .output_opt = TDA18271_OUTPUT_LT_OFF,
+       .gate = TDA18271_GATE_DIGITAL,
+};
+
 static u8 m88rs2000_inittab[] = {
        DEMOD_WRITE, 0x9a, 0x30,
        DEMOD_WRITE, 0x00, 0x01,
@@ -1364,6 +1385,49 @@ static int su3000_frontend_attach(struct dvb_usb_adapter *d)
        return -EIO;
 }
 
+static int t220_frontend_attach(struct dvb_usb_adapter *d)
+{
+       u8 obuf[3] = { 0xe, 0x80, 0 };
+       u8 ibuf[] = { 0 };
+
+       if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+               err("command 0x0e transfer failed.");
+
+       obuf[0] = 0xe;
+       obuf[1] = 0x83;
+       obuf[2] = 0;
+
+       if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+               err("command 0x0e transfer failed.");
+
+       msleep(100);
+
+       obuf[0] = 0xe;
+       obuf[1] = 0x80;
+       obuf[2] = 1;
+
+       if (dvb_usb_generic_rw(d->dev, obuf, 3, ibuf, 1, 0) < 0)
+               err("command 0x0e transfer failed.");
+
+       obuf[0] = 0x51;
+
+       if (dvb_usb_generic_rw(d->dev, obuf, 1, ibuf, 1, 0) < 0)
+               err("command 0x51 transfer failed.");
+
+       d->fe_adap[0].fe = dvb_attach(cxd2820r_attach, &cxd2820r_config,
+                                       &d->dev->i2c_adap, NULL);
+       if (d->fe_adap[0].fe != NULL) {
+               if (dvb_attach(tda18271_attach, d->fe_adap[0].fe, 0x60,
+                                       &d->dev->i2c_adap, &tda18271_config)) {
+                       info("Attached TDA18271HD/CXD2820R!\n");
+                       return 0;
+               }
+       }
+
+       info("Failed to attach TDA18271HD/CXD2820R!\n");
+       return -EIO;
+}
+
 static int m88rs2000_frontend_attach(struct dvb_usb_adapter *d)
 {
        u8 obuf[] = { 0x51 };
@@ -1404,174 +1468,29 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
        return 0;
 }
 
-static struct rc_map_table rc_map_dw210x_table[] = {
-       { 0xf80a, KEY_POWER2 },         /*power*/
-       { 0xf80c, KEY_MUTE },           /*mute*/
-       { 0xf811, KEY_1 },
-       { 0xf812, KEY_2 },
-       { 0xf813, KEY_3 },
-       { 0xf814, KEY_4 },
-       { 0xf815, KEY_5 },
-       { 0xf816, KEY_6 },
-       { 0xf817, KEY_7 },
-       { 0xf818, KEY_8 },
-       { 0xf819, KEY_9 },
-       { 0xf810, KEY_0 },
-       { 0xf81c, KEY_CHANNELUP },      /*ch+*/
-       { 0xf80f, KEY_CHANNELDOWN },    /*ch-*/
-       { 0xf81a, KEY_VOLUMEUP },       /*vol+*/
-       { 0xf80e, KEY_VOLUMEDOWN },     /*vol-*/
-       { 0xf804, KEY_RECORD },         /*rec*/
-       { 0xf809, KEY_FAVORITES },      /*fav*/
-       { 0xf808, KEY_REWIND },         /*rewind*/
-       { 0xf807, KEY_FASTFORWARD },    /*fast*/
-       { 0xf80b, KEY_PAUSE },          /*pause*/
-       { 0xf802, KEY_ESC },            /*cancel*/
-       { 0xf803, KEY_TAB },            /*tab*/
-       { 0xf800, KEY_UP },             /*up*/
-       { 0xf81f, KEY_OK },             /*ok*/
-       { 0xf801, KEY_DOWN },           /*down*/
-       { 0xf805, KEY_CAMERA },         /*cap*/
-       { 0xf806, KEY_STOP },           /*stop*/
-       { 0xf840, KEY_ZOOM },           /*full*/
-       { 0xf81e, KEY_TV },             /*tvmode*/
-       { 0xf81b, KEY_LAST },           /*recall*/
-};
-
-static struct rc_map_table rc_map_tevii_table[] = {
-       { 0xf80a, KEY_POWER },
-       { 0xf80c, KEY_MUTE },
-       { 0xf811, KEY_1 },
-       { 0xf812, KEY_2 },
-       { 0xf813, KEY_3 },
-       { 0xf814, KEY_4 },
-       { 0xf815, KEY_5 },
-       { 0xf816, KEY_6 },
-       { 0xf817, KEY_7 },
-       { 0xf818, KEY_8 },
-       { 0xf819, KEY_9 },
-       { 0xf810, KEY_0 },
-       { 0xf81c, KEY_MENU },
-       { 0xf80f, KEY_VOLUMEDOWN },
-       { 0xf81a, KEY_LAST },
-       { 0xf80e, KEY_OPEN },
-       { 0xf804, KEY_RECORD },
-       { 0xf809, KEY_VOLUMEUP },
-       { 0xf808, KEY_CHANNELUP },
-       { 0xf807, KEY_PVR },
-       { 0xf80b, KEY_TIME },
-       { 0xf802, KEY_RIGHT },
-       { 0xf803, KEY_LEFT },
-       { 0xf800, KEY_UP },
-       { 0xf81f, KEY_OK },
-       { 0xf801, KEY_DOWN },
-       { 0xf805, KEY_TUNER },
-       { 0xf806, KEY_CHANNELDOWN },
-       { 0xf840, KEY_PLAYPAUSE },
-       { 0xf81e, KEY_REWIND },
-       { 0xf81b, KEY_FAVORITES },
-       { 0xf81d, KEY_BACK },
-       { 0xf84d, KEY_FASTFORWARD },
-       { 0xf844, KEY_EPG },
-       { 0xf84c, KEY_INFO },
-       { 0xf841, KEY_AB },
-       { 0xf843, KEY_AUDIO },
-       { 0xf845, KEY_SUBTITLE },
-       { 0xf84a, KEY_LIST },
-       { 0xf846, KEY_F1 },
-       { 0xf847, KEY_F2 },
-       { 0xf85e, KEY_F3 },
-       { 0xf85c, KEY_F4 },
-       { 0xf852, KEY_F5 },
-       { 0xf85a, KEY_F6 },
-       { 0xf856, KEY_MODE },
-       { 0xf858, KEY_SWITCHVIDEOMODE },
-};
-
-static struct rc_map_table rc_map_tbs_table[] = {
-       { 0xf884, KEY_POWER },
-       { 0xf894, KEY_MUTE },
-       { 0xf887, KEY_1 },
-       { 0xf886, KEY_2 },
-       { 0xf885, KEY_3 },
-       { 0xf88b, KEY_4 },
-       { 0xf88a, KEY_5 },
-       { 0xf889, KEY_6 },
-       { 0xf88f, KEY_7 },
-       { 0xf88e, KEY_8 },
-       { 0xf88d, KEY_9 },
-       { 0xf892, KEY_0 },
-       { 0xf896, KEY_CHANNELUP },
-       { 0xf891, KEY_CHANNELDOWN },
-       { 0xf893, KEY_VOLUMEUP },
-       { 0xf88c, KEY_VOLUMEDOWN },
-       { 0xf883, KEY_RECORD },
-       { 0xf898, KEY_PAUSE  },
-       { 0xf899, KEY_OK },
-       { 0xf89a, KEY_SHUFFLE },
-       { 0xf881, KEY_UP },
-       { 0xf890, KEY_LEFT },
-       { 0xf882, KEY_RIGHT },
-       { 0xf888, KEY_DOWN },
-       { 0xf895, KEY_FAVORITES },
-       { 0xf897, KEY_SUBTITLE },
-       { 0xf89d, KEY_ZOOM },
-       { 0xf89f, KEY_EXIT },
-       { 0xf89e, KEY_MENU },
-       { 0xf89c, KEY_EPG },
-       { 0xf880, KEY_PREVIOUS },
-       { 0xf89b, KEY_MODE }
-};
+static int dw2102_rc_query(struct dvb_usb_device *d)
+{
+       u8 key[2];
+       struct i2c_msg msg = {
+               .addr = DW2102_RC_QUERY,
+               .flags = I2C_M_RD,
+               .buf = key,
+               .len = 2
+       };
 
-static struct rc_map_table rc_map_su3000_table[] = {
-       { 0x25, KEY_POWER },    /* right-bottom Red */
-       { 0x0a, KEY_MUTE },     /* -/-- */
-       { 0x01, KEY_1 },
-       { 0x02, KEY_2 },
-       { 0x03, KEY_3 },
-       { 0x04, KEY_4 },
-       { 0x05, KEY_5 },
-       { 0x06, KEY_6 },
-       { 0x07, KEY_7 },
-       { 0x08, KEY_8 },
-       { 0x09, KEY_9 },
-       { 0x00, KEY_0 },
-       { 0x20, KEY_UP },       /* CH+ */
-       { 0x21, KEY_DOWN },     /* CH+ */
-       { 0x12, KEY_VOLUMEUP }, /* Brightness Up */
-       { 0x13, KEY_VOLUMEDOWN },/* Brightness Down */
-       { 0x1f, KEY_RECORD },
-       { 0x17, KEY_PLAY },
-       { 0x16, KEY_PAUSE },
-       { 0x0b, KEY_STOP },
-       { 0x27, KEY_FASTFORWARD },/* >> */
-       { 0x26, KEY_REWIND },   /* << */
-       { 0x0d, KEY_OK },       /* Mute */
-       { 0x11, KEY_LEFT },     /* VOL- */
-       { 0x10, KEY_RIGHT },    /* VOL+ */
-       { 0x29, KEY_BACK },     /* button under 9 */
-       { 0x2c, KEY_MENU },     /* TTX */
-       { 0x2b, KEY_EPG },      /* EPG */
-       { 0x1e, KEY_RED },      /* OSD */
-       { 0x0e, KEY_GREEN },    /* Window */
-       { 0x2d, KEY_YELLOW },   /* button under << */
-       { 0x0f, KEY_BLUE },     /* bottom yellow button */
-       { 0x14, KEY_AUDIO },    /* Snapshot */
-       { 0x38, KEY_TV },       /* TV/Radio */
-       { 0x0c, KEY_ESC }       /* upper Red button */
-};
+       if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
+               if (msg.buf[0] != 0xff) {
+                       deb_rc("%s: rc code: %x, %x\n",
+                                       __func__, key[0], key[1]);
+                       rc_keydown(d->rc_dev, key[0], 1);
+               }
+       }
 
-static struct rc_map_dvb_usb_table_table keys_tables[] = {
-       { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) },
-       { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) },
-       { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) },
-       { rc_map_su3000_table, ARRAY_SIZE(rc_map_su3000_table) },
-};
+       return 0;
+}
 
-static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int prof_rc_query(struct dvb_usb_device *d)
 {
-       struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
-       int keymap_size = d->props.rc.legacy.rc_map_size;
        u8 key[2];
        struct i2c_msg msg = {
                .addr = DW2102_RC_QUERY,
@@ -1579,32 +1498,34 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
                .buf = key,
                .len = 2
        };
-       int i;
-       /* override keymap */
-       if ((ir_keymap > 0) && (ir_keymap <= ARRAY_SIZE(keys_tables))) {
-               keymap = keys_tables[ir_keymap - 1].rc_keys ;
-               keymap_size = keys_tables[ir_keymap - 1].rc_keys_size;
-       } else if (ir_keymap > ARRAY_SIZE(keys_tables))
-               return 0; /* none */
-
-       *state = REMOTE_NO_KEY_PRESSED;
-       if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
-               for (i = 0; i < keymap_size ; i++) {
-                       if (rc5_data(&keymap[i]) == msg.buf[0]) {
-                               *state = REMOTE_KEY_PRESSED;
-                               *event = keymap[i].keycode;
-                               break;
-                       }
 
+       if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
+               if (msg.buf[0] != 0xff) {
+                       deb_rc("%s: rc code: %x, %x\n",
+                                       __func__, key[0], key[1]);
+                       rc_keydown(d->rc_dev, key[0]^0xff, 1);
                }
+       }
 
-               if ((*state) == REMOTE_KEY_PRESSED)
-                       deb_rc("%s: found rc key: %x, %x, event: %x\n",
-                                       __func__, key[0], key[1], (*event));
-               else if (key[0] != 0xff)
-                       deb_rc("%s: unknown rc key: %x, %x\n",
-                                       __func__, key[0], key[1]);
+       return 0;
+}
 
+static int su3000_rc_query(struct dvb_usb_device *d)
+{
+       u8 key[2];
+       struct i2c_msg msg = {
+               .addr = DW2102_RC_QUERY,
+               .flags = I2C_M_RD,
+               .buf = key,
+               .len = 2
+       };
+
+       if (d->props.i2c_algo->master_xfer(&d->i2c_adap, &msg, 1) == 1) {
+               if (msg.buf[0] != 0xff) {
+                       deb_rc("%s: rc code: %x, %x\n",
+                                       __func__, key[0], key[1]);
+                       rc_keydown(d->rc_dev, key[1] << 8 | key[0], 1);
+               }
        }
 
        return 0;
@@ -1630,6 +1551,7 @@ enum dw2102_table_entry {
        TEVII_S632,
        TERRATEC_CINERGY_S2_R2,
        GOTVIEW_SAT_HD,
+       GENIATECH_T220,
 };
 
 static struct usb_device_id dw2102_table[] = {
@@ -1652,6 +1574,7 @@ static struct usb_device_id dw2102_table[] = {
        [TEVII_S632] = {USB_DEVICE(0x9022, USB_PID_TEVII_S632)},
        [TERRATEC_CINERGY_S2_R2] = {USB_DEVICE(USB_VID_TERRATEC, 0x00b0)},
        [GOTVIEW_SAT_HD] = {USB_DEVICE(0x1FE1, USB_PID_GOTVIEW_SAT_HD)},
+       [GENIATECH_T220] = {USB_DEVICE(0x1f4d, 0xD220)},
        { }
 };
 
@@ -1711,9 +1634,7 @@ static int dw2102_load_firmware(struct usb_device *dev,
                /* init registers */
                switch (dev->descriptor.idProduct) {
                case USB_PID_TEVII_S650:
-                       dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
-                       dw2104_properties.rc.legacy.rc_map_size =
-                                       ARRAY_SIZE(rc_map_tevii_table);
+                       dw2104_properties.rc.core.rc_codes = RC_MAP_TEVII_NEC;
                case USB_PID_DW2104:
                        reset = 1;
                        dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
@@ -1777,10 +1698,11 @@ static struct dvb_usb_device_properties dw2102_properties = {
 
        .i2c_algo = &dw2102_serit_i2c_algo,
 
-       .rc.legacy = {
-               .rc_map_table = rc_map_dw210x_table,
-               .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+       .rc.core = {
                .rc_interval = 150,
+               .rc_codes = RC_MAP_DM1105_NEC,
+               .module_name = "dw2102",
+               .allowed_protos   = RC_BIT_NEC,
                .rc_query = dw2102_rc_query,
        },
 
@@ -1831,10 +1753,11 @@ static struct dvb_usb_device_properties dw2104_properties = {
        .no_reconnect = 1,
 
        .i2c_algo = &dw2104_i2c_algo,
-       .rc.legacy = {
-               .rc_map_table = rc_map_dw210x_table,
-               .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+       .rc.core = {
                .rc_interval = 150,
+               .rc_codes = RC_MAP_DM1105_NEC,
+               .module_name = "dw2102",
+               .allowed_protos   = RC_BIT_NEC,
                .rc_query = dw2102_rc_query,
        },
 
@@ -1881,10 +1804,11 @@ static struct dvb_usb_device_properties dw3101_properties = {
        .no_reconnect = 1,
 
        .i2c_algo = &dw3101_i2c_algo,
-       .rc.legacy = {
-               .rc_map_table = rc_map_dw210x_table,
-               .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+       .rc.core = {
                .rc_interval = 150,
+               .rc_codes = RC_MAP_DM1105_NEC,
+               .module_name = "dw2102",
+               .allowed_protos   = RC_BIT_NEC,
                .rc_query = dw2102_rc_query,
        },
 
@@ -1929,10 +1853,11 @@ static struct dvb_usb_device_properties s6x0_properties = {
        .no_reconnect = 1,
 
        .i2c_algo = &s6x0_i2c_algo,
-       .rc.legacy = {
-               .rc_map_table = rc_map_tevii_table,
-               .rc_map_size = ARRAY_SIZE(rc_map_tevii_table),
+       .rc.core = {
                .rc_interval = 150,
+               .rc_codes = RC_MAP_TEVII_NEC,
+               .module_name = "dw2102",
+               .allowed_protos   = RC_BIT_NEC,
                .rc_query = dw2102_rc_query,
        },
 
@@ -2022,11 +1947,12 @@ static struct dvb_usb_device_properties su3000_properties = {
        .identify_state = su3000_identify_state,
        .i2c_algo = &su3000_i2c_algo,
 
-       .rc.legacy = {
-               .rc_map_table = rc_map_su3000_table,
-               .rc_map_size = ARRAY_SIZE(rc_map_su3000_table),
+       .rc.core = {
                .rc_interval = 150,
-               .rc_query = dw2102_rc_query,
+               .rc_codes = RC_MAP_SU3000,
+               .module_name = "dw2102",
+               .allowed_protos   = RC_BIT_RC5,
+               .rc_query = su3000_rc_query,
        },
 
        .read_mac_address = su3000_read_mac_address,
@@ -2077,6 +2003,55 @@ static struct dvb_usb_device_properties su3000_properties = {
        }
 };
 
+static struct dvb_usb_device_properties t220_properties = {
+       .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+       .usb_ctrl = DEVICE_SPECIFIC,
+       .size_of_priv = sizeof(struct su3000_state),
+       .power_ctrl = su3000_power_ctrl,
+       .num_adapters = 1,
+       .identify_state = su3000_identify_state,
+       .i2c_algo = &su3000_i2c_algo,
+
+       .rc.core = {
+               .rc_interval = 150,
+               .rc_codes = RC_MAP_SU3000,
+               .module_name = "dw2102",
+               .allowed_protos   = RC_BIT_RC5,
+               .rc_query = su3000_rc_query,
+       },
+
+       .read_mac_address = su3000_read_mac_address,
+
+       .generic_bulk_ctrl_endpoint = 0x01,
+
+       .adapter = {
+               {
+               .num_frontends = 1,
+               .fe = { {
+                       .streaming_ctrl   = su3000_streaming_ctrl,
+                       .frontend_attach  = t220_frontend_attach,
+                       .stream = {
+                               .type = USB_BULK,
+                               .count = 8,
+                               .endpoint = 0x82,
+                               .u = {
+                                       .bulk = {
+                                               .buffersize = 4096,
+                                       }
+                               }
+                       }
+               } },
+               }
+       },
+       .num_device_descs = 1,
+       .devices = {
+               { "Geniatech T220 DVB-T/T2 USB2.0",
+                       { &dw2102_table[GENIATECH_T220], NULL },
+                       { NULL },
+               },
+       }
+};
+
 static int dw2102_probe(struct usb_interface *intf,
                const struct usb_device_id *id)
 {
@@ -2088,8 +2063,8 @@ static int dw2102_probe(struct usb_interface *intf,
        /* fill only different fields */
        p1100->firmware = P1100_FIRMWARE;
        p1100->devices[0] = d1100;
-       p1100->rc.legacy.rc_map_table = rc_map_tbs_table;
-       p1100->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
+       p1100->rc.core.rc_query = prof_rc_query;
+       p1100->rc.core.rc_codes = RC_MAP_TBS_NEC;
        p1100->adapter->fe[0].frontend_attach = stv0288_frontend_attach;
 
        s660 = kmemdup(&s6x0_properties,
@@ -2114,8 +2089,8 @@ static int dw2102_probe(struct usb_interface *intf,
        }
        p7500->firmware = P7500_FIRMWARE;
        p7500->devices[0] = d7500;
-       p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
-       p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
+       p7500->rc.core.rc_query = prof_rc_query;
+       p7500->rc.core.rc_codes = RC_MAP_TBS_NEC;
        p7500->adapter->fe[0].frontend_attach = prof_7500_frontend_attach;
 
 
@@ -2149,7 +2124,9 @@ static int dw2102_probe(struct usb_interface *intf,
            0 == dvb_usb_device_init(intf, s421,
                        THIS_MODULE, NULL, adapter_nr) ||
            0 == dvb_usb_device_init(intf, &su3000_properties,
-                                    THIS_MODULE, NULL, adapter_nr))
+                        THIS_MODULE, NULL, adapter_nr) ||
+           0 == dvb_usb_device_init(intf, &t220_properties,
+                        THIS_MODULE, NULL, adapter_nr))
                return 0;
 
        return -ENODEV;
@@ -2169,7 +2146,7 @@ MODULE_DESCRIPTION("Driver for DVBWorld DVB-S 2101, 2102, DVB-S2 2104,"
                        " DVB-C 3101 USB2.0,"
                        " TeVii S600, S630, S650, S660, S480, S421, S632"
                        " Prof 1100, 7500 USB2.0,"
-                       " Geniatech SU3000 devices");
+                       " Geniatech SU3000, T220 devices");
 MODULE_VERSION("0.1");
 MODULE_LICENSE("GPL");
 MODULE_FIRMWARE(DW2101_FIRMWARE);
index ca5ee6aceb62c52466248bd58d3fb4bd3ef1ae49..a1fccf3096de7825097383c427e5471e2ceb40b8 100644 (file)
@@ -1,8 +1,12 @@
 config VIDEO_EM28XX
-       tristate "Empia EM28xx USB video capture support"
+       tristate "Empia EM28xx USB devices support"
        depends on VIDEO_DEV && I2C
        select VIDEO_TUNER
        select VIDEO_TVEEPROM
+
+config VIDEO_EM28XX_V4L2
+       tristate "Empia EM28xx analog TV, video capture and/or webcam support"
+       depends on VIDEO_EM28XX
        select VIDEOBUF2_VMALLOC
        select VIDEO_SAA711X if MEDIA_SUBDRV_AUTOSELECT
        select VIDEO_TVP5150 if MEDIA_SUBDRV_AUTOSELECT
@@ -49,6 +53,8 @@ config VIDEO_EM28XX_DVB
        select DVB_MB86A20S if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_QT1010 if MEDIA_SUBDRV_AUTOSELECT
        select MEDIA_TUNER_TDA18271 if MEDIA_SUBDRV_AUTOSELECT
+       select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
+       select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
        ---help---
          This adds support for DVB cards based on the
          Empiatech em28xx chips.
index ad6d4855794072bccd7dfcc2988c233757013aee..3f850d5063d0e2b6145dc7e389747b330bbf30ed 100644 (file)
@@ -1,10 +1,11 @@
-em28xx-y +=    em28xx-video.o em28xx-i2c.o em28xx-cards.o
-em28xx-y +=    em28xx-core.o  em28xx-vbi.o em28xx-camera.o
+em28xx-y +=    em28xx-core.o em28xx-i2c.o em28xx-cards.o em28xx-camera.o
 
+em28xx-v4l-objs := em28xx-video.o em28xx-vbi.o
 em28xx-alsa-objs := em28xx-audio.o
 em28xx-rc-objs := em28xx-input.o
 
 obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
+obj-$(CONFIG_VIDEO_EM28XX_V4L2) += em28xx-v4l.o
 obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
 obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
 obj-$(CONFIG_VIDEO_EM28XX_RC) += em28xx-rc.o
index 2fdb66ee44ab7532b7e0d6a9bf3e043eddec8a87..05e9bd11a3ff016128e6c9dd05e1086cd454ce0e 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2006 Markus Rechberger <mrechberger@gmail.com>
  *
- *  Copyright (C) 2007-2011 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *  Copyright (C) 2007-2014 Mauro Carvalho Chehab
  *     - Port to work with the in-kernel driver
  *     - Cleanups, fixes, alsa-controls, etc.
  *
@@ -50,6 +50,9 @@ static int debug;
 module_param(debug, int, 0644);
 MODULE_PARM_DESC(debug, "activates debug info");
 
+#define EM28XX_MAX_AUDIO_BUFS          5
+#define EM28XX_MIN_AUDIO_PACKETS       64
+
 #define dprintk(fmt, arg...) do {                                      \
            if (debug)                                                  \
                printk(KERN_INFO "em28xx-audio %s: " fmt,               \
@@ -63,17 +66,13 @@ static int em28xx_deinit_isoc_audio(struct em28xx *dev)
        int i;
 
        dprintk("Stopping isoc\n");
-       for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
+       for (i = 0; i < dev->adev.num_urb; i++) {
+               struct urb *urb = dev->adev.urb[i];
+
                if (!irqs_disabled())
-                       usb_kill_urb(dev->adev.urb[i]);
+                       usb_kill_urb(urb);
                else
-                       usb_unlink_urb(dev->adev.urb[i]);
-
-               usb_free_urb(dev->adev.urb[i]);
-               dev->adev.urb[i] = NULL;
-
-               kfree(dev->adev.transfer_buffer[i]);
-               dev->adev.transfer_buffer[i] = NULL;
+                       usb_unlink_urb(urb);
        }
 
        return 0;
@@ -91,6 +90,12 @@ static void em28xx_audio_isocirq(struct urb *urb)
        struct snd_pcm_substream *substream;
        struct snd_pcm_runtime   *runtime;
 
+       if (dev->disconnected) {
+               dprintk("device disconnected while streaming. URB status=%d.\n", urb->status);
+               atomic_set(&dev->stream_started, 0);
+               return;
+       }
+
        switch (urb->status) {
        case 0:             /* success */
        case -ETIMEDOUT:    /* NAK */
@@ -158,63 +163,27 @@ static void em28xx_audio_isocirq(struct urb *urb)
        urb->status = 0;
 
        status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status < 0) {
+       if (status < 0)
                em28xx_errdev("resubmit of audio urb failed (error=%i)\n",
                              status);
-       }
        return;
 }
 
 static int em28xx_init_audio_isoc(struct em28xx *dev)
 {
        int       i, errCode;
-       const int sb_size = EM28XX_NUM_AUDIO_PACKETS *
-                           EM28XX_AUDIO_MAX_PACKET_SIZE;
 
        dprintk("Starting isoc transfers\n");
 
-       for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
-               struct urb *urb;
-               int j, k;
-
-               dev->adev.transfer_buffer[i] = kmalloc(sb_size, GFP_ATOMIC);
-               if (!dev->adev.transfer_buffer[i])
-                       return -ENOMEM;
-
-               memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
-               urb = usb_alloc_urb(EM28XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
-               if (!urb) {
-                       em28xx_errdev("usb_alloc_urb failed!\n");
-                       for (j = 0; j < i; j++) {
-                               usb_free_urb(dev->adev.urb[j]);
-                               kfree(dev->adev.transfer_buffer[j]);
-                       }
-                       return -ENOMEM;
-               }
-
-               urb->dev = dev->udev;
-               urb->context = dev;
-               urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->transfer_buffer = dev->adev.transfer_buffer[i];
-               urb->interval = 1;
-               urb->complete = em28xx_audio_isocirq;
-               urb->number_of_packets = EM28XX_NUM_AUDIO_PACKETS;
-               urb->transfer_buffer_length = sb_size;
-
-               for (j = k = 0; j < EM28XX_NUM_AUDIO_PACKETS;
-                            j++, k += EM28XX_AUDIO_MAX_PACKET_SIZE) {
-                       urb->iso_frame_desc[j].offset = k;
-                       urb->iso_frame_desc[j].length =
-                           EM28XX_AUDIO_MAX_PACKET_SIZE;
-               }
-               dev->adev.urb[i] = urb;
-       }
+       /* Start streaming */
+       for (i = 0; i < dev->adev.num_urb; i++) {
+               memset(dev->adev.transfer_buffer[i], 0x80,
+                      dev->adev.urb[i]->transfer_buffer_length);
 
-       for (i = 0; i < EM28XX_AUDIO_BUFS; i++) {
                errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
                if (errCode) {
-                       em28xx_errdev("submit of audio urb failed\n");
+                       em28xx_errdev("submit of audio urb failed (error=%i)\n",
+                                     errCode);
                        em28xx_deinit_isoc_audio(dev);
                        atomic_set(&dev->stream_started, 0);
                        return errCode;
@@ -255,15 +224,26 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = {
 
        .formats = SNDRV_PCM_FMTBIT_S16_LE,
 
-       .rates = SNDRV_PCM_RATE_CONTINUOUS | SNDRV_PCM_RATE_KNOT,
+       .rates = SNDRV_PCM_RATE_48000,
 
        .rate_min = 48000,
        .rate_max = 48000,
        .channels_min = 2,
        .channels_max = 2,
        .buffer_bytes_max = 62720 * 8,  /* just about the value in usbaudio.c */
-       .period_bytes_min = 64,         /* 12544/2, */
-       .period_bytes_max = 12544,
+
+
+       /*
+        * The period is 12.288 bytes. Allow a 10% of variation along its
+        * value, in order to avoid overruns/underruns due to some clock
+        * drift.
+        *
+        * FIXME: This period assumes 64 packets, and a 48000 PCM rate.
+        * Calculate it dynamically.
+        */
+       .period_bytes_min = 11059,
+       .period_bytes_max = 13516,
+
        .periods_min = 2,
        .periods_max = 98,              /* 12544, */
 };
@@ -274,28 +254,48 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
        struct snd_pcm_runtime *runtime = substream->runtime;
        int ret = 0;
 
-       dprintk("opening device and trying to acquire exclusive lock\n");
-
        if (!dev) {
                em28xx_err("BUG: em28xx can't find device struct."
                                " Can't proceed with open\n");
                return -ENODEV;
        }
 
+       if (dev->disconnected)
+               return -ENODEV;
+
+       dprintk("opening device and trying to acquire exclusive lock\n");
+
        runtime->hw = snd_em28xx_hw_capture;
-       if ((dev->alt == 0 || dev->audio_ifnum) && dev->adev.users == 0) {
-               if (dev->audio_ifnum)
+       if ((dev->alt == 0 || dev->is_audio_only) && dev->adev.users == 0) {
+               int nonblock = !!(substream->f_flags & O_NONBLOCK);
+
+               if (nonblock) {
+                       if (!mutex_trylock(&dev->lock))
+                               return -EAGAIN;
+               } else
+                       mutex_lock(&dev->lock);
+               if (dev->is_audio_only)
+                       /* vendor audio is on a separate interface */
                        dev->alt = 1;
                else
+                       /* vendor audio is on the same interface as video */
                        dev->alt = 7;
+                       /*
+                        * FIXME: The intention seems to be to select the alt
+                        * setting with the largest wMaxPacketSize for the video
+                        * endpoint.
+                        * At least dev->alt should be used instead, but we
+                        * should probably not touch it at all if it is
+                        * already >0, because wMaxPacketSize of the audio
+                        * endpoints seems to be the same for all.
+                        */
 
                dprintk("changing alternate number on interface %d to %d\n",
-                       dev->audio_ifnum, dev->alt);
-               usb_set_interface(dev->udev, dev->audio_ifnum, dev->alt);
+                       dev->ifnum, dev->alt);
+               usb_set_interface(dev->udev, dev->ifnum, dev->alt);
 
                /* Sets volume, mute, etc */
                dev->mute = 0;
-               mutex_lock(&dev->lock);
                ret = em28xx_audio_analog_set(dev);
                if (ret < 0)
                        goto err;
@@ -304,7 +304,12 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
                mutex_unlock(&dev->lock);
        }
 
+       /* Dynamically adjust the period size */
        snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
+       snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_BYTES,
+                                    dev->adev.period * 95 / 100,
+                                    dev->adev.period * 105 / 100);
+
        dev->adev.capture_pcm_substream = substream;
 
        return 0;
@@ -344,6 +349,10 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
                                        struct snd_pcm_hw_params *hw_params)
 {
        int ret;
+       struct em28xx *dev = snd_pcm_substream_chip(substream);
+
+       if (dev->disconnected)
+               return -ENODEV;
 
        dprintk("Setting capture parameters\n");
 
@@ -383,6 +392,9 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
 {
        struct em28xx *dev = snd_pcm_substream_chip(substream);
 
+       if (dev->disconnected)
+               return -ENODEV;
+
        dev->adev.hwptr_done_capture = 0;
        dev->adev.capture_transfer_done = 0;
 
@@ -408,6 +420,9 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
        struct em28xx *dev = snd_pcm_substream_chip(substream);
        int retval = 0;
 
+       if (dev->disconnected)
+               return -ENODEV;
+
        switch (cmd) {
        case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
        case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
@@ -434,6 +449,9 @@ static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
        snd_pcm_uframes_t hwptr_done;
 
        dev = snd_pcm_substream_chip(substream);
+       if (dev->disconnected)
+               return SNDRV_PCM_POS_XRUN;
+
        spin_lock_irqsave(&dev->adev.slock, flags);
        hwptr_done = dev->adev.hwptr_done_capture;
        spin_unlock_irqrestore(&dev->adev.slock, flags);
@@ -455,6 +473,11 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
 static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
                                struct snd_ctl_elem_info *info)
 {
+       struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+
+       if (dev->disconnected)
+               return -ENODEV;
+
        info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
        info->count = 2;
        info->value.integer.min = 0;
@@ -467,11 +490,22 @@ static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *value)
 {
        struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
        u16 val = (0x1f - (value->value.integer.value[0] & 0x1f)) |
                  (0x1f - (value->value.integer.value[1] & 0x1f)) << 8;
+       int nonblock = 0;
        int rc;
 
-       mutex_lock(&dev->lock);
+       if (dev->disconnected)
+               return -ENODEV;
+
+       if (substream)
+               nonblock = !!(substream->f_flags & O_NONBLOCK);
+       if (nonblock) {
+               if (!mutex_trylock(&dev->lock))
+                       return -EAGAIN;
+       } else
+               mutex_lock(&dev->lock);
        rc = em28xx_read_ac97(dev, kcontrol->private_value);
        if (rc < 0)
                goto err;
@@ -496,9 +530,20 @@ static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *value)
 {
        struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
+       int nonblock = 0;
        int val;
 
-       mutex_lock(&dev->lock);
+       if (dev->disconnected)
+               return -ENODEV;
+
+       if (substream)
+               nonblock = !!(substream->f_flags & O_NONBLOCK);
+       if (nonblock) {
+               if (!mutex_trylock(&dev->lock))
+                       return -EAGAIN;
+       } else
+               mutex_lock(&dev->lock);
        val = em28xx_read_ac97(dev, kcontrol->private_value);
        mutex_unlock(&dev->lock);
        if (val < 0)
@@ -520,9 +565,20 @@ static int em28xx_vol_put_mute(struct snd_kcontrol *kcontrol,
 {
        struct em28xx *dev = snd_kcontrol_chip(kcontrol);
        u16 val = value->value.integer.value[0];
+       struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
+       int nonblock = 0;
        int rc;
 
-       mutex_lock(&dev->lock);
+       if (dev->disconnected)
+               return -ENODEV;
+
+       if (substream)
+               nonblock = !!(substream->f_flags & O_NONBLOCK);
+       if (nonblock) {
+               if (!mutex_trylock(&dev->lock))
+                       return -EAGAIN;
+       } else
+               mutex_lock(&dev->lock);
        rc = em28xx_read_ac97(dev, kcontrol->private_value);
        if (rc < 0)
                goto err;
@@ -550,9 +606,20 @@ static int em28xx_vol_get_mute(struct snd_kcontrol *kcontrol,
                               struct snd_ctl_elem_value *value)
 {
        struct em28xx *dev = snd_kcontrol_chip(kcontrol);
+       struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
+       int nonblock = 0;
        int val;
 
-       mutex_lock(&dev->lock);
+       if (dev->disconnected)
+               return -ENODEV;
+
+       if (substream)
+               nonblock = !!(substream->f_flags & O_NONBLOCK);
+       if (nonblock) {
+               if (!mutex_trylock(&dev->lock))
+                       return -EAGAIN;
+       } else
+               mutex_lock(&dev->lock);
        val = em28xx_read_ac97(dev, kcontrol->private_value);
        mutex_unlock(&dev->lock);
        if (val < 0)
@@ -634,25 +701,204 @@ static struct snd_pcm_ops snd_em28xx_pcm_capture = {
        .page      = snd_pcm_get_vmalloc_page,
 };
 
+static void em28xx_audio_free_urb(struct em28xx *dev)
+{
+       int i;
+
+       for (i = 0; i < dev->adev.num_urb; i++) {
+               struct urb *urb = dev->adev.urb[i];
+
+               if (!urb)
+                       continue;
+
+               usb_free_coherent(dev->udev, urb->transfer_buffer_length,
+                                 dev->adev.transfer_buffer[i],
+                                 urb->transfer_dma);
+
+               usb_free_urb(urb);
+       }
+       kfree(dev->adev.urb);
+       kfree(dev->adev.transfer_buffer);
+       dev->adev.num_urb = 0;
+}
+
+/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
+static int em28xx_audio_ep_packet_size(struct usb_device *udev,
+                                       struct usb_endpoint_descriptor *e)
+{
+       int size = le16_to_cpu(e->wMaxPacketSize);
+
+       if (udev->speed == USB_SPEED_HIGH)
+               return (size & 0x7ff) *  (1 + (((size) >> 11) & 0x03));
+
+       return size & 0x7ff;
+}
+
+static int em28xx_audio_urb_init(struct em28xx *dev)
+{
+       struct usb_interface *intf;
+       struct usb_endpoint_descriptor *e, *ep = NULL;
+       int                 i, ep_size, interval, num_urb, npackets;
+       int                 urb_size, bytes_per_transfer;
+       u8 alt;
+
+       if (dev->ifnum)
+               alt = 1;
+       else
+               alt = 7;
+
+       intf = usb_ifnum_to_if(dev->udev, dev->ifnum);
+
+       if (intf->num_altsetting <= alt) {
+               em28xx_errdev("alt %d doesn't exist on interface %d\n",
+                             dev->ifnum, alt);
+               return -ENODEV;
+       }
+
+       for (i = 0; i < intf->altsetting[alt].desc.bNumEndpoints; i++) {
+               e = &intf->altsetting[alt].endpoint[i].desc;
+               if (!usb_endpoint_dir_in(e))
+                       continue;
+               if (e->bEndpointAddress == EM28XX_EP_AUDIO) {
+                       ep = e;
+                       break;
+               }
+       }
+
+       if (!ep) {
+               em28xx_errdev("Couldn't find an audio endpoint");
+               return -ENODEV;
+       }
+
+       ep_size = em28xx_audio_ep_packet_size(dev->udev, ep);
+       interval = 1 << (ep->bInterval - 1);
+
+       em28xx_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n",
+                    EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed),
+                    dev->ifnum, alt,
+                    interval,
+                    ep_size);
+
+       /* Calculate the number and size of URBs to better fit the audio samples */
+
+       /*
+        * Estimate the number of bytes per DMA transfer.
+        *
+        * This is given by the bit rate (for now, only 48000 Hz) multiplied
+        * by 2 channels and 2 bytes/sample divided by the number of microframe
+        * intervals and by the microframe rate (125 us)
+        */
+       bytes_per_transfer = DIV_ROUND_UP(48000 * 2 * 2, 125 * interval);
+
+       /*
+        * Estimate the number of transfer URBs. Don't let it go past the
+        * maximum number of URBs that is known to be supported by the device.
+        */
+       num_urb = DIV_ROUND_UP(bytes_per_transfer, ep_size);
+       if (num_urb > EM28XX_MAX_AUDIO_BUFS)
+               num_urb = EM28XX_MAX_AUDIO_BUFS;
+
+       /*
+        * Now that we know the number of bytes per transfer and the number of
+        * URBs, estimate the typical size of an URB, in order to adjust the
+        * minimal number of packets.
+        */
+       urb_size = bytes_per_transfer / num_urb;
+
+       /*
+        * Now, calculate the amount of audio packets to be filled on each
+        * URB. In order to preserve the old behaviour, use a minimal
+        * threshold for this value.
+        */
+       npackets = EM28XX_MIN_AUDIO_PACKETS;
+       if (urb_size > ep_size * npackets)
+               npackets = DIV_ROUND_UP(urb_size, ep_size);
+
+       em28xx_info("Number of URBs: %d, with %d packets and %d size",
+                   num_urb, npackets, urb_size);
+
+       /* Estimate the bytes per period */
+       dev->adev.period = urb_size * npackets;
+
+       /* Allocate space to store the number of URBs to be used */
+
+       dev->adev.transfer_buffer = kcalloc(num_urb,
+                                           sizeof(*dev->adev.transfer_buffer),
+                                           GFP_ATOMIC);
+       if (!dev->adev.transfer_buffer) {
+               return -ENOMEM;
+       }
+
+       dev->adev.urb = kcalloc(num_urb, sizeof(*dev->adev.urb), GFP_ATOMIC);
+       if (!dev->adev.urb) {
+               kfree(dev->adev.transfer_buffer);
+               return -ENOMEM;
+       }
+
+       /* Alloc memory for each URB and for each transfer buffer */
+       dev->adev.num_urb = num_urb;
+       for (i = 0; i < num_urb; i++) {
+               struct urb *urb;
+               int j, k;
+               void *buf;
+
+               urb = usb_alloc_urb(npackets, GFP_ATOMIC);
+               if (!urb) {
+                       em28xx_errdev("usb_alloc_urb failed!\n");
+                       em28xx_audio_free_urb(dev);
+                       return -ENOMEM;
+               }
+               dev->adev.urb[i] = urb;
+
+               buf = usb_alloc_coherent(dev->udev, npackets * ep_size, GFP_ATOMIC,
+                                        &urb->transfer_dma);
+               if (!buf) {
+                       em28xx_errdev("usb_alloc_coherent failed!\n");
+                       em28xx_audio_free_urb(dev);
+                       return -ENOMEM;
+               }
+               dev->adev.transfer_buffer[i] = buf;
+
+               urb->dev = dev->udev;
+               urb->context = dev;
+               urb->pipe = usb_rcvisocpipe(dev->udev, EM28XX_EP_AUDIO);
+               urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
+               urb->transfer_buffer = buf;
+               urb->interval = interval;
+               urb->complete = em28xx_audio_isocirq;
+               urb->number_of_packets = npackets;
+               urb->transfer_buffer_length = ep_size * npackets;
+
+               for (j = k = 0; j < npackets; j++, k += ep_size) {
+                       urb->iso_frame_desc[j].offset = k;
+                       urb->iso_frame_desc[j].length = ep_size;
+               }
+       }
+
+       return 0;
+}
+
 static int em28xx_audio_init(struct em28xx *dev)
 {
        struct em28xx_audio *adev = &dev->adev;
        struct snd_pcm      *pcm;
        struct snd_card     *card;
        static int          devnr;
-       int                 err;
+       int                 err;
 
-       if (!dev->has_alsa_audio || dev->audio_ifnum < 0) {
+       if (!dev->has_alsa_audio) {
                /* 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) */
                return 0;
        }
 
-       printk(KERN_INFO "em28xx-audio.c: probing for em28xx Audio Vendor Class\n");
+       em28xx_info("Binding audio extension\n");
+
        printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2006 Markus "
                         "Rechberger\n");
-       printk(KERN_INFO "em28xx-audio.c: Copyright (C) 2007-2011 Mauro Carvalho Chehab\n");
+       printk(KERN_INFO
+              "em28xx-audio.c: Copyright (C) 2007-2014 Mauro Carvalho Chehab\n");
 
        err = snd_card_create(index[devnr], "Em28xx Audio", THIS_MODULE, 0,
                              &card);
@@ -660,11 +906,12 @@ static int em28xx_audio_init(struct em28xx *dev)
                return err;
 
        spin_lock_init(&adev->slock);
+       adev->sndcard = card;
+       adev->udev = dev->udev;
+
        err = snd_pcm_new(card, "Em28xx Audio", 0, 0, 1, &pcm);
-       if (err < 0) {
-               snd_card_free(card);
-               return err;
-       }
+       if (err < 0)
+               goto card_free;
 
        snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_em28xx_pcm_capture);
        pcm->info_flags = 0;
@@ -694,15 +941,25 @@ static int em28xx_audio_init(struct em28xx *dev)
                em28xx_cvol_new(card, dev, "Surround", AC97_SURROUND_MASTER);
        }
 
+       err = em28xx_audio_urb_init(dev);
+       if (err)
+               goto card_free;
+
        err = snd_card_register(card);
-       if (err < 0) {
-               snd_card_free(card);
-               return err;
-       }
-       adev->sndcard = card;
-       adev->udev = dev->udev;
+       if (err < 0)
+               goto urb_free;
 
+       em28xx_info("Audio extension successfully initialized\n");
        return 0;
+
+urb_free:
+       em28xx_audio_free_urb(dev);
+
+card_free:
+       snd_card_free(card);
+       adev->sndcard = NULL;
+
+       return err;
 }
 
 static int em28xx_audio_fini(struct em28xx *dev)
@@ -717,7 +974,14 @@ static int em28xx_audio_fini(struct em28xx *dev)
                return 0;
        }
 
+       em28xx_info("Closing audio extension");
+
        if (dev->adev.sndcard) {
+               snd_card_disconnect(dev->adev.sndcard);
+               flush_work(&dev->wq_trigger);
+
+               em28xx_audio_free_urb(dev);
+
                snd_card_free(dev->adev.sndcard);
                dev->adev.sndcard = NULL;
        }
@@ -745,7 +1009,8 @@ static void __exit em28xx_alsa_unregister(void)
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Markus Rechberger <mrechberger@gmail.com>");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Em28xx Audio driver");
+MODULE_DESCRIPTION(DRIVER_DESC " - audio interface");
+MODULE_VERSION(EM28XX_VERSION);
 
 module_init(em28xx_alsa_register);
 module_exit(em28xx_alsa_unregister);
index d666741797d4e690fbd6a62aa2141cd50ec1e507..c29f5c4e7b4074858503d0ef876540a0ede66db1 100644 (file)
@@ -454,3 +454,4 @@ int em28xx_init_camera(struct em28xx *dev)
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(em28xx_init_camera);
index a5196697627f3be4098d849111731b352f989e0f..4d97a76cc3b085cd20b274a90db73e4049218439 100644 (file)
@@ -36,7 +36,6 @@
 #include <media/tvaudio.h>
 #include <media/i2c-addr.h>
 #include <media/tveeprom.h>
-#include <media/v4l2-clk.h>
 #include <media/v4l2-common.h>
 
 #include "em28xx.h"
@@ -67,7 +66,7 @@ MODULE_PARM_DESC(usb_xfer_mode,
 
 
 /* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */
-static unsigned long em28xx_devused;
+DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS);
 
 struct em28xx_hash_table {
        unsigned long hash;
@@ -356,6 +355,28 @@ static struct em28xx_reg_seq c3tech_digital_duo_digital[] = {
        {       -1,                     -1,     -1,     -1},
 };
 
+/*
+ * 2013:0258 PCTV DVB-S2 Stick (461e)
+ * GPIO 0 = POWER_ON
+ * GPIO 1 = BOOST
+ * GPIO 2 = VUV_LNB (red LED)
+ * GPIO 3 = #EXT_12V
+ * GPIO 4 = INT_DEM
+ * GPIO 5 = INT_LNB
+ * GPIO 6 = #RESET_DEM
+ * GPIO 7 = P07_LED (green LED)
+ */
+static struct em28xx_reg_seq pctv_461e[] = {
+       {EM2874_R80_GPIO_P0_CTRL,      0x7f, 0xff,    0},
+       {0x0d,                 0xff, 0xff,    0},
+       {EM2874_R80_GPIO_P0_CTRL,      0x3f, 0xff,  100}, /* reset demod */
+       {EM2874_R80_GPIO_P0_CTRL,      0x7f, 0xff,  200}, /* reset demod */
+       {0x0d,                 0x42, 0xff,    0},
+       {EM2874_R80_GPIO_P0_CTRL,      0xeb, 0xff,    0},
+       {EM2874_R5F_TS_ENABLE, 0x84, 0x84,    0}, /* parallel? | null discard */
+       {                  -1,   -1,   -1,   -1},
+};
+
 #if 0
 static struct em28xx_reg_seq hauppauge_930c_gpio[] = {
        {EM2874_R80_GPIO_P0_CTRL,       0x6f,   0xff,   10},
@@ -412,6 +433,70 @@ static struct em28xx_reg_seq pctv_520e[] = {
        {       -1,                     -1,     -1,     -1},
 };
 
+/* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
+ * reg 0x80/0x84:
+ * GPIO_0: capturing LED, 0=on, 1=off
+ * GPIO_2: AV mute button, 0=pressed, 1=unpressed
+ * GPIO 3: illumination button, 0=pressed, 1=unpressed
+ * GPIO_6: illumination/flash LED, 0=on, 1=off
+ * reg 0x81/0x85:
+ * GPIO_7: snapshot button, 0=pressed, 1=unpressed
+ */
+static struct em28xx_reg_seq speedlink_vad_laplace_reg_seq[] = {
+       {EM2820_R08_GPIO_CTRL,          0xf7,   0xff,   10},
+       {EM2874_R80_GPIO_P0_CTRL,       0xff,   0xb2,   10},
+       {       -1,                     -1,     -1,     -1},
+};
+
+/*
+ *  Button definitions
+ */
+static struct em28xx_button std_snapshot_button[] = {
+       {
+               .role         = EM28XX_BUTTON_SNAPSHOT,
+               .reg_r        = EM28XX_R0C_USBSUSP,
+               .reg_clearing = EM28XX_R0C_USBSUSP,
+               .mask         = EM28XX_R0C_USBSUSP_SNAPSHOT,
+               .inverted     = 0,
+       },
+       {-1, 0, 0, 0, 0},
+};
+
+static struct em28xx_button speedlink_vad_laplace_buttons[] = {
+       {
+               .role     = EM28XX_BUTTON_SNAPSHOT,
+               .reg_r    = EM2874_R85_GPIO_P1_STATE,
+               .mask     = 0x80,
+               .inverted = 1,
+       },
+       {
+               .role     = EM28XX_BUTTON_ILLUMINATION,
+               .reg_r    = EM2874_R84_GPIO_P0_STATE,
+               .mask     = 0x08,
+               .inverted = 1,
+       },
+       {-1, 0, 0, 0, 0},
+};
+
+/*
+ *  LED definitions
+ */
+static struct em28xx_led speedlink_vad_laplace_leds[] = {
+       {
+               .role      = EM28XX_LED_ANALOG_CAPTURING,
+               .gpio_reg  = EM2874_R80_GPIO_P0_CTRL,
+               .gpio_mask = 0x01,
+               .inverted  = 1,
+       },
+       {
+               .role      = EM28XX_LED_ILLUMINATION,
+               .gpio_reg  = EM2874_R80_GPIO_P0_CTRL,
+               .gpio_mask = 0x40,
+               .inverted  = 1,
+       },
+       {-1, 0, 0, 0},
+};
+
 /*
  *  Board definitions
  */
@@ -1391,7 +1476,7 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2820_BOARD_PROLINK_PLAYTV_USB2] = {
                .name         = "SIIG AVTuner-PVR / Pixelview Prolink PlayTV USB 2.0",
-               .has_snapshot_button = 1,
+               .buttons = std_snapshot_button,
                .tda9887_conf = TDA9887_PRESENT,
                .tuner_type   = TUNER_YMEC_TVF_5533MF,
                .decoder      = EM28XX_SAA711X,
@@ -1413,7 +1498,7 @@ struct em28xx_board em28xx_boards[] = {
        },
        [EM2860_BOARD_SAA711X_REFERENCE_DESIGN] = {
                .name                = "EM2860/SAA711X Reference Design",
-               .has_snapshot_button = 1,
+               .buttons = std_snapshot_button,
                .tuner_type          = TUNER_ABSENT,
                .decoder             = EM28XX_SAA711X,
                .input               = { {
@@ -2020,7 +2105,7 @@ struct em28xx_board em28xx_boards[] = {
        },
        /* 1b80:e1cc Delock 61959
         * Empia EM2874B + Micronas DRX 3913KA2 + NXP TDA18271HDC2
-         * mostly the same as MaxMedia UB-425-TC but different remote */
+        * mostly the same as MaxMedia UB-425-TC but different remote */
        [EM2874_BOARD_DELOCK_61959] = {
                .name          = "Delock 61959",
                .tuner_type    = TUNER_ABSENT,
@@ -2043,7 +2128,38 @@ struct em28xx_board em28xx_boards[] = {
                .tuner_gpio     = default_tuner_gpio,
                .def_i2c_bus    = 1,
        },
+       /* 1ae7:9003/9004 SpeedLink Vicious And Devine Laplace webcam
+        * Empia EM2765 + OmniVision OV2640 */
+       [EM2765_BOARD_SPEEDLINK_VAD_LAPLACE] = {
+               .name         = "SpeedLink Vicious And Devine Laplace webcam",
+               .xclk         = EM28XX_XCLK_FREQUENCY_24MHZ,
+               .i2c_speed    = EM28XX_I2C_CLK_WAIT_ENABLE |
+                               EM28XX_I2C_FREQ_100_KHZ,
+               .def_i2c_bus  = 1,
+               .tuner_type   = TUNER_ABSENT,
+               .is_webcam    = 1,
+               .input        = { {
+                       .type     = EM28XX_VMUX_COMPOSITE1,
+                       .amux     = EM28XX_AMUX_VIDEO,
+                       .gpio     = speedlink_vad_laplace_reg_seq,
+               } },
+               .buttons = speedlink_vad_laplace_buttons,
+               .leds = speedlink_vad_laplace_leds,
+       },
+       /* 2013:0258 PCTV DVB-S2 Stick (461e)
+        * Empia EM28178, Montage M88DS3103, Montage M88TS2022, Allegro A8293 */
+       [EM28178_BOARD_PCTV_461E] = {
+               .def_i2c_bus   = 1,
+               .i2c_speed     = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+               .name          = "PCTV DVB-S2 Stick (461e)",
+               .tuner_type    = TUNER_ABSENT,
+               .tuner_gpio    = pctv_461e,
+               .has_dvb       = 1,
+               .ir_codes      = RC_MAP_PINNACLE_PCTV_HD,
+       },
 };
+EXPORT_SYMBOL_GPL(em28xx_boards);
+
 const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
 
 /* table of devices that work with this driver */
@@ -2208,6 +2324,12 @@ struct usb_device_id em28xx_id_table[] = {
                        .driver_info = EM2884_BOARD_PCTV_520E },
        { USB_DEVICE(0x1b80, 0xe1cc),
                        .driver_info = EM2874_BOARD_DELOCK_61959 },
+       { USB_DEVICE(0x1ae7, 0x9003),
+                       .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
+       { USB_DEVICE(0x1ae7, 0x9004),
+                       .driver_info = EM2765_BOARD_SPEEDLINK_VAD_LAPLACE },
+       { USB_DEVICE(0x2013, 0x0258),
+                       .driver_info = EM28178_BOARD_PCTV_461E },
        { },
 };
 MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2239,24 +2361,6 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
 };
 /* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
 
-/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
-static unsigned short saa711x_addrs[] = {
-       0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
-       0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
-       I2C_CLIENT_END };
-
-static unsigned short tvp5150_addrs[] = {
-       0xb8 >> 1,
-       0xba >> 1,
-       I2C_CLIENT_END
-};
-
-static unsigned short msp3400_addrs[] = {
-       0x80 >> 1,
-       0x88 >> 1,
-       I2C_CLIENT_END
-};
-
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
 {
        struct em28xx_i2c_bus *i2c_bus = ptr;
@@ -2408,113 +2512,6 @@ static void em28xx_pre_card_setup(struct em28xx *dev)
        em28xx_set_mode(dev, EM28XX_SUSPEND);
 }
 
-static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
-{
-       memset(ctl, 0, sizeof(*ctl));
-
-       ctl->fname   = XC2028_DEFAULT_FIRMWARE;
-       ctl->max_len = 64;
-       ctl->mts = em28xx_boards[dev->model].mts_firmware;
-
-       switch (dev->model) {
-       case EM2880_BOARD_EMPIRE_DUAL_TV:
-       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
-       case EM2882_BOARD_TERRATEC_HYBRID_XS:
-               ctl->demod = XC3028_FE_ZARLINK456;
-               break;
-       case EM2880_BOARD_TERRATEC_HYBRID_XS:
-       case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
-       case EM2881_BOARD_PINNACLE_HYBRID_PRO:
-               ctl->demod = XC3028_FE_ZARLINK456;
-               break;
-       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
-       case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
-               ctl->demod = XC3028_FE_DEFAULT;
-               break;
-       case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
-               ctl->demod = XC3028_FE_DEFAULT;
-               ctl->fname = XC3028L_DEFAULT_FIRMWARE;
-               break;
-       case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
-       case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
-       case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
-               /* FIXME: Better to specify the needed IF */
-               ctl->demod = XC3028_FE_DEFAULT;
-               break;
-       case EM2883_BOARD_KWORLD_HYBRID_330U:
-       case EM2882_BOARD_DIKOM_DK300:
-       case EM2882_BOARD_KWORLD_VS_DVBT:
-               ctl->demod = XC3028_FE_CHINA;
-               ctl->fname = XC2028_DEFAULT_FIRMWARE;
-               break;
-       case EM2882_BOARD_EVGA_INDTUBE:
-               ctl->demod = XC3028_FE_CHINA;
-               ctl->fname = XC3028L_DEFAULT_FIRMWARE;
-               break;
-       default:
-               ctl->demod = XC3028_FE_OREN538;
-       }
-}
-
-static void em28xx_tuner_setup(struct em28xx *dev)
-{
-       struct tuner_setup           tun_setup;
-       struct v4l2_frequency        f;
-
-       if (dev->tuner_type == TUNER_ABSENT)
-               return;
-
-       memset(&tun_setup, 0, sizeof(tun_setup));
-
-       tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
-       tun_setup.tuner_callback = em28xx_tuner_callback;
-
-       if (dev->board.radio.type) {
-               tun_setup.type = dev->board.radio.type;
-               tun_setup.addr = dev->board.radio_addr;
-
-               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
-       }
-
-       if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
-               tun_setup.type   = dev->tuner_type;
-               tun_setup.addr   = dev->tuner_addr;
-
-               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
-       }
-
-       if (dev->tda9887_conf) {
-               struct v4l2_priv_tun_config tda9887_cfg;
-
-               tda9887_cfg.tuner = TUNER_TDA9887;
-               tda9887_cfg.priv = &dev->tda9887_conf;
-
-               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
-       }
-
-       if (dev->tuner_type == TUNER_XC2028) {
-               struct v4l2_priv_tun_config  xc2028_cfg;
-               struct xc2028_ctrl           ctl;
-
-               memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
-               memset(&ctl, 0, sizeof(ctl));
-
-               em28xx_setup_xc3028(dev, &ctl);
-
-               xc2028_cfg.tuner = TUNER_XC2028;
-               xc2028_cfg.priv  = &ctl;
-
-               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
-       }
-
-       /* configure tuner */
-       f.tuner = 0;
-       f.type = V4L2_TUNER_ANALOG_TV;
-       f.frequency = 9076;     /* just a magic number */
-       dev->ctl_freq = f.frequency;
-       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
-}
-
 static int em28xx_hint_board(struct em28xx *dev)
 {
        int i;
@@ -2768,57 +2765,56 @@ static void em28xx_card_setup(struct em28xx *dev)
        /* Allow override tuner type by a module parameter */
        if (tuner >= 0)
                dev->tuner_type = tuner;
+}
 
-       /* request some modules */
-       if (dev->board.has_msp34xx)
-               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-                       "msp3400", 0, msp3400_addrs);
-
-       if (dev->board.decoder == EM28XX_SAA711X)
-               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-                       "saa7115_auto", 0, saa711x_addrs);
-
-       if (dev->board.decoder == EM28XX_TVP5150)
-               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-                       "tvp5150", 0, tvp5150_addrs);
-
-       if (dev->board.adecoder == EM28XX_TVAUDIO)
-               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-                       "tvaudio", dev->board.tvaudio_addr, NULL);
-
-       if (dev->board.tuner_type != TUNER_ABSENT) {
-               int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
-
-               if (dev->board.radio.type)
-                       v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-                               "tuner", dev->board.radio_addr, NULL);
-
-               if (has_demod)
-                       v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_adap[dev->def_i2c_bus], "tuner",
-                               0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
-               if (dev->tuner_addr == 0) {
-                       enum v4l2_i2c_tuner_type type =
-                               has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
-                       struct v4l2_subdev *sd;
-
-                       sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
-                               &dev->i2c_adap[dev->def_i2c_bus], "tuner",
-                               0, v4l2_i2c_tuner_addrs(type));
-
-                       if (sd)
-                               dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
-               } else {
-                       v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
-                               "tuner", dev->tuner_addr, NULL);
-               }
-       }
+void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
+{
+       memset(ctl, 0, sizeof(*ctl));
 
-       em28xx_tuner_setup(dev);
+       ctl->fname   = XC2028_DEFAULT_FIRMWARE;
+       ctl->max_len = 64;
+       ctl->mts = em28xx_boards[dev->model].mts_firmware;
 
-       em28xx_init_camera(dev);
+       switch (dev->model) {
+       case EM2880_BOARD_EMPIRE_DUAL_TV:
+       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+       case EM2882_BOARD_TERRATEC_HYBRID_XS:
+               ctl->demod = XC3028_FE_ZARLINK456;
+               break;
+       case EM2880_BOARD_TERRATEC_HYBRID_XS:
+       case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
+       case EM2881_BOARD_PINNACLE_HYBRID_PRO:
+               ctl->demod = XC3028_FE_ZARLINK456;
+               break;
+       case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900_R2:
+       case EM2882_BOARD_PINNACLE_HYBRID_PRO_330E:
+               ctl->demod = XC3028_FE_DEFAULT;
+               break;
+       case EM2880_BOARD_AMD_ATI_TV_WONDER_HD_600:
+               ctl->demod = XC3028_FE_DEFAULT;
+               ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+               break;
+       case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
+       case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
+       case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
+               /* FIXME: Better to specify the needed IF */
+               ctl->demod = XC3028_FE_DEFAULT;
+               break;
+       case EM2883_BOARD_KWORLD_HYBRID_330U:
+       case EM2882_BOARD_DIKOM_DK300:
+       case EM2882_BOARD_KWORLD_VS_DVBT:
+               ctl->demod = XC3028_FE_CHINA;
+               ctl->fname = XC2028_DEFAULT_FIRMWARE;
+               break;
+       case EM2882_BOARD_EVGA_INDTUBE:
+               ctl->demod = XC3028_FE_CHINA;
+               ctl->fname = XC3028L_DEFAULT_FIRMWARE;
+               break;
+       default:
+               ctl->demod = XC3028_FE_OREN538;
+       }
 }
-
+EXPORT_SYMBOL_GPL(em28xx_setup_xc3028);
 
 static void request_module_async(struct work_struct *work)
 {
@@ -2831,17 +2827,30 @@ static void request_module_async(struct work_struct *work)
         * can be initialised right now. Otherwise, the module init
         * code will do it.
         */
+
+       /*
+        * Devicdes with an audio-only interface also have a V4L/DVB/RC
+        * interface. Don't register extensions twice on those devices.
+        */
+       if (dev->is_audio_only) {
+#if defined(CONFIG_MODULES) && defined(MODULE)
+               request_module("em28xx-alsa");
+#endif
+               return;
+       }
+
        em28xx_init_extension(dev);
 
 #if defined(CONFIG_MODULES) && defined(MODULE)
+       if (dev->has_video)
+               request_module("em28xx-v4l");
        if (dev->has_audio_class)
                request_module("snd-usb-audio");
        else if (dev->has_alsa_audio)
                request_module("em28xx-alsa");
-
        if (dev->board.has_dvb)
                request_module("em28xx-dvb");
-       if (dev->board.has_snapshot_button ||
+       if (dev->board.buttons ||
            ((dev->board.ir_codes || dev->board.has_ir_i2c) && !disable_ir))
                request_module("em28xx-rc");
 #endif /* CONFIG_MODULES */
@@ -2867,23 +2876,20 @@ void em28xx_release_resources(struct em28xx *dev)
 {
        /*FIXME: I2C IR should be disconnected */
 
-       em28xx_release_analog_resources(dev);
+       mutex_lock(&dev->lock);
 
        if (dev->def_i2c_bus)
                em28xx_i2c_unregister(dev, 1);
        em28xx_i2c_unregister(dev, 0);
-       if (dev->clk)
-               v4l2_clk_unregister_fixed(dev->clk);
-
-       v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
-       v4l2_device_unregister(&dev->v4l2_dev);
 
        usb_put_dev(dev->udev);
 
        /* Mark device as unused */
-       clear_bit(dev->devno, &em28xx_devused);
+       clear_bit(dev->devno, em28xx_devused);
+
+       mutex_unlock(&dev->lock);
 };
+EXPORT_SYMBOL_GPL(em28xx_release_resources);
 
 /*
  * em28xx_init_dev()
@@ -2893,7 +2899,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                           struct usb_interface *interface,
                           int minor)
 {
-       struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
        int retval;
        static const char *default_chip_name = "em28xx";
        const char *chip_name = default_chip_name;
@@ -2968,6 +2973,11 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                        dev->wait_after_write = 0;
                        dev->eeprom_addrwidth_16bit = 1;
                        break;
+               case CHIP_ID_EM28178:
+                       chip_name = "em28178";
+                       dev->wait_after_write = 0;
+                       dev->eeprom_addrwidth_16bit = 1;
+                       break;
                case CHIP_ID_EM2883:
                        chip_name = "em2882/3";
                        dev->wait_after_write = 0;
@@ -2983,6 +2993,16 @@ 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);
@@ -3015,15 +3035,6 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                }
        }
 
-       retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
-       if (retval < 0) {
-               em28xx_errdev("Call to v4l2_device_register() failed!\n");
-               return retval;
-       }
-
-       v4l2_ctrl_handler_init(hdl, 8);
-       dev->v4l2_dev.ctrl_handler = hdl;
-
        rt_mutex_init(&dev->i2c_bus_lock);
 
        /* register i2c bus 0 */
@@ -3034,7 +3045,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
        if (retval < 0) {
                em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
                        __func__, retval);
-               goto unregister_dev;
+               return retval;
        }
 
        /* register i2c bus 1 */
@@ -3048,88 +3059,17 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
                if (retval < 0) {
                        em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
                                __func__, retval);
-                       goto unregister_dev;
-               }
-       }
-
-       /*
-        * Default format, used for tvp5150 or saa711x output formats
-        */
-       dev->vinmode = 0x10;
-       dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
-                      EM28XX_VINCTRL_CCIR656_ENABLE;
 
-       /* Do board specific init and eeprom reading */
-       em28xx_card_setup(dev);
+                       em28xx_i2c_unregister(dev, 0);
 
-       /* Configure audio */
-       retval = em28xx_audio_setup(dev);
-       if (retval < 0) {
-               em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
-                       __func__, retval);
-               goto fail;
-       }
-       if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
-               v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
-                       V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
-               v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
-                       V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
-       } else {
-               /* install the em28xx notify callback */
-               v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
-                               em28xx_ctrl_notify, dev);
-               v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
-                               em28xx_ctrl_notify, dev);
-       }
-
-       /* wake i2c devices */
-       em28xx_wake_i2c(dev);
-
-       /* init video dma queues */
-       INIT_LIST_HEAD(&dev->vidq.active);
-       INIT_LIST_HEAD(&dev->vbiq.active);
-
-       if (dev->board.has_msp34xx) {
-               /* Send a reset to other chips via gpio */
-               retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
-               if (retval < 0) {
-                       em28xx_errdev("%s: em28xx_write_reg - "
-                                     "msp34xx(1) failed! error [%d]\n",
-                                     __func__, retval);
-                       goto fail;
-               }
-               msleep(3);
-
-               retval = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
-               if (retval < 0) {
-                       em28xx_errdev("%s: em28xx_write_reg - "
-                                     "msp34xx(2) failed! error [%d]\n",
-                                     __func__, retval);
-                       goto fail;
+                       return retval;
                }
-               msleep(3);
-       }
-
-       retval = em28xx_register_analog_devices(dev);
-       if (retval < 0) {
-               goto fail;
        }
 
-       /* Save some power by putting tuner to sleep */
-       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+       /* Do board specific init and eeprom reading */
+       em28xx_card_setup(dev);
 
        return 0;
-
-fail:
-       if (dev->def_i2c_bus)
-               em28xx_i2c_unregister(dev, 1);
-       em28xx_i2c_unregister(dev, 0);
-       v4l2_ctrl_handler_free(&dev->ctrl_handler);
-
-unregister_dev:
-       v4l2_device_unregister(&dev->v4l2_dev);
-
-       return retval;
 }
 
 /* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
@@ -3154,7 +3094,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 
        /* Check to see next free device and mark as used */
        do {
-               nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+               nr = find_first_zero_bit(em28xx_devused, EM28XX_MAXBOARDS);
                if (nr >= EM28XX_MAXBOARDS) {
                        /* No free device slots */
                        printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
@@ -3162,7 +3102,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
                        retval = -ENOMEM;
                        goto err_no_slot;
                }
-       } while (test_and_set_bit(nr, &em28xx_devused));
+       } while (test_and_set_bit(nr, em28xx_devused));
 
        /* Don't register audio interfaces */
        if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
@@ -3332,7 +3272,9 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        dev->alt   = -1;
        dev->is_audio_only = has_audio && !(has_video || has_dvb);
        dev->has_alsa_audio = has_audio;
-       dev->audio_ifnum = ifnum;
+       dev->audio_mode.has_audio = has_audio;
+       dev->has_video = has_video;
+       dev->ifnum = ifnum;
 
        /* Checks if audio is provided by some interface */
        for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
@@ -3369,15 +3311,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        /* save our data pointer in this interface device */
        usb_set_intfdata(interface, dev);
 
-       /* initialize videobuf2 stuff */
-       em28xx_vb2_setup(dev);
-
        /* allocate device struct */
        mutex_init(&dev->lock);
-       mutex_lock(&dev->lock);
        retval = em28xx_init_dev(dev, udev, interface, nr);
        if (retval) {
-               goto unlock_and_free;
+               goto err_free;
        }
 
        if (usb_xfer_mode < 0) {
@@ -3402,26 +3340,6 @@ static int em28xx_usb_probe(struct usb_interface *interface,
 
                em28xx_info("dvb set to %s mode.\n",
                            dev->dvb_xfer_bulk ? "bulk" : "isoc");
-
-               /* pre-allocate DVB usb transfer buffers */
-               if (dev->dvb_xfer_bulk) {
-                       retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
-                                           dev->dvb_xfer_bulk,
-                                           EM28XX_DVB_NUM_BUFS,
-                                           512,
-                                           EM28XX_DVB_BULK_PACKET_MULTIPLIER);
-               } else {
-                       retval = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
-                                           dev->dvb_xfer_bulk,
-                                           EM28XX_DVB_NUM_BUFS,
-                                           dev->dvb_max_pkt_size_isoc,
-                                           EM28XX_DVB_NUM_ISOC_PACKETS);
-               }
-               if (retval) {
-                       printk(DRIVER_NAME
-                              ": Failed to pre-allocate USB transfer buffers for DVB.\n");
-                       goto unlock_and_free;
-               }
        }
 
        request_modules(dev);
@@ -3429,19 +3347,15 @@ static int em28xx_usb_probe(struct usb_interface *interface,
        /* Should be the last thing to do, to avoid newer udev's to
           open the device before fully initializing it
         */
-       mutex_unlock(&dev->lock);
 
        return 0;
 
-unlock_and_free:
-       mutex_unlock(&dev->lock);
-
 err_free:
        kfree(dev->alt_max_pkt_size_isoc);
        kfree(dev);
 
 err:
-       clear_bit(nr, &em28xx_devused);
+       clear_bit(nr, em28xx_devused);
 
 err_no_slot:
        usb_put_dev(udev);
@@ -3465,36 +3379,13 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
 
        dev->disconnected = 1;
 
-       if (dev->is_audio_only) {
-               mutex_lock(&dev->lock);
-               em28xx_close_extension(dev);
-               mutex_unlock(&dev->lock);
-               return;
-       }
-
-       em28xx_info("disconnecting %s\n", dev->vdev->name);
+       em28xx_info("Disconnecting %s\n", dev->name);
 
        flush_request_modules(dev);
 
-       mutex_lock(&dev->lock);
-
-       v4l2_device_disconnect(&dev->v4l2_dev);
-
-       if (dev->users) {
-               em28xx_warn("device %s is open! Deregistration and memory deallocation are deferred on close.\n",
-                           video_device_node_name(dev->vdev));
-
-               em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
-               em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
-       }
-
        em28xx_close_extension(dev);
-       /* NOTE: must be called BEFORE the resources are released */
-
-       if (!dev->users)
-               em28xx_release_resources(dev);
 
-       mutex_unlock(&dev->lock);
+       em28xx_release_resources(dev);
 
        if (!dev->users) {
                kfree(dev->alt_max_pkt_size_isoc);
index fc157af5234a3e2c82c83dbd3f6d498758b96589..898fb9bd88a279db1cec20f44dc952eb4a721254 100644 (file)
@@ -23,6 +23,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/jiffies.h>
 #include <linux/list.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 
 #include "em28xx.h"
 
+#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
+                     "Markus Rechberger <mrechberger@gmail.com>, " \
+                     "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
+                     "Sascha Sommer <saschasommer@freenet.de>"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_VERSION(EM28XX_VERSION);
+
 /* #define ENABLE_DEBUG_ISOC_FRAMES */
 
 static unsigned int core_debug;
@@ -53,14 +64,6 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
                printk(KERN_INFO "%s %s :"fmt, \
                         dev->name, __func__ , ##arg); } while (0)
 
-static int alt;
-module_param(alt, int, 0644);
-MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
-
-static unsigned int disable_vbi;
-module_param(disable_vbi, int, 0644);
-MODULE_PARM_DESC(disable_vbi, "disable vbi support");
-
 /* FIXME */
 #define em28xx_isocdbg(fmt, arg...) do {\
        if (core_debug) \
@@ -225,22 +228,43 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
 }
 EXPORT_SYMBOL_GPL(em28xx_write_reg_bits);
 
+/*
+ * em28xx_toggle_reg_bits()
+ * toggles/inverts the bits (specified by bitmask) of a register
+ */
+int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask)
+{
+       int oldval;
+       u8 newval;
+
+       oldval = em28xx_read_reg(dev, reg);
+       if (oldval < 0)
+               return oldval;
+
+       newval = (~oldval & bitmask) | (oldval & ~bitmask);
+
+       return em28xx_write_reg(dev, reg, newval);
+}
+EXPORT_SYMBOL_GPL(em28xx_toggle_reg_bits);
+
 /*
  * em28xx_is_ac97_ready()
  * Checks if ac97 is ready
  */
 static int em28xx_is_ac97_ready(struct em28xx *dev)
 {
-       int ret, i;
+       unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_AC97_XFER_TIMEOUT);
+       int ret;
 
        /* Wait up to 50 ms for AC97 command to complete */
-       for (i = 0; i < 10; i++, msleep(5)) {
+       while (time_is_after_jiffies(timeout)) {
                ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
                if (ret < 0)
                        return ret;
 
                if (!(ret & 0x01))
                        return 0;
+               msleep(5);
        }
 
        em28xx_warn("AC97 command still being executed: not handled properly!\n");
@@ -482,16 +506,8 @@ int em28xx_audio_setup(struct em28xx *dev)
        int vid1, vid2, feat, cfg;
        u32 vid;
 
-       if (dev->chip_id == CHIP_ID_EM2870 || dev->chip_id == CHIP_ID_EM2874
-               || dev->chip_id == CHIP_ID_EM28174) {
-               /* 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 (!dev->audio_mode.has_audio)
                return 0;
-       }
-
-       dev->audio_mode.has_audio = true;
 
        /* See how this device is configured */
        cfg = em28xx_read_reg(dev, EM28XX_R00_CHIPCFG);
@@ -504,17 +520,19 @@ int em28xx_audio_setup(struct em28xx *dev)
                dev->has_alsa_audio = false;
                dev->audio_mode.has_audio = false;
                return 0;
-       } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
-                  EM28XX_CHIPCFG_I2S_3_SAMPRATES) {
-               em28xx_info("I2S Audio (3 sample rates)\n");
-               dev->audio_mode.i2s_3rates = 1;
-       } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
-                  EM28XX_CHIPCFG_I2S_5_SAMPRATES) {
-               em28xx_info("I2S Audio (5 sample rates)\n");
-               dev->audio_mode.i2s_5rates = 1;
-       }
-
-       if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+       } else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
+               if (dev->chip_id < CHIP_ID_EM2860 &&
+                   (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+                   EM2820_CHIPCFG_I2S_1_SAMPRATE)
+                       dev->audio_mode.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;
+               else
+                       dev->audio_mode.i2s_samplerates = 3;
+               em28xx_info("I2S Audio (%d sample rate(s))\n",
+                                              dev->audio_mode.i2s_samplerates);
                /* Skip the code that does AC97 vendor detection */
                dev->audio_mode.ac97 = EM28XX_NO_AC97;
                goto init_audio;
@@ -582,23 +600,21 @@ init_audio:
 }
 EXPORT_SYMBOL_GPL(em28xx_audio_setup);
 
-int em28xx_colorlevels_set_default(struct em28xx *dev)
+const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
+                                        enum em28xx_led_role role)
 {
-       em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
-       em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
-       em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
-       em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
-       em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
-       em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
-
-       em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
-       em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
-       em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
-       em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
-       em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
-       em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
-       return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
+       if (dev->board.leds) {
+               u8 k = 0;
+               while (dev->board.leds[k].role >= 0 &&
+                              dev->board.leds[k].role < EM28XX_NUM_LED_ROLES) {
+                       if (dev->board.leds[k].role == role)
+                               return &dev->board.leds[k];
+                       k++;
+               }
+       }
+       return NULL;
 }
+EXPORT_SYMBOL_GPL(em28xx_find_led);
 
 int em28xx_capture_start(struct em28xx *dev, int start)
 {
@@ -606,271 +622,57 @@ int em28xx_capture_start(struct em28xx *dev, int start)
 
        if (dev->chip_id == CHIP_ID_EM2874 ||
            dev->chip_id == CHIP_ID_EM2884 ||
-           dev->chip_id == CHIP_ID_EM28174) {
+           dev->chip_id == CHIP_ID_EM28174 ||
+           dev->chip_id == CHIP_ID_EM28178) {
                /* The Transport Stream Enable Register moved in em2874 */
-               if (!start) {
-                       rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
-                                                  0x00,
-                                                  EM2874_TS1_CAPTURE_ENABLE);
-                       return rc;
-               }
-
-               /* Enable Transport Stream */
                rc = em28xx_write_reg_bits(dev, EM2874_R5F_TS_ENABLE,
-                                          EM2874_TS1_CAPTURE_ENABLE,
+                                          start ?
+                                              EM2874_TS1_CAPTURE_ENABLE : 0x00,
                                           EM2874_TS1_CAPTURE_ENABLE);
-               return rc;
-       }
-
-
-       /* FIXME: which is the best order? */
-       /* video registers are sampled by VREF */
-       rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
-                                  start ? 0x10 : 0x00, 0x10);
-       if (rc < 0)
-               return rc;
-
-       if (!start) {
-               /* disable video capture */
-               rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
-               return rc;
-       }
-
-       if (dev->board.is_webcam)
-               rc = em28xx_write_reg(dev, 0x13, 0x0c);
-
-       /* enable video capture */
-       rc = em28xx_write_reg(dev, 0x48, 0x00);
-
-       if (dev->mode == EM28XX_ANALOG_MODE)
-               rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x67);
-       else
-               rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x37);
-
-       msleep(6);
-
-       return rc;
-}
-
-int em28xx_vbi_supported(struct em28xx *dev)
-{
-       /* Modprobe option to manually disable */
-       if (disable_vbi == 1)
-               return 0;
-
-       if (dev->board.is_webcam)
-               return 0;
-
-       /* FIXME: check subdevices for VBI support */
-
-       if (dev->chip_id == CHIP_ID_EM2860 ||
-           dev->chip_id == CHIP_ID_EM2883)
-               return 1;
-
-       /* Version of em28xx that does not support VBI */
-       return 0;
-}
-
-int em28xx_set_outfmt(struct em28xx *dev)
-{
-       int ret;
-       u8 fmt, vinctrl;
-
-       fmt = dev->format->reg;
-       if (!dev->is_em25xx)
-               fmt |= 0x20;
-       /*
-        * NOTE: it's not clear if this is really needed !
-        * The datasheets say bit 5 is a reserved bit and devices seem to work
-        * fine without it. But the Windows driver sets it for em2710/50+em28xx
-        * devices and we've always been setting it, too.
-        *
-        * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
-        * it's likely used for an additional (compressed ?) format there.
-        */
-       ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
-       if (ret < 0)
-               return ret;
-
-       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
-       if (ret < 0)
-               return ret;
-
-       vinctrl = dev->vinctl;
-       if (em28xx_vbi_supported(dev) == 1) {
-               vinctrl |= EM28XX_VINCTRL_VBI_RAW;
-               em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
-               em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
-               em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
-               if (dev->norm & V4L2_STD_525_60) {
-                       /* NTSC */
-                       em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
-               } else if (dev->norm & V4L2_STD_625_50) {
-                       /* PAL */
-                       em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
-               }
-       }
-
-       return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
-}
-
-static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
-                                 u8 ymin, u8 ymax)
-{
-       em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
-                       xmin, ymin, xmax, ymax);
-
-       em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
-       em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
-       em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
-       return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
-}
-
-static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
-                                  u16 width, u16 height)
-{
-       u8 cwidth = width >> 2;
-       u8 cheight = height >> 2;
-       u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
-       /* NOTE: size limit: 2047x1023 = 2MPix */
-
-       em28xx_coredbg("capture area set to (%d,%d): %dx%d\n",
-                      hstart, vstart,
-                      ((overflow & 2) << 9 | cwidth << 2),
-                      ((overflow & 1) << 10 | cheight << 2));
-
-       em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
-       em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
-       em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
-       em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
-       em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
-
-       /* FIXME: function/meaning of these registers ? */
-       /* FIXME: align width+height to multiples of 4 ?! */
-       if (dev->is_em25xx) {
-               em28xx_write_reg(dev, 0x34, width >> 4);
-               em28xx_write_reg(dev, 0x35, height >> 4);
-       }
-}
-
-static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
-{
-       u8 mode;
-       /* the em2800 scaler only supports scaling down to 50% */
-
-       if (dev->board.is_em2800) {
-               mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
        } else {
-               u8 buf[2];
-
-               buf[0] = h;
-               buf[1] = h >> 8;
-               em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
-
-               buf[0] = v;
-               buf[1] = v >> 8;
-               em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
-               /* it seems that both H and V scalers must be active
-                  to work correctly */
-               mode = (h || v) ? 0x30 : 0x00;
-       }
-       return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
-}
-
-/* FIXME: this only function read values from dev */
-int em28xx_resolution_set(struct em28xx *dev)
-{
-       int width, height;
-       width = norm_maxw(dev);
-       height = norm_maxh(dev);
-
-       /* Properly setup VBI */
-       dev->vbi_width = 720;
-       if (dev->norm & V4L2_STD_525_60)
-               dev->vbi_height = 12;
-       else
-               dev->vbi_height = 18;
-
-       em28xx_set_outfmt(dev);
+               /* FIXME: which is the best order? */
+               /* video registers are sampled by VREF */
+               rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
+                                          start ? 0x10 : 0x00, 0x10);
+               if (rc < 0)
+                       return rc;
 
-       em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+               if (start) {
+                       if (dev->board.is_webcam)
+                               rc = em28xx_write_reg(dev, 0x13, 0x0c);
 
-       /* If we don't set the start position to 2 in VBI mode, we end up
-          with line 20/21 being YUYV encoded instead of being in 8-bit
-          greyscale.  The core of the issue is that line 21 (and line 23 for
-          PAL WSS) are inside of active video region, and as a result they
-          get the pixelformatting associated with that area.  So by cropping
-          it out, we end up with the same format as the rest of the VBI
-          region */
-       if (em28xx_vbi_supported(dev) == 1)
-               em28xx_capture_area_set(dev, 0, 2, width, height);
-       else
-               em28xx_capture_area_set(dev, 0, 0, width, height);
+                       /* Enable video capture */
+                       rc = em28xx_write_reg(dev, 0x48, 0x00);
 
-       return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
-}
+                       if (dev->mode == EM28XX_ANALOG_MODE)
+                               rc = em28xx_write_reg(dev,
+                                                   EM28XX_R12_VINENABLE, 0x67);
+                       else
+                               rc = em28xx_write_reg(dev,
+                                                   EM28XX_R12_VINENABLE, 0x37);
 
-/* Set USB alternate setting for analog video */
-int em28xx_set_alternate(struct em28xx *dev)
-{
-       int errCode;
-       int i;
-       unsigned int min_pkt_size = dev->width * 2 + 4;
-
-       /* NOTE: for isoc transfers, only alt settings > 0 are allowed
-                bulk transfers seem to work only with alt=0 ! */
-       dev->alt = 0;
-       if ((alt > 0) && (alt < dev->num_alt)) {
-               em28xx_coredbg("alternate forced to %d\n", dev->alt);
-               dev->alt = alt;
-               goto set_alt;
+                       msleep(6);
+               } else {
+                       /* disable video capture */
+                       rc = em28xx_write_reg(dev, EM28XX_R12_VINENABLE, 0x27);
+               }
        }
-       if (dev->analog_xfer_bulk)
-               goto set_alt;
 
-       /* When image size is bigger than a certain value,
-          the frame size should be increased, otherwise, only
-          green screen will be received.
-        */
-       if (dev->width * 2 * dev->height > 720 * 240 * 2)
-               min_pkt_size *= 2;
+       if (rc < 0)
+               return rc;
 
-       for (i = 0; i < dev->num_alt; i++) {
-               /* stop when the selected alt setting offers enough bandwidth */
-               if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
-                       dev->alt = i;
-                       break;
-               /* otherwise make sure that we end up with the maximum bandwidth
-                  because the min_pkt_size equation might be wrong...
-               */
-               } else if (dev->alt_max_pkt_size_isoc[i] >
-                          dev->alt_max_pkt_size_isoc[dev->alt])
-                       dev->alt = i;
+       /* Switch (explicitly controlled) analog capturing LED on/off */
+       if (dev->mode == EM28XX_ANALOG_MODE) {
+               const struct em28xx_led *led;
+               led = em28xx_find_led(dev, EM28XX_LED_ANALOG_CAPTURING);
+               if (led)
+                       em28xx_write_reg_bits(dev, led->gpio_reg,
+                                             (!start ^ led->inverted) ?
+                                             ~led->gpio_mask : led->gpio_mask,
+                                             led->gpio_mask);
        }
 
-set_alt:
-       /* NOTE: for bulk transfers, we need to call usb_set_interface()
-        * even if the previous settings were the same. Otherwise streaming
-        * fails with all urbs having status = -EOVERFLOW ! */
-       if (dev->analog_xfer_bulk) {
-               dev->max_pkt_size = 512; /* USB 2.0 spec */
-               dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
-       } else { /* isoc */
-               em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
-                              min_pkt_size, dev->alt);
-               dev->max_pkt_size =
-                                 dev->alt_max_pkt_size_isoc[dev->alt];
-               dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
-       }
-       em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
-                      dev->alt, dev->max_pkt_size);
-       errCode = usb_set_interface(dev->udev, 0, dev->alt);
-       if (errCode < 0) {
-               em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
-                             dev->alt, errCode);
-               return errCode;
-       }
-       return 0;
+       return rc;
 }
 
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
@@ -1237,18 +1039,6 @@ int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
 }
 EXPORT_SYMBOL_GPL(em28xx_init_usb_xfer);
 
-/*
- * em28xx_wake_i2c()
- * configure i2c attached devices
- */
-void em28xx_wake_i2c(struct em28xx *dev)
-{
-       v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
-       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
-                       INPUT(dev->ctl_input)->vmux, 0, 0);
-       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
-}
-
 /*
  * Device control list
  */
@@ -1272,7 +1062,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
                ops->init(dev);
        }
        mutex_unlock(&em28xx_devlist_mutex);
-       printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
+       printk(KERN_INFO "em28xx: Registered (%s) extension\n", ops->name);
        return 0;
 }
 EXPORT_SYMBOL(em28xx_register_extension);
index 344042bb845cbee2326e47ca021085e0299447e4..a0a669e81362956878755eea3cbf1a134905a303 100644 (file)
 #include "a8293.h"
 #include "qt1010.h"
 #include "mb86a20s.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
 
-MODULE_DESCRIPTION("driver for em28xx based DVB cards");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
 MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface");
+MODULE_VERSION(EM28XX_VERSION);
+
 
 static unsigned int debug;
 module_param(debug, int, 0644);
@@ -87,6 +91,7 @@ struct em28xx_dvb {
        struct semaphore      pll_mutex;
        bool                    dont_attach_fe1;
        int                     lna_gpio;
+       struct i2c_client       *i2c_client_tuner;
 };
 
 
@@ -198,7 +203,7 @@ static int em28xx_start_streaming(struct em28xx_dvb *dvb)
                dvb_alt = dev->dvb_alt_isoc;
        }
 
-       usb_set_interface(dev->udev, 0, dvb_alt);
+       usb_set_interface(dev->udev, dev->ifnum, dvb_alt);
        rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        if (rc < 0)
                return rc;
@@ -271,7 +276,7 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
 static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
 {
        struct em28xx_i2c_bus *i2c_bus = fe->dvb->priv;
-        struct em28xx *dev = i2c_bus->dev;
+       struct em28xx *dev = i2c_bus->dev;
 
        if (acquire)
                return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
@@ -370,7 +375,6 @@ static struct drxk_config terratec_h5_drxk = {
        .no_i2c_bridge = 1,
        .microcode_name = "dvb-usb-terratec-h5-drxk.fw",
        .qam_demod_parameter_count = 2,
-       .load_firmware_sync = true,
 };
 
 static struct drxk_config hauppauge_930c_drxk = {
@@ -380,7 +384,6 @@ static struct drxk_config hauppauge_930c_drxk = {
        .microcode_name = "dvb-usb-hauppauge-hvr930c-drxk.fw",
        .chunk_size = 56,
        .qam_demod_parameter_count = 2,
-       .load_firmware_sync = true,
 };
 
 static struct drxk_config terratec_htc_stick_drxk = {
@@ -394,7 +397,6 @@ static struct drxk_config terratec_htc_stick_drxk = {
        .antenna_dvbt = true,
        /* The windows driver uses the same. This will disable LNA. */
        .antenna_gpio = 0x6,
-       .load_firmware_sync = true,
 };
 
 static struct drxk_config maxmedia_ub425_tc_drxk = {
@@ -403,7 +405,6 @@ static struct drxk_config maxmedia_ub425_tc_drxk = {
        .no_i2c_bridge = 1,
        .microcode_name = "dvb-demod-drxk-01.fw",
        .chunk_size = 62,
-       .load_firmware_sync = true,
        .qam_demod_parameter_count = 2,
 };
 
@@ -415,7 +416,6 @@ static struct drxk_config pctv_520e_drxk = {
        .chunk_size = 58,
        .antenna_dvbt = true, /* disable LNA */
        .antenna_gpio = (1 << 2), /* disable LNA */
-       .load_firmware_sync = true,
 };
 
 static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable)
@@ -808,6 +808,14 @@ static struct tda18271_config c3tech_duo_tda18271_config = {
        .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
 };
 
+static const struct m88ds3103_config pctv_461e_m88ds3103_config = {
+       .i2c_addr = 0x68,
+       .clock = 27000000,
+       .i2c_wr_max = 33,
+       .clock_out = 0,
+       .ts_mode = M88DS3103_TS_PARALLEL_16,
+       .agc = 0x99,
+};
 
 /* ------------------------------------------------------------------ */
 
@@ -815,11 +823,16 @@ static int em28xx_attach_xc3028(u8 addr, struct em28xx *dev)
 {
        struct dvb_frontend *fe;
        struct xc2028_config cfg;
+       struct xc2028_ctrl ctl;
 
        memset(&cfg, 0, sizeof(cfg));
        cfg.i2c_adap  = &dev->i2c_adap[dev->def_i2c_bus];
        cfg.i2c_addr  = addr;
 
+       memset(&ctl, 0, sizeof(ctl));
+       em28xx_setup_xc3028(dev, &ctl);
+       cfg.ctrl  = &ctl;
+
        if (!dev->dvb->fe[0]) {
                em28xx_errdev("/2: dvb frontend not attached. "
                                "Can't attach xc3028\n");
@@ -979,12 +992,18 @@ static int em28xx_dvb_init(struct em28xx *dev)
        int result = 0, mfe_shared = 0;
        struct em28xx_dvb *dvb;
 
+       if (dev->is_audio_only) {
+               /* Shouldn't initialize IR for this interface */
+               return 0;
+       }
+
        if (!dev->board.has_dvb) {
                /* This device does not support the extension */
-               printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
                return 0;
        }
 
+       em28xx_info("Binding DVB extension\n");
+
        dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
 
        if (dvb == NULL) {
@@ -994,6 +1013,27 @@ static int em28xx_dvb_init(struct em28xx *dev)
        dev->dvb = dvb;
        dvb->fe[0] = dvb->fe[1] = NULL;
 
+       /* pre-allocate DVB usb transfer buffers */
+       if (dev->dvb_xfer_bulk) {
+               result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+                                          dev->dvb_xfer_bulk,
+                                          EM28XX_DVB_NUM_BUFS,
+                                          512,
+                                          EM28XX_DVB_BULK_PACKET_MULTIPLIER);
+       } else {
+               result = em28xx_alloc_urbs(dev, EM28XX_DIGITAL_MODE,
+                                          dev->dvb_xfer_bulk,
+                                          EM28XX_DVB_NUM_BUFS,
+                                          dev->dvb_max_pkt_size_isoc,
+                                          EM28XX_DVB_NUM_ISOC_PACKETS);
+       }
+       if (result) {
+               em28xx_errdev("em28xx_dvb: failed to pre-allocate USB transfer buffers for DVB.\n");
+               kfree(dvb);
+               dev->dvb = NULL;
+               return result;
+       }
+
        mutex_lock(&dev->lock);
        em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
        /* init frontend */
@@ -1330,6 +1370,48 @@ static int em28xx_dvb_init(struct em28xx *dev)
                        goto out_free;
                }
                break;
+       case EM28178_BOARD_PCTV_461E:
+               {
+                       /* demod I2C adapter */
+                       struct i2c_adapter *i2c_adapter;
+                       struct i2c_board_info info;
+                       struct m88ts2022_config m88ts2022_config = {
+                               .clock = 27000000,
+                       };
+                       memset(&info, 0, sizeof(struct i2c_board_info));
+
+                       /* attach demod */
+                       dvb->fe[0] = dvb_attach(m88ds3103_attach,
+                                       &pctv_461e_m88ds3103_config,
+                                       &dev->i2c_adap[dev->def_i2c_bus],
+                                       &i2c_adapter);
+                       if (dvb->fe[0] == NULL) {
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+
+                       /* attach tuner */
+                       m88ts2022_config.fe = dvb->fe[0];
+                       strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+                       info.addr = 0x60;
+                       info.platform_data = &m88ts2022_config;
+                       request_module("m88ts2022");
+                       dvb->i2c_client_tuner = i2c_new_device(i2c_adapter, &info);
+
+                       /* delegate signal strength measurement to tuner */
+                       dvb->fe[0]->ops.read_signal_strength =
+                                       dvb->fe[0]->ops.tuner_ops.get_rf_strength;
+
+                       /* attach SEC */
+                       if (!dvb_attach(a8293_attach, dvb->fe[0],
+                                       &dev->i2c_adap[dev->def_i2c_bus],
+                                       &em28xx_a8293_config)) {
+                               dvb_frontend_detach(dvb->fe[0]);
+                               result = -ENODEV;
+                               goto out_free;
+                       }
+               }
+               break;
        default:
                em28xx_errdev("/2: The frontend of your DVB/ATSC card"
                                " isn't supported yet\n");
@@ -1354,7 +1436,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
        /* MFE lock */
        dvb->adapter.mfe_shared = mfe_shared;
 
-       em28xx_info("Successfully loaded em28xx-dvb\n");
+       em28xx_info("DVB extension successfully initialized\n");
 ret:
        em28xx_set_mode(dev, EM28XX_SUSPEND);
        mutex_unlock(&dev->lock);
@@ -1375,14 +1457,23 @@ static inline void prevent_sleep(struct dvb_frontend_ops *ops)
 
 static int em28xx_dvb_fini(struct em28xx *dev)
 {
+       if (dev->is_audio_only) {
+               /* Shouldn't initialize IR for this interface */
+               return 0;
+       }
+
        if (!dev->board.has_dvb) {
                /* This device does not support the extension */
                return 0;
        }
 
+       em28xx_info("Closing DVB extension");
+
        if (dev->dvb) {
                struct em28xx_dvb *dvb = dev->dvb;
 
+               em28xx_uninit_usb_xfer(dev, EM28XX_DIGITAL_MODE);
+
                if (dev->disconnected) {
                        /* We cannot tell the device to sleep
                         * once it has been unplugged. */
@@ -1392,6 +1483,7 @@ static int em28xx_dvb_fini(struct em28xx *dev)
                                prevent_sleep(&dvb->fe[1]->ops);
                }
 
+               i2c_release_client(dvb->i2c_client_tuner);
                em28xx_unregister_dvb(dvb);
                kfree(dvb);
                dev->dvb = NULL;
index c4ff9739a7ae8cb099b21637dc23723e5e170d1b..7e1724076ac462b8b7e715bee8c53ec55119f83f 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kernel.h>
 #include <linux/usb.h>
 #include <linux/i2c.h>
+#include <linux/jiffies.h>
 
 #include "em28xx.h"
 #include "tuner-xc2028.h"
@@ -40,7 +41,7 @@ MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
 
 static unsigned int i2c_debug;
 module_param(i2c_debug, int, 0644);
-MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+MODULE_PARM_DESC(i2c_debug, "i2c debug message level (1: normal debug, 2: show I2C transfers)");
 
 /*
  * em2800_i2c_send_bytes()
@@ -48,8 +49,8 @@ MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
  */
 static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 {
+       unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
        int ret;
-       int write_timeout;
        u8 b2[6];
 
        if (len < 1 || len > 4)
@@ -74,22 +75,26 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
                return (ret < 0) ? ret : -EIO;
        }
        /* wait for completion */
-       for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
-            write_timeout -= 5) {
+       while (time_is_after_jiffies(timeout)) {
                ret = dev->em28xx_read_reg(dev, 0x05);
-               if (ret == 0x80 + len - 1) {
+               if (ret == 0x80 + len - 1)
                        return len;
-               } else if (ret == 0x94 + len - 1) {
-                       return -ENODEV;
-               } else if (ret < 0) {
+               if (ret == 0x94 + len - 1) {
+                       if (i2c_debug == 1)
+                               em28xx_warn("R05 returned 0x%02x: I2C timeout",
+                                           ret);
+                       return -ENXIO;
+               }
+               if (ret < 0) {
                        em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
                                    ret);
                        return ret;
                }
                msleep(5);
        }
-       em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
-       return -EIO;
+       if (i2c_debug)
+               em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
+       return -ETIMEDOUT;
 }
 
 /*
@@ -98,9 +103,9 @@ static int em2800_i2c_send_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
  */
 static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
 {
+       unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
        u8 buf2[4];
        int ret;
-       int read_timeout;
        int i;
 
        if (len < 1 || len > 4)
@@ -117,22 +122,28 @@ static int em2800_i2c_recv_bytes(struct em28xx *dev, u8 addr, u8 *buf, u16 len)
        }
 
        /* wait for completion */
-       for (read_timeout = EM2800_I2C_XFER_TIMEOUT; read_timeout > 0;
-            read_timeout -= 5) {
+       while (time_is_after_jiffies(timeout)) {
                ret = dev->em28xx_read_reg(dev, 0x05);
-               if (ret == 0x84 + len - 1) {
+               if (ret == 0x84 + len - 1)
                        break;
-               } else if (ret == 0x94 + len - 1) {
-                       return -ENODEV;
-               } else if (ret < 0) {
+               if (ret == 0x94 + len - 1) {
+                       if (i2c_debug == 1)
+                               em28xx_warn("R05 returned 0x%02x: I2C timeout",
+                                           ret);
+                       return -ENXIO;
+               }
+               if (ret < 0) {
                        em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
                                    ret);
                        return ret;
                }
                msleep(5);
        }
-       if (ret != 0x84 + len - 1)
-               em28xx_warn("read from i2c device at 0x%x timed out\n", addr);
+       if (ret != 0x84 + len - 1) {
+               if (i2c_debug)
+                       em28xx_warn("read from i2c device at 0x%x timed out\n",
+                                   addr);
+       }
 
        /* get the received message */
        ret = dev->em28xx_read_reg_req_len(dev, 0x00, 4-len, buf2, len);
@@ -168,7 +179,8 @@ static int em2800_i2c_check_for_device(struct em28xx *dev, u8 addr)
 static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
                                 u16 len, int stop)
 {
-       int write_timeout, ret;
+       unsigned long timeout = jiffies + msecs_to_jiffies(EM28XX_I2C_XFER_TIMEOUT);
+       int ret;
 
        if (len < 1 || len > 64)
                return -EOPNOTSUPP;
@@ -191,16 +203,19 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
                }
        }
 
-       /* Check success of the i2c operation */
-       for (write_timeout = EM2800_I2C_XFER_TIMEOUT; write_timeout > 0;
-            write_timeout -= 5) {
+       /* wait for completion */
+       while (time_is_after_jiffies(timeout)) {
                ret = dev->em28xx_read_reg(dev, 0x05);
-               if (ret == 0) /* success */
+               if (ret == 0) /* success */
                        return len;
-               } else if (ret == 0x10) {
-                       return -ENODEV;
-               } else if (ret < 0) {
-                       em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+               if (ret == 0x10) {
+                       if (i2c_debug == 1)
+                               em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
+                                           addr);
+                       return -ENXIO;
+               }
+               if (ret < 0) {
+                       em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
                                    ret);
                        return ret;
                }
@@ -211,8 +226,10 @@ static int em28xx_i2c_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
                 * (even with high payload) ...
                 */
        }
-       em28xx_warn("write to i2c device at 0x%x timed out\n", addr);
-       return -EIO;
+       if (i2c_debug)
+               em28xx_warn("write to i2c device at 0x%x timed out (status=%i)\n",
+                           addr, ret);
+       return -ETIMEDOUT;
 }
 
 /*
@@ -242,26 +259,28 @@ static int em28xx_i2c_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf, u16 len)
         * bytes if we are on bus B AND there was no write attempt to the
         * specified slave address before AND no device is present at the
         * requested slave address.
-        * Anyway, the next check will fail with -ENODEV in this case, so avoid
+        * Anyway, the next check will fail with -ENXIO in this case, so avoid
         * spamming the system log on device probing and do nothing here.
         */
 
        /* Check success of the i2c operation */
        ret = dev->em28xx_read_reg(dev, 0x05);
+       if (ret == 0) /* success */
+               return len;
        if (ret < 0) {
-               em28xx_warn("failed to read i2c transfer status from bridge (error=%i)\n",
+               em28xx_warn("failed to get i2c transfer status from bridge register (error=%i)\n",
                            ret);
                return ret;
        }
-       if (ret > 0) {
-               if (ret == 0x10) {
-                       return -ENODEV;
-               } else {
-                       em28xx_warn("unknown i2c error (status=%i)\n", ret);
-                       return -EIO;
-               }
+       if (ret == 0x10) {
+               if (i2c_debug == 1)
+                       em28xx_warn("I2C transfer timeout on writing to addr 0x%02x",
+                                   addr);
+               return -ENXIO;
        }
-       return len;
+
+       em28xx_warn("unknown i2c error (status=%i)\n", ret);
+       return -ETIMEDOUT;
 }
 
 /*
@@ -316,8 +335,12 @@ static int em25xx_bus_B_send_bytes(struct em28xx *dev, u16 addr, u8 *buf,
         */
        if (!ret)
                return len;
-       else if (ret > 0)
-               return -ENODEV;
+       else if (ret > 0) {
+               if (i2c_debug == 1)
+                       em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
+                                   ret);
+               return -ENXIO;
+       }
 
        return ret;
        /*
@@ -355,7 +378,7 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
         * bytes if we are on bus B AND there was no write attempt to the
         * specified slave address before AND no device is present at the
         * requested slave address.
-        * Anyway, the next check will fail with -ENODEV in this case, so avoid
+        * Anyway, the next check will fail with -ENXIO in this case, so avoid
         * spamming the system log on device probing and do nothing here.
         */
 
@@ -367,8 +390,12 @@ static int em25xx_bus_B_recv_bytes(struct em28xx *dev, u16 addr, u8 *buf,
         */
        if (!ret)
                return len;
-       else if (ret > 0)
-               return -ENODEV;
+       else if (ret > 0) {
+               if (i2c_debug == 1)
+                       em28xx_warn("Bus B R08 returned 0x%02x: I2C timeout",
+                                   ret);
+               return -ENXIO;
+       }
 
        return ret;
        /*
@@ -409,10 +436,6 @@ static inline int i2c_check_for_device(struct em28xx_i2c_bus *i2c_bus, u16 addr)
                rc = em2800_i2c_check_for_device(dev, addr);
        else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
                rc = em25xx_bus_B_check_for_device(dev, addr);
-       if (rc == -ENODEV) {
-               if (i2c_debug)
-                       printk(" no device\n");
-       }
        return rc;
 }
 
@@ -421,7 +444,7 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
 {
        struct em28xx *dev = i2c_bus->dev;
        u16 addr = msg.addr << 1;
-       int byte, rc = -EOPNOTSUPP;
+       int rc = -EOPNOTSUPP;
 
        if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
                rc = em28xx_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
@@ -429,10 +452,6 @@ static inline int i2c_recv_bytes(struct em28xx_i2c_bus *i2c_bus,
                rc = em2800_i2c_recv_bytes(dev, addr, msg.buf, msg.len);
        else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM25XX_BUS_B)
                rc = em25xx_bus_B_recv_bytes(dev, addr, msg.buf, msg.len);
-       if (i2c_debug) {
-               for (byte = 0; byte < msg.len; byte++)
-                       printk(" %02x", msg.buf[byte]);
-       }
        return rc;
 }
 
@@ -441,12 +460,8 @@ static inline int i2c_send_bytes(struct em28xx_i2c_bus *i2c_bus,
 {
        struct em28xx *dev = i2c_bus->dev;
        u16 addr = msg.addr << 1;
-       int byte, rc = -EOPNOTSUPP;
+       int rc = -EOPNOTSUPP;
 
-       if (i2c_debug) {
-               for (byte = 0; byte < msg.len; byte++)
-                       printk(" %02x", msg.buf[byte]);
-       }
        if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM28XX)
                rc = em28xx_i2c_send_bytes(dev, addr, msg.buf, msg.len, stop);
        else if (i2c_bus->algo_type == EM28XX_I2C_ALGO_EM2800)
@@ -491,33 +506,53 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
        }
        for (i = 0; i < num; i++) {
                addr = msgs[i].addr << 1;
-               if (i2c_debug)
+               if (i2c_debug > 1)
                        printk(KERN_DEBUG "%s at %s: %s %s addr=%02x len=%d:",
                               dev->name, __func__ ,
                               (msgs[i].flags & I2C_M_RD) ? "read" : "write",
                               i == num - 1 ? "stop" : "nonstop",
                               addr, msgs[i].len);
-               if (!msgs[i].len) { /* no len: check only for device presence */
+               if (!msgs[i].len) {
+                       /*
+                        * no len: check only for device presence
+                        * This code is only called during device probe.
+                        */
                        rc = i2c_check_for_device(i2c_bus, addr);
-                       if (rc == -ENODEV) {
+                       if (rc < 0) {
+                               if (rc == -ENXIO) {
+                                       if (i2c_debug > 1)
+                                               printk(KERN_CONT " no device\n");
+                                       rc = -ENODEV;
+                               } else {
+                                       if (i2c_debug > 1)
+                                               printk(KERN_CONT " ERROR: %i\n", rc);
+                               }
                                rt_mutex_unlock(&dev->i2c_bus_lock);
                                return rc;
                        }
                } else if (msgs[i].flags & I2C_M_RD) {
                        /* read bytes */
                        rc = i2c_recv_bytes(i2c_bus, msgs[i]);
+
+                       if (i2c_debug > 1 && rc >= 0)
+                               printk(KERN_CONT " %*ph",
+                                      msgs[i].len, msgs[i].buf);
                } else {
+                       if (i2c_debug > 1)
+                               printk(KERN_CONT " %*ph",
+                                      msgs[i].len, msgs[i].buf);
+
                        /* write bytes */
                        rc = i2c_send_bytes(i2c_bus, msgs[i], i == num - 1);
                }
                if (rc < 0) {
-                       if (i2c_debug)
-                               printk(" ERROR: %i\n", rc);
+                       if (i2c_debug > 1)
+                               printk(KERN_CONT " ERROR: %i\n", rc);
                        rt_mutex_unlock(&dev->i2c_bus_lock);
                        return rc;
                }
-               if (i2c_debug)
-                       printk("\n");
+               if (i2c_debug > 1)
+                       printk(KERN_CONT "\n");
        }
 
        rt_mutex_unlock(&dev->i2c_bus_lock);
@@ -600,7 +635,7 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
         * calculation and returned device dataset. Simplifies the code a lot,
         * but we might have to deal with multiple sizes in the future !
         */
-       int i, err;
+       int err;
        struct em28xx_eeprom *dev_config;
        u8 buf, *data;
 
@@ -631,20 +666,14 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
                goto error;
        }
 
-       /* Display eeprom content */
-       for (i = 0; i < len; i++) {
-               if (0 == (i % 16)) {
-                       if (dev->eeprom_addrwidth_16bit)
-                               em28xx_info("i2c eeprom %04x:", i);
-                       else
-                               em28xx_info("i2c eeprom %02x:", i);
-               }
-               printk(" %02x", data[i]);
-               if (15 == (i % 16))
-                       printk("\n");
+       if (i2c_debug) {
+               /* Display eeprom content */
+               print_hex_dump(KERN_INFO, "eeprom ", DUMP_PREFIX_OFFSET,
+                              16, 1, data, len, true);
+
+               if (dev->eeprom_addrwidth_16bit)
+                       em28xx_info("eeprom %06x: ... (skipped)\n", 256);
        }
-       if (dev->eeprom_addrwidth_16bit)
-               em28xx_info("i2c eeprom %04x: ... (skipped)\n", i);
 
        if (dev->eeprom_addrwidth_16bit &&
            data[0] == 0x26 && data[3] == 0x00) {
@@ -736,10 +765,16 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned bus,
                em28xx_info("\tAC97 audio (5 sample rates)\n");
                break;
        case 2:
-               em28xx_info("\tI2S audio, sample rate=32k\n");
+               if (dev->chip_id < CHIP_ID_EM2860)
+                       em28xx_info("\tI2S audio, sample rate=32k\n");
+               else
+                       em28xx_info("\tI2S audio, 3 sample rates\n");
                break;
        case 3:
-               em28xx_info("\tI2S audio, 3 sample rates\n");
+               if (dev->chip_id < CHIP_ID_EM2860)
+                       em28xx_info("\tI2S audio, 3 sample rates\n");
+               else
+                       em28xx_info("\tI2S audio, 5 sample rates\n");
                break;
        }
 
index ea181e4b68c5b445026b5f75458f86a7b7096db8..18f65d89d4bc783a5005fc7b3aaa2b196c1c9904 100644 (file)
@@ -30,8 +30,9 @@
 
 #include "em28xx.h"
 
-#define EM28XX_SNAPSHOT_KEY KEY_CAMERA
-#define EM28XX_SBUTTON_QUERY_INTERVAL 500
+#define EM28XX_SNAPSHOT_KEY                            KEY_CAMERA
+#define EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL                500 /* [ms] */
+#define EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL         100 /* [ms] */
 
 static unsigned int ir_debug;
 module_param(ir_debug, int, 0644);
@@ -442,6 +443,7 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
        case CHIP_ID_EM2884:
        case CHIP_ID_EM2874:
        case CHIP_ID_EM28174:
+       case CHIP_ID_EM28178:
                return em2874_ir_change_protocol(rc_dev, rc_type);
        default:
                printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n",
@@ -470,54 +472,98 @@ static int em28xx_probe_i2c_ir(struct em28xx *dev)
 }
 
 /**********************************************************
- Handle Webcam snapshot button
+ Handle buttons
  **********************************************************/
 
-static void em28xx_query_sbutton(struct work_struct *work)
+static void em28xx_query_buttons(struct work_struct *work)
 {
-       /* Poll the register and see if the button is depressed */
        struct em28xx *dev =
-               container_of(work, struct em28xx, sbutton_query_work.work);
-       int ret;
-
-       ret = em28xx_read_reg(dev, EM28XX_R0C_USBSUSP);
-
-       if (ret & EM28XX_R0C_USBSUSP_SNAPSHOT) {
-               u8 cleared;
-               /* Button is depressed, clear the register */
-               cleared = ((u8) ret) & ~EM28XX_R0C_USBSUSP_SNAPSHOT;
-               em28xx_write_regs(dev, EM28XX_R0C_USBSUSP, &cleared, 1);
-
-               /* Not emulate the keypress */
-               input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
-                                1);
-               /* Now unpress the key */
-               input_report_key(dev->sbutton_input_dev, EM28XX_SNAPSHOT_KEY,
-                                0);
+               container_of(work, struct em28xx, buttons_query_work.work);
+       u8 i, j;
+       int regval;
+       bool is_pressed, was_pressed;
+       const struct em28xx_led *led;
+
+       /* Poll and evaluate all addresses */
+       for (i = 0; i < dev->num_button_polling_addresses; i++) {
+               /* Read value from register */
+               regval = em28xx_read_reg(dev, dev->button_polling_addresses[i]);
+               if (regval < 0)
+                       continue;
+               /* Check states of the buttons and act */
+               j = 0;
+               while (dev->board.buttons[j].role >= 0 &&
+                        dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) {
+                       struct em28xx_button *button = &dev->board.buttons[j];
+                       /* Check if button uses the current address */
+                       if (button->reg_r != dev->button_polling_addresses[i]) {
+                               j++;
+                               continue;
+                       }
+                       /* Determine if button is and was pressed last time */
+                       is_pressed = regval & button->mask;
+                       was_pressed = dev->button_polling_last_values[i]
+                                      & button->mask;
+                       if (button->inverted) {
+                               is_pressed = !is_pressed;
+                               was_pressed = !was_pressed;
+                       }
+                       /* Clear button state (if needed) */
+                       if (is_pressed && button->reg_clearing)
+                               em28xx_write_reg(dev, button->reg_clearing,
+                                                (~regval & button->mask)
+                                                   | (regval & ~button->mask));
+                       /* Handle button state */
+                       if (!is_pressed || was_pressed) {
+                               j++;
+                               continue;
+                       }
+                       switch (button->role) {
+                       case EM28XX_BUTTON_SNAPSHOT:
+                               /* Emulate the keypress */
+                               input_report_key(dev->sbutton_input_dev,
+                                                EM28XX_SNAPSHOT_KEY, 1);
+                               /* Unpress the key */
+                               input_report_key(dev->sbutton_input_dev,
+                                                EM28XX_SNAPSHOT_KEY, 0);
+                               break;
+                       case EM28XX_BUTTON_ILLUMINATION:
+                               led = em28xx_find_led(dev,
+                                                     EM28XX_LED_ILLUMINATION);
+                               /* Switch illumination LED on/off */
+                               if (led)
+                                       em28xx_toggle_reg_bits(dev,
+                                                              led->gpio_reg,
+                                                              led->gpio_mask);
+                               break;
+                       default:
+                               WARN_ONCE(1, "BUG: unhandled button role.");
+                       }
+                       /* Next button */
+                       j++;
+               }
+               /* Save current value for comparison during the next polling */
+               dev->button_polling_last_values[i] = regval;
        }
-
        /* Schedule next poll */
-       schedule_delayed_work(&dev->sbutton_query_work,
-                             msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
+       schedule_delayed_work(&dev->buttons_query_work,
+                             msecs_to_jiffies(dev->button_polling_interval));
 }
 
-static void em28xx_register_snapshot_button(struct em28xx *dev)
+static int em28xx_register_snapshot_button(struct em28xx *dev)
 {
        struct input_dev *input_dev;
        int err;
 
        em28xx_info("Registering snapshot button...\n");
        input_dev = input_allocate_device();
-       if (!input_dev) {
-               em28xx_errdev("input_allocate_device failed\n");
-               return;
-       }
+       if (!input_dev)
+               return -ENOMEM;
 
        usb_make_path(dev->udev, dev->snapshot_button_path,
                      sizeof(dev->snapshot_button_path));
        strlcat(dev->snapshot_button_path, "/sbutton",
                sizeof(dev->snapshot_button_path));
-       INIT_DELAYED_WORK(&dev->sbutton_query_work, em28xx_query_sbutton);
 
        input_dev->name = "em28xx snapshot button";
        input_dev->phys = dev->snapshot_button_path;
@@ -535,25 +581,86 @@ static void em28xx_register_snapshot_button(struct em28xx *dev)
        if (err) {
                em28xx_errdev("input_register_device failed\n");
                input_free_device(input_dev);
-               return;
+               return err;
        }
 
        dev->sbutton_input_dev = input_dev;
-       schedule_delayed_work(&dev->sbutton_query_work,
-                             msecs_to_jiffies(EM28XX_SBUTTON_QUERY_INTERVAL));
-       return;
+       return 0;
+}
 
+static void em28xx_init_buttons(struct em28xx *dev)
+{
+       u8  i = 0, j = 0;
+       bool addr_new = 0;
+
+       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;
+               for (j = 0; j < dev->num_button_polling_addresses; j++) {
+                       if (button->reg_r == dev->button_polling_addresses[j]) {
+                               addr_new = 0;
+                               break;
+                       }
+               }
+               /* Check if max. number of polling addresses is exceeded */
+               if (addr_new && dev->num_button_polling_addresses
+                                          >= EM28XX_NUM_BUTTON_ADDRESSES_MAX) {
+                       WARN_ONCE(1, "BUG: maximum number of button polling addresses exceeded.");
+                       goto next_button;
+               }
+               /* Button role specific checks and actions */
+               if (button->role == EM28XX_BUTTON_SNAPSHOT) {
+                       /* Register input device */
+                       if (em28xx_register_snapshot_button(dev) < 0)
+                               goto next_button;
+               } else if (button->role == EM28XX_BUTTON_ILLUMINATION) {
+                       /* Check sanity */
+                       if (!em28xx_find_led(dev, EM28XX_LED_ILLUMINATION)) {
+                               em28xx_errdev("BUG: illumination button defined, but no illumination LED.\n");
+                               goto next_button;
+                       }
+               }
+               /* Add read address to list of polling addresses */
+               if (addr_new) {
+                       unsigned int index = dev->num_button_polling_addresses;
+                       dev->button_polling_addresses[index] = button->reg_r;
+                       dev->num_button_polling_addresses++;
+               }
+               /* Reduce polling interval if necessary */
+               if (!button->reg_clearing)
+                       dev->button_polling_interval =
+                                        EM28XX_BUTTONS_VOLATILE_QUERY_INTERVAL;
+next_button:
+               /* Next button */
+               i++;
+       }
+
+       /* Start polling */
+       if (dev->num_button_polling_addresses) {
+               memset(dev->button_polling_last_values, 0,
+                                              EM28XX_NUM_BUTTON_ADDRESSES_MAX);
+               INIT_DELAYED_WORK(&dev->buttons_query_work,
+                                                         em28xx_query_buttons);
+               schedule_delayed_work(&dev->buttons_query_work,
+                              msecs_to_jiffies(dev->button_polling_interval));
+       }
 }
 
-static void em28xx_deregister_snapshot_button(struct em28xx *dev)
+static void em28xx_shutdown_buttons(struct em28xx *dev)
 {
+       /* Cancel polling */
+       cancel_delayed_work_sync(&dev->buttons_query_work);
+       /* Clear polling addresses list */
+       dev->num_button_polling_addresses = 0;
+       /* Deregister input devices */
        if (dev->sbutton_input_dev != NULL) {
                em28xx_info("Deregistering snapshot button\n");
-               cancel_delayed_work_sync(&dev->sbutton_query_work);
                input_unregister_device(dev->sbutton_input_dev);
                dev->sbutton_input_dev = NULL;
        }
-       return;
 }
 
 static int em28xx_ir_init(struct em28xx *dev)
@@ -564,8 +671,13 @@ static int em28xx_ir_init(struct em28xx *dev)
        u64 rc_type;
        u16 i2c_rc_dev_addr = 0;
 
-       if (dev->board.has_snapshot_button)
-               em28xx_register_snapshot_button(dev);
+       if (dev->is_audio_only) {
+               /* Shouldn't initialize IR for this interface */
+               return 0;
+       }
+
+       if (dev->board.buttons)
+               em28xx_init_buttons(dev);
 
        if (dev->board.has_ir_i2c) {
                i2c_rc_dev_addr = em28xx_probe_i2c_ir(dev);
@@ -583,6 +695,8 @@ static int em28xx_ir_init(struct em28xx *dev)
                return 0;
        }
 
+       em28xx_info("Registering input extension\n");
+
        ir = kzalloc(sizeof(*ir), GFP_KERNEL);
        rc = rc_allocate_device();
        if (!ir || !rc)
@@ -633,6 +747,7 @@ static int em28xx_ir_init(struct em28xx *dev)
                case CHIP_ID_EM2884:
                case CHIP_ID_EM2874:
                case CHIP_ID_EM28174:
+               case CHIP_ID_EM28178:
                        ir->get_key = em2874_polling_getkey;
                        rc->allowed_protos = RC_BIT_RC5 | RC_BIT_NEC |
                                             RC_BIT_RC6_0;
@@ -675,6 +790,8 @@ static int em28xx_ir_init(struct em28xx *dev)
        if (err)
                goto error;
 
+       em28xx_info("Input extension successfully initalized\n");
+
        return 0;
 
 error:
@@ -688,7 +805,14 @@ static int em28xx_ir_fini(struct em28xx *dev)
 {
        struct em28xx_IR *ir = dev->ir;
 
-       em28xx_deregister_snapshot_button(dev);
+       if (dev->is_audio_only) {
+               /* Shouldn't initialize IR for this interface */
+               return 0;
+       }
+
+       em28xx_info("Closing input extension");
+
+       em28xx_shutdown_buttons(dev);
 
        /* skip detach on non attached boards */
        if (!ir)
@@ -722,7 +846,8 @@ static void __exit em28xx_rc_unregister(void)
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_DESCRIPTION("Em28xx Input driver");
+MODULE_DESCRIPTION(DRIVER_DESC " - input interface");
+MODULE_VERSION(EM28XX_VERSION);
 
 module_init(em28xx_rc_register);
 module_exit(em28xx_rc_unregister);
index 0e0477847965ad822b61ba005de3b34865910275..311fb349dafac0cae43cdfd2076d90073307e4a1 100644 (file)
 #define EM28XX_R00_CHIPCFG     0x00
 
 /* em28xx Chip Configuration 0x00 */
-#define EM28XX_CHIPCFG_VENDOR_AUDIO            0x80
-#define EM28XX_CHIPCFG_I2S_VOLUME_CAPABLE      0x40
-#define EM28XX_CHIPCFG_I2S_5_SAMPRATES         0x30
-#define EM28XX_CHIPCFG_I2S_3_SAMPRATES         0x20
+#define EM2860_CHIPCFG_VENDOR_AUDIO            0x80
+#define EM2860_CHIPCFG_I2S_VOLUME_CAPABLE      0x40
+#define EM2820_CHIPCFG_I2S_3_SAMPRATES         0x30
+#define EM2860_CHIPCFG_I2S_5_SAMPRATES         0x30
+#define EM2820_CHIPCFG_I2S_1_SAMPRATE          0x20
+#define EM2860_CHIPCFG_I2S_3_SAMPRATES         0x20
 #define EM28XX_CHIPCFG_AC97                    0x10
 #define EM28XX_CHIPCFG_AUDIOMASK               0x30
 
@@ -245,6 +247,7 @@ enum em28xx_chip_id {
        CHIP_ID_EM2874 = 65,
        CHIP_ID_EM2884 = 68,
        CHIP_ID_EM28174 = 113,
+       CHIP_ID_EM28178 = 114,
 };
 
 /*
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
new file mode 100644 (file)
index 0000000..bce4386
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+   em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+                   video capture devices
+
+   Copyright (C) 2013-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 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.
+ */
+
+
+int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
+int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
+extern struct vb2_ops em28xx_vbi_qops;
index 39f39c527c13fd1880ed20246ad7c9c798631969..db3d655600df3b7612de4a4eb697b4ce9628ade2 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/init.h>
 
 #include "em28xx.h"
+#include "em28xx-v4l.h"
 
 static unsigned int vbibufs = 5;
 module_param(vbibufs, int, 0644);
index dd19c9ff76e0f9a159c6630320814c89e9e83d5a..c3c928937dcd800172bf959cae5fd2d73ad34f81 100644 (file)
 #include <linux/slab.h>
 
 #include "em28xx.h"
+#include "em28xx-v4l.h"
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 #include <media/v4l2-event.h>
+#include <media/v4l2-clk.h>
 #include <media/msp3400.h>
 #include <media/tuner.h>
 
                      "Mauro Carvalho Chehab <mchehab@infradead.org>, " \
                      "Sascha Sommer <saschasommer@freenet.de>"
 
-#define DRIVER_DESC         "Empia em28xx based USB video device driver"
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+static unsigned int disable_vbi;
+module_param(disable_vbi, int, 0644);
+MODULE_PARM_DESC(disable_vbi, "disable vbi support");
 
-#define EM28XX_VERSION "0.2.0"
+static int alt;
+module_param(alt, int, 0644);
+MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
 
 #define em28xx_videodbg(fmt, arg...) do {\
        if (video_debug) \
                printk(KERN_INFO "%s %s :"fmt, \
                         dev->name, __func__ , ##arg); } while (0)
 
-static unsigned int isoc_debug;
-module_param(isoc_debug, int, 0644);
-MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
-
 #define em28xx_isocdbg(fmt, arg...) \
 do {\
        if (isoc_debug) { \
@@ -71,7 +77,7 @@ do {\
   } while (0)
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(EM28XX_VERSION);
 
@@ -135,6 +141,257 @@ static struct em28xx_fmt format[] = {
        },
 };
 
+static int em28xx_vbi_supported(struct em28xx *dev)
+{
+       /* Modprobe option to manually disable */
+       if (disable_vbi == 1)
+               return 0;
+
+       if (dev->board.is_webcam)
+               return 0;
+
+       /* FIXME: check subdevices for VBI support */
+
+       if (dev->chip_id == CHIP_ID_EM2860 ||
+           dev->chip_id == CHIP_ID_EM2883)
+               return 1;
+
+       /* Version of em28xx that does not support VBI */
+       return 0;
+}
+
+/*
+ * em28xx_wake_i2c()
+ * configure i2c attached devices
+ */
+static void em28xx_wake_i2c(struct em28xx *dev)
+{
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core,  reset, 0);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_routing,
+                       INPUT(dev->ctl_input)->vmux, 0, 0);
+       v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+}
+
+static int em28xx_colorlevels_set_default(struct em28xx *dev)
+{
+       em28xx_write_reg(dev, EM28XX_R20_YGAIN, CONTRAST_DEFAULT);
+       em28xx_write_reg(dev, EM28XX_R21_YOFFSET, BRIGHTNESS_DEFAULT);
+       em28xx_write_reg(dev, EM28XX_R22_UVGAIN, SATURATION_DEFAULT);
+       em28xx_write_reg(dev, EM28XX_R23_UOFFSET, BLUE_BALANCE_DEFAULT);
+       em28xx_write_reg(dev, EM28XX_R24_VOFFSET, RED_BALANCE_DEFAULT);
+       em28xx_write_reg(dev, EM28XX_R25_SHARPNESS, SHARPNESS_DEFAULT);
+
+       em28xx_write_reg(dev, EM28XX_R14_GAMMA, 0x20);
+       em28xx_write_reg(dev, EM28XX_R15_RGAIN, 0x20);
+       em28xx_write_reg(dev, EM28XX_R16_GGAIN, 0x20);
+       em28xx_write_reg(dev, EM28XX_R17_BGAIN, 0x20);
+       em28xx_write_reg(dev, EM28XX_R18_ROFFSET, 0x00);
+       em28xx_write_reg(dev, EM28XX_R19_GOFFSET, 0x00);
+       return em28xx_write_reg(dev, EM28XX_R1A_BOFFSET, 0x00);
+}
+
+static int em28xx_set_outfmt(struct em28xx *dev)
+{
+       int ret;
+       u8 fmt, vinctrl;
+
+       fmt = dev->format->reg;
+       if (!dev->is_em25xx)
+               fmt |= 0x20;
+       /*
+        * NOTE: it's not clear if this is really needed !
+        * The datasheets say bit 5 is a reserved bit and devices seem to work
+        * fine without it. But the Windows driver sets it for em2710/50+em28xx
+        * devices and we've always been setting it, too.
+        *
+        * em2765 (em25xx, em276x/7x/8x) devices do NOT work with this bit set,
+        * it's likely used for an additional (compressed ?) format there.
+        */
+       ret = em28xx_write_reg(dev, EM28XX_R27_OUTFMT, fmt);
+       if (ret < 0)
+               return ret;
+
+       ret = em28xx_write_reg(dev, EM28XX_R10_VINMODE, dev->vinmode);
+       if (ret < 0)
+               return ret;
+
+       vinctrl = dev->vinctl;
+       if (em28xx_vbi_supported(dev) == 1) {
+               vinctrl |= EM28XX_VINCTRL_VBI_RAW;
+               em28xx_write_reg(dev, EM28XX_R34_VBI_START_H, 0x00);
+               em28xx_write_reg(dev, EM28XX_R36_VBI_WIDTH, dev->vbi_width/4);
+               em28xx_write_reg(dev, EM28XX_R37_VBI_HEIGHT, dev->vbi_height);
+               if (dev->norm & V4L2_STD_525_60) {
+                       /* NTSC */
+                       em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x09);
+               } else if (dev->norm & V4L2_STD_625_50) {
+                       /* PAL */
+                       em28xx_write_reg(dev, EM28XX_R35_VBI_START_V, 0x07);
+               }
+       }
+
+       return em28xx_write_reg(dev, EM28XX_R11_VINCTRL, vinctrl);
+}
+
+static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
+                                 u8 ymin, u8 ymax)
+{
+       em28xx_videodbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+                       xmin, ymin, xmax, ymax);
+
+       em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
+       em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
+       em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
+       return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
+}
+
+static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
+                                  u16 width, u16 height)
+{
+       u8 cwidth = width >> 2;
+       u8 cheight = height >> 2;
+       u8 overflow = (height >> 9 & 0x02) | (width >> 10 & 0x01);
+       /* NOTE: size limit: 2047x1023 = 2MPix */
+
+       em28xx_videodbg("capture area set to (%d,%d): %dx%d\n",
+                      hstart, vstart,
+                      ((overflow & 2) << 9 | cwidth << 2),
+                      ((overflow & 1) << 10 | cheight << 2));
+
+       em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
+       em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
+       em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
+       em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
+       em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
+
+       /* FIXME: function/meaning of these registers ? */
+       /* FIXME: align width+height to multiples of 4 ?! */
+       if (dev->is_em25xx) {
+               em28xx_write_reg(dev, 0x34, width >> 4);
+               em28xx_write_reg(dev, 0x35, height >> 4);
+       }
+}
+
+static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
+{
+       u8 mode;
+       /* the em2800 scaler only supports scaling down to 50% */
+
+       if (dev->board.is_em2800) {
+               mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
+       } else {
+               u8 buf[2];
+
+               buf[0] = h;
+               buf[1] = h >> 8;
+               em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
+
+               buf[0] = v;
+               buf[1] = v >> 8;
+               em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+               /* it seems that both H and V scalers must be active
+                  to work correctly */
+               mode = (h || v) ? 0x30 : 0x00;
+       }
+       return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
+}
+
+/* FIXME: this only function read values from dev */
+static int em28xx_resolution_set(struct em28xx *dev)
+{
+       int width, height;
+       width = norm_maxw(dev);
+       height = norm_maxh(dev);
+
+       /* Properly setup VBI */
+       dev->vbi_width = 720;
+       if (dev->norm & V4L2_STD_525_60)
+               dev->vbi_height = 12;
+       else
+               dev->vbi_height = 18;
+
+       em28xx_set_outfmt(dev);
+
+       em28xx_accumulator_set(dev, 1, (width - 4) >> 2, 1, (height - 4) >> 2);
+
+       /* If we don't set the start position to 2 in VBI mode, we end up
+          with line 20/21 being YUYV encoded instead of being in 8-bit
+          greyscale.  The core of the issue is that line 21 (and line 23 for
+          PAL WSS) are inside of active video region, and as a result they
+          get the pixelformatting associated with that area.  So by cropping
+          it out, we end up with the same format as the rest of the VBI
+          region */
+       if (em28xx_vbi_supported(dev) == 1)
+               em28xx_capture_area_set(dev, 0, 2, width, height);
+       else
+               em28xx_capture_area_set(dev, 0, 0, width, height);
+
+       return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
+}
+
+/* Set USB alternate setting for analog video */
+static int em28xx_set_alternate(struct em28xx *dev)
+{
+       int errCode;
+       int i;
+       unsigned int min_pkt_size = dev->width * 2 + 4;
+
+       /* NOTE: for isoc transfers, only alt settings > 0 are allowed
+                bulk transfers seem to work only with alt=0 ! */
+       dev->alt = 0;
+       if ((alt > 0) && (alt < dev->num_alt)) {
+               em28xx_videodbg("alternate forced to %d\n", dev->alt);
+               dev->alt = alt;
+               goto set_alt;
+       }
+       if (dev->analog_xfer_bulk)
+               goto set_alt;
+
+       /* When image size is bigger than a certain value,
+          the frame size should be increased, otherwise, only
+          green screen will be received.
+        */
+       if (dev->width * 2 * dev->height > 720 * 240 * 2)
+               min_pkt_size *= 2;
+
+       for (i = 0; i < dev->num_alt; i++) {
+               /* stop when the selected alt setting offers enough bandwidth */
+               if (dev->alt_max_pkt_size_isoc[i] >= min_pkt_size) {
+                       dev->alt = i;
+                       break;
+               /* otherwise make sure that we end up with the maximum bandwidth
+                  because the min_pkt_size equation might be wrong...
+               */
+               } else if (dev->alt_max_pkt_size_isoc[i] >
+                          dev->alt_max_pkt_size_isoc[dev->alt])
+                       dev->alt = i;
+       }
+
+set_alt:
+       /* NOTE: for bulk transfers, we need to call usb_set_interface()
+        * even if the previous settings were the same. Otherwise streaming
+        * fails with all urbs having status = -EOVERFLOW ! */
+       if (dev->analog_xfer_bulk) {
+               dev->max_pkt_size = 512; /* USB 2.0 spec */
+               dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
+       } else { /* isoc */
+               em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n",
+                              min_pkt_size, dev->alt);
+               dev->max_pkt_size =
+                                 dev->alt_max_pkt_size_isoc[dev->alt];
+               dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
+       }
+       em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n",
+                      dev->alt, dev->max_pkt_size);
+       errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt);
+       if (errCode < 0) {
+               em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
+                             dev->alt, errCode);
+               return errCode;
+       }
+       return 0;
+}
+
 /* ------------------------------------------------------------------
        DMA and thread functions
    ------------------------------------------------------------------*/
@@ -763,7 +1020,7 @@ static struct vb2_ops em28xx_video_qops = {
        .wait_finish    = vb2_ops_wait_finish,
 };
 
-int em28xx_vb2_setup(struct em28xx *dev)
+static int em28xx_vb2_setup(struct em28xx *dev)
 {
        int rc;
        struct vb2_queue *q;
@@ -831,7 +1088,7 @@ static void video_mux(struct em28xx *dev, int index)
        em28xx_audio_analog_set(dev);
 }
 
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
+static void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv)
 {
        struct em28xx *dev = priv;
 
@@ -890,7 +1147,7 @@ static int em28xx_s_ctrl(struct v4l2_ctrl *ctrl)
        return (ret < 0) ? ret : 0;
 }
 
-const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
+static const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
        .s_ctrl = em28xx_s_ctrl,
 };
 
@@ -1368,7 +1625,7 @@ static int vidioc_g_register(struct file *file, void *priv,
                reg->val = ret;
        } else {
                __le16 val = 0;
-               ret = em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
+               ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
                                                   reg->reg, (char *)&val, 2);
                if (ret < 0)
                        return ret;
@@ -1570,6 +1827,10 @@ static int em28xx_v4l2_open(struct file *filp)
        case VFL_TYPE_VBI:
                fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
                break;
+       case VFL_TYPE_RADIO:
+               break;
+       default:
+               return -EINVAL;
        }
 
        em28xx_videodbg("open dev=%s type=%s users=%d\n",
@@ -1590,15 +1851,17 @@ static int em28xx_v4l2_open(struct file *filp)
        fh->type = fh_type;
        filp->private_data = fh;
 
-       if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+       if (dev->users == 0) {
                em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
-               em28xx_resolution_set(dev);
 
-               /* Needed, since GPIO might have disabled power of
-                  some i2c device
+               if (vdev->vfl_type != VFL_TYPE_RADIO)
+                       em28xx_resolution_set(dev);
+
+               /*
+                * Needed, since GPIO might have disabled power
+                * of some i2c devices
                 */
                em28xx_wake_i2c(dev);
-
        }
 
        if (vdev->vfl_type == VFL_TYPE_RADIO) {
@@ -1615,40 +1878,59 @@ static int em28xx_v4l2_open(struct file *filp)
 }
 
 /*
- * em28xx_realease_resources()
+ * em28xx_v4l2_fini()
  * unregisters the v4l2,i2c and usb devices
  * called when the device gets disconected or at module unload
 */
-void em28xx_release_analog_resources(struct em28xx *dev)
+static int em28xx_v4l2_fini(struct em28xx *dev)
 {
+       if (dev->is_audio_only) {
+               /* Shouldn't initialize IR for this interface */
+               return 0;
+       }
+
+       if (!dev->has_video) {
+               /* This device does not support the v4l2 extension */
+               return 0;
+       }
 
-       /*FIXME: I2C IR should be disconnected */
+       em28xx_info("Closing video extension");
+
+       mutex_lock(&dev->lock);
+
+       v4l2_device_disconnect(&dev->v4l2_dev);
+
+       em28xx_uninit_usb_xfer(dev, EM28XX_ANALOG_MODE);
 
        if (dev->radio_dev) {
-               if (video_is_registered(dev->radio_dev))
-                       video_unregister_device(dev->radio_dev);
-               else
-                       video_device_release(dev->radio_dev);
-               dev->radio_dev = NULL;
+               em28xx_info("V4L2 device %s deregistered\n",
+                           video_device_node_name(dev->radio_dev));
+               video_unregister_device(dev->radio_dev);
        }
        if (dev->vbi_dev) {
                em28xx_info("V4L2 device %s deregistered\n",
                            video_device_node_name(dev->vbi_dev));
-               if (video_is_registered(dev->vbi_dev))
-                       video_unregister_device(dev->vbi_dev);
-               else
-                       video_device_release(dev->vbi_dev);
-               dev->vbi_dev = NULL;
+               video_unregister_device(dev->vbi_dev);
        }
        if (dev->vdev) {
                em28xx_info("V4L2 device %s deregistered\n",
                            video_device_node_name(dev->vdev));
-               if (video_is_registered(dev->vdev))
-                       video_unregister_device(dev->vdev);
-               else
-                       video_device_release(dev->vdev);
-               dev->vdev = NULL;
+               video_unregister_device(dev->vdev);
        }
+
+       if (dev->clk) {
+               v4l2_clk_unregister_fixed(dev->clk);
+               dev->clk = NULL;
+       }
+
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       v4l2_device_unregister(&dev->v4l2_dev);
+
+       if (dev->users)
+               em28xx_warn("Device is open ! Memory deallocation is deferred on last close.\n");
+       mutex_unlock(&dev->lock);
+
+       return 0;
 }
 
 /*
@@ -1668,14 +1950,10 @@ static int em28xx_v4l2_close(struct file *filp)
        mutex_lock(&dev->lock);
 
        if (dev->users == 1) {
-               /* the device is already disconnect,
-                  free the remaining resources */
+               /* free the remaining resources if device is disconnected */
                if (dev->disconnected) {
-                       em28xx_release_resources(dev);
                        kfree(dev->alt_max_pkt_size_isoc);
-                       mutex_unlock(&dev->lock);
-                       kfree(dev);
-                       return 0;
+                       goto exit;
                }
 
                /* Save some power by putting tuner to sleep */
@@ -1694,11 +1972,29 @@ static int em28xx_v4l2_close(struct file *filp)
                }
        }
 
+exit:
        dev->users--;
        mutex_unlock(&dev->lock);
        return 0;
 }
 
+/*
+ * em28xx_videodevice_release()
+ * called when the last user of the video device exits and frees the memeory
+ */
+static void em28xx_videodevice_release(struct video_device *vdev)
+{
+       struct em28xx *dev = video_get_drvdata(vdev);
+
+       video_device_release(vdev);
+       if (vdev == dev->vdev)
+               dev->vdev = NULL;
+       else if (vdev == dev->vbi_dev)
+               dev->vbi_dev = NULL;
+       else if (vdev == dev->radio_dev)
+               dev->radio_dev = NULL;
+}
+
 static const struct v4l2_file_operations em28xx_v4l_fops = {
        .owner         = THIS_MODULE,
        .open          = em28xx_v4l2_open,
@@ -1753,11 +2049,10 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
 };
 
 static const struct video_device em28xx_video_template = {
-       .fops                       = &em28xx_v4l_fops,
-       .release                    = video_device_release_empty,
-       .ioctl_ops                  = &video_ioctl_ops,
-
-       .tvnorms                    = V4L2_STD_ALL,
+       .fops           = &em28xx_v4l_fops,
+       .ioctl_ops      = &video_ioctl_ops,
+       .release        = em28xx_videodevice_release,
+       .tvnorms        = V4L2_STD_ALL,
 };
 
 static const struct v4l2_file_operations radio_fops = {
@@ -1783,14 +2078,30 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
 };
 
 static struct video_device em28xx_radio_template = {
-       .name                 = "em28xx-radio",
-       .fops                 = &radio_fops,
-       .ioctl_ops            = &radio_ioctl_ops,
+       .fops           = &radio_fops,
+       .ioctl_ops      = &radio_ioctl_ops,
+       .release        = em28xx_videodevice_release,
 };
 
-/******************************** usb interface ******************************/
+/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
+static unsigned short saa711x_addrs[] = {
+       0x4a >> 1, 0x48 >> 1,   /* SAA7111, SAA7111A and SAA7113 */
+       0x42 >> 1, 0x40 >> 1,   /* SAA7114, SAA7115 and SAA7118 */
+       I2C_CLIENT_END };
 
+static unsigned short tvp5150_addrs[] = {
+       0xb8 >> 1,
+       0xba >> 1,
+       I2C_CLIENT_END
+};
 
+static unsigned short msp3400_addrs[] = {
+       0x80 >> 1,
+       0x88 >> 1,
+       I2C_CLIENT_END
+};
+
+/******************************** usb interface ******************************/
 
 static struct video_device *em28xx_vdev_init(struct em28xx *dev,
                                        const struct video_device *template,
@@ -1817,14 +2128,198 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
        return vfd;
 }
 
-int em28xx_register_analog_devices(struct em28xx *dev)
+static void em28xx_tuner_setup(struct em28xx *dev)
+{
+       struct tuner_setup           tun_setup;
+       struct v4l2_frequency        f;
+
+       if (dev->tuner_type == TUNER_ABSENT)
+               return;
+
+       memset(&tun_setup, 0, sizeof(tun_setup));
+
+       tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+       tun_setup.tuner_callback = em28xx_tuner_callback;
+
+       if (dev->board.radio.type) {
+               tun_setup.type = dev->board.radio.type;
+               tun_setup.addr = dev->board.radio_addr;
+
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+       }
+
+       if ((dev->tuner_type != TUNER_ABSENT) && (dev->tuner_type)) {
+               tun_setup.type   = dev->tuner_type;
+               tun_setup.addr   = dev->tuner_addr;
+
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_type_addr, &tun_setup);
+       }
+
+       if (dev->tda9887_conf) {
+               struct v4l2_priv_tun_config tda9887_cfg;
+
+               tda9887_cfg.tuner = TUNER_TDA9887;
+               tda9887_cfg.priv = &dev->tda9887_conf;
+
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &tda9887_cfg);
+       }
+
+       if (dev->tuner_type == TUNER_XC2028) {
+               struct v4l2_priv_tun_config  xc2028_cfg;
+               struct xc2028_ctrl           ctl;
+
+               memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+               memset(&ctl, 0, sizeof(ctl));
+
+               em28xx_setup_xc3028(dev, &ctl);
+
+               xc2028_cfg.tuner = TUNER_XC2028;
+               xc2028_cfg.priv  = &ctl;
+
+               v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_config, &xc2028_cfg);
+       }
+
+       /* configure tuner */
+       f.tuner = 0;
+       f.type = V4L2_TUNER_ANALOG_TV;
+       f.frequency = 9076;     /* just a magic number */
+       dev->ctl_freq = f.frequency;
+       v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, &f);
+}
+
+static int em28xx_v4l2_init(struct em28xx *dev)
 {
        u8 val;
        int ret;
        unsigned int maxw;
+       struct v4l2_ctrl_handler *hdl = &dev->ctrl_handler;
+
+       if (dev->is_audio_only) {
+               /* Shouldn't initialize IR for this interface */
+               return 0;
+       }
+
+       if (!dev->has_video) {
+               /* This device does not support the v4l2 extension */
+               return 0;
+       }
+
+       em28xx_info("Registering V4L2 extension\n");
+
+       mutex_lock(&dev->lock);
+
+       ret = v4l2_device_register(&dev->udev->dev, &dev->v4l2_dev);
+       if (ret < 0) {
+               em28xx_errdev("Call to v4l2_device_register() failed!\n");
+               goto err;
+       }
+
+       v4l2_ctrl_handler_init(hdl, 8);
+       dev->v4l2_dev.ctrl_handler = hdl;
+
+       /*
+        * Default format, used for tvp5150 or saa711x output formats
+        */
+       dev->vinmode = 0x10;
+       dev->vinctl  = EM28XX_VINCTRL_INTERLACED |
+                      EM28XX_VINCTRL_CCIR656_ENABLE;
+
+       /* request some modules */
+
+       if (dev->board.has_msp34xx)
+               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+                       "msp3400", 0, msp3400_addrs);
+
+       if (dev->board.decoder == EM28XX_SAA711X)
+               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+                       "saa7115_auto", 0, saa711x_addrs);
+
+       if (dev->board.decoder == EM28XX_TVP5150)
+               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+                       "tvp5150", 0, tvp5150_addrs);
+
+       if (dev->board.adecoder == EM28XX_TVAUDIO)
+               v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+                       "tvaudio", dev->board.tvaudio_addr, NULL);
+
+       /* Initialize tuner and camera */
+
+       if (dev->board.tuner_type != TUNER_ABSENT) {
+               int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
+
+               if (dev->board.radio.type)
+                       v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+                               "tuner", dev->board.radio_addr, NULL);
+
+               if (has_demod)
+                       v4l2_i2c_new_subdev(&dev->v4l2_dev,
+                               &dev->i2c_adap[dev->def_i2c_bus], "tuner",
+                               0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+               if (dev->tuner_addr == 0) {
+                       enum v4l2_i2c_tuner_type type =
+                               has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
+                       struct v4l2_subdev *sd;
+
+                       sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+                               &dev->i2c_adap[dev->def_i2c_bus], "tuner",
+                               0, v4l2_i2c_tuner_addrs(type));
+
+                       if (sd)
+                               dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
+               } else {
+                       v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap[dev->def_i2c_bus],
+                               "tuner", dev->tuner_addr, NULL);
+               }
+       }
+
+       em28xx_tuner_setup(dev);
+       em28xx_init_camera(dev);
+
+       /* Configure audio */
+       ret = em28xx_audio_setup(dev);
+       if (ret < 0) {
+               em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
+                       __func__, ret);
+               goto unregister_dev;
+       }
+       if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
+               v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+                       V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+               v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
+                       V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
+       } else {
+               /* install the em28xx notify callback */
+               v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
+                               em28xx_ctrl_notify, dev);
+               v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
+                               em28xx_ctrl_notify, dev);
+       }
+
+       /* wake i2c devices */
+       em28xx_wake_i2c(dev);
+
+       /* init video dma queues */
+       INIT_LIST_HEAD(&dev->vidq.active);
+       INIT_LIST_HEAD(&dev->vbiq.active);
 
-       printk(KERN_INFO "%s: v4l2 driver version %s\n",
-               dev->name, EM28XX_VERSION);
+       if (dev->board.has_msp34xx) {
+               /* Send a reset to other chips via gpio */
+               ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xf7);
+               if (ret < 0) {
+                       em28xx_errdev("%s: em28xx_write_reg - msp34xx(1) failed! error [%d]\n",
+                                     __func__, ret);
+                       goto unregister_dev;
+               }
+               msleep(3);
+
+               ret = em28xx_write_reg(dev, EM2820_R08_GPIO_CTRL, 0xff);
+               if (ret < 0) {
+                       em28xx_errdev("%s: em28xx_write_reg - msp34xx(2) failed! error [%d]\n",
+                                     __func__, ret);
+                       goto unregister_dev;
+               }
+               msleep(3);
+       }
 
        /* set default norm */
        dev->norm = V4L2_STD_PAL;
@@ -1888,14 +2383,16 @@ int em28xx_register_analog_devices(struct em28xx *dev)
        /* Reset image controls */
        em28xx_colorlevels_set_default(dev);
        v4l2_ctrl_handler_setup(&dev->ctrl_handler);
-       if (dev->ctrl_handler.error)
-               return dev->ctrl_handler.error;
+       ret = dev->ctrl_handler.error;
+       if (ret)
+               goto unregister_dev;
 
        /* allocate and fill video video_device struct */
        dev->vdev = em28xx_vdev_init(dev, &em28xx_video_template, "video");
        if (!dev->vdev) {
                em28xx_errdev("cannot allocate video_device.\n");
-               return -ENODEV;
+               ret = -ENODEV;
+               goto unregister_dev;
        }
        dev->vdev->queue = &dev->vb_vidq;
        dev->vdev->queue->lock = &dev->vb_queue_lock;
@@ -1925,7 +2422,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
        if (ret) {
                em28xx_errdev("unable to register video device (error=%i).\n",
                              ret);
-               return ret;
+               goto unregister_dev;
        }
 
        /* Allocate and fill vbi video_device struct */
@@ -1954,7 +2451,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
                                            vbi_nr[dev->devno]);
                if (ret < 0) {
                        em28xx_errdev("unable to register vbi device\n");
-                       return ret;
+                       goto unregister_dev;
                }
        }
 
@@ -1963,13 +2460,14 @@ int em28xx_register_analog_devices(struct em28xx *dev)
                                                  "radio");
                if (!dev->radio_dev) {
                        em28xx_errdev("cannot allocate video_device.\n");
-                       return -ENODEV;
+                       ret = -ENODEV;
+                       goto unregister_dev;
                }
                ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
                                            radio_nr[dev->devno]);
                if (ret < 0) {
                        em28xx_errdev("can't register radio device\n");
-                       return ret;
+                       goto unregister_dev;
                }
                em28xx_info("Registered radio device as %s\n",
                            video_device_node_name(dev->radio_dev));
@@ -1982,5 +2480,41 @@ int em28xx_register_analog_devices(struct em28xx *dev)
                em28xx_info("V4L2 VBI device registered as %s\n",
                            video_device_node_name(dev->vbi_dev));
 
+       /* Save some power by putting tuner to sleep */
+       v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
+
+       /* initialize videobuf2 stuff */
+       em28xx_vb2_setup(dev);
+
+       em28xx_info("V4L2 extension successfully initialized\n");
+
+       mutex_unlock(&dev->lock);
        return 0;
+
+unregister_dev:
+       v4l2_ctrl_handler_free(&dev->ctrl_handler);
+       v4l2_device_unregister(&dev->v4l2_dev);
+err:
+       mutex_unlock(&dev->lock);
+       return ret;
+}
+
+static struct em28xx_ops v4l2_ops = {
+       .id   = EM28XX_V4L2,
+       .name = "Em28xx v4l2 Extension",
+       .init = em28xx_v4l2_init,
+       .fini = em28xx_v4l2_fini,
+};
+
+static int __init em28xx_video_register(void)
+{
+       return em28xx_register_extension(&v4l2_ops);
+}
+
+static void __exit em28xx_video_unregister(void)
+{
+       em28xx_unregister_extension(&v4l2_ops);
 }
+
+module_init(em28xx_video_register);
+module_exit(em28xx_video_unregister);
index f8726ad5d0a8776063c6acbc482c9180ee10b08c..32d8a4bb79613c8016d0209160af122532d072d5 100644 (file)
@@ -26,6 +26,9 @@
 #ifndef _EM28XX_H
 #define _EM28XX_H
 
+#define EM28XX_VERSION "0.2.1"
+#define DRIVER_DESC    "Empia em28xx device driver"
+
 #include <linux/workqueue.h>
 #include <linux/i2c.h>
 #include <linux/mutex.h>
 #define EM2884_BOARD_C3TECH_DIGITAL_DUO                  88
 #define EM2874_BOARD_DELOCK_61959                89
 #define EM2874_BOARD_KWORLD_UB435Q_V2            90
+#define EM2765_BOARD_SPEEDLINK_VAD_LAPLACE       91
+#define EM28178_BOARD_PCTV_461E                   92
 
 /* Limits minimum and default number of buffers */
 #define EM28XX_MIN_BUF 4
 
 #define EM28XX_INTERLACED_DEFAULT 1
 
-/* time in msecs to wait for i2c writes to finish */
-#define EM2800_I2C_XFER_TIMEOUT                20
+/*
+ * Time in msecs to wait for i2c xfers to finish.
+ * 35ms is the maximum time a SMBUS device could wait when
+ * clock stretching is used. As the transfer itself will take
+ * some time to happen, set it to 35 ms.
+ *
+ * Ok, I2C doesn't specify any limit. So, eventually, we may need
+ * to increase this timeout.
+ *
+ * FIXME: this assumes that an I2C message is not longer than 1ms.
+ * This is actually dependent on the I2C bus speed, although most
+ * devices use a 100kHz clock. So, this assumtion is true most of
+ * the time.
+ */
+#define EM28XX_I2C_XFER_TIMEOUT                36
+
+/* time in msecs to wait for AC97 xfers to finish */
+#define EM28XX_AC97_XFER_TIMEOUT       100
+
+/* max. number of button state polling addresses */
+#define EM28XX_NUM_BUTTON_ADDRESSES_MAX                5
 
 enum em28xx_mode {
        EM28XX_SUSPEND,
@@ -287,8 +311,7 @@ struct em28xx_audio_mode {
 
        unsigned int has_audio:1;
 
-       unsigned int i2s_3rates:1;
-       unsigned int i2s_5rates:1;
+       u8 i2s_samplerates;
 };
 
 /* em28xx has two audio inputs: tuner and line in.
@@ -374,6 +397,33 @@ enum em28xx_adecoder {
        EM28XX_TVAUDIO,
 };
 
+enum em28xx_led_role {
+       EM28XX_LED_ANALOG_CAPTURING = 0,
+       EM28XX_LED_ILLUMINATION,
+       EM28XX_NUM_LED_ROLES, /* must be the last */
+};
+
+struct em28xx_led {
+       enum em28xx_led_role role;
+       u8 gpio_reg;
+       u8 gpio_mask;
+       bool inverted;
+};
+
+enum em28xx_button_role {
+       EM28XX_BUTTON_SNAPSHOT = 0,
+       EM28XX_BUTTON_ILLUMINATION,
+       EM28XX_NUM_BUTTON_ROLES, /* must be the last */
+};
+
+struct em28xx_button {
+       enum em28xx_button_role role;
+       u8 reg_r;
+       u8 reg_clearing;
+       u8 mask;
+       bool inverted;
+};
+
 struct em28xx_board {
        char *name;
        int vchannels;
@@ -395,7 +445,6 @@ struct em28xx_board {
        unsigned int mts_firmware:1;
        unsigned int max_range_640_480:1;
        unsigned int has_dvb:1;
-       unsigned int has_snapshot_button:1;
        unsigned int is_webcam:1;
        unsigned int valid:1;
        unsigned int has_ir_i2c:1;
@@ -410,6 +459,12 @@ struct em28xx_board {
        struct em28xx_input       input[MAX_EM28XX_INPUT];
        struct em28xx_input       radio;
        char                      *ir_codes;
+
+       /* LEDs that need to be controlled explicitly */
+       struct em28xx_led         *leds;
+
+       /* Buttons */
+       struct em28xx_button      *buttons;
 };
 
 struct em28xx_eeprom {
@@ -426,15 +481,13 @@ struct em28xx_eeprom {
        u8 string_idx_table;
 };
 
-#define EM28XX_AUDIO_BUFS 5
-#define EM28XX_NUM_AUDIO_PACKETS 64
-#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
 #define EM28XX_CAPTURE_STREAM_EN 1
 
 /* em28xx extensions */
 #define EM28XX_AUDIO   0x10
 #define EM28XX_DVB     0x20
 #define EM28XX_RC      0x30
+#define EM28XX_V4L2    0x40
 
 /* em28xx resource types (used for res_get/res_lock etc */
 #define EM28XX_RESOURCE_VIDEO 0x01
@@ -442,8 +495,9 @@ struct em28xx_eeprom {
 
 struct em28xx_audio {
        char name[50];
-       char *transfer_buffer[EM28XX_AUDIO_BUFS];
-       struct urb *urb[EM28XX_AUDIO_BUFS];
+       unsigned num_urb;
+       char **transfer_buffer;
+       struct urb **urb;
        struct usb_device *udev;
        unsigned int capture_transfer_done;
        struct snd_pcm_substream   *capture_pcm_substream;
@@ -451,6 +505,8 @@ struct em28xx_audio {
        unsigned int hwptr_done_capture;
        struct snd_card            *sndcard;
 
+       size_t period;
+
        int users;
        spinlock_t slock;
 };
@@ -485,11 +541,13 @@ struct em28xx {
        int model;              /* index in the device_data struct */
        int devno;              /* marks the number of this device */
        enum em28xx_chip_id chip_id;
-       unsigned int is_em25xx:1;       /* em25xx/em276x/7x/8x family bridge */
 
+       unsigned int is_em25xx:1;       /* em25xx/em276x/7x/8x family bridge */
        unsigned char disconnected:1;   /* device has been diconnected */
-
-       int audio_ifnum;
+       unsigned int has_video:1;
+       unsigned int has_audio_class:1;
+       unsigned int has_alsa_audio:1;
+       unsigned int is_audio_only:1;
 
        struct v4l2_device v4l2_dev;
        struct v4l2_ctrl_handler ctrl_handler;
@@ -507,10 +565,6 @@ struct em28xx {
        /* Vinmode/Vinctl used at the driver */
        int vinmode, vinctl;
 
-       unsigned int has_audio_class:1;
-       unsigned int has_alsa_audio:1;
-       unsigned int is_audio_only:1;
-
        /* Controls audio streaming */
        struct work_struct wq_trigger;  /* Trigger to start/stop audio for alsa module */
        atomic_t       stream_started;  /* stream should be running if true */
@@ -608,6 +662,7 @@ struct em28xx {
 
        /* usb transfer */
        struct usb_device *udev;        /* the usb device */
+       u8 ifnum;               /* number of the assigned usb interface */
        u8 analog_ep_isoc;      /* address of isoc endpoint for analog */
        u8 analog_ep_bulk;      /* address of bulk endpoint for analog */
        u8 dvb_ep_isoc;         /* address of isoc endpoint for DVB */
@@ -639,10 +694,15 @@ struct em28xx {
 
        enum em28xx_mode mode;
 
-       /* Snapshot button */
+       /* Button state polling */
+       struct delayed_work buttons_query_work;
+       u8 button_polling_addresses[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
+       u8 button_polling_last_values[EM28XX_NUM_BUTTON_ADDRESSES_MAX];
+       u8 num_button_polling_addresses;
+       u16 button_polling_interval; /* [ms] */
+       /* Snapshot button input device */
        char snapshot_button_path[30];  /* path of the input dev */
        struct input_dev *sbutton_input_dev;
-       struct delayed_work sbutton_query_work;
 
        struct em28xx_dvb *dvb;
 };
@@ -672,6 +732,7 @@ int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
 int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
 int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
                                 u8 bitmask);
+int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask);
 
 int em28xx_read_ac97(struct em28xx *dev, u8 reg);
 int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
@@ -679,12 +740,9 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val);
 int em28xx_audio_analog_set(struct em28xx *dev);
 int em28xx_audio_setup(struct em28xx *dev);
 
-int em28xx_colorlevels_set_default(struct em28xx *dev);
+const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
+                                        enum em28xx_led_role role);
 int em28xx_capture_start(struct em28xx *dev, int start);
-int em28xx_vbi_supported(struct em28xx *dev);
-int em28xx_set_outfmt(struct em28xx *dev);
-int em28xx_resolution_set(struct em28xx *dev);
-int em28xx_set_alternate(struct em28xx *dev);
 int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
                      int num_bufs, int max_pkt_size, int packet_multiplier);
 int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
@@ -696,30 +754,18 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode);
 void em28xx_stop_urbs(struct em28xx *dev);
 int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
 int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
-void em28xx_wake_i2c(struct em28xx *dev);
 int em28xx_register_extension(struct em28xx_ops *dev);
 void em28xx_unregister_extension(struct em28xx_ops *dev);
 void em28xx_init_extension(struct em28xx *dev);
 void em28xx_close_extension(struct em28xx *dev);
 
-/* Provided by em28xx-video.c */
-int em28xx_vb2_setup(struct em28xx *dev);
-int em28xx_register_analog_devices(struct em28xx *dev);
-void em28xx_release_analog_resources(struct em28xx *dev);
-void em28xx_ctrl_notify(struct v4l2_ctrl *ctrl, void *priv);
-int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
-int em28xx_stop_vbi_streaming(struct vb2_queue *vq);
-extern const struct v4l2_ctrl_ops em28xx_ctrl_ops;
-
 /* Provided by em28xx-cards.c */
 extern struct em28xx_board em28xx_boards[];
 extern struct usb_device_id em28xx_id_table[];
 int em28xx_tuner_callback(void *ptr, int component, int command, int arg);
+void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl);
 void em28xx_release_resources(struct em28xx *dev);
 
-/* Provided by em28xx-vbi.c */
-extern struct vb2_ops em28xx_vbi_qops;
-
 /* Provided by em28xx-camera.c */
 int em28xx_detect_sensor(struct em28xx *dev);
 int em28xx_init_camera(struct em28xx *dev);
index 78c9bc8e7f561744364a6de94f4aeaae382dd077..abf365ab025da5a92d432c06b61bf223642b0a37 100644 (file)
@@ -1078,7 +1078,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
        /* register webcam snapshot button input device */
        pdev->button_dev = input_allocate_device();
        if (!pdev->button_dev) {
-               PWC_ERROR("Err, insufficient memory for webcam snapshot button device.");
                rc = -ENOMEM;
                goto err_video_unreg;
        }
index 8c05565a240e4ef7f36c6fe7859eb4a21a199193..2189bfb2e8287759034c2236a5b31d7db85b06c3 100644 (file)
@@ -83,14 +83,3 @@ config VIDEOBUF2_DMA_SG
        #depends on HAS_DMA
        select VIDEOBUF2_CORE
        select VIDEOBUF2_MEMOPS
-
-config VIDEO_V4L2_INT_DEVICE
-       tristate "V4L2 int device (DEPRECATED)"
-       depends on VIDEO_V4L2
-       ---help---
-         An early framework for a hardware-independent interface for
-         image sensors and bridges etc. Currently used by omap24xxcam and
-         tcm825x drivers that should be converted to V4L2 subdev.
-
-         Do not use for new developments.
-
index 1a85eee581f8ebde5de908638c47edf0de15631f..c6ae7bad951ec1b27177bc0e134b9277fd8bf4c8 100644 (file)
@@ -15,7 +15,6 @@ ifeq ($(CONFIG_OF),y)
 endif
 
 obj-$(CONFIG_VIDEO_V4L2) += videodev.o
-obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o
 obj-$(CONFIG_VIDEO_V4L2) += v4l2-common.o
 obj-$(CONFIG_VIDEO_V4L2) += v4l2-dv-timings.o
 
index fb46790d0eca795d5e411c54bf7129d96e61d3e9..6ff002bd5909045e97ed56d51ecb3813877583cb 100644 (file)
@@ -745,6 +745,11 @@ const char *v4l2_ctrl_get_name(u32 id)
        case V4L2_CID_MPEG_VIDEO_VPX_FILTER_SHARPNESS:          return "VPX Deblocking Effect Control";
        case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_REF_PERIOD:   return "VPX Golden Frame Refresh Period";
        case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:          return "VPX Golden Frame Indicator";
+       case V4L2_CID_MPEG_VIDEO_VPX_MIN_QP:                    return "VPX Minimum QP Value";
+       case V4L2_CID_MPEG_VIDEO_VPX_MAX_QP:                    return "VPX Maximum QP Value";
+       case V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP:                return "VPX I-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP:                return "VPX P-Frame QP Value";
+       case V4L2_CID_MPEG_VIDEO_VPX_PROFILE:                   return "VPX Profile";
 
        /* CAMERA controls */
        /* Keep the order of the 'case's the same as in videodev2.h! */
index b5aaaac427add9180221b4bd19fe88133e6bc212..0a30dbf3d05c8c1c26086df64ac8382118643d84 100644 (file)
@@ -872,8 +872,8 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
 
        /* Should not happen since we thought this minor was free */
        WARN_ON(video_device[vdev->minor] != NULL);
-       video_device[vdev->minor] = vdev;
        vdev->index = get_index(vdev);
+       video_device[vdev->minor] = vdev;
        mutex_unlock(&videodev_lock);
 
        if (vdev->ioctl_ops)
index 68e6b5e912ff6221a0c6ca04231e3e4925f806ff..707aef705a475bd49fac2cdcf78e06f5e30c5ccd 100644 (file)
@@ -28,6 +28,9 @@
 #include <media/v4l2-device.h>
 #include <media/videobuf2-core.h>
 
+#define CREATE_TRACE_POINTS
+#include <trace/events/v4l2.h>
+
 /* Zero out the end of the struct pointed to by p.  Everything after, but
  * not including, the specified field is cleared. */
 #define CLEAR_AFTER_FIELD(p, field) \
@@ -2338,6 +2341,12 @@ video_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
        err = func(file, cmd, parg);
        if (err == -ENOIOCTLCMD)
                err = -ENOTTY;
+       if (err == 0) {
+               if (cmd == VIDIOC_DQBUF)
+                       trace_v4l2_dqbuf(video_devdata(file)->minor, parg);
+               else if (cmd == VIDIOC_QBUF)
+                       trace_v4l2_qbuf(video_devdata(file)->minor, parg);
+       }
 
        if (has_array_args) {
                *kernel_ptr = user_ptr;
index 73035ee0f4def8c7425872dba6c1687419b1303f..178ce96556c6424432a9220295219ccd0dadf4e7 100644 (file)
@@ -558,6 +558,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 
        if (m2m_ctx->m2m_dev->m2m_ops->unlock)
                m2m_ctx->m2m_dev->m2m_ops->unlock(m2m_ctx->priv);
+       else if (m2m_ctx->q_lock)
+               mutex_unlock(m2m_ctx->q_lock);
 
        if (list_empty(&src_q->done_list))
                poll_wait(file, &src_q->done_wq, wait);
@@ -566,6 +568,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
 
        if (m2m_ctx->m2m_dev->m2m_ops->lock)
                m2m_ctx->m2m_dev->m2m_ops->lock(m2m_ctx->priv);
+       else if (m2m_ctx->q_lock)
+               mutex_lock(m2m_ctx->q_lock);
 
        spin_lock_irqsave(&src_q->done_lock, flags);
        if (!list_empty(&src_q->done_list))
@@ -693,6 +697,13 @@ struct v4l2_m2m_ctx *v4l2_m2m_ctx_init(struct v4l2_m2m_dev *m2m_dev,
 
        if (ret)
                goto err;
+       /*
+        * If both queues use same mutex assign it as the common buffer
+        * queues lock to the m2m context. This lock is used in the
+        * v4l2_m2m_ioctl_* helpers.
+        */
+       if (out_q_ctx->q.lock == cap_q_ctx->q.lock)
+               m2m_ctx->q_lock = out_q_ctx->q.lock;
 
        return m2m_ctx;
 err:
@@ -740,3 +751,118 @@ void v4l2_m2m_buf_queue(struct v4l2_m2m_ctx *m2m_ctx, struct vb2_buffer *vb)
 }
 EXPORT_SYMBOL_GPL(v4l2_m2m_buf_queue);
 
+/* Videobuf2 ioctl helpers */
+
+int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv,
+                               struct v4l2_requestbuffers *rb)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_reqbufs(file, fh->m2m_ctx, rb);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_reqbufs);
+
+int v4l2_m2m_ioctl_create_bufs(struct file *file, void *priv,
+                               struct v4l2_create_buffers *create)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_create_bufs(file, fh->m2m_ctx, create);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_create_bufs);
+
+int v4l2_m2m_ioctl_querybuf(struct file *file, void *priv,
+                               struct v4l2_buffer *buf)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_querybuf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_querybuf);
+
+int v4l2_m2m_ioctl_qbuf(struct file *file, void *priv,
+                               struct v4l2_buffer *buf)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_qbuf);
+
+int v4l2_m2m_ioctl_dqbuf(struct file *file, void *priv,
+                               struct v4l2_buffer *buf)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_dqbuf(file, fh->m2m_ctx, buf);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_dqbuf);
+
+int v4l2_m2m_ioctl_expbuf(struct file *file, void *priv,
+                               struct v4l2_exportbuffer *eb)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_expbuf(file, fh->m2m_ctx, eb);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_expbuf);
+
+int v4l2_m2m_ioctl_streamon(struct file *file, void *priv,
+                               enum v4l2_buf_type type)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_streamon(file, fh->m2m_ctx, type);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamon);
+
+int v4l2_m2m_ioctl_streamoff(struct file *file, void *priv,
+                               enum v4l2_buf_type type)
+{
+       struct v4l2_fh *fh = file->private_data;
+
+       return v4l2_m2m_streamoff(file, fh->m2m_ctx, type);
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_ioctl_streamoff);
+
+/*
+ * v4l2_file_operations helpers. It is assumed here same lock is used
+ * for the output and the capture buffer queue.
+ */
+
+int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct v4l2_fh *fh = file->private_data;
+       struct v4l2_m2m_ctx *m2m_ctx = fh->m2m_ctx;
+       int ret;
+
+       if (m2m_ctx->q_lock && mutex_lock_interruptible(m2m_ctx->q_lock))
+               return -ERESTARTSYS;
+
+       ret = v4l2_m2m_mmap(file, m2m_ctx, vma);
+
+       if (m2m_ctx->q_lock)
+               mutex_unlock(m2m_ctx->q_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_fop_mmap);
+
+unsigned int v4l2_m2m_fop_poll(struct file *file, poll_table *wait)
+{
+       struct v4l2_fh *fh = file->private_data;
+       struct v4l2_m2m_ctx *m2m_ctx = fh->m2m_ctx;
+       unsigned int ret;
+
+       if (m2m_ctx->q_lock)
+               mutex_lock(m2m_ctx->q_lock);
+
+       ret = v4l2_m2m_poll(file, m2m_ctx, wait);
+
+       if (m2m_ctx->q_lock)
+               mutex_unlock(m2m_ctx->q_lock);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_m2m_fop_poll);
+
index a6478dca0cde8086f27ced521cb3a26305793408..42e3e8a5e3613a5e78eef9c5a39fe6e85232ad22 100644 (file)
@@ -121,9 +121,11 @@ static void v4l2_of_parse_parallel_bus(const struct device_node *node,
  * the bus as serial CSI-2 and clock-noncontinuous isn't set, we set the
  * V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag.
  * The caller should hold a reference to @node.
+ *
+ * Return: 0.
  */
-void v4l2_of_parse_endpoint(const struct device_node *node,
-                           struct v4l2_of_endpoint *endpoint)
+int v4l2_of_parse_endpoint(const struct device_node *node,
+                          struct v4l2_of_endpoint *endpoint)
 {
        struct device_node *port_node = of_get_parent(node);
 
@@ -146,6 +148,8 @@ void v4l2_of_parse_endpoint(const struct device_node *node,
                v4l2_of_parse_parallel_bus(node, endpoint);
 
        of_node_put(port_node);
+
+       return 0;
 }
 EXPORT_SYMBOL(v4l2_of_parse_endpoint);
 
@@ -262,6 +266,6 @@ struct device_node *v4l2_of_get_remote_port(const struct device_node *node)
        np = of_parse_phandle(node, "remote-endpoint", 0);
        if (!np)
                return NULL;
-       return of_get_parent(np);
+       return of_get_next_parent(np);
 }
 EXPORT_SYMBOL(v4l2_of_get_remote_port);
index 0edc165f418d9449f46e5696e4e093e7b3288fd1..5a5fb7f09b7bd1857bc7e660c24d7e1b95117dc6 100644 (file)
@@ -298,10 +298,28 @@ static void __vb2_free_mem(struct vb2_queue *q, unsigned int buffers)
  * related information, if no buffers are left return the queue to an
  * uninitialized state. Might be called even if the queue has already been freed.
  */
-static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
+static int __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
 {
        unsigned int buffer;
 
+       /*
+        * Sanity check: when preparing a buffer the queue lock is released for
+        * a short while (see __buf_prepare for the details), which would allow
+        * a race with a reqbufs which can call this function. Removing the
+        * buffers from underneath __buf_prepare is obviously a bad idea, so we
+        * check if any of the buffers is in the state PREPARING, and if so we
+        * just return -EAGAIN.
+        */
+       for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
+            ++buffer) {
+               if (q->bufs[buffer] == NULL)
+                       continue;
+               if (q->bufs[buffer]->state == VB2_BUF_STATE_PREPARING) {
+                       dprintk(1, "reqbufs: preparing buffers, cannot free\n");
+                       return -EAGAIN;
+               }
+       }
+
        /* Call driver-provided cleanup function for each buffer, if provided */
        if (q->ops->buf_cleanup) {
                for (buffer = q->num_buffers - buffers; buffer < q->num_buffers;
@@ -326,6 +344,7 @@ static void __vb2_queue_free(struct vb2_queue *q, unsigned int buffers)
        if (!q->num_buffers)
                q->memory = 0;
        INIT_LIST_HEAD(&q->queued_list);
+       return 0;
 }
 
 /**
@@ -481,6 +500,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b)
        case VB2_BUF_STATE_PREPARED:
                b->flags |= V4L2_BUF_FLAG_PREPARED;
                break;
+       case VB2_BUF_STATE_PREPARING:
        case VB2_BUF_STATE_DEQUEUED:
                /* nothing */
                break;
@@ -657,7 +677,9 @@ static int __reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
                        return -EBUSY;
                }
 
-               __vb2_queue_free(q, q->num_buffers);
+               ret = __vb2_queue_free(q, q->num_buffers);
+               if (ret)
+                       return ret;
 
                /*
                 * In case of REQBUFS(0) return immediately without calling
@@ -1116,7 +1138,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
        int ret;
        int write = !V4L2_TYPE_IS_OUTPUT(q->type);
 
-       /* Verify and copy relevant information provided by the userspace */
+       /* Copy relevant information provided by the userspace */
        __fill_vb2_buffer(vb, b, planes);
 
        for (plane = 0; plane < vb->num_planes; ++plane) {
@@ -1135,6 +1157,8 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
 
                if (planes[plane].length < planes[plane].data_offset +
                    q->plane_sizes[plane]) {
+                       dprintk(1, "qbuf: invalid dmabuf length for plane %d\n",
+                               plane);
                        ret = -EINVAL;
                        goto err;
                }
@@ -1226,6 +1250,7 @@ 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);
@@ -1235,12 +1260,32 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
                return ret;
        }
 
+       vb->state = VB2_BUF_STATE_PREPARING;
        switch (q->memory) {
        case V4L2_MEMORY_MMAP:
                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_qop(q, wait_prepare, q);
+               down_read(mmap_sem);
+               call_qop(q, wait_finish, q);
+
                ret = __qbuf_userptr(vb, b);
+
+               up_read(mmap_sem);
                break;
        case V4L2_MEMORY_DMABUF:
                ret = __qbuf_dmabuf(vb, b);
@@ -1254,105 +1299,36 @@ static int __buf_prepare(struct vb2_buffer *vb, const struct v4l2_buffer *b)
                ret = call_qop(q, buf_prepare, vb);
        if (ret)
                dprintk(1, "qbuf: buffer preparation failed: %d\n", ret);
-       else
-               vb->state = VB2_BUF_STATE_PREPARED;
+       vb->state = ret ? VB2_BUF_STATE_DEQUEUED : VB2_BUF_STATE_PREPARED;
 
        return ret;
 }
 
 static int vb2_queue_or_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
-                                   const char *opname,
-                                   int (*handler)(struct vb2_queue *,
-                                                  struct v4l2_buffer *,
-                                                  struct vb2_buffer *))
+                                   const char *opname)
 {
-       struct rw_semaphore *mmap_sem = NULL;
-       struct vb2_buffer *vb;
-       int ret;
-
-       /*
-        * 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.
-        *
-        * To avoid racing with other vb2 calls, which might be called after
-        * releasing the driver's lock, this operation is performed at the
-        * beginning of qbuf/prepare_buf processing. This way the queue status
-        * is consistent after getting the driver's lock back.
-        */
-       if (q->memory == V4L2_MEMORY_USERPTR) {
-               mmap_sem = &current->mm->mmap_sem;
-               call_qop(q, wait_prepare, q);
-               down_read(mmap_sem);
-               call_qop(q, wait_finish, q);
-       }
-
-       if (q->fileio) {
-               dprintk(1, "%s(): file io in progress\n", opname);
-               ret = -EBUSY;
-               goto unlock;
-       }
-
        if (b->type != q->type) {
                dprintk(1, "%s(): invalid buffer type\n", opname);
-               ret = -EINVAL;
-               goto unlock;
+               return -EINVAL;
        }
 
        if (b->index >= q->num_buffers) {
                dprintk(1, "%s(): buffer index out of range\n", opname);
-               ret = -EINVAL;
-               goto unlock;
+               return -EINVAL;
        }
 
-       vb = q->bufs[b->index];
-       if (NULL == vb) {
+       if (q->bufs[b->index] == NULL) {
                /* Should never happen */
                dprintk(1, "%s(): buffer is NULL\n", opname);
-               ret = -EINVAL;
-               goto unlock;
+               return -EINVAL;
        }
 
        if (b->memory != q->memory) {
                dprintk(1, "%s(): invalid memory type\n", opname);
-               ret = -EINVAL;
-               goto unlock;
-       }
-
-       ret = __verify_planes_array(vb, b);
-       if (ret)
-               goto unlock;
-
-       ret = handler(q, b, vb);
-       if (ret)
-               goto unlock;
-
-       /* Fill buffer information for the userspace */
-       __fill_v4l2_buffer(vb, b);
-
-       dprintk(1, "%s() of buffer %d succeeded\n", opname, vb->v4l2_buf.index);
-unlock:
-       if (mmap_sem)
-               up_read(mmap_sem);
-       return ret;
-}
-
-static int __vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
-                            struct vb2_buffer *vb)
-{
-       if (vb->state != VB2_BUF_STATE_DEQUEUED) {
-               dprintk(1, "%s(): invalid buffer state %d\n", __func__,
-                       vb->state);
                return -EINVAL;
        }
 
-       return __buf_prepare(vb, b);
+       return __verify_planes_array(q->bufs[b->index], b);
 }
 
 /**
@@ -1372,22 +1348,95 @@ static int __vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b,
  */
 int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
 {
-       return vb2_queue_or_prepare_buf(q, b, "prepare_buf", __vb2_prepare_buf);
+       struct vb2_buffer *vb;
+       int ret;
+
+       if (q->fileio) {
+               dprintk(1, "%s(): file io in progress\n", __func__);
+               return -EBUSY;
+       }
+
+       ret = vb2_queue_or_prepare_buf(q, b, "prepare_buf");
+       if (ret)
+               return ret;
+
+       vb = q->bufs[b->index];
+       if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+               dprintk(1, "%s(): invalid buffer state %d\n", __func__,
+                       vb->state);
+               return -EINVAL;
+       }
+
+       ret = __buf_prepare(vb, b);
+       if (!ret) {
+               /* Fill buffer information for the userspace */
+               __fill_v4l2_buffer(vb, b);
+
+               dprintk(1, "%s() of buffer %d succeeded\n", __func__, vb->v4l2_buf.index);
+       }
+       return ret;
 }
 EXPORT_SYMBOL_GPL(vb2_prepare_buf);
 
-static int __vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b,
-                     struct vb2_buffer *vb)
+/**
+ * vb2_start_streaming() - Attempt to start streaming.
+ * @q:         videobuf2 queue
+ *
+ * If there are not enough buffers, then retry_start_streaming is set to
+ * 1 and 0 is returned. The next time a buffer is queued and
+ * retry_start_streaming is 1, this function will be called again to
+ * retry starting the DMA engine.
+ */
+static int vb2_start_streaming(struct vb2_queue *q)
 {
        int ret;
 
+       /* Tell the driver to start streaming */
+       ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
+
+       /*
+        * If there are not enough buffers queued to start streaming, then
+        * the start_streaming operation will return -ENOBUFS and you have to
+        * retry when the next buffer is queued.
+        */
+       if (ret == -ENOBUFS) {
+               dprintk(1, "qbuf: not enough buffers, retry when more buffers are queued.\n");
+               q->retry_start_streaming = 1;
+               return 0;
+       }
+       if (ret)
+               dprintk(1, "qbuf: driver refused to start streaming\n");
+       else
+               q->retry_start_streaming = 0;
+       return ret;
+}
+
+static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
+{
+       int ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
+       struct vb2_buffer *vb;
+
+       if (ret)
+               return ret;
+
+       vb = q->bufs[b->index];
+       if (vb->state != VB2_BUF_STATE_DEQUEUED) {
+               dprintk(1, "%s(): invalid buffer state %d\n", __func__,
+                       vb->state);
+               return -EINVAL;
+       }
+
        switch (vb->state) {
        case VB2_BUF_STATE_DEQUEUED:
                ret = __buf_prepare(vb, b);
                if (ret)
                        return ret;
+               break;
        case VB2_BUF_STATE_PREPARED:
                break;
+       case VB2_BUF_STATE_PREPARING:
+               dprintk(1, "qbuf: buffer still being prepared\n");
+               return -EINVAL;
        default:
                dprintk(1, "qbuf: buffer already in use\n");
                return -EINVAL;
@@ -1407,6 +1456,16 @@ static int __vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b,
        if (q->streaming)
                __enqueue_in_driver(vb);
 
+       /* Fill buffer information for the userspace */
+       __fill_v4l2_buffer(vb, b);
+
+       if (q->retry_start_streaming) {
+               ret = vb2_start_streaming(q);
+               if (ret)
+                       return ret;
+       }
+
+       dprintk(1, "%s() of buffer %d succeeded\n", __func__, vb->v4l2_buf.index);
        return 0;
 }
 
@@ -1429,7 +1488,12 @@ static int __vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b,
  */
 int vb2_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 {
-       return vb2_queue_or_prepare_buf(q, b, "qbuf", __vb2_qbuf);
+       if (q->fileio) {
+               dprintk(1, "%s(): file io in progress\n", __func__);
+               return -EBUSY;
+       }
+
+       return vb2_internal_qbuf(q, b);
 }
 EXPORT_SYMBOL_GPL(vb2_qbuf);
 
@@ -1550,7 +1614,8 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q)
                return -EINVAL;
        }
 
-       wait_event(q->done_wq, !atomic_read(&q->queued_count));
+       if (!q->retry_start_streaming)
+               wait_event(q->done_wq, !atomic_read(&q->queued_count));
        return 0;
 }
 EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers);
@@ -1579,37 +1644,11 @@ static void __vb2_dqbuf(struct vb2_buffer *vb)
                }
 }
 
-/**
- * vb2_dqbuf() - Dequeue a buffer to the userspace
- * @q:         videobuf2 queue
- * @b:         buffer structure passed from userspace to vidioc_dqbuf handler
- *             in driver
- * @nonblocking: if true, this call will not sleep waiting for a buffer if no
- *              buffers ready for dequeuing are present. Normally the driver
- *              would be passing (file->f_flags & O_NONBLOCK) here
- *
- * Should be called from vidioc_dqbuf ioctl handler of a driver.
- * This function:
- * 1) verifies the passed buffer,
- * 2) calls buf_finish callback in the driver (if provided), in which
- *    driver can perform any additional operations that may be required before
- *    returning the buffer to userspace, such as cache sync,
- * 3) the buffer struct members are filled with relevant information for
- *    the userspace.
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_dqbuf handler in driver.
- */
-int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
+static int vb2_internal_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
 {
        struct vb2_buffer *vb = NULL;
        int ret;
 
-       if (q->fileio) {
-               dprintk(1, "dqbuf: file io in progress\n");
-               return -EBUSY;
-       }
-
        if (b->type != q->type) {
                dprintk(1, "dqbuf: invalid buffer type\n");
                return -EINVAL;
@@ -1648,6 +1687,36 @@ int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
 
        return 0;
 }
+
+/**
+ * vb2_dqbuf() - Dequeue a buffer to the userspace
+ * @q:         videobuf2 queue
+ * @b:         buffer structure passed from userspace to vidioc_dqbuf handler
+ *             in driver
+ * @nonblocking: if true, this call will not sleep waiting for a buffer if no
+ *              buffers ready for dequeuing are present. Normally the driver
+ *              would be passing (file->f_flags & O_NONBLOCK) here
+ *
+ * Should be called from vidioc_dqbuf ioctl handler of a driver.
+ * This function:
+ * 1) verifies the passed buffer,
+ * 2) calls buf_finish callback in the driver (if provided), in which
+ *    driver can perform any additional operations that may be required before
+ *    returning the buffer to userspace, such as cache sync,
+ * 3) the buffer struct members are filled with relevant information for
+ *    the userspace.
+ *
+ * The return values from this function are intended to be directly returned
+ * from vidioc_dqbuf handler in driver.
+ */
+int vb2_dqbuf(struct vb2_queue *q, struct v4l2_buffer *b, bool nonblocking)
+{
+       if (q->fileio) {
+               dprintk(1, "dqbuf: file io in progress\n");
+               return -EBUSY;
+       }
+       return vb2_internal_dqbuf(q, b, nonblocking);
+}
 EXPORT_SYMBOL_GPL(vb2_dqbuf);
 
 /**
@@ -1660,6 +1729,11 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
 {
        unsigned int i;
 
+       if (q->retry_start_streaming) {
+               q->retry_start_streaming = 0;
+               q->streaming = 0;
+       }
+
        /*
         * Tell driver to stop all transactions and release all queued
         * buffers.
@@ -1687,37 +1761,19 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
                __vb2_dqbuf(q->bufs[i]);
 }
 
-/**
- * vb2_streamon - start streaming
- * @q:         videobuf2 queue
- * @type:      type argument passed from userspace to vidioc_streamon handler
- *
- * Should be called from vidioc_streamon handler of a driver.
- * This function:
- * 1) verifies current state
- * 2) passes any previously queued buffers to the driver and starts streaming
- *
- * The return values from this function are intended to be directly returned
- * from vidioc_streamon handler in the driver.
- */
-int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
+static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
 {
        struct vb2_buffer *vb;
        int ret;
 
-       if (q->fileio) {
-               dprintk(1, "streamon: file io in progress\n");
-               return -EBUSY;
-       }
-
        if (type != q->type) {
                dprintk(1, "streamon: invalid stream type\n");
                return -EINVAL;
        }
 
        if (q->streaming) {
-               dprintk(1, "streamon: already streaming\n");
-               return -EBUSY;
+               dprintk(3, "streamon successful: already streaming\n");
+               return 0;
        }
 
        /*
@@ -1727,12 +1783,9 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
        list_for_each_entry(vb, &q->queued_list, queued_entry)
                __enqueue_in_driver(vb);
 
-       /*
-        * Let driver notice that streaming state has been enabled.
-        */
-       ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
+       /* Tell driver to start streaming. */
+       ret = vb2_start_streaming(q);
        if (ret) {
-               dprintk(1, "streamon: driver refused to start streaming\n");
                __vb2_queue_cancel(q);
                return ret;
        }
@@ -1742,39 +1795,40 @@ int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
        dprintk(3, "Streamon successful\n");
        return 0;
 }
-EXPORT_SYMBOL_GPL(vb2_streamon);
-
 
 /**
- * vb2_streamoff - stop streaming
+ * vb2_streamon - start streaming
  * @q:         videobuf2 queue
- * @type:      type argument passed from userspace to vidioc_streamoff handler
+ * @type:      type argument passed from userspace to vidioc_streamon handler
  *
- * Should be called from vidioc_streamoff handler of a driver.
+ * Should be called from vidioc_streamon handler of a driver.
  * This function:
- * 1) verifies current state,
- * 2) stop streaming and dequeues any queued buffers, including those previously
- *    passed to the driver (after waiting for the driver to finish).
+ * 1) verifies current state
+ * 2) passes any previously queued buffers to the driver and starts streaming
  *
- * This call can be used for pausing playback.
  * The return values from this function are intended to be directly returned
- * from vidioc_streamoff handler in the driver
+ * from vidioc_streamon handler in the driver.
  */
-int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+int vb2_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
 {
        if (q->fileio) {
-               dprintk(1, "streamoff: file io in progress\n");
+               dprintk(1, "streamon: file io in progress\n");
                return -EBUSY;
        }
+       return vb2_internal_streamon(q, type);
+}
+EXPORT_SYMBOL_GPL(vb2_streamon);
 
+static int vb2_internal_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+{
        if (type != q->type) {
                dprintk(1, "streamoff: invalid stream type\n");
                return -EINVAL;
        }
 
        if (!q->streaming) {
-               dprintk(1, "streamoff: not streaming\n");
-               return -EINVAL;
+               dprintk(3, "streamoff successful: not streaming\n");
+               return 0;
        }
 
        /*
@@ -1786,6 +1840,30 @@ int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
        dprintk(3, "Streamoff successful\n");
        return 0;
 }
+
+/**
+ * vb2_streamoff - stop streaming
+ * @q:         videobuf2 queue
+ * @type:      type argument passed from userspace to vidioc_streamoff handler
+ *
+ * Should be called from vidioc_streamoff handler of a driver.
+ * This function:
+ * 1) verifies current state,
+ * 2) stop streaming and dequeues any queued buffers, including those previously
+ *    passed to the driver (after waiting for the driver to finish).
+ *
+ * This call can be used for pausing playback.
+ * The return values from this function are intended to be directly returned
+ * from vidioc_streamoff handler in the driver
+ */
+int vb2_streamoff(struct vb2_queue *q, enum v4l2_buf_type type)
+{
+       if (q->fileio) {
+               dprintk(1, "streamoff: file io in progress\n");
+               return -EBUSY;
+       }
+       return vb2_internal_streamoff(q, type);
+}
 EXPORT_SYMBOL_GPL(vb2_streamoff);
 
 /**
@@ -2277,15 +2355,16 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
                                goto err_reqbufs;
                        fileio->bufs[i].queued = 1;
                }
-
-               /*
-                * Start streaming.
-                */
-               ret = vb2_streamon(q, q->type);
-               if (ret)
-                       goto err_reqbufs;
+               fileio->index = q->num_buffers;
        }
 
+       /*
+        * Start streaming.
+        */
+       ret = vb2_streamon(q, q->type);
+       if (ret)
+               goto err_reqbufs;
+
        q->fileio = fileio;
 
        return ret;
@@ -2308,13 +2387,8 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q)
        struct vb2_fileio_data *fileio = q->fileio;
 
        if (fileio) {
-               /*
-                * Hack fileio context to enable direct calls to vb2 ioctl
-                * interface.
-                */
+               vb2_internal_streamoff(q, q->type);
                q->fileio = NULL;
-
-               vb2_streamoff(q, q->type);
                fileio->req.count = 0;
                vb2_reqbufs(q, &fileio->req);
                kfree(fileio);
@@ -2357,40 +2431,35 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
        }
        fileio = q->fileio;
 
-       /*
-        * Hack fileio context to enable direct calls to vb2 ioctl interface.
-        * The pointer will be restored before returning from this function.
-        */
-       q->fileio = NULL;
-
-       index = fileio->index;
-       buf = &fileio->bufs[index];
-
        /*
         * Check if we need to dequeue the buffer.
         */
-       if (buf->queued) {
-               struct vb2_buffer *vb;
-
+       index = fileio->index;
+       if (index >= q->num_buffers) {
                /*
                 * Call vb2_dqbuf to get buffer back.
                 */
                memset(&fileio->b, 0, sizeof(fileio->b));
                fileio->b.type = q->type;
                fileio->b.memory = q->memory;
-               fileio->b.index = index;
-               ret = vb2_dqbuf(q, &fileio->b, nonblock);
+               ret = vb2_internal_dqbuf(q, &fileio->b, nonblock);
                dprintk(5, "file io: vb2_dqbuf result: %d\n", ret);
                if (ret)
-                       goto end;
+                       return ret;
                fileio->dq_count += 1;
 
+               index = fileio->b.index;
+               buf = &fileio->bufs[index];
+
                /*
                 * Get number of bytes filled by the driver
                 */
-               vb = q->bufs[index];
-               buf->size = vb2_get_plane_payload(vb, 0);
+               buf->pos = 0;
                buf->queued = 0;
+               buf->size = read ? vb2_get_plane_payload(q->bufs[index], 0)
+                                : vb2_plane_size(q->bufs[index], 0);
+       } else {
+               buf = &fileio->bufs[index];
        }
 
        /*
@@ -2412,8 +2481,7 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
                ret = copy_from_user(buf->vaddr + buf->pos, data, count);
        if (ret) {
                dprintk(3, "file io: error copying data\n");
-               ret = -EFAULT;
-               goto end;
+               return -EFAULT;
        }
 
        /*
@@ -2433,10 +2501,6 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
                if (read && (fileio->flags & VB2_FILEIO_READ_ONCE) &&
                    fileio->dq_count == 1) {
                        dprintk(3, "file io: read limit reached\n");
-                       /*
-                        * Restore fileio pointer and release the context.
-                        */
-                       q->fileio = fileio;
                        return __vb2_cleanup_fileio(q);
                }
 
@@ -2448,32 +2512,20 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
                fileio->b.memory = q->memory;
                fileio->b.index = index;
                fileio->b.bytesused = buf->pos;
-               ret = vb2_qbuf(q, &fileio->b);
+               ret = vb2_internal_qbuf(q, &fileio->b);
                dprintk(5, "file io: vb2_dbuf result: %d\n", ret);
                if (ret)
-                       goto end;
+                       return ret;
 
                /*
                 * Buffer has been queued, update the status
                 */
                buf->pos = 0;
                buf->queued = 1;
-               buf->size = q->bufs[0]->v4l2_planes[0].length;
+               buf->size = vb2_plane_size(q->bufs[index], 0);
                fileio->q_count += 1;
-
-               /*
-                * Switch to the next buffer
-                */
-               fileio->index = (index + 1) % q->num_buffers;
-
-               /*
-                * Start streaming if required.
-                */
-               if (!read && !q->streaming) {
-                       ret = vb2_streamon(q, q->type);
-                       if (ret)
-                               goto end;
-               }
+               if (fileio->index < q->num_buffers)
+                       fileio->index++;
        }
 
        /*
@@ -2481,11 +2533,6 @@ static size_t __vb2_perform_fileio(struct vb2_queue *q, char __user *data, size_
         */
        if (ret == 0)
                ret = count;
-end:
-       /*
-        * Restore the fileio context and block vb2 ioctl interface.
-        */
-       q->fileio = fileio;
        return ret;
 }
 
@@ -2649,16 +2696,29 @@ int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma)
 }
 EXPORT_SYMBOL_GPL(vb2_fop_mmap);
 
-int vb2_fop_release(struct file *file)
+int _vb2_fop_release(struct file *file, struct mutex *lock)
 {
        struct video_device *vdev = video_devdata(file);
 
        if (file->private_data == vdev->queue->owner) {
+               if (lock)
+                       mutex_lock(lock);
                vb2_queue_release(vdev->queue);
                vdev->queue->owner = NULL;
+               if (lock)
+                       mutex_unlock(lock);
        }
        return v4l2_fh_release(file);
 }
+EXPORT_SYMBOL_GPL(_vb2_fop_release);
+
+int vb2_fop_release(struct file *file)
+{
+       struct video_device *vdev = video_devdata(file);
+       struct mutex *lock = vdev->queue->lock ? vdev->queue->lock : vdev->lock;
+
+       return _vb2_fop_release(file, lock);
+}
 EXPORT_SYMBOL_GPL(vb2_fop_release);
 
 ssize_t vb2_fop_write(struct file *file, const char __user *buf,
index 0d3a8ffe47a3c15efc27faef3712f682e6a7f620..c779f210d2c623e9807ad7c41737813ed92d43ea 100644 (file)
@@ -40,6 +40,7 @@ struct vb2_dma_sg_buf {
        unsigned int                    num_pages;
        atomic_t                        refcount;
        struct vb2_vmarea_handler       handler;
+       struct vm_area_struct           *vma;
 };
 
 static void vb2_dma_sg_put(void *buf_priv);
@@ -155,12 +156,18 @@ static void vb2_dma_sg_put(void *buf_priv)
        }
 }
 
+static inline int vma_is_io(struct vm_area_struct *vma)
+{
+       return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
+}
+
 static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
                                    unsigned long size, int write)
 {
        struct vb2_dma_sg_buf *buf;
        unsigned long first, last;
        int num_pages_from_user;
+       struct vm_area_struct *vma;
 
        buf = kzalloc(sizeof *buf, GFP_KERNEL);
        if (!buf)
@@ -180,7 +187,38 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
        if (!buf->pages)
                goto userptr_fail_alloc_pages;
 
-       num_pages_from_user = get_user_pages(current, current->mm,
+       vma = find_vma(current->mm, vaddr);
+       if (!vma) {
+               dprintk(1, "no vma for address %lu\n", vaddr);
+               goto userptr_fail_find_vma;
+       }
+
+       if (vma->vm_end < vaddr + size) {
+               dprintk(1, "vma at %lu is too small for %lu bytes\n",
+                       vaddr, size);
+               goto userptr_fail_find_vma;
+       }
+
+       buf->vma = vb2_get_vma(vma);
+       if (!buf->vma) {
+               dprintk(1, "failed to copy vma\n");
+               goto userptr_fail_find_vma;
+       }
+
+       if (vma_is_io(buf->vma)) {
+               for (num_pages_from_user = 0;
+                    num_pages_from_user < buf->num_pages;
+                    ++num_pages_from_user, vaddr += PAGE_SIZE) {
+                       unsigned long pfn;
+
+                       if (follow_pfn(buf->vma, vaddr, &pfn)) {
+                               dprintk(1, "no page for address %lu\n", vaddr);
+                               break;
+                       }
+                       buf->pages[num_pages_from_user] = pfn_to_page(pfn);
+               }
+       } else
+               num_pages_from_user = get_user_pages(current, current->mm,
                                             vaddr & PAGE_MASK,
                                             buf->num_pages,
                                             write,
@@ -200,9 +238,12 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
 userptr_fail_alloc_table_from_pages:
 userptr_fail_get_user_pages:
        dprintk(1, "get_user_pages requested/got: %d/%d]\n",
-              num_pages_from_user, buf->num_pages);
-       while (--num_pages_from_user >= 0)
-               put_page(buf->pages[num_pages_from_user]);
+               buf->num_pages, num_pages_from_user);
+       if (!vma_is_io(buf->vma))
+               while (--num_pages_from_user >= 0)
+                       put_page(buf->pages[num_pages_from_user]);
+       vb2_put_vma(buf->vma);
+userptr_fail_find_vma:
        kfree(buf->pages);
 userptr_fail_alloc_pages:
        kfree(buf);
@@ -226,9 +267,11 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)
        while (--i >= 0) {
                if (buf->write)
                        set_page_dirty_lock(buf->pages[i]);
-               put_page(buf->pages[i]);
+               if (!vma_is_io(buf->vma))
+                       put_page(buf->pages[i]);
        }
        kfree(buf->pages);
+       vb2_put_vma(buf->vma);
        kfree(buf);
 }
 
index dd239bdbfcb4a0877db2ab49aa3c27a81eec7dd1..00d339c361fc0ecbd0b9b086e8c5756d28983d77 100644 (file)
@@ -2235,10 +2235,10 @@ static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        }
 
        /* do we need to support multiple segments? */
-       if (bio_segments(req->bio) > 1 || bio_segments(rsp->bio) > 1) {
-               printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
-                   ioc->name, __func__, bio_segments(req->bio), blk_rq_bytes(req),
-                   bio_segments(rsp->bio), blk_rq_bytes(rsp));
+       if (bio_multiple_segments(req->bio) ||
+           bio_multiple_segments(rsp->bio)) {
+               printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n",
+                   ioc->name, __func__, blk_rq_bytes(req), blk_rq_bytes(rsp));
                return -EINVAL;
        }
 
index c169e07654cb918310b61cf0f554ee87971b7e58..f0fa4e8ca124a905844f8f30d705be967d467965 100644 (file)
@@ -3,7 +3,7 @@
  *                           Philip Edelbrock <phil@netroedge.com>
  * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>
  * Copyright (C) 2003 IBM Corp.
- * Copyright (C) 2004 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2004 Jean Delvare <jdelvare@suse.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
index 5fab4e6e83013c033c01d2465b4f25c756f39dce..5ebcda39f55407e146ab06d811edd5825939a41d 100644 (file)
@@ -157,10 +157,11 @@ config MTD_BCM47XX_PARTS
 
 comment "User Modules And Translation Layers"
 
+#
+# MTD block device support is select'ed if needed
+#
 config MTD_BLKDEVS
-       tristate "Common interface to block layer for MTD 'translation layers'"
-       depends on BLOCK
-       default n
+       tristate
 
 config MTD_BLOCK
        tristate "Caching block device access to MTD devices"
index 5a3942bf109cd9ccded20d42fc4ee62b36a3ad8e..96a33e3f7b000394c1480260246585531c88b920 100644 (file)
@@ -264,7 +264,8 @@ static struct mtd_part_parser afs_parser = {
 
 static int __init afs_parser_init(void)
 {
-       return register_mtd_parser(&afs_parser);
+       register_mtd_parser(&afs_parser);
+       return 0;
 }
 
 static void __exit afs_parser_exit(void)
index ddc0a4287a4b89c8124dd3629b9647e3ca800b74..7c9172ad26210e1d25c9506889e0cbb54212dbfe 100644 (file)
@@ -139,7 +139,8 @@ static struct mtd_part_parser ar7_parser = {
 
 static int __init ar7_parser_init(void)
 {
-       return register_mtd_parser(&ar7_parser);
+       register_mtd_parser(&ar7_parser);
+       return 0;
 }
 
 static void __exit ar7_parser_exit(void)
index 7a6384b0962a9de2c92dffb81f1fc45d6d89a490..de1eb92e42f57f15f197c3ba21d1831ab6dac06f 100644 (file)
  * Amount of bytes we read when analyzing each block of flash memory.
  * Set it big enough to allow detecting partition and reading important data.
  */
-#define BCM47XXPART_BYTES_TO_READ      0x404
+#define BCM47XXPART_BYTES_TO_READ      0x4e8
 
 /* Magics */
 #define BOARD_DATA_MAGIC               0x5246504D      /* MPFR */
+#define BOARD_DATA_MAGIC2              0xBD0D0BBD
+#define CFE_MAGIC                      0x43464531      /* 1EFC */
 #define FACTORY_MAGIC                  0x59544346      /* FCTY */
 #define POT_MAGIC1                     0x54544f50      /* POTT */
 #define POT_MAGIC2                     0x504f          /* OP */
@@ -102,8 +104,9 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                        continue;
                }
 
-               /* CFE has small NVRAM at 0x400 */
-               if (buf[0x400 / 4] == NVRAM_HEADER) {
+               /* Magic or small NVRAM at 0x400 */
+               if ((buf[0x4e0 / 4] == CFE_MAGIC && buf[0x4e4 / 4] == CFE_MAGIC) ||
+                   (buf[0x400 / 4] == NVRAM_HEADER)) {
                        bcm47xxpart_add_part(&parts[curr_part++], "boot",
                                             offset, MTD_WRITEABLE);
                        continue;
@@ -190,6 +193,21 @@ static int bcm47xxpart_parse(struct mtd_info *master,
                                             offset, 0);
                        continue;
                }
+
+               /* Read middle of the block */
+               if (mtd_read(master, offset + 0x8000, 0x4,
+                            &bytes_read, (uint8_t *)buf) < 0) {
+                       pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+                              offset);
+                       continue;
+               }
+
+               /* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */
+               if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) {
+                       bcm47xxpart_add_part(&parts[curr_part++], "board_data",
+                                            offset, MTD_WRITEABLE);
+                       continue;
+               }
        }
 
        /* Look for NVRAM at the end of the last block. */
@@ -243,7 +261,8 @@ static struct mtd_part_parser bcm47xxpart_mtd_parser = {
 
 static int __init bcm47xxpart_init(void)
 {
-       return register_mtd_parser(&bcm47xxpart_mtd_parser);
+       register_mtd_parser(&bcm47xxpart_mtd_parser);
+       return 0;
 }
 
 static void __exit bcm47xxpart_exit(void)
index 5c813907661c3415c979b1176bf937f7c086f2c8..b2443f7031c9afb0bda808a37b6da7e8113d0a61 100644 (file)
@@ -221,7 +221,8 @@ static struct mtd_part_parser bcm63xx_cfe_parser = {
 
 static int __init bcm63xx_cfe_parser_init(void)
 {
-       return register_mtd_parser(&bcm63xx_cfe_parser);
+       register_mtd_parser(&bcm63xx_cfe_parser);
+       return 0;
 }
 
 static void __exit bcm63xx_cfe_parser_exit(void)
index 721caebbc5cc21344a58a710d466205f75f845ef..3e829b37af8d0e0d5c73eff2c03e054ed6516eab 100644 (file)
@@ -395,7 +395,8 @@ static int __init cmdline_parser_init(void)
 {
        if (mtdparts)
                mtdpart_setup(mtdparts);
-       return register_mtd_parser(&cmdline_parser);
+       register_mtd_parser(&cmdline_parser);
+       return 0;
 }
 
 static void __exit cmdline_parser_exit(void)
index 4f091c1a9981c060e3ea2cae43960ade8b4bc2f7..dd5e1018d37b39e9301c9c43e01195f4f363a66c 100644 (file)
@@ -2047,21 +2047,21 @@ static int __init docg3_probe(struct platform_device *pdev)
        ress = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!ress) {
                dev_err(dev, "No I/O memory resource defined\n");
-               goto noress;
+               return ret;
        }
-       base = ioremap(ress->start, DOC_IOSPACE_SIZE);
+       base = devm_ioremap(dev, ress->start, DOC_IOSPACE_SIZE);
 
        ret = -ENOMEM;
-       cascade = kzalloc(sizeof(*cascade) * DOC_MAX_NBFLOORS,
-                         GFP_KERNEL);
+       cascade = devm_kzalloc(dev, sizeof(*cascade) * DOC_MAX_NBFLOORS,
+                              GFP_KERNEL);
        if (!cascade)
-               goto nomem1;
+               return ret;
        cascade->base = base;
        mutex_init(&cascade->lock);
        cascade->bch = init_bch(DOC_ECC_BCH_M, DOC_ECC_BCH_T,
                             DOC_ECC_BCH_PRIMPOLY);
        if (!cascade->bch)
-               goto nomem2;
+               return ret;
 
        for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++) {
                mtd = doc_probe_device(cascade, floor, dev);
@@ -2101,11 +2101,6 @@ err_probe:
        for (floor = 0; floor < DOC_MAX_NBFLOORS; floor++)
                if (cascade->floors[floor])
                        doc_release_device(cascade->floors[floor]);
-nomem2:
-       kfree(cascade);
-nomem1:
-       iounmap(base);
-noress:
        return ret;
 }
 
@@ -2119,7 +2114,6 @@ static int __exit docg3_release(struct platform_device *pdev)
 {
        struct docg3_cascade *cascade = platform_get_drvdata(pdev);
        struct docg3 *docg3 = cascade->floors[0]->priv;
-       void __iomem *base = cascade->base;
        int floor;
 
        doc_unregister_sysfs(pdev, cascade);
@@ -2129,8 +2123,6 @@ static int __exit docg3_release(struct platform_device *pdev)
                        doc_release_device(cascade->floors[floor]);
 
        free_bch(docg3->cascade->bch);
-       kfree(cascade);
-       iounmap(base);
        return 0;
 }
 
index 7eda71dbc183b7aa456e60a41f0490c882d94331..ad19139097025b97839fb7cbe123a1261e6cf876 100644 (file)
@@ -41,6 +41,7 @@
 #define        OPCODE_WRSR             0x01    /* Write status register 1 byte */
 #define        OPCODE_NORM_READ        0x03    /* Read data bytes (low frequency) */
 #define        OPCODE_FAST_READ        0x0b    /* Read data bytes (high frequency) */
+#define        OPCODE_QUAD_READ        0x6b    /* Read data bytes */
 #define        OPCODE_PP               0x02    /* Page program (up to 256 bytes) */
 #define        OPCODE_BE_4K            0x20    /* Erase 4KiB block */
 #define        OPCODE_BE_4K_PMC        0xd7    /* Erase 4KiB block on PMC chips */
 #define        OPCODE_CHIP_ERASE       0xc7    /* Erase whole flash chip */
 #define        OPCODE_SE               0xd8    /* Sector erase (usually 64KiB) */
 #define        OPCODE_RDID             0x9f    /* Read JEDEC ID */
+#define        OPCODE_RDCR             0x35    /* Read configuration register */
 
 /* 4-byte address opcodes - used on Spansion and some Macronix flashes. */
 #define        OPCODE_NORM_READ_4B     0x13    /* Read data bytes (low frequency) */
 #define        OPCODE_FAST_READ_4B     0x0c    /* Read data bytes (high frequency) */
+#define        OPCODE_QUAD_READ_4B     0x6c    /* Read data bytes */
 #define        OPCODE_PP_4B            0x12    /* Page program (up to 256 bytes) */
 #define        OPCODE_SE_4B            0xdc    /* Sector erase (usually 64KiB) */
 
 #define        SR_BP2                  0x10    /* Block protect 2 */
 #define        SR_SRWD                 0x80    /* SR write protect */
 
+#define SR_QUAD_EN_MX           0x40    /* Macronix Quad I/O */
+
+/* Configuration Register bits. */
+#define CR_QUAD_EN_SPAN                0x2     /* Spansion Quad I/O */
+
 /* Define max times to check status register before we give up. */
 #define        MAX_READY_WAIT_JIFFIES  (40 * HZ)       /* M25P16 specs 40s max chip erase */
 #define        MAX_CMD_SIZE            6
 
 /****************************************************************************/
 
+enum read_type {
+       M25P80_NORMAL = 0,
+       M25P80_FAST,
+       M25P80_QUAD,
+};
+
 struct m25p {
        struct spi_device       *spi;
        struct mutex            lock;
@@ -94,7 +108,7 @@ struct m25p {
        u8                      read_opcode;
        u8                      program_opcode;
        u8                      *command;
-       bool                    fast_read;
+       enum read_type          flash_read;
 };
 
 static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
@@ -130,6 +144,26 @@ static int read_sr(struct m25p *flash)
        return val;
 }
 
+/*
+ * Read configuration register, returning its value in the
+ * location. Return the configuration register value.
+ * Returns negative if error occured.
+ */
+static int read_cr(struct m25p *flash)
+{
+       u8 code = OPCODE_RDCR;
+       int ret;
+       u8 val;
+
+       ret = spi_write_then_read(flash->spi, &code, 1, &val, 1);
+       if (ret < 0) {
+               dev_err(&flash->spi->dev, "error %d reading CR\n", ret);
+               return ret;
+       }
+
+       return val;
+}
+
 /*
  * Write status register 1 byte
  * Returns negative if error occurred.
@@ -219,6 +253,93 @@ static int wait_till_ready(struct m25p *flash)
        return 1;
 }
 
+/*
+ * Write status Register and configuration register with 2 bytes
+ * The first byte will be written to the status register, while the
+ * second byte will be written to the configuration register.
+ * Return negative if error occured.
+ */
+static int write_sr_cr(struct m25p *flash, u16 val)
+{
+       flash->command[0] = OPCODE_WRSR;
+       flash->command[1] = val & 0xff;
+       flash->command[2] = (val >> 8);
+
+       return spi_write(flash->spi, flash->command, 3);
+}
+
+static int macronix_quad_enable(struct m25p *flash)
+{
+       int ret, val;
+       u8 cmd[2];
+       cmd[0] = OPCODE_WRSR;
+
+       val = read_sr(flash);
+       cmd[1] = val | SR_QUAD_EN_MX;
+       write_enable(flash);
+
+       spi_write(flash->spi, &cmd, 2);
+
+       if (wait_till_ready(flash))
+               return 1;
+
+       ret = read_sr(flash);
+       if (!(ret > 0 && (ret & SR_QUAD_EN_MX))) {
+               dev_err(&flash->spi->dev, "Macronix Quad bit not set\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int spansion_quad_enable(struct m25p *flash)
+{
+       int ret;
+       int quad_en = CR_QUAD_EN_SPAN << 8;
+
+       write_enable(flash);
+
+       ret = write_sr_cr(flash, quad_en);
+       if (ret < 0) {
+               dev_err(&flash->spi->dev,
+                       "error while writing configuration register\n");
+               return -EINVAL;
+       }
+
+       /* read back and check it */
+       ret = read_cr(flash);
+       if (!(ret > 0 && (ret & CR_QUAD_EN_SPAN))) {
+               dev_err(&flash->spi->dev, "Spansion Quad bit not set\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int set_quad_mode(struct m25p *flash, u32 jedec_id)
+{
+       int status;
+
+       switch (JEDEC_MFR(jedec_id)) {
+       case CFI_MFR_MACRONIX:
+               status = macronix_quad_enable(flash);
+               if (status) {
+                       dev_err(&flash->spi->dev,
+                               "Macronix quad-read not enabled\n");
+                       return -EINVAL;
+               }
+               return status;
+       default:
+               status = spansion_quad_enable(flash);
+               if (status) {
+                       dev_err(&flash->spi->dev,
+                               "Spansion quad-read not enabled\n");
+                       return -EINVAL;
+               }
+               return status;
+       }
+}
+
 /*
  * Erase the whole flash memory
  *
@@ -349,6 +470,35 @@ static int m25p80_erase(struct mtd_info *mtd, struct erase_info *instr)
        return 0;
 }
 
+/*
+ * Dummy Cycle calculation for different type of read.
+ * It can be used to support more commands with
+ * different dummy cycle requirements.
+ */
+static inline int m25p80_dummy_cycles_read(struct m25p *flash)
+{
+       switch (flash->flash_read) {
+       case M25P80_FAST:
+       case M25P80_QUAD:
+               return 1;
+       case M25P80_NORMAL:
+               return 0;
+       default:
+               dev_err(&flash->spi->dev, "No valid read type supported\n");
+               return -1;
+       }
+}
+
+static inline unsigned int m25p80_rx_nbits(const struct m25p *flash)
+{
+       switch (flash->flash_read) {
+       case M25P80_QUAD:
+               return 4;
+       default:
+               return 0;
+       }
+}
+
 /*
  * Read an address range from the flash chip.  The address range
  * may be any size provided it is within the physical boundaries.
@@ -360,6 +510,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
        struct spi_transfer t[2];
        struct spi_message m;
        uint8_t opcode;
+       int dummy;
 
        pr_debug("%s: %s from 0x%08x, len %zd\n", dev_name(&flash->spi->dev),
                        __func__, (u32)from, len);
@@ -367,11 +518,18 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
        spi_message_init(&m);
        memset(t, 0, (sizeof t));
 
+       dummy =  m25p80_dummy_cycles_read(flash);
+       if (dummy < 0) {
+               dev_err(&flash->spi->dev, "No valid read command supported\n");
+               return -EINVAL;
+       }
+
        t[0].tx_buf = flash->command;
-       t[0].len = m25p_cmdsz(flash) + (flash->fast_read ? 1 : 0);
+       t[0].len = m25p_cmdsz(flash) + dummy;
        spi_message_add_tail(&t[0], &m);
 
        t[1].rx_buf = buf;
+       t[1].rx_nbits = m25p80_rx_nbits(flash);
        t[1].len = len;
        spi_message_add_tail(&t[1], &m);
 
@@ -391,8 +549,7 @@ static int m25p80_read(struct mtd_info *mtd, loff_t from, size_t len,
 
        spi_sync(flash->spi, &m);
 
-       *retlen = m.actual_length - m25p_cmdsz(flash) -
-                       (flash->fast_read ? 1 : 0);
+       *retlen = m.actual_length - m25p_cmdsz(flash) - dummy;
 
        mutex_unlock(&flash->lock);
 
@@ -698,6 +855,7 @@ struct flash_info {
 #define        SST_WRITE       0x04            /* use SST byte programming */
 #define        M25P_NO_FR      0x08            /* Can't do fastread */
 #define        SECT_4K_PMC     0x10            /* OPCODE_BE_4K_PMC works uniformly */
+#define        M25P80_QUAD_READ        0x20    /* Flash supports Quad Read */
 };
 
 #define INFO(_jedec_id, _ext_id, _sector_size, _n_sectors, _flags)     \
@@ -775,7 +933,7 @@ static const struct spi_device_id m25p_ids[] = {
        { "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
        { "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, 0) },
        { "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
-       { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, 0) },
+       { "mx66l51235l", INFO(0xc2201a, 0, 64 * 1024, 1024, M25P80_QUAD_READ) },
 
        /* Micron */
        { "n25q064",     INFO(0x20ba17, 0, 64 * 1024,  128, 0) },
@@ -795,8 +953,8 @@ static const struct spi_device_id m25p_ids[] = {
        { "s25sl032p",  INFO(0x010215, 0x4d00,  64 * 1024,  64, 0) },
        { "s25sl064p",  INFO(0x010216, 0x4d00,  64 * 1024, 128, 0) },
        { "s25fl256s0", INFO(0x010219, 0x4d00, 256 * 1024, 128, 0) },
-       { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, 0) },
-       { "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, 0) },
+       { "s25fl256s1", INFO(0x010219, 0x4d01,  64 * 1024, 512, M25P80_QUAD_READ) },
+       { "s25fl512s",  INFO(0x010220, 0x4d00, 256 * 1024, 256, M25P80_QUAD_READ) },
        { "s70fl01gs",  INFO(0x010221, 0x4d00, 256 * 1024, 256, 0) },
        { "s25sl12800", INFO(0x012018, 0x0300, 256 * 1024,  64, 0) },
        { "s25sl12801", INFO(0x012018, 0x0301,  64 * 1024, 256, 0) },
@@ -851,6 +1009,7 @@ static const struct spi_device_id m25p_ids[] = {
        { "m25pe80", INFO(0x208014,  0, 64 * 1024, 16,       0) },
        { "m25pe16", INFO(0x208015,  0, 64 * 1024, 32, SECT_4K) },
 
+       { "m25px16",    INFO(0x207115,  0, 64 * 1024, 32, SECT_4K) },
        { "m25px32",    INFO(0x207116,  0, 64 * 1024, 64, SECT_4K) },
        { "m25px32-s0", INFO(0x207316,  0, 64 * 1024, 64, SECT_4K) },
        { "m25px32-s1", INFO(0x206316,  0, 64 * 1024, 64, SECT_4K) },
@@ -937,6 +1096,7 @@ static int m25p_probe(struct spi_device *spi)
        unsigned                        i;
        struct mtd_part_parser_data     ppdata;
        struct device_node *np = spi->dev.of_node;
+       int ret;
 
        /* Platform data helps sort out which chip type we have, as
         * well as how this board partitions it.  If we don't have
@@ -1051,22 +1211,46 @@ static int m25p_probe(struct spi_device *spi)
        flash->page_size = info->page_size;
        flash->mtd.writebufsize = flash->page_size;
 
-       if (np)
+       if (np) {
                /* If we were instantiated by DT, use it */
-               flash->fast_read = of_property_read_bool(np, "m25p,fast-read");
-       else
+               if (of_property_read_bool(np, "m25p,fast-read"))
+                       flash->flash_read = M25P80_FAST;
+               else
+                       flash->flash_read = M25P80_NORMAL;
+       } else {
                /* If we weren't instantiated by DT, default to fast-read */
-               flash->fast_read = true;
+               flash->flash_read = M25P80_FAST;
+       }
 
        /* Some devices cannot do fast-read, no matter what DT tells us */
        if (info->flags & M25P_NO_FR)
-               flash->fast_read = false;
+               flash->flash_read = M25P80_NORMAL;
+
+       /* Quad-read mode takes precedence over fast/normal */
+       if (spi->mode & SPI_RX_QUAD && info->flags & M25P80_QUAD_READ) {
+               ret = set_quad_mode(flash, info->jedec_id);
+               if (ret) {
+                       dev_err(&flash->spi->dev, "quad mode not supported\n");
+                       return ret;
+               }
+               flash->flash_read = M25P80_QUAD;
+       }
 
        /* Default commands */
-       if (flash->fast_read)
+       switch (flash->flash_read) {
+       case M25P80_QUAD:
+               flash->read_opcode = OPCODE_QUAD_READ;
+               break;
+       case M25P80_FAST:
                flash->read_opcode = OPCODE_FAST_READ;
-       else
+               break;
+       case M25P80_NORMAL:
                flash->read_opcode = OPCODE_NORM_READ;
+               break;
+       default:
+               dev_err(&flash->spi->dev, "No Read opcode defined\n");
+               return -EINVAL;
+       }
 
        flash->program_opcode = OPCODE_PP;
 
@@ -1077,9 +1261,17 @@ static int m25p_probe(struct spi_device *spi)
                flash->addr_width = 4;
                if (JEDEC_MFR(info->jedec_id) == CFI_MFR_AMD) {
                        /* Dedicated 4-byte command set */
-                       flash->read_opcode = flash->fast_read ?
-                               OPCODE_FAST_READ_4B :
-                               OPCODE_NORM_READ_4B;
+                       switch (flash->flash_read) {
+                       case M25P80_QUAD:
+                               flash->read_opcode = OPCODE_QUAD_READ_4B;
+                               break;
+                       case M25P80_FAST:
+                               flash->read_opcode = OPCODE_FAST_READ_4B;
+                               break;
+                       case M25P80_NORMAL:
+                               flash->read_opcode = OPCODE_NORM_READ_4B;
+                               break;
+                       }
                        flash->program_opcode = OPCODE_PP_4B;
                        /* No small sector erase for 4-byte command set */
                        flash->erase_opcode = OPCODE_SE_4B;
index 182849d39c61acb34c40a79ab6bf04e30162da79..5c8b322ba904b1691bf204efc3f4523106dc8f67 100644 (file)
@@ -205,7 +205,7 @@ static int __init ms02nv_init_one(ulong addr)
        mtd->type = MTD_RAM;
        mtd->flags = MTD_CAP_RAM;
        mtd->size = fixsize;
-       mtd->name = (char *)ms02nv_name;
+       mtd->name = ms02nv_name;
        mtd->owner = THIS_MODULE;
        mtd->_read = ms02nv_read;
        mtd->_write = ms02nv_write;
index 4a47b0266d4e587761a2db5c1cd2e1613fc710bc..624069de4f28c067260fc4fec75c35b713fc5c84 100644 (file)
@@ -669,7 +669,6 @@ static int add_dataflash_otp(struct spi_device *spi, char *name, int nr_pages,
        if (!err)
                return 0;
 
-       spi_set_drvdata(spi, NULL);
        kfree(priv);
        return err;
 }
@@ -899,10 +898,8 @@ static int dataflash_remove(struct spi_device *spi)
        pr_debug("%s: remove\n", dev_name(&spi->dev));
 
        status = mtd_device_unregister(&flash->mtd);
-       if (status == 0) {
-               spi_set_drvdata(spi, NULL);
+       if (status == 0)
                kfree(flash);
-       }
        return status;
 }
 
index ec59d65897fbe38976112ab071741b6c2d3b9189..8e285089229c364ee29c6b4f7c90a872d6e7c693 100644 (file)
@@ -92,7 +92,7 @@ static void __exit cleanup_mtdram(void)
 }
 
 int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
-               unsigned long size, char *name)
+               unsigned long size, const char *name)
 {
        memset(mtd, 0, sizeof(*mtd));
 
index 2ef19aa0086bee62d51a9986ea50f5983461869c..d38b6460d50565c21fa46978d3f2383d13299e6f 100644 (file)
@@ -388,7 +388,7 @@ static void put_chip(struct map_info *map, struct flchip *chip)
        wake_up(&chip->wq);
 }
 
-int do_write_buffer(struct map_info *map, struct flchip *chip,
+static int do_write_buffer(struct map_info *map, struct flchip *chip,
                        unsigned long adr, const struct kvec **pvec,
                        unsigned long *pvec_seek, int len)
 {
@@ -469,7 +469,7 @@ int do_write_buffer(struct map_info *map, struct flchip *chip,
        return ret;
 }
 
-int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
+static int do_erase_oneblock(struct mtd_info *mtd, loff_t adr)
 {
        struct map_info *map = mtd->priv;
        struct lpddr_private *lpddr = map->fldrv_priv;
@@ -748,34 +748,6 @@ static int lpddr_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
        return do_xxlock(mtd, ofs, len, DO_XXLOCK_UNLOCK);
 }
 
-int word_program(struct map_info *map, loff_t adr, uint32_t curval)
-{
-    int ret;
-       struct lpddr_private *lpddr = map->fldrv_priv;
-       int chipnum = adr >> lpddr->chipshift;
-       struct flchip *chip = &lpddr->chips[chipnum];
-
-       mutex_lock(&chip->mutex);
-       ret = get_chip(map, chip, FL_WRITING);
-       if (ret) {
-               mutex_unlock(&chip->mutex);
-               return ret;
-       }
-
-       send_pfow_command(map, LPDDR_WORD_PROGRAM, adr, 0x00, (map_word *)&curval);
-
-       ret = wait_for_ready(map, chip, (1<<lpddr->qinfo->SingleWordProgTime));
-       if (ret)        {
-               printk(KERN_WARNING"%s word_program error at: %llx; val: %x\n",
-                       map->name, adr, curval);
-               goto out;
-       }
-
-out:   put_chip(map, chip);
-       mutex_unlock(&chip->mutex);
-       return ret;
-}
-
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Alexey Korolev <akorolev@infradead.org>");
 MODULE_DESCRIPTION("MTD driver for LPDDR flash chips");
index 10debfea81e7147c25fa00e4913bd2d336c24b6a..d6b2451eab1d9f0db5808c3ad837ac2f6f604499 100644 (file)
@@ -13,6 +13,7 @@
  *
  */
 
+#include <linux/err.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
@@ -162,13 +163,6 @@ static int ixp4xx_flash_remove(struct platform_device *dev)
                mtd_device_unregister(info->mtd);
                map_destroy(info->mtd);
        }
-       if (info->map.virt)
-               iounmap(info->map.virt);
-
-       if (info->res) {
-               release_resource(info->res);
-               kfree(info->res);
-       }
 
        if (plat->exit)
                plat->exit();
@@ -194,7 +188,8 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
                        return err;
        }
 
-       info = kzalloc(sizeof(struct ixp4xx_flash_info), GFP_KERNEL);
+       info = devm_kzalloc(&dev->dev, sizeof(struct ixp4xx_flash_info),
+                           GFP_KERNEL);
        if(!info) {
                err = -ENOMEM;
                goto Error;
@@ -220,20 +215,9 @@ static int ixp4xx_flash_probe(struct platform_device *dev)
        info->map.write = ixp4xx_probe_write16;
        info->map.copy_from = ixp4xx_copy_from;
 
-       info->res = request_mem_region(dev->resource->start,
-                       resource_size(dev->resource),
-                       "IXP4XXFlash");
-       if (!info->res) {
-               printk(KERN_ERR "IXP4XXFlash: Could not reserve memory region\n");
-               err = -ENOMEM;
-               goto Error;
-       }
-
-       info->map.virt = ioremap(dev->resource->start,
-                                resource_size(dev->resource));
-       if (!info->map.virt) {
-               printk(KERN_ERR "IXP4XXFlash: Failed to ioremap region\n");
-               err = -EIO;
+       info->map.virt = devm_ioremap_resource(&dev->dev, dev->resource);
+       if (IS_ERR(info->map.virt)) {
+               err = PTR_ERR(info->map.virt);
                goto Error;
        }
 
index d7ac65d1d569dee08e325480501e29cc550ef012..93c507a6f86245024d6b1e79a54ca2f8ad8d78b1 100644 (file)
@@ -123,24 +123,28 @@ ltq_mtd_probe(struct platform_device *pdev)
                return -ENODEV;
        }
 
-       ltq_mtd = kzalloc(sizeof(struct ltq_mtd), GFP_KERNEL);
+       ltq_mtd = devm_kzalloc(&pdev->dev, sizeof(struct ltq_mtd), GFP_KERNEL);
+       if (!ltq_mtd)
+               return -ENOMEM;
+
        platform_set_drvdata(pdev, ltq_mtd);
 
        ltq_mtd->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!ltq_mtd->res) {
                dev_err(&pdev->dev, "failed to get memory resource\n");
-               err = -ENOENT;
-               goto err_out;
+               return -ENOENT;
        }
 
-       ltq_mtd->map = kzalloc(sizeof(struct map_info), GFP_KERNEL);
+       ltq_mtd->map = devm_kzalloc(&pdev->dev, sizeof(struct map_info),
+                                   GFP_KERNEL);
+       if (!ltq_mtd->map)
+               return -ENOMEM;
+
        ltq_mtd->map->phys = ltq_mtd->res->start;
        ltq_mtd->map->size = resource_size(ltq_mtd->res);
        ltq_mtd->map->virt = devm_ioremap_resource(&pdev->dev, ltq_mtd->res);
-       if (IS_ERR(ltq_mtd->map->virt)) {
-               err = PTR_ERR(ltq_mtd->map->virt);
-               goto err_out;
-       }
+       if (IS_ERR(ltq_mtd->map->virt))
+               return PTR_ERR(ltq_mtd->map->virt);
 
        ltq_mtd->map->name = ltq_map_name;
        ltq_mtd->map->bankwidth = 2;
@@ -155,8 +159,7 @@ ltq_mtd_probe(struct platform_device *pdev)
 
        if (!ltq_mtd->mtd) {
                dev_err(&pdev->dev, "probing failed\n");
-               err = -ENXIO;
-               goto err_free;
+               return -ENXIO;
        }
 
        ltq_mtd->mtd->owner = THIS_MODULE;
@@ -177,10 +180,6 @@ ltq_mtd_probe(struct platform_device *pdev)
 
 err_destroy:
        map_destroy(ltq_mtd->mtd);
-err_free:
-       kfree(ltq_mtd->map);
-err_out:
-       kfree(ltq_mtd);
        return err;
 }
 
@@ -189,13 +188,9 @@ ltq_mtd_remove(struct platform_device *pdev)
 {
        struct ltq_mtd *ltq_mtd = platform_get_drvdata(pdev);
 
-       if (ltq_mtd) {
-               if (ltq_mtd->mtd) {
-                       mtd_device_unregister(ltq_mtd->mtd);
-                       map_destroy(ltq_mtd->mtd);
-               }
-               kfree(ltq_mtd->map);
-               kfree(ltq_mtd);
+       if (ltq_mtd && ltq_mtd->mtd) {
+               mtd_device_unregister(ltq_mtd->mtd);
+               map_destroy(ltq_mtd->mtd);
        }
        return 0;
 }
index 0f55589a56b815af4c00bc521c504db468774fa5..9aad854fe9121aaa821181bffe64e819ec0e8498 100644 (file)
@@ -61,7 +61,7 @@ static int pxa2xx_flash_probe(struct platform_device *pdev)
        if (!info)
                return -ENOMEM;
 
-       info->map.name = (char *) flash->name;
+       info->map.name = flash->name;
        info->map.bankwidth = flash->width;
        info->map.phys = res->start;
        info->map.size = resource_size(res);
index d467f3b11c96c72ded5f3019cc823eb50fc6bd0b..39cc4181f02538a438b8fc427e00e19c1074fde3 100644 (file)
@@ -75,7 +75,7 @@ int uflash_devinit(struct platform_device *op, struct device_node *dp)
 
        up->name = of_get_property(dp, "model", NULL);
        if (up->name && 0 < strlen(up->name))
-               up->map.name = (char *)up->name;
+               up->map.name = up->name;
 
        up->map.phys = op->resource[0].start;
 
index 92311a56939fca8d53e05e178054520f80b3bcec..34c0b16aed5c4e2f7d61a22d3fdeaf2ca066a632 100644 (file)
@@ -313,15 +313,7 @@ static struct attribute *mtd_attrs[] = {
        &dev_attr_bitflip_threshold.attr,
        NULL,
 };
-
-static struct attribute_group mtd_group = {
-       .attrs          = mtd_attrs,
-};
-
-static const struct attribute_group *mtd_groups[] = {
-       &mtd_group,
-       NULL,
-};
+ATTRIBUTE_GROUPS(mtd);
 
 static struct device_type mtd_devtype = {
        .name           = "mtd",
index 6e732c3820c14bf9d07b693a0c1de9bfff0088f0..3c7d6d7623c1cd5557b4dfeb38e80e03fc6e2abc 100644 (file)
@@ -534,7 +534,7 @@ out_register:
        return slave;
 }
 
-int mtd_add_partition(struct mtd_info *master, char *name,
+int mtd_add_partition(struct mtd_info *master, const char *name,
                      long long offset, long long length)
 {
        struct mtd_partition part;
@@ -672,22 +672,19 @@ static struct mtd_part_parser *get_partition_parser(const char *name)
 
 #define put_partition_parser(p) do { module_put((p)->owner); } while (0)
 
-int register_mtd_parser(struct mtd_part_parser *p)
+void register_mtd_parser(struct mtd_part_parser *p)
 {
        spin_lock(&part_parser_lock);
        list_add(&p->list, &part_parsers);
        spin_unlock(&part_parser_lock);
-
-       return 0;
 }
 EXPORT_SYMBOL_GPL(register_mtd_parser);
 
-int deregister_mtd_parser(struct mtd_part_parser *p)
+void deregister_mtd_parser(struct mtd_part_parser *p)
 {
        spin_lock(&part_parser_lock);
        list_del(&p->list);
        spin_unlock(&part_parser_lock);
-       return 0;
 }
 EXPORT_SYMBOL_GPL(deregister_mtd_parser);
 
index 93ae6a6d94f713d6352abd612efd1fed05f43dfd..90ff447bf0437707fe763133532fbb6b89bae7b7 100644 (file)
@@ -95,7 +95,7 @@ config MTD_NAND_OMAP2
          platforms.
 
 config MTD_NAND_OMAP_BCH
-       depends on MTD_NAND && MTD_NAND_OMAP2 && ARCH_OMAP3
+       depends on MTD_NAND_OMAP2
        tristate "Support hardware based BCH error correction"
        default n
        select BCH
@@ -326,11 +326,11 @@ config MTD_NAND_ATMEL
          on Atmel AT91 and AVR32 processors.
 
 config MTD_NAND_PXA3xx
-       tristate "Support for NAND flash devices on PXA3xx"
+       tristate "NAND support on PXA3xx and Armada 370/XP"
        depends on PXA3xx || ARCH_MMP || PLAT_ORION
        help
          This enables the driver for the NAND flash device found on
-         PXA3xx processors
+         PXA3xx processors (NFCv1) and also on Armada 370/XP (NFCv2).
 
 config MTD_NAND_SLC_LPC32XX
        tristate "NXP LPC32xx SLC Controller"
@@ -458,17 +458,17 @@ config MTD_NAND_MXC
 
 config MTD_NAND_SH_FLCTL
        tristate "Support for NAND on Renesas SuperH FLCTL"
-       depends on SUPERH || ARCH_SHMOBILE
+       depends on SUPERH || ARCH_SHMOBILE || COMPILE_TEST
        help
          Several Renesas SuperH CPU has FLCTL. This option enables support
          for NAND Flash using FLCTL.
 
 config MTD_NAND_DAVINCI
-        tristate "Support NAND on DaVinci SoC"
-        depends on ARCH_DAVINCI
+        tristate "Support NAND on DaVinci/Keystone SoC"
+        depends on ARCH_DAVINCI || (ARCH_KEYSTONE && TI_AEMIF)
         help
          Enable the driver for NAND flash chips on Texas Instruments
-         DaVinci processors.
+         DaVinci/Keystone processors.
 
 config MTD_NAND_TXX9NDFMC
        tristate "NAND Flash support for TXx9 SoC"
index 59f08c44abdbc9be920ea62974d19bcdc7884889..c36e9b84487cd36b55d96efd1d17c6db9494c0fc 100644 (file)
@@ -1961,10 +1961,8 @@ static int atmel_nand_probe(struct platform_device *pdev)
 
        /* Allocate memory for the device structure (and zero it) */
        host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
-       if (!host) {
-               printk(KERN_ERR "atmel_nand: failed to allocate device structure.\n");
+       if (!host)
                return -ENOMEM;
-       }
 
        res = platform_driver_register(&atmel_nand_nfc_driver);
        if (res)
@@ -2062,14 +2060,14 @@ static int atmel_nand_probe(struct platform_device *pdev)
                }
 
                if (gpio_get_value(host->board.det_pin)) {
-                       printk(KERN_INFO "No SmartMedia card inserted.\n");
+                       dev_info(&pdev->dev, "No SmartMedia card inserted.\n");
                        res = -ENXIO;
                        goto err_no_card;
                }
        }
 
        if (host->board.on_flash_bbt || on_flash_bbt) {
-               printk(KERN_INFO "atmel_nand: Use On Flash BBT\n");
+               dev_info(&pdev->dev, "Use On Flash BBT\n");
                nand_chip->bbt_options |= NAND_BBT_USE_FLASH;
        }
 
index ae8dd7c4103922fc760786be079b7576ad648893..2880d888cfc5c260aefcdd5caba743d05a292ae6 100644 (file)
@@ -418,10 +418,8 @@ static int au1550nd_probe(struct platform_device *pdev)
        }
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
-       if (!ctx) {
-               dev_err(&pdev->dev, "no memory for NAND context\n");
+       if (!ctx)
                return -ENOMEM;
-       }
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r) {
@@ -480,6 +478,8 @@ static int au1550nd_probe(struct platform_device *pdev)
 
        mtd_device_register(&ctx->info, pd->parts, pd->num_parts);
 
+       platform_set_drvdata(pdev, ctx);
+
        return 0;
 
 out3:
index 2c42e125720f2141258e064e1fc024fef092057b..94f55dbde995974213b48158048a92553bfc7475 100644 (file)
@@ -745,7 +745,6 @@ static int bf5xx_nand_probe(struct platform_device *pdev)
 
        info = kzalloc(sizeof(*info), GFP_KERNEL);
        if (info == NULL) {
-               dev_err(&pdev->dev, "no memory for flash info\n");
                err = -ENOMEM;
                goto out_err_kzalloc;
        }
index c34985a55101b0606f76ed580f1e13ac562913e2..f2f64addb5e87119d8b72e9122565ae3ec9150f9 100644 (file)
@@ -640,10 +640,8 @@ static int cafe_nand_probe(struct pci_dev *pdev,
        pci_set_master(pdev);
 
        mtd = kzalloc(sizeof(*mtd) + sizeof(struct cafe_priv), GFP_KERNEL);
-       if (!mtd) {
-               dev_warn(&pdev->dev, "failed to alloc mtd_info\n");
+       if (!mtd)
                return  -ENOMEM;
-       }
        cafe = (void *)(&mtd[1]);
 
        mtd->dev.parent = &pdev->dev;
index 39b2ef848811a5d1cf1c7fea98ef8f6168e98c5f..66ec95e6ca6c760c2713a621d14ec09a51446d66 100644 (file)
@@ -164,7 +164,6 @@ static int __init cmx270_init(void)
                                  sizeof(struct nand_chip),
                                  GFP_KERNEL);
        if (!cmx270_nand_mtd) {
-               pr_debug("Unable to allocate CM-X270 NAND MTD device structure.\n");
                ret = -ENOMEM;
                goto err_kzalloc;
        }
index d469a9a1dea0de7ea5f31172995c6e79411e7822..88109d375ae7f65546a2225e894e19ade98c41ba 100644 (file)
@@ -199,7 +199,6 @@ static int __init cs553x_init_one(int cs, int mmio, unsigned long adr)
        /* Allocate memory for MTD device structure and private data */
        new_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip), GFP_KERNEL);
        if (!new_mtd) {
-               printk(KERN_WARNING "Unable to allocate CS553X NAND MTD device structure.\n");
                err = -ENOMEM;
                goto out;
        }
index b77a01efb4837ea325988ee6e58e82bd128d7892..a4989ec6292efa0127ba4cc84d13fd07ad09fe4b 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/slab.h>
 #include <linux/of_device.h>
 #include <linux/of.h>
+#include <linux/of_mtd.h>
 
 #include <linux/platform_data/mtd-davinci.h>
 #include <linux/platform_data/mtd-davinci-aemif.h>
@@ -487,7 +488,7 @@ static int nand_davinci_dev_ready(struct mtd_info *mtd)
  * ten ECC bytes plus the manufacturer's bad block marker byte, and
  * and not overlapping the default BBT markers.
  */
-static struct nand_ecclayout hwecc4_small __initconst = {
+static struct nand_ecclayout hwecc4_small = {
        .eccbytes = 10,
        .eccpos = { 0, 1, 2, 3, 4,
                /* offset 5 holds the badblock marker */
@@ -503,7 +504,7 @@ static struct nand_ecclayout hwecc4_small __initconst = {
  * storing ten ECC bytes plus the manufacturer's bad block marker byte,
  * and not overlapping the default BBT markers.
  */
-static struct nand_ecclayout hwecc4_2048 __initconst = {
+static struct nand_ecclayout hwecc4_2048 = {
        .eccbytes = 40,
        .eccpos = {
                /* at the end of spare sector */
@@ -534,17 +535,19 @@ static struct davinci_nand_pdata
                struct davinci_nand_pdata *pdata;
                const char *mode;
                u32 prop;
-               int len;
 
                pdata =  devm_kzalloc(&pdev->dev,
                                sizeof(struct davinci_nand_pdata),
                                GFP_KERNEL);
                pdev->dev.platform_data = pdata;
                if (!pdata)
-                       return NULL;
+                       return ERR_PTR(-ENOMEM);
                if (!of_property_read_u32(pdev->dev.of_node,
                        "ti,davinci-chipselect", &prop))
                        pdev->id = prop;
+               else
+                       return ERR_PTR(-EINVAL);
+
                if (!of_property_read_u32(pdev->dev.of_node,
                        "ti,davinci-mask-ale", &prop))
                        pdata->mask_ale = prop;
@@ -555,6 +558,8 @@ static struct davinci_nand_pdata
                        "ti,davinci-mask-chipsel", &prop))
                        pdata->mask_chipsel = prop;
                if (!of_property_read_string(pdev->dev.of_node,
+                       "nand-ecc-mode", &mode) ||
+                   !of_property_read_string(pdev->dev.of_node,
                        "ti,davinci-ecc-mode", &mode)) {
                        if (!strncmp("none", mode, 4))
                                pdata->ecc_mode = NAND_ECC_NONE;
@@ -566,12 +571,16 @@ static struct davinci_nand_pdata
                if (!of_property_read_u32(pdev->dev.of_node,
                        "ti,davinci-ecc-bits", &prop))
                        pdata->ecc_bits = prop;
-               if (!of_property_read_u32(pdev->dev.of_node,
+
+               prop = of_get_nand_bus_width(pdev->dev.of_node);
+               if (0 < prop || !of_property_read_u32(pdev->dev.of_node,
                        "ti,davinci-nand-buswidth", &prop))
                        if (prop == 16)
                                pdata->options |= NAND_BUSWIDTH_16;
-               if (of_find_property(pdev->dev.of_node,
-                       "ti,davinci-nand-use-bbt", &len))
+               if (of_property_read_bool(pdev->dev.of_node,
+                       "nand-on-flash-bbt") ||
+                   of_property_read_bool(pdev->dev.of_node,
+                       "ti,davinci-nand-use-bbt"))
                        pdata->bbt_options = NAND_BBT_USE_FLASH;
        }
 
@@ -585,7 +594,7 @@ static struct davinci_nand_pdata
 }
 #endif
 
-static int __init nand_davinci_probe(struct platform_device *pdev)
+static int nand_davinci_probe(struct platform_device *pdev)
 {
        struct davinci_nand_pdata       *pdata;
        struct davinci_nand_info        *info;
@@ -598,6 +607,9 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        nand_ecc_modes_t                ecc_mode;
 
        pdata = nand_davinci_get_pdata(pdev);
+       if (IS_ERR(pdata))
+               return PTR_ERR(pdata);
+
        /* insist on board-specific configuration */
        if (!pdata)
                return -ENODEV;
@@ -607,11 +619,8 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                return -ENODEV;
 
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
-       if (!info) {
-               dev_err(&pdev->dev, "unable to allocate memory\n");
-               ret = -ENOMEM;
-               goto err_nomem;
-       }
+       if (!info)
+               return -ENOMEM;
 
        platform_set_drvdata(pdev, info);
 
@@ -619,19 +628,23 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        res2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
        if (!res1 || !res2) {
                dev_err(&pdev->dev, "resource missing\n");
-               ret = -EINVAL;
-               goto err_nomem;
+               return -EINVAL;
        }
 
        vaddr = devm_ioremap_resource(&pdev->dev, res1);
-       if (IS_ERR(vaddr)) {
-               ret = PTR_ERR(vaddr);
-               goto err_ioremap;
-       }
-       base = devm_ioremap_resource(&pdev->dev, res2);
-       if (IS_ERR(base)) {
-               ret = PTR_ERR(base);
-               goto err_ioremap;
+       if (IS_ERR(vaddr))
+               return PTR_ERR(vaddr);
+
+       /*
+        * This registers range is used to setup NAND settings. In case with
+        * TI AEMIF driver, the same memory address range is requested already
+        * by AEMIF, so we cannot request it twice, just ioremap.
+        * The AEMIF and NAND drivers not use the same registers in this range.
+        */
+       base = devm_ioremap(&pdev->dev, res2->start, resource_size(res2));
+       if (!base) {
+               dev_err(&pdev->dev, "ioremap failed for resource %pR\n", res2);
+               return -EADDRNOTAVAIL;
        }
 
        info->dev               = &pdev->dev;
@@ -699,7 +712,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                        spin_unlock_irq(&davinci_nand_lock);
 
                        if (ret == -EBUSY)
-                               goto err_ecc;
+                               return ret;
 
                        info->chip.ecc.calculate = nand_davinci_calculate_4bit;
                        info->chip.ecc.correct = nand_davinci_correct_4bit;
@@ -715,8 +728,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                info->chip.ecc.strength = pdata->ecc_bits;
                break;
        default:
-               ret = -EINVAL;
-               goto err_ecc;
+               return -EINVAL;
        }
        info->chip.ecc.mode = ecc_mode;
 
@@ -724,7 +736,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        if (IS_ERR(info->clk)) {
                ret = PTR_ERR(info->clk);
                dev_dbg(&pdev->dev, "unable to get AEMIF clock, err %d\n", ret);
-               goto err_clk;
+               return ret;
        }
 
        ret = clk_prepare_enable(info->clk);
@@ -753,7 +765,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                                                        info->core_chipsel);
        if (ret < 0) {
                dev_dbg(&pdev->dev, "NAND timing values setup fail\n");
-               goto err_timing;
+               goto err;
        }
 
        spin_lock_irq(&davinci_nand_lock);
@@ -769,7 +781,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
        ret = nand_scan_ident(&info->mtd, pdata->mask_chipsel ? 2 : 1, NULL);
        if (ret < 0) {
                dev_dbg(&pdev->dev, "no NAND chip(s) found\n");
-               goto err_scan;
+               goto err;
        }
 
        /* Update ECC layout if needed ... for 1-bit HW ECC, the default
@@ -783,7 +795,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                if (!chunks || info->mtd.oobsize < 16) {
                        dev_dbg(&pdev->dev, "too small\n");
                        ret = -EINVAL;
-                       goto err_scan;
+                       goto err;
                }
 
                /* For small page chips, preserve the manufacturer's
@@ -814,7 +826,7 @@ static int __init nand_davinci_probe(struct platform_device *pdev)
                dev_warn(&pdev->dev, "no 4-bit ECC support yet "
                                "for 4KiB-page NAND\n");
                ret = -EIO;
-               goto err_scan;
+               goto err;
 
 syndrome_done:
                info->chip.ecc.layout = &info->ecclayout;
@@ -822,7 +834,7 @@ syndrome_done:
 
        ret = nand_scan_tail(&info->mtd);
        if (ret < 0)
-               goto err_scan;
+               goto err;
 
        if (pdata->parts)
                ret = mtd_device_parse_register(&info->mtd, NULL, NULL,
@@ -835,7 +847,7 @@ syndrome_done:
                                                NULL, 0);
        }
        if (ret < 0)
-               goto err_scan;
+               goto err;
 
        val = davinci_nand_readl(info, NRCSR_OFFSET);
        dev_info(&pdev->dev, "controller rev. %d.%d\n",
@@ -843,8 +855,7 @@ syndrome_done:
 
        return 0;
 
-err_scan:
-err_timing:
+err:
        clk_disable_unprepare(info->clk);
 
 err_clk_enable:
@@ -852,15 +863,10 @@ err_clk_enable:
        if (ecc_mode == NAND_ECC_HW_SYNDROME)
                ecc4_busy = false;
        spin_unlock_irq(&davinci_nand_lock);
-
-err_ecc:
-err_clk:
-err_ioremap:
-err_nomem:
        return ret;
 }
 
-static int __exit nand_davinci_remove(struct platform_device *pdev)
+static int nand_davinci_remove(struct platform_device *pdev)
 {
        struct davinci_nand_info *info = platform_get_drvdata(pdev);
 
@@ -877,7 +883,8 @@ static int __exit nand_davinci_remove(struct platform_device *pdev)
 }
 
 static struct platform_driver nand_davinci_driver = {
-       .remove         = __exit_p(nand_davinci_remove),
+       .probe          = nand_davinci_probe,
+       .remove         = nand_davinci_remove,
        .driver         = {
                .name   = "davinci_nand",
                .owner  = THIS_MODULE,
@@ -886,7 +893,7 @@ static struct platform_driver nand_davinci_driver = {
 };
 MODULE_ALIAS("platform:davinci_nand");
 
-module_platform_driver_probe(nand_davinci_driver, nand_davinci_probe);
+module_platform_driver(nand_davinci_driver);
 
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Texas Instruments");
index 370b9dd7a2786841f3180d732321c99416030559..c07cd573ad3af0dd4fa1e91f36c4a44259bbd5e7 100644 (file)
@@ -125,7 +125,6 @@ static void reset_buf(struct denali_nand_info *denali)
 
 static void write_byte_to_buf(struct denali_nand_info *denali, uint8_t byte)
 {
-       BUG_ON(denali->buf.tail >= sizeof(denali->buf.buf));
        denali->buf.buf[denali->buf.tail++] = byte;
 }
 
@@ -897,7 +896,7 @@ static void read_oob_data(struct mtd_info *mtd, uint8_t *buf, int page)
 /* this function examines buffers to see if they contain data that
  * indicate that the buffer is part of an erased region of flash.
  */
-bool is_erased(uint8_t *buf, int len)
+static bool is_erased(uint8_t *buf, int len)
 {
        int i = 0;
        for (i = 0; i < len; i++)
@@ -1429,20 +1428,12 @@ int denali_init(struct denali_nand_info *denali)
                }
        }
 
-       /* Is 32-bit DMA supported? */
-       ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
-       if (ret) {
-               pr_err("Spectra: no usable DMA configuration\n");
-               return ret;
-       }
-       denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
-                                            DENALI_BUF_SIZE,
-                                            DMA_BIDIRECTIONAL);
+       /* allocate a temporary buffer for nand_scan_ident() */
+       denali->buf.buf = devm_kzalloc(denali->dev, PAGE_SIZE,
+                                       GFP_DMA | GFP_KERNEL);
+       if (!denali->buf.buf)
+               return -ENOMEM;
 
-       if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
-               dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
-               return -EIO;
-       }
        denali->mtd.dev.parent = denali->dev;
        denali_hw_init(denali);
        denali_drv_init(denali);
@@ -1475,12 +1466,29 @@ int denali_init(struct denali_nand_info *denali)
                goto failed_req_irq;
        }
 
-       /* MTD supported page sizes vary by kernel. We validate our
-        * kernel supports the device here.
-        */
-       if (denali->mtd.writesize > NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE) {
-               ret = -ENODEV;
-               pr_err("Spectra: device size not supported by this version of MTD.");
+       /* allocate the right size buffer now */
+       devm_kfree(denali->dev, denali->buf.buf);
+       denali->buf.buf = devm_kzalloc(denali->dev,
+                            denali->mtd.writesize + denali->mtd.oobsize,
+                            GFP_KERNEL);
+       if (!denali->buf.buf) {
+               ret = -ENOMEM;
+               goto failed_req_irq;
+       }
+
+       /* Is 32-bit DMA supported? */
+       ret = dma_set_mask(denali->dev, DMA_BIT_MASK(32));
+       if (ret) {
+               pr_err("Spectra: no usable DMA configuration\n");
+               goto failed_req_irq;
+       }
+
+       denali->buf.dma_buf = dma_map_single(denali->dev, denali->buf.buf,
+                            denali->mtd.writesize + denali->mtd.oobsize,
+                            DMA_BIDIRECTIONAL);
+       if (dma_mapping_error(denali->dev, denali->buf.dma_buf)) {
+               dev_err(denali->dev, "Spectra: failed to map DMA buffer\n");
+               ret = -EIO;
                goto failed_req_irq;
        }
 
@@ -1602,7 +1610,8 @@ EXPORT_SYMBOL(denali_init);
 void denali_remove(struct denali_nand_info *denali)
 {
        denali_irq_cleanup(denali->irq, denali);
-       dma_unmap_single(denali->dev, denali->buf.dma_buf, DENALI_BUF_SIZE,
+       dma_unmap_single(denali->dev, denali->buf.dma_buf,
+                       denali->mtd.writesize + denali->mtd.oobsize,
                        DMA_BIDIRECTIONAL);
 }
 EXPORT_SYMBOL(denali_remove);
index cec5712862c9d01c50c417cad96f0bf3aa9a60ec..96681746242171fcbb5fdb4ab6beb6a77be3e54b 100644 (file)
 
 #define ECC_SECTOR_SIZE     512
 
-#define DENALI_BUF_SIZE                (NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE)
-
 struct nand_buf {
        int head;
        int tail;
-       uint8_t buf[DENALI_BUF_SIZE];
+       uint8_t *buf;
        dma_addr_t dma_buf;
 };
 
index 92530244e2cbfdf48ecc2aa2282b90d12a98d0ad..babb02c4b2204ed0c5881a3577084c2ea826d5df 100644 (file)
@@ -108,7 +108,7 @@ static int denali_dt_probe(struct platform_device *ofdev)
                denali->dev->dma_mask = NULL;
        }
 
-       dt->clk = clk_get(&ofdev->dev, NULL);
+       dt->clk = devm_clk_get(&ofdev->dev, NULL);
        if (IS_ERR(dt->clk)) {
                dev_err(&ofdev->dev, "no clk available\n");
                return PTR_ERR(dt->clk);
@@ -124,7 +124,6 @@ static int denali_dt_probe(struct platform_device *ofdev)
 
 out_disable_clk:
        clk_disable_unprepare(dt->clk);
-       clk_put(dt->clk);
 
        return ret;
 }
@@ -135,7 +134,6 @@ static int denali_dt_remove(struct platform_device *ofdev)
 
        denali_remove(&dt->denali);
        clk_disable(dt->clk);
-       clk_put(dt->clk);
 
        return 0;
 }
index 033f177a6369b2d240b499f33df0b6bd925ed4d2..6e2f387b823f694e59e368bc987850a986c7d0c2 100644 (file)
@@ -21,7 +21,7 @@
 #define DENALI_NAND_NAME    "denali-nand-pci"
 
 /* List of platforms this NAND controller has be integrated into */
-static DEFINE_PCI_DEVICE_TABLE(denali_pci_ids) = {
+static const struct pci_device_id denali_pci_ids[] = {
        { PCI_VDEVICE(INTEL, 0x0701), INTEL_CE4100 },
        { PCI_VDEVICE(INTEL, 0x0809), INTEL_MRST },
        { /* end: all zeroes */ }
@@ -131,7 +131,6 @@ static struct pci_driver denali_pci_driver = {
 
 static int denali_init_pci(void)
 {
-       pr_info("Spectra MTD driver built on %s @ %s\n", __DATE__, __TIME__);
        return pci_register_driver(&denali_pci_driver);
 }
 module_init(denali_init_pci);
index b68a4959f700af3e2768af69e6dd9afd0f94c8e1..fec31d71b84e03d7a84cbaf15b4558c16d413e0a 100644 (file)
@@ -1058,7 +1058,6 @@ static inline int __init nftl_partscan(struct mtd_info *mtd, struct mtd_partitio
 
        buf = kmalloc(mtd->writesize, GFP_KERNEL);
        if (!buf) {
-               printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
                return 0;
        }
        if (!(numheaders = find_media_headers(mtd, buf, "ANAND", 1)))
@@ -1166,7 +1165,6 @@ static inline int __init inftl_partscan(struct mtd_info *mtd, struct mtd_partiti
 
        buf = kmalloc(mtd->writesize, GFP_KERNEL);
        if (!buf) {
-               printk(KERN_ERR "DiskOnChip mediaheader kmalloc failed!\n");
                return 0;
        }
 
@@ -1440,10 +1438,13 @@ static int __init doc_probe(unsigned long physadr)
        int reg, len, numchips;
        int ret = 0;
 
+       if (!request_mem_region(physadr, DOC_IOREMAP_LEN, NULL))
+               return -EBUSY;
        virtadr = ioremap(physadr, DOC_IOREMAP_LEN);
        if (!virtadr) {
                printk(KERN_ERR "Diskonchip ioremap failed: 0x%x bytes at 0x%lx\n", DOC_IOREMAP_LEN, physadr);
-               return -EIO;
+               ret = -EIO;
+               goto error_ioremap;
        }
 
        /* It's not possible to cleanly detect the DiskOnChip - the
@@ -1561,7 +1562,6 @@ static int __init doc_probe(unsigned long physadr)
            sizeof(struct nand_chip) + sizeof(struct doc_priv) + (2 * sizeof(struct nand_bbt_descr));
        mtd = kzalloc(len, GFP_KERNEL);
        if (!mtd) {
-               printk(KERN_ERR "DiskOnChip kmalloc (%d bytes) failed!\n", len);
                ret = -ENOMEM;
                goto fail;
        }
@@ -1629,6 +1629,10 @@ static int __init doc_probe(unsigned long physadr)
        WriteDOC(save_control, virtadr, DOCControl);
  fail:
        iounmap(virtadr);
+
+error_ioremap:
+       release_mem_region(physadr, DOC_IOREMAP_LEN);
+
        return ret;
 }
 
@@ -1645,6 +1649,7 @@ static void release_nanddoc(void)
                nextmtd = doc->nextdoc;
                nand_release(mtd);
                iounmap(doc->virtadr);
+               release_mem_region(doc->physadr, DOC_IOREMAP_LEN);
                kfree(mtd);
        }
 }
index c966fc7474ced5fc8423b9440340f1d9b5072bbc..bcf60800c3ce7f5e0489972ebe7a3e3f83d225df 100644 (file)
@@ -847,7 +847,6 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
        if (!fsl_lbc_ctrl_dev->nand) {
                elbc_fcm_ctrl = kzalloc(sizeof(*elbc_fcm_ctrl), GFP_KERNEL);
                if (!elbc_fcm_ctrl) {
-                       dev_err(dev, "failed to allocate memory\n");
                        mutex_unlock(&fsl_elbc_nand_mutex);
                        ret = -ENOMEM;
                        goto err;
@@ -875,7 +874,7 @@ static int fsl_elbc_nand_probe(struct platform_device *pdev)
                goto err;
        }
 
-       priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start);
+       priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
        if (!priv->mtd.name) {
                ret = -ENOMEM;
                goto err;
index 43355779cff583975721e5c7bd7770bc055aa1c3..90ca7e75d6f038e4cefb365ee2a436eac4ac8cc2 100644 (file)
@@ -1060,7 +1060,6 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
        if (!fsl_ifc_ctrl_dev->nand) {
                ifc_nand_ctrl = kzalloc(sizeof(*ifc_nand_ctrl), GFP_KERNEL);
                if (!ifc_nand_ctrl) {
-                       dev_err(&dev->dev, "failed to allocate memory\n");
                        mutex_unlock(&fsl_ifc_nand_mutex);
                        return -ENOMEM;
                }
@@ -1101,7 +1100,7 @@ static int fsl_ifc_nand_probe(struct platform_device *dev)
                    IFC_NAND_EVTER_INTR_FTOERIR_EN |
                    IFC_NAND_EVTER_INTR_WPERIR_EN,
                    &ifc->ifc_nand.nand_evter_intr_en);
-       priv->mtd.name = kasprintf(GFP_KERNEL, "%x.flash", (unsigned)res.start);
+       priv->mtd.name = kasprintf(GFP_KERNEL, "%llx.flash", (u64)res.start);
        if (!priv->mtd.name) {
                ret = -ENOMEM;
                goto err;
index 8b2752263db9a5549742bb36c3dcee48999b8b62..1550692973dc2ebcaa6864bc3e2c51607872b818 100644 (file)
@@ -889,10 +889,8 @@ static int fsmc_nand_probe_config_dt(struct platform_device *pdev,
 
        pdata->nand_timings = devm_kzalloc(&pdev->dev,
                                sizeof(*pdata->nand_timings), GFP_KERNEL);
-       if (!pdata->nand_timings) {
-               dev_err(&pdev->dev, "no memory for nand_timing\n");
+       if (!pdata->nand_timings)
                return -ENOMEM;
-       }
        of_property_read_u8_array(np, "timings", (u8 *)pdata->nand_timings,
                                                sizeof(*pdata->nand_timings));
 
@@ -950,10 +948,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
 
        /* Allocate memory for the device structure (and zero it) */
        host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
-       if (!host) {
-               dev_err(&pdev->dev, "failed to allocate device structure\n");
+       if (!host)
                return -ENOMEM;
-       }
 
        res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "nand_data");
        host->data_va = devm_ioremap_resource(&pdev->dev, res);
@@ -1108,8 +1104,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
                        host->ecc_place = &fsmc_ecc4_lp_place;
                        break;
                default:
-                       printk(KERN_WARNING "No oob scheme defined for "
-                              "oobsize %d\n", mtd->oobsize);
+                       dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
+                                mtd->oobsize);
                        BUG();
                }
        } else {
@@ -1124,8 +1120,8 @@ static int __init fsmc_nand_probe(struct platform_device *pdev)
                        nand->ecc.layout = &fsmc_ecc1_128_layout;
                        break;
                default:
-                       printk(KERN_WARNING "No oob scheme defined for "
-                              "oobsize %d\n", mtd->oobsize);
+                       dev_warn(&pdev->dev, "No oob scheme defined for oobsize %d\n",
+                                mtd->oobsize);
                        BUG();
                }
        }
index e826f898241f92b24704ba7103fc0cdd970a63d1..8e6148aa4539a290b4b3a4cda8883f1bbba58f92 100644 (file)
@@ -132,13 +132,17 @@ static int gpio_nand_get_config_of(const struct device *dev,
 
 static struct resource *gpio_nand_get_io_sync_of(struct platform_device *pdev)
 {
-       struct resource *r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
+       struct resource *r;
        u64 addr;
 
-       if (!r || of_property_read_u64(pdev->dev.of_node,
+       if (of_property_read_u64(pdev->dev.of_node,
                                       "gpio-control-nand,io-sync-reg", &addr))
                return NULL;
 
+       r = devm_kzalloc(&pdev->dev, sizeof(*r), GFP_KERNEL);
+       if (!r)
+               return NULL;
+
        r->start = addr;
        r->end = r->start + 0x3;
        r->flags = IORESOURCE_MEM;
@@ -211,10 +215,8 @@ static int gpio_nand_probe(struct platform_device *pdev)
                return -EINVAL;
 
        gpiomtd = devm_kzalloc(&pdev->dev, sizeof(*gpiomtd), GFP_KERNEL);
-       if (!gpiomtd) {
-               dev_err(&pdev->dev, "failed to create NAND MTD\n");
+       if (!gpiomtd)
                return -ENOMEM;
-       }
 
        chip = &gpiomtd->nand_chip;
 
index aaced29727fb0437f6a0c142253b04cbc0ca82d0..dd1df605a1d61ec8a43ffb5515ea50ce2f3c9b69 100644 (file)
@@ -20,6 +20,7 @@
  */
 #include <linux/delay.h>
 #include <linux/clk.h>
+#include <linux/slab.h>
 
 #include "gpmi-nand.h"
 #include "gpmi-regs.h"
@@ -207,30 +208,41 @@ void gpmi_dump_info(struct gpmi_nand_data *this)
        u32 reg;
        int i;
 
-       pr_err("Show GPMI registers :\n");
+       dev_err(this->dev, "Show GPMI registers :\n");
        for (i = 0; i <= HW_GPMI_DEBUG / 0x10 + 1; i++) {
                reg = readl(r->gpmi_regs + i * 0x10);
-               pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+               dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
        }
 
        /* start to print out the BCH info */
-       pr_err("Show BCH registers :\n");
+       dev_err(this->dev, "Show BCH registers :\n");
        for (i = 0; i <= HW_BCH_VERSION / 0x10 + 1; i++) {
                reg = readl(r->bch_regs + i * 0x10);
-               pr_err("offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
+               dev_err(this->dev, "offset 0x%.3x : 0x%.8x\n", i * 0x10, reg);
        }
-       pr_err("BCH Geometry :\n");
-       pr_err("GF length              : %u\n", geo->gf_len);
-       pr_err("ECC Strength           : %u\n", geo->ecc_strength);
-       pr_err("Page Size in Bytes     : %u\n", geo->page_size);
-       pr_err("Metadata Size in Bytes : %u\n", geo->metadata_size);
-       pr_err("ECC Chunk Size in Bytes: %u\n", geo->ecc_chunk_size);
-       pr_err("ECC Chunk Count        : %u\n", geo->ecc_chunk_count);
-       pr_err("Payload Size in Bytes  : %u\n", geo->payload_size);
-       pr_err("Auxiliary Size in Bytes: %u\n", geo->auxiliary_size);
-       pr_err("Auxiliary Status Offset: %u\n", geo->auxiliary_status_offset);
-       pr_err("Block Mark Byte Offset : %u\n", geo->block_mark_byte_offset);
-       pr_err("Block Mark Bit Offset  : %u\n", geo->block_mark_bit_offset);
+       dev_err(this->dev, "BCH Geometry :\n"
+               "GF length              : %u\n"
+               "ECC Strength           : %u\n"
+               "Page Size in Bytes     : %u\n"
+               "Metadata Size in Bytes : %u\n"
+               "ECC Chunk Size in Bytes: %u\n"
+               "ECC Chunk Count        : %u\n"
+               "Payload Size in Bytes  : %u\n"
+               "Auxiliary Size in Bytes: %u\n"
+               "Auxiliary Status Offset: %u\n"
+               "Block Mark Byte Offset : %u\n"
+               "Block Mark Bit Offset  : %u\n",
+               geo->gf_len,
+               geo->ecc_strength,
+               geo->page_size,
+               geo->metadata_size,
+               geo->ecc_chunk_size,
+               geo->ecc_chunk_count,
+               geo->payload_size,
+               geo->auxiliary_size,
+               geo->auxiliary_status_offset,
+               geo->block_mark_byte_offset,
+               geo->block_mark_bit_offset);
 }
 
 /* Configures the geometry for BCH.  */
@@ -265,8 +277,8 @@ int bch_set_geometry(struct gpmi_nand_data *this)
        * chip, otherwise it will lock up. So we skip resetting BCH on the MX23.
        * On the other hand, the MX28 needs the reset, because one case has been
        * seen where the BCH produced ECC errors constantly after 10000
-       * consecutive reboots. The latter case has not been seen on the MX23 yet,
-       * still we don't know if it could happen there as well.
+       * consecutive reboots. The latter case has not been seen on the MX23
+       * yet, still we don't know if it could happen there as well.
        */
        ret = gpmi_reset_block(r->bch_regs, GPMI_IS_MX23(this));
        if (ret)
@@ -353,7 +365,7 @@ static int gpmi_nfc_compute_hardware_timing(struct gpmi_nand_data *this,
        improved_timing_is_available =
                (target.tREA_in_ns  >= 0) &&
                (target.tRLOH_in_ns >= 0) &&
-               (target.tRHOH_in_ns >= 0) ;
+               (target.tRHOH_in_ns >= 0);
 
        /* Inspect the clock. */
        nfc->clock_frequency_in_hz = clk_get_rate(r->clock[0]);
@@ -911,10 +923,14 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
        struct resources  *r = &this->resources;
        struct nand_chip *nand = &this->nand;
        struct mtd_info  *mtd = &this->mtd;
-       uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {};
+       uint8_t *feature;
        unsigned long rate;
        int ret;
 
+       feature = kzalloc(ONFI_SUBFEATURE_PARAM_LEN, GFP_KERNEL);
+       if (!feature)
+               return -ENOMEM;
+
        nand->select_chip(mtd, 0);
 
        /* [1] send SET FEATURE commond to NAND */
@@ -942,11 +958,13 @@ static int enable_edo_mode(struct gpmi_nand_data *this, int mode)
 
        this->flags |= GPMI_ASYNC_EDO_ENABLED;
        this->timing_mode = mode;
+       kfree(feature);
        dev_info(this->dev, "enable the asynchronous EDO mode %d\n", mode);
        return 0;
 
 err_out:
        nand->select_chip(mtd, -1);
+       kfree(feature);
        dev_err(this->dev, "mode:%d ,failed in set feature.\n", mode);
        return -EINVAL;
 }
@@ -986,7 +1004,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
        /* Enable the clock. */
        ret = gpmi_enable_clk(this);
        if (ret) {
-               pr_err("We failed in enable the clk\n");
+               dev_err(this->dev, "We failed in enable the clk\n");
                goto err_out;
        }
 
@@ -1003,7 +1021,7 @@ void gpmi_begin(struct gpmi_nand_data *this)
        /* [1] Set HW_GPMI_TIMING0 */
        reg = BF_GPMI_TIMING0_ADDRESS_SETUP(hw.address_setup_in_cycles) |
                BF_GPMI_TIMING0_DATA_HOLD(hw.data_hold_in_cycles)         |
-               BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles)       ;
+               BF_GPMI_TIMING0_DATA_SETUP(hw.data_setup_in_cycles);
 
        writel(reg, gpmi_regs + HW_GPMI_TIMING0);
 
@@ -1090,7 +1108,7 @@ int gpmi_is_ready(struct gpmi_nand_data *this, unsigned chip)
                mask = MX28_BF_GPMI_STAT_READY_BUSY(1 << chip);
                reg = readl(r->gpmi_regs + HW_GPMI_STAT);
        } else
-               pr_err("unknow arch.\n");
+               dev_err(this->dev, "unknow arch.\n");
        return reg & mask;
 }
 
@@ -1121,10 +1139,8 @@ int gpmi_send_command(struct gpmi_nand_data *this)
        desc = dmaengine_prep_slave_sg(channel,
                                        (struct scatterlist *)pio,
                                        ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
-       if (!desc) {
-               pr_err("step 1 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
 
        /* [2] send out the COMMAND + ADDRESS string stored in @buffer */
        sgl = &this->cmd_sgl;
@@ -1134,11 +1150,8 @@ int gpmi_send_command(struct gpmi_nand_data *this)
        desc = dmaengine_prep_slave_sg(channel,
                                sgl, 1, DMA_MEM_TO_DEV,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-
-       if (!desc) {
-               pr_err("step 2 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
 
        /* [3] submit the DMA */
        set_dma_type(this, DMA_FOR_COMMAND);
@@ -1167,20 +1180,17 @@ int gpmi_send_data(struct gpmi_nand_data *this)
        pio[1] = 0;
        desc = dmaengine_prep_slave_sg(channel, (struct scatterlist *)pio,
                                        ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
-       if (!desc) {
-               pr_err("step 1 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
 
        /* [2] send DMA request */
        prepare_data_dma(this, DMA_TO_DEVICE);
        desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
                                        1, DMA_MEM_TO_DEV,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               pr_err("step 2 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
+
        /* [3] submit the DMA */
        set_dma_type(this, DMA_FOR_WRITE_DATA);
        return start_dma_without_bch_irq(this, desc);
@@ -1204,20 +1214,16 @@ int gpmi_read_data(struct gpmi_nand_data *this)
        desc = dmaengine_prep_slave_sg(channel,
                                        (struct scatterlist *)pio,
                                        ARRAY_SIZE(pio), DMA_TRANS_NONE, 0);
-       if (!desc) {
-               pr_err("step 1 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
 
        /* [2] : send DMA request */
        prepare_data_dma(this, DMA_FROM_DEVICE);
        desc = dmaengine_prep_slave_sg(channel, &this->data_sgl,
                                        1, DMA_DEV_TO_MEM,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               pr_err("step 2 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
 
        /* [3] : submit the DMA */
        set_dma_type(this, DMA_FOR_READ_DATA);
@@ -1262,10 +1268,9 @@ int gpmi_send_page(struct gpmi_nand_data *this,
                                        (struct scatterlist *)pio,
                                        ARRAY_SIZE(pio), DMA_TRANS_NONE,
                                        DMA_CTRL_ACK);
-       if (!desc) {
-               pr_err("step 2 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
+
        set_dma_type(this, DMA_FOR_WRITE_ECC_PAGE);
        return start_dma_with_bch_irq(this, desc);
 }
@@ -1297,10 +1302,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
        desc = dmaengine_prep_slave_sg(channel,
                                (struct scatterlist *)pio, 2,
                                DMA_TRANS_NONE, 0);
-       if (!desc) {
-               pr_err("step 1 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
 
        /* [2] Enable the BCH block and read. */
        command_mode = BV_GPMI_CTRL0_COMMAND_MODE__READ;
@@ -1327,10 +1330,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
                                        (struct scatterlist *)pio,
                                        ARRAY_SIZE(pio), DMA_TRANS_NONE,
                                        DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               pr_err("step 2 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
 
        /* [3] Disable the BCH block */
        command_mode = BV_GPMI_CTRL0_COMMAND_MODE__WAIT_FOR_READY;
@@ -1348,10 +1349,8 @@ int gpmi_read_page(struct gpmi_nand_data *this,
                                (struct scatterlist *)pio, 3,
                                DMA_TRANS_NONE,
                                DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
-       if (!desc) {
-               pr_err("step 3 error\n");
-               return -1;
-       }
+       if (!desc)
+               return -EINVAL;
 
        /* [4] submit the DMA */
        set_dma_type(this, DMA_FOR_READ_ECC_PAGE);
index dabbc14db5630d8592268012fc067559179aa0f8..ca6369fe91ff31fc89bd382dca62261774310ff0 100644 (file)
@@ -18,9 +18,6 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/clk.h>
 #include <linux/slab.h>
 #include <linux/interrupt.h>
@@ -352,6 +349,9 @@ static int legacy_set_geometry(struct gpmi_nand_data *this)
 
 int common_nfc_set_geometry(struct gpmi_nand_data *this)
 {
+       if (of_property_read_bool(this->dev->of_node, "fsl,use-minimum-ecc")
+               && set_geometry_by_ecc_info(this))
+               return 0;
        return legacy_set_geometry(this);
 }
 
@@ -367,25 +367,28 @@ void prepare_data_dma(struct gpmi_nand_data *this, enum dma_data_direction dr)
        struct scatterlist *sgl = &this->data_sgl;
        int ret;
 
-       this->direct_dma_map_ok = true;
-
        /* first try to map the upper buffer directly */
-       sg_init_one(sgl, this->upper_buf, this->upper_len);
-       ret = dma_map_sg(this->dev, sgl, 1, dr);
-       if (ret == 0) {
-               /* We have to use our own DMA buffer. */
-               sg_init_one(sgl, this->data_buffer_dma, PAGE_SIZE);
-
-               if (dr == DMA_TO_DEVICE)
-                       memcpy(this->data_buffer_dma, this->upper_buf,
-                               this->upper_len);
-
+       if (virt_addr_valid(this->upper_buf) &&
+               !object_is_on_stack(this->upper_buf)) {
+               sg_init_one(sgl, this->upper_buf, this->upper_len);
                ret = dma_map_sg(this->dev, sgl, 1, dr);
                if (ret == 0)
-                       pr_err("DMA mapping failed.\n");
+                       goto map_fail;
 
-               this->direct_dma_map_ok = false;
+               this->direct_dma_map_ok = true;
+               return;
        }
+
+map_fail:
+       /* We have to use our own DMA buffer. */
+       sg_init_one(sgl, this->data_buffer_dma, this->upper_len);
+
+       if (dr == DMA_TO_DEVICE)
+               memcpy(this->data_buffer_dma, this->upper_buf, this->upper_len);
+
+       dma_map_sg(this->dev, sgl, 1, dr);
+
+       this->direct_dma_map_ok = false;
 }
 
 /* This will be called after the DMA operation is finished. */
@@ -416,7 +419,7 @@ static void dma_irq_callback(void *param)
                break;
 
        default:
-               pr_err("in wrong DMA operation.\n");
+               dev_err(this->dev, "in wrong DMA operation.\n");
        }
 
        complete(dma_c);
@@ -438,7 +441,8 @@ int start_dma_without_bch_irq(struct gpmi_nand_data *this,
        /* Wait for the interrupt from the DMA block. */
        err = wait_for_completion_timeout(dma_c, msecs_to_jiffies(1000));
        if (!err) {
-               pr_err("DMA timeout, last DMA :%d\n", this->last_dma_type);
+               dev_err(this->dev, "DMA timeout, last DMA :%d\n",
+                       this->last_dma_type);
                gpmi_dump_info(this);
                return -ETIMEDOUT;
        }
@@ -467,7 +471,8 @@ int start_dma_with_bch_irq(struct gpmi_nand_data *this,
        /* Wait for the interrupt from the BCH block. */
        err = wait_for_completion_timeout(bch_c, msecs_to_jiffies(1000));
        if (!err) {
-               pr_err("BCH timeout, last DMA :%d\n", this->last_dma_type);
+               dev_err(this->dev, "BCH timeout, last DMA :%d\n",
+                       this->last_dma_type);
                gpmi_dump_info(this);
                return -ETIMEDOUT;
        }
@@ -483,70 +488,38 @@ static int acquire_register_block(struct gpmi_nand_data *this,
        void __iomem *p;
 
        r = platform_get_resource_byname(pdev, IORESOURCE_MEM, res_name);
-       if (!r) {
-               pr_err("Can't get resource for %s\n", res_name);
-               return -ENODEV;
-       }
-
-       p = ioremap(r->start, resource_size(r));
-       if (!p) {
-               pr_err("Can't remap %s\n", res_name);
-               return -ENOMEM;
-       }
+       p = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(p))
+               return PTR_ERR(p);
 
        if (!strcmp(res_name, GPMI_NAND_GPMI_REGS_ADDR_RES_NAME))
                res->gpmi_regs = p;
        else if (!strcmp(res_name, GPMI_NAND_BCH_REGS_ADDR_RES_NAME))
                res->bch_regs = p;
        else
-               pr_err("unknown resource name : %s\n", res_name);
+               dev_err(this->dev, "unknown resource name : %s\n", res_name);
 
        return 0;
 }
 
-static void release_register_block(struct gpmi_nand_data *this)
-{
-       struct resources *res = &this->resources;
-       if (res->gpmi_regs)
-               iounmap(res->gpmi_regs);
-       if (res->bch_regs)
-               iounmap(res->bch_regs);
-       res->gpmi_regs = NULL;
-       res->bch_regs = NULL;
-}
-
 static int acquire_bch_irq(struct gpmi_nand_data *this, irq_handler_t irq_h)
 {
        struct platform_device *pdev = this->pdev;
-       struct resources *res = &this->resources;
        const char *res_name = GPMI_NAND_BCH_INTERRUPT_RES_NAME;
        struct resource *r;
        int err;
 
        r = platform_get_resource_byname(pdev, IORESOURCE_IRQ, res_name);
        if (!r) {
-               pr_err("Can't get resource for %s\n", res_name);
+               dev_err(this->dev, "Can't get resource for %s\n", res_name);
                return -ENODEV;
        }
 
-       err = request_irq(r->start, irq_h, 0, res_name, this);
-       if (err) {
-               pr_err("Can't own %s\n", res_name);
-               return err;
-       }
-
-       res->bch_low_interrupt = r->start;
-       res->bch_high_interrupt = r->end;
-       return 0;
-}
-
-static void release_bch_irq(struct gpmi_nand_data *this)
-{
-       struct resources *res = &this->resources;
-       int i = res->bch_low_interrupt;
+       err = devm_request_irq(this->dev, r->start, irq_h, 0, res_name, this);
+       if (err)
+               dev_err(this->dev, "error requesting BCH IRQ\n");
 
-       for (; i <= res->bch_high_interrupt; i++)
-               free_irq(i, this);
+       return err;
 }
 
 static void release_dma_channels(struct gpmi_nand_data *this)
@@ -567,7 +540,7 @@ static int acquire_dma_channels(struct gpmi_nand_data *this)
        /* request dma channel */
        dma_chan = dma_request_slave_channel(&pdev->dev, "rx-tx");
        if (!dma_chan) {
-               pr_err("Failed to request DMA channel.\n");
+               dev_err(this->dev, "Failed to request DMA channel.\n");
                goto acquire_err;
        }
 
@@ -579,21 +552,6 @@ acquire_err:
        return -EINVAL;
 }
 
-static void gpmi_put_clks(struct gpmi_nand_data *this)
-{
-       struct resources *r = &this->resources;
-       struct clk *clk;
-       int i;
-
-       for (i = 0; i < GPMI_CLK_MAX; i++) {
-               clk = r->clock[i];
-               if (clk) {
-                       clk_put(clk);
-                       r->clock[i] = NULL;
-               }
-       }
-}
-
 static char *extra_clks_for_mx6q[GPMI_CLK_MAX] = {
        "gpmi_apb", "gpmi_bch", "gpmi_bch_apb", "per1_bch",
 };
@@ -606,7 +564,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
        int err, i;
 
        /* The main clock is stored in the first. */
-       r->clock[0] = clk_get(this->dev, "gpmi_io");
+       r->clock[0] = devm_clk_get(this->dev, "gpmi_io");
        if (IS_ERR(r->clock[0])) {
                err = PTR_ERR(r->clock[0]);
                goto err_clock;
@@ -622,7 +580,7 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
                if (extra_clks[i - 1] == NULL)
                        break;
 
-               clk = clk_get(this->dev, extra_clks[i - 1]);
+               clk = devm_clk_get(this->dev, extra_clks[i - 1]);
                if (IS_ERR(clk)) {
                        err = PTR_ERR(clk);
                        goto err_clock;
@@ -644,7 +602,6 @@ static int gpmi_get_clks(struct gpmi_nand_data *this)
 
 err_clock:
        dev_dbg(this->dev, "failed in finding the clocks.\n");
-       gpmi_put_clks(this);
        return err;
 }
 
@@ -666,7 +623,7 @@ static int acquire_resources(struct gpmi_nand_data *this)
 
        ret = acquire_dma_channels(this);
        if (ret)
-               goto exit_dma_channels;
+               goto exit_regs;
 
        ret = gpmi_get_clks(this);
        if (ret)
@@ -675,18 +632,12 @@ static int acquire_resources(struct gpmi_nand_data *this)
 
 exit_clock:
        release_dma_channels(this);
-exit_dma_channels:
-       release_bch_irq(this);
 exit_regs:
-       release_register_block(this);
        return ret;
 }
 
 static void release_resources(struct gpmi_nand_data *this)
 {
-       gpmi_put_clks(this);
-       release_register_block(this);
-       release_bch_irq(this);
        release_dma_channels(this);
 }
 
@@ -732,8 +683,7 @@ static int read_page_prepare(struct gpmi_nand_data *this,
                                                length, DMA_FROM_DEVICE);
                if (dma_mapping_error(dev, dest_phys)) {
                        if (alt_size < length) {
-                               pr_err("%s, Alternate buffer is too small\n",
-                                       __func__);
+                               dev_err(dev, "Alternate buffer is too small\n");
                                return -ENOMEM;
                        }
                        goto map_failed;
@@ -783,8 +733,7 @@ static int send_page_prepare(struct gpmi_nand_data *this,
                                                DMA_TO_DEVICE);
                if (dma_mapping_error(dev, source_phys)) {
                        if (alt_size < length) {
-                               pr_err("%s, Alternate buffer is too small\n",
-                                       __func__);
+                               dev_err(dev, "Alternate buffer is too small\n");
                                return -ENOMEM;
                        }
                        goto map_failed;
@@ -837,14 +786,23 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
 {
        struct bch_geometry *geo = &this->bch_geometry;
        struct device *dev = this->dev;
+       struct mtd_info *mtd = &this->mtd;
 
        /* [1] Allocate a command buffer. PAGE_SIZE is enough. */
        this->cmd_buffer = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
        if (this->cmd_buffer == NULL)
                goto error_alloc;
 
-       /* [2] Allocate a read/write data buffer. PAGE_SIZE is enough. */
-       this->data_buffer_dma = kzalloc(PAGE_SIZE, GFP_DMA | GFP_KERNEL);
+       /*
+        * [2] Allocate a read/write data buffer.
+        *     The gpmi_alloc_dma_buffer can be called twice.
+        *     We allocate a PAGE_SIZE length buffer if gpmi_alloc_dma_buffer
+        *     is called before the nand_scan_ident; and we allocate a buffer
+        *     of the real NAND page size when the gpmi_alloc_dma_buffer is
+        *     called after the nand_scan_ident.
+        */
+       this->data_buffer_dma = kzalloc(mtd->writesize ?: PAGE_SIZE,
+                                       GFP_DMA | GFP_KERNEL);
        if (this->data_buffer_dma == NULL)
                goto error_alloc;
 
@@ -872,7 +830,6 @@ static int gpmi_alloc_dma_buffer(struct gpmi_nand_data *this)
 
 error_alloc:
        gpmi_free_dma_buffer(this);
-       pr_err("Error allocating DMA buffers!\n");
        return -ENOMEM;
 }
 
@@ -904,7 +861,8 @@ static void gpmi_cmd_ctrl(struct mtd_info *mtd, int data, unsigned int ctrl)
 
        ret = gpmi_send_command(this);
        if (ret)
-               pr_err("Chip: %u, Error %d\n", this->current_chip, ret);
+               dev_err(this->dev, "Chip: %u, Error %d\n",
+                       this->current_chip, ret);
 
        this->command_length = 0;
 }
@@ -935,7 +893,7 @@ static void gpmi_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
        struct nand_chip *chip = mtd->priv;
        struct gpmi_nand_data *this = chip->priv;
 
-       pr_debug("len is %d\n", len);
+       dev_dbg(this->dev, "len is %d\n", len);
        this->upper_buf = buf;
        this->upper_len = len;
 
@@ -947,7 +905,7 @@ static void gpmi_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
        struct nand_chip *chip = mtd->priv;
        struct gpmi_nand_data *this = chip->priv;
 
-       pr_debug("len is %d\n", len);
+       dev_dbg(this->dev, "len is %d\n", len);
        this->upper_buf = (uint8_t *)buf;
        this->upper_len = len;
 
@@ -1026,13 +984,13 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
        unsigned int  max_bitflips = 0;
        int           ret;
 
-       pr_debug("page number is : %d\n", page);
+       dev_dbg(this->dev, "page number is : %d\n", page);
        ret = read_page_prepare(this, buf, mtd->writesize,
                                        this->payload_virt, this->payload_phys,
                                        nfc_geo->payload_size,
                                        &payload_virt, &payload_phys);
        if (ret) {
-               pr_err("Inadequate DMA buffer\n");
+               dev_err(this->dev, "Inadequate DMA buffer\n");
                ret = -ENOMEM;
                return ret;
        }
@@ -1046,7 +1004,7 @@ static int gpmi_ecc_read_page(struct mtd_info *mtd, struct nand_chip *chip,
                        nfc_geo->payload_size,
                        payload_virt, payload_phys);
        if (ret) {
-               pr_err("Error in ECC-based read: %d\n", ret);
+               dev_err(this->dev, "Error in ECC-based read: %d\n", ret);
                return ret;
        }
 
@@ -1102,7 +1060,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        dma_addr_t auxiliary_phys;
        int        ret;
 
-       pr_debug("ecc write page.\n");
+       dev_dbg(this->dev, "ecc write page.\n");
        if (this->swap_block_mark) {
                /*
                 * If control arrives here, we're doing block mark swapping.
@@ -1132,7 +1090,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                nfc_geo->payload_size,
                                &payload_virt, &payload_phys);
                if (ret) {
-                       pr_err("Inadequate payload DMA buffer\n");
+                       dev_err(this->dev, "Inadequate payload DMA buffer\n");
                        return 0;
                }
 
@@ -1142,7 +1100,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
                                nfc_geo->auxiliary_size,
                                &auxiliary_virt, &auxiliary_phys);
                if (ret) {
-                       pr_err("Inadequate auxiliary DMA buffer\n");
+                       dev_err(this->dev, "Inadequate auxiliary DMA buffer\n");
                        goto exit_auxiliary;
                }
        }
@@ -1150,7 +1108,7 @@ static int gpmi_ecc_write_page(struct mtd_info *mtd, struct nand_chip *chip,
        /* Ask the NFC. */
        ret = gpmi_send_page(this, payload_phys, auxiliary_phys);
        if (ret)
-               pr_err("Error in ECC-based write: %d\n", ret);
+               dev_err(this->dev, "Error in ECC-based write: %d\n", ret);
 
        if (!this->swap_block_mark) {
                send_page_end(this, chip->oob_poi, mtd->oobsize,
@@ -1240,7 +1198,7 @@ static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
 {
        struct gpmi_nand_data *this = chip->priv;
 
-       pr_debug("page number is %d\n", page);
+       dev_dbg(this->dev, "page number is %d\n", page);
        /* clear the OOB buffer */
        memset(chip->oob_poi, ~0, mtd->oobsize);
 
@@ -1453,7 +1411,6 @@ static int mx23_write_transcription_stamp(struct gpmi_nand_data *this)
 
        /* Write the NCB fingerprint into the page buffer. */
        memset(buffer, ~0, mtd->writesize);
-       memset(chip->oob_poi, ~0, mtd->oobsize);
        memcpy(buffer + 12, fingerprint, strlen(fingerprint));
 
        /* Loop through the first search area, writing NCB fingerprints. */
@@ -1568,7 +1525,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
        /* Set up the NFC geometry which is used by BCH. */
        ret = bch_set_geometry(this);
        if (ret) {
-               pr_err("Error setting BCH geometry : %d\n", ret);
+               dev_err(this->dev, "Error setting BCH geometry : %d\n", ret);
                return ret;
        }
 
@@ -1576,20 +1533,7 @@ static int gpmi_set_geometry(struct gpmi_nand_data *this)
        return gpmi_alloc_dma_buffer(this);
 }
 
-static int gpmi_pre_bbt_scan(struct gpmi_nand_data  *this)
-{
-       /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
-       if (GPMI_IS_MX23(this))
-               this->swap_block_mark = false;
-       else
-               this->swap_block_mark = true;
-
-       /* Set up the medium geometry */
-       return gpmi_set_geometry(this);
-
-}
-
-static void gpmi_nfc_exit(struct gpmi_nand_data *this)
+static void gpmi_nand_exit(struct gpmi_nand_data *this)
 {
        nand_release(&this->mtd);
        gpmi_free_dma_buffer(this);
@@ -1603,8 +1547,11 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
        struct bch_geometry *bch_geo = &this->bch_geometry;
        int ret;
 
-       /* Prepare for the BBT scan. */
-       ret = gpmi_pre_bbt_scan(this);
+       /* Set up swap_block_mark, must be set before the gpmi_set_geometry() */
+       this->swap_block_mark = !GPMI_IS_MX23(this);
+
+       /* Set up the medium geometry */
+       ret = gpmi_set_geometry(this);
        if (ret)
                return ret;
 
@@ -1629,7 +1576,7 @@ static int gpmi_init_last(struct gpmi_nand_data *this)
        return 0;
 }
 
-static int gpmi_nfc_init(struct gpmi_nand_data *this)
+static int gpmi_nand_init(struct gpmi_nand_data *this)
 {
        struct mtd_info  *mtd = &this->mtd;
        struct nand_chip *chip = &this->nand;
@@ -1693,7 +1640,7 @@ static int gpmi_nfc_init(struct gpmi_nand_data *this)
        return 0;
 
 err_out:
-       gpmi_nfc_exit(this);
+       gpmi_nand_exit(this);
        return ret;
 }
 
@@ -1728,15 +1675,13 @@ static int gpmi_nand_probe(struct platform_device *pdev)
        if (of_id) {
                pdev->id_entry = of_id->data;
        } else {
-               pr_err("Failed to find the right device id.\n");
+               dev_err(&pdev->dev, "Failed to find the right device id.\n");
                return -ENODEV;
        }
 
        this = devm_kzalloc(&pdev->dev, sizeof(*this), GFP_KERNEL);
-       if (!this) {
-               pr_err("Failed to allocate per-device memory\n");
+       if (!this)
                return -ENOMEM;
-       }
 
        platform_set_drvdata(pdev, this);
        this->pdev  = pdev;
@@ -1750,7 +1695,7 @@ static int gpmi_nand_probe(struct platform_device *pdev)
        if (ret)
                goto exit_nfc_init;
 
-       ret = gpmi_nfc_init(this);
+       ret = gpmi_nand_init(this);
        if (ret)
                goto exit_nfc_init;
 
@@ -1770,7 +1715,7 @@ static int gpmi_nand_remove(struct platform_device *pdev)
 {
        struct gpmi_nand_data *this = platform_get_drvdata(pdev);
 
-       gpmi_nfc_exit(this);
+       gpmi_nand_exit(this);
        release_resources(this);
        return 0;
 }
index a7685e3a87486b86713fef19da82e9bbad3c6253..4c801fa1872530e681e801d2adaee333d4acffb4 100644 (file)
@@ -26,8 +26,6 @@
 struct resources {
        void __iomem  *gpmi_regs;
        void __iomem  *bch_regs;
-       unsigned int  bch_low_interrupt;
-       unsigned int  bch_high_interrupt;
        unsigned int  dma_low_channel;
        unsigned int  dma_high_channel;
        struct clk    *clock[GPMI_CLK_MAX];
index a264b888c66cc9153e0f160af0c50e4675826a93..a2c804de156bc71d31407020b9ffb133a408b4f1 100644 (file)
@@ -416,10 +416,8 @@ static int jz_nand_probe(struct platform_device *pdev)
        uint8_t nand_maf_id = 0, nand_dev_id = 0;
 
        nand = kzalloc(sizeof(*nand), GFP_KERNEL);
-       if (!nand) {
-               dev_err(&pdev->dev, "Failed to allocate device structure.\n");
+       if (!nand)
                return -ENOMEM;
-       }
 
        ret = jz_nand_ioremap_resource(pdev, "mmio", &nand->mem, &nand->base);
        if (ret)
index 327d96c035050ce178711f03ee8ff4dd527a1fb3..687478c9f09c9a92aee00bdc595f6b5a8757bc0c 100644 (file)
@@ -539,20 +539,6 @@ static int lpc32xx_write_page_lowlevel(struct mtd_info *mtd,
        return 0;
 }
 
-static int lpc32xx_write_page(struct mtd_info *mtd, struct nand_chip *chip,
-                       uint32_t offset, int data_len, const uint8_t *buf,
-                       int oob_required, int page, int cached, int raw)
-{
-       int res;
-
-       chip->cmdfunc(mtd, NAND_CMD_SEQIN, 0x00, page);
-       res = lpc32xx_write_page_lowlevel(mtd, chip, buf, oob_required);
-       chip->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
-       lpc32xx_waitfunc(mtd, chip);
-
-       return res;
-}
-
 static int lpc32xx_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
                            int page)
 {
@@ -627,10 +613,8 @@ static struct lpc32xx_nand_cfg_mlc *lpc32xx_parse_dt(struct device *dev)
        struct device_node *np = dev->of_node;
 
        ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
-       if (!ncfg) {
-               dev_err(dev, "could not allocate memory for platform data\n");
+       if (!ncfg)
                return NULL;
-       }
 
        of_property_read_u32(np, "nxp,tcea-delay", &ncfg->tcea_delay);
        of_property_read_u32(np, "nxp,busy-delay", &ncfg->busy_delay);
@@ -666,10 +650,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 
        /* Allocate memory for the device structure (and zero it) */
        host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
-       if (!host) {
-               dev_err(&pdev->dev, "failed to allocate device structure.\n");
+       if (!host)
                return -ENOMEM;
-       }
 
        rc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        host->io_base = devm_ioremap_resource(&pdev->dev, rc);
@@ -732,9 +714,9 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        nand_chip->ecc.write_oob = lpc32xx_write_oob;
        nand_chip->ecc.read_oob = lpc32xx_read_oob;
        nand_chip->ecc.strength = 4;
-       nand_chip->write_page = lpc32xx_write_page;
        nand_chip->waitfunc = lpc32xx_waitfunc;
 
+       nand_chip->options = NAND_NO_SUBPAGE_WRITE;
        nand_chip->bbt_options = NAND_BBT_USE_FLASH | NAND_BBT_NO_OOB;
        nand_chip->bbt_td = &lpc32xx_nand_bbt;
        nand_chip->bbt_md = &lpc32xx_nand_bbt_mirror;
@@ -764,14 +746,12 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 
        host->dma_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
        if (!host->dma_buf) {
-               dev_err(&pdev->dev, "Error allocating dma_buf memory\n");
                res = -ENOMEM;
                goto err_exit3;
        }
 
        host->dummy_buf = devm_kzalloc(&pdev->dev, mtd->writesize, GFP_KERNEL);
        if (!host->dummy_buf) {
-               dev_err(&pdev->dev, "Error allocating dummy_buf memory\n");
                res = -ENOMEM;
                goto err_exit3;
        }
index 23e6974ccd205ec23a7bf19adcea54ffb3304bfa..53a6742e3da39a2e1e43be81cf11be943c07a886 100644 (file)
@@ -725,10 +725,8 @@ static struct lpc32xx_nand_cfg_slc *lpc32xx_parse_dt(struct device *dev)
        struct device_node *np = dev->of_node;
 
        ncfg = devm_kzalloc(dev, sizeof(*ncfg), GFP_KERNEL);
-       if (!ncfg) {
-               dev_err(dev, "could not allocate memory for NAND config\n");
+       if (!ncfg)
                return NULL;
-       }
 
        of_property_read_u32(np, "nxp,wdr-clks", &ncfg->wdr_clks);
        of_property_read_u32(np, "nxp,wwidth", &ncfg->wwidth);
@@ -772,10 +770,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
 
        /* Allocate memory for the device structure (and zero it) */
        host = devm_kzalloc(&pdev->dev, sizeof(*host), GFP_KERNEL);
-       if (!host) {
-               dev_err(&pdev->dev, "failed to allocate device structure\n");
+       if (!host)
                return -ENOMEM;
-       }
        host->io_base_dma = rc->start;
 
        host->io_base = devm_ioremap_resource(&pdev->dev, rc);
@@ -791,8 +787,8 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        }
        if (host->ncfg->wp_gpio == -EPROBE_DEFER)
                return -EPROBE_DEFER;
-       if (gpio_is_valid(host->ncfg->wp_gpio) &&
-                       gpio_request(host->ncfg->wp_gpio, "NAND WP")) {
+       if (gpio_is_valid(host->ncfg->wp_gpio) && devm_gpio_request(&pdev->dev,
+                       host->ncfg->wp_gpio, "NAND WP")) {
                dev_err(&pdev->dev, "GPIO not available\n");
                return -EBUSY;
        }
@@ -808,7 +804,7 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        mtd->dev.parent = &pdev->dev;
 
        /* Get NAND clock */
-       host->clk = clk_get(&pdev->dev, NULL);
+       host->clk = devm_clk_get(&pdev->dev, NULL);
        if (IS_ERR(host->clk)) {
                dev_err(&pdev->dev, "Clock failure\n");
                res = -ENOENT;
@@ -858,7 +854,6 @@ static int lpc32xx_nand_probe(struct platform_device *pdev)
        host->data_buf = devm_kzalloc(&pdev->dev, host->dma_buf_len,
                                      GFP_KERNEL);
        if (host->data_buf == NULL) {
-               dev_err(&pdev->dev, "Error allocating memory\n");
                res = -ENOMEM;
                goto err_exit2;
        }
@@ -927,10 +922,8 @@ err_exit3:
        dma_release_channel(host->dma_chan);
 err_exit2:
        clk_disable(host->clk);
-       clk_put(host->clk);
 err_exit1:
        lpc32xx_wp_enable(host);
-       gpio_free(host->ncfg->wp_gpio);
 
        return res;
 }
@@ -953,9 +946,7 @@ static int lpc32xx_nand_remove(struct platform_device *pdev)
        writel(tmp, SLC_CTRL(host->io_base));
 
        clk_disable(host->clk);
-       clk_put(host->clk);
        lpc32xx_wp_enable(host);
-       gpio_free(host->ncfg->wp_gpio);
 
        return 0;
 }
index 439bc389641841dc05f79ab638f7010e4a9cd053..31ee7cfbc12b628c9599f3d0c78b3de23185dc6c 100644 (file)
@@ -653,10 +653,8 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        }
 
        prv = devm_kzalloc(dev, sizeof(*prv), GFP_KERNEL);
-       if (!prv) {
-               dev_err(dev, "Memory exhausted!\n");
+       if (!prv)
                return -ENOMEM;
-       }
 
        mtd = &prv->mtd;
        chip = &prv->chip;
@@ -731,7 +729,7 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        of_node_put(rootnode);
 
        /* Enable NFC clock */
-       clk = devm_clk_get(dev, "nfc_clk");
+       clk = devm_clk_get(dev, "ipg");
        if (IS_ERR(clk)) {
                dev_err(dev, "Unable to acquire NFC clock!\n");
                retval = PTR_ERR(clk);
@@ -786,7 +784,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        /* Detect NAND chips */
        if (nand_scan(mtd, be32_to_cpup(chips_no))) {
                dev_err(dev, "NAND Flash not found !\n");
-               devm_free_irq(dev, prv->irq, mtd);
                retval = -ENXIO;
                goto error;
        }
@@ -811,7 +808,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
 
        default:
                dev_err(dev, "Unsupported NAND flash!\n");
-               devm_free_irq(dev, prv->irq, mtd);
                retval = -ENXIO;
                goto error;
        }
@@ -822,7 +818,6 @@ static int mpc5121_nfc_probe(struct platform_device *op)
        retval = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
        if (retval) {
                dev_err(dev, "Error adding MTD device!\n");
-               devm_free_irq(dev, prv->irq, mtd);
                goto error;
        }
 
@@ -836,11 +831,8 @@ static int mpc5121_nfc_remove(struct platform_device *op)
 {
        struct device *dev = &op->dev;
        struct mtd_info *mtd = dev_get_drvdata(dev);
-       struct nand_chip *chip = mtd->priv;
-       struct mpc5121_nfc_prv *prv = chip->priv;
 
        nand_release(mtd);
-       devm_free_irq(dev, prv->irq, mtd);
        mpc5121_nfc_free(dev, mtd);
 
        return 0;
index 9dfdb06c508b05439cd93a71ce5c30ef8558335e..e9a4835c4dd9887f8546c5e95ce298674d5182a3 100644 (file)
@@ -677,7 +677,6 @@ static int mxc_nand_correct_data_v2_v3(struct mtd_info *mtd, u_char *dat,
                ecc_stat >>= 4;
        } while (--no_subpages);
 
-       mtd->ecc_stats.corrected += ret;
        pr_debug("%d Symbol Correctable RS-ECC Error\n", ret);
 
        return ret;
@@ -1400,12 +1399,15 @@ static int mxcnd_probe(struct platform_device *pdev)
        int err = 0;
 
        /* Allocate memory for MTD device structure and private data */
-       host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host) +
-                       NAND_MAX_PAGESIZE + NAND_MAX_OOBSIZE, GFP_KERNEL);
+       host = devm_kzalloc(&pdev->dev, sizeof(struct mxc_nand_host),
+                       GFP_KERNEL);
        if (!host)
                return -ENOMEM;
 
-       host->data_buf = (uint8_t *)(host + 1);
+       /* allocate a temporary buffer for the nand_scan_ident() */
+       host->data_buf = devm_kzalloc(&pdev->dev, PAGE_SIZE, GFP_KERNEL);
+       if (!host->data_buf)
+               return -ENOMEM;
 
        host->dev = &pdev->dev;
        /* structures must be linked */
@@ -1512,7 +1514,9 @@ static int mxcnd_probe(struct platform_device *pdev)
        if (err)
                return err;
 
-       clk_prepare_enable(host->clk);
+       err = clk_prepare_enable(host->clk);
+       if (err)
+               return err;
        host->clk_act = 1;
 
        /*
@@ -1531,6 +1535,15 @@ static int mxcnd_probe(struct platform_device *pdev)
                goto escan;
        }
 
+       /* allocate the right size buffer now */
+       devm_kfree(&pdev->dev, (void *)host->data_buf);
+       host->data_buf = devm_kzalloc(&pdev->dev, mtd->writesize + mtd->oobsize,
+                                       GFP_KERNEL);
+       if (!host->data_buf) {
+               err = -ENOMEM;
+               goto escan;
+       }
+
        /* Call preset again, with correct writesize this time */
        host->devtype_data->preset(mtd);
 
@@ -1576,6 +1589,8 @@ static int mxcnd_remove(struct platform_device *pdev)
        struct mxc_nand_host *host = platform_get_drvdata(pdev);
 
        nand_release(&host->mtd);
+       if (host->clk_act)
+               clk_disable_unprepare(host->clk);
 
        return 0;
 }
index bd39f7b67906f65db526cbd0d1d27bb84ad93277..59eba5d2c68574fae787d36d2bd9e5ed29eb9f25 100644 (file)
@@ -29,6 +29,8 @@
  *
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
@@ -201,6 +203,51 @@ static void nand_select_chip(struct mtd_info *mtd, int chipnr)
        }
 }
 
+/**
+ * nand_write_byte - [DEFAULT] write single byte to chip
+ * @mtd: MTD device structure
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0]
+ */
+static void nand_write_byte(struct mtd_info *mtd, uint8_t byte)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       chip->write_buf(mtd, &byte, 1);
+}
+
+/**
+ * nand_write_byte16 - [DEFAULT] write single byte to a chip with width 16
+ * @mtd: MTD device structure
+ * @byte: value to write
+ *
+ * Default function to write a byte to I/O[7:0] on a 16-bit wide chip.
+ */
+static void nand_write_byte16(struct mtd_info *mtd, uint8_t byte)
+{
+       struct nand_chip *chip = mtd->priv;
+       uint16_t word = byte;
+
+       /*
+        * It's not entirely clear what should happen to I/O[15:8] when writing
+        * a byte. The ONFi spec (Revision 3.1; 2012-09-19, Section 2.16) reads:
+        *
+        *    When the host supports a 16-bit bus width, only data is
+        *    transferred at the 16-bit width. All address and command line
+        *    transfers shall use only the lower 8-bits of the data bus. During
+        *    command transfers, the host may place any value on the upper
+        *    8-bits of the data bus. During address transfers, the host shall
+        *    set the upper 8-bits of the data bus to 00h.
+        *
+        * One user of the write_byte callback is nand_onfi_set_features. The
+        * four parameters are specified to be written to I/O[7:0], but this is
+        * neither an address nor a command transfer. Let's assume a 0 on the
+        * upper I/O lines is OK.
+        */
+       chip->write_buf(mtd, (uint8_t *)&word, 2);
+}
+
 /**
  * nand_write_buf - [DEFAULT] write buffer to chip
  * @mtd: MTD device structure
@@ -1407,6 +1454,30 @@ static uint8_t *nand_transfer_oob(struct nand_chip *chip, uint8_t *oob,
        return NULL;
 }
 
+/**
+ * nand_setup_read_retry - [INTERN] Set the READ RETRY mode
+ * @mtd: MTD device structure
+ * @retry_mode: the retry mode to use
+ *
+ * Some vendors supply a special command to shift the Vt threshold, to be used
+ * when there are too many bitflips in a page (i.e., ECC error). After setting
+ * a new threshold, the host should retry reading the page.
+ */
+static int nand_setup_read_retry(struct mtd_info *mtd, int retry_mode)
+{
+       struct nand_chip *chip = mtd->priv;
+
+       pr_debug("setting READ RETRY mode %d\n", retry_mode);
+
+       if (retry_mode >= chip->read_retries)
+               return -EINVAL;
+
+       if (!chip->setup_read_retry)
+               return -EOPNOTSUPP;
+
+       return chip->setup_read_retry(mtd, retry_mode);
+}
+
 /**
  * nand_do_read_ops - [INTERN] Read data with ECC
  * @mtd: MTD device structure
@@ -1420,7 +1491,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 {
        int chipnr, page, realpage, col, bytes, aligned, oob_required;
        struct nand_chip *chip = mtd->priv;
-       struct mtd_ecc_stats stats;
        int ret = 0;
        uint32_t readlen = ops->len;
        uint32_t oobreadlen = ops->ooblen;
@@ -1429,8 +1499,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
        uint8_t *bufpoi, *oob, *buf;
        unsigned int max_bitflips = 0;
-
-       stats = mtd->ecc_stats;
+       int retry_mode = 0;
+       bool ecc_fail = false;
 
        chipnr = (int)(from >> chip->chip_shift);
        chip->select_chip(mtd, chipnr);
@@ -1445,6 +1515,8 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        oob_required = oob ? 1 : 0;
 
        while (1) {
+               unsigned int ecc_failures = mtd->ecc_stats.failed;
+
                bytes = min(mtd->writesize - col, readlen);
                aligned = (bytes == mtd->writesize);
 
@@ -1452,6 +1524,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                if (realpage != chip->pagebuf || oob) {
                        bufpoi = aligned ? buf : chip->buffers->databuf;
 
+read_retry:
                        chip->cmdfunc(mtd, NAND_CMD_READ0, 0x00, page);
 
                        /*
@@ -1481,7 +1554,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                        /* Transfer not aligned data */
                        if (!aligned) {
                                if (!NAND_HAS_SUBPAGE_READ(chip) && !oob &&
-                                   !(mtd->ecc_stats.failed - stats.failed) &&
+                                   !(mtd->ecc_stats.failed - ecc_failures) &&
                                    (ops->mode != MTD_OPS_RAW)) {
                                        chip->pagebuf = realpage;
                                        chip->pagebuf_bitflips = ret;
@@ -1492,8 +1565,6 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                memcpy(buf, chip->buffers->databuf + col, bytes);
                        }
 
-                       buf += bytes;
-
                        if (unlikely(oob)) {
                                int toread = min(oobreadlen, max_oobsize);
 
@@ -1511,6 +1582,25 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
                                else
                                        nand_wait_ready(mtd);
                        }
+
+                       if (mtd->ecc_stats.failed - ecc_failures) {
+                               if (retry_mode + 1 <= chip->read_retries) {
+                                       retry_mode++;
+                                       ret = nand_setup_read_retry(mtd,
+                                                       retry_mode);
+                                       if (ret < 0)
+                                               break;
+
+                                       /* Reset failures; retry */
+                                       mtd->ecc_stats.failed = ecc_failures;
+                                       goto read_retry;
+                               } else {
+                                       /* No more retry modes; real failure */
+                                       ecc_fail = true;
+                               }
+                       }
+
+                       buf += bytes;
                } else {
                        memcpy(buf, chip->buffers->databuf + col, bytes);
                        buf += bytes;
@@ -1520,6 +1610,14 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
 
                readlen -= bytes;
 
+               /* Reset to retry mode 0 */
+               if (retry_mode) {
+                       ret = nand_setup_read_retry(mtd, 0);
+                       if (ret < 0)
+                               break;
+                       retry_mode = 0;
+               }
+
                if (!readlen)
                        break;
 
@@ -1545,7 +1643,7 @@ static int nand_do_read_ops(struct mtd_info *mtd, loff_t from,
        if (ret < 0)
                return ret;
 
-       if (mtd->ecc_stats.failed - stats.failed)
+       if (ecc_fail)
                return -EBADMSG;
 
        return max_bitflips;
@@ -2716,6 +2814,7 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
                        int addr, uint8_t *subfeature_param)
 {
        int status;
+       int i;
 
        if (!chip->onfi_version ||
            !(le16_to_cpu(chip->onfi_params.opt_cmd)
@@ -2723,7 +2822,9 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
                return -EINVAL;
 
        chip->cmdfunc(mtd, NAND_CMD_SET_FEATURES, addr, -1);
-       chip->write_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);
+       for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+               chip->write_byte(mtd, subfeature_param[i]);
+
        status = chip->waitfunc(mtd, chip);
        if (status & NAND_STATUS_FAIL)
                return -EIO;
@@ -2740,6 +2841,8 @@ static int nand_onfi_set_features(struct mtd_info *mtd, struct nand_chip *chip,
 static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
                        int addr, uint8_t *subfeature_param)
 {
+       int i;
+
        if (!chip->onfi_version ||
            !(le16_to_cpu(chip->onfi_params.opt_cmd)
              & ONFI_OPT_CMD_SET_GET_FEATURES))
@@ -2749,7 +2852,8 @@ static int nand_onfi_get_features(struct mtd_info *mtd, struct nand_chip *chip,
        memset(subfeature_param, 0, ONFI_SUBFEATURE_PARAM_LEN);
 
        chip->cmdfunc(mtd, NAND_CMD_GET_FEATURES, addr, -1);
-       chip->read_buf(mtd, subfeature_param, ONFI_SUBFEATURE_PARAM_LEN);
+       for (i = 0; i < ONFI_SUBFEATURE_PARAM_LEN; ++i)
+               *subfeature_param++ = chip->read_byte(mtd);
        return 0;
 }
 
@@ -2812,6 +2916,8 @@ static void nand_set_defaults(struct nand_chip *chip, int busw)
                chip->block_markbad = nand_default_block_markbad;
        if (!chip->write_buf || chip->write_buf == nand_write_buf)
                chip->write_buf = busw ? nand_write_buf16 : nand_write_buf;
+       if (!chip->write_byte || chip->write_byte == nand_write_byte)
+               chip->write_byte = busw ? nand_write_byte16 : nand_write_byte;
        if (!chip->read_buf || chip->read_buf == nand_read_buf)
                chip->read_buf = busw ? nand_read_buf16 : nand_read_buf;
        if (!chip->scan_bbt)
@@ -2926,6 +3032,30 @@ ext_out:
        return ret;
 }
 
+static int nand_setup_read_retry_micron(struct mtd_info *mtd, int retry_mode)
+{
+       struct nand_chip *chip = mtd->priv;
+       uint8_t feature[ONFI_SUBFEATURE_PARAM_LEN] = {retry_mode};
+
+       return chip->onfi_set_features(mtd, chip, ONFI_FEATURE_ADDR_READ_RETRY,
+                       feature);
+}
+
+/*
+ * Configure chip properties from Micron vendor-specific ONFI table
+ */
+static void nand_onfi_detect_micron(struct nand_chip *chip,
+               struct nand_onfi_params *p)
+{
+       struct nand_onfi_vendor_micron *micron = (void *)p->vendor;
+
+       if (le16_to_cpu(p->vendor_revision) < 1)
+               return;
+
+       chip->read_retries = micron->read_retry_options;
+       chip->setup_read_retry = nand_setup_read_retry_micron;
+}
+
 /*
  * Check if the NAND chip is ONFI compliant, returns 1 if it is, 0 otherwise.
  */
@@ -2979,7 +3109,7 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
                chip->onfi_version = 10;
 
        if (!chip->onfi_version) {
-               pr_info("%s: unsupported ONFI version: %d\n", __func__, val);
+               pr_info("unsupported ONFI version: %d\n", val);
                return 0;
        }
 
@@ -3032,6 +3162,9 @@ static int nand_flash_detect_onfi(struct mtd_info *mtd, struct nand_chip *chip,
                pr_warn("Could not retrieve ONFI ECC requirements\n");
        }
 
+       if (p->jedec_id == NAND_MFR_MICRON)
+               nand_onfi_detect_micron(chip, p);
+
        return 1;
 }
 
@@ -3152,9 +3285,12 @@ static void nand_decode_ext_id(struct mtd_info *mtd, struct nand_chip *chip,
                        mtd->oobsize = 512;
                        break;
                case 6:
-               default: /* Other cases are "reserved" (unknown) */
                        mtd->oobsize = 640;
                        break;
+               case 7:
+               default: /* Other cases are "reserved" (unknown) */
+                       mtd->oobsize = 1024;
+                       break;
                }
                extid >>= 2;
                /* Calc blocksize */
@@ -3325,6 +3461,9 @@ static bool find_full_id_nand(struct mtd_info *mtd, struct nand_chip *chip,
 
                *busw = type->options & NAND_BUSWIDTH_16;
 
+               if (!mtd->name)
+                       mtd->name = type->name;
+
                return true;
        }
        return false;
@@ -3372,8 +3511,7 @@ static struct nand_flash_dev *nand_get_flash_type(struct mtd_info *mtd,
                id_data[i] = chip->read_byte(mtd);
 
        if (id_data[0] != *maf_id || id_data[1] != *dev_id) {
-               pr_info("%s: second ID read did not match "
-                       "%02x,%02x against %02x,%02x\n", __func__,
+               pr_info("second ID read did not match %02x,%02x against %02x,%02x\n",
                        *maf_id, *dev_id, id_data[0], id_data[1]);
                return ERR_PTR(-ENODEV);
        }
@@ -3440,10 +3578,10 @@ ident_done:
                 * Check, if buswidth is correct. Hardware drivers should set
                 * chip correct!
                 */
-               pr_info("NAND device: Manufacturer ID:"
-                       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id,
-                       *dev_id, nand_manuf_ids[maf_idx].name, mtd->name);
-               pr_warn("NAND bus width %d instead %d bit\n",
+               pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
+                       *maf_id, *dev_id);
+               pr_info("%s %s\n", nand_manuf_ids[maf_idx].name, mtd->name);
+               pr_warn("bus width %d instead %d bit\n",
                           (chip->options & NAND_BUSWIDTH_16) ? 16 : 8,
                           busw ? 16 : 8);
                return ERR_PTR(-EINVAL);
@@ -3472,14 +3610,13 @@ ident_done:
        if (mtd->writesize > 512 && chip->cmdfunc == nand_command)
                chip->cmdfunc = nand_command_lp;
 
-       pr_info("NAND device: Manufacturer ID: 0x%02x, Chip ID: 0x%02x (%s %s)\n",
-               *maf_id, *dev_id, nand_manuf_ids[maf_idx].name,
+       pr_info("device found, Manufacturer ID: 0x%02x, Chip ID: 0x%02x\n",
+               *maf_id, *dev_id);
+       pr_info("%s %s\n", nand_manuf_ids[maf_idx].name,
                chip->onfi_version ? chip->onfi_params.model : type->name);
-
-       pr_info("NAND device: %dMiB, %s, page size: %d, OOB size: %d\n",
+       pr_info("%dMiB, %s, page size: %d, OOB size: %d\n",
                (int)(chip->chipsize >> 20), nand_is_slc(chip) ? "SLC" : "MLC",
                mtd->writesize, mtd->oobsize);
-
        return type;
 }
 
@@ -3535,7 +3672,7 @@ int nand_scan_ident(struct mtd_info *mtd, int maxchips,
                chip->select_chip(mtd, -1);
        }
        if (i > 1)
-               pr_info("%d NAND chips detected\n", i);
+               pr_info("%d chips detected\n", i);
 
        /* Store the number of chips and calc total size for mtd */
        chip->numchips = i;
index a87b0a3afa351a1b8f8991836cb99af930d858da..daa2faacd7d09f99422fa3f64fc6947a7f4f92cc 100644 (file)
@@ -169,6 +169,8 @@ struct nand_manufacturers nand_manuf_ids[] = {
        {NAND_MFR_AMD, "AMD/Spansion"},
        {NAND_MFR_MACRONIX, "Macronix"},
        {NAND_MFR_EON, "Eon"},
+       {NAND_MFR_SANDISK, "SanDisk"},
+       {NAND_MFR_INTEL, "Intel"},
        {0x0, "Unknown"}
 };
 
index 52115151e4a7f325491a3dbf6f16ccd87221b37a..9ee09a8177c67feae055da60dcb033e9bf76f4c4 100644 (file)
@@ -241,12 +241,10 @@ static int nuc900_nand_probe(struct platform_device *pdev)
 {
        struct nuc900_nand *nuc900_nand;
        struct nand_chip *chip;
-       int retval;
        struct resource *res;
 
-       retval = 0;
-
-       nuc900_nand = kzalloc(sizeof(struct nuc900_nand), GFP_KERNEL);
+       nuc900_nand = devm_kzalloc(&pdev->dev, sizeof(struct nuc900_nand),
+                                  GFP_KERNEL);
        if (!nuc900_nand)
                return -ENOMEM;
        chip = &(nuc900_nand->chip);
@@ -255,11 +253,9 @@ static int nuc900_nand_probe(struct platform_device *pdev)
        nuc900_nand->mtd.owner  = THIS_MODULE;
        spin_lock_init(&nuc900_nand->lock);
 
-       nuc900_nand->clk = clk_get(&pdev->dev, NULL);
-       if (IS_ERR(nuc900_nand->clk)) {
-               retval = -ENOENT;
-               goto fail1;
-       }
+       nuc900_nand->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(nuc900_nand->clk))
+               return -ENOENT;
        clk_enable(nuc900_nand->clk);
 
        chip->cmdfunc           = nuc900_nand_command_lp;
@@ -272,57 +268,29 @@ static int nuc900_nand_probe(struct platform_device *pdev)
        chip->ecc.mode          = NAND_ECC_SOFT;
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               retval = -ENXIO;
-               goto fail1;
-       }
-
-       if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
-               retval = -EBUSY;
-               goto fail1;
-       }
-
-       nuc900_nand->reg = ioremap(res->start, resource_size(res));
-       if (!nuc900_nand->reg) {
-               retval = -ENOMEM;
-               goto fail2;
-       }
+       nuc900_nand->reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(nuc900_nand->reg))
+               return PTR_ERR(nuc900_nand->reg);
 
        nuc900_nand_enable(nuc900_nand);
 
-       if (nand_scan(&(nuc900_nand->mtd), 1)) {
-               retval = -ENXIO;
-               goto fail3;
-       }
+       if (nand_scan(&(nuc900_nand->mtd), 1))
+               return -ENXIO;
 
        mtd_device_register(&(nuc900_nand->mtd), partitions,
                            ARRAY_SIZE(partitions));
 
        platform_set_drvdata(pdev, nuc900_nand);
 
-       return retval;
-
-fail3: iounmap(nuc900_nand->reg);
-fail2: release_mem_region(res->start, resource_size(res));
-fail1: kfree(nuc900_nand);
-       return retval;
+       return 0;
 }
 
 static int nuc900_nand_remove(struct platform_device *pdev)
 {
        struct nuc900_nand *nuc900_nand = platform_get_drvdata(pdev);
-       struct resource *res;
 
        nand_release(&nuc900_nand->mtd);
-       iounmap(nuc900_nand->reg);
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       release_mem_region(res->start, resource_size(res));
-
        clk_disable(nuc900_nand->clk);
-       clk_put(nuc900_nand->clk);
-
-       kfree(nuc900_nand);
 
        return 0;
 }
index f77725009907751e62963f02a6ce52b10e41e366..ef4190a02b7bd591af7c97be8ee1e3caecf6f83c 100644 (file)
@@ -1730,13 +1730,7 @@ static int omap_nand_probe(struct platform_device *pdev)
                break;
 
        case NAND_OMAP_POLLED:
-               if (nand_chip->options & NAND_BUSWIDTH_16) {
-                       nand_chip->read_buf   = omap_read_buf16;
-                       nand_chip->write_buf  = omap_write_buf16;
-               } else {
-                       nand_chip->read_buf   = omap_read_buf8;
-                       nand_chip->write_buf  = omap_write_buf8;
-               }
+               /* Use nand_base defaults for {read,write}_buf */
                break;
 
        case NAND_OMAP_PREFETCH_DMA:
index a393a5b6ce1e5028155a415ae33db88067a7bfff..dd7fe817eafb319ebc9ae92b2cbbac8613b38add 100644 (file)
@@ -87,7 +87,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 
        nc = kzalloc(sizeof(struct nand_chip) + sizeof(struct mtd_info), GFP_KERNEL);
        if (!nc) {
-               printk(KERN_ERR "orion_nand: failed to allocate device structure.\n");
                ret = -ENOMEM;
                goto no_res;
        }
@@ -101,7 +100,7 @@ static int __init orion_nand_probe(struct platform_device *pdev)
 
        io_base = ioremap(res->start, resource_size(res));
        if (!io_base) {
-               printk(KERN_ERR "orion_nand: ioremap failed\n");
+               dev_err(&pdev->dev, "ioremap failed\n");
                ret = -EIO;
                goto no_res;
        }
@@ -110,7 +109,6 @@ static int __init orion_nand_probe(struct platform_device *pdev)
                board = devm_kzalloc(&pdev->dev, sizeof(struct orion_nand_data),
                                        GFP_KERNEL);
                if (!board) {
-                       printk(KERN_ERR "orion_nand: failed to allocate board structure.\n");
                        ret = -ENOMEM;
                        goto no_res;
                }
index 4d174366a0f09ec2ebecd99fc8241fc978a05caa..90f871acb0efec737c918532bbdd350ca7969220 100644 (file)
@@ -223,7 +223,7 @@ MODULE_DEVICE_TABLE(of, pasemi_nand_match);
 static struct platform_driver pasemi_nand_driver =
 {
        .driver = {
-               .name = (char*)driver_name,
+               .name = driver_name,
                .owner = THIS_MODULE,
                .of_match_table = pasemi_nand_match,
        },
index cad4cdc9df399a70c77640be5a634b837996790d..0b068a5c0bff3c05aa2eba8e1ae93a01f6b8db98 100644 (file)
@@ -9,6 +9,7 @@
  *
  */
 
+#include <linux/err.h>
 #include <linux/io.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -47,30 +48,16 @@ static int plat_nand_probe(struct platform_device *pdev)
                return -EINVAL;
        }
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res)
-               return -ENXIO;
-
        /* Allocate memory for the device structure (and zero it) */
-       data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
-       if (!data) {
-               dev_err(&pdev->dev, "failed to allocate device structure.\n");
+       data = devm_kzalloc(&pdev->dev, sizeof(struct plat_nand_data),
+                           GFP_KERNEL);
+       if (!data)
                return -ENOMEM;
-       }
-
-       if (!request_mem_region(res->start, resource_size(res),
-                               dev_name(&pdev->dev))) {
-               dev_err(&pdev->dev, "request_mem_region failed\n");
-               err = -EBUSY;
-               goto out_free;
-       }
 
-       data->io_base = ioremap(res->start, resource_size(res));
-       if (data->io_base == NULL) {
-               dev_err(&pdev->dev, "ioremap failed\n");
-               err = -EIO;
-               goto out_release_io;
-       }
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       data->io_base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(data->io_base))
+               return PTR_ERR(data->io_base);
 
        data->chip.priv = &data;
        data->mtd.priv = &data->chip;
@@ -122,11 +109,6 @@ static int plat_nand_probe(struct platform_device *pdev)
 out:
        if (pdata->ctrl.remove)
                pdata->ctrl.remove(pdev);
-       iounmap(data->io_base);
-out_release_io:
-       release_mem_region(res->start, resource_size(res));
-out_free:
-       kfree(data);
        return err;
 }
 
@@ -137,16 +119,10 @@ static int plat_nand_remove(struct platform_device *pdev)
 {
        struct plat_nand_data *data = platform_get_drvdata(pdev);
        struct platform_nand_data *pdata = dev_get_platdata(&pdev->dev);
-       struct resource *res;
-
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
        nand_release(&data->mtd);
        if (pdata->ctrl.remove)
                pdata->ctrl.remove(pdev);
-       iounmap(data->io_base);
-       release_mem_region(res->start, resource_size(res));
-       kfree(data);
 
        return 0;
 }
index 4b3aaa898a8b6b3a4975d2218370711981cb59c4..2a7a0b27ac38dccc511abd296742a767ef183133 100644 (file)
@@ -7,6 +7,8 @@
  * 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.
+ *
+ * See Documentation/mtd/nand/pxa3xx-nand.txt for more details.
  */
 
 #include <linux/kernel.h>
@@ -24,6 +26,7 @@
 #include <linux/slab.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
+#include <linux/of_mtd.h>
 
 #if defined(CONFIG_ARCH_PXA) || defined(CONFIG_ARCH_MMP)
 #define ARCH_HAS_DMA
@@ -35,6 +38,7 @@
 
 #include <linux/platform_data/mtd-nand-pxa3xx.h>
 
+#define NAND_DEV_READY_TIMEOUT  50
 #define        CHIP_DELAY_TIMEOUT      (2 * HZ/10)
 #define NAND_STOP_DELAY                (2 * HZ/50)
 #define PAGE_CHUNK_SIZE                (2048)
@@ -54,6 +58,7 @@
 #define NDPCR          (0x18) /* Page Count Register */
 #define NDBDR0         (0x1C) /* Bad Block Register 0 */
 #define NDBDR1         (0x20) /* Bad Block Register 1 */
+#define NDECCCTRL      (0x28) /* ECC control */
 #define NDDB           (0x40) /* Data Buffer */
 #define NDCB0          (0x48) /* Command Buffer0 */
 #define NDCB1          (0x4C) /* Command Buffer1 */
@@ -80,6 +85,9 @@
 #define NDCR_INT_MASK           (0xFFF)
 
 #define NDSR_MASK              (0xfff)
+#define NDSR_ERR_CNT_OFF       (16)
+#define NDSR_ERR_CNT_MASK       (0x1f)
+#define NDSR_ERR_CNT(sr)       ((sr >> NDSR_ERR_CNT_OFF) & NDSR_ERR_CNT_MASK)
 #define NDSR_RDY                (0x1 << 12)
 #define NDSR_FLASH_RDY          (0x1 << 11)
 #define NDSR_CS0_PAGED         (0x1 << 10)
@@ -88,8 +96,8 @@
 #define NDSR_CS1_CMDD          (0x1 << 7)
 #define NDSR_CS0_BBD           (0x1 << 6)
 #define NDSR_CS1_BBD           (0x1 << 5)
-#define NDSR_DBERR             (0x1 << 4)
-#define NDSR_SBERR             (0x1 << 3)
+#define NDSR_UNCORERR          (0x1 << 4)
+#define NDSR_CORERR            (0x1 << 3)
 #define NDSR_WRDREQ            (0x1 << 2)
 #define NDSR_RDDREQ            (0x1 << 1)
 #define NDSR_WRCMDREQ          (0x1)
 #define NDCB0_ST_ROW_EN         (0x1 << 26)
 #define NDCB0_AUTO_RS          (0x1 << 25)
 #define NDCB0_CSEL             (0x1 << 24)
+#define NDCB0_EXT_CMD_TYPE_MASK        (0x7 << 29)
+#define NDCB0_EXT_CMD_TYPE(x)  (((x) << 29) & NDCB0_EXT_CMD_TYPE_MASK)
 #define NDCB0_CMD_TYPE_MASK    (0x7 << 21)
 #define NDCB0_CMD_TYPE(x)      (((x) << 21) & NDCB0_CMD_TYPE_MASK)
 #define NDCB0_NC               (0x1 << 20)
 #define NDCB0_CMD1_MASK                (0xff)
 #define NDCB0_ADDR_CYC_SHIFT   (16)
 
+#define EXT_CMD_TYPE_DISPATCH  6 /* Command dispatch */
+#define EXT_CMD_TYPE_NAKED_RW  5 /* Naked read or Naked write */
+#define EXT_CMD_TYPE_READ      4 /* Read */
+#define EXT_CMD_TYPE_DISP_WR   4 /* Command dispatch with write */
+#define EXT_CMD_TYPE_FINAL     3 /* Final command */
+#define EXT_CMD_TYPE_LAST_RW   1 /* Last naked read/write */
+#define EXT_CMD_TYPE_MONO      0 /* Monolithic read/write */
+
 /* macros for registers read/write */
 #define nand_writel(info, off, val)    \
        __raw_writel((val), (info)->mmio_base + (off))
@@ -120,9 +138,9 @@ enum {
        ERR_NONE        = 0,
        ERR_DMABUSERR   = -1,
        ERR_SENDCMD     = -2,
-       ERR_DBERR       = -3,
+       ERR_UNCORERR    = -3,
        ERR_BBERR       = -4,
-       ERR_SBERR       = -5,
+       ERR_CORERR      = -5,
 };
 
 enum {
@@ -149,7 +167,6 @@ struct pxa3xx_nand_host {
        void                    *info_data;
 
        /* page size of attached chip */
-       unsigned int            page_size;
        int                     use_ecc;
        int                     cs;
 
@@ -167,11 +184,13 @@ struct pxa3xx_nand_info {
        struct clk              *clk;
        void __iomem            *mmio_base;
        unsigned long           mmio_phys;
-       struct completion       cmd_complete;
+       struct completion       cmd_complete, dev_ready;
 
        unsigned int            buf_start;
        unsigned int            buf_count;
        unsigned int            buf_size;
+       unsigned int            data_buff_pos;
+       unsigned int            oob_buff_pos;
 
        /* DMA information */
        int                     drcmr_dat;
@@ -195,13 +214,18 @@ struct pxa3xx_nand_info {
 
        int                     cs;
        int                     use_ecc;        /* use HW ECC ? */
+       int                     ecc_bch;        /* using BCH ECC? */
        int                     use_dma;        /* use DMA ? */
        int                     use_spare;      /* use spare ? */
-       int                     is_ready;
+       int                     need_wait;
 
-       unsigned int            page_size;      /* page size of attached chip */
-       unsigned int            data_size;      /* data size in FIFO */
+       unsigned int            data_size;      /* data to be read from FIFO */
+       unsigned int            chunk_size;     /* split commands chunk size */
        unsigned int            oob_size;
+       unsigned int            spare_size;
+       unsigned int            ecc_size;
+       unsigned int            ecc_err_cnt;
+       unsigned int            max_bitflips;
        int                     retcode;
 
        /* cached register value */
@@ -239,6 +263,64 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
 { "256MiB 16-bit", 0xba20,  64, 2048, 16, 16, 2048, &timing[3] },
 };
 
+static u8 bbt_pattern[] = {'M', 'V', 'B', 'b', 't', '0' };
+static u8 bbt_mirror_pattern[] = {'1', 't', 'b', 'B', 'V', 'M' };
+
+static struct nand_bbt_descr bbt_main_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
+       .offs = 8,
+       .len = 6,
+       .veroffs = 14,
+       .maxblocks = 8,         /* Last 8 blocks in each chip */
+       .pattern = bbt_pattern
+};
+
+static struct nand_bbt_descr bbt_mirror_descr = {
+       .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
+               | NAND_BBT_2BIT | NAND_BBT_VERSION,
+       .offs = 8,
+       .len = 6,
+       .veroffs = 14,
+       .maxblocks = 8,         /* Last 8 blocks in each chip */
+       .pattern = bbt_mirror_pattern
+};
+
+static struct nand_ecclayout ecc_layout_2KB_bch4bit = {
+       .eccbytes = 32,
+       .eccpos = {
+               32, 33, 34, 35, 36, 37, 38, 39,
+               40, 41, 42, 43, 44, 45, 46, 47,
+               48, 49, 50, 51, 52, 53, 54, 55,
+               56, 57, 58, 59, 60, 61, 62, 63},
+       .oobfree = { {2, 30} }
+};
+
+static struct nand_ecclayout ecc_layout_4KB_bch4bit = {
+       .eccbytes = 64,
+       .eccpos = {
+               32,  33,  34,  35,  36,  37,  38,  39,
+               40,  41,  42,  43,  44,  45,  46,  47,
+               48,  49,  50,  51,  52,  53,  54,  55,
+               56,  57,  58,  59,  60,  61,  62,  63,
+               96,  97,  98,  99,  100, 101, 102, 103,
+               104, 105, 106, 107, 108, 109, 110, 111,
+               112, 113, 114, 115, 116, 117, 118, 119,
+               120, 121, 122, 123, 124, 125, 126, 127},
+       /* Bootrom looks in bytes 0 & 5 for bad blocks */
+       .oobfree = { {6, 26}, { 64, 32} }
+};
+
+static struct nand_ecclayout ecc_layout_4KB_bch8bit = {
+       .eccbytes = 128,
+       .eccpos = {
+               32,  33,  34,  35,  36,  37,  38,  39,
+               40,  41,  42,  43,  44,  45,  46,  47,
+               48,  49,  50,  51,  52,  53,  54,  55,
+               56,  57,  58,  59,  60,  61,  62,  63},
+       .oobfree = { }
+};
+
 /* Define a default flash type setting serve as flash detecting only */
 #define DEFAULT_FLASH_TYPE (&builtin_flash_types[0])
 
@@ -256,6 +338,29 @@ static struct pxa3xx_nand_flash builtin_flash_types[] = {
 /* convert nano-seconds to nand flash controller clock cycles */
 #define ns2cycle(ns, clk)      (int)((ns) * (clk / 1000000) / 1000)
 
+static struct of_device_id pxa3xx_nand_dt_ids[] = {
+       {
+               .compatible = "marvell,pxa3xx-nand",
+               .data       = (void *)PXA3XX_NAND_VARIANT_PXA,
+       },
+       {
+               .compatible = "marvell,armada370-nand",
+               .data       = (void *)PXA3XX_NAND_VARIANT_ARMADA370,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
+
+static enum pxa3xx_nand_variant
+pxa3xx_nand_get_variant(struct platform_device *pdev)
+{
+       const struct of_device_id *of_id =
+                       of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
+       if (!of_id)
+               return PXA3XX_NAND_VARIANT_PXA;
+       return (enum pxa3xx_nand_variant)of_id->data;
+}
+
 static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
                                   const struct pxa3xx_nand_timing *t)
 {
@@ -280,25 +385,23 @@ static void pxa3xx_nand_set_timing(struct pxa3xx_nand_host *host,
        nand_writel(info, NDTR1CS0, ndtr1);
 }
 
-static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info)
+/*
+ * Set the data and OOB size, depending on the selected
+ * spare and ECC configuration.
+ * Only applicable to READ0, READOOB and PAGEPROG commands.
+ */
+static void pxa3xx_set_datasize(struct pxa3xx_nand_info *info,
+                               struct mtd_info *mtd)
 {
-       struct pxa3xx_nand_host *host = info->host[info->cs];
        int oob_enable = info->reg_ndcr & NDCR_SPARE_EN;
 
-       info->data_size = host->page_size;
-       if (!oob_enable) {
-               info->oob_size = 0;
+       info->data_size = mtd->writesize;
+       if (!oob_enable)
                return;
-       }
 
-       switch (host->page_size) {
-       case 2048:
-               info->oob_size = (info->use_ecc) ? 40 : 64;
-               break;
-       case 512:
-               info->oob_size = (info->use_ecc) ? 8 : 16;
-               break;
-       }
+       info->oob_size = info->spare_size;
+       if (!info->use_ecc)
+               info->oob_size += info->ecc_size;
 }
 
 /**
@@ -313,10 +416,15 @@ static void pxa3xx_nand_start(struct pxa3xx_nand_info *info)
 
        ndcr = info->reg_ndcr;
 
-       if (info->use_ecc)
+       if (info->use_ecc) {
                ndcr |= NDCR_ECC_EN;
-       else
+               if (info->ecc_bch)
+                       nand_writel(info, NDECCCTRL, 0x1);
+       } else {
                ndcr &= ~NDCR_ECC_EN;
+               if (info->ecc_bch)
+                       nand_writel(info, NDECCCTRL, 0x0);
+       }
 
        if (info->use_dma)
                ndcr |= NDCR_DMA_EN;
@@ -375,26 +483,39 @@ static void disable_int(struct pxa3xx_nand_info *info, uint32_t int_mask)
 
 static void handle_data_pio(struct pxa3xx_nand_info *info)
 {
+       unsigned int do_bytes = min(info->data_size, info->chunk_size);
+
        switch (info->state) {
        case STATE_PIO_WRITING:
-               __raw_writesl(info->mmio_base + NDDB, info->data_buff,
-                               DIV_ROUND_UP(info->data_size, 4));
+               __raw_writesl(info->mmio_base + NDDB,
+                             info->data_buff + info->data_buff_pos,
+                             DIV_ROUND_UP(do_bytes, 4));
+
                if (info->oob_size > 0)
-                       __raw_writesl(info->mmio_base + NDDB, info->oob_buff,
-                                       DIV_ROUND_UP(info->oob_size, 4));
+                       __raw_writesl(info->mmio_base + NDDB,
+                                     info->oob_buff + info->oob_buff_pos,
+                                     DIV_ROUND_UP(info->oob_size, 4));
                break;
        case STATE_PIO_READING:
-               __raw_readsl(info->mmio_base + NDDB, info->data_buff,
-                               DIV_ROUND_UP(info->data_size, 4));
+               __raw_readsl(info->mmio_base + NDDB,
+                            info->data_buff + info->data_buff_pos,
+                            DIV_ROUND_UP(do_bytes, 4));
+
                if (info->oob_size > 0)
-                       __raw_readsl(info->mmio_base + NDDB, info->oob_buff,
-                                       DIV_ROUND_UP(info->oob_size, 4));
+                       __raw_readsl(info->mmio_base + NDDB,
+                                    info->oob_buff + info->oob_buff_pos,
+                                    DIV_ROUND_UP(info->oob_size, 4));
                break;
        default:
                dev_err(&info->pdev->dev, "%s: invalid state %d\n", __func__,
                                info->state);
                BUG();
        }
+
+       /* Update buffer pointers for multi-page read/write */
+       info->data_buff_pos += do_bytes;
+       info->oob_buff_pos += info->oob_size;
+       info->data_size -= do_bytes;
 }
 
 #ifdef ARCH_HAS_DMA
@@ -452,7 +573,7 @@ static void start_data_dma(struct pxa3xx_nand_info *info)
 static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 {
        struct pxa3xx_nand_info *info = devid;
-       unsigned int status, is_completed = 0;
+       unsigned int status, is_completed = 0, is_ready = 0;
        unsigned int ready, cmd_done;
 
        if (info->cs == 0) {
@@ -465,10 +586,25 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
 
        status = nand_readl(info, NDSR);
 
-       if (status & NDSR_DBERR)
-               info->retcode = ERR_DBERR;
-       if (status & NDSR_SBERR)
-               info->retcode = ERR_SBERR;
+       if (status & NDSR_UNCORERR)
+               info->retcode = ERR_UNCORERR;
+       if (status & NDSR_CORERR) {
+               info->retcode = ERR_CORERR;
+               if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370 &&
+                   info->ecc_bch)
+                       info->ecc_err_cnt = NDSR_ERR_CNT(status);
+               else
+                       info->ecc_err_cnt = 1;
+
+               /*
+                * Each chunk composing a page is corrected independently,
+                * and we need to store maximum number of corrected bitflips
+                * to return it to the MTD layer in ecc.read_page().
+                */
+               info->max_bitflips = max_t(unsigned int,
+                                          info->max_bitflips,
+                                          info->ecc_err_cnt);
+       }
        if (status & (NDSR_RDDREQ | NDSR_WRDREQ)) {
                /* whether use dma to transfer data */
                if (info->use_dma) {
@@ -488,8 +624,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
                is_completed = 1;
        }
        if (status & ready) {
-               info->is_ready = 1;
                info->state = STATE_READY;
+               is_ready = 1;
        }
 
        if (status & NDSR_WRCMDREQ) {
@@ -518,6 +654,8 @@ static irqreturn_t pxa3xx_nand_irq(int irq, void *devid)
        nand_writel(info, NDSR, status);
        if (is_completed)
                complete(&info->cmd_complete);
+       if (is_ready)
+               complete(&info->dev_ready);
 NORMAL_IRQ_EXIT:
        return IRQ_HANDLED;
 }
@@ -530,51 +668,94 @@ static inline int is_buf_blank(uint8_t *buf, size_t len)
        return 1;
 }
 
-static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
-               uint16_t column, int page_addr)
+static void set_command_address(struct pxa3xx_nand_info *info,
+               unsigned int page_size, uint16_t column, int page_addr)
 {
-       int addr_cycle, exec_cmd;
-       struct pxa3xx_nand_host *host;
-       struct mtd_info *mtd;
+       /* small page addr setting */
+       if (page_size < PAGE_CHUNK_SIZE) {
+               info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
+                               | (column & 0xFF);
 
-       host = info->host[info->cs];
-       mtd = host->mtd;
-       addr_cycle = 0;
-       exec_cmd = 1;
+               info->ndcb2 = 0;
+       } else {
+               info->ndcb1 = ((page_addr & 0xFFFF) << 16)
+                               | (column & 0xFFFF);
+
+               if (page_addr & 0xFF0000)
+                       info->ndcb2 = (page_addr & 0xFF0000) >> 16;
+               else
+                       info->ndcb2 = 0;
+       }
+}
+
+static void prepare_start_command(struct pxa3xx_nand_info *info, int command)
+{
+       struct pxa3xx_nand_host *host = info->host[info->cs];
+       struct mtd_info *mtd = host->mtd;
 
        /* reset data and oob column point to handle data */
        info->buf_start         = 0;
        info->buf_count         = 0;
        info->oob_size          = 0;
+       info->data_buff_pos     = 0;
+       info->oob_buff_pos      = 0;
        info->use_ecc           = 0;
        info->use_spare         = 1;
-       info->is_ready          = 0;
        info->retcode           = ERR_NONE;
-       if (info->cs != 0)
-               info->ndcb0 = NDCB0_CSEL;
-       else
-               info->ndcb0 = 0;
+       info->ecc_err_cnt       = 0;
+       info->ndcb3             = 0;
+       info->need_wait         = 0;
 
        switch (command) {
        case NAND_CMD_READ0:
        case NAND_CMD_PAGEPROG:
                info->use_ecc = 1;
        case NAND_CMD_READOOB:
-               pxa3xx_set_datasize(info);
+               pxa3xx_set_datasize(info, mtd);
                break;
        case NAND_CMD_PARAM:
                info->use_spare = 0;
                break;
-       case NAND_CMD_SEQIN:
-               exec_cmd = 0;
-               break;
        default:
                info->ndcb1 = 0;
                info->ndcb2 = 0;
-               info->ndcb3 = 0;
                break;
        }
 
+       /*
+        * If we are about to issue a read command, or about to set
+        * the write address, then clean the data buffer.
+        */
+       if (command == NAND_CMD_READ0 ||
+           command == NAND_CMD_READOOB ||
+           command == NAND_CMD_SEQIN) {
+
+               info->buf_count = mtd->writesize + mtd->oobsize;
+               memset(info->data_buff, 0xFF, info->buf_count);
+       }
+
+}
+
+static int prepare_set_command(struct pxa3xx_nand_info *info, int command,
+               int ext_cmd_type, uint16_t column, int page_addr)
+{
+       int addr_cycle, exec_cmd;
+       struct pxa3xx_nand_host *host;
+       struct mtd_info *mtd;
+
+       host = info->host[info->cs];
+       mtd = host->mtd;
+       addr_cycle = 0;
+       exec_cmd = 1;
+
+       if (info->cs != 0)
+               info->ndcb0 = NDCB0_CSEL;
+       else
+               info->ndcb0 = 0;
+
+       if (command == NAND_CMD_SEQIN)
+               exec_cmd = 0;
+
        addr_cycle = NDCB0_ADDR_CYC(host->row_addr_cycles
                                    + host->col_addr_cycles);
 
@@ -589,30 +770,42 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
                if (command == NAND_CMD_READOOB)
                        info->buf_start += mtd->writesize;
 
-               /* Second command setting for large pages */
-               if (host->page_size >= PAGE_CHUNK_SIZE)
+               /*
+                * Multiple page read needs an 'extended command type' field,
+                * which is either naked-read or last-read according to the
+                * state.
+                */
+               if (mtd->writesize == PAGE_CHUNK_SIZE) {
                        info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8);
+               } else if (mtd->writesize > PAGE_CHUNK_SIZE) {
+                       info->ndcb0 |= NDCB0_DBC | (NAND_CMD_READSTART << 8)
+                                       | NDCB0_LEN_OVRD
+                                       | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
+                       info->ndcb3 = info->chunk_size +
+                                     info->oob_size;
+               }
+
+               set_command_address(info, mtd->writesize, column, page_addr);
+               break;
 
        case NAND_CMD_SEQIN:
-               /* small page addr setting */
-               if (unlikely(host->page_size < PAGE_CHUNK_SIZE)) {
-                       info->ndcb1 = ((page_addr & 0xFFFFFF) << 8)
-                                       | (column & 0xFF);
 
-                       info->ndcb2 = 0;
-               } else {
-                       info->ndcb1 = ((page_addr & 0xFFFF) << 16)
-                                       | (column & 0xFFFF);
+               info->buf_start = column;
+               set_command_address(info, mtd->writesize, 0, page_addr);
 
-                       if (page_addr & 0xFF0000)
-                               info->ndcb2 = (page_addr & 0xFF0000) >> 16;
-                       else
-                               info->ndcb2 = 0;
+               /*
+                * Multiple page programming needs to execute the initial
+                * SEQIN command that sets the page address.
+                */
+               if (mtd->writesize > PAGE_CHUNK_SIZE) {
+                       info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+                               | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
+                               | addr_cycle
+                               | command;
+                       /* No data transfer in this case */
+                       info->data_size = 0;
+                       exec_cmd = 1;
                }
-
-               info->buf_count = mtd->writesize + mtd->oobsize;
-               memset(info->data_buff, 0xFF, info->buf_count);
-
                break;
 
        case NAND_CMD_PAGEPROG:
@@ -622,13 +815,40 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
                        break;
                }
 
-               info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
-                               | NDCB0_AUTO_RS
-                               | NDCB0_ST_ROW_EN
-                               | NDCB0_DBC
-                               | (NAND_CMD_PAGEPROG << 8)
-                               | NAND_CMD_SEQIN
-                               | addr_cycle;
+               /* Second command setting for large pages */
+               if (mtd->writesize > PAGE_CHUNK_SIZE) {
+                       /*
+                        * Multiple page write uses the 'extended command'
+                        * field. This can be used to issue a command dispatch
+                        * or a naked-write depending on the current stage.
+                        */
+                       info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+                                       | NDCB0_LEN_OVRD
+                                       | NDCB0_EXT_CMD_TYPE(ext_cmd_type);
+                       info->ndcb3 = info->chunk_size +
+                                     info->oob_size;
+
+                       /*
+                        * This is the command dispatch that completes a chunked
+                        * page program operation.
+                        */
+                       if (info->data_size == 0) {
+                               info->ndcb0 = NDCB0_CMD_TYPE(0x1)
+                                       | NDCB0_EXT_CMD_TYPE(ext_cmd_type)
+                                       | command;
+                               info->ndcb1 = 0;
+                               info->ndcb2 = 0;
+                               info->ndcb3 = 0;
+                       }
+               } else {
+                       info->ndcb0 |= NDCB0_CMD_TYPE(0x1)
+                                       | NDCB0_AUTO_RS
+                                       | NDCB0_ST_ROW_EN
+                                       | NDCB0_DBC
+                                       | (NAND_CMD_PAGEPROG << 8)
+                                       | NAND_CMD_SEQIN
+                                       | addr_cycle;
+               }
                break;
 
        case NAND_CMD_PARAM:
@@ -691,8 +911,8 @@ static int prepare_command_pool(struct pxa3xx_nand_info *info, int command,
        return exec_cmd;
 }
 
-static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
-                               int column, int page_addr)
+static void nand_cmdfunc(struct mtd_info *mtd, unsigned command,
+                        int column, int page_addr)
 {
        struct pxa3xx_nand_host *host = mtd->priv;
        struct pxa3xx_nand_info *info = host->info_data;
@@ -717,10 +937,15 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
                nand_writel(info, NDTR1CS0, info->ndtr1cs0);
        }
 
+       prepare_start_command(info, command);
+
        info->state = STATE_PREPARED;
-       exec_cmd = prepare_command_pool(info, command, column, page_addr);
+       exec_cmd = prepare_set_command(info, command, 0, column, page_addr);
+
        if (exec_cmd) {
                init_completion(&info->cmd_complete);
+               init_completion(&info->dev_ready);
+               info->need_wait = 1;
                pxa3xx_nand_start(info);
 
                ret = wait_for_completion_timeout(&info->cmd_complete,
@@ -734,6 +959,117 @@ static void pxa3xx_nand_cmdfunc(struct mtd_info *mtd, unsigned command,
        info->state = STATE_IDLE;
 }
 
+static void nand_cmdfunc_extended(struct mtd_info *mtd,
+                                 const unsigned command,
+                                 int column, int page_addr)
+{
+       struct pxa3xx_nand_host *host = mtd->priv;
+       struct pxa3xx_nand_info *info = host->info_data;
+       int ret, exec_cmd, ext_cmd_type;
+
+       /*
+        * if this is a x16 device then convert the input
+        * "byte" address into a "word" address appropriate
+        * for indexing a word-oriented device
+        */
+       if (info->reg_ndcr & NDCR_DWIDTH_M)
+               column /= 2;
+
+       /*
+        * There may be different NAND chip hooked to
+        * different chip select, so check whether
+        * chip select has been changed, if yes, reset the timing
+        */
+       if (info->cs != host->cs) {
+               info->cs = host->cs;
+               nand_writel(info, NDTR0CS0, info->ndtr0cs0);
+               nand_writel(info, NDTR1CS0, info->ndtr1cs0);
+       }
+
+       /* Select the extended command for the first command */
+       switch (command) {
+       case NAND_CMD_READ0:
+       case NAND_CMD_READOOB:
+               ext_cmd_type = EXT_CMD_TYPE_MONO;
+               break;
+       case NAND_CMD_SEQIN:
+               ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
+               break;
+       case NAND_CMD_PAGEPROG:
+               ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
+               break;
+       default:
+               ext_cmd_type = 0;
+               break;
+       }
+
+       prepare_start_command(info, command);
+
+       /*
+        * Prepare the "is ready" completion before starting a command
+        * transaction sequence. If the command is not executed the
+        * completion will be completed, see below.
+        *
+        * We can do that inside the loop because the command variable
+        * is invariant and thus so is the exec_cmd.
+        */
+       info->need_wait = 1;
+       init_completion(&info->dev_ready);
+       do {
+               info->state = STATE_PREPARED;
+               exec_cmd = prepare_set_command(info, command, ext_cmd_type,
+                                              column, page_addr);
+               if (!exec_cmd) {
+                       info->need_wait = 0;
+                       complete(&info->dev_ready);
+                       break;
+               }
+
+               init_completion(&info->cmd_complete);
+               pxa3xx_nand_start(info);
+
+               ret = wait_for_completion_timeout(&info->cmd_complete,
+                               CHIP_DELAY_TIMEOUT);
+               if (!ret) {
+                       dev_err(&info->pdev->dev, "Wait time out!!!\n");
+                       /* Stop State Machine for next command cycle */
+                       pxa3xx_nand_stop(info);
+                       break;
+               }
+
+               /* Check if the sequence is complete */
+               if (info->data_size == 0 && command != NAND_CMD_PAGEPROG)
+                       break;
+
+               /*
+                * After a splitted program command sequence has issued
+                * the command dispatch, the command sequence is complete.
+                */
+               if (info->data_size == 0 &&
+                   command == NAND_CMD_PAGEPROG &&
+                   ext_cmd_type == EXT_CMD_TYPE_DISPATCH)
+                       break;
+
+               if (command == NAND_CMD_READ0 || command == NAND_CMD_READOOB) {
+                       /* Last read: issue a 'last naked read' */
+                       if (info->data_size == info->chunk_size)
+                               ext_cmd_type = EXT_CMD_TYPE_LAST_RW;
+                       else
+                               ext_cmd_type = EXT_CMD_TYPE_NAKED_RW;
+
+               /*
+                * If a splitted program command has no more data to transfer,
+                * the command dispatch must be issued to complete.
+                */
+               } else if (command == NAND_CMD_PAGEPROG &&
+                          info->data_size == 0) {
+                               ext_cmd_type = EXT_CMD_TYPE_DISPATCH;
+               }
+       } while (1);
+
+       info->state = STATE_IDLE;
+}
+
 static int pxa3xx_nand_write_page_hwecc(struct mtd_info *mtd,
                struct nand_chip *chip, const uint8_t *buf, int oob_required)
 {
@@ -753,20 +1089,14 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
        chip->read_buf(mtd, buf, mtd->writesize);
        chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
 
-       if (info->retcode == ERR_SBERR) {
-               switch (info->use_ecc) {
-               case 1:
-                       mtd->ecc_stats.corrected++;
-                       break;
-               case 0:
-               default:
-                       break;
-               }
-       } else if (info->retcode == ERR_DBERR) {
+       if (info->retcode == ERR_CORERR && info->use_ecc) {
+               mtd->ecc_stats.corrected += info->ecc_err_cnt;
+
+       } else if (info->retcode == ERR_UNCORERR) {
                /*
                 * for blank page (all 0xff), HW will calculate its ECC as
                 * 0, which is different from the ECC information within
-                * OOB, ignore such double bit errors
+                * OOB, ignore such uncorrectable errors
                 */
                if (is_buf_blank(buf, mtd->writesize))
                        info->retcode = ERR_NONE;
@@ -774,7 +1104,7 @@ static int pxa3xx_nand_read_page_hwecc(struct mtd_info *mtd,
                        mtd->ecc_stats.failed++;
        }
 
-       return 0;
+       return info->max_bitflips;
 }
 
 static uint8_t pxa3xx_nand_read_byte(struct mtd_info *mtd)
@@ -833,21 +1163,27 @@ static int pxa3xx_nand_waitfunc(struct mtd_info *mtd, struct nand_chip *this)
 {
        struct pxa3xx_nand_host *host = mtd->priv;
        struct pxa3xx_nand_info *info = host->info_data;
+       int ret;
+
+       if (info->need_wait) {
+               ret = wait_for_completion_timeout(&info->dev_ready,
+                               CHIP_DELAY_TIMEOUT);
+               info->need_wait = 0;
+               if (!ret) {
+                       dev_err(&info->pdev->dev, "Ready time out!!!\n");
+                       return NAND_STATUS_FAIL;
+               }
+       }
 
        /* pxa3xx_nand_send_command has waited for command complete */
        if (this->state == FL_WRITING || this->state == FL_ERASING) {
                if (info->retcode == ERR_NONE)
                        return 0;
-               else {
-                       /*
-                        * any error make it return 0x01 which will tell
-                        * the caller the erase and write fail
-                        */
-                       return 0x01;
-               }
+               else
+                       return NAND_STATUS_FAIL;
        }
 
-       return 0;
+       return NAND_STATUS_READY;
 }
 
 static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
@@ -869,7 +1205,6 @@ static int pxa3xx_nand_config_flash(struct pxa3xx_nand_info *info,
        }
 
        /* calculate flash information */
-       host->page_size = f->page_size;
        host->read_id_bytes = (f->page_size == 2048) ? 4 : 2;
 
        /* calculate addressing information */
@@ -906,13 +1241,15 @@ static int pxa3xx_nand_detect_config(struct pxa3xx_nand_info *info)
        uint32_t ndcr = nand_readl(info, NDCR);
 
        if (ndcr & NDCR_PAGE_SZ) {
-               host->page_size = 2048;
+               /* Controller's FIFO size */
+               info->chunk_size = 2048;
                host->read_id_bytes = 4;
        } else {
-               host->page_size = 512;
+               info->chunk_size = 512;
                host->read_id_bytes = 2;
        }
 
+       /* Set an initial chunk size */
        info->reg_ndcr = ndcr & ~NDCR_INT_MASK;
        info->ndtr0cs0 = nand_readl(info, NDTR0CS0);
        info->ndtr1cs0 = nand_readl(info, NDTR1CS0);
@@ -988,18 +1325,89 @@ static void pxa3xx_nand_free_buff(struct pxa3xx_nand_info *info)
 static int pxa3xx_nand_sensing(struct pxa3xx_nand_info *info)
 {
        struct mtd_info *mtd;
+       struct nand_chip *chip;
        int ret;
+
        mtd = info->host[info->cs]->mtd;
+       chip = mtd->priv;
+
        /* use the common timing to make a try */
        ret = pxa3xx_nand_config_flash(info, &builtin_flash_types[0]);
        if (ret)
                return ret;
 
-       pxa3xx_nand_cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
-       if (info->is_ready)
-               return 0;
+       chip->cmdfunc(mtd, NAND_CMD_RESET, 0, 0);
+       ret = chip->waitfunc(mtd, chip);
+       if (ret & NAND_STATUS_FAIL)
+               return -ENODEV;
+
+       return 0;
+}
 
-       return -ENODEV;
+static int pxa_ecc_init(struct pxa3xx_nand_info *info,
+                       struct nand_ecc_ctrl *ecc,
+                       int strength, int ecc_stepsize, int page_size)
+{
+       if (strength == 1 && ecc_stepsize == 512 && page_size == 2048) {
+               info->chunk_size = 2048;
+               info->spare_size = 40;
+               info->ecc_size = 24;
+               ecc->mode = NAND_ECC_HW;
+               ecc->size = 512;
+               ecc->strength = 1;
+               return 1;
+
+       } else if (strength == 1 && ecc_stepsize == 512 && page_size == 512) {
+               info->chunk_size = 512;
+               info->spare_size = 8;
+               info->ecc_size = 8;
+               ecc->mode = NAND_ECC_HW;
+               ecc->size = 512;
+               ecc->strength = 1;
+               return 1;
+
+       /*
+        * Required ECC: 4-bit correction per 512 bytes
+        * Select: 16-bit correction per 2048 bytes
+        */
+       } else if (strength == 4 && ecc_stepsize == 512 && page_size == 2048) {
+               info->ecc_bch = 1;
+               info->chunk_size = 2048;
+               info->spare_size = 32;
+               info->ecc_size = 32;
+               ecc->mode = NAND_ECC_HW;
+               ecc->size = info->chunk_size;
+               ecc->layout = &ecc_layout_2KB_bch4bit;
+               ecc->strength = 16;
+               return 1;
+
+       } else if (strength == 4 && ecc_stepsize == 512 && page_size == 4096) {
+               info->ecc_bch = 1;
+               info->chunk_size = 2048;
+               info->spare_size = 32;
+               info->ecc_size = 32;
+               ecc->mode = NAND_ECC_HW;
+               ecc->size = info->chunk_size;
+               ecc->layout = &ecc_layout_4KB_bch4bit;
+               ecc->strength = 16;
+               return 1;
+
+       /*
+        * Required ECC: 8-bit correction per 512 bytes
+        * Select: 16-bit correction per 1024 bytes
+        */
+       } else if (strength == 8 && ecc_stepsize == 512 && page_size == 4096) {
+               info->ecc_bch = 1;
+               info->chunk_size = 1024;
+               info->spare_size = 0;
+               info->ecc_size = 32;
+               ecc->mode = NAND_ECC_HW;
+               ecc->size = info->chunk_size;
+               ecc->layout = &ecc_layout_4KB_bch8bit;
+               ecc->strength = 16;
+               return 1;
+       }
+       return 0;
 }
 
 static int pxa3xx_nand_scan(struct mtd_info *mtd)
@@ -1014,6 +1422,7 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
        uint32_t id = -1;
        uint64_t chipsize;
        int i, ret, num;
+       uint16_t ecc_strength, ecc_step;
 
        if (pdata->keep_config && !pxa3xx_nand_detect_config(info))
                goto KEEP_CONFIG;
@@ -1072,15 +1481,60 @@ static int pxa3xx_nand_scan(struct mtd_info *mtd)
        pxa3xx_flash_ids[1].name = NULL;
        def = pxa3xx_flash_ids;
 KEEP_CONFIG:
-       chip->ecc.mode = NAND_ECC_HW;
-       chip->ecc.size = host->page_size;
-       chip->ecc.strength = 1;
-
        if (info->reg_ndcr & NDCR_DWIDTH_M)
                chip->options |= NAND_BUSWIDTH_16;
 
+       /* Device detection must be done with ECC disabled */
+       if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370)
+               nand_writel(info, NDECCCTRL, 0x0);
+
        if (nand_scan_ident(mtd, 1, def))
                return -ENODEV;
+
+       if (pdata->flash_bbt) {
+               /*
+                * We'll use a bad block table stored in-flash and don't
+                * allow writing the bad block marker to the flash.
+                */
+               chip->bbt_options |= NAND_BBT_USE_FLASH |
+                                    NAND_BBT_NO_OOB_BBM;
+               chip->bbt_td = &bbt_main_descr;
+               chip->bbt_md = &bbt_mirror_descr;
+       }
+
+       /*
+        * If the page size is bigger than the FIFO size, let's check
+        * we are given the right variant and then switch to the extended
+        * (aka splitted) command handling,
+        */
+       if (mtd->writesize > PAGE_CHUNK_SIZE) {
+               if (info->variant == PXA3XX_NAND_VARIANT_ARMADA370) {
+                       chip->cmdfunc = nand_cmdfunc_extended;
+               } else {
+                       dev_err(&info->pdev->dev,
+                               "unsupported page size on this variant\n");
+                       return -ENODEV;
+               }
+       }
+
+       ecc_strength = chip->ecc_strength_ds;
+       ecc_step = chip->ecc_step_ds;
+
+       /* Set default ECC strength requirements on non-ONFI devices */
+       if (ecc_strength < 1 && ecc_step < 1) {
+               ecc_strength = 1;
+               ecc_step = 512;
+       }
+
+       ret = pxa_ecc_init(info, &chip->ecc, ecc_strength,
+                          ecc_step, mtd->writesize);
+       if (!ret) {
+               dev_err(&info->pdev->dev,
+                       "ECC strength %d at page size %d is not supported\n",
+                       chip->ecc_strength_ds, mtd->writesize);
+               return -ENODEV;
+       }
+
        /* calculate addressing information */
        if (mtd->writesize >= 2048)
                host->col_addr_cycles = 2;
@@ -1121,6 +1575,7 @@ static int alloc_nand_resource(struct platform_device *pdev)
                return -ENOMEM;
 
        info->pdev = pdev;
+       info->variant = pxa3xx_nand_get_variant(pdev);
        for (cs = 0; cs < pdata->num_cs; cs++) {
                mtd = (struct mtd_info *)((unsigned int)&info[1] +
                      (sizeof(*mtd) + sizeof(*host)) * cs);
@@ -1138,11 +1593,12 @@ static int alloc_nand_resource(struct platform_device *pdev)
                chip->controller        = &info->controller;
                chip->waitfunc          = pxa3xx_nand_waitfunc;
                chip->select_chip       = pxa3xx_nand_select_chip;
-               chip->cmdfunc           = pxa3xx_nand_cmdfunc;
                chip->read_word         = pxa3xx_nand_read_word;
                chip->read_byte         = pxa3xx_nand_read_byte;
                chip->read_buf          = pxa3xx_nand_read_buf;
                chip->write_buf         = pxa3xx_nand_write_buf;
+               chip->options           |= NAND_NO_SUBPAGE_WRITE;
+               chip->cmdfunc           = nand_cmdfunc;
        }
 
        spin_lock_init(&chip->controller->lock);
@@ -1254,25 +1710,6 @@ static int pxa3xx_nand_remove(struct platform_device *pdev)
        return 0;
 }
 
-static struct of_device_id pxa3xx_nand_dt_ids[] = {
-       {
-               .compatible = "marvell,pxa3xx-nand",
-               .data       = (void *)PXA3XX_NAND_VARIANT_PXA,
-       },
-       {}
-};
-MODULE_DEVICE_TABLE(of, pxa3xx_nand_dt_ids);
-
-static enum pxa3xx_nand_variant
-pxa3xx_nand_get_variant(struct platform_device *pdev)
-{
-       const struct of_device_id *of_id =
-                       of_match_device(pxa3xx_nand_dt_ids, &pdev->dev);
-       if (!of_id)
-               return PXA3XX_NAND_VARIANT_PXA;
-       return (enum pxa3xx_nand_variant)of_id->data;
-}
-
 static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
 {
        struct pxa3xx_nand_platform_data *pdata;
@@ -1292,6 +1729,7 @@ static int pxa3xx_nand_probe_dt(struct platform_device *pdev)
        if (of_get_property(np, "marvell,nand-keep-config", NULL))
                pdata->keep_config = 1;
        of_property_read_u32(np, "num-cs", &pdata->num_cs);
+       pdata->flash_bbt = of_get_nand_on_flash_bbt(np);
 
        pdev->dev.platform_data = pdata;
 
@@ -1329,7 +1767,6 @@ static int pxa3xx_nand_probe(struct platform_device *pdev)
        }
 
        info = platform_get_drvdata(pdev);
-       info->variant = pxa3xx_nand_get_variant(pdev);
        probe_success = 0;
        for (cs = 0; cs < pdata->num_cs; cs++) {
                struct mtd_info *mtd = info->host[cs]->mtd;
index d65cbe903d4015e37076f0505db987ee4383e0d5..f0918e7411d99147fd67c26c48a8672cb237437f 100644 (file)
 #include <linux/mtd/nand_ecc.h>
 #include <linux/mtd/partitions.h>
 
-#include <plat/regs-nand.h>
 #include <linux/platform_data/mtd-nand-s3c2410.h>
 
+#define S3C2410_NFREG(x) (x)
+
+#define S3C2410_NFCONF         S3C2410_NFREG(0x00)
+#define S3C2410_NFCMD          S3C2410_NFREG(0x04)
+#define S3C2410_NFADDR         S3C2410_NFREG(0x08)
+#define S3C2410_NFDATA         S3C2410_NFREG(0x0C)
+#define S3C2410_NFSTAT         S3C2410_NFREG(0x10)
+#define S3C2410_NFECC          S3C2410_NFREG(0x14)
+#define S3C2440_NFCONT         S3C2410_NFREG(0x04)
+#define S3C2440_NFCMD          S3C2410_NFREG(0x08)
+#define S3C2440_NFADDR         S3C2410_NFREG(0x0C)
+#define S3C2440_NFDATA         S3C2410_NFREG(0x10)
+#define S3C2440_NFSTAT         S3C2410_NFREG(0x20)
+#define S3C2440_NFMECC0                S3C2410_NFREG(0x2C)
+#define S3C2412_NFSTAT         S3C2410_NFREG(0x28)
+#define S3C2412_NFMECC0                S3C2410_NFREG(0x34)
+#define S3C2410_NFCONF_EN              (1<<15)
+#define S3C2410_NFCONF_INITECC         (1<<12)
+#define S3C2410_NFCONF_nFCE            (1<<11)
+#define S3C2410_NFCONF_TACLS(x)                ((x)<<8)
+#define S3C2410_NFCONF_TWRPH0(x)       ((x)<<4)
+#define S3C2410_NFCONF_TWRPH1(x)       ((x)<<0)
+#define S3C2410_NFSTAT_BUSY            (1<<0)
+#define S3C2440_NFCONF_TACLS(x)                ((x)<<12)
+#define S3C2440_NFCONF_TWRPH0(x)       ((x)<<8)
+#define S3C2440_NFCONF_TWRPH1(x)       ((x)<<4)
+#define S3C2440_NFCONT_INITECC         (1<<4)
+#define S3C2440_NFCONT_nFCE            (1<<1)
+#define S3C2440_NFCONT_ENABLE          (1<<0)
+#define S3C2440_NFSTAT_READY           (1<<0)
+#define S3C2412_NFCONF_NANDBOOT                (1<<31)
+#define S3C2412_NFCONT_INIT_MAIN_ECC   (1<<5)
+#define S3C2412_NFCONT_nFCE0           (1<<1)
+#define S3C2412_NFSTAT_READY           (1<<0)
+
 /* new oob placement block for use with hardware ecc generation
  */
 
@@ -919,7 +953,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
 
        info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
        if (info == NULL) {
-               dev_err(&pdev->dev, "no memory for flash info\n");
                err = -ENOMEM;
                goto exit_error;
        }
@@ -974,7 +1007,6 @@ static int s3c24xx_nand_probe(struct platform_device *pdev)
        size = nr_sets * sizeof(*info->mtds);
        info->mtds = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
        if (info->mtds == NULL) {
-               dev_err(&pdev->dev, "failed to allocate mtd storage\n");
                err = -ENOMEM;
                goto exit_error;
        }
index a3c84ebbe39227dac06bae3d0f9014849cf48b17..d72783dd7b962f798f1256067e3d4d9f5a1c5366 100644 (file)
@@ -151,7 +151,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
        dma_cap_set(DMA_SLAVE, mask);
 
        flctl->chan_fifo0_tx = dma_request_channel(mask, shdma_chan_filter,
-                                           (void *)pdata->slave_id_fifo0_tx);
+                               (void *)(uintptr_t)pdata->slave_id_fifo0_tx);
        dev_dbg(&pdev->dev, "%s: TX: got channel %p\n", __func__,
                flctl->chan_fifo0_tx);
 
@@ -168,7 +168,7 @@ static void flctl_setup_dma(struct sh_flctl *flctl)
                goto err;
 
        flctl->chan_fifo0_rx = dma_request_channel(mask, shdma_chan_filter,
-                                           (void *)pdata->slave_id_fifo0_rx);
+                               (void *)(uintptr_t)pdata->slave_id_fifo0_rx);
        dev_dbg(&pdev->dev, "%s: RX: got channel %p\n", __func__,
                flctl->chan_fifo0_rx);
 
@@ -1021,7 +1021,6 @@ static irqreturn_t flctl_handle_flste(int irq, void *dev_id)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_OF
 struct flctl_soc_config {
        unsigned long flcmncr_val;
        unsigned has_hwecc:1;
@@ -1059,10 +1058,8 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
 
        pdata = devm_kzalloc(dev, sizeof(struct sh_flctl_platform_data),
                                                                GFP_KERNEL);
-       if (!pdata) {
-               dev_err(dev, "%s: failed to allocate config data\n", __func__);
+       if (!pdata)
                return NULL;
-       }
 
        /* set SoC specific options */
        pdata->flcmncr_val = config->flcmncr_val;
@@ -1080,12 +1077,6 @@ static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
 
        return pdata;
 }
-#else /* CONFIG_OF */
-static struct sh_flctl_platform_data *flctl_parse_dt(struct device *dev)
-{
-       return NULL;
-}
-#endif /* CONFIG_OF */
 
 static int flctl_probe(struct platform_device *pdev)
 {
@@ -1094,38 +1085,30 @@ static int flctl_probe(struct platform_device *pdev)
        struct mtd_info *flctl_mtd;
        struct nand_chip *nand;
        struct sh_flctl_platform_data *pdata;
-       int ret = -ENXIO;
+       int ret;
        int irq;
        struct mtd_part_parser_data ppdata = {};
 
-       flctl = kzalloc(sizeof(struct sh_flctl), GFP_KERNEL);
-       if (!flctl) {
-               dev_err(&pdev->dev, "failed to allocate driver data\n");
+       flctl = devm_kzalloc(&pdev->dev, sizeof(struct sh_flctl), GFP_KERNEL);
+       if (!flctl)
                return -ENOMEM;
-       }
 
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!res) {
-               dev_err(&pdev->dev, "failed to get I/O memory\n");
-               goto err_iomap;
-       }
-
-       flctl->reg = ioremap(res->start, resource_size(res));
-       if (flctl->reg == NULL) {
-               dev_err(&pdev->dev, "failed to remap I/O memory\n");
-               goto err_iomap;
-       }
+       flctl->reg = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(flctl->reg))
+               return PTR_ERR(flctl->reg);
 
        irq = platform_get_irq(pdev, 0);
        if (irq < 0) {
                dev_err(&pdev->dev, "failed to get flste irq data\n");
-               goto err_flste;
+               return -ENXIO;
        }
 
-       ret = request_irq(irq, flctl_handle_flste, IRQF_SHARED, "flste", flctl);
+       ret = devm_request_irq(&pdev->dev, irq, flctl_handle_flste, IRQF_SHARED,
+                              "flste", flctl);
        if (ret) {
                dev_err(&pdev->dev, "request interrupt failed.\n");
-               goto err_flste;
+               return ret;
        }
 
        if (pdev->dev.of_node)
@@ -1135,8 +1118,7 @@ static int flctl_probe(struct platform_device *pdev)
 
        if (!pdata) {
                dev_err(&pdev->dev, "no setup data defined\n");
-               ret = -EINVAL;
-               goto err_pdata;
+               return -EINVAL;
        }
 
        platform_set_drvdata(pdev, flctl);
@@ -1190,12 +1172,6 @@ static int flctl_probe(struct platform_device *pdev)
 err_chip:
        flctl_release_dma(flctl);
        pm_runtime_disable(&pdev->dev);
-err_pdata:
-       free_irq(irq, flctl);
-err_flste:
-       iounmap(flctl->reg);
-err_iomap:
-       kfree(flctl);
        return ret;
 }
 
@@ -1206,9 +1182,6 @@ static int flctl_remove(struct platform_device *pdev)
        flctl_release_dma(flctl);
        nand_release(&flctl->mtd);
        pm_runtime_disable(&pdev->dev);
-       free_irq(platform_get_irq(pdev, 0), flctl);
-       iounmap(flctl->reg);
-       kfree(flctl);
 
        return 0;
 }
index 87908d760feb067c3cb179b35bfa5a3c462ab737..e81059b58382f23af69848211415c4095ea36edf 100644 (file)
@@ -121,10 +121,8 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
 
        /* Allocate memory for MTD device structure and private data */
        sharpsl = kzalloc(sizeof(struct sharpsl_nand), GFP_KERNEL);
-       if (!sharpsl) {
-               printk("Unable to allocate SharpSL NAND MTD device structure.\n");
+       if (!sharpsl)
                return -ENOMEM;
-       }
 
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!r) {
@@ -136,7 +134,7 @@ static int sharpsl_nand_probe(struct platform_device *pdev)
        /* map physical address */
        sharpsl->io = ioremap(r->start, resource_size(r));
        if (!sharpsl->io) {
-               printk("ioremap to access Sharp SL NAND chip failed\n");
+               dev_err(&pdev->dev, "ioremap to access Sharp SL NAND chip failed\n");
                err = -EIO;
                goto err_ioremap;
        }
index a3747c914d5718abd342f53f8253e2d4c0ea3353..fb8fd35fa668516dcb763037e164691482eca9ea 100644 (file)
@@ -371,11 +371,9 @@ static int tmio_probe(struct platform_device *dev)
        if (data == NULL)
                dev_warn(&dev->dev, "NULL platform data!\n");
 
-       tmio = kzalloc(sizeof *tmio, GFP_KERNEL);
-       if (!tmio) {
-               retval = -ENOMEM;
-               goto err_kzalloc;
-       }
+       tmio = devm_kzalloc(&dev->dev, sizeof(*tmio), GFP_KERNEL);
+       if (!tmio)
+               return -ENOMEM;
 
        tmio->dev = dev;
 
@@ -385,22 +383,18 @@ static int tmio_probe(struct platform_device *dev)
        mtd->priv = nand_chip;
        mtd->name = "tmio-nand";
 
-       tmio->ccr = ioremap(ccr->start, resource_size(ccr));
-       if (!tmio->ccr) {
-               retval = -EIO;
-               goto err_iomap_ccr;
-       }
+       tmio->ccr = devm_ioremap(&dev->dev, ccr->start, resource_size(ccr));
+       if (!tmio->ccr)
+               return -EIO;
 
        tmio->fcr_base = fcr->start & 0xfffff;
-       tmio->fcr = ioremap(fcr->start, resource_size(fcr));
-       if (!tmio->fcr) {
-               retval = -EIO;
-               goto err_iomap_fcr;
-       }
+       tmio->fcr = devm_ioremap(&dev->dev, fcr->start, resource_size(fcr));
+       if (!tmio->fcr)
+               return -EIO;
 
        retval = tmio_hw_init(dev, tmio);
        if (retval)
-               goto err_hwinit;
+               return retval;
 
        /* Set address of NAND IO lines */
        nand_chip->IO_ADDR_R = tmio->fcr;
@@ -428,7 +422,8 @@ static int tmio_probe(struct platform_device *dev)
        /* 15 us command delay time */
        nand_chip->chip_delay = 15;
 
-       retval = request_irq(irq, &tmio_irq, 0, dev_name(&dev->dev), tmio);
+       retval = devm_request_irq(&dev->dev, irq, &tmio_irq, 0,
+                                 dev_name(&dev->dev), tmio);
        if (retval) {
                dev_err(&dev->dev, "request_irq error %d\n", retval);
                goto err_irq;
@@ -440,7 +435,7 @@ static int tmio_probe(struct platform_device *dev)
        /* Scan to find existence of the device */
        if (nand_scan(mtd, 1)) {
                retval = -ENODEV;
-               goto err_scan;
+               goto err_irq;
        }
        /* Register the partitions */
        retval = mtd_device_parse_register(mtd, NULL, NULL,
@@ -451,18 +446,8 @@ static int tmio_probe(struct platform_device *dev)
 
        nand_release(mtd);
 
-err_scan:
-       if (tmio->irq)
-               free_irq(tmio->irq, tmio);
 err_irq:
        tmio_hw_stop(dev, tmio);
-err_hwinit:
-       iounmap(tmio->fcr);
-err_iomap_fcr:
-       iounmap(tmio->ccr);
-err_iomap_ccr:
-       kfree(tmio);
-err_kzalloc:
        return retval;
 }
 
@@ -471,12 +456,7 @@ static int tmio_remove(struct platform_device *dev)
        struct tmio_nand *tmio = platform_get_drvdata(dev);
 
        nand_release(&tmio->mtd);
-       if (tmio->irq)
-               free_irq(tmio->irq, tmio);
        tmio_hw_stop(dev, tmio);
-       iounmap(tmio->fcr);
-       iounmap(tmio->ccr);
-       kfree(tmio);
        return 0;
 }
 
index 235714a421dd6770851f2f5026522123f46dbefc..c1622a5ba8140710bf7807a31a622c283c45ad4b 100644 (file)
@@ -319,11 +319,8 @@ static int __init txx9ndfmc_probe(struct platform_device *dev)
                        continue;
                txx9_priv = kzalloc(sizeof(struct txx9ndfmc_priv),
                                    GFP_KERNEL);
-               if (!txx9_priv) {
-                       dev_err(&dev->dev, "Unable to allocate "
-                               "TXx9 NDFMC MTD device structure.\n");
+               if (!txx9_priv)
                        continue;
-               }
                chip = &txx9_priv->chip;
                mtd = &txx9_priv->mtd;
                mtd->owner = THIS_MODULE;
index d64f8c30945fbcd8e2d09a5b8342e75c081cd343..aa26c32e1bc28943426992eba09fddc207cf104d 100644 (file)
@@ -81,7 +81,7 @@ static int parse_ofpart_partitions(struct mtd_info *master,
                partname = of_get_property(pp, "label", &len);
                if (!partname)
                        partname = of_get_property(pp, "name", &len);
-               (*pparts)[i].name = (char *)partname;
+               (*pparts)[i].name = partname;
 
                if (of_get_property(pp, "read-only", &len))
                        (*pparts)[i].mask_flags |= MTD_WRITEABLE;
@@ -152,7 +152,7 @@ static int parse_ofoldpart_partitions(struct mtd_info *master,
                if (names && (plen > 0)) {
                        int len = strlen(names) + 1;
 
-                       (*pparts)[i].name = (char *)names;
+                       (*pparts)[i].name = names;
                        plen -= len;
                        names += len;
                } else {
@@ -173,18 +173,9 @@ static struct mtd_part_parser ofoldpart_parser = {
 
 static int __init ofpart_parser_init(void)
 {
-       int rc;
-       rc = register_mtd_parser(&ofpart_parser);
-       if (rc)
-               goto out;
-
-       rc = register_mtd_parser(&ofoldpart_parser);
-       if (!rc)
-               return 0;
-
-       deregister_mtd_parser(&ofoldpart_parser);
-out:
-       return rc;
+       register_mtd_parser(&ofpart_parser);
+       register_mtd_parser(&ofoldpart_parser);
+       return 0;
 }
 
 static void __exit ofpart_parser_exit(void)
index 63699fffc96de24b3098f629ea495184103386c8..8e1919b6f07449f007c0b1766f4ffcde5db4c0f1 100644 (file)
@@ -58,7 +58,7 @@ static int generic_onenand_probe(struct platform_device *pdev)
                goto out_release_mem_region;
        }
 
-       info->onenand.mmcontrol = pdata ? pdata->mmcontrol : 0;
+       info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL;
        info->onenand.irq = platform_get_irq(pdev, 0);
 
        info->mtd.name = dev_name(&pdev->dev);
index 580035c803d693eb38b8f37750a85d57f70cadfa..5da911ebdf495152c68c52af72d0784f0a8ede54 100644 (file)
@@ -300,7 +300,8 @@ MODULE_ALIAS("RedBoot");
 
 static int __init redboot_parser_init(void)
 {
-       return register_mtd_parser(&redboot_parser);
+       register_mtd_parser(&redboot_parser);
+       return 0;
 }
 
 static void __exit redboot_parser_exit(void)
index 70106607c247289b6328c9ff99321d64ffc49c81..e579f9027c47d82bb1e4d577ddd13128324a0075 100644 (file)
@@ -19,7 +19,7 @@
  * or detected.
  */
 
-#if defined(CONFIG_MTD_NAND) || defined(CONFIG_MTD_NAND_MODULE)
+#if IS_ENABLED(CONFIG_MTD_NAND)
 
 struct nand_ecc_test {
        const char *name;
index 33bb1f2b63e4f323f0c0c9494b12a1ce3e46d1e2..6f27d9a1be3b7ff3294e0549bc7fef308a9a1b85 100644 (file)
@@ -1453,8 +1453,10 @@ int ubi_attach(struct ubi_device *ubi, int force_scan)
                struct ubi_attach_info *scan_ai;
 
                scan_ai = alloc_ai("ubi_ckh_aeb_slab_cache");
-               if (!scan_ai)
+               if (!scan_ai) {
+                       err = -ENOMEM;
                        goto out_wl;
+               }
 
                err = scan_all(ubi, scan_ai, 0);
                if (err) {
index e05dc6298c1dcc157598e99ac57cb32e702918ae..57deae961429d0a161de940072cbc24dc984a008 100644 (file)
@@ -1245,8 +1245,10 @@ static int __init ubi_init(void)
        ubi_wl_entry_slab = kmem_cache_create("ubi_wl_entry_slab",
                                              sizeof(struct ubi_wl_entry),
                                              0, 0, NULL);
-       if (!ubi_wl_entry_slab)
+       if (!ubi_wl_entry_slab) {
+               err = -ENOMEM;
                goto out_dev_unreg;
+       }
 
        err = ubi_debugfs_init();
        if (err)
index bf79def40126865e4df5c13633fa5e5b052e3176..d36134925d31fc91bf8c2cacf0429a7b1e366757 100644 (file)
@@ -495,10 +495,12 @@ out:
  */
 static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
 {
-       int err, err1;
+       int err;
        size_t written;
        loff_t addr;
        uint32_t data = 0;
+       struct ubi_ec_hdr ec_hdr;
+
        /*
         * Note, we cannot generally define VID header buffers on stack,
         * because of the way we deal with these buffers (see the header
@@ -509,50 +511,38 @@ static int nor_erase_prepare(struct ubi_device *ubi, int pnum)
        struct ubi_vid_hdr vid_hdr;
 
        /*
+        * If VID or EC is valid, we have to corrupt them before erasing.
         * It is important to first invalidate the EC header, and then the VID
         * header. Otherwise a power cut may lead to valid EC header and
         * invalid VID header, in which case UBI will treat this PEB as
         * corrupted and will try to preserve it, and print scary warnings.
         */
        addr = (loff_t)pnum * ubi->peb_size;
-       err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data);
-       if (!err) {
-               addr += ubi->vid_hdr_aloffset;
+       err = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0);
+       if (err != UBI_IO_BAD_HDR_EBADMSG && err != UBI_IO_BAD_HDR &&
+           err != UBI_IO_FF){
                err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data);
-               if (!err)
-                       return 0;
+               if(err)
+                       goto error;
        }
 
-       /*
-        * We failed to write to the media. This was observed with Spansion
-        * S29GL512N NOR flash. Most probably the previously eraseblock erasure
-        * was interrupted at a very inappropriate moment, so it became
-        * unwritable. In this case we probably anyway have garbage in this
-        * PEB.
-        */
-       err1 = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
-       if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
-           err1 == UBI_IO_FF) {
-               struct ubi_ec_hdr ec_hdr;
-
-               err1 = ubi_io_read_ec_hdr(ubi, pnum, &ec_hdr, 0);
-               if (err1 == UBI_IO_BAD_HDR_EBADMSG || err1 == UBI_IO_BAD_HDR ||
-                   err1 == UBI_IO_FF)
-                       /*
-                        * Both VID and EC headers are corrupted, so we can
-                        * safely erase this PEB and not afraid that it will be
-                        * treated as a valid PEB in case of an unclean reboot.
-                        */
-                       return 0;
+       err = ubi_io_read_vid_hdr(ubi, pnum, &vid_hdr, 0);
+       if (err != UBI_IO_BAD_HDR_EBADMSG && err != UBI_IO_BAD_HDR &&
+           err != UBI_IO_FF){
+               addr += ubi->vid_hdr_aloffset;
+               err = mtd_write(ubi->mtd, addr, 4, &written, (void *)&data);
+               if (err)
+                       goto error;
        }
+       return 0;
 
+error:
        /*
-        * The PEB contains a valid VID header, but we cannot invalidate it.
-        * Supposedly the flash media or the driver is screwed up, so return an
-        * error.
+        * The PEB contains a valid VID or EC header, but we cannot invalidate
+        * it. Supposedly the flash media or the driver is screwed up, so
+        * return an error.
         */
-       ubi_err("cannot invalidate PEB %d, write returned %d read returned %d",
-               pnum, err, err1);
+       ubi_err("cannot invalidate PEB %d, write returned %d", pnum, err);
        ubi_dump_flash(ubi, pnum, 0, ubi->peb_size);
        return -EIO;
 }
index a7db819bca9278356598152060c4684bd6f615c7..4c08018d7333138a95d0d6a3c72c67131f842ed5 100644 (file)
@@ -2346,7 +2346,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
                                            arp_work.work);
        struct slave *slave, *oldcurrent;
        struct list_head *iter;
-       int do_failover = 0;
+       int do_failover = 0, slave_state_changed = 0;
 
        if (!bond_has_slaves(bond))
                goto re_arm;
@@ -2370,7 +2370,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
                            bond_time_in_interval(bond, slave->dev->last_rx, 1)) {
 
                                slave->link  = BOND_LINK_UP;
-                               bond_set_active_slave(slave);
+                               slave_state_changed = 1;
 
                                /* primary_slave has no meaning in round-robin
                                 * mode. the window of a slave being up and
@@ -2399,7 +2399,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
                            !bond_time_in_interval(bond, slave->dev->last_rx, 2)) {
 
                                slave->link  = BOND_LINK_DOWN;
-                               bond_set_backup_slave(slave);
+                               slave_state_changed = 1;
 
                                if (slave->link_failure_count < UINT_MAX)
                                        slave->link_failure_count++;
@@ -2426,19 +2426,24 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
 
        rcu_read_unlock();
 
-       if (do_failover) {
-               /* the bond_select_active_slave must hold RTNL
-                * and curr_slave_lock for write.
-                */
+       if (do_failover || slave_state_changed) {
                if (!rtnl_trylock())
                        goto re_arm;
-               block_netpoll_tx();
-               write_lock_bh(&bond->curr_slave_lock);
 
-               bond_select_active_slave(bond);
+               if (slave_state_changed) {
+                       bond_slave_state_change(bond);
+               } else if (do_failover) {
+                       /* the bond_select_active_slave must hold RTNL
+                        * and curr_slave_lock for write.
+                        */
+                       block_netpoll_tx();
+                       write_lock_bh(&bond->curr_slave_lock);
 
-               write_unlock_bh(&bond->curr_slave_lock);
-               unblock_netpoll_tx();
+                       bond_select_active_slave(bond);
+
+                       write_unlock_bh(&bond->curr_slave_lock);
+                       unblock_netpoll_tx();
+               }
                rtnl_unlock();
        }
 
@@ -2599,45 +2604,51 @@ do_failover:
 
 /*
  * Send ARP probes for active-backup mode ARP monitor.
- *
- * Called with rcu_read_lock hold.
  */
-static void bond_ab_arp_probe(struct bonding *bond)
+static bool bond_ab_arp_probe(struct bonding *bond)
 {
        struct slave *slave, *before = NULL, *new_slave = NULL,
-                    *curr_arp_slave = rcu_dereference(bond->current_arp_slave);
+                    *curr_arp_slave, *curr_active_slave;
        struct list_head *iter;
        bool found = false;
 
-       read_lock(&bond->curr_slave_lock);
+       rcu_read_lock();
+       curr_arp_slave = rcu_dereference(bond->current_arp_slave);
+       curr_active_slave = rcu_dereference(bond->curr_active_slave);
 
-       if (curr_arp_slave && bond->curr_active_slave)
+       if (curr_arp_slave && curr_active_slave)
                pr_info("PROBE: c_arp %s && cas %s BAD\n",
                        curr_arp_slave->dev->name,
-                       bond->curr_active_slave->dev->name);
+                       curr_active_slave->dev->name);
 
-       if (bond->curr_active_slave) {
-               bond_arp_send_all(bond, bond->curr_active_slave);
-               read_unlock(&bond->curr_slave_lock);
-               return;
+       if (curr_active_slave) {
+               bond_arp_send_all(bond, curr_active_slave);
+               rcu_read_unlock();
+               return true;
        }
-
-       read_unlock(&bond->curr_slave_lock);
+       rcu_read_unlock();
 
        /* if we don't have a curr_active_slave, search for the next available
         * backup slave from the current_arp_slave and make it the candidate
         * for becoming the curr_active_slave
         */
 
+       if (!rtnl_trylock())
+               return false;
+       /* curr_arp_slave might have gone away */
+       curr_arp_slave = ACCESS_ONCE(bond->current_arp_slave);
+
        if (!curr_arp_slave) {
-               curr_arp_slave = bond_first_slave_rcu(bond);
-               if (!curr_arp_slave)
-                       return;
+               curr_arp_slave = bond_first_slave(bond);
+               if (!curr_arp_slave) {
+                       rtnl_unlock();
+                       return true;
+               }
        }
 
        bond_set_slave_inactive_flags(curr_arp_slave);
 
-       bond_for_each_slave_rcu(bond, slave, iter) {
+       bond_for_each_slave(bond, slave, iter) {
                if (!found && !before && IS_UP(slave->dev))
                        before = slave;
 
@@ -2667,21 +2678,26 @@ static void bond_ab_arp_probe(struct bonding *bond)
        if (!new_slave && before)
                new_slave = before;
 
-       if (!new_slave)
-               return;
+       if (!new_slave) {
+               rtnl_unlock();
+               return true;
+       }
 
        new_slave->link = BOND_LINK_BACK;
        bond_set_slave_active_flags(new_slave);
        bond_arp_send_all(bond, new_slave);
        new_slave->jiffies = jiffies;
        rcu_assign_pointer(bond->current_arp_slave, new_slave);
+       rtnl_unlock();
+
+       return true;
 }
 
 static void bond_activebackup_arp_mon(struct work_struct *work)
 {
        struct bonding *bond = container_of(work, struct bonding,
                                            arp_work.work);
-       bool should_notify_peers = false;
+       bool should_notify_peers = false, should_commit = false;
        int delta_in_ticks;
 
        delta_in_ticks = msecs_to_jiffies(bond->params.arp_interval);
@@ -2690,12 +2706,11 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
                goto re_arm;
 
        rcu_read_lock();
-
        should_notify_peers = bond_should_notify_peers(bond);
+       should_commit = bond_ab_arp_inspect(bond);
+       rcu_read_unlock();
 
-       if (bond_ab_arp_inspect(bond)) {
-               rcu_read_unlock();
-
+       if (should_commit) {
                /* Race avoidance with bond_close flush of workqueue */
                if (!rtnl_trylock()) {
                        delta_in_ticks = 1;
@@ -2704,13 +2719,14 @@ static void bond_activebackup_arp_mon(struct work_struct *work)
                }
 
                bond_ab_arp_commit(bond);
-
                rtnl_unlock();
-               rcu_read_lock();
        }
 
-       bond_ab_arp_probe(bond);
-       rcu_read_unlock();
+       if (!bond_ab_arp_probe(bond)) {
+               /* rtnl locking failed, re-arm */
+               delta_in_ticks = 1;
+               should_notify_peers = false;
+       }
 
 re_arm:
        if (bond->params.arp_interval)
index 1a9062f4e0d6d4429d6cfb230867905b446615c5..86ccfb9f71cc4dd8c843f40f5eee38b7c0c033ab 100644 (file)
@@ -303,6 +303,19 @@ static inline void bond_set_backup_slave(struct slave *slave)
        }
 }
 
+static inline void bond_slave_state_change(struct bonding *bond)
+{
+       struct list_head *iter;
+       struct slave *tmp;
+
+       bond_for_each_slave(bond, tmp, iter) {
+               if (tmp->link == BOND_LINK_UP)
+                       bond_set_active_slave(tmp);
+               else if (tmp->link == BOND_LINK_DOWN)
+                       bond_set_backup_slave(tmp);
+       }
+}
+
 static inline int bond_slave_state(struct slave *slave)
 {
        return slave->backup;
index 035e235e31186ecc629ce4903f771fe40799f1b1..44725296f72a25b07d21bb92f9af1f0534980bc5 100644 (file)
@@ -108,135 +108,170 @@ static u32 mpc52xx_can_get_clock(struct platform_device *ofdev,
 #endif /* CONFIG_PPC_MPC52xx */
 
 #ifdef CONFIG_PPC_MPC512x
-struct mpc512x_clockctl {
-       u32 spmr;               /* System PLL Mode Reg */
-       u32 sccr[2];            /* System Clk Ctrl Reg 1 & 2 */
-       u32 scfr1;              /* System Clk Freq Reg 1 */
-       u32 scfr2;              /* System Clk Freq Reg 2 */
-       u32 reserved;
-       u32 bcr;                /* Bread Crumb Reg */
-       u32 pccr[12];           /* PSC Clk Ctrl Reg 0-11 */
-       u32 spccr;              /* SPDIF Clk Ctrl Reg */
-       u32 cccr;               /* CFM Clk Ctrl Reg */
-       u32 dccr;               /* DIU Clk Cnfg Reg */
-       u32 mccr[4];            /* MSCAN Clk Ctrl Reg 1-3 */
-};
-
-static struct of_device_id mpc512x_clock_ids[] = {
-       { .compatible = "fsl,mpc5121-clock", },
-       {}
-};
-
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
-                                const char *clock_name, int *mscan_clksrc)
+                                const char *clock_source, int *mscan_clksrc)
 {
-       struct mpc512x_clockctl __iomem *clockctl;
-       struct device_node *np_clock;
-       struct clk *sys_clk, *ref_clk;
-       int plen, clockidx, clocksrc = -1;
-       u32 sys_freq, val, clockdiv = 1, freq = 0;
-       const u32 *pval;
-
-       np_clock = of_find_matching_node(NULL, mpc512x_clock_ids);
-       if (!np_clock) {
-               dev_err(&ofdev->dev, "couldn't find clock node\n");
-               return 0;
-       }
-       clockctl = of_iomap(np_clock, 0);
-       if (!clockctl) {
-               dev_err(&ofdev->dev, "couldn't map clock registers\n");
-               goto exit_put;
-       }
+       struct device_node *np;
+       u32 clockdiv;
+       enum {
+               CLK_FROM_AUTO,
+               CLK_FROM_IPS,
+               CLK_FROM_SYS,
+               CLK_FROM_REF,
+       } clk_from;
+       struct clk *clk_in, *clk_can;
+       unsigned long freq_calc;
+       struct mscan_priv *priv;
+       struct clk *clk_ipg;
 
-       /* Determine the MSCAN device index from the peripheral's
-        * physical address. Register address offsets against the
-        * IMMR base are:  0x1300, 0x1380, 0x2300, 0x2380
+       /* the caller passed in the clock source spec that was read from
+        * the device tree, get the optional clock divider as well
         */
-       pval = of_get_property(ofdev->dev.of_node, "reg", &plen);
-       BUG_ON(!pval || plen < sizeof(*pval));
-       clockidx = (*pval & 0x80) ? 1 : 0;
-       if (*pval & 0x2000)
-               clockidx += 2;
+       np = ofdev->dev.of_node;
+       clockdiv = 1;
+       of_property_read_u32(np, "fsl,mscan-clock-divider", &clockdiv);
+       dev_dbg(&ofdev->dev, "device tree specs: clk src[%s] div[%d]\n",
+               clock_source ? clock_source : "<NULL>", clockdiv);
+
+       /* when clock-source is 'ip', the CANCTL1[CLKSRC] bit needs to
+        * get set, and the 'ips' clock is the input to the MSCAN
+        * component
+        *
+        * for clock-source values of 'ref' or 'sys' the CANCTL1[CLKSRC]
+        * bit needs to get cleared, an optional clock-divider may have
+        * been specified (the default value is 1), the appropriate
+        * MSCAN related MCLK is the input to the MSCAN component
+        *
+        * in the absence of a clock-source spec, first an optimal clock
+        * gets determined based on the 'sys' clock, if that fails the
+        * 'ref' clock is used
+        */
+       clk_from = CLK_FROM_AUTO;
+       if (clock_source) {
+               /* interpret the device tree's spec for the clock source */
+               if (!strcmp(clock_source, "ip"))
+                       clk_from = CLK_FROM_IPS;
+               else if (!strcmp(clock_source, "sys"))
+                       clk_from = CLK_FROM_SYS;
+               else if (!strcmp(clock_source, "ref"))
+                       clk_from = CLK_FROM_REF;
+               else
+                       goto err_invalid;
+               dev_dbg(&ofdev->dev, "got a clk source spec[%d]\n", clk_from);
+       }
+       if (clk_from == CLK_FROM_AUTO) {
+               /* no spec so far, try the 'sys' clock; round to the
+                * next MHz and see if we can get a multiple of 16MHz
+                */
+               dev_dbg(&ofdev->dev, "no clk source spec, trying SYS\n");
+               clk_in = devm_clk_get(&ofdev->dev, "sys");
+               if (IS_ERR(clk_in))
+                       goto err_notavail;
+               freq_calc = clk_get_rate(clk_in);
+               freq_calc +=  499999;
+               freq_calc /= 1000000;
+               freq_calc *= 1000000;
+               if ((freq_calc % 16000000) == 0) {
+                       clk_from = CLK_FROM_SYS;
+                       clockdiv = freq_calc / 16000000;
+                       dev_dbg(&ofdev->dev,
+                               "clk fit, sys[%lu] div[%d] freq[%lu]\n",
+                               freq_calc, clockdiv, freq_calc / clockdiv);
+               }
+       }
+       if (clk_from == CLK_FROM_AUTO) {
+               /* no spec so far, use the 'ref' clock */
+               dev_dbg(&ofdev->dev, "no clk source spec, trying REF\n");
+               clk_in = devm_clk_get(&ofdev->dev, "ref");
+               if (IS_ERR(clk_in))
+                       goto err_notavail;
+               clk_from = CLK_FROM_REF;
+               freq_calc = clk_get_rate(clk_in);
+               dev_dbg(&ofdev->dev,
+                       "clk fit, ref[%lu] (no div) freq[%lu]\n",
+                       freq_calc, freq_calc);
+       }
 
-       /*
-        * Clock source and divider selection: 3 different clock sources
-        * can be selected: "ip", "ref" or "sys". For the latter two, a
-        * clock divider can be defined as well. If the clock source is
-        * not specified by the device tree, we first try to find an
-        * optimal CAN source clock based on the system clock. If that
-        * is not posslible, the reference clock will be used.
+       /* select IPS or MCLK as the MSCAN input (returned to the caller),
+        * setup the MCLK mux source and rate if applicable, apply the
+        * optionally specified or derived above divider, and determine
+        * the actual resulting clock rate to return to the caller
         */
-       if (clock_name && !strcmp(clock_name, "ip")) {
+       switch (clk_from) {
+       case CLK_FROM_IPS:
+               clk_can = devm_clk_get(&ofdev->dev, "ips");
+               if (IS_ERR(clk_can))
+                       goto err_notavail;
+               priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+               priv->clk_can = clk_can;
+               freq_calc = clk_get_rate(clk_can);
                *mscan_clksrc = MSCAN_CLKSRC_IPS;
-               freq = mpc5xxx_get_bus_frequency(ofdev->dev.of_node);
-       } else {
+               dev_dbg(&ofdev->dev, "clk from IPS, clksrc[%d] freq[%lu]\n",
+                       *mscan_clksrc, freq_calc);
+               break;
+       case CLK_FROM_SYS:
+       case CLK_FROM_REF:
+               clk_can = devm_clk_get(&ofdev->dev, "mclk");
+               if (IS_ERR(clk_can))
+                       goto err_notavail;
+               priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+               priv->clk_can = clk_can;
+               if (clk_from == CLK_FROM_SYS)
+                       clk_in = devm_clk_get(&ofdev->dev, "sys");
+               if (clk_from == CLK_FROM_REF)
+                       clk_in = devm_clk_get(&ofdev->dev, "ref");
+               if (IS_ERR(clk_in))
+                       goto err_notavail;
+               clk_set_parent(clk_can, clk_in);
+               freq_calc = clk_get_rate(clk_in);
+               freq_calc /= clockdiv;
+               clk_set_rate(clk_can, freq_calc);
+               freq_calc = clk_get_rate(clk_can);
                *mscan_clksrc = MSCAN_CLKSRC_BUS;
-
-               pval = of_get_property(ofdev->dev.of_node,
-                                      "fsl,mscan-clock-divider", &plen);
-               if (pval && plen == sizeof(*pval))
-                       clockdiv = *pval;
-               if (!clockdiv)
-                       clockdiv = 1;
-
-               if (!clock_name || !strcmp(clock_name, "sys")) {
-                       sys_clk = devm_clk_get(&ofdev->dev, "sys_clk");
-                       if (IS_ERR(sys_clk)) {
-                               dev_err(&ofdev->dev, "couldn't get sys_clk\n");
-                               goto exit_unmap;
-                       }
-                       /* Get and round up/down sys clock rate */
-                       sys_freq = 1000000 *
-                               ((clk_get_rate(sys_clk) + 499999) / 1000000);
-
-                       if (!clock_name) {
-                               /* A multiple of 16 MHz would be optimal */
-                               if ((sys_freq % 16000000) == 0) {
-                                       clocksrc = 0;
-                                       clockdiv = sys_freq / 16000000;
-                                       freq = sys_freq / clockdiv;
-                               }
-                       } else {
-                               clocksrc = 0;
-                               freq = sys_freq / clockdiv;
-                       }
-               }
-
-               if (clocksrc < 0) {
-                       ref_clk = devm_clk_get(&ofdev->dev, "ref_clk");
-                       if (IS_ERR(ref_clk)) {
-                               dev_err(&ofdev->dev, "couldn't get ref_clk\n");
-                               goto exit_unmap;
-                       }
-                       clocksrc = 1;
-                       freq = clk_get_rate(ref_clk) / clockdiv;
-               }
+               dev_dbg(&ofdev->dev, "clk from MCLK, clksrc[%d] freq[%lu]\n",
+                       *mscan_clksrc, freq_calc);
+               break;
+       default:
+               goto err_invalid;
        }
 
-       /* Disable clock */
-       out_be32(&clockctl->mccr[clockidx], 0x0);
-       if (clocksrc >= 0) {
-               /* Set source and divider */
-               val = (clocksrc << 14) | ((clockdiv - 1) << 17);
-               out_be32(&clockctl->mccr[clockidx], val);
-               /* Enable clock */
-               out_be32(&clockctl->mccr[clockidx], val | 0x10000);
-       }
+       /* the above clk_can item is used for the bitrate, access to
+        * the peripheral's register set needs the clk_ipg item
+        */
+       clk_ipg = devm_clk_get(&ofdev->dev, "ipg");
+       if (IS_ERR(clk_ipg))
+               goto err_notavail_ipg;
+       if (clk_prepare_enable(clk_ipg))
+               goto err_notavail_ipg;
+       priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+       priv->clk_ipg = clk_ipg;
+
+       /* return the determined clock source rate */
+       return freq_calc;
+
+err_invalid:
+       dev_err(&ofdev->dev, "invalid clock source specification\n");
+       /* clock source rate could not get determined */
+       return 0;
 
-       /* Enable MSCAN clock domain */
-       val = in_be32(&clockctl->sccr[1]);
-       if (!(val & (1 << 25)))
-               out_be32(&clockctl->sccr[1], val | (1 << 25));
+err_notavail:
+       dev_err(&ofdev->dev, "cannot acquire or setup bitrate clock source\n");
+       /* clock source rate could not get determined */
+       return 0;
 
-       dev_dbg(&ofdev->dev, "using '%s' with frequency divider %d\n",
-               *mscan_clksrc == MSCAN_CLKSRC_IPS ? "ips_clk" :
-               clocksrc == 1 ? "ref_clk" : "sys_clk", clockdiv);
+err_notavail_ipg:
+       dev_err(&ofdev->dev, "cannot acquire or setup register clock\n");
+       /* clock source rate could not get determined */
+       return 0;
+}
 
-exit_unmap:
-       iounmap(clockctl);
-exit_put:
-       of_node_put(np_clock);
-       return freq;
+static void mpc512x_can_put_clock(struct platform_device *ofdev)
+{
+       struct mscan_priv *priv;
+
+       priv = netdev_priv(dev_get_drvdata(&ofdev->dev));
+       if (priv->clk_ipg)
+               clk_disable_unprepare(priv->clk_ipg);
 }
 #else /* !CONFIG_PPC_MPC512x */
 static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
@@ -244,6 +279,7 @@ static u32 mpc512x_can_get_clock(struct platform_device *ofdev,
 {
        return 0;
 }
+#define mpc512x_can_put_clock NULL
 #endif /* CONFIG_PPC_MPC512x */
 
 static const struct of_device_id mpc5xxx_can_table[];
@@ -385,11 +421,13 @@ static int mpc5xxx_can_resume(struct platform_device *ofdev)
 static const struct mpc5xxx_can_data mpc5200_can_data = {
        .type = MSCAN_TYPE_MPC5200,
        .get_clock = mpc52xx_can_get_clock,
+       /* .put_clock not applicable */
 };
 
 static const struct mpc5xxx_can_data mpc5121_can_data = {
        .type = MSCAN_TYPE_MPC5121,
        .get_clock = mpc512x_can_get_clock,
+       .put_clock = mpc512x_can_put_clock,
 };
 
 static const struct of_device_id mpc5xxx_can_table[] = {
index 811fa5d5c6971c0a71f55d12e420fb38691bb9f7..30104b60da85a2df50259d0216991d0004e06069 100644 (file)
@@ -212,7 +212,6 @@ static int __init apne_probe1(struct net_device *dev, int ioaddr)
     int neX000, ctron;
 #endif
     static unsigned version_printed;
-    struct ei_device *ei_local = netdev_priv(dev);
 
     if ((apne_msg_enable & NETIF_MSG_DRV) && (version_printed++ == 0))
                netdev_info(dev, version);
index 92a467ff4104da3bedd8aa6762c51c19ea977a22..38fc794c1655d9d011d425ccce35cfa41ee43889 100644 (file)
@@ -358,49 +358,47 @@ static int bnx2x_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 
        cfg_idx = bnx2x_get_link_cfg_idx(bp);
        old_multi_phy_config = bp->link_params.multi_phy_config;
-       switch (cmd->port) {
-       case PORT_TP:
-               if (bp->port.supported[cfg_idx] & SUPPORTED_TP)
-                       break; /* no port change */
-
-               if (!(bp->port.supported[0] & SUPPORTED_TP ||
-                     bp->port.supported[1] & SUPPORTED_TP)) {
-                       DP(BNX2X_MSG_ETHTOOL, "Unsupported port type\n");
-                       return -EINVAL;
-               }
-               bp->link_params.multi_phy_config &=
-                       ~PORT_HW_CFG_PHY_SELECTION_MASK;
-               if (bp->link_params.multi_phy_config &
-                   PORT_HW_CFG_PHY_SWAPPED_ENABLED)
-                       bp->link_params.multi_phy_config |=
-                       PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
-               else
-                       bp->link_params.multi_phy_config |=
-                       PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
-               break;
-       case PORT_FIBRE:
-       case PORT_DA:
-               if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE)
-                       break; /* no port change */
-
-               if (!(bp->port.supported[0] & SUPPORTED_FIBRE ||
-                     bp->port.supported[1] & SUPPORTED_FIBRE)) {
+       if (cmd->port != bnx2x_get_port_type(bp)) {
+               switch (cmd->port) {
+               case PORT_TP:
+                       if (!(bp->port.supported[0] & SUPPORTED_TP ||
+                             bp->port.supported[1] & SUPPORTED_TP)) {
+                               DP(BNX2X_MSG_ETHTOOL,
+                                  "Unsupported port type\n");
+                               return -EINVAL;
+                       }
+                       bp->link_params.multi_phy_config &=
+                               ~PORT_HW_CFG_PHY_SELECTION_MASK;
+                       if (bp->link_params.multi_phy_config &
+                           PORT_HW_CFG_PHY_SWAPPED_ENABLED)
+                               bp->link_params.multi_phy_config |=
+                               PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
+                       else
+                               bp->link_params.multi_phy_config |=
+                               PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
+                       break;
+               case PORT_FIBRE:
+               case PORT_DA:
+                       if (!(bp->port.supported[0] & SUPPORTED_FIBRE ||
+                             bp->port.supported[1] & SUPPORTED_FIBRE)) {
+                               DP(BNX2X_MSG_ETHTOOL,
+                                  "Unsupported port type\n");
+                               return -EINVAL;
+                       }
+                       bp->link_params.multi_phy_config &=
+                               ~PORT_HW_CFG_PHY_SELECTION_MASK;
+                       if (bp->link_params.multi_phy_config &
+                           PORT_HW_CFG_PHY_SWAPPED_ENABLED)
+                               bp->link_params.multi_phy_config |=
+                               PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
+                       else
+                               bp->link_params.multi_phy_config |=
+                               PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
+                       break;
+               default:
                        DP(BNX2X_MSG_ETHTOOL, "Unsupported port type\n");
                        return -EINVAL;
                }
-               bp->link_params.multi_phy_config &=
-                       ~PORT_HW_CFG_PHY_SELECTION_MASK;
-               if (bp->link_params.multi_phy_config &
-                   PORT_HW_CFG_PHY_SWAPPED_ENABLED)
-                       bp->link_params.multi_phy_config |=
-                       PORT_HW_CFG_PHY_SELECTION_FIRST_PHY;
-               else
-                       bp->link_params.multi_phy_config |=
-                       PORT_HW_CFG_PHY_SELECTION_SECOND_PHY;
-               break;
-       default:
-               DP(BNX2X_MSG_ETHTOOL, "Unsupported port type\n");
-               return -EINVAL;
        }
        /* Save new config in case command complete successfully */
        new_multi_phy_config = bp->link_params.multi_phy_config;
index e118a3ec62bc263fcf380aa9832c7b251bf59460..c9c445e7b4a5ab0d756880926fc529ed538a70a6 100644 (file)
@@ -13102,9 +13102,9 @@ static void __bnx2x_remove(struct pci_dev *pdev,
 
                if (atomic_read(&pdev->enable_cnt) == 1)
                        pci_release_regions(pdev);
-       }
 
-       pci_disable_device(pdev);
+               pci_disable_device(pdev);
+       }
 }
 
 static void bnx2x_remove_one(struct pci_dev *pdev)
index cde0fd941f0ce6bbb8364f268a141cc1917d8e41..4be9715904616b3f9c1ff2a3bc38d55b58135e58 100644 (file)
@@ -1275,18 +1275,21 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
 {
        struct net_device *netdev = dev_get_drvdata(&vdev->dev);
        struct ibmveth_adapter *adapter;
+       struct iommu_table *tbl;
        unsigned long ret;
        int i;
        int rxqentries = 1;
 
+       tbl = get_iommu_table_base(&vdev->dev);
+
        /* netdev inits at probe time along with the structures we need below*/
        if (netdev == NULL)
-               return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT);
+               return IOMMU_PAGE_ALIGN(IBMVETH_IO_ENTITLEMENT_DEFAULT, tbl);
 
        adapter = netdev_priv(netdev);
 
        ret = IBMVETH_BUFF_LIST_SIZE + IBMVETH_FILT_LIST_SIZE;
-       ret += IOMMU_PAGE_ALIGN(netdev->mtu);
+       ret += IOMMU_PAGE_ALIGN(netdev->mtu, tbl);
 
        for (i = 0; i < IBMVETH_NUM_BUFF_POOLS; i++) {
                /* add the size of the active receive buffers */
@@ -1294,11 +1297,12 @@ static unsigned long ibmveth_get_desired_dma(struct vio_dev *vdev)
                        ret +=
                            adapter->rx_buff_pool[i].size *
                            IOMMU_PAGE_ALIGN(adapter->rx_buff_pool[i].
-                                   buff_size);
+                                            buff_size, tbl);
                rxqentries += adapter->rx_buff_pool[i].size;
        }
        /* add the size of the receive queue entries */
-       ret += IOMMU_PAGE_ALIGN(rxqentries * sizeof(struct ibmveth_rx_q_entry));
+       ret += IOMMU_PAGE_ALIGN(
+               rxqentries * sizeof(struct ibmveth_rx_q_entry), tbl);
 
        return ret;
 }
index a4b940862b83b49b392d23bffb2b0d0f922d2af0..b901371ca361a1e6eafa411f5b144f6e8866aa9c 100644 (file)
@@ -4440,9 +4440,10 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
        /* Check if APP Table has changed */
        if (memcmp(&new_cfg->app,
                   &old_cfg->app,
-                  sizeof(new_cfg->app)))
+                  sizeof(new_cfg->app))) {
                need_reconfig = true;
                dev_info(&pf->pdev->dev, "APP Table change detected.\n");
+       }
 
        return need_reconfig;
 }
index 6509935d145e8930ad7594b0583f31e872a4aa69..55a37ae11440791d78e5dd69bf486cb5b4f976f3 100644 (file)
@@ -5020,6 +5020,8 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                }
        }
 
+       netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT);
+
        err = register_netdev(dev);
        if (err) {
                dev_err(&pdev->dev, "cannot register net device\n");
@@ -5028,8 +5030,6 @@ static int sky2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
 
        netif_carrier_off(dev);
 
-       netif_napi_add(dev, &hw->napi, sky2_poll, NAPI_WEIGHT);
-
        sky2_show_addr(dev);
 
        if (hw->ports > 1) {
index 30874cda84764996735d2a070ab45516311e8def..54ebf300332a353246066e5cf62f1d097355e1e5 100644 (file)
@@ -683,12 +683,17 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
                adapter->ahw->linkup = 0;
                netif_carrier_off(netdev);
        } else if (!adapter->ahw->linkup && linkup) {
-               /* Do not advertise Link up if the port is in loopback mode */
-               if (qlcnic_83xx_check(adapter) && adapter->ahw->lb_mode)
+               adapter->ahw->linkup = 1;
+
+               /* Do not advertise Link up to the stack if device
+                * is in loopback mode
+                */
+               if (qlcnic_83xx_check(adapter) && adapter->ahw->lb_mode) {
+                       netdev_info(netdev, "NIC Link is up for loopback test\n");
                        return;
+               }
 
                netdev_info(netdev, "NIC Link is up\n");
-               adapter->ahw->linkup = 1;
                netif_carrier_on(netdev);
        }
 }
@@ -1150,13 +1155,13 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
        u16 lro_length, length, data_offset, t_vid, vid = 0xffff;
        u32 seq_number;
 
-       if (unlikely(ring > adapter->max_rds_rings))
+       if (unlikely(ring >= adapter->max_rds_rings))
                return NULL;
 
        rds_ring = &recv_ctx->rds_rings[ring];
 
        index = qlcnic_get_lro_sts_refhandle(sts_data0);
-       if (unlikely(index > rds_ring->num_desc))
+       if (unlikely(index >= rds_ring->num_desc))
                return NULL;
 
        buffer = &rds_ring->rx_buf_arr[index];
@@ -1662,13 +1667,13 @@ qlcnic_83xx_process_lro(struct qlcnic_adapter *adapter,
        u16 vid = 0xffff;
        int err;
 
-       if (unlikely(ring > adapter->max_rds_rings))
+       if (unlikely(ring >= adapter->max_rds_rings))
                return NULL;
 
        rds_ring = &recv_ctx->rds_rings[ring];
 
        index = qlcnic_83xx_hndl(sts_data[0]);
-       if (unlikely(index > rds_ring->num_desc))
+       if (unlikely(index >= rds_ring->num_desc))
                return NULL;
 
        buffer = &rds_ring->rx_buf_arr[index];
index 1f79d47c45fa3c9ec9b747958c71428cd0850ce5..ba78c7481fa3432f32fd7d5a5e7c56b66423b801 100644 (file)
@@ -1837,6 +1837,7 @@ int __qlcnic_up(struct qlcnic_adapter *adapter, struct net_device *netdev)
        qlcnic_linkevent_request(adapter, 1);
 
        adapter->ahw->reset_context = 0;
+       netif_tx_start_all_queues(netdev);
        return 0;
 }
 
@@ -2704,14 +2705,8 @@ static int qlcnic_open(struct net_device *netdev)
 
        err = __qlcnic_up(adapter, netdev);
        if (err)
-               goto err_out;
-
-       netif_tx_start_all_queues(netdev);
-
-       return 0;
+               qlcnic_detach(adapter);
 
-err_out:
-       qlcnic_detach(adapter);
        return err;
 }
 
index 17a1ca2050f4eaa9f47f9394d43849ba6f97cfba..0638c1810d54547df9eafb961439085dff4364a2 100644 (file)
@@ -448,8 +448,7 @@ static int qlcnic_sriov_set_guest_vlan_mode(struct qlcnic_adapter *adapter,
        return 0;
 }
 
-static int qlcnic_sriov_get_vf_acl(struct qlcnic_adapter *adapter,
-                                  struct qlcnic_info *info)
+static int qlcnic_sriov_get_vf_acl(struct qlcnic_adapter *adapter)
 {
        struct qlcnic_sriov *sriov = adapter->ahw->sriov;
        struct qlcnic_cmd_args cmd;
@@ -495,10 +494,6 @@ static int qlcnic_sriov_vf_init_driver(struct qlcnic_adapter *adapter)
        if (err)
                return -EIO;
 
-       err = qlcnic_sriov_get_vf_acl(adapter, &nic_info);
-       if (err)
-               return err;
-
        if (qlcnic_83xx_get_port_info(adapter))
                return -EIO;
 
@@ -555,6 +550,10 @@ static int qlcnic_sriov_setup_vf(struct qlcnic_adapter *adapter,
        if (err)
                goto err_out_send_channel_term;
 
+       err = qlcnic_sriov_get_vf_acl(adapter);
+       if (err)
+               goto err_out_send_channel_term;
+
        err = qlcnic_setup_netdev(adapter, adapter->netdev, pci_using_dac);
        if (err)
                goto err_out_send_channel_term;
index d93aa87408c222760cc0ce3c40030917051b7b0c..a2e7d2c96e3678c309377d3e4dbb416feb5fbc38 100644 (file)
@@ -1524,9 +1524,9 @@ static void stmmac_check_ether_addr(struct stmmac_priv *priv)
                                             priv->dev->dev_addr, 0);
                if (!is_valid_ether_addr(priv->dev->dev_addr))
                        eth_hw_addr_random(priv->dev);
+               pr_info("%s: device MAC address %pM\n", priv->dev->name,
+                       priv->dev->dev_addr);
        }
-       pr_warn("%s: device MAC address %pM\n", priv->dev->name,
-               priv->dev->dev_addr);
 }
 
 /**
@@ -1635,7 +1635,7 @@ static int stmmac_hw_setup(struct net_device *dev)
        stmmac_mmc_setup(priv);
 
        ret = stmmac_init_ptp(priv);
-       if (ret)
+       if (ret && ret != -EOPNOTSUPP)
                pr_warn("%s: failed PTP initialisation\n", __func__);
 
 #ifdef CONFIG_STMMAC_DEBUG_FS
index a26eecb1212ce735a2de234e31a12ae9a4e90b37..7b594ce3f21db2102139e8802d4d9e69bb61a3e8 100644 (file)
@@ -462,7 +462,7 @@ struct nvsp_message {
 
 #define NETVSC_MTU 65536
 
-#define NETVSC_RECEIVE_BUFFER_SIZE             (1024*1024*2)   /* 2MB */
+#define NETVSC_RECEIVE_BUFFER_SIZE             (1024*1024*16)  /* 16MB */
 
 #define NETVSC_RECEIVE_BUFFER_ID               0xcafe
 
index 93b485b96249b32347586f6494b7e1d15ab3cc2a..03a2c6e171584ff5f639d686458fbb75b7dcfb47 100644 (file)
@@ -136,8 +136,7 @@ static int netvsc_destroy_recv_buf(struct netvsc_device *net_device)
 
        if (net_device->recv_buf) {
                /* Free up the receive buffer */
-               free_pages((unsigned long)net_device->recv_buf,
-                       get_order(net_device->recv_buf_size));
+               vfree(net_device->recv_buf);
                net_device->recv_buf = NULL;
        }
 
@@ -163,9 +162,7 @@ static int netvsc_init_recv_buf(struct hv_device *device)
                return -ENODEV;
        ndev = net_device->ndev;
 
-       net_device->recv_buf =
-               (void *)__get_free_pages(GFP_KERNEL|__GFP_ZERO,
-                               get_order(net_device->recv_buf_size));
+       net_device->recv_buf = vzalloc(net_device->recv_buf_size);
        if (!net_device->recv_buf) {
                netdev_err(ndev, "unable to allocate receive "
                        "buffer of size %d\n", net_device->recv_buf_size);
index 930694d3a13f7e7568fab6997ccdcd0ecabbb063..71e49000fbf33fc50d08e3c6979014c89fdb4478 100644 (file)
@@ -150,6 +150,7 @@ int mdiobus_register(struct mii_bus *bus)
        err = device_register(&bus->dev);
        if (err) {
                pr_err("mii_bus %s failed to register\n", bus->id);
+               put_device(&bus->dev);
                return -EINVAL;
        }
 
index bcf01af4b879252dbe5d6339dd7134cb848280f4..44c4db8450f0347b4ea6ce861da7f05524ebdb5d 100644 (file)
@@ -69,6 +69,7 @@
 #include <net/netns/generic.h>
 #include <net/rtnetlink.h>
 #include <net/sock.h>
+#include <linux/seq_file.h>
 
 #include <asm/uaccess.h>
 
@@ -2228,6 +2229,27 @@ static int tun_chr_close(struct inode *inode, struct file *file)
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
+static int tun_chr_show_fdinfo(struct seq_file *m, struct file *f)
+{
+       struct tun_struct *tun;
+       struct ifreq ifr;
+
+       memset(&ifr, 0, sizeof(ifr));
+
+       rtnl_lock();
+       tun = tun_get(f);
+       if (tun)
+               tun_get_iff(current->nsproxy->net_ns, tun, &ifr);
+       rtnl_unlock();
+
+       if (tun)
+               tun_put(tun);
+
+       return seq_printf(m, "iff:\t%s\n", ifr.ifr_name);
+}
+#endif
+
 static const struct file_operations tun_fops = {
        .owner  = THIS_MODULE,
        .llseek = no_llseek,
@@ -2242,7 +2264,10 @@ static const struct file_operations tun_fops = {
 #endif
        .open   = tun_chr_open,
        .release = tun_chr_close,
-       .fasync = tun_chr_fasync
+       .fasync = tun_chr_fasync,
+#ifdef CONFIG_PROC_FS
+       .show_fdinfo = tun_chr_show_fdinfo,
+#endif
 };
 
 static struct miscdevice tun_miscdev = {
index e955c569298626c924f6cec16c3d32de8bec54d6..ff04d4f95baa3561fbf42899bf95f69eab28412f 100644 (file)
@@ -117,6 +117,7 @@ struct netfront_info {
        } tx_skbs[NET_TX_RING_SIZE];
        grant_ref_t gref_tx_head;
        grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
+       struct page *grant_tx_page[NET_TX_RING_SIZE];
        unsigned tx_skb_freelist;
 
        spinlock_t   rx_lock ____cacheline_aligned_in_smp;
@@ -396,6 +397,7 @@ static void xennet_tx_buf_gc(struct net_device *dev)
                        gnttab_release_grant_reference(
                                &np->gref_tx_head, np->grant_tx_ref[id]);
                        np->grant_tx_ref[id] = GRANT_INVALID_REF;
+                       np->grant_tx_page[id] = NULL;
                        add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id);
                        dev_kfree_skb_irq(skb);
                }
@@ -452,6 +454,7 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
                gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
                                                mfn, GNTMAP_readonly);
 
+               np->grant_tx_page[id] = virt_to_page(data);
                tx->gref = np->grant_tx_ref[id] = ref;
                tx->offset = offset;
                tx->size = len;
@@ -497,6 +500,7 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
                                                        np->xbdev->otherend_id,
                                                        mfn, GNTMAP_readonly);
 
+                       np->grant_tx_page[id] = page;
                        tx->gref = np->grant_tx_ref[id] = ref;
                        tx->offset = offset;
                        tx->size = bytes;
@@ -596,6 +600,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
        mfn = virt_to_mfn(data);
        gnttab_grant_foreign_access_ref(
                ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly);
+       np->grant_tx_page[id] = virt_to_page(data);
        tx->gref = np->grant_tx_ref[id] = ref;
        tx->offset = offset;
        tx->size = len;
@@ -1085,10 +1090,11 @@ static void xennet_release_tx_bufs(struct netfront_info *np)
                        continue;
 
                skb = np->tx_skbs[i].skb;
-               gnttab_end_foreign_access_ref(np->grant_tx_ref[i],
-                                             GNTMAP_readonly);
-               gnttab_release_grant_reference(&np->gref_tx_head,
-                                              np->grant_tx_ref[i]);
+               get_page(np->grant_tx_page[i]);
+               gnttab_end_foreign_access(np->grant_tx_ref[i],
+                                         GNTMAP_readonly,
+                                         (unsigned long)page_address(np->grant_tx_page[i]));
+               np->grant_tx_page[i] = NULL;
                np->grant_tx_ref[i] = GRANT_INVALID_REF;
                add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i);
                dev_kfree_skb_irq(skb);
@@ -1097,78 +1103,35 @@ static void xennet_release_tx_bufs(struct netfront_info *np)
 
 static void xennet_release_rx_bufs(struct netfront_info *np)
 {
-       struct mmu_update      *mmu = np->rx_mmu;
-       struct multicall_entry *mcl = np->rx_mcl;
-       struct sk_buff_head free_list;
-       struct sk_buff *skb;
-       unsigned long mfn;
-       int xfer = 0, noxfer = 0, unused = 0;
        int id, ref;
 
-       dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n",
-                        __func__);
-       return;
-
-       skb_queue_head_init(&free_list);
-
        spin_lock_bh(&np->rx_lock);
 
        for (id = 0; id < NET_RX_RING_SIZE; id++) {
-               ref = np->grant_rx_ref[id];
-               if (ref == GRANT_INVALID_REF) {
-                       unused++;
-                       continue;
-               }
+               struct sk_buff *skb;
+               struct page *page;
 
                skb = np->rx_skbs[id];
-               mfn = gnttab_end_foreign_transfer_ref(ref);
-               gnttab_release_grant_reference(&np->gref_rx_head, ref);
-               np->grant_rx_ref[id] = GRANT_INVALID_REF;
-
-               if (0 == mfn) {
-                       skb_shinfo(skb)->nr_frags = 0;
-                       dev_kfree_skb(skb);
-                       noxfer++;
+               if (!skb)
                        continue;
-               }
 
-               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-                       /* Remap the page. */
-                       const struct page *page =
-                               skb_frag_page(&skb_shinfo(skb)->frags[0]);
-                       unsigned long pfn = page_to_pfn(page);
-                       void *vaddr = page_address(page);
+               ref = np->grant_rx_ref[id];
+               if (ref == GRANT_INVALID_REF)
+                       continue;
 
-                       MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
-                                               mfn_pte(mfn, PAGE_KERNEL),
-                                               0);
-                       mcl++;
-                       mmu->ptr = ((u64)mfn << PAGE_SHIFT)
-                               | MMU_MACHPHYS_UPDATE;
-                       mmu->val = pfn;
-                       mmu++;
+               page = skb_frag_page(&skb_shinfo(skb)->frags[0]);
 
-                       set_phys_to_machine(pfn, mfn);
-               }
-               __skb_queue_tail(&free_list, skb);
-               xfer++;
-       }
-
-       dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n",
-                __func__, xfer, noxfer, unused);
+               /* gnttab_end_foreign_access() needs a page ref until
+                * foreign access is ended (which may be deferred).
+                */
+               get_page(page);
+               gnttab_end_foreign_access(ref, 0,
+                                         (unsigned long)page_address(page));
+               np->grant_rx_ref[id] = GRANT_INVALID_REF;
 
-       if (xfer) {
-               if (!xen_feature(XENFEAT_auto_translated_physmap)) {
-                       /* Do all the remapping work and M2P updates. */
-                       MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu,
-                                        NULL, DOMID_SELF);
-                       mcl++;
-                       HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
-               }
+               kfree_skb(skb);
        }
 
-       __skb_queue_purge(&free_list);
-
        spin_unlock_bh(&np->rx_lock);
 }
 
@@ -1339,6 +1302,7 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
        for (i = 0; i < NET_RX_RING_SIZE; i++) {
                np->rx_skbs[i] = NULL;
                np->grant_rx_ref[i] = GRANT_INVALID_REF;
+               np->grant_tx_page[i] = NULL;
        }
 
        /* A grant for every tx ring slot */
index 04796c056d1201d3334a0609b133fda1e15018c3..6e34498ec9f0269387c296e498174ccb29cbe3fb 100644 (file)
@@ -1208,18 +1208,6 @@ static void pci_release_capabilities(struct pci_dev *dev)
        pci_free_cap_save_buffers(dev);
 }
 
-static void pci_free_resources(struct pci_dev *dev)
-{
-       int i;
-
-       pci_cleanup_rom(dev);
-       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
-               struct resource *res = dev->resource + i;
-               if (res->parent)
-                       release_resource(res);
-       }
-}
-
 /**
  * pci_release_dev - free a pci device structure when all users of it are finished.
  * @dev: device that's been disconnected
@@ -1229,14 +1217,9 @@ static void pci_free_resources(struct pci_dev *dev)
  */
 static void pci_release_dev(struct device *dev)
 {
-       struct pci_dev *pci_dev = to_pci_dev(dev);
-
-       down_write(&pci_bus_sem);
-       list_del(&pci_dev->bus_list);
-       up_write(&pci_bus_sem);
-
-       pci_free_resources(pci_dev);
+       struct pci_dev *pci_dev;
 
+       pci_dev = to_pci_dev(dev);
        pci_release_capabilities(pci_dev);
        pci_release_of_node(pci_dev);
        pcibios_release_device(pci_dev);
index 4ff36bfa785e56f9561d1e45d5813e438f64a95e..8bd76c9ba21cf4e5c5a4b58cb40ccd990cfacc5e 100644 (file)
@@ -3,6 +3,18 @@
 #include <linux/pci-aspm.h>
 #include "pci.h"
 
+static void pci_free_resources(struct pci_dev *dev)
+{
+       int i;
+
+       pci_cleanup_rom(dev);
+       for (i = 0; i < PCI_NUM_RESOURCES; i++) {
+               struct resource *res = dev->resource + i;
+               if (res->parent)
+                       release_resource(res);
+       }
+}
+
 static void pci_stop_dev(struct pci_dev *dev)
 {
        pci_pme_active(dev, false);
@@ -25,6 +37,11 @@ static void pci_destroy_dev(struct pci_dev *dev)
 
        device_del(&dev->dev);
 
+       down_write(&pci_bus_sem);
+       list_del(&dev->bus_list);
+       up_write(&pci_bus_sem);
+
+       pci_free_resources(dev);
        put_device(&dev->dev);
 }
 
index b13303e75a34ea1b4f3d563eac5bb88b2c1d1a8d..440ed776efd4c97d015cd1ebef066d2a2f528719 100644 (file)
@@ -25,4 +25,18 @@ config CHROMEOS_LAPTOP
          If you have a supported Chromebook, choose Y or M here.
          The module will be called chromeos_laptop.
 
+config CHROMEOS_PSTORE
+       tristate "Chrome OS pstore support"
+       ---help---
+         This module instantiates the persistent storage on x86 ChromeOS
+         devices. It can be used to store away console logs and crash
+         information across reboots.
+
+         The range of memory used is 0xf00000-0x1000000, traditionally
+         the memory used to back VGA controller memory.
+
+         If you have a supported Chromebook, choose Y or M here.
+         The module will be called chromeos_pstore.
+
+
 endif # CHROMEOS_PLATFORMS
index 015e9195e2266a62838d6dde999bdd547610a807..2b860ca7450fd57bee3c70c82de4a24d53c480f0 100644 (file)
@@ -1,2 +1,3 @@
 
 obj-$(CONFIG_CHROMEOS_LAPTOP)  += chromeos_laptop.o
+obj-$(CONFIG_CHROMEOS_PSTORE)  += chromeos_pstore.o
index 3e5b4497a1d02010b4c63bdc939f67127bb19976..7f3aad0e115c49f4c2ea85c149dace0e901620ce 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/platform_device.h>
 
 #define ATMEL_TP_I2C_ADDR      0x4b
 #define ATMEL_TP_I2C_BL_ADDR   0x25
@@ -40,7 +41,7 @@ static struct i2c_client *als;
 static struct i2c_client *tp;
 static struct i2c_client *ts;
 
-const char *i2c_adapter_names[] = {
+static const char *i2c_adapter_names[] = {
        "SMBus I801 adapter",
        "i915 gmbus vga",
        "i915 gmbus panel",
@@ -53,20 +54,33 @@ enum i2c_adapter_type {
        I2C_ADAPTER_PANEL,
 };
 
-static struct i2c_board_info __initdata cyapa_device = {
+struct i2c_peripheral {
+       int (*add)(enum i2c_adapter_type type);
+       enum i2c_adapter_type type;
+};
+
+#define MAX_I2C_PERIPHERALS 3
+
+struct chromeos_laptop {
+       struct i2c_peripheral i2c_peripherals[MAX_I2C_PERIPHERALS];
+};
+
+static struct chromeos_laptop *cros_laptop;
+
+static struct i2c_board_info cyapa_device = {
        I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
        .flags          = I2C_CLIENT_WAKE,
 };
 
-static struct i2c_board_info __initdata isl_als_device = {
+static struct i2c_board_info isl_als_device = {
        I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
 };
 
-static struct i2c_board_info __initdata tsl2583_als_device = {
+static struct i2c_board_info tsl2583_als_device = {
        I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
 };
 
-static struct i2c_board_info __initdata tsl2563_als_device = {
+static struct i2c_board_info tsl2563_als_device = {
        I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
 };
 
@@ -89,7 +103,7 @@ static struct mxt_platform_data atmel_224s_tp_platform_data = {
        .config_length          = 0,
 };
 
-static struct i2c_board_info __initdata atmel_224s_tp_device = {
+static struct i2c_board_info atmel_224s_tp_device = {
        I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR),
        .platform_data = &atmel_224s_tp_platform_data,
        .flags          = I2C_CLIENT_WAKE,
@@ -110,13 +124,13 @@ static struct mxt_platform_data atmel_1664s_platform_data = {
        .config_length          = 0,
 };
 
-static struct i2c_board_info __initdata atmel_1664s_device = {
+static struct i2c_board_info atmel_1664s_device = {
        I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR),
        .platform_data = &atmel_1664s_platform_data,
        .flags          = I2C_CLIENT_WAKE,
 };
 
-static struct i2c_client __init *__add_probed_i2c_device(
+static struct i2c_client *__add_probed_i2c_device(
                const char *name,
                int bus,
                struct i2c_board_info *info,
@@ -169,7 +183,7 @@ static struct i2c_client __init *__add_probed_i2c_device(
        return client;
 }
 
-static int __init __find_i2c_adap(struct device *dev, void *data)
+static int __find_i2c_adap(struct device *dev, void *data)
 {
        const char *name = data;
        static const char *prefix = "i2c-";
@@ -180,7 +194,7 @@ static int __init __find_i2c_adap(struct device *dev, void *data)
        return (strncmp(adapter->name, name, strlen(name)) == 0);
 }
 
-static int __init find_i2c_adapter_num(enum i2c_adapter_type type)
+static int find_i2c_adapter_num(enum i2c_adapter_type type)
 {
        struct device *dev = NULL;
        struct i2c_adapter *adapter;
@@ -189,8 +203,9 @@ static int __init find_i2c_adapter_num(enum i2c_adapter_type type)
        dev = bus_find_device(&i2c_bus_type, NULL, (void *)name,
                              __find_i2c_adap);
        if (!dev) {
-               pr_err("%s: i2c adapter %s not found on system.\n", __func__,
-                      name);
+               /* Adapters may appear later. Deferred probing will retry */
+               pr_notice("%s: i2c adapter %s not found on system.\n", __func__,
+                         name);
                return -ENODEV;
        }
        adapter = to_i2c_adapter(dev);
@@ -205,7 +220,7 @@ static int __init find_i2c_adapter_num(enum i2c_adapter_type type)
  * Returns NULL if no devices found.
  * See Documentation/i2c/instantiating-devices for more information.
  */
-static __init struct i2c_client *add_probed_i2c_device(
+static struct i2c_client *add_probed_i2c_device(
                const char *name,
                enum i2c_adapter_type type,
                struct i2c_board_info *info,
@@ -222,7 +237,7 @@ static __init struct i2c_client *add_probed_i2c_device(
  * info->addr.
  * Returns NULL if no device found.
  */
-static __init struct i2c_client *add_i2c_device(const char *name,
+static struct i2c_client *add_i2c_device(const char *name,
                                                enum i2c_adapter_type type,
                                                struct i2c_board_info *info)
 {
@@ -233,161 +248,259 @@ static __init struct i2c_client *add_i2c_device(const char *name,
                                       addr_list);
 }
 
-
-static struct i2c_client __init *add_smbus_device(const char *name,
-                                                 struct i2c_board_info *info)
+static int setup_cyapa_tp(enum i2c_adapter_type type)
 {
-       return add_i2c_device(name, I2C_ADAPTER_SMBUS, info);
-}
+       if (tp)
+               return 0;
 
-static int __init setup_cyapa_smbus_tp(const struct dmi_system_id *id)
-{
-       /* add cyapa touchpad on smbus */
-       tp = add_smbus_device("trackpad", &cyapa_device);
-       return 0;
+       /* add cyapa touchpad */
+       tp = add_i2c_device("trackpad", type, &cyapa_device);
+       return (!tp) ? -EAGAIN : 0;
 }
 
-static int __init setup_atmel_224s_tp(const struct dmi_system_id *id)
+static int setup_atmel_224s_tp(enum i2c_adapter_type type)
 {
        const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR,
                                             ATMEL_TP_I2C_ADDR,
                                             I2C_CLIENT_END };
+       if (tp)
+               return 0;
 
-       /* add atmel mxt touchpad on VGA DDC GMBus */
-       tp = add_probed_i2c_device("trackpad", I2C_ADAPTER_VGADDC,
+       /* add atmel mxt touchpad */
+       tp = add_probed_i2c_device("trackpad", type,
                                   &atmel_224s_tp_device, addr_list);
-       return 0;
+       return (!tp) ? -EAGAIN : 0;
 }
 
-static int __init setup_atmel_1664s_ts(const struct dmi_system_id *id)
+static int setup_atmel_1664s_ts(enum i2c_adapter_type type)
 {
        const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR,
                                             ATMEL_TS_I2C_ADDR,
                                             I2C_CLIENT_END };
+       if (ts)
+               return 0;
 
-       /* add atmel mxt touch device on PANEL GMBus */
-       ts = add_probed_i2c_device("touchscreen", I2C_ADAPTER_PANEL,
+       /* add atmel mxt touch device */
+       ts = add_probed_i2c_device("touchscreen", type,
                                   &atmel_1664s_device, addr_list);
-       return 0;
+       return (!ts) ? -EAGAIN : 0;
 }
 
-
-static int __init setup_isl29018_als(const struct dmi_system_id *id)
+static int setup_isl29018_als(enum i2c_adapter_type type)
 {
+       if (als)
+               return 0;
+
        /* add isl29018 light sensor */
-       als = add_smbus_device("lightsensor", &isl_als_device);
-       return 0;
+       als = add_i2c_device("lightsensor", type, &isl_als_device);
+       return (!als) ? -EAGAIN : 0;
 }
 
-static int __init setup_isl29023_als(const struct dmi_system_id *id)
+static int setup_tsl2583_als(enum i2c_adapter_type type)
 {
-       /* add isl29023 light sensor on Panel GMBus */
-       als = add_i2c_device("lightsensor", I2C_ADAPTER_PANEL,
-                            &isl_als_device);
-       return 0;
+       if (als)
+               return 0;
+
+       /* add tsl2583 light sensor */
+       als = add_i2c_device(NULL, type, &tsl2583_als_device);
+       return (!als) ? -EAGAIN : 0;
 }
 
-static int __init setup_tsl2583_als(const struct dmi_system_id *id)
+static int setup_tsl2563_als(enum i2c_adapter_type type)
 {
-       /* add tsl2583 light sensor on smbus */
-       als = add_smbus_device(NULL, &tsl2583_als_device);
-       return 0;
+       if (als)
+               return 0;
+
+       /* add tsl2563 light sensor */
+       als = add_i2c_device(NULL, type, &tsl2563_als_device);
+       return (!als) ? -EAGAIN : 0;
 }
 
-static int __init setup_tsl2563_als(const struct dmi_system_id *id)
+static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)
 {
-       /* add tsl2563 light sensor on smbus */
-       als = add_smbus_device(NULL, &tsl2563_als_device);
-       return 0;
+       cros_laptop = (void *)id->driver_data;
+       pr_debug("DMI Matched %s.\n", id->ident);
+
+       /* Indicate to dmi_scan that processing is done. */
+       return 1;
 }
 
-static struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = {
-       {
-               .ident = "Samsung Series 5 550 - Touchpad",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
-               },
-               .callback = setup_cyapa_smbus_tp,
+static int chromeos_laptop_probe(struct platform_device *pdev)
+{
+       int i;
+       int ret = 0;
+
+       for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
+               struct i2c_peripheral *i2c_dev;
+
+               i2c_dev = &cros_laptop->i2c_peripherals[i];
+
+               /* No more peripherals. */
+               if (i2c_dev->add == NULL)
+                       break;
+
+               /* Add the device. Set -EPROBE_DEFER on any failure */
+               if (i2c_dev->add(i2c_dev->type))
+                       ret = -EPROBE_DEFER;
+       }
+
+       return ret;
+}
+
+static struct chromeos_laptop samsung_series_5_550 = {
+       .i2c_peripherals = {
+               /* Touchpad. */
+               { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
+               /* Light Sensor. */
+               { .add = setup_isl29018_als, I2C_ADAPTER_SMBUS },
        },
-       {
-               .ident = "Chromebook Pixel - Touchscreen",
-               .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
-               },
-               .callback = setup_atmel_1664s_ts,
+};
+
+static struct chromeos_laptop samsung_series_5 = {
+       .i2c_peripherals = {
+               /* Light Sensor. */
+               { .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS },
+       },
+};
+
+static struct chromeos_laptop chromebook_pixel = {
+       .i2c_peripherals = {
+               /* Touch Screen. */
+               { .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL },
+               /* Touchpad. */
+               { .add = setup_atmel_224s_tp, I2C_ADAPTER_VGADDC },
+               /* Light Sensor. */
+               { .add = setup_isl29018_als, I2C_ADAPTER_PANEL },
+       },
+};
+
+static struct chromeos_laptop acer_c7_chromebook = {
+       .i2c_peripherals = {
+               /* Touchpad. */
+               { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
+       },
+};
+
+static struct chromeos_laptop acer_ac700 = {
+       .i2c_peripherals = {
+               /* Light Sensor. */
+               { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
        },
+};
+
+static struct chromeos_laptop hp_pavilion_14_chromebook = {
+       .i2c_peripherals = {
+               /* Touchpad. */
+               { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
+       },
+};
+
+static struct chromeos_laptop cr48 = {
+       .i2c_peripherals = {
+               /* Light Sensor. */
+               { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
+       },
+};
+
+#define _CBDD(board_) \
+       .callback = chromeos_laptop_dmi_matched, \
+       .driver_data = (void *)&board_
+
+static struct dmi_system_id chromeos_laptop_dmi_table[] __initdata = {
        {
-               .ident = "Chromebook Pixel - Touchpad",
+               .ident = "Samsung Series 5 550",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
                },
-               .callback = setup_atmel_224s_tp,
+               _CBDD(samsung_series_5_550),
        },
        {
-               .ident = "Samsung Series 5 550 - Light Sensor",
+               .ident = "Samsung Series 5",
                .matches = {
-                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
                },
-               .callback = setup_isl29018_als,
+               _CBDD(samsung_series_5),
        },
        {
-               .ident = "Chromebook Pixel - Light Sensor",
+               .ident = "Chromebook Pixel",
                .matches = {
                        DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
                        DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
                },
-               .callback = setup_isl29023_als,
+               _CBDD(chromebook_pixel),
        },
        {
-               .ident = "Acer C7 Chromebook - Touchpad",
+               .ident = "Acer C7 Chromebook",
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
                },
-               .callback = setup_cyapa_smbus_tp,
+               _CBDD(acer_c7_chromebook),
        },
        {
-               .ident = "HP Pavilion 14 Chromebook - Touchpad",
+               .ident = "Acer AC700",
                .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
                },
-               .callback = setup_cyapa_smbus_tp,
+               _CBDD(acer_ac700),
        },
        {
-               .ident = "Samsung Series 5 - Light Sensor",
+               .ident = "HP Pavilion 14 Chromebook",
                .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
                },
-               .callback = setup_tsl2583_als,
+               _CBDD(hp_pavilion_14_chromebook),
        },
        {
-               .ident = "Cr-48 - Light Sensor",
+               .ident = "Cr-48",
                .matches = {
                        DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
                },
-               .callback = setup_tsl2563_als,
-       },
-       {
-               .ident = "Acer AC700 - Light Sensor",
-               .matches = {
-                       DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
-               },
-               .callback = setup_tsl2563_als,
+               _CBDD(cr48),
        },
        { }
 };
 MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
 
+static struct platform_device *cros_platform_device;
+
+static struct platform_driver cros_platform_driver = {
+       .driver = {
+               .name = "chromeos_laptop",
+               .owner = THIS_MODULE,
+       },
+       .probe = chromeos_laptop_probe,
+};
+
 static int __init chromeos_laptop_init(void)
 {
+       int ret;
        if (!dmi_check_system(chromeos_laptop_dmi_table)) {
                pr_debug("%s unsupported system.\n", __func__);
                return -ENODEV;
        }
+
+       ret = platform_driver_register(&cros_platform_driver);
+       if (ret)
+               return ret;
+
+       cros_platform_device = platform_device_alloc("chromeos_laptop", -1);
+       if (!cros_platform_device) {
+               ret = -ENOMEM;
+               goto fail_platform_device1;
+       }
+
+       ret = platform_device_add(cros_platform_device);
+       if (ret)
+               goto fail_platform_device2;
+
        return 0;
+
+fail_platform_device2:
+       platform_device_put(cros_platform_device);
+fail_platform_device1:
+       platform_driver_unregister(&cros_platform_driver);
+       return ret;
 }
 
 static void __exit chromeos_laptop_exit(void)
@@ -398,6 +511,9 @@ static void __exit chromeos_laptop_exit(void)
                i2c_unregister_device(tp);
        if (ts)
                i2c_unregister_device(ts);
+
+       platform_device_unregister(cros_platform_device);
+       platform_driver_unregister(&cros_platform_driver);
 }
 
 module_init(chromeos_laptop_init);
diff --git a/drivers/platform/chrome/chromeos_pstore.c b/drivers/platform/chrome/chromeos_pstore.c
new file mode 100644 (file)
index 0000000..e0e0e65
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ *  chromeos_pstore.c - Driver to instantiate Chromebook ramoops device
+ *
+ *  Copyright (C) 2013 Google, 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, version 2 of the License.
+ */
+
+#include <linux/dmi.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pstore_ram.h>
+
+static struct dmi_system_id chromeos_pstore_dmi_table[] __initdata = {
+       {
+               /*
+                * Today all Chromebooks/boxes ship with GOOGLE as vendor and
+                * coreboot as bios vendor. No other systems with this
+                * combination are known to date.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
+                       DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
+               },
+       },
+       {
+               /*
+                * The first Samsung Chromebox and Chromebook Series 5 550 use
+                * coreboot but with Samsung as the system vendor.
+                */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
+                       DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
+               },
+       },
+       {
+               /* x86-alex, the first Samsung Chromebook. */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
+               },
+       },
+       {
+               /* x86-mario, the Cr-48 pilot device from Google. */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "IEC"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
+               },
+       },
+       {
+               /* x86-zgb, the first Acer Chromebook. */
+               .matches = {
+                       DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
+                       DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
+               },
+       },
+       { }
+};
+MODULE_DEVICE_TABLE(dmi, chromeos_pstore_dmi_table);
+
+/*
+ * On x86 chromebooks/boxes, the firmware will keep the legacy VGA memory
+ * range untouched across reboots, so we use that to store our pstore
+ * contents for panic logs, etc.
+ */
+static struct ramoops_platform_data chromeos_ramoops_data = {
+       .mem_size       = 0x100000,
+       .mem_address    = 0xf00000,
+       .record_size    = 0x20000,
+       .console_size   = 0x20000,
+       .ftrace_size    = 0x20000,
+       .dump_oops      = 1,
+};
+
+static struct platform_device chromeos_ramoops = {
+       .name = "ramoops",
+       .dev = {
+               .platform_data = &chromeos_ramoops_data,
+       },
+};
+
+static int __init chromeos_pstore_init(void)
+{
+       if (dmi_check_system(chromeos_pstore_dmi_table))
+               return platform_device_register(&chromeos_ramoops);
+
+       return -ENODEV;
+}
+
+static void __exit chromeos_pstore_exit(void)
+{
+       platform_device_unregister(&chromeos_ramoops);
+}
+
+module_init(chromeos_pstore_init);
+module_exit(chromeos_pstore_exit);
+
+MODULE_DESCRIPTION("Chrome OS pstore module");
+MODULE_LICENSE("GPL");
index d9dcd37b5a521e86baf54702ff96f91657037aff..5ae65c11d544d4feb9affb727b6e00bec4b13894 100644 (file)
@@ -197,6 +197,17 @@ config HP_ACCEL
          To compile this driver as a module, choose M here: the module will
          be called hp_accel.
 
+config HP_WIRELESS
+       tristate "HP WIRELESS"
+       depends on ACPI
+       depends on INPUT
+       help
+        This driver provides supports for new HP wireless button for Windows 8.
+        On such systems the driver should load automatically (via ACPI alias).
+
+        To compile this driver as a module, choose M here: the module will
+        be called hp-wireless.
+
 config HP_WMI
        tristate "HP WMI extras"
        depends on ACPI_WMI
@@ -808,4 +819,12 @@ config PVPANIC
          a paravirtualized device provided by QEMU; it lets a virtual machine
          (guest) communicate panic events to the host.
 
+config INTEL_BAYTRAIL_MBI
+       tristate
+       depends on PCI
+       ---help---
+         Needed on Baytrail platforms for access to the IOSF Sideband Mailbox
+         Interface. This is a requirement for systems that need to configure
+         the PUNIT for power management features such as RAPL.
+
 endif # X86_PLATFORM_DEVICES
index f0e6aa407ffb9ee8786e7aa71f5c76ed00ec6d81..9b87cfc42b8419202553a1d49986b7a737932882 100644 (file)
@@ -16,6 +16,7 @@ obj-$(CONFIG_DELL_WMI_AIO)    += dell-wmi-aio.o
 obj-$(CONFIG_ACER_WMI)         += acer-wmi.o
 obj-$(CONFIG_ACERHDF)          += acerhdf.o
 obj-$(CONFIG_HP_ACCEL)         += hp_accel.o
+obj-$(CONFIG_HP_WIRELESS)      += hp-wireless.o
 obj-$(CONFIG_HP_WMI)           += hp-wmi.o
 obj-$(CONFIG_AMILO_RFKILL)     += amilo-rfkill.o
 obj-$(CONFIG_TC1100_WMI)       += tc1100-wmi.o
@@ -54,3 +55,4 @@ obj-$(CONFIG_INTEL_RST)               += intel-rst.o
 obj-$(CONFIG_INTEL_SMARTCONNECT)       += intel-smartconnect.o
 
 obj-$(CONFIG_PVPANIC)           += pvpanic.o
+obj-$(CONFIG_INTEL_BAYTRAIL_MBI)       += intel_baytrail.o
index 109f6383040cf99b99430a44a989c129660de8d3..c5e082fb82fa1b3a56b8673f48778bdac8276cac 100644 (file)
@@ -183,7 +183,6 @@ struct asus_wmi {
 
        struct input_dev *inputdev;
        struct backlight_device *backlight_device;
-       struct device *hwmon_device;
        struct platform_device *platform_device;
 
        struct led_classdev wlan_led;
@@ -1072,20 +1071,12 @@ static ssize_t asus_hwmon_temp1(struct device *dev,
        return sprintf(buf, "%d\n", value);
 }
 
-static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL, 0);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL, 0);
-
-static ssize_t
-show_name(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "asus\n");
-}
-static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
+static DEVICE_ATTR(pwm1, S_IRUGO, asus_hwmon_pwm1, NULL);
+static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
 
 static struct attribute *hwmon_attributes[] = {
-       &sensor_dev_attr_pwm1.dev_attr.attr,
-       &sensor_dev_attr_temp1_input.dev_attr.attr,
-       &sensor_dev_attr_name.dev_attr.attr,
+       &dev_attr_pwm1.attr,
+       &dev_attr_temp1_input.attr,
        NULL
 };
 
@@ -1099,9 +1090,9 @@ static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
        int dev_id = -1;
        u32 value = ASUS_WMI_UNSUPPORTED_METHOD;
 
-       if (attr == &sensor_dev_attr_pwm1.dev_attr.attr)
+       if (attr == &dev_attr_pwm1.attr)
                dev_id = ASUS_WMI_DEVID_FAN_CTRL;
-       else if (attr == &sensor_dev_attr_temp1_input.dev_attr.attr)
+       else if (attr == &dev_attr_temp1_input.attr)
                dev_id = ASUS_WMI_DEVID_THERMAL_CTRL;
 
        if (dev_id != -1) {
@@ -1136,35 +1127,20 @@ static struct attribute_group hwmon_attribute_group = {
        .is_visible = asus_hwmon_sysfs_is_visible,
        .attrs = hwmon_attributes
 };
-
-static void asus_wmi_hwmon_exit(struct asus_wmi *asus)
-{
-       struct device *hwmon;
-
-       hwmon = asus->hwmon_device;
-       if (!hwmon)
-               return;
-       sysfs_remove_group(&hwmon->kobj, &hwmon_attribute_group);
-       hwmon_device_unregister(hwmon);
-       asus->hwmon_device = NULL;
-}
+__ATTRIBUTE_GROUPS(hwmon_attribute);
 
 static int asus_wmi_hwmon_init(struct asus_wmi *asus)
 {
        struct device *hwmon;
-       int result;
 
-       hwmon = hwmon_device_register(&asus->platform_device->dev);
+       hwmon = hwmon_device_register_with_groups(&asus->platform_device->dev,
+                                                 "asus", asus,
+                                                 hwmon_attribute_groups);
        if (IS_ERR(hwmon)) {
                pr_err("Could not register asus hwmon device\n");
                return PTR_ERR(hwmon);
        }
-       dev_set_drvdata(hwmon, asus);
-       asus->hwmon_device = hwmon;
-       result = sysfs_create_group(&hwmon->kobj, &hwmon_attribute_group);
-       if (result)
-               asus_wmi_hwmon_exit(asus);
-       return result;
+       return 0;
 }
 
 /*
@@ -1835,7 +1811,6 @@ fail_backlight:
 fail_rfkill:
        asus_wmi_led_exit(asus);
 fail_leds:
-       asus_wmi_hwmon_exit(asus);
 fail_hwmon:
        asus_wmi_input_exit(asus);
 fail_input:
@@ -1853,7 +1828,6 @@ static int asus_wmi_remove(struct platform_device *device)
        wmi_remove_notify_handler(asus->driver->event_guid);
        asus_wmi_backlight_exit(asus);
        asus_wmi_input_exit(asus);
-       asus_wmi_hwmon_exit(asus);
        asus_wmi_led_exit(asus);
        asus_wmi_rfkill_exit(asus);
        asus_wmi_debugfs_exit(asus);
index eaa78edb1f4ef2b9f5af80bd0f715dfaa9304bd8..7297df2ebf503771d080a3467869819d72921b08 100644 (file)
 /* ======= */
 struct compal_data{
        /* Fan control */
-       struct device *hwmon_dev;
-       int pwm_enable; /* 0:full on, 1:set by pwm1, 2:control by moterboard */
+       int pwm_enable; /* 0:full on, 1:set by pwm1, 2:control by motherboard */
        unsigned char curr_pwm;
 
        /* Power supply */
@@ -402,15 +401,6 @@ SIMPLE_MASKED_STORE_SHOW(wake_up_wlan,     WAKE_UP_ADDR, WAKE_UP_WLAN)
 SIMPLE_MASKED_STORE_SHOW(wake_up_key,  WAKE_UP_ADDR, WAKE_UP_KEY)
 SIMPLE_MASKED_STORE_SHOW(wake_up_mouse,        WAKE_UP_ADDR, WAKE_UP_MOUSE)
 
-
-/* General hwmon interface */
-static ssize_t hwmon_name_show(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "%s\n", DRIVER_NAME);
-}
-
-
 /* Fan control interface */
 static ssize_t pwm_enable_show(struct device *dev,
                struct device_attribute *attr, char *buf)
@@ -665,55 +655,55 @@ static DEVICE_ATTR(wake_up_key,
 static DEVICE_ATTR(wake_up_mouse,
                0644, wake_up_mouse_show,       wake_up_mouse_store);
 
-static SENSOR_DEVICE_ATTR(name,        S_IRUGO, hwmon_name_show,   NULL, 1);
-static SENSOR_DEVICE_ATTR(fan1_input,  S_IRUGO, fan_show,          NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, temp_cpu,          NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, temp_cpu_local,    NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, temp_cpu_DTS,      NULL, 1);
-static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, temp_northbridge,  NULL, 1);
-static SENSOR_DEVICE_ATTR(temp5_input, S_IRUGO, temp_vga,          NULL, 1);
-static SENSOR_DEVICE_ATTR(temp6_input, S_IRUGO, temp_SKIN,         NULL, 1);
-static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, label_cpu,         NULL, 1);
-static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, label_cpu_local,   NULL, 1);
-static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, label_cpu_DTS,     NULL, 1);
-static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, label_northbridge, NULL, 1);
-static SENSOR_DEVICE_ATTR(temp5_label, S_IRUGO, label_vga,         NULL, 1);
-static SENSOR_DEVICE_ATTR(temp6_label, S_IRUGO, label_SKIN,        NULL, 1);
-static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, pwm_show, pwm_store, 1);
-static SENSOR_DEVICE_ATTR(pwm1_enable,
-               S_IRUGO | S_IWUSR, pwm_enable_show, pwm_enable_store, 0);
-
-static struct attribute *compal_attributes[] = {
+static DEVICE_ATTR(fan1_input,  S_IRUGO, fan_show,          NULL);
+static DEVICE_ATTR(temp1_input, S_IRUGO, temp_cpu,          NULL);
+static DEVICE_ATTR(temp2_input, S_IRUGO, temp_cpu_local,    NULL);
+static DEVICE_ATTR(temp3_input, S_IRUGO, temp_cpu_DTS,      NULL);
+static DEVICE_ATTR(temp4_input, S_IRUGO, temp_northbridge,  NULL);
+static DEVICE_ATTR(temp5_input, S_IRUGO, temp_vga,          NULL);
+static DEVICE_ATTR(temp6_input, S_IRUGO, temp_SKIN,         NULL);
+static DEVICE_ATTR(temp1_label, S_IRUGO, label_cpu,         NULL);
+static DEVICE_ATTR(temp2_label, S_IRUGO, label_cpu_local,   NULL);
+static DEVICE_ATTR(temp3_label, S_IRUGO, label_cpu_DTS,     NULL);
+static DEVICE_ATTR(temp4_label, S_IRUGO, label_northbridge, NULL);
+static DEVICE_ATTR(temp5_label, S_IRUGO, label_vga,         NULL);
+static DEVICE_ATTR(temp6_label, S_IRUGO, label_SKIN,        NULL);
+static DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, pwm_show, pwm_store);
+static DEVICE_ATTR(pwm1_enable,
+                  S_IRUGO | S_IWUSR, pwm_enable_show, pwm_enable_store);
+
+static struct attribute *compal_platform_attrs[] = {
        &dev_attr_wake_up_pme.attr,
        &dev_attr_wake_up_modem.attr,
        &dev_attr_wake_up_lan.attr,
        &dev_attr_wake_up_wlan.attr,
        &dev_attr_wake_up_key.attr,
        &dev_attr_wake_up_mouse.attr,
-       /* Maybe put the sensor-stuff in a separate hwmon-driver? That way,
-        * the hwmon sysfs won't be cluttered with the above files. */
-       &sensor_dev_attr_name.dev_attr.attr,
-       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
-       &sensor_dev_attr_pwm1.dev_attr.attr,
-       &sensor_dev_attr_fan1_input.dev_attr.attr,
-       &sensor_dev_attr_temp1_input.dev_attr.attr,
-       &sensor_dev_attr_temp2_input.dev_attr.attr,
-       &sensor_dev_attr_temp3_input.dev_attr.attr,
-       &sensor_dev_attr_temp4_input.dev_attr.attr,
-       &sensor_dev_attr_temp5_input.dev_attr.attr,
-       &sensor_dev_attr_temp6_input.dev_attr.attr,
-       &sensor_dev_attr_temp1_label.dev_attr.attr,
-       &sensor_dev_attr_temp2_label.dev_attr.attr,
-       &sensor_dev_attr_temp3_label.dev_attr.attr,
-       &sensor_dev_attr_temp4_label.dev_attr.attr,
-       &sensor_dev_attr_temp5_label.dev_attr.attr,
-       &sensor_dev_attr_temp6_label.dev_attr.attr,
        NULL
 };
+static struct attribute_group compal_platform_attr_group = {
+       .attrs = compal_platform_attrs
+};
 
-static struct attribute_group compal_attribute_group = {
-       .attrs = compal_attributes
+static struct attribute *compal_hwmon_attrs[] = {
+       &dev_attr_pwm1_enable.attr,
+       &dev_attr_pwm1.attr,
+       &dev_attr_fan1_input.attr,
+       &dev_attr_temp1_input.attr,
+       &dev_attr_temp2_input.attr,
+       &dev_attr_temp3_input.attr,
+       &dev_attr_temp4_input.attr,
+       &dev_attr_temp5_input.attr,
+       &dev_attr_temp6_input.attr,
+       &dev_attr_temp1_label.attr,
+       &dev_attr_temp2_label.attr,
+       &dev_attr_temp3_label.attr,
+       &dev_attr_temp4_label.attr,
+       &dev_attr_temp5_label.attr,
+       &dev_attr_temp6_label.attr,
+       NULL
 };
+ATTRIBUTE_GROUPS(compal_hwmon);
 
 static int compal_probe(struct platform_device *);
 static int compal_remove(struct platform_device *);
@@ -1021,30 +1011,28 @@ static int compal_probe(struct platform_device *pdev)
 {
        int err;
        struct compal_data *data;
+       struct device *hwmon_dev;
 
        if (!extra_features)
                return 0;
 
        /* Fan control */
-       data = kzalloc(sizeof(struct compal_data), GFP_KERNEL);
+       data = devm_kzalloc(&pdev->dev, sizeof(struct compal_data), GFP_KERNEL);
        if (!data)
                return -ENOMEM;
 
        initialize_fan_control_data(data);
 
-       err = sysfs_create_group(&pdev->dev.kobj, &compal_attribute_group);
-       if (err) {
-               kfree(data);
+       err = sysfs_create_group(&pdev->dev.kobj, &compal_platform_attr_group);
+       if (err)
                return err;
-       }
 
-       data->hwmon_dev = hwmon_device_register(&pdev->dev);
-       if (IS_ERR(data->hwmon_dev)) {
-               err = PTR_ERR(data->hwmon_dev);
-               sysfs_remove_group(&pdev->dev.kobj,
-                               &compal_attribute_group);
-               kfree(data);
-               return err;
+       hwmon_dev = hwmon_device_register_with_groups(&pdev->dev,
+                                                     DRIVER_NAME, data,
+                                                     compal_hwmon_groups);
+       if (IS_ERR(hwmon_dev)) {
+               err = PTR_ERR(hwmon_dev);
+               goto remove;
        }
 
        /* Power supply */
@@ -1054,6 +1042,10 @@ static int compal_probe(struct platform_device *pdev)
        platform_set_drvdata(pdev, data);
 
        return 0;
+
+remove:
+       sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
+       return err;
 }
 
 static void __exit compal_cleanup(void)
@@ -1080,12 +1072,9 @@ static int compal_remove(struct platform_device *pdev)
        pwm_disable_control();
 
        data = platform_get_drvdata(pdev);
-       hwmon_device_unregister(data->hwmon_dev);
        power_supply_unregister(&data->psy);
 
-       kfree(data);
-
-       sysfs_remove_group(&pdev->dev.kobj, &compal_attribute_group);
+       sysfs_remove_group(&pdev->dev.kobj, &compal_platform_attr_group);
 
        return 0;
 }
index c608b1d33f4a60893a3bdc87b52773f872259f6d..fed4111ac31a6d6fbff0c02a6be563485ccec7dc 100644 (file)
@@ -559,19 +559,45 @@ static void dell_update_rfkill(struct work_struct *ignored)
 }
 static DECLARE_DELAYED_WORK(dell_rfkill_work, dell_update_rfkill);
 
+static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
+                             struct serio *port)
+{
+       static bool extended;
+
+       if (str & 0x20)
+               return false;
+
+       if (unlikely(data == 0xe0)) {
+               extended = true;
+               return false;
+       } else if (unlikely(extended)) {
+               switch (data) {
+               case 0x8:
+                       schedule_delayed_work(&dell_rfkill_work,
+                                             round_jiffies_relative(HZ / 4));
+                       break;
+               }
+               extended = false;
+       }
+
+       return false;
+}
 
 static int __init dell_setup_rfkill(void)
 {
-       int status;
-       int ret;
+       int status, ret, whitelisted;
        const char *product;
 
        /*
-        * rfkill causes trouble on various non Latitudes, according to Dell
-        * actually testing the rfkill functionality is only done on Latitudes.
+        * rfkill support causes trouble on various models, mostly Inspirons.
+        * So we whitelist certain series, and don't support rfkill on others.
         */
+       whitelisted = 0;
        product = dmi_get_system_info(DMI_PRODUCT_NAME);
-       if (!force_rfkill && (!product || strncmp(product, "Latitude", 8)))
+       if (product &&  (strncmp(product, "Latitude", 8) == 0 ||
+                        strncmp(product, "Precision", 9) == 0))
+               whitelisted = 1;
+       if (!force_rfkill && !whitelisted)
                return 0;
 
        get_buffer();
@@ -633,7 +659,16 @@ static int __init dell_setup_rfkill(void)
                        goto err_wwan;
        }
 
+       ret = i8042_install_filter(dell_laptop_i8042_filter);
+       if (ret) {
+               pr_warn("Unable to install key filter\n");
+               goto err_filter;
+       }
+
        return 0;
+err_filter:
+       if (wwan_rfkill)
+               rfkill_unregister(wwan_rfkill);
 err_wwan:
        rfkill_destroy(wwan_rfkill);
        if (bluetooth_rfkill)
@@ -684,7 +719,7 @@ static int dell_send_intensity(struct backlight_device *bd)
 
 out:
        release_buffer();
-       return 0;
+       return ret;
 }
 
 static int dell_get_intensity(struct backlight_device *bd)
@@ -755,30 +790,6 @@ static void touchpad_led_exit(void)
        led_classdev_unregister(&touchpad_led);
 }
 
-static bool dell_laptop_i8042_filter(unsigned char data, unsigned char str,
-                             struct serio *port)
-{
-       static bool extended;
-
-       if (str & 0x20)
-               return false;
-
-       if (unlikely(data == 0xe0)) {
-               extended = true;
-               return false;
-       } else if (unlikely(extended)) {
-               switch (data) {
-               case 0x8:
-                       schedule_delayed_work(&dell_rfkill_work,
-                                             round_jiffies_relative(HZ / 4));
-                       break;
-               }
-               extended = false;
-       }
-
-       return false;
-}
-
 static int __init dell_init(void)
 {
        int max_intensity = 0;
@@ -828,12 +839,6 @@ static int __init dell_init(void)
                goto fail_rfkill;
        }
 
-       ret = i8042_install_filter(dell_laptop_i8042_filter);
-       if (ret) {
-               pr_warn("Unable to install key filter\n");
-               goto fail_filter;
-       }
-
        if (quirks && quirks->touchpad_led)
                touchpad_led_init(&platform_device->dev);
 
@@ -885,7 +890,6 @@ static int __init dell_init(void)
 fail_backlight:
        i8042_remove_filter(dell_laptop_i8042_filter);
        cancel_delayed_work_sync(&dell_rfkill_work);
-fail_filter:
        dell_cleanup_rfkill();
 fail_rfkill:
        free_page((unsigned long)bufferpage);
index ed69ec5f36f77b73afb23ff5199c4d2885f29cbe..399e8c5621923890a43ea81f25fde5d0388f152e 100644 (file)
@@ -165,7 +165,6 @@ struct eeepc_laptop {
 
        struct platform_device *platform_device;
        struct acpi_device *device;             /* the device we are in */
-       struct device *hwmon_device;
        struct backlight_device *backlight_device;
 
        struct input_dev *inputdev;
@@ -1068,7 +1067,7 @@ static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
        {                                                               \
                return store_sys_hwmon(_get, buf, count);               \
        }                                                               \
-       static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
+       static DEVICE_ATTR(_name, _mode, show_##_name, store_##_name);
 
 EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
 EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
@@ -1076,55 +1075,26 @@ EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
 EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
                         eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
 
-static ssize_t
-show_name(struct device *dev, struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "eeepc\n");
-}
-static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
-
-static struct attribute *hwmon_attributes[] = {
-       &sensor_dev_attr_pwm1.dev_attr.attr,
-       &sensor_dev_attr_fan1_input.dev_attr.attr,
-       &sensor_dev_attr_pwm1_enable.dev_attr.attr,
-       &sensor_dev_attr_name.dev_attr.attr,
+static struct attribute *hwmon_attrs[] = {
+       &dev_attr_pwm1.attr,
+       &dev_attr_fan1_input.attr,
+       &dev_attr_pwm1_enable.attr,
        NULL
 };
-
-static struct attribute_group hwmon_attribute_group = {
-       .attrs = hwmon_attributes
-};
-
-static void eeepc_hwmon_exit(struct eeepc_laptop *eeepc)
-{
-       struct device *hwmon;
-
-       hwmon = eeepc->hwmon_device;
-       if (!hwmon)
-               return;
-       sysfs_remove_group(&hwmon->kobj,
-                          &hwmon_attribute_group);
-       hwmon_device_unregister(hwmon);
-       eeepc->hwmon_device = NULL;
-}
+ATTRIBUTE_GROUPS(hwmon);
 
 static int eeepc_hwmon_init(struct eeepc_laptop *eeepc)
 {
+       struct device *dev = &eeepc->platform_device->dev;
        struct device *hwmon;
-       int result;
 
-       hwmon = hwmon_device_register(&eeepc->platform_device->dev);
+       hwmon = devm_hwmon_device_register_with_groups(dev, "eeepc", NULL,
+                                                      hwmon_groups);
        if (IS_ERR(hwmon)) {
                pr_err("Could not register eeepc hwmon device\n");
-               eeepc->hwmon_device = NULL;
                return PTR_ERR(hwmon);
        }
-       eeepc->hwmon_device = hwmon;
-       result = sysfs_create_group(&hwmon->kobj,
-                                   &hwmon_attribute_group);
-       if (result)
-               eeepc_hwmon_exit(eeepc);
-       return result;
+       return 0;
 }
 
 /*
@@ -1480,7 +1450,6 @@ static int eeepc_acpi_add(struct acpi_device *device)
 fail_rfkill:
        eeepc_led_exit(eeepc);
 fail_led:
-       eeepc_hwmon_exit(eeepc);
 fail_hwmon:
        eeepc_input_exit(eeepc);
 fail_input:
@@ -1500,7 +1469,6 @@ static int eeepc_acpi_remove(struct acpi_device *device)
        eeepc_backlight_exit(eeepc);
        eeepc_rfkill_exit(eeepc);
        eeepc_input_exit(eeepc);
-       eeepc_hwmon_exit(eeepc);
        eeepc_led_exit(eeepc);
        eeepc_platform_exit(eeepc);
 
index 9d30d69aa78f24a3bbb1caa71f797f9c520bbc5c..be02bcc346d30cb9dc17fff807aa414d0147216a 100644 (file)
@@ -633,7 +633,6 @@ static struct dmi_system_id fujitsu_dmi_table[] = {
 
 static int acpi_fujitsu_add(struct acpi_device *device)
 {
-       int result = 0;
        int state = 0;
        struct input_dev *input;
        int error;
@@ -669,8 +668,8 @@ static int acpi_fujitsu_add(struct acpi_device *device)
        if (error)
                goto err_free_input_dev;
 
-       result = acpi_bus_update_power(fujitsu->acpi_handle, &state);
-       if (result) {
+       error = acpi_bus_update_power(fujitsu->acpi_handle, &state);
+       if (error) {
                pr_err("Error reading power state\n");
                goto err_unregister_input_dev;
        }
@@ -700,7 +699,7 @@ static int acpi_fujitsu_add(struct acpi_device *device)
                fujitsu->max_brightness = FUJITSU_LCD_N_LEVELS;
        get_lcd_level();
 
-       return result;
+       return 0;
 
 err_unregister_input_dev:
        input_unregister_device(input);
@@ -708,7 +707,7 @@ err_unregister_input_dev:
 err_free_input_dev:
        input_free_device(input);
 err_stop:
-       return result;
+       return error;
 }
 
 static int acpi_fujitsu_remove(struct acpi_device *device)
@@ -831,8 +830,8 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
        if (error)
                goto err_free_input_dev;
 
-       result = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state);
-       if (result) {
+       error = acpi_bus_update_power(fujitsu_hotkey->acpi_handle, &state);
+       if (error) {
                pr_err("Error reading power state\n");
                goto err_unregister_input_dev;
        }
@@ -907,7 +906,7 @@ err_free_input_dev:
 err_free_fifo:
        kfifo_free(&fujitsu_hotkey->fifo);
 err_stop:
-       return result;
+       return error;
 }
 
 static int acpi_fujitsu_hotkey_remove(struct acpi_device *device)
diff --git a/drivers/platform/x86/hp-wireless.c b/drivers/platform/x86/hp-wireless.c
new file mode 100644 (file)
index 0000000..415348f
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *  hp-wireless button for Windows 8
+ *
+ *  Copyright (C) 2014 Alex Hung <alex.hung@canonical.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.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/platform_device.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Alex Hung");
+MODULE_ALIAS("acpi*:HPQ6001:*");
+
+static struct input_dev *hpwl_input_dev;
+
+static const struct acpi_device_id hpwl_ids[] = {
+       {"HPQ6001", 0},
+       {"", 0},
+};
+
+static int hp_wireless_input_setup(void)
+{
+       int err;
+
+       hpwl_input_dev = input_allocate_device();
+       if (!hpwl_input_dev)
+               return -ENOMEM;
+
+       hpwl_input_dev->name = "HP Wireless hotkeys";
+       hpwl_input_dev->phys = "hpq6001/input0";
+       hpwl_input_dev->id.bustype = BUS_HOST;
+       hpwl_input_dev->evbit[0] = BIT(EV_KEY);
+       set_bit(KEY_RFKILL, hpwl_input_dev->keybit);
+
+       err = input_register_device(hpwl_input_dev);
+       if (err)
+               goto err_free_dev;
+
+       return 0;
+
+err_free_dev:
+       input_free_device(hpwl_input_dev);
+       return err;
+}
+
+static void hp_wireless_input_destroy(void)
+{
+       input_unregister_device(hpwl_input_dev);
+}
+
+static void hpwl_notify(struct acpi_device *acpi_dev, u32 event)
+{
+       if (event != 0x80) {
+               pr_info("Received unknown event (0x%x)\n", event);
+               return;
+       }
+
+       input_report_key(hpwl_input_dev, KEY_RFKILL, 1);
+       input_sync(hpwl_input_dev);
+       input_report_key(hpwl_input_dev, KEY_RFKILL, 0);
+       input_sync(hpwl_input_dev);
+}
+
+static int hpwl_add(struct acpi_device *device)
+{
+       int err;
+
+       err = hp_wireless_input_setup();
+       return err;
+}
+
+static int hpwl_remove(struct acpi_device *device)
+{
+       hp_wireless_input_destroy();
+       return 0;
+}
+
+static struct acpi_driver hpwl_driver = {
+       .name   = "hp-wireless",
+       .owner  = THIS_MODULE,
+       .ids    = hpwl_ids,
+       .ops    = {
+               .add    = hpwl_add,
+               .remove = hpwl_remove,
+               .notify = hpwl_notify,
+       },
+};
+
+static int __init hpwl_init(void)
+{
+       int err;
+
+       pr_info("Initializing HPQ6001 module\n");
+       err = acpi_bus_register_driver(&hpwl_driver);
+       if (err) {
+               pr_err("Unable to register HP wireless control driver.\n");
+               goto error_acpi_register;
+       }
+
+       return 0;
+
+error_acpi_register:
+       return err;
+}
+
+static void __exit hpwl_exit(void)
+{
+       pr_info("Exiting HPQ6001 module\n");
+       acpi_bus_unregister_driver(&hpwl_driver);
+}
+
+module_init(hpwl_init);
+module_exit(hpwl_exit);
index aff4d0670edfec733e131c0137fd82f70e0d2206..3dc934438c28f9082144ded5f346f39e3716f4db 100644 (file)
@@ -77,6 +77,7 @@ static inline void delayed_sysfs_set(struct led_classdev *led_cdev,
 static struct acpi_device_id lis3lv02d_device_ids[] = {
        {"HPQ0004", 0}, /* HP Mobile Data Protection System PNP */
        {"HPQ6000", 0}, /* HP Mobile Data Protection System PNP */
+       {"HPQ6007", 0}, /* HP Mobile Data Protection System PNP */
        {"", 0},
 };
 MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
@@ -88,7 +89,7 @@ MODULE_DEVICE_TABLE(acpi, lis3lv02d_device_ids);
  *
  * Returns 0 on success.
  */
-int lis3lv02d_acpi_init(struct lis3lv02d *lis3)
+static int lis3lv02d_acpi_init(struct lis3lv02d *lis3)
 {
        struct acpi_device *dev = lis3->bus_priv;
        if (acpi_evaluate_object(dev->handle, METHOD_NAME__INI,
@@ -106,7 +107,7 @@ int lis3lv02d_acpi_init(struct lis3lv02d *lis3)
  *
  * Returns 0 on success.
  */
-int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret)
+static int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret)
 {
        struct acpi_device *dev = lis3->bus_priv;
        union acpi_object arg0 = { ACPI_TYPE_INTEGER };
@@ -129,7 +130,7 @@ int lis3lv02d_acpi_read(struct lis3lv02d *lis3, int reg, u8 *ret)
  *
  * Returns 0 on success.
  */
-int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
+static int lis3lv02d_acpi_write(struct lis3lv02d *lis3, int reg, u8 val)
 {
        struct acpi_device *dev = lis3->bus_priv;
        unsigned long long ret; /* Not used when writting */
diff --git a/drivers/platform/x86/intel_baytrail.c b/drivers/platform/x86/intel_baytrail.c
new file mode 100644 (file)
index 0000000..f96626b
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * Baytrail IOSF-SB MailBox Interface Driver
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ *
+ * The IOSF-SB is a fabric bus available on Atom based SOC's that uses a
+ * mailbox interface (MBI) to communicate with mutiple devices. This
+ * driver implements BayTrail-specific access to this interface.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/pci.h>
+
+#include "intel_baytrail.h"
+
+static DEFINE_SPINLOCK(iosf_mbi_lock);
+
+static inline u32 iosf_mbi_form_mcr(u8 op, u8 port, u8 offset)
+{
+       return (op << 24) | (port << 16) | (offset << 8) | BT_MBI_ENABLE;
+}
+
+static struct pci_dev *mbi_pdev;       /* one mbi device */
+
+/* Hold lock before calling */
+static int iosf_mbi_pci_read_mdr(u32 mcrx, u32 mcr, u32 *mdr)
+{
+       int result;
+
+       if (!mbi_pdev)
+               return -ENODEV;
+
+       if (mcrx) {
+               result = pci_write_config_dword(mbi_pdev,
+                                               BT_MBI_MCRX_OFFSET, mcrx);
+               if (result < 0)
+                       goto iosf_mbi_read_err;
+       }
+
+       result = pci_write_config_dword(mbi_pdev,
+                                       BT_MBI_MCR_OFFSET, mcr);
+       if (result < 0)
+               goto iosf_mbi_read_err;
+
+       result = pci_read_config_dword(mbi_pdev,
+                                      BT_MBI_MDR_OFFSET, mdr);
+       if (result < 0)
+               goto iosf_mbi_read_err;
+
+       return 0;
+
+iosf_mbi_read_err:
+       dev_err(&mbi_pdev->dev, "error: PCI config operation returned %d\n",
+               result);
+       return result;
+}
+
+/* Hold lock before calling */
+static int iosf_mbi_pci_write_mdr(u32 mcrx, u32 mcr, u32 mdr)
+{
+       int result;
+
+       if (!mbi_pdev)
+               return -ENODEV;
+
+       result = pci_write_config_dword(mbi_pdev,
+                                       BT_MBI_MDR_OFFSET, mdr);
+       if (result < 0)
+               goto iosf_mbi_write_err;
+
+       if (mcrx) {
+               result = pci_write_config_dword(mbi_pdev,
+                        BT_MBI_MCRX_OFFSET, mcrx);
+               if (result < 0)
+                       goto iosf_mbi_write_err;
+       }
+
+       result = pci_write_config_dword(mbi_pdev,
+                                       BT_MBI_MCR_OFFSET, mcr);
+       if (result < 0)
+               goto iosf_mbi_write_err;
+
+       return 0;
+
+iosf_mbi_write_err:
+       dev_err(&mbi_pdev->dev, "error: PCI config operation returned %d\n",
+               result);
+       return result;
+}
+
+int bt_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr)
+{
+       u32 mcr, mcrx;
+       unsigned long flags;
+       int ret;
+
+       /*Access to the GFX unit is handled by GPU code */
+       BUG_ON(port == BT_MBI_UNIT_GFX);
+
+       mcr = iosf_mbi_form_mcr(opcode, port, offset & BT_MBI_MASK_LO);
+       mcrx = offset & BT_MBI_MASK_HI;
+
+       spin_lock_irqsave(&iosf_mbi_lock, flags);
+       ret = iosf_mbi_pci_read_mdr(mcrx, mcr, mdr);
+       spin_unlock_irqrestore(&iosf_mbi_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(bt_mbi_read);
+
+int bt_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr)
+{
+       u32 mcr, mcrx;
+       unsigned long flags;
+       int ret;
+
+       /*Access to the GFX unit is handled by GPU code */
+       BUG_ON(port == BT_MBI_UNIT_GFX);
+
+       mcr = iosf_mbi_form_mcr(opcode, port, offset & BT_MBI_MASK_LO);
+       mcrx = offset & BT_MBI_MASK_HI;
+
+       spin_lock_irqsave(&iosf_mbi_lock, flags);
+       ret = iosf_mbi_pci_write_mdr(mcrx, mcr, mdr);
+       spin_unlock_irqrestore(&iosf_mbi_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(bt_mbi_write);
+
+int bt_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask)
+{
+       u32 mcr, mcrx;
+       u32 value;
+       unsigned long flags;
+       int ret;
+
+       /*Access to the GFX unit is handled by GPU code */
+       BUG_ON(port == BT_MBI_UNIT_GFX);
+
+       mcr = iosf_mbi_form_mcr(opcode, port, offset & BT_MBI_MASK_LO);
+       mcrx = offset & BT_MBI_MASK_HI;
+
+       spin_lock_irqsave(&iosf_mbi_lock, flags);
+
+       /* Read current mdr value */
+       ret = iosf_mbi_pci_read_mdr(mcrx, mcr & BT_MBI_RD_MASK, &value);
+       if (ret < 0) {
+               spin_unlock_irqrestore(&iosf_mbi_lock, flags);
+               return ret;
+       }
+
+       /* Apply mask */
+       value &= ~mask;
+       mdr &= mask;
+       value |= mdr;
+
+       /* Write back */
+       ret = iosf_mbi_pci_write_mdr(mcrx, mcr | BT_MBI_WR_MASK, value);
+
+       spin_unlock_irqrestore(&iosf_mbi_lock, flags);
+
+       return ret;
+}
+EXPORT_SYMBOL(bt_mbi_modify);
+
+static int iosf_mbi_probe(struct pci_dev *pdev,
+                         const struct pci_device_id *unused)
+{
+       int ret;
+
+       ret = pci_enable_device(pdev);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "error: could not enable device\n");
+               return ret;
+       }
+
+       mbi_pdev = pci_dev_get(pdev);
+       return 0;
+}
+
+static DEFINE_PCI_DEVICE_TABLE(iosf_mbi_pci_ids) = {
+       { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0F00) },
+       { 0, },
+};
+MODULE_DEVICE_TABLE(pci, iosf_mbi_pci_ids);
+
+static struct pci_driver iosf_mbi_pci_driver = {
+       .name           = "iosf_mbi_pci",
+       .probe          = iosf_mbi_probe,
+       .id_table       = iosf_mbi_pci_ids,
+};
+
+static int __init bt_mbi_init(void)
+{
+       return pci_register_driver(&iosf_mbi_pci_driver);
+}
+
+static void __exit bt_mbi_exit(void)
+{
+       pci_unregister_driver(&iosf_mbi_pci_driver);
+       if (mbi_pdev) {
+               pci_dev_put(mbi_pdev);
+               mbi_pdev = NULL;
+       }
+}
+
+module_init(bt_mbi_init);
+module_exit(bt_mbi_exit);
+
+MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
+MODULE_DESCRIPTION("BayTrail Mailbox Interface accessor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/platform/x86/intel_baytrail.h b/drivers/platform/x86/intel_baytrail.h
new file mode 100644 (file)
index 0000000..8bcc311
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * intel_baytrail.h: MailBox access support for Intel BayTrail platforms
+ */
+
+#ifndef INTEL_BAYTRAIL_MBI_SYMS_H
+#define INTEL_BAYTRAIL_MBI_SYMS_H
+
+#define BT_MBI_MCR_OFFSET      0xD0
+#define BT_MBI_MDR_OFFSET      0xD4
+#define BT_MBI_MCRX_OFFSET     0xD8
+
+#define BT_MBI_RD_MASK         0xFEFFFFFF
+#define BT_MBI_WR_MASK         0X01000000
+
+#define BT_MBI_MASK_HI         0xFFFFFF00
+#define BT_MBI_MASK_LO         0x000000FF
+#define BT_MBI_ENABLE          0xF0
+
+/* BT-SB unit access methods */
+#define BT_MBI_UNIT_AUNIT      0x00
+#define BT_MBI_UNIT_SMC                0x01
+#define BT_MBI_UNIT_CPU                0x02
+#define BT_MBI_UNIT_BUNIT      0x03
+#define BT_MBI_UNIT_PMC                0x04
+#define BT_MBI_UNIT_GFX                0x06
+#define BT_MBI_UNIT_SMI                0x0C
+#define BT_MBI_UNIT_USB                0x43
+#define BT_MBI_UNIT_SATA       0xA3
+#define BT_MBI_UNIT_PCIE       0xA6
+
+/* Read/write opcodes */
+#define BT_MBI_AUNIT_READ      0x10
+#define BT_MBI_AUNIT_WRITE     0x11
+#define BT_MBI_SMC_READ                0x10
+#define BT_MBI_SMC_WRITE       0x11
+#define BT_MBI_CPU_READ                0x10
+#define BT_MBI_CPU_WRITE       0x11
+#define BT_MBI_BUNIT_READ      0x10
+#define BT_MBI_BUNIT_WRITE     0x11
+#define BT_MBI_PMC_READ                0x06
+#define BT_MBI_PMC_WRITE       0x07
+#define BT_MBI_GFX_READ                0x00
+#define BT_MBI_GFX_WRITE       0x01
+#define BT_MBI_SMIO_READ       0x06
+#define BT_MBI_SMIO_WRITE      0x07
+#define BT_MBI_USB_READ                0x06
+#define BT_MBI_USB_WRITE       0x07
+#define BT_MBI_SATA_READ       0x00
+#define BT_MBI_SATA_WRITE      0x01
+#define BT_MBI_PCIE_READ       0x00
+#define BT_MBI_PCIE_WRITE      0x01
+
+/**
+ * bt_mbi_read() - MailBox Interface read command
+ * @port:      port indicating subunit being accessed
+ * @opcode:    port specific read or write opcode
+ * @offset:    register address offset
+ * @mdr:       register data to be read
+ *
+ * Locking is handled by spinlock - cannot sleep.
+ * Return: Nonzero on error
+ */
+int bt_mbi_read(u8 port, u8 opcode, u32 offset, u32 *mdr);
+
+/**
+ * bt_mbi_write() - MailBox unmasked write command
+ * @port:      port indicating subunit being accessed
+ * @opcode:    port specific read or write opcode
+ * @offset:    register address offset
+ * @mdr:       register data to be written
+ *
+ * Locking is handled by spinlock - cannot sleep.
+ * Return: Nonzero on error
+ */
+int bt_mbi_write(u8 port, u8 opcode, u32 offset, u32 mdr);
+
+/**
+ * bt_mbi_modify() - MailBox masked write command
+ * @port:      port indicating subunit being accessed
+ * @opcode:    port specific read or write opcode
+ * @offset:    register address offset
+ * @mdr:       register data being modified
+ * @mask:      mask indicating bits in mdr to be modified
+ *
+ * Locking is handled by spinlock - cannot sleep.
+ * Return: Nonzero on error
+ */
+int bt_mbi_modify(u8 port, u8 opcode, u32 offset, u32 mdr, u32 mask);
+
+#endif /* INTEL_BAYTRAIL_MBI_SYMS_H */
index 60ea476a91305c8f357f1950064cee54e92f0f29..76ca094ed01237fff731a46b84c04a5edcedc71b 100644 (file)
 #define IPC_RWBUF_SIZE    20           /* IPC Read buffer Size */
 #define IPC_IOC                  0x100         /* IPC command register IOC bit */
 
-enum {
-       SCU_IPC_LINCROFT,
-       SCU_IPC_PENWELL,
-       SCU_IPC_CLOVERVIEW,
-       SCU_IPC_TANGIER,
-};
+#define PCI_DEVICE_ID_LINCROFT         0x082a
+#define PCI_DEVICE_ID_PENWELL          0x080e
+#define PCI_DEVICE_ID_CLOVERVIEW       0x08ea
+#define PCI_DEVICE_ID_TANGIER          0x11a0
 
 /* intel scu ipc driver data*/
 struct intel_scu_ipc_pdata_t {
@@ -78,35 +76,29 @@ struct intel_scu_ipc_pdata_t {
        u8 irq_mode;
 };
 
-static struct intel_scu_ipc_pdata_t intel_scu_ipc_pdata[] = {
-       [SCU_IPC_LINCROFT] = {
-               .ipc_base = 0xff11c000,
-               .i2c_base = 0xff12b000,
-               .ipc_len = 0x100,
-               .i2c_len = 0x10,
-               .irq_mode = 0,
-       },
-       [SCU_IPC_PENWELL] = {
-               .ipc_base = 0xff11c000,
-               .i2c_base = 0xff12b000,
-               .ipc_len = 0x100,
-               .i2c_len = 0x10,
-               .irq_mode = 1,
-       },
-       [SCU_IPC_CLOVERVIEW] = {
-               .ipc_base = 0xff11c000,
-               .i2c_base = 0xff12b000,
-               .ipc_len = 0x100,
-               .i2c_len = 0x10,
-               .irq_mode = 1,
-       },
-       [SCU_IPC_TANGIER] = {
-               .ipc_base = 0xff009000,
-               .i2c_base  = 0xff00d000,
-               .ipc_len  = 0x100,
-               .i2c_len = 0x10,
-               .irq_mode = 0,
-       },
+static struct intel_scu_ipc_pdata_t intel_scu_ipc_lincroft_pdata = {
+       .ipc_base = 0xff11c000,
+       .i2c_base = 0xff12b000,
+       .ipc_len = 0x100,
+       .i2c_len = 0x10,
+       .irq_mode = 0,
+};
+
+/* Penwell and Cloverview */
+static struct intel_scu_ipc_pdata_t intel_scu_ipc_penwell_pdata = {
+       .ipc_base = 0xff11c000,
+       .i2c_base = 0xff12b000,
+       .ipc_len = 0x100,
+       .i2c_len = 0x10,
+       .irq_mode = 1,
+};
+
+static struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = {
+       .ipc_base = 0xff009000,
+       .i2c_base  = 0xff00d000,
+       .ipc_len  = 0x100,
+       .i2c_len = 0x10,
+       .irq_mode = 0,
 };
 
 static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id);
@@ -583,15 +575,14 @@ static irqreturn_t ioc(int irq, void *dev_id)
  */
 static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       int err, pid;
+       int err;
        struct intel_scu_ipc_pdata_t *pdata;
        resource_size_t pci_resource;
 
        if (ipcdev.pdev)                /* We support only one SCU */
                return -EBUSY;
 
-       pid = id->driver_data;
-       pdata = &intel_scu_ipc_pdata[pid];
+       pdata = (struct intel_scu_ipc_pdata_t *)id->driver_data;
 
        ipcdev.pdev = pci_dev_get(dev);
        ipcdev.irq_mode = pdata->irq_mode;
@@ -650,11 +641,21 @@ static void ipc_remove(struct pci_dev *pdev)
 }
 
 static DEFINE_PCI_DEVICE_TABLE(pci_ids) = {
-       {PCI_VDEVICE(INTEL, 0x082a), SCU_IPC_LINCROFT},
-       {PCI_VDEVICE(INTEL, 0x080e), SCU_IPC_PENWELL},
-       {PCI_VDEVICE(INTEL, 0x08ea), SCU_IPC_CLOVERVIEW},
-       {PCI_VDEVICE(INTEL, 0x11a0), SCU_IPC_TANGIER},
-       { 0,}
+       {
+               PCI_VDEVICE(INTEL, PCI_DEVICE_ID_LINCROFT),
+               (kernel_ulong_t)&intel_scu_ipc_lincroft_pdata,
+       }, {
+               PCI_VDEVICE(INTEL, PCI_DEVICE_ID_PENWELL),
+               (kernel_ulong_t)&intel_scu_ipc_penwell_pdata,
+       }, {
+               PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CLOVERVIEW),
+               (kernel_ulong_t)&intel_scu_ipc_penwell_pdata,
+       }, {
+               PCI_VDEVICE(INTEL, PCI_DEVICE_ID_TANGIER),
+               (kernel_ulong_t)&intel_scu_ipc_tangier_pdata,
+       }, {
+               0,
+       }
 };
 MODULE_DEVICE_TABLE(pci, pci_ids);
 
index 3c59c0a3ee0f0f2d57a895f853d6915c37d39822..f4bad83053a9d5972e504a1cc4c0f80c8f6ba96b 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/mxm-wmi.h>
 #include <linux/acpi.h>
 
 MODULE_AUTHOR("Dave Airlie");
index 563e4f595f836c1d1ad966688d61c33e4a8d33d5..8f8551a63cc0b6de1bbb55a63ad538e760b72b63 100644 (file)
@@ -789,7 +789,7 @@ static int sony_nc_buffer_call(acpi_handle handle, char *name, u64 *value,
                void *buffer, size_t buflen)
 {
        int ret = 0;
-       size_t len = len;
+       size_t len;
        union acpi_object *object = __call_snc_method(handle, name, value);
 
        if (!object)
index 7ad1ed091f9225fc572a1b70fde9ecf622d06ad1..90dd7645a9e504449fd837ec1ad280775fc84ae9 100644 (file)
@@ -149,6 +149,7 @@ static const struct acpi_device_id toshiba_device_ids[] = {
 MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
 
 static const struct key_entry toshiba_acpi_keymap[] = {
+       { KE_KEY, 0x9e, { KEY_RFKILL } },
        { KE_KEY, 0x101, { KEY_MUTE } },
        { KE_KEY, 0x102, { KEY_ZOOMOUT } },
        { KE_KEY, 0x103, { KEY_ZOOMIN } },
index 7acab93d5a47effcb69a94062efb33fe16ffda24..22f2f2857b820675950fdd11f34470789cf81ff0 100644 (file)
@@ -41,6 +41,15 @@ config PWM_AB8500
          To compile this driver as a module, choose M here: the module
          will be called pwm-ab8500.
 
+config PWM_ATMEL
+       tristate "Atmel PWM support"
+       depends on ARCH_AT91
+       help
+         Generic PWM framework driver for Atmel SoC.
+
+         To compile this driver as a module, choose M here: the module
+         will be called pwm-atmel.
+
 config PWM_ATMEL_TCB
        tristate "Atmel TC Block PWM support"
        depends on ATMEL_TCLIB && OF
@@ -122,7 +131,8 @@ config PWM_MXS
 
 config PWM_PCA9685
        tristate "NXP PCA9685 PWM driver"
-       depends on OF && REGMAP_I2C
+       depends on OF && I2C
+       select REGMAP_I2C
        help
          Generic PWM framework driver for NXP PCA9685 LED controller.
 
@@ -149,7 +159,7 @@ config PWM_PXA
 
 config PWM_RENESAS_TPU
        tristate "Renesas TPU PWM support"
-       depends on ARCH_SHMOBILE
+       depends on ARCH_SHMOBILE || COMPILE_TEST
        help
          This driver exposes the Timer Pulse Unit (TPU) PWM controller found
          in Renesas chips through the PWM API.
index 4abf337dcd0231759d0450943516b3d45026c02b..d8906ec699761ac573c74839c83e9eb46b9db767 100644 (file)
@@ -1,6 +1,7 @@
 obj-$(CONFIG_PWM)              += core.o
 obj-$(CONFIG_PWM_SYSFS)                += sysfs.o
 obj-$(CONFIG_PWM_AB8500)       += pwm-ab8500.o
+obj-$(CONFIG_PWM_ATMEL)                += pwm-atmel.o
 obj-$(CONFIG_PWM_ATMEL_TCB)    += pwm-atmel-tcb.o
 obj-$(CONFIG_PWM_BFIN)         += pwm-bfin.o
 obj-$(CONFIG_PWM_EP93XX)       += pwm-ep93xx.o
index 2ca95042a0b93bbe80289675f9aafe36e64031cc..a80471399c20314edb69442bac0fe57cf06efec9 100644 (file)
@@ -808,12 +808,12 @@ static void pwm_dbg_show(struct pwm_chip *chip, struct seq_file *s)
                seq_printf(s, " pwm-%-3d (%-20.20s):", i, pwm->label);
 
                if (test_bit(PWMF_REQUESTED, &pwm->flags))
-                       seq_printf(s, " requested");
+                       seq_puts(s, " requested");
 
                if (test_bit(PWMF_ENABLED, &pwm->flags))
-                       seq_printf(s, " enabled");
+                       seq_puts(s, " enabled");
 
-               seq_printf(s, "\n");
+               seq_puts(s, "\n");
        }
 }
 
diff --git a/drivers/pwm/pwm-atmel.c b/drivers/pwm/pwm-atmel.c
new file mode 100644 (file)
index 0000000..bf4144a
--- /dev/null
@@ -0,0 +1,395 @@
+/*
+ * Driver for Atmel Pulse Width Modulation Controller
+ *
+ * Copyright (C) 2013 Atmel Corporation
+ *              Bo Shen <voice.shen@atmel.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+
+/* The following is global registers for PWM controller */
+#define PWM_ENA                        0x04
+#define PWM_DIS                        0x08
+#define PWM_SR                 0x0C
+/* Bit field in SR */
+#define PWM_SR_ALL_CH_ON       0x0F
+
+/* The following register is PWM channel related registers */
+#define PWM_CH_REG_OFFSET      0x200
+#define PWM_CH_REG_SIZE                0x20
+
+#define PWM_CMR                        0x0
+/* Bit field in CMR */
+#define PWM_CMR_CPOL           (1 << 9)
+#define PWM_CMR_UPD_CDTY       (1 << 10)
+
+/* The following registers for PWM v1 */
+#define PWMV1_CDTY             0x04
+#define PWMV1_CPRD             0x08
+#define PWMV1_CUPD             0x10
+
+/* The following registers for PWM v2 */
+#define PWMV2_CDTY             0x04
+#define PWMV2_CDTYUPD          0x08
+#define PWMV2_CPRD             0x0C
+#define PWMV2_CPRDUPD          0x10
+
+/*
+ * Max value for duty and period
+ *
+ * Although the duty and period register is 32 bit,
+ * however only the LSB 16 bits are significant.
+ */
+#define PWM_MAX_DTY            0xFFFF
+#define PWM_MAX_PRD            0xFFFF
+#define PRD_MAX_PRES           10
+
+struct atmel_pwm_chip {
+       struct pwm_chip chip;
+       struct clk *clk;
+       void __iomem *base;
+
+       void (*config)(struct pwm_chip *chip, struct pwm_device *pwm,
+                      unsigned long dty, unsigned long prd);
+};
+
+static inline struct atmel_pwm_chip *to_atmel_pwm_chip(struct pwm_chip *chip)
+{
+       return container_of(chip, struct atmel_pwm_chip, chip);
+}
+
+static inline u32 atmel_pwm_readl(struct atmel_pwm_chip *chip,
+                                 unsigned long offset)
+{
+       return readl_relaxed(chip->base + offset);
+}
+
+static inline void atmel_pwm_writel(struct atmel_pwm_chip *chip,
+                                   unsigned long offset, unsigned long val)
+{
+       writel_relaxed(val, chip->base + offset);
+}
+
+static inline u32 atmel_pwm_ch_readl(struct atmel_pwm_chip *chip,
+                                    unsigned int ch, unsigned long offset)
+{
+       unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE;
+
+       return readl_relaxed(chip->base + base + offset);
+}
+
+static inline void atmel_pwm_ch_writel(struct atmel_pwm_chip *chip,
+                                      unsigned int ch, unsigned long offset,
+                                      unsigned long val)
+{
+       unsigned long base = PWM_CH_REG_OFFSET + ch * PWM_CH_REG_SIZE;
+
+       writel_relaxed(val, chip->base + base + offset);
+}
+
+static int atmel_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+                           int duty_ns, int period_ns)
+{
+       struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
+       unsigned long clk_rate, prd, dty;
+       unsigned long long div;
+       unsigned int pres = 0;
+       int ret;
+
+       if (test_bit(PWMF_ENABLED, &pwm->flags) && (period_ns != pwm->period)) {
+               dev_err(chip->dev, "cannot change PWM period while enabled\n");
+               return -EBUSY;
+       }
+
+       clk_rate = clk_get_rate(atmel_pwm->clk);
+       div = clk_rate;
+
+       /* Calculate the period cycles */
+       while (div > PWM_MAX_PRD) {
+               div = clk_rate / (1 << pres);
+               div = div * period_ns;
+               /* 1/Hz = 100000000 ns */
+               do_div(div, 1000000000);
+
+               if (pres++ > PRD_MAX_PRES) {
+                       dev_err(chip->dev, "pres exceeds the maximum value\n");
+                       return -EINVAL;
+               }
+       }
+
+       /* Calculate the duty cycles */
+       prd = div;
+       div *= duty_ns;
+       do_div(div, period_ns);
+       dty = div;
+
+       ret = clk_enable(atmel_pwm->clk);
+       if (ret) {
+               dev_err(chip->dev, "failed to enable PWM clock\n");
+               return ret;
+       }
+
+       atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, pres);
+       atmel_pwm->config(chip, pwm, dty, prd);
+
+       clk_disable(atmel_pwm->clk);
+       return ret;
+}
+
+static void atmel_pwm_config_v1(struct pwm_chip *chip, struct pwm_device *pwm,
+                               unsigned long dty, unsigned long prd)
+{
+       struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
+       unsigned int val;
+
+       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+               /*
+                * If the PWM channel is enabled, using the update register,
+                * it needs to set bit 10 of CMR to 0
+                */
+               atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CUPD, dty);
+
+               val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
+               val &= ~PWM_CMR_UPD_CDTY;
+               atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
+       } else {
+               /*
+                * If the PWM channel is disabled, write value to duty and
+                * period registers directly.
+                */
+               atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CDTY, dty);
+               atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV1_CPRD, prd);
+       }
+}
+
+static void atmel_pwm_config_v2(struct pwm_chip *chip, struct pwm_device *pwm,
+                               unsigned long dty, unsigned long prd)
+{
+       struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
+
+       if (test_bit(PWMF_ENABLED, &pwm->flags)) {
+               /*
+                * If the PWM channel is enabled, using the duty update register
+                * to update the value.
+                */
+               atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CDTYUPD, dty);
+       } else {
+               /*
+                * If the PWM channel is disabled, write value to duty and
+                * period registers directly.
+                */
+               atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CDTY, dty);
+               atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWMV2_CPRD, prd);
+       }
+}
+
+static int atmel_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+                                 enum pwm_polarity polarity)
+{
+       struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
+       u32 val;
+       int ret;
+
+       val = atmel_pwm_ch_readl(atmel_pwm, pwm->hwpwm, PWM_CMR);
+
+       if (polarity == PWM_POLARITY_NORMAL)
+               val &= ~PWM_CMR_CPOL;
+       else
+               val |= PWM_CMR_CPOL;
+
+       ret = clk_enable(atmel_pwm->clk);
+       if (ret) {
+               dev_err(chip->dev, "failed to enable PWM clock\n");
+               return ret;
+       }
+
+       atmel_pwm_ch_writel(atmel_pwm, pwm->hwpwm, PWM_CMR, val);
+
+       clk_disable(atmel_pwm->clk);
+
+       return 0;
+}
+
+static int atmel_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
+       int ret;
+
+       ret = clk_enable(atmel_pwm->clk);
+       if (ret) {
+               dev_err(chip->dev, "failed to enable PWM clock\n");
+               return ret;
+       }
+
+       atmel_pwm_writel(atmel_pwm, PWM_ENA, 1 << pwm->hwpwm);
+
+       return 0;
+}
+
+static void atmel_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+       struct atmel_pwm_chip *atmel_pwm = to_atmel_pwm_chip(chip);
+
+       atmel_pwm_writel(atmel_pwm, PWM_DIS, 1 << pwm->hwpwm);
+
+       clk_disable(atmel_pwm->clk);
+}
+
+static const struct pwm_ops atmel_pwm_ops = {
+       .config = atmel_pwm_config,
+       .set_polarity = atmel_pwm_set_polarity,
+       .enable = atmel_pwm_enable,
+       .disable = atmel_pwm_disable,
+       .owner = THIS_MODULE,
+};
+
+struct atmel_pwm_data {
+       void (*config)(struct pwm_chip *chip, struct pwm_device *pwm,
+                      unsigned long dty, unsigned long prd);
+};
+
+static const struct atmel_pwm_data atmel_pwm_data_v1 = {
+       .config = atmel_pwm_config_v1,
+};
+
+static const struct atmel_pwm_data atmel_pwm_data_v2 = {
+       .config = atmel_pwm_config_v2,
+};
+
+static const struct platform_device_id atmel_pwm_devtypes[] = {
+       {
+               .name = "at91sam9rl-pwm",
+               .driver_data = (kernel_ulong_t)&atmel_pwm_data_v1,
+       }, {
+               .name = "sama5d3-pwm",
+               .driver_data = (kernel_ulong_t)&atmel_pwm_data_v2,
+       }, {
+               /* sentinel */
+       },
+};
+MODULE_DEVICE_TABLE(platform, atmel_pwm_devtypes);
+
+static const struct of_device_id atmel_pwm_dt_ids[] = {
+       {
+               .compatible = "atmel,at91sam9rl-pwm",
+               .data = &atmel_pwm_data_v1,
+       }, {
+               .compatible = "atmel,sama5d3-pwm",
+               .data = &atmel_pwm_data_v2,
+       }, {
+               /* sentinel */
+       },
+};
+MODULE_DEVICE_TABLE(of, atmel_pwm_dt_ids);
+
+static inline const struct atmel_pwm_data *
+atmel_pwm_get_driver_data(struct platform_device *pdev)
+{
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+
+               match = of_match_device(atmel_pwm_dt_ids, &pdev->dev);
+               if (!match)
+                       return NULL;
+
+               return match->data;
+       } else {
+               const struct platform_device_id *id;
+
+               id = platform_get_device_id(pdev);
+
+               return (struct atmel_pwm_data *)id->driver_data;
+       }
+}
+
+static int atmel_pwm_probe(struct platform_device *pdev)
+{
+       const struct atmel_pwm_data *data;
+       struct atmel_pwm_chip *atmel_pwm;
+       struct resource *res;
+       int ret;
+
+       data = atmel_pwm_get_driver_data(pdev);
+       if (!data)
+               return -ENODEV;
+
+       atmel_pwm = devm_kzalloc(&pdev->dev, sizeof(*atmel_pwm), GFP_KERNEL);
+       if (!atmel_pwm)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       atmel_pwm->base = devm_ioremap_resource(&pdev->dev, res);
+       if (IS_ERR(atmel_pwm->base))
+               return PTR_ERR(atmel_pwm->base);
+
+       atmel_pwm->clk = devm_clk_get(&pdev->dev, NULL);
+       if (IS_ERR(atmel_pwm->clk))
+               return PTR_ERR(atmel_pwm->clk);
+
+       ret = clk_prepare(atmel_pwm->clk);
+       if (ret) {
+               dev_err(&pdev->dev, "failed to prepare PWM clock\n");
+               return ret;
+       }
+
+       atmel_pwm->chip.dev = &pdev->dev;
+       atmel_pwm->chip.ops = &atmel_pwm_ops;
+
+       if (pdev->dev.of_node) {
+               atmel_pwm->chip.of_xlate = of_pwm_xlate_with_flags;
+               atmel_pwm->chip.of_pwm_n_cells = 3;
+       }
+
+       atmel_pwm->chip.base = -1;
+       atmel_pwm->chip.npwm = 4;
+       atmel_pwm->config = data->config;
+
+       ret = pwmchip_add(&atmel_pwm->chip);
+       if (ret < 0) {
+               dev_err(&pdev->dev, "failed to add PWM chip %d\n", ret);
+               goto unprepare_clk;
+       }
+
+       platform_set_drvdata(pdev, atmel_pwm);
+
+       return ret;
+
+unprepare_clk:
+       clk_unprepare(atmel_pwm->clk);
+       return ret;
+}
+
+static int atmel_pwm_remove(struct platform_device *pdev)
+{
+       struct atmel_pwm_chip *atmel_pwm = platform_get_drvdata(pdev);
+
+       clk_unprepare(atmel_pwm->clk);
+
+       return pwmchip_remove(&atmel_pwm->chip);
+}
+
+static struct platform_driver atmel_pwm_driver = {
+       .driver = {
+               .name = "atmel-pwm",
+               .of_match_table = of_match_ptr(atmel_pwm_dt_ids),
+       },
+       .id_table = atmel_pwm_devtypes,
+       .probe = atmel_pwm_probe,
+       .remove = atmel_pwm_remove,
+};
+module_platform_driver(atmel_pwm_driver);
+
+MODULE_ALIAS("platform:atmel-pwm");
+MODULE_AUTHOR("Bo Shen <voice.shen@atmel.com>");
+MODULE_DESCRIPTION("Atmel PWM driver");
+MODULE_LICENSE("GPL v2");
index 33aa4461e1ce8735d0ddc7a9a1688823a25a22b8..e593e9c45c51c1118f88ae12cc4a546498c77b40 100644 (file)
@@ -224,7 +224,7 @@ static struct platform_driver ep93xx_pwm_driver = {
 module_platform_driver(ep93xx_pwm_driver);
 
 MODULE_DESCRIPTION("Cirrus Logic EP93xx PWM driver");
-MODULE_AUTHOR("Matthieu Crapet <mcrapet@gmail.com>, "
-             "H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_AUTHOR("Matthieu Crapet <mcrapet@gmail.com>");
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
 MODULE_ALIAS("platform:ep93xx-pwm");
 MODULE_LICENSE("GPL");
index 0a2ede3c3932cf440e1b72d38d199bfac759335b..9c46209e1d02aae6845bfe8d4dad5a153c36b07d 100644 (file)
@@ -165,13 +165,12 @@ static const struct pwm_ops jz4740_pwm_ops = {
 static int jz4740_pwm_probe(struct platform_device *pdev)
 {
        struct jz4740_pwm_chip *jz4740;
-       int ret;
 
        jz4740 = devm_kzalloc(&pdev->dev, sizeof(*jz4740), GFP_KERNEL);
        if (!jz4740)
                return -ENOMEM;
 
-       jz4740->clk = clk_get(NULL, "ext");
+       jz4740->clk = devm_clk_get(&pdev->dev, "ext");
        if (IS_ERR(jz4740->clk))
                return PTR_ERR(jz4740->clk);
 
@@ -180,29 +179,16 @@ static int jz4740_pwm_probe(struct platform_device *pdev)
        jz4740->chip.npwm = NUM_PWM;
        jz4740->chip.base = -1;
 
-       ret = pwmchip_add(&jz4740->chip);
-       if (ret < 0) {
-               clk_put(jz4740->clk);
-               return ret;
-       }
-
        platform_set_drvdata(pdev, jz4740);
 
-       return 0;
+       return pwmchip_add(&jz4740->chip);
 }
 
 static int jz4740_pwm_remove(struct platform_device *pdev)
 {
        struct jz4740_pwm_chip *jz4740 = platform_get_drvdata(pdev);
-       int ret;
-
-       ret = pwmchip_remove(&jz4740->chip);
-       if (ret < 0)
-               return ret;
 
-       clk_put(jz4740->clk);
-
-       return 0;
+       return pwmchip_remove(&jz4740->chip);
 }
 
 static struct platform_driver jz4740_pwm_driver = {
index a4d2164aaf55836cc662784f1e9a6f071e6d8be5..8d995731cef8d13a96f8168161a038c7446e3d5a 100644 (file)
@@ -8,7 +8,7 @@
  * published by the Free Software Foundation.
  *
  * 2008-02-13  initial version
- *             eric miao <eric.miao@marvell.com>
+ *             eric miao <eric.miao@marvell.com>
  */
 
 #include <linux/module.h>
@@ -19,6 +19,7 @@
 #include <linux/clk.h>
 #include <linux/io.h>
 #include <linux/pwm.h>
+#include <linux/of_device.h>
 
 #include <asm/div64.h>
 
@@ -124,6 +125,46 @@ static struct pwm_ops pxa_pwm_ops = {
        .owner = THIS_MODULE,
 };
 
+#ifdef CONFIG_OF
+/*
+ * Device tree users must create one device instance for each pwm channel.
+ * Hence we dispense with the HAS_SECONDARY_PWM and "tell" the original driver
+ * code that this is a single channel pxa25x-pwm.  Currently all devices are
+ * supported identically.
+ */
+static struct of_device_id pwm_of_match[] = {
+       { .compatible = "marvell,pxa250-pwm", .data = &pwm_id_table[0]},
+       { .compatible = "marvell,pxa270-pwm", .data = &pwm_id_table[0]},
+       { .compatible = "marvell,pxa168-pwm", .data = &pwm_id_table[0]},
+       { .compatible = "marvell,pxa910-pwm", .data = &pwm_id_table[0]},
+       { }
+};
+MODULE_DEVICE_TABLE(of, pwm_of_match);
+#else
+#define pwm_of_match NULL
+#endif
+
+static const struct platform_device_id *pxa_pwm_get_id_dt(struct device *dev)
+{
+       const struct of_device_id *id = of_match_device(pwm_of_match, dev);
+
+       return id ? id->data : NULL;
+}
+
+static struct pwm_device *
+pxa_pwm_of_xlate(struct pwm_chip *pc, const struct of_phandle_args *args)
+{
+       struct pwm_device *pwm;
+
+       pwm = pwm_request_from_chip(pc, 0, NULL);
+       if (IS_ERR(pwm))
+               return pwm;
+
+       pwm_set_period(pwm, args->args[0]);
+
+       return pwm;
+}
+
 static int pwm_probe(struct platform_device *pdev)
 {
        const struct platform_device_id *id = platform_get_device_id(pdev);
@@ -131,6 +172,12 @@ static int pwm_probe(struct platform_device *pdev)
        struct resource *r;
        int ret = 0;
 
+       if (IS_ENABLED(CONFIG_OF) && id == NULL)
+               id = pxa_pwm_get_id_dt(&pdev->dev);
+
+       if (id == NULL)
+               return -EINVAL;
+
        pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
        if (pwm == NULL) {
                dev_err(&pdev->dev, "failed to allocate memory\n");
@@ -146,6 +193,11 @@ static int pwm_probe(struct platform_device *pdev)
        pwm->chip.base = -1;
        pwm->chip.npwm = (id->driver_data & HAS_SECONDARY_PWM) ? 2 : 1;
 
+       if (IS_ENABLED(CONFIG_OF)) {
+               pwm->chip.of_xlate = pxa_pwm_of_xlate;
+               pwm->chip.of_pwm_n_cells = 1;
+       }
+
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        pwm->mmio_base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(pwm->mmio_base))
@@ -176,6 +228,7 @@ static struct platform_driver pwm_driver = {
        .driver         = {
                .name   = "pxa25x-pwm",
                .owner  = THIS_MODULE,
+               .of_match_table = pwm_of_match,
        },
        .probe          = pwm_probe,
        .remove         = pwm_remove,
index 4e5c3d13d4f8d31a0faa65ccd7146c0a28436e3c..032092c7a6ae3d23705ca79d6d1e175b2a524768 100644 (file)
@@ -279,7 +279,6 @@ static int ecap_pwm_remove(struct platform_device *pdev)
        pwmss_submodule_state_change(pdev->dev.parent, PWMSS_ECAPCLK_STOP_REQ);
        pm_runtime_put_sync(&pdev->dev);
 
-       pm_runtime_put_sync(&pdev->dev);
        pm_runtime_disable(&pdev->dev);
        return pwmchip_remove(&pc->chip);
 }
index a4d8f519d965660d1a33e0cdfc7bda02224fbd7d..aee4471424d14a98da494f877909ae5e9f804990 100644 (file)
@@ -360,8 +360,8 @@ static int ehrpwm_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
        /* Enable TBCLK before enabling PWM device */
        ret = clk_enable(pc->tbclk);
        if (ret) {
-               pr_err("Failed to enable TBCLK for %s\n",
-                               dev_name(pc->chip.dev));
+               dev_err(chip->dev, "Failed to enable TBCLK for %s\n",
+                       dev_name(pc->chip.dev));
                return ret;
        }
 
index 8c20332d4825810a366e3af07b1d8831617d1951..4bd0c639e16da9d49598f637c5473ae37e419def 100644 (file)
@@ -169,15 +169,7 @@ static struct attribute *pwm_attrs[] = {
        &dev_attr_polarity.attr,
        NULL
 };
-
-static const struct attribute_group pwm_attr_group = {
-       .attrs          = pwm_attrs,
-};
-
-static const struct attribute_group *pwm_attr_groups[] = {
-       &pwm_attr_group,
-       NULL,
-};
+ATTRIBUTE_GROUPS(pwm);
 
 static void pwm_export_release(struct device *child)
 {
@@ -205,7 +197,7 @@ static int pwm_export_child(struct device *parent, struct pwm_device *pwm)
        export->child.release = pwm_export_release;
        export->child.parent = parent;
        export->child.devt = MKDEV(0, 0);
-       export->child.groups = pwm_attr_groups;
+       export->child.groups = pwm_groups;
        dev_set_name(&export->child, "pwm%u", pwm->hwpwm);
 
        ret = device_register(&export->child);
index 92bd22ce676012697be18504d96741b4a3910466..9cbc567698cefd0d3933f7c77198d4ccf34ceeeb 100644 (file)
@@ -504,7 +504,7 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
        struct dasd_diag_req *dreq;
        struct dasd_diag_bio *dbio;
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        char *dst;
        unsigned int count, datasize;
        sector_t recid, first_rec, last_rec;
@@ -525,10 +525,10 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
        /* Check struct bio and count the number of blocks for the request. */
        count = 0;
        rq_for_each_segment(bv, req, iter) {
-               if (bv->bv_len & (blksize - 1))
+               if (bv.bv_len & (blksize - 1))
                        /* Fba can only do full blocks. */
                        return ERR_PTR(-EINVAL);
-               count += bv->bv_len >> (block->s2b_shift + 9);
+               count += bv.bv_len >> (block->s2b_shift + 9);
        }
        /* Paranoia. */
        if (count != last_rec - first_rec + 1)
@@ -545,8 +545,8 @@ static struct dasd_ccw_req *dasd_diag_build_cp(struct dasd_device *memdev,
        dbio = dreq->bio;
        recid = first_rec;
        rq_for_each_segment(bv, req, iter) {
-               dst = page_address(bv->bv_page) + bv->bv_offset;
-               for (off = 0; off < bv->bv_len; off += blksize) {
+               dst = page_address(bv.bv_page) + bv.bv_offset;
+               for (off = 0; off < bv.bv_len; off += blksize) {
                        memset(dbio, 0, sizeof (struct dasd_diag_bio));
                        dbio->type = rw_cmd;
                        dbio->block_number = recid + 1;
index 95e45782692fa7bb2a89e9ec566a6a035f736381..2e8e0755070b609b13e9e49f5db5f17ac232ef69 100644 (file)
@@ -2551,7 +2551,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        char *dst;
        unsigned int off;
        int count, cidaw, cplength, datasize;
@@ -2573,13 +2573,13 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
        count = 0;
        cidaw = 0;
        rq_for_each_segment(bv, req, iter) {
-               if (bv->bv_len & (blksize - 1))
+               if (bv.bv_len & (blksize - 1))
                        /* Eckd can only do full blocks. */
                        return ERR_PTR(-EINVAL);
-               count += bv->bv_len >> (block->s2b_shift + 9);
+               count += bv.bv_len >> (block->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
-               if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
-                       cidaw += bv->bv_len >> (block->s2b_shift + 9);
+               if (idal_is_needed (page_address(bv.bv_page), bv.bv_len))
+                       cidaw += bv.bv_len >> (block->s2b_shift + 9);
 #endif
        }
        /* Paranoia. */
@@ -2650,16 +2650,16 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_single(
                              last_rec - recid + 1, cmd, basedev, blksize);
        }
        rq_for_each_segment(bv, req, iter) {
-               dst = page_address(bv->bv_page) + bv->bv_offset;
+               dst = page_address(bv.bv_page) + bv.bv_offset;
                if (dasd_page_cache) {
                        char *copy = kmem_cache_alloc(dasd_page_cache,
                                                      GFP_DMA | __GFP_NOWARN);
                        if (copy && rq_data_dir(req) == WRITE)
-                               memcpy(copy + bv->bv_offset, dst, bv->bv_len);
+                               memcpy(copy + bv.bv_offset, dst, bv.bv_len);
                        if (copy)
-                               dst = copy + bv->bv_offset;
+                               dst = copy + bv.bv_offset;
                }
-               for (off = 0; off < bv->bv_len; off += blksize) {
+               for (off = 0; off < bv.bv_len; off += blksize) {
                        sector_t trkid = recid;
                        unsigned int recoffs = sector_div(trkid, blk_per_trk);
                        rcmd = cmd;
@@ -2735,7 +2735,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        char *dst, *idaw_dst;
        unsigned int cidaw, cplength, datasize;
        unsigned int tlf;
@@ -2813,8 +2813,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_cmd_track(
        idaw_dst = NULL;
        idaw_len = 0;
        rq_for_each_segment(bv, req, iter) {
-               dst = page_address(bv->bv_page) + bv->bv_offset;
-               seg_len = bv->bv_len;
+               dst = page_address(bv.bv_page) + bv.bv_offset;
+               seg_len = bv.bv_len;
                while (seg_len) {
                        if (new_track) {
                                trkid = recid;
@@ -3039,7 +3039,7 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
 {
        struct dasd_ccw_req *cqr;
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        char *dst;
        unsigned int trkcount, ctidaw;
        unsigned char cmd;
@@ -3125,8 +3125,8 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
                new_track = 1;
                recid = first_rec;
                rq_for_each_segment(bv, req, iter) {
-                       dst = page_address(bv->bv_page) + bv->bv_offset;
-                       seg_len = bv->bv_len;
+                       dst = page_address(bv.bv_page) + bv.bv_offset;
+                       seg_len = bv.bv_len;
                        while (seg_len) {
                                if (new_track) {
                                        trkid = recid;
@@ -3158,9 +3158,9 @@ static struct dasd_ccw_req *dasd_eckd_build_cp_tpm_track(
                }
        } else {
                rq_for_each_segment(bv, req, iter) {
-                       dst = page_address(bv->bv_page) + bv->bv_offset;
+                       dst = page_address(bv.bv_page) + bv.bv_offset;
                        last_tidaw = itcw_add_tidaw(itcw, 0x00,
-                                                   dst, bv->bv_len);
+                                                   dst, bv.bv_len);
                        if (IS_ERR(last_tidaw)) {
                                ret = -EINVAL;
                                goto out_error;
@@ -3278,7 +3278,7 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        char *dst;
        unsigned char cmd;
        unsigned int trkcount;
@@ -3378,8 +3378,8 @@ static struct dasd_ccw_req *dasd_raw_build_cp(struct dasd_device *startdev,
                        idaws = idal_create_words(idaws, rawpadpage, PAGE_SIZE);
        }
        rq_for_each_segment(bv, req, iter) {
-               dst = page_address(bv->bv_page) + bv->bv_offset;
-               seg_len = bv->bv_len;
+               dst = page_address(bv.bv_page) + bv.bv_offset;
+               seg_len = bv.bv_len;
                if (cmd == DASD_ECKD_CCW_READ_TRACK)
                        memset(dst, 0, seg_len);
                if (!len_to_track_end) {
@@ -3424,7 +3424,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
        struct dasd_eckd_private *private;
        struct ccw1 *ccw;
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        char *dst, *cda;
        unsigned int blksize, blk_per_trk, off;
        sector_t recid;
@@ -3442,8 +3442,8 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
        if (private->uses_cdl == 0 || recid > 2*blk_per_trk)
                ccw++;
        rq_for_each_segment(bv, req, iter) {
-               dst = page_address(bv->bv_page) + bv->bv_offset;
-               for (off = 0; off < bv->bv_len; off += blksize) {
+               dst = page_address(bv.bv_page) + bv.bv_offset;
+               for (off = 0; off < bv.bv_len; off += blksize) {
                        /* Skip locate record. */
                        if (private->uses_cdl && recid <= 2*blk_per_trk)
                                ccw++;
@@ -3454,7 +3454,7 @@ dasd_eckd_free_cp(struct dasd_ccw_req *cqr, struct request *req)
                                        cda = (char *)((addr_t) ccw->cda);
                                if (dst != cda) {
                                        if (rq_data_dir(req) == READ)
-                                               memcpy(dst, cda, bv->bv_len);
+                                               memcpy(dst, cda, bv.bv_len);
                                        kmem_cache_free(dasd_page_cache,
                                            (void *)((addr_t)cda & PAGE_MASK));
                                }
index 9cbc8c32ba595739cdff63da752a8f080b51e0de..2c8e68bf9a1cd658be919151387fe3ae24bffad3 100644 (file)
@@ -260,7 +260,7 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
        struct dasd_ccw_req *cqr;
        struct ccw1 *ccw;
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        char *dst;
        int count, cidaw, cplength, datasize;
        sector_t recid, first_rec, last_rec;
@@ -283,13 +283,13 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
        count = 0;
        cidaw = 0;
        rq_for_each_segment(bv, req, iter) {
-               if (bv->bv_len & (blksize - 1))
+               if (bv.bv_len & (blksize - 1))
                        /* Fba can only do full blocks. */
                        return ERR_PTR(-EINVAL);
-               count += bv->bv_len >> (block->s2b_shift + 9);
+               count += bv.bv_len >> (block->s2b_shift + 9);
 #if defined(CONFIG_64BIT)
-               if (idal_is_needed (page_address(bv->bv_page), bv->bv_len))
-                       cidaw += bv->bv_len / blksize;
+               if (idal_is_needed (page_address(bv.bv_page), bv.bv_len))
+                       cidaw += bv.bv_len / blksize;
 #endif
        }
        /* Paranoia. */
@@ -326,16 +326,16 @@ static struct dasd_ccw_req *dasd_fba_build_cp(struct dasd_device * memdev,
        }
        recid = first_rec;
        rq_for_each_segment(bv, req, iter) {
-               dst = page_address(bv->bv_page) + bv->bv_offset;
+               dst = page_address(bv.bv_page) + bv.bv_offset;
                if (dasd_page_cache) {
                        char *copy = kmem_cache_alloc(dasd_page_cache,
                                                      GFP_DMA | __GFP_NOWARN);
                        if (copy && rq_data_dir(req) == WRITE)
-                               memcpy(copy + bv->bv_offset, dst, bv->bv_len);
+                               memcpy(copy + bv.bv_offset, dst, bv.bv_len);
                        if (copy)
-                               dst = copy + bv->bv_offset;
+                               dst = copy + bv.bv_offset;
                }
-               for (off = 0; off < bv->bv_len; off += blksize) {
+               for (off = 0; off < bv.bv_len; off += blksize) {
                        /* Locate record for stupid devices. */
                        if (private->rdc_data.mode.bits.data_chain == 0) {
                                ccw[-1].flags |= CCW_FLAG_CC;
@@ -384,7 +384,7 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
        struct dasd_fba_private *private;
        struct ccw1 *ccw;
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        char *dst, *cda;
        unsigned int blksize, off;
        int status;
@@ -399,8 +399,8 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
        if (private->rdc_data.mode.bits.data_chain != 0)
                ccw++;
        rq_for_each_segment(bv, req, iter) {
-               dst = page_address(bv->bv_page) + bv->bv_offset;
-               for (off = 0; off < bv->bv_len; off += blksize) {
+               dst = page_address(bv.bv_page) + bv.bv_offset;
+               for (off = 0; off < bv.bv_len; off += blksize) {
                        /* Skip locate record. */
                        if (private->rdc_data.mode.bits.data_chain == 0)
                                ccw++;
@@ -411,7 +411,7 @@ dasd_fba_free_cp(struct dasd_ccw_req *cqr, struct request *req)
                                        cda = (char *)((addr_t) ccw->cda);
                                if (dst != cda) {
                                        if (rq_data_dir(req) == READ)
-                                               memcpy(dst, cda, bv->bv_len);
+                                               memcpy(dst, cda, bv.bv_len);
                                        kmem_cache_free(dasd_page_cache,
                                            (void *)((addr_t)cda & PAGE_MASK));
                                }
index 6eca019bcf30a50edfab1a80daf1b351d2320474..ebf41e228e55836e6ec764b105c357e1856c9d1b 100644 (file)
@@ -808,18 +808,19 @@ static void
 dcssblk_make_request(struct request_queue *q, struct bio *bio)
 {
        struct dcssblk_dev_info *dev_info;
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
        unsigned long index;
        unsigned long page_addr;
        unsigned long source_addr;
        unsigned long bytes_done;
-       int i;
 
        bytes_done = 0;
        dev_info = bio->bi_bdev->bd_disk->private_data;
        if (dev_info == NULL)
                goto fail;
-       if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0)
+       if ((bio->bi_iter.bi_sector & 7) != 0 ||
+           (bio->bi_iter.bi_size & 4095) != 0)
                /* Request is not page-aligned. */
                goto fail;
        if (bio_end_sector(bio) > get_capacity(bio->bi_bdev->bd_disk)) {
@@ -842,22 +843,22 @@ dcssblk_make_request(struct request_queue *q, struct bio *bio)
                }
        }
 
-       index = (bio->bi_sector >> 3);
-       bio_for_each_segment(bvec, bio, i) {
+       index = (bio->bi_iter.bi_sector >> 3);
+       bio_for_each_segment(bvec, bio, iter) {
                page_addr = (unsigned long)
-                       page_address(bvec->bv_page) + bvec->bv_offset;
+                       page_address(bvec.bv_page) + bvec.bv_offset;
                source_addr = dev_info->start + (index<<12) + bytes_done;
-               if (unlikely((page_addr & 4095) != 0) || (bvec->bv_len & 4095) != 0)
+               if (unlikely((page_addr & 4095) != 0) || (bvec.bv_len & 4095) != 0)
                        // More paranoia.
                        goto fail;
                if (bio_data_dir(bio) == READ) {
                        memcpy((void*)page_addr, (void*)source_addr,
-                               bvec->bv_len);
+                               bvec.bv_len);
                } else {
                        memcpy((void*)source_addr, (void*)page_addr,
-                               bvec->bv_len);
+                               bvec.bv_len);
                }
-               bytes_done += bvec->bv_len;
+               bytes_done += bvec.bv_len;
        }
        bio_endio(bio, 0);
        return;
index d0ab5019d885cea6113f677a4f58990fa4a3ca55..76bed1743db1c7ef23576282b13d9ef8f551aed8 100644 (file)
@@ -130,7 +130,7 @@ static void scm_request_prepare(struct scm_request *scmrq)
        struct aidaw *aidaw = scmrq->aidaw;
        struct msb *msb = &scmrq->aob->msb[0];
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
 
        msb->bs = MSB_BS_4K;
        scmrq->aob->request.msb_count = 1;
@@ -142,9 +142,9 @@ static void scm_request_prepare(struct scm_request *scmrq)
        msb->data_addr = (u64) aidaw;
 
        rq_for_each_segment(bv, scmrq->request, iter) {
-               WARN_ON(bv->bv_offset);
-               msb->blk_count += bv->bv_len >> 12;
-               aidaw->data_addr = (u64) page_address(bv->bv_page);
+               WARN_ON(bv.bv_offset);
+               msb->blk_count += bv.bv_len >> 12;
+               aidaw->data_addr = (u64) page_address(bv.bv_page);
                aidaw++;
        }
 }
index 27f930cd657fcdd3a223412cb68c393ebd565556..9aae909d47a53c88d6345101db2f344b8bc1f7a9 100644 (file)
@@ -122,7 +122,7 @@ static void scm_prepare_cluster_request(struct scm_request *scmrq)
        struct aidaw *aidaw = scmrq->aidaw;
        struct msb *msb = &scmrq->aob->msb[0];
        struct req_iterator iter;
-       struct bio_vec *bv;
+       struct bio_vec bv;
        int i = 0;
        u64 addr;
 
@@ -163,7 +163,7 @@ static void scm_prepare_cluster_request(struct scm_request *scmrq)
                        i++;
                }
                rq_for_each_segment(bv, req, iter) {
-                       aidaw->data_addr = (u64) page_address(bv->bv_page);
+                       aidaw->data_addr = (u64) page_address(bv.bv_page);
                        aidaw++;
                        i++;
                }
index 464dd29d06c07dcbeb1e6ee96a439dbb037a25a9..6969d39f1e2eba7de41856cabc0d1557b7f3efe4 100644 (file)
@@ -184,25 +184,26 @@ static unsigned long xpram_highest_page_index(void)
 static void xpram_make_request(struct request_queue *q, struct bio *bio)
 {
        xpram_device_t *xdev = bio->bi_bdev->bd_disk->private_data;
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
        unsigned int index;
        unsigned long page_addr;
        unsigned long bytes;
-       int i;
 
-       if ((bio->bi_sector & 7) != 0 || (bio->bi_size & 4095) != 0)
+       if ((bio->bi_iter.bi_sector & 7) != 0 ||
+           (bio->bi_iter.bi_size & 4095) != 0)
                /* Request is not page-aligned. */
                goto fail;
-       if ((bio->bi_size >> 12) > xdev->size)
+       if ((bio->bi_iter.bi_size >> 12) > xdev->size)
                /* Request size is no page-aligned. */
                goto fail;
-       if ((bio->bi_sector >> 3) > 0xffffffffU - xdev->offset)
+       if ((bio->bi_iter.bi_sector >> 3) > 0xffffffffU - xdev->offset)
                goto fail;
-       index = (bio->bi_sector >> 3) + xdev->offset;
-       bio_for_each_segment(bvec, bio, i) {
+       index = (bio->bi_iter.bi_sector >> 3) + xdev->offset;
+       bio_for_each_segment(bvec, bio, iter) {
                page_addr = (unsigned long)
-                       kmap(bvec->bv_page) + bvec->bv_offset;
-               bytes = bvec->bv_len;
+                       kmap(bvec.bv_page) + bvec.bv_offset;
+               bytes = bvec.bv_len;
                if ((page_addr & 4095) != 0 || (bytes & 4095) != 0)
                        /* More paranoia. */
                        goto fail;
@@ -257,6 +258,7 @@ static int __init xpram_setup_sizes(unsigned long pages)
        unsigned long mem_needed;
        unsigned long mem_auto;
        unsigned long long size;
+       char *sizes_end;
        int mem_auto_no;
        int i;
 
@@ -275,8 +277,8 @@ static int __init xpram_setup_sizes(unsigned long pages)
        mem_auto_no = 0;
        for (i = 0; i < xpram_devs; i++) {
                if (sizes[i]) {
-                       size = simple_strtoull(sizes[i], &sizes[i], 0);
-                       switch (sizes[i][0]) {
+                       size = simple_strtoull(sizes[i], &sizes_end, 0);
+                       switch (*sizes_end) {
                        case 'g':
                        case 'G':
                                size <<= 20;
index cb3c4e05a38503c043f35f1f9a70bc8f186e929f..49af8eeb90ea2b3cbd5786bdd075727b20a9a327 100644 (file)
@@ -700,3 +700,8 @@ out:
        free_page((unsigned long) sccb);
        return rc;
 }
+
+bool sclp_has_sprp(void)
+{
+       return !!(sclp_fac84 & 0x2);
+}
index 64c467998a90cbb47e5eed32cee3a0f6dc8a8ae3..0efb27f6f1999f4c85af4587c491b926fc30b251 100644 (file)
@@ -922,8 +922,8 @@ static int ur_set_online(struct ccw_device *cdev)
                goto fail_free_cdev;
        }
 
-       urd->device = device_create(vmur_class, NULL, urd->char_device->dev,
-                                   NULL, "%s", node_id);
+       urd->device = device_create(vmur_class, &cdev->dev,
+                                   urd->char_device->dev, NULL, "%s", node_id);
        if (IS_ERR(urd->device)) {
                rc = PTR_ERR(urd->device);
                TRACE("ur_set_online: device_create rc=%d\n", rc);
index d6297176ab85b8b306eb69be685dfba811ae35ba..0fc5848320018434997baed720632390b73ec0bf 100644 (file)
@@ -642,8 +642,15 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
             (SCSW_STCTL_ALERT_STATUS | SCSW_STCTL_STATUS_PEND))) {
                /* OK */
        }
-       if (irb_is_error(irb))
-               vcdev->err = -EIO; /* XXX - use real error */
+       if (irb_is_error(irb)) {
+               /* Command reject? */
+               if ((scsw_dstat(&irb->scsw) & DEV_STAT_UNIT_CHECK) &&
+                   (irb->ecw[0] & SNS0_CMD_REJECT))
+                       vcdev->err = -EOPNOTSUPP;
+               else
+                       /* Map everything else to -EIO. */
+                       vcdev->err = -EIO;
+       }
        if (vcdev->curr_io & activity) {
                switch (activity) {
                case VIRTIO_CCW_DOING_READ_FEAT:
index ac0bdded060fb259b483ecbe88c433550fff27c7..a0de045eb227d5eeb845bf9f6c925bbfcfe73634 100644 (file)
@@ -738,6 +738,8 @@ struct qeth_discipline {
        int (*freeze)(struct ccwgroup_device *);
        int (*thaw) (struct ccwgroup_device *);
        int (*restore)(struct ccwgroup_device *);
+       int (*control_event_handler)(struct qeth_card *card,
+                                       struct qeth_ipa_cmd *cmd);
 };
 
 struct qeth_vlan_vid {
@@ -948,13 +950,10 @@ int qeth_query_card_info(struct qeth_card *card,
 int qeth_send_control_data(struct qeth_card *, int, struct qeth_cmd_buffer *,
        int (*reply_cb)(struct qeth_card *, struct qeth_reply*, unsigned long),
        void *reply_param);
-void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd);
-void qeth_bridgeport_query_support(struct qeth_card *card);
 int qeth_bridgeport_query_ports(struct qeth_card *card,
        enum qeth_sbp_roles *role, enum qeth_sbp_states *state);
 int qeth_bridgeport_setrole(struct qeth_card *card, enum qeth_sbp_roles role);
 int qeth_bridgeport_an_set(struct qeth_card *card, int enable);
-void qeth_bridge_host_event(struct qeth_card *card, struct qeth_ipa_cmd *cmd);
 int qeth_get_priority_queue(struct qeth_card *, struct sk_buff *, int, int);
 int qeth_get_elements_no(struct qeth_card *, struct sk_buff *, int);
 int qeth_get_elements_for_frags(struct sk_buff *);
index c05dacbf4e23563eb73eafb6687080b9bad58faf..c3a83df07894e51195d914111c15be2c615f09c1 100644 (file)
@@ -69,6 +69,7 @@ static void qeth_clear_output_buffer(struct qeth_qdio_out_q *queue,
 static int qeth_init_qdio_out_buf(struct qeth_qdio_out_q *, int);
 
 struct workqueue_struct *qeth_wq;
+EXPORT_SYMBOL_GPL(qeth_wq);
 
 static void qeth_close_dev_handler(struct work_struct *work)
 {
@@ -616,15 +617,12 @@ static struct qeth_ipa_cmd *qeth_check_ipa_data(struct qeth_card *card,
                                qeth_schedule_recovery(card);
                                return NULL;
                        case IPA_CMD_SETBRIDGEPORT:
-                               if (cmd->data.sbp.hdr.command_code ==
-                                       IPA_SBP_BRIDGE_PORT_STATE_CHANGE) {
-                                       qeth_bridge_state_change(card, cmd);
-                                       return NULL;
-                               } else
-                                       return cmd;
                        case IPA_CMD_ADDRESS_CHANGE_NOTIF:
-                               qeth_bridge_host_event(card, cmd);
-                               return NULL;
+                               if (card->discipline->control_event_handler
+                                                               (card, cmd))
+                                       return cmd;
+                               else
+                                       return NULL;
                        case IPA_CMD_MODCCID:
                                return cmd;
                        case IPA_CMD_REGISTER_LOCAL_ADDR:
@@ -4973,10 +4971,6 @@ retriable:
                qeth_query_setadapterparms(card);
        if (qeth_adp_supported(card, IPA_SETADP_SET_DIAG_ASSIST))
                qeth_query_setdiagass(card);
-       qeth_bridgeport_query_support(card);
-       if (card->options.sbp.supported_funcs)
-               dev_info(&card->gdev->dev,
-               "The device represents a HiperSockets Bridge Capable Port\n");
        return 0;
 out:
        dev_warn(&card->gdev->dev, "The qeth device driver failed to recover "
index 914d2c121fd87c92fe9ed4acbddee3b5bee2c95d..0710550093ce6ac5fea8ddbf80f8409bbc1186f6 100644 (file)
@@ -33,6 +33,11 @@ static int qeth_l2_send_setdelmac(struct qeth_card *, __u8 *,
                                            unsigned long));
 static void qeth_l2_set_multicast_list(struct net_device *);
 static int qeth_l2_recover(void *);
+static void qeth_bridgeport_query_support(struct qeth_card *card);
+static void qeth_bridge_state_change(struct qeth_card *card,
+                                       struct qeth_ipa_cmd *cmd);
+static void qeth_bridge_host_event(struct qeth_card *card,
+                                       struct qeth_ipa_cmd *cmd);
 
 static int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
@@ -989,6 +994,10 @@ static int __qeth_l2_set_online(struct ccwgroup_device *gdev, int recovery_mode)
                rc = -ENODEV;
                goto out_remove;
        }
+       qeth_bridgeport_query_support(card);
+       if (card->options.sbp.supported_funcs)
+               dev_info(&card->gdev->dev,
+               "The device represents a HiperSockets Bridge Capable Port\n");
        qeth_trace_features(card);
 
        if (!card->dev && qeth_l2_setup_netdev(card)) {
@@ -1233,6 +1242,26 @@ out:
        return rc;
 }
 
+/* Returns zero if the command is successfully "consumed" */
+static int qeth_l2_control_event(struct qeth_card *card,
+                                       struct qeth_ipa_cmd *cmd)
+{
+       switch (cmd->hdr.command) {
+       case IPA_CMD_SETBRIDGEPORT:
+               if (cmd->data.sbp.hdr.command_code ==
+                               IPA_SBP_BRIDGE_PORT_STATE_CHANGE) {
+                       qeth_bridge_state_change(card, cmd);
+                       return 0;
+               } else
+                       return 1;
+       case IPA_CMD_ADDRESS_CHANGE_NOTIF:
+               qeth_bridge_host_event(card, cmd);
+               return 0;
+       default:
+               return 1;
+       }
+}
+
 struct qeth_discipline qeth_l2_discipline = {
        .start_poll = qeth_qdio_start_poll,
        .input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
@@ -1246,6 +1275,7 @@ struct qeth_discipline qeth_l2_discipline = {
        .freeze = qeth_l2_pm_suspend,
        .thaw = qeth_l2_pm_resume,
        .restore = qeth_l2_pm_resume,
+       .control_event_handler = qeth_l2_control_event,
 };
 EXPORT_SYMBOL_GPL(qeth_l2_discipline);
 
@@ -1463,7 +1493,8 @@ static void qeth_bridge_state_change_worker(struct work_struct *work)
        kfree(data);
 }
 
-void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd)
+static void qeth_bridge_state_change(struct qeth_card *card,
+                                       struct qeth_ipa_cmd *cmd)
 {
        struct qeth_sbp_state_change *qports =
                 &cmd->data.sbp.data.state_change;
@@ -1488,7 +1519,6 @@ void qeth_bridge_state_change(struct qeth_card *card, struct qeth_ipa_cmd *cmd)
                        sizeof(struct qeth_sbp_state_change) + extrasize);
        queue_work(qeth_wq, &data->worker);
 }
-EXPORT_SYMBOL(qeth_bridge_state_change);
 
 struct qeth_bridge_host_data {
        struct work_struct worker;
@@ -1528,7 +1558,8 @@ static void qeth_bridge_host_event_worker(struct work_struct *work)
        kfree(data);
 }
 
-void qeth_bridge_host_event(struct qeth_card *card, struct qeth_ipa_cmd *cmd)
+static void qeth_bridge_host_event(struct qeth_card *card,
+                                       struct qeth_ipa_cmd *cmd)
 {
        struct qeth_ipacmd_addr_change *hostevs =
                 &cmd->data.addrchange;
@@ -1560,7 +1591,6 @@ void qeth_bridge_host_event(struct qeth_card *card, struct qeth_ipa_cmd *cmd)
                        sizeof(struct qeth_ipacmd_addr_change) + extrasize);
        queue_work(qeth_wq, &data->worker);
 }
-EXPORT_SYMBOL(qeth_bridge_host_event);
 
 /* SETBRIDGEPORT support; sending commands */
 
@@ -1683,7 +1713,7 @@ static int qeth_bridgeport_query_support_cb(struct qeth_card *card,
  * Sets bitmask of supported setbridgeport subfunctions in the qeth_card
  * strucutre: card->options.sbp.supported_funcs.
  */
-void qeth_bridgeport_query_support(struct qeth_card *card)
+static void qeth_bridgeport_query_support(struct qeth_card *card)
 {
        struct qeth_cmd_buffer *iob;
        struct qeth_ipa_cmd *cmd;
@@ -1709,7 +1739,6 @@ void qeth_bridgeport_query_support(struct qeth_card *card)
        }
        card->options.sbp.supported_funcs = cbctl.data.supported;
 }
-EXPORT_SYMBOL_GPL(qeth_bridgeport_query_support);
 
 static int qeth_bridgeport_query_ports_cb(struct qeth_card *card,
        struct qeth_reply *reply, unsigned long data)
index c1b0b2761f8dce6e0d3ad709902eeb19a925beba..0f430424c3b8b0aec231c3e2ca69d739c0c29701 100644 (file)
@@ -3593,6 +3593,13 @@ out:
        return rc;
 }
 
+/* Returns zero if the command is successfully "consumed" */
+static int qeth_l3_control_event(struct qeth_card *card,
+                                       struct qeth_ipa_cmd *cmd)
+{
+       return 1;
+}
+
 struct qeth_discipline qeth_l3_discipline = {
        .start_poll = qeth_qdio_start_poll,
        .input_handler = (qdio_handler_t *) qeth_qdio_input_handler,
@@ -3606,6 +3613,7 @@ struct qeth_discipline qeth_l3_discipline = {
        .freeze = qeth_l3_pm_suspend,
        .thaw = qeth_l3_pm_resume,
        .restore = qeth_l3_pm_resume,
+       .control_event_handler = qeth_l3_control_event,
 };
 EXPORT_SYMBOL_GPL(qeth_l3_discipline);
 
index c1441ed282eb911ff67a6363ce5a78f6cbe45199..c7763e482eb235a12d4b48887070ec88154580ff 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/delay.h>
-#include <linux/init.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
 #include <linux/of_device.h>
index fc1339cf91ac65d135ef5bf3c14e242462e1453b..7c71e7b4febf96a2cebc62446acee68550116d97 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/fs.h>
 #include <linux/errno.h>
 #include <linux/major.h>
-#include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/ioport.h>              /* request_region */
 #include <linux/slab.h>
index ddbe5a9e713dfba93218ad886e5df1f49b9fd19c..af15a2fdab5e92e9473b1dbf7184a2f024a2e236 100644 (file)
@@ -19,7 +19,6 @@
  */
 
 #include <linux/module.h>
-#include <linux/init.h>
 #include <linux/kthread.h>
 #include <linux/delay.h>
 #include <linux/ioport.h>
index d9f268f237749df06e63f11cec4c19c69326f995..25c738e9ef19cea55a7a48ccbfb4b874789b056b 100644 (file)
@@ -9,7 +9,6 @@
 #include <linux/miscdevice.h>
 #include <linux/fcntl.h>
 #include <linux/poll.h>
-#include <linux/init.h>
 #include <linux/mutex.h>
 #include <linux/spinlock.h>
 #include <linux/mm.h>
index b0aae0536d588441aee8409e200ba417a6080b39..b7acafc8509956d583a506b54b7fdab30a723eff 100644 (file)
@@ -11,7 +11,6 @@
 #include <linux/slab.h>
 #include <linux/mutex.h>
 #include <linux/ioport.h>
-#include <linux/init.h>
 #include <linux/miscdevice.h>
 #include <linux/mm.h>
 #include <linux/of.h>
index 446b85110a1fc0a69b07e42bb3ecc7144d76d1ce..0cac7d8fd0f7cac75b0ecc2d63662d18eeda4a56 100644 (file)
@@ -2163,10 +2163,10 @@ int sas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        }
 
        /* do we need to support multiple segments? */
-       if (bio_segments(req->bio) > 1 || bio_segments(rsp->bio) > 1) {
-               printk("%s: multiple segments req %u %u, rsp %u %u\n",
-                      __func__, bio_segments(req->bio), blk_rq_bytes(req),
-                      bio_segments(rsp->bio), blk_rq_bytes(rsp));
+       if (bio_multiple_segments(req->bio) ||
+           bio_multiple_segments(rsp->bio)) {
+               printk("%s: multiple segments req %u, rsp %u\n",
+                      __func__, blk_rq_bytes(req), blk_rq_bytes(rsp));
                return -EINVAL;
        }
 
index 9d26637308bebe2fc2b2fdec681891cfcbaf9b07..410f4a3e88887a6f0087c06f9da42f22b61f556d 100644 (file)
@@ -1901,7 +1901,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        struct MPT2SAS_ADAPTER *ioc = shost_priv(shost);
        Mpi2SmpPassthroughRequest_t *mpi_request;
        Mpi2SmpPassthroughReply_t *mpi_reply;
-       int rc, i;
+       int rc;
        u16 smid;
        u32 ioc_state;
        unsigned long timeleft;
@@ -1916,7 +1916,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        void *pci_addr_out = NULL;
        u16 wait_state_count;
        struct request *rsp = req->next_rq;
-       struct bio_vec *bvec = NULL;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
 
        if (!rsp) {
                printk(MPT2SAS_ERR_FMT "%s: the smp response space is "
@@ -1942,7 +1943,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        ioc->transport_cmds.status = MPT2_CMD_PENDING;
 
        /* Check if the request is split across multiple segments */
-       if (bio_segments(req->bio) > 1) {
+       if (bio_multiple_segments(req->bio)) {
                u32 offset = 0;
 
                /* Allocate memory and copy the request */
@@ -1955,11 +1956,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                        goto out;
                }
 
-               bio_for_each_segment(bvec, req->bio, i) {
+               bio_for_each_segment(bvec, req->bio, iter) {
                        memcpy(pci_addr_out + offset,
-                           page_address(bvec->bv_page) + bvec->bv_offset,
-                           bvec->bv_len);
-                       offset += bvec->bv_len;
+                           page_address(bvec.bv_page) + bvec.bv_offset,
+                           bvec.bv_len);
+                       offset += bvec.bv_len;
                }
        } else {
                dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
@@ -1974,7 +1975,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
        /* Check if the response needs to be populated across
         * multiple segments */
-       if (bio_segments(rsp->bio) > 1) {
+       if (bio_multiple_segments(rsp->bio)) {
                pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp),
                    &pci_dma_in);
                if (!pci_addr_in) {
@@ -2041,7 +2042,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        sgl_flags = (MPI2_SGE_FLAGS_SIMPLE_ELEMENT |
            MPI2_SGE_FLAGS_END_OF_BUFFER | MPI2_SGE_FLAGS_HOST_TO_IOC);
        sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
-       if (bio_segments(req->bio) > 1) {
+       if (bio_multiple_segments(req->bio)) {
                ioc->base_add_sg_single(psge, sgl_flags |
                    (blk_rq_bytes(req) - 4), pci_dma_out);
        } else {
@@ -2057,7 +2058,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
            MPI2_SGE_FLAGS_LAST_ELEMENT | MPI2_SGE_FLAGS_END_OF_BUFFER |
            MPI2_SGE_FLAGS_END_OF_LIST);
        sgl_flags = sgl_flags << MPI2_SGE_FLAGS_SHIFT;
-       if (bio_segments(rsp->bio) > 1) {
+       if (bio_multiple_segments(rsp->bio)) {
                ioc->base_add_sg_single(psge, sgl_flags |
                    (blk_rq_bytes(rsp) + 4), pci_dma_in);
        } else {
@@ -2102,23 +2103,23 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                    le16_to_cpu(mpi_reply->ResponseDataLength);
                /* check if the resp needs to be copied from the allocated
                 * pci mem */
-               if (bio_segments(rsp->bio) > 1) {
+               if (bio_multiple_segments(rsp->bio)) {
                        u32 offset = 0;
                        u32 bytes_to_copy =
                            le16_to_cpu(mpi_reply->ResponseDataLength);
-                       bio_for_each_segment(bvec, rsp->bio, i) {
-                               if (bytes_to_copy <= bvec->bv_len) {
-                                       memcpy(page_address(bvec->bv_page) +
-                                           bvec->bv_offset, pci_addr_in +
+                       bio_for_each_segment(bvec, rsp->bio, iter) {
+                               if (bytes_to_copy <= bvec.bv_len) {
+                                       memcpy(page_address(bvec.bv_page) +
+                                           bvec.bv_offset, pci_addr_in +
                                            offset, bytes_to_copy);
                                        break;
                                } else {
-                                       memcpy(page_address(bvec->bv_page) +
-                                           bvec->bv_offset, pci_addr_in +
-                                           offset, bvec->bv_len);
-                                       bytes_to_copy -= bvec->bv_len;
+                                       memcpy(page_address(bvec.bv_page) +
+                                           bvec.bv_offset, pci_addr_in +
+                                           offset, bvec.bv_len);
+                                       bytes_to_copy -= bvec.bv_len;
                                }
-                               offset += bvec->bv_len;
+                               offset += bvec.bv_len;
                        }
                }
        } else {
index e771a88c6a7441c45c6b49e8ffb85d5258b22e99..65170cb1a00fa5fa0ca3c95a94e3ed686edca9f7 100644 (file)
@@ -1884,7 +1884,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        struct MPT3SAS_ADAPTER *ioc = shost_priv(shost);
        Mpi2SmpPassthroughRequest_t *mpi_request;
        Mpi2SmpPassthroughReply_t *mpi_reply;
-       int rc, i;
+       int rc;
        u16 smid;
        u32 ioc_state;
        unsigned long timeleft;
@@ -1898,7 +1898,8 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        void *pci_addr_out = NULL;
        u16 wait_state_count;
        struct request *rsp = req->next_rq;
-       struct bio_vec *bvec = NULL;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
 
        if (!rsp) {
                pr_err(MPT3SAS_FMT "%s: the smp response space is missing\n",
@@ -1925,7 +1926,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        ioc->transport_cmds.status = MPT3_CMD_PENDING;
 
        /* Check if the request is split across multiple segments */
-       if (req->bio->bi_vcnt > 1) {
+       if (bio_multiple_segments(req->bio)) {
                u32 offset = 0;
 
                /* Allocate memory and copy the request */
@@ -1938,11 +1939,11 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
                        goto out;
                }
 
-               bio_for_each_segment(bvec, req->bio, i) {
+               bio_for_each_segment(bvec, req->bio, iter) {
                        memcpy(pci_addr_out + offset,
-                           page_address(bvec->bv_page) + bvec->bv_offset,
-                           bvec->bv_len);
-                       offset += bvec->bv_len;
+                           page_address(bvec.bv_page) + bvec.bv_offset,
+                           bvec.bv_len);
+                       offset += bvec.bv_len;
                }
        } else {
                dma_addr_out = pci_map_single(ioc->pdev, bio_data(req->bio),
@@ -1957,7 +1958,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
        /* Check if the response needs to be populated across
         * multiple segments */
-       if (rsp->bio->bi_vcnt > 1) {
+       if (bio_multiple_segments(rsp->bio)) {
                pci_addr_in = pci_alloc_consistent(ioc->pdev, blk_rq_bytes(rsp),
                    &pci_dma_in);
                if (!pci_addr_in) {
@@ -2018,7 +2019,7 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
        mpi_request->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
        psge = &mpi_request->SGL;
 
-       if (req->bio->bi_vcnt > 1)
+       if (bio_multiple_segments(req->bio))
                ioc->build_sg(ioc, psge, pci_dma_out, (blk_rq_bytes(req) - 4),
                    pci_dma_in, (blk_rq_bytes(rsp) + 4));
        else
@@ -2063,23 +2064,23 @@ _transport_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
 
                /* check if the resp needs to be copied from the allocated
                 * pci mem */
-               if (rsp->bio->bi_vcnt > 1) {
+               if (bio_multiple_segments(rsp->bio)) {
                        u32 offset = 0;
                        u32 bytes_to_copy =
                            le16_to_cpu(mpi_reply->ResponseDataLength);
-                       bio_for_each_segment(bvec, rsp->bio, i) {
-                               if (bytes_to_copy <= bvec->bv_len) {
-                                       memcpy(page_address(bvec->bv_page) +
-                                           bvec->bv_offset, pci_addr_in +
+                       bio_for_each_segment(bvec, rsp->bio, iter) {
+                               if (bytes_to_copy <= bvec.bv_len) {
+                                       memcpy(page_address(bvec.bv_page) +
+                                           bvec.bv_offset, pci_addr_in +
                                            offset, bytes_to_copy);
                                        break;
                                } else {
-                                       memcpy(page_address(bvec->bv_page) +
-                                           bvec->bv_offset, pci_addr_in +
-                                           offset, bvec->bv_len);
-                                       bytes_to_copy -= bvec->bv_len;
+                                       memcpy(page_address(bvec.bv_page) +
+                                           bvec.bv_offset, pci_addr_in +
+                                           offset, bvec.bv_len);
+                                       bytes_to_copy -= bvec.bv_len;
                                }
-                               offset += bvec->bv_len;
+                               offset += bvec.bv_len;
                        }
                }
        } else {
index aa66361ed44b71772da913c74c69640b43909f23..bac04c2335aaf997c73e7b3b8b8a08129bfca455 100644 (file)
@@ -731,7 +731,7 @@ static int _osd_req_list_objects(struct osd_request *or,
 
        bio->bi_rw &= ~REQ_WRITE;
        or->in.bio = bio;
-       or->in.total_bytes = bio->bi_size;
+       or->in.total_bytes = bio->bi_iter.bi_size;
        return 0;
 }
 
index 570c7fcc0c4df5dff1c805754757c598e5cb311d..4a0d7c92181f974730b7964a029822ef4a565297 100644 (file)
@@ -1990,6 +1990,8 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
 
        vha->flags.delete_progress = 1;
 
+       qlt_remove_target(ha, vha);
+
        fc_remove_host(vha->host);
 
        scsi_remove_host(vha->host);
index 41d6491d7bd9ec9e376ef93c710774b793df6889..e1fe95ef23e11353aed91a8da9dd1d1f8ef2a9c3 100644 (file)
@@ -2750,6 +2750,13 @@ struct qlfc_fw {
        uint32_t len;
 };
 
+struct scsi_qlt_host {
+       void *target_lport_ptr;
+       struct mutex tgt_mutex;
+       struct mutex tgt_host_action_mutex;
+       struct qla_tgt *qla_tgt;
+};
+
 struct qlt_hw_data {
        /* Protected by hw lock */
        uint32_t enable_class_2:1;
@@ -2765,15 +2772,11 @@ struct qlt_hw_data {
        uint32_t __iomem *atio_q_in;
        uint32_t __iomem *atio_q_out;
 
-       void *target_lport_ptr;
        struct qla_tgt_func_tmpl *tgt_ops;
-       struct qla_tgt *qla_tgt;
        struct qla_tgt_cmd *cmds[DEFAULT_OUTSTANDING_COMMANDS];
        uint16_t current_handle;
 
        struct qla_tgt_vp_map *tgt_vp_map;
-       struct mutex tgt_mutex;
-       struct mutex tgt_host_action_mutex;
 
        int saved_set;
        uint16_t saved_exchange_count;
@@ -3435,6 +3438,7 @@ typedef struct scsi_qla_host {
 #define VP_ERR_FAB_LOGOUT      4
 #define VP_ERR_ADAP_NORESOURCES        5
        struct qla_hw_data *hw;
+       struct scsi_qlt_host vha_tgt;
        struct req_que *req;
        int             fw_heartbeat_counter;
        int             seconds_since_last_heartbeat;
index 38a1257e76e1ec432c6cc81893b54a27ee30081a..9e80d61e5a3aa0f62e0dbc6d9aeae8632d81935c 100644 (file)
@@ -590,7 +590,7 @@ static struct qla_tgt_sess *qlt_create_sess(
 
        /* Check to avoid double sessions */
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       list_for_each_entry(sess, &ha->tgt.qla_tgt->sess_list,
+       list_for_each_entry(sess, &vha->vha_tgt.qla_tgt->sess_list,
                                sess_list_entry) {
                if (!memcmp(sess->port_name, fcport->port_name, WWN_SIZE)) {
                        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf005,
@@ -627,7 +627,7 @@ static struct qla_tgt_sess *qlt_create_sess(
 
                return NULL;
        }
-       sess->tgt = ha->tgt.qla_tgt;
+       sess->tgt = vha->vha_tgt.qla_tgt;
        sess->vha = vha;
        sess->s_id = fcport->d_id;
        sess->loop_id = fcport->loop_id;
@@ -635,7 +635,7 @@ static struct qla_tgt_sess *qlt_create_sess(
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf006,
            "Adding sess %p to tgt %p via ->check_initiator_node_acl()\n",
-           sess, ha->tgt.qla_tgt);
+           sess, vha->vha_tgt.qla_tgt);
 
        be_sid[0] = sess->s_id.b.domain;
        be_sid[1] = sess->s_id.b.area;
@@ -662,8 +662,8 @@ static struct qla_tgt_sess *qlt_create_sess(
        memcpy(sess->port_name, fcport->port_name, sizeof(sess->port_name));
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       list_add_tail(&sess->sess_list_entry, &ha->tgt.qla_tgt->sess_list);
-       ha->tgt.qla_tgt->sess_count++;
+       list_add_tail(&sess->sess_list_entry, &vha->vha_tgt.qla_tgt->sess_list);
+       vha->vha_tgt.qla_tgt->sess_count++;
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04b,
@@ -682,7 +682,7 @@ static struct qla_tgt_sess *qlt_create_sess(
 void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        struct qla_tgt_sess *sess;
        unsigned long flags;
 
@@ -692,6 +692,9 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
        if (!tgt || (fcport->port_type != FCT_INITIATOR))
                return;
 
+       if (qla_ini_mode_enabled(vha))
+               return;
+
        spin_lock_irqsave(&ha->hardware_lock, flags);
        if (tgt->tgt_stop) {
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -701,9 +704,9 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
        if (!sess) {
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-               mutex_lock(&ha->tgt.tgt_mutex);
+               mutex_lock(&vha->vha_tgt.tgt_mutex);
                sess = qlt_create_sess(vha, fcport, false);
-               mutex_unlock(&ha->tgt.tgt_mutex);
+               mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
                spin_lock_irqsave(&ha->hardware_lock, flags);
        } else {
@@ -739,7 +742,7 @@ void qlt_fc_port_added(struct scsi_qla_host *vha, fc_port_t *fcport)
 void qlt_fc_port_deleted(struct scsi_qla_host *vha, fc_port_t *fcport)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        struct qla_tgt_sess *sess;
        unsigned long flags;
 
@@ -806,12 +809,12 @@ void qlt_stop_phase1(struct qla_tgt *tgt)
         * Mutex needed to sync with qla_tgt_fc_port_[added,deleted].
         * Lock is needed, because we still can get an incoming packet.
         */
-       mutex_lock(&ha->tgt.tgt_mutex);
+       mutex_lock(&vha->vha_tgt.tgt_mutex);
        spin_lock_irqsave(&ha->hardware_lock, flags);
        tgt->tgt_stop = 1;
        qlt_clear_tgt_db(tgt, true);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       mutex_unlock(&ha->tgt.tgt_mutex);
+       mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
        flush_delayed_work(&tgt->sess_del_work);
 
@@ -845,20 +848,21 @@ EXPORT_SYMBOL(qlt_stop_phase1);
 void qlt_stop_phase2(struct qla_tgt *tgt)
 {
        struct qla_hw_data *ha = tgt->ha;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        unsigned long flags;
 
        if (tgt->tgt_stopped) {
-               ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf04f,
+               ql_dbg(ql_dbg_tgt_mgt, vha, 0xf04f,
                    "Already in tgt->tgt_stopped state\n");
                dump_stack();
                return;
        }
 
-       ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf00b,
+       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00b,
            "Waiting for %d IRQ commands to complete (tgt %p)",
            tgt->irq_cmd_count, tgt);
 
-       mutex_lock(&ha->tgt.tgt_mutex);
+       mutex_lock(&vha->vha_tgt.tgt_mutex);
        spin_lock_irqsave(&ha->hardware_lock, flags);
        while (tgt->irq_cmd_count != 0) {
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -868,9 +872,9 @@ void qlt_stop_phase2(struct qla_tgt *tgt)
        tgt->tgt_stop = 0;
        tgt->tgt_stopped = 1;
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
-       mutex_unlock(&ha->tgt.tgt_mutex);
+       mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
-       ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf00c, "Stop of tgt %p finished",
+       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00c, "Stop of tgt %p finished",
            tgt);
 }
 EXPORT_SYMBOL(qlt_stop_phase2);
@@ -878,14 +882,14 @@ EXPORT_SYMBOL(qlt_stop_phase2);
 /* Called from qlt_remove_target() -> qla2x00_remove_one() */
 static void qlt_release(struct qla_tgt *tgt)
 {
-       struct qla_hw_data *ha = tgt->ha;
+       scsi_qla_host_t *vha = tgt->vha;
 
-       if ((ha->tgt.qla_tgt != NULL) && !tgt->tgt_stopped)
+       if ((vha->vha_tgt.qla_tgt != NULL) && !tgt->tgt_stopped)
                qlt_stop_phase2(tgt);
 
-       ha->tgt.qla_tgt = NULL;
+       vha->vha_tgt.qla_tgt = NULL;
 
-       ql_dbg(ql_dbg_tgt_mgt, tgt->vha, 0xf00d,
+       ql_dbg(ql_dbg_tgt_mgt, vha, 0xf00d,
            "Release of tgt %p finished\n", tgt);
 
        kfree(tgt);
@@ -949,8 +953,8 @@ static void qlt_send_notify_ack(struct scsi_qla_host *vha,
                return;
        }
 
-       if (ha->tgt.qla_tgt != NULL)
-               ha->tgt.qla_tgt->notify_ack_expected++;
+       if (vha->vha_tgt.qla_tgt != NULL)
+               vha->vha_tgt.qla_tgt->notify_ack_expected++;
 
        pkt->entry_type = NOTIFY_ACK_TYPE;
        pkt->entry_count = 1;
@@ -1054,7 +1058,7 @@ static void qlt_24xx_send_abts_resp(struct scsi_qla_host *vha,
                /* Other bytes are zero */
        }
 
-       ha->tgt.qla_tgt->abts_resp_expected++;
+       vha->vha_tgt.qla_tgt->abts_resp_expected++;
 
        qla2x00_start_iocbs(vha, vha->req);
 }
@@ -1206,7 +1210,7 @@ static void qlt_24xx_handle_abts(struct scsi_qla_host *vha,
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf012,
                    "qla_target(%d): task abort for non-existant session\n",
                    vha->vp_idx);
-               rc = qlt_sched_sess_work(ha->tgt.qla_tgt,
+               rc = qlt_sched_sess_work(vha->vha_tgt.qla_tgt,
                    QLA_TGT_SESS_WORK_ABORT, abts, sizeof(*abts));
                if (rc != 0) {
                        qlt_24xx_send_abts_resp(vha, abts, FCP_TMF_REJECTED,
@@ -2157,8 +2161,7 @@ static int qlt_prepare_srr_ctio(struct scsi_qla_host *vha,
        struct qla_tgt_cmd *cmd, void *ctio)
 {
        struct qla_tgt_srr_ctio *sc;
-       struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        struct qla_tgt_srr_imm *imm;
 
        tgt->ctio_srr_id++;
@@ -2474,7 +2477,7 @@ static void qlt_do_work(struct work_struct *work)
        struct qla_tgt_cmd *cmd = container_of(work, struct qla_tgt_cmd, work);
        scsi_qla_host_t *vha = cmd->vha;
        struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        struct qla_tgt_sess *sess = NULL;
        struct atio_from_isp *atio = &cmd->atio;
        unsigned char *cdb;
@@ -2507,10 +2510,10 @@ static void qlt_do_work(struct work_struct *work)
                        goto out_term;
                }
 
-               mutex_lock(&ha->tgt.tgt_mutex);
+               mutex_lock(&vha->vha_tgt.tgt_mutex);
                sess = qlt_make_local_sess(vha, s_id);
                /* sess has an extra creation ref. */
-               mutex_unlock(&ha->tgt.tgt_mutex);
+               mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
                if (!sess)
                        goto out_term;
@@ -2576,8 +2579,7 @@ out_term:
 static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
        struct atio_from_isp *atio)
 {
-       struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        struct qla_tgt_cmd *cmd;
 
        if (unlikely(tgt->tgt_stop)) {
@@ -2597,7 +2599,7 @@ static int qlt_handle_cmd_for_atio(struct scsi_qla_host *vha,
 
        memcpy(&cmd->atio, atio, sizeof(*atio));
        cmd->state = QLA_TGT_STATE_NEW;
-       cmd->tgt = ha->tgt.qla_tgt;
+       cmd->tgt = vha->vha_tgt.qla_tgt;
        cmd->vha = vha;
 
        INIT_WORK(&cmd->work, qlt_do_work);
@@ -2723,7 +2725,7 @@ static int qlt_handle_task_mgmt(struct scsi_qla_host *vha, void *iocb)
        uint32_t lun, unpacked_lun;
        int lun_size, fn;
 
-       tgt = ha->tgt.qla_tgt;
+       tgt = vha->vha_tgt.qla_tgt;
 
        lun = a->u.isp24.fcp_cmnd.lun;
        lun_size = sizeof(a->u.isp24.fcp_cmnd.lun);
@@ -2797,7 +2799,7 @@ static int qlt_abort_task(struct scsi_qla_host *vha,
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf025,
                    "qla_target(%d): task abort for unexisting "
                    "session\n", vha->vp_idx);
-               return qlt_sched_sess_work(ha->tgt.qla_tgt,
+               return qlt_sched_sess_work(vha->vha_tgt.qla_tgt,
                    QLA_TGT_SESS_WORK_ABORT, iocb, sizeof(*iocb));
        }
 
@@ -2810,7 +2812,6 @@ static int qlt_abort_task(struct scsi_qla_host *vha,
 static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
        struct imm_ntfy_from_isp *iocb)
 {
-       struct qla_hw_data *ha = vha->hw;
        int res = 0;
 
        ql_dbg(ql_dbg_tgt_mgt, vha, 0xf026,
@@ -2828,7 +2829,7 @@ static int qlt_24xx_handle_els(struct scsi_qla_host *vha,
        case ELS_PDISC:
        case ELS_ADISC:
        {
-               struct qla_tgt *tgt = ha->tgt.qla_tgt;
+               struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
                if (tgt->link_reinit_iocb_pending) {
                        qlt_send_notify_ack(vha, &tgt->link_reinit_iocb,
                            0, 0, 0, 0, 0, 0);
@@ -3202,8 +3203,7 @@ static void qlt_prepare_srr_imm(struct scsi_qla_host *vha,
        struct imm_ntfy_from_isp *iocb)
 {
        struct qla_tgt_srr_imm *imm;
-       struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        struct qla_tgt_srr_ctio *sctio;
 
        tgt->imm_srr_id++;
@@ -3313,7 +3313,7 @@ static void qlt_handle_imm_notify(struct scsi_qla_host *vha,
 
        case IMM_NTFY_LIP_LINK_REINIT:
        {
-               struct qla_tgt *tgt = ha->tgt.qla_tgt;
+               struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf033,
                    "qla_target(%d): LINK REINIT (loop %#x, "
                    "subcode %x)\n", vha->vp_idx,
@@ -3489,7 +3489,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
        struct atio_from_isp *atio)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        int rc;
 
        if (unlikely(tgt == NULL)) {
@@ -3591,7 +3591,7 @@ static void qlt_24xx_atio_pkt(struct scsi_qla_host *vha,
 static void qlt_response_pkt(struct scsi_qla_host *vha, response_t *pkt)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
 
        if (unlikely(tgt == NULL)) {
                ql_dbg(ql_dbg_tgt, vha, 0xe05d,
@@ -3794,7 +3794,7 @@ void qlt_async_event(uint16_t code, struct scsi_qla_host *vha,
        uint16_t *mailbox)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        int login_code;
 
        ql_dbg(ql_dbg_tgt, vha, 0xe039,
@@ -3924,14 +3924,14 @@ static fc_port_t *qlt_get_port_database(struct scsi_qla_host *vha,
 static struct qla_tgt_sess *qlt_make_local_sess(struct scsi_qla_host *vha,
        uint8_t *s_id)
 {
-       struct qla_hw_data *ha = vha->hw;
        struct qla_tgt_sess *sess = NULL;
        fc_port_t *fcport = NULL;
        int rc, global_resets;
        uint16_t loop_id = 0;
 
 retry:
-       global_resets = atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count);
+       global_resets =
+           atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count);
 
        rc = qla24xx_get_loop_id(vha, s_id, &loop_id);
        if (rc != 0) {
@@ -3958,12 +3958,13 @@ retry:
                return NULL;
 
        if (global_resets !=
-           atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count)) {
+           atomic_read(&vha->vha_tgt.qla_tgt->tgt_global_resets_count)) {
                ql_dbg(ql_dbg_tgt_mgt, vha, 0xf043,
                    "qla_target(%d): global reset during session discovery "
                    "(counter was %d, new %d), retrying", vha->vp_idx,
                    global_resets,
-                   atomic_read(&ha->tgt.qla_tgt->tgt_global_resets_count));
+                   atomic_read(&vha->vha_tgt.
+                       qla_tgt->tgt_global_resets_count));
                goto retry;
        }
 
@@ -3998,10 +3999,10 @@ static void qlt_abort_work(struct qla_tgt *tgt,
        if (!sess) {
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-               mutex_lock(&ha->tgt.tgt_mutex);
+               mutex_lock(&vha->vha_tgt.tgt_mutex);
                sess = qlt_make_local_sess(vha, s_id);
                /* sess has got an extra creation ref */
-               mutex_unlock(&ha->tgt.tgt_mutex);
+               mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
                spin_lock_irqsave(&ha->hardware_lock, flags);
                if (!sess)
@@ -4052,10 +4053,10 @@ static void qlt_tmr_work(struct qla_tgt *tgt,
        if (!sess) {
                spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-               mutex_lock(&ha->tgt.tgt_mutex);
+               mutex_lock(&vha->vha_tgt.tgt_mutex);
                sess = qlt_make_local_sess(vha, s_id);
                /* sess has got an extra creation ref */
-               mutex_unlock(&ha->tgt.tgt_mutex);
+               mutex_unlock(&vha->vha_tgt.tgt_mutex);
 
                spin_lock_irqsave(&ha->hardware_lock, flags);
                if (!sess)
@@ -4141,9 +4142,9 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha)
        }
 
        ql_dbg(ql_dbg_tgt, base_vha, 0xe03b,
-           "Registering target for host %ld(%p)", base_vha->host_no, ha);
+           "Registering target for host %ld(%p).\n", base_vha->host_no, ha);
 
-       BUG_ON((ha->tgt.qla_tgt != NULL) || (ha->tgt.tgt_ops != NULL));
+       BUG_ON(base_vha->vha_tgt.qla_tgt != NULL);
 
        tgt = kzalloc(sizeof(struct qla_tgt), GFP_KERNEL);
        if (!tgt) {
@@ -4171,7 +4172,7 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha)
        INIT_WORK(&tgt->srr_work, qlt_handle_srr_work);
        atomic_set(&tgt->tgt_global_resets_count, 0);
 
-       ha->tgt.qla_tgt = tgt;
+       base_vha->vha_tgt.qla_tgt = tgt;
 
        ql_dbg(ql_dbg_tgt, base_vha, 0xe067,
                "qla_target(%d): using 64 Bit PCI addressing",
@@ -4192,16 +4193,16 @@ int qlt_add_target(struct qla_hw_data *ha, struct scsi_qla_host *base_vha)
 /* Must be called under tgt_host_action_mutex */
 int qlt_remove_target(struct qla_hw_data *ha, struct scsi_qla_host *vha)
 {
-       if (!ha->tgt.qla_tgt)
+       if (!vha->vha_tgt.qla_tgt)
                return 0;
 
        mutex_lock(&qla_tgt_mutex);
-       list_del(&ha->tgt.qla_tgt->tgt_list_entry);
+       list_del(&vha->vha_tgt.qla_tgt->tgt_list_entry);
        mutex_unlock(&qla_tgt_mutex);
 
        ql_dbg(ql_dbg_tgt, vha, 0xe03c, "Unregistering target for host %ld(%p)",
            vha->host_no, ha);
-       qlt_release(ha->tgt.qla_tgt);
+       qlt_release(vha->vha_tgt.qla_tgt);
 
        return 0;
 }
@@ -4235,8 +4236,9 @@ static void qlt_lport_dump(struct scsi_qla_host *vha, u64 wwpn,
  * @callback:  lport initialization callback for tcm_qla2xxx code
  * @target_lport_ptr: pointer for tcm_qla2xxx specific lport data
  */
-int qlt_lport_register(struct qla_tgt_func_tmpl *qla_tgt_ops, u64 wwpn,
-       int (*callback)(struct scsi_qla_host *), void *target_lport_ptr)
+int qlt_lport_register(void *target_lport_ptr, u64 phys_wwpn,
+                      u64 npiv_wwpn, u64 npiv_wwnn,
+                      int (*callback)(struct scsi_qla_host *, void *, u64, u64))
 {
        struct qla_tgt *tgt;
        struct scsi_qla_host *vha;
@@ -4255,14 +4257,11 @@ int qlt_lport_register(struct qla_tgt_func_tmpl *qla_tgt_ops, u64 wwpn,
                if (!host)
                        continue;
 
-               if (ha->tgt.tgt_ops != NULL)
-                       continue;
-
                if (!(host->hostt->supported_mode & MODE_TARGET))
                        continue;
 
                spin_lock_irqsave(&ha->hardware_lock, flags);
-               if (host->active_mode & MODE_TARGET) {
+               if ((!npiv_wwpn || !npiv_wwnn) && host->active_mode & MODE_TARGET) {
                        pr_debug("MODE_TARGET already active on qla2xxx(%d)\n",
                            host->host_no);
                        spin_unlock_irqrestore(&ha->hardware_lock, flags);
@@ -4276,24 +4275,18 @@ int qlt_lport_register(struct qla_tgt_func_tmpl *qla_tgt_ops, u64 wwpn,
                            " qla2xxx scsi_host\n");
                        continue;
                }
-               qlt_lport_dump(vha, wwpn, b);
+               qlt_lport_dump(vha, phys_wwpn, b);
 
                if (memcmp(vha->port_name, b, WWN_SIZE)) {
                        scsi_host_put(host);
                        continue;
                }
-               /*
-                * Setup passed parameters ahead of invoking callback
-                */
-               ha->tgt.tgt_ops = qla_tgt_ops;
-               ha->tgt.target_lport_ptr = target_lport_ptr;
-               rc = (*callback)(vha);
-               if (rc != 0) {
-                       ha->tgt.tgt_ops = NULL;
-                       ha->tgt.target_lport_ptr = NULL;
-                       scsi_host_put(host);
-               }
                mutex_unlock(&qla_tgt_mutex);
+
+               rc = (*callback)(vha, target_lport_ptr, npiv_wwpn, npiv_wwnn);
+               if (rc != 0)
+                       scsi_host_put(host);
+
                return rc;
        }
        mutex_unlock(&qla_tgt_mutex);
@@ -4314,7 +4307,7 @@ void qlt_lport_deregister(struct scsi_qla_host *vha)
        /*
         * Clear the target_lport_ptr qla_target_template pointer in qla_hw_data
         */
-       ha->tgt.target_lport_ptr = NULL;
+       vha->vha_tgt.target_lport_ptr = NULL;
        ha->tgt.tgt_ops = NULL;
        /*
         * Release the Scsi_Host reference for the underlying qla2xxx host
@@ -4376,8 +4369,9 @@ void
 qlt_enable_vha(struct scsi_qla_host *vha)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        unsigned long flags;
+       scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
 
        if (!tgt) {
                ql_dbg(ql_dbg_tgt, vha, 0xe069,
@@ -4392,9 +4386,14 @@ qlt_enable_vha(struct scsi_qla_host *vha)
        qlt_set_mode(vha);
        spin_unlock_irqrestore(&ha->hardware_lock, flags);
 
-       set_bit(ISP_ABORT_NEEDED, &vha->dpc_flags);
-       qla2xxx_wake_dpc(vha);
-       qla2x00_wait_for_hba_online(vha);
+       if (vha->vp_idx) {
+               qla24xx_disable_vp(vha);
+               qla24xx_enable_vp(vha);
+       } else {
+               set_bit(ISP_ABORT_NEEDED, &base_vha->dpc_flags);
+               qla2xxx_wake_dpc(base_vha);
+               qla2x00_wait_for_hba_online(base_vha);
+       }
 }
 EXPORT_SYMBOL(qlt_enable_vha);
 
@@ -4407,7 +4406,7 @@ void
 qlt_disable_vha(struct scsi_qla_host *vha)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct qla_tgt *tgt = ha->tgt.qla_tgt;
+       struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
        unsigned long flags;
 
        if (!tgt) {
@@ -4438,8 +4437,10 @@ qlt_vport_create(struct scsi_qla_host *vha, struct qla_hw_data *ha)
        if (!qla_tgt_mode_enabled(vha))
                return;
 
-       mutex_init(&ha->tgt.tgt_mutex);
-       mutex_init(&ha->tgt.tgt_host_action_mutex);
+       vha->vha_tgt.qla_tgt = NULL;
+
+       mutex_init(&vha->vha_tgt.tgt_mutex);
+       mutex_init(&vha->vha_tgt.tgt_host_action_mutex);
 
        qlt_clear_mode(vha);
 
@@ -4450,6 +4451,8 @@ qlt_vport_create(struct scsi_qla_host *vha, struct qla_hw_data *ha)
         * assigning the value appropriately.
         */
        ha->tgt.atio_q_length = ATIO_ENTRY_CNT_24XX;
+
+       qlt_add_target(ha, vha);
 }
 
 void
@@ -4768,8 +4771,8 @@ qlt_probe_one_stage1(struct scsi_qla_host *base_vha, struct qla_hw_data *ha)
                ISP_ATIO_Q_OUT(base_vha) = &ha->iobase->isp24.atio_q_out;
        }
 
-       mutex_init(&ha->tgt.tgt_mutex);
-       mutex_init(&ha->tgt.tgt_host_action_mutex);
+       mutex_init(&base_vha->vha_tgt.tgt_mutex);
+       mutex_init(&base_vha->vha_tgt.tgt_host_action_mutex);
        qlt_clear_mode(base_vha);
 }
 
index b33e411f28a0754e4a6cf3886d098d6d494b72d8..1d10eecad499a3598dc3bbd1dc566416d210c54a 100644 (file)
@@ -932,8 +932,8 @@ void qlt_disable_vha(struct scsi_qla_host *);
  */
 extern int qlt_add_target(struct qla_hw_data *, struct scsi_qla_host *);
 extern int qlt_remove_target(struct qla_hw_data *, struct scsi_qla_host *);
-extern int qlt_lport_register(struct qla_tgt_func_tmpl *, u64,
-                       int (*callback)(struct scsi_qla_host *), void *);
+extern int qlt_lport_register(void *, u64, u64, u64,
+                       int (*callback)(struct scsi_qla_host *, void *, u64, u64));
 extern void qlt_lport_deregister(struct scsi_qla_host *);
 extern void qlt_unreg_sess(struct qla_tgt_sess *);
 extern void qlt_fc_port_added(struct scsi_qla_host *, fc_port_t *);
index 7eb19be35d461cfff2cc9f27897fd8b91bf8d17b..75a141bbe74d178834a9f58c6fc723734e63758f 100644 (file)
 struct workqueue_struct *tcm_qla2xxx_free_wq;
 struct workqueue_struct *tcm_qla2xxx_cmd_wq;
 
-static int tcm_qla2xxx_check_true(struct se_portal_group *se_tpg)
-{
-       return 1;
-}
-
-static int tcm_qla2xxx_check_false(struct se_portal_group *se_tpg)
-{
-       return 0;
-}
-
 /*
  * Parse WWN.
  * If strict, we require lower-case hex and colon separators to be sure
@@ -174,7 +164,7 @@ static int tcm_qla2xxx_npiv_parse_wwn(
        *wwnn = 0;
 
        /* count may include a LF at end of string */
-       if (name[cnt-1] == '\n')
+       if (name[cnt-1] == '\n' || name[cnt-1] == 0)
                cnt--;
 
        /* validate we have enough characters for WWPN */
@@ -777,6 +767,9 @@ static void tcm_qla2xxx_put_session(struct se_session *se_sess)
 
 static void tcm_qla2xxx_put_sess(struct qla_tgt_sess *sess)
 {
+       if (!sess)
+               return;
+
        assert_spin_locked(&sess->vha->hw->hardware_lock);
        kref_put(&sess->se_sess->sess_kref, tcm_qla2xxx_release_session);
 }
@@ -957,7 +950,6 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
        struct tcm_qla2xxx_lport *lport = container_of(se_wwn,
                        struct tcm_qla2xxx_lport, lport_wwn);
        struct scsi_qla_host *vha = lport->qla_vha;
-       struct qla_hw_data *ha = vha->hw;
        struct tcm_qla2xxx_tpg *tpg = container_of(se_tpg,
                        struct tcm_qla2xxx_tpg, se_tpg);
        unsigned long op;
@@ -977,12 +969,12 @@ static ssize_t tcm_qla2xxx_tpg_store_enable(
                atomic_set(&tpg->lport_tpg_enabled, 1);
                qlt_enable_vha(vha);
        } else {
-               if (!ha->tgt.qla_tgt) {
-                       pr_err("truct qla_hw_data *ha->tgt.qla_tgt is NULL\n");
+               if (!vha->vha_tgt.qla_tgt) {
+                       pr_err("struct qla_hw_data *vha->vha_tgt.qla_tgt is NULL\n");
                        return -ENODEV;
                }
                atomic_set(&tpg->lport_tpg_enabled, 0);
-               qlt_stop_phase1(ha->tgt.qla_tgt);
+               qlt_stop_phase1(vha->vha_tgt.qla_tgt);
        }
 
        return count;
@@ -1011,7 +1003,7 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(
        if (kstrtoul(name + 5, 10, &tpgt) || tpgt > USHRT_MAX)
                return ERR_PTR(-EINVAL);
 
-       if (!lport->qla_npiv_vp && (tpgt != 1)) {
+       if ((tpgt != 1)) {
                pr_err("In non NPIV mode, a single TPG=1 is used for HW port mappings\n");
                return ERR_PTR(-ENOSYS);
        }
@@ -1038,11 +1030,8 @@ static struct se_portal_group *tcm_qla2xxx_make_tpg(
                kfree(tpg);
                return NULL;
        }
-       /*
-        * Setup local TPG=1 pointer for non NPIV mode.
-        */
-       if (lport->qla_npiv_vp == NULL)
-               lport->tpg_1 = tpg;
+
+       lport->tpg_1 = tpg;
 
        return &tpg->se_tpg;
 }
@@ -1053,19 +1042,17 @@ static void tcm_qla2xxx_drop_tpg(struct se_portal_group *se_tpg)
                        struct tcm_qla2xxx_tpg, se_tpg);
        struct tcm_qla2xxx_lport *lport = tpg->lport;
        struct scsi_qla_host *vha = lport->qla_vha;
-       struct qla_hw_data *ha = vha->hw;
        /*
         * Call into qla2x_target.c LLD logic to shutdown the active
         * FC Nexuses and disable target mode operation for this qla_hw_data
         */
-       if (ha->tgt.qla_tgt && !ha->tgt.qla_tgt->tgt_stop)
-               qlt_stop_phase1(ha->tgt.qla_tgt);
+       if (vha->vha_tgt.qla_tgt && !vha->vha_tgt.qla_tgt->tgt_stop)
+               qlt_stop_phase1(vha->vha_tgt.qla_tgt);
 
        core_tpg_deregister(se_tpg);
        /*
         * Clear local TPG=1 pointer for non NPIV mode.
         */
-       if (lport->qla_npiv_vp == NULL)
                lport->tpg_1 = NULL;
 
        kfree(tpg);
@@ -1095,12 +1082,22 @@ static struct se_portal_group *tcm_qla2xxx_npiv_make_tpg(
        tpg->lport = lport;
        tpg->lport_tpgt = tpgt;
 
+       /*
+        * By default allow READ-ONLY TPG demo-mode access w/ cached dynamic
+        * NodeACLs
+        */
+       tpg->tpg_attrib.generate_node_acls = 1;
+       tpg->tpg_attrib.demo_mode_write_protect = 1;
+       tpg->tpg_attrib.cache_dynamic_acls = 1;
+       tpg->tpg_attrib.demo_mode_login_only = 1;
+
        ret = core_tpg_register(&tcm_qla2xxx_npiv_fabric_configfs->tf_ops, wwn,
                                &tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
        if (ret < 0) {
                kfree(tpg);
                return NULL;
        }
+       lport->tpg_1 = tpg;
        return &tpg->se_tpg;
 }
 
@@ -1111,13 +1108,12 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_s_id(
        scsi_qla_host_t *vha,
        const uint8_t *s_id)
 {
-       struct qla_hw_data *ha = vha->hw;
        struct tcm_qla2xxx_lport *lport;
        struct se_node_acl *se_nacl;
        struct tcm_qla2xxx_nacl *nacl;
        u32 key;
 
-       lport = ha->tgt.target_lport_ptr;
+       lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
                pr_err("Unable to locate struct tcm_qla2xxx_lport\n");
                dump_stack();
@@ -1221,13 +1217,12 @@ static struct qla_tgt_sess *tcm_qla2xxx_find_sess_by_loop_id(
        scsi_qla_host_t *vha,
        const uint16_t loop_id)
 {
-       struct qla_hw_data *ha = vha->hw;
        struct tcm_qla2xxx_lport *lport;
        struct se_node_acl *se_nacl;
        struct tcm_qla2xxx_nacl *nacl;
        struct tcm_qla2xxx_fc_loopid *fc_loopid;
 
-       lport = ha->tgt.target_lport_ptr;
+       lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
                pr_err("Unable to locate struct tcm_qla2xxx_lport\n");
                dump_stack();
@@ -1341,6 +1336,7 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess)
 {
        struct qla_tgt *tgt = sess->tgt;
        struct qla_hw_data *ha = tgt->ha;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
        struct se_session *se_sess;
        struct se_node_acl *se_nacl;
        struct tcm_qla2xxx_lport *lport;
@@ -1357,7 +1353,7 @@ static void tcm_qla2xxx_free_session(struct qla_tgt_sess *sess)
        se_nacl = se_sess->se_node_acl;
        nacl = container_of(se_nacl, struct tcm_qla2xxx_nacl, se_node_acl);
 
-       lport = ha->tgt.target_lport_ptr;
+       lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
                pr_err("Unable to locate struct tcm_qla2xxx_lport\n");
                dump_stack();
@@ -1391,7 +1387,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
        unsigned char port_name[36];
        unsigned long flags;
 
-       lport = ha->tgt.target_lport_ptr;
+       lport = vha->vha_tgt.target_lport_ptr;
        if (!lport) {
                pr_err("Unable to locate struct tcm_qla2xxx_lport\n");
                dump_stack();
@@ -1455,7 +1451,8 @@ static void tcm_qla2xxx_update_sess(struct qla_tgt_sess *sess, port_id_t s_id,
 {
        struct qla_tgt *tgt = sess->tgt;
        struct qla_hw_data *ha = tgt->ha;
-       struct tcm_qla2xxx_lport *lport = ha->tgt.target_lport_ptr;
+       scsi_qla_host_t *vha = pci_get_drvdata(ha->pdev);
+       struct tcm_qla2xxx_lport *lport = vha->vha_tgt.target_lport_ptr;
        struct se_node_acl *se_nacl = sess->se_sess->se_node_acl;
        struct tcm_qla2xxx_nacl *nacl = container_of(se_nacl,
                        struct tcm_qla2xxx_nacl, se_node_acl);
@@ -1562,15 +1559,18 @@ static int tcm_qla2xxx_init_lport(struct tcm_qla2xxx_lport *lport)
        return 0;
 }
 
-static int tcm_qla2xxx_lport_register_cb(struct scsi_qla_host *vha)
+static int tcm_qla2xxx_lport_register_cb(struct scsi_qla_host *vha,
+                                        void *target_lport_ptr,
+                                        u64 npiv_wwpn, u64 npiv_wwnn)
 {
        struct qla_hw_data *ha = vha->hw;
-       struct tcm_qla2xxx_lport *lport;
+       struct tcm_qla2xxx_lport *lport =
+                       (struct tcm_qla2xxx_lport *)target_lport_ptr;
        /*
-        * Setup local pointer to vha, NPIV VP pointer (if present) and
-        * vha->tcm_lport pointer
+        * Setup tgt_ops, local pointer to vha and target_lport_ptr
         */
-       lport = (struct tcm_qla2xxx_lport *)ha->tgt.target_lport_ptr;
+       ha->tgt.tgt_ops = &tcm_qla2xxx_template;
+       vha->vha_tgt.target_lport_ptr = target_lport_ptr;
        lport->qla_vha = vha;
 
        return 0;
@@ -1602,8 +1602,8 @@ static struct se_wwn *tcm_qla2xxx_make_lport(
        if (ret != 0)
                goto out;
 
-       ret = qlt_lport_register(&tcm_qla2xxx_template, wwpn,
-                               tcm_qla2xxx_lport_register_cb, lport);
+       ret = qlt_lport_register(lport, wwpn, 0, 0,
+                                tcm_qla2xxx_lport_register_cb);
        if (ret != 0)
                goto out_lport;
 
@@ -1621,7 +1621,6 @@ static void tcm_qla2xxx_drop_lport(struct se_wwn *wwn)
        struct tcm_qla2xxx_lport *lport = container_of(wwn,
                        struct tcm_qla2xxx_lport, lport_wwn);
        struct scsi_qla_host *vha = lport->qla_vha;
-       struct qla_hw_data *ha = vha->hw;
        struct se_node_acl *node;
        u32 key = 0;
 
@@ -1630,8 +1629,8 @@ static void tcm_qla2xxx_drop_lport(struct se_wwn *wwn)
         * shutdown of struct qla_tgt after the call to
         * qlt_stop_phase1() from tcm_qla2xxx_drop_tpg() above..
         */
-       if (ha->tgt.qla_tgt && !ha->tgt.qla_tgt->tgt_stopped)
-               qlt_stop_phase2(ha->tgt.qla_tgt);
+       if (vha->vha_tgt.qla_tgt && !vha->vha_tgt.qla_tgt->tgt_stopped)
+               qlt_stop_phase2(vha->vha_tgt.qla_tgt);
 
        qlt_lport_deregister(vha);
 
@@ -1642,17 +1641,70 @@ static void tcm_qla2xxx_drop_lport(struct se_wwn *wwn)
        kfree(lport);
 }
 
+static int tcm_qla2xxx_lport_register_npiv_cb(struct scsi_qla_host *base_vha,
+                                             void *target_lport_ptr,
+                                             u64 npiv_wwpn, u64 npiv_wwnn)
+{
+       struct fc_vport *vport;
+       struct Scsi_Host *sh = base_vha->host;
+       struct scsi_qla_host *npiv_vha;
+       struct tcm_qla2xxx_lport *lport =
+                       (struct tcm_qla2xxx_lport *)target_lport_ptr;
+       struct fc_vport_identifiers vport_id;
+
+       if (!qla_tgt_mode_enabled(base_vha)) {
+               pr_err("qla2xxx base_vha not enabled for target mode\n");
+               return -EPERM;
+       }
+
+       memset(&vport_id, 0, sizeof(vport_id));
+       vport_id.port_name = npiv_wwpn;
+       vport_id.node_name = npiv_wwnn;
+       vport_id.roles = FC_PORT_ROLE_FCP_INITIATOR;
+       vport_id.vport_type = FC_PORTTYPE_NPIV;
+       vport_id.disable = false;
+
+       vport = fc_vport_create(sh, 0, &vport_id);
+       if (!vport) {
+               pr_err("fc_vport_create failed for qla2xxx_npiv\n");
+               return -ENODEV;
+       }
+       /*
+        * Setup local pointer to NPIV vhba + target_lport_ptr
+        */
+       npiv_vha = (struct scsi_qla_host *)vport->dd_data;
+       npiv_vha->vha_tgt.target_lport_ptr = target_lport_ptr;
+       lport->qla_vha = npiv_vha;
+
+       scsi_host_get(npiv_vha->host);
+       return 0;
+}
+
+
 static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
        struct target_fabric_configfs *tf,
        struct config_group *group,
        const char *name)
 {
        struct tcm_qla2xxx_lport *lport;
-       u64 npiv_wwpn, npiv_wwnn;
+       u64 phys_wwpn, npiv_wwpn, npiv_wwnn;
+       char *p, tmp[128];
        int ret;
 
-       if (tcm_qla2xxx_npiv_parse_wwn(name, strlen(name)+1,
-                               &npiv_wwpn, &npiv_wwnn) < 0)
+       snprintf(tmp, 128, "%s", name);
+
+       p = strchr(tmp, '@');
+       if (!p) {
+               pr_err("Unable to locate NPIV '@' seperator\n");
+               return ERR_PTR(-EINVAL);
+       }
+       *p++ = '\0';
+
+       if (tcm_qla2xxx_parse_wwn(tmp, &phys_wwpn, 1) < 0)
+               return ERR_PTR(-EINVAL);
+
+       if (tcm_qla2xxx_npiv_parse_wwn(p, strlen(p)+1,
+                                      &npiv_wwpn, &npiv_wwnn) < 0)
                return ERR_PTR(-EINVAL);
 
        lport = kzalloc(sizeof(struct tcm_qla2xxx_lport), GFP_KERNEL);
@@ -1666,12 +1718,19 @@ static struct se_wwn *tcm_qla2xxx_npiv_make_lport(
                        TCM_QLA2XXX_NAMELEN, npiv_wwpn, npiv_wwnn);
        sprintf(lport->lport_naa_name, "naa.%016llx", (unsigned long long) npiv_wwpn);
 
-/* FIXME: tcm_qla2xxx_npiv_make_lport */
-       ret = -ENOSYS;
+       ret = tcm_qla2xxx_init_lport(lport);
        if (ret != 0)
                goto out;
 
+       ret = qlt_lport_register(lport, phys_wwpn, npiv_wwpn, npiv_wwnn,
+                                tcm_qla2xxx_lport_register_npiv_cb);
+       if (ret != 0)
+               goto out_lport;
+
        return &lport->lport_wwn;
+out_lport:
+       vfree(lport->lport_loopid_map);
+       btree_destroy32(&lport->lport_fcport_map);
 out:
        kfree(lport);
        return ERR_PTR(ret);
@@ -1681,14 +1740,16 @@ static void tcm_qla2xxx_npiv_drop_lport(struct se_wwn *wwn)
 {
        struct tcm_qla2xxx_lport *lport = container_of(wwn,
                        struct tcm_qla2xxx_lport, lport_wwn);
-       struct scsi_qla_host *vha = lport->qla_vha;
-       struct Scsi_Host *sh = vha->host;
+       struct scsi_qla_host *npiv_vha = lport->qla_vha;
+       struct qla_hw_data *ha = npiv_vha->hw;
+       scsi_qla_host_t *base_vha = pci_get_drvdata(ha->pdev);
+
+       scsi_host_put(npiv_vha->host);
        /*
-        * Notify libfc that we want to release the lport->npiv_vport
+        * Notify libfc that we want to release the vha->fc_vport
         */
-       fc_vport_terminate(lport->npiv_vport);
-
-       scsi_host_put(sh);
+       fc_vport_terminate(npiv_vha->fc_vport);
+       scsi_host_put(base_vha->host);
        kfree(lport);
 }
 
@@ -1769,14 +1830,16 @@ static struct target_core_fabric_ops tcm_qla2xxx_npiv_ops = {
        .tpg_get_pr_transport_id        = tcm_qla2xxx_get_pr_transport_id,
        .tpg_get_pr_transport_id_len    = tcm_qla2xxx_get_pr_transport_id_len,
        .tpg_parse_pr_out_transport_id  = tcm_qla2xxx_parse_pr_out_transport_id,
-       .tpg_check_demo_mode            = tcm_qla2xxx_check_false,
-       .tpg_check_demo_mode_cache      = tcm_qla2xxx_check_true,
-       .tpg_check_demo_mode_write_protect = tcm_qla2xxx_check_true,
-       .tpg_check_prod_mode_write_protect = tcm_qla2xxx_check_false,
+       .tpg_check_demo_mode            = tcm_qla2xxx_check_demo_mode,
+       .tpg_check_demo_mode_cache      = tcm_qla2xxx_check_demo_mode_cache,
+       .tpg_check_demo_mode_write_protect = tcm_qla2xxx_check_demo_mode,
+       .tpg_check_prod_mode_write_protect =
+           tcm_qla2xxx_check_prod_write_protect,
        .tpg_check_demo_mode_login_only = tcm_qla2xxx_check_demo_mode_login_only,
        .tpg_alloc_fabric_acl           = tcm_qla2xxx_alloc_fabric_acl,
        .tpg_release_fabric_acl         = tcm_qla2xxx_release_fabric_acl,
        .tpg_get_inst_index             = tcm_qla2xxx_tpg_get_inst_index,
+       .check_stop_free                = tcm_qla2xxx_check_stop_free,
        .release_cmd                    = tcm_qla2xxx_release_cmd,
        .put_session                    = tcm_qla2xxx_put_session,
        .shutdown_session               = tcm_qla2xxx_shutdown_session,
@@ -1871,7 +1934,8 @@ static int tcm_qla2xxx_register_configfs(void)
         * Setup default attribute lists for various npiv_fabric->tf_cit_tmpl
         */
        npiv_fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_qla2xxx_wwn_attrs;
-       npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = NULL;
+       npiv_fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs =
+           tcm_qla2xxx_tpg_attrs;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
        npiv_fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
index 771f7b816443603bb1787a93f4aa79666bdf5f69..275d8b9a7a34121d4d7d356659bfe92816219a3f 100644 (file)
@@ -70,12 +70,8 @@ struct tcm_qla2xxx_lport {
        struct tcm_qla2xxx_fc_loopid *lport_loopid_map;
        /* Pointer to struct scsi_qla_host from qla2xxx LLD */
        struct scsi_qla_host *qla_vha;
-       /* Pointer to struct scsi_qla_host for NPIV VP from qla2xxx LLD */
-       struct scsi_qla_host *qla_npiv_vp;
        /* Pointer to struct qla_tgt pointer */
        struct qla_tgt lport_qla_tgt;
-       /* Pointer to struct fc_vport for NPIV vport from libfc */
-       struct fc_vport *npiv_vport;
        /* Pointer to TPG=1 for non NPIV mode */
        struct tcm_qla2xxx_tpg *tpg_1;
        /* Returned by tcm_qla2xxx_make_lport() */
index 9846c6ab2aaa92eeab130a92fe4d7b8d539b624c..470954aba7289a758a650cd82b2f1dfe50ae54f1 100644 (file)
@@ -801,7 +801,7 @@ static int sd_setup_write_same_cmnd(struct scsi_device *sdp, struct request *rq)
        if (sdkp->device->no_write_same)
                return BLKPREP_KILL;
 
-       BUG_ON(bio_offset(bio) || bio_iovec(bio)->bv_len != sdp->sector_size);
+       BUG_ON(bio_offset(bio) || bio_iovec(bio).bv_len != sdp->sector_size);
 
        sector >>= ilog2(sdp->sector_size) - 9;
        nr_sectors >>= ilog2(sdp->sector_size) - 9;
index 6174ca4ea27594487d7dc0828d9e21841742b8ed..a7a691d0af7d105a431ba3b560a5496acb71d58b 100644 (file)
@@ -365,7 +365,6 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector,
        struct bio *bio;
        struct scsi_disk *sdkp;
        struct sd_dif_tuple *sdt;
-       unsigned int i, j;
        u32 phys, virt;
 
        sdkp = rq->bio->bi_bdev->bd_disk->private_data;
@@ -376,19 +375,21 @@ void sd_dif_prepare(struct request *rq, sector_t hw_sector,
        phys = hw_sector & 0xffffffff;
 
        __rq_for_each_bio(bio, rq) {
-               struct bio_vec *iv;
+               struct bio_vec iv;
+               struct bvec_iter iter;
+               unsigned int j;
 
                /* Already remapped? */
                if (bio_flagged(bio, BIO_MAPPED_INTEGRITY))
                        break;
 
-               virt = bio->bi_integrity->bip_sector & 0xffffffff;
+               virt = bio->bi_integrity->bip_iter.bi_sector & 0xffffffff;
 
-               bip_for_each_vec(iv, bio->bi_integrity, i) {
-                       sdt = kmap_atomic(iv->bv_page)
-                               + iv->bv_offset;
+               bip_for_each_vec(iv, bio->bi_integrity, iter) {
+                       sdt = kmap_atomic(iv.bv_page)
+                               + iv.bv_offset;
 
-                       for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) {
+                       for (j = 0; j < iv.bv_len; j += tuple_sz, sdt++) {
 
                                if (be32_to_cpu(sdt->ref_tag) == virt)
                                        sdt->ref_tag = cpu_to_be32(phys);
@@ -414,7 +415,7 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
        struct scsi_disk *sdkp;
        struct bio *bio;
        struct sd_dif_tuple *sdt;
-       unsigned int i, j, sectors, sector_sz;
+       unsigned int j, sectors, sector_sz;
        u32 phys, virt;
 
        sdkp = scsi_disk(scmd->request->rq_disk);
@@ -430,15 +431,16 @@ void sd_dif_complete(struct scsi_cmnd *scmd, unsigned int good_bytes)
                phys >>= 3;
 
        __rq_for_each_bio(bio, scmd->request) {
-               struct bio_vec *iv;
+               struct bio_vec iv;
+               struct bvec_iter iter;
 
-               virt = bio->bi_integrity->bip_sector & 0xffffffff;
+               virt = bio->bi_integrity->bip_iter.bi_sector & 0xffffffff;
 
-               bip_for_each_vec(iv, bio->bi_integrity, i) {
-                       sdt = kmap_atomic(iv->bv_page)
-                               + iv->bv_offset;
+               bip_for_each_vec(iv, bio->bi_integrity, iter) {
+                       sdt = kmap_atomic(iv.bv_page)
+                               + iv.bv_offset;
 
-                       for (j = 0 ; j < iv->bv_len ; j += tuple_sz, sdt++) {
+                       for (j = 0; j < iv.bv_len; j += tuple_sz, sdt++) {
 
                                if (sectors == 0) {
                                        kunmap_atomic(sdt);
index 46d2313f7c6fc1e155ff15c7f60962291c923524..5032141eeeec4ee0cbb46b7d7af7c8a65e76212c 100644 (file)
@@ -40,6 +40,7 @@ struct mpc512x_psc_spi {
        unsigned int irq;
        u8 bits_per_word;
        struct clk *clk_mclk;
+       struct clk *clk_ipg;
        u32 mclk_rate;
 
        struct completion txisrdone;
@@ -475,8 +476,6 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
        struct spi_master *master;
        int ret;
        void *tempp;
-       int psc_num;
-       char clk_name[16];
        struct clk *clk;
 
        master = spi_alloc_master(dev, sizeof *mps);
@@ -519,9 +518,7 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
                goto free_master;
        init_completion(&mps->txisrdone);
 
-       psc_num = master->bus_num;
-       snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-       clk = devm_clk_get(dev, clk_name);
+       clk = devm_clk_get(dev, "mclk");
        if (IS_ERR(clk)) {
                ret = PTR_ERR(clk);
                goto free_master;
@@ -532,17 +529,29 @@ static int mpc512x_psc_spi_do_probe(struct device *dev, u32 regaddr,
        mps->clk_mclk = clk;
        mps->mclk_rate = clk_get_rate(clk);
 
+       clk = devm_clk_get(dev, "ipg");
+       if (IS_ERR(clk)) {
+               ret = PTR_ERR(clk);
+               goto free_mclk_clock;
+       }
+       ret = clk_prepare_enable(clk);
+       if (ret)
+               goto free_mclk_clock;
+       mps->clk_ipg = clk;
+
        ret = mpc512x_psc_spi_port_config(master, mps);
        if (ret < 0)
-               goto free_clock;
+               goto free_ipg_clock;
 
        ret = devm_spi_register_master(dev, master);
        if (ret < 0)
-               goto free_clock;
+               goto free_ipg_clock;
 
        return ret;
 
-free_clock:
+free_ipg_clock:
+       clk_disable_unprepare(mps->clk_ipg);
+free_mclk_clock:
        clk_disable_unprepare(mps->clk_mclk);
 free_master:
        spi_master_put(master);
@@ -556,6 +565,7 @@ static int mpc512x_psc_spi_do_remove(struct device *dev)
        struct mpc512x_psc_spi *mps = spi_master_get_devdata(master);
 
        clk_disable_unprepare(mps->clk_mclk);
+       clk_disable_unprepare(mps->clk_ipg);
 
        return 0;
 }
index 2cd9b0e44a41cede503dbb9e588020e7a949406b..75b3603906c1457dc94e915ee84bb681d087029e 100644 (file)
@@ -168,6 +168,7 @@ config SSB_DRIVER_GIGE
 config SSB_DRIVER_GPIO
        bool "SSB GPIO driver"
        depends on SSB && GPIOLIB
+       select IRQ_DOMAIN if SSB_EMBEDDED
        help
          Driver to provide access to the GPIO pins on the bus.
 
index dc109de228c67b079f5eed0623fc3e1d94451b6e..ba350d2035c0d868cc6a9436eb65c593805c5ae5 100644 (file)
@@ -9,16 +9,40 @@
  */
 
 #include <linux/gpio.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/export.h>
 #include <linux/ssb/ssb.h>
 
 #include "ssb_private.h"
 
+
+/**************************************************
+ * Shared
+ **************************************************/
+
 static struct ssb_bus *ssb_gpio_get_bus(struct gpio_chip *chip)
 {
        return container_of(chip, struct ssb_bus, gpio);
 }
 
+#if IS_ENABLED(CONFIG_SSB_EMBEDDED)
+static int ssb_gpio_to_irq(struct gpio_chip *chip, unsigned gpio)
+{
+       struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+
+       if (bus->bustype == SSB_BUSTYPE_SSB)
+               return irq_find_mapping(bus->irq_domain, gpio);
+       else
+               return -EINVAL;
+}
+#endif
+
+/**************************************************
+ * ChipCommon
+ **************************************************/
+
 static int ssb_gpio_chipco_get_value(struct gpio_chip *chip, unsigned gpio)
 {
        struct ssb_bus *bus = ssb_gpio_get_bus(chip);
@@ -74,19 +98,129 @@ static void ssb_gpio_chipco_free(struct gpio_chip *chip, unsigned gpio)
        ssb_chipco_gpio_pullup(&bus->chipco, 1 << gpio, 0);
 }
 
-static int ssb_gpio_chipco_to_irq(struct gpio_chip *chip, unsigned gpio)
+#if IS_ENABLED(CONFIG_SSB_EMBEDDED)
+static void ssb_gpio_irq_chipco_mask(struct irq_data *d)
 {
-       struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+       struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
+       int gpio = irqd_to_hwirq(d);
 
-       if (bus->bustype == SSB_BUSTYPE_SSB)
-               return ssb_mips_irq(bus->chipco.dev) + 2;
-       else
-               return -EINVAL;
+       ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), 0);
+}
+
+static void ssb_gpio_irq_chipco_unmask(struct irq_data *d)
+{
+       struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
+       int gpio = irqd_to_hwirq(d);
+       u32 val = ssb_chipco_gpio_in(&bus->chipco, BIT(gpio));
+
+       ssb_chipco_gpio_polarity(&bus->chipco, BIT(gpio), val);
+       ssb_chipco_gpio_intmask(&bus->chipco, BIT(gpio), BIT(gpio));
+}
+
+static struct irq_chip ssb_gpio_irq_chipco_chip = {
+       .name           = "SSB-GPIO-CC",
+       .irq_mask       = ssb_gpio_irq_chipco_mask,
+       .irq_unmask     = ssb_gpio_irq_chipco_unmask,
+};
+
+static irqreturn_t ssb_gpio_irq_chipco_handler(int irq, void *dev_id)
+{
+       struct ssb_bus *bus = dev_id;
+       struct ssb_chipcommon *chipco = &bus->chipco;
+       u32 val = chipco_read32(chipco, SSB_CHIPCO_GPIOIN);
+       u32 mask = chipco_read32(chipco, SSB_CHIPCO_GPIOIRQ);
+       u32 pol = chipco_read32(chipco, SSB_CHIPCO_GPIOPOL);
+       unsigned long irqs = (val ^ pol) & mask;
+       int gpio;
+
+       if (!irqs)
+               return IRQ_NONE;
+
+       for_each_set_bit(gpio, &irqs, bus->gpio.ngpio)
+               generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio));
+       ssb_chipco_gpio_polarity(chipco, irqs, val & irqs);
+
+       return IRQ_HANDLED;
+}
+
+static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus)
+{
+       struct ssb_chipcommon *chipco = &bus->chipco;
+       struct gpio_chip *chip = &bus->gpio;
+       int gpio, hwirq, err;
+
+       if (bus->bustype != SSB_BUSTYPE_SSB)
+               return 0;
+
+       bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio,
+                                               &irq_domain_simple_ops, chipco);
+       if (!bus->irq_domain) {
+               err = -ENODEV;
+               goto err_irq_domain;
+       }
+       for (gpio = 0; gpio < chip->ngpio; gpio++) {
+               int irq = irq_create_mapping(bus->irq_domain, gpio);
+
+               irq_set_chip_data(irq, bus);
+               irq_set_chip_and_handler(irq, &ssb_gpio_irq_chipco_chip,
+                                        handle_simple_irq);
+       }
+
+       hwirq = ssb_mips_irq(bus->chipco.dev) + 2;
+       err = request_irq(hwirq, ssb_gpio_irq_chipco_handler, IRQF_SHARED,
+                         "gpio", bus);
+       if (err)
+               goto err_req_irq;
+
+       ssb_chipco_gpio_intmask(&bus->chipco, ~0, 0);
+       chipco_set32(chipco, SSB_CHIPCO_IRQMASK, SSB_CHIPCO_IRQ_GPIO);
+
+       return 0;
+
+err_req_irq:
+       for (gpio = 0; gpio < chip->ngpio; gpio++) {
+               int irq = irq_find_mapping(bus->irq_domain, gpio);
+
+               irq_dispose_mapping(irq);
+       }
+       irq_domain_remove(bus->irq_domain);
+err_irq_domain:
+       return err;
+}
+
+static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus)
+{
+       struct ssb_chipcommon *chipco = &bus->chipco;
+       struct gpio_chip *chip = &bus->gpio;
+       int gpio;
+
+       if (bus->bustype != SSB_BUSTYPE_SSB)
+               return;
+
+       chipco_mask32(chipco, SSB_CHIPCO_IRQMASK, ~SSB_CHIPCO_IRQ_GPIO);
+       free_irq(ssb_mips_irq(bus->chipco.dev) + 2, chipco);
+       for (gpio = 0; gpio < chip->ngpio; gpio++) {
+               int irq = irq_find_mapping(bus->irq_domain, gpio);
+
+               irq_dispose_mapping(irq);
+       }
+       irq_domain_remove(bus->irq_domain);
+}
+#else
+static int ssb_gpio_irq_chipco_domain_init(struct ssb_bus *bus)
+{
+       return 0;
 }
 
+static void ssb_gpio_irq_chipco_domain_exit(struct ssb_bus *bus)
+{
+}
+#endif
+
 static int ssb_gpio_chipco_init(struct ssb_bus *bus)
 {
        struct gpio_chip *chip = &bus->gpio;
+       int err;
 
        chip->label             = "ssb_chipco_gpio";
        chip->owner             = THIS_MODULE;
@@ -96,7 +230,9 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus)
        chip->set               = ssb_gpio_chipco_set_value;
        chip->direction_input   = ssb_gpio_chipco_direction_input;
        chip->direction_output  = ssb_gpio_chipco_direction_output;
-       chip->to_irq            = ssb_gpio_chipco_to_irq;
+#if IS_ENABLED(CONFIG_SSB_EMBEDDED)
+       chip->to_irq            = ssb_gpio_to_irq;
+#endif
        chip->ngpio             = 16;
        /* There is just one SoC in one device and its GPIO addresses should be
         * deterministic to address them more easily. The other buses could get
@@ -106,9 +242,23 @@ static int ssb_gpio_chipco_init(struct ssb_bus *bus)
        else
                chip->base              = -1;
 
-       return gpiochip_add(chip);
+       err = ssb_gpio_irq_chipco_domain_init(bus);
+       if (err)
+               return err;
+
+       err = gpiochip_add(chip);
+       if (err) {
+               ssb_gpio_irq_chipco_domain_exit(bus);
+               return err;
+       }
+
+       return 0;
 }
 
+/**************************************************
+ * EXTIF
+ **************************************************/
+
 #ifdef CONFIG_SSB_DRIVER_EXTIF
 
 static int ssb_gpio_extif_get_value(struct gpio_chip *chip, unsigned gpio)
@@ -145,19 +295,127 @@ static int ssb_gpio_extif_direction_output(struct gpio_chip *chip,
        return 0;
 }
 
-static int ssb_gpio_extif_to_irq(struct gpio_chip *chip, unsigned gpio)
+#if IS_ENABLED(CONFIG_SSB_EMBEDDED)
+static void ssb_gpio_irq_extif_mask(struct irq_data *d)
 {
-       struct ssb_bus *bus = ssb_gpio_get_bus(chip);
+       struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
+       int gpio = irqd_to_hwirq(d);
 
-       if (bus->bustype == SSB_BUSTYPE_SSB)
-               return ssb_mips_irq(bus->extif.dev) + 2;
-       else
-               return -EINVAL;
+       ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), 0);
+}
+
+static void ssb_gpio_irq_extif_unmask(struct irq_data *d)
+{
+       struct ssb_bus *bus = irq_data_get_irq_chip_data(d);
+       int gpio = irqd_to_hwirq(d);
+       u32 val = ssb_extif_gpio_in(&bus->extif, BIT(gpio));
+
+       ssb_extif_gpio_polarity(&bus->extif, BIT(gpio), val);
+       ssb_extif_gpio_intmask(&bus->extif, BIT(gpio), BIT(gpio));
+}
+
+static struct irq_chip ssb_gpio_irq_extif_chip = {
+       .name           = "SSB-GPIO-EXTIF",
+       .irq_mask       = ssb_gpio_irq_extif_mask,
+       .irq_unmask     = ssb_gpio_irq_extif_unmask,
+};
+
+static irqreturn_t ssb_gpio_irq_extif_handler(int irq, void *dev_id)
+{
+       struct ssb_bus *bus = dev_id;
+       struct ssb_extif *extif = &bus->extif;
+       u32 val = ssb_read32(extif->dev, SSB_EXTIF_GPIO_IN);
+       u32 mask = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTMASK);
+       u32 pol = ssb_read32(extif->dev, SSB_EXTIF_GPIO_INTPOL);
+       unsigned long irqs = (val ^ pol) & mask;
+       int gpio;
+
+       if (!irqs)
+               return IRQ_NONE;
+
+       for_each_set_bit(gpio, &irqs, bus->gpio.ngpio)
+               generic_handle_irq(ssb_gpio_to_irq(&bus->gpio, gpio));
+       ssb_extif_gpio_polarity(extif, irqs, val & irqs);
+
+       return IRQ_HANDLED;
+}
+
+static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus)
+{
+       struct ssb_extif *extif = &bus->extif;
+       struct gpio_chip *chip = &bus->gpio;
+       int gpio, hwirq, err;
+
+       if (bus->bustype != SSB_BUSTYPE_SSB)
+               return 0;
+
+       bus->irq_domain = irq_domain_add_linear(NULL, chip->ngpio,
+                                               &irq_domain_simple_ops, extif);
+       if (!bus->irq_domain) {
+               err = -ENODEV;
+               goto err_irq_domain;
+       }
+       for (gpio = 0; gpio < chip->ngpio; gpio++) {
+               int irq = irq_create_mapping(bus->irq_domain, gpio);
+
+               irq_set_chip_data(irq, bus);
+               irq_set_chip_and_handler(irq, &ssb_gpio_irq_extif_chip,
+                                        handle_simple_irq);
+       }
+
+       hwirq = ssb_mips_irq(bus->extif.dev) + 2;
+       err = request_irq(hwirq, ssb_gpio_irq_extif_handler, IRQF_SHARED,
+                         "gpio", bus);
+       if (err)
+               goto err_req_irq;
+
+       ssb_extif_gpio_intmask(&bus->extif, ~0, 0);
+
+       return 0;
+
+err_req_irq:
+       for (gpio = 0; gpio < chip->ngpio; gpio++) {
+               int irq = irq_find_mapping(bus->irq_domain, gpio);
+
+               irq_dispose_mapping(irq);
+       }
+       irq_domain_remove(bus->irq_domain);
+err_irq_domain:
+       return err;
+}
+
+static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus)
+{
+       struct ssb_extif *extif = &bus->extif;
+       struct gpio_chip *chip = &bus->gpio;
+       int gpio;
+
+       if (bus->bustype != SSB_BUSTYPE_SSB)
+               return;
+
+       free_irq(ssb_mips_irq(bus->extif.dev) + 2, extif);
+       for (gpio = 0; gpio < chip->ngpio; gpio++) {
+               int irq = irq_find_mapping(bus->irq_domain, gpio);
+
+               irq_dispose_mapping(irq);
+       }
+       irq_domain_remove(bus->irq_domain);
 }
+#else
+static int ssb_gpio_irq_extif_domain_init(struct ssb_bus *bus)
+{
+       return 0;
+}
+
+static void ssb_gpio_irq_extif_domain_exit(struct ssb_bus *bus)
+{
+}
+#endif
 
 static int ssb_gpio_extif_init(struct ssb_bus *bus)
 {
        struct gpio_chip *chip = &bus->gpio;
+       int err;
 
        chip->label             = "ssb_extif_gpio";
        chip->owner             = THIS_MODULE;
@@ -165,7 +423,9 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus)
        chip->set               = ssb_gpio_extif_set_value;
        chip->direction_input   = ssb_gpio_extif_direction_input;
        chip->direction_output  = ssb_gpio_extif_direction_output;
-       chip->to_irq            = ssb_gpio_extif_to_irq;
+#if IS_ENABLED(CONFIG_SSB_EMBEDDED)
+       chip->to_irq            = ssb_gpio_to_irq;
+#endif
        chip->ngpio             = 5;
        /* There is just one SoC in one device and its GPIO addresses should be
         * deterministic to address them more easily. The other buses could get
@@ -175,7 +435,17 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus)
        else
                chip->base              = -1;
 
-       return gpiochip_add(chip);
+       err = ssb_gpio_irq_extif_domain_init(bus);
+       if (err)
+               return err;
+
+       err = gpiochip_add(chip);
+       if (err) {
+               ssb_gpio_irq_extif_domain_exit(bus);
+               return err;
+       }
+
+       return 0;
 }
 
 #else
@@ -185,6 +455,10 @@ static int ssb_gpio_extif_init(struct ssb_bus *bus)
 }
 #endif
 
+/**************************************************
+ * Init
+ **************************************************/
+
 int ssb_gpio_init(struct ssb_bus *bus)
 {
        if (ssb_chipco_available(&bus->chipco))
index 32a811d11c25cc419fc11878a9b2d3ff7c74c4bb..2fead3820849f028f34f2a84c5aa35d8a6f566fd 100644 (file)
@@ -593,6 +593,13 @@ static int ssb_attach_queued_buses(void)
                ssb_pcicore_init(&bus->pcicore);
                if (bus->bustype == SSB_BUSTYPE_SSB)
                        ssb_watchdog_register(bus);
+
+               err = ssb_gpio_init(bus);
+               if (err == -ENOTSUPP)
+                       ssb_dbg("GPIO driver not activated\n");
+               else if (err)
+                       ssb_dbg("Error registering GPIO driver: %i\n", err);
+
                ssb_bus_may_powerdown(bus);
 
                err = ssb_devices_register(bus);
@@ -830,11 +837,6 @@ static int ssb_bus_register(struct ssb_bus *bus,
        ssb_chipcommon_init(&bus->chipco);
        ssb_extif_init(&bus->extif);
        ssb_mipscore_init(&bus->mipscore);
-       err = ssb_gpio_init(bus);
-       if (err == -ENOTSUPP)
-               ssb_dbg("GPIO driver not activated\n");
-       else if (err)
-               ssb_dbg("Error registering GPIO driver: %i\n", err);
        err = ssb_fetch_invariants(bus, get_invariants);
        if (err) {
                ssb_bus_may_powerdown(bus);
index 810bcb31740ac5b8b7f89f9255d5ae513ea4e125..99375f0a9440931760338f5dd302de7e4eab45b5 100644 (file)
@@ -78,10 +78,6 @@ source "drivers/staging/sep/Kconfig"
 
 source "drivers/staging/iio/Kconfig"
 
-source "drivers/staging/zsmalloc/Kconfig"
-
-source "drivers/staging/zram/Kconfig"
-
 source "drivers/staging/wlags49_h2/Kconfig"
 
 source "drivers/staging/wlags49_h25/Kconfig"
index d925cde979cf330388a4ab931b7618953376071f..ddc3c4a5d39d5c185e5c791c4a04e69fa1d3f00e 100644 (file)
@@ -33,8 +33,6 @@ obj-$(CONFIG_VT6656)          += vt6656/
 obj-$(CONFIG_VME_BUS)          += vme/
 obj-$(CONFIG_DX_SEP)            += sep/
 obj-$(CONFIG_IIO)              += iio/
-obj-$(CONFIG_ZRAM)             += zram/
-obj-$(CONFIG_ZSMALLOC)         += zsmalloc/
 obj-$(CONFIG_WLAGS49_H2)       += wlags49_h2/
 obj-$(CONFIG_WLAGS49_H25)      += wlags49_h25/
 obj-$(CONFIG_FB_SM7XX)         += sm7xxfb/
index 5338e8d4c50fa998582fb86209f66c95a11419a8..0718905adeb256cb2a2dd12336f3dbb7db365d23 100644 (file)
@@ -194,10 +194,10 @@ static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head)
        struct cl_object     *obj = ll_i2info(inode)->lli_clob;
        pgoff_t        offset;
        int                ret;
-       int                i;
        int                rw;
        obd_count            page_count = 0;
-       struct bio_vec       *bvec;
+       struct bio_vec       bvec;
+       struct bvec_iter   iter;
        struct bio         *bio;
        ssize_t        bytes;
 
@@ -220,15 +220,15 @@ static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head)
        for (bio = head; bio != NULL; bio = bio->bi_next) {
                LASSERT(rw == bio->bi_rw);
 
-               offset = (pgoff_t)(bio->bi_sector << 9) + lo->lo_offset;
-               bio_for_each_segment(bvec, bio, i) {
-                       BUG_ON(bvec->bv_offset != 0);
-                       BUG_ON(bvec->bv_len != PAGE_CACHE_SIZE);
+               offset = (pgoff_t)(bio->bi_iter.bi_sector << 9) + lo->lo_offset;
+               bio_for_each_segment(bvec, bio, iter) {
+                       BUG_ON(bvec.bv_offset != 0);
+                       BUG_ON(bvec.bv_len != PAGE_CACHE_SIZE);
 
-                       pages[page_count] = bvec->bv_page;
+                       pages[page_count] = bvec.bv_page;
                        offsets[page_count] = offset;
                        page_count++;
-                       offset += bvec->bv_len;
+                       offset += bvec.bv_len;
                }
                LASSERT(page_count <= LLOOP_MAX_SEGMENTS);
        }
@@ -313,7 +313,8 @@ static unsigned int loop_get_bio(struct lloop_device *lo, struct bio **req)
        bio = &lo->lo_bio;
        while (*bio && (*bio)->bi_rw == rw) {
                CDEBUG(D_INFO, "bio sector %llu size %u count %u vcnt%u \n",
-                      (unsigned long long)(*bio)->bi_sector, (*bio)->bi_size,
+                      (unsigned long long)(*bio)->bi_iter.bi_sector,
+                      (*bio)->bi_iter.bi_size,
                       page_count, (*bio)->bi_vcnt);
                if (page_count + (*bio)->bi_vcnt > LLOOP_MAX_SEGMENTS)
                        break;
@@ -347,7 +348,8 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio)
                goto err;
 
        CDEBUG(D_INFO, "submit bio sector %llu size %u\n",
-              (unsigned long long)old_bio->bi_sector, old_bio->bi_size);
+              (unsigned long long)old_bio->bi_iter.bi_sector,
+              old_bio->bi_iter.bi_size);
 
        spin_lock_irq(&lo->lo_lock);
        inactive = (lo->lo_state != LLOOP_BOUND);
@@ -367,7 +369,7 @@ static void loop_make_request(struct request_queue *q, struct bio *old_bio)
        loop_add_bio(lo, old_bio);
        return;
 err:
-       cfs_bio_io_error(old_bio, old_bio->bi_size);
+       cfs_bio_io_error(old_bio, old_bio->bi_iter.bi_size);
 }
 
 
@@ -378,7 +380,7 @@ static inline void loop_handle_bio(struct lloop_device *lo, struct bio *bio)
        while (bio) {
                struct bio *tmp = bio->bi_next;
                bio->bi_next = NULL;
-               cfs_bio_endio(bio, bio->bi_size, ret);
+               cfs_bio_endio(bio, bio->bi_iter.bi_size, ret);
                bio = tmp;
        }
 }
index 46f1e619cbd838f29bd9891832db00b6610a44a7..22b0c9d6f0464059257ac552119287f621e8c9cb 100644 (file)
@@ -21,6 +21,8 @@ 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"
 
 source "drivers/staging/media/davinci_vpfe/Kconfig"
@@ -31,8 +33,14 @@ source "drivers/staging/media/go7007/Kconfig"
 
 source "drivers/staging/media/msi3101/Kconfig"
 
+source "drivers/staging/media/omap24xx/Kconfig"
+
+source "drivers/staging/media/sn9c102/Kconfig"
+
 source "drivers/staging/media/solo6x10/Kconfig"
 
+source "drivers/staging/media/omap4iss/Kconfig"
+
 # Keep LIRC at the end, as it has sub-menus
 source "drivers/staging/media/lirc/Kconfig"
 
index eb7f30b1ccd8863ddf0399c30e38df56e0e89a4f..bedc62aaede68f9a27e42aa4a380c6ca7bfed551 100644 (file)
@@ -1,4 +1,5 @@
 obj-$(CONFIG_DVB_AS102)                += as102/
+obj-$(CONFIG_I2C_BCM2048)      += bcm2048/
 obj-$(CONFIG_DVB_CXD2099)      += cxd2099/
 obj-$(CONFIG_LIRC_STAGING)     += lirc/
 obj-$(CONFIG_SOLO6X10)         += solo6x10/
@@ -6,3 +7,7 @@ obj-$(CONFIG_VIDEO_DT3155)      += dt3155v4l/
 obj-$(CONFIG_VIDEO_GO7007)     += go7007/
 obj-$(CONFIG_USB_MSI3101)      += msi3101/
 obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
+obj-$(CONFIG_VIDEO_OMAP4)      += omap4iss/
+obj-$(CONFIG_USB_SN9C102)       += sn9c102/
+obj-$(CONFIG_VIDEO_OMAP2)       += omap24xx/
+obj-$(CONFIG_VIDEO_TCM825X)     += omap24xx/
index 8b7bb954707983df857e99e68693e1bd4914fb2b..09d64cd675020f65669b3b8c7b9386414fb7738e 100644 (file)
@@ -111,8 +111,6 @@ static int as10x_pid_filter(struct as102_dev_t *dev,
        struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
        int ret = -EFAULT;
 
-       ENTER();
-
        if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
                dprintk(debug, "mutex_lock_interruptible(lock) failed !\n");
                return -EBUSY;
@@ -133,15 +131,14 @@ static int as10x_pid_filter(struct as102_dev_t *dev,
                filter.pid = pid;
 
                ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
-               dprintk(debug, "ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
+               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);
-
-       LEAVE();
        return ret;
 }
 
@@ -151,8 +148,6 @@ static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
        struct dvb_demux *demux = dvbdmxfeed->demux;
        struct as102_dev_t *as102_dev = demux->priv;
 
-       ENTER();
-
        if (mutex_lock_interruptible(&as102_dev->sem))
                return -ERESTARTSYS;
 
@@ -164,7 +159,6 @@ static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
                ret = as102_start_stream(as102_dev);
 
        mutex_unlock(&as102_dev->sem);
-       LEAVE();
        return ret;
 }
 
@@ -173,8 +167,6 @@ 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;
 
-       ENTER();
-
        if (mutex_lock_interruptible(&as102_dev->sem))
                return -ERESTARTSYS;
 
@@ -186,7 +178,6 @@ static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
                                 dvbdmxfeed->pid, 0);
 
        mutex_unlock(&as102_dev->sem);
-       LEAVE();
        return 0;
 }
 
index b0e5a23bd5323569911afc7e904377fae594fb01..a06837dcc05d017b800baabc43b71527eb7112ba 100644 (file)
@@ -38,14 +38,6 @@ extern int elna_enable;
                printk(args);   \
        } } while (0)
 
-#ifdef TRACE
-#define ENTER()        pr_debug(">> enter %s\n", __func__)
-#define LEAVE()        pr_debug("<< leave %s\n", __func__)
-#else
-#define ENTER()
-#define LEAVE()
-#endif
-
 #define AS102_DEVICE_MAJOR     192
 
 #define AS102_USB_BUF_SIZE     512
index 9ce8c9daa2e7a6862bc904b99e23d9b83902a575..b686b7617cdc1bc31a7e64e9233d215b0fa576e1 100644 (file)
@@ -34,8 +34,6 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe)
        struct as102_dev_t *dev;
        struct as10x_tune_args tune_args = { 0 };
 
-       ENTER();
-
        dev = (struct as102_dev_t *) fe->tuner_priv;
        if (dev == NULL)
                return -ENODEV;
@@ -52,7 +50,6 @@ static int as102_fe_set_frontend(struct dvb_frontend *fe)
 
        mutex_unlock(&dev->bus_adap.lock);
 
-       LEAVE();
        return (ret < 0) ? -EINVAL : 0;
 }
 
@@ -63,8 +60,6 @@ static int as102_fe_get_frontend(struct dvb_frontend *fe)
        struct as102_dev_t *dev;
        struct as10x_tps tps = { 0 };
 
-       ENTER();
-
        dev = (struct as102_dev_t *) fe->tuner_priv;
        if (dev == NULL)
                return -EINVAL;
@@ -80,13 +75,11 @@ static int as102_fe_get_frontend(struct dvb_frontend *fe)
 
        mutex_unlock(&dev->bus_adap.lock);
 
-       LEAVE();
        return (ret < 0) ? -EINVAL : 0;
 }
 
 static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
                        struct dvb_frontend_tune_settings *settings) {
-       ENTER();
 
 #if 0
        dprintk(debug, "step_size    = %d\n", settings->step_size);
@@ -97,7 +90,6 @@ static int as102_fe_get_tune_settings(struct dvb_frontend *fe,
 
        settings->min_delay_ms = 1000;
 
-       LEAVE();
        return 0;
 }
 
@@ -108,8 +100,6 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
        struct as102_dev_t *dev;
        struct as10x_tune_status tstate = { 0 };
 
-       ENTER();
-
        dev = (struct as102_dev_t *) fe->tuner_priv;
        if (dev == NULL)
                return -ENODEV;
@@ -151,8 +141,8 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
                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");
+                       dprintk(debug,
+                               "as10x_cmd_get_demod_stats failed (probably not tuned)\n");
                } else {
                        dprintk(debug,
                                "demod status: fc: 0x%08x, bad fc: 0x%08x, "
@@ -168,7 +158,6 @@ static int as102_fe_read_status(struct dvb_frontend *fe, fe_status_t *status)
 
 out:
        mutex_unlock(&dev->bus_adap.lock);
-       LEAVE();
        return ret;
 }
 
@@ -183,15 +172,12 @@ static int as102_fe_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
        struct as102_dev_t *dev;
 
-       ENTER();
-
        dev = (struct as102_dev_t *) fe->tuner_priv;
        if (dev == NULL)
                return -ENODEV;
 
        *snr = dev->demod_stats.mer;
 
-       LEAVE();
        return 0;
 }
 
@@ -199,15 +185,12 @@ static int as102_fe_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        struct as102_dev_t *dev;
 
-       ENTER();
-
        dev = (struct as102_dev_t *) fe->tuner_priv;
        if (dev == NULL)
                return -ENODEV;
 
        *ber = dev->ber;
 
-       LEAVE();
        return 0;
 }
 
@@ -216,15 +199,12 @@ static int as102_fe_read_signal_strength(struct dvb_frontend *fe,
 {
        struct as102_dev_t *dev;
 
-       ENTER();
-
        dev = (struct as102_dev_t *) fe->tuner_priv;
        if (dev == NULL)
                return -ENODEV;
 
        *strength = (((0xffff * 400) * dev->signal_strength + 41000) * 2);
 
-       LEAVE();
        return 0;
 }
 
@@ -232,8 +212,6 @@ static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
        struct as102_dev_t *dev;
 
-       ENTER();
-
        dev = (struct as102_dev_t *) fe->tuner_priv;
        if (dev == NULL)
                return -ENODEV;
@@ -243,7 +221,6 @@ static int as102_fe_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
        else
                *ucblocks = 0;
 
-       LEAVE();
        return 0;
 }
 
@@ -252,8 +229,6 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
        struct as102_dev_t *dev;
        int ret;
 
-       ENTER();
-
        dev = (struct as102_dev_t *) fe->tuner_priv;
        if (dev == NULL)
                return -ENODEV;
@@ -263,7 +238,8 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
 
        if (acquire) {
                if (elna_enable)
-                       as10x_cmd_set_context(&dev->bus_adap, CONTEXT_LNA, dev->elna_cfg);
+                       as10x_cmd_set_context(&dev->bus_adap,
+                                             CONTEXT_LNA, dev->elna_cfg);
 
                ret = as10x_cmd_turn_on(&dev->bus_adap);
        } else {
@@ -272,7 +248,6 @@ static int as102_fe_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
 
        mutex_unlock(&dev->bus_adap.lock);
 
-       LEAVE();
        return ret;
 }
 
@@ -581,8 +556,8 @@ static void as102_fe_copy_tune_parameters(struct as10x_tune_args *tune_args,
                           as102_fe_get_code_rate(params->code_rate_LP);
                }
 
-               dprintk(debug, "\thierarchy: 0x%02x  "
-                               "selected: %s  code_rate_%s: 0x%02x\n",
+               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",
index b9670ee41b4ec3b59c07f72a514ab57a29ac4942..f33f752c0aadfcf6788fce3cf87df07394e94c08 100644 (file)
 #include "as102_drv.h"
 #include "as102_fw.h"
 
-char as102_st_fw1[] = "as102_data1_st.hex";
-char as102_st_fw2[] = "as102_data2_st.hex";
-char as102_dt_fw1[] = "as102_data1_dt.hex";
-char as102_dt_fw2[] = "as102_data2_dt.hex";
+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)
 {
@@ -109,8 +109,6 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
        int total_read_bytes = 0, errno = 0;
        unsigned char addr_has_changed = 0;
 
-       ENTER();
-
        for (total_read_bytes = 0; total_read_bytes < firmware->size; ) {
                int read_bytes = 0, data_len = 0;
 
@@ -158,7 +156,6 @@ static int as102_firmware_upload(struct as10x_bus_adapter_t *bus_adap,
                }
        }
 error:
-       LEAVE();
        return (errno == 0) ? total_read_bytes : errno;
 }
 
@@ -167,11 +164,9 @@ int as102_fw_upload(struct as10x_bus_adapter_t *bus_adap)
        int errno = -EFAULT;
        const struct firmware *firmware = NULL;
        unsigned char *cmd_buf = NULL;
-       char *fw1, *fw2;
+       const char *fw1, *fw2;
        struct usb_device *dev = bus_adap->usb_dev;
 
-       ENTER();
-
        /* select fw file to upload */
        if (dual_tuner) {
                fw1 = as102_dt_fw1;
@@ -233,6 +228,5 @@ error:
        kfree(cmd_buf);
        release_firmware(firmware);
 
-       LEAVE();
        return errno;
 }
index 9f275f02015044017c21196dfb883053b64b9964..e4a69454ebeb5f862ad73399e6a5969b8d08782b 100644 (file)
@@ -92,7 +92,6 @@ static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap,
                              unsigned char *recv_buf, int recv_buf_len)
 {
        int ret = 0;
-       ENTER();
 
        if (send_buf != NULL) {
                ret = usb_control_msg(bus_adap->usb_dev,
@@ -140,7 +139,6 @@ static int as102_usb_xfer_cmd(struct as10x_bus_adapter_t *bus_adap,
 #endif
        }
 
-       LEAVE();
        return ret;
 }
 
@@ -191,7 +189,7 @@ static int as102_read_ep2(struct as10x_bus_adapter_t *bus_adap,
        return ret ? ret : actual_len;
 }
 
-struct as102_priv_ops_t as102_priv_ops = {
+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,
@@ -240,8 +238,6 @@ static void as102_free_usb_stream_buffer(struct as102_dev_t *dev)
 {
        int i;
 
-       ENTER();
-
        for (i = 0; i < MAX_STREAM_URB; i++)
                usb_free_urb(dev->stream_urb[i]);
 
@@ -249,15 +245,12 @@ static void as102_free_usb_stream_buffer(struct as102_dev_t *dev)
                        MAX_STREAM_URB * AS102_USB_BUF_SIZE,
                        dev->stream,
                        dev->dma_addr);
-       LEAVE();
 }
 
 static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
 {
        int i, ret = 0;
 
-       ENTER();
-
        dev->stream = usb_alloc_coherent(dev->bus_adap.usb_dev,
                                       MAX_STREAM_URB * AS102_USB_BUF_SIZE,
                                       GFP_KERNEL,
@@ -287,7 +280,6 @@ static int as102_alloc_usb_stream_buffer(struct as102_dev_t *dev)
 
                dev->stream_urb[i] = urb;
        }
-       LEAVE();
        return ret;
 }
 
@@ -318,23 +310,17 @@ static void as102_usb_release(struct kref *kref)
 {
        struct as102_dev_t *as102_dev;
 
-       ENTER();
-
        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);
        }
-
-       LEAVE();
 }
 
 static void as102_usb_disconnect(struct usb_interface *intf)
 {
        struct as102_dev_t *as102_dev;
 
-       ENTER();
-
        /* extract as102_dev_t from usb_device private data */
        as102_dev = usb_get_intfdata(intf);
 
@@ -353,8 +339,6 @@ static void as102_usb_disconnect(struct usb_interface *intf)
        kref_put(&as102_dev->kref, as102_usb_release);
 
        pr_info("%s: device has been disconnected\n", DRIVER_NAME);
-
-       LEAVE();
 }
 
 static int as102_usb_probe(struct usb_interface *intf,
@@ -364,8 +348,6 @@ static int as102_usb_probe(struct usb_interface *intf,
        struct as102_dev_t *as102_dev;
        int i;
 
-       ENTER();
-
        /* This should never actually happen */
        if (ARRAY_SIZE(as102_usb_id_table) !=
            (sizeof(as102_device_names) / sizeof(const char *))) {
@@ -419,15 +401,21 @@ static int as102_usb_probe(struct usb_interface *intf,
        /* request buffer allocation for streaming */
        ret = as102_alloc_usb_stream_buffer(as102_dev);
        if (ret != 0)
-               goto failed;
+               goto failed_stream;
 
        /* register dvb layer */
        ret = as102_dvb_register(as102_dev);
+       if (ret != 0)
+               goto failed_dvb;
 
-       LEAVE();
        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;
@@ -439,8 +427,6 @@ static int as102_open(struct inode *inode, struct file *file)
        struct usb_interface *intf = NULL;
        struct as102_dev_t *dev = NULL;
 
-       ENTER();
-
        /* read minor from inode */
        minor = iminor(inode);
 
@@ -467,7 +453,6 @@ static int as102_open(struct inode *inode, struct file *file)
        kref_get(&dev->kref);
 
 exit:
-       LEAVE();
        return ret;
 }
 
@@ -476,15 +461,12 @@ static int as102_release(struct inode *inode, struct file *file)
        int ret = 0;
        struct as102_dev_t *dev = NULL;
 
-       ENTER();
-
        dev = file->private_data;
        if (dev != NULL) {
                /* decrement the count on our device */
                kref_put(&dev->kref, as102_usb_release);
        }
 
-       LEAVE();
        return ret;
 }
 
index a73df10982d079b63e8cf8a72c94665fdfccaa22..9e49f15a7c9f1df77f825231596cc8b9e6f79fa2 100644 (file)
@@ -34,8 +34,6 @@ int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
        int error = AS10X_CMD_ERROR;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -63,7 +61,6 @@ int as10x_cmd_turn_on(struct as10x_bus_adapter_t *adap)
        error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNON_RSP);
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -78,8 +75,6 @@ int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
        int error = AS10X_CMD_ERROR;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -106,7 +101,6 @@ int as10x_cmd_turn_off(struct as10x_bus_adapter_t *adap)
        error = as10x_rsp_parse(prsp, CONTROL_PROC_TURNOFF_RSP);
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -123,8 +117,6 @@ int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
        int error = AS10X_CMD_ERROR;
        struct as10x_cmd_t *preq, *prsp;
 
-       ENTER();
-
        preq = adap->cmd;
        prsp = adap->rsp;
 
@@ -164,7 +156,6 @@ int as10x_cmd_set_tune(struct as10x_bus_adapter_t *adap,
        error = as10x_rsp_parse(prsp, CONTROL_PROC_SETTUNE_RSP);
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -181,8 +172,6 @@ int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
        int error = AS10X_CMD_ERROR;
        struct as10x_cmd_t  *preq, *prsp;
 
-       ENTER();
-
        preq = adap->cmd;
        prsp = adap->rsp;
 
@@ -220,7 +209,6 @@ int as10x_cmd_get_tune_status(struct as10x_bus_adapter_t *adap,
        pstatus->BER = le16_to_cpu(prsp->body.get_tune_status.rsp.sts.BER);
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -236,8 +224,6 @@ 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;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -281,7 +267,6 @@ int as10x_cmd_get_tps(struct as10x_bus_adapter_t *adap, struct as10x_tps *ptps)
        ptps->cell_ID = le16_to_cpu(prsp->body.get_tps.rsp.tps.cell_ID);
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -298,8 +283,6 @@ int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
        int error = AS10X_CMD_ERROR;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -343,7 +326,6 @@ int as10x_cmd_get_demod_stats(struct as10x_bus_adapter_t *adap,
                prsp->body.get_demod_stats.rsp.stats.has_started;
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -361,8 +343,6 @@ int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
        int error = AS10X_CMD_ERROR;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -397,7 +377,6 @@ int as10x_cmd_get_impulse_resp(struct as10x_bus_adapter_t *adap,
        *is_ready = prsp->body.get_impulse_rsp.rsp.is_ready;
 
 out:
-       LEAVE();
        return error;
 }
 
index 4a2bbd76665541990d69009b133686ae7b947fd6..b1e300d88753978d517a5f4ae27b0f1dfda229f5 100644 (file)
@@ -40,8 +40,6 @@ int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
        int  error;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -81,7 +79,6 @@ int as10x_cmd_get_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
        }
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -99,8 +96,6 @@ int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -136,7 +131,6 @@ int as10x_cmd_set_context(struct as10x_bus_adapter_t *adap, uint16_t tag,
        error = as10x_context_rsp_parse(prsp, CONTROL_PROC_CONTEXT_RSP);
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -156,8 +150,6 @@ int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode)
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -188,7 +180,6 @@ int as10x_cmd_eLNA_change_mode(struct as10x_bus_adapter_t *adap, uint8_t mode)
        error = as10x_rsp_parse(prsp, CONTROL_PROC_ELNA_CHANGE_MODE_RSP);
 
 out:
-       LEAVE();
        return error;
 }
 
index 6d000f60fb0e9650fe10d0aefc7cd986dfe38b73..1088ca1fe92fa616ea06d19d40d0ca4ba55201bb 100644 (file)
@@ -34,8 +34,6 @@ int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -77,7 +75,6 @@ int as10x_cmd_add_PID_filter(struct as10x_bus_adapter_t *adap,
        }
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -94,8 +91,6 @@ int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -126,7 +121,6 @@ int as10x_cmd_del_PID_filter(struct as10x_bus_adapter_t *adap,
        error = as10x_rsp_parse(prsp, CONTROL_PROC_REMOVEFILTER_RSP);
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -141,8 +135,6 @@ int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap)
        int error;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -172,7 +164,6 @@ int as10x_cmd_start_streaming(struct as10x_bus_adapter_t *adap)
        error = as10x_rsp_parse(prsp, CONTROL_PROC_START_STREAMING_RSP);
 
 out:
-       LEAVE();
        return error;
 }
 
@@ -187,8 +178,6 @@ int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap)
        int8_t error;
        struct as10x_cmd_t *pcmd, *prsp;
 
-       ENTER();
-
        pcmd = adap->cmd;
        prsp = adap->rsp;
 
@@ -218,6 +207,5 @@ int as10x_cmd_stop_streaming(struct as10x_bus_adapter_t *adap)
        error = as10x_rsp_parse(prsp, CONTROL_PROC_STOP_STREAMING_RSP);
 
 out:
-       LEAVE();
        return error;
 }
diff --git a/drivers/staging/media/bcm2048/Kconfig b/drivers/staging/media/bcm2048/Kconfig
new file mode 100644 (file)
index 0000000..a9fc6e1
--- /dev/null
@@ -0,0 +1,13 @@
+#
+# Multimedia Video device configuration
+#
+
+config I2C_BCM2048
+       tristate "Broadcom BCM2048 FM Radio Receiver support"
+       depends on I2C && VIDEO_V4L2 && RADIO_ADAPTERS
+       ---help---
+         Say Y here if you want support to BCM2048 FM Radio Receiver.
+         This device driver supports only i2c bus.
+
+         To compile this driver as a module, choose M here: the
+         module will be called radio-bcm2048.
diff --git a/drivers/staging/media/bcm2048/Makefile b/drivers/staging/media/bcm2048/Makefile
new file mode 100644 (file)
index 0000000..b4f5663
--- /dev/null
@@ -0,0 +1 @@
+obj-$(CONFIG_I2C_BCM2048) += radio-bcm2048.o
diff --git a/drivers/staging/media/bcm2048/TODO b/drivers/staging/media/bcm2048/TODO
new file mode 100644 (file)
index 0000000..051f85d
--- /dev/null
@@ -0,0 +1,24 @@
+TODO:
+
+From the initial code review:
+
+The main thing you need to do is to implement all the controls using the
+control framework (see Documentation/video4linux/v4l2-controls.txt).
+Most drivers are by now converted to the control framework, so you will
+find many examples of how to do this in drivers/media/radio.
+
+The sysfs stuff should be replaced by controls as well. A lot of the RDS
+support is now available as controls (although there may well be some
+missing features, but that is easy enough to add). Since the RDS data is
+actually read() from the device I am not sure whether the RDS
+properties/controls should be there at all.
+
+Correct Coding Style, as this driver also violates several Style
+rules, and do evil tricks, like returning from a function inside a
+macro.
+
+Finally this driver should probably be split up into two parts: one
+v4l2_subdev-based core driver and one platform driver. See e.g.
+radio-si4713/si4713-i2c.c as a good example. But I would wait with that
+until the rest of the driver is cleaned up. Then I have a better idea of
+whether this is necessary or not.
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c
new file mode 100644 (file)
index 0000000..b2cd3a8
--- /dev/null
@@ -0,0 +1,2744 @@
+/*
+ * drivers/staging/media/radio-bcm2048.c
+ *
+ * Driver for I2C Broadcom BCM2048 FM Radio Receiver:
+ *
+ * Copyright (C) Nokia Corporation
+ * Contact: Eero Nurkkala <ext-eero.nurkkala@nokia.com>
+ *
+ * Copyright (C) Nils Faerber <nils.faerber@kernelconcepts.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.
+ *
+ * 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
+ */
+
+/*
+ * History:
+ *             Eero Nurkkala <ext-eero.nurkkala@nokia.com>
+ *             Version 0.0.1
+ *             - Initial implementation
+ * 2010-02-21  Nils Faerber <nils.faerber@kernelconcepts.de>
+ *             Version 0.0.2
+ *             - Add support for interrupt driven rds data reading
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/version.h>
+#include <linux/interrupt.h>
+#include <linux/sysfs.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include "radio-bcm2048.h"
+
+/* driver definitions */
+#define BCM2048_DRIVER_AUTHOR  "Eero Nurkkala <ext-eero.nurkkala@nokia.com>"
+#define BCM2048_DRIVER_NAME    BCM2048_NAME
+#define BCM2048_DRIVER_VERSION KERNEL_VERSION(0, 0, 1)
+#define BCM2048_DRIVER_CARD    "Broadcom bcm2048 FM Radio Receiver"
+#define BCM2048_DRIVER_DESC    "I2C driver for BCM2048 FM Radio Receiver"
+
+/* I2C Control Registers */
+#define BCM2048_I2C_FM_RDS_SYSTEM      0x00
+#define BCM2048_I2C_FM_CTRL            0x01
+#define BCM2048_I2C_RDS_CTRL0          0x02
+#define BCM2048_I2C_RDS_CTRL1          0x03
+#define BCM2048_I2C_FM_AUDIO_PAUSE     0x04
+#define BCM2048_I2C_FM_AUDIO_CTRL0     0x05
+#define BCM2048_I2C_FM_AUDIO_CTRL1     0x06
+#define BCM2048_I2C_FM_SEARCH_CTRL0    0x07
+#define BCM2048_I2C_FM_SEARCH_CTRL1    0x08
+#define BCM2048_I2C_FM_SEARCH_TUNE_MODE        0x09
+#define BCM2048_I2C_FM_FREQ0           0x0a
+#define BCM2048_I2C_FM_FREQ1           0x0b
+#define BCM2048_I2C_FM_AF_FREQ0                0x0c
+#define BCM2048_I2C_FM_AF_FREQ1                0x0d
+#define BCM2048_I2C_FM_CARRIER         0x0e
+#define BCM2048_I2C_FM_RSSI            0x0f
+#define BCM2048_I2C_FM_RDS_MASK0       0x10
+#define BCM2048_I2C_FM_RDS_MASK1       0x11
+#define BCM2048_I2C_FM_RDS_FLAG0       0x12
+#define BCM2048_I2C_FM_RDS_FLAG1       0x13
+#define BCM2048_I2C_RDS_WLINE          0x14
+#define BCM2048_I2C_RDS_BLKB_MATCH0    0x16
+#define BCM2048_I2C_RDS_BLKB_MATCH1    0x17
+#define BCM2048_I2C_RDS_BLKB_MASK0     0x18
+#define BCM2048_I2C_RDS_BLKB_MASK1     0x19
+#define BCM2048_I2C_RDS_PI_MATCH0      0x1a
+#define BCM2048_I2C_RDS_PI_MATCH1      0x1b
+#define BCM2048_I2C_RDS_PI_MASK0       0x1c
+#define BCM2048_I2C_RDS_PI_MASK1       0x1d
+#define BCM2048_I2C_SPARE1             0x20
+#define BCM2048_I2C_SPARE2             0x21
+#define BCM2048_I2C_FM_RDS_REV         0x28
+#define BCM2048_I2C_SLAVE_CONFIGURATION        0x29
+#define BCM2048_I2C_RDS_DATA           0x80
+#define BCM2048_I2C_FM_BEST_TUNE_MODE  0x90
+
+/* BCM2048_I2C_FM_RDS_SYSTEM */
+#define BCM2048_FM_ON                  0x01
+#define BCM2048_RDS_ON                 0x02
+
+/* BCM2048_I2C_FM_CTRL */
+#define BCM2048_BAND_SELECT                    0x01
+#define BCM2048_STEREO_MONO_AUTO_SELECT                0x02
+#define BCM2048_STEREO_MONO_MANUAL_SELECT      0x04
+#define BCM2048_STEREO_MONO_BLEND_SWITCH       0x08
+#define BCM2048_HI_LO_INJECTION                        0x10
+
+/* BCM2048_I2C_RDS_CTRL0 */
+#define BCM2048_RBDS_RDS_SELECT                0x01
+#define BCM2048_FLUSH_FIFO             0x02
+
+/* BCM2048_I2C_FM_AUDIO_PAUSE */
+#define BCM2048_AUDIO_PAUSE_RSSI_TRESH 0x0f
+#define BCM2048_AUDIO_PAUSE_DURATION   0xf0
+
+/* BCM2048_I2C_FM_AUDIO_CTRL0 */
+#define BCM2048_RF_MUTE                        0x01
+#define BCM2048_MANUAL_MUTE            0x02
+#define BCM2048_DAC_OUTPUT_LEFT                0x04
+#define BCM2048_DAC_OUTPUT_RIGHT       0x08
+#define BCM2048_AUDIO_ROUTE_DAC                0x10
+#define BCM2048_AUDIO_ROUTE_I2S                0x20
+#define BCM2048_DE_EMPHASIS_SELECT     0x40
+#define BCM2048_AUDIO_BANDWIDTH_SELECT 0x80
+
+/* BCM2048_I2C_FM_SEARCH_CTRL0 */
+#define BCM2048_SEARCH_RSSI_THRESHOLD  0x7f
+#define BCM2048_SEARCH_DIRECTION       0x80
+
+/* BCM2048_I2C_FM_SEARCH_TUNE_MODE */
+#define BCM2048_FM_AUTO_SEARCH         0x03
+
+/* BCM2048_I2C_FM_RSSI */
+#define BCM2048_RSSI_VALUE             0xff
+
+/* BCM2048_I2C_FM_RDS_MASK0 */
+/* BCM2048_I2C_FM_RDS_MASK1 */
+#define BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED   0x01
+#define BCM2048_FM_FLAG_SEARCH_TUNE_FAIL       0x02
+#define BCM2048_FM_FLAG_RSSI_LOW               0x04
+#define BCM2048_FM_FLAG_CARRIER_ERROR_HIGH     0x08
+#define BCM2048_FM_FLAG_AUDIO_PAUSE_INDICATION 0x10
+#define BCM2048_FLAG_STEREO_DETECTED           0x20
+#define BCM2048_FLAG_STEREO_ACTIVE             0x40
+
+/* BCM2048_I2C_RDS_DATA */
+#define BCM2048_SLAVE_ADDRESS                  0x3f
+#define BCM2048_SLAVE_ENABLE                   0x80
+
+/* BCM2048_I2C_FM_BEST_TUNE_MODE */
+#define BCM2048_BEST_TUNE_MODE                 0x80
+
+#define BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED   0x01
+#define BCM2048_FM_FLAG_SEARCH_TUNE_FAIL       0x02
+#define BCM2048_FM_FLAG_RSSI_LOW               0x04
+#define BCM2048_FM_FLAG_CARRIER_ERROR_HIGH     0x08
+#define BCM2048_FM_FLAG_AUDIO_PAUSE_INDICATION 0x10
+#define BCM2048_FLAG_STEREO_DETECTED           0x20
+#define BCM2048_FLAG_STEREO_ACTIVE             0x40
+
+#define BCM2048_RDS_FLAG_FIFO_WLINE            0x02
+#define BCM2048_RDS_FLAG_B_BLOCK_MATCH         0x08
+#define BCM2048_RDS_FLAG_SYNC_LOST             0x10
+#define BCM2048_RDS_FLAG_PI_MATCH              0x20
+
+#define BCM2048_RDS_MARK_END_BYTE0             0x7C
+#define BCM2048_RDS_MARK_END_BYTEN             0xFF
+
+#define BCM2048_FM_FLAGS_ALL   (FM_FLAG_SEARCH_TUNE_FINISHED | \
+                                FM_FLAG_SEARCH_TUNE_FAIL | \
+                                FM_FLAG_RSSI_LOW | \
+                                FM_FLAG_CARRIER_ERROR_HIGH | \
+                                FM_FLAG_AUDIO_PAUSE_INDICATION | \
+                                FLAG_STEREO_DETECTED | FLAG_STEREO_ACTIVE)
+
+#define BCM2048_RDS_FLAGS_ALL  (RDS_FLAG_FIFO_WLINE | \
+                                RDS_FLAG_B_BLOCK_MATCH | \
+                                RDS_FLAG_SYNC_LOST | RDS_FLAG_PI_MATCH)
+
+#define BCM2048_DEFAULT_TIMEOUT                1500
+#define BCM2048_AUTO_SEARCH_TIMEOUT    3000
+
+
+#define BCM2048_FREQDEV_UNIT           10000
+#define BCM2048_FREQV4L2_MULTI         625
+#define dev_to_v4l2(f) ((f * BCM2048_FREQDEV_UNIT) / BCM2048_FREQV4L2_MULTI)
+#define v4l2_to_dev(f) ((f * BCM2048_FREQV4L2_MULTI) / BCM2048_FREQDEV_UNIT)
+
+#define msb(x)                  ((u8)((u16) x >> 8))
+#define lsb(x)                  ((u8)((u16) x &  0x00FF))
+#define compose_u16(msb, lsb)  (((u16)msb << 8) | lsb)
+
+#define BCM2048_DEFAULT_POWERING_DELAY 20
+#define BCM2048_DEFAULT_REGION         0x02
+#define BCM2048_DEFAULT_MUTE           0x01
+#define BCM2048_DEFAULT_RSSI_THRESHOLD 0x64
+#define BCM2048_DEFAULT_RDS_WLINE      0x7E
+
+#define BCM2048_FM_SEARCH_INACTIVE     0x00
+#define BCM2048_FM_PRE_SET_MODE                0x01
+#define BCM2048_FM_AUTO_SEARCH_MODE    0x02
+#define BCM2048_FM_AF_JUMP_MODE                0x03
+
+#define BCM2048_FREQUENCY_BASE         64000
+
+#define BCM2048_POWER_ON               0x01
+#define BCM2048_POWER_OFF              0x00
+
+#define BCM2048_ITEM_ENABLED           0x01
+#define BCM2048_SEARCH_DIRECTION_UP    0x01
+
+#define BCM2048_DE_EMPHASIS_75us       75
+#define BCM2048_DE_EMPHASIS_50us       50
+
+#define BCM2048_SCAN_FAIL              0x00
+#define BCM2048_SCAN_OK                        0x01
+
+#define BCM2048_FREQ_ERROR_FLOOR       -20
+#define BCM2048_FREQ_ERROR_ROOF                20
+
+/* -60 dB is reported as full signal strenght */
+#define BCM2048_RSSI_LEVEL_BASE                -60
+#define BCM2048_RSSI_LEVEL_ROOF                -100
+#define BCM2048_RSSI_LEVEL_ROOF_NEG    100
+#define BCM2048_SIGNAL_MULTIPLIER      (0xFFFF / \
+                                        (BCM2048_RSSI_LEVEL_ROOF_NEG + \
+                                         BCM2048_RSSI_LEVEL_BASE))
+
+#define BCM2048_RDS_FIFO_DUPLE_SIZE    0x03
+#define BCM2048_RDS_CRC_MASK           0x0F
+#define BCM2048_RDS_CRC_NONE           0x00
+#define BCM2048_RDS_CRC_MAX_2BITS      0x04
+#define BCM2048_RDS_CRC_LEAST_2BITS    0x08
+#define BCM2048_RDS_CRC_UNRECOVARABLE  0x0C
+
+#define BCM2048_RDS_BLOCK_MASK         0xF0
+#define BCM2048_RDS_BLOCK_A            0x00
+#define BCM2048_RDS_BLOCK_B            0x10
+#define BCM2048_RDS_BLOCK_C            0x20
+#define BCM2048_RDS_BLOCK_D            0x30
+#define BCM2048_RDS_BLOCK_C_SCORED     0x40
+#define BCM2048_RDS_BLOCK_E            0x60
+
+#define BCM2048_RDS_RT                 0x20
+#define BCM2048_RDS_PS                 0x00
+
+#define BCM2048_RDS_GROUP_AB_MASK      0x08
+#define BCM2048_RDS_GROUP_A            0x00
+#define BCM2048_RDS_GROUP_B            0x08
+
+#define BCM2048_RDS_RT_AB_MASK         0x10
+#define BCM2048_RDS_RT_A               0x00
+#define BCM2048_RDS_RT_B               0x10
+#define BCM2048_RDS_RT_INDEX           0x0F
+
+#define BCM2048_RDS_PS_INDEX           0x03
+
+struct rds_info {
+       u16 rds_pi;
+#define BCM2048_MAX_RDS_RT (64 + 1)
+       u8 rds_rt[BCM2048_MAX_RDS_RT];
+       u8 rds_rt_group_b;
+       u8 rds_rt_ab;
+#define BCM2048_MAX_RDS_PS (8 + 1)
+       u8 rds_ps[BCM2048_MAX_RDS_PS];
+       u8 rds_ps_group;
+       u8 rds_ps_group_cnt;
+#define BCM2048_MAX_RDS_RADIO_TEXT 255
+       u8 radio_text[BCM2048_MAX_RDS_RADIO_TEXT + 3];
+       u8 text_len;
+};
+
+struct region_info {
+       u32 bottom_frequency;
+       u32 top_frequency;
+       u8 deemphasis;
+       u8 channel_spacing;
+       u8 region;
+};
+
+struct bcm2048_device {
+       struct i2c_client *client;
+       struct video_device *videodev;
+       struct work_struct work;
+       struct completion compl;
+       struct mutex mutex;
+       struct bcm2048_platform_data *platform_data;
+       struct rds_info rds_info;
+       struct region_info region_info;
+       u16 frequency;
+       u8 cache_fm_rds_system;
+       u8 cache_fm_ctrl;
+       u8 cache_fm_audio_ctrl0;
+       u8 cache_fm_search_ctrl0;
+       u8 power_state;
+       u8 rds_state;
+       u8 fifo_size;
+       u8 scan_state;
+       u8 mute_state;
+
+       /* for rds data device read */
+       wait_queue_head_t read_queue;
+       unsigned int users;
+       unsigned char rds_data_available;
+       unsigned int rd_index;
+};
+
+static int radio_nr = -1;      /* radio device minor (-1 ==> auto assign) */
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr,
+                "Minor number for radio device (-1 ==> auto assign)");
+
+static struct region_info region_configs[] = {
+       /* USA */
+       {
+               .channel_spacing        = 20,
+               .bottom_frequency       = 87500,
+               .top_frequency          = 108000,
+               .deemphasis             = 75,
+               .region                 = 0,
+       },
+       /* Australia */
+       {
+               .channel_spacing        = 20,
+               .bottom_frequency       = 87500,
+               .top_frequency          = 108000,
+               .deemphasis             = 50,
+               .region                 = 1,
+       },
+       /* Europe */
+       {
+               .channel_spacing        = 10,
+               .bottom_frequency       = 87500,
+               .top_frequency          = 108000,
+               .deemphasis             = 50,
+               .region                 = 2,
+       },
+       /* Japan */
+       {
+               .channel_spacing        = 10,
+               .bottom_frequency       = 76000,
+               .top_frequency          = 90000,
+               .deemphasis             = 50,
+               .region                 = 3,
+       },
+       /* Japan wide band */
+       {
+               .channel_spacing        = 10,
+               .bottom_frequency       = 76000,
+               .top_frequency          = 108000,
+               .deemphasis             = 50,
+               .region                 = 4,
+       },
+};
+
+/*
+ *     I2C Interface read / write
+ */
+static int bcm2048_send_command(struct bcm2048_device *bdev, unsigned int reg,
+                                       unsigned int value)
+{
+       struct i2c_client *client = bdev->client;
+       u8 data[2];
+
+       if (!bdev->power_state) {
+               dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n");
+               return -EIO;
+       }
+
+       data[0] = reg & 0xff;
+       data[1] = value & 0xff;
+
+       if (i2c_master_send(client, data, 2) == 2) {
+               return 0;
+       } else {
+               dev_err(&bdev->client->dev, "BCM I2C error!\n");
+               dev_err(&bdev->client->dev, "Is Bluetooth up and running?\n");
+               return -EIO;
+       }
+}
+
+static int bcm2048_recv_command(struct bcm2048_device *bdev, unsigned int reg,
+                       u8 *value)
+{
+       struct i2c_client *client = bdev->client;
+
+       if (!bdev->power_state) {
+               dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n");
+               return -EIO;
+       }
+
+       value[0] = i2c_smbus_read_byte_data(client, reg & 0xff);
+
+       return 0;
+}
+
+static int bcm2048_recv_duples(struct bcm2048_device *bdev, unsigned int reg,
+                       u8 *value, u8 duples)
+{
+       struct i2c_client *client = bdev->client;
+       struct i2c_adapter *adap = client->adapter;
+       struct i2c_msg msg[2];
+       u8 buf;
+
+       if (!bdev->power_state) {
+               dev_err(&bdev->client->dev, "bcm2048: chip not powered!\n");
+               return -EIO;
+       }
+
+       buf = reg & 0xff;
+
+       msg[0].addr = client->addr;
+       msg[0].flags = client->flags & I2C_M_TEN;
+       msg[0].len = 1;
+       msg[0].buf = &buf;
+
+       msg[1].addr = client->addr;
+       msg[1].flags = client->flags & I2C_M_TEN;
+       msg[1].flags |= I2C_M_RD;
+       msg[1].len = duples;
+       msg[1].buf = value;
+
+       return i2c_transfer(adap, msg, 2);
+}
+
+/*
+ *     BCM2048 - I2C register programming helpers
+ */
+static int bcm2048_set_power_state(struct bcm2048_device *bdev, u8 power)
+{
+       int err = 0;
+
+       mutex_lock(&bdev->mutex);
+
+       if (power) {
+               bdev->power_state = BCM2048_POWER_ON;
+               bdev->cache_fm_rds_system |= BCM2048_FM_ON;
+       } else {
+               bdev->cache_fm_rds_system &= ~BCM2048_FM_ON;
+       }
+
+       /*
+        * Warning! FM cannot be turned off because then
+        * the I2C communications get ruined!
+        * Comment off the "if (power)" when the chip works!
+        */
+       if (power)
+               err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM,
+                                       bdev->cache_fm_rds_system);
+       msleep(BCM2048_DEFAULT_POWERING_DELAY);
+
+       if (!power)
+               bdev->power_state = BCM2048_POWER_OFF;
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_power_state(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err && (value & BCM2048_FM_ON))
+               return BCM2048_POWER_ON;
+
+       return err;
+}
+
+static int bcm2048_set_rds_no_lock(struct bcm2048_device *bdev, u8 rds_on)
+{
+       int err;
+       u8 flags;
+
+       bdev->cache_fm_rds_system &= ~BCM2048_RDS_ON;
+
+       if (rds_on) {
+               bdev->cache_fm_rds_system |= BCM2048_RDS_ON;
+               bdev->rds_state = BCM2048_RDS_ON;
+               flags = BCM2048_RDS_FLAG_FIFO_WLINE;
+               err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
+                                               flags);
+       } else {
+               flags = 0;
+               bdev->rds_state = 0;
+               err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
+                                               flags);
+               memset(&bdev->rds_info, 0, sizeof(bdev->rds_info));
+       }
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM,
+                                       bdev->cache_fm_rds_system);
+
+       return err;
+}
+
+static int bcm2048_get_rds_no_lock(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_SYSTEM, &value);
+
+       if (!err && (value & BCM2048_RDS_ON))
+               return BCM2048_ITEM_ENABLED;
+
+       return err;
+}
+
+static int bcm2048_set_rds(struct bcm2048_device *bdev, u8 rds_on)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_set_rds_no_lock(bdev, rds_on);
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_rds(struct bcm2048_device *bdev)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_get_rds_no_lock(bdev);
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_rds_pi(struct bcm2048_device *bdev)
+{
+       return bdev->rds_info.rds_pi;
+}
+
+static int bcm2048_set_fm_automatic_stereo_mono(struct bcm2048_device *bdev,
+                                               u8 enabled)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       bdev->cache_fm_ctrl &= ~BCM2048_STEREO_MONO_AUTO_SELECT;
+
+       if (enabled)
+               bdev->cache_fm_ctrl |= BCM2048_STEREO_MONO_AUTO_SELECT;
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL,
+                                       bdev->cache_fm_ctrl);
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_set_fm_hi_lo_injection(struct bcm2048_device *bdev,
+                                               u8 hi_lo)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       bdev->cache_fm_ctrl &= ~BCM2048_HI_LO_INJECTION;
+
+       if (hi_lo)
+               bdev->cache_fm_ctrl |= BCM2048_HI_LO_INJECTION;
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_CTRL,
+                                       bdev->cache_fm_ctrl);
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_fm_hi_lo_injection(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_CTRL, &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err && (value & BCM2048_HI_LO_INJECTION))
+               return BCM2048_ITEM_ENABLED;
+
+       return err;
+}
+
+static int bcm2048_set_fm_frequency(struct bcm2048_device *bdev, u32 frequency)
+{
+       int err;
+
+       if (frequency < bdev->region_info.bottom_frequency ||
+               frequency > bdev->region_info.top_frequency)
+               return -EDOM;
+
+       frequency -= BCM2048_FREQUENCY_BASE;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ0, lsb(frequency));
+       err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_FREQ1,
+                                       msb(frequency));
+
+       if (!err)
+               bdev->frequency = frequency;
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_fm_frequency(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 lsb, msb;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_FREQ0, &lsb);
+       err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_FREQ1, &msb);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (err)
+               return err;
+
+       err = compose_u16(msb, lsb);
+       err += BCM2048_FREQUENCY_BASE;
+
+       return err;
+}
+
+static int bcm2048_set_fm_af_frequency(struct bcm2048_device *bdev,
+                                               u32 frequency)
+{
+       int err;
+
+       if (frequency < bdev->region_info.bottom_frequency ||
+               frequency > bdev->region_info.top_frequency)
+               return -EDOM;
+
+       frequency -= BCM2048_FREQUENCY_BASE;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ0,
+                                       lsb(frequency));
+       err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_AF_FREQ1,
+                                       msb(frequency));
+       if (!err)
+               bdev->frequency = frequency;
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_fm_af_frequency(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 lsb, msb;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AF_FREQ0, &lsb);
+       err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_AF_FREQ1, &msb);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (err)
+               return err;
+
+       err = compose_u16(msb, lsb);
+       err += BCM2048_FREQUENCY_BASE;
+
+       return err;
+}
+
+static int bcm2048_set_fm_deemphasis(struct bcm2048_device *bdev, int d)
+{
+       int err;
+       u8 deemphasis;
+
+       if (d == BCM2048_DE_EMPHASIS_75us)
+               deemphasis = BCM2048_DE_EMPHASIS_SELECT;
+       else
+               deemphasis = 0;
+
+       mutex_lock(&bdev->mutex);
+
+       bdev->cache_fm_audio_ctrl0 &= ~BCM2048_DE_EMPHASIS_SELECT;
+       bdev->cache_fm_audio_ctrl0 |= deemphasis;
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
+               bdev->cache_fm_audio_ctrl0);
+
+       if (!err)
+               bdev->region_info.deemphasis = d;
+
+       mutex_unlock(&bdev->mutex);
+
+       return err;
+}
+
+static int bcm2048_get_fm_deemphasis(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err) {
+               if (value & BCM2048_DE_EMPHASIS_SELECT)
+                       return BCM2048_DE_EMPHASIS_75us;
+               else
+                       return BCM2048_DE_EMPHASIS_50us;
+       }
+
+       return err;
+}
+
+static int bcm2048_set_region(struct bcm2048_device *bdev, u8 region)
+{
+       int err;
+       u32 new_frequency = 0;
+
+       if (region > ARRAY_SIZE(region_configs))
+               return -EINVAL;
+
+       mutex_lock(&bdev->mutex);
+       bdev->region_info = region_configs[region];
+       mutex_unlock(&bdev->mutex);
+
+       if (bdev->frequency < region_configs[region].bottom_frequency ||
+               bdev->frequency > region_configs[region].top_frequency)
+               new_frequency = region_configs[region].bottom_frequency;
+
+       if (new_frequency > 0) {
+               err = bcm2048_set_fm_frequency(bdev, new_frequency);
+
+               if (err)
+                       goto done;
+       }
+
+       err = bcm2048_set_fm_deemphasis(bdev,
+                       region_configs[region].deemphasis);
+
+done:
+       return err;
+}
+
+static int bcm2048_get_region(struct bcm2048_device *bdev)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+       err = bdev->region_info.region;
+       mutex_unlock(&bdev->mutex);
+
+       return err;
+}
+
+static int bcm2048_set_mute(struct bcm2048_device *bdev, u16 mute)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_RF_MUTE | BCM2048_MANUAL_MUTE);
+
+       if (mute)
+               bdev->cache_fm_audio_ctrl0 |= (BCM2048_RF_MUTE |
+                                               BCM2048_MANUAL_MUTE);
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
+                                       bdev->cache_fm_audio_ctrl0);
+
+       if (!err)
+               bdev->mute_state = mute;
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_mute(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       if (bdev->power_state) {
+               err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
+                                               &value);
+               if (!err)
+                       err = value & (BCM2048_RF_MUTE | BCM2048_MANUAL_MUTE);
+       } else {
+               err = bdev->mute_state;
+       }
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_set_audio_route(struct bcm2048_device *bdev, u8 route)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       route &= (BCM2048_AUDIO_ROUTE_DAC | BCM2048_AUDIO_ROUTE_I2S);
+       bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_AUDIO_ROUTE_DAC |
+               BCM2048_AUDIO_ROUTE_I2S);
+       bdev->cache_fm_audio_ctrl0 |= route;
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
+                                       bdev->cache_fm_audio_ctrl0);
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_audio_route(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return value & (BCM2048_AUDIO_ROUTE_DAC |
+                       BCM2048_AUDIO_ROUTE_I2S);
+
+       return err;
+}
+
+static int bcm2048_set_dac_output(struct bcm2048_device *bdev, u8 channels)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       bdev->cache_fm_audio_ctrl0 &= ~(BCM2048_DAC_OUTPUT_LEFT |
+                                       BCM2048_DAC_OUTPUT_RIGHT);
+       bdev->cache_fm_audio_ctrl0 |= channels;
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0,
+                                       bdev->cache_fm_audio_ctrl0);
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_dac_output(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_AUDIO_CTRL0, &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return value & (BCM2048_DAC_OUTPUT_LEFT |
+                       BCM2048_DAC_OUTPUT_RIGHT);
+
+       return err;
+}
+
+static int bcm2048_set_fm_search_rssi_threshold(struct bcm2048_device *bdev,
+                                                       u8 threshold)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       threshold &= BCM2048_SEARCH_RSSI_THRESHOLD;
+       bdev->cache_fm_search_ctrl0 &= ~BCM2048_SEARCH_RSSI_THRESHOLD;
+       bdev->cache_fm_search_ctrl0 |= threshold;
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0,
+                                       bdev->cache_fm_search_ctrl0);
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_fm_search_rssi_threshold(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return value & BCM2048_SEARCH_RSSI_THRESHOLD;
+
+       return err;
+}
+
+static int bcm2048_set_fm_search_mode_direction(struct bcm2048_device *bdev,
+                                               u8 direction)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       bdev->cache_fm_search_ctrl0 &= ~BCM2048_SEARCH_DIRECTION;
+
+       if (direction)
+               bdev->cache_fm_search_ctrl0 |= BCM2048_SEARCH_DIRECTION;
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0,
+                                       bdev->cache_fm_search_ctrl0);
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_fm_search_mode_direction(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_CTRL0, &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err && (value & BCM2048_SEARCH_DIRECTION))
+               return BCM2048_SEARCH_DIRECTION_UP;
+
+       return err;
+}
+
+static int bcm2048_set_fm_search_tune_mode(struct bcm2048_device *bdev,
+                                               u8 mode)
+{
+       int err, timeout, restart_rds = 0;
+       u8 value, flags;
+
+       value = mode & BCM2048_FM_AUTO_SEARCH;
+
+       flags = BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED |
+               BCM2048_FM_FLAG_SEARCH_TUNE_FAIL;
+
+       mutex_lock(&bdev->mutex);
+
+       /*
+        * If RDS is enabled, and frequency is changed, RDS quits working.
+        * Thus, always restart RDS if it's enabled. Moreover, RDS must
+        * not be enabled while changing the frequency because it can
+        * provide a race to the mutex from the workqueue handler if RDS
+        * IRQ occurs while waiting for frequency changed IRQ.
+        */
+       if (bcm2048_get_rds_no_lock(bdev)) {
+               err = bcm2048_set_rds_no_lock(bdev, 0);
+               if (err)
+                       goto unlock;
+               restart_rds = 1;
+       }
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK0, flags);
+
+       if (err)
+               goto unlock;
+
+       bcm2048_send_command(bdev, BCM2048_I2C_FM_SEARCH_TUNE_MODE, value);
+
+       if (mode != BCM2048_FM_AUTO_SEARCH_MODE)
+               timeout = BCM2048_DEFAULT_TIMEOUT;
+       else
+               timeout = BCM2048_AUTO_SEARCH_TIMEOUT;
+
+       if (!wait_for_completion_timeout(&bdev->compl,
+                       msecs_to_jiffies(timeout)))
+                       dev_err(&bdev->client->dev, "IRQ timeout.\n");
+
+       if (value)
+               if (!bdev->scan_state)
+                       err = -EIO;
+
+unlock:
+       if (restart_rds)
+               err |= bcm2048_set_rds_no_lock(bdev, 1);
+
+       mutex_unlock(&bdev->mutex);
+
+       return err;
+}
+
+static int bcm2048_get_fm_search_tune_mode(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_SEARCH_TUNE_MODE,
+                                       &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return value & BCM2048_FM_AUTO_SEARCH;
+
+       return err;
+}
+
+static int bcm2048_set_rds_b_block_mask(struct bcm2048_device *bdev, u16 mask)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_send_command(bdev,
+                       BCM2048_I2C_RDS_BLKB_MASK0, lsb(mask));
+       err |= bcm2048_send_command(bdev,
+                       BCM2048_I2C_RDS_BLKB_MASK1, msb(mask));
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_rds_b_block_mask(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 lsb, msb;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev,
+                       BCM2048_I2C_RDS_BLKB_MASK0, &lsb);
+       err |= bcm2048_recv_command(bdev,
+                       BCM2048_I2C_RDS_BLKB_MASK1, &msb);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return compose_u16(msb, lsb);
+
+       return err;
+}
+
+static int bcm2048_set_rds_b_block_match(struct bcm2048_device *bdev,
+                                               u16 match)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_send_command(bdev,
+                       BCM2048_I2C_RDS_BLKB_MATCH0, lsb(match));
+       err |= bcm2048_send_command(bdev,
+                       BCM2048_I2C_RDS_BLKB_MATCH1, msb(match));
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_rds_b_block_match(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 lsb, msb;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev,
+                       BCM2048_I2C_RDS_BLKB_MATCH0, &lsb);
+       err |= bcm2048_recv_command(bdev,
+                       BCM2048_I2C_RDS_BLKB_MATCH1, &msb);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return compose_u16(msb, lsb);
+
+       return err;
+}
+
+static int bcm2048_set_rds_pi_mask(struct bcm2048_device *bdev, u16 mask)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_send_command(bdev,
+                       BCM2048_I2C_RDS_PI_MASK0, lsb(mask));
+       err |= bcm2048_send_command(bdev,
+                       BCM2048_I2C_RDS_PI_MASK1, msb(mask));
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_rds_pi_mask(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 lsb, msb;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev,
+                       BCM2048_I2C_RDS_PI_MASK0, &lsb);
+       err |= bcm2048_recv_command(bdev,
+                       BCM2048_I2C_RDS_PI_MASK1, &msb);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return compose_u16(msb, lsb);
+
+       return err;
+}
+
+static int bcm2048_set_rds_pi_match(struct bcm2048_device *bdev, u16 match)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_send_command(bdev,
+                       BCM2048_I2C_RDS_PI_MATCH0, lsb(match));
+       err |= bcm2048_send_command(bdev,
+                       BCM2048_I2C_RDS_PI_MATCH1, msb(match));
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_rds_pi_match(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 lsb, msb;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev,
+                       BCM2048_I2C_RDS_PI_MATCH0, &lsb);
+       err |= bcm2048_recv_command(bdev,
+                       BCM2048_I2C_RDS_PI_MATCH1, &msb);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return compose_u16(msb, lsb);
+
+       return err;
+}
+
+static int bcm2048_set_fm_rds_mask(struct bcm2048_device *bdev, u16 mask)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_send_command(bdev,
+                       BCM2048_I2C_FM_RDS_MASK0, lsb(mask));
+       err |= bcm2048_send_command(bdev,
+                       BCM2048_I2C_FM_RDS_MASK1, msb(mask));
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_fm_rds_mask(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value0, value1;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_MASK0, &value0);
+       err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_MASK1, &value1);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return compose_u16(value1, value0);
+
+       return err;
+}
+
+static int bcm2048_get_fm_rds_flags(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value0, value1;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG0, &value0);
+       err |= bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG1, &value1);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return compose_u16(value1, value0);
+
+       return err;
+}
+
+static int bcm2048_get_region_bottom_frequency(struct bcm2048_device *bdev)
+{
+       return bdev->region_info.bottom_frequency;
+}
+
+static int bcm2048_get_region_top_frequency(struct bcm2048_device *bdev)
+{
+       return bdev->region_info.top_frequency;
+}
+
+static int bcm2048_set_fm_best_tune_mode(struct bcm2048_device *bdev, u8 mode)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       /* Perform read as the manual indicates */
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE,
+                                       &value);
+       value &= ~BCM2048_BEST_TUNE_MODE;
+
+       if (mode)
+               value |= BCM2048_BEST_TUNE_MODE;
+       err |= bcm2048_send_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE,
+                                       value);
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_fm_best_tune_mode(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_BEST_TUNE_MODE,
+                                       &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err && (value & BCM2048_BEST_TUNE_MODE))
+               return BCM2048_ITEM_ENABLED;
+
+       return err;
+}
+
+static int bcm2048_get_fm_carrier_error(struct bcm2048_device *bdev)
+{
+       int err = 0;
+       s8 value;
+
+       mutex_lock(&bdev->mutex);
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_CARRIER, &value);
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return value;
+
+       return err;
+}
+
+static int bcm2048_get_fm_rssi(struct bcm2048_device *bdev)
+{
+       int err;
+       s8 value;
+
+       mutex_lock(&bdev->mutex);
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RSSI, &value);
+       mutex_unlock(&bdev->mutex);
+
+       if (!err)
+               return value;
+
+       return err;
+}
+
+static int bcm2048_set_rds_wline(struct bcm2048_device *bdev, u8 wline)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_send_command(bdev, BCM2048_I2C_RDS_WLINE, wline);
+
+       if (!err)
+               bdev->fifo_size = wline;
+
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_rds_wline(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 value;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_RDS_WLINE, &value);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err) {
+               bdev->fifo_size = value;
+               return value;
+       }
+
+       return err;
+}
+
+static int bcm2048_checkrev(struct bcm2048_device *bdev)
+{
+       int err;
+       u8 version;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_REV, &version);
+
+       mutex_unlock(&bdev->mutex);
+
+       if (!err) {
+               dev_info(&bdev->client->dev, "BCM2048 Version 0x%x\n",
+                       version);
+               return version;
+       }
+
+       return err;
+}
+
+static int bcm2048_get_rds_rt(struct bcm2048_device *bdev, char *data)
+{
+       int err = 0, i, j = 0, ce = 0, cr = 0;
+       char data_buffer[BCM2048_MAX_RDS_RT+1];
+
+       mutex_lock(&bdev->mutex);
+
+       if (!bdev->rds_info.text_len) {
+               err = -EINVAL;
+               goto unlock;
+       }
+
+       for (i = 0; i < BCM2048_MAX_RDS_RT; i++) {
+               if (bdev->rds_info.rds_rt[i]) {
+                       ce = i;
+                       /* Skip the carriage return */
+                       if (bdev->rds_info.rds_rt[i] != 0x0d) {
+                               data_buffer[j++] = bdev->rds_info.rds_rt[i];
+                       } else {
+                               cr = i;
+                               break;
+                       }
+               }
+       }
+
+       if (j <= BCM2048_MAX_RDS_RT)
+               data_buffer[j] = 0;
+
+       for (i = 0; i < BCM2048_MAX_RDS_RT; i++) {
+               if (!bdev->rds_info.rds_rt[i]) {
+                       if (cr && (i < cr)) {
+                               err = -EBUSY;
+                               goto unlock;
+                       }
+                       if (i < ce) {
+                               if (cr && (i >= cr))
+                                       break;
+                               err = -EBUSY;
+                               goto unlock;
+                       }
+               }
+       }
+
+       memcpy(data, data_buffer, sizeof(data_buffer));
+
+unlock:
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static int bcm2048_get_rds_ps(struct bcm2048_device *bdev, char *data)
+{
+       int err = 0, i, j = 0;
+       char data_buffer[BCM2048_MAX_RDS_PS+1];
+
+       mutex_lock(&bdev->mutex);
+
+       if (!bdev->rds_info.text_len) {
+               err = -EINVAL;
+               goto unlock;
+       }
+
+       for (i = 0; i < BCM2048_MAX_RDS_PS; i++) {
+               if (bdev->rds_info.rds_ps[i]) {
+                       data_buffer[j++] = bdev->rds_info.rds_ps[i];
+               } else {
+                       if (i < (BCM2048_MAX_RDS_PS - 1)) {
+                               err = -EBUSY;
+                               goto unlock;
+                       }
+               }
+       }
+
+       if (j <= BCM2048_MAX_RDS_PS)
+               data_buffer[j] = 0;
+
+       memcpy(data, data_buffer, sizeof(data_buffer));
+
+unlock:
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+static void bcm2048_parse_rds_pi(struct bcm2048_device *bdev)
+{
+       int i, cnt = 0;
+       u16 pi;
+
+       for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) {
+
+               /* Block A match, only data without crc errors taken */
+               if (bdev->rds_info.radio_text[i] == BCM2048_RDS_BLOCK_A) {
+
+                       pi = ((bdev->rds_info.radio_text[i+1] << 8) +
+                               bdev->rds_info.radio_text[i+2]);
+
+                       if (!bdev->rds_info.rds_pi) {
+                               bdev->rds_info.rds_pi = pi;
+                               return;
+                       }
+                       if (pi != bdev->rds_info.rds_pi) {
+                               cnt++;
+                               if (cnt > 3) {
+                                       bdev->rds_info.rds_pi = pi;
+                                       cnt = 0;
+                               }
+                       } else {
+                               cnt = 0;
+                       }
+               }
+       }
+}
+
+static int bcm2048_rds_block_crc(struct bcm2048_device *bdev, int i)
+{
+       return bdev->rds_info.radio_text[i] & BCM2048_RDS_CRC_MASK;
+}
+
+static void bcm2048_parse_rds_rt_block(struct bcm2048_device *bdev, int i,
+                                       int index, int crc)
+{
+       /* Good data will overwrite poor data */
+       if (crc) {
+               if (!bdev->rds_info.rds_rt[index])
+                       bdev->rds_info.rds_rt[index] =
+                               bdev->rds_info.radio_text[i+1];
+               if (!bdev->rds_info.rds_rt[index+1])
+                       bdev->rds_info.rds_rt[index+1] =
+                               bdev->rds_info.radio_text[i+2];
+       } else {
+               bdev->rds_info.rds_rt[index] = bdev->rds_info.radio_text[i+1];
+               bdev->rds_info.rds_rt[index+1] =
+                       bdev->rds_info.radio_text[i+2];
+       }
+}
+
+static int bcm2048_parse_rt_match_b(struct bcm2048_device *bdev, int i)
+{
+       int crc, rt_id, rt_group_b, rt_ab, index = 0;
+
+       crc = bcm2048_rds_block_crc(bdev, i);
+
+       if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
+               return -EIO;
+
+       if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
+               BCM2048_RDS_BLOCK_B) {
+
+               rt_id = (bdev->rds_info.radio_text[i+1] &
+                       BCM2048_RDS_BLOCK_MASK);
+               rt_group_b = bdev->rds_info.radio_text[i+1] &
+                       BCM2048_RDS_GROUP_AB_MASK;
+               rt_ab = bdev->rds_info.radio_text[i+2] &
+                               BCM2048_RDS_RT_AB_MASK;
+
+               if (rt_group_b != bdev->rds_info.rds_rt_group_b) {
+                       memset(bdev->rds_info.rds_rt, 0,
+                               sizeof(bdev->rds_info.rds_rt));
+                       bdev->rds_info.rds_rt_group_b = rt_group_b;
+               }
+
+               if (rt_id == BCM2048_RDS_RT) {
+                       /* A to B or (vice versa), means: clear screen */
+                       if (rt_ab != bdev->rds_info.rds_rt_ab) {
+                               memset(bdev->rds_info.rds_rt, 0,
+                                       sizeof(bdev->rds_info.rds_rt));
+                               bdev->rds_info.rds_rt_ab = rt_ab;
+                       }
+
+                       index = bdev->rds_info.radio_text[i+2] &
+                                       BCM2048_RDS_RT_INDEX;
+
+                       if (bdev->rds_info.rds_rt_group_b)
+                               index <<= 1;
+                       else
+                               index <<= 2;
+
+                       return index;
+               }
+       }
+
+       return -EIO;
+}
+
+static int bcm2048_parse_rt_match_c(struct bcm2048_device *bdev, int i,
+                                       int index)
+{
+       int crc;
+
+       crc = bcm2048_rds_block_crc(bdev, i);
+
+       if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
+               return 0;
+
+       BUG_ON((index+2) >= BCM2048_MAX_RDS_RT);
+
+       if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
+               BCM2048_RDS_BLOCK_C) {
+               if (bdev->rds_info.rds_rt_group_b)
+                       return 1;
+               bcm2048_parse_rds_rt_block(bdev, i, index, crc);
+               return 1;
+       }
+
+       return 0;
+}
+
+static void bcm2048_parse_rt_match_d(struct bcm2048_device *bdev, int i,
+                                       int index)
+{
+       int crc;
+
+       crc = bcm2048_rds_block_crc(bdev, i);
+
+       if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
+               return;
+
+       BUG_ON((index+4) >= BCM2048_MAX_RDS_RT);
+
+       if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
+               BCM2048_RDS_BLOCK_D)
+               bcm2048_parse_rds_rt_block(bdev, i, index+2, crc);
+}
+
+static int bcm2048_parse_rds_rt(struct bcm2048_device *bdev)
+{
+       int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0;
+
+       for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) {
+
+               if (match_b) {
+                       match_b = 0;
+                       index = bcm2048_parse_rt_match_b(bdev, i);
+                       if (index >= 0 && index <= (BCM2048_MAX_RDS_RT - 5))
+                               match_c = 1;
+                       continue;
+               } else if (match_c) {
+                       match_c = 0;
+                       if (bcm2048_parse_rt_match_c(bdev, i, index))
+                               match_d = 1;
+                       continue;
+               } else if (match_d) {
+                       match_d = 0;
+                       bcm2048_parse_rt_match_d(bdev, i, index);
+                       continue;
+               }
+
+               /* Skip erroneous blocks due to messed up A block altogether */
+               if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK)
+                       == BCM2048_RDS_BLOCK_A) {
+                       crc = bcm2048_rds_block_crc(bdev, i);
+                       if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
+                               continue;
+                       /* Syncronize to a good RDS PI */
+                       if (((bdev->rds_info.radio_text[i+1] << 8) +
+                               bdev->rds_info.radio_text[i+2]) ==
+                               bdev->rds_info.rds_pi)
+                                       match_b = 1;
+               }
+       }
+
+       return 0;
+}
+
+static void bcm2048_parse_rds_ps_block(struct bcm2048_device *bdev, int i,
+                                       int index, int crc)
+{
+       /* Good data will overwrite poor data */
+       if (crc) {
+               if (!bdev->rds_info.rds_ps[index])
+                       bdev->rds_info.rds_ps[index] =
+                               bdev->rds_info.radio_text[i+1];
+               if (!bdev->rds_info.rds_ps[index+1])
+                       bdev->rds_info.rds_ps[index+1] =
+                               bdev->rds_info.radio_text[i+2];
+       } else {
+               bdev->rds_info.rds_ps[index] = bdev->rds_info.radio_text[i+1];
+               bdev->rds_info.rds_ps[index+1] =
+                       bdev->rds_info.radio_text[i+2];
+       }
+}
+
+static int bcm2048_parse_ps_match_c(struct bcm2048_device *bdev, int i,
+                                       int index)
+{
+       int crc;
+
+       crc = bcm2048_rds_block_crc(bdev, i);
+
+       if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
+               return 0;
+
+       if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
+               BCM2048_RDS_BLOCK_C)
+               return 1;
+
+       return 0;
+}
+
+static void bcm2048_parse_ps_match_d(struct bcm2048_device *bdev, int i,
+                                       int index)
+{
+       int crc;
+
+       crc = bcm2048_rds_block_crc(bdev, i);
+
+       if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
+               return;
+
+       if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
+               BCM2048_RDS_BLOCK_D)
+               bcm2048_parse_rds_ps_block(bdev, i, index, crc);
+}
+
+static int bcm2048_parse_ps_match_b(struct bcm2048_device *bdev, int i)
+{
+       int crc, index, ps_id, ps_group;
+
+       crc = bcm2048_rds_block_crc(bdev, i);
+
+       if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
+               return -EIO;
+
+       /* Block B Radio PS match */
+       if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK) ==
+               BCM2048_RDS_BLOCK_B) {
+               ps_id = bdev->rds_info.radio_text[i+1] &
+                       BCM2048_RDS_BLOCK_MASK;
+               ps_group = bdev->rds_info.radio_text[i+1] &
+                       BCM2048_RDS_GROUP_AB_MASK;
+
+               /*
+                * Poor RSSI will lead to RDS data corruption
+                * So using 3 (same) sequential values to justify major changes
+                */
+               if (ps_group != bdev->rds_info.rds_ps_group) {
+                       if (crc == BCM2048_RDS_CRC_NONE) {
+                               bdev->rds_info.rds_ps_group_cnt++;
+                               if (bdev->rds_info.rds_ps_group_cnt > 2) {
+                                       bdev->rds_info.rds_ps_group = ps_group;
+                                       bdev->rds_info.rds_ps_group_cnt = 0;
+                                       dev_err(&bdev->client->dev,
+                                               "RDS PS Group change!\n");
+                               } else {
+                                       return -EIO;
+                               }
+                       } else {
+                               bdev->rds_info.rds_ps_group_cnt = 0;
+                       }
+               }
+
+               if (ps_id == BCM2048_RDS_PS) {
+                       index = bdev->rds_info.radio_text[i+2] &
+                               BCM2048_RDS_PS_INDEX;
+                       index <<= 1;
+                       return index;
+               }
+       }
+
+       return -EIO;
+}
+
+static void bcm2048_parse_rds_ps(struct bcm2048_device *bdev)
+{
+       int i, index = 0, crc, match_b = 0, match_c = 0, match_d = 0;
+
+       for (i = 0; i < bdev->fifo_size; i += BCM2048_RDS_FIFO_DUPLE_SIZE) {
+
+               if (match_b) {
+                       match_b = 0;
+                       index = bcm2048_parse_ps_match_b(bdev, i);
+                       if (index >= 0 && index < (BCM2048_MAX_RDS_PS - 1))
+                               match_c = 1;
+                       continue;
+               } else if (match_c) {
+                       match_c = 0;
+                       if (bcm2048_parse_ps_match_c(bdev, i, index))
+                               match_d = 1;
+                       continue;
+               } else if (match_d) {
+                       match_d = 0;
+                       bcm2048_parse_ps_match_d(bdev, i, index);
+                       continue;
+               }
+
+               /* Skip erroneous blocks due to messed up A block altogether */
+               if ((bdev->rds_info.radio_text[i] & BCM2048_RDS_BLOCK_MASK)
+                       == BCM2048_RDS_BLOCK_A) {
+                       crc = bcm2048_rds_block_crc(bdev, i);
+                       if (crc == BCM2048_RDS_CRC_UNRECOVARABLE)
+                               continue;
+                       /* Syncronize to a good RDS PI */
+                       if (((bdev->rds_info.radio_text[i+1] << 8) +
+                               bdev->rds_info.radio_text[i+2]) ==
+                               bdev->rds_info.rds_pi)
+                                       match_b = 1;
+               }
+       }
+}
+
+static void bcm2048_rds_fifo_receive(struct bcm2048_device *bdev)
+{
+       int err;
+
+       mutex_lock(&bdev->mutex);
+
+       err = bcm2048_recv_duples(bdev, BCM2048_I2C_RDS_DATA,
+                               bdev->rds_info.radio_text, bdev->fifo_size);
+       if (err != 2) {
+               dev_err(&bdev->client->dev, "RDS Read problem\n");
+               mutex_unlock(&bdev->mutex);
+               return;
+       }
+
+       bdev->rds_info.text_len = bdev->fifo_size;
+
+       bcm2048_parse_rds_pi(bdev);
+       bcm2048_parse_rds_rt(bdev);
+       bcm2048_parse_rds_ps(bdev);
+
+       mutex_unlock(&bdev->mutex);
+
+       wake_up_interruptible(&bdev->read_queue);
+}
+
+static int bcm2048_get_rds_data(struct bcm2048_device *bdev, char *data)
+{
+       int err = 0, i, p = 0;
+       char *data_buffer;
+
+       mutex_lock(&bdev->mutex);
+
+       if (!bdev->rds_info.text_len) {
+               err = -EINVAL;
+               goto unlock;
+       }
+
+       data_buffer = kzalloc(BCM2048_MAX_RDS_RADIO_TEXT*5, GFP_KERNEL);
+       if (!data_buffer) {
+               err = -ENOMEM;
+               goto unlock;
+       }
+
+       for (i = 0; i < bdev->rds_info.text_len; i++) {
+               p += sprintf(data_buffer+p, "%x ",
+                       bdev->rds_info.radio_text[i]);
+       }
+
+       memcpy(data, data_buffer, p);
+       kfree(data_buffer);
+
+unlock:
+       mutex_unlock(&bdev->mutex);
+       return err;
+}
+
+/*
+ *     BCM2048 default initialization sequence
+ */
+static int bcm2048_init(struct bcm2048_device *bdev)
+{
+       int err;
+
+       err = bcm2048_set_power_state(bdev, BCM2048_POWER_ON);
+       if (err < 0)
+               goto exit;
+
+       err = bcm2048_set_audio_route(bdev, BCM2048_AUDIO_ROUTE_DAC);
+       if (err < 0)
+               goto exit;
+
+       err = bcm2048_set_dac_output(bdev, BCM2048_DAC_OUTPUT_LEFT |
+               BCM2048_DAC_OUTPUT_RIGHT);
+
+exit:
+       return err;
+}
+
+/*
+ *     BCM2048 default deinitialization sequence
+ */
+static int bcm2048_deinit(struct bcm2048_device *bdev)
+{
+       int err;
+
+       err = bcm2048_set_audio_route(bdev, 0);
+       if (err < 0)
+               goto exit;
+
+       err = bcm2048_set_dac_output(bdev, 0);
+       if (err < 0)
+               goto exit;
+
+       err = bcm2048_set_power_state(bdev, BCM2048_POWER_OFF);
+       if (err < 0)
+               goto exit;
+
+exit:
+       return err;
+}
+
+/*
+ *     BCM2048 probe sequence
+ */
+static int bcm2048_probe(struct bcm2048_device *bdev)
+{
+       int err;
+
+       err = bcm2048_set_power_state(bdev, BCM2048_POWER_ON);
+       if (err < 0)
+               goto unlock;
+
+       err = bcm2048_checkrev(bdev);
+       if (err < 0)
+               goto unlock;
+
+       err = bcm2048_set_mute(bdev, BCM2048_DEFAULT_MUTE);
+       if (err < 0)
+               goto unlock;
+
+       err = bcm2048_set_region(bdev, BCM2048_DEFAULT_REGION);
+       if (err < 0)
+               goto unlock;
+
+       err = bcm2048_set_fm_search_rssi_threshold(bdev,
+                                       BCM2048_DEFAULT_RSSI_THRESHOLD);
+       if (err < 0)
+               goto unlock;
+
+       err = bcm2048_set_fm_automatic_stereo_mono(bdev, BCM2048_ITEM_ENABLED);
+       if (err < 0)
+               goto unlock;
+
+       err = bcm2048_get_rds_wline(bdev);
+       if (err < BCM2048_DEFAULT_RDS_WLINE)
+               err = bcm2048_set_rds_wline(bdev, BCM2048_DEFAULT_RDS_WLINE);
+       if (err < 0)
+               goto unlock;
+
+       err = bcm2048_set_power_state(bdev, BCM2048_POWER_OFF);
+
+       init_waitqueue_head(&bdev->read_queue);
+       bdev->rds_data_available = 0;
+       bdev->rd_index = 0;
+       bdev->users = 0;
+
+unlock:
+       return err;
+}
+
+/*
+ *     BCM2048 workqueue handler
+ */
+static void bcm2048_work(struct work_struct *work)
+{
+       struct bcm2048_device *bdev;
+       u8 flag_lsb, flag_msb, flags;
+
+       bdev = container_of(work, struct bcm2048_device, work);
+       bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG0, &flag_lsb);
+       bcm2048_recv_command(bdev, BCM2048_I2C_FM_RDS_FLAG1, &flag_msb);
+
+       if (flag_lsb & (BCM2048_FM_FLAG_SEARCH_TUNE_FINISHED |
+                       BCM2048_FM_FLAG_SEARCH_TUNE_FAIL)) {
+
+               if (flag_lsb & BCM2048_FM_FLAG_SEARCH_TUNE_FAIL)
+                       bdev->scan_state = BCM2048_SCAN_FAIL;
+               else
+                       bdev->scan_state = BCM2048_SCAN_OK;
+
+               complete(&bdev->compl);
+       }
+
+       if (flag_msb & BCM2048_RDS_FLAG_FIFO_WLINE) {
+               bcm2048_rds_fifo_receive(bdev);
+               if (bdev->rds_state) {
+                       flags = BCM2048_RDS_FLAG_FIFO_WLINE;
+                       bcm2048_send_command(bdev, BCM2048_I2C_FM_RDS_MASK1,
+                                               flags);
+               }
+               bdev->rds_data_available = 1;
+               bdev->rd_index = 0; /* new data, new start */
+       }
+}
+
+/*
+ *     BCM2048 interrupt handler
+ */
+static irqreturn_t bcm2048_handler(int irq, void *dev)
+{
+       struct bcm2048_device *bdev = dev;
+
+       dev_dbg(&bdev->client->dev, "IRQ called, queuing work\n");
+       if (bdev->power_state)
+               schedule_work(&bdev->work);
+
+       return IRQ_HANDLED;
+}
+
+/*
+ *     BCM2048 sysfs interface definitions
+ */
+#define property_write(prop, type, mask, check)                                \
+static ssize_t bcm2048_##prop##_write(struct device *dev,              \
+                                       struct device_attribute *attr,  \
+                                       const char *buf,                \
+                                       size_t count)                   \
+{                                                                      \
+       struct bcm2048_device *bdev = dev_get_drvdata(dev);             \
+       type value;                                                     \
+       int err;                                                        \
+                                                                       \
+       if (!bdev)                                                      \
+               return -ENODEV;                                         \
+                                                                       \
+       sscanf(buf, mask, &value);                                      \
+                                                                       \
+       if (check)                                                      \
+               return -EDOM;                                           \
+                                                                       \
+       err = bcm2048_set_##prop(bdev, value);                          \
+                                                                       \
+       return err < 0 ? err : count;                                   \
+}
+
+#define property_read(prop, size, mask)                                        \
+static ssize_t bcm2048_##prop##_read(struct device *dev,               \
+                                       struct device_attribute *attr,  \
+                                       char *buf)                      \
+{                                                                      \
+       struct bcm2048_device *bdev = dev_get_drvdata(dev);             \
+       int value;                                                      \
+                                                                       \
+       if (!bdev)                                                      \
+               return -ENODEV;                                         \
+                                                                       \
+       value = bcm2048_get_##prop(bdev);                               \
+                                                                       \
+       if (value >= 0)                                                 \
+               value = sprintf(buf, mask "\n", value);                 \
+                                                                       \
+       return value;                                                   \
+}
+
+#define property_signed_read(prop, size, mask)                         \
+static ssize_t bcm2048_##prop##_read(struct device *dev,               \
+                                       struct device_attribute *attr,  \
+                                       char *buf)                      \
+{                                                                      \
+       struct bcm2048_device *bdev = dev_get_drvdata(dev);             \
+       size value;                                                     \
+                                                                       \
+       if (!bdev)                                                      \
+               return -ENODEV;                                         \
+                                                                       \
+       value = bcm2048_get_##prop(bdev);                               \
+                                                                       \
+       value = sprintf(buf, mask "\n", value);                         \
+                                                                       \
+       return value;                                                   \
+}
+
+#define DEFINE_SYSFS_PROPERTY(prop, signal, size, mask, check)         \
+property_write(prop, signal size, mask, check)                         \
+property_read(prop, size, mask)
+
+#define property_str_read(prop, size)                                  \
+static ssize_t bcm2048_##prop##_read(struct device *dev,               \
+                                       struct device_attribute *attr,  \
+                                       char *buf)                      \
+{                                                                      \
+       struct bcm2048_device *bdev = dev_get_drvdata(dev);             \
+       int count;                                                      \
+       u8 *out;                                                        \
+                                                                       \
+       if (!bdev)                                                      \
+               return -ENODEV;                                         \
+                                                                       \
+       out = kzalloc(size + 1, GFP_KERNEL);                            \
+       if (!out)                                                       \
+               return -ENOMEM;                                         \
+                                                                       \
+       bcm2048_get_##prop(bdev, out);                                  \
+       count = sprintf(buf, "%s\n", out);                              \
+                                                                       \
+       kfree(out);                                                     \
+                                                                       \
+       return count;                                                   \
+}
+
+DEFINE_SYSFS_PROPERTY(power_state, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(mute, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(audio_route, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(dac_output, unsigned, int, "%u", 0)
+
+DEFINE_SYSFS_PROPERTY(fm_hi_lo_injection, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(fm_frequency, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(fm_af_frequency, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(fm_deemphasis, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(fm_rds_mask, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(fm_best_tune_mode, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(fm_search_rssi_threshold, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(fm_search_mode_direction, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(fm_search_tune_mode, unsigned, int, "%u", value > 3)
+
+DEFINE_SYSFS_PROPERTY(rds, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(rds_b_block_mask, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(rds_b_block_match, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(rds_pi_mask, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(rds_pi_match, unsigned, int, "%u", 0)
+DEFINE_SYSFS_PROPERTY(rds_wline, unsigned, int, "%u", 0)
+property_read(rds_pi, unsigned int, "%x")
+property_str_read(rds_rt, (BCM2048_MAX_RDS_RT + 1))
+property_str_read(rds_ps, (BCM2048_MAX_RDS_PS + 1))
+
+property_read(fm_rds_flags, unsigned int, "%u")
+property_str_read(rds_data, BCM2048_MAX_RDS_RADIO_TEXT*5)
+
+property_read(region_bottom_frequency, unsigned int, "%u")
+property_read(region_top_frequency, unsigned int, "%u")
+property_signed_read(fm_carrier_error, int, "%d")
+property_signed_read(fm_rssi, int, "%d")
+DEFINE_SYSFS_PROPERTY(region, unsigned, int, "%u", 0)
+
+static struct device_attribute attrs[] = {
+       __ATTR(power_state, S_IRUGO | S_IWUSR, bcm2048_power_state_read,
+               bcm2048_power_state_write),
+       __ATTR(mute, S_IRUGO | S_IWUSR, bcm2048_mute_read,
+               bcm2048_mute_write),
+       __ATTR(audio_route, S_IRUGO | S_IWUSR, bcm2048_audio_route_read,
+               bcm2048_audio_route_write),
+       __ATTR(dac_output, S_IRUGO | S_IWUSR, bcm2048_dac_output_read,
+               bcm2048_dac_output_write),
+       __ATTR(fm_hi_lo_injection, S_IRUGO | S_IWUSR,
+               bcm2048_fm_hi_lo_injection_read,
+               bcm2048_fm_hi_lo_injection_write),
+       __ATTR(fm_frequency, S_IRUGO | S_IWUSR, bcm2048_fm_frequency_read,
+               bcm2048_fm_frequency_write),
+       __ATTR(fm_af_frequency, S_IRUGO | S_IWUSR,
+               bcm2048_fm_af_frequency_read,
+               bcm2048_fm_af_frequency_write),
+       __ATTR(fm_deemphasis, S_IRUGO | S_IWUSR, bcm2048_fm_deemphasis_read,
+               bcm2048_fm_deemphasis_write),
+       __ATTR(fm_rds_mask, S_IRUGO | S_IWUSR, bcm2048_fm_rds_mask_read,
+               bcm2048_fm_rds_mask_write),
+       __ATTR(fm_best_tune_mode, S_IRUGO | S_IWUSR,
+               bcm2048_fm_best_tune_mode_read,
+               bcm2048_fm_best_tune_mode_write),
+       __ATTR(fm_search_rssi_threshold, S_IRUGO | S_IWUSR,
+               bcm2048_fm_search_rssi_threshold_read,
+               bcm2048_fm_search_rssi_threshold_write),
+       __ATTR(fm_search_mode_direction, S_IRUGO | S_IWUSR,
+               bcm2048_fm_search_mode_direction_read,
+               bcm2048_fm_search_mode_direction_write),
+       __ATTR(fm_search_tune_mode, S_IRUGO | S_IWUSR,
+               bcm2048_fm_search_tune_mode_read,
+               bcm2048_fm_search_tune_mode_write),
+       __ATTR(rds, S_IRUGO | S_IWUSR, bcm2048_rds_read,
+               bcm2048_rds_write),
+       __ATTR(rds_b_block_mask, S_IRUGO | S_IWUSR,
+               bcm2048_rds_b_block_mask_read,
+               bcm2048_rds_b_block_mask_write),
+       __ATTR(rds_b_block_match, S_IRUGO | S_IWUSR,
+               bcm2048_rds_b_block_match_read,
+               bcm2048_rds_b_block_match_write),
+       __ATTR(rds_pi_mask, S_IRUGO | S_IWUSR, bcm2048_rds_pi_mask_read,
+               bcm2048_rds_pi_mask_write),
+       __ATTR(rds_pi_match, S_IRUGO | S_IWUSR, bcm2048_rds_pi_match_read,
+               bcm2048_rds_pi_match_write),
+       __ATTR(rds_wline, S_IRUGO | S_IWUSR, bcm2048_rds_wline_read,
+               bcm2048_rds_wline_write),
+       __ATTR(rds_pi, S_IRUGO, bcm2048_rds_pi_read, NULL),
+       __ATTR(rds_rt, S_IRUGO, bcm2048_rds_rt_read, NULL),
+       __ATTR(rds_ps, S_IRUGO, bcm2048_rds_ps_read, NULL),
+       __ATTR(fm_rds_flags, S_IRUGO, bcm2048_fm_rds_flags_read, NULL),
+       __ATTR(region_bottom_frequency, S_IRUGO,
+               bcm2048_region_bottom_frequency_read, NULL),
+       __ATTR(region_top_frequency, S_IRUGO,
+               bcm2048_region_top_frequency_read, NULL),
+       __ATTR(fm_carrier_error, S_IRUGO,
+               bcm2048_fm_carrier_error_read, NULL),
+       __ATTR(fm_rssi, S_IRUGO,
+               bcm2048_fm_rssi_read, NULL),
+       __ATTR(region, S_IRUGO | S_IWUSR, bcm2048_region_read,
+               bcm2048_region_write),
+       __ATTR(rds_data, S_IRUGO, bcm2048_rds_data_read, NULL),
+};
+
+static int bcm2048_sysfs_unregister_properties(struct bcm2048_device *bdev,
+                                               int size)
+{
+       int i;
+
+       for (i = 0; i < size; i++)
+               device_remove_file(&bdev->client->dev, &attrs[i]);
+
+       return 0;
+}
+
+static int bcm2048_sysfs_register_properties(struct bcm2048_device *bdev)
+{
+       int err = 0;
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(attrs); i++) {
+               if (device_create_file(&bdev->client->dev, &attrs[i]) != 0) {
+                       dev_err(&bdev->client->dev,
+                                       "could not register sysfs entry\n");
+                       err = -EBUSY;
+                       bcm2048_sysfs_unregister_properties(bdev, i);
+                       break;
+               }
+       }
+
+       return err;
+}
+
+
+static int bcm2048_fops_open(struct file *file)
+{
+       struct bcm2048_device *bdev = video_drvdata(file);
+
+       bdev->users++;
+       bdev->rd_index = 0;
+       bdev->rds_data_available = 0;
+
+       return 0;
+}
+
+static int bcm2048_fops_release(struct file *file)
+{
+       struct bcm2048_device *bdev = video_drvdata(file);
+
+       bdev->users--;
+
+       return 0;
+}
+
+static unsigned int bcm2048_fops_poll(struct file *file,
+               struct poll_table_struct *pts)
+{
+       struct bcm2048_device *bdev = video_drvdata(file);
+       int retval = 0;
+
+       poll_wait(file, &bdev->read_queue, pts);
+
+       if (bdev->rds_data_available)
+               retval = POLLIN | POLLRDNORM;
+
+       return retval;
+}
+
+static ssize_t bcm2048_fops_read(struct file *file, char __user *buf,
+       size_t count, loff_t *ppos)
+{
+       struct bcm2048_device *bdev = video_drvdata(file);
+       int i;
+       int retval = 0;
+
+       /* we return at least 3 bytes, one block */
+       count = (count / 3) * 3; /* only multiples of 3 */
+       if (count < 3)
+               return -ENOBUFS;
+
+       while (!bdev->rds_data_available) {
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EWOULDBLOCK;
+                       goto done;
+               }
+               /* interruptible_sleep_on(&bdev->read_queue); */
+               if (wait_event_interruptible(bdev->read_queue,
+                       bdev->rds_data_available) < 0) {
+                       retval = -EINTR;
+                       goto done;
+               }
+       }
+
+       mutex_lock(&bdev->mutex);
+       /* copy data to userspace */
+       i = bdev->fifo_size - bdev->rd_index;
+       if (count > i)
+               count = (i / 3) * 3;
+
+       i = 0;
+       while (i < count) {
+               unsigned char tmpbuf[3];
+               tmpbuf[i] = bdev->rds_info.radio_text[bdev->rd_index+i+2];
+               tmpbuf[i+1] = bdev->rds_info.radio_text[bdev->rd_index+i+1];
+               tmpbuf[i+2] = ((bdev->rds_info.radio_text[bdev->rd_index+i]
+                               & 0xf0) >> 4);
+               if ((bdev->rds_info.radio_text[bdev->rd_index+i] &
+                       BCM2048_RDS_CRC_MASK) == BCM2048_RDS_CRC_UNRECOVARABLE)
+                       tmpbuf[i+2] |= 0x80;
+               if (copy_to_user(buf+i, tmpbuf, 3)) {
+                       retval = -EFAULT;
+                       break;
+               }
+               i += 3;
+       }
+
+       bdev->rd_index += i;
+       if (bdev->rd_index >= bdev->fifo_size)
+               bdev->rds_data_available = 0;
+
+       mutex_unlock(&bdev->mutex);
+       if (retval == 0)
+               retval = i;
+
+done:
+       return retval;
+}
+
+/*
+ *     bcm2048_fops - file operations interface
+ */
+static const struct v4l2_file_operations bcm2048_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = video_ioctl2,
+       /* for RDS read support */
+       .open           = bcm2048_fops_open,
+       .release        = bcm2048_fops_release,
+       .read           = bcm2048_fops_read,
+       .poll           = bcm2048_fops_poll
+};
+
+/*
+ *     Video4Linux Interface
+ */
+static struct v4l2_queryctrl bcm2048_v4l2_queryctrl[] = {
+       {
+               .id             = V4L2_CID_AUDIO_VOLUME,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_BALANCE,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_BASS,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_TREBLE,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_MUTE,
+               .type           = V4L2_CTRL_TYPE_BOOLEAN,
+               .name           = "Mute",
+               .minimum        = 0,
+               .maximum        = 1,
+               .step           = 1,
+               .default_value  = 1,
+       },
+       {
+               .id             = V4L2_CID_AUDIO_LOUDNESS,
+               .flags          = V4L2_CTRL_FLAG_DISABLED,
+       },
+};
+
+static int bcm2048_vidioc_querycap(struct file *file, void *priv,
+               struct v4l2_capability *capability)
+{
+       struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
+
+       strlcpy(capability->driver, BCM2048_DRIVER_NAME,
+               sizeof(capability->driver));
+       strlcpy(capability->card, BCM2048_DRIVER_CARD,
+               sizeof(capability->card));
+       snprintf(capability->bus_info, 32, "I2C: 0x%X", bdev->client->addr);
+       capability->version = BCM2048_DRIVER_VERSION;
+       capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+                                       V4L2_CAP_HW_FREQ_SEEK;
+
+       return 0;
+}
+
+static int bcm2048_vidioc_g_input(struct file *filp, void *priv,
+               unsigned int *i)
+{
+       *i = 0;
+
+       return 0;
+}
+
+static int bcm2048_vidioc_s_input(struct file *filp, void *priv,
+                                       unsigned int i)
+{
+       if (i)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int bcm2048_vidioc_queryctrl(struct file *file, void *priv,
+               struct v4l2_queryctrl *qc)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_SIZE(bcm2048_v4l2_queryctrl); i++) {
+               if (qc->id && qc->id == bcm2048_v4l2_queryctrl[i].id) {
+                       *qc = bcm2048_v4l2_queryctrl[i];
+                       return 0;
+               }
+       }
+
+       return -EINVAL;
+}
+
+static int bcm2048_vidioc_g_ctrl(struct file *file, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
+       int err = 0;
+
+       if (!bdev)
+               return -ENODEV;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               err = bcm2048_get_mute(bdev);
+               if (err >= 0)
+                       ctrl->value = err;
+               break;
+       }
+
+       return err;
+}
+
+static int bcm2048_vidioc_s_ctrl(struct file *file, void *priv,
+               struct v4l2_control *ctrl)
+{
+       struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
+       int err = 0;
+
+       if (!bdev)
+               return -ENODEV;
+
+       switch (ctrl->id) {
+       case V4L2_CID_AUDIO_MUTE:
+               if (ctrl->value) {
+                       if (bdev->power_state) {
+                               err = bcm2048_set_mute(bdev, ctrl->value);
+                               err |= bcm2048_deinit(bdev);
+                       }
+               } else {
+                       if (!bdev->power_state) {
+                               err = bcm2048_init(bdev);
+                               err |= bcm2048_set_mute(bdev, ctrl->value);
+                       }
+               }
+               break;
+       }
+
+       return err;
+}
+
+static int bcm2048_vidioc_g_audio(struct file *file, void *priv,
+               struct v4l2_audio *audio)
+{
+       if (audio->index > 1)
+               return -EINVAL;
+
+       strncpy(audio->name, "Radio", 32);
+       audio->capability = V4L2_AUDCAP_STEREO;
+
+       return 0;
+}
+
+static int bcm2048_vidioc_s_audio(struct file *file, void *priv,
+               const struct v4l2_audio *audio)
+{
+       if (audio->index != 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int bcm2048_vidioc_g_tuner(struct file *file, void *priv,
+               struct v4l2_tuner *tuner)
+{
+       struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
+       s8 f_error;
+       s8 rssi;
+
+       if (!bdev)
+               return -ENODEV;
+
+       if (tuner->index > 0)
+               return -EINVAL;
+
+       strncpy(tuner->name, "FM Receiver", 32);
+       tuner->type = V4L2_TUNER_RADIO;
+       tuner->rangelow =
+               dev_to_v4l2(bcm2048_get_region_bottom_frequency(bdev));
+       tuner->rangehigh =
+               dev_to_v4l2(bcm2048_get_region_top_frequency(bdev));
+       tuner->rxsubchans = V4L2_TUNER_SUB_STEREO;
+       tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
+       tuner->audmode = V4L2_TUNER_MODE_STEREO;
+       tuner->afc = 0;
+       if (bdev->power_state) {
+               /*
+                * Report frequencies with high carrier errors to have zero
+                * signal level
+                */
+               f_error = bcm2048_get_fm_carrier_error(bdev);
+               if (f_error < BCM2048_FREQ_ERROR_FLOOR ||
+                   f_error > BCM2048_FREQ_ERROR_ROOF) {
+                       tuner->signal = 0;
+               } else {
+                       /*
+                        * RSSI level -60 dB is defined to report full
+                        * signal strenght
+                        */
+                       rssi = bcm2048_get_fm_rssi(bdev);
+                       if (rssi >= BCM2048_RSSI_LEVEL_BASE) {
+                               tuner->signal = 0xFFFF;
+                       } else if (rssi > BCM2048_RSSI_LEVEL_ROOF) {
+                               tuner->signal = (rssi +
+                                                BCM2048_RSSI_LEVEL_ROOF_NEG)
+                                                * BCM2048_SIGNAL_MULTIPLIER;
+                       } else {
+                               tuner->signal = 0;
+                       }
+               }
+       } else {
+               tuner->signal = 0;
+       }
+
+       return 0;
+}
+
+static int bcm2048_vidioc_s_tuner(struct file *file, void *priv,
+               const struct v4l2_tuner *tuner)
+{
+       struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
+
+       if (!bdev)
+               return -ENODEV;
+
+       if (tuner->index > 0)
+               return -EINVAL;
+
+       return 0;
+}
+
+static int bcm2048_vidioc_g_frequency(struct file *file, void *priv,
+               struct v4l2_frequency *freq)
+{
+       struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
+       int err = 0;
+       int f;
+
+       if (!bdev->power_state)
+               return -ENODEV;
+
+       freq->type = V4L2_TUNER_RADIO;
+       f = bcm2048_get_fm_frequency(bdev);
+
+       if (f < 0)
+               err = f;
+       else
+               freq->frequency = dev_to_v4l2(f);
+
+       return err;
+}
+
+static int bcm2048_vidioc_s_frequency(struct file *file, void *priv,
+               const struct v4l2_frequency *freq)
+{
+       struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
+       int err;
+
+       if (freq->type != V4L2_TUNER_RADIO)
+               return -EINVAL;
+
+       if (!bdev->power_state)
+               return -ENODEV;
+
+       err = bcm2048_set_fm_frequency(bdev, v4l2_to_dev(freq->frequency));
+       err |= bcm2048_set_fm_search_tune_mode(bdev, BCM2048_FM_PRE_SET_MODE);
+
+       return err;
+}
+
+static int bcm2048_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+                                       const struct v4l2_hw_freq_seek *seek)
+{
+       struct bcm2048_device *bdev = video_get_drvdata(video_devdata(file));
+       int err;
+
+       if (!bdev->power_state)
+               return -ENODEV;
+
+       if ((seek->tuner != 0) || (seek->type != V4L2_TUNER_RADIO))
+               return -EINVAL;
+
+       err = bcm2048_set_fm_search_mode_direction(bdev, seek->seek_upward);
+       err |= bcm2048_set_fm_search_tune_mode(bdev,
+                       BCM2048_FM_AUTO_SEARCH_MODE);
+
+       return err;
+}
+
+static struct v4l2_ioctl_ops bcm2048_ioctl_ops = {
+       .vidioc_querycap        = bcm2048_vidioc_querycap,
+       .vidioc_g_input         = bcm2048_vidioc_g_input,
+       .vidioc_s_input         = bcm2048_vidioc_s_input,
+       .vidioc_queryctrl       = bcm2048_vidioc_queryctrl,
+       .vidioc_g_ctrl          = bcm2048_vidioc_g_ctrl,
+       .vidioc_s_ctrl          = bcm2048_vidioc_s_ctrl,
+       .vidioc_g_audio         = bcm2048_vidioc_g_audio,
+       .vidioc_s_audio         = bcm2048_vidioc_s_audio,
+       .vidioc_g_tuner         = bcm2048_vidioc_g_tuner,
+       .vidioc_s_tuner         = bcm2048_vidioc_s_tuner,
+       .vidioc_g_frequency     = bcm2048_vidioc_g_frequency,
+       .vidioc_s_frequency     = bcm2048_vidioc_s_frequency,
+       .vidioc_s_hw_freq_seek  = bcm2048_vidioc_s_hw_freq_seek,
+};
+
+/*
+ * bcm2048_viddev_template - video device interface
+ */
+static struct video_device bcm2048_viddev_template = {
+       .fops                   = &bcm2048_fops,
+       .name                   = BCM2048_DRIVER_NAME,
+       .release                = video_device_release,
+       .ioctl_ops              = &bcm2048_ioctl_ops,
+};
+
+/*
+ *     I2C driver interface
+ */
+static int bcm2048_i2c_driver_probe(struct i2c_client *client,
+                                       const struct i2c_device_id *id)
+{
+       struct bcm2048_device *bdev;
+       int err, skip_release = 0;
+
+       bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
+       if (!bdev) {
+               dev_dbg(&client->dev, "Failed to alloc video device.\n");
+               err = -ENOMEM;
+               goto exit;
+       }
+
+       bdev->videodev = video_device_alloc();
+       if (!bdev->videodev) {
+               dev_dbg(&client->dev, "Failed to alloc video device.\n");
+               err = -ENOMEM;
+               goto free_bdev;
+       }
+
+       bdev->client = client;
+       i2c_set_clientdata(client, bdev);
+       mutex_init(&bdev->mutex);
+       init_completion(&bdev->compl);
+       INIT_WORK(&bdev->work, bcm2048_work);
+
+       if (client->irq) {
+               err = request_irq(client->irq,
+                       bcm2048_handler, IRQF_TRIGGER_FALLING | IRQF_DISABLED,
+                       client->name, bdev);
+               if (err < 0) {
+                       dev_err(&client->dev, "Could not request IRQ\n");
+                       goto free_vdev;
+               }
+               dev_dbg(&client->dev, "IRQ requested.\n");
+       } else {
+               dev_dbg(&client->dev, "IRQ not configured. Using timeouts.\n");
+       }
+
+       *bdev->videodev = bcm2048_viddev_template;
+       video_set_drvdata(bdev->videodev, bdev);
+       if (video_register_device(bdev->videodev, VFL_TYPE_RADIO, radio_nr)) {
+               dev_dbg(&client->dev, "Could not register video device.\n");
+               err = -EIO;
+               goto free_irq;
+       }
+
+       err = bcm2048_sysfs_register_properties(bdev);
+       if (err < 0) {
+               dev_dbg(&client->dev, "Could not register sysfs interface.\n");
+               goto free_registration;
+       }
+
+       err = bcm2048_probe(bdev);
+       if (err < 0) {
+               dev_dbg(&client->dev, "Failed to probe device information.\n");
+               goto free_sysfs;
+       }
+
+       return 0;
+
+free_sysfs:
+       bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs));
+free_registration:
+       video_unregister_device(bdev->videodev);
+       /* video_unregister_device frees bdev->videodev */
+       bdev->videodev = NULL;
+       skip_release = 1;
+free_irq:
+       if (client->irq)
+               free_irq(client->irq, bdev);
+free_vdev:
+       if (!skip_release)
+               video_device_release(bdev->videodev);
+       i2c_set_clientdata(client, NULL);
+free_bdev:
+       kfree(bdev);
+exit:
+       return err;
+}
+
+static int __exit bcm2048_i2c_driver_remove(struct i2c_client *client)
+{
+       struct bcm2048_device *bdev = i2c_get_clientdata(client);
+       struct video_device *vd;
+
+       if (!client->adapter)
+               return -ENODEV;
+
+       if (bdev) {
+               vd = bdev->videodev;
+
+               bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs));
+
+               if (vd)
+                       video_unregister_device(vd);
+
+               if (bdev->power_state)
+                       bcm2048_set_power_state(bdev, BCM2048_POWER_OFF);
+
+               if (client->irq > 0)
+                       free_irq(client->irq, bdev);
+
+               cancel_work_sync(&bdev->work);
+
+               kfree(bdev);
+       }
+
+       i2c_set_clientdata(client, NULL);
+
+       return 0;
+}
+
+/*
+ *     bcm2048_i2c_driver - i2c driver interface
+ */
+static const struct i2c_device_id bcm2048_id[] = {
+       { "bcm2048" , 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(i2c, bcm2048_id);
+
+static struct i2c_driver bcm2048_i2c_driver = {
+       .driver         = {
+               .name   = BCM2048_DRIVER_NAME,
+       },
+       .probe          = bcm2048_i2c_driver_probe,
+       .remove         = __exit_p(bcm2048_i2c_driver_remove),
+       .id_table       = bcm2048_id,
+};
+
+/*
+ *     Module Interface
+ */
+static int __init bcm2048_module_init(void)
+{
+       pr_info(BCM2048_DRIVER_DESC "\n");
+
+       return i2c_add_driver(&bcm2048_i2c_driver);
+}
+module_init(bcm2048_module_init);
+
+static void __exit bcm2048_module_exit(void)
+{
+       i2c_del_driver(&bcm2048_i2c_driver);
+}
+module_exit(bcm2048_module_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR(BCM2048_DRIVER_AUTHOR);
+MODULE_DESCRIPTION(BCM2048_DRIVER_DESC);
+MODULE_VERSION("0.0.2");
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.h b/drivers/staging/media/bcm2048/radio-bcm2048.h
new file mode 100644 (file)
index 0000000..4c90a32
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * drivers/staging/media/radio-bcm2048.h
+ *
+ * Property and command definitions for bcm2048 radio receiver chip.
+ *
+ * Copyright (C) Nokia Corporation
+ * Contact: Eero Nurkkala <ext-eero.nurkkala@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef BCM2048_H
+#define BCM2048_H
+
+#define BCM2048_NAME           "bcm2048"
+#define BCM2048_I2C_ADDR       0x22
+
+#endif /* ifndef BCM2048_H */
index ff48fce94fcbda376938d3482d44978bd65533b6..b942bf73c43f095df99c4b3443a85804c8b0cfeb 100644 (file)
@@ -19,6 +19,7 @@
  *      Prabhakar Lad <prabhakar.lad@ti.com>
  */
 
+#include <linux/delay.h>
 #include "dm365_isif.h"
 #include "vpfe_mc_capture.h"
 
@@ -918,7 +919,7 @@ isif_config_dfc(struct vpfe_isif_device *isif, struct vpfe_isif_dfc *vdfc)
                   (0 << ISIF_VDFC_EN_SHIFT), DFCCTL);
 
        isif_write(isif->isif_cfg.base_addr, 0x6, DFCMEMCTL);
-       for (i = 0 ; i < vdfc->num_vdefects; i++) {
+       for (i = 0; i < vdfc->num_vdefects; i++) {
                count = DFC_WRITE_WAIT_COUNT;
                while (count &&
                        (isif_read(isif->isif_cfg.base_addr, DFCMEMCTL) & 0x2))
index 24d98a6866bb7d91178daffaba6e867a8f332a18..1f3b0f9a8d102e2852603dc376c79b79ceae9323 100644 (file)
@@ -346,7 +346,7 @@ static int vpfe_pipeline_disable(struct vpfe_pipeline *pipe)
        }
        mutex_unlock(&mdev->graph_mutex);
 
-       return (ret == 0) ? ret : -ETIMEDOUT ;
+       return ret ? -ETIMEDOUT : 0;
 }
 
 /*
@@ -1201,6 +1201,8 @@ static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count)
        unsigned long addr;
        int ret;
 
+       if (count == 0)
+               return -ENOBUFS;
        ret = mutex_lock_interruptible(&video->lock);
        if (ret)
                goto streamoff;
index 41d110f8bc02e2775236315342d0b06a79a9bd35..0b589892351af3075d191c8a1622e947f5eb1fa3 100644 (file)
@@ -220,7 +220,7 @@ static void rbuf_write(int signal)
        wptr = nwptr;
 }
 
-static void irq_handler(void *blah)
+static void lirc_lirc_irq_handler(void *blah)
 {
        struct timeval tv;
        static struct timeval lasttv;
@@ -659,7 +659,7 @@ static int __init lirc_parallel_init(void)
                goto exit_device_put;
        }
        ppdevice = parport_register_device(pport, LIRC_DRIVER_NAME,
-                                          pf, kf, irq_handler, 0, NULL);
+                                          pf, kf, lirc_lirc_irq_handler, 0, NULL);
        parport_put_port(pport);
        if (ppdevice == NULL) {
                pr_notice("parport_register_device() failed\n");
index abe0d5caa20b2e8836d2f02159647e1f0d44bdf4..10c685d5de7cea672eae318eaa6df034095fa19c 100644 (file)
@@ -650,7 +650,7 @@ static void frbwrite(int l)
        rbwrite(l);
 }
 
-static irqreturn_t irq_handler(int i, void *blah)
+static irqreturn_t lirc_irq_handler(int i, void *blah)
 {
        struct timeval tv;
        int counter, dcd;
@@ -852,7 +852,7 @@ static int lirc_serial_probe(struct platform_device *dev)
                return result;
 #endif
 
-       result = request_irq(irq, irq_handler,
+       result = request_irq(irq, lirc_irq_handler,
                             (share_irq ? IRQF_SHARED : 0),
                             LIRC_DRIVER_NAME, (void *)&hardware);
        if (result < 0) {
diff --git a/drivers/staging/media/omap24xx/Kconfig b/drivers/staging/media/omap24xx/Kconfig
new file mode 100644 (file)
index 0000000..82e569a
--- /dev/null
@@ -0,0 +1,35 @@
+config VIDEO_V4L2_INT_DEVICE
+       tristate
+
+config VIDEO_OMAP2
+       tristate "OMAP2 Camera Capture Interface driver (DEPRECATED)"
+       depends on VIDEO_DEV && ARCH_OMAP2
+       select VIDEOBUF_DMA_SG
+       select VIDEO_V4L2_INT_DEVICE
+       ---help---
+         This is a v4l2 driver for the TI OMAP2 camera capture interface
+
+         It uses the deprecated int-device API. Since this driver is no
+         longer actively maintained and nobody is interested in converting
+         it to the subdev API, this driver will be removed soon.
+
+         If you do want to keep this driver in the kernel, and are willing
+         to convert it to the subdev API, then please contact the linux-media
+         mailinglist.
+
+config VIDEO_TCM825X
+       tristate "TCM825x camera sensor support (DEPRECATED)"
+       depends on I2C && VIDEO_V4L2
+       depends on MEDIA_CAMERA_SUPPORT
+       select VIDEO_V4L2_INT_DEVICE
+       ---help---
+         This is a driver for the Toshiba TCM825x VGA camera sensor.
+         It is used for example in Nokia N800.
+
+         It uses the deprecated int-device API. Since this driver is no
+         longer actively maintained and nobody is interested in converting
+         it to the subdev API, this driver will be removed soon.
+
+         If you do want to keep this driver in the kernel, and are willing
+         to convert it to the subdev API, then please contact the linux-media
+         mailinglist.
diff --git a/drivers/staging/media/omap24xx/Makefile b/drivers/staging/media/omap24xx/Makefile
new file mode 100644 (file)
index 0000000..c2e7175
--- /dev/null
@@ -0,0 +1,5 @@
+omap2cam-objs  :=      omap24xxcam.o omap24xxcam-dma.o
+
+obj-$(CONFIG_VIDEO_OMAP2)   += omap2cam.o
+obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
+obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o
similarity index 99%
rename from drivers/media/platform/omap24xxcam.h
rename to drivers/staging/media/omap24xx/omap24xxcam.h
index 7f6f79155537a9fbdb921d516acdac9ca073d59c..233bb40cfec34e4ecd5064a8e874234962186002 100644 (file)
@@ -28,8 +28,8 @@
 #define OMAP24XXCAM_H
 
 #include <media/videobuf-dma-sg.h>
-#include <media/v4l2-int-device.h>
 #include <media/v4l2-device.h>
+#include "v4l2-int-device.h"
 
 /*
  *
similarity index 99%
rename from drivers/media/i2c/tcm825x.c
rename to drivers/staging/media/omap24xx/tcm825x.c
index 9252529fc5ddd69f7bd9aa8ff8e20072cb111aab..b1ae8e9c7e1428fdbe1e81bcbdf4533b51c99319 100644 (file)
@@ -28,7 +28,7 @@
 
 #include <linux/i2c.h>
 #include <linux/module.h>
-#include <media/v4l2-int-device.h>
+#include "v4l2-int-device.h"
 
 #include "tcm825x.h"
 
similarity index 99%
rename from drivers/media/i2c/tcm825x.h
rename to drivers/staging/media/omap24xx/tcm825x.h
index 8ebab953963f869b5f63ea4e8686def0e5e9f573..e2d1bcd0bcbe1f3af5ccfb5901fac732bb5f4fd1 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <linux/videodev2.h>
 
-#include <media/v4l2-int-device.h>
+#include "v4l2-int-device.h"
 
 #define TCM825X_NAME "tcm825x"
 
similarity index 99%
rename from drivers/media/v4l2-core/v4l2-int-device.c
rename to drivers/staging/media/omap24xx/v4l2-int-device.c
index f4473494af7aef3e9db95729905c610aef4b8f40..427a89033a1d604c5563ea07ac46a6456fc4e003 100644 (file)
@@ -28,7 +28,7 @@
 #include <linux/string.h>
 #include <linux/module.h>
 
-#include <media/v4l2-int-device.h>
+#include "v4l2-int-device.h"
 
 static DEFINE_MUTEX(mutex);
 static LIST_HEAD(int_list);
diff --git a/drivers/staging/media/omap4iss/Kconfig b/drivers/staging/media/omap4iss/Kconfig
new file mode 100644 (file)
index 0000000..b9fe753
--- /dev/null
@@ -0,0 +1,12 @@
+config VIDEO_OMAP4
+       bool "OMAP 4 Camera support"
+       depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && I2C && ARCH_OMAP4
+       select VIDEOBUF2_DMA_CONTIG
+       ---help---
+         Driver for an OMAP 4 ISS controller.
+
+config VIDEO_OMAP4_DEBUG
+       bool "OMAP 4 Camera debug messages"
+       depends on VIDEO_OMAP4
+       ---help---
+         Enable debug messages on OMAP 4 ISS controller driver.
diff --git a/drivers/staging/media/omap4iss/Makefile b/drivers/staging/media/omap4iss/Makefile
new file mode 100644 (file)
index 0000000..a716ce9
--- /dev/null
@@ -0,0 +1,6 @@
+# Makefile for OMAP4 ISS driver
+
+omap4-iss-objs += \
+       iss.o iss_csi2.o iss_csiphy.o iss_ipipeif.o iss_ipipe.o iss_resizer.o iss_video.o
+
+obj-$(CONFIG_VIDEO_OMAP4) += omap4-iss.o
diff --git a/drivers/staging/media/omap4iss/TODO b/drivers/staging/media/omap4iss/TODO
new file mode 100644 (file)
index 0000000..fcde888
--- /dev/null
@@ -0,0 +1,4 @@
+* Make the driver compile as a module
+* Fix FIFO/buffer overflows and underflows
+* Replace dummy resizer code with a real implementation
+* Fix checkpatch errors and warnings
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
new file mode 100644 (file)
index 0000000..61fbfcd
--- /dev/null
@@ -0,0 +1,1563 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver
+ *
+ * Copyright (C) 2012, Texas Instruments
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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 <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+
+#include "iss.h"
+#include "iss_regs.h"
+
+#define ISS_PRINT_REGISTER(iss, name)\
+       dev_dbg(iss->dev, "###ISS " #name "=0x%08x\n", \
+               iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_##name))
+
+static void iss_print_status(struct iss_device *iss)
+{
+       dev_dbg(iss->dev, "-------------ISS HL Register dump-------------\n");
+
+       ISS_PRINT_REGISTER(iss, HL_REVISION);
+       ISS_PRINT_REGISTER(iss, HL_SYSCONFIG);
+       ISS_PRINT_REGISTER(iss, HL_IRQSTATUS(5));
+       ISS_PRINT_REGISTER(iss, HL_IRQENABLE_SET(5));
+       ISS_PRINT_REGISTER(iss, HL_IRQENABLE_CLR(5));
+       ISS_PRINT_REGISTER(iss, CTRL);
+       ISS_PRINT_REGISTER(iss, CLKCTRL);
+       ISS_PRINT_REGISTER(iss, CLKSTAT);
+
+       dev_dbg(iss->dev, "-----------------------------------------------\n");
+}
+
+/*
+ * omap4iss_flush - Post pending L3 bus writes by doing a register readback
+ * @iss: OMAP4 ISS device
+ *
+ * In order to force posting of pending writes, we need to write and
+ * readback the same register, in this case the revision register.
+ *
+ * See this link for reference:
+ *   http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
+ */
+void omap4iss_flush(struct iss_device *iss)
+{
+       iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION, 0);
+       iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION);
+}
+
+/*
+ * iss_isp_enable_interrupts - Enable ISS ISP interrupts.
+ * @iss: OMAP4 ISS device
+ */
+static void omap4iss_isp_enable_interrupts(struct iss_device *iss)
+{
+       static const u32 isp_irq = ISP5_IRQ_OCP_ERR |
+                                  ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR |
+                                  ISP5_IRQ_RSZ_FIFO_OVF |
+                                  ISP5_IRQ_RSZ_INT_DMA |
+                                  ISP5_IRQ_ISIF_INT(0);
+
+       /* Enable ISP interrupts */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQSTATUS(0), isp_irq);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQENABLE_SET(0),
+                     isp_irq);
+}
+
+/*
+ * iss_isp_disable_interrupts - Disable ISS interrupts.
+ * @iss: OMAP4 ISS device
+ */
+static void omap4iss_isp_disable_interrupts(struct iss_device *iss)
+{
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQENABLE_CLR(0), ~0);
+}
+
+/*
+ * iss_enable_interrupts - Enable ISS interrupts.
+ * @iss: OMAP4 ISS device
+ */
+static void iss_enable_interrupts(struct iss_device *iss)
+{
+       static const u32 hl_irq = ISS_HL_IRQ_CSIA | ISS_HL_IRQ_CSIB
+                               | ISS_HL_IRQ_ISP(0);
+
+       /* Enable HL interrupts */
+       iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5), hl_irq);
+       iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQENABLE_SET(5), hl_irq);
+
+       if (iss->regs[OMAP4_ISS_MEM_ISP_SYS1])
+               omap4iss_isp_enable_interrupts(iss);
+}
+
+/*
+ * iss_disable_interrupts - Disable ISS interrupts.
+ * @iss: OMAP4 ISS device
+ */
+static void iss_disable_interrupts(struct iss_device *iss)
+{
+       if (iss->regs[OMAP4_ISS_MEM_ISP_SYS1])
+               omap4iss_isp_disable_interrupts(iss);
+
+       iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQENABLE_CLR(5), ~0);
+}
+
+int omap4iss_get_external_info(struct iss_pipeline *pipe,
+                              struct media_link *link)
+{
+       struct iss_device *iss =
+               container_of(pipe, struct iss_video, pipe)->iss;
+       struct v4l2_subdev_format fmt;
+       struct v4l2_ctrl *ctrl;
+       int ret;
+
+       if (!pipe->external)
+               return 0;
+
+       if (pipe->external_rate)
+               return 0;
+
+       memset(&fmt, 0, sizeof(fmt));
+
+       fmt.pad = link->source->index;
+       fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       ret = v4l2_subdev_call(media_entity_to_v4l2_subdev(link->sink->entity),
+                              pad, get_fmt, NULL, &fmt);
+       if (ret < 0)
+               return -EPIPE;
+
+       pipe->external_bpp = omap4iss_video_format_info(fmt.format.code)->bpp;
+
+       ctrl = v4l2_ctrl_find(pipe->external->ctrl_handler,
+                             V4L2_CID_PIXEL_RATE);
+       if (ctrl == NULL) {
+               dev_warn(iss->dev, "no pixel rate control in subdev %s\n",
+                        pipe->external->name);
+               return -EPIPE;
+       }
+
+       pipe->external_rate = v4l2_ctrl_g_ctrl_int64(ctrl);
+
+       return 0;
+}
+
+/*
+ * Configure the bridge. Valid inputs are
+ *
+ * IPIPEIF_INPUT_CSI2A: CSI2a receiver
+ * IPIPEIF_INPUT_CSI2B: CSI2b receiver
+ *
+ * The bridge and lane shifter are configured according to the selected input
+ * and the ISP platform data.
+ */
+void omap4iss_configure_bridge(struct iss_device *iss,
+                              enum ipipeif_input_entity input)
+{
+       u32 issctrl_val;
+       u32 isp5ctrl_val;
+
+       issctrl_val = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_CTRL);
+       issctrl_val &= ~ISS_CTRL_INPUT_SEL_MASK;
+       issctrl_val &= ~ISS_CTRL_CLK_DIV_MASK;
+
+       isp5ctrl_val = iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL);
+
+       switch (input) {
+       case IPIPEIF_INPUT_CSI2A:
+               issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2A;
+               break;
+
+       case IPIPEIF_INPUT_CSI2B:
+               issctrl_val |= ISS_CTRL_INPUT_SEL_CSI2B;
+               break;
+
+       default:
+               return;
+       }
+
+       issctrl_val |= ISS_CTRL_SYNC_DETECT_VS_RAISING;
+
+       isp5ctrl_val |= ISP5_CTRL_VD_PULSE_EXT | ISP5_CTRL_PSYNC_CLK_SEL |
+                       ISP5_CTRL_SYNC_ENABLE;
+
+       iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_CTRL, issctrl_val);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, isp5ctrl_val);
+}
+
+#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
+static void iss_isr_dbg(struct iss_device *iss, u32 irqstatus)
+{
+       static const char * const name[] = {
+               "ISP_0",
+               "ISP_1",
+               "ISP_2",
+               "ISP_3",
+               "CSIA",
+               "CSIB",
+               "CCP2_0",
+               "CCP2_1",
+               "CCP2_2",
+               "CCP2_3",
+               "CBUFF",
+               "BTE",
+               "SIMCOP_0",
+               "SIMCOP_1",
+               "SIMCOP_2",
+               "SIMCOP_3",
+               "CCP2_8",
+               "HS_VS",
+               "18",
+               "19",
+               "20",
+               "21",
+               "22",
+               "23",
+               "24",
+               "25",
+               "26",
+               "27",
+               "28",
+               "29",
+               "30",
+               "31",
+       };
+       unsigned int i;
+
+       dev_dbg(iss->dev, "ISS IRQ: ");
+
+       for (i = 0; i < ARRAY_SIZE(name); i++) {
+               if ((1 << i) & irqstatus)
+                       pr_cont("%s ", name[i]);
+       }
+       pr_cont("\n");
+}
+
+static void iss_isp_isr_dbg(struct iss_device *iss, u32 irqstatus)
+{
+       static const char * const name[] = {
+               "ISIF_0",
+               "ISIF_1",
+               "ISIF_2",
+               "ISIF_3",
+               "IPIPEREQ",
+               "IPIPELAST_PIX",
+               "IPIPEDMA",
+               "IPIPEBSC",
+               "IPIPEHST",
+               "IPIPEIF",
+               "AEW",
+               "AF",
+               "H3A",
+               "RSZ_REG",
+               "RSZ_LAST_PIX",
+               "RSZ_DMA",
+               "RSZ_CYC_RZA",
+               "RSZ_CYC_RZB",
+               "RSZ_FIFO_OVF",
+               "RSZ_FIFO_IN_BLK_ERR",
+               "20",
+               "21",
+               "RSZ_EOF0",
+               "RSZ_EOF1",
+               "H3A_EOF",
+               "IPIPE_EOF",
+               "26",
+               "IPIPE_DPC_INI",
+               "IPIPE_DPC_RNEW0",
+               "IPIPE_DPC_RNEW1",
+               "30",
+               "OCP_ERR",
+       };
+       unsigned int i;
+
+       dev_dbg(iss->dev, "ISP IRQ: ");
+
+       for (i = 0; i < ARRAY_SIZE(name); i++) {
+               if ((1 << i) & irqstatus)
+                       pr_cont("%s ", name[i]);
+       }
+       pr_cont("\n");
+}
+#endif
+
+/*
+ * iss_isr - Interrupt Service Routine for ISS module.
+ * @irq: Not used currently.
+ * @_iss: Pointer to the OMAP4 ISS device
+ *
+ * Handles the corresponding callback if plugged in.
+ *
+ * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
+ * IRQ wasn't handled.
+ */
+static irqreturn_t iss_isr(int irq, void *_iss)
+{
+       static const u32 ipipeif_events = ISP5_IRQ_IPIPEIF_IRQ |
+                                         ISP5_IRQ_ISIF_INT(0);
+       static const u32 resizer_events = ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR |
+                                         ISP5_IRQ_RSZ_FIFO_OVF |
+                                         ISP5_IRQ_RSZ_INT_DMA;
+       struct iss_device *iss = _iss;
+       u32 irqstatus;
+
+       irqstatus = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5));
+       iss_reg_write(iss, OMAP4_ISS_MEM_TOP, ISS_HL_IRQSTATUS(5), irqstatus);
+
+       if (irqstatus & ISS_HL_IRQ_CSIA)
+               omap4iss_csi2_isr(&iss->csi2a);
+
+       if (irqstatus & ISS_HL_IRQ_CSIB)
+               omap4iss_csi2_isr(&iss->csi2b);
+
+       if (irqstatus & ISS_HL_IRQ_ISP(0)) {
+               u32 isp_irqstatus = iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1,
+                                                ISP5_IRQSTATUS(0));
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_IRQSTATUS(0),
+                             isp_irqstatus);
+
+               if (isp_irqstatus & ISP5_IRQ_OCP_ERR)
+                       dev_dbg(iss->dev, "ISP5 OCP Error!\n");
+
+               if (isp_irqstatus & ipipeif_events) {
+                       omap4iss_ipipeif_isr(&iss->ipipeif,
+                                            isp_irqstatus & ipipeif_events);
+               }
+
+               if (isp_irqstatus & resizer_events)
+                       omap4iss_resizer_isr(&iss->resizer,
+                                            isp_irqstatus & resizer_events);
+
+#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
+               iss_isp_isr_dbg(iss, isp_irqstatus);
+#endif
+       }
+
+       omap4iss_flush(iss);
+
+#if defined(DEBUG) && defined(ISS_ISR_DEBUG)
+       iss_isr_dbg(iss, irqstatus);
+#endif
+
+       return IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline power management
+ *
+ * Entities must be powered up when part of a pipeline that contains at least
+ * one open video device node.
+ *
+ * To achieve this use the entity use_count field to track the number of users.
+ * For entities corresponding to video device nodes the use_count field stores
+ * the users count of the node. For entities corresponding to subdevs the
+ * use_count field stores the total number of users of all video device nodes
+ * in the pipeline.
+ *
+ * The omap4iss_pipeline_pm_use() function must be called in the open() and
+ * close() handlers of video device nodes. It increments or decrements the use
+ * count of all subdev entities in the pipeline.
+ *
+ * To react to link management on powered pipelines, the link setup notification
+ * callback updates the use count of all entities in the source and sink sides
+ * of the link.
+ */
+
+/*
+ * iss_pipeline_pm_use_count - Count the number of users of a pipeline
+ * @entity: The entity
+ *
+ * Return the total number of users of all video device nodes in the pipeline.
+ */
+static int iss_pipeline_pm_use_count(struct media_entity *entity)
+{
+       struct media_entity_graph graph;
+       int use = 0;
+
+       media_entity_graph_walk_start(&graph, entity);
+
+       while ((entity = media_entity_graph_walk_next(&graph))) {
+               if (media_entity_type(entity) == MEDIA_ENT_T_DEVNODE)
+                       use += entity->use_count;
+       }
+
+       return use;
+}
+
+/*
+ * iss_pipeline_pm_power_one - Apply power change to an entity
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Change the entity use count by @change. If the entity is a subdev update its
+ * power state by calling the core::s_power operation when the use count goes
+ * from 0 to != 0 or from != 0 to 0.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int iss_pipeline_pm_power_one(struct media_entity *entity, int change)
+{
+       struct v4l2_subdev *subdev;
+
+       subdev = media_entity_type(entity) == MEDIA_ENT_T_V4L2_SUBDEV
+              ? media_entity_to_v4l2_subdev(entity) : NULL;
+
+       if (entity->use_count == 0 && change > 0 && subdev != NULL) {
+               int ret;
+
+               ret = v4l2_subdev_call(subdev, core, s_power, 1);
+               if (ret < 0 && ret != -ENOIOCTLCMD)
+                       return ret;
+       }
+
+       entity->use_count += change;
+       WARN_ON(entity->use_count < 0);
+
+       if (entity->use_count == 0 && change < 0 && subdev != NULL)
+               v4l2_subdev_call(subdev, core, s_power, 0);
+
+       return 0;
+}
+
+/*
+ * iss_pipeline_pm_power - Apply power change to all entities in a pipeline
+ * @entity: The entity
+ * @change: Use count change
+ *
+ * Walk the pipeline to update the use count and the power state of all non-node
+ * entities.
+ *
+ * Return 0 on success or a negative error code on failure.
+ */
+static int iss_pipeline_pm_power(struct media_entity *entity, int change)
+{
+       struct media_entity_graph graph;
+       struct media_entity *first = entity;
+       int ret = 0;
+
+       if (!change)
+               return 0;
+
+       media_entity_graph_walk_start(&graph, entity);
+
+       while (!ret && (entity = media_entity_graph_walk_next(&graph)))
+               if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+                       ret = iss_pipeline_pm_power_one(entity, change);
+
+       if (!ret)
+               return 0;
+
+       media_entity_graph_walk_start(&graph, first);
+
+       while ((first = media_entity_graph_walk_next(&graph))
+              && first != entity)
+               if (media_entity_type(first) != MEDIA_ENT_T_DEVNODE)
+                       iss_pipeline_pm_power_one(first, -change);
+
+       return ret;
+}
+
+/*
+ * omap4iss_pipeline_pm_use - Update the use count of an entity
+ * @entity: The entity
+ * @use: Use (1) or stop using (0) the entity
+ *
+ * Update the use count of all entities in the pipeline and power entities on or
+ * off accordingly.
+ *
+ * Return 0 on success or a negative error code on failure. Powering entities
+ * off is assumed to never fail. No failure can occur when the use parameter is
+ * set to 0.
+ */
+int omap4iss_pipeline_pm_use(struct media_entity *entity, int use)
+{
+       int change = use ? 1 : -1;
+       int ret;
+
+       mutex_lock(&entity->parent->graph_mutex);
+
+       /* Apply use count to node. */
+       entity->use_count += change;
+       WARN_ON(entity->use_count < 0);
+
+       /* Apply power change to connected non-nodes. */
+       ret = iss_pipeline_pm_power(entity, change);
+       if (ret < 0)
+               entity->use_count -= change;
+
+       mutex_unlock(&entity->parent->graph_mutex);
+
+       return ret;
+}
+
+/*
+ * iss_pipeline_link_notify - Link management notification callback
+ * @link: The link
+ * @flags: New link flags that will be applied
+ *
+ * React to link management on powered pipelines by updating the use count of
+ * all entities in the source and sink sides of the link. Entities are powered
+ * on or off accordingly.
+ *
+ * Return 0 on success or a negative error code on failure. Powering entities
+ * off is assumed to never fail. This function will not fail for disconnection
+ * events.
+ */
+static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
+                                   unsigned int notification)
+{
+       struct media_entity *source = link->source->entity;
+       struct media_entity *sink = link->sink->entity;
+       int source_use = iss_pipeline_pm_use_count(source);
+       int sink_use = iss_pipeline_pm_use_count(sink);
+       int ret;
+
+       if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+           !(link->flags & MEDIA_LNK_FL_ENABLED)) {
+               /* Powering off entities is assumed to never fail. */
+               iss_pipeline_pm_power(source, -sink_use);
+               iss_pipeline_pm_power(sink, -source_use);
+               return 0;
+       }
+
+       if (notification == MEDIA_DEV_NOTIFY_POST_LINK_CH &&
+               (flags & MEDIA_LNK_FL_ENABLED)) {
+               ret = iss_pipeline_pm_power(source, sink_use);
+               if (ret < 0)
+                       return ret;
+
+               ret = iss_pipeline_pm_power(sink, source_use);
+               if (ret < 0)
+                       iss_pipeline_pm_power(source, -sink_use);
+
+               return ret;
+       }
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Pipeline stream management
+ */
+
+/*
+ * iss_pipeline_enable - Enable streaming on a pipeline
+ * @pipe: ISS pipeline
+ * @mode: Stream mode (single shot or continuous)
+ *
+ * Walk the entities chain starting at the pipeline output video node and start
+ * all modules in the chain in the given mode.
+ *
+ * Return 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise.
+ */
+static int iss_pipeline_enable(struct iss_pipeline *pipe,
+                              enum iss_pipeline_stream_state mode)
+{
+       struct iss_device *iss = pipe->output->iss;
+       struct media_entity *entity;
+       struct media_pad *pad;
+       struct v4l2_subdev *subdev;
+       unsigned long flags;
+       int ret;
+
+       /* If one of the entities in the pipeline has crashed it will not work
+        * properly. Refuse to start streaming in that case. This check must be
+        * performed before the loop below to avoid starting entities if the
+        * pipeline won't start anyway (those entities would then likely fail to
+        * stop, making the problem worse).
+        */
+       if (pipe->entities & iss->crashed)
+               return -EIO;
+
+       spin_lock_irqsave(&pipe->lock, flags);
+       pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
+       spin_unlock_irqrestore(&pipe->lock, flags);
+
+       pipe->do_propagation = false;
+
+       entity = &pipe->output->video.entity;
+       while (1) {
+               pad = &entity->pads[0];
+               if (!(pad->flags & MEDIA_PAD_FL_SINK))
+                       break;
+
+               pad = media_entity_remote_pad(pad);
+               if (pad == NULL ||
+                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+                       break;
+
+               entity = pad->entity;
+               subdev = media_entity_to_v4l2_subdev(entity);
+
+               ret = v4l2_subdev_call(subdev, video, s_stream, mode);
+               if (ret < 0 && ret != -ENOIOCTLCMD)
+                       return ret;
+       }
+       iss_print_status(pipe->output->iss);
+       return 0;
+}
+
+/*
+ * iss_pipeline_disable - Disable streaming on a pipeline
+ * @pipe: ISS pipeline
+ *
+ * Walk the entities chain starting at the pipeline output video node and stop
+ * all modules in the chain. Wait synchronously for the modules to be stopped if
+ * necessary.
+ */
+static int iss_pipeline_disable(struct iss_pipeline *pipe)
+{
+       struct iss_device *iss = pipe->output->iss;
+       struct media_entity *entity;
+       struct media_pad *pad;
+       struct v4l2_subdev *subdev;
+       int failure = 0;
+       int ret;
+
+       entity = &pipe->output->video.entity;
+       while (1) {
+               pad = &entity->pads[0];
+               if (!(pad->flags & MEDIA_PAD_FL_SINK))
+                       break;
+
+               pad = media_entity_remote_pad(pad);
+               if (pad == NULL ||
+                   media_entity_type(pad->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+                       break;
+
+               entity = pad->entity;
+               subdev = media_entity_to_v4l2_subdev(entity);
+
+               ret = v4l2_subdev_call(subdev, video, s_stream, 0);
+               if (ret < 0) {
+                       dev_dbg(iss->dev, "%s: module stop timeout.\n",
+                               subdev->name);
+                       /* If the entity failed to stopped, assume it has
+                        * crashed. Mark it as such, the ISS will be reset when
+                        * applications will release it.
+                        */
+                       iss->crashed |= 1U << subdev->entity.id;
+                       failure = -ETIMEDOUT;
+               }
+       }
+
+       return failure;
+}
+
+/*
+ * omap4iss_pipeline_set_stream - Enable/disable streaming on a pipeline
+ * @pipe: ISS pipeline
+ * @state: Stream state (stopped, single shot or continuous)
+ *
+ * Set the pipeline to the given stream state. Pipelines can be started in
+ * single-shot or continuous mode.
+ *
+ * Return 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise. The pipeline state is not updated when the operation
+ * fails, except when stopping the pipeline.
+ */
+int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
+                                enum iss_pipeline_stream_state state)
+{
+       int ret;
+
+       if (state == ISS_PIPELINE_STREAM_STOPPED)
+               ret = iss_pipeline_disable(pipe);
+       else
+               ret = iss_pipeline_enable(pipe, state);
+
+       if (ret == 0 || state == ISS_PIPELINE_STREAM_STOPPED)
+               pipe->stream_state = state;
+
+       return ret;
+}
+
+/*
+ * omap4iss_pipeline_cancel_stream - Cancel stream on a pipeline
+ * @pipe: ISS pipeline
+ *
+ * Cancelling a stream mark all buffers on all video nodes in the pipeline as
+ * erroneous and makes sure no new buffer can be queued. This function is called
+ * when a fatal error that prevents any further operation on the pipeline
+ * occurs.
+ */
+void omap4iss_pipeline_cancel_stream(struct iss_pipeline *pipe)
+{
+       if (pipe->input)
+               omap4iss_video_cancel_stream(pipe->input);
+       if (pipe->output)
+               omap4iss_video_cancel_stream(pipe->output);
+}
+
+/*
+ * iss_pipeline_is_last - Verify if entity has an enabled link to the output
+ *                       video node
+ * @me: ISS module's media entity
+ *
+ * Returns 1 if the entity has an enabled link to the output video node or 0
+ * otherwise. It's true only while pipeline can have no more than one output
+ * node.
+ */
+static int iss_pipeline_is_last(struct media_entity *me)
+{
+       struct iss_pipeline *pipe;
+       struct media_pad *pad;
+
+       if (!me->pipe)
+               return 0;
+       pipe = to_iss_pipeline(me);
+       if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED)
+               return 0;
+       pad = media_entity_remote_pad(&pipe->output->pad);
+       return pad->entity == me;
+}
+
+static int iss_reset(struct iss_device *iss)
+{
+       unsigned long timeout = 0;
+
+       iss_reg_set(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG,
+                   ISS_HL_SYSCONFIG_SOFTRESET);
+
+       while (iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_SYSCONFIG) &
+              ISS_HL_SYSCONFIG_SOFTRESET) {
+               if (timeout++ > 100) {
+                       dev_alert(iss->dev, "cannot reset ISS\n");
+                       return -ETIMEDOUT;
+               }
+               usleep_range(10, 10);
+       }
+
+       iss->crashed = 0;
+       return 0;
+}
+
+static int iss_isp_reset(struct iss_device *iss)
+{
+       unsigned long timeout = 0;
+
+       /* Fist, ensure that the ISP is IDLE (no transactions happening) */
+       iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG,
+                      ISP5_SYSCONFIG_STANDBYMODE_MASK,
+                      ISP5_SYSCONFIG_STANDBYMODE_SMART);
+
+       iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL, ISP5_CTRL_MSTANDBY);
+
+       for (;;) {
+               if (iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL) &
+                   ISP5_CTRL_MSTANDBY_WAIT)
+                       break;
+               if (timeout++ > 1000) {
+                       dev_alert(iss->dev, "cannot set ISP5 to standby\n");
+                       return -ETIMEDOUT;
+               }
+               usleep_range(1000, 1500);
+       }
+
+       /* Now finally, do the reset */
+       iss_reg_set(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG,
+                   ISP5_SYSCONFIG_SOFTRESET);
+
+       timeout = 0;
+       while (iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_SYSCONFIG) &
+              ISP5_SYSCONFIG_SOFTRESET) {
+               if (timeout++ > 1000) {
+                       dev_alert(iss->dev, "cannot reset ISP5\n");
+                       return -ETIMEDOUT;
+               }
+               usleep_range(1000, 1500);
+       }
+
+       return 0;
+}
+
+/*
+ * iss_module_sync_idle - Helper to sync module with its idle state
+ * @me: ISS submodule's media entity
+ * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
+ * @stopping: flag which tells module wants to stop
+ *
+ * This function checks if ISS submodule needs to wait for next interrupt. If
+ * yes, makes the caller to sleep while waiting for such event.
+ */
+int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
+                             atomic_t *stopping)
+{
+       struct iss_pipeline *pipe = to_iss_pipeline(me);
+       struct iss_video *video = pipe->output;
+       unsigned long flags;
+
+       if (pipe->stream_state == ISS_PIPELINE_STREAM_STOPPED ||
+           (pipe->stream_state == ISS_PIPELINE_STREAM_SINGLESHOT &&
+            !iss_pipeline_ready(pipe)))
+               return 0;
+
+       /*
+        * atomic_set() doesn't include memory barrier on ARM platform for SMP
+        * scenario. We'll call it here to avoid race conditions.
+        */
+       atomic_set(stopping, 1);
+       smp_wmb();
+
+       /*
+        * If module is the last one, it's writing to memory. In this case,
+        * it's necessary to check if the module is already paused due to
+        * DMA queue underrun or if it has to wait for next interrupt to be
+        * idle.
+        * If it isn't the last one, the function won't sleep but *stopping
+        * will still be set to warn next submodule caller's interrupt the
+        * module wants to be idle.
+        */
+       if (!iss_pipeline_is_last(me))
+               return 0;
+
+       spin_lock_irqsave(&video->qlock, flags);
+       if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) {
+               spin_unlock_irqrestore(&video->qlock, flags);
+               atomic_set(stopping, 0);
+               smp_wmb();
+               return 0;
+       }
+       spin_unlock_irqrestore(&video->qlock, flags);
+       if (!wait_event_timeout(*wait, !atomic_read(stopping),
+                               msecs_to_jiffies(1000))) {
+               atomic_set(stopping, 0);
+               smp_wmb();
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+/*
+ * omap4iss_module_sync_is_stopped - Helper to verify if module was stopping
+ * @wait: ISS submodule's wait queue for streamoff/interrupt synchronization
+ * @stopping: flag which tells module wants to stop
+ *
+ * This function checks if ISS submodule was stopping. In case of yes, it
+ * notices the caller by setting stopping to 0 and waking up the wait queue.
+ * Returns 1 if it was stopping or 0 otherwise.
+ */
+int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait,
+                                    atomic_t *stopping)
+{
+       if (atomic_cmpxchg(stopping, 1, 0)) {
+               wake_up(wait);
+               return 1;
+       }
+
+       return 0;
+}
+
+/* --------------------------------------------------------------------------
+ * Clock management
+ */
+
+#define ISS_CLKCTRL_MASK       (ISS_CLKCTRL_CSI2_A |\
+                                ISS_CLKCTRL_CSI2_B |\
+                                ISS_CLKCTRL_ISP)
+
+static int __iss_subclk_update(struct iss_device *iss)
+{
+       u32 clk = 0;
+       int ret = 0, timeout = 1000;
+
+       if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_A)
+               clk |= ISS_CLKCTRL_CSI2_A;
+
+       if (iss->subclk_resources & OMAP4_ISS_SUBCLK_CSI2_B)
+               clk |= ISS_CLKCTRL_CSI2_B;
+
+       if (iss->subclk_resources & OMAP4_ISS_SUBCLK_ISP)
+               clk |= ISS_CLKCTRL_ISP;
+
+       iss_reg_update(iss, OMAP4_ISS_MEM_TOP, ISS_CLKCTRL,
+                      ISS_CLKCTRL_MASK, clk);
+
+       /* Wait for HW assertion */
+       while (--timeout > 0) {
+               udelay(1);
+               if ((iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_CLKSTAT) &
+                   ISS_CLKCTRL_MASK) == clk)
+                       break;
+       }
+
+       if (!timeout)
+               ret = -EBUSY;
+
+       return ret;
+}
+
+int omap4iss_subclk_enable(struct iss_device *iss,
+                           enum iss_subclk_resource res)
+{
+       iss->subclk_resources |= res;
+
+       return __iss_subclk_update(iss);
+}
+
+int omap4iss_subclk_disable(struct iss_device *iss,
+                            enum iss_subclk_resource res)
+{
+       iss->subclk_resources &= ~res;
+
+       return __iss_subclk_update(iss);
+}
+
+#define ISS_ISP5_CLKCTRL_MASK  (ISP5_CTRL_BL_CLK_ENABLE |\
+                                ISP5_CTRL_ISIF_CLK_ENABLE |\
+                                ISP5_CTRL_H3A_CLK_ENABLE |\
+                                ISP5_CTRL_RSZ_CLK_ENABLE |\
+                                ISP5_CTRL_IPIPE_CLK_ENABLE |\
+                                ISP5_CTRL_IPIPEIF_CLK_ENABLE)
+
+static void __iss_isp_subclk_update(struct iss_device *iss)
+{
+       u32 clk = 0;
+
+       if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_ISIF)
+               clk |= ISP5_CTRL_ISIF_CLK_ENABLE;
+
+       if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_H3A)
+               clk |= ISP5_CTRL_H3A_CLK_ENABLE;
+
+       if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_RSZ)
+               clk |= ISP5_CTRL_RSZ_CLK_ENABLE;
+
+       if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPE)
+               clk |= ISP5_CTRL_IPIPE_CLK_ENABLE;
+
+       if (iss->isp_subclk_resources & OMAP4_ISS_ISP_SUBCLK_IPIPEIF)
+               clk |= ISP5_CTRL_IPIPEIF_CLK_ENABLE;
+
+       if (clk)
+               clk |= ISP5_CTRL_BL_CLK_ENABLE;
+
+       iss_reg_update(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_CTRL,
+                      ISS_ISP5_CLKCTRL_MASK, clk);
+}
+
+void omap4iss_isp_subclk_enable(struct iss_device *iss,
+                               enum iss_isp_subclk_resource res)
+{
+       iss->isp_subclk_resources |= res;
+
+       __iss_isp_subclk_update(iss);
+}
+
+void omap4iss_isp_subclk_disable(struct iss_device *iss,
+                                enum iss_isp_subclk_resource res)
+{
+       iss->isp_subclk_resources &= ~res;
+
+       __iss_isp_subclk_update(iss);
+}
+
+/*
+ * iss_enable_clocks - Enable ISS clocks
+ * @iss: OMAP4 ISS device
+ *
+ * Return 0 if successful, or clk_enable return value if any of tthem fails.
+ */
+static int iss_enable_clocks(struct iss_device *iss)
+{
+       int ret;
+
+       ret = clk_enable(iss->iss_fck);
+       if (ret) {
+               dev_err(iss->dev, "clk_enable iss_fck failed\n");
+               return ret;
+       }
+
+       ret = clk_enable(iss->iss_ctrlclk);
+       if (ret) {
+               dev_err(iss->dev, "clk_enable iss_ctrlclk failed\n");
+               clk_disable(iss->iss_fck);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+ * iss_disable_clocks - Disable ISS clocks
+ * @iss: OMAP4 ISS device
+ */
+static void iss_disable_clocks(struct iss_device *iss)
+{
+       clk_disable(iss->iss_ctrlclk);
+       clk_disable(iss->iss_fck);
+}
+
+static void iss_put_clocks(struct iss_device *iss)
+{
+       if (iss->iss_fck) {
+               clk_put(iss->iss_fck);
+               iss->iss_fck = NULL;
+       }
+
+       if (iss->iss_ctrlclk) {
+               clk_put(iss->iss_ctrlclk);
+               iss->iss_ctrlclk = NULL;
+       }
+}
+
+static int iss_get_clocks(struct iss_device *iss)
+{
+       iss->iss_fck = clk_get(iss->dev, "iss_fck");
+       if (IS_ERR(iss->iss_fck)) {
+               dev_err(iss->dev, "Unable to get iss_fck clock info\n");
+               iss_put_clocks(iss);
+               return PTR_ERR(iss->iss_fck);
+       }
+
+       iss->iss_ctrlclk = clk_get(iss->dev, "iss_ctrlclk");
+       if (IS_ERR(iss->iss_ctrlclk)) {
+               dev_err(iss->dev, "Unable to get iss_ctrlclk clock info\n");
+               iss_put_clocks(iss);
+               return PTR_ERR(iss->iss_fck);
+       }
+
+       return 0;
+}
+
+/*
+ * omap4iss_get - Acquire the ISS resource.
+ *
+ * Initializes the clocks for the first acquire.
+ *
+ * Increment the reference count on the ISS. If the first reference is taken,
+ * enable clocks and power-up all submodules.
+ *
+ * Return a pointer to the ISS device structure, or NULL if an error occurred.
+ */
+struct iss_device *omap4iss_get(struct iss_device *iss)
+{
+       struct iss_device *__iss = iss;
+
+       if (iss == NULL)
+               return NULL;
+
+       mutex_lock(&iss->iss_mutex);
+       if (iss->ref_count > 0)
+               goto out;
+
+       if (iss_enable_clocks(iss) < 0) {
+               __iss = NULL;
+               goto out;
+       }
+
+       iss_enable_interrupts(iss);
+
+out:
+       if (__iss != NULL)
+               iss->ref_count++;
+       mutex_unlock(&iss->iss_mutex);
+
+       return __iss;
+}
+
+/*
+ * omap4iss_put - Release the ISS
+ *
+ * Decrement the reference count on the ISS. If the last reference is released,
+ * power-down all submodules, disable clocks and free temporary buffers.
+ */
+void omap4iss_put(struct iss_device *iss)
+{
+       if (iss == NULL)
+               return;
+
+       mutex_lock(&iss->iss_mutex);
+       BUG_ON(iss->ref_count == 0);
+       if (--iss->ref_count == 0) {
+               iss_disable_interrupts(iss);
+               /* Reset the ISS if an entity has failed to stop. This is the
+                * only way to recover from such conditions, although it would
+                * be worth investigating whether resetting the ISP only can't
+                * fix the problem in some cases.
+                */
+               if (iss->crashed)
+                       iss_reset(iss);
+               iss_disable_clocks(iss);
+       }
+       mutex_unlock(&iss->iss_mutex);
+}
+
+static int iss_map_mem_resource(struct platform_device *pdev,
+                               struct iss_device *iss,
+                               enum iss_mem_resources res)
+{
+       struct resource *mem;
+
+       /* request the mem region for the camera registers */
+
+       mem = platform_get_resource(pdev, IORESOURCE_MEM, res);
+       if (!mem) {
+               dev_err(iss->dev, "no mem resource?\n");
+               return -ENODEV;
+       }
+
+       if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
+               dev_err(iss->dev,
+                       "cannot reserve camera register I/O region\n");
+               return -ENODEV;
+       }
+       iss->res[res] = mem;
+
+       /* map the region */
+       iss->regs[res] = ioremap_nocache(mem->start, resource_size(mem));
+       if (!iss->regs[res]) {
+               dev_err(iss->dev, "cannot map camera register I/O region\n");
+               return -ENODEV;
+       }
+
+       return 0;
+}
+
+static void iss_unregister_entities(struct iss_device *iss)
+{
+       omap4iss_resizer_unregister_entities(&iss->resizer);
+       omap4iss_ipipe_unregister_entities(&iss->ipipe);
+       omap4iss_ipipeif_unregister_entities(&iss->ipipeif);
+       omap4iss_csi2_unregister_entities(&iss->csi2a);
+       omap4iss_csi2_unregister_entities(&iss->csi2b);
+
+       v4l2_device_unregister(&iss->v4l2_dev);
+       media_device_unregister(&iss->media_dev);
+}
+
+/*
+ * iss_register_subdev_group - Register a group of subdevices
+ * @iss: OMAP4 ISS device
+ * @board_info: I2C subdevs board information array
+ *
+ * Register all I2C subdevices in the board_info array. The array must be
+ * terminated by a NULL entry, and the first entry must be the sensor.
+ *
+ * Return a pointer to the sensor media entity if it has been successfully
+ * registered, or NULL otherwise.
+ */
+static struct v4l2_subdev *
+iss_register_subdev_group(struct iss_device *iss,
+                    struct iss_subdev_i2c_board_info *board_info)
+{
+       struct v4l2_subdev *sensor = NULL;
+       unsigned int first;
+
+       if (board_info->board_info == NULL)
+               return NULL;
+
+       for (first = 1; board_info->board_info; ++board_info, first = 0) {
+               struct v4l2_subdev *subdev;
+               struct i2c_adapter *adapter;
+
+               adapter = i2c_get_adapter(board_info->i2c_adapter_id);
+               if (adapter == NULL) {
+                       dev_err(iss->dev,
+                               "%s: Unable to get I2C adapter %d for device %s\n",
+                               __func__, board_info->i2c_adapter_id,
+                               board_info->board_info->type);
+                       continue;
+               }
+
+               subdev = v4l2_i2c_new_subdev_board(&iss->v4l2_dev, adapter,
+                               board_info->board_info, NULL);
+               if (subdev == NULL) {
+                       dev_err(iss->dev, "%s: Unable to register subdev %s\n",
+                               __func__, board_info->board_info->type);
+                       continue;
+               }
+
+               if (first)
+                       sensor = subdev;
+       }
+
+       return sensor;
+}
+
+static int iss_register_entities(struct iss_device *iss)
+{
+       struct iss_platform_data *pdata = iss->pdata;
+       struct iss_v4l2_subdevs_group *subdevs;
+       int ret;
+
+       iss->media_dev.dev = iss->dev;
+       strlcpy(iss->media_dev.model, "TI OMAP4 ISS",
+               sizeof(iss->media_dev.model));
+       iss->media_dev.hw_revision = iss->revision;
+       iss->media_dev.link_notify = iss_pipeline_link_notify;
+       ret = media_device_register(&iss->media_dev);
+       if (ret < 0) {
+               dev_err(iss->dev, "%s: Media device registration failed (%d)\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       iss->v4l2_dev.mdev = &iss->media_dev;
+       ret = v4l2_device_register(iss->dev, &iss->v4l2_dev);
+       if (ret < 0) {
+               dev_err(iss->dev, "%s: V4L2 device registration failed (%d)\n",
+                       __func__, ret);
+               goto done;
+       }
+
+       /* Register internal entities */
+       ret = omap4iss_csi2_register_entities(&iss->csi2a, &iss->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap4iss_csi2_register_entities(&iss->csi2b, &iss->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap4iss_ipipeif_register_entities(&iss->ipipeif, &iss->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap4iss_ipipe_register_entities(&iss->ipipe, &iss->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       ret = omap4iss_resizer_register_entities(&iss->resizer, &iss->v4l2_dev);
+       if (ret < 0)
+               goto done;
+
+       /* Register external entities */
+       for (subdevs = pdata->subdevs; subdevs && subdevs->subdevs; ++subdevs) {
+               struct v4l2_subdev *sensor;
+               struct media_entity *input;
+               unsigned int flags;
+               unsigned int pad;
+
+               sensor = iss_register_subdev_group(iss, subdevs->subdevs);
+               if (sensor == NULL)
+                       continue;
+
+               sensor->host_priv = subdevs;
+
+               /* Connect the sensor to the correct interface module.
+                * CSI2a receiver through CSIPHY1, or
+                * CSI2b receiver through CSIPHY2
+                */
+               switch (subdevs->interface) {
+               case ISS_INTERFACE_CSI2A_PHY1:
+                       input = &iss->csi2a.subdev.entity;
+                       pad = CSI2_PAD_SINK;
+                       flags = MEDIA_LNK_FL_IMMUTABLE
+                             | MEDIA_LNK_FL_ENABLED;
+                       break;
+
+               case ISS_INTERFACE_CSI2B_PHY2:
+                       input = &iss->csi2b.subdev.entity;
+                       pad = CSI2_PAD_SINK;
+                       flags = MEDIA_LNK_FL_IMMUTABLE
+                             | MEDIA_LNK_FL_ENABLED;
+                       break;
+
+               default:
+                       dev_err(iss->dev, "%s: invalid interface type %u\n",
+                               __func__, subdevs->interface);
+                       ret = -EINVAL;
+                       goto done;
+               }
+
+               ret = media_entity_create_link(&sensor->entity, 0, input, pad,
+                                              flags);
+               if (ret < 0)
+                       goto done;
+       }
+
+       ret = v4l2_device_register_subdev_nodes(&iss->v4l2_dev);
+
+done:
+       if (ret < 0)
+               iss_unregister_entities(iss);
+
+       return ret;
+}
+
+static void iss_cleanup_modules(struct iss_device *iss)
+{
+       omap4iss_csi2_cleanup(iss);
+       omap4iss_ipipeif_cleanup(iss);
+       omap4iss_ipipe_cleanup(iss);
+       omap4iss_resizer_cleanup(iss);
+}
+
+static int iss_initialize_modules(struct iss_device *iss)
+{
+       int ret;
+
+       ret = omap4iss_csiphy_init(iss);
+       if (ret < 0) {
+               dev_err(iss->dev, "CSI PHY initialization failed\n");
+               goto error_csiphy;
+       }
+
+       ret = omap4iss_csi2_init(iss);
+       if (ret < 0) {
+               dev_err(iss->dev, "CSI2 initialization failed\n");
+               goto error_csi2;
+       }
+
+       ret = omap4iss_ipipeif_init(iss);
+       if (ret < 0) {
+               dev_err(iss->dev, "ISP IPIPEIF initialization failed\n");
+               goto error_ipipeif;
+       }
+
+       ret = omap4iss_ipipe_init(iss);
+       if (ret < 0) {
+               dev_err(iss->dev, "ISP IPIPE initialization failed\n");
+               goto error_ipipe;
+       }
+
+       ret = omap4iss_resizer_init(iss);
+       if (ret < 0) {
+               dev_err(iss->dev, "ISP RESIZER initialization failed\n");
+               goto error_resizer;
+       }
+
+       /* Connect the submodules. */
+       ret = media_entity_create_link(
+                       &iss->csi2a.subdev.entity, CSI2_PAD_SOURCE,
+                       &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &iss->csi2b.subdev.entity, CSI2_PAD_SOURCE,
+                       &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
+                       &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &iss->ipipeif.subdev.entity, IPIPEIF_PAD_SOURCE_VP,
+                       &iss->ipipe.subdev.entity, IPIPE_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       ret = media_entity_create_link(
+                       &iss->ipipe.subdev.entity, IPIPE_PAD_SOURCE_VP,
+                       &iss->resizer.subdev.entity, RESIZER_PAD_SINK, 0);
+       if (ret < 0)
+               goto error_link;
+
+       return 0;
+
+error_link:
+       omap4iss_resizer_cleanup(iss);
+error_resizer:
+       omap4iss_ipipe_cleanup(iss);
+error_ipipe:
+       omap4iss_ipipeif_cleanup(iss);
+error_ipipeif:
+       omap4iss_csi2_cleanup(iss);
+error_csi2:
+error_csiphy:
+       return ret;
+}
+
+static int iss_probe(struct platform_device *pdev)
+{
+       struct iss_platform_data *pdata = pdev->dev.platform_data;
+       struct iss_device *iss;
+       unsigned int i;
+       int ret;
+
+       if (pdata == NULL)
+               return -EINVAL;
+
+       iss = kzalloc(sizeof(*iss), GFP_KERNEL);
+       if (!iss) {
+               dev_err(&pdev->dev, "Could not allocate memory\n");
+               return -ENOMEM;
+       }
+
+       mutex_init(&iss->iss_mutex);
+
+       iss->dev = &pdev->dev;
+       iss->pdata = pdata;
+
+       iss->raw_dmamask = DMA_BIT_MASK(32);
+       iss->dev->dma_mask = &iss->raw_dmamask;
+       iss->dev->coherent_dma_mask = DMA_BIT_MASK(32);
+
+       platform_set_drvdata(pdev, iss);
+
+       /* Clocks */
+       ret = iss_map_mem_resource(pdev, iss, OMAP4_ISS_MEM_TOP);
+       if (ret < 0)
+               goto error;
+
+       ret = iss_get_clocks(iss);
+       if (ret < 0)
+               goto error;
+
+       if (omap4iss_get(iss) == NULL)
+               goto error;
+
+       ret = iss_reset(iss);
+       if (ret < 0)
+               goto error_iss;
+
+       iss->revision = iss_reg_read(iss, OMAP4_ISS_MEM_TOP, ISS_HL_REVISION);
+       dev_info(iss->dev, "Revision %08x found\n", iss->revision);
+
+       for (i = 1; i < OMAP4_ISS_MEM_LAST; i++) {
+               ret = iss_map_mem_resource(pdev, iss, i);
+               if (ret)
+                       goto error_iss;
+       }
+
+       /* Configure BTE BW_LIMITER field to max recommended value (1 GB) */
+       iss_reg_update(iss, OMAP4_ISS_MEM_BTE, BTE_CTRL,
+                      BTE_CTRL_BW_LIMITER_MASK,
+                      18 << BTE_CTRL_BW_LIMITER_SHIFT);
+
+       /* Perform ISP reset */
+       ret = omap4iss_subclk_enable(iss, OMAP4_ISS_SUBCLK_ISP);
+       if (ret < 0)
+               goto error_iss;
+
+       ret = iss_isp_reset(iss);
+       if (ret < 0)
+               goto error_iss;
+
+       dev_info(iss->dev, "ISP Revision %08x found\n",
+                iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_REVISION));
+
+       /* Interrupt */
+       iss->irq_num = platform_get_irq(pdev, 0);
+       if (iss->irq_num <= 0) {
+               dev_err(iss->dev, "No IRQ resource\n");
+               ret = -ENODEV;
+               goto error_iss;
+       }
+
+       if (request_irq(iss->irq_num, iss_isr, IRQF_SHARED, "OMAP4 ISS", iss)) {
+               dev_err(iss->dev, "Unable to request IRQ\n");
+               ret = -EINVAL;
+               goto error_iss;
+       }
+
+       /* Entities */
+       ret = iss_initialize_modules(iss);
+       if (ret < 0)
+               goto error_irq;
+
+       ret = iss_register_entities(iss);
+       if (ret < 0)
+               goto error_modules;
+
+       omap4iss_put(iss);
+
+       return 0;
+
+error_modules:
+       iss_cleanup_modules(iss);
+error_irq:
+       free_irq(iss->irq_num, iss);
+error_iss:
+       omap4iss_put(iss);
+error:
+       iss_put_clocks(iss);
+
+       for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) {
+               if (iss->regs[i]) {
+                       iounmap(iss->regs[i]);
+                       iss->regs[i] = NULL;
+               }
+
+               if (iss->res[i]) {
+                       release_mem_region(iss->res[i]->start,
+                                          resource_size(iss->res[i]));
+                       iss->res[i] = NULL;
+               }
+       }
+       platform_set_drvdata(pdev, NULL);
+
+       mutex_destroy(&iss->iss_mutex);
+       kfree(iss);
+
+       return ret;
+}
+
+static int iss_remove(struct platform_device *pdev)
+{
+       struct iss_device *iss = platform_get_drvdata(pdev);
+       unsigned int i;
+
+       iss_unregister_entities(iss);
+       iss_cleanup_modules(iss);
+
+       free_irq(iss->irq_num, iss);
+       iss_put_clocks(iss);
+
+       for (i = 0; i < OMAP4_ISS_MEM_LAST; i++) {
+               if (iss->regs[i]) {
+                       iounmap(iss->regs[i]);
+                       iss->regs[i] = NULL;
+               }
+
+               if (iss->res[i]) {
+                       release_mem_region(iss->res[i]->start,
+                                          resource_size(iss->res[i]));
+                       iss->res[i] = NULL;
+               }
+       }
+
+       kfree(iss);
+
+       return 0;
+}
+
+static struct platform_device_id omap4iss_id_table[] = {
+       { "omap4iss", 0 },
+       { },
+};
+MODULE_DEVICE_TABLE(platform, omap4iss_id_table);
+
+static struct platform_driver iss_driver = {
+       .probe          = iss_probe,
+       .remove         = iss_remove,
+       .id_table       = omap4iss_id_table,
+       .driver = {
+               .owner  = THIS_MODULE,
+               .name   = "omap4iss",
+       },
+};
+
+module_platform_driver(iss_driver);
+
+MODULE_DESCRIPTION("TI OMAP4 ISS driver");
+MODULE_AUTHOR("Sergio Aguirre <sergio.a.aguirre@gmail.com>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ISS_VIDEO_DRIVER_VERSION);
diff --git a/drivers/staging/media/omap4iss/iss.h b/drivers/staging/media/omap4iss/iss.h
new file mode 100644 (file)
index 0000000..346db92
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver
+ *
+ * Copyright (C) 2012 Texas Instruments.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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.
+ */
+
+#ifndef _OMAP4_ISS_H_
+#define _OMAP4_ISS_H_
+
+#include <media/v4l2-device.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/wait.h>
+
+#include <media/omap4iss.h>
+
+#include "iss_regs.h"
+#include "iss_csiphy.h"
+#include "iss_csi2.h"
+#include "iss_ipipeif.h"
+#include "iss_ipipe.h"
+#include "iss_resizer.h"
+
+#define to_iss_device(ptr_module)                              \
+       container_of(ptr_module, struct iss_device, ptr_module)
+#define to_device(ptr_module)                                          \
+       (to_iss_device(ptr_module)->dev)
+
+enum iss_mem_resources {
+       OMAP4_ISS_MEM_TOP,
+       OMAP4_ISS_MEM_CSI2_A_REGS1,
+       OMAP4_ISS_MEM_CAMERARX_CORE1,
+       OMAP4_ISS_MEM_CSI2_B_REGS1,
+       OMAP4_ISS_MEM_CAMERARX_CORE2,
+       OMAP4_ISS_MEM_BTE,
+       OMAP4_ISS_MEM_ISP_SYS1,
+       OMAP4_ISS_MEM_ISP_RESIZER,
+       OMAP4_ISS_MEM_ISP_IPIPE,
+       OMAP4_ISS_MEM_ISP_ISIF,
+       OMAP4_ISS_MEM_ISP_IPIPEIF,
+       OMAP4_ISS_MEM_LAST,
+};
+
+enum iss_subclk_resource {
+       OMAP4_ISS_SUBCLK_SIMCOP         = (1 << 0),
+       OMAP4_ISS_SUBCLK_ISP            = (1 << 1),
+       OMAP4_ISS_SUBCLK_CSI2_A         = (1 << 2),
+       OMAP4_ISS_SUBCLK_CSI2_B         = (1 << 3),
+       OMAP4_ISS_SUBCLK_CCP2           = (1 << 4),
+};
+
+enum iss_isp_subclk_resource {
+       OMAP4_ISS_ISP_SUBCLK_BL         = (1 << 0),
+       OMAP4_ISS_ISP_SUBCLK_ISIF       = (1 << 1),
+       OMAP4_ISS_ISP_SUBCLK_H3A        = (1 << 2),
+       OMAP4_ISS_ISP_SUBCLK_RSZ        = (1 << 3),
+       OMAP4_ISS_ISP_SUBCLK_IPIPE      = (1 << 4),
+       OMAP4_ISS_ISP_SUBCLK_IPIPEIF    = (1 << 5),
+};
+
+/*
+ * struct iss_reg - Structure for ISS register values.
+ * @reg: 32-bit Register address.
+ * @val: 32-bit Register value.
+ */
+struct iss_reg {
+       enum iss_mem_resources mmio_range;
+       u32 reg;
+       u32 val;
+};
+
+/*
+ * struct iss_device - ISS device structure.
+ * @crashed: Bitmask of crashed entities (indexed by entity ID)
+ */
+struct iss_device {
+       struct v4l2_device v4l2_dev;
+       struct media_device media_dev;
+       struct device *dev;
+       u32 revision;
+
+       /* platform HW resources */
+       struct iss_platform_data *pdata;
+       unsigned int irq_num;
+
+       struct resource *res[OMAP4_ISS_MEM_LAST];
+       void __iomem *regs[OMAP4_ISS_MEM_LAST];
+
+       u64 raw_dmamask;
+
+       struct mutex iss_mutex; /* For handling ref_count field */
+       bool crashed;
+       int has_context;
+       int ref_count;
+
+       struct clk *iss_fck;
+       struct clk *iss_ctrlclk;
+
+       /* ISS modules */
+       struct iss_csi2_device csi2a;
+       struct iss_csi2_device csi2b;
+       struct iss_csiphy csiphy1;
+       struct iss_csiphy csiphy2;
+       struct iss_ipipeif_device ipipeif;
+       struct iss_ipipe_device ipipe;
+       struct iss_resizer_device resizer;
+
+       unsigned int subclk_resources;
+       unsigned int isp_subclk_resources;
+};
+
+#define v4l2_dev_to_iss_device(dev) \
+       container_of(dev, struct iss_device, v4l2_dev)
+
+int omap4iss_get_external_info(struct iss_pipeline *pipe,
+                              struct media_link *link);
+
+int omap4iss_module_sync_idle(struct media_entity *me, wait_queue_head_t *wait,
+                             atomic_t *stopping);
+
+int omap4iss_module_sync_is_stopping(wait_queue_head_t *wait,
+                                    atomic_t *stopping);
+
+int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
+                                enum iss_pipeline_stream_state state);
+void omap4iss_pipeline_cancel_stream(struct iss_pipeline *pipe);
+
+void omap4iss_configure_bridge(struct iss_device *iss,
+                              enum ipipeif_input_entity input);
+
+struct iss_device *omap4iss_get(struct iss_device *iss);
+void omap4iss_put(struct iss_device *iss);
+int omap4iss_subclk_enable(struct iss_device *iss,
+                          enum iss_subclk_resource res);
+int omap4iss_subclk_disable(struct iss_device *iss,
+                           enum iss_subclk_resource res);
+void omap4iss_isp_subclk_enable(struct iss_device *iss,
+                               enum iss_isp_subclk_resource res);
+void omap4iss_isp_subclk_disable(struct iss_device *iss,
+                                enum iss_isp_subclk_resource res);
+
+int omap4iss_pipeline_pm_use(struct media_entity *entity, int use);
+
+int omap4iss_register_entities(struct platform_device *pdev,
+                              struct v4l2_device *v4l2_dev);
+void omap4iss_unregister_entities(struct platform_device *pdev);
+
+/*
+ * iss_reg_read - Read the value of an OMAP4 ISS register
+ * @iss: the ISS device
+ * @res: memory resource in which the register is located
+ * @offset: register offset in the memory resource
+ *
+ * Return the register value.
+ */
+static inline
+u32 iss_reg_read(struct iss_device *iss, enum iss_mem_resources res,
+                u32 offset)
+{
+       return readl(iss->regs[res] + offset);
+}
+
+/*
+ * iss_reg_write - Write a value to an OMAP4 ISS register
+ * @iss: the ISS device
+ * @res: memory resource in which the register is located
+ * @offset: register offset in the memory resource
+ * @value: value to be written
+ */
+static inline
+void iss_reg_write(struct iss_device *iss, enum iss_mem_resources res,
+                  u32 offset, u32 value)
+{
+       writel(value, iss->regs[res] + offset);
+}
+
+/*
+ * iss_reg_clr - Clear bits in an OMAP4 ISS register
+ * @iss: the ISS device
+ * @res: memory resource in which the register is located
+ * @offset: register offset in the memory resource
+ * @clr: bit mask to be cleared
+ */
+static inline
+void iss_reg_clr(struct iss_device *iss, enum iss_mem_resources res,
+                u32 offset, u32 clr)
+{
+       u32 v = iss_reg_read(iss, res, offset);
+
+       iss_reg_write(iss, res, offset, v & ~clr);
+}
+
+/*
+ * iss_reg_set - Set bits in an OMAP4 ISS register
+ * @iss: the ISS device
+ * @res: memory resource in which the register is located
+ * @offset: register offset in the memory resource
+ * @set: bit mask to be set
+ */
+static inline
+void iss_reg_set(struct iss_device *iss, enum iss_mem_resources res,
+                u32 offset, u32 set)
+{
+       u32 v = iss_reg_read(iss, res, offset);
+
+       iss_reg_write(iss, res, offset, v | set);
+}
+
+/*
+ * iss_reg_update - Clear and set bits in an OMAP4 ISS register
+ * @iss: the ISS device
+ * @res: memory resource in which the register is located
+ * @offset: register offset in the memory resource
+ * @clr: bit mask to be cleared
+ * @set: bit mask to be set
+ *
+ * Clear the clr mask first and then set the set mask.
+ */
+static inline
+void iss_reg_update(struct iss_device *iss, enum iss_mem_resources res,
+                   u32 offset, u32 clr, u32 set)
+{
+       u32 v = iss_reg_read(iss, res, offset);
+
+       iss_reg_write(iss, res, offset, (v & ~clr) | set);
+}
+
+#endif /* _OMAP4_ISS_H_ */
diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c
new file mode 100644 (file)
index 0000000..61fc350
--- /dev/null
@@ -0,0 +1,1343 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - CSI PHY module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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 <linux/delay.h>
+#include <media/v4l2-common.h>
+#include <linux/v4l2-mediabus.h>
+#include <linux/mm.h>
+
+#include "iss.h"
+#include "iss_regs.h"
+#include "iss_csi2.h"
+
+/*
+ * csi2_if_enable - Enable CSI2 Receiver interface.
+ * @enable: enable flag
+ *
+ */
+static void csi2_if_enable(struct iss_csi2_device *csi2, u8 enable)
+{
+       struct iss_csi2_ctrl_cfg *currctrl = &csi2->ctrl;
+
+       iss_reg_update(csi2->iss, csi2->regs1, CSI2_CTRL, CSI2_CTRL_IF_EN,
+                      enable ? CSI2_CTRL_IF_EN : 0);
+
+       currctrl->if_enable = enable;
+}
+
+/*
+ * csi2_recv_config - CSI2 receiver module configuration.
+ * @currctrl: iss_csi2_ctrl_cfg structure
+ *
+ */
+static void csi2_recv_config(struct iss_csi2_device *csi2,
+                            struct iss_csi2_ctrl_cfg *currctrl)
+{
+       u32 reg = 0;
+
+       if (currctrl->frame_mode)
+               reg |= CSI2_CTRL_FRAME;
+       else
+               reg &= ~CSI2_CTRL_FRAME;
+
+       if (currctrl->vp_clk_enable)
+               reg |= CSI2_CTRL_VP_CLK_EN;
+       else
+               reg &= ~CSI2_CTRL_VP_CLK_EN;
+
+       if (currctrl->vp_only_enable)
+               reg |= CSI2_CTRL_VP_ONLY_EN;
+       else
+               reg &= ~CSI2_CTRL_VP_ONLY_EN;
+
+       reg &= ~CSI2_CTRL_VP_OUT_CTRL_MASK;
+       reg |= currctrl->vp_out_ctrl << CSI2_CTRL_VP_OUT_CTRL_SHIFT;
+
+       if (currctrl->ecc_enable)
+               reg |= CSI2_CTRL_ECC_EN;
+       else
+               reg &= ~CSI2_CTRL_ECC_EN;
+
+       /*
+        * Set MFlag assertion boundaries to:
+        * Low: 4/8 of FIFO size
+        * High: 6/8 of FIFO size
+        */
+       reg &= ~(CSI2_CTRL_MFLAG_LEVH_MASK | CSI2_CTRL_MFLAG_LEVL_MASK);
+       reg |= (2 << CSI2_CTRL_MFLAG_LEVH_SHIFT) |
+              (4 << CSI2_CTRL_MFLAG_LEVL_SHIFT);
+
+       /* Generation of 16x64-bit bursts (Recommended) */
+       reg |= CSI2_CTRL_BURST_SIZE_EXPAND;
+
+       /* Do Non-Posted writes (Recommended) */
+       reg |= CSI2_CTRL_NON_POSTED_WRITE;
+
+       /*
+        * Enforce Little endian for all formats, including:
+        * YUV4:2:2 8-bit and YUV4:2:0 Legacy
+        */
+       reg |= CSI2_CTRL_ENDIANNESS;
+
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTRL, reg);
+}
+
+static const unsigned int csi2_input_fmts[] = {
+       V4L2_MBUS_FMT_SGRBG10_1X10,
+       V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+       V4L2_MBUS_FMT_SRGGB10_1X10,
+       V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
+       V4L2_MBUS_FMT_SBGGR10_1X10,
+       V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
+       V4L2_MBUS_FMT_SGBRG10_1X10,
+       V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
+       V4L2_MBUS_FMT_SBGGR8_1X8,
+       V4L2_MBUS_FMT_SGBRG8_1X8,
+       V4L2_MBUS_FMT_SGRBG8_1X8,
+       V4L2_MBUS_FMT_SRGGB8_1X8,
+       V4L2_MBUS_FMT_UYVY8_1X16,
+       V4L2_MBUS_FMT_YUYV8_1X16,
+};
+
+/* To set the format on the CSI2 requires a mapping function that takes
+ * the following inputs:
+ * - 3 different formats (at this time)
+ * - 2 destinations (mem, vp+mem) (vp only handled separately)
+ * - 2 decompression options (on, off)
+ * Output should be CSI2 frame format code
+ * Array indices as follows: [format][dest][decompr]
+ * Not all combinations are valid. 0 means invalid.
+ */
+static const u16 __csi2_fmt_map[][2][2] = {
+       /* RAW10 formats */
+       {
+               /* Output to memory */
+               {
+                       /* No DPCM decompression */
+                       CSI2_PIX_FMT_RAW10_EXP16,
+                       /* DPCM decompression */
+                       0,
+               },
+               /* Output to both */
+               {
+                       /* No DPCM decompression */
+                       CSI2_PIX_FMT_RAW10_EXP16_VP,
+                       /* DPCM decompression */
+                       0,
+               },
+       },
+       /* RAW10 DPCM8 formats */
+       {
+               /* Output to memory */
+               {
+                       /* No DPCM decompression */
+                       CSI2_USERDEF_8BIT_DATA1,
+                       /* DPCM decompression */
+                       CSI2_USERDEF_8BIT_DATA1_DPCM10,
+               },
+               /* Output to both */
+               {
+                       /* No DPCM decompression */
+                       CSI2_PIX_FMT_RAW8_VP,
+                       /* DPCM decompression */
+                       CSI2_USERDEF_8BIT_DATA1_DPCM10_VP,
+               },
+       },
+       /* RAW8 formats */
+       {
+               /* Output to memory */
+               {
+                       /* No DPCM decompression */
+                       CSI2_PIX_FMT_RAW8,
+                       /* DPCM decompression */
+                       0,
+               },
+               /* Output to both */
+               {
+                       /* No DPCM decompression */
+                       CSI2_PIX_FMT_RAW8_VP,
+                       /* DPCM decompression */
+                       0,
+               },
+       },
+       /* YUV422 formats */
+       {
+               /* Output to memory */
+               {
+                       /* No DPCM decompression */
+                       CSI2_PIX_FMT_YUV422_8BIT,
+                       /* DPCM decompression */
+                       0,
+               },
+               /* Output to both */
+               {
+                       /* No DPCM decompression */
+                       CSI2_PIX_FMT_YUV422_8BIT_VP16,
+                       /* DPCM decompression */
+                       0,
+               },
+       },
+};
+
+/*
+ * csi2_ctx_map_format - Map CSI2 sink media bus format to CSI2 format ID
+ * @csi2: ISS CSI2 device
+ *
+ * Returns CSI2 physical format id
+ */
+static u16 csi2_ctx_map_format(struct iss_csi2_device *csi2)
+{
+       const struct v4l2_mbus_framefmt *fmt = &csi2->formats[CSI2_PAD_SINK];
+       int fmtidx, destidx;
+
+       switch (fmt->code) {
+       case V4L2_MBUS_FMT_SGRBG10_1X10:
+       case V4L2_MBUS_FMT_SRGGB10_1X10:
+       case V4L2_MBUS_FMT_SBGGR10_1X10:
+       case V4L2_MBUS_FMT_SGBRG10_1X10:
+               fmtidx = 0;
+               break;
+       case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
+       case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
+               fmtidx = 1;
+               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:
+               fmtidx = 2;
+               break;
+       case V4L2_MBUS_FMT_UYVY8_1X16:
+       case V4L2_MBUS_FMT_YUYV8_1X16:
+               fmtidx = 3;
+               break;
+       default:
+               WARN(1, KERN_ERR "CSI2: pixel format %08x unsupported!\n",
+                    fmt->code);
+               return 0;
+       }
+
+       if (!(csi2->output & CSI2_OUTPUT_IPIPEIF) &&
+           !(csi2->output & CSI2_OUTPUT_MEMORY)) {
+               /* Neither output enabled is a valid combination */
+               return CSI2_PIX_FMT_OTHERS;
+       }
+
+       /* If we need to skip frames at the beginning of the stream disable the
+        * video port to avoid sending the skipped frames to the IPIPEIF.
+        */
+       destidx = csi2->frame_skip ? 0 : !!(csi2->output & CSI2_OUTPUT_IPIPEIF);
+
+       return __csi2_fmt_map[fmtidx][destidx][csi2->dpcm_decompress];
+}
+
+/*
+ * csi2_set_outaddr - Set memory address to save output image
+ * @csi2: Pointer to ISS CSI2a device.
+ * @addr: 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ *
+ * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
+ * boundary.
+ */
+static void csi2_set_outaddr(struct iss_csi2_device *csi2, u32 addr)
+{
+       struct iss_csi2_ctx_cfg *ctx = &csi2->contexts[0];
+
+       ctx->ping_addr = addr;
+       ctx->pong_addr = addr;
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PING_ADDR(ctx->ctxnum),
+                     ctx->ping_addr);
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PONG_ADDR(ctx->ctxnum),
+                     ctx->pong_addr);
+}
+
+/*
+ * is_usr_def_mapping - Checks whether USER_DEF_MAPPING should
+ *                     be enabled by CSI2.
+ * @format_id: mapped format id
+ *
+ */
+static inline int is_usr_def_mapping(u32 format_id)
+{
+       return (format_id & 0xf0) == 0x40 ? 1 : 0;
+}
+
+/*
+ * csi2_ctx_enable - Enable specified CSI2 context
+ * @ctxnum: Context number, valid between 0 and 7 values.
+ * @enable: enable
+ *
+ */
+static void csi2_ctx_enable(struct iss_csi2_device *csi2, u8 ctxnum, u8 enable)
+{
+       struct iss_csi2_ctx_cfg *ctx = &csi2->contexts[ctxnum];
+       u32 reg;
+
+       reg = iss_reg_read(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctxnum));
+
+       if (enable) {
+               unsigned int skip = 0;
+
+               if (csi2->frame_skip)
+                       skip = csi2->frame_skip;
+               else if (csi2->output & CSI2_OUTPUT_MEMORY)
+                       skip = 1;
+
+               reg &= ~CSI2_CTX_CTRL1_COUNT_MASK;
+               reg |= CSI2_CTX_CTRL1_COUNT_UNLOCK
+                   |  (skip << CSI2_CTX_CTRL1_COUNT_SHIFT)
+                   |  CSI2_CTX_CTRL1_CTX_EN;
+       } else {
+               reg &= ~CSI2_CTX_CTRL1_CTX_EN;
+       }
+
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctxnum), reg);
+       ctx->enabled = enable;
+}
+
+/*
+ * csi2_ctx_config - CSI2 context configuration.
+ * @ctx: context configuration
+ *
+ */
+static void csi2_ctx_config(struct iss_csi2_device *csi2,
+                           struct iss_csi2_ctx_cfg *ctx)
+{
+       u32 reg;
+
+       /* Set up CSI2_CTx_CTRL1 */
+       if (ctx->eof_enabled)
+               reg = CSI2_CTX_CTRL1_EOF_EN;
+
+       if (ctx->eol_enabled)
+               reg |= CSI2_CTX_CTRL1_EOL_EN;
+
+       if (ctx->checksum_enabled)
+               reg |= CSI2_CTX_CTRL1_CS_EN;
+
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL1(ctx->ctxnum), reg);
+
+       /* Set up CSI2_CTx_CTRL2 */
+       reg = ctx->virtual_id << CSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
+       reg |= ctx->format_id << CSI2_CTX_CTRL2_FORMAT_SHIFT;
+
+       if (ctx->dpcm_decompress && ctx->dpcm_predictor)
+               reg |= CSI2_CTX_CTRL2_DPCM_PRED;
+
+       if (is_usr_def_mapping(ctx->format_id))
+               reg |= 2 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT;
+
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL2(ctx->ctxnum), reg);
+
+       /* Set up CSI2_CTx_CTRL3 */
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_CTRL3(ctx->ctxnum),
+                     ctx->alpha << CSI2_CTX_CTRL3_ALPHA_SHIFT);
+
+       /* Set up CSI2_CTx_DAT_OFST */
+       iss_reg_update(csi2->iss, csi2->regs1, CSI2_CTX_DAT_OFST(ctx->ctxnum),
+                      CSI2_CTX_DAT_OFST_MASK, ctx->data_offset);
+
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PING_ADDR(ctx->ctxnum),
+                     ctx->ping_addr);
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_PONG_ADDR(ctx->ctxnum),
+                     ctx->pong_addr);
+}
+
+/*
+ * csi2_timing_config - CSI2 timing configuration.
+ * @timing: csi2_timing_cfg structure
+ */
+static void csi2_timing_config(struct iss_csi2_device *csi2,
+                              struct iss_csi2_timing_cfg *timing)
+{
+       u32 reg;
+
+       reg = iss_reg_read(csi2->iss, csi2->regs1, CSI2_TIMING);
+
+       if (timing->force_rx_mode)
+               reg |= CSI2_TIMING_FORCE_RX_MODE_IO1;
+       else
+               reg &= ~CSI2_TIMING_FORCE_RX_MODE_IO1;
+
+       if (timing->stop_state_16x)
+               reg |= CSI2_TIMING_STOP_STATE_X16_IO1;
+       else
+               reg &= ~CSI2_TIMING_STOP_STATE_X16_IO1;
+
+       if (timing->stop_state_4x)
+               reg |= CSI2_TIMING_STOP_STATE_X4_IO1;
+       else
+               reg &= ~CSI2_TIMING_STOP_STATE_X4_IO1;
+
+       reg &= ~CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK;
+       reg |= timing->stop_state_counter <<
+              CSI2_TIMING_STOP_STATE_COUNTER_IO1_SHIFT;
+
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_TIMING, reg);
+}
+
+/*
+ * csi2_irq_ctx_set - Enables CSI2 Context IRQs.
+ * @enable: Enable/disable CSI2 Context interrupts
+ */
+static void csi2_irq_ctx_set(struct iss_csi2_device *csi2, int enable)
+{
+       u32 reg = CSI2_CTX_IRQ_FE;
+       int i;
+
+       if (csi2->use_fs_irq)
+               reg |= CSI2_CTX_IRQ_FS;
+
+       for (i = 0; i < 8; i++) {
+               iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(i),
+                             reg);
+               if (enable)
+                       iss_reg_set(csi2->iss, csi2->regs1,
+                                   CSI2_CTX_IRQENABLE(i), reg);
+               else
+                       iss_reg_clr(csi2->iss, csi2->regs1,
+                                   CSI2_CTX_IRQENABLE(i), reg);
+       }
+}
+
+/*
+ * csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
+ * @enable: Enable/disable CSI2 ComplexIO #1 interrupts
+ */
+static void csi2_irq_complexio1_set(struct iss_csi2_device *csi2, int enable)
+{
+       u32 reg;
+       reg = CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT |
+               CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER |
+               CSI2_COMPLEXIO_IRQ_STATEULPM5 |
+               CSI2_COMPLEXIO_IRQ_ERRCONTROL5 |
+               CSI2_COMPLEXIO_IRQ_ERRESC5 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTHS5 |
+               CSI2_COMPLEXIO_IRQ_STATEULPM4 |
+               CSI2_COMPLEXIO_IRQ_ERRCONTROL4 |
+               CSI2_COMPLEXIO_IRQ_ERRESC4 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTHS4 |
+               CSI2_COMPLEXIO_IRQ_STATEULPM3 |
+               CSI2_COMPLEXIO_IRQ_ERRCONTROL3 |
+               CSI2_COMPLEXIO_IRQ_ERRESC3 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTHS3 |
+               CSI2_COMPLEXIO_IRQ_STATEULPM2 |
+               CSI2_COMPLEXIO_IRQ_ERRCONTROL2 |
+               CSI2_COMPLEXIO_IRQ_ERRESC2 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTHS2 |
+               CSI2_COMPLEXIO_IRQ_STATEULPM1 |
+               CSI2_COMPLEXIO_IRQ_ERRCONTROL1 |
+               CSI2_COMPLEXIO_IRQ_ERRESC1 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1 |
+               CSI2_COMPLEXIO_IRQ_ERRSOTHS1;
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQSTATUS, reg);
+       if (enable)
+               iss_reg_set(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQENABLE,
+                           reg);
+       else
+               iss_reg_write(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQENABLE,
+                             0);
+}
+
+/*
+ * csi2_irq_status_set - Enables CSI2 Status IRQs.
+ * @enable: Enable/disable CSI2 Status interrupts
+ */
+static void csi2_irq_status_set(struct iss_csi2_device *csi2, int enable)
+{
+       u32 reg;
+       reg = CSI2_IRQ_OCP_ERR |
+               CSI2_IRQ_SHORT_PACKET |
+               CSI2_IRQ_ECC_CORRECTION |
+               CSI2_IRQ_ECC_NO_CORRECTION |
+               CSI2_IRQ_COMPLEXIO_ERR |
+               CSI2_IRQ_FIFO_OVF |
+               CSI2_IRQ_CONTEXT0;
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_IRQSTATUS, reg);
+       if (enable)
+               iss_reg_set(csi2->iss, csi2->regs1, CSI2_IRQENABLE, reg);
+       else
+               iss_reg_write(csi2->iss, csi2->regs1, CSI2_IRQENABLE, 0);
+}
+
+/*
+ * omap4iss_csi2_reset - Resets the CSI2 module.
+ *
+ * Must be called with the phy lock held.
+ *
+ * Returns 0 if successful, or -EBUSY if power command didn't respond.
+ */
+int omap4iss_csi2_reset(struct iss_csi2_device *csi2)
+{
+       u8 soft_reset_retries = 0;
+       u32 reg;
+       int i;
+
+       if (!csi2->available)
+               return -ENODEV;
+
+       if (csi2->phy->phy_in_use)
+               return -EBUSY;
+
+       iss_reg_set(csi2->iss, csi2->regs1, CSI2_SYSCONFIG,
+                   CSI2_SYSCONFIG_SOFT_RESET);
+
+       do {
+               reg = iss_reg_read(csi2->iss, csi2->regs1, CSI2_SYSSTATUS)
+                   & CSI2_SYSSTATUS_RESET_DONE;
+               if (reg == CSI2_SYSSTATUS_RESET_DONE)
+                       break;
+               soft_reset_retries++;
+               if (soft_reset_retries < 5)
+                       usleep_range(100, 100);
+       } while (soft_reset_retries < 5);
+
+       if (soft_reset_retries == 5) {
+               dev_err(csi2->iss->dev,
+                       "CSI2: Soft reset try count exceeded!\n");
+               return -EBUSY;
+       }
+
+       iss_reg_set(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_CFG,
+                   CSI2_COMPLEXIO_CFG_RESET_CTRL);
+
+       i = 100;
+       do {
+               reg = iss_reg_read(csi2->iss, csi2->phy->phy_regs, REGISTER1)
+                   & REGISTER1_RESET_DONE_CTRLCLK;
+               if (reg == REGISTER1_RESET_DONE_CTRLCLK)
+                       break;
+               usleep_range(100, 100);
+       } while (--i > 0);
+
+       if (i == 0) {
+               dev_err(csi2->iss->dev,
+                       "CSI2: Reset for CSI2_96M_FCLK domain Failed!\n");
+               return -EBUSY;
+       }
+
+       iss_reg_update(csi2->iss, csi2->regs1, CSI2_SYSCONFIG,
+                      CSI2_SYSCONFIG_MSTANDBY_MODE_MASK |
+                      CSI2_SYSCONFIG_AUTO_IDLE,
+                      CSI2_SYSCONFIG_MSTANDBY_MODE_NO);
+
+       return 0;
+}
+
+static int csi2_configure(struct iss_csi2_device *csi2)
+{
+       const struct iss_v4l2_subdevs_group *pdata;
+       struct iss_csi2_timing_cfg *timing = &csi2->timing[0];
+       struct v4l2_subdev *sensor;
+       struct media_pad *pad;
+
+       /*
+        * CSI2 fields that can be updated while the context has
+        * been enabled or the interface has been enabled are not
+        * updated dynamically currently. So we do not allow to
+        * reconfigure if either has been enabled
+        */
+       if (csi2->contexts[0].enabled || csi2->ctrl.if_enable)
+               return -EBUSY;
+
+       pad = media_entity_remote_pad(&csi2->pads[CSI2_PAD_SINK]);
+       sensor = media_entity_to_v4l2_subdev(pad->entity);
+       pdata = sensor->host_priv;
+
+       csi2->frame_skip = 0;
+       v4l2_subdev_call(sensor, sensor, g_skip_frames, &csi2->frame_skip);
+
+       csi2->ctrl.vp_out_ctrl = pdata->bus.csi2.vpclk_div;
+       csi2->ctrl.frame_mode = ISS_CSI2_FRAME_IMMEDIATE;
+       csi2->ctrl.ecc_enable = pdata->bus.csi2.crc;
+
+       timing->force_rx_mode = 1;
+       timing->stop_state_16x = 1;
+       timing->stop_state_4x = 1;
+       timing->stop_state_counter = 0x1ff;
+
+       /*
+        * The CSI2 receiver can't do any format conversion except DPCM
+        * decompression, so every set_format call configures both pads
+        * and enables DPCM decompression as a special case:
+        */
+       if (csi2->formats[CSI2_PAD_SINK].code !=
+           csi2->formats[CSI2_PAD_SOURCE].code)
+               csi2->dpcm_decompress = true;
+       else
+               csi2->dpcm_decompress = false;
+
+       csi2->contexts[0].format_id = csi2_ctx_map_format(csi2);
+
+       if (csi2->video_out.bpl_padding == 0)
+               csi2->contexts[0].data_offset = 0;
+       else
+               csi2->contexts[0].data_offset = csi2->video_out.bpl_value;
+
+       /*
+        * Enable end of frame and end of line signals generation for
+        * context 0. These signals are generated from CSI2 receiver to
+        * qualify the last pixel of a frame and the last pixel of a line.
+        * Without enabling the signals CSI2 receiver writes data to memory
+        * beyond buffer size and/or data line offset is not handled correctly.
+        */
+       csi2->contexts[0].eof_enabled = 1;
+       csi2->contexts[0].eol_enabled = 1;
+
+       csi2_irq_complexio1_set(csi2, 1);
+       csi2_irq_ctx_set(csi2, 1);
+       csi2_irq_status_set(csi2, 1);
+
+       /* Set configuration (timings, format and links) */
+       csi2_timing_config(csi2, timing);
+       csi2_recv_config(csi2, &csi2->ctrl);
+       csi2_ctx_config(csi2, &csi2->contexts[0]);
+
+       return 0;
+}
+
+/*
+ * csi2_print_status - Prints CSI2 debug information.
+ */
+#define CSI2_PRINT_REGISTER(iss, regs, name)\
+       dev_dbg(iss->dev, "###CSI2 " #name "=0x%08x\n", \
+               iss_reg_read(iss, regs, CSI2_##name))
+
+static void csi2_print_status(struct iss_csi2_device *csi2)
+{
+       struct iss_device *iss = csi2->iss;
+
+       if (!csi2->available)
+               return;
+
+       dev_dbg(iss->dev, "-------------CSI2 Register dump-------------\n");
+
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, SYSCONFIG);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, SYSSTATUS);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, IRQENABLE);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, IRQSTATUS);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, CTRL);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, DBG_H);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, COMPLEXIO_CFG);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, COMPLEXIO_IRQSTATUS);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, SHORT_PACKET);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, COMPLEXIO_IRQENABLE);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, DBG_P);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, TIMING);
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_CTRL1(0));
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_CTRL2(0));
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_DAT_OFST(0));
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_PING_ADDR(0));
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_PONG_ADDR(0));
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_IRQENABLE(0));
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_IRQSTATUS(0));
+       CSI2_PRINT_REGISTER(iss, csi2->regs1, CTX_CTRL3(0));
+
+       dev_dbg(iss->dev, "--------------------------------------------\n");
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+/*
+ * csi2_isr_buffer - Does buffer handling at end-of-frame
+ * when writing to memory.
+ */
+static void csi2_isr_buffer(struct iss_csi2_device *csi2)
+{
+       struct iss_buffer *buffer;
+
+       csi2_ctx_enable(csi2, 0, 0);
+
+       buffer = omap4iss_video_buffer_next(&csi2->video_out);
+
+       /*
+        * Let video queue operation restart engine if there is an underrun
+        * condition.
+        */
+       if (buffer == NULL)
+               return;
+
+       csi2_set_outaddr(csi2, buffer->iss_addr);
+       csi2_ctx_enable(csi2, 0, 1);
+}
+
+static void csi2_isr_ctx(struct iss_csi2_device *csi2,
+                        struct iss_csi2_ctx_cfg *ctx)
+{
+       unsigned int n = ctx->ctxnum;
+       u32 status;
+
+       status = iss_reg_read(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n));
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(n), status);
+
+       /* Propagate frame number */
+       if (status & CSI2_CTX_IRQ_FS) {
+               struct iss_pipeline *pipe =
+                                    to_iss_pipeline(&csi2->subdev.entity);
+               if (pipe->do_propagation)
+                       atomic_inc(&pipe->frame_number);
+       }
+
+       if (!(status & CSI2_CTX_IRQ_FE))
+               return;
+
+       /* Skip interrupts until we reach the frame skip count. The CSI2 will be
+        * automatically disabled, as the frame skip count has been programmed
+        * in the CSI2_CTx_CTRL1::COUNT field, so reenable it.
+        *
+        * It would have been nice to rely on the FRAME_NUMBER interrupt instead
+        * but it turned out that the interrupt is only generated when the CSI2
+        * writes to memory (the CSI2_CTx_CTRL1::COUNT field is decreased
+        * correctly and reaches 0 when data is forwarded to the video port only
+        * but no interrupt arrives). Maybe a CSI2 hardware bug.
+        */
+       if (csi2->frame_skip) {
+               csi2->frame_skip--;
+               if (csi2->frame_skip == 0) {
+                       ctx->format_id = csi2_ctx_map_format(csi2);
+                       csi2_ctx_config(csi2, ctx);
+                       csi2_ctx_enable(csi2, n, 1);
+               }
+               return;
+       }
+
+       if (csi2->output & CSI2_OUTPUT_MEMORY)
+               csi2_isr_buffer(csi2);
+}
+
+/*
+ * omap4iss_csi2_isr - CSI2 interrupt handling.
+ */
+void omap4iss_csi2_isr(struct iss_csi2_device *csi2)
+{
+       struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity);
+       u32 csi2_irqstatus, cpxio1_irqstatus;
+       struct iss_device *iss = csi2->iss;
+
+       if (!csi2->available)
+               return;
+
+       csi2_irqstatus = iss_reg_read(csi2->iss, csi2->regs1, CSI2_IRQSTATUS);
+       iss_reg_write(csi2->iss, csi2->regs1, CSI2_IRQSTATUS, csi2_irqstatus);
+
+       /* Failure Cases */
+       if (csi2_irqstatus & CSI2_IRQ_COMPLEXIO_ERR) {
+               cpxio1_irqstatus = iss_reg_read(csi2->iss, csi2->regs1,
+                                               CSI2_COMPLEXIO_IRQSTATUS);
+               iss_reg_write(csi2->iss, csi2->regs1, CSI2_COMPLEXIO_IRQSTATUS,
+                             cpxio1_irqstatus);
+               dev_dbg(iss->dev, "CSI2: ComplexIO Error IRQ %x\n",
+                       cpxio1_irqstatus);
+               pipe->error = true;
+       }
+
+       if (csi2_irqstatus & (CSI2_IRQ_OCP_ERR |
+                             CSI2_IRQ_SHORT_PACKET |
+                             CSI2_IRQ_ECC_NO_CORRECTION |
+                             CSI2_IRQ_COMPLEXIO_ERR |
+                             CSI2_IRQ_FIFO_OVF)) {
+               dev_dbg(iss->dev,
+                       "CSI2 Err: OCP:%d SHORT:%d ECC:%d CPXIO:%d OVF:%d\n",
+                       csi2_irqstatus & CSI2_IRQ_OCP_ERR ? 1 : 0,
+                       csi2_irqstatus & CSI2_IRQ_SHORT_PACKET ? 1 : 0,
+                       csi2_irqstatus & CSI2_IRQ_ECC_NO_CORRECTION ? 1 : 0,
+                       csi2_irqstatus & CSI2_IRQ_COMPLEXIO_ERR ? 1 : 0,
+                       csi2_irqstatus & CSI2_IRQ_FIFO_OVF ? 1 : 0);
+               pipe->error = true;
+       }
+
+       if (omap4iss_module_sync_is_stopping(&csi2->wait, &csi2->stopping))
+               return;
+
+       /* Successful cases */
+       if (csi2_irqstatus & CSI2_IRQ_CONTEXT0)
+               csi2_isr_ctx(csi2, &csi2->contexts[0]);
+
+       if (csi2_irqstatus & CSI2_IRQ_ECC_CORRECTION)
+               dev_dbg(iss->dev, "CSI2: ECC correction done\n");
+}
+
+/* -----------------------------------------------------------------------------
+ * ISS video operations
+ */
+
+/*
+ * csi2_queue - Queues the first buffer when using memory output
+ * @video: The video node
+ * @buffer: buffer to queue
+ */
+static int csi2_queue(struct iss_video *video, struct iss_buffer *buffer)
+{
+       struct iss_csi2_device *csi2 = container_of(video,
+                               struct iss_csi2_device, video_out);
+
+       csi2_set_outaddr(csi2, buffer->iss_addr);
+
+       /*
+        * If streaming was enabled before there was a buffer queued
+        * or underrun happened in the ISR, the hardware was not enabled
+        * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set.
+        * Enable it now.
+        */
+       if (csi2->video_out.dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) {
+               /* Enable / disable context 0 and IRQs */
+               csi2_if_enable(csi2, 1);
+               csi2_ctx_enable(csi2, 0, 1);
+               iss_video_dmaqueue_flags_clr(&csi2->video_out);
+       }
+
+       return 0;
+}
+
+static const struct iss_video_operations csi2_issvideo_ops = {
+       .queue = csi2_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+static struct v4l2_mbus_framefmt *
+__csi2_get_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+                 unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &csi2->formats[pad];
+}
+
+static void
+csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh,
+               unsigned int pad, struct v4l2_mbus_framefmt *fmt,
+               enum v4l2_subdev_format_whence which)
+{
+       enum v4l2_mbus_pixelcode pixelcode;
+       struct v4l2_mbus_framefmt *format;
+       const struct iss_format_info *info;
+       unsigned int i;
+
+       switch (pad) {
+       case CSI2_PAD_SINK:
+               /* Clamp the width and height to valid range (1-8191). */
+               for (i = 0; i < ARRAY_SIZE(csi2_input_fmts); i++) {
+                       if (fmt->code == csi2_input_fmts[i])
+                               break;
+               }
+
+               /* If not found, use SGRBG10 as default */
+               if (i >= ARRAY_SIZE(csi2_input_fmts))
+                       fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+               fmt->width = clamp_t(u32, fmt->width, 1, 8191);
+               fmt->height = clamp_t(u32, fmt->height, 1, 8191);
+               break;
+
+       case CSI2_PAD_SOURCE:
+               /* Source format same as sink format, except for DPCM
+                * compression.
+                */
+               pixelcode = fmt->code;
+               format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK, which);
+               memcpy(fmt, format, sizeof(*fmt));
+
+               /*
+                * Only Allow DPCM decompression, and check that the
+                * pattern is preserved
+                */
+               info = omap4iss_video_format_info(fmt->code);
+               if (info->uncompressed == pixelcode)
+                       fmt->code = pixelcode;
+               break;
+       }
+
+       /* RGB, non-interlaced */
+       fmt->colorspace = V4L2_COLORSPACE_SRGB;
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * csi2_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh     : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_enum_mbus_code(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+       const struct iss_format_info *info;
+
+       if (code->pad == CSI2_PAD_SINK) {
+               if (code->index >= ARRAY_SIZE(csi2_input_fmts))
+                       return -EINVAL;
+
+               code->code = csi2_input_fmts[code->index];
+       } else {
+               format = __csi2_get_format(csi2, fh, CSI2_PAD_SINK,
+                                          V4L2_SUBDEV_FORMAT_TRY);
+               switch (code->index) {
+               case 0:
+                       /* Passthrough sink pad code */
+                       code->code = format->code;
+                       break;
+               case 1:
+                       /* Uncompressed code */
+                       info = omap4iss_video_format_info(format->code);
+                       if (info->uncompressed == format->code)
+                               return -EINVAL;
+
+                       code->code = info->uncompressed;
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
+static int csi2_enum_frame_size(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt format;
+
+       if (fse->index != 0)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = 1;
+       format.height = 1;
+       csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->min_width = format.width;
+       fse->min_height = format.height;
+
+       if (format.code != fse->code)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = -1;
+       format.height = -1;
+       csi2_try_format(csi2, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->max_width = format.width;
+       fse->max_height = format.height;
+
+       return 0;
+}
+
+/*
+ * csi2_get_format - Handle get format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+/*
+ * csi2_set_format - Handle set format by pads subdev method
+ * @sd : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @fmt: pointer to v4l2 subdev format structure
+ * return -EINVAL or zero on success
+ */
+static int csi2_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __csi2_get_format(csi2, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       csi2_try_format(csi2, fh, fmt->pad, &fmt->format, fmt->which);
+       *format = fmt->format;
+
+       /* Propagate the format from sink to source */
+       if (fmt->pad == CSI2_PAD_SINK) {
+               format = __csi2_get_format(csi2, fh, CSI2_PAD_SOURCE,
+                                          fmt->which);
+               *format = fmt->format;
+               csi2_try_format(csi2, fh, CSI2_PAD_SOURCE, format, fmt->which);
+       }
+
+       return 0;
+}
+
+static int csi2_link_validate(struct v4l2_subdev *sd, struct media_link *link,
+                             struct v4l2_subdev_format *source_fmt,
+                             struct v4l2_subdev_format *sink_fmt)
+{
+       struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity);
+       int rval;
+
+       pipe->external = media_entity_to_v4l2_subdev(link->source->entity);
+       rval = omap4iss_get_external_info(pipe, link);
+       if (rval < 0)
+               return rval;
+
+       return v4l2_subdev_link_validate_default(sd, link, source_fmt,
+                                                sink_fmt);
+}
+
+/*
+ * csi2_init_formats - Initialize formats on all pads
+ * @sd: ISS CSI2 V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_subdev_format format;
+
+       memset(&format, 0, sizeof(format));
+       format.pad = CSI2_PAD_SINK;
+       format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       format.format.width = 4096;
+       format.format.height = 4096;
+       csi2_set_format(sd, fh, &format);
+
+       return 0;
+}
+
+/*
+ * csi2_set_stream - Enable/Disable streaming on the CSI2 module
+ * @sd: ISS CSI2 V4L2 subdevice
+ * @enable: ISS pipeline stream state
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct iss_device *iss = csi2->iss;
+       struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity);
+       struct iss_video *video_out = &csi2->video_out;
+       int ret = 0;
+
+       if (csi2->state == ISS_PIPELINE_STREAM_STOPPED) {
+               if (enable == ISS_PIPELINE_STREAM_STOPPED)
+                       return 0;
+
+               omap4iss_subclk_enable(iss, csi2->subclk);
+       }
+
+       switch (enable) {
+       case ISS_PIPELINE_STREAM_CONTINUOUS: {
+               ret = omap4iss_csiphy_config(iss, sd);
+               if (ret < 0)
+                       return ret;
+
+               if (omap4iss_csiphy_acquire(csi2->phy) < 0)
+                       return -ENODEV;
+               csi2->use_fs_irq = pipe->do_propagation;
+               csi2_configure(csi2);
+               csi2_print_status(csi2);
+
+               /*
+                * When outputting to memory with no buffer available, let the
+                * buffer queue handler start the hardware. A DMA queue flag
+                * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is
+                * a buffer available.
+                */
+               if (csi2->output & CSI2_OUTPUT_MEMORY &&
+                   !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED))
+                       break;
+               /* Enable context 0 and IRQs */
+               atomic_set(&csi2->stopping, 0);
+               csi2_ctx_enable(csi2, 0, 1);
+               csi2_if_enable(csi2, 1);
+               iss_video_dmaqueue_flags_clr(video_out);
+               break;
+       }
+       case ISS_PIPELINE_STREAM_STOPPED:
+               if (csi2->state == ISS_PIPELINE_STREAM_STOPPED)
+                       return 0;
+               if (omap4iss_module_sync_idle(&sd->entity, &csi2->wait,
+                                             &csi2->stopping))
+                       ret = -ETIMEDOUT;
+               csi2_ctx_enable(csi2, 0, 0);
+               csi2_if_enable(csi2, 0);
+               csi2_irq_ctx_set(csi2, 0);
+               omap4iss_csiphy_release(csi2->phy);
+               omap4iss_subclk_disable(iss, csi2->subclk);
+               iss_video_dmaqueue_flags_clr(video_out);
+               break;
+       }
+
+       csi2->state = enable;
+       return ret;
+}
+
+/* subdev video operations */
+static const struct v4l2_subdev_video_ops csi2_video_ops = {
+       .s_stream = csi2_set_stream,
+};
+
+/* subdev pad operations */
+static const struct v4l2_subdev_pad_ops csi2_pad_ops = {
+       .enum_mbus_code = csi2_enum_mbus_code,
+       .enum_frame_size = csi2_enum_frame_size,
+       .get_fmt = csi2_get_format,
+       .set_fmt = csi2_set_format,
+       .link_validate = csi2_link_validate,
+};
+
+/* subdev operations */
+static const struct v4l2_subdev_ops csi2_ops = {
+       .video = &csi2_video_ops,
+       .pad = &csi2_pad_ops,
+};
+
+/* subdev internal operations */
+static const struct v4l2_subdev_internal_ops csi2_internal_ops = {
+       .open = csi2_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * csi2_link_setup - Setup CSI2 connections.
+ * @entity : Pointer to media entity structure
+ * @local  : Pointer to local pad array
+ * @remote : Pointer to remote pad array
+ * @flags  : Link flags
+ * return -EINVAL or zero on success
+ */
+static int csi2_link_setup(struct media_entity *entity,
+                          const struct media_pad *local,
+                          const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
+       struct iss_csi2_ctrl_cfg *ctrl = &csi2->ctrl;
+
+       /*
+        * The ISS core doesn't support pipelines with multiple video outputs.
+        * Revisit this when it will be implemented, and return -EBUSY for now.
+        */
+
+       switch (local->index | media_entity_type(remote->entity)) {
+       case CSI2_PAD_SOURCE | MEDIA_ENT_T_DEVNODE:
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (csi2->output & ~CSI2_OUTPUT_MEMORY)
+                               return -EBUSY;
+                       csi2->output |= CSI2_OUTPUT_MEMORY;
+               } else {
+                       csi2->output &= ~CSI2_OUTPUT_MEMORY;
+               }
+               break;
+
+       case CSI2_PAD_SOURCE | MEDIA_ENT_T_V4L2_SUBDEV:
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (csi2->output & ~CSI2_OUTPUT_IPIPEIF)
+                               return -EBUSY;
+                       csi2->output |= CSI2_OUTPUT_IPIPEIF;
+               } else {
+                       csi2->output &= ~CSI2_OUTPUT_IPIPEIF;
+               }
+               break;
+
+       default:
+               /* Link from camera to CSI2 is fixed... */
+               return -EINVAL;
+       }
+
+       ctrl->vp_only_enable = csi2->output & CSI2_OUTPUT_MEMORY ? false : true;
+       ctrl->vp_clk_enable = !!(csi2->output & CSI2_OUTPUT_IPIPEIF);
+
+       return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations csi2_media_ops = {
+       .link_setup = csi2_link_setup,
+       .link_validate = v4l2_subdev_link_validate,
+};
+
+void omap4iss_csi2_unregister_entities(struct iss_csi2_device *csi2)
+{
+       v4l2_device_unregister_subdev(&csi2->subdev);
+       omap4iss_video_unregister(&csi2->video_out);
+}
+
+int omap4iss_csi2_register_entities(struct iss_csi2_device *csi2,
+                                   struct v4l2_device *vdev)
+{
+       int ret;
+
+       /* Register the subdev and video nodes. */
+       ret = v4l2_device_register_subdev(vdev, &csi2->subdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap4iss_video_register(&csi2->video_out, vdev);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       omap4iss_csi2_unregister_entities(csi2);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISS CSI2 initialisation and cleanup
+ */
+
+/*
+ * csi2_init_entities - Initialize subdev and media entity.
+ * @csi2: Pointer to csi2 structure.
+ * return -ENOMEM or zero on success
+ */
+static int csi2_init_entities(struct iss_csi2_device *csi2, const char *subname)
+{
+       struct v4l2_subdev *sd = &csi2->subdev;
+       struct media_pad *pads = csi2->pads;
+       struct media_entity *me = &sd->entity;
+       int ret;
+       char name[V4L2_SUBDEV_NAME_SIZE];
+
+       v4l2_subdev_init(sd, &csi2_ops);
+       sd->internal_ops = &csi2_internal_ops;
+       sprintf(name, "CSI2%s", subname);
+       snprintf(sd->name, sizeof(sd->name), "OMAP4 ISS %s", name);
+
+       sd->grp_id = 1 << 16;   /* group ID for iss subdevs */
+       v4l2_set_subdevdata(sd, csi2);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       pads[CSI2_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+       pads[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+
+       me->ops = &csi2_media_ops;
+       ret = media_entity_init(me, CSI2_PADS_NUM, pads, 0);
+       if (ret < 0)
+               return ret;
+
+       csi2_init_formats(sd, NULL);
+
+       /* Video device node */
+       csi2->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       csi2->video_out.ops = &csi2_issvideo_ops;
+       csi2->video_out.bpl_alignment = 32;
+       csi2->video_out.bpl_zero_padding = 1;
+       csi2->video_out.bpl_max = 0x1ffe0;
+       csi2->video_out.iss = csi2->iss;
+       csi2->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+
+       ret = omap4iss_video_init(&csi2->video_out, name);
+       if (ret < 0)
+               goto error_video;
+
+       /* Connect the CSI2 subdev to the video node. */
+       ret = media_entity_create_link(&csi2->subdev.entity, CSI2_PAD_SOURCE,
+                                      &csi2->video_out.video.entity, 0, 0);
+       if (ret < 0)
+               goto error_link;
+
+       return 0;
+
+error_link:
+       omap4iss_video_cleanup(&csi2->video_out);
+error_video:
+       media_entity_cleanup(&csi2->subdev.entity);
+       return ret;
+}
+
+/*
+ * omap4iss_csi2_init - Routine for module driver init
+ */
+int omap4iss_csi2_init(struct iss_device *iss)
+{
+       struct iss_csi2_device *csi2a = &iss->csi2a;
+       struct iss_csi2_device *csi2b = &iss->csi2b;
+       int ret;
+
+       csi2a->iss = iss;
+       csi2a->available = 1;
+       csi2a->regs1 = OMAP4_ISS_MEM_CSI2_A_REGS1;
+       csi2a->phy = &iss->csiphy1;
+       csi2a->subclk = OMAP4_ISS_SUBCLK_CSI2_A;
+       csi2a->state = ISS_PIPELINE_STREAM_STOPPED;
+       init_waitqueue_head(&csi2a->wait);
+
+       ret = csi2_init_entities(csi2a, "a");
+       if (ret < 0)
+               return ret;
+
+       csi2b->iss = iss;
+       csi2b->available = 1;
+       csi2b->regs1 = OMAP4_ISS_MEM_CSI2_B_REGS1;
+       csi2b->phy = &iss->csiphy2;
+       csi2b->subclk = OMAP4_ISS_SUBCLK_CSI2_B;
+       csi2b->state = ISS_PIPELINE_STREAM_STOPPED;
+       init_waitqueue_head(&csi2b->wait);
+
+       ret = csi2_init_entities(csi2b, "b");
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+/*
+ * omap4iss_csi2_cleanup - Routine for module driver cleanup
+ */
+void omap4iss_csi2_cleanup(struct iss_device *iss)
+{
+       struct iss_csi2_device *csi2a = &iss->csi2a;
+       struct iss_csi2_device *csi2b = &iss->csi2b;
+
+       omap4iss_video_cleanup(&csi2a->video_out);
+       media_entity_cleanup(&csi2a->subdev.entity);
+
+       omap4iss_video_cleanup(&csi2b->video_out);
+       media_entity_cleanup(&csi2b->subdev.entity);
+}
diff --git a/drivers/staging/media/omap4iss/iss_csi2.h b/drivers/staging/media/omap4iss/iss_csi2.h
new file mode 100644 (file)
index 0000000..971aa7b
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - CSI2 module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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.
+ */
+
+#ifndef OMAP4_ISS_CSI2_H
+#define OMAP4_ISS_CSI2_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include "iss_video.h"
+
+struct iss_csiphy;
+
+/* This is not an exhaustive list */
+enum iss_csi2_pix_formats {
+       CSI2_PIX_FMT_OTHERS = 0,
+       CSI2_PIX_FMT_YUV422_8BIT = 0x1e,
+       CSI2_PIX_FMT_YUV422_8BIT_VP = 0x9e,
+       CSI2_PIX_FMT_YUV422_8BIT_VP16 = 0xde,
+       CSI2_PIX_FMT_RAW10_EXP16 = 0xab,
+       CSI2_PIX_FMT_RAW10_EXP16_VP = 0x12f,
+       CSI2_PIX_FMT_RAW8 = 0x2a,
+       CSI2_PIX_FMT_RAW8_DPCM10_EXP16 = 0x2aa,
+       CSI2_PIX_FMT_RAW8_DPCM10_VP = 0x32a,
+       CSI2_PIX_FMT_RAW8_VP = 0x12a,
+       CSI2_USERDEF_8BIT_DATA1_DPCM10_VP = 0x340,
+       CSI2_USERDEF_8BIT_DATA1_DPCM10 = 0x2c0,
+       CSI2_USERDEF_8BIT_DATA1 = 0x40,
+};
+
+enum iss_csi2_irqevents {
+       OCP_ERR_IRQ = 0x4000,
+       SHORT_PACKET_IRQ = 0x2000,
+       ECC_CORRECTION_IRQ = 0x1000,
+       ECC_NO_CORRECTION_IRQ = 0x800,
+       COMPLEXIO2_ERR_IRQ = 0x400,
+       COMPLEXIO1_ERR_IRQ = 0x200,
+       FIFO_OVF_IRQ = 0x100,
+       CONTEXT7 = 0x80,
+       CONTEXT6 = 0x40,
+       CONTEXT5 = 0x20,
+       CONTEXT4 = 0x10,
+       CONTEXT3 = 0x8,
+       CONTEXT2 = 0x4,
+       CONTEXT1 = 0x2,
+       CONTEXT0 = 0x1,
+};
+
+enum iss_csi2_ctx_irqevents {
+       CTX_ECC_CORRECTION = 0x100,
+       CTX_LINE_NUMBER = 0x80,
+       CTX_FRAME_NUMBER = 0x40,
+       CTX_CS = 0x20,
+       CTX_LE = 0x8,
+       CTX_LS = 0x4,
+       CTX_FE = 0x2,
+       CTX_FS = 0x1,
+};
+
+enum iss_csi2_frame_mode {
+       ISS_CSI2_FRAME_IMMEDIATE,
+       ISS_CSI2_FRAME_AFTERFEC,
+};
+
+#define ISS_CSI2_MAX_CTX_NUM   7
+
+struct iss_csi2_ctx_cfg {
+       u8 ctxnum;              /* context number 0 - 7 */
+       u8 dpcm_decompress;
+
+       /* Fields in CSI2_CTx_CTRL2 - locked by CSI2_CTx_CTRL1.CTX_EN */
+       u8 virtual_id;
+       u16 format_id;          /* as in CSI2_CTx_CTRL2[9:0] */
+       u8 dpcm_predictor;      /* 1: simple, 0: advanced */
+
+       /* Fields in CSI2_CTx_CTRL1/3 - Shadowed */
+       u16 alpha;
+       u16 data_offset;
+       u32 ping_addr;
+       u32 pong_addr;
+       u8 eof_enabled;
+       u8 eol_enabled;
+       u8 checksum_enabled;
+       u8 enabled;
+};
+
+struct iss_csi2_timing_cfg {
+       u8 ionum;                       /* IO1 or IO2 as in CSI2_TIMING */
+       unsigned force_rx_mode:1;
+       unsigned stop_state_16x:1;
+       unsigned stop_state_4x:1;
+       u16 stop_state_counter;
+};
+
+struct iss_csi2_ctrl_cfg {
+       bool vp_clk_enable;
+       bool vp_only_enable;
+       u8 vp_out_ctrl;
+       enum iss_csi2_frame_mode frame_mode;
+       bool ecc_enable;
+       bool if_enable;
+};
+
+#define CSI2_PAD_SINK          0
+#define CSI2_PAD_SOURCE                1
+#define CSI2_PADS_NUM          2
+
+#define CSI2_OUTPUT_IPIPEIF    (1 << 0)
+#define CSI2_OUTPUT_MEMORY     (1 << 1)
+
+struct iss_csi2_device {
+       struct v4l2_subdev subdev;
+       struct media_pad pads[CSI2_PADS_NUM];
+       struct v4l2_mbus_framefmt formats[CSI2_PADS_NUM];
+
+       struct iss_video video_out;
+       struct iss_device *iss;
+
+       u8 available;           /* Is the IP present on the silicon? */
+
+       /* memory resources, as defined in enum iss_mem_resources */
+       unsigned int regs1;
+       unsigned int regs2;
+       /* ISP subclock, as defined in enum iss_isp_subclk_resource */
+       unsigned int subclk;
+
+       u32 output; /* output to IPIPEIF, memory or both? */
+       bool dpcm_decompress;
+       unsigned int frame_skip;
+       bool use_fs_irq;
+
+       struct iss_csiphy *phy;
+       struct iss_csi2_ctx_cfg contexts[ISS_CSI2_MAX_CTX_NUM + 1];
+       struct iss_csi2_timing_cfg timing[2];
+       struct iss_csi2_ctrl_cfg ctrl;
+       enum iss_pipeline_stream_state state;
+       wait_queue_head_t wait;
+       atomic_t stopping;
+};
+
+void omap4iss_csi2_isr(struct iss_csi2_device *csi2);
+int omap4iss_csi2_reset(struct iss_csi2_device *csi2);
+int omap4iss_csi2_init(struct iss_device *iss);
+void omap4iss_csi2_cleanup(struct iss_device *iss);
+void omap4iss_csi2_unregister_entities(struct iss_csi2_device *csi2);
+int omap4iss_csi2_register_entities(struct iss_csi2_device *csi2,
+                                   struct v4l2_device *vdev);
+#endif /* OMAP4_ISS_CSI2_H */
diff --git a/drivers/staging/media/omap4iss/iss_csiphy.c b/drivers/staging/media/omap4iss/iss_csiphy.c
new file mode 100644 (file)
index 0000000..7c3d55d
--- /dev/null
@@ -0,0 +1,279 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - CSI PHY module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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 <linux/delay.h>
+#include <linux/device.h>
+
+#include "../../../../arch/arm/mach-omap2/control.h"
+
+#include "iss.h"
+#include "iss_regs.h"
+#include "iss_csiphy.h"
+
+/*
+ * csiphy_lanes_config - Configuration of CSIPHY lanes.
+ *
+ * Updates HW configuration.
+ * Called with phy->mutex taken.
+ */
+static void csiphy_lanes_config(struct iss_csiphy *phy)
+{
+       unsigned int i;
+       u32 reg;
+
+       reg = iss_reg_read(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG);
+
+       for (i = 0; i < phy->max_data_lanes; i++) {
+               reg &= ~(CSI2_COMPLEXIO_CFG_DATA_POL(i + 1) |
+                        CSI2_COMPLEXIO_CFG_DATA_POSITION_MASK(i + 1));
+               reg |= (phy->lanes.data[i].pol ?
+                       CSI2_COMPLEXIO_CFG_DATA_POL(i + 1) : 0);
+               reg |= (phy->lanes.data[i].pos <<
+                       CSI2_COMPLEXIO_CFG_DATA_POSITION_SHIFT(i + 1));
+       }
+
+       reg &= ~(CSI2_COMPLEXIO_CFG_CLOCK_POL |
+                CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK);
+       reg |= phy->lanes.clk.pol ? CSI2_COMPLEXIO_CFG_CLOCK_POL : 0;
+       reg |= phy->lanes.clk.pos << CSI2_COMPLEXIO_CFG_CLOCK_POSITION_SHIFT;
+
+       iss_reg_write(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG, reg);
+}
+
+/*
+ * csiphy_set_power
+ * @power: Power state to be set.
+ *
+ * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
+ */
+static int csiphy_set_power(struct iss_csiphy *phy, u32 power)
+{
+       u32 reg;
+       u8 retry_count;
+
+       iss_reg_update(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG,
+                      CSI2_COMPLEXIO_CFG_PWD_CMD_MASK,
+                      power | CSI2_COMPLEXIO_CFG_PWR_AUTO);
+
+       retry_count = 0;
+       do {
+               udelay(1);
+               reg = iss_reg_read(phy->iss, phy->cfg_regs, CSI2_COMPLEXIO_CFG)
+                   & CSI2_COMPLEXIO_CFG_PWD_STATUS_MASK;
+
+               if (reg != power >> 2)
+                       retry_count++;
+
+       } while ((reg != power >> 2) && (retry_count < 250));
+
+       if (retry_count == 250) {
+               dev_err(phy->iss->dev, "CSI2 CIO set power failed!\n");
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+/*
+ * csiphy_dphy_config - Configure CSI2 D-PHY parameters.
+ *
+ * Called with phy->mutex taken.
+ */
+static void csiphy_dphy_config(struct iss_csiphy *phy)
+{
+       u32 reg;
+
+       /* Set up REGISTER0 */
+       reg = phy->dphy.ths_term << REGISTER0_THS_TERM_SHIFT;
+       reg |= phy->dphy.ths_settle << REGISTER0_THS_SETTLE_SHIFT;
+
+       iss_reg_write(phy->iss, phy->phy_regs, REGISTER0, reg);
+
+       /* Set up REGISTER1 */
+       reg = phy->dphy.tclk_term << REGISTER1_TCLK_TERM_SHIFT;
+       reg |= phy->dphy.tclk_miss << REGISTER1_CTRLCLK_DIV_FACTOR_SHIFT;
+       reg |= phy->dphy.tclk_settle << REGISTER1_TCLK_SETTLE_SHIFT;
+       reg |= 0xb8 << REGISTER1_DPHY_HS_SYNC_PATTERN_SHIFT;
+
+       iss_reg_write(phy->iss, phy->phy_regs, REGISTER1, reg);
+}
+
+/*
+ * TCLK values are OK at their reset values
+ */
+#define TCLK_TERM      0
+#define TCLK_MISS      1
+#define TCLK_SETTLE    14
+
+int omap4iss_csiphy_config(struct iss_device *iss,
+                          struct v4l2_subdev *csi2_subdev)
+{
+       struct iss_csi2_device *csi2 = v4l2_get_subdevdata(csi2_subdev);
+       struct iss_pipeline *pipe = to_iss_pipeline(&csi2_subdev->entity);
+       struct iss_v4l2_subdevs_group *subdevs = pipe->external->host_priv;
+       struct iss_csiphy_dphy_cfg csi2phy;
+       int csi2_ddrclk_khz;
+       struct iss_csiphy_lanes_cfg *lanes;
+       unsigned int used_lanes = 0;
+       u32 cam_rx_ctrl;
+       unsigned int i;
+
+       lanes = &subdevs->bus.csi2.lanecfg;
+
+       /*
+        * SCM.CONTROL_CAMERA_RX
+        * - bit [31] : CSIPHY2 lane 2 enable (4460+ only)
+        * - bit [30:29] : CSIPHY2 per-lane enable (1 to 0)
+        * - bit [28:24] : CSIPHY1 per-lane enable (4 to 0)
+        * - bit [21] : CSIPHY2 CTRLCLK enable
+        * - bit [20:19] : CSIPHY2 config: 00 d-phy, 01/10 ccp2
+        * - bit [18] : CSIPHY1 CTRLCLK enable
+        * - bit [17:16] : CSIPHY1 config: 00 d-phy, 01/10 ccp2
+        */
+       cam_rx_ctrl = omap4_ctrl_pad_readl(
+                       OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_CAMERA_RX);
+
+
+       if (subdevs->interface == ISS_INTERFACE_CSI2A_PHY1) {
+               cam_rx_ctrl &= ~(OMAP4_CAMERARX_CSI21_LANEENABLE_MASK |
+                               OMAP4_CAMERARX_CSI21_CAMMODE_MASK);
+               /* NOTE: Leave CSIPHY1 config to 0x0: D-PHY mode */
+               /* Enable all lanes for now */
+               cam_rx_ctrl |=
+                       0x1f << OMAP4_CAMERARX_CSI21_LANEENABLE_SHIFT;
+               /* Enable CTRLCLK */
+               cam_rx_ctrl |= OMAP4_CAMERARX_CSI21_CTRLCLKEN_MASK;
+       }
+
+       if (subdevs->interface == ISS_INTERFACE_CSI2B_PHY2) {
+               cam_rx_ctrl &= ~(OMAP4_CAMERARX_CSI22_LANEENABLE_MASK |
+                               OMAP4_CAMERARX_CSI22_CAMMODE_MASK);
+               /* NOTE: Leave CSIPHY2 config to 0x0: D-PHY mode */
+               /* Enable all lanes for now */
+               cam_rx_ctrl |=
+                       0x3 << OMAP4_CAMERARX_CSI22_LANEENABLE_SHIFT;
+               /* Enable CTRLCLK */
+               cam_rx_ctrl |= OMAP4_CAMERARX_CSI22_CTRLCLKEN_MASK;
+       }
+
+       omap4_ctrl_pad_writel(cam_rx_ctrl,
+                OMAP4_CTRL_MODULE_PAD_CORE_CONTROL_CAMERA_RX);
+
+       /* Reset used lane count */
+       csi2->phy->used_data_lanes = 0;
+
+       /* Clock and data lanes verification */
+       for (i = 0; i < csi2->phy->max_data_lanes; i++) {
+               if (lanes->data[i].pos == 0)
+                       continue;
+
+               if (lanes->data[i].pol > 1 ||
+                   lanes->data[i].pos > (csi2->phy->max_data_lanes + 1))
+                       return -EINVAL;
+
+               if (used_lanes & (1 << lanes->data[i].pos))
+                       return -EINVAL;
+
+               used_lanes |= 1 << lanes->data[i].pos;
+               csi2->phy->used_data_lanes++;
+       }
+
+       if (lanes->clk.pol > 1 ||
+           lanes->clk.pos > (csi2->phy->max_data_lanes + 1))
+               return -EINVAL;
+
+       if (lanes->clk.pos == 0 || used_lanes & (1 << lanes->clk.pos))
+               return -EINVAL;
+
+       csi2_ddrclk_khz = pipe->external_rate / 1000
+               / (2 * csi2->phy->used_data_lanes)
+               * pipe->external_bpp;
+
+       /*
+        * THS_TERM: Programmed value = ceil(12.5 ns/DDRClk period) - 1.
+        * THS_SETTLE: Programmed value = ceil(90 ns/DDRClk period) + 3.
+        */
+       csi2phy.ths_term = DIV_ROUND_UP(25 * csi2_ddrclk_khz, 2000000) - 1;
+       csi2phy.ths_settle = DIV_ROUND_UP(90 * csi2_ddrclk_khz, 1000000) + 3;
+       csi2phy.tclk_term = TCLK_TERM;
+       csi2phy.tclk_miss = TCLK_MISS;
+       csi2phy.tclk_settle = TCLK_SETTLE;
+
+       mutex_lock(&csi2->phy->mutex);
+       csi2->phy->dphy = csi2phy;
+       csi2->phy->lanes = *lanes;
+       mutex_unlock(&csi2->phy->mutex);
+
+       return 0;
+}
+
+int omap4iss_csiphy_acquire(struct iss_csiphy *phy)
+{
+       int rval;
+
+       mutex_lock(&phy->mutex);
+
+       rval = omap4iss_csi2_reset(phy->csi2);
+       if (rval)
+               goto done;
+
+       csiphy_dphy_config(phy);
+       csiphy_lanes_config(phy);
+
+       rval = csiphy_set_power(phy, CSI2_COMPLEXIO_CFG_PWD_CMD_ON);
+       if (rval)
+               goto done;
+
+       phy->phy_in_use = 1;
+
+done:
+       mutex_unlock(&phy->mutex);
+       return rval;
+}
+
+void omap4iss_csiphy_release(struct iss_csiphy *phy)
+{
+       mutex_lock(&phy->mutex);
+       if (phy->phy_in_use) {
+               csiphy_set_power(phy, CSI2_COMPLEXIO_CFG_PWD_CMD_OFF);
+               phy->phy_in_use = 0;
+       }
+       mutex_unlock(&phy->mutex);
+}
+
+/*
+ * omap4iss_csiphy_init - Initialize the CSI PHY frontends
+ */
+int omap4iss_csiphy_init(struct iss_device *iss)
+{
+       struct iss_csiphy *phy1 = &iss->csiphy1;
+       struct iss_csiphy *phy2 = &iss->csiphy2;
+
+       phy1->iss = iss;
+       phy1->csi2 = &iss->csi2a;
+       phy1->max_data_lanes = ISS_CSIPHY1_NUM_DATA_LANES;
+       phy1->used_data_lanes = 0;
+       phy1->cfg_regs = OMAP4_ISS_MEM_CSI2_A_REGS1;
+       phy1->phy_regs = OMAP4_ISS_MEM_CAMERARX_CORE1;
+       mutex_init(&phy1->mutex);
+
+       phy2->iss = iss;
+       phy2->csi2 = &iss->csi2b;
+       phy2->max_data_lanes = ISS_CSIPHY2_NUM_DATA_LANES;
+       phy2->used_data_lanes = 0;
+       phy2->cfg_regs = OMAP4_ISS_MEM_CSI2_B_REGS1;
+       phy2->phy_regs = OMAP4_ISS_MEM_CAMERARX_CORE2;
+       mutex_init(&phy2->mutex);
+
+       return 0;
+}
diff --git a/drivers/staging/media/omap4iss/iss_csiphy.h b/drivers/staging/media/omap4iss/iss_csiphy.h
new file mode 100644 (file)
index 0000000..e9ca439
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - CSI PHY module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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.
+ */
+
+#ifndef OMAP4_ISS_CSI_PHY_H
+#define OMAP4_ISS_CSI_PHY_H
+
+#include <media/omap4iss.h>
+
+struct iss_csi2_device;
+
+struct iss_csiphy_dphy_cfg {
+       u8 ths_term;
+       u8 ths_settle;
+       u8 tclk_term;
+       unsigned tclk_miss:1;
+       u8 tclk_settle;
+};
+
+struct iss_csiphy {
+       struct iss_device *iss;
+       struct mutex mutex;     /* serialize csiphy configuration */
+       u8 phy_in_use;
+       struct iss_csi2_device *csi2;
+
+       /* memory resources, as defined in enum iss_mem_resources */
+       unsigned int cfg_regs;
+       unsigned int phy_regs;
+
+       u8 max_data_lanes;      /* number of CSI2 Data Lanes supported */
+       u8 used_data_lanes;     /* number of CSI2 Data Lanes used */
+       struct iss_csiphy_lanes_cfg lanes;
+       struct iss_csiphy_dphy_cfg dphy;
+};
+
+int omap4iss_csiphy_config(struct iss_device *iss,
+                          struct v4l2_subdev *csi2_subdev);
+int omap4iss_csiphy_acquire(struct iss_csiphy *phy);
+void omap4iss_csiphy_release(struct iss_csiphy *phy);
+int omap4iss_csiphy_init(struct iss_device *iss);
+
+#endif /* OMAP4_ISS_CSI_PHY_H */
diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c
new file mode 100644 (file)
index 0000000..6eaafc5
--- /dev/null
@@ -0,0 +1,570 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - ISP IPIPE module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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 <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include "iss.h"
+#include "iss_regs.h"
+#include "iss_ipipe.h"
+
+static struct v4l2_mbus_framefmt *
+__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh,
+                 unsigned int pad, enum v4l2_subdev_format_whence which);
+
+static const unsigned int ipipe_fmts[] = {
+       V4L2_MBUS_FMT_SGRBG10_1X10,
+       V4L2_MBUS_FMT_SRGGB10_1X10,
+       V4L2_MBUS_FMT_SBGGR10_1X10,
+       V4L2_MBUS_FMT_SGBRG10_1X10,
+};
+
+/*
+ * ipipe_print_status - Print current IPIPE Module register values.
+ * @ipipe: Pointer to ISS ISP IPIPE device.
+ *
+ * Also prints other debug information stored in the IPIPE module.
+ */
+#define IPIPE_PRINT_REGISTER(iss, name)\
+       dev_dbg(iss->dev, "###IPIPE " #name "=0x%08x\n", \
+               iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_##name))
+
+static void ipipe_print_status(struct iss_ipipe_device *ipipe)
+{
+       struct iss_device *iss = to_iss_device(ipipe);
+
+       dev_dbg(iss->dev, "-------------IPIPE Register dump-------------\n");
+
+       IPIPE_PRINT_REGISTER(iss, SRC_EN);
+       IPIPE_PRINT_REGISTER(iss, SRC_MODE);
+       IPIPE_PRINT_REGISTER(iss, SRC_FMT);
+       IPIPE_PRINT_REGISTER(iss, SRC_COL);
+       IPIPE_PRINT_REGISTER(iss, SRC_VPS);
+       IPIPE_PRINT_REGISTER(iss, SRC_VSZ);
+       IPIPE_PRINT_REGISTER(iss, SRC_HPS);
+       IPIPE_PRINT_REGISTER(iss, SRC_HSZ);
+       IPIPE_PRINT_REGISTER(iss, GCK_MMR);
+       IPIPE_PRINT_REGISTER(iss, YUV_PHS);
+
+       dev_dbg(iss->dev, "-----------------------------------------------\n");
+}
+
+/*
+ * ipipe_enable - Enable/Disable IPIPE.
+ * @enable: enable flag
+ *
+ */
+static void ipipe_enable(struct iss_ipipe_device *ipipe, u8 enable)
+{
+       struct iss_device *iss = to_iss_device(ipipe);
+
+       iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_EN,
+                      IPIPE_SRC_EN_EN, enable ? IPIPE_SRC_EN_EN : 0);
+}
+
+/* -----------------------------------------------------------------------------
+ * Format- and pipeline-related configuration helpers
+ */
+
+static void ipipe_configure(struct iss_ipipe_device *ipipe)
+{
+       struct iss_device *iss = to_iss_device(ipipe);
+       struct v4l2_mbus_framefmt *format;
+
+       /* IPIPE_PAD_SINK */
+       format = &ipipe->formats[IPIPE_PAD_SINK];
+
+       /* NOTE: Currently just supporting pipeline IN: RGB, OUT: YUV422 */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_FMT,
+                     IPIPE_SRC_FMT_RAW2YUV);
+
+       /* Enable YUV444 -> YUV422 conversion */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_YUV_PHS,
+                     IPIPE_YUV_PHS_LPF);
+
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VPS, 0);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HPS, 0);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_VSZ,
+                     (format->height - 2) & IPIPE_SRC_VSZ_MASK);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_HSZ,
+                     (format->width - 1) & IPIPE_SRC_HSZ_MASK);
+
+       /* Ignore ipipeif_wrt signal, and operate on-the-fly.  */
+       iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_MODE,
+                   IPIPE_SRC_MODE_WRT | IPIPE_SRC_MODE_OST);
+
+       /* HACK: Values tuned for Ducati SW (OV) */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_SRC_COL,
+                     IPIPE_SRC_COL_EE_B | IPIPE_SRC_COL_EO_GB |
+                     IPIPE_SRC_COL_OE_GR | IPIPE_SRC_COL_OO_R);
+
+       /* IPIPE_PAD_SOURCE_VP */
+       format = &ipipe->formats[IPIPE_PAD_SOURCE_VP];
+       /* Do nothing? */
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * ipipe_set_stream - Enable/Disable streaming on the IPIPE module
+ * @sd: ISP IPIPE V4L2 subdevice
+ * @enable: Enable/disable stream
+ */
+static int ipipe_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
+       struct iss_device *iss = to_iss_device(ipipe);
+       int ret = 0;
+
+       if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED) {
+               if (enable == ISS_PIPELINE_STREAM_STOPPED)
+                       return 0;
+
+               omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
+
+               /* Enable clk_arm_g0 */
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_MMR,
+                             IPIPE_GCK_MMR_REG);
+
+               /* Enable clk_pix_g[3:0] */
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_IPIPE, IPIPE_GCK_PIX,
+                             IPIPE_GCK_PIX_G3 | IPIPE_GCK_PIX_G2 |
+                             IPIPE_GCK_PIX_G1 | IPIPE_GCK_PIX_G0);
+       }
+
+       switch (enable) {
+       case ISS_PIPELINE_STREAM_CONTINUOUS:
+
+               ipipe_configure(ipipe);
+               ipipe_print_status(ipipe);
+
+               atomic_set(&ipipe->stopping, 0);
+               ipipe_enable(ipipe, 1);
+               break;
+
+       case ISS_PIPELINE_STREAM_STOPPED:
+               if (ipipe->state == ISS_PIPELINE_STREAM_STOPPED)
+                       return 0;
+               if (omap4iss_module_sync_idle(&sd->entity, &ipipe->wait,
+                                             &ipipe->stopping))
+                       ret = -ETIMEDOUT;
+
+               ipipe_enable(ipipe, 0);
+               omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_IPIPE);
+               break;
+       }
+
+       ipipe->state = enable;
+       return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+__ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh,
+                 unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &ipipe->formats[pad];
+}
+
+/*
+ * ipipe_try_format - Try video format on a pad
+ * @ipipe: ISS IPIPE device
+ * @fh : V4L2 subdev file handle
+ * @pad: Pad number
+ * @fmt: Format
+ */
+static void
+ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh,
+               unsigned int pad, struct v4l2_mbus_framefmt *fmt,
+               enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_mbus_framefmt *format;
+       unsigned int width = fmt->width;
+       unsigned int height = fmt->height;
+       unsigned int i;
+
+       switch (pad) {
+       case IPIPE_PAD_SINK:
+               for (i = 0; i < ARRAY_SIZE(ipipe_fmts); i++) {
+                       if (fmt->code == ipipe_fmts[i])
+                               break;
+               }
+
+               /* If not found, use SGRBG10 as default */
+               if (i >= ARRAY_SIZE(ipipe_fmts))
+                       fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+               /* Clamp the input size. */
+               fmt->width = clamp_t(u32, width, 1, 8192);
+               fmt->height = clamp_t(u32, height, 1, 8192);
+               fmt->colorspace = V4L2_COLORSPACE_SRGB;
+               break;
+
+       case IPIPE_PAD_SOURCE_VP:
+               format = __ipipe_get_format(ipipe, fh, IPIPE_PAD_SINK, which);
+               memcpy(fmt, format, sizeof(*fmt));
+
+               fmt->code = V4L2_MBUS_FMT_UYVY8_1X16;
+               fmt->width = clamp_t(u32, width, 32, fmt->width);
+               fmt->height = clamp_t(u32, height, 32, fmt->height);
+               fmt->colorspace = V4L2_COLORSPACE_JPEG;
+               break;
+       }
+
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * ipipe_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_mbus_code_enum *code)
+{
+       switch (code->pad) {
+       case IPIPE_PAD_SINK:
+               if (code->index >= ARRAY_SIZE(ipipe_fmts))
+                       return -EINVAL;
+
+               code->code = ipipe_fmts[code->index];
+               break;
+
+       case IPIPE_PAD_SOURCE_VP:
+               /* FIXME: Forced format conversion inside IPIPE ? */
+               if (code->index != 0)
+                       return -EINVAL;
+
+               code->code = V4L2_MBUS_FMT_UYVY8_1X16;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ipipe_enum_frame_size(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt format;
+
+       if (fse->index != 0)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = 1;
+       format.height = 1;
+       ipipe_try_format(ipipe, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->min_width = format.width;
+       fse->min_height = format.height;
+
+       if (format.code != fse->code)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = -1;
+       format.height = -1;
+       ipipe_try_format(ipipe, fh, fse->pad, &format, V4L2_SUBDEV_FORMAT_TRY);
+       fse->max_width = format.width;
+       fse->max_height = format.height;
+
+       return 0;
+}
+
+/*
+ * ipipe_get_format - Retrieve the video format on a pad
+ * @sd : ISP IPIPE V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ipipe_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+/*
+ * ipipe_set_format - Set the video format on a pad
+ * @sd : ISP IPIPE V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ipipe_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __ipipe_get_format(ipipe, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       ipipe_try_format(ipipe, fh, fmt->pad, &fmt->format, fmt->which);
+       *format = fmt->format;
+
+       /* Propagate the format from sink to source */
+       if (fmt->pad == IPIPE_PAD_SINK) {
+               format = __ipipe_get_format(ipipe, fh, IPIPE_PAD_SOURCE_VP,
+                                          fmt->which);
+               *format = fmt->format;
+               ipipe_try_format(ipipe, fh, IPIPE_PAD_SOURCE_VP, format,
+                               fmt->which);
+       }
+
+       return 0;
+}
+
+static int ipipe_link_validate(struct v4l2_subdev *sd, struct media_link *link,
+                                struct v4l2_subdev_format *source_fmt,
+                                struct v4l2_subdev_format *sink_fmt)
+{
+       /* Check if the two ends match */
+       if (source_fmt->format.width != sink_fmt->format.width ||
+           source_fmt->format.height != sink_fmt->format.height)
+               return -EPIPE;
+
+       if (source_fmt->format.code != sink_fmt->format.code)
+               return -EPIPE;
+
+       return 0;
+}
+
+/*
+ * ipipe_init_formats - Initialize formats on all pads
+ * @sd: ISP IPIPE V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_subdev_format format;
+
+       memset(&format, 0, sizeof(format));
+       format.pad = IPIPE_PAD_SINK;
+       format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       format.format.width = 4096;
+       format.format.height = 4096;
+       ipipe_set_format(sd, fh, &format);
+
+       return 0;
+}
+
+/* V4L2 subdev video operations */
+static const struct v4l2_subdev_video_ops ipipe_v4l2_video_ops = {
+       .s_stream = ipipe_set_stream,
+};
+
+/* V4L2 subdev pad operations */
+static const struct v4l2_subdev_pad_ops ipipe_v4l2_pad_ops = {
+       .enum_mbus_code = ipipe_enum_mbus_code,
+       .enum_frame_size = ipipe_enum_frame_size,
+       .get_fmt = ipipe_get_format,
+       .set_fmt = ipipe_set_format,
+       .link_validate = ipipe_link_validate,
+};
+
+/* V4L2 subdev operations */
+static const struct v4l2_subdev_ops ipipe_v4l2_ops = {
+       .video = &ipipe_v4l2_video_ops,
+       .pad = &ipipe_v4l2_pad_ops,
+};
+
+/* V4L2 subdev internal operations */
+static const struct v4l2_subdev_internal_ops ipipe_v4l2_internal_ops = {
+       .open = ipipe_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * ipipe_link_setup - Setup IPIPE connections
+ * @entity: IPIPE media entity
+ * @local: Pad at the local end of the link
+ * @remote: Pad at the remote end of the link
+ * @flags: Link flags
+ *
+ * return -EINVAL or zero on success
+ */
+static int ipipe_link_setup(struct media_entity *entity,
+                          const struct media_pad *local,
+                          const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct iss_ipipe_device *ipipe = v4l2_get_subdevdata(sd);
+       struct iss_device *iss = to_iss_device(ipipe);
+
+       switch (local->index | media_entity_type(remote->entity)) {
+       case IPIPE_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* Read from IPIPEIF. */
+               if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+                       ipipe->input = IPIPE_INPUT_NONE;
+                       break;
+               }
+
+               if (ipipe->input != IPIPE_INPUT_NONE)
+                       return -EBUSY;
+
+               if (remote->entity == &iss->ipipeif.subdev.entity)
+                       ipipe->input = IPIPE_INPUT_IPIPEIF;
+
+               break;
+
+       case IPIPE_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* Send to RESIZER */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (ipipe->output & ~IPIPE_OUTPUT_VP)
+                               return -EBUSY;
+                       ipipe->output |= IPIPE_OUTPUT_VP;
+               } else {
+                       ipipe->output &= ~IPIPE_OUTPUT_VP;
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations ipipe_media_ops = {
+       .link_setup = ipipe_link_setup,
+       .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * ipipe_init_entities - Initialize V4L2 subdev and media entity
+ * @ipipe: ISS ISP IPIPE module
+ *
+ * Return 0 on success and a negative error code on failure.
+ */
+static int ipipe_init_entities(struct iss_ipipe_device *ipipe)
+{
+       struct v4l2_subdev *sd = &ipipe->subdev;
+       struct media_pad *pads = ipipe->pads;
+       struct media_entity *me = &sd->entity;
+       int ret;
+
+       ipipe->input = IPIPE_INPUT_NONE;
+
+       v4l2_subdev_init(sd, &ipipe_v4l2_ops);
+       sd->internal_ops = &ipipe_v4l2_internal_ops;
+       strlcpy(sd->name, "OMAP4 ISS ISP IPIPE", sizeof(sd->name));
+       sd->grp_id = 1 << 16;   /* group ID for iss subdevs */
+       v4l2_set_subdevdata(sd, ipipe);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       pads[IPIPE_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[IPIPE_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
+
+       me->ops = &ipipe_media_ops;
+       ret = media_entity_init(me, IPIPE_PADS_NUM, pads, 0);
+       if (ret < 0)
+               return ret;
+
+       ipipe_init_formats(sd, NULL);
+
+       return 0;
+}
+
+void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe)
+{
+       media_entity_cleanup(&ipipe->subdev.entity);
+
+       v4l2_device_unregister_subdev(&ipipe->subdev);
+}
+
+int omap4iss_ipipe_register_entities(struct iss_ipipe_device *ipipe,
+       struct v4l2_device *vdev)
+{
+       int ret;
+
+       /* Register the subdev and video node. */
+       ret = v4l2_device_register_subdev(vdev, &ipipe->subdev);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       omap4iss_ipipe_unregister_entities(ipipe);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP IPIPE initialisation and cleanup
+ */
+
+/*
+ * omap4iss_ipipe_init - IPIPE module initialization.
+ * @iss: Device pointer specific to the OMAP4 ISS.
+ *
+ * TODO: Get the initialisation values from platform data.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int omap4iss_ipipe_init(struct iss_device *iss)
+{
+       struct iss_ipipe_device *ipipe = &iss->ipipe;
+
+       ipipe->state = ISS_PIPELINE_STREAM_STOPPED;
+       init_waitqueue_head(&ipipe->wait);
+
+       return ipipe_init_entities(ipipe);
+}
+
+/*
+ * omap4iss_ipipe_cleanup - IPIPE module cleanup.
+ * @iss: Device pointer specific to the OMAP4 ISS.
+ */
+void omap4iss_ipipe_cleanup(struct iss_device *iss)
+{
+       /* FIXME: are you sure there's nothing to do? */
+}
diff --git a/drivers/staging/media/omap4iss/iss_ipipe.h b/drivers/staging/media/omap4iss/iss_ipipe.h
new file mode 100644 (file)
index 0000000..c22d904
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - ISP IPIPE module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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.
+ */
+
+#ifndef OMAP4_ISS_IPIPE_H
+#define OMAP4_ISS_IPIPE_H
+
+#include "iss_video.h"
+
+enum ipipe_input_entity {
+       IPIPE_INPUT_NONE,
+       IPIPE_INPUT_IPIPEIF,
+};
+
+#define IPIPE_OUTPUT_VP                (1 << 0)
+
+/* Sink and source IPIPE pads */
+#define IPIPE_PAD_SINK                         0
+#define IPIPE_PAD_SOURCE_VP                    1
+#define IPIPE_PADS_NUM                         2
+
+/*
+ * struct iss_ipipe_device - Structure for the IPIPE module to store its own
+ *                         information
+ * @subdev: V4L2 subdevice
+ * @pads: Sink and source media entity pads
+ * @formats: Active video formats
+ * @input: Active input
+ * @output: Active outputs
+ * @error: A hardware error occurred during capture
+ * @state: Streaming state
+ * @wait: Wait queue used to stop the module
+ * @stopping: Stopping state
+ */
+struct iss_ipipe_device {
+       struct v4l2_subdev subdev;
+       struct media_pad pads[IPIPE_PADS_NUM];
+       struct v4l2_mbus_framefmt formats[IPIPE_PADS_NUM];
+
+       enum ipipe_input_entity input;
+       unsigned int output;
+       unsigned int error;
+
+       enum iss_pipeline_stream_state state;
+       wait_queue_head_t wait;
+       atomic_t stopping;
+};
+
+struct iss_device;
+
+int omap4iss_ipipe_register_entities(struct iss_ipipe_device *ipipe,
+       struct v4l2_device *vdev);
+void omap4iss_ipipe_unregister_entities(struct iss_ipipe_device *ipipe);
+
+int omap4iss_ipipe_init(struct iss_device *iss);
+void omap4iss_ipipe_cleanup(struct iss_device *iss);
+
+#endif /* OMAP4_ISS_IPIPE_H */
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c
new file mode 100644 (file)
index 0000000..7bc1457
--- /dev/null
@@ -0,0 +1,849 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - ISP IPIPEIF module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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 <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include "iss.h"
+#include "iss_regs.h"
+#include "iss_ipipeif.h"
+
+static const unsigned int ipipeif_fmts[] = {
+       V4L2_MBUS_FMT_SGRBG10_1X10,
+       V4L2_MBUS_FMT_SRGGB10_1X10,
+       V4L2_MBUS_FMT_SBGGR10_1X10,
+       V4L2_MBUS_FMT_SGBRG10_1X10,
+       V4L2_MBUS_FMT_UYVY8_1X16,
+       V4L2_MBUS_FMT_YUYV8_1X16,
+};
+
+/*
+ * ipipeif_print_status - Print current IPIPEIF Module register values.
+ * @ipipeif: Pointer to ISS ISP IPIPEIF device.
+ *
+ * Also prints other debug information stored in the IPIPEIF module.
+ */
+#define IPIPEIF_PRINT_REGISTER(iss, name)\
+       dev_dbg(iss->dev, "###IPIPEIF " #name "=0x%08x\n", \
+               iss_reg_read(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_##name))
+
+#define ISIF_PRINT_REGISTER(iss, name)\
+       dev_dbg(iss->dev, "###ISIF " #name "=0x%08x\n", \
+               iss_reg_read(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_##name))
+
+#define ISP5_PRINT_REGISTER(iss, name)\
+       dev_dbg(iss->dev, "###ISP5 " #name "=0x%08x\n", \
+               iss_reg_read(iss, OMAP4_ISS_MEM_ISP_SYS1, ISP5_##name))
+
+static void ipipeif_print_status(struct iss_ipipeif_device *ipipeif)
+{
+       struct iss_device *iss = to_iss_device(ipipeif);
+
+       dev_dbg(iss->dev, "-------------IPIPEIF Register dump-------------\n");
+
+       IPIPEIF_PRINT_REGISTER(iss, CFG1);
+       IPIPEIF_PRINT_REGISTER(iss, CFG2);
+
+       ISIF_PRINT_REGISTER(iss, SYNCEN);
+       ISIF_PRINT_REGISTER(iss, CADU);
+       ISIF_PRINT_REGISTER(iss, CADL);
+       ISIF_PRINT_REGISTER(iss, MODESET);
+       ISIF_PRINT_REGISTER(iss, CCOLP);
+       ISIF_PRINT_REGISTER(iss, SPH);
+       ISIF_PRINT_REGISTER(iss, LNH);
+       ISIF_PRINT_REGISTER(iss, LNV);
+       ISIF_PRINT_REGISTER(iss, VDINT(0));
+       ISIF_PRINT_REGISTER(iss, HSIZE);
+
+       ISP5_PRINT_REGISTER(iss, SYSCONFIG);
+       ISP5_PRINT_REGISTER(iss, CTRL);
+       ISP5_PRINT_REGISTER(iss, IRQSTATUS(0));
+       ISP5_PRINT_REGISTER(iss, IRQENABLE_SET(0));
+       ISP5_PRINT_REGISTER(iss, IRQENABLE_CLR(0));
+
+       dev_dbg(iss->dev, "-----------------------------------------------\n");
+}
+
+static void ipipeif_write_enable(struct iss_ipipeif_device *ipipeif, u8 enable)
+{
+       struct iss_device *iss = to_iss_device(ipipeif);
+
+       iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SYNCEN,
+                      ISIF_SYNCEN_DWEN, enable ? ISIF_SYNCEN_DWEN : 0);
+}
+
+/*
+ * ipipeif_enable - Enable/Disable IPIPEIF.
+ * @enable: enable flag
+ *
+ */
+static void ipipeif_enable(struct iss_ipipeif_device *ipipeif, u8 enable)
+{
+       struct iss_device *iss = to_iss_device(ipipeif);
+
+       iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SYNCEN,
+                      ISIF_SYNCEN_SYEN, enable ? ISIF_SYNCEN_SYEN : 0);
+}
+
+/* -----------------------------------------------------------------------------
+ * Format- and pipeline-related configuration helpers
+ */
+
+/*
+ * ipipeif_set_outaddr - Set memory address to save output image
+ * @ipipeif: Pointer to ISP IPIPEIF device.
+ * @addr: 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ */
+static void ipipeif_set_outaddr(struct iss_ipipeif_device *ipipeif, u32 addr)
+{
+       struct iss_device *iss = to_iss_device(ipipeif);
+
+       /* Save address splitted in Base Address H & L */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CADU,
+                     (addr >> (16 + 5)) & ISIF_CADU_MASK);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CADL,
+                     (addr >> 5) & ISIF_CADL_MASK);
+}
+
+static void ipipeif_configure(struct iss_ipipeif_device *ipipeif)
+{
+       struct iss_device *iss = to_iss_device(ipipeif);
+       const struct iss_format_info *info;
+       struct v4l2_mbus_framefmt *format;
+       u32 isif_ccolp = 0;
+
+       omap4iss_configure_bridge(iss, ipipeif->input);
+
+       /* IPIPEIF_PAD_SINK */
+       format = &ipipeif->formats[IPIPEIF_PAD_SINK];
+
+       /* IPIPEIF with YUV422 input from ISIF */
+       iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG1,
+                   IPIPEIF_CFG1_INPSRC1_MASK | IPIPEIF_CFG1_INPSRC2_MASK);
+
+       /* Select ISIF/IPIPEIF input format */
+       switch (format->code) {
+       case V4L2_MBUS_FMT_UYVY8_1X16:
+       case V4L2_MBUS_FMT_YUYV8_1X16:
+               iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET,
+                              ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK |
+                              ISIF_MODESET_CCDW_MASK,
+                              ISIF_MODESET_INPMOD_YCBCR16);
+
+               iss_reg_update(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2,
+                              IPIPEIF_CFG2_YUV8, IPIPEIF_CFG2_YUV16);
+
+               break;
+       case V4L2_MBUS_FMT_SGRBG10_1X10:
+               isif_ccolp = ISIF_CCOLP_CP0_F0_GR |
+                       ISIF_CCOLP_CP1_F0_R |
+                       ISIF_CCOLP_CP2_F0_B |
+                       ISIF_CCOLP_CP3_F0_GB;
+               goto cont_raw;
+       case V4L2_MBUS_FMT_SRGGB10_1X10:
+               isif_ccolp = ISIF_CCOLP_CP0_F0_R |
+                       ISIF_CCOLP_CP1_F0_GR |
+                       ISIF_CCOLP_CP2_F0_GB |
+                       ISIF_CCOLP_CP3_F0_B;
+               goto cont_raw;
+       case V4L2_MBUS_FMT_SBGGR10_1X10:
+               isif_ccolp = ISIF_CCOLP_CP0_F0_B |
+                       ISIF_CCOLP_CP1_F0_GB |
+                       ISIF_CCOLP_CP2_F0_GR |
+                       ISIF_CCOLP_CP3_F0_R;
+               goto cont_raw;
+       case V4L2_MBUS_FMT_SGBRG10_1X10:
+               isif_ccolp = ISIF_CCOLP_CP0_F0_GB |
+                       ISIF_CCOLP_CP1_F0_B |
+                       ISIF_CCOLP_CP2_F0_R |
+                       ISIF_CCOLP_CP3_F0_GR;
+cont_raw:
+               iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_IPIPEIF, IPIPEIF_CFG2,
+                           IPIPEIF_CFG2_YUV16);
+
+               iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET,
+                              ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK |
+                              ISIF_MODESET_CCDW_MASK, ISIF_MODESET_INPMOD_RAW |
+                              ISIF_MODESET_CCDW_2BIT);
+
+               info = omap4iss_video_format_info(format->code);
+               iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CGAMMAWD,
+                              ISIF_CGAMMAWD_GWDI_MASK,
+                              ISIF_CGAMMAWD_GWDI(info->bpp));
+
+               /* Set RAW Bayer pattern */
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_CCOLP,
+                             isif_ccolp);
+               break;
+       }
+
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_SPH, 0 & ISIF_SPH_MASK);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNH,
+                     (format->width - 1) & ISIF_LNH_MASK);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_LNV,
+                     (format->height - 1) & ISIF_LNV_MASK);
+
+       /* Generate ISIF0 on the last line of the image */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_VDINT(0),
+                     format->height - 1);
+
+       /* IPIPEIF_PAD_SOURCE_ISIF_SF */
+       format = &ipipeif->formats[IPIPEIF_PAD_SOURCE_ISIF_SF];
+
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_HSIZE,
+                     (ipipeif->video_out.bpl_value >> 5) &
+                     ISIF_HSIZE_HSIZE_MASK);
+
+       /* IPIPEIF_PAD_SOURCE_VP */
+       /* Do nothing? */
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void ipipeif_isr_buffer(struct iss_ipipeif_device *ipipeif)
+{
+       struct iss_buffer *buffer;
+
+       /* The ISIF generates VD0 interrupts even when writes are disabled.
+        * deal with it anyway). Disabling the ISIF when no buffer is available
+        * is thus not be enough, we need to handle the situation explicitly.
+        */
+       if (list_empty(&ipipeif->video_out.dmaqueue))
+               return;
+
+       ipipeif_write_enable(ipipeif, 0);
+
+       buffer = omap4iss_video_buffer_next(&ipipeif->video_out);
+       if (buffer == NULL)
+               return;
+
+       ipipeif_set_outaddr(ipipeif, buffer->iss_addr);
+
+       ipipeif_write_enable(ipipeif, 1);
+}
+
+/*
+ * ipipeif_isif0_isr - Handle ISIF0 event
+ * @ipipeif: Pointer to ISP IPIPEIF device.
+ *
+ * Executes LSC deferred enablement before next frame starts.
+ */
+static void ipipeif_isif0_isr(struct iss_ipipeif_device *ipipeif)
+{
+       struct iss_pipeline *pipe =
+                            to_iss_pipeline(&ipipeif->subdev.entity);
+       if (pipe->do_propagation)
+               atomic_inc(&pipe->frame_number);
+
+       if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)
+               ipipeif_isr_buffer(ipipeif);
+}
+
+/*
+ * omap4iss_ipipeif_isr - Configure ipipeif during interframe time.
+ * @ipipeif: Pointer to ISP IPIPEIF device.
+ * @events: IPIPEIF events
+ */
+void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events)
+{
+       if (omap4iss_module_sync_is_stopping(&ipipeif->wait,
+                                            &ipipeif->stopping))
+               return;
+
+       if (events & ISP5_IRQ_ISIF_INT(0))
+               ipipeif_isif0_isr(ipipeif);
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP video operations
+ */
+
+static int ipipeif_video_queue(struct iss_video *video,
+                              struct iss_buffer *buffer)
+{
+       struct iss_ipipeif_device *ipipeif = container_of(video,
+                               struct iss_ipipeif_device, video_out);
+
+       if (!(ipipeif->output & IPIPEIF_OUTPUT_MEMORY))
+               return -ENODEV;
+
+       ipipeif_set_outaddr(ipipeif, buffer->iss_addr);
+
+       /*
+        * If streaming was enabled before there was a buffer queued
+        * or underrun happened in the ISR, the hardware was not enabled
+        * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set.
+        * Enable it now.
+        */
+       if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) {
+               if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)
+                       ipipeif_write_enable(ipipeif, 1);
+               ipipeif_enable(ipipeif, 1);
+               iss_video_dmaqueue_flags_clr(video);
+       }
+
+       return 0;
+}
+
+static const struct iss_video_operations ipipeif_video_ops = {
+       .queue = ipipeif_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+#define IPIPEIF_DRV_SUBCLK_MASK        (OMAP4_ISS_ISP_SUBCLK_IPIPEIF |\
+                                OMAP4_ISS_ISP_SUBCLK_ISIF)
+/*
+ * ipipeif_set_stream - Enable/Disable streaming on the IPIPEIF module
+ * @sd: ISP IPIPEIF V4L2 subdevice
+ * @enable: Enable/disable stream
+ */
+static int ipipeif_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
+       struct iss_device *iss = to_iss_device(ipipeif);
+       struct iss_video *video_out = &ipipeif->video_out;
+       int ret = 0;
+
+       if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED) {
+               if (enable == ISS_PIPELINE_STREAM_STOPPED)
+                       return 0;
+
+               omap4iss_isp_subclk_enable(iss, IPIPEIF_DRV_SUBCLK_MASK);
+       }
+
+       switch (enable) {
+       case ISS_PIPELINE_STREAM_CONTINUOUS:
+
+               ipipeif_configure(ipipeif);
+               ipipeif_print_status(ipipeif);
+
+               /*
+                * When outputting to memory with no buffer available, let the
+                * buffer queue handler start the hardware. A DMA queue flag
+                * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is
+                * a buffer available.
+                */
+               if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY &&
+                   !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED))
+                       break;
+
+               atomic_set(&ipipeif->stopping, 0);
+               if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)
+                       ipipeif_write_enable(ipipeif, 1);
+               ipipeif_enable(ipipeif, 1);
+               iss_video_dmaqueue_flags_clr(video_out);
+               break;
+
+       case ISS_PIPELINE_STREAM_STOPPED:
+               if (ipipeif->state == ISS_PIPELINE_STREAM_STOPPED)
+                       return 0;
+               if (omap4iss_module_sync_idle(&sd->entity, &ipipeif->wait,
+                                             &ipipeif->stopping))
+                       ret = -ETIMEDOUT;
+
+               if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)
+                       ipipeif_write_enable(ipipeif, 0);
+               ipipeif_enable(ipipeif, 0);
+               omap4iss_isp_subclk_disable(iss, IPIPEIF_DRV_SUBCLK_MASK);
+               iss_video_dmaqueue_flags_clr(video_out);
+               break;
+       }
+
+       ipipeif->state = enable;
+       return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+__ipipeif_get_format(struct iss_ipipeif_device *ipipeif,
+                    struct v4l2_subdev_fh *fh, unsigned int pad,
+                    enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &ipipeif->formats[pad];
+}
+
+/*
+ * ipipeif_try_format - Try video format on a pad
+ * @ipipeif: ISS IPIPEIF device
+ * @fh : V4L2 subdev file handle
+ * @pad: Pad number
+ * @fmt: Format
+ */
+static void
+ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
+                  struct v4l2_subdev_fh *fh, unsigned int pad,
+                  struct v4l2_mbus_framefmt *fmt,
+                  enum v4l2_subdev_format_whence which)
+{
+       struct v4l2_mbus_framefmt *format;
+       unsigned int width = fmt->width;
+       unsigned int height = fmt->height;
+       unsigned int i;
+
+       switch (pad) {
+       case IPIPEIF_PAD_SINK:
+               /* TODO: If the IPIPEIF output formatter pad is connected
+                * directly to the resizer, only YUV formats can be used.
+                */
+               for (i = 0; i < ARRAY_SIZE(ipipeif_fmts); i++) {
+                       if (fmt->code == ipipeif_fmts[i])
+                               break;
+               }
+
+               /* If not found, use SGRBG10 as default */
+               if (i >= ARRAY_SIZE(ipipeif_fmts))
+                       fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+
+               /* Clamp the input size. */
+               fmt->width = clamp_t(u32, width, 1, 8192);
+               fmt->height = clamp_t(u32, height, 1, 8192);
+               break;
+
+       case IPIPEIF_PAD_SOURCE_ISIF_SF:
+               format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK,
+                                             which);
+               memcpy(fmt, format, sizeof(*fmt));
+
+               /* The data formatter truncates the number of horizontal output
+                * pixels to a multiple of 16. To avoid clipping data, allow
+                * callers to request an output size bigger than the input size
+                * up to the nearest multiple of 16.
+                */
+               fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15);
+               fmt->width &= ~15;
+               fmt->height = clamp_t(u32, height, 32, fmt->height);
+               break;
+
+       case IPIPEIF_PAD_SOURCE_VP:
+               format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK,
+                                             which);
+               memcpy(fmt, format, sizeof(*fmt));
+
+               fmt->width = clamp_t(u32, width, 32, fmt->width);
+               fmt->height = clamp_t(u32, height, 32, fmt->height);
+               break;
+       }
+
+       /* Data is written to memory unpacked, each 10-bit or 12-bit pixel is
+        * stored on 2 bytes.
+        */
+       fmt->colorspace = V4L2_COLORSPACE_SRGB;
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * ipipeif_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int ipipeif_enum_mbus_code(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       switch (code->pad) {
+       case IPIPEIF_PAD_SINK:
+               if (code->index >= ARRAY_SIZE(ipipeif_fmts))
+                       return -EINVAL;
+
+               code->code = ipipeif_fmts[code->index];
+               break;
+
+       case IPIPEIF_PAD_SOURCE_ISIF_SF:
+       case IPIPEIF_PAD_SOURCE_VP:
+               /* No format conversion inside IPIPEIF */
+               if (code->index != 0)
+                       return -EINVAL;
+
+               format = __ipipeif_get_format(ipipeif, fh, IPIPEIF_PAD_SINK,
+                                             V4L2_SUBDEV_FORMAT_TRY);
+
+               code->code = format->code;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int ipipeif_enum_frame_size(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt format;
+
+       if (fse->index != 0)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = 1;
+       format.height = 1;
+       ipipeif_try_format(ipipeif, fh, fse->pad, &format,
+                          V4L2_SUBDEV_FORMAT_TRY);
+       fse->min_width = format.width;
+       fse->min_height = format.height;
+
+       if (format.code != fse->code)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = -1;
+       format.height = -1;
+       ipipeif_try_format(ipipeif, fh, fse->pad, &format,
+                          V4L2_SUBDEV_FORMAT_TRY);
+       fse->max_width = format.width;
+       fse->max_height = format.height;
+
+       return 0;
+}
+
+/*
+ * ipipeif_get_format - Retrieve the video format on a pad
+ * @sd : ISP IPIPEIF V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ipipeif_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+/*
+ * ipipeif_set_format - Set the video format on a pad
+ * @sd : ISP IPIPEIF V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int ipipeif_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __ipipeif_get_format(ipipeif, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       ipipeif_try_format(ipipeif, fh, fmt->pad, &fmt->format, fmt->which);
+       *format = fmt->format;
+
+       /* Propagate the format from sink to source */
+       if (fmt->pad == IPIPEIF_PAD_SINK) {
+               format = __ipipeif_get_format(ipipeif, fh,
+                                             IPIPEIF_PAD_SOURCE_ISIF_SF,
+                                             fmt->which);
+               *format = fmt->format;
+               ipipeif_try_format(ipipeif, fh, IPIPEIF_PAD_SOURCE_ISIF_SF,
+                                  format, fmt->which);
+
+               format = __ipipeif_get_format(ipipeif, fh,
+                                             IPIPEIF_PAD_SOURCE_VP,
+                                             fmt->which);
+               *format = fmt->format;
+               ipipeif_try_format(ipipeif, fh, IPIPEIF_PAD_SOURCE_VP, format,
+                               fmt->which);
+       }
+
+       return 0;
+}
+
+static int ipipeif_link_validate(struct v4l2_subdev *sd,
+                                struct media_link *link,
+                                struct v4l2_subdev_format *source_fmt,
+                                struct v4l2_subdev_format *sink_fmt)
+{
+       /* Check if the two ends match */
+       if (source_fmt->format.width != sink_fmt->format.width ||
+           source_fmt->format.height != sink_fmt->format.height)
+               return -EPIPE;
+
+       if (source_fmt->format.code != sink_fmt->format.code)
+               return -EPIPE;
+
+       return 0;
+}
+
+/*
+ * ipipeif_init_formats - Initialize formats on all pads
+ * @sd: ISP IPIPEIF V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int ipipeif_init_formats(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_subdev_format format;
+
+       memset(&format, 0, sizeof(format));
+       format.pad = IPIPEIF_PAD_SINK;
+       format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+       format.format.width = 4096;
+       format.format.height = 4096;
+       ipipeif_set_format(sd, fh, &format);
+
+       return 0;
+}
+
+/* V4L2 subdev video operations */
+static const struct v4l2_subdev_video_ops ipipeif_v4l2_video_ops = {
+       .s_stream = ipipeif_set_stream,
+};
+
+/* V4L2 subdev pad operations */
+static const struct v4l2_subdev_pad_ops ipipeif_v4l2_pad_ops = {
+       .enum_mbus_code = ipipeif_enum_mbus_code,
+       .enum_frame_size = ipipeif_enum_frame_size,
+       .get_fmt = ipipeif_get_format,
+       .set_fmt = ipipeif_set_format,
+       .link_validate = ipipeif_link_validate,
+};
+
+/* V4L2 subdev operations */
+static const struct v4l2_subdev_ops ipipeif_v4l2_ops = {
+       .video = &ipipeif_v4l2_video_ops,
+       .pad = &ipipeif_v4l2_pad_ops,
+};
+
+/* V4L2 subdev internal operations */
+static const struct v4l2_subdev_internal_ops ipipeif_v4l2_internal_ops = {
+       .open = ipipeif_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * ipipeif_link_setup - Setup IPIPEIF connections
+ * @entity: IPIPEIF media entity
+ * @local: Pad at the local end of the link
+ * @remote: Pad at the remote end of the link
+ * @flags: Link flags
+ *
+ * return -EINVAL or zero on success
+ */
+static int ipipeif_link_setup(struct media_entity *entity,
+                          const struct media_pad *local,
+                          const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct iss_ipipeif_device *ipipeif = v4l2_get_subdevdata(sd);
+       struct iss_device *iss = to_iss_device(ipipeif);
+
+       switch (local->index | media_entity_type(remote->entity)) {
+       case IPIPEIF_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* Read from the sensor CSI2a or CSI2b. */
+               if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+                       ipipeif->input = IPIPEIF_INPUT_NONE;
+                       break;
+               }
+
+               if (ipipeif->input != IPIPEIF_INPUT_NONE)
+                       return -EBUSY;
+
+               if (remote->entity == &iss->csi2a.subdev.entity)
+                       ipipeif->input = IPIPEIF_INPUT_CSI2A;
+               else if (remote->entity == &iss->csi2b.subdev.entity)
+                       ipipeif->input = IPIPEIF_INPUT_CSI2B;
+
+               break;
+
+       case IPIPEIF_PAD_SOURCE_ISIF_SF | MEDIA_ENT_T_DEVNODE:
+               /* Write to memory */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (ipipeif->output & ~IPIPEIF_OUTPUT_MEMORY)
+                               return -EBUSY;
+                       ipipeif->output |= IPIPEIF_OUTPUT_MEMORY;
+               } else {
+                       ipipeif->output &= ~IPIPEIF_OUTPUT_MEMORY;
+               }
+               break;
+
+       case IPIPEIF_PAD_SOURCE_VP | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* Send to IPIPE/RESIZER */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (ipipeif->output & ~IPIPEIF_OUTPUT_VP)
+                               return -EBUSY;
+                       ipipeif->output |= IPIPEIF_OUTPUT_VP;
+               } else {
+                       ipipeif->output &= ~IPIPEIF_OUTPUT_VP;
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations ipipeif_media_ops = {
+       .link_setup = ipipeif_link_setup,
+       .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * ipipeif_init_entities - Initialize V4L2 subdev and media entity
+ * @ipipeif: ISS ISP IPIPEIF module
+ *
+ * Return 0 on success and a negative error code on failure.
+ */
+static int ipipeif_init_entities(struct iss_ipipeif_device *ipipeif)
+{
+       struct v4l2_subdev *sd = &ipipeif->subdev;
+       struct media_pad *pads = ipipeif->pads;
+       struct media_entity *me = &sd->entity;
+       int ret;
+
+       ipipeif->input = IPIPEIF_INPUT_NONE;
+
+       v4l2_subdev_init(sd, &ipipeif_v4l2_ops);
+       sd->internal_ops = &ipipeif_v4l2_internal_ops;
+       strlcpy(sd->name, "OMAP4 ISS ISP IPIPEIF", sizeof(sd->name));
+       sd->grp_id = 1 << 16;   /* group ID for iss subdevs */
+       v4l2_set_subdevdata(sd, ipipeif);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       pads[IPIPEIF_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[IPIPEIF_PAD_SOURCE_ISIF_SF].flags = MEDIA_PAD_FL_SOURCE;
+       pads[IPIPEIF_PAD_SOURCE_VP].flags = MEDIA_PAD_FL_SOURCE;
+
+       me->ops = &ipipeif_media_ops;
+       ret = media_entity_init(me, IPIPEIF_PADS_NUM, pads, 0);
+       if (ret < 0)
+               return ret;
+
+       ipipeif_init_formats(sd, NULL);
+
+       ipipeif->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       ipipeif->video_out.ops = &ipipeif_video_ops;
+       ipipeif->video_out.iss = to_iss_device(ipipeif);
+       ipipeif->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+       ipipeif->video_out.bpl_alignment = 32;
+       ipipeif->video_out.bpl_zero_padding = 1;
+       ipipeif->video_out.bpl_max = 0x1ffe0;
+
+       ret = omap4iss_video_init(&ipipeif->video_out, "ISP IPIPEIF");
+       if (ret < 0)
+               return ret;
+
+       /* Connect the IPIPEIF subdev to the video node. */
+       ret = media_entity_create_link(&ipipeif->subdev.entity,
+                                      IPIPEIF_PAD_SOURCE_ISIF_SF,
+                                      &ipipeif->video_out.video.entity, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif)
+{
+       media_entity_cleanup(&ipipeif->subdev.entity);
+
+       v4l2_device_unregister_subdev(&ipipeif->subdev);
+       omap4iss_video_unregister(&ipipeif->video_out);
+}
+
+int omap4iss_ipipeif_register_entities(struct iss_ipipeif_device *ipipeif,
+       struct v4l2_device *vdev)
+{
+       int ret;
+
+       /* Register the subdev and video node. */
+       ret = v4l2_device_register_subdev(vdev, &ipipeif->subdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap4iss_video_register(&ipipeif->video_out, vdev);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       omap4iss_ipipeif_unregister_entities(ipipeif);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP IPIPEIF initialisation and cleanup
+ */
+
+/*
+ * omap4iss_ipipeif_init - IPIPEIF module initialization.
+ * @iss: Device pointer specific to the OMAP4 ISS.
+ *
+ * TODO: Get the initialisation values from platform data.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int omap4iss_ipipeif_init(struct iss_device *iss)
+{
+       struct iss_ipipeif_device *ipipeif = &iss->ipipeif;
+
+       ipipeif->state = ISS_PIPELINE_STREAM_STOPPED;
+       init_waitqueue_head(&ipipeif->wait);
+
+       return ipipeif_init_entities(ipipeif);
+}
+
+/*
+ * omap4iss_ipipeif_cleanup - IPIPEIF module cleanup.
+ * @iss: Device pointer specific to the OMAP4 ISS.
+ */
+void omap4iss_ipipeif_cleanup(struct iss_device *iss)
+{
+       /* FIXME: are you sure there's nothing to do? */
+}
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.h b/drivers/staging/media/omap4iss/iss_ipipeif.h
new file mode 100644 (file)
index 0000000..cbdccb9
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - ISP IPIPEIF module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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.
+ */
+
+#ifndef OMAP4_ISS_IPIPEIF_H
+#define OMAP4_ISS_IPIPEIF_H
+
+#include "iss_video.h"
+
+enum ipipeif_input_entity {
+       IPIPEIF_INPUT_NONE,
+       IPIPEIF_INPUT_CSI2A,
+       IPIPEIF_INPUT_CSI2B
+};
+
+#define IPIPEIF_OUTPUT_MEMORY          (1 << 0)
+#define IPIPEIF_OUTPUT_VP              (1 << 1)
+
+/* Sink and source IPIPEIF pads */
+#define IPIPEIF_PAD_SINK                       0
+#define IPIPEIF_PAD_SOURCE_ISIF_SF             1
+#define IPIPEIF_PAD_SOURCE_VP                  2
+#define IPIPEIF_PADS_NUM                       3
+
+/*
+ * struct iss_ipipeif_device - Structure for the IPIPEIF module to store its own
+ *                         information
+ * @subdev: V4L2 subdevice
+ * @pads: Sink and source media entity pads
+ * @formats: Active video formats
+ * @input: Active input
+ * @output: Active outputs
+ * @video_out: Output video node
+ * @error: A hardware error occurred during capture
+ * @alaw: A-law compression enabled (1) or disabled (0)
+ * @lpf: Low pass filter enabled (1) or disabled (0)
+ * @obclamp: Optical-black clamp enabled (1) or disabled (0)
+ * @fpc_en: Faulty pixels correction enabled (1) or disabled (0)
+ * @blcomp: Black level compensation configuration
+ * @clamp: Optical-black or digital clamp configuration
+ * @fpc: Faulty pixels correction configuration
+ * @lsc: Lens shading compensation configuration
+ * @update: Bitmask of controls to update during the next interrupt
+ * @shadow_update: Controls update in progress by userspace
+ * @syncif: Interface synchronization configuration
+ * @vpcfg: Video port configuration
+ * @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
+ * @ioctl_lock: Serializes ioctl calls and LSC requests freeing
+ */
+struct iss_ipipeif_device {
+       struct v4l2_subdev subdev;
+       struct media_pad pads[IPIPEIF_PADS_NUM];
+       struct v4l2_mbus_framefmt formats[IPIPEIF_PADS_NUM];
+
+       enum ipipeif_input_entity input;
+       unsigned int output;
+       struct iss_video video_out;
+       unsigned int error;
+
+       enum iss_pipeline_stream_state state;
+       wait_queue_head_t wait;
+       atomic_t stopping;
+};
+
+struct iss_device;
+
+int omap4iss_ipipeif_init(struct iss_device *iss);
+void omap4iss_ipipeif_cleanup(struct iss_device *iss);
+int omap4iss_ipipeif_register_entities(struct iss_ipipeif_device *ipipeif,
+       struct v4l2_device *vdev);
+void omap4iss_ipipeif_unregister_entities(struct iss_ipipeif_device *ipipeif);
+
+int omap4iss_ipipeif_busy(struct iss_ipipeif_device *ipipeif);
+void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events);
+void omap4iss_ipipeif_restore_context(struct iss_device *iss);
+void omap4iss_ipipeif_max_rate(struct iss_ipipeif_device *ipipeif,
+       unsigned int *max_rate);
+
+#endif /* OMAP4_ISS_IPIPEIF_H */
diff --git a/drivers/staging/media/omap4iss/iss_regs.h b/drivers/staging/media/omap4iss/iss_regs.h
new file mode 100644 (file)
index 0000000..efd0291
--- /dev/null
@@ -0,0 +1,901 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - Register defines
+ *
+ * Copyright (C) 2012 Texas Instruments.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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.
+ */
+
+#ifndef _OMAP4_ISS_REGS_H_
+#define _OMAP4_ISS_REGS_H_
+
+/* ISS */
+#define ISS_HL_REVISION                                        0x0
+
+#define ISS_HL_SYSCONFIG                               0x10
+#define ISS_HL_SYSCONFIG_IDLEMODE_SHIFT                        2
+#define ISS_HL_SYSCONFIG_IDLEMODE_FORCEIDLE            0x0
+#define ISS_HL_SYSCONFIG_IDLEMODE_NOIDLE               0x1
+#define ISS_HL_SYSCONFIG_IDLEMODE_SMARTIDLE            0x2
+#define ISS_HL_SYSCONFIG_SOFTRESET                     (1 << 0)
+
+#define ISS_HL_IRQSTATUS_RAW(i)                                (0x20 + (0x10 * (i)))
+#define ISS_HL_IRQSTATUS(i)                            (0x24 + (0x10 * (i)))
+#define ISS_HL_IRQENABLE_SET(i)                                (0x28 + (0x10 * (i)))
+#define ISS_HL_IRQENABLE_CLR(i)                                (0x2c + (0x10 * (i)))
+
+#define ISS_HL_IRQ_HS_VS                               (1 << 17)
+#define ISS_HL_IRQ_SIMCOP(i)                           (1 << (12 + (i)))
+#define ISS_HL_IRQ_BTE                                 (1 << 11)
+#define ISS_HL_IRQ_CBUFF                               (1 << 10)
+#define ISS_HL_IRQ_CCP2(i)                             (1 << ((i) > 3 ? 16 : 14 + (i)))
+#define ISS_HL_IRQ_CSIB                                        (1 << 5)
+#define ISS_HL_IRQ_CSIA                                        (1 << 4)
+#define ISS_HL_IRQ_ISP(i)                              (1 << (i))
+
+#define ISS_CTRL                                       0x80
+#define ISS_CTRL_CLK_DIV_MASK                          (3 << 4)
+#define ISS_CTRL_INPUT_SEL_MASK                                (3 << 2)
+#define ISS_CTRL_INPUT_SEL_CSI2A                       (0 << 2)
+#define ISS_CTRL_INPUT_SEL_CSI2B                       (1 << 2)
+#define ISS_CTRL_SYNC_DETECT_VS_RAISING                        (3 << 0)
+
+#define ISS_CLKCTRL                                    0x84
+#define ISS_CLKCTRL_VPORT2_CLK                         (1 << 30)
+#define ISS_CLKCTRL_VPORT1_CLK                         (1 << 29)
+#define ISS_CLKCTRL_VPORT0_CLK                         (1 << 28)
+#define ISS_CLKCTRL_CCP2                               (1 << 4)
+#define ISS_CLKCTRL_CSI2_B                             (1 << 3)
+#define ISS_CLKCTRL_CSI2_A                             (1 << 2)
+#define ISS_CLKCTRL_ISP                                        (1 << 1)
+#define ISS_CLKCTRL_SIMCOP                             (1 << 0)
+
+#define ISS_CLKSTAT                                    0x88
+#define ISS_CLKSTAT_VPORT2_CLK                         (1 << 30)
+#define ISS_CLKSTAT_VPORT1_CLK                         (1 << 29)
+#define ISS_CLKSTAT_VPORT0_CLK                         (1 << 28)
+#define ISS_CLKSTAT_CCP2                               (1 << 4)
+#define ISS_CLKSTAT_CSI2_B                             (1 << 3)
+#define ISS_CLKSTAT_CSI2_A                             (1 << 2)
+#define ISS_CLKSTAT_ISP                                        (1 << 1)
+#define ISS_CLKSTAT_SIMCOP                             (1 << 0)
+
+#define ISS_PM_STATUS                                  0x8c
+#define ISS_PM_STATUS_CBUFF_PM_MASK                    (3 << 12)
+#define ISS_PM_STATUS_BTE_PM_MASK                      (3 << 10)
+#define ISS_PM_STATUS_SIMCOP_PM_MASK                   (3 << 8)
+#define ISS_PM_STATUS_ISP_PM_MASK                      (3 << 6)
+#define ISS_PM_STATUS_CCP2_PM_MASK                     (3 << 4)
+#define ISS_PM_STATUS_CSI2_B_PM_MASK                   (3 << 2)
+#define ISS_PM_STATUS_CSI2_A_PM_MASK                   (3 << 0)
+
+#define REGISTER0                                      0x0
+#define REGISTER0_HSCLOCKCONFIG                                (1 << 24)
+#define REGISTER0_THS_TERM_MASK                                (0xff << 8)
+#define REGISTER0_THS_TERM_SHIFT                       8
+#define REGISTER0_THS_SETTLE_MASK                      (0xff << 0)
+#define REGISTER0_THS_SETTLE_SHIFT                     0
+
+#define REGISTER1                                      0x4
+#define REGISTER1_RESET_DONE_CTRLCLK                   (1 << 29)
+#define REGISTER1_CLOCK_MISS_DETECTOR_STATUS           (1 << 25)
+#define REGISTER1_TCLK_TERM_MASK                       (0x3f << 18)
+#define REGISTER1_TCLK_TERM_SHIFT                      18
+#define REGISTER1_DPHY_HS_SYNC_PATTERN_SHIFT           10
+#define REGISTER1_CTRLCLK_DIV_FACTOR_MASK              (0x3 << 8)
+#define REGISTER1_CTRLCLK_DIV_FACTOR_SHIFT             8
+#define REGISTER1_TCLK_SETTLE_MASK                     (0xff << 0)
+#define REGISTER1_TCLK_SETTLE_SHIFT                    0
+
+#define REGISTER2                                      0x8
+
+#define CSI2_SYSCONFIG                                 0x10
+#define CSI2_SYSCONFIG_MSTANDBY_MODE_MASK              (3 << 12)
+#define CSI2_SYSCONFIG_MSTANDBY_MODE_FORCE             (0 << 12)
+#define CSI2_SYSCONFIG_MSTANDBY_MODE_NO                        (1 << 12)
+#define CSI2_SYSCONFIG_MSTANDBY_MODE_SMART             (2 << 12)
+#define CSI2_SYSCONFIG_SOFT_RESET                      (1 << 1)
+#define CSI2_SYSCONFIG_AUTO_IDLE                       (1 << 0)
+
+#define CSI2_SYSSTATUS                                 0x14
+#define CSI2_SYSSTATUS_RESET_DONE                      (1 << 0)
+
+#define CSI2_IRQSTATUS                                 0x18
+#define CSI2_IRQENABLE                                 0x1c
+
+/* Shared bits across CSI2_IRQENABLE and IRQSTATUS */
+
+#define CSI2_IRQ_OCP_ERR                               (1 << 14)
+#define CSI2_IRQ_SHORT_PACKET                          (1 << 13)
+#define CSI2_IRQ_ECC_CORRECTION                                (1 << 12)
+#define CSI2_IRQ_ECC_NO_CORRECTION                     (1 << 11)
+#define CSI2_IRQ_COMPLEXIO_ERR                         (1 << 9)
+#define CSI2_IRQ_FIFO_OVF                              (1 << 8)
+#define CSI2_IRQ_CONTEXT0                              (1 << 0)
+
+#define CSI2_CTRL                                      0x40
+#define CSI2_CTRL_MFLAG_LEVH_MASK                      (7 << 20)
+#define CSI2_CTRL_MFLAG_LEVH_SHIFT                     20
+#define CSI2_CTRL_MFLAG_LEVL_MASK                      (7 << 17)
+#define CSI2_CTRL_MFLAG_LEVL_SHIFT                     17
+#define CSI2_CTRL_BURST_SIZE_EXPAND                    (1 << 16)
+#define CSI2_CTRL_VP_CLK_EN                            (1 << 15)
+#define CSI2_CTRL_NON_POSTED_WRITE                     (1 << 13)
+#define CSI2_CTRL_VP_ONLY_EN                           (1 << 11)
+#define CSI2_CTRL_VP_OUT_CTRL_MASK                     (3 << 8)
+#define CSI2_CTRL_VP_OUT_CTRL_SHIFT                    8
+#define CSI2_CTRL_DBG_EN                               (1 << 7)
+#define CSI2_CTRL_BURST_SIZE_MASK                      (3 << 5)
+#define CSI2_CTRL_ENDIANNESS                           (1 << 4)
+#define CSI2_CTRL_FRAME                                        (1 << 3)
+#define CSI2_CTRL_ECC_EN                               (1 << 2)
+#define CSI2_CTRL_IF_EN                                        (1 << 0)
+
+#define CSI2_DBG_H                                     0x44
+
+#define CSI2_COMPLEXIO_CFG                             0x50
+#define CSI2_COMPLEXIO_CFG_RESET_CTRL                  (1 << 30)
+#define CSI2_COMPLEXIO_CFG_RESET_DONE                  (1 << 29)
+#define CSI2_COMPLEXIO_CFG_PWD_CMD_MASK                        (3 << 27)
+#define CSI2_COMPLEXIO_CFG_PWD_CMD_OFF                 (0 << 27)
+#define CSI2_COMPLEXIO_CFG_PWD_CMD_ON                  (1 << 27)
+#define CSI2_COMPLEXIO_CFG_PWD_CMD_ULP                 (2 << 27)
+#define CSI2_COMPLEXIO_CFG_PWD_STATUS_MASK             (3 << 25)
+#define CSI2_COMPLEXIO_CFG_PWD_STATUS_OFF              (0 << 25)
+#define CSI2_COMPLEXIO_CFG_PWD_STATUS_ON               (1 << 25)
+#define CSI2_COMPLEXIO_CFG_PWD_STATUS_ULP              (2 << 25)
+#define CSI2_COMPLEXIO_CFG_PWR_AUTO                    (1 << 24)
+#define CSI2_COMPLEXIO_CFG_DATA_POL(i)                 (1 << (((i) * 4) + 3))
+#define CSI2_COMPLEXIO_CFG_DATA_POSITION_MASK(i)       (7 << ((i) * 4))
+#define CSI2_COMPLEXIO_CFG_DATA_POSITION_SHIFT(i)      ((i) * 4)
+#define CSI2_COMPLEXIO_CFG_CLOCK_POL                   (1 << 3)
+#define CSI2_COMPLEXIO_CFG_CLOCK_POSITION_MASK         (7 << 0)
+#define CSI2_COMPLEXIO_CFG_CLOCK_POSITION_SHIFT                0
+
+#define CSI2_COMPLEXIO_IRQSTATUS                       0x54
+
+#define CSI2_SHORT_PACKET                              0x5c
+
+#define CSI2_COMPLEXIO_IRQENABLE                       0x60
+
+/* Shared bits across CSI2_COMPLEXIO_IRQENABLE and IRQSTATUS */
+#define CSI2_COMPLEXIO_IRQ_STATEALLULPMEXIT            (1 << 26)
+#define CSI2_COMPLEXIO_IRQ_STATEALLULPMENTER           (1 << 25)
+#define CSI2_COMPLEXIO_IRQ_STATEULPM5                  (1 << 24)
+#define CSI2_COMPLEXIO_IRQ_STATEULPM4                  (1 << 23)
+#define CSI2_COMPLEXIO_IRQ_STATEULPM3                  (1 << 22)
+#define CSI2_COMPLEXIO_IRQ_STATEULPM2                  (1 << 21)
+#define CSI2_COMPLEXIO_IRQ_STATEULPM1                  (1 << 20)
+#define CSI2_COMPLEXIO_IRQ_ERRCONTROL5                 (1 << 19)
+#define CSI2_COMPLEXIO_IRQ_ERRCONTROL4                 (1 << 18)
+#define CSI2_COMPLEXIO_IRQ_ERRCONTROL3                 (1 << 17)
+#define CSI2_COMPLEXIO_IRQ_ERRCONTROL2                 (1 << 16)
+#define CSI2_COMPLEXIO_IRQ_ERRCONTROL1                 (1 << 15)
+#define CSI2_COMPLEXIO_IRQ_ERRESC5                     (1 << 14)
+#define CSI2_COMPLEXIO_IRQ_ERRESC4                     (1 << 13)
+#define CSI2_COMPLEXIO_IRQ_ERRESC3                     (1 << 12)
+#define CSI2_COMPLEXIO_IRQ_ERRESC2                     (1 << 11)
+#define CSI2_COMPLEXIO_IRQ_ERRESC1                     (1 << 10)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS5               (1 << 9)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS4               (1 << 8)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS3               (1 << 7)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS2               (1 << 6)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTSYNCHS1               (1 << 5)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTHS5                   (1 << 4)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTHS4                   (1 << 3)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTHS3                   (1 << 2)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTHS2                   (1 << 1)
+#define CSI2_COMPLEXIO_IRQ_ERRSOTHS1                   (1 << 0)
+
+#define CSI2_DBG_P                                     0x68
+
+#define CSI2_TIMING                                    0x6c
+#define CSI2_TIMING_FORCE_RX_MODE_IO1                  (1 << 15)
+#define CSI2_TIMING_STOP_STATE_X16_IO1                 (1 << 14)
+#define CSI2_TIMING_STOP_STATE_X4_IO1                  (1 << 13)
+#define CSI2_TIMING_STOP_STATE_COUNTER_IO1_MASK                (0x1fff << 0)
+#define CSI2_TIMING_STOP_STATE_COUNTER_IO1_SHIFT       0
+
+#define CSI2_CTX_CTRL1(i)                              (0x70 + (0x20 * i))
+#define CSI2_CTX_CTRL1_GENERIC                         (1 << 30)
+#define CSI2_CTX_CTRL1_TRANSCODE                       (0xf << 24)
+#define CSI2_CTX_CTRL1_FEC_NUMBER_MASK                 (0xff << 16)
+#define CSI2_CTX_CTRL1_COUNT_MASK                      (0xff << 8)
+#define CSI2_CTX_CTRL1_COUNT_SHIFT                     8
+#define CSI2_CTX_CTRL1_EOF_EN                          (1 << 7)
+#define CSI2_CTX_CTRL1_EOL_EN                          (1 << 6)
+#define CSI2_CTX_CTRL1_CS_EN                           (1 << 5)
+#define CSI2_CTX_CTRL1_COUNT_UNLOCK                    (1 << 4)
+#define CSI2_CTX_CTRL1_PING_PONG                       (1 << 3)
+#define CSI2_CTX_CTRL1_CTX_EN                          (1 << 0)
+
+#define CSI2_CTX_CTRL2(i)                              (0x74 + (0x20 * i))
+#define CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT              13
+#define CSI2_CTX_CTRL2_USER_DEF_MAP_MASK               \
+               (0x3 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT)
+#define CSI2_CTX_CTRL2_VIRTUAL_ID_MASK                 (3 << 11)
+#define CSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT                        11
+#define CSI2_CTX_CTRL2_DPCM_PRED                       (1 << 10)
+#define CSI2_CTX_CTRL2_FORMAT_MASK                     (0x3ff << 0)
+#define CSI2_CTX_CTRL2_FORMAT_SHIFT                    0
+
+#define CSI2_CTX_DAT_OFST(i)                           (0x78 + (0x20 * i))
+#define CSI2_CTX_DAT_OFST_MASK                         (0xfff << 5)
+
+#define CSI2_CTX_PING_ADDR(i)                          (0x7c + (0x20 * i))
+#define CSI2_CTX_PING_ADDR_MASK                                0xffffffe0
+
+#define CSI2_CTX_PONG_ADDR(i)                          (0x80 + (0x20 * i))
+#define CSI2_CTX_PONG_ADDR_MASK                                CSI2_CTX_PING_ADDR_MASK
+
+#define CSI2_CTX_IRQENABLE(i)                          (0x84 + (0x20 * i))
+#define CSI2_CTX_IRQSTATUS(i)                          (0x88 + (0x20 * i))
+
+#define CSI2_CTX_CTRL3(i)                              (0x8c + (0x20 * i))
+#define CSI2_CTX_CTRL3_ALPHA_SHIFT                     5
+#define CSI2_CTX_CTRL3_ALPHA_MASK                      \
+               (0x3fff << CSI2_CTX_CTRL3_ALPHA_SHIFT)
+
+/* Shared bits across CSI2_CTX_IRQENABLE and IRQSTATUS */
+#define CSI2_CTX_IRQ_ECC_CORRECTION                    (1 << 8)
+#define CSI2_CTX_IRQ_LINE_NUMBER                       (1 << 7)
+#define CSI2_CTX_IRQ_FRAME_NUMBER                      (1 << 6)
+#define CSI2_CTX_IRQ_CS                                        (1 << 5)
+#define CSI2_CTX_IRQ_LE                                        (1 << 3)
+#define CSI2_CTX_IRQ_LS                                        (1 << 2)
+#define CSI2_CTX_IRQ_FE                                        (1 << 1)
+#define CSI2_CTX_IRQ_FS                                        (1 << 0)
+
+/* ISS BTE */
+#define BTE_CTRL                                       (0x0030)
+#define BTE_CTRL_BW_LIMITER_MASK                       (0x3ff << 22)
+#define BTE_CTRL_BW_LIMITER_SHIFT                      22
+
+/* ISS ISP_SYS1 */
+#define ISP5_REVISION                                  (0x0000)
+#define ISP5_SYSCONFIG                                 (0x0010)
+#define ISP5_SYSCONFIG_STANDBYMODE_MASK                        (3 << 4)
+#define ISP5_SYSCONFIG_STANDBYMODE_FORCE               (0 << 4)
+#define ISP5_SYSCONFIG_STANDBYMODE_NO                  (1 << 4)
+#define ISP5_SYSCONFIG_STANDBYMODE_SMART               (2 << 4)
+#define ISP5_SYSCONFIG_SOFTRESET                       (1 << 1)
+
+#define ISP5_IRQSTATUS(i)                              (0x0028 + (0x10 * (i)))
+#define ISP5_IRQENABLE_SET(i)                          (0x002c + (0x10 * (i)))
+#define ISP5_IRQENABLE_CLR(i)                          (0x0030 + (0x10 * (i)))
+
+/* Bits shared for ISP5_IRQ* registers */
+#define ISP5_IRQ_OCP_ERR                               (1 << 31)
+#define ISP5_IRQ_IPIPE_INT_DPC_RNEW1                   (1 << 29)
+#define ISP5_IRQ_IPIPE_INT_DPC_RNEW0                   (1 << 28)
+#define ISP5_IRQ_IPIPE_INT_DPC_INIT                    (1 << 27)
+#define ISP5_IRQ_IPIPE_INT_EOF                         (1 << 25)
+#define ISP5_IRQ_H3A_INT_EOF                           (1 << 24)
+#define ISP5_IRQ_RSZ_INT_EOF1                          (1 << 23)
+#define ISP5_IRQ_RSZ_INT_EOF0                          (1 << 22)
+#define ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR                   (1 << 19)
+#define ISP5_IRQ_RSZ_FIFO_OVF                          (1 << 18)
+#define ISP5_IRQ_RSZ_INT_CYC_RSZB                      (1 << 17)
+#define ISP5_IRQ_RSZ_INT_CYC_RSZA                      (1 << 16)
+#define ISP5_IRQ_RSZ_INT_DMA                           (1 << 15)
+#define ISP5_IRQ_RSZ_INT_LAST_PIX                      (1 << 14)
+#define ISP5_IRQ_RSZ_INT_REG                           (1 << 13)
+#define ISP5_IRQ_H3A_INT                               (1 << 12)
+#define ISP5_IRQ_AF_INT                                        (1 << 11)
+#define ISP5_IRQ_AEW_INT                               (1 << 10)
+#define ISP5_IRQ_IPIPEIF_IRQ                           (1 << 9)
+#define ISP5_IRQ_IPIPE_INT_HST                         (1 << 8)
+#define ISP5_IRQ_IPIPE_INT_BSC                         (1 << 7)
+#define ISP5_IRQ_IPIPE_INT_DMA                         (1 << 6)
+#define ISP5_IRQ_IPIPE_INT_LAST_PIX                    (1 << 5)
+#define ISP5_IRQ_IPIPE_INT_REG                         (1 << 4)
+#define ISP5_IRQ_ISIF_INT(i)                           (1 << (i))
+
+#define ISP5_CTRL                                      (0x006c)
+#define ISP5_CTRL_MSTANDBY                             (1 << 24)
+#define ISP5_CTRL_VD_PULSE_EXT                         (1 << 23)
+#define ISP5_CTRL_MSTANDBY_WAIT                                (1 << 20)
+#define ISP5_CTRL_BL_CLK_ENABLE                                (1 << 15)
+#define ISP5_CTRL_ISIF_CLK_ENABLE                      (1 << 14)
+#define ISP5_CTRL_H3A_CLK_ENABLE                       (1 << 13)
+#define ISP5_CTRL_RSZ_CLK_ENABLE                       (1 << 12)
+#define ISP5_CTRL_IPIPE_CLK_ENABLE                     (1 << 11)
+#define ISP5_CTRL_IPIPEIF_CLK_ENABLE                   (1 << 10)
+#define ISP5_CTRL_SYNC_ENABLE                          (1 << 9)
+#define ISP5_CTRL_PSYNC_CLK_SEL                                (1 << 8)
+
+/* ISS ISP ISIF register offsets */
+#define ISIF_SYNCEN                                    (0x0000)
+#define ISIF_SYNCEN_DWEN                               (1 << 1)
+#define ISIF_SYNCEN_SYEN                               (1 << 0)
+
+#define ISIF_MODESET                                   (0x0004)
+#define ISIF_MODESET_INPMOD_MASK                       (3 << 12)
+#define ISIF_MODESET_INPMOD_RAW                                (0 << 12)
+#define ISIF_MODESET_INPMOD_YCBCR16                    (1 << 12)
+#define ISIF_MODESET_INPMOD_YCBCR8                     (2 << 12)
+#define ISIF_MODESET_CCDW_MASK                         (7 << 8)
+#define ISIF_MODESET_CCDW_2BIT                         (2 << 8)
+#define ISIF_MODESET_CCDMD                             (1 << 7)
+#define ISIF_MODESET_SWEN                              (1 << 5)
+#define ISIF_MODESET_HDPOL                             (1 << 3)
+#define ISIF_MODESET_VDPOL                             (1 << 2)
+
+#define ISIF_SPH                                       (0x0018)
+#define ISIF_SPH_MASK                                  (0x7fff)
+
+#define ISIF_LNH                                       (0x001c)
+#define ISIF_LNH_MASK                                  (0x7fff)
+
+#define ISIF_LNV                                       (0x0028)
+#define ISIF_LNV_MASK                                  (0x7fff)
+
+#define ISIF_HSIZE                                     (0x0034)
+#define ISIF_HSIZE_ADCR                                        (1 << 12)
+#define ISIF_HSIZE_HSIZE_MASK                          (0xfff)
+
+#define ISIF_CADU                                      (0x003c)
+#define ISIF_CADU_MASK                                 (0x7ff)
+
+#define ISIF_CADL                                      (0x0040)
+#define ISIF_CADL_MASK                                 (0xffff)
+
+#define ISIF_CCOLP                                     (0x004c)
+#define ISIF_CCOLP_CP0_F0_R                            (0 << 6)
+#define ISIF_CCOLP_CP0_F0_GR                           (1 << 6)
+#define ISIF_CCOLP_CP0_F0_B                            (3 << 6)
+#define ISIF_CCOLP_CP0_F0_GB                           (2 << 6)
+#define ISIF_CCOLP_CP1_F0_R                            (0 << 4)
+#define ISIF_CCOLP_CP1_F0_GR                           (1 << 4)
+#define ISIF_CCOLP_CP1_F0_B                            (3 << 4)
+#define ISIF_CCOLP_CP1_F0_GB                           (2 << 4)
+#define ISIF_CCOLP_CP2_F0_R                            (0 << 2)
+#define ISIF_CCOLP_CP2_F0_GR                           (1 << 2)
+#define ISIF_CCOLP_CP2_F0_B                            (3 << 2)
+#define ISIF_CCOLP_CP2_F0_GB                           (2 << 2)
+#define ISIF_CCOLP_CP3_F0_R                            (0 << 0)
+#define ISIF_CCOLP_CP3_F0_GR                           (1 << 0)
+#define ISIF_CCOLP_CP3_F0_B                            (3 << 0)
+#define ISIF_CCOLP_CP3_F0_GB                           (2 << 0)
+
+#define ISIF_VDINT(i)                                  (0x0070 + (i) * 4)
+#define ISIF_VDINT_MASK                                        (0x7fff)
+
+#define ISIF_CGAMMAWD                                  (0x0080)
+#define ISIF_CGAMMAWD_GWDI_MASK                                (0xf << 1)
+#define ISIF_CGAMMAWD_GWDI(bpp)                                ((16 - (bpp)) << 1)
+
+#define ISIF_CCDCFG                                    (0x0088)
+#define ISIF_CCDCFG_Y8POS                              (1 << 11)
+
+/* ISS ISP IPIPEIF register offsets */
+#define IPIPEIF_ENABLE                                 (0x0000)
+
+#define IPIPEIF_CFG1                                   (0x0004)
+#define IPIPEIF_CFG1_INPSRC1_MASK                      (3 << 14)
+#define IPIPEIF_CFG1_INPSRC1_VPORT_RAW                 (0 << 14)
+#define IPIPEIF_CFG1_INPSRC1_SDRAM_RAW                 (1 << 14)
+#define IPIPEIF_CFG1_INPSRC1_ISIF_DARKFM               (2 << 14)
+#define IPIPEIF_CFG1_INPSRC1_SDRAM_YUV                 (3 << 14)
+#define IPIPEIF_CFG1_INPSRC2_MASK                      (3 << 2)
+#define IPIPEIF_CFG1_INPSRC2_ISIF                      (0 << 2)
+#define IPIPEIF_CFG1_INPSRC2_SDRAM_RAW                 (1 << 2)
+#define IPIPEIF_CFG1_INPSRC2_ISIF_DARKFM               (2 << 2)
+#define IPIPEIF_CFG1_INPSRC2_SDRAM_YUV                 (3 << 2)
+
+#define IPIPEIF_CFG2                                   (0x0030)
+#define IPIPEIF_CFG2_YUV8P                             (1 << 7)
+#define IPIPEIF_CFG2_YUV8                              (1 << 6)
+#define IPIPEIF_CFG2_YUV16                             (1 << 3)
+#define IPIPEIF_CFG2_VDPOL                             (1 << 2)
+#define IPIPEIF_CFG2_HDPOL                             (1 << 1)
+#define IPIPEIF_CFG2_INTSW                             (1 << 0)
+
+#define IPIPEIF_CLKDIV                                 (0x0040)
+
+/* ISS ISP IPIPE register offsets */
+#define IPIPE_SRC_EN                                   (0x0000)
+#define IPIPE_SRC_EN_EN                                        (1 << 0)
+
+#define IPIPE_SRC_MODE                                 (0x0004)
+#define IPIPE_SRC_MODE_WRT                             (1 << 1)
+#define IPIPE_SRC_MODE_OST                             (1 << 0)
+
+#define IPIPE_SRC_FMT                                  (0x0008)
+#define IPIPE_SRC_FMT_RAW2YUV                          (0 << 0)
+#define IPIPE_SRC_FMT_RAW2RAW                          (1 << 0)
+#define IPIPE_SRC_FMT_RAW2STATS                                (2 << 0)
+#define IPIPE_SRC_FMT_YUV2YUV                          (3 << 0)
+
+#define IPIPE_SRC_COL                                  (0x000c)
+#define IPIPE_SRC_COL_OO_R                             (0 << 6)
+#define IPIPE_SRC_COL_OO_GR                            (1 << 6)
+#define IPIPE_SRC_COL_OO_B                             (3 << 6)
+#define IPIPE_SRC_COL_OO_GB                            (2 << 6)
+#define IPIPE_SRC_COL_OE_R                             (0 << 4)
+#define IPIPE_SRC_COL_OE_GR                            (1 << 4)
+#define IPIPE_SRC_COL_OE_B                             (3 << 4)
+#define IPIPE_SRC_COL_OE_GB                            (2 << 4)
+#define IPIPE_SRC_COL_EO_R                             (0 << 2)
+#define IPIPE_SRC_COL_EO_GR                            (1 << 2)
+#define IPIPE_SRC_COL_EO_B                             (3 << 2)
+#define IPIPE_SRC_COL_EO_GB                            (2 << 2)
+#define IPIPE_SRC_COL_EE_R                             (0 << 0)
+#define IPIPE_SRC_COL_EE_GR                            (1 << 0)
+#define IPIPE_SRC_COL_EE_B                             (3 << 0)
+#define IPIPE_SRC_COL_EE_GB                            (2 << 0)
+
+#define IPIPE_SRC_VPS                                  (0x0010)
+#define IPIPE_SRC_VPS_MASK                             (0xffff)
+
+#define IPIPE_SRC_VSZ                                  (0x0014)
+#define IPIPE_SRC_VSZ_MASK                             (0x1fff)
+
+#define IPIPE_SRC_HPS                                  (0x0018)
+#define IPIPE_SRC_HPS_MASK                             (0xffff)
+
+#define IPIPE_SRC_HSZ                                  (0x001c)
+#define IPIPE_SRC_HSZ_MASK                             (0x1ffe)
+
+#define IPIPE_SEL_SBU                                  (0x0020)
+
+#define IPIPE_SRC_STA                                  (0x0024)
+
+#define IPIPE_GCK_MMR                                  (0x0028)
+#define IPIPE_GCK_MMR_REG                              (1 << 0)
+
+#define IPIPE_GCK_PIX                                  (0x002c)
+#define IPIPE_GCK_PIX_G3                               (1 << 3)
+#define IPIPE_GCK_PIX_G2                               (1 << 2)
+#define IPIPE_GCK_PIX_G1                               (1 << 1)
+#define IPIPE_GCK_PIX_G0                               (1 << 0)
+
+#define IPIPE_DPC_LUT_EN                               (0x0034)
+#define IPIPE_DPC_LUT_SEL                              (0x0038)
+#define IPIPE_DPC_LUT_ADR                              (0x003c)
+#define IPIPE_DPC_LUT_SIZ                              (0x0040)
+
+#define IPIPE_DPC_OTF_EN                               (0x0044)
+#define IPIPE_DPC_OTF_TYP                              (0x0048)
+#define IPIPE_DPC_OTF_2_D_THR_R                                (0x004c)
+#define IPIPE_DPC_OTF_2_D_THR_GR                       (0x0050)
+#define IPIPE_DPC_OTF_2_D_THR_GB                       (0x0054)
+#define IPIPE_DPC_OTF_2_D_THR_B                                (0x0058)
+#define IPIPE_DPC_OTF_2_C_THR_R                                (0x005c)
+#define IPIPE_DPC_OTF_2_C_THR_GR                       (0x0060)
+#define IPIPE_DPC_OTF_2_C_THR_GB                       (0x0064)
+#define IPIPE_DPC_OTF_2_C_THR_B                                (0x0068)
+#define IPIPE_DPC_OTF_3_SHF                            (0x006c)
+#define IPIPE_DPC_OTF_3_D_THR                          (0x0070)
+#define IPIPE_DPC_OTF_3_D_SPL                          (0x0074)
+#define IPIPE_DPC_OTF_3_D_MIN                          (0x0078)
+#define IPIPE_DPC_OTF_3_D_MAX                          (0x007c)
+#define IPIPE_DPC_OTF_3_C_THR                          (0x0080)
+#define IPIPE_DPC_OTF_3_C_SLP                          (0x0084)
+#define IPIPE_DPC_OTF_3_C_MIN                          (0x0088)
+#define IPIPE_DPC_OTF_3_C_MAX                          (0x008c)
+
+#define IPIPE_LSC_VOFT                                 (0x0090)
+#define IPIPE_LSC_VA2                                  (0x0094)
+#define IPIPE_LSC_VA1                                  (0x0098)
+#define IPIPE_LSC_VS                                   (0x009c)
+#define IPIPE_LSC_HOFT                                 (0x00a0)
+#define IPIPE_LSC_HA2                                  (0x00a4)
+#define IPIPE_LSC_HA1                                  (0x00a8)
+#define IPIPE_LSC_HS                                   (0x00ac)
+#define IPIPE_LSC_GAN_R                                        (0x00b0)
+#define IPIPE_LSC_GAN_GR                               (0x00b4)
+#define IPIPE_LSC_GAN_GB                               (0x00b8)
+#define IPIPE_LSC_GAN_B                                        (0x00bc)
+#define IPIPE_LSC_OFT_R                                        (0x00c0)
+#define IPIPE_LSC_OFT_GR                               (0x00c4)
+#define IPIPE_LSC_OFT_GB                               (0x00c8)
+#define IPIPE_LSC_OFT_B                                        (0x00cc)
+#define IPIPE_LSC_SHF                                  (0x00d0)
+#define IPIPE_LSC_MAX                                  (0x00d4)
+
+#define IPIPE_D2F_1ST_EN                               (0x00d8)
+#define IPIPE_D2F_1ST_TYP                              (0x00dc)
+#define IPIPE_D2F_1ST_THR_00                           (0x00e0)
+#define IPIPE_D2F_1ST_THR_01                           (0x00e4)
+#define IPIPE_D2F_1ST_THR_02                           (0x00e8)
+#define IPIPE_D2F_1ST_THR_03                           (0x00ec)
+#define IPIPE_D2F_1ST_THR_04                           (0x00f0)
+#define IPIPE_D2F_1ST_THR_05                           (0x00f4)
+#define IPIPE_D2F_1ST_THR_06                           (0x00f8)
+#define IPIPE_D2F_1ST_THR_07                           (0x00fc)
+#define IPIPE_D2F_1ST_STR_00                           (0x0100)
+#define IPIPE_D2F_1ST_STR_01                           (0x0104)
+#define IPIPE_D2F_1ST_STR_02                           (0x0108)
+#define IPIPE_D2F_1ST_STR_03                           (0x010c)
+#define IPIPE_D2F_1ST_STR_04                           (0x0110)
+#define IPIPE_D2F_1ST_STR_05                           (0x0114)
+#define IPIPE_D2F_1ST_STR_06                           (0x0118)
+#define IPIPE_D2F_1ST_STR_07                           (0x011c)
+#define IPIPE_D2F_1ST_SPR_00                           (0x0120)
+#define IPIPE_D2F_1ST_SPR_01                           (0x0124)
+#define IPIPE_D2F_1ST_SPR_02                           (0x0128)
+#define IPIPE_D2F_1ST_SPR_03                           (0x012c)
+#define IPIPE_D2F_1ST_SPR_04                           (0x0130)
+#define IPIPE_D2F_1ST_SPR_05                           (0x0134)
+#define IPIPE_D2F_1ST_SPR_06                           (0x0138)
+#define IPIPE_D2F_1ST_SPR_07                           (0x013c)
+#define IPIPE_D2F_1ST_EDG_MIN                          (0x0140)
+#define IPIPE_D2F_1ST_EDG_MAX                          (0x0144)
+#define IPIPE_D2F_2ND_EN                               (0x0148)
+#define IPIPE_D2F_2ND_TYP                              (0x014c)
+#define IPIPE_D2F_2ND_THR00                            (0x0150)
+#define IPIPE_D2F_2ND_THR01                            (0x0154)
+#define IPIPE_D2F_2ND_THR02                            (0x0158)
+#define IPIPE_D2F_2ND_THR03                            (0x015c)
+#define IPIPE_D2F_2ND_THR04                            (0x0160)
+#define IPIPE_D2F_2ND_THR05                            (0x0164)
+#define IPIPE_D2F_2ND_THR06                            (0x0168)
+#define IPIPE_D2F_2ND_THR07                            (0x016c)
+#define IPIPE_D2F_2ND_STR_00                           (0x0170)
+#define IPIPE_D2F_2ND_STR_01                           (0x0174)
+#define IPIPE_D2F_2ND_STR_02                           (0x0178)
+#define IPIPE_D2F_2ND_STR_03                           (0x017c)
+#define IPIPE_D2F_2ND_STR_04                           (0x0180)
+#define IPIPE_D2F_2ND_STR_05                           (0x0184)
+#define IPIPE_D2F_2ND_STR_06                           (0x0188)
+#define IPIPE_D2F_2ND_STR_07                           (0x018c)
+#define IPIPE_D2F_2ND_SPR_00                           (0x0190)
+#define IPIPE_D2F_2ND_SPR_01                           (0x0194)
+#define IPIPE_D2F_2ND_SPR_02                           (0x0198)
+#define IPIPE_D2F_2ND_SPR_03                           (0x019c)
+#define IPIPE_D2F_2ND_SPR_04                           (0x01a0)
+#define IPIPE_D2F_2ND_SPR_05                           (0x01a4)
+#define IPIPE_D2F_2ND_SPR_06                           (0x01a8)
+#define IPIPE_D2F_2ND_SPR_07                           (0x01ac)
+#define IPIPE_D2F_2ND_EDG_MIN                          (0x01b0)
+#define IPIPE_D2F_2ND_EDG_MAX                          (0x01b4)
+
+#define IPIPE_GIC_EN                                   (0x01b8)
+#define IPIPE_GIC_TYP                                  (0x01bc)
+#define IPIPE_GIC_GAN                                  (0x01c0)
+#define IPIPE_GIC_NFGAIN                               (0x01c4)
+#define IPIPE_GIC_THR                                  (0x01c8)
+#define IPIPE_GIC_SLP                                  (0x01cc)
+
+#define IPIPE_WB2_OFT_R                                        (0x01d0)
+#define IPIPE_WB2_OFT_GR                               (0x01d4)
+#define IPIPE_WB2_OFT_GB                               (0x01d8)
+#define IPIPE_WB2_OFT_B                                        (0x01dc)
+
+#define IPIPE_WB2_WGN_R                                        (0x01e0)
+#define IPIPE_WB2_WGN_GR                               (0x01e4)
+#define IPIPE_WB2_WGN_GB                               (0x01e8)
+#define IPIPE_WB2_WGN_B                                        (0x01ec)
+
+#define IPIPE_CFA_MODE                                 (0x01f0)
+#define IPIPE_CFA_2DIR_HPF_THR                         (0x01f4)
+#define IPIPE_CFA_2DIR_HPF_SLP                         (0x01f8)
+#define IPIPE_CFA_2DIR_MIX_THR                         (0x01fc)
+#define IPIPE_CFA_2DIR_MIX_SLP                         (0x0200)
+#define IPIPE_CFA_2DIR_DIR_TRH                         (0x0204)
+#define IPIPE_CFA_2DIR_DIR_SLP                         (0x0208)
+#define IPIPE_CFA_2DIR_NDWT                            (0x020c)
+#define IPIPE_CFA_MONO_HUE_FRA                         (0x0210)
+#define IPIPE_CFA_MONO_EDG_THR                         (0x0214)
+#define IPIPE_CFA_MONO_THR_MIN                         (0x0218)
+
+#define IPIPE_CFA_MONO_THR_SLP                         (0x021c)
+#define IPIPE_CFA_MONO_SLP_MIN                         (0x0220)
+#define IPIPE_CFA_MONO_SLP_SLP                         (0x0224)
+#define IPIPE_CFA_MONO_LPWT                            (0x0228)
+
+#define IPIPE_RGB1_MUL_RR                              (0x022c)
+#define IPIPE_RGB1_MUL_GR                              (0x0230)
+#define IPIPE_RGB1_MUL_BR                              (0x0234)
+#define IPIPE_RGB1_MUL_RG                              (0x0238)
+#define IPIPE_RGB1_MUL_GG                              (0x023c)
+#define IPIPE_RGB1_MUL_BG                              (0x0240)
+#define IPIPE_RGB1_MUL_RB                              (0x0244)
+#define IPIPE_RGB1_MUL_GB                              (0x0248)
+#define IPIPE_RGB1_MUL_BB                              (0x024c)
+#define IPIPE_RGB1_OFT_OR                              (0x0250)
+#define IPIPE_RGB1_OFT_OG                              (0x0254)
+#define IPIPE_RGB1_OFT_OB                              (0x0258)
+#define IPIPE_GMM_CFG                                  (0x025c)
+#define IPIPE_RGB2_MUL_RR                              (0x0260)
+#define IPIPE_RGB2_MUL_GR                              (0x0264)
+#define IPIPE_RGB2_MUL_BR                              (0x0268)
+#define IPIPE_RGB2_MUL_RG                              (0x026c)
+#define IPIPE_RGB2_MUL_GG                              (0x0270)
+#define IPIPE_RGB2_MUL_BG                              (0x0274)
+#define IPIPE_RGB2_MUL_RB                              (0x0278)
+#define IPIPE_RGB2_MUL_GB                              (0x027c)
+#define IPIPE_RGB2_MUL_BB                              (0x0280)
+#define IPIPE_RGB2_OFT_OR                              (0x0284)
+#define IPIPE_RGB2_OFT_OG                              (0x0288)
+#define IPIPE_RGB2_OFT_OB                              (0x028c)
+
+#define IPIPE_YUV_ADJ                                  (0x0294)
+#define IPIPE_YUV_MUL_RY                               (0x0298)
+#define IPIPE_YUV_MUL_GY                               (0x029c)
+#define IPIPE_YUV_MUL_BY                               (0x02a0)
+#define IPIPE_YUV_MUL_RCB                              (0x02a4)
+#define IPIPE_YUV_MUL_GCB                              (0x02a8)
+#define IPIPE_YUV_MUL_BCB                              (0x02ac)
+#define IPIPE_YUV_MUL_RCR                              (0x02b0)
+#define IPIPE_YUV_MUL_GCR                              (0x02b4)
+#define IPIPE_YUV_MUL_BCR                              (0x02b8)
+#define IPIPE_YUV_OFT_Y                                        (0x02bc)
+#define IPIPE_YUV_OFT_CB                               (0x02c0)
+#define IPIPE_YUV_OFT_CR                               (0x02c4)
+
+#define IPIPE_YUV_PHS                                  (0x02c8)
+#define IPIPE_YUV_PHS_LPF                              (1 << 1)
+#define IPIPE_YUV_PHS_POS                              (1 << 0)
+
+#define IPIPE_YEE_EN                                   (0x02d4)
+#define IPIPE_YEE_TYP                                  (0x02d8)
+#define IPIPE_YEE_SHF                                  (0x02dc)
+#define IPIPE_YEE_MUL_00                               (0x02e0)
+#define IPIPE_YEE_MUL_01                               (0x02e4)
+#define IPIPE_YEE_MUL_02                               (0x02e8)
+#define IPIPE_YEE_MUL_10                               (0x02ec)
+#define IPIPE_YEE_MUL_11                               (0x02f0)
+#define IPIPE_YEE_MUL_12                               (0x02f4)
+#define IPIPE_YEE_MUL_20                               (0x02f8)
+#define IPIPE_YEE_MUL_21                               (0x02fc)
+#define IPIPE_YEE_MUL_22                               (0x0300)
+#define IPIPE_YEE_THR                                  (0x0304)
+#define IPIPE_YEE_E_GAN                                        (0x0308)
+#define IPIPE_YEE_E_THR_1                              (0x030c)
+#define IPIPE_YEE_E_THR_2                              (0x0310)
+#define IPIPE_YEE_G_GAN                                        (0x0314)
+#define IPIPE_YEE_G_OFT                                        (0x0318)
+
+#define IPIPE_CAR_EN                                   (0x031c)
+#define IPIPE_CAR_TYP                                  (0x0320)
+#define IPIPE_CAR_SW                                   (0x0324)
+#define IPIPE_CAR_HPF_TYP                              (0x0328)
+#define IPIPE_CAR_HPF_SHF                              (0x032c)
+#define IPIPE_CAR_HPF_THR                              (0x0330)
+#define IPIPE_CAR_GN1_GAN                              (0x0334)
+#define IPIPE_CAR_GN1_SHF                              (0x0338)
+#define IPIPE_CAR_GN1_MIN                              (0x033c)
+#define IPIPE_CAR_GN2_GAN                              (0x0340)
+#define IPIPE_CAR_GN2_SHF                              (0x0344)
+#define IPIPE_CAR_GN2_MIN                              (0x0348)
+#define IPIPE_CGS_EN                                   (0x034c)
+#define IPIPE_CGS_GN1_L_THR                            (0x0350)
+#define IPIPE_CGS_GN1_L_GAIN                           (0x0354)
+#define IPIPE_CGS_GN1_L_SHF                            (0x0358)
+#define IPIPE_CGS_GN1_L_MIN                            (0x035c)
+#define IPIPE_CGS_GN1_H_THR                            (0x0360)
+#define IPIPE_CGS_GN1_H_GAIN                           (0x0364)
+#define IPIPE_CGS_GN1_H_SHF                            (0x0368)
+#define IPIPE_CGS_GN1_H_MIN                            (0x036c)
+#define IPIPE_CGS_GN2_L_THR                            (0x0370)
+#define IPIPE_CGS_GN2_L_GAIN                           (0x0374)
+#define IPIPE_CGS_GN2_L_SHF                            (0x0378)
+#define IPIPE_CGS_GN2_L_MIN                            (0x037c)
+
+#define IPIPE_BOX_EN                                   (0x0380)
+#define IPIPE_BOX_MODE                                 (0x0384)
+#define IPIPE_BOX_TYP                                  (0x0388)
+#define IPIPE_BOX_SHF                                  (0x038c)
+#define IPIPE_BOX_SDR_SAD_H                            (0x0390)
+#define IPIPE_BOX_SDR_SAD_L                            (0x0394)
+
+#define IPIPE_HST_EN                                   (0x039c)
+#define IPIPE_HST_MODE                                 (0x03a0)
+#define IPIPE_HST_SEL                                  (0x03a4)
+#define IPIPE_HST_PARA                                 (0x03a8)
+#define IPIPE_HST_0_VPS                                        (0x03ac)
+#define IPIPE_HST_0_VSZ                                        (0x03b0)
+#define IPIPE_HST_0_HPS                                        (0x03b4)
+#define IPIPE_HST_0_HSZ                                        (0x03b8)
+#define IPIPE_HST_1_VPS                                        (0x03bc)
+#define IPIPE_HST_1_VSZ                                        (0x03c0)
+#define IPIPE_HST_1_HPS                                        (0x03c4)
+#define IPIPE_HST_1_HSZ                                        (0x03c8)
+#define IPIPE_HST_2_VPS                                        (0x03cc)
+#define IPIPE_HST_2_VSZ                                        (0x03d0)
+#define IPIPE_HST_2_HPS                                        (0x03d4)
+#define IPIPE_HST_2_HSZ                                        (0x03d8)
+#define IPIPE_HST_3_VPS                                        (0x03dc)
+#define IPIPE_HST_3_VSZ                                        (0x03e0)
+#define IPIPE_HST_3_HPS                                        (0x03e4)
+#define IPIPE_HST_3_HSZ                                        (0x03e8)
+#define IPIPE_HST_TBL                                  (0x03ec)
+#define IPIPE_HST_MUL_R                                        (0x03f0)
+#define IPIPE_HST_MUL_GR                               (0x03f4)
+#define IPIPE_HST_MUL_GB                               (0x03f8)
+#define IPIPE_HST_MUL_B                                        (0x03fc)
+
+#define IPIPE_BSC_EN                                   (0x0400)
+#define IPIPE_BSC_MODE                                 (0x0404)
+#define IPIPE_BSC_TYP                                  (0x0408)
+#define IPIPE_BSC_ROW_VCT                              (0x040c)
+#define IPIPE_BSC_ROW_SHF                              (0x0410)
+#define IPIPE_BSC_ROW_VPO                              (0x0414)
+#define IPIPE_BSC_ROW_VNU                              (0x0418)
+#define IPIPE_BSC_ROW_VSKIP                            (0x041c)
+#define IPIPE_BSC_ROW_HPO                              (0x0420)
+#define IPIPE_BSC_ROW_HNU                              (0x0424)
+#define IPIPE_BSC_ROW_HSKIP                            (0x0428)
+#define IPIPE_BSC_COL_VCT                              (0x042c)
+#define IPIPE_BSC_COL_SHF                              (0x0430)
+#define IPIPE_BSC_COL_VPO                              (0x0434)
+#define IPIPE_BSC_COL_VNU                              (0x0438)
+#define IPIPE_BSC_COL_VSKIP                            (0x043c)
+#define IPIPE_BSC_COL_HPO                              (0x0440)
+#define IPIPE_BSC_COL_HNU                              (0x0444)
+#define IPIPE_BSC_COL_HSKIP                            (0x0448)
+
+#define IPIPE_BSC_EN                                   (0x0400)
+
+/* ISS ISP Resizer register offsets */
+#define RSZ_REVISION                                   (0x0000)
+#define RSZ_SYSCONFIG                                  (0x0004)
+#define RSZ_SYSCONFIG_RSZB_CLK_EN                      (1 << 9)
+#define RSZ_SYSCONFIG_RSZA_CLK_EN                      (1 << 8)
+
+#define RSZ_IN_FIFO_CTRL                               (0x000c)
+#define RSZ_IN_FIFO_CTRL_THRLD_LOW_MASK                        (0x1ff << 16)
+#define RSZ_IN_FIFO_CTRL_THRLD_LOW_SHIFT               16
+#define RSZ_IN_FIFO_CTRL_THRLD_HIGH_MASK               (0x1ff << 0)
+#define RSZ_IN_FIFO_CTRL_THRLD_HIGH_SHIFT              0
+
+#define RSZ_FRACDIV                                    (0x0008)
+#define RSZ_FRACDIV_MASK                               (0xffff)
+
+#define RSZ_SRC_EN                                     (0x0020)
+#define RSZ_SRC_EN_SRC_EN                              (1 << 0)
+
+#define RSZ_SRC_MODE                                   (0x0024)
+#define RSZ_SRC_MODE_OST                               (1 << 0)
+#define RSZ_SRC_MODE_WRT                               (1 << 1)
+
+#define RSZ_SRC_FMT0                                   (0x0028)
+#define RSZ_SRC_FMT0_BYPASS                            (1 << 1)
+#define RSZ_SRC_FMT0_SEL                               (1 << 0)
+
+#define RSZ_SRC_FMT1                                   (0x002c)
+#define RSZ_SRC_FMT1_IN420                             (1 << 1)
+
+#define RSZ_SRC_VPS                                    (0x0030)
+#define RSZ_SRC_VSZ                                    (0x0034)
+#define RSZ_SRC_HPS                                    (0x0038)
+#define RSZ_SRC_HSZ                                    (0x003c)
+#define RSZ_DMA_RZA                                    (0x0040)
+#define RSZ_DMA_RZB                                    (0x0044)
+#define RSZ_DMA_STA                                    (0x0048)
+#define RSZ_GCK_MMR                                    (0x004c)
+#define RSZ_GCK_MMR_MMR                                        (1 << 0)
+
+#define RSZ_GCK_SDR                                    (0x0054)
+#define RSZ_GCK_SDR_CORE                               (1 << 0)
+
+#define RSZ_IRQ_RZA                                    (0x0058)
+#define RSZ_IRQ_RZA_MASK                               (0x1fff)
+
+#define RSZ_IRQ_RZB                                    (0x005c)
+#define RSZ_IRQ_RZB_MASK                               (0x1fff)
+
+#define RSZ_YUV_Y_MIN                                  (0x0060)
+#define RSZ_YUV_Y_MAX                                  (0x0064)
+#define RSZ_YUV_C_MIN                                  (0x0068)
+#define RSZ_YUV_C_MAX                                  (0x006c)
+
+#define RSZ_SEQ                                                (0x0074)
+#define RSZ_SEQ_HRVB                                   (1 << 2)
+#define RSZ_SEQ_HRVA                                   (1 << 0)
+
+#define RZA_EN                                         (0x0078)
+#define RZA_MODE                                       (0x007c)
+#define RZA_MODE_ONE_SHOT                              (1 << 0)
+
+#define RZA_420                                                (0x0080)
+#define RZA_I_VPS                                      (0x0084)
+#define RZA_I_HPS                                      (0x0088)
+#define RZA_O_VSZ                                      (0x008c)
+#define RZA_O_HSZ                                      (0x0090)
+#define RZA_V_PHS_Y                                    (0x0094)
+#define RZA_V_PHS_C                                    (0x0098)
+#define RZA_V_DIF                                      (0x009c)
+#define RZA_V_TYP                                      (0x00a0)
+#define RZA_V_LPF                                      (0x00a4)
+#define RZA_H_PHS                                      (0x00a8)
+#define RZA_H_DIF                                      (0x00b0)
+#define RZA_H_TYP                                      (0x00b4)
+#define RZA_H_LPF                                      (0x00b8)
+#define RZA_DWN_EN                                     (0x00bc)
+#define RZA_SDR_Y_BAD_H                                        (0x00d0)
+#define RZA_SDR_Y_BAD_L                                        (0x00d4)
+#define RZA_SDR_Y_SAD_H                                        (0x00d8)
+#define RZA_SDR_Y_SAD_L                                        (0x00dc)
+#define RZA_SDR_Y_OFT                                  (0x00e0)
+#define RZA_SDR_Y_PTR_S                                        (0x00e4)
+#define RZA_SDR_Y_PTR_E                                        (0x00e8)
+#define RZA_SDR_C_BAD_H                                        (0x00ec)
+#define RZA_SDR_C_BAD_L                                        (0x00f0)
+#define RZA_SDR_C_SAD_H                                        (0x00f4)
+#define RZA_SDR_C_SAD_L                                        (0x00f8)
+#define RZA_SDR_C_OFT                                  (0x00fc)
+#define RZA_SDR_C_PTR_S                                        (0x0100)
+#define RZA_SDR_C_PTR_E                                        (0x0104)
+
+#define RZB_EN                                         (0x0108)
+#define RZB_MODE                                       (0x010c)
+#define RZB_420                                                (0x0110)
+#define RZB_I_VPS                                      (0x0114)
+#define RZB_I_HPS                                      (0x0118)
+#define RZB_O_VSZ                                      (0x011c)
+#define RZB_O_HSZ                                      (0x0120)
+
+#define RZB_V_DIF                                      (0x012c)
+#define RZB_V_TYP                                      (0x0130)
+#define RZB_V_LPF                                      (0x0134)
+
+#define RZB_H_DIF                                      (0x0140)
+#define RZB_H_TYP                                      (0x0144)
+#define RZB_H_LPF                                      (0x0148)
+
+#define RZB_SDR_Y_BAD_H                                        (0x0160)
+#define RZB_SDR_Y_BAD_L                                        (0x0164)
+#define RZB_SDR_Y_SAD_H                                        (0x0168)
+#define RZB_SDR_Y_SAD_L                                        (0x016c)
+#define RZB_SDR_Y_OFT                                  (0x0170)
+#define RZB_SDR_Y_PTR_S                                        (0x0174)
+#define RZB_SDR_Y_PTR_E                                        (0x0178)
+#define RZB_SDR_C_BAD_H                                        (0x017c)
+#define RZB_SDR_C_BAD_L                                        (0x0180)
+#define RZB_SDR_C_SAD_H                                        (0x0184)
+#define RZB_SDR_C_SAD_L                                        (0x0188)
+
+#define RZB_SDR_C_PTR_S                                        (0x0190)
+#define RZB_SDR_C_PTR_E                                        (0x0194)
+
+/* Shared Bitmasks between RZA & RZB */
+#define RSZ_EN_EN                                      (1 << 0)
+
+#define RSZ_420_CEN                                    (1 << 1)
+#define RSZ_420_YEN                                    (1 << 0)
+
+#define RSZ_I_VPS_MASK                                 (0x1fff)
+
+#define RSZ_I_HPS_MASK                                 (0x1fff)
+
+#define RSZ_O_VSZ_MASK                                 (0x1fff)
+
+#define RSZ_O_HSZ_MASK                                 (0x1ffe)
+
+#define RSZ_V_PHS_Y_MASK                               (0x3fff)
+
+#define RSZ_V_PHS_C_MASK                               (0x3fff)
+
+#define RSZ_V_DIF_MASK                                 (0x3fff)
+
+#define RSZ_V_TYP_C                                    (1 << 1)
+#define RSZ_V_TYP_Y                                    (1 << 0)
+
+#define RSZ_V_LPF_C_MASK                               (0x3f << 6)
+#define RSZ_V_LPF_C_SHIFT                              6
+#define RSZ_V_LPF_Y_MASK                               (0x3f << 0)
+#define RSZ_V_LPF_Y_SHIFT                              0
+
+#define RSZ_H_PHS_MASK                                 (0x3fff)
+
+#define RSZ_H_DIF_MASK                                 (0x3fff)
+
+#define RSZ_H_TYP_C                                    (1 << 1)
+#define RSZ_H_TYP_Y                                    (1 << 0)
+
+#define RSZ_H_LPF_C_MASK                               (0x3f << 6)
+#define RSZ_H_LPF_C_SHIFT                              6
+#define RSZ_H_LPF_Y_MASK                               (0x3f << 0)
+#define RSZ_H_LPF_Y_SHIFT                              0
+
+#define RSZ_DWN_EN_DWN_EN                              (1 << 0)
+
+#endif /* _OMAP4_ISS_REGS_H_ */
diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c
new file mode 100644 (file)
index 0000000..ae831b8
--- /dev/null
@@ -0,0 +1,893 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - ISP RESIZER module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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 <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include "iss.h"
+#include "iss_regs.h"
+#include "iss_resizer.h"
+
+static const unsigned int resizer_fmts[] = {
+       V4L2_MBUS_FMT_UYVY8_1X16,
+       V4L2_MBUS_FMT_YUYV8_1X16,
+};
+
+/*
+ * resizer_print_status - Print current RESIZER Module register values.
+ * @resizer: Pointer to ISS ISP RESIZER device.
+ *
+ * Also prints other debug information stored in the RESIZER module.
+ */
+#define RSZ_PRINT_REGISTER(iss, name)\
+       dev_dbg(iss->dev, "###RSZ " #name "=0x%08x\n", \
+               iss_reg_read(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_##name))
+
+#define RZA_PRINT_REGISTER(iss, name)\
+       dev_dbg(iss->dev, "###RZA " #name "=0x%08x\n", \
+               iss_reg_read(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_##name))
+
+static void resizer_print_status(struct iss_resizer_device *resizer)
+{
+       struct iss_device *iss = to_iss_device(resizer);
+
+       dev_dbg(iss->dev, "-------------RESIZER Register dump-------------\n");
+
+       RSZ_PRINT_REGISTER(iss, SYSCONFIG);
+       RSZ_PRINT_REGISTER(iss, IN_FIFO_CTRL);
+       RSZ_PRINT_REGISTER(iss, FRACDIV);
+       RSZ_PRINT_REGISTER(iss, SRC_EN);
+       RSZ_PRINT_REGISTER(iss, SRC_MODE);
+       RSZ_PRINT_REGISTER(iss, SRC_FMT0);
+       RSZ_PRINT_REGISTER(iss, SRC_FMT1);
+       RSZ_PRINT_REGISTER(iss, SRC_VPS);
+       RSZ_PRINT_REGISTER(iss, SRC_VSZ);
+       RSZ_PRINT_REGISTER(iss, SRC_HPS);
+       RSZ_PRINT_REGISTER(iss, SRC_HSZ);
+       RSZ_PRINT_REGISTER(iss, DMA_RZA);
+       RSZ_PRINT_REGISTER(iss, DMA_RZB);
+       RSZ_PRINT_REGISTER(iss, DMA_STA);
+       RSZ_PRINT_REGISTER(iss, GCK_MMR);
+       RSZ_PRINT_REGISTER(iss, GCK_SDR);
+       RSZ_PRINT_REGISTER(iss, IRQ_RZA);
+       RSZ_PRINT_REGISTER(iss, IRQ_RZB);
+       RSZ_PRINT_REGISTER(iss, YUV_Y_MIN);
+       RSZ_PRINT_REGISTER(iss, YUV_Y_MAX);
+       RSZ_PRINT_REGISTER(iss, YUV_C_MIN);
+       RSZ_PRINT_REGISTER(iss, YUV_C_MAX);
+       RSZ_PRINT_REGISTER(iss, SEQ);
+
+       RZA_PRINT_REGISTER(iss, EN);
+       RZA_PRINT_REGISTER(iss, MODE);
+       RZA_PRINT_REGISTER(iss, 420);
+       RZA_PRINT_REGISTER(iss, I_VPS);
+       RZA_PRINT_REGISTER(iss, I_HPS);
+       RZA_PRINT_REGISTER(iss, O_VSZ);
+       RZA_PRINT_REGISTER(iss, O_HSZ);
+       RZA_PRINT_REGISTER(iss, V_PHS_Y);
+       RZA_PRINT_REGISTER(iss, V_PHS_C);
+       RZA_PRINT_REGISTER(iss, V_DIF);
+       RZA_PRINT_REGISTER(iss, V_TYP);
+       RZA_PRINT_REGISTER(iss, V_LPF);
+       RZA_PRINT_REGISTER(iss, H_PHS);
+       RZA_PRINT_REGISTER(iss, H_DIF);
+       RZA_PRINT_REGISTER(iss, H_TYP);
+       RZA_PRINT_REGISTER(iss, H_LPF);
+       RZA_PRINT_REGISTER(iss, DWN_EN);
+       RZA_PRINT_REGISTER(iss, SDR_Y_BAD_H);
+       RZA_PRINT_REGISTER(iss, SDR_Y_BAD_L);
+       RZA_PRINT_REGISTER(iss, SDR_Y_SAD_H);
+       RZA_PRINT_REGISTER(iss, SDR_Y_SAD_L);
+       RZA_PRINT_REGISTER(iss, SDR_Y_OFT);
+       RZA_PRINT_REGISTER(iss, SDR_Y_PTR_S);
+       RZA_PRINT_REGISTER(iss, SDR_Y_PTR_E);
+       RZA_PRINT_REGISTER(iss, SDR_C_BAD_H);
+       RZA_PRINT_REGISTER(iss, SDR_C_BAD_L);
+       RZA_PRINT_REGISTER(iss, SDR_C_SAD_H);
+       RZA_PRINT_REGISTER(iss, SDR_C_SAD_L);
+       RZA_PRINT_REGISTER(iss, SDR_C_OFT);
+       RZA_PRINT_REGISTER(iss, SDR_C_PTR_S);
+       RZA_PRINT_REGISTER(iss, SDR_C_PTR_E);
+
+       dev_dbg(iss->dev, "-----------------------------------------------\n");
+}
+
+/*
+ * resizer_enable - Enable/Disable RESIZER.
+ * @enable: enable flag
+ *
+ */
+static void resizer_enable(struct iss_resizer_device *resizer, u8 enable)
+{
+       struct iss_device *iss = to_iss_device(resizer);
+
+       iss_reg_update(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_EN,
+                      RSZ_SRC_EN_SRC_EN, enable ? RSZ_SRC_EN_SRC_EN : 0);
+
+       /* TODO: Enable RSZB */
+       iss_reg_update(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_EN, RSZ_EN_EN,
+                      enable ? RSZ_EN_EN : 0);
+}
+
+/* -----------------------------------------------------------------------------
+ * Format- and pipeline-related configuration helpers
+ */
+
+/*
+ * resizer_set_outaddr - Set memory address to save output image
+ * @resizer: Pointer to ISP RESIZER device.
+ * @addr: 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ */
+static void resizer_set_outaddr(struct iss_resizer_device *resizer, u32 addr)
+{
+       struct iss_device *iss = to_iss_device(resizer);
+       struct v4l2_mbus_framefmt *informat, *outformat;
+
+       informat = &resizer->formats[RESIZER_PAD_SINK];
+       outformat = &resizer->formats[RESIZER_PAD_SOURCE_MEM];
+
+       /* Save address splitted in Base Address H & L */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_BAD_H,
+                     (addr >> 16) & 0xffff);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_BAD_L,
+                     addr & 0xffff);
+
+       /* SAD = BAD */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_SAD_H,
+                     (addr >> 16) & 0xffff);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_SAD_L,
+                     addr & 0xffff);
+
+       /* Program UV buffer address... Hardcoded to be contiguous! */
+       if ((informat->code == V4L2_MBUS_FMT_UYVY8_1X16) &&
+           (outformat->code == V4L2_MBUS_FMT_YUYV8_1_5X8)) {
+               u32 c_addr = addr + (resizer->video_out.bpl_value *
+                                    (outformat->height - 1));
+
+               /* Ensure Y_BAD_L[6:0] = C_BAD_L[6:0]*/
+               if ((c_addr ^ addr) & 0x7f) {
+                       c_addr &= ~0x7f;
+                       c_addr += 0x80;
+                       c_addr |= addr & 0x7f;
+               }
+
+               /* Save address splitted in Base Address H & L */
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_BAD_H,
+                             (c_addr >> 16) & 0xffff);
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_BAD_L,
+                             c_addr & 0xffff);
+
+               /* SAD = BAD */
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_SAD_H,
+                             (c_addr >> 16) & 0xffff);
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_SAD_L,
+                             c_addr & 0xffff);
+       }
+}
+
+static void resizer_configure(struct iss_resizer_device *resizer)
+{
+       struct iss_device *iss = to_iss_device(resizer);
+       struct v4l2_mbus_framefmt *informat, *outformat;
+
+       informat = &resizer->formats[RESIZER_PAD_SINK];
+       outformat = &resizer->formats[RESIZER_PAD_SOURCE_MEM];
+
+       /* Disable pass-through more. Despite its name, the BYPASS bit controls
+        * pass-through mode, not bypass mode.
+        */
+       iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_FMT0,
+                   RSZ_SRC_FMT0_BYPASS);
+
+       /* Select RSZ input */
+       iss_reg_update(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_FMT0,
+                      RSZ_SRC_FMT0_SEL,
+                      resizer->input == RESIZER_INPUT_IPIPEIF ?
+                      RSZ_SRC_FMT0_SEL : 0);
+
+       /* RSZ ignores WEN signal from IPIPE/IPIPEIF */
+       iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_MODE,
+                   RSZ_SRC_MODE_WRT);
+
+       /* Set Resizer in free-running mode */
+       iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_MODE,
+                   RSZ_SRC_MODE_OST);
+
+       /* Init Resizer A */
+       iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_MODE,
+                   RZA_MODE_ONE_SHOT);
+
+       /* Set size related things now */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_VPS, 0);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_HPS, 0);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_VSZ,
+                     informat->height - 2);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SRC_HSZ,
+                     informat->width - 1);
+
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_I_VPS, 0);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_I_HPS, 0);
+
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_O_VSZ,
+                     outformat->height - 2);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_O_HSZ,
+                     outformat->width - 1);
+
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_V_DIF, 0x100);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_H_DIF, 0x100);
+
+       /* Buffer output settings */
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_PTR_S, 0);
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_PTR_E,
+                     outformat->height - 1);
+
+       iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_Y_OFT,
+                     resizer->video_out.bpl_value);
+
+       /* UYVY -> NV12 conversion */
+       if ((informat->code == V4L2_MBUS_FMT_UYVY8_1X16) &&
+           (outformat->code == V4L2_MBUS_FMT_YUYV8_1_5X8)) {
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_420,
+                             RSZ_420_CEN | RSZ_420_YEN);
+
+               /* UV Buffer output settings */
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_PTR_S,
+                             0);
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_PTR_E,
+                             outformat->height - 1);
+
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_SDR_C_OFT,
+                             resizer->video_out.bpl_value);
+       } else {
+               iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_420, 0);
+       }
+}
+
+/* -----------------------------------------------------------------------------
+ * Interrupt handling
+ */
+
+static void resizer_isr_buffer(struct iss_resizer_device *resizer)
+{
+       struct iss_buffer *buffer;
+
+       /* The whole resizer needs to be stopped. Disabling RZA only produces
+        * input FIFO overflows, most probably when the next frame is received.
+        */
+       resizer_enable(resizer, 0);
+
+       buffer = omap4iss_video_buffer_next(&resizer->video_out);
+       if (buffer == NULL)
+               return;
+
+       resizer_set_outaddr(resizer, buffer->iss_addr);
+
+       resizer_enable(resizer, 1);
+}
+
+/*
+ * resizer_isif0_isr - Handle ISIF0 event
+ * @resizer: Pointer to ISP RESIZER device.
+ *
+ * Executes LSC deferred enablement before next frame starts.
+ */
+static void resizer_int_dma_isr(struct iss_resizer_device *resizer)
+{
+       struct iss_pipeline *pipe =
+                            to_iss_pipeline(&resizer->subdev.entity);
+       if (pipe->do_propagation)
+               atomic_inc(&pipe->frame_number);
+
+       resizer_isr_buffer(resizer);
+}
+
+/*
+ * omap4iss_resizer_isr - Configure resizer during interframe time.
+ * @resizer: Pointer to ISP RESIZER device.
+ * @events: RESIZER events
+ */
+void omap4iss_resizer_isr(struct iss_resizer_device *resizer, u32 events)
+{
+       struct iss_device *iss = to_iss_device(resizer);
+       struct iss_pipeline *pipe =
+                            to_iss_pipeline(&resizer->subdev.entity);
+
+       if (events & (ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR |
+                     ISP5_IRQ_RSZ_FIFO_OVF)) {
+               dev_dbg(iss->dev, "RSZ Err: FIFO_IN_BLK:%d, FIFO_OVF:%d\n",
+                       events & ISP5_IRQ_RSZ_FIFO_IN_BLK_ERR ? 1 : 0,
+                       events & ISP5_IRQ_RSZ_FIFO_OVF ? 1 : 0);
+               omap4iss_pipeline_cancel_stream(pipe);
+       }
+
+       if (omap4iss_module_sync_is_stopping(&resizer->wait,
+                                            &resizer->stopping))
+               return;
+
+       if (events & ISP5_IRQ_RSZ_INT_DMA)
+               resizer_int_dma_isr(resizer);
+}
+
+/* -----------------------------------------------------------------------------
+ * ISS video operations
+ */
+
+static int resizer_video_queue(struct iss_video *video,
+                              struct iss_buffer *buffer)
+{
+       struct iss_resizer_device *resizer = container_of(video,
+                               struct iss_resizer_device, video_out);
+
+       if (!(resizer->output & RESIZER_OUTPUT_MEMORY))
+               return -ENODEV;
+
+       resizer_set_outaddr(resizer, buffer->iss_addr);
+
+       /*
+        * If streaming was enabled before there was a buffer queued
+        * or underrun happened in the ISR, the hardware was not enabled
+        * and DMA queue flag ISS_VIDEO_DMAQUEUE_UNDERRUN is still set.
+        * Enable it now.
+        */
+       if (video->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_UNDERRUN) {
+               resizer_enable(resizer, 1);
+               iss_video_dmaqueue_flags_clr(video);
+       }
+
+       return 0;
+}
+
+static const struct iss_video_operations resizer_video_ops = {
+       .queue = resizer_video_queue,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 subdev operations
+ */
+
+/*
+ * resizer_set_stream - Enable/Disable streaming on the RESIZER module
+ * @sd: ISP RESIZER V4L2 subdevice
+ * @enable: Enable/disable stream
+ */
+static int resizer_set_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
+       struct iss_device *iss = to_iss_device(resizer);
+       struct iss_video *video_out = &resizer->video_out;
+       int ret = 0;
+
+       if (resizer->state == ISS_PIPELINE_STREAM_STOPPED) {
+               if (enable == ISS_PIPELINE_STREAM_STOPPED)
+                       return 0;
+
+               omap4iss_isp_subclk_enable(iss, OMAP4_ISS_ISP_SUBCLK_RSZ);
+
+               iss_reg_set(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_GCK_MMR,
+                           RSZ_GCK_MMR_MMR);
+               iss_reg_set(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_GCK_SDR,
+                           RSZ_GCK_SDR_CORE);
+
+               /* FIXME: Enable RSZB also */
+               iss_reg_set(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SYSCONFIG,
+                           RSZ_SYSCONFIG_RSZA_CLK_EN);
+       }
+
+       switch (enable) {
+       case ISS_PIPELINE_STREAM_CONTINUOUS:
+
+               resizer_configure(resizer);
+               resizer_print_status(resizer);
+
+               /*
+                * When outputting to memory with no buffer available, let the
+                * buffer queue handler start the hardware. A DMA queue flag
+                * ISS_VIDEO_DMAQUEUE_QUEUED will be set as soon as there is
+                * a buffer available.
+                */
+               if (resizer->output & RESIZER_OUTPUT_MEMORY &&
+                   !(video_out->dmaqueue_flags & ISS_VIDEO_DMAQUEUE_QUEUED))
+                       break;
+
+               atomic_set(&resizer->stopping, 0);
+               resizer_enable(resizer, 1);
+               iss_video_dmaqueue_flags_clr(video_out);
+               break;
+
+       case ISS_PIPELINE_STREAM_STOPPED:
+               if (resizer->state == ISS_PIPELINE_STREAM_STOPPED)
+                       return 0;
+               if (omap4iss_module_sync_idle(&sd->entity, &resizer->wait,
+                                             &resizer->stopping))
+                       ret = -ETIMEDOUT;
+
+               resizer_enable(resizer, 0);
+               iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_SYSCONFIG,
+                           RSZ_SYSCONFIG_RSZA_CLK_EN);
+               iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_GCK_SDR,
+                           RSZ_GCK_SDR_CORE);
+               iss_reg_clr(iss, OMAP4_ISS_MEM_ISP_RESIZER, RSZ_GCK_MMR,
+                           RSZ_GCK_MMR_MMR);
+               omap4iss_isp_subclk_disable(iss, OMAP4_ISS_ISP_SUBCLK_RSZ);
+               iss_video_dmaqueue_flags_clr(video_out);
+               break;
+       }
+
+       resizer->state = enable;
+       return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+__resizer_get_format(struct iss_resizer_device *resizer,
+                    struct v4l2_subdev_fh *fh, unsigned int pad,
+                    enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(fh, pad);
+       else
+               return &resizer->formats[pad];
+}
+
+/*
+ * resizer_try_format - Try video format on a pad
+ * @resizer: ISS RESIZER device
+ * @fh : V4L2 subdev file handle
+ * @pad: Pad number
+ * @fmt: Format
+ */
+static void
+resizer_try_format(struct iss_resizer_device *resizer,
+                  struct v4l2_subdev_fh *fh, unsigned int pad,
+                  struct v4l2_mbus_framefmt *fmt,
+                  enum v4l2_subdev_format_whence which)
+{
+       enum v4l2_mbus_pixelcode pixelcode;
+       struct v4l2_mbus_framefmt *format;
+       unsigned int width = fmt->width;
+       unsigned int height = fmt->height;
+       unsigned int i;
+
+       switch (pad) {
+       case RESIZER_PAD_SINK:
+               for (i = 0; i < ARRAY_SIZE(resizer_fmts); i++) {
+                       if (fmt->code == resizer_fmts[i])
+                               break;
+               }
+
+               /* If not found, use UYVY as default */
+               if (i >= ARRAY_SIZE(resizer_fmts))
+                       fmt->code = V4L2_MBUS_FMT_UYVY8_1X16;
+
+               /* Clamp the input size. */
+               fmt->width = clamp_t(u32, width, 1, 8192);
+               fmt->height = clamp_t(u32, height, 1, 8192);
+               break;
+
+       case RESIZER_PAD_SOURCE_MEM:
+               pixelcode = fmt->code;
+               format = __resizer_get_format(resizer, fh, RESIZER_PAD_SINK,
+                                             which);
+               memcpy(fmt, format, sizeof(*fmt));
+
+               if ((pixelcode == V4L2_MBUS_FMT_YUYV8_1_5X8) &&
+                   (fmt->code == V4L2_MBUS_FMT_UYVY8_1X16))
+                       fmt->code = pixelcode;
+
+               /* The data formatter truncates the number of horizontal output
+                * pixels to a multiple of 16. To avoid clipping data, allow
+                * callers to request an output size bigger than the input size
+                * up to the nearest multiple of 16.
+                */
+               fmt->width = clamp_t(u32, width, 32, (fmt->width + 15) & ~15);
+               fmt->width &= ~15;
+               fmt->height = clamp_t(u32, height, 32, fmt->height);
+               break;
+
+       }
+
+       fmt->colorspace = V4L2_COLORSPACE_JPEG;
+       fmt->field = V4L2_FIELD_NONE;
+}
+
+/*
+ * resizer_enum_mbus_code - Handle pixel format enumeration
+ * @sd     : pointer to v4l2 subdev structure
+ * @fh : V4L2 subdev file handle
+ * @code   : pointer to v4l2_subdev_mbus_code_enum structure
+ * return -EINVAL or zero on success
+ */
+static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
+                              struct v4l2_subdev_fh *fh,
+                              struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       switch (code->pad) {
+       case RESIZER_PAD_SINK:
+               if (code->index >= ARRAY_SIZE(resizer_fmts))
+                       return -EINVAL;
+
+               code->code = resizer_fmts[code->index];
+               break;
+
+       case RESIZER_PAD_SOURCE_MEM:
+               format = __resizer_get_format(resizer, fh, RESIZER_PAD_SINK,
+                                             V4L2_SUBDEV_FORMAT_TRY);
+
+               if (code->index == 0) {
+                       code->code = format->code;
+                       break;
+               }
+
+               switch (format->code) {
+               case V4L2_MBUS_FMT_UYVY8_1X16:
+                       if (code->index == 1)
+                               code->code = V4L2_MBUS_FMT_YUYV8_1_5X8;
+                       else
+                               return -EINVAL;
+                       break;
+               default:
+                       if (code->index != 0)
+                               return -EINVAL;
+               }
+
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+static int resizer_enum_frame_size(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh,
+                               struct v4l2_subdev_frame_size_enum *fse)
+{
+       struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt format;
+
+       if (fse->index != 0)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = 1;
+       format.height = 1;
+       resizer_try_format(resizer, fh, fse->pad, &format,
+                          V4L2_SUBDEV_FORMAT_TRY);
+       fse->min_width = format.width;
+       fse->min_height = format.height;
+
+       if (format.code != fse->code)
+               return -EINVAL;
+
+       format.code = fse->code;
+       format.width = -1;
+       format.height = -1;
+       resizer_try_format(resizer, fh, fse->pad, &format,
+                          V4L2_SUBDEV_FORMAT_TRY);
+       fse->max_width = format.width;
+       fse->max_height = format.height;
+
+       return 0;
+}
+
+/*
+ * resizer_get_format - Retrieve the video format on a pad
+ * @sd : ISP RESIZER V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int resizer_get_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                          struct v4l2_subdev_format *fmt)
+{
+       struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __resizer_get_format(resizer, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       fmt->format = *format;
+       return 0;
+}
+
+/*
+ * resizer_set_format - Set the video format on a pad
+ * @sd : ISP RESIZER V4L2 subdevice
+ * @fh : V4L2 subdev file handle
+ * @fmt: Format
+ *
+ * Return 0 on success or -EINVAL if the pad is invalid or doesn't correspond
+ * to the format type.
+ */
+static int resizer_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+                             struct v4l2_subdev_format *fmt)
+{
+       struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *format;
+
+       format = __resizer_get_format(resizer, fh, fmt->pad, fmt->which);
+       if (format == NULL)
+               return -EINVAL;
+
+       resizer_try_format(resizer, fh, fmt->pad, &fmt->format, fmt->which);
+       *format = fmt->format;
+
+       /* Propagate the format from sink to source */
+       if (fmt->pad == RESIZER_PAD_SINK) {
+               format = __resizer_get_format(resizer, fh,
+                                             RESIZER_PAD_SOURCE_MEM,
+                                             fmt->which);
+               *format = fmt->format;
+               resizer_try_format(resizer, fh, RESIZER_PAD_SOURCE_MEM, format,
+                               fmt->which);
+       }
+
+       return 0;
+}
+
+static int resizer_link_validate(struct v4l2_subdev *sd,
+                                struct media_link *link,
+                                struct v4l2_subdev_format *source_fmt,
+                                struct v4l2_subdev_format *sink_fmt)
+{
+       /* Check if the two ends match */
+       if (source_fmt->format.width != sink_fmt->format.width ||
+           source_fmt->format.height != sink_fmt->format.height)
+               return -EPIPE;
+
+       if (source_fmt->format.code != sink_fmt->format.code)
+               return -EPIPE;
+
+       return 0;
+}
+
+/*
+ * resizer_init_formats - Initialize formats on all pads
+ * @sd: ISP RESIZER V4L2 subdevice
+ * @fh: V4L2 subdev file handle
+ *
+ * Initialize all pad formats with default values. If fh is not NULL, try
+ * formats are initialized on the file handle. Otherwise active formats are
+ * initialized on the device.
+ */
+static int resizer_init_formats(struct v4l2_subdev *sd,
+                               struct v4l2_subdev_fh *fh)
+{
+       struct v4l2_subdev_format format;
+
+       memset(&format, 0, sizeof(format));
+       format.pad = RESIZER_PAD_SINK;
+       format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       format.format.code = V4L2_MBUS_FMT_UYVY8_1X16;
+       format.format.width = 4096;
+       format.format.height = 4096;
+       resizer_set_format(sd, fh, &format);
+
+       return 0;
+}
+
+/* V4L2 subdev video operations */
+static const struct v4l2_subdev_video_ops resizer_v4l2_video_ops = {
+       .s_stream = resizer_set_stream,
+};
+
+/* V4L2 subdev pad operations */
+static const struct v4l2_subdev_pad_ops resizer_v4l2_pad_ops = {
+       .enum_mbus_code = resizer_enum_mbus_code,
+       .enum_frame_size = resizer_enum_frame_size,
+       .get_fmt = resizer_get_format,
+       .set_fmt = resizer_set_format,
+       .link_validate = resizer_link_validate,
+};
+
+/* V4L2 subdev operations */
+static const struct v4l2_subdev_ops resizer_v4l2_ops = {
+       .video = &resizer_v4l2_video_ops,
+       .pad = &resizer_v4l2_pad_ops,
+};
+
+/* V4L2 subdev internal operations */
+static const struct v4l2_subdev_internal_ops resizer_v4l2_internal_ops = {
+       .open = resizer_init_formats,
+};
+
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+/*
+ * resizer_link_setup - Setup RESIZER connections
+ * @entity: RESIZER media entity
+ * @local: Pad at the local end of the link
+ * @remote: Pad at the remote end of the link
+ * @flags: Link flags
+ *
+ * return -EINVAL or zero on success
+ */
+static int resizer_link_setup(struct media_entity *entity,
+                          const struct media_pad *local,
+                          const struct media_pad *remote, u32 flags)
+{
+       struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+       struct iss_resizer_device *resizer = v4l2_get_subdevdata(sd);
+       struct iss_device *iss = to_iss_device(resizer);
+
+       switch (local->index | media_entity_type(remote->entity)) {
+       case RESIZER_PAD_SINK | MEDIA_ENT_T_V4L2_SUBDEV:
+               /* Read from IPIPE or IPIPEIF. */
+               if (!(flags & MEDIA_LNK_FL_ENABLED)) {
+                       resizer->input = RESIZER_INPUT_NONE;
+                       break;
+               }
+
+               if (resizer->input != RESIZER_INPUT_NONE)
+                       return -EBUSY;
+
+               if (remote->entity == &iss->ipipeif.subdev.entity)
+                       resizer->input = RESIZER_INPUT_IPIPEIF;
+               else if (remote->entity == &iss->ipipe.subdev.entity)
+                       resizer->input = RESIZER_INPUT_IPIPE;
+
+
+               break;
+
+       case RESIZER_PAD_SOURCE_MEM | MEDIA_ENT_T_DEVNODE:
+               /* Write to memory */
+               if (flags & MEDIA_LNK_FL_ENABLED) {
+                       if (resizer->output & ~RESIZER_OUTPUT_MEMORY)
+                               return -EBUSY;
+                       resizer->output |= RESIZER_OUTPUT_MEMORY;
+               } else {
+                       resizer->output &= ~RESIZER_OUTPUT_MEMORY;
+               }
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* media operations */
+static const struct media_entity_operations resizer_media_ops = {
+       .link_setup = resizer_link_setup,
+       .link_validate = v4l2_subdev_link_validate,
+};
+
+/*
+ * resizer_init_entities - Initialize V4L2 subdev and media entity
+ * @resizer: ISS ISP RESIZER module
+ *
+ * Return 0 on success and a negative error code on failure.
+ */
+static int resizer_init_entities(struct iss_resizer_device *resizer)
+{
+       struct v4l2_subdev *sd = &resizer->subdev;
+       struct media_pad *pads = resizer->pads;
+       struct media_entity *me = &sd->entity;
+       int ret;
+
+       resizer->input = RESIZER_INPUT_NONE;
+
+       v4l2_subdev_init(sd, &resizer_v4l2_ops);
+       sd->internal_ops = &resizer_v4l2_internal_ops;
+       strlcpy(sd->name, "OMAP4 ISS ISP resizer", sizeof(sd->name));
+       sd->grp_id = 1 << 16;   /* group ID for iss subdevs */
+       v4l2_set_subdevdata(sd, resizer);
+       sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
+
+       pads[RESIZER_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+       pads[RESIZER_PAD_SOURCE_MEM].flags = MEDIA_PAD_FL_SOURCE;
+
+       me->ops = &resizer_media_ops;
+       ret = media_entity_init(me, RESIZER_PADS_NUM, pads, 0);
+       if (ret < 0)
+               return ret;
+
+       resizer_init_formats(sd, NULL);
+
+       resizer->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       resizer->video_out.ops = &resizer_video_ops;
+       resizer->video_out.iss = to_iss_device(resizer);
+       resizer->video_out.capture_mem = PAGE_ALIGN(4096 * 4096) * 3;
+       resizer->video_out.bpl_alignment = 32;
+       resizer->video_out.bpl_zero_padding = 1;
+       resizer->video_out.bpl_max = 0x1ffe0;
+
+       ret = omap4iss_video_init(&resizer->video_out, "ISP resizer a");
+       if (ret < 0)
+               return ret;
+
+       /* Connect the RESIZER subdev to the video node. */
+       ret = media_entity_create_link(&resizer->subdev.entity,
+                                      RESIZER_PAD_SOURCE_MEM,
+                                      &resizer->video_out.video.entity, 0, 0);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+void omap4iss_resizer_unregister_entities(struct iss_resizer_device *resizer)
+{
+       media_entity_cleanup(&resizer->subdev.entity);
+
+       v4l2_device_unregister_subdev(&resizer->subdev);
+       omap4iss_video_unregister(&resizer->video_out);
+}
+
+int omap4iss_resizer_register_entities(struct iss_resizer_device *resizer,
+       struct v4l2_device *vdev)
+{
+       int ret;
+
+       /* Register the subdev and video node. */
+       ret = v4l2_device_register_subdev(vdev, &resizer->subdev);
+       if (ret < 0)
+               goto error;
+
+       ret = omap4iss_video_register(&resizer->video_out, vdev);
+       if (ret < 0)
+               goto error;
+
+       return 0;
+
+error:
+       omap4iss_resizer_unregister_entities(resizer);
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * ISP RESIZER initialisation and cleanup
+ */
+
+/*
+ * omap4iss_resizer_init - RESIZER module initialization.
+ * @iss: Device pointer specific to the OMAP4 ISS.
+ *
+ * TODO: Get the initialisation values from platform data.
+ *
+ * Return 0 on success or a negative error code otherwise.
+ */
+int omap4iss_resizer_init(struct iss_device *iss)
+{
+       struct iss_resizer_device *resizer = &iss->resizer;
+
+       resizer->state = ISS_PIPELINE_STREAM_STOPPED;
+       init_waitqueue_head(&resizer->wait);
+
+       return resizer_init_entities(resizer);
+}
+
+/*
+ * omap4iss_resizer_cleanup - RESIZER module cleanup.
+ * @iss: Device pointer specific to the OMAP4 ISS.
+ */
+void omap4iss_resizer_cleanup(struct iss_device *iss)
+{
+       /* FIXME: are you sure there's nothing to do? */
+}
diff --git a/drivers/staging/media/omap4iss/iss_resizer.h b/drivers/staging/media/omap4iss/iss_resizer.h
new file mode 100644 (file)
index 0000000..3727498
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - ISP RESIZER module
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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.
+ */
+
+#ifndef OMAP4_ISS_RESIZER_H
+#define OMAP4_ISS_RESIZER_H
+
+#include "iss_video.h"
+
+enum resizer_input_entity {
+       RESIZER_INPUT_NONE,
+       RESIZER_INPUT_IPIPE,
+       RESIZER_INPUT_IPIPEIF
+};
+
+#define RESIZER_OUTPUT_MEMORY          (1 << 0)
+
+/* Sink and source RESIZER pads */
+#define RESIZER_PAD_SINK                       0
+#define RESIZER_PAD_SOURCE_MEM                 1
+#define RESIZER_PADS_NUM                       2
+
+/*
+ * struct iss_resizer_device - Structure for the RESIZER module to store its own
+ *                         information
+ * @subdev: V4L2 subdevice
+ * @pads: Sink and source media entity pads
+ * @formats: Active video formats
+ * @input: Active input
+ * @output: Active outputs
+ * @video_out: Output video node
+ * @error: A hardware error occurred during capture
+ * @state: Streaming state
+ * @wait: Wait queue used to stop the module
+ * @stopping: Stopping state
+ */
+struct iss_resizer_device {
+       struct v4l2_subdev subdev;
+       struct media_pad pads[RESIZER_PADS_NUM];
+       struct v4l2_mbus_framefmt formats[RESIZER_PADS_NUM];
+
+       enum resizer_input_entity input;
+       unsigned int output;
+       struct iss_video video_out;
+       unsigned int error;
+
+       enum iss_pipeline_stream_state state;
+       wait_queue_head_t wait;
+       atomic_t stopping;
+};
+
+struct iss_device;
+
+int omap4iss_resizer_init(struct iss_device *iss);
+void omap4iss_resizer_cleanup(struct iss_device *iss);
+int omap4iss_resizer_register_entities(struct iss_resizer_device *resizer,
+       struct v4l2_device *vdev);
+void omap4iss_resizer_unregister_entities(struct iss_resizer_device *resizer);
+
+int omap4iss_resizer_busy(struct iss_resizer_device *resizer);
+void omap4iss_resizer_isr(struct iss_resizer_device *resizer, u32 events);
+void omap4iss_resizer_restore_context(struct iss_device *iss);
+void omap4iss_resizer_max_rate(struct iss_resizer_device *resizer,
+       unsigned int *max_rate);
+
+#endif /* OMAP4_ISS_RESIZER_H */
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
new file mode 100644 (file)
index 0000000..8c7f350
--- /dev/null
@@ -0,0 +1,1226 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - Generic video node
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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 <asm/cacheflush.h>
+#include <linux/clk.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+
+#include "iss_video.h"
+#include "iss.h"
+
+
+/* -----------------------------------------------------------------------------
+ * Helper functions
+ */
+
+static struct iss_format_info formats[] = {
+       { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_PIX_FMT_GREY, 8, "Greyscale 8 bpp", },
+       { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
+         V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_PIX_FMT_Y10, 10, "Greyscale 10 bpp", },
+       { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
+         V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
+         V4L2_PIX_FMT_Y12, 12, "Greyscale 12 bpp", },
+       { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_PIX_FMT_SBGGR8, 8, "BGGR Bayer 8 bpp", },
+       { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_PIX_FMT_SGBRG8, 8, "GBRG Bayer 8 bpp", },
+       { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_PIX_FMT_SGRBG8, 8, "GRBG Bayer 8 bpp", },
+       { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_PIX_FMT_SRGGB8, 8, "RGGB Bayer 8 bpp", },
+       { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+         V4L2_MBUS_FMT_SGRBG10_1X10, 0,
+         V4L2_PIX_FMT_SGRBG10DPCM8, 8, "GRBG Bayer 10 bpp DPCM8",  },
+       { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
+         V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_PIX_FMT_SBGGR10, 10, "BGGR Bayer 10 bpp", },
+       { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
+         V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_PIX_FMT_SGBRG10, 10, "GBRG Bayer 10 bpp", },
+       { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
+         V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_PIX_FMT_SGRBG10, 10, "GRBG Bayer 10 bpp", },
+       { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
+         V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_PIX_FMT_SRGGB10, 10, "RGGB Bayer 10 bpp", },
+       { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
+         V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
+         V4L2_PIX_FMT_SBGGR12, 12, "BGGR Bayer 12 bpp", },
+       { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
+         V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
+         V4L2_PIX_FMT_SGBRG12, 12, "GBRG Bayer 12 bpp", },
+       { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
+         V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
+         V4L2_PIX_FMT_SGRBG12, 12, "GRBG Bayer 12 bpp", },
+       { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
+         V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
+         V4L2_PIX_FMT_SRGGB12, 12, "RGGB Bayer 12 bpp", },
+       { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
+         V4L2_MBUS_FMT_UYVY8_1X16, 0,
+         V4L2_PIX_FMT_UYVY, 16, "YUV 4:2:2 (UYVY)", },
+       { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
+         V4L2_MBUS_FMT_YUYV8_1X16, 0,
+         V4L2_PIX_FMT_YUYV, 16, "YUV 4:2:2 (YUYV)", },
+       { V4L2_MBUS_FMT_YUYV8_1_5X8, V4L2_MBUS_FMT_YUYV8_1_5X8,
+         V4L2_MBUS_FMT_YUYV8_1_5X8, 0,
+         V4L2_PIX_FMT_NV12, 8, "YUV 4:2:0 (NV12)", },
+};
+
+const struct iss_format_info *
+omap4iss_video_format_info(enum v4l2_mbus_pixelcode code)
+{
+       unsigned int i;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (formats[i].code == code)
+                       return &formats[i];
+       }
+
+       return NULL;
+}
+
+/*
+ * iss_video_mbus_to_pix - Convert v4l2_mbus_framefmt to v4l2_pix_format
+ * @video: ISS video instance
+ * @mbus: v4l2_mbus_framefmt format (input)
+ * @pix: v4l2_pix_format format (output)
+ *
+ * Fill the output pix structure with information from the input mbus format.
+ * The bytesperline and sizeimage fields are computed from the requested bytes
+ * per line value in the pix format and information from the video instance.
+ *
+ * Return the number of padding bytes at end of line.
+ */
+static unsigned int iss_video_mbus_to_pix(const struct iss_video *video,
+                                         const struct v4l2_mbus_framefmt *mbus,
+                                         struct v4l2_pix_format *pix)
+{
+       unsigned int bpl = pix->bytesperline;
+       unsigned int min_bpl;
+       unsigned int i;
+
+       memset(pix, 0, sizeof(*pix));
+       pix->width = mbus->width;
+       pix->height = mbus->height;
+
+       /* Skip the last format in the loop so that it will be selected if no
+        * match is found.
+        */
+       for (i = 0; i < ARRAY_SIZE(formats) - 1; ++i) {
+               if (formats[i].code == mbus->code)
+                       break;
+       }
+
+       min_bpl = pix->width * ALIGN(formats[i].bpp, 8) / 8;
+
+       /* Clamp the requested bytes per line value. If the maximum bytes per
+        * line value is zero, the module doesn't support user configurable line
+        * sizes. Override the requested value with the minimum in that case.
+        */
+       if (video->bpl_max)
+               bpl = clamp(bpl, min_bpl, video->bpl_max);
+       else
+               bpl = min_bpl;
+
+       if (!video->bpl_zero_padding || bpl != min_bpl)
+               bpl = ALIGN(bpl, video->bpl_alignment);
+
+       pix->pixelformat = formats[i].pixelformat;
+       pix->bytesperline = bpl;
+       pix->sizeimage = pix->bytesperline * pix->height;
+       pix->colorspace = mbus->colorspace;
+       pix->field = mbus->field;
+
+       /* FIXME: Special case for NV12! We should make this nicer... */
+       if (pix->pixelformat == V4L2_PIX_FMT_NV12)
+               pix->sizeimage += (pix->bytesperline * pix->height) / 2;
+
+       return bpl - min_bpl;
+}
+
+static void iss_video_pix_to_mbus(const struct v4l2_pix_format *pix,
+                                 struct v4l2_mbus_framefmt *mbus)
+{
+       unsigned int i;
+
+       memset(mbus, 0, sizeof(*mbus));
+       mbus->width = pix->width;
+       mbus->height = pix->height;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               if (formats[i].pixelformat == pix->pixelformat)
+                       break;
+       }
+
+       if (WARN_ON(i == ARRAY_SIZE(formats)))
+               return;
+
+       mbus->code = formats[i].code;
+       mbus->colorspace = pix->colorspace;
+       mbus->field = pix->field;
+}
+
+static struct v4l2_subdev *
+iss_video_remote_subdev(struct iss_video *video, u32 *pad)
+{
+       struct media_pad *remote;
+
+       remote = media_entity_remote_pad(&video->pad);
+
+       if (remote == NULL ||
+           media_entity_type(remote->entity) != MEDIA_ENT_T_V4L2_SUBDEV)
+               return NULL;
+
+       if (pad)
+               *pad = remote->index;
+
+       return media_entity_to_v4l2_subdev(remote->entity);
+}
+
+/* Return a pointer to the ISS video instance at the far end of the pipeline. */
+static struct iss_video *
+iss_video_far_end(struct iss_video *video)
+{
+       struct media_entity_graph graph;
+       struct media_entity *entity = &video->video.entity;
+       struct media_device *mdev = entity->parent;
+       struct iss_video *far_end = NULL;
+
+       mutex_lock(&mdev->graph_mutex);
+       media_entity_graph_walk_start(&graph, entity);
+
+       while ((entity = media_entity_graph_walk_next(&graph))) {
+               if (entity == &video->video.entity)
+                       continue;
+
+               if (media_entity_type(entity) != MEDIA_ENT_T_DEVNODE)
+                       continue;
+
+               far_end = to_iss_video(media_entity_to_video_device(entity));
+               if (far_end->type != video->type)
+                       break;
+
+               far_end = NULL;
+       }
+
+       mutex_unlock(&mdev->graph_mutex);
+       return far_end;
+}
+
+static int
+__iss_video_get_format(struct iss_video *video,
+                      struct v4l2_mbus_framefmt *format)
+{
+       struct v4l2_subdev_format fmt;
+       struct v4l2_subdev *subdev;
+       u32 pad;
+       int ret;
+
+       subdev = iss_video_remote_subdev(video, &pad);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       memset(&fmt, 0, sizeof(fmt));
+       fmt.pad = pad;
+       fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+
+       mutex_lock(&video->mutex);
+       ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+       mutex_unlock(&video->mutex);
+
+       if (ret)
+               return ret;
+
+       *format = fmt.format;
+       return 0;
+}
+
+static int
+iss_video_check_format(struct iss_video *video, struct iss_video_fh *vfh)
+{
+       struct v4l2_mbus_framefmt format;
+       struct v4l2_pix_format pixfmt;
+       int ret;
+
+       ret = __iss_video_get_format(video, &format);
+       if (ret < 0)
+               return ret;
+
+       pixfmt.bytesperline = 0;
+       ret = iss_video_mbus_to_pix(video, &format, &pixfmt);
+
+       if (vfh->format.fmt.pix.pixelformat != pixfmt.pixelformat ||
+           vfh->format.fmt.pix.height != pixfmt.height ||
+           vfh->format.fmt.pix.width != pixfmt.width ||
+           vfh->format.fmt.pix.bytesperline != pixfmt.bytesperline ||
+           vfh->format.fmt.pix.sizeimage != pixfmt.sizeimage)
+               return -EINVAL;
+
+       return ret;
+}
+
+/* -----------------------------------------------------------------------------
+ * Video queue operations
+ */
+
+static int iss_video_queue_setup(struct vb2_queue *vq,
+                                const struct v4l2_format *fmt,
+                                unsigned int *count, unsigned int *num_planes,
+                                unsigned int sizes[], void *alloc_ctxs[])
+{
+       struct iss_video_fh *vfh = vb2_get_drv_priv(vq);
+       struct iss_video *video = vfh->video;
+
+       /* Revisit multi-planar support for NV12 */
+       *num_planes = 1;
+
+       sizes[0] = vfh->format.fmt.pix.sizeimage;
+       if (sizes[0] == 0)
+               return -EINVAL;
+
+       alloc_ctxs[0] = video->alloc_ctx;
+
+       *count = min(*count, video->capture_mem / PAGE_ALIGN(sizes[0]));
+
+       return 0;
+}
+
+static void iss_video_buf_cleanup(struct vb2_buffer *vb)
+{
+       struct iss_buffer *buffer = container_of(vb, struct iss_buffer, vb);
+
+       if (buffer->iss_addr)
+               buffer->iss_addr = 0;
+}
+
+static int iss_video_buf_prepare(struct vb2_buffer *vb)
+{
+       struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue);
+       struct iss_buffer *buffer = container_of(vb, struct iss_buffer, vb);
+       struct iss_video *video = vfh->video;
+       unsigned long size = vfh->format.fmt.pix.sizeimage;
+       dma_addr_t addr;
+
+       if (vb2_plane_size(vb, 0) < size)
+               return -ENOBUFS;
+
+       /* Refuse to prepare the buffer is the video node has registered an
+        * error. We don't need to take any lock here as the operation is
+        * inherently racy. The authoritative check will be performed in the
+        * queue handler, which can't return an error, this check is just a best
+        * effort to notify userspace as early as possible.
+        */
+       if (unlikely(video->error))
+               return -EIO;
+
+       addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+       if (!IS_ALIGNED(addr, 32)) {
+               dev_dbg(video->iss->dev,
+                       "Buffer address must be aligned to 32 bytes boundary.\n");
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(vb, 0, size);
+       buffer->iss_addr = addr;
+       return 0;
+}
+
+static void iss_video_buf_queue(struct vb2_buffer *vb)
+{
+       struct iss_video_fh *vfh = vb2_get_drv_priv(vb->vb2_queue);
+       struct iss_video *video = vfh->video;
+       struct iss_buffer *buffer = container_of(vb, struct iss_buffer, vb);
+       struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity);
+       unsigned long flags;
+       bool empty;
+
+       spin_lock_irqsave(&video->qlock, flags);
+
+       if (unlikely(video->error)) {
+               vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+               spin_unlock_irqrestore(&video->qlock, flags);
+               return;
+       }
+
+       empty = list_empty(&video->dmaqueue);
+       list_add_tail(&buffer->list, &video->dmaqueue);
+
+       spin_unlock_irqrestore(&video->qlock, flags);
+
+       if (empty) {
+               enum iss_pipeline_state state;
+               unsigned int start;
+
+               if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       state = ISS_PIPELINE_QUEUE_OUTPUT;
+               else
+                       state = ISS_PIPELINE_QUEUE_INPUT;
+
+               spin_lock_irqsave(&pipe->lock, flags);
+               pipe->state |= state;
+               video->ops->queue(video, buffer);
+               video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_QUEUED;
+
+               start = iss_pipeline_ready(pipe);
+               if (start)
+                       pipe->state |= ISS_PIPELINE_STREAM;
+               spin_unlock_irqrestore(&pipe->lock, flags);
+
+               if (start)
+                       omap4iss_pipeline_set_stream(pipe,
+                                               ISS_PIPELINE_STREAM_SINGLESHOT);
+       }
+}
+
+static struct vb2_ops iss_video_vb2ops = {
+       .queue_setup    = iss_video_queue_setup,
+       .buf_prepare    = iss_video_buf_prepare,
+       .buf_queue      = iss_video_buf_queue,
+       .buf_cleanup    = iss_video_buf_cleanup,
+};
+
+/*
+ * omap4iss_video_buffer_next - Complete the current buffer and return the next
+ * @video: ISS video object
+ *
+ * Remove the current video buffer from the DMA queue and fill its timestamp,
+ * field count and state fields before waking up its completion handler.
+ *
+ * For capture video nodes, the buffer state is set to VB2_BUF_STATE_DONE if no
+ * error has been flagged in the pipeline, or to VB2_BUF_STATE_ERROR otherwise.
+ *
+ * The DMA queue is expected to contain at least one buffer.
+ *
+ * Return a pointer to the next buffer in the DMA queue, or NULL if the queue is
+ * empty.
+ */
+struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video)
+{
+       struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity);
+       enum iss_pipeline_state state;
+       struct iss_buffer *buf;
+       unsigned long flags;
+       struct timespec ts;
+
+       spin_lock_irqsave(&video->qlock, flags);
+       if (WARN_ON(list_empty(&video->dmaqueue))) {
+               spin_unlock_irqrestore(&video->qlock, flags);
+               return NULL;
+       }
+
+       buf = list_first_entry(&video->dmaqueue, struct iss_buffer,
+                              list);
+       list_del(&buf->list);
+       spin_unlock_irqrestore(&video->qlock, flags);
+
+       ktime_get_ts(&ts);
+       buf->vb.v4l2_buf.timestamp.tv_sec = ts.tv_sec;
+       buf->vb.v4l2_buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+
+       /* Do frame number propagation only if this is the output video node.
+        * Frame number either comes from the CSI receivers or it gets
+        * incremented here if H3A is not active.
+        * Note: There is no guarantee that the output buffer will finish
+        * first, so the input number might lag behind by 1 in some cases.
+        */
+       if (video == pipe->output && !pipe->do_propagation)
+               buf->vb.v4l2_buf.sequence =
+                       atomic_inc_return(&pipe->frame_number);
+       else
+               buf->vb.v4l2_buf.sequence = atomic_read(&pipe->frame_number);
+
+       vb2_buffer_done(&buf->vb, pipe->error ?
+                       VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+       pipe->error = false;
+
+       spin_lock_irqsave(&video->qlock, flags);
+       if (list_empty(&video->dmaqueue)) {
+               spin_unlock_irqrestore(&video->qlock, flags);
+               if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+                       state = ISS_PIPELINE_QUEUE_OUTPUT
+                             | ISS_PIPELINE_STREAM;
+               else
+                       state = ISS_PIPELINE_QUEUE_INPUT
+                             | ISS_PIPELINE_STREAM;
+
+               spin_lock_irqsave(&pipe->lock, flags);
+               pipe->state &= ~state;
+               if (video->pipe.stream_state == ISS_PIPELINE_STREAM_CONTINUOUS)
+                       video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN;
+               spin_unlock_irqrestore(&pipe->lock, flags);
+               return NULL;
+       }
+
+       if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && pipe->input != NULL) {
+               spin_lock(&pipe->lock);
+               pipe->state &= ~ISS_PIPELINE_STREAM;
+               spin_unlock(&pipe->lock);
+       }
+
+       buf = list_first_entry(&video->dmaqueue, struct iss_buffer,
+                              list);
+       spin_unlock_irqrestore(&video->qlock, flags);
+       buf->vb.state = VB2_BUF_STATE_ACTIVE;
+       return buf;
+}
+
+/*
+ * omap4iss_video_cancel_stream - Cancel stream on a video node
+ * @video: ISS video object
+ *
+ * Cancelling a stream mark all buffers on the video node as erroneous and makes
+ * sure no new buffer can be queued.
+ */
+void omap4iss_video_cancel_stream(struct iss_video *video)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&video->qlock, flags);
+
+       while (!list_empty(&video->dmaqueue)) {
+               struct iss_buffer *buf;
+
+               buf = list_first_entry(&video->dmaqueue, struct iss_buffer,
+                                      list);
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+       }
+
+       video->error = true;
+
+       spin_unlock_irqrestore(&video->qlock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 ioctls
+ */
+
+static int
+iss_video_querycap(struct file *file, void *fh, struct v4l2_capability *cap)
+{
+       struct iss_video *video = video_drvdata(file);
+
+       strlcpy(cap->driver, ISS_VIDEO_DRIVER_NAME, sizeof(cap->driver));
+       strlcpy(cap->card, video->video.name, sizeof(cap->card));
+       strlcpy(cap->bus_info, "media", sizeof(cap->bus_info));
+
+       if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+       else
+               cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+
+       cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
+                         | V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
+
+       return 0;
+}
+
+static int
+iss_video_enum_format(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+       struct iss_video *video = video_drvdata(file);
+       struct v4l2_mbus_framefmt format;
+       unsigned int index = f->index;
+       unsigned int i;
+       int ret;
+
+       if (f->type != video->type)
+               return -EINVAL;
+
+       ret = __iss_video_get_format(video, &format);
+       if (ret < 0)
+               return ret;
+
+       for (i = 0; i < ARRAY_SIZE(formats); ++i) {
+               const struct iss_format_info *info = &formats[i];
+
+               if (format.code != info->code)
+                       continue;
+
+               if (index == 0) {
+                       f->pixelformat = info->pixelformat;
+                       strlcpy(f->description, info->description,
+                               sizeof(f->description));
+                       return 0;
+               }
+
+               index--;
+       }
+
+       return -EINVAL;
+}
+
+static int
+iss_video_get_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+       struct iss_video *video = video_drvdata(file);
+
+       if (format->type != video->type)
+               return -EINVAL;
+
+       mutex_lock(&video->mutex);
+       *format = vfh->format;
+       mutex_unlock(&video->mutex);
+
+       return 0;
+}
+
+static int
+iss_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+       struct iss_video *video = video_drvdata(file);
+       struct v4l2_mbus_framefmt fmt;
+
+       if (format->type != video->type)
+               return -EINVAL;
+
+       mutex_lock(&video->mutex);
+
+       /* Fill the bytesperline and sizeimage fields by converting to media bus
+        * format and back to pixel format.
+        */
+       iss_video_pix_to_mbus(&format->fmt.pix, &fmt);
+       iss_video_mbus_to_pix(video, &fmt, &format->fmt.pix);
+
+       vfh->format = *format;
+
+       mutex_unlock(&video->mutex);
+       return 0;
+}
+
+static int
+iss_video_try_format(struct file *file, void *fh, struct v4l2_format *format)
+{
+       struct iss_video *video = video_drvdata(file);
+       struct v4l2_subdev_format fmt;
+       struct v4l2_subdev *subdev;
+       u32 pad;
+       int ret;
+
+       if (format->type != video->type)
+               return -EINVAL;
+
+       subdev = iss_video_remote_subdev(video, &pad);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       iss_video_pix_to_mbus(&format->fmt.pix, &fmt.format);
+
+       fmt.pad = pad;
+       fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+       if (ret)
+               return ret;
+
+       iss_video_mbus_to_pix(video, &fmt.format, &format->fmt.pix);
+       return 0;
+}
+
+static int
+iss_video_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
+{
+       struct iss_video *video = video_drvdata(file);
+       struct v4l2_subdev *subdev;
+       int ret;
+
+       subdev = iss_video_remote_subdev(video, NULL);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       mutex_lock(&video->mutex);
+       ret = v4l2_subdev_call(subdev, video, cropcap, cropcap);
+       mutex_unlock(&video->mutex);
+
+       return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
+}
+
+static int
+iss_video_get_crop(struct file *file, void *fh, struct v4l2_crop *crop)
+{
+       struct iss_video *video = video_drvdata(file);
+       struct v4l2_subdev_format format;
+       struct v4l2_subdev *subdev;
+       u32 pad;
+       int ret;
+
+       subdev = iss_video_remote_subdev(video, &pad);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       /* Try the get crop operation first and fallback to get format if not
+        * implemented.
+        */
+       ret = v4l2_subdev_call(subdev, video, g_crop, crop);
+       if (ret != -ENOIOCTLCMD)
+               return ret;
+
+       format.pad = pad;
+       format.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &format);
+       if (ret < 0)
+               return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
+
+       crop->c.left = 0;
+       crop->c.top = 0;
+       crop->c.width = format.format.width;
+       crop->c.height = format.format.height;
+
+       return 0;
+}
+
+static int
+iss_video_set_crop(struct file *file, void *fh, const struct v4l2_crop *crop)
+{
+       struct iss_video *video = video_drvdata(file);
+       struct v4l2_subdev *subdev;
+       int ret;
+
+       subdev = iss_video_remote_subdev(video, NULL);
+       if (subdev == NULL)
+               return -EINVAL;
+
+       mutex_lock(&video->mutex);
+       ret = v4l2_subdev_call(subdev, video, s_crop, crop);
+       mutex_unlock(&video->mutex);
+
+       return ret == -ENOIOCTLCMD ? -ENOTTY : ret;
+}
+
+static int
+iss_video_get_param(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+       struct iss_video *video = video_drvdata(file);
+
+       if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+           video->type != a->type)
+               return -EINVAL;
+
+       memset(a, 0, sizeof(*a));
+       a->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+       a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
+       a->parm.output.timeperframe = vfh->timeperframe;
+
+       return 0;
+}
+
+static int
+iss_video_set_param(struct file *file, void *fh, struct v4l2_streamparm *a)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+       struct iss_video *video = video_drvdata(file);
+
+       if (video->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
+           video->type != a->type)
+               return -EINVAL;
+
+       if (a->parm.output.timeperframe.denominator == 0)
+               a->parm.output.timeperframe.denominator = 1;
+
+       vfh->timeperframe = a->parm.output.timeperframe;
+
+       return 0;
+}
+
+static int
+iss_video_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *rb)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+
+       return vb2_reqbufs(&vfh->queue, rb);
+}
+
+static int
+iss_video_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+
+       return vb2_querybuf(&vfh->queue, b);
+}
+
+static int
+iss_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+
+       return vb2_qbuf(&vfh->queue, b);
+}
+
+static int
+iss_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+
+       return vb2_dqbuf(&vfh->queue, b, file->f_flags & O_NONBLOCK);
+}
+
+/*
+ * Stream management
+ *
+ * Every ISS pipeline has a single input and a single output. The input can be
+ * either a sensor or a video node. The output is always a video node.
+ *
+ * As every pipeline has an output video node, the ISS video objects at the
+ * pipeline output stores the pipeline state. It tracks the streaming state of
+ * both the input and output, as well as the availability of buffers.
+ *
+ * In sensor-to-memory mode, frames are always available at the pipeline input.
+ * Starting the sensor usually requires I2C transfers and must be done in
+ * interruptible context. The pipeline is started and stopped synchronously
+ * to the stream on/off commands. All modules in the pipeline will get their
+ * subdev set stream handler called. The module at the end of the pipeline must
+ * delay starting the hardware until buffers are available at its output.
+ *
+ * In memory-to-memory mode, starting/stopping the stream requires
+ * synchronization between the input and output. ISS modules can't be stopped
+ * in the middle of a frame, and at least some of the modules seem to become
+ * busy as soon as they're started, even if they don't receive a frame start
+ * event. For that reason frames need to be processed in single-shot mode. The
+ * driver needs to wait until a frame is completely processed and written to
+ * memory before restarting the pipeline for the next frame. Pipelined
+ * processing might be possible but requires more testing.
+ *
+ * Stream start must be delayed until buffers are available at both the input
+ * and output. The pipeline must be started in the videobuf queue callback with
+ * the buffers queue spinlock held. The modules subdev set stream operation must
+ * not sleep.
+ */
+static int
+iss_video_streamon(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+       struct iss_video *video = video_drvdata(file);
+       struct media_entity_graph graph;
+       struct media_entity *entity;
+       enum iss_pipeline_state state;
+       struct iss_pipeline *pipe;
+       struct iss_video *far_end;
+       unsigned long flags;
+       int ret;
+
+       if (type != video->type)
+               return -EINVAL;
+
+       mutex_lock(&video->stream_lock);
+
+       /* Start streaming on the pipeline. No link touching an entity in the
+        * pipeline can be activated or deactivated once streaming is started.
+        */
+       pipe = video->video.entity.pipe
+            ? to_iss_pipeline(&video->video.entity) : &video->pipe;
+       pipe->external = NULL;
+       pipe->external_rate = 0;
+       pipe->external_bpp = 0;
+       pipe->entities = 0;
+
+       if (video->iss->pdata->set_constraints)
+               video->iss->pdata->set_constraints(video->iss, true);
+
+       ret = media_entity_pipeline_start(&video->video.entity, &pipe->pipe);
+       if (ret < 0)
+               goto err_media_entity_pipeline_start;
+
+       entity = &video->video.entity;
+       media_entity_graph_walk_start(&graph, entity);
+       while ((entity = media_entity_graph_walk_next(&graph)))
+               pipe->entities |= 1 << entity->id;
+
+       /* Verify that the currently configured format matches the output of
+        * the connected subdev.
+        */
+       ret = iss_video_check_format(video, vfh);
+       if (ret < 0)
+               goto err_iss_video_check_format;
+
+       video->bpl_padding = ret;
+       video->bpl_value = vfh->format.fmt.pix.bytesperline;
+
+       /* Find the ISS video node connected at the far end of the pipeline and
+        * update the pipeline.
+        */
+       far_end = iss_video_far_end(video);
+
+       if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+               state = ISS_PIPELINE_STREAM_OUTPUT | ISS_PIPELINE_IDLE_OUTPUT;
+               pipe->input = far_end;
+               pipe->output = video;
+       } else {
+               if (far_end == NULL) {
+                       ret = -EPIPE;
+                       goto err_iss_video_check_format;
+               }
+
+               state = ISS_PIPELINE_STREAM_INPUT | ISS_PIPELINE_IDLE_INPUT;
+               pipe->input = video;
+               pipe->output = far_end;
+       }
+
+       spin_lock_irqsave(&pipe->lock, flags);
+       pipe->state &= ~ISS_PIPELINE_STREAM;
+       pipe->state |= state;
+       spin_unlock_irqrestore(&pipe->lock, flags);
+
+       /* Set the maximum time per frame as the value requested by userspace.
+        * This is a soft limit that can be overridden if the hardware doesn't
+        * support the request limit.
+        */
+       if (video->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+               pipe->max_timeperframe = vfh->timeperframe;
+
+       video->queue = &vfh->queue;
+       INIT_LIST_HEAD(&video->dmaqueue);
+       spin_lock_init(&video->qlock);
+       video->error = false;
+       atomic_set(&pipe->frame_number, -1);
+
+       ret = vb2_streamon(&vfh->queue, type);
+       if (ret < 0)
+               goto err_iss_video_check_format;
+
+       /* In sensor-to-memory mode, the stream can be started synchronously
+        * to the stream on command. In memory-to-memory mode, it will be
+        * started when buffers are queued on both the input and output.
+        */
+       if (pipe->input == NULL) {
+               unsigned long flags;
+               ret = omap4iss_pipeline_set_stream(pipe,
+                                             ISS_PIPELINE_STREAM_CONTINUOUS);
+               if (ret < 0)
+                       goto err_omap4iss_set_stream;
+               spin_lock_irqsave(&video->qlock, flags);
+               if (list_empty(&video->dmaqueue))
+                       video->dmaqueue_flags |= ISS_VIDEO_DMAQUEUE_UNDERRUN;
+               spin_unlock_irqrestore(&video->qlock, flags);
+       }
+
+       mutex_unlock(&video->stream_lock);
+       return 0;
+
+err_omap4iss_set_stream:
+       vb2_streamoff(&vfh->queue, type);
+err_iss_video_check_format:
+       media_entity_pipeline_stop(&video->video.entity);
+err_media_entity_pipeline_start:
+       if (video->iss->pdata->set_constraints)
+               video->iss->pdata->set_constraints(video->iss, false);
+       video->queue = NULL;
+
+       mutex_unlock(&video->stream_lock);
+       return ret;
+}
+
+static int
+iss_video_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(fh);
+       struct iss_video *video = video_drvdata(file);
+       struct iss_pipeline *pipe = to_iss_pipeline(&video->video.entity);
+       enum iss_pipeline_state state;
+       unsigned long flags;
+
+       if (type != video->type)
+               return -EINVAL;
+
+       mutex_lock(&video->stream_lock);
+
+       if (!vb2_is_streaming(&vfh->queue))
+               goto done;
+
+       /* Update the pipeline state. */
+       if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               state = ISS_PIPELINE_STREAM_OUTPUT
+                     | ISS_PIPELINE_QUEUE_OUTPUT;
+       else
+               state = ISS_PIPELINE_STREAM_INPUT
+                     | ISS_PIPELINE_QUEUE_INPUT;
+
+       spin_lock_irqsave(&pipe->lock, flags);
+       pipe->state &= ~state;
+       spin_unlock_irqrestore(&pipe->lock, flags);
+
+       /* Stop the stream. */
+       omap4iss_pipeline_set_stream(pipe, ISS_PIPELINE_STREAM_STOPPED);
+       vb2_streamoff(&vfh->queue, type);
+       video->queue = NULL;
+
+       if (video->iss->pdata->set_constraints)
+               video->iss->pdata->set_constraints(video->iss, false);
+       media_entity_pipeline_stop(&video->video.entity);
+
+done:
+       mutex_unlock(&video->stream_lock);
+       return 0;
+}
+
+static int
+iss_video_enum_input(struct file *file, void *fh, struct v4l2_input *input)
+{
+       if (input->index > 0)
+               return -EINVAL;
+
+       strlcpy(input->name, "camera", sizeof(input->name));
+       input->type = V4L2_INPUT_TYPE_CAMERA;
+
+       return 0;
+}
+
+static int
+iss_video_g_input(struct file *file, void *fh, unsigned int *input)
+{
+       *input = 0;
+
+       return 0;
+}
+
+static int
+iss_video_s_input(struct file *file, void *fh, unsigned int input)
+{
+       return input == 0 ? 0 : -EINVAL;
+}
+
+static const struct v4l2_ioctl_ops iss_video_ioctl_ops = {
+       .vidioc_querycap                = iss_video_querycap,
+       .vidioc_enum_fmt_vid_cap        = iss_video_enum_format,
+       .vidioc_g_fmt_vid_cap           = iss_video_get_format,
+       .vidioc_s_fmt_vid_cap           = iss_video_set_format,
+       .vidioc_try_fmt_vid_cap         = iss_video_try_format,
+       .vidioc_g_fmt_vid_out           = iss_video_get_format,
+       .vidioc_s_fmt_vid_out           = iss_video_set_format,
+       .vidioc_try_fmt_vid_out         = iss_video_try_format,
+       .vidioc_cropcap                 = iss_video_cropcap,
+       .vidioc_g_crop                  = iss_video_get_crop,
+       .vidioc_s_crop                  = iss_video_set_crop,
+       .vidioc_g_parm                  = iss_video_get_param,
+       .vidioc_s_parm                  = iss_video_set_param,
+       .vidioc_reqbufs                 = iss_video_reqbufs,
+       .vidioc_querybuf                = iss_video_querybuf,
+       .vidioc_qbuf                    = iss_video_qbuf,
+       .vidioc_dqbuf                   = iss_video_dqbuf,
+       .vidioc_streamon                = iss_video_streamon,
+       .vidioc_streamoff               = iss_video_streamoff,
+       .vidioc_enum_input              = iss_video_enum_input,
+       .vidioc_g_input                 = iss_video_g_input,
+       .vidioc_s_input                 = iss_video_s_input,
+};
+
+/* -----------------------------------------------------------------------------
+ * V4L2 file operations
+ */
+
+static int iss_video_open(struct file *file)
+{
+       struct iss_video *video = video_drvdata(file);
+       struct iss_video_fh *handle;
+       struct vb2_queue *q;
+       int ret = 0;
+
+       handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+       if (handle == NULL)
+               return -ENOMEM;
+
+       v4l2_fh_init(&handle->vfh, &video->video);
+       v4l2_fh_add(&handle->vfh);
+
+       /* If this is the first user, initialise the pipeline. */
+       if (omap4iss_get(video->iss) == NULL) {
+               ret = -EBUSY;
+               goto done;
+       }
+
+       ret = omap4iss_pipeline_pm_use(&video->video.entity, 1);
+       if (ret < 0) {
+               omap4iss_put(video->iss);
+               goto done;
+       }
+
+       video->alloc_ctx = vb2_dma_contig_init_ctx(video->iss->dev);
+       if (IS_ERR(video->alloc_ctx)) {
+               ret = PTR_ERR(video->alloc_ctx);
+               omap4iss_put(video->iss);
+               goto done;
+       }
+
+       q = &handle->queue;
+
+       q->type = video->type;
+       q->io_modes = VB2_MMAP;
+       q->drv_priv = handle;
+       q->ops = &iss_video_vb2ops;
+       q->mem_ops = &vb2_dma_contig_memops;
+       q->buf_struct_size = sizeof(struct iss_buffer);
+       q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+
+       ret = vb2_queue_init(q);
+       if (ret) {
+               omap4iss_put(video->iss);
+               goto done;
+       }
+
+       memset(&handle->format, 0, sizeof(handle->format));
+       handle->format.type = video->type;
+       handle->timeperframe.denominator = 1;
+
+       handle->video = video;
+       file->private_data = &handle->vfh;
+
+done:
+       if (ret < 0) {
+               v4l2_fh_del(&handle->vfh);
+               kfree(handle);
+       }
+
+       return ret;
+}
+
+static int iss_video_release(struct file *file)
+{
+       struct iss_video *video = video_drvdata(file);
+       struct v4l2_fh *vfh = file->private_data;
+       struct iss_video_fh *handle = to_iss_video_fh(vfh);
+
+       /* Disable streaming and free the buffers queue resources. */
+       iss_video_streamoff(file, vfh, video->type);
+
+       omap4iss_pipeline_pm_use(&video->video.entity, 0);
+
+       /* Release the videobuf2 queue */
+       vb2_queue_release(&handle->queue);
+
+       /* Release the file handle. */
+       v4l2_fh_del(vfh);
+       kfree(handle);
+       file->private_data = NULL;
+
+       omap4iss_put(video->iss);
+
+       return 0;
+}
+
+static unsigned int iss_video_poll(struct file *file, poll_table *wait)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(file->private_data);
+
+       return vb2_poll(&vfh->queue, file, wait);
+}
+
+static int iss_video_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       struct iss_video_fh *vfh = to_iss_video_fh(file->private_data);
+
+       return vb2_mmap(&vfh->queue, vma);
+}
+
+static struct v4l2_file_operations iss_video_fops = {
+       .owner = THIS_MODULE,
+       .unlocked_ioctl = video_ioctl2,
+       .open = iss_video_open,
+       .release = iss_video_release,
+       .poll = iss_video_poll,
+       .mmap = iss_video_mmap,
+};
+
+/* -----------------------------------------------------------------------------
+ * ISS video core
+ */
+
+static const struct iss_video_operations iss_video_dummy_ops = {
+};
+
+int omap4iss_video_init(struct iss_video *video, const char *name)
+{
+       const char *direction;
+       int ret;
+
+       switch (video->type) {
+       case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+               direction = "output";
+               video->pad.flags = MEDIA_PAD_FL_SINK;
+               break;
+       case V4L2_BUF_TYPE_VIDEO_OUTPUT:
+               direction = "input";
+               video->pad.flags = MEDIA_PAD_FL_SOURCE;
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       ret = media_entity_init(&video->video.entity, 1, &video->pad, 0);
+       if (ret < 0)
+               return ret;
+
+       mutex_init(&video->mutex);
+       atomic_set(&video->active, 0);
+
+       spin_lock_init(&video->pipe.lock);
+       mutex_init(&video->stream_lock);
+
+       /* Initialize the video device. */
+       if (video->ops == NULL)
+               video->ops = &iss_video_dummy_ops;
+
+       video->video.fops = &iss_video_fops;
+       snprintf(video->video.name, sizeof(video->video.name),
+                "OMAP4 ISS %s %s", name, direction);
+       video->video.vfl_type = VFL_TYPE_GRABBER;
+       video->video.release = video_device_release_empty;
+       video->video.ioctl_ops = &iss_video_ioctl_ops;
+       video->pipe.stream_state = ISS_PIPELINE_STREAM_STOPPED;
+
+       video_set_drvdata(&video->video, video);
+
+       return 0;
+}
+
+void omap4iss_video_cleanup(struct iss_video *video)
+{
+       media_entity_cleanup(&video->video.entity);
+       mutex_destroy(&video->stream_lock);
+       mutex_destroy(&video->mutex);
+}
+
+int omap4iss_video_register(struct iss_video *video, struct v4l2_device *vdev)
+{
+       int ret;
+
+       video->video.v4l2_dev = vdev;
+
+       ret = video_register_device(&video->video, VFL_TYPE_GRABBER, -1);
+       if (ret < 0)
+               dev_err(video->iss->dev,
+                       "%s: could not register video device (%d)\n",
+                       __func__, ret);
+
+       return ret;
+}
+
+void omap4iss_video_unregister(struct iss_video *video)
+{
+       video_unregister_device(&video->video);
+}
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
new file mode 100644 (file)
index 0000000..878e4a3
--- /dev/null
@@ -0,0 +1,204 @@
+/*
+ * TI OMAP4 ISS V4L2 Driver - Generic video node
+ *
+ * Copyright (C) 2012 Texas Instruments, Inc.
+ *
+ * Author: Sergio Aguirre <sergio.a.aguirre@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.
+ */
+
+#ifndef OMAP4_ISS_VIDEO_H
+#define OMAP4_ISS_VIDEO_H
+
+#include <linux/v4l2-mediabus.h>
+#include <media/media-entity.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#define ISS_VIDEO_DRIVER_NAME          "issvideo"
+#define ISS_VIDEO_DRIVER_VERSION       "0.0.2"
+
+struct iss_device;
+struct iss_video;
+struct v4l2_mbus_framefmt;
+struct v4l2_pix_format;
+
+/*
+ * struct iss_format_info - ISS media bus format information
+ * @code: V4L2 media bus format code
+ * @truncated: V4L2 media bus format code for the same format truncated to 10
+ *     bits. Identical to @code if the format is 10 bits wide or less.
+ * @uncompressed: V4L2 media bus format code for the corresponding uncompressed
+ *     format. Identical to @code if the format is not DPCM compressed.
+ * @flavor: V4L2 media bus format code for the same pixel layout but
+ *     shifted to be 8 bits per pixel. =0 if format is not shiftable.
+ * @pixelformat: V4L2 pixel format FCC identifier
+ * @bpp: Bits per pixel
+ * @description: Human-readable format description
+ */
+struct iss_format_info {
+       enum v4l2_mbus_pixelcode code;
+       enum v4l2_mbus_pixelcode truncated;
+       enum v4l2_mbus_pixelcode uncompressed;
+       enum v4l2_mbus_pixelcode flavor;
+       u32 pixelformat;
+       unsigned int bpp;
+       const char *description;
+};
+
+enum iss_pipeline_stream_state {
+       ISS_PIPELINE_STREAM_STOPPED = 0,
+       ISS_PIPELINE_STREAM_CONTINUOUS = 1,
+       ISS_PIPELINE_STREAM_SINGLESHOT = 2,
+};
+
+enum iss_pipeline_state {
+       /* The stream has been started on the input video node. */
+       ISS_PIPELINE_STREAM_INPUT = 1,
+       /* The stream has been started on the output video node. */
+       ISS_PIPELINE_STREAM_OUTPUT = (1 << 1),
+       /* At least one buffer is queued on the input video node. */
+       ISS_PIPELINE_QUEUE_INPUT = (1 << 2),
+       /* At least one buffer is queued on the output video node. */
+       ISS_PIPELINE_QUEUE_OUTPUT = (1 << 3),
+       /* The input entity is idle, ready to be started. */
+       ISS_PIPELINE_IDLE_INPUT = (1 << 4),
+       /* The output entity is idle, ready to be started. */
+       ISS_PIPELINE_IDLE_OUTPUT = (1 << 5),
+       /* The pipeline is currently streaming. */
+       ISS_PIPELINE_STREAM = (1 << 6),
+};
+
+/*
+ * struct iss_pipeline - An OMAP4 ISS hardware pipeline
+ * @entities: Bitmask of entities in the pipeline (indexed by entity ID)
+ * @error: A hardware error occurred during capture
+ */
+struct iss_pipeline {
+       struct media_pipeline pipe;
+       spinlock_t lock;                /* Pipeline state and queue flags */
+       unsigned int state;
+       enum iss_pipeline_stream_state stream_state;
+       struct iss_video *input;
+       struct iss_video *output;
+       unsigned int entities;
+       atomic_t frame_number;
+       bool do_propagation; /* of frame number */
+       bool error;
+       struct v4l2_fract max_timeperframe;
+       struct v4l2_subdev *external;
+       unsigned int external_rate;
+       int external_bpp;
+};
+
+#define to_iss_pipeline(__e) \
+       container_of((__e)->pipe, struct iss_pipeline, pipe)
+
+static inline int iss_pipeline_ready(struct iss_pipeline *pipe)
+{
+       return pipe->state == (ISS_PIPELINE_STREAM_INPUT |
+                              ISS_PIPELINE_STREAM_OUTPUT |
+                              ISS_PIPELINE_QUEUE_INPUT |
+                              ISS_PIPELINE_QUEUE_OUTPUT |
+                              ISS_PIPELINE_IDLE_INPUT |
+                              ISS_PIPELINE_IDLE_OUTPUT);
+}
+
+/*
+ * struct iss_buffer - ISS buffer
+ * @buffer: ISS video buffer
+ * @iss_addr: Physical address of the buffer.
+ */
+struct iss_buffer {
+       /* common v4l buffer stuff -- must be first */
+       struct vb2_buffer       vb;
+       struct list_head        list;
+       dma_addr_t iss_addr;
+};
+
+#define to_iss_buffer(buf)     container_of(buf, struct iss_buffer, buffer)
+
+enum iss_video_dmaqueue_flags {
+       /* Set if DMA queue becomes empty when ISS_PIPELINE_STREAM_CONTINUOUS */
+       ISS_VIDEO_DMAQUEUE_UNDERRUN = (1 << 0),
+       /* Set when queuing buffer to an empty DMA queue */
+       ISS_VIDEO_DMAQUEUE_QUEUED = (1 << 1),
+};
+
+#define iss_video_dmaqueue_flags_clr(video)    \
+                       ({ (video)->dmaqueue_flags = 0; })
+
+/*
+ * struct iss_video_operations - ISS video operations
+ * @queue:     Resume streaming when a buffer is queued. Called on VIDIOC_QBUF
+ *             if there was no buffer previously queued.
+ */
+struct iss_video_operations {
+       int(*queue)(struct iss_video *video, struct iss_buffer *buffer);
+};
+
+struct iss_video {
+       struct video_device video;
+       enum v4l2_buf_type type;
+       struct media_pad pad;
+
+       struct mutex mutex;             /* format and crop settings */
+       atomic_t active;
+
+       struct iss_device *iss;
+
+       unsigned int capture_mem;
+       unsigned int bpl_alignment;     /* alignment value */
+       unsigned int bpl_zero_padding;  /* whether the alignment is optional */
+       unsigned int bpl_max;           /* maximum bytes per line value */
+       unsigned int bpl_value;         /* bytes per line value */
+       unsigned int bpl_padding;       /* padding at end of line */
+
+       /* Pipeline state */
+       struct iss_pipeline pipe;
+       struct mutex stream_lock;       /* pipeline and stream states */
+       bool error;
+
+       /* Video buffers queue */
+       struct vb2_queue *queue;
+       spinlock_t qlock;               /* protects dmaqueue and error */
+       struct list_head dmaqueue;
+       enum iss_video_dmaqueue_flags dmaqueue_flags;
+       struct vb2_alloc_ctx *alloc_ctx;
+
+       const struct iss_video_operations *ops;
+};
+
+#define to_iss_video(vdev)     container_of(vdev, struct iss_video, video)
+
+struct iss_video_fh {
+       struct v4l2_fh vfh;
+       struct iss_video *video;
+       struct vb2_queue queue;
+       struct v4l2_format format;
+       struct v4l2_fract timeperframe;
+};
+
+#define to_iss_video_fh(fh)    container_of(fh, struct iss_video_fh, vfh)
+#define iss_video_queue_to_iss_video_fh(q) \
+                               container_of(q, struct iss_video_fh, queue)
+
+int omap4iss_video_init(struct iss_video *video, const char *name);
+void omap4iss_video_cleanup(struct iss_video *video);
+int omap4iss_video_register(struct iss_video *video,
+                           struct v4l2_device *vdev);
+void omap4iss_video_unregister(struct iss_video *video);
+struct iss_buffer *omap4iss_video_buffer_next(struct iss_video *video);
+void omap4iss_video_cancel_stream(struct iss_video *video);
+struct media_pad *omap4iss_video_remote_pad(struct iss_video *video);
+
+const struct iss_format_info *
+omap4iss_video_format_info(enum v4l2_mbus_pixelcode code);
+
+#endif /* OMAP4_ISS_VIDEO_H */
similarity index 52%
rename from drivers/media/usb/sn9c102/Kconfig
rename to drivers/staging/media/sn9c102/Kconfig
index 6ebaf2940d06b3af7b9392360d144cd03e27236b..c9aba59258d946cc7406b02adbfcbb666cf34488 100644 (file)
@@ -1,14 +1,17 @@
 config USB_SN9C102
        tristate "USB SN9C1xx PC Camera Controller support (DEPRECATED)"
-       depends on VIDEO_V4L2
+       depends on VIDEO_V4L2 && MEDIA_USB_SUPPORT
        ---help---
-         This driver is DEPRECATED please use the gspca sonixb and
+         This driver is DEPRECATED, please use the gspca sonixb and
          sonixj modules instead.
 
          Say Y here if you want support for cameras based on SONiX SN9C101,
          SN9C102, SN9C103, SN9C105 and SN9C120 PC Camera Controllers.
 
-         See <file:Documentation/video4linux/sn9c102.txt> for more info.
+         See <file:drivers/staging/media/sn9c102/sn9c102.txt> for more info.
+
+         If you have webcams that are only supported by this driver and not by
+         the gspca driver, then contact the linux-media mailinglist.
 
          To compile this driver as a module, choose M here: the
          module will be called sn9c102.
index d582c5b84c14cc2c8821d9a982ba47746187cf76..ce9e5aaf7fd49f65104200befe0d19c2f89d743b 100644 (file)
@@ -964,7 +964,7 @@ static int solo_enc_s_std(struct file *file, void *priv, v4l2_std_id std)
 {
        struct solo_enc_dev *solo_enc = video_drvdata(file);
 
-       return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_PAL);
+       return solo_set_video_type(solo_enc->solo_dev, std & V4L2_STD_625_50);
 }
 
 static int solo_enum_framesizes(struct file *file, void *priv,
index 7b26de3488da16d3f70bb99079ccc3d5a80af98f..47e72dac9b13652c6eb6a1d063f69e7da0aa0ead 100644 (file)
@@ -527,7 +527,7 @@ static int solo_g_std(struct file *file, void *priv, v4l2_std_id *i)
        return 0;
 }
 
-int solo_set_video_type(struct solo_dev *solo_dev, bool type)
+int solo_set_video_type(struct solo_dev *solo_dev, bool is_50hz)
 {
        int i;
 
@@ -537,7 +537,8 @@ int solo_set_video_type(struct solo_dev *solo_dev, bool type)
        for (i = 0; i < solo_dev->nr_chans; i++)
                if (vb2_is_busy(&solo_dev->v4l2_enc[i]->vidq))
                        return -EBUSY;
-       solo_dev->video_type = type;
+       solo_dev->video_type = is_50hz ? SOLO_VO_FMT_TYPE_PAL :
+                                        SOLO_VO_FMT_TYPE_NTSC;
        /* Reconfigure for the new standard */
        solo_disp_init(solo_dev);
        solo_enc_init(solo_dev);
@@ -551,7 +552,7 @@ static int solo_s_std(struct file *file, void *priv, v4l2_std_id std)
 {
        struct solo_dev *solo_dev = video_drvdata(file);
 
-       return solo_set_video_type(solo_dev, std & V4L2_STD_PAL);
+       return solo_set_video_type(solo_dev, std & V4L2_STD_625_50);
 }
 
 static int solo_s_ctrl(struct v4l2_ctrl *ctrl)
index f1bbb8cb74e69db4fcc2d327c745d7e261f685f6..8964f8be158e95dfcb0d60a075e4325371c977e5 100644 (file)
@@ -398,7 +398,7 @@ int solo_p2m_dma_desc(struct solo_dev *solo_dev,
                      int desc_cnt);
 
 /* Global s_std ioctl */
-int solo_set_video_type(struct solo_dev *solo_dev, bool type);
+int solo_set_video_type(struct solo_dev *solo_dev, bool is_50hz);
 void solo_update_mode(struct solo_enc_dev *solo_enc);
 
 /* Set the threshold for motion detection */
diff --git a/drivers/staging/zsmalloc/Kconfig b/drivers/staging/zsmalloc/Kconfig
deleted file mode 100644 (file)
index 9d1f2a2..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-config ZSMALLOC
-       bool "Memory allocator for compressed pages"
-       depends on MMU
-       default n
-       help
-         zsmalloc is a slab-based memory allocator designed to store
-         compressed RAM pages.  zsmalloc uses virtual memory mapping
-         in order to reduce fragmentation.  However, this results in a
-         non-standard allocator interface where a handle, not a pointer, is
-         returned by an alloc().  This handle must be mapped in order to
-         access the allocated space.
-
-config PGTABLE_MAPPING
-       bool "Use page table mapping to access object in zsmalloc"
-       depends on ZSMALLOC
-       help
-         By default, zsmalloc uses a copy-based object mapping method to
-         access allocations that span two pages. However, if a particular
-         architecture (ex, ARM) performs VM mapping faster than copying,
-         then you should select this. This causes zsmalloc to use page table
-         mapping rather than copying for object mapping.
-
-         You can check speed with zsmalloc benchmark[1].
-         [1] https://github.com/spartacus06/zsmalloc
diff --git a/drivers/staging/zsmalloc/Makefile b/drivers/staging/zsmalloc/Makefile
deleted file mode 100644 (file)
index b134848..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-zsmalloc-y             := zsmalloc-main.o
-
-obj-$(CONFIG_ZSMALLOC) += zsmalloc.o
index 18303686eb58eed2aa0bdf20f35dd19eaf1ad65d..dc2d84ac5a0e0077355b97d8b7a13b74083d9e79 100644 (file)
@@ -3,6 +3,7 @@ menuconfig TARGET_CORE
        tristate "Generic Target Core Mod (TCM) and ConfigFS Infrastructure"
        depends on SCSI && BLOCK
        select CONFIGFS_FS
+       select CRC_T10DIF
        default n
        help
        Say Y or M here to enable the TCM Storage Engine and ConfigFS enabled
@@ -13,6 +14,7 @@ if TARGET_CORE
 
 config TCM_IBLOCK
        tristate "TCM/IBLOCK Subsystem Plugin for Linux/BLOCK"
+       select BLK_DEV_INTEGRITY
        help
        Say Y here to enable the TCM/IBLOCK subsystem plugin for non-buffered
        access to Linux/Block devices using BIO
index 00867190413c78d1f3226348e5c68718077c0b9f..7f1a7ce4b771a791cdf636906fd5fcdcc16c9ba6 100644 (file)
@@ -52,7 +52,7 @@
 static LIST_HEAD(g_tiqn_list);
 static LIST_HEAD(g_np_list);
 static DEFINE_SPINLOCK(tiqn_lock);
-static DEFINE_SPINLOCK(np_lock);
+static DEFINE_MUTEX(np_lock);
 
 static struct idr tiqn_idr;
 struct idr sess_idr;
@@ -307,6 +307,9 @@ bool iscsit_check_np_match(
        return false;
 }
 
+/*
+ * Called with mutex np_lock held
+ */
 static struct iscsi_np *iscsit_get_np(
        struct __kernel_sockaddr_storage *sockaddr,
        int network_transport)
@@ -314,11 +317,10 @@ static struct iscsi_np *iscsit_get_np(
        struct iscsi_np *np;
        bool match;
 
-       spin_lock_bh(&np_lock);
        list_for_each_entry(np, &g_np_list, np_list) {
-               spin_lock(&np->np_thread_lock);
+               spin_lock_bh(&np->np_thread_lock);
                if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) {
-                       spin_unlock(&np->np_thread_lock);
+                       spin_unlock_bh(&np->np_thread_lock);
                        continue;
                }
 
@@ -330,13 +332,11 @@ static struct iscsi_np *iscsit_get_np(
                         * while iscsi_tpg_add_network_portal() is called.
                         */
                        np->np_exports++;
-                       spin_unlock(&np->np_thread_lock);
-                       spin_unlock_bh(&np_lock);
+                       spin_unlock_bh(&np->np_thread_lock);
                        return np;
                }
-               spin_unlock(&np->np_thread_lock);
+               spin_unlock_bh(&np->np_thread_lock);
        }
-       spin_unlock_bh(&np_lock);
 
        return NULL;
 }
@@ -350,16 +350,22 @@ struct iscsi_np *iscsit_add_np(
        struct sockaddr_in6 *sock_in6;
        struct iscsi_np *np;
        int ret;
+
+       mutex_lock(&np_lock);
+
        /*
         * Locate the existing struct iscsi_np if already active..
         */
        np = iscsit_get_np(sockaddr, network_transport);
-       if (np)
+       if (np) {
+               mutex_unlock(&np_lock);
                return np;
+       }
 
        np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL);
        if (!np) {
                pr_err("Unable to allocate memory for struct iscsi_np\n");
+               mutex_unlock(&np_lock);
                return ERR_PTR(-ENOMEM);
        }
 
@@ -382,6 +388,7 @@ struct iscsi_np *iscsit_add_np(
        ret = iscsi_target_setup_login_socket(np, sockaddr);
        if (ret != 0) {
                kfree(np);
+               mutex_unlock(&np_lock);
                return ERR_PTR(ret);
        }
 
@@ -390,6 +397,7 @@ struct iscsi_np *iscsit_add_np(
                pr_err("Unable to create kthread: iscsi_np\n");
                ret = PTR_ERR(np->np_thread);
                kfree(np);
+               mutex_unlock(&np_lock);
                return ERR_PTR(ret);
        }
        /*
@@ -400,10 +408,10 @@ struct iscsi_np *iscsit_add_np(
         * point because iscsi_np has not been added to g_np_list yet.
         */
        np->np_exports = 1;
+       np->np_thread_state = ISCSI_NP_THREAD_ACTIVE;
 
-       spin_lock_bh(&np_lock);
        list_add_tail(&np->np_list, &g_np_list);
-       spin_unlock_bh(&np_lock);
+       mutex_unlock(&np_lock);
 
        pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n",
                np->np_ip, np->np_port, np->np_transport->name);
@@ -470,9 +478,9 @@ int iscsit_del_np(struct iscsi_np *np)
 
        np->np_transport->iscsit_free_np(np);
 
-       spin_lock_bh(&np_lock);
+       mutex_lock(&np_lock);
        list_del(&np->np_list);
-       spin_unlock_bh(&np_lock);
+       mutex_unlock(&np_lock);
 
        pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n",
                np->np_ip, np->np_port, np->np_transport->name);
@@ -622,7 +630,7 @@ static int iscsit_add_reject(
 {
        struct iscsi_cmd *cmd;
 
-       cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+       cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
        if (!cmd)
                return -1;
 
@@ -2475,7 +2483,7 @@ static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn)
        if (!conn_p)
                return;
 
-       cmd = iscsit_allocate_cmd(conn_p, GFP_ATOMIC);
+       cmd = iscsit_allocate_cmd(conn_p, TASK_RUNNING);
        if (!cmd) {
                iscsit_dec_conn_usage_count(conn_p);
                return;
@@ -3951,7 +3959,7 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
 
        switch (hdr->opcode & ISCSI_OPCODE_MASK) {
        case ISCSI_OP_SCSI_CMD:
-               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
                if (!cmd)
                        goto reject;
 
@@ -3963,28 +3971,28 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
        case ISCSI_OP_NOOP_OUT:
                cmd = NULL;
                if (hdr->ttt == cpu_to_be32(0xFFFFFFFF)) {
-                       cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+                       cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
                        if (!cmd)
                                goto reject;
                }
                ret = iscsit_handle_nop_out(conn, cmd, buf);
                break;
        case ISCSI_OP_SCSI_TMFUNC:
-               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
                if (!cmd)
                        goto reject;
 
                ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
                break;
        case ISCSI_OP_TEXT:
-               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
                if (!cmd)
                        goto reject;
 
                ret = iscsit_handle_text_cmd(conn, cmd, buf);
                break;
        case ISCSI_OP_LOGOUT:
-               cmd = iscsit_allocate_cmd(conn, GFP_KERNEL);
+               cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
                if (!cmd)
                        goto reject;
 
index 83c965c65386da1ce9b8772d5fe3b7193f852f13..582ba84075ec0889bd4e00c55d8dd57e0608c823 100644 (file)
@@ -1192,7 +1192,7 @@ get_target:
         */
 alloc_tags:
        tag_num = max_t(u32, ISCSIT_MIN_TAGS, queue_depth);
-       tag_num += (tag_num / 2) + ISCSIT_EXTRA_TAGS;
+       tag_num = (tag_num * 2) + ISCSIT_EXTRA_TAGS;
        tag_size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
 
        ret = transport_alloc_session_tags(sess->se_sess, tag_num, tag_size);
index 0819e688a3986586200a3131380445a084ff5291..e655b042ed1895cbb2390dfc2bc13adeed89d517 100644 (file)
@@ -152,13 +152,16 @@ void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd)
  * May be called from software interrupt (timer) context for allocating
  * iSCSI NopINs.
  */
-struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask)
+struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, int state)
 {
        struct iscsi_cmd *cmd;
        struct se_session *se_sess = conn->sess->se_sess;
        int size, tag;
 
-       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, gfp_mask);
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, state);
+       if (tag < 0)
+               return NULL;
+
        size = sizeof(struct iscsi_cmd) + conn->conn_transport->priv_size;
        cmd = (struct iscsi_cmd *)(se_sess->sess_cmd_map + (tag * size));
        memset(cmd, 0, size);
@@ -926,7 +929,7 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
        u8 state;
        struct iscsi_cmd *cmd;
 
-       cmd = iscsit_allocate_cmd(conn, GFP_ATOMIC);
+       cmd = iscsit_allocate_cmd(conn, TASK_RUNNING);
        if (!cmd)
                return -1;
 
index e4fc34a02f57b0d7ed88354a315efa87f41ed500..561a424d19800f4540a97ce92312c04ff0f0bc12 100644 (file)
@@ -9,7 +9,7 @@ extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *);
 extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *);
 extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *);
 extern struct iscsi_cmd *iscsit_alloc_cmd(struct iscsi_conn *, gfp_t);
-extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
+extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, int);
 extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32);
 extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *);
 extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
index 1b41e6776152a446b5fda48a1db3fd4594083b99..fadad7c5f635f01496acdc79d56a678a4e4fb1a6 100644 (file)
@@ -217,7 +217,8 @@ static void tcm_loop_submission_work(struct work_struct *work)
                        scsi_bufflen(sc), tcm_loop_sam_attr(sc),
                        sc->sc_data_direction, 0,
                        scsi_sglist(sc), scsi_sg_count(sc),
-                       sgl_bidi, sgl_bidi_count);
+                       sgl_bidi, sgl_bidi_count,
+                       scsi_prot_sglist(sc), scsi_prot_sg_count(sc));
        if (rc < 0) {
                set_host_byte(sc, DID_NO_CONNECT);
                goto out_done;
@@ -462,7 +463,7 @@ static int tcm_loop_driver_probe(struct device *dev)
 {
        struct tcm_loop_hba *tl_hba;
        struct Scsi_Host *sh;
-       int error;
+       int error, host_prot;
 
        tl_hba = to_tcm_loop_hba(dev);
 
@@ -486,6 +487,13 @@ static int tcm_loop_driver_probe(struct device *dev)
        sh->max_channel = 0;
        sh->max_cmd_len = TL_SCSI_MAX_CMD_LEN;
 
+       host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION |
+                   SHOST_DIF_TYPE3_PROTECTION | SHOST_DIX_TYPE1_PROTECTION |
+                   SHOST_DIX_TYPE2_PROTECTION | SHOST_DIX_TYPE3_PROTECTION;
+
+       scsi_host_set_prot(sh, host_prot);
+       scsi_host_set_guard(sh, SHOST_DIX_GUARD_CRC);
+
        error = scsi_add_host(sh, &tl_hba->dev);
        if (error) {
                pr_err("%s: scsi_add_host failed\n", __func__);
@@ -1228,7 +1236,7 @@ static struct configfs_attribute *tcm_loop_tpg_attrs[] = {
 
 /* Start items for tcm_loop_naa_cit */
 
-struct se_portal_group *tcm_loop_make_naa_tpg(
+static struct se_portal_group *tcm_loop_make_naa_tpg(
        struct se_wwn *wwn,
        struct config_group *group,
        const char *name)
@@ -1273,7 +1281,7 @@ struct se_portal_group *tcm_loop_make_naa_tpg(
        return &tl_tpg->tl_se_tpg;
 }
 
-void tcm_loop_drop_naa_tpg(
+static void tcm_loop_drop_naa_tpg(
        struct se_portal_group *se_tpg)
 {
        struct se_wwn *wwn = se_tpg->se_tpg_wwn;
@@ -1305,7 +1313,7 @@ void tcm_loop_drop_naa_tpg(
 
 /* Start items for tcm_loop_cit */
 
-struct se_wwn *tcm_loop_make_scsi_hba(
+static struct se_wwn *tcm_loop_make_scsi_hba(
        struct target_fabric_configfs *tf,
        struct config_group *group,
        const char *name)
@@ -1375,7 +1383,7 @@ out:
        return ERR_PTR(ret);
 }
 
-void tcm_loop_drop_scsi_hba(
+static void tcm_loop_drop_scsi_hba(
        struct se_wwn *wwn)
 {
        struct tcm_loop_hba *tl_hba = container_of(wwn,
index fdcee326bfbc0c2b579fc48b758a224dfa74a205..12da9b386169b7ece6150387777bf467426dc42e 100644 (file)
 #include "target_core_alua.h"
 #include "target_core_ua.h"
 
-static sense_reason_t core_alua_check_transition(int state, int *primary);
+static sense_reason_t core_alua_check_transition(int state, int valid,
+                                                int *primary);
 static int core_alua_set_tg_pt_secondary_state(
                struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
                struct se_port *port, int explicit, int offline);
 
+static char *core_alua_dump_state(int state);
+
 static u16 alua_lu_gps_counter;
 static u32 alua_lu_gps_count;
 
@@ -54,6 +57,86 @@ static LIST_HEAD(lu_gps_list);
 
 struct t10_alua_lu_gp *default_lu_gp;
 
+/*
+ * REPORT REFERRALS
+ *
+ * See sbc3r35 section 5.23
+ */
+sense_reason_t
+target_emulate_report_referrals(struct se_cmd *cmd)
+{
+       struct se_device *dev = cmd->se_dev;
+       struct t10_alua_lba_map *map;
+       struct t10_alua_lba_map_member *map_mem;
+       unsigned char *buf;
+       u32 rd_len = 0, off;
+
+       if (cmd->data_length < 4) {
+               pr_warn("REPORT REFERRALS allocation length %u too"
+                       " small\n", cmd->data_length);
+               return TCM_INVALID_CDB_FIELD;
+       }
+
+       buf = transport_kmap_data_sg(cmd);
+       if (!buf)
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+       off = 4;
+       spin_lock(&dev->t10_alua.lba_map_lock);
+       if (list_empty(&dev->t10_alua.lba_map_list)) {
+               spin_unlock(&dev->t10_alua.lba_map_lock);
+               transport_kunmap_data_sg(cmd);
+
+               return TCM_UNSUPPORTED_SCSI_OPCODE;
+       }
+
+       list_for_each_entry(map, &dev->t10_alua.lba_map_list,
+                           lba_map_list) {
+               int desc_num = off + 3;
+               int pg_num;
+
+               off += 4;
+               if (cmd->data_length > off)
+                       put_unaligned_be64(map->lba_map_first_lba, &buf[off]);
+               off += 8;
+               if (cmd->data_length > off)
+                       put_unaligned_be64(map->lba_map_last_lba, &buf[off]);
+               off += 8;
+               rd_len += 20;
+               pg_num = 0;
+               list_for_each_entry(map_mem, &map->lba_map_mem_list,
+                                   lba_map_mem_list) {
+                       int alua_state = map_mem->lba_map_mem_alua_state;
+                       int alua_pg_id = map_mem->lba_map_mem_alua_pg_id;
+
+                       if (cmd->data_length > off)
+                               buf[off] = alua_state & 0x0f;
+                       off += 2;
+                       if (cmd->data_length > off)
+                               buf[off] = (alua_pg_id >> 8) & 0xff;
+                       off++;
+                       if (cmd->data_length > off)
+                               buf[off] = (alua_pg_id & 0xff);
+                       off++;
+                       rd_len += 4;
+                       pg_num++;
+               }
+               if (cmd->data_length > desc_num)
+                       buf[desc_num] = pg_num;
+       }
+       spin_unlock(&dev->t10_alua.lba_map_lock);
+
+       /*
+        * Set the RETURN DATA LENGTH set in the header of the DataIN Payload
+        */
+       put_unaligned_be16(rd_len, &buf[2]);
+
+       transport_kunmap_data_sg(cmd);
+
+       target_complete_cmd(cmd, GOOD);
+       return 0;
+}
+
 /*
  * REPORT_TARGET_PORT_GROUPS
  *
@@ -210,7 +293,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
        unsigned char *ptr;
        sense_reason_t rc = TCM_NO_SENSE;
        u32 len = 4; /* Skip over RESERVED area in header */
-       int alua_access_state, primary = 0;
+       int alua_access_state, primary = 0, valid_states;
        u16 tg_pt_id, rtpi;
 
        if (!l_port)
@@ -252,6 +335,7 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
                rc = TCM_UNSUPPORTED_SCSI_OPCODE;
                goto out;
        }
+       valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
 
        ptr = &buf[4]; /* Skip over RESERVED area in header */
 
@@ -263,7 +347,8 @@ target_emulate_set_target_port_groups(struct se_cmd *cmd)
                 * the state is a primary or secondary target port asymmetric
                 * access state.
                 */
-               rc = core_alua_check_transition(alua_access_state, &primary);
+               rc = core_alua_check_transition(alua_access_state,
+                                               valid_states, &primary);
                if (rc) {
                        /*
                         * If the SET TARGET PORT GROUPS attempts to establish
@@ -386,6 +471,81 @@ static inline int core_alua_state_nonoptimized(
        return 0;
 }
 
+static inline int core_alua_state_lba_dependent(
+       struct se_cmd *cmd,
+       struct t10_alua_tg_pt_gp *tg_pt_gp,
+       u8 *alua_ascq)
+{
+       struct se_device *dev = cmd->se_dev;
+       u64 segment_size, segment_mult, sectors, lba;
+
+       /* Only need to check for cdb actually containing LBAs */
+       if (!(cmd->se_cmd_flags & SCF_SCSI_DATA_CDB))
+               return 0;
+
+       spin_lock(&dev->t10_alua.lba_map_lock);
+       segment_size = dev->t10_alua.lba_map_segment_size;
+       segment_mult = dev->t10_alua.lba_map_segment_multiplier;
+       sectors = cmd->data_length / dev->dev_attrib.block_size;
+
+       lba = cmd->t_task_lba;
+       while (lba < cmd->t_task_lba + sectors) {
+               struct t10_alua_lba_map *cur_map = NULL, *map;
+               struct t10_alua_lba_map_member *map_mem;
+
+               list_for_each_entry(map, &dev->t10_alua.lba_map_list,
+                                   lba_map_list) {
+                       u64 start_lba, last_lba;
+                       u64 first_lba = map->lba_map_first_lba;
+
+                       if (segment_mult) {
+                               u64 tmp = lba;
+                               start_lba = sector_div(tmp, segment_size * segment_mult);
+
+                               last_lba = first_lba + segment_size - 1;
+                               if (start_lba >= first_lba &&
+                                   start_lba <= last_lba) {
+                                       lba += segment_size;
+                                       cur_map = map;
+                                       break;
+                               }
+                       } else {
+                               last_lba = map->lba_map_last_lba;
+                               if (lba >= first_lba && lba <= last_lba) {
+                                       lba = last_lba + 1;
+                                       cur_map = map;
+                                       break;
+                               }
+                       }
+               }
+               if (!cur_map) {
+                       spin_unlock(&dev->t10_alua.lba_map_lock);
+                       *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
+                       return 1;
+               }
+               list_for_each_entry(map_mem, &cur_map->lba_map_mem_list,
+                                   lba_map_mem_list) {
+                       if (map_mem->lba_map_mem_alua_pg_id !=
+                           tg_pt_gp->tg_pt_gp_id)
+                               continue;
+                       switch(map_mem->lba_map_mem_alua_state) {
+                       case ALUA_ACCESS_STATE_STANDBY:
+                               spin_unlock(&dev->t10_alua.lba_map_lock);
+                               *alua_ascq = ASCQ_04H_ALUA_TG_PT_STANDBY;
+                               return 1;
+                       case ALUA_ACCESS_STATE_UNAVAILABLE:
+                               spin_unlock(&dev->t10_alua.lba_map_lock);
+                               *alua_ascq = ASCQ_04H_ALUA_TG_PT_UNAVAILABLE;
+                               return 1;
+                       default:
+                               break;
+                       }
+               }
+       }
+       spin_unlock(&dev->t10_alua.lba_map_lock);
+       return 0;
+}
+
 static inline int core_alua_state_standby(
        struct se_cmd *cmd,
        unsigned char *cdb,
@@ -583,6 +743,9 @@ target_alua_state_check(struct se_cmd *cmd)
        case ALUA_ACCESS_STATE_TRANSITION:
                ret = core_alua_state_transition(cmd, cdb, &alua_ascq);
                break;
+       case ALUA_ACCESS_STATE_LBA_DEPENDENT:
+               ret = core_alua_state_lba_dependent(cmd, tg_pt_gp, &alua_ascq);
+               break;
        /*
         * OFFLINE is a secondary ALUA target port group access state, that is
         * handled above with struct se_port->sep_tg_pt_secondary_offline=1
@@ -618,17 +781,36 @@ out:
  * Check implicit and explicit ALUA state change request.
  */
 static sense_reason_t
-core_alua_check_transition(int state, int *primary)
+core_alua_check_transition(int state, int valid, int *primary)
 {
+       /*
+        * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are
+        * defined as primary target port asymmetric access states.
+        */
        switch (state) {
        case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED:
+               if (!(valid & ALUA_AO_SUP))
+                       goto not_supported;
+               *primary = 1;
+               break;
        case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
+               if (!(valid & ALUA_AN_SUP))
+                       goto not_supported;
+               *primary = 1;
+               break;
        case ALUA_ACCESS_STATE_STANDBY:
+               if (!(valid & ALUA_S_SUP))
+                       goto not_supported;
+               *primary = 1;
+               break;
        case ALUA_ACCESS_STATE_UNAVAILABLE:
-               /*
-                * OPTIMIZED, NON-OPTIMIZED, STANDBY and UNAVAILABLE are
-                * defined as primary target port asymmetric access states.
-                */
+               if (!(valid & ALUA_U_SUP))
+                       goto not_supported;
+               *primary = 1;
+               break;
+       case ALUA_ACCESS_STATE_LBA_DEPENDENT:
+               if (!(valid & ALUA_LBD_SUP))
+                       goto not_supported;
                *primary = 1;
                break;
        case ALUA_ACCESS_STATE_OFFLINE:
@@ -636,14 +818,27 @@ core_alua_check_transition(int state, int *primary)
                 * OFFLINE state is defined as a secondary target port
                 * asymmetric access state.
                 */
+               if (!(valid & ALUA_O_SUP))
+                       goto not_supported;
                *primary = 0;
                break;
+       case ALUA_ACCESS_STATE_TRANSITION:
+               /*
+                * Transitioning is set internally, and
+                * cannot be selected manually.
+                */
+               goto not_supported;
        default:
                pr_err("Unknown ALUA access state: 0x%02x\n", state);
                return TCM_INVALID_PARAMETER_LIST;
        }
 
        return 0;
+
+not_supported:
+       pr_err("ALUA access state %s not supported",
+              core_alua_dump_state(state));
+       return TCM_INVALID_PARAMETER_LIST;
 }
 
 static char *core_alua_dump_state(int state)
@@ -653,12 +848,16 @@ static char *core_alua_dump_state(int state)
                return "Active/Optimized";
        case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
                return "Active/NonOptimized";
+       case ALUA_ACCESS_STATE_LBA_DEPENDENT:
+               return "LBA Dependent";
        case ALUA_ACCESS_STATE_STANDBY:
                return "Standby";
        case ALUA_ACCESS_STATE_UNAVAILABLE:
                return "Unavailable";
        case ALUA_ACCESS_STATE_OFFLINE:
                return "Offline";
+       case ALUA_ACCESS_STATE_TRANSITION:
+               return "Transitioning";
        default:
                return "Unknown";
        }
@@ -735,58 +934,49 @@ static int core_alua_write_tpg_metadata(
  * Called with tg_pt_gp->tg_pt_gp_md_mutex held
  */
 static int core_alua_update_tpg_primary_metadata(
-       struct t10_alua_tg_pt_gp *tg_pt_gp,
-       int primary_state,
-       unsigned char *md_buf)
+       struct t10_alua_tg_pt_gp *tg_pt_gp)
 {
+       unsigned char *md_buf;
        struct t10_wwn *wwn = &tg_pt_gp->tg_pt_gp_dev->t10_wwn;
        char path[ALUA_METADATA_PATH_LEN];
-       int len;
+       int len, rc;
+
+       md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL);
+       if (!md_buf) {
+               pr_err("Unable to allocate buf for ALUA metadata\n");
+               return -ENOMEM;
+       }
 
        memset(path, 0, ALUA_METADATA_PATH_LEN);
 
-       len = snprintf(md_buf, tg_pt_gp->tg_pt_gp_md_buf_len,
+       len = snprintf(md_buf, ALUA_MD_BUF_LEN,
                        "tg_pt_gp_id=%hu\n"
                        "alua_access_state=0x%02x\n"
                        "alua_access_status=0x%02x\n",
-                       tg_pt_gp->tg_pt_gp_id, primary_state,
+                       tg_pt_gp->tg_pt_gp_id,
+                       tg_pt_gp->tg_pt_gp_alua_pending_state,
                        tg_pt_gp->tg_pt_gp_alua_access_status);
 
        snprintf(path, ALUA_METADATA_PATH_LEN,
                "/var/target/alua/tpgs_%s/%s", &wwn->unit_serial[0],
                config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item));
 
-       return core_alua_write_tpg_metadata(path, md_buf, len);
+       rc = core_alua_write_tpg_metadata(path, md_buf, len);
+       kfree(md_buf);
+       return rc;
 }
 
-static int core_alua_do_transition_tg_pt(
-       struct t10_alua_tg_pt_gp *tg_pt_gp,
-       struct se_port *l_port,
-       struct se_node_acl *nacl,
-       unsigned char *md_buf,
-       int new_state,
-       int explicit)
+static void core_alua_do_transition_tg_pt_work(struct work_struct *work)
 {
+       struct t10_alua_tg_pt_gp *tg_pt_gp = container_of(work,
+               struct t10_alua_tg_pt_gp, tg_pt_gp_transition_work.work);
+       struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
        struct se_dev_entry *se_deve;
        struct se_lun_acl *lacl;
        struct se_port *port;
        struct t10_alua_tg_pt_gp_member *mem;
-       int old_state = 0;
-       /*
-        * Save the old primary ALUA access state, and set the current state
-        * to ALUA_ACCESS_STATE_TRANSITION.
-        */
-       old_state = atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state);
-       atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,
-                       ALUA_ACCESS_STATE_TRANSITION);
-       tg_pt_gp->tg_pt_gp_alua_access_status = (explicit) ?
-                               ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG :
-                               ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA;
-       /*
-        * Check for the optional ALUA primary state transition delay
-        */
-       if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0)
-               msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs);
+       bool explicit = (tg_pt_gp->tg_pt_gp_alua_access_status ==
+                        ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG);
 
        spin_lock(&tg_pt_gp->tg_pt_gp_lock);
        list_for_each_entry(mem, &tg_pt_gp->tg_pt_gp_mem_list,
@@ -821,9 +1011,12 @@ static int core_alua_do_transition_tg_pt(
                        if (!lacl)
                                continue;
 
-                       if (explicit &&
-                          (nacl != NULL) && (nacl == lacl->se_lun_nacl) &&
-                          (l_port != NULL) && (l_port == port))
+                       if ((tg_pt_gp->tg_pt_gp_alua_access_status ==
+                            ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG) &&
+                          (tg_pt_gp->tg_pt_gp_alua_nacl != NULL) &&
+                           (tg_pt_gp->tg_pt_gp_alua_nacl == lacl->se_lun_nacl) &&
+                          (tg_pt_gp->tg_pt_gp_alua_port != NULL) &&
+                           (tg_pt_gp->tg_pt_gp_alua_port == port))
                                continue;
 
                        core_scsi3_ua_allocate(lacl->se_lun_nacl,
@@ -851,20 +1044,102 @@ static int core_alua_do_transition_tg_pt(
         */
        if (tg_pt_gp->tg_pt_gp_write_metadata) {
                mutex_lock(&tg_pt_gp->tg_pt_gp_md_mutex);
-               core_alua_update_tpg_primary_metadata(tg_pt_gp,
-                                       new_state, md_buf);
+               core_alua_update_tpg_primary_metadata(tg_pt_gp);
                mutex_unlock(&tg_pt_gp->tg_pt_gp_md_mutex);
        }
        /*
         * Set the current primary ALUA access state to the requested new state
         */
-       atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state, new_state);
+       atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,
+                  tg_pt_gp->tg_pt_gp_alua_pending_state);
 
        pr_debug("Successful %s ALUA transition TG PT Group: %s ID: %hu"
                " from primary access state %s to %s\n", (explicit) ? "explicit" :
                "implicit", config_item_name(&tg_pt_gp->tg_pt_gp_group.cg_item),
-               tg_pt_gp->tg_pt_gp_id, core_alua_dump_state(old_state),
-               core_alua_dump_state(new_state));
+               tg_pt_gp->tg_pt_gp_id,
+               core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_previous_state),
+               core_alua_dump_state(tg_pt_gp->tg_pt_gp_alua_pending_state));
+       spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+       atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
+       smp_mb__after_atomic_dec();
+       spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+
+       if (tg_pt_gp->tg_pt_gp_transition_complete)
+               complete(tg_pt_gp->tg_pt_gp_transition_complete);
+}
+
+static int core_alua_do_transition_tg_pt(
+       struct t10_alua_tg_pt_gp *tg_pt_gp,
+       int new_state,
+       int explicit)
+{
+       struct se_device *dev = tg_pt_gp->tg_pt_gp_dev;
+       DECLARE_COMPLETION_ONSTACK(wait);
+
+       /* Nothing to be done here */
+       if (atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state) == new_state)
+               return 0;
+
+       if (new_state == ALUA_ACCESS_STATE_TRANSITION)
+               return -EAGAIN;
+
+       /*
+        * Flush any pending transitions
+        */
+       if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs &&
+           atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state) ==
+           ALUA_ACCESS_STATE_TRANSITION) {
+               /* Just in case */
+               tg_pt_gp->tg_pt_gp_alua_pending_state = new_state;
+               tg_pt_gp->tg_pt_gp_transition_complete = &wait;
+               flush_delayed_work(&tg_pt_gp->tg_pt_gp_transition_work);
+               wait_for_completion(&wait);
+               tg_pt_gp->tg_pt_gp_transition_complete = NULL;
+               return 0;
+       }
+
+       /*
+        * Save the old primary ALUA access state, and set the current state
+        * to ALUA_ACCESS_STATE_TRANSITION.
+        */
+       tg_pt_gp->tg_pt_gp_alua_previous_state =
+               atomic_read(&tg_pt_gp->tg_pt_gp_alua_access_state);
+       tg_pt_gp->tg_pt_gp_alua_pending_state = new_state;
+
+       atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,
+                       ALUA_ACCESS_STATE_TRANSITION);
+       tg_pt_gp->tg_pt_gp_alua_access_status = (explicit) ?
+                               ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG :
+                               ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA;
+
+       /*
+        * Check for the optional ALUA primary state transition delay
+        */
+       if (tg_pt_gp->tg_pt_gp_trans_delay_msecs != 0)
+               msleep_interruptible(tg_pt_gp->tg_pt_gp_trans_delay_msecs);
+
+       /*
+        * Take a reference for workqueue item
+        */
+       spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+       atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
+       smp_mb__after_atomic_inc();
+       spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+
+       if (!explicit && tg_pt_gp->tg_pt_gp_implicit_trans_secs) {
+               unsigned long transition_tmo;
+
+               transition_tmo = tg_pt_gp->tg_pt_gp_implicit_trans_secs * HZ;
+               queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq,
+                                  &tg_pt_gp->tg_pt_gp_transition_work,
+                                  transition_tmo);
+       } else {
+               tg_pt_gp->tg_pt_gp_transition_complete = &wait;
+               queue_delayed_work(tg_pt_gp->tg_pt_gp_dev->tmr_wq,
+                                  &tg_pt_gp->tg_pt_gp_transition_work, 0);
+               wait_for_completion(&wait);
+               tg_pt_gp->tg_pt_gp_transition_complete = NULL;
+       }
 
        return 0;
 }
@@ -878,23 +1153,15 @@ int core_alua_do_port_transition(
        int explicit)
 {
        struct se_device *dev;
-       struct se_port *port;
-       struct se_node_acl *nacl;
        struct t10_alua_lu_gp *lu_gp;
        struct t10_alua_lu_gp_member *lu_gp_mem, *local_lu_gp_mem;
        struct t10_alua_tg_pt_gp *tg_pt_gp;
-       unsigned char *md_buf;
-       int primary;
+       int primary, valid_states, rc = 0;
 
-       if (core_alua_check_transition(new_state, &primary) != 0)
+       valid_states = l_tg_pt_gp->tg_pt_gp_alua_supported_states;
+       if (core_alua_check_transition(new_state, valid_states, &primary) != 0)
                return -EINVAL;
 
-       md_buf = kzalloc(l_tg_pt_gp->tg_pt_gp_md_buf_len, GFP_KERNEL);
-       if (!md_buf) {
-               pr_err("Unable to allocate buf for ALUA metadata\n");
-               return -ENOMEM;
-       }
-
        local_lu_gp_mem = l_dev->dev_alua_lu_gp_mem;
        spin_lock(&local_lu_gp_mem->lu_gp_mem_lock);
        lu_gp = local_lu_gp_mem->lu_gp;
@@ -911,12 +1178,13 @@ int core_alua_do_port_transition(
                 * core_alua_do_transition_tg_pt() will always return
                 * success.
                 */
-               core_alua_do_transition_tg_pt(l_tg_pt_gp, l_port, l_nacl,
-                                       md_buf, new_state, explicit);
+               l_tg_pt_gp->tg_pt_gp_alua_port = l_port;
+               l_tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl;
+               rc = core_alua_do_transition_tg_pt(l_tg_pt_gp,
+                                                  new_state, explicit);
                atomic_dec(&lu_gp->lu_gp_ref_cnt);
                smp_mb__after_atomic_dec();
-               kfree(md_buf);
-               return 0;
+               return rc;
        }
        /*
         * For all other LU groups aside from 'default_lu_gp', walk all of
@@ -951,11 +1219,11 @@ int core_alua_do_port_transition(
                                continue;
 
                        if (l_tg_pt_gp == tg_pt_gp) {
-                               port = l_port;
-                               nacl = l_nacl;
+                               tg_pt_gp->tg_pt_gp_alua_port = l_port;
+                               tg_pt_gp->tg_pt_gp_alua_nacl = l_nacl;
                        } else {
-                               port = NULL;
-                               nacl = NULL;
+                               tg_pt_gp->tg_pt_gp_alua_port = NULL;
+                               tg_pt_gp->tg_pt_gp_alua_nacl = NULL;
                        }
                        atomic_inc(&tg_pt_gp->tg_pt_gp_ref_cnt);
                        smp_mb__after_atomic_inc();
@@ -964,12 +1232,14 @@ int core_alua_do_port_transition(
                         * core_alua_do_transition_tg_pt() will always return
                         * success.
                         */
-                       core_alua_do_transition_tg_pt(tg_pt_gp, port,
-                                       nacl, md_buf, new_state, explicit);
+                       rc = core_alua_do_transition_tg_pt(tg_pt_gp,
+                                       new_state, explicit);
 
                        spin_lock(&dev->t10_alua.tg_pt_gps_lock);
                        atomic_dec(&tg_pt_gp->tg_pt_gp_ref_cnt);
                        smp_mb__after_atomic_dec();
+                       if (rc)
+                               break;
                }
                spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
 
@@ -979,16 +1249,18 @@ int core_alua_do_port_transition(
        }
        spin_unlock(&lu_gp->lu_gp_lock);
 
-       pr_debug("Successfully processed LU Group: %s all ALUA TG PT"
-               " Group IDs: %hu %s transition to primary state: %s\n",
-               config_item_name(&lu_gp->lu_gp_group.cg_item),
-               l_tg_pt_gp->tg_pt_gp_id, (explicit) ? "explicit" : "implicit",
-               core_alua_dump_state(new_state));
+       if (!rc) {
+               pr_debug("Successfully processed LU Group: %s all ALUA TG PT"
+                        " Group IDs: %hu %s transition to primary state: %s\n",
+                        config_item_name(&lu_gp->lu_gp_group.cg_item),
+                        l_tg_pt_gp->tg_pt_gp_id,
+                        (explicit) ? "explicit" : "implicit",
+                        core_alua_dump_state(new_state));
+       }
 
        atomic_dec(&lu_gp->lu_gp_ref_cnt);
        smp_mb__after_atomic_dec();
-       kfree(md_buf);
-       return 0;
+       return rc;
 }
 
 /*
@@ -996,13 +1268,18 @@ int core_alua_do_port_transition(
  */
 static int core_alua_update_tpg_secondary_metadata(
        struct t10_alua_tg_pt_gp_member *tg_pt_gp_mem,
-       struct se_port *port,
-       unsigned char *md_buf,
-       u32 md_buf_len)
+       struct se_port *port)
 {
+       unsigned char *md_buf;
        struct se_portal_group *se_tpg = port->sep_tpg;
        char path[ALUA_METADATA_PATH_LEN], wwn[ALUA_SECONDARY_METADATA_WWN_LEN];
-       int len;
+       int len, rc;
+
+       md_buf = kzalloc(ALUA_MD_BUF_LEN, GFP_KERNEL);
+       if (!md_buf) {
+               pr_err("Unable to allocate buf for ALUA metadata\n");
+               return -ENOMEM;
+       }
 
        memset(path, 0, ALUA_METADATA_PATH_LEN);
        memset(wwn, 0, ALUA_SECONDARY_METADATA_WWN_LEN);
@@ -1014,7 +1291,7 @@ static int core_alua_update_tpg_secondary_metadata(
                snprintf(wwn+len, ALUA_SECONDARY_METADATA_WWN_LEN-len, "+%hu",
                                se_tpg->se_tpg_tfo->tpg_get_tag(se_tpg));
 
-       len = snprintf(md_buf, md_buf_len, "alua_tg_pt_offline=%d\n"
+       len = snprintf(md_buf, ALUA_MD_BUF_LEN, "alua_tg_pt_offline=%d\n"
                        "alua_tg_pt_status=0x%02x\n",
                        atomic_read(&port->sep_tg_pt_secondary_offline),
                        port->sep_tg_pt_secondary_stat);
@@ -1023,7 +1300,10 @@ static int core_alua_update_tpg_secondary_metadata(
                        se_tpg->se_tpg_tfo->get_fabric_name(), wwn,
                        port->sep_lun->unpacked_lun);
 
-       return core_alua_write_tpg_metadata(path, md_buf, len);
+       rc = core_alua_write_tpg_metadata(path, md_buf, len);
+       kfree(md_buf);
+
+       return rc;
 }
 
 static int core_alua_set_tg_pt_secondary_state(
@@ -1033,8 +1313,6 @@ static int core_alua_set_tg_pt_secondary_state(
        int offline)
 {
        struct t10_alua_tg_pt_gp *tg_pt_gp;
-       unsigned char *md_buf;
-       u32 md_buf_len;
        int trans_delay_msecs;
 
        spin_lock(&tg_pt_gp_mem->tg_pt_gp_mem_lock);
@@ -1055,7 +1333,6 @@ static int core_alua_set_tg_pt_secondary_state(
        else
                atomic_set(&port->sep_tg_pt_secondary_offline, 0);
 
-       md_buf_len = tg_pt_gp->tg_pt_gp_md_buf_len;
        port->sep_tg_pt_secondary_stat = (explicit) ?
                        ALUA_STATUS_ALTERED_BY_EXPLICIT_STPG :
                        ALUA_STATUS_ALTERED_BY_IMPLICIT_ALUA;
@@ -1077,23 +1354,115 @@ static int core_alua_set_tg_pt_secondary_state(
         * secondary state and status
         */
        if (port->sep_tg_pt_secondary_write_md) {
-               md_buf = kzalloc(md_buf_len, GFP_KERNEL);
-               if (!md_buf) {
-                       pr_err("Unable to allocate md_buf for"
-                               " secondary ALUA access metadata\n");
-                       return -ENOMEM;
-               }
                mutex_lock(&port->sep_tg_pt_md_mutex);
-               core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port,
-                               md_buf, md_buf_len);
+               core_alua_update_tpg_secondary_metadata(tg_pt_gp_mem, port);
                mutex_unlock(&port->sep_tg_pt_md_mutex);
+       }
+
+       return 0;
+}
+
+struct t10_alua_lba_map *
+core_alua_allocate_lba_map(struct list_head *list,
+                          u64 first_lba, u64 last_lba)
+{
+       struct t10_alua_lba_map *lba_map;
+
+       lba_map = kmem_cache_zalloc(t10_alua_lba_map_cache, GFP_KERNEL);
+       if (!lba_map) {
+               pr_err("Unable to allocate struct t10_alua_lba_map\n");
+               return ERR_PTR(-ENOMEM);
+       }
+       INIT_LIST_HEAD(&lba_map->lba_map_mem_list);
+       lba_map->lba_map_first_lba = first_lba;
+       lba_map->lba_map_last_lba = last_lba;
 
-               kfree(md_buf);
+       list_add_tail(&lba_map->lba_map_list, list);
+       return lba_map;
+}
+
+int
+core_alua_allocate_lba_map_mem(struct t10_alua_lba_map *lba_map,
+                              int pg_id, int state)
+{
+       struct t10_alua_lba_map_member *lba_map_mem;
+
+       list_for_each_entry(lba_map_mem, &lba_map->lba_map_mem_list,
+                           lba_map_mem_list) {
+               if (lba_map_mem->lba_map_mem_alua_pg_id == pg_id) {
+                       pr_err("Duplicate pg_id %d in lba_map\n", pg_id);
+                       return -EINVAL;
+               }
+       }
+
+       lba_map_mem = kmem_cache_zalloc(t10_alua_lba_map_mem_cache, GFP_KERNEL);
+       if (!lba_map_mem) {
+               pr_err("Unable to allocate struct t10_alua_lba_map_mem\n");
+               return -ENOMEM;
        }
+       lba_map_mem->lba_map_mem_alua_state = state;
+       lba_map_mem->lba_map_mem_alua_pg_id = pg_id;
 
+       list_add_tail(&lba_map_mem->lba_map_mem_list,
+                     &lba_map->lba_map_mem_list);
        return 0;
 }
 
+void
+core_alua_free_lba_map(struct list_head *lba_list)
+{
+       struct t10_alua_lba_map *lba_map, *lba_map_tmp;
+       struct t10_alua_lba_map_member *lba_map_mem, *lba_map_mem_tmp;
+
+       list_for_each_entry_safe(lba_map, lba_map_tmp, lba_list,
+                                lba_map_list) {
+               list_for_each_entry_safe(lba_map_mem, lba_map_mem_tmp,
+                                        &lba_map->lba_map_mem_list,
+                                        lba_map_mem_list) {
+                       list_del(&lba_map_mem->lba_map_mem_list);
+                       kmem_cache_free(t10_alua_lba_map_mem_cache,
+                                       lba_map_mem);
+               }
+               list_del(&lba_map->lba_map_list);
+               kmem_cache_free(t10_alua_lba_map_cache, lba_map);
+       }
+}
+
+void
+core_alua_set_lba_map(struct se_device *dev, struct list_head *lba_map_list,
+                     int segment_size, int segment_mult)
+{
+       struct list_head old_lba_map_list;
+       struct t10_alua_tg_pt_gp *tg_pt_gp;
+       int activate = 0, supported;
+
+       INIT_LIST_HEAD(&old_lba_map_list);
+       spin_lock(&dev->t10_alua.lba_map_lock);
+       dev->t10_alua.lba_map_segment_size = segment_size;
+       dev->t10_alua.lba_map_segment_multiplier = segment_mult;
+       list_splice_init(&dev->t10_alua.lba_map_list, &old_lba_map_list);
+       if (lba_map_list) {
+               list_splice_init(lba_map_list, &dev->t10_alua.lba_map_list);
+               activate = 1;
+       }
+       spin_unlock(&dev->t10_alua.lba_map_lock);
+       spin_lock(&dev->t10_alua.tg_pt_gps_lock);
+       list_for_each_entry(tg_pt_gp, &dev->t10_alua.tg_pt_gps_list,
+                           tg_pt_gp_list) {
+
+               if (!tg_pt_gp->tg_pt_gp_valid_id)
+                       continue;
+               supported = tg_pt_gp->tg_pt_gp_alua_supported_states;
+               if (activate)
+                       supported |= ALUA_LBD_SUP;
+               else
+                       supported &= ~ALUA_LBD_SUP;
+               tg_pt_gp->tg_pt_gp_alua_supported_states = supported;
+       }
+       spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
+       core_alua_free_lba_map(&old_lba_map_list);
+}
+
 struct t10_alua_lu_gp *
 core_alua_allocate_lu_gp(const char *name, int def_group)
 {
@@ -1346,8 +1715,9 @@ struct t10_alua_tg_pt_gp *core_alua_allocate_tg_pt_gp(struct se_device *dev,
        mutex_init(&tg_pt_gp->tg_pt_gp_md_mutex);
        spin_lock_init(&tg_pt_gp->tg_pt_gp_lock);
        atomic_set(&tg_pt_gp->tg_pt_gp_ref_cnt, 0);
+       INIT_DELAYED_WORK(&tg_pt_gp->tg_pt_gp_transition_work,
+                         core_alua_do_transition_tg_pt_work);
        tg_pt_gp->tg_pt_gp_dev = dev;
-       tg_pt_gp->tg_pt_gp_md_buf_len = ALUA_MD_BUF_LEN;
        atomic_set(&tg_pt_gp->tg_pt_gp_alua_access_state,
                ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED);
        /*
@@ -1475,6 +1845,8 @@ void core_alua_free_tg_pt_gp(
        dev->t10_alua.alua_tg_pt_gps_counter--;
        spin_unlock(&dev->t10_alua.tg_pt_gps_lock);
 
+       flush_delayed_work(&tg_pt_gp->tg_pt_gp_transition_work);
+
        /*
         * Allow a struct t10_alua_tg_pt_gp_member * referenced by
         * core_alua_get_tg_pt_gp_by_name() in
index 88e2e835f14aeec7247005514fcd6cc9ffc4d3fa..0a7d65e804045e465a488ae52c521a4669d4b9ba 100644 (file)
 /*
  * ASYMMETRIC ACCESS STATE field
  *
- * from spc4r17 section 6.27 Table 245
+ * from spc4r36j section 6.37 Table 307
  */
 #define ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED     0x0
 #define ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED 0x1
 #define ALUA_ACCESS_STATE_STANDBY              0x2
 #define ALUA_ACCESS_STATE_UNAVAILABLE          0x3
+#define ALUA_ACCESS_STATE_LBA_DEPENDENT                0x4
 #define ALUA_ACCESS_STATE_OFFLINE              0xe
 #define ALUA_ACCESS_STATE_TRANSITION           0xf
 
  */
 #define ALUA_SECONDARY_METADATA_WWN_LEN                        256
 
+/* Used by core_alua_update_tpg_(primary,secondary)_metadata */
+#define ALUA_MD_BUF_LEN                                        1024
+
 extern struct kmem_cache *t10_alua_lu_gp_cache;
 extern struct kmem_cache *t10_alua_lu_gp_mem_cache;
 extern struct kmem_cache *t10_alua_tg_pt_gp_cache;
 extern struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
+extern struct kmem_cache *t10_alua_lba_map_cache;
+extern struct kmem_cache *t10_alua_lba_map_mem_cache;
 
 extern sense_reason_t target_emulate_report_target_port_groups(struct se_cmd *);
 extern sense_reason_t target_emulate_set_target_port_groups(struct se_cmd *);
+extern sense_reason_t target_emulate_report_referrals(struct se_cmd *);
 extern int core_alua_check_nonop_delay(struct se_cmd *);
 extern int core_alua_do_port_transition(struct t10_alua_tg_pt_gp *,
                                struct se_device *, struct se_port *,
                                struct se_node_acl *, int, int);
 extern char *core_alua_dump_status(int);
+extern struct t10_alua_lba_map *core_alua_allocate_lba_map(
+                               struct list_head *, u64, u64);
+extern int core_alua_allocate_lba_map_mem(struct t10_alua_lba_map *, int, int);
+extern void core_alua_free_lba_map(struct list_head *);
+extern void core_alua_set_lba_map(struct se_device *, struct list_head *,
+                               int, int);
 extern struct t10_alua_lu_gp *core_alua_allocate_lu_gp(const char *, int);
 extern int core_alua_set_lu_gp_id(struct t10_alua_lu_gp *, u16);
 extern void core_alua_free_lu_gp(struct t10_alua_lu_gp *);
index 272755d03e5aca23785e859c896d9f1ca71635c7..f0e85b1196926383149854c8e373104f1344ea59 100644 (file)
@@ -643,6 +643,15 @@ SE_DEV_ATTR(emulate_caw, S_IRUGO | S_IWUSR);
 DEF_DEV_ATTRIB(emulate_3pc);
 SE_DEV_ATTR(emulate_3pc, S_IRUGO | S_IWUSR);
 
+DEF_DEV_ATTRIB(pi_prot_type);
+SE_DEV_ATTR(pi_prot_type, S_IRUGO | S_IWUSR);
+
+DEF_DEV_ATTRIB_RO(hw_pi_prot_type);
+SE_DEV_ATTR_RO(hw_pi_prot_type);
+
+DEF_DEV_ATTRIB(pi_prot_format);
+SE_DEV_ATTR(pi_prot_format, S_IRUGO | S_IWUSR);
+
 DEF_DEV_ATTRIB(enforce_pr_isids);
 SE_DEV_ATTR(enforce_pr_isids, S_IRUGO | S_IWUSR);
 
@@ -702,6 +711,9 @@ static struct configfs_attribute *target_core_dev_attrib_attrs[] = {
        &target_core_dev_attrib_emulate_tpws.attr,
        &target_core_dev_attrib_emulate_caw.attr,
        &target_core_dev_attrib_emulate_3pc.attr,
+       &target_core_dev_attrib_pi_prot_type.attr,
+       &target_core_dev_attrib_hw_pi_prot_type.attr,
+       &target_core_dev_attrib_pi_prot_format.attr,
        &target_core_dev_attrib_enforce_pr_isids.attr,
        &target_core_dev_attrib_is_nonrot.attr,
        &target_core_dev_attrib_emulate_rest_reord.attr,
@@ -1741,6 +1753,176 @@ static struct target_core_configfs_attribute target_core_attr_dev_alua_lu_gp = {
        .store  = target_core_store_alua_lu_gp,
 };
 
+static ssize_t target_core_show_dev_lba_map(void *p, char *page)
+{
+       struct se_device *dev = p;
+       struct t10_alua_lba_map *map;
+       struct t10_alua_lba_map_member *mem;
+       char *b = page;
+       int bl = 0;
+       char state;
+
+       spin_lock(&dev->t10_alua.lba_map_lock);
+       if (!list_empty(&dev->t10_alua.lba_map_list))
+           bl += sprintf(b + bl, "%u %u\n",
+                         dev->t10_alua.lba_map_segment_size,
+                         dev->t10_alua.lba_map_segment_multiplier);
+       list_for_each_entry(map, &dev->t10_alua.lba_map_list, lba_map_list) {
+               bl += sprintf(b + bl, "%llu %llu",
+                             map->lba_map_first_lba, map->lba_map_last_lba);
+               list_for_each_entry(mem, &map->lba_map_mem_list,
+                                   lba_map_mem_list) {
+                       switch (mem->lba_map_mem_alua_state) {
+                       case ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED:
+                               state = 'O';
+                               break;
+                       case ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED:
+                               state = 'A';
+                               break;
+                       case ALUA_ACCESS_STATE_STANDBY:
+                               state = 'S';
+                               break;
+                       case ALUA_ACCESS_STATE_UNAVAILABLE:
+                               state = 'U';
+                               break;
+                       default:
+                               state = '.';
+                               break;
+                       }
+                       bl += sprintf(b + bl, " %d:%c",
+                                     mem->lba_map_mem_alua_pg_id, state);
+               }
+               bl += sprintf(b + bl, "\n");
+       }
+       spin_unlock(&dev->t10_alua.lba_map_lock);
+       return bl;
+}
+
+static ssize_t target_core_store_dev_lba_map(
+       void *p,
+       const char *page,
+       size_t count)
+{
+       struct se_device *dev = p;
+       struct t10_alua_lba_map *lba_map = NULL;
+       struct list_head lba_list;
+       char *map_entries, *ptr;
+       char state;
+       int pg_num = -1, pg;
+       int ret = 0, num = 0, pg_id, alua_state;
+       unsigned long start_lba = -1, end_lba = -1;
+       unsigned long segment_size = -1, segment_mult = -1;
+
+       map_entries = kstrdup(page, GFP_KERNEL);
+       if (!map_entries)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&lba_list);
+       while ((ptr = strsep(&map_entries, "\n")) != NULL) {
+               if (!*ptr)
+                       continue;
+
+               if (num == 0) {
+                       if (sscanf(ptr, "%lu %lu\n",
+                                  &segment_size, &segment_mult) != 2) {
+                               pr_err("Invalid line %d\n", num);
+                               ret = -EINVAL;
+                               break;
+                       }
+                       num++;
+                       continue;
+               }
+               if (sscanf(ptr, "%lu %lu", &start_lba, &end_lba) != 2) {
+                       pr_err("Invalid line %d\n", num);
+                       ret = -EINVAL;
+                       break;
+               }
+               ptr = strchr(ptr, ' ');
+               if (!ptr) {
+                       pr_err("Invalid line %d, missing end lba\n", num);
+                       ret = -EINVAL;
+                       break;
+               }
+               ptr++;
+               ptr = strchr(ptr, ' ');
+               if (!ptr) {
+                       pr_err("Invalid line %d, missing state definitions\n",
+                              num);
+                       ret = -EINVAL;
+                       break;
+               }
+               ptr++;
+               lba_map = core_alua_allocate_lba_map(&lba_list,
+                                                    start_lba, end_lba);
+               if (IS_ERR(lba_map)) {
+                       ret = PTR_ERR(lba_map);
+                       break;
+               }
+               pg = 0;
+               while (sscanf(ptr, "%d:%c", &pg_id, &state) == 2) {
+                       switch (state) {
+                       case 'O':
+                               alua_state = ALUA_ACCESS_STATE_ACTIVE_OPTIMIZED;
+                               break;
+                       case 'A':
+                               alua_state = ALUA_ACCESS_STATE_ACTIVE_NON_OPTIMIZED;
+                               break;
+                       case 'S':
+                               alua_state = ALUA_ACCESS_STATE_STANDBY;
+                               break;
+                       case 'U':
+                               alua_state = ALUA_ACCESS_STATE_UNAVAILABLE;
+                               break;
+                       default:
+                               pr_err("Invalid ALUA state '%c'\n", state);
+                               ret = -EINVAL;
+                               goto out;
+                       }
+
+                       ret = core_alua_allocate_lba_map_mem(lba_map,
+                                                            pg_id, alua_state);
+                       if (ret) {
+                               pr_err("Invalid target descriptor %d:%c "
+                                      "at line %d\n",
+                                      pg_id, state, num);
+                               break;
+                       }
+                       pg++;
+                       ptr = strchr(ptr, ' ');
+                       if (ptr)
+                               ptr++;
+                       else
+                               break;
+               }
+               if (pg_num == -1)
+                   pg_num = pg;
+               else if (pg != pg_num) {
+                       pr_err("Only %d from %d port groups definitions "
+                              "at line %d\n", pg, pg_num, num);
+                       ret = -EINVAL;
+                       break;
+               }
+               num++;
+       }
+out:
+       if (ret) {
+               core_alua_free_lba_map(&lba_list);
+               count = ret;
+       } else
+               core_alua_set_lba_map(dev, &lba_list,
+                                     segment_size, segment_mult);
+       kfree(map_entries);
+       return count;
+}
+
+static struct target_core_configfs_attribute target_core_attr_dev_lba_map = {
+       .attr   = { .ca_owner = THIS_MODULE,
+                   .ca_name = "lba_map",
+                   .ca_mode = S_IRUGO | S_IWUSR },
+       .show   = target_core_show_dev_lba_map,
+       .store  = target_core_store_dev_lba_map,
+};
+
 static struct configfs_attribute *lio_core_dev_attrs[] = {
        &target_core_attr_dev_info.attr,
        &target_core_attr_dev_control.attr,
@@ -1748,6 +1930,7 @@ static struct configfs_attribute *lio_core_dev_attrs[] = {
        &target_core_attr_dev_udev_path.attr,
        &target_core_attr_dev_enable.attr,
        &target_core_attr_dev_alua_lu_gp.attr,
+       &target_core_attr_dev_lba_map.attr,
        NULL,
 };
 
@@ -2054,6 +2237,13 @@ static ssize_t target_core_alua_tg_pt_gp_store_attr_alua_access_state(
                        " transition while TPGS_IMPLICIT_ALUA is disabled\n");
                return -EINVAL;
        }
+       if (tg_pt_gp->tg_pt_gp_alua_access_type & TPGS_EXPLICIT_ALUA &&
+           new_state == ALUA_ACCESS_STATE_LBA_DEPENDENT) {
+               /* LBA DEPENDENT is only allowed with implicit ALUA */
+               pr_err("Unable to process implicit configfs ALUA transition"
+                      " while explicit ALUA management is enabled\n");
+               return -EINVAL;
+       }
 
        ret = core_alua_do_port_transition(tg_pt_gp, dev,
                                        NULL, NULL, new_state, 0);
@@ -2188,7 +2378,7 @@ SE_DEV_ALUA_SUPPORT_STATE_SHOW(lba_dependent,
                               tg_pt_gp_alua_supported_states, ALUA_LBD_SUP);
 SE_DEV_ALUA_SUPPORT_STATE_STORE(lba_dependent,
                                tg_pt_gp_alua_supported_states, ALUA_LBD_SUP);
-SE_DEV_ALUA_TG_PT_ATTR(alua_support_lba_dependent, S_IRUGO | S_IWUSR);
+SE_DEV_ALUA_TG_PT_ATTR(alua_support_lba_dependent, S_IRUGO);
 
 SE_DEV_ALUA_SUPPORT_STATE_SHOW(unavailable,
                               tg_pt_gp_alua_supported_states, ALUA_U_SUP);
@@ -2937,7 +3127,7 @@ static int __init target_core_init_configfs(void)
         * and ALUA Logical Unit Group and Target Port Group infrastructure.
         */
        target_cg = &subsys->su_group;
-       target_cg->default_groups = kmalloc(sizeof(struct config_group) * 2,
+       target_cg->default_groups = kmalloc(sizeof(struct config_group *) * 2,
                                GFP_KERNEL);
        if (!target_cg->default_groups) {
                pr_err("Unable to allocate target_cg->default_groups\n");
index d06de84b069bb0c283495bdf09da4b3e9b96ba2f..65001e1336702966108081443d5a44f39988d5af 100644 (file)
@@ -918,6 +918,90 @@ int se_dev_set_emulate_3pc(struct se_device *dev, int flag)
        return 0;
 }
 
+int se_dev_set_pi_prot_type(struct se_device *dev, int flag)
+{
+       int rc, old_prot = dev->dev_attrib.pi_prot_type;
+
+       if (flag != 0 && flag != 1 && flag != 2 && flag != 3) {
+               pr_err("Illegal value %d for pi_prot_type\n", flag);
+               return -EINVAL;
+       }
+       if (flag == 2) {
+               pr_err("DIF TYPE2 protection currently not supported\n");
+               return -ENOSYS;
+       }
+       if (dev->dev_attrib.hw_pi_prot_type) {
+               pr_warn("DIF protection enabled on underlying hardware,"
+                       " ignoring\n");
+               return 0;
+       }
+       if (!dev->transport->init_prot || !dev->transport->free_prot) {
+               pr_err("DIF protection not supported by backend: %s\n",
+                      dev->transport->name);
+               return -ENOSYS;
+       }
+       if (!(dev->dev_flags & DF_CONFIGURED)) {
+               pr_err("DIF protection requires device to be configured\n");
+               return -ENODEV;
+       }
+       if (dev->export_count) {
+               pr_err("dev[%p]: Unable to change SE Device PROT type while"
+                      " export_count is %d\n", dev, dev->export_count);
+               return -EINVAL;
+       }
+
+       dev->dev_attrib.pi_prot_type = flag;
+
+       if (flag && !old_prot) {
+               rc = dev->transport->init_prot(dev);
+               if (rc) {
+                       dev->dev_attrib.pi_prot_type = old_prot;
+                       return rc;
+               }
+
+       } else if (!flag && old_prot) {
+               dev->transport->free_prot(dev);
+       }
+       pr_debug("dev[%p]: SE Device Protection Type: %d\n", dev, flag);
+
+       return 0;
+}
+
+int se_dev_set_pi_prot_format(struct se_device *dev, int flag)
+{
+       int rc;
+
+       if (!flag)
+               return 0;
+
+       if (flag != 1) {
+               pr_err("Illegal value %d for pi_prot_format\n", flag);
+               return -EINVAL;
+       }
+       if (!dev->transport->format_prot) {
+               pr_err("DIF protection format not supported by backend %s\n",
+                      dev->transport->name);
+               return -ENOSYS;
+       }
+       if (!(dev->dev_flags & DF_CONFIGURED)) {
+               pr_err("DIF protection format requires device to be configured\n");
+               return -ENODEV;
+       }
+       if (dev->export_count) {
+               pr_err("dev[%p]: Unable to format SE Device PROT type while"
+                      " export_count is %d\n", dev, dev->export_count);
+               return -EINVAL;
+       }
+
+       rc = dev->transport->format_prot(dev);
+       if (rc)
+               return rc;
+
+       pr_debug("dev[%p]: SE Device Protection Format complete\n", dev);
+
+       return 0;
+}
+
 int se_dev_set_enforce_pr_isids(struct se_device *dev, int flag)
 {
        if ((flag != 0) && (flag != 1)) {
@@ -1117,23 +1201,23 @@ int se_dev_set_block_size(struct se_device *dev, u32 block_size)
 struct se_lun *core_dev_add_lun(
        struct se_portal_group *tpg,
        struct se_device *dev,
-       u32 lun)
+       u32 unpacked_lun)
 {
-       struct se_lun *lun_p;
+       struct se_lun *lun;
        int rc;
 
-       lun_p = core_tpg_pre_addlun(tpg, lun);
-       if (IS_ERR(lun_p))
-               return lun_p;
+       lun = core_tpg_alloc_lun(tpg, unpacked_lun);
+       if (IS_ERR(lun))
+               return lun;
 
-       rc = core_tpg_post_addlun(tpg, lun_p,
+       rc = core_tpg_add_lun(tpg, lun,
                                TRANSPORT_LUNFLAGS_READ_WRITE, dev);
        if (rc < 0)
                return ERR_PTR(rc);
 
        pr_debug("%s_TPG[%u]_LUN[%u] - Activated %s Logical Unit from"
                " CORE HBA: %u\n", tpg->se_tpg_tfo->get_fabric_name(),
-               tpg->se_tpg_tfo->tpg_get_tag(tpg), lun_p->unpacked_lun,
+               tpg->se_tpg_tfo->tpg_get_tag(tpg), lun->unpacked_lun,
                tpg->se_tpg_tfo->get_fabric_name(), dev->se_hba->hba_id);
        /*
         * Update LUN maps for dynamically added initiators when
@@ -1154,7 +1238,7 @@ struct se_lun *core_dev_add_lun(
                spin_unlock_irq(&tpg->acl_node_lock);
        }
 
-       return lun_p;
+       return lun;
 }
 
 /*      core_dev_del_lun():
@@ -1420,6 +1504,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        dev->dev_link_magic = SE_DEV_LINK_MAGIC;
        dev->se_hba = hba;
        dev->transport = hba->transport;
+       dev->prot_length = sizeof(struct se_dif_v1_tuple);
 
        INIT_LIST_HEAD(&dev->dev_list);
        INIT_LIST_HEAD(&dev->dev_sep_list);
@@ -1444,6 +1529,8 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        spin_lock_init(&dev->t10_pr.aptpl_reg_lock);
        INIT_LIST_HEAD(&dev->t10_alua.tg_pt_gps_list);
        spin_lock_init(&dev->t10_alua.tg_pt_gps_lock);
+       INIT_LIST_HEAD(&dev->t10_alua.lba_map_list);
+       spin_lock_init(&dev->t10_alua.lba_map_lock);
 
        dev->t10_wwn.t10_dev = dev;
        dev->t10_alua.t10_dev = dev;
@@ -1460,6 +1547,7 @@ struct se_device *target_alloc_device(struct se_hba *hba, const char *name)
        dev->dev_attrib.emulate_tpws = DA_EMULATE_TPWS;
        dev->dev_attrib.emulate_caw = DA_EMULATE_CAW;
        dev->dev_attrib.emulate_3pc = DA_EMULATE_3PC;
+       dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE0_PROT;
        dev->dev_attrib.enforce_pr_isids = DA_ENFORCE_PR_ISIDS;
        dev->dev_attrib.is_nonrot = DA_IS_NONROT;
        dev->dev_attrib.emulate_rest_reord = DA_EMULATE_REST_REORD;
@@ -1588,9 +1676,13 @@ void target_free_device(struct se_device *dev)
        }
 
        core_alua_free_lu_gp_mem(dev);
+       core_alua_set_lba_map(dev, NULL, 0, 0);
        core_scsi3_free_all_registrations(dev);
        se_release_vpd_for_dev(dev);
 
+       if (dev->transport->free_prot)
+               dev->transport->free_prot(dev);
+
        dev->transport->free_device(dev);
 }
 
index dae2ad6a669e277d9c95c67098c20cc233dbede6..7de9f0475d0552e2b10f58ffa227083336659a2c 100644 (file)
@@ -906,7 +906,7 @@ static struct config_group *target_fabric_make_lun(
        lun_cg->default_groups[1] = NULL;
 
        port_stat_grp = &lun->port_stat_grps.stat_group;
-       port_stat_grp->default_groups =  kzalloc(sizeof(struct config_group) * 3,
+       port_stat_grp->default_groups =  kzalloc(sizeof(struct config_group *) * 4,
                                GFP_KERNEL);
        if (!port_stat_grp->default_groups) {
                pr_err("Unable to allocate port_stat_grp->default_groups\n");
index 78241a53b555fc5600d0a6ffe7b8d8b4e15687d0..cf991a91a8a9699f655fd325f654cb16ed3046d5 100644 (file)
@@ -257,6 +257,72 @@ static void fd_free_device(struct se_device *dev)
        kfree(fd_dev);
 }
 
+static int fd_do_prot_rw(struct se_cmd *cmd, struct fd_prot *fd_prot,
+                        int is_write)
+{
+       struct se_device *se_dev = cmd->se_dev;
+       struct fd_dev *dev = FD_DEV(se_dev);
+       struct file *prot_fd = dev->fd_prot_file;
+       struct scatterlist *sg;
+       loff_t pos = (cmd->t_task_lba * se_dev->prot_length);
+       unsigned char *buf;
+       u32 prot_size, len, size;
+       int rc, ret = 1, i;
+
+       prot_size = (cmd->data_length / se_dev->dev_attrib.block_size) *
+                    se_dev->prot_length;
+
+       if (!is_write) {
+               fd_prot->prot_buf = vzalloc(prot_size);
+               if (!fd_prot->prot_buf) {
+                       pr_err("Unable to allocate fd_prot->prot_buf\n");
+                       return -ENOMEM;
+               }
+               buf = fd_prot->prot_buf;
+
+               fd_prot->prot_sg_nents = cmd->t_prot_nents;
+               fd_prot->prot_sg = kzalloc(sizeof(struct scatterlist) *
+                                          fd_prot->prot_sg_nents, GFP_KERNEL);
+               if (!fd_prot->prot_sg) {
+                       pr_err("Unable to allocate fd_prot->prot_sg\n");
+                       vfree(fd_prot->prot_buf);
+                       return -ENOMEM;
+               }
+               size = prot_size;
+
+               for_each_sg(fd_prot->prot_sg, sg, fd_prot->prot_sg_nents, i) {
+
+                       len = min_t(u32, PAGE_SIZE, size);
+                       sg_set_buf(sg, buf, len);
+                       size -= len;
+                       buf += len;
+               }
+       }
+
+       if (is_write) {
+               rc = kernel_write(prot_fd, fd_prot->prot_buf, prot_size, pos);
+               if (rc < 0 || prot_size != rc) {
+                       pr_err("kernel_write() for fd_do_prot_rw failed:"
+                              " %d\n", rc);
+                       ret = -EINVAL;
+               }
+       } else {
+               rc = kernel_read(prot_fd, pos, fd_prot->prot_buf, prot_size);
+               if (rc < 0) {
+                       pr_err("kernel_read() for fd_do_prot_rw failed:"
+                              " %d\n", rc);
+                       ret = -EINVAL;
+               }
+       }
+
+       if (is_write || ret < 0) {
+               kfree(fd_prot->prot_sg);
+               vfree(fd_prot->prot_buf);
+       }
+
+       return ret;
+}
+
 static int fd_do_rw(struct se_cmd *cmd, struct scatterlist *sgl,
                u32 sgl_nents, int is_write)
 {
@@ -551,6 +617,8 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
              enum dma_data_direction data_direction)
 {
        struct se_device *dev = cmd->se_dev;
+       struct fd_prot fd_prot;
+       sense_reason_t rc;
        int ret = 0;
 
        /*
@@ -558,8 +626,48 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
         * physical memory addresses to struct iovec virtual memory.
         */
        if (data_direction == DMA_FROM_DEVICE) {
+               memset(&fd_prot, 0, sizeof(struct fd_prot));
+
+               if (cmd->prot_type) {
+                       ret = fd_do_prot_rw(cmd, &fd_prot, false);
+                       if (ret < 0)
+                               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+               }
+
                ret = fd_do_rw(cmd, sgl, sgl_nents, 0);
+
+               if (ret > 0 && cmd->prot_type) {
+                       u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
+
+                       rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors,
+                                                0, fd_prot.prot_sg, 0);
+                       if (rc) {
+                               kfree(fd_prot.prot_sg);
+                               vfree(fd_prot.prot_buf);
+                               return rc;
+                       }
+                       kfree(fd_prot.prot_sg);
+                       vfree(fd_prot.prot_buf);
+               }
        } else {
+               memset(&fd_prot, 0, sizeof(struct fd_prot));
+
+               if (cmd->prot_type) {
+                       u32 sectors = cmd->data_length / dev->dev_attrib.block_size;
+
+                       ret = fd_do_prot_rw(cmd, &fd_prot, false);
+                       if (ret < 0)
+                               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+                       rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors,
+                                                 0, fd_prot.prot_sg, 0);
+                       if (rc) {
+                               kfree(fd_prot.prot_sg);
+                               vfree(fd_prot.prot_buf);
+                               return rc;
+                       }
+               }
+
                ret = fd_do_rw(cmd, sgl, sgl_nents, 1);
                /*
                 * Perform implicit vfs_fsync_range() for fd_do_writev() ops
@@ -576,10 +684,19 @@ fd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
 
                        vfs_fsync_range(fd_dev->fd_file, start, end, 1);
                }
+
+               if (ret > 0 && cmd->prot_type) {
+                       ret = fd_do_prot_rw(cmd, &fd_prot, true);
+                       if (ret < 0)
+                               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+               }
        }
 
-       if (ret < 0)
+       if (ret < 0) {
+               kfree(fd_prot.prot_sg);
+               vfree(fd_prot.prot_buf);
                return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+       }
 
        if (ret)
                target_complete_cmd(cmd, SAM_STAT_GOOD);
@@ -700,6 +817,140 @@ static sector_t fd_get_blocks(struct se_device *dev)
                       dev->dev_attrib.block_size);
 }
 
+static int fd_init_prot(struct se_device *dev)
+{
+       struct fd_dev *fd_dev = FD_DEV(dev);
+       struct file *prot_file, *file = fd_dev->fd_file;
+       struct inode *inode;
+       int ret, flags = O_RDWR | O_CREAT | O_LARGEFILE | O_DSYNC;
+       char buf[FD_MAX_DEV_PROT_NAME];
+
+       if (!file) {
+               pr_err("Unable to locate fd_dev->fd_file\n");
+               return -ENODEV;
+       }
+
+       inode = file->f_mapping->host;
+       if (S_ISBLK(inode->i_mode)) {
+               pr_err("FILEIO Protection emulation only supported on"
+                      " !S_ISBLK\n");
+               return -ENOSYS;
+       }
+
+       if (fd_dev->fbd_flags & FDBD_HAS_BUFFERED_IO_WCE)
+               flags &= ~O_DSYNC;
+
+       snprintf(buf, FD_MAX_DEV_PROT_NAME, "%s.protection",
+                fd_dev->fd_dev_name);
+
+       prot_file = filp_open(buf, flags, 0600);
+       if (IS_ERR(prot_file)) {
+               pr_err("filp_open(%s) failed\n", buf);
+               ret = PTR_ERR(prot_file);
+               return ret;
+       }
+       fd_dev->fd_prot_file = prot_file;
+
+       return 0;
+}
+
+static void fd_init_format_buf(struct se_device *dev, unsigned char *buf,
+                              u32 unit_size, u32 *ref_tag, u16 app_tag,
+                              bool inc_reftag)
+{
+       unsigned char *p = buf;
+       int i;
+
+       for (i = 0; i < unit_size; i += dev->prot_length) {
+               *((u16 *)&p[0]) = 0xffff;
+               *((__be16 *)&p[2]) = cpu_to_be16(app_tag);
+               *((__be32 *)&p[4]) = cpu_to_be32(*ref_tag);
+
+               if (inc_reftag)
+                       (*ref_tag)++;
+
+               p += dev->prot_length;
+       }
+}
+
+static int fd_format_prot(struct se_device *dev)
+{
+       struct fd_dev *fd_dev = FD_DEV(dev);
+       struct file *prot_fd = fd_dev->fd_prot_file;
+       sector_t prot_length, prot;
+       unsigned char *buf;
+       loff_t pos = 0;
+       u32 ref_tag = 0;
+       int unit_size = FDBD_FORMAT_UNIT_SIZE * dev->dev_attrib.block_size;
+       int rc, ret = 0, size, len;
+       bool inc_reftag = false;
+
+       if (!dev->dev_attrib.pi_prot_type) {
+               pr_err("Unable to format_prot while pi_prot_type == 0\n");
+               return -ENODEV;
+       }
+       if (!prot_fd) {
+               pr_err("Unable to locate fd_dev->fd_prot_file\n");
+               return -ENODEV;
+       }
+
+       switch (dev->dev_attrib.pi_prot_type) {
+       case TARGET_DIF_TYPE3_PROT:
+               ref_tag = 0xffffffff;
+               break;
+       case TARGET_DIF_TYPE2_PROT:
+       case TARGET_DIF_TYPE1_PROT:
+               inc_reftag = true;
+               break;
+       default:
+               break;
+       }
+
+       buf = vzalloc(unit_size);
+       if (!buf) {
+               pr_err("Unable to allocate FILEIO prot buf\n");
+               return -ENOMEM;
+       }
+
+       prot_length = (dev->transport->get_blocks(dev) + 1) * dev->prot_length;
+       size = prot_length;
+
+       pr_debug("Using FILEIO prot_length: %llu\n",
+                (unsigned long long)prot_length);
+
+       for (prot = 0; prot < prot_length; prot += unit_size) {
+
+               fd_init_format_buf(dev, buf, unit_size, &ref_tag, 0xffff,
+                                  inc_reftag);
+
+               len = min(unit_size, size);
+
+               rc = kernel_write(prot_fd, buf, len, pos);
+               if (rc != len) {
+                       pr_err("vfs_write to prot file failed: %d\n", rc);
+                       ret = -ENODEV;
+                       goto out;
+               }
+               pos += len;
+               size -= len;
+       }
+
+out:
+       vfree(buf);
+       return ret;
+}
+
+static void fd_free_prot(struct se_device *dev)
+{
+       struct fd_dev *fd_dev = FD_DEV(dev);
+
+       if (!fd_dev->fd_prot_file)
+               return;
+
+       filp_close(fd_dev->fd_prot_file, NULL);
+       fd_dev->fd_prot_file = NULL;
+}
+
 static struct sbc_ops fd_sbc_ops = {
        .execute_rw             = fd_execute_rw,
        .execute_sync_cache     = fd_execute_sync_cache,
@@ -730,6 +981,9 @@ static struct se_subsystem_api fileio_template = {
        .show_configfs_dev_params = fd_show_configfs_dev_params,
        .get_device_type        = sbc_get_device_type,
        .get_blocks             = fd_get_blocks,
+       .init_prot              = fd_init_prot,
+       .format_prot            = fd_format_prot,
+       .free_prot              = fd_free_prot,
 };
 
 static int __init fileio_module_init(void)
index d7772c167685fecc89caf699884198b9a9d9f999..182cbb2950395efa43630364ba3d3f78aca3f925 100644 (file)
@@ -4,6 +4,7 @@
 #define FD_VERSION             "4.0"
 
 #define FD_MAX_DEV_NAME                256
+#define FD_MAX_DEV_PROT_NAME   FD_MAX_DEV_NAME + 16
 #define FD_DEVICE_QUEUE_DEPTH  32
 #define FD_MAX_DEVICE_QUEUE_DEPTH 128
 #define FD_BLOCKSIZE           512
 #define FBDF_HAS_PATH          0x01
 #define FBDF_HAS_SIZE          0x02
 #define FDBD_HAS_BUFFERED_IO_WCE 0x04
+#define FDBD_FORMAT_UNIT_SIZE  2048
+
+struct fd_prot {
+       unsigned char   *prot_buf;
+       struct scatterlist *prot_sg;
+       u32 prot_sg_nents;
+};
 
 struct fd_dev {
        struct se_device dev;
@@ -32,6 +40,7 @@ struct fd_dev {
        u32             fd_block_size;
        unsigned long long fd_dev_size;
        struct file     *fd_file;
+       struct file     *fd_prot_file;
        /* FILEIO HBA device is connected to */
        struct fd_host *fd_host;
 } ____cacheline_aligned;
index c87959f12760462ca76740737e7cc839bdd4fc58..554d4f75a75a6263ac7fb731804f787af64731ac 100644 (file)
@@ -91,6 +91,7 @@ static int iblock_configure_device(struct se_device *dev)
        struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
        struct request_queue *q;
        struct block_device *bd = NULL;
+       struct blk_integrity *bi;
        fmode_t mode;
        int ret = -ENOMEM;
 
@@ -155,8 +156,40 @@ static int iblock_configure_device(struct se_device *dev)
        if (blk_queue_nonrot(q))
                dev->dev_attrib.is_nonrot = 1;
 
+       bi = bdev_get_integrity(bd);
+       if (bi) {
+               struct bio_set *bs = ib_dev->ibd_bio_set;
+
+               if (!strcmp(bi->name, "T10-DIF-TYPE3-IP") ||
+                   !strcmp(bi->name, "T10-DIF-TYPE1-IP")) {
+                       pr_err("IBLOCK export of blk_integrity: %s not"
+                              " supported\n", bi->name);
+                       ret = -ENOSYS;
+                       goto out_blkdev_put;
+               }
+
+               if (!strcmp(bi->name, "T10-DIF-TYPE3-CRC")) {
+                       dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE3_PROT;
+               } else if (!strcmp(bi->name, "T10-DIF-TYPE1-CRC")) {
+                       dev->dev_attrib.pi_prot_type = TARGET_DIF_TYPE1_PROT;
+               }
+
+               if (dev->dev_attrib.pi_prot_type) {
+                       if (bioset_integrity_create(bs, IBLOCK_BIO_POOL_SIZE) < 0) {
+                               pr_err("Unable to allocate bioset for PI\n");
+                               ret = -ENOMEM;
+                               goto out_blkdev_put;
+                       }
+                       pr_debug("IBLOCK setup BIP bs->bio_integrity_pool: %p\n",
+                                bs->bio_integrity_pool);
+               }
+               dev->dev_attrib.hw_pi_prot_type = dev->dev_attrib.pi_prot_type;
+       }
+
        return 0;
 
+out_blkdev_put:
+       blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
 out_free_bioset:
        bioset_free(ib_dev->ibd_bio_set);
        ib_dev->ibd_bio_set = NULL;
@@ -170,8 +203,10 @@ static void iblock_free_device(struct se_device *dev)
 
        if (ib_dev->ibd_bd != NULL)
                blkdev_put(ib_dev->ibd_bd, FMODE_WRITE|FMODE_READ|FMODE_EXCL);
-       if (ib_dev->ibd_bio_set != NULL)
+       if (ib_dev->ibd_bio_set != NULL) {
+               bioset_integrity_free(ib_dev->ibd_bio_set);
                bioset_free(ib_dev->ibd_bio_set);
+       }
        kfree(ib_dev);
 }
 
@@ -319,7 +354,7 @@ iblock_get_bio(struct se_cmd *cmd, sector_t lba, u32 sg_num)
        bio->bi_bdev = ib_dev->ibd_bd;
        bio->bi_private = cmd;
        bio->bi_end_io = &iblock_bio_done;
-       bio->bi_sector = lba;
+       bio->bi_iter.bi_sector = lba;
 
        return bio;
 }
@@ -586,13 +621,58 @@ static ssize_t iblock_show_configfs_dev_params(struct se_device *dev, char *b)
        return bl;
 }
 
+static int
+iblock_alloc_bip(struct se_cmd *cmd, struct bio *bio)
+{
+       struct se_device *dev = cmd->se_dev;
+       struct blk_integrity *bi;
+       struct bio_integrity_payload *bip;
+       struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
+       struct scatterlist *sg;
+       int i, rc;
+
+       bi = bdev_get_integrity(ib_dev->ibd_bd);
+       if (!bi) {
+               pr_err("Unable to locate bio_integrity\n");
+               return -ENODEV;
+       }
+
+       bip = bio_integrity_alloc(bio, GFP_NOIO, cmd->t_prot_nents);
+       if (!bip) {
+               pr_err("Unable to allocate bio_integrity_payload\n");
+               return -ENOMEM;
+       }
+
+       bip->bip_iter.bi_size = (cmd->data_length / dev->dev_attrib.block_size) *
+                        dev->prot_length;
+       bip->bip_iter.bi_sector = bio->bi_iter.bi_sector;
+
+       pr_debug("IBLOCK BIP Size: %u Sector: %llu\n", bip->bip_iter.bi_size,
+                (unsigned long long)bip->bip_iter.bi_sector);
+
+       for_each_sg(cmd->t_prot_sg, sg, cmd->t_prot_nents, i) {
+
+               rc = bio_integrity_add_page(bio, sg_page(sg), sg->length,
+                                           sg->offset);
+               if (rc != sg->length) {
+                       pr_err("bio_integrity_add_page() failed; %d\n", rc);
+                       return -ENOMEM;
+               }
+
+               pr_debug("Added bio integrity page: %p length: %d offset; %d\n",
+                        sg_page(sg), sg->length, sg->offset);
+       }
+
+       return 0;
+}
+
 static sense_reason_t
 iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
                  enum dma_data_direction data_direction)
 {
        struct se_device *dev = cmd->se_dev;
        struct iblock_req *ibr;
-       struct bio *bio;
+       struct bio *bio, *bio_start;
        struct bio_list list;
        struct scatterlist *sg;
        u32 sg_num = sgl_nents;
@@ -655,6 +735,7 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
        if (!bio)
                goto fail_free_ibr;
 
+       bio_start = bio;
        bio_list_init(&list);
        bio_list_add(&list, bio);
 
@@ -688,6 +769,12 @@ iblock_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
                sg_num--;
        }
 
+       if (cmd->prot_type) {
+               int rc = iblock_alloc_bip(cmd, bio_start);
+               if (rc)
+                       goto fail_put_bios;
+       }
+
        iblock_submit_bios(&list, rw);
        iblock_complete_cmd(cmd);
        return 0;
@@ -763,7 +850,7 @@ iblock_parse_cdb(struct se_cmd *cmd)
        return sbc_parse_cdb(cmd, &iblock_sbc_ops);
 }
 
-bool iblock_get_write_cache(struct se_device *dev)
+static bool iblock_get_write_cache(struct se_device *dev)
 {
        struct iblock_dev *ib_dev = IBLOCK_DEV(dev);
        struct block_device *bd = ib_dev->ibd_bd;
index 47b63b094cdcacd0ace2e6fe2dee7c18d4091b49..de9cab708f4590ee98034898992e68c1f0459077 100644 (file)
@@ -35,6 +35,8 @@ int   se_dev_set_emulate_tpu(struct se_device *, int);
 int    se_dev_set_emulate_tpws(struct se_device *, int);
 int    se_dev_set_emulate_caw(struct se_device *, int);
 int    se_dev_set_emulate_3pc(struct se_device *, int);
+int    se_dev_set_pi_prot_type(struct se_device *, int);
+int    se_dev_set_pi_prot_format(struct se_device *, int);
 int    se_dev_set_enforce_pr_isids(struct se_device *, int);
 int    se_dev_set_is_nonrot(struct se_device *, int);
 int    se_dev_set_emulate_rest_reord(struct se_device *dev, int);
@@ -77,9 +79,9 @@ struct se_node_acl *__core_tpg_get_initiator_node_acl(struct se_portal_group *tp
                const char *);
 void   core_tpg_add_node_to_devs(struct se_node_acl *, struct se_portal_group *);
 void   core_tpg_wait_for_nacl_pr_ref(struct se_node_acl *);
-struct se_lun *core_tpg_pre_addlun(struct se_portal_group *, u32);
-int    core_tpg_post_addlun(struct se_portal_group *, struct se_lun *,
-               u32, void *);
+struct se_lun *core_tpg_alloc_lun(struct se_portal_group *, u32);
+int    core_tpg_add_lun(struct se_portal_group *, struct se_lun *,
+               u32, struct se_device *);
 struct se_lun *core_tpg_pre_dellun(struct se_portal_group *, u32 unpacked_lun);
 int    core_tpg_post_dellun(struct se_portal_group *, struct se_lun *);
 
index ed75cdd32cb0964f64d1423f29dfb47e3bd3229c..2ee2936fa0bd065d8755e96e85fa0a63250e9cc4 100644 (file)
 #define PR_APTPL_MAX_IPORT_LEN                 256
 #define PR_APTPL_MAX_TPORT_LEN                 256
 
+/*
+ *  Function defined in target_core_spc.c
+ */
+void spc_parse_naa_6h_vendor_specific(struct se_device *, unsigned char *);
+
 extern struct kmem_cache *t10_pr_reg_cache;
 
 extern void core_pr_dump_initiator_port(struct t10_pr_registration *,
index 4ffe5f2ec0e98c956944d2f72e692e5f353c73b5..66a5aba5a0d9c6a6708582a026b25b0f6a17075e 100644 (file)
@@ -78,23 +78,14 @@ static void rd_detach_hba(struct se_hba *hba)
        hba->hba_ptr = NULL;
 }
 
-/*     rd_release_device_space():
- *
- *
- */
-static void rd_release_device_space(struct rd_dev *rd_dev)
+static u32 rd_release_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *sg_table,
+                                u32 sg_table_count)
 {
-       u32 i, j, page_count = 0, sg_per_table;
-       struct rd_dev_sg_table *sg_table;
        struct page *pg;
        struct scatterlist *sg;
+       u32 i, j, page_count = 0, sg_per_table;
 
-       if (!rd_dev->sg_table_array || !rd_dev->sg_table_count)
-               return;
-
-       sg_table = rd_dev->sg_table_array;
-
-       for (i = 0; i < rd_dev->sg_table_count; i++) {
+       for (i = 0; i < sg_table_count; i++) {
                sg = sg_table[i].sg_table;
                sg_per_table = sg_table[i].rd_sg_count;
 
@@ -105,16 +96,28 @@ static void rd_release_device_space(struct rd_dev *rd_dev)
                                page_count++;
                        }
                }
-
                kfree(sg);
        }
 
+       kfree(sg_table);
+       return page_count;
+}
+
+static void rd_release_device_space(struct rd_dev *rd_dev)
+{
+       u32 page_count;
+
+       if (!rd_dev->sg_table_array || !rd_dev->sg_table_count)
+               return;
+
+       page_count = rd_release_sgl_table(rd_dev, rd_dev->sg_table_array,
+                                         rd_dev->sg_table_count);
+
        pr_debug("CORE_RD[%u] - Released device space for Ramdisk"
                " Device ID: %u, pages %u in %u tables total bytes %lu\n",
                rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count,
                rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE);
 
-       kfree(sg_table);
        rd_dev->sg_table_array = NULL;
        rd_dev->sg_table_count = 0;
 }
@@ -124,38 +127,15 @@ static void rd_release_device_space(struct rd_dev *rd_dev)
  *
  *
  */
-static int rd_build_device_space(struct rd_dev *rd_dev)
+static int rd_allocate_sgl_table(struct rd_dev *rd_dev, struct rd_dev_sg_table *sg_table,
+                                u32 total_sg_needed, unsigned char init_payload)
 {
-       u32 i = 0, j, page_offset = 0, sg_per_table, sg_tables, total_sg_needed;
+       u32 i = 0, j, page_offset = 0, sg_per_table;
        u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE /
                                sizeof(struct scatterlist));
-       struct rd_dev_sg_table *sg_table;
        struct page *pg;
        struct scatterlist *sg;
-
-       if (rd_dev->rd_page_count <= 0) {
-               pr_err("Illegal page count: %u for Ramdisk device\n",
-                       rd_dev->rd_page_count);
-               return -EINVAL;
-       }
-
-       /* Don't need backing pages for NULLIO */
-       if (rd_dev->rd_flags & RDF_NULLIO)
-               return 0;
-
-       total_sg_needed = rd_dev->rd_page_count;
-
-       sg_tables = (total_sg_needed / max_sg_per_table) + 1;
-
-       sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
-       if (!sg_table) {
-               pr_err("Unable to allocate memory for Ramdisk"
-                       " scatterlist tables\n");
-               return -ENOMEM;
-       }
-
-       rd_dev->sg_table_array = sg_table;
-       rd_dev->sg_table_count = sg_tables;
+       unsigned char *p;
 
        while (total_sg_needed) {
                sg_per_table = (total_sg_needed > max_sg_per_table) ?
@@ -186,16 +166,114 @@ static int rd_build_device_space(struct rd_dev *rd_dev)
                        }
                        sg_assign_page(&sg[j], pg);
                        sg[j].length = PAGE_SIZE;
+
+                       p = kmap(pg);
+                       memset(p, init_payload, PAGE_SIZE);
+                       kunmap(pg);
                }
 
                page_offset += sg_per_table;
                total_sg_needed -= sg_per_table;
        }
 
+       return 0;
+}
+
+static int rd_build_device_space(struct rd_dev *rd_dev)
+{
+       struct rd_dev_sg_table *sg_table;
+       u32 sg_tables, total_sg_needed;
+       u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE /
+                               sizeof(struct scatterlist));
+       int rc;
+
+       if (rd_dev->rd_page_count <= 0) {
+               pr_err("Illegal page count: %u for Ramdisk device\n",
+                      rd_dev->rd_page_count);
+               return -EINVAL;
+       }
+
+       /* Don't need backing pages for NULLIO */
+       if (rd_dev->rd_flags & RDF_NULLIO)
+               return 0;
+
+       total_sg_needed = rd_dev->rd_page_count;
+
+       sg_tables = (total_sg_needed / max_sg_per_table) + 1;
+
+       sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
+       if (!sg_table) {
+               pr_err("Unable to allocate memory for Ramdisk"
+                      " scatterlist tables\n");
+               return -ENOMEM;
+       }
+
+       rd_dev->sg_table_array = sg_table;
+       rd_dev->sg_table_count = sg_tables;
+
+       rc = rd_allocate_sgl_table(rd_dev, sg_table, total_sg_needed, 0x00);
+       if (rc)
+               return rc;
+
        pr_debug("CORE_RD[%u] - Built Ramdisk Device ID: %u space of"
-               " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id,
-               rd_dev->rd_dev_id, rd_dev->rd_page_count,
-               rd_dev->sg_table_count);
+                " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id,
+                rd_dev->rd_dev_id, rd_dev->rd_page_count,
+                rd_dev->sg_table_count);
+
+       return 0;
+}
+
+static void rd_release_prot_space(struct rd_dev *rd_dev)
+{
+       u32 page_count;
+
+       if (!rd_dev->sg_prot_array || !rd_dev->sg_prot_count)
+               return;
+
+       page_count = rd_release_sgl_table(rd_dev, rd_dev->sg_prot_array,
+                                         rd_dev->sg_prot_count);
+
+       pr_debug("CORE_RD[%u] - Released protection space for Ramdisk"
+                " Device ID: %u, pages %u in %u tables total bytes %lu\n",
+                rd_dev->rd_host->rd_host_id, rd_dev->rd_dev_id, page_count,
+                rd_dev->sg_table_count, (unsigned long)page_count * PAGE_SIZE);
+
+       rd_dev->sg_prot_array = NULL;
+       rd_dev->sg_prot_count = 0;
+}
+
+static int rd_build_prot_space(struct rd_dev *rd_dev, int prot_length)
+{
+       struct rd_dev_sg_table *sg_table;
+       u32 total_sg_needed, sg_tables;
+       u32 max_sg_per_table = (RD_MAX_ALLOCATION_SIZE /
+                               sizeof(struct scatterlist));
+       int rc;
+
+       if (rd_dev->rd_flags & RDF_NULLIO)
+               return 0;
+
+       total_sg_needed = rd_dev->rd_page_count / prot_length;
+
+       sg_tables = (total_sg_needed / max_sg_per_table) + 1;
+
+       sg_table = kzalloc(sg_tables * sizeof(struct rd_dev_sg_table), GFP_KERNEL);
+       if (!sg_table) {
+               pr_err("Unable to allocate memory for Ramdisk protection"
+                      " scatterlist tables\n");
+               return -ENOMEM;
+       }
+
+       rd_dev->sg_prot_array = sg_table;
+       rd_dev->sg_prot_count = sg_tables;
+
+       rc = rd_allocate_sgl_table(rd_dev, sg_table, total_sg_needed, 0xff);
+       if (rc)
+               return rc;
+
+       pr_debug("CORE_RD[%u] - Built Ramdisk Device ID: %u prot space of"
+                " %u pages in %u tables\n", rd_dev->rd_host->rd_host_id,
+                rd_dev->rd_dev_id, total_sg_needed, rd_dev->sg_prot_count);
 
        return 0;
 }
@@ -278,6 +356,26 @@ static struct rd_dev_sg_table *rd_get_sg_table(struct rd_dev *rd_dev, u32 page)
        return NULL;
 }
 
+static struct rd_dev_sg_table *rd_get_prot_table(struct rd_dev *rd_dev, u32 page)
+{
+       struct rd_dev_sg_table *sg_table;
+       u32 i, sg_per_table = (RD_MAX_ALLOCATION_SIZE /
+                               sizeof(struct scatterlist));
+
+       i = page / sg_per_table;
+       if (i < rd_dev->sg_prot_count) {
+               sg_table = &rd_dev->sg_prot_array[i];
+               if ((sg_table->page_start_offset <= page) &&
+                    (sg_table->page_end_offset >= page))
+                       return sg_table;
+       }
+
+       pr_err("Unable to locate struct prot rd_dev_sg_table for page: %u\n",
+                       page);
+
+       return NULL;
+}
+
 static sense_reason_t
 rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
              enum dma_data_direction data_direction)
@@ -292,6 +390,7 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
        u32 rd_page;
        u32 src_len;
        u64 tmp;
+       sense_reason_t rc;
 
        if (dev->rd_flags & RDF_NULLIO) {
                target_complete_cmd(cmd, SAM_STAT_GOOD);
@@ -314,6 +413,28 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
                        data_direction == DMA_FROM_DEVICE ? "Read" : "Write",
                        cmd->t_task_lba, rd_size, rd_page, rd_offset);
 
+       if (cmd->prot_type && data_direction == DMA_TO_DEVICE) {
+               struct rd_dev_sg_table *prot_table;
+               struct scatterlist *prot_sg;
+               u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
+               u32 prot_offset, prot_page;
+
+               tmp = cmd->t_task_lba * se_dev->prot_length;
+               prot_offset = do_div(tmp, PAGE_SIZE);
+               prot_page = tmp;
+
+               prot_table = rd_get_prot_table(dev, prot_page);
+               if (!prot_table)
+                       return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+               prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
+
+               rc = sbc_dif_verify_write(cmd, cmd->t_task_lba, sectors, 0,
+                                         prot_sg, prot_offset);
+               if (rc)
+                       return rc;
+       }
+
        src_len = PAGE_SIZE - rd_offset;
        sg_miter_start(&m, sgl, sgl_nents,
                        data_direction == DMA_FROM_DEVICE ?
@@ -375,6 +496,28 @@ rd_execute_rw(struct se_cmd *cmd, struct scatterlist *sgl, u32 sgl_nents,
        }
        sg_miter_stop(&m);
 
+       if (cmd->prot_type && data_direction == DMA_FROM_DEVICE) {
+               struct rd_dev_sg_table *prot_table;
+               struct scatterlist *prot_sg;
+               u32 sectors = cmd->data_length / se_dev->dev_attrib.block_size;
+               u32 prot_offset, prot_page;
+
+               tmp = cmd->t_task_lba * se_dev->prot_length;
+               prot_offset = do_div(tmp, PAGE_SIZE);
+               prot_page = tmp;
+
+               prot_table = rd_get_prot_table(dev, prot_page);
+               if (!prot_table)
+                       return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+
+               prot_sg = &prot_table->sg_table[prot_page - prot_table->page_start_offset];
+
+               rc = sbc_dif_verify_read(cmd, cmd->t_task_lba, sectors, 0,
+                                        prot_sg, prot_offset);
+               if (rc)
+                       return rc;
+       }
+
        target_complete_cmd(cmd, SAM_STAT_GOOD);
        return 0;
 }
@@ -456,6 +599,23 @@ static sector_t rd_get_blocks(struct se_device *dev)
        return blocks_long;
 }
 
+static int rd_init_prot(struct se_device *dev)
+{
+       struct rd_dev *rd_dev = RD_DEV(dev);
+
+        if (!dev->dev_attrib.pi_prot_type)
+               return 0;
+
+       return rd_build_prot_space(rd_dev, dev->prot_length);
+}
+
+static void rd_free_prot(struct se_device *dev)
+{
+       struct rd_dev *rd_dev = RD_DEV(dev);
+
+       rd_release_prot_space(rd_dev);
+}
+
 static struct sbc_ops rd_sbc_ops = {
        .execute_rw             = rd_execute_rw,
 };
@@ -481,6 +641,8 @@ static struct se_subsystem_api rd_mcp_template = {
        .show_configfs_dev_params = rd_show_configfs_dev_params,
        .get_device_type        = sbc_get_device_type,
        .get_blocks             = rd_get_blocks,
+       .init_prot              = rd_init_prot,
+       .free_prot              = rd_free_prot,
 };
 
 int __init rd_module_init(void)
index 1789d1e14395e0c631d56485972a5ad65b5799a1..cc46a6a89b38e863a3d7b4c2f13207d251539fd2 100644 (file)
@@ -33,8 +33,12 @@ struct rd_dev {
        u32             rd_page_count;
        /* Number of SG tables in sg_table_array */
        u32             sg_table_count;
+       /* Number of SG tables in sg_prot_array */
+       u32             sg_prot_count;
        /* Array of rd_dev_sg_table_t containing scatterlists */
        struct rd_dev_sg_table *sg_table_array;
+       /* Array of rd_dev_sg_table containing protection scatterlists */
+       struct rd_dev_sg_table *sg_prot_array;
        /* Ramdisk HBA device is connected to */
        struct rd_host *rd_host;
 } ____cacheline_aligned;
index 52ae54e60105652df99df8e64a619a5ba9958ab6..fa3cae393e13e64056da79e9a8daf43bfe8dc721 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/ratelimit.h>
+#include <linux/crc-t10dif.h>
 #include <asm/unaligned.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_tcq.h>
@@ -33,7 +34,7 @@
 
 #include "target_core_internal.h"
 #include "target_core_ua.h"
-
+#include "target_core_alua.h"
 
 static sense_reason_t
 sbc_emulate_readcapacity(struct se_cmd *cmd)
@@ -105,6 +106,11 @@ sbc_emulate_readcapacity_16(struct se_cmd *cmd)
        buf[9] = (dev->dev_attrib.block_size >> 16) & 0xff;
        buf[10] = (dev->dev_attrib.block_size >> 8) & 0xff;
        buf[11] = dev->dev_attrib.block_size & 0xff;
+       /*
+        * Set P_TYPE and PROT_EN bits for DIF support
+        */
+       if (dev->dev_attrib.pi_prot_type)
+               buf[12] = (dev->dev_attrib.pi_prot_type - 1) << 1 | 0x1;
 
        if (dev->transport->get_lbppbe)
                buf[13] = dev->transport->get_lbppbe(dev) & 0x0f;
@@ -563,6 +569,44 @@ sbc_compare_and_write(struct se_cmd *cmd)
        return TCM_NO_SENSE;
 }
 
+static bool
+sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
+              u32 sectors)
+{
+       if (!cmd->t_prot_sg || !cmd->t_prot_nents)
+               return true;
+
+       switch (dev->dev_attrib.pi_prot_type) {
+       case TARGET_DIF_TYPE3_PROT:
+               if (!(cdb[1] & 0xe0))
+                       return true;
+
+               cmd->reftag_seed = 0xffffffff;
+               break;
+       case TARGET_DIF_TYPE2_PROT:
+               if (cdb[1] & 0xe0)
+                       return false;
+
+               cmd->reftag_seed = cmd->t_task_lba;
+               break;
+       case TARGET_DIF_TYPE1_PROT:
+               if (!(cdb[1] & 0xe0))
+                       return true;
+
+               cmd->reftag_seed = cmd->t_task_lba;
+               break;
+       case TARGET_DIF_TYPE0_PROT:
+       default:
+               return true;
+       }
+
+       cmd->prot_type = dev->dev_attrib.pi_prot_type;
+       cmd->prot_length = dev->prot_length * sectors;
+       cmd->prot_handover = PROT_SEPERATED;
+
+       return true;
+}
+
 sense_reason_t
 sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
 {
@@ -583,6 +627,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
        case READ_10:
                sectors = transport_get_sectors_10(cdb);
                cmd->t_task_lba = transport_lba_32(cdb);
+
+               if (!sbc_check_prot(dev, cmd, cdb, sectors))
+                       return TCM_UNSUPPORTED_SCSI_OPCODE;
+
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
                cmd->execute_rw = ops->execute_rw;
                cmd->execute_cmd = sbc_execute_rw;
@@ -590,6 +638,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
        case READ_12:
                sectors = transport_get_sectors_12(cdb);
                cmd->t_task_lba = transport_lba_32(cdb);
+
+               if (!sbc_check_prot(dev, cmd, cdb, sectors))
+                       return TCM_UNSUPPORTED_SCSI_OPCODE;
+
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
                cmd->execute_rw = ops->execute_rw;
                cmd->execute_cmd = sbc_execute_rw;
@@ -597,6 +649,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
        case READ_16:
                sectors = transport_get_sectors_16(cdb);
                cmd->t_task_lba = transport_lba_64(cdb);
+
+               if (!sbc_check_prot(dev, cmd, cdb, sectors))
+                       return TCM_UNSUPPORTED_SCSI_OPCODE;
+
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
                cmd->execute_rw = ops->execute_rw;
                cmd->execute_cmd = sbc_execute_rw;
@@ -612,6 +668,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
        case WRITE_VERIFY:
                sectors = transport_get_sectors_10(cdb);
                cmd->t_task_lba = transport_lba_32(cdb);
+
+               if (!sbc_check_prot(dev, cmd, cdb, sectors))
+                       return TCM_UNSUPPORTED_SCSI_OPCODE;
+
                if (cdb[1] & 0x8)
                        cmd->se_cmd_flags |= SCF_FUA;
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
@@ -621,6 +681,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
        case WRITE_12:
                sectors = transport_get_sectors_12(cdb);
                cmd->t_task_lba = transport_lba_32(cdb);
+
+               if (!sbc_check_prot(dev, cmd, cdb, sectors))
+                       return TCM_UNSUPPORTED_SCSI_OPCODE;
+
                if (cdb[1] & 0x8)
                        cmd->se_cmd_flags |= SCF_FUA;
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
@@ -630,6 +694,10 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
        case WRITE_16:
                sectors = transport_get_sectors_16(cdb);
                cmd->t_task_lba = transport_lba_64(cdb);
+
+               if (!sbc_check_prot(dev, cmd, cdb, sectors))
+                       return TCM_UNSUPPORTED_SCSI_OPCODE;
+
                if (cdb[1] & 0x8)
                        cmd->se_cmd_flags |= SCF_FUA;
                cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
@@ -731,6 +799,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
                case SAI_READ_CAPACITY_16:
                        cmd->execute_cmd = sbc_emulate_readcapacity_16;
                        break;
+               case SAI_REPORT_REFERRALS:
+                       cmd->execute_cmd = target_emulate_report_referrals;
+                       break;
                default:
                        pr_err("Unsupported SA: 0x%02x\n",
                                cmd->t_task_cdb[1] & 0x1f);
@@ -959,3 +1030,182 @@ err:
        return ret;
 }
 EXPORT_SYMBOL(sbc_execute_unmap);
+
+static sense_reason_t
+sbc_dif_v1_verify(struct se_device *dev, struct se_dif_v1_tuple *sdt,
+                 const void *p, sector_t sector, unsigned int ei_lba)
+{
+       int block_size = dev->dev_attrib.block_size;
+       __be16 csum;
+
+       csum = cpu_to_be16(crc_t10dif(p, block_size));
+
+       if (sdt->guard_tag != csum) {
+               pr_err("DIFv1 checksum failed on sector %llu guard tag 0x%04x"
+                       " csum 0x%04x\n", (unsigned long long)sector,
+                       be16_to_cpu(sdt->guard_tag), be16_to_cpu(csum));
+               return TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED;
+       }
+
+       if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT &&
+           be32_to_cpu(sdt->ref_tag) != (sector & 0xffffffff)) {
+               pr_err("DIFv1 Type 1 reference failed on sector: %llu tag: 0x%08x"
+                      " sector MSB: 0x%08x\n", (unsigned long long)sector,
+                      be32_to_cpu(sdt->ref_tag), (u32)(sector & 0xffffffff));
+               return TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
+       }
+
+       if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE2_PROT &&
+           be32_to_cpu(sdt->ref_tag) != ei_lba) {
+               pr_err("DIFv1 Type 2 reference failed on sector: %llu tag: 0x%08x"
+                      " ei_lba: 0x%08x\n", (unsigned long long)sector,
+                       be32_to_cpu(sdt->ref_tag), ei_lba);
+               return TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED;
+       }
+
+       return 0;
+}
+
+static void
+sbc_dif_copy_prot(struct se_cmd *cmd, unsigned int sectors, bool read,
+                 struct scatterlist *sg, int sg_off)
+{
+       struct se_device *dev = cmd->se_dev;
+       struct scatterlist *psg;
+       void *paddr, *addr;
+       unsigned int i, len, left;
+
+       left = sectors * dev->prot_length;
+
+       for_each_sg(cmd->t_prot_sg, psg, cmd->t_prot_nents, i) {
+
+               len = min(psg->length, left);
+               paddr = kmap_atomic(sg_page(psg)) + psg->offset;
+               addr = kmap_atomic(sg_page(sg)) + sg_off;
+
+               if (read)
+                       memcpy(paddr, addr, len);
+               else
+                       memcpy(addr, paddr, len);
+
+               left -= len;
+               kunmap_atomic(paddr);
+               kunmap_atomic(addr);
+       }
+}
+
+sense_reason_t
+sbc_dif_verify_write(struct se_cmd *cmd, sector_t start, unsigned int sectors,
+                    unsigned int ei_lba, struct scatterlist *sg, int sg_off)
+{
+       struct se_device *dev = cmd->se_dev;
+       struct se_dif_v1_tuple *sdt;
+       struct scatterlist *dsg, *psg = cmd->t_prot_sg;
+       sector_t sector = start;
+       void *daddr, *paddr;
+       int i, j, offset = 0;
+       sense_reason_t rc;
+
+       for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) {
+               daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
+               paddr = kmap_atomic(sg_page(psg)) + psg->offset;
+
+               for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) {
+
+                       if (offset >= psg->length) {
+                               kunmap_atomic(paddr);
+                               psg = sg_next(psg);
+                               paddr = kmap_atomic(sg_page(psg)) + psg->offset;
+                               offset = 0;
+                       }
+
+                       sdt = paddr + offset;
+
+                       pr_debug("DIF WRITE sector: %llu guard_tag: 0x%04x"
+                                " app_tag: 0x%04x ref_tag: %u\n",
+                                (unsigned long long)sector, sdt->guard_tag,
+                                sdt->app_tag, be32_to_cpu(sdt->ref_tag));
+
+                       rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
+                                              ei_lba);
+                       if (rc) {
+                               kunmap_atomic(paddr);
+                               kunmap_atomic(daddr);
+                               cmd->bad_sector = sector;
+                               return rc;
+                       }
+
+                       sector++;
+                       ei_lba++;
+                       offset += sizeof(struct se_dif_v1_tuple);
+               }
+
+               kunmap_atomic(paddr);
+               kunmap_atomic(daddr);
+       }
+       sbc_dif_copy_prot(cmd, sectors, false, sg, sg_off);
+
+       return 0;
+}
+EXPORT_SYMBOL(sbc_dif_verify_write);
+
+sense_reason_t
+sbc_dif_verify_read(struct se_cmd *cmd, sector_t start, unsigned int sectors,
+                   unsigned int ei_lba, struct scatterlist *sg, int sg_off)
+{
+       struct se_device *dev = cmd->se_dev;
+       struct se_dif_v1_tuple *sdt;
+       struct scatterlist *dsg;
+       sector_t sector = start;
+       void *daddr, *paddr;
+       int i, j, offset = sg_off;
+       sense_reason_t rc;
+
+       for_each_sg(cmd->t_data_sg, dsg, cmd->t_data_nents, i) {
+               daddr = kmap_atomic(sg_page(dsg)) + dsg->offset;
+               paddr = kmap_atomic(sg_page(sg)) + sg->offset;
+
+               for (j = 0; j < dsg->length; j += dev->dev_attrib.block_size) {
+
+                       if (offset >= sg->length) {
+                               kunmap_atomic(paddr);
+                               sg = sg_next(sg);
+                               paddr = kmap_atomic(sg_page(sg)) + sg->offset;
+                               offset = 0;
+                       }
+
+                       sdt = paddr + offset;
+
+                       pr_debug("DIF READ sector: %llu guard_tag: 0x%04x"
+                                " app_tag: 0x%04x ref_tag: %u\n",
+                                (unsigned long long)sector, sdt->guard_tag,
+                                sdt->app_tag, be32_to_cpu(sdt->ref_tag));
+
+                       if (sdt->app_tag == cpu_to_be16(0xffff)) {
+                               sector++;
+                               offset += sizeof(struct se_dif_v1_tuple);
+                               continue;
+                       }
+
+                       rc = sbc_dif_v1_verify(dev, sdt, daddr + j, sector,
+                                              ei_lba);
+                       if (rc) {
+                               kunmap_atomic(paddr);
+                               kunmap_atomic(daddr);
+                               cmd->bad_sector = sector;
+                               return rc;
+                       }
+
+                       sector++;
+                       ei_lba++;
+                       offset += sizeof(struct se_dif_v1_tuple);
+               }
+
+               kunmap_atomic(paddr);
+               kunmap_atomic(daddr);
+       }
+       sbc_dif_copy_prot(cmd, sectors, true, sg, sg_off);
+
+       return 0;
+}
+EXPORT_SYMBOL(sbc_dif_verify_read);
index 021c3f4a4f004a8e308825612d0923c48ebe755f..43c5ca9878bc5b6f3f1d675c04779b245ccc1a22 100644 (file)
@@ -100,6 +100,11 @@ spc_emulate_inquiry_std(struct se_cmd *cmd, unsigned char *buf)
         */
        if (dev->dev_attrib.emulate_3pc)
                buf[5] |= 0x8;
+       /*
+        * Set Protection (PROTECT) bit when DIF has been enabled.
+        */
+       if (dev->dev_attrib.pi_prot_type)
+               buf[5] |= 0x1;
 
        buf[7] = 0x2; /* CmdQue=1 */
 
@@ -267,7 +272,7 @@ check_t10_vend_desc:
        port = lun->lun_sep;
        if (port) {
                struct t10_alua_lu_gp *lu_gp;
-               u32 padding, scsi_name_len;
+               u32 padding, scsi_name_len, scsi_target_len;
                u16 lu_gp_id = 0;
                u16 tg_pt_gp_id = 0;
                u16 tpgt;
@@ -365,16 +370,6 @@ check_lu_gp:
                 * section 7.5.1 Table 362
                 */
 check_scsi_name:
-               scsi_name_len = strlen(tpg->se_tpg_tfo->tpg_get_wwn(tpg));
-               /* UTF-8 ",t,0x<16-bit TPGT>" + NULL Terminator */
-               scsi_name_len += 10;
-               /* Check for 4-byte padding */
-               padding = ((-scsi_name_len) & 3);
-               if (padding != 0)
-                       scsi_name_len += padding;
-               /* Header size + Designation descriptor */
-               scsi_name_len += 4;
-
                buf[off] =
                        (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
                buf[off++] |= 0x3; /* CODE SET == UTF-8 */
@@ -402,13 +397,57 @@ check_scsi_name:
                 * shall be no larger than 256 and shall be a multiple
                 * of four.
                 */
+               padding = ((-scsi_name_len) & 3);
                if (padding)
                        scsi_name_len += padding;
+               if (scsi_name_len > 256)
+                       scsi_name_len = 256;
 
                buf[off-1] = scsi_name_len;
                off += scsi_name_len;
                /* Header size + Designation descriptor */
                len += (scsi_name_len + 4);
+
+               /*
+                * Target device designator
+                */
+               buf[off] =
+                       (tpg->se_tpg_tfo->get_fabric_proto_ident(tpg) << 4);
+               buf[off++] |= 0x3; /* CODE SET == UTF-8 */
+               buf[off] = 0x80; /* Set PIV=1 */
+               /* Set ASSOCIATION == target device: 10b */
+               buf[off] |= 0x20;
+               /* DESIGNATOR TYPE == SCSI name string */
+               buf[off++] |= 0x8;
+               off += 2; /* Skip over Reserved and length */
+               /*
+                * SCSI name string identifer containing, $FABRIC_MOD
+                * dependent information.  For LIO-Target and iSCSI
+                * Target Port, this means "<iSCSI name>" in
+                * UTF-8 encoding.
+                */
+               scsi_target_len = sprintf(&buf[off], "%s",
+                                         tpg->se_tpg_tfo->tpg_get_wwn(tpg));
+               scsi_target_len += 1 /* Include  NULL terminator */;
+               /*
+                * The null-terminated, null-padded (see 4.4.2) SCSI
+                * NAME STRING field contains a UTF-8 format string.
+                * The number of bytes in the SCSI NAME STRING field
+                * (i.e., the value in the DESIGNATOR LENGTH field)
+                * shall be no larger than 256 and shall be a multiple
+                * of four.
+                */
+               padding = ((-scsi_target_len) & 3);
+               if (padding)
+                       scsi_target_len += padding;
+               if (scsi_name_len > 256)
+                       scsi_name_len = 256;
+
+               buf[off-1] = scsi_target_len;
+               off += scsi_target_len;
+
+               /* Header size + Designation descriptor */
+               len += (scsi_target_len + 4);
        }
        buf[2] = ((len >> 8) & 0xff);
        buf[3] = (len & 0xff); /* Page Length for VPD 0x83 */
@@ -436,12 +475,26 @@ spc_emulate_evpd_86(struct se_cmd *cmd, unsigned char *buf)
        struct se_device *dev = cmd->se_dev;
 
        buf[3] = 0x3c;
+       /*
+        * Set GRD_CHK + REF_CHK for TYPE1 protection, or GRD_CHK
+        * only for TYPE3 protection.
+        */
+       if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE1_PROT)
+               buf[4] = 0x5;
+       else if (dev->dev_attrib.pi_prot_type == TARGET_DIF_TYPE3_PROT)
+               buf[4] = 0x4;
+
        /* Set HEADSUP, ORDSUP, SIMPSUP */
        buf[5] = 0x07;
 
        /* If WriteCache emulation is enabled, set V_SUP */
        if (spc_check_dev_wce(dev))
                buf[6] = 0x01;
+       /* If an LBA map is present set R_SUP */
+       spin_lock(&cmd->se_dev->t10_alua.lba_map_lock);
+       if (!list_empty(&dev->t10_alua.lba_map_list))
+               buf[8] = 0x10;
+       spin_unlock(&cmd->se_dev->t10_alua.lba_map_lock);
        return 0;
 }
 
@@ -600,6 +653,20 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
        return 0;
 }
 
+/* Referrals VPD page */
+static sense_reason_t
+spc_emulate_evpd_b3(struct se_cmd *cmd, unsigned char *buf)
+{
+       struct se_device *dev = cmd->se_dev;
+
+       buf[0] = dev->transport->get_device_type(dev);
+       buf[3] = 0x0c;
+       put_unaligned_be32(dev->t10_alua.lba_map_segment_size, &buf[8]);
+       put_unaligned_be32(dev->t10_alua.lba_map_segment_size, &buf[12]);
+
+       return 0;
+}
+
 static sense_reason_t
 spc_emulate_evpd_00(struct se_cmd *cmd, unsigned char *buf);
 
@@ -614,6 +681,7 @@ static struct {
        { .page = 0xb0, .emulate = spc_emulate_evpd_b0 },
        { .page = 0xb1, .emulate = spc_emulate_evpd_b1 },
        { .page = 0xb2, .emulate = spc_emulate_evpd_b2 },
+       { .page = 0xb3, .emulate = spc_emulate_evpd_b3 },
 };
 
 /* supported vital product data pages */
@@ -643,11 +711,15 @@ spc_emulate_inquiry(struct se_cmd *cmd)
        struct se_portal_group *tpg = cmd->se_lun->lun_sep->sep_tpg;
        unsigned char *rbuf;
        unsigned char *cdb = cmd->t_task_cdb;
-       unsigned char buf[SE_INQUIRY_BUF];
+       unsigned char *buf;
        sense_reason_t ret;
        int p;
 
-       memset(buf, 0, SE_INQUIRY_BUF);
+       buf = kzalloc(SE_INQUIRY_BUF, GFP_KERNEL);
+       if (!buf) {
+               pr_err("Unable to allocate response buffer for INQUIRY\n");
+               return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+       }
 
        if (dev == tpg->tpg_virt_lun0.lun_se_dev)
                buf[0] = 0x3f; /* Not connected */
@@ -680,9 +752,10 @@ spc_emulate_inquiry(struct se_cmd *cmd)
 out:
        rbuf = transport_kmap_data_sg(cmd);
        if (rbuf) {
-               memcpy(rbuf, buf, min_t(u32, sizeof(buf), cmd->data_length));
+               memcpy(rbuf, buf, min_t(u32, SE_INQUIRY_BUF, cmd->data_length));
                transport_kunmap_data_sg(cmd);
        }
+       kfree(buf);
 
        if (!ret)
                target_complete_cmd(cmd, GOOD);
@@ -785,6 +858,19 @@ static int spc_modesense_control(struct se_device *dev, u8 pc, u8 *p)
         * status (see SAM-4).
         */
        p[5] = (dev->dev_attrib.emulate_tas) ? 0x40 : 0x00;
+       /*
+        * From spc4r30, section 7.5.7 Control mode page
+        *
+        * Application Tag Owner (ATO) bit set to one.
+        *
+        * If the ATO bit is set to one the device server shall not modify the
+        * LOGICAL BLOCK APPLICATION TAG field and, depending on the protection
+        * type, shall not modify the contents of the LOGICAL BLOCK REFERENCE
+        * TAG field.
+        */
+       if (dev->dev_attrib.pi_prot_type)
+               p[5] |= 0x80;
+
        p[8] = 0xff;
        p[9] = 0xff;
        p[11] = 30;
index 2a573de19a9fdceea07d233f15a699be6c10c770..c036595b17cfc9cfc75f9bd57d146bfb4179d67b 100644 (file)
@@ -656,7 +656,7 @@ static int core_tpg_setup_virtual_lun0(struct se_portal_group *se_tpg)
        spin_lock_init(&lun->lun_sep_lock);
        init_completion(&lun->lun_ref_comp);
 
-       ret = core_tpg_post_addlun(se_tpg, lun, lun_access, dev);
+       ret = core_tpg_add_lun(se_tpg, lun, lun_access, dev);
        if (ret < 0)
                return ret;
 
@@ -781,7 +781,7 @@ int core_tpg_deregister(struct se_portal_group *se_tpg)
 }
 EXPORT_SYMBOL(core_tpg_deregister);
 
-struct se_lun *core_tpg_pre_addlun(
+struct se_lun *core_tpg_alloc_lun(
        struct se_portal_group *tpg,
        u32 unpacked_lun)
 {
@@ -811,11 +811,11 @@ struct se_lun *core_tpg_pre_addlun(
        return lun;
 }
 
-int core_tpg_post_addlun(
+int core_tpg_add_lun(
        struct se_portal_group *tpg,
        struct se_lun *lun,
        u32 lun_access,
-       void *lun_ptr)
+       struct se_device *dev)
 {
        int ret;
 
@@ -823,7 +823,7 @@ int core_tpg_post_addlun(
        if (ret < 0)
                return ret;
 
-       ret = core_dev_export(lun_ptr, tpg, lun);
+       ret = core_dev_export(dev, tpg, lun);
        if (ret < 0) {
                percpu_ref_cancel_init(&lun->lun_ref);
                return ret;
index 91953da0f62329af488a91eaa1d83be6fda68f08..c50fd9f11aab8b0dfb8b90991378a51bf8255d1b 100644 (file)
@@ -62,6 +62,8 @@ struct kmem_cache *t10_alua_lu_gp_cache;
 struct kmem_cache *t10_alua_lu_gp_mem_cache;
 struct kmem_cache *t10_alua_tg_pt_gp_cache;
 struct kmem_cache *t10_alua_tg_pt_gp_mem_cache;
+struct kmem_cache *t10_alua_lba_map_cache;
+struct kmem_cache *t10_alua_lba_map_mem_cache;
 
 static void transport_complete_task_attr(struct se_cmd *cmd);
 static void transport_handle_queue_full(struct se_cmd *cmd,
@@ -128,14 +130,36 @@ int init_se_kmem_caches(void)
                                "mem_t failed\n");
                goto out_free_tg_pt_gp_cache;
        }
+       t10_alua_lba_map_cache = kmem_cache_create(
+                       "t10_alua_lba_map_cache",
+                       sizeof(struct t10_alua_lba_map),
+                       __alignof__(struct t10_alua_lba_map), 0, NULL);
+       if (!t10_alua_lba_map_cache) {
+               pr_err("kmem_cache_create() for t10_alua_lba_map_"
+                               "cache failed\n");
+               goto out_free_tg_pt_gp_mem_cache;
+       }
+       t10_alua_lba_map_mem_cache = kmem_cache_create(
+                       "t10_alua_lba_map_mem_cache",
+                       sizeof(struct t10_alua_lba_map_member),
+                       __alignof__(struct t10_alua_lba_map_member), 0, NULL);
+       if (!t10_alua_lba_map_mem_cache) {
+               pr_err("kmem_cache_create() for t10_alua_lba_map_mem_"
+                               "cache failed\n");
+               goto out_free_lba_map_cache;
+       }
 
        target_completion_wq = alloc_workqueue("target_completion",
                                               WQ_MEM_RECLAIM, 0);
        if (!target_completion_wq)
-               goto out_free_tg_pt_gp_mem_cache;
+               goto out_free_lba_map_mem_cache;
 
        return 0;
 
+out_free_lba_map_mem_cache:
+       kmem_cache_destroy(t10_alua_lba_map_mem_cache);
+out_free_lba_map_cache:
+       kmem_cache_destroy(t10_alua_lba_map_cache);
 out_free_tg_pt_gp_mem_cache:
        kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
 out_free_tg_pt_gp_cache:
@@ -164,6 +188,8 @@ void release_se_kmem_caches(void)
        kmem_cache_destroy(t10_alua_lu_gp_mem_cache);
        kmem_cache_destroy(t10_alua_tg_pt_gp_cache);
        kmem_cache_destroy(t10_alua_tg_pt_gp_mem_cache);
+       kmem_cache_destroy(t10_alua_lba_map_cache);
+       kmem_cache_destroy(t10_alua_lba_map_mem_cache);
 }
 
 /* This code ensures unique mib indexes are handed out. */
@@ -568,10 +594,11 @@ static void transport_lun_remove_cmd(struct se_cmd *cmd)
 {
        struct se_lun *lun = cmd->se_lun;
 
-       if (!lun || !cmd->lun_ref_active)
+       if (!lun)
                return;
 
-       percpu_ref_put(&lun->lun_ref);
+       if (cmpxchg(&cmd->lun_ref_active, true, false))
+               percpu_ref_put(&lun->lun_ref);
 }
 
 void transport_cmd_finish_abort(struct se_cmd *cmd, int remove)
@@ -1284,6 +1311,8 @@ transport_generic_map_mem_to_cmd(struct se_cmd *cmd, struct scatterlist *sgl,
  * @sgl_count: scatterlist count for unidirectional mapping
  * @sgl_bidi: struct scatterlist memory for bidirectional READ mapping
  * @sgl_bidi_count: scatterlist count for bidirectional READ mapping
+ * @sgl_prot: struct scatterlist memory protection information
+ * @sgl_prot_count: scatterlist count for protection information
  *
  * Returns non zero to signal active I/O shutdown failure.  All other
  * setup exceptions will be returned as a SCSI CHECK_CONDITION response,
@@ -1296,7 +1325,8 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
                unsigned char *cdb, unsigned char *sense, u32 unpacked_lun,
                u32 data_length, int task_attr, int data_dir, int flags,
                struct scatterlist *sgl, u32 sgl_count,
-               struct scatterlist *sgl_bidi, u32 sgl_bidi_count)
+               struct scatterlist *sgl_bidi, u32 sgl_bidi_count,
+               struct scatterlist *sgl_prot, u32 sgl_prot_count)
 {
        struct se_portal_group *se_tpg;
        sense_reason_t rc;
@@ -1338,6 +1368,14 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
                target_put_sess_cmd(se_sess, se_cmd);
                return 0;
        }
+       /*
+        * Save pointers for SGLs containing protection information,
+        * if present.
+        */
+       if (sgl_prot_count) {
+               se_cmd->t_prot_sg = sgl_prot;
+               se_cmd->t_prot_nents = sgl_prot_count;
+       }
 
        rc = target_setup_cmd_from_cdb(se_cmd, cdb);
        if (rc != 0) {
@@ -1380,6 +1418,7 @@ int target_submit_cmd_map_sgls(struct se_cmd *se_cmd, struct se_session *se_sess
                        return 0;
                }
        }
+
        /*
         * Check if we need to delay processing because of ALUA
         * Active/NonOptimized primary access state..
@@ -1419,7 +1458,7 @@ int target_submit_cmd(struct se_cmd *se_cmd, struct se_session *se_sess,
 {
        return target_submit_cmd_map_sgls(se_cmd, se_sess, cdb, sense,
                        unpacked_lun, data_length, task_attr, data_dir,
-                       flags, NULL, 0, NULL, 0);
+                       flags, NULL, 0, NULL, 0, NULL, 0);
 }
 EXPORT_SYMBOL(target_submit_cmd);
 
@@ -2455,6 +2494,19 @@ static int transport_get_sense_codes(
        return 0;
 }
 
+static
+void transport_err_sector_info(unsigned char *buffer, sector_t bad_sector)
+{
+       /* Place failed LBA in sense data information descriptor 0. */
+       buffer[SPC_ADD_SENSE_LEN_OFFSET] = 0xc;
+       buffer[SPC_DESC_TYPE_OFFSET] = 0; /* Information */
+       buffer[SPC_ADDITIONAL_DESC_LEN_OFFSET] = 0xa;
+       buffer[SPC_VALIDITY_OFFSET] = 0x80;
+
+       /* Descriptor Information: failing sector */
+       put_unaligned_be64(bad_sector, &buffer[12]);
+}
+
 int
 transport_send_check_condition_and_sense(struct se_cmd *cmd,
                sense_reason_t reason, int from_transport)
@@ -2648,6 +2700,39 @@ transport_send_check_condition_and_sense(struct se_cmd *cmd,
                buffer[SPC_ASC_KEY_OFFSET] = 0x1d;
                buffer[SPC_ASCQ_KEY_OFFSET] = 0x00;
                break;
+       case TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED:
+               /* CURRENT ERROR */
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ILLEGAL REQUEST */
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               /* LOGICAL BLOCK GUARD CHECK FAILED */
+               buffer[SPC_ASC_KEY_OFFSET] = 0x10;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0x01;
+               transport_err_sector_info(buffer, cmd->bad_sector);
+               break;
+       case TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED:
+               /* CURRENT ERROR */
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ILLEGAL REQUEST */
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               /* LOGICAL BLOCK APPLICATION TAG CHECK FAILED */
+               buffer[SPC_ASC_KEY_OFFSET] = 0x10;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0x02;
+               transport_err_sector_info(buffer, cmd->bad_sector);
+               break;
+       case TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED:
+               /* CURRENT ERROR */
+               buffer[0] = 0x70;
+               buffer[SPC_ADD_SENSE_LEN_OFFSET] = 10;
+               /* ILLEGAL REQUEST */
+               buffer[SPC_SENSE_KEY_OFFSET] = ILLEGAL_REQUEST;
+               /* LOGICAL BLOCK REFERENCE TAG CHECK FAILED */
+               buffer[SPC_ASC_KEY_OFFSET] = 0x10;
+               buffer[SPC_ASCQ_KEY_OFFSET] = 0x03;
+               transport_err_sector_info(buffer, cmd->bad_sector);
+               break;
        case TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE:
        default:
                /* CURRENT ERROR */
index b04467e7547c97817e611e2341568bd7a592a1e1..505519b10cb75bdb1e7e4c204e89f7c570500821 100644 (file)
@@ -98,7 +98,6 @@ int core_scsi3_ua_allocate(
                pr_err("Unable to allocate struct se_ua\n");
                return -ENOMEM;
        }
-       INIT_LIST_HEAD(&ua->ua_dev_list);
        INIT_LIST_HEAD(&ua->ua_nacl_list);
 
        ua->ua_nacl = nacl;
index 6b88a9958f6126ab9267cc1c23e97dd8e59b5a57..669c536fd959575da69816e4a8714b5f78a362c7 100644 (file)
 #include "target_core_xcopy.h"
 
 static struct workqueue_struct *xcopy_wq = NULL;
-/*
- * From target_core_spc.c
- */
-extern void spc_parse_naa_6h_vendor_specific(struct se_device *, unsigned char *);
 /*
  * From target_core_device.c
  */
index 479ec5621a4eafd9eb10e9652577a608dc8b3e4d..8b2c1aaf81dede06ebe9263f5c2d010ad4f8a997 100644 (file)
@@ -438,7 +438,7 @@ static void ft_recv_cmd(struct ft_sess *sess, struct fc_frame *fp)
        struct se_session *se_sess = sess->se_sess;
        int tag;
 
-       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
        if (tag < 0)
                goto busy;
 
index c6932fb53a8dd32f08f235fc98ac0a72ff6d5104..e879da81ad9303c2ad1d0d4d0487662523bc1b1c 100644 (file)
@@ -267,7 +267,7 @@ struct ft_node_acl *ft_acl_get(struct ft_tpg *tpg, struct fc_rport_priv *rdata)
        return found;
 }
 
-struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg)
+static struct se_node_acl *ft_tpg_alloc_fabric_acl(struct se_portal_group *se_tpg)
 {
        struct ft_node_acl *acl;
 
@@ -552,7 +552,7 @@ static struct target_core_fabric_ops ft_fabric_ops = {
        .fabric_drop_nodeacl =          &ft_del_acl,
 };
 
-int ft_register_configfs(void)
+static int ft_register_configfs(void)
 {
        struct target_fabric_configfs *fabric;
        int ret;
@@ -599,7 +599,7 @@ int ft_register_configfs(void)
        return 0;
 }
 
-void ft_deregister_configfs(void)
+static void ft_deregister_configfs(void)
 {
        if (!ft_configfs)
                return;
index 978db344bda06ec333c2e0c434d1f0c69718ae48..b24aa010f68c5fd156c8abba916be24a61ed4c2f 100644 (file)
@@ -366,7 +366,7 @@ config TRACE_SINK
          "Trace data router for MIPI P1149.7 cJTAG standard".
 
 config PPC_EPAPR_HV_BYTECHAN
-       tristate "ePAPR hypervisor byte channel driver"
+       bool "ePAPR hypervisor byte channel driver"
        depends on PPC
        select EPAPR_PARAVIRT
        help
index db19a38c8c69b0d33dddac2c1fff95f3f79b80f3..ea74460f363862507cbf85af2b2873ae8208ae72 100644 (file)
@@ -77,6 +77,7 @@ struct hvc_iucv_private {
        struct list_head        tty_outqueue;   /* outgoing IUCV messages */
        struct list_head        tty_inqueue;    /* incoming IUCV messages */
        struct device           *dev;           /* device structure */
+       u8                      info_path[16];  /* IUCV path info (dev attr) */
 };
 
 struct iucv_tty_buffer {
@@ -126,7 +127,7 @@ static struct iucv_handler hvc_iucv_handler = {
  * This function returns the struct hvc_iucv_private instance that corresponds
  * to the HVC virtual terminal number specified as parameter @num.
  */
-struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
+static struct hvc_iucv_private *hvc_iucv_get_private(uint32_t num)
 {
        if ((num < HVC_IUCV_MAGIC) || (num - HVC_IUCV_MAGIC > hvc_iucv_devices))
                return NULL;
@@ -772,18 +773,37 @@ static int hvc_iucv_filter_connreq(u8 ipvmid[8])
 static int hvc_iucv_path_pending(struct iucv_path *path,
                                  u8 ipvmid[8], u8 ipuser[16])
 {
-       struct hvc_iucv_private *priv;
+       struct hvc_iucv_private *priv, *tmp;
+       u8 wildcard[9] = "lnxhvc  ";
+       int i, rc, find_unused;
        u8 nuser_data[16];
        u8 vm_user_id[9];
-       int i, rc;
 
+       ASCEBC(wildcard, sizeof(wildcard));
+       find_unused = !memcmp(wildcard, ipuser, 8);
+
+       /* First, check if the pending path request is managed by this
+        * IUCV handler:
+        * - find a disconnected device if ipuser contains the wildcard
+        * - find the device that matches the terminal ID in ipuser
+        */
        priv = NULL;
-       for (i = 0; i < hvc_iucv_devices; i++)
-               if (hvc_iucv_table[i] &&
-                   (0 == memcmp(hvc_iucv_table[i]->srv_name, ipuser, 8))) {
-                       priv = hvc_iucv_table[i];
+       for (i = 0; i < hvc_iucv_devices; i++) {
+               tmp = hvc_iucv_table[i];
+               if (!tmp)
+                       continue;
+
+               if (find_unused) {
+                       spin_lock(&tmp->lock);
+                       if (tmp->iucv_state == IUCV_DISCONN)
+                               priv = tmp;
+                       spin_unlock(&tmp->lock);
+
+               } else if (!memcmp(tmp->srv_name, ipuser, 8))
+                               priv = tmp;
+               if (priv)
                        break;
-               }
+       }
        if (!priv)
                return -ENODEV;
 
@@ -826,6 +846,10 @@ static     int hvc_iucv_path_pending(struct iucv_path *path,
        priv->path = path;
        priv->iucv_state = IUCV_CONNECTED;
 
+       /* store path information */
+       memcpy(priv->info_path, ipvmid, 8);
+       memcpy(priv->info_path + 8, ipuser + 8, 8);
+
        /* flush buffered output data... */
        schedule_delayed_work(&priv->sndbuf_work, 5);
 
@@ -960,6 +984,49 @@ static int hvc_iucv_pm_restore_thaw(struct device *dev)
        return 0;
 }
 
+static ssize_t hvc_iucv_dev_termid_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct hvc_iucv_private *priv = dev_get_drvdata(dev);
+       size_t len;
+
+       len = sizeof(priv->srv_name);
+       memcpy(buf, priv->srv_name, len);
+       EBCASC(buf, len);
+       buf[len++] = '\n';
+       return len;
+}
+
+static ssize_t hvc_iucv_dev_state_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       struct hvc_iucv_private *priv = dev_get_drvdata(dev);
+       return sprintf(buf, "%u:%u\n", priv->iucv_state, priv->tty_state);
+}
+
+static ssize_t hvc_iucv_dev_peer_show(struct device *dev,
+                                     struct device_attribute *attr,
+                                     char *buf)
+{
+       struct hvc_iucv_private *priv = dev_get_drvdata(dev);
+       char vmid[9], ipuser[9];
+
+       memset(vmid, 0, sizeof(vmid));
+       memset(ipuser, 0, sizeof(ipuser));
+
+       spin_lock_bh(&priv->lock);
+       if (priv->iucv_state == IUCV_CONNECTED) {
+               memcpy(vmid, priv->info_path, 8);
+               memcpy(ipuser, priv->info_path + 8, 8);
+       }
+       spin_unlock_bh(&priv->lock);
+       EBCASC(ipuser, 8);
+
+       return sprintf(buf, "%s:%s\n", vmid, ipuser);
+}
+
 
 /* HVC operations */
 static const struct hv_ops hvc_iucv_ops = {
@@ -985,6 +1052,25 @@ static struct device_driver hvc_iucv_driver = {
        .pm   = &hvc_iucv_pm_ops,
 };
 
+/* IUCV HVC device attributes */
+static DEVICE_ATTR(termid, 0640, hvc_iucv_dev_termid_show, NULL);
+static DEVICE_ATTR(state, 0640, hvc_iucv_dev_state_show, NULL);
+static DEVICE_ATTR(peer, 0640, hvc_iucv_dev_peer_show, NULL);
+static struct attribute *hvc_iucv_dev_attrs[] = {
+       &dev_attr_termid.attr,
+       &dev_attr_state.attr,
+       &dev_attr_peer.attr,
+       NULL,
+};
+static struct attribute_group hvc_iucv_dev_attr_group = {
+       .attrs = hvc_iucv_dev_attrs,
+};
+static const struct attribute_group *hvc_iucv_dev_attr_groups[] = {
+       &hvc_iucv_dev_attr_group,
+       NULL,
+};
+
+
 /**
  * hvc_iucv_alloc() - Allocates a new struct hvc_iucv_private instance
  * @id:                        hvc_iucv_table index
@@ -1046,6 +1132,7 @@ static int __init hvc_iucv_alloc(int id, unsigned int is_console)
        priv->dev->bus = &iucv_bus;
        priv->dev->parent = iucv_root;
        priv->dev->driver = &hvc_iucv_driver;
+       priv->dev->groups = hvc_iucv_dev_attr_groups;
        priv->dev->release = (void (*)(struct device *)) kfree;
        rc = device_register(priv->dev);
        if (rc) {
index 649d5129c4b44458c5aa7233572d9974ee4b3ff4..78e82b017b928bb55982cb4b015a2e81a6862c46 100644 (file)
 #include <linux/sysrq.h>
 #include <linux/serial.h>
 #include <linux/serial_core.h>
-
-#include <bcm63xx_irq.h>
-#include <bcm63xx_regs.h>
-#include <bcm63xx_io.h>
+#include <linux/serial_bcm63xx.h>
 
 #define BCM63XX_NR_UARTS       2
 
@@ -81,13 +78,13 @@ static struct uart_port ports[BCM63XX_NR_UARTS];
 static inline unsigned int bcm_uart_readl(struct uart_port *port,
                                         unsigned int offset)
 {
-       return bcm_readl(port->membase + offset);
+       return __raw_readl(port->membase + offset);
 }
 
 static inline void bcm_uart_writel(struct uart_port *port,
                                  unsigned int value, unsigned int offset)
 {
-       bcm_writel(value, port->membase + offset);
+       __raw_writel(value, port->membase + offset);
 }
 
 /*
index d98e4334897040cd7e6a482fee5a7a913338c4ec..67423805e6d9b0ed761c26958e7cf2df9a31e8f0 100644 (file)
@@ -455,11 +455,11 @@ static void load_code(struct icom_port *icom_port)
        for (index = 0; index < fw->size; index++)
                new_page[index] = fw->data[index];
 
-       release_firmware(fw);
-
        writeb((char) ((fw->size + 16)/16), &icom_port->dram->mac_length);
        writel(temp_pci, &icom_port->dram->mac_load_addr);
 
+       release_firmware(fw);
+
        /*Setting the syncReg to 0x80 causes adapter to start downloading
           the personality code into adapter instruction RAM.
           Once code is loaded, it will begin executing and, based on
index ec06505e3ae63704d73f44ad23252b3de7bc6656..97888f4900eced03ab3a656faa6de016c16d3851 100644 (file)
@@ -421,6 +421,7 @@ struct psc_fifoc {
 
 static struct psc_fifoc __iomem *psc_fifoc;
 static unsigned int psc_fifoc_irq;
+static struct clk *psc_fifoc_clk;
 
 static void mpc512x_psc_fifo_init(struct uart_port *port)
 {
@@ -568,36 +569,73 @@ static unsigned int mpc512x_psc_set_baudrate(struct uart_port *port,
 /* Init PSC FIFO Controller */
 static int __init mpc512x_psc_fifoc_init(void)
 {
+       int err;
        struct device_node *np;
+       struct clk *clk;
+
+       /* default error code, potentially overwritten by clock calls */
+       err = -ENODEV;
 
        np = of_find_compatible_node(NULL, NULL,
                                     "fsl,mpc5121-psc-fifo");
        if (!np) {
                pr_err("%s: Can't find FIFOC node\n", __func__);
-               return -ENODEV;
+               goto out_err;
        }
 
+       clk = of_clk_get(np, 0);
+       if (IS_ERR(clk)) {
+               /* backwards compat with device trees that lack clock specs */
+               clk = clk_get_sys(np->name, "ipg");
+       }
+       if (IS_ERR(clk)) {
+               pr_err("%s: Can't lookup FIFO clock\n", __func__);
+               err = PTR_ERR(clk);
+               goto out_ofnode_put;
+       }
+       if (clk_prepare_enable(clk)) {
+               pr_err("%s: Can't enable FIFO clock\n", __func__);
+               clk_put(clk);
+               goto out_ofnode_put;
+       }
+       psc_fifoc_clk = clk;
+
        psc_fifoc = of_iomap(np, 0);
        if (!psc_fifoc) {
                pr_err("%s: Can't map FIFOC\n", __func__);
-               of_node_put(np);
-               return -ENODEV;
+               goto out_clk_disable;
        }
 
        psc_fifoc_irq = irq_of_parse_and_map(np, 0);
-       of_node_put(np);
        if (psc_fifoc_irq == 0) {
                pr_err("%s: Can't get FIFOC irq\n", __func__);
-               iounmap(psc_fifoc);
-               return -ENODEV;
+               goto out_unmap;
        }
 
+       of_node_put(np);
        return 0;
+
+out_unmap:
+       iounmap(psc_fifoc);
+out_clk_disable:
+       clk_disable_unprepare(psc_fifoc_clk);
+       clk_put(psc_fifoc_clk);
+out_ofnode_put:
+       of_node_put(np);
+out_err:
+       return err;
 }
 
 static void __exit mpc512x_psc_fifoc_uninit(void)
 {
        iounmap(psc_fifoc);
+
+       /* disable the clock, errors are not fatal */
+       if (psc_fifoc_clk) {
+               clk_disable_unprepare(psc_fifoc_clk);
+               clk_put(psc_fifoc_clk);
+               psc_fifoc_clk = NULL;
+       }
 }
 
 /* 512x specific interrupt handler. The caller holds the port lock */
@@ -619,29 +657,55 @@ static irqreturn_t mpc512x_psc_handle_irq(struct uart_port *port)
 }
 
 static struct clk *psc_mclk_clk[MPC52xx_PSC_MAXNUM];
+static struct clk *psc_ipg_clk[MPC52xx_PSC_MAXNUM];
 
 /* called from within the .request_port() callback (allocation) */
 static int mpc512x_psc_alloc_clock(struct uart_port *port)
 {
        int psc_num;
-       char clk_name[16];
        struct clk *clk;
        int err;
 
        psc_num = (port->mapbase & 0xf00) >> 8;
-       snprintf(clk_name, sizeof(clk_name), "psc%d_mclk", psc_num);
-       clk = devm_clk_get(port->dev, clk_name);
+
+       clk = devm_clk_get(port->dev, "mclk");
        if (IS_ERR(clk)) {
                dev_err(port->dev, "Failed to get MCLK!\n");
-               return PTR_ERR(clk);
+               err = PTR_ERR(clk);
+               goto out_err;
        }
        err = clk_prepare_enable(clk);
        if (err) {
                dev_err(port->dev, "Failed to enable MCLK!\n");
-               return err;
+               goto out_err;
        }
        psc_mclk_clk[psc_num] = clk;
+
+       clk = devm_clk_get(port->dev, "ipg");
+       if (IS_ERR(clk)) {
+               dev_err(port->dev, "Failed to get IPG clock!\n");
+               err = PTR_ERR(clk);
+               goto out_err;
+       }
+       err = clk_prepare_enable(clk);
+       if (err) {
+               dev_err(port->dev, "Failed to enable IPG clock!\n");
+               goto out_err;
+       }
+       psc_ipg_clk[psc_num] = clk;
+
        return 0;
+
+out_err:
+       if (psc_mclk_clk[psc_num]) {
+               clk_disable_unprepare(psc_mclk_clk[psc_num]);
+               psc_mclk_clk[psc_num] = NULL;
+       }
+       if (psc_ipg_clk[psc_num]) {
+               clk_disable_unprepare(psc_ipg_clk[psc_num]);
+               psc_ipg_clk[psc_num] = NULL;
+       }
+       return err;
 }
 
 /* called from within the .release_port() callback (release) */
@@ -656,6 +720,10 @@ static void mpc512x_psc_relse_clock(struct uart_port *port)
                clk_disable_unprepare(clk);
                psc_mclk_clk[psc_num] = NULL;
        }
+       if (psc_ipg_clk[psc_num]) {
+               clk_disable_unprepare(psc_ipg_clk[psc_num]);
+               psc_ipg_clk[psc_num] = NULL;
+       }
 }
 
 /* implementation of the .clock() callback (enable/disable) */
index 9cbd3acaf37fca13a55ea6b9a854e259790d1758..8fa1134e005165dc2ca33ef43b9d575368602590 100644 (file)
@@ -1508,10 +1508,14 @@ static int pch_uart_verify_port(struct uart_port *port,
                        __func__);
                return -EOPNOTSUPP;
 #endif
-               dev_info(priv->port.dev, "PCH UART : Use DMA Mode\n");
-               if (!priv->use_dma)
+               if (!priv->use_dma) {
                        pch_request_dma(port);
-               priv->use_dma = 1;
+                       if (priv->chan_rx)
+                               priv->use_dma = 1;
+               }
+               dev_info(priv->port.dev, "PCH UART: %s\n",
+                               priv->use_dma ?
+                               "Use DMA Mode" : "No DMA");
        }
 
        return 0;
index c1af04d46682657794b4893f3eac571a13acc685..9cd706df3b3351cbfa10fa14c254b36724601cc1 100644 (file)
@@ -1209,7 +1209,6 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
 
        /* reset the fifos (and setup the uart) */
        s3c24xx_serial_resetport(port, cfg);
-       clk_disable_unprepare(ourport->clk);
        return 0;
 }
 
@@ -1287,6 +1286,13 @@ static int s3c24xx_serial_probe(struct platform_device *pdev)
        uart_add_one_port(&s3c24xx_uart_drv, &ourport->port);
        platform_set_drvdata(pdev, &ourport->port);
 
+       /*
+        * Deactivate the clock enabled in s3c24xx_serial_init_port here,
+        * so that a potential re-enablement through the pm-callback overlaps
+        * and keeps the clock enabled in this case.
+        */
+       clk_disable_unprepare(ourport->clk);
+
 #ifdef CONFIG_SAMSUNG_CLOCK
        ret = device_create_file(&pdev->dev, &dev_attr_clock_source);
        if (ret < 0)
index abd5050a4899bdb4518294175477a418583c4e83..9162d1b6c0a348f9a6d028bf7c7eef9df0261240 100644 (file)
@@ -261,19 +261,8 @@ int fsl_usb2_mpc5121_init(struct platform_device *pdev)
        struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
        struct clk *clk;
        int err;
-       char clk_name[10];
-       int base, clk_num;
-
-       base = pdev->resource->start & 0xf000;
-       if (base == 0x3000)
-               clk_num = 1;
-       else if (base == 0x4000)
-               clk_num = 2;
-       else
-               return -ENODEV;
 
-       snprintf(clk_name, sizeof(clk_name), "usb%d_clk", clk_num);
-       clk = devm_clk_get(pdev->dev.parent, clk_name);
+       clk = devm_clk_get(pdev->dev.parent, "ipg");
        if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "failed to get clk\n");
                return PTR_ERR(clk);
index bdae7a04af75c48b80f16dfc7faa8ba842cc70c1..a84788ba662c98056bf047996c907ec816a10165 100644 (file)
@@ -81,7 +81,7 @@ static int tce_iommu_enable(struct tce_container *container)
         * enforcing the limit based on the max that the guest can map.
         */
        down_write(&current->mm->mmap_sem);
-       npages = (tbl->it_size << IOMMU_PAGE_SHIFT) >> PAGE_SHIFT;
+       npages = (tbl->it_size << IOMMU_PAGE_SHIFT_4K) >> PAGE_SHIFT;
        locked = current->mm->locked_vm + npages;
        lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
        if (locked > lock_limit && !capable(CAP_IPC_LOCK)) {
@@ -110,7 +110,7 @@ static void tce_iommu_disable(struct tce_container *container)
 
        down_write(&current->mm->mmap_sem);
        current->mm->locked_vm -= (container->tbl->it_size <<
-                       IOMMU_PAGE_SHIFT) >> PAGE_SHIFT;
+                       IOMMU_PAGE_SHIFT_4K) >> PAGE_SHIFT;
        up_write(&current->mm->mmap_sem);
 }
 
@@ -174,8 +174,8 @@ static long tce_iommu_ioctl(void *iommu_data,
                if (info.argsz < minsz)
                        return -EINVAL;
 
-               info.dma32_window_start = tbl->it_offset << IOMMU_PAGE_SHIFT;
-               info.dma32_window_size = tbl->it_size << IOMMU_PAGE_SHIFT;
+               info.dma32_window_start = tbl->it_offset << IOMMU_PAGE_SHIFT_4K;
+               info.dma32_window_size = tbl->it_size << IOMMU_PAGE_SHIFT_4K;
                info.flags = 0;
 
                if (copy_to_user((void __user *)arg, &info, minsz))
@@ -205,8 +205,8 @@ static long tce_iommu_ioctl(void *iommu_data,
                                VFIO_DMA_MAP_FLAG_WRITE))
                        return -EINVAL;
 
-               if ((param.size & ~IOMMU_PAGE_MASK) ||
-                               (param.vaddr & ~IOMMU_PAGE_MASK))
+               if ((param.size & ~IOMMU_PAGE_MASK_4K) ||
+                               (param.vaddr & ~IOMMU_PAGE_MASK_4K))
                        return -EINVAL;
 
                /* iova is checked by the IOMMU API */
@@ -220,17 +220,17 @@ static long tce_iommu_ioctl(void *iommu_data,
                if (ret)
                        return ret;
 
-               for (i = 0; i < (param.size >> IOMMU_PAGE_SHIFT); ++i) {
+               for (i = 0; i < (param.size >> IOMMU_PAGE_SHIFT_4K); ++i) {
                        ret = iommu_put_tce_user_mode(tbl,
-                                       (param.iova >> IOMMU_PAGE_SHIFT) + i,
+                                       (param.iova >> IOMMU_PAGE_SHIFT_4K) + i,
                                        tce);
                        if (ret)
                                break;
-                       tce += IOMMU_PAGE_SIZE;
+                       tce += IOMMU_PAGE_SIZE_4K;
                }
                if (ret)
                        iommu_clear_tces_and_put_pages(tbl,
-                                       param.iova >> IOMMU_PAGE_SHIFT, i);
+                                       param.iova >> IOMMU_PAGE_SHIFT_4K, i);
 
                iommu_flush_tce(tbl);
 
@@ -256,17 +256,17 @@ static long tce_iommu_ioctl(void *iommu_data,
                if (param.flags)
                        return -EINVAL;
 
-               if (param.size & ~IOMMU_PAGE_MASK)
+               if (param.size & ~IOMMU_PAGE_MASK_4K)
                        return -EINVAL;
 
                ret = iommu_tce_clear_param_check(tbl, param.iova, 0,
-                               param.size >> IOMMU_PAGE_SHIFT);
+                               param.size >> IOMMU_PAGE_SHIFT_4K);
                if (ret)
                        return ret;
 
                ret = iommu_clear_tces_and_put_pages(tbl,
-                               param.iova >> IOMMU_PAGE_SHIFT,
-                               param.size >> IOMMU_PAGE_SHIFT);
+                               param.iova >> IOMMU_PAGE_SHIFT_4K,
+                               param.size >> IOMMU_PAGE_SHIFT_4K);
                iommu_flush_tce(tbl);
 
                return ret;
index 1e4c75c5b36bd3c9a394c755c39a291a0d2b831d..0a025b8e2a12efd2f58434b8084a45ad2454b604 100644 (file)
@@ -728,7 +728,7 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq,
        }
        se_sess = tv_nexus->tvn_se_sess;
 
-       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, GFP_ATOMIC);
+       tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
        if (tag < 0) {
                pr_err("Unable to obtain tag for tcm_vhost_cmd\n");
                return ERR_PTR(-ENOMEM);
@@ -889,7 +889,7 @@ static void tcm_vhost_submission_work(struct work_struct *work)
                        cmd->tvc_lun, cmd->tvc_exp_data_len,
                        cmd->tvc_task_attr, cmd->tvc_data_direction,
                        TARGET_SCF_ACK_KREF, sg_ptr, cmd->tvc_sgl_count,
-                       sg_bidi_ptr, sg_no_bidi);
+                       sg_bidi_ptr, sg_no_bidi, NULL, 0);
        if (rc < 0) {
                transport_send_check_condition_and_sense(se_cmd,
                                TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
index 93cf15efc717d4ea015a05c06da529831af1192f..7de847df224fd2c24ac62b4c97d46c174f5e026f 100644 (file)
@@ -228,7 +228,7 @@ struct lcd_device *lcd_device_register(const char *name, struct device *parent,
 
        rc = device_register(&new_ld->dev);
        if (rc) {
-               kfree(new_ld);
+               put_device(&new_ld->dev);
                return ERR_PTR(rc);
        }
 
index fb80d68f4d3366e5672498da5bd05f3140e7a753..b75201ff46f6d1bc133a5cae571b90082d11347d 100644 (file)
@@ -241,7 +241,6 @@ static int pwm_backlight_probe(struct platform_device *pdev)
 
        pb = devm_kzalloc(&pdev->dev, sizeof(*pb), GFP_KERNEL);
        if (!pb) {
-               dev_err(&pdev->dev, "no memory for state\n");
                ret = -ENOMEM;
                goto err_alloc;
        }
index cde4619327606e87b1869fb10fee0ebcefe95c46..7309ac704e2641e410fe75f60278e273348573e3 100644 (file)
@@ -1577,10 +1577,10 @@ static bool fb_do_apertures_overlap(struct apertures_struct *gena,
 static int do_unregister_framebuffer(struct fb_info *fb_info);
 
 #define VGA_FB_PHYS 0xA0000
-static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
-                                    const char *name, bool primary)
+static int do_remove_conflicting_framebuffers(struct apertures_struct *a,
+                                             const char *name, bool primary)
 {
-       int i;
+       int i, ret;
 
        /* check all firmware fbs and kick off if the base addr overlaps */
        for (i = 0 ; i < FB_MAX; i++) {
@@ -1599,22 +1599,29 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
                        printk(KERN_INFO "fb: conflicting fb hw usage "
                               "%s vs %s - removing generic driver\n",
                               name, registered_fb[i]->fix.id);
-                       do_unregister_framebuffer(registered_fb[i]);
+                       ret = do_unregister_framebuffer(registered_fb[i]);
+                       if (ret)
+                               return ret;
                }
        }
+
+       return 0;
 }
 
 static int do_register_framebuffer(struct fb_info *fb_info)
 {
-       int i;
+       int i, ret;
        struct fb_event event;
        struct fb_videomode mode;
 
        if (fb_check_foreignness(fb_info))
                return -ENOSYS;
 
-       do_remove_conflicting_framebuffers(fb_info->apertures, fb_info->fix.id,
-                                        fb_is_primary_device(fb_info));
+       ret = do_remove_conflicting_framebuffers(fb_info->apertures,
+                                                fb_info->fix.id,
+                                                fb_is_primary_device(fb_info));
+       if (ret)
+               return ret;
 
        if (num_registered_fb == FB_MAX)
                return -ENXIO;
@@ -1739,12 +1746,16 @@ int unlink_framebuffer(struct fb_info *fb_info)
 }
 EXPORT_SYMBOL(unlink_framebuffer);
 
-void remove_conflicting_framebuffers(struct apertures_struct *a,
-                                    const char *name, bool primary)
+int remove_conflicting_framebuffers(struct apertures_struct *a,
+                                   const char *name, bool primary)
 {
+       int ret;
+
        mutex_lock(&registration_lock);
-       do_remove_conflicting_framebuffers(a, name, primary);
+       ret = do_remove_conflicting_framebuffers(a, name, primary);
        mutex_unlock(&registration_lock);
+
+       return ret;
 }
 EXPORT_SYMBOL(remove_conflicting_framebuffers);
 
index f51646f15cf2d4a6826c35f52d6f0f1074c6d898..bbeb8dd7f108fe9f65111337b7d1a30a039c3e2c 100644 (file)
@@ -3726,7 +3726,6 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
        }
 
        pm_runtime_enable(&pdev->dev);
-       pm_runtime_irq_safe(&pdev->dev);
 
        r = dispc_runtime_get();
        if (r)
index 5be6e919f7850d7d101542b55120163cec935162..4c4c566c52a35c73e582aa27b35fb7821ae69f8a 100644 (file)
@@ -87,6 +87,14 @@ config DA9055_WATCHDOG
          This driver can also be built as a module.  If so, the module
          will be called da9055_wdt.
 
+config GPIO_WATCHDOG
+       tristate "Watchdog device controlled through GPIO-line"
+       depends on OF_GPIO
+       select WATCHDOG_CORE
+       help
+         If you say yes here you get support for watchdog device
+         controlled through GPIO-line.
+
 config WM831X_WATCHDOG
        tristate "WM831x watchdog"
        depends on MFD_WM831X
@@ -109,7 +117,7 @@ config WM8350_WATCHDOG
 
 config ARM_SP805_WATCHDOG
        tristate "ARM SP805 Watchdog"
-       depends on ARM && ARM_AMBA
+       depends on (ARM || ARM64) && ARM_AMBA
        select WATCHDOG_CORE
        help
          ARM Primecell SP805 Watchdog timer. This will reboot your system when
@@ -188,6 +196,7 @@ config S3C2410_WATCHDOG
        tristate "S3C2410 Watchdog"
        depends on HAVE_S3C2410_WATCHDOG
        select WATCHDOG_CORE
+       select MFD_SYSCON if ARCH_EXYNOS5
        help
          Watchdog timer block in the Samsung SoCs. This will reboot
          the system when the timer expires with the watchdog enabled.
@@ -214,10 +223,9 @@ config SA1100_WATCHDOG
 
 config DW_WATCHDOG
        tristate "Synopsys DesignWare watchdog"
-       depends on ARM && HAVE_CLK
        help
          Say Y here if to include support for the Synopsys DesignWare
-         watchdog timer found in many ARM chips.
+         watchdog timer found in many chips.
          To compile this driver as a module, choose M here: the
          module will be called dw_wdt.
 
@@ -270,10 +278,11 @@ config IOP_WATCHDOG
 
 config DAVINCI_WATCHDOG
        tristate "DaVinci watchdog"
-       depends on ARCH_DAVINCI
+       depends on ARCH_DAVINCI || ARCH_KEYSTONE
+       select WATCHDOG_CORE
        help
          Say Y here if to include support for the watchdog timer
-         in the DaVinci DM644x/DM646x processors.
+         in the DaVinci DM644x/DM646x or Keystone processors.
          To compile this driver as a module, choose M here: the
          module will be called davinci_wdt.
 
@@ -883,13 +892,22 @@ config VIA_WDT
        Most people will say N.
 
 config W83627HF_WDT
-       tristate "W83627HF/W83627DHG Watchdog Timer"
+       tristate "Watchdog timer for W83627HF/W83627DHG and compatibles"
        depends on X86
        select WATCHDOG_CORE
        ---help---
-         This is the driver for the hardware watchdog on the W83627HF chipset
-         as used in Advantech PC-9578 and Tyan S2721-533 motherboards
-         (and likely others). The driver also supports the W83627DHG chip.
+         This is the driver for the hardware watchdog on the following
+         Super I/O chips.
+               W83627DHG/DHG-P/EHF/EHG/F/G/HF/S/SF/THF/UHG/UG
+               W83637HF
+               W83667HG/HG-B
+               W83687THF
+               W83697HF
+               W83697UG
+               NCT6775
+               NCT6776
+               NCT6779
+
          This watchdog simply watches your kernel to make sure it doesn't
          freeze, and if it does, it reboots your computer after a certain
          amount of time.
@@ -1139,6 +1157,28 @@ config BCM2835_WDT
          To compile this driver as a loadable module, choose M here.
          The module will be called bcm2835_wdt.
 
+config BCM_KONA_WDT
+       tristate "BCM Kona Watchdog"
+       depends on ARCH_BCM
+       select WATCHDOG_CORE
+       help
+         Support for the watchdog timer on the following Broadcom BCM281xx
+         family, which includes BCM11130, BCM11140, BCM11351, BCM28145 and
+         BCM28155 variants.
+
+         Say 'Y' or 'M' here to enable the driver. The module will be called
+         bcm_kona_wdt.
+
+config BCM_KONA_WDT_DEBUG
+       bool "DEBUGFS support for BCM Kona Watchdog"
+       depends on BCM_KONA_WDT
+       help
+         If enabled, adds /sys/kernel/debug/bcm_kona_wdt/info which provides
+         access to the driver's internal data structures as well as watchdog
+         timer hardware registres.
+
+         If in doubt, say 'N'.
+
 config LANTIQ_WDT
        tristate "Lantiq SoC watchdog"
        depends on LANTIQ
@@ -1171,6 +1211,7 @@ config MPC5200_WDT
 config 8xxx_WDT
        tristate "MPC8xxx Platform Watchdog Timer"
        depends on PPC_8xx || PPC_83xx || PPC_86xx
+       select WATCHDOG_CORE
        help
          This driver is for a SoC level watchdog that exists on some
          Freescale PowerPC processors. So far this driver supports:
index 91bd95a64baf7bfe083e6f67ff803f2edc0ce2f9..985a66cda76f23ac89932672f1f813c9cab2dade 100644 (file)
@@ -57,6 +57,7 @@ obj-$(CONFIG_RETU_WATCHDOG) += retu_wdt.o
 obj-$(CONFIG_BCM2835_WDT) += bcm2835_wdt.o
 obj-$(CONFIG_MOXART_WDT) += moxart_wdt.o
 obj-$(CONFIG_SIRFSOC_WATCHDOG) += sirfsoc_wdt.o
+obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
 
 # AVR32 Architecture
 obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -171,6 +172,7 @@ obj-$(CONFIG_XEN_WDT) += xen_wdt.o
 # Architecture Independent
 obj-$(CONFIG_DA9052_WATCHDOG) += da9052_wdt.o
 obj-$(CONFIG_DA9055_WATCHDOG) += da9055_wdt.o
+obj-$(CONFIG_GPIO_WATCHDOG)    += gpio_wdt.o
 obj-$(CONFIG_WM831X_WATCHDOG) += wm831x_wdt.o
 obj-$(CONFIG_WM8350_WATCHDOG) += wm8350_wdt.o
 obj-$(CONFIG_MAX63XX_WATCHDOG) += max63xx_wdt.o
index fbb7b94cabfd5816e7532fe0093b579b831b63a8..3a17fbd39f8aed015f00ecafdbb5839a2e8296f4 100644 (file)
@@ -301,7 +301,7 @@ static int ali_notify_sys(struct notifier_block *this,
  *     want to register another driver on the same PCI id.
  */
 
-static DEFINE_PCI_DEVICE_TABLE(ali_pci_tbl) __used = {
+static const struct pci_device_id ali_pci_tbl[] __used = {
        { PCI_VENDOR_ID_AL, 0x1533, PCI_ANY_ID, PCI_ANY_ID,},
        { PCI_VENDOR_ID_AL, 0x1535, PCI_ANY_ID, PCI_ANY_ID,},
        { 0, },
index 12f0b762b528948b15e30fab605860a34c01ba57..996b2f7d330e94ec3143e6bebe0c86f74e162943 100644 (file)
@@ -414,7 +414,7 @@ err_out:
 module_init(alim7101_wdt_init);
 module_exit(alim7101_wdt_unload);
 
-static DEFINE_PCI_DEVICE_TABLE(alim7101_pci_tbl) __used = {
+static const struct pci_device_id alim7101_pci_tbl[] __used = {
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533) },
        { PCI_DEVICE(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M7101) },
        { }
index be37dde4f864448c13643ee4535e5b6a830be34c..489729b262987965dd760fd50c60053c2caec57c 100644 (file)
 
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
+#include <linux/reboot.h>
 #include <linux/types.h>
 #include <linux/watchdog.h>
 #include <linux/jiffies.h>
 #include <linux/bitops.h>
 #include <linux/uaccess.h>
 #include <linux/of.h>
+#include <linux/of_irq.h>
 
 #include "at91sam9_wdt.h"
 
 #define DRV_NAME "AT91SAM9 Watchdog"
 
-#define wdt_read(field) \
-       __raw_readl(at91wdt_private.base + field)
-#define wdt_write(field, val) \
-       __raw_writel((val), at91wdt_private.base + field)
+#define wdt_read(wdt, field) \
+       __raw_readl((wdt)->base + (field))
+#define wdt_write(wtd, field, val) \
+       __raw_writel((val), (wdt)->base + (field))
 
 /* AT91SAM9 watchdog runs a 12bit counter @ 256Hz,
  * use this to convert a watchdog
  * value from/to milliseconds.
  */
-#define ms_to_ticks(t) (((t << 8) / 1000) - 1)
-#define ticks_to_ms(t) (((t + 1) * 1000) >> 8)
+#define ticks_to_hz_rounddown(t)       ((((t) + 1) * HZ) >> 8)
+#define ticks_to_hz_roundup(t)         (((((t) + 1) * HZ) + 255) >> 8)
+#define ticks_to_secs(t)               (((t) + 1) >> 8)
+#define secs_to_ticks(s)               ((s) ? (((s) << 8) - 1) : 0)
+
+#define WDT_MR_RESET   0x3FFF2FFF
+
+/* Watchdog max counter value in ticks */
+#define WDT_COUNTER_MAX_TICKS  0xFFF
+
+/* Watchdog max delta/value in secs */
+#define WDT_COUNTER_MAX_SECS   ticks_to_secs(WDT_COUNTER_MAX_TICKS)
 
 /* Hardware timeout in seconds */
 #define WDT_HW_TIMEOUT 2
@@ -66,23 +79,40 @@ module_param(nowayout, bool, 0);
 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
        "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
 
-static struct watchdog_device at91_wdt_dev;
-static void at91_ping(unsigned long data);
-
-static struct {
+#define to_wdt(wdd) container_of(wdd, struct at91wdt, wdd)
+struct at91wdt {
+       struct watchdog_device wdd;
        void __iomem *base;
        unsigned long next_heartbeat;   /* the next_heartbeat for the timer */
        struct timer_list timer;        /* The timer that pings the watchdog */
-} at91wdt_private;
+       u32 mr;
+       u32 mr_mask;
+       unsigned long heartbeat;        /* WDT heartbeat in jiffies */
+       bool nowayout;
+       unsigned int irq;
+};
 
 /* ......................................................................... */
 
+static irqreturn_t wdt_interrupt(int irq, void *dev_id)
+{
+       struct at91wdt *wdt = (struct at91wdt *)dev_id;
+
+       if (wdt_read(wdt, AT91_WDT_SR)) {
+               pr_crit("at91sam9 WDT software reset\n");
+               emergency_restart();
+               pr_crit("Reboot didn't ?????\n");
+       }
+
+       return IRQ_HANDLED;
+}
+
 /*
  * Reload the watchdog timer.  (ie, pat the watchdog)
  */
-static inline void at91_wdt_reset(void)
+static inline void at91_wdt_reset(struct at91wdt *wdt)
 {
-       wdt_write(AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
+       wdt_write(wdt, AT91_WDT_CR, AT91_WDT_KEY | AT91_WDT_WDRSTT);
 }
 
 /*
@@ -90,26 +120,21 @@ static inline void at91_wdt_reset(void)
  */
 static void at91_ping(unsigned long data)
 {
-       if (time_before(jiffies, at91wdt_private.next_heartbeat) ||
-           (!watchdog_active(&at91_wdt_dev))) {
-               at91_wdt_reset();
-               mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
-       } else
+       struct at91wdt *wdt = (struct at91wdt *)data;
+       if (time_before(jiffies, wdt->next_heartbeat) ||
+           !watchdog_active(&wdt->wdd)) {
+               at91_wdt_reset(wdt);
+               mod_timer(&wdt->timer, jiffies + wdt->heartbeat);
+       } else {
                pr_crit("I will reset your machine !\n");
-}
-
-static int at91_wdt_ping(struct watchdog_device *wdd)
-{
-       /* calculate when the next userspace timeout will be */
-       at91wdt_private.next_heartbeat = jiffies + wdd->timeout * HZ;
-       return 0;
+       }
 }
 
 static int at91_wdt_start(struct watchdog_device *wdd)
 {
-       /* calculate the next userspace timeout and modify the timer */
-       at91_wdt_ping(wdd);
-       mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+       struct at91wdt *wdt = to_wdt(wdd);
+       /* calculate when the next userspace timeout will be */
+       wdt->next_heartbeat = jiffies + wdd->timeout * HZ;
        return 0;
 }
 
@@ -122,39 +147,104 @@ static int at91_wdt_stop(struct watchdog_device *wdd)
 static int at91_wdt_set_timeout(struct watchdog_device *wdd, unsigned int new_timeout)
 {
        wdd->timeout = new_timeout;
-       return 0;
+       return at91_wdt_start(wdd);
 }
 
-/*
- * Set the watchdog time interval in 1/256Hz (write-once)
- * Counter is 12 bit.
- */
-static int at91_wdt_settimeout(unsigned int timeout)
+static int at91_wdt_init(struct platform_device *pdev, struct at91wdt *wdt)
 {
-       unsigned int reg;
-       unsigned int mr;
-
-       /* Check if disabled */
-       mr = wdt_read(AT91_WDT_MR);
-       if (mr & AT91_WDT_WDDIS) {
-               pr_err("sorry, watchdog is disabled\n");
-               return -EIO;
+       u32 tmp;
+       u32 delta;
+       u32 value;
+       int err;
+       u32 mask = wdt->mr_mask;
+       unsigned long min_heartbeat = 1;
+       unsigned long max_heartbeat;
+       struct device *dev = &pdev->dev;
+
+       tmp = wdt_read(wdt, AT91_WDT_MR);
+       if ((tmp & mask) != (wdt->mr & mask)) {
+               if (tmp == WDT_MR_RESET) {
+                       wdt_write(wdt, AT91_WDT_MR, wdt->mr);
+                       tmp = wdt_read(wdt, AT91_WDT_MR);
+               }
+       }
+
+       if (tmp & AT91_WDT_WDDIS) {
+               if (wdt->mr & AT91_WDT_WDDIS)
+                       return 0;
+               dev_err(dev, "watchdog is disabled\n");
+               return -EINVAL;
+       }
+
+       value = tmp & AT91_WDT_WDV;
+       delta = (tmp & AT91_WDT_WDD) >> 16;
+
+       if (delta < value)
+               min_heartbeat = ticks_to_hz_roundup(value - delta);
+
+       max_heartbeat = ticks_to_hz_rounddown(value);
+       if (!max_heartbeat) {
+               dev_err(dev,
+                       "heartbeat is too small for the system to handle it correctly\n");
+               return -EINVAL;
        }
 
        /*
-        * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
-        *
-        * Since WDV is a 12-bit counter, the maximum period is
-        * 4096 / 256 = 16 seconds.
+        * Try to reset the watchdog counter 4 or 2 times more often than
+        * actually requested, to avoid spurious watchdog reset.
+        * If this is not possible because of the min_heartbeat value, reset
+        * it at the min_heartbeat period.
         */
-       reg = AT91_WDT_WDRSTEN  /* causes watchdog reset */
-               /* | AT91_WDT_WDRPROC   causes processor reset only */
-               | AT91_WDT_WDDBGHLT     /* disabled in debug mode */
-               | AT91_WDT_WDD          /* restart at any time */
-               | (timeout & AT91_WDT_WDV);  /* timer value */
-       wdt_write(AT91_WDT_MR, reg);
+       if ((max_heartbeat / 4) >= min_heartbeat)
+               wdt->heartbeat = max_heartbeat / 4;
+       else if ((max_heartbeat / 2) >= min_heartbeat)
+               wdt->heartbeat = max_heartbeat / 2;
+       else
+               wdt->heartbeat = min_heartbeat;
+
+       if (max_heartbeat < min_heartbeat + 4)
+               dev_warn(dev,
+                        "min heartbeat and max heartbeat might be too close for the system to handle it correctly\n");
+
+       if ((tmp & AT91_WDT_WDFIEN) && wdt->irq) {
+               err = request_irq(wdt->irq, wdt_interrupt,
+                                 IRQF_SHARED | IRQF_IRQPOLL,
+                                 pdev->name, wdt);
+               if (err)
+                       return err;
+       }
+
+       if ((tmp & wdt->mr_mask) != (wdt->mr & wdt->mr_mask))
+               dev_warn(dev,
+                        "watchdog already configured differently (mr = %x expecting %x)\n",
+                        tmp & wdt->mr_mask, wdt->mr & wdt->mr_mask);
+
+       setup_timer(&wdt->timer, at91_ping, (unsigned long)wdt);
+
+       /*
+        * Use min_heartbeat the first time to avoid spurious watchdog reset:
+        * we don't know for how long the watchdog counter is running, and
+        *  - resetting it right now might trigger a watchdog fault reset
+        *  - waiting for heartbeat time might lead to a watchdog timeout
+        *    reset
+        */
+       mod_timer(&wdt->timer, jiffies + min_heartbeat);
+
+       /* Try to set timeout from device tree first */
+       if (watchdog_init_timeout(&wdt->wdd, 0, dev))
+               watchdog_init_timeout(&wdt->wdd, heartbeat, dev);
+       watchdog_set_nowayout(&wdt->wdd, wdt->nowayout);
+       err = watchdog_register_device(&wdt->wdd);
+       if (err)
+               goto out_stop_timer;
+
+       wdt->next_heartbeat = jiffies + wdt->wdd.timeout * HZ;
 
        return 0;
+
+out_stop_timer:
+       del_timer(&wdt->timer);
+       return err;
 }
 
 /* ......................................................................... */
@@ -169,61 +259,123 @@ static const struct watchdog_ops at91_wdt_ops = {
        .owner =        THIS_MODULE,
        .start =        at91_wdt_start,
        .stop =         at91_wdt_stop,
-       .ping =         at91_wdt_ping,
        .set_timeout =  at91_wdt_set_timeout,
 };
 
-static struct watchdog_device at91_wdt_dev = {
-       .info =         &at91_wdt_info,
-       .ops =          &at91_wdt_ops,
-       .timeout =      WDT_HEARTBEAT,
-       .min_timeout =  1,
-       .max_timeout =  0xFFFF,
-};
+#if defined(CONFIG_OF)
+static int of_at91wdt_init(struct device_node *np, struct at91wdt *wdt)
+{
+       u32 min = 0;
+       u32 max = WDT_COUNTER_MAX_SECS;
+       const char *tmp;
+
+       /* Get the interrupts property */
+       wdt->irq = irq_of_parse_and_map(np, 0);
+       if (!wdt->irq)
+               dev_warn(wdt->wdd.parent, "failed to get IRQ from DT\n");
+
+       if (!of_property_read_u32_index(np, "atmel,max-heartbeat-sec", 0,
+                                       &max)) {
+               if (!max || max > WDT_COUNTER_MAX_SECS)
+                       max = WDT_COUNTER_MAX_SECS;
+
+               if (!of_property_read_u32_index(np, "atmel,min-heartbeat-sec",
+                                               0, &min)) {
+                       if (min >= max)
+                               min = max - 1;
+               }
+       }
+
+       min = secs_to_ticks(min);
+       max = secs_to_ticks(max);
+
+       wdt->mr_mask = 0x3FFFFFFF;
+       wdt->mr = 0;
+       if (!of_property_read_string(np, "atmel,watchdog-type", &tmp) &&
+           !strcmp(tmp, "software")) {
+               wdt->mr |= AT91_WDT_WDFIEN;
+               wdt->mr_mask &= ~AT91_WDT_WDRPROC;
+       } else {
+               wdt->mr |= AT91_WDT_WDRSTEN;
+       }
+
+       if (!of_property_read_string(np, "atmel,reset-type", &tmp) &&
+           !strcmp(tmp, "proc"))
+               wdt->mr |= AT91_WDT_WDRPROC;
+
+       if (of_property_read_bool(np, "atmel,disable")) {
+               wdt->mr |= AT91_WDT_WDDIS;
+               wdt->mr_mask &= AT91_WDT_WDDIS;
+       }
+
+       if (of_property_read_bool(np, "atmel,idle-halt"))
+               wdt->mr |= AT91_WDT_WDIDLEHLT;
+
+       if (of_property_read_bool(np, "atmel,dbg-halt"))
+               wdt->mr |= AT91_WDT_WDDBGHLT;
+
+       wdt->mr |= max | ((max - min) << 16);
+
+       return 0;
+}
+#else
+static inline int of_at91wdt_init(struct device_node *np, struct at91wdt *wdt)
+{
+       return 0;
+}
+#endif
 
 static int __init at91wdt_probe(struct platform_device *pdev)
 {
        struct resource *r;
-       int res;
+       int err;
+       struct at91wdt *wdt;
 
-       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       if (!r)
-               return -ENODEV;
-       at91wdt_private.base = ioremap(r->start, resource_size(r));
-       if (!at91wdt_private.base) {
-               dev_err(&pdev->dev, "failed to map registers, aborting.\n");
+       wdt = devm_kzalloc(&pdev->dev, sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
                return -ENOMEM;
-       }
 
-       at91_wdt_dev.parent = &pdev->dev;
-       watchdog_init_timeout(&at91_wdt_dev, heartbeat, &pdev->dev);
-       watchdog_set_nowayout(&at91_wdt_dev, nowayout);
+       wdt->mr = (WDT_HW_TIMEOUT * 256) | AT91_WDT_WDRSTEN | AT91_WDT_WDD |
+                 AT91_WDT_WDDBGHLT | AT91_WDT_WDIDLEHLT;
+       wdt->mr_mask = 0x3FFFFFFF;
+       wdt->nowayout = nowayout;
+       wdt->wdd.parent = &pdev->dev;
+       wdt->wdd.info = &at91_wdt_info;
+       wdt->wdd.ops = &at91_wdt_ops;
+       wdt->wdd.timeout = WDT_HEARTBEAT;
+       wdt->wdd.min_timeout = 1;
+       wdt->wdd.max_timeout = 0xFFFF;
 
-       /* Set watchdog */
-       res = at91_wdt_settimeout(ms_to_ticks(WDT_HW_TIMEOUT * 1000));
-       if (res)
-               return res;
+       r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdt->base = devm_ioremap_resource(&pdev->dev, r);
+       if (IS_ERR(wdt->base))
+               return PTR_ERR(wdt->base);
+
+       if (pdev->dev.of_node) {
+               err = of_at91wdt_init(pdev->dev.of_node, wdt);
+               if (err)
+                       return err;
+       }
 
-       res = watchdog_register_device(&at91_wdt_dev);
-       if (res)
-               return res;
+       err = at91_wdt_init(pdev, wdt);
+       if (err)
+               return err;
 
-       at91wdt_private.next_heartbeat = jiffies + at91_wdt_dev.timeout * HZ;
-       setup_timer(&at91wdt_private.timer, at91_ping, 0);
-       mod_timer(&at91wdt_private.timer, jiffies + WDT_TIMEOUT);
+       platform_set_drvdata(pdev, wdt);
 
        pr_info("enabled (heartbeat=%d sec, nowayout=%d)\n",
-               at91_wdt_dev.timeout, nowayout);
+               wdt->wdd.timeout, wdt->nowayout);
 
        return 0;
 }
 
 static int __exit at91wdt_remove(struct platform_device *pdev)
 {
-       watchdog_unregister_device(&at91_wdt_dev);
+       struct at91wdt *wdt = platform_get_drvdata(pdev);
+       watchdog_unregister_device(&wdt->wdd);
 
        pr_warn("I quit now, hardware will probably reboot!\n");
-       del_timer(&at91wdt_private.timer);
+       del_timer(&wdt->timer);
 
        return 0;
 }
diff --git a/drivers/watchdog/bcm_kona_wdt.c b/drivers/watchdog/bcm_kona_wdt.c
new file mode 100644 (file)
index 0000000..9c24809
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2013 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/watchdog.h>
+
+#define SECWDOG_CTRL_REG               0x00000000
+#define SECWDOG_COUNT_REG              0x00000004
+
+#define SECWDOG_RESERVED_MASK          0x1dffffff
+#define SECWDOG_WD_LOAD_FLAG           0x10000000
+#define SECWDOG_EN_MASK                        0x08000000
+#define SECWDOG_SRSTEN_MASK            0x04000000
+#define SECWDOG_RES_MASK               0x00f00000
+#define SECWDOG_COUNT_MASK             0x000fffff
+
+#define SECWDOG_MAX_COUNT              SECWDOG_COUNT_MASK
+#define SECWDOG_CLKS_SHIFT             20
+#define SECWDOG_MAX_RES                        15
+#define SECWDOG_DEFAULT_RESOLUTION     4
+#define SECWDOG_MAX_TRY                        1000
+
+#define SECS_TO_TICKS(x, w)            ((x) << (w)->resolution)
+#define TICKS_TO_SECS(x, w)            ((x) >> (w)->resolution)
+
+#define BCM_KONA_WDT_NAME              "bcm_kona_wdt"
+
+struct bcm_kona_wdt {
+       void __iomem *base;
+       /*
+        * One watchdog tick is 1/(2^resolution) seconds. Resolution can take
+        * the values 0-15, meaning one tick can be 1s to 30.52us. Our default
+        * resolution of 4 means one tick is 62.5ms.
+        *
+        * The watchdog counter is 20 bits. Depending on resolution, the maximum
+        * counter value of 0xfffff expires after about 12 days (resolution 0)
+        * down to only 32s (resolution 15). The default resolution of 4 gives
+        * us a maximum of about 18 hours and 12 minutes before the watchdog
+        * times out.
+        */
+       int resolution;
+       spinlock_t lock;
+#ifdef CONFIG_BCM_KONA_WDT_DEBUG
+       unsigned long busy_count;
+       struct dentry *debugfs;
+#endif
+};
+
+static int secure_register_read(struct bcm_kona_wdt *wdt, uint32_t offset)
+{
+       uint32_t val;
+       unsigned count = 0;
+
+       /*
+        * If the WD_LOAD_FLAG is set, the watchdog counter field is being
+        * updated in hardware. Once the WD timer is updated in hardware, it
+        * gets cleared.
+        */
+       do {
+               if (unlikely(count > 1))
+                       udelay(5);
+               val = readl_relaxed(wdt->base + offset);
+               count++;
+       } while ((val & SECWDOG_WD_LOAD_FLAG) && count < SECWDOG_MAX_TRY);
+
+#ifdef CONFIG_BCM_KONA_WDT_DEBUG
+       /* Remember the maximum number iterations due to WD_LOAD_FLAG */
+       if (count > wdt->busy_count)
+               wdt->busy_count = count;
+#endif
+
+       /* This is the only place we return a negative value. */
+       if (val & SECWDOG_WD_LOAD_FLAG)
+               return -ETIMEDOUT;
+
+       /* We always mask out reserved bits. */
+       val &= SECWDOG_RESERVED_MASK;
+
+       return val;
+}
+
+#ifdef CONFIG_BCM_KONA_WDT_DEBUG
+
+static int bcm_kona_wdt_dbg_show(struct seq_file *s, void *data)
+{
+       int ctl_val, cur_val, ret;
+       unsigned long flags;
+       struct bcm_kona_wdt *wdt = s->private;
+
+       if (!wdt)
+               return seq_puts(s, "No device pointer\n");
+
+       spin_lock_irqsave(&wdt->lock, flags);
+       ctl_val = secure_register_read(wdt, SECWDOG_CTRL_REG);
+       cur_val = secure_register_read(wdt, SECWDOG_COUNT_REG);
+       spin_unlock_irqrestore(&wdt->lock, flags);
+
+       if (ctl_val < 0 || cur_val < 0) {
+               ret = seq_puts(s, "Error accessing hardware\n");
+       } else {
+               int ctl, cur, ctl_sec, cur_sec, res;
+
+               ctl = ctl_val & SECWDOG_COUNT_MASK;
+               res = (ctl_val & SECWDOG_RES_MASK) >> SECWDOG_CLKS_SHIFT;
+               cur = cur_val & SECWDOG_COUNT_MASK;
+               ctl_sec = TICKS_TO_SECS(ctl, wdt);
+               cur_sec = TICKS_TO_SECS(cur, wdt);
+               ret = seq_printf(s, "Resolution: %d / %d\n"
+                               "Control: %d s / %d (%#x) ticks\n"
+                               "Current: %d s / %d (%#x) ticks\n"
+                               "Busy count: %lu\n", res,
+                               wdt->resolution, ctl_sec, ctl, ctl, cur_sec,
+                               cur, cur, wdt->busy_count);
+       }
+
+       return ret;
+}
+
+static int bcm_kona_dbg_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, bcm_kona_wdt_dbg_show, inode->i_private);
+}
+
+static const struct file_operations bcm_kona_dbg_operations = {
+       .open           = bcm_kona_dbg_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static void bcm_kona_wdt_debug_init(struct platform_device *pdev)
+{
+       struct dentry *dir;
+       struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev);
+
+       if (!wdt)
+               return;
+
+       wdt->debugfs = NULL;
+
+       dir = debugfs_create_dir(BCM_KONA_WDT_NAME, NULL);
+       if (IS_ERR_OR_NULL(dir))
+               return;
+
+       if (debugfs_create_file("info", S_IFREG | S_IRUGO, dir, wdt,
+                               &bcm_kona_dbg_operations))
+               wdt->debugfs = dir;
+       else
+               debugfs_remove_recursive(dir);
+}
+
+static void bcm_kona_wdt_debug_exit(struct platform_device *pdev)
+{
+       struct bcm_kona_wdt *wdt = platform_get_drvdata(pdev);
+
+       if (wdt && wdt->debugfs) {
+               debugfs_remove_recursive(wdt->debugfs);
+               wdt->debugfs = NULL;
+       }
+}
+
+#else
+
+static void bcm_kona_wdt_debug_init(struct platform_device *pdev) {}
+static void bcm_kona_wdt_debug_exit(struct platform_device *pdev) {}
+
+#endif /* CONFIG_BCM_KONA_WDT_DEBUG */
+
+static int bcm_kona_wdt_ctrl_reg_modify(struct bcm_kona_wdt *wdt,
+                                       unsigned mask, unsigned newval)
+{
+       int val;
+       unsigned long flags;
+       int ret = 0;
+
+       spin_lock_irqsave(&wdt->lock, flags);
+
+       val = secure_register_read(wdt, SECWDOG_CTRL_REG);
+       if (val < 0) {
+               ret = val;
+       } else {
+               val &= ~mask;
+               val |= newval;
+               writel_relaxed(val, wdt->base + SECWDOG_CTRL_REG);
+       }
+
+       spin_unlock_irqrestore(&wdt->lock, flags);
+
+       return ret;
+}
+
+static int bcm_kona_wdt_set_resolution_reg(struct bcm_kona_wdt *wdt)
+{
+       if (wdt->resolution > SECWDOG_MAX_RES)
+               return -EINVAL;
+
+       return bcm_kona_wdt_ctrl_reg_modify(wdt, SECWDOG_RES_MASK,
+                                       wdt->resolution << SECWDOG_CLKS_SHIFT);
+}
+
+static int bcm_kona_wdt_set_timeout_reg(struct watchdog_device *wdog,
+                                       unsigned watchdog_flags)
+{
+       struct bcm_kona_wdt *wdt = watchdog_get_drvdata(wdog);
+
+       return bcm_kona_wdt_ctrl_reg_modify(wdt, SECWDOG_COUNT_MASK,
+                                       SECS_TO_TICKS(wdog->timeout, wdt) |
+                                       watchdog_flags);
+}
+
+static int bcm_kona_wdt_set_timeout(struct watchdog_device *wdog,
+       unsigned int t)
+{
+       wdog->timeout = t;
+       return 0;
+}
+
+static unsigned int bcm_kona_wdt_get_timeleft(struct watchdog_device *wdog)
+{
+       struct bcm_kona_wdt *wdt = watchdog_get_drvdata(wdog);
+       int val;
+       unsigned long flags;
+
+       spin_lock_irqsave(&wdt->lock, flags);
+       val = secure_register_read(wdt, SECWDOG_COUNT_REG);
+       spin_unlock_irqrestore(&wdt->lock, flags);
+
+       if (val < 0)
+               return val;
+
+       return TICKS_TO_SECS(val & SECWDOG_COUNT_MASK, wdt);
+}
+
+static int bcm_kona_wdt_start(struct watchdog_device *wdog)
+{
+       return bcm_kona_wdt_set_timeout_reg(wdog,
+                                       SECWDOG_EN_MASK | SECWDOG_SRSTEN_MASK);
+}
+
+static int bcm_kona_wdt_stop(struct watchdog_device *wdog)
+{
+       struct bcm_kona_wdt *wdt = watchdog_get_drvdata(wdog);
+
+       return bcm_kona_wdt_ctrl_reg_modify(wdt, SECWDOG_EN_MASK |
+                                           SECWDOG_SRSTEN_MASK, 0);
+}
+
+static struct watchdog_ops bcm_kona_wdt_ops = {
+       .owner =        THIS_MODULE,
+       .start =        bcm_kona_wdt_start,
+       .stop =         bcm_kona_wdt_stop,
+       .set_timeout =  bcm_kona_wdt_set_timeout,
+       .get_timeleft = bcm_kona_wdt_get_timeleft,
+};
+
+static struct watchdog_info bcm_kona_wdt_info = {
+       .options =      WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE |
+                       WDIOF_KEEPALIVEPING,
+       .identity =     "Broadcom Kona Watchdog Timer",
+};
+
+static struct watchdog_device bcm_kona_wdt_wdd = {
+       .info =         &bcm_kona_wdt_info,
+       .ops =          &bcm_kona_wdt_ops,
+       .min_timeout =  1,
+       .max_timeout =  SECWDOG_MAX_COUNT >> SECWDOG_DEFAULT_RESOLUTION,
+       .timeout =      SECWDOG_MAX_COUNT >> SECWDOG_DEFAULT_RESOLUTION,
+};
+
+static void bcm_kona_wdt_shutdown(struct platform_device *pdev)
+{
+       bcm_kona_wdt_stop(&bcm_kona_wdt_wdd);
+}
+
+static int bcm_kona_wdt_probe(struct platform_device *pdev)
+{
+       struct device *dev = &pdev->dev;
+       struct bcm_kona_wdt *wdt;
+       struct resource *res;
+       int ret;
+
+       wdt = devm_kzalloc(dev, sizeof(*wdt), GFP_KERNEL);
+       if (!wdt)
+               return -ENOMEM;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       wdt->base = devm_ioremap_resource(dev, res);
+       if (IS_ERR(wdt->base))
+               return -ENODEV;
+
+       wdt->resolution = SECWDOG_DEFAULT_RESOLUTION;
+       ret = bcm_kona_wdt_set_resolution_reg(wdt);
+       if (ret) {
+               dev_err(dev, "Failed to set resolution (error: %d)", ret);
+               return ret;
+       }
+
+       spin_lock_init(&wdt->lock);
+       platform_set_drvdata(pdev, wdt);
+       watchdog_set_drvdata(&bcm_kona_wdt_wdd, wdt);
+
+       ret = bcm_kona_wdt_set_timeout_reg(&bcm_kona_wdt_wdd, 0);
+       if (ret) {
+               dev_err(dev, "Failed set watchdog timeout");
+               return ret;
+       }
+
+       ret = watchdog_register_device(&bcm_kona_wdt_wdd);
+       if (ret) {
+               dev_err(dev, "Failed to register watchdog device");
+               return ret;
+       }
+
+       bcm_kona_wdt_debug_init(pdev);
+       dev_dbg(dev, "Broadcom Kona Watchdog Timer");
+
+       return 0;
+}
+
+static int bcm_kona_wdt_remove(struct platform_device *pdev)
+{
+       bcm_kona_wdt_debug_exit(pdev);
+       bcm_kona_wdt_shutdown(pdev);
+       watchdog_unregister_device(&bcm_kona_wdt_wdd);
+       dev_dbg(&pdev->dev, "Watchdog driver disabled");
+
+       return 0;
+}
+
+static const struct of_device_id bcm_kona_wdt_of_match[] = {
+       { .compatible = "brcm,kona-wdt", },
+       {},
+};
+MODULE_DEVICE_TABLE(of, bcm_kona_wdt_of_match);
+
+static struct platform_driver bcm_kona_wdt_driver = {
+       .driver = {
+                       .name = BCM_KONA_WDT_NAME,
+                       .owner = THIS_MODULE,
+                       .of_match_table = bcm_kona_wdt_of_match,
+                 },
+       .probe = bcm_kona_wdt_probe,
+       .remove = bcm_kona_wdt_remove,
+       .shutdown = bcm_kona_wdt_shutdown,
+};
+
+module_platform_driver(bcm_kona_wdt_driver);
+
+MODULE_ALIAS("platform:" BCM_KONA_WDT_NAME);
+MODULE_AUTHOR("Markus Mayer <mmayer@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom Kona Watchdog Driver");
+MODULE_LICENSE("GPL v2");
index 12591f6596efe54a2d9f58b3cf26547867440685..b1bae03742a9a6cf5a2c32e5746ecc520c45add9 100644 (file)
@@ -3,7 +3,7 @@
  *
  * Watchdog driver for DaVinci DM644x/DM646x processors
  *
- * Copyright (C) 2006 Texas Instruments.
+ * Copyright (C) 2006-2013 Texas Instruments.
  *
  * 2007 (c) MontaVista Software, Inc. This file is licensed under
  * the terms of the GNU General Public License version 2. This program
 #include <linux/moduleparam.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
 #include <linux/watchdog.h>
 #include <linux/init.h>
-#include <linux/bitops.h>
 #include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/device.h>
 #include <linux/clk.h>
-#include <linux/slab.h>
 #include <linux/err.h>
 
 #define MODULE_NAME "DAVINCI-WDT: "
 #define WDKEY_SEQ0             (0xa5c6 << 16)
 #define WDKEY_SEQ1             (0xda7e << 16)
 
-static int heartbeat = DEFAULT_HEARTBEAT;
+static int heartbeat;
 
-static DEFINE_SPINLOCK(io_lock);
-static unsigned long wdt_status;
-#define WDT_IN_USE        0
-#define WDT_OK_TO_CLOSE   1
-#define WDT_REGION_INITED 2
-#define WDT_DEVICE_INITED 3
-
-static void __iomem    *wdt_base;
-struct clk             *wdt_clk;
-
-static void wdt_service(void)
-{
-       spin_lock(&io_lock);
-
-       /* put watchdog in service state */
-       iowrite32(WDKEY_SEQ0, wdt_base + WDTCR);
-       /* put watchdog in active state */
-       iowrite32(WDKEY_SEQ1, wdt_base + WDTCR);
-
-       spin_unlock(&io_lock);
-}
+/*
+ * struct to hold data for each WDT device
+ * @base - base io address of WD device
+ * @clk - source clock of WDT
+ * @wdd - hold watchdog device as is in WDT core
+ */
+struct davinci_wdt_device {
+       void __iomem            *base;
+       struct clk              *clk;
+       struct watchdog_device  wdd;
+};
 
-static void wdt_enable(void)
+static int davinci_wdt_start(struct watchdog_device *wdd)
 {
        u32 tgcr;
        u32 timer_margin;
        unsigned long wdt_freq;
+       struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
 
-       wdt_freq = clk_get_rate(wdt_clk);
-
-       spin_lock(&io_lock);
+       wdt_freq = clk_get_rate(davinci_wdt->clk);
 
        /* disable, internal clock source */
-       iowrite32(0, wdt_base + TCR);
+       iowrite32(0, davinci_wdt->base + TCR);
        /* reset timer, set mode to 64-bit watchdog, and unreset */
-       iowrite32(0, wdt_base + TGCR);
+       iowrite32(0, davinci_wdt->base + TGCR);
        tgcr = TIMMODE_64BIT_WDOG | TIM12RS_UNRESET | TIM34RS_UNRESET;
-       iowrite32(tgcr, wdt_base + TGCR);
+       iowrite32(tgcr, davinci_wdt->base + TGCR);
        /* clear counter regs */
-       iowrite32(0, wdt_base + TIM12);
-       iowrite32(0, wdt_base + TIM34);
+       iowrite32(0, davinci_wdt->base + TIM12);
+       iowrite32(0, davinci_wdt->base + TIM34);
        /* set timeout period */
-       timer_margin = (((u64)heartbeat * wdt_freq) & 0xffffffff);
-       iowrite32(timer_margin, wdt_base + PRD12);
-       timer_margin = (((u64)heartbeat * wdt_freq) >> 32);
-       iowrite32(timer_margin, wdt_base + PRD34);
+       timer_margin = (((u64)wdd->timeout * wdt_freq) & 0xffffffff);
+       iowrite32(timer_margin, davinci_wdt->base + PRD12);
+       timer_margin = (((u64)wdd->timeout * wdt_freq) >> 32);
+       iowrite32(timer_margin, davinci_wdt->base + PRD34);
        /* enable run continuously */
-       iowrite32(ENAMODE12_PERIODIC, wdt_base + TCR);
+       iowrite32(ENAMODE12_PERIODIC, davinci_wdt->base + TCR);
        /* Once the WDT is in pre-active state write to
         * TIM12, TIM34, PRD12, PRD34, TCR, TGCR, WDTCR are
         * write protected (except for the WDKEY field)
         */
        /* put watchdog in pre-active state */
-       iowrite32(WDKEY_SEQ0 | WDEN, wdt_base + WDTCR);
+       iowrite32(WDKEY_SEQ0 | WDEN, davinci_wdt->base + WDTCR);
        /* put watchdog in active state */
-       iowrite32(WDKEY_SEQ1 | WDEN, wdt_base + WDTCR);
-
-       spin_unlock(&io_lock);
+       iowrite32(WDKEY_SEQ1 | WDEN, davinci_wdt->base + WDTCR);
+       return 0;
 }
 
-static int davinci_wdt_open(struct inode *inode, struct file *file)
+static int davinci_wdt_ping(struct watchdog_device *wdd)
 {
-       if (test_and_set_bit(WDT_IN_USE, &wdt_status))
-               return -EBUSY;
-
-       wdt_enable();
+       struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
 
-       return nonseekable_open(inode, file);
+       /* put watchdog in service state */
+       iowrite32(WDKEY_SEQ0, davinci_wdt->base + WDTCR);
+       /* put watchdog in active state */
+       iowrite32(WDKEY_SEQ1, davinci_wdt->base + WDTCR);
+       return 0;
 }
 
-static ssize_t
-davinci_wdt_write(struct file *file, const char *data, size_t len,
-                 loff_t *ppos)
+static unsigned int davinci_wdt_get_timeleft(struct watchdog_device *wdd)
 {
-       if (len)
-               wdt_service();
+       u64 timer_counter;
+       unsigned long freq;
+       u32 val;
+       struct davinci_wdt_device *davinci_wdt = watchdog_get_drvdata(wdd);
 
-       return len;
-}
+       /* if timeout has occured then return 0 */
+       val = ioread32(davinci_wdt->base + WDTCR);
+       if (val & WDFLAG)
+               return 0;
 
-static const struct watchdog_info ident = {
-       .options = WDIOF_KEEPALIVEPING,
-       .identity = "DaVinci Watchdog",
-};
+       freq = clk_get_rate(davinci_wdt->clk);
 
-static long davinci_wdt_ioctl(struct file *file,
-                                       unsigned int cmd, unsigned long arg)
-{
-       int ret = -ENOTTY;
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               ret = copy_to_user((struct watchdog_info *)arg, &ident,
-                                  sizeof(ident)) ? -EFAULT : 0;
-               break;
-
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               ret = put_user(0, (int *)arg);
-               break;
-
-       case WDIOC_KEEPALIVE:
-               wdt_service();
-               ret = 0;
-               break;
-
-       case WDIOC_GETTIMEOUT:
-               ret = put_user(heartbeat, (int *)arg);
-               break;
-       }
-       return ret;
-}
+       if (!freq)
+               return 0;
 
-static int davinci_wdt_release(struct inode *inode, struct file *file)
-{
-       wdt_service();
-       clear_bit(WDT_IN_USE, &wdt_status);
+       timer_counter = ioread32(davinci_wdt->base + TIM12);
+       timer_counter |= ((u64)ioread32(davinci_wdt->base + TIM34) << 32);
 
-       return 0;
+       do_div(timer_counter, freq);
+
+       return wdd->timeout - timer_counter;
 }
 
-static const struct file_operations davinci_wdt_fops = {
-       .owner = THIS_MODULE,
-       .llseek = no_llseek,
-       .write = davinci_wdt_write,
-       .unlocked_ioctl = davinci_wdt_ioctl,
-       .open = davinci_wdt_open,
-       .release = davinci_wdt_release,
+static const struct watchdog_info davinci_wdt_info = {
+       .options = WDIOF_KEEPALIVEPING,
+       .identity = "DaVinci/Keystone Watchdog",
 };
 
-static struct miscdevice davinci_wdt_miscdev = {
-       .minor = WATCHDOG_MINOR,
-       .name = "watchdog",
-       .fops = &davinci_wdt_fops,
+static const struct watchdog_ops davinci_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = davinci_wdt_start,
+       .stop           = davinci_wdt_ping,
+       .ping           = davinci_wdt_ping,
+       .get_timeleft   = davinci_wdt_get_timeleft,
 };
 
 static int davinci_wdt_probe(struct platform_device *pdev)
@@ -204,37 +159,53 @@ static int davinci_wdt_probe(struct platform_device *pdev)
        int ret = 0;
        struct device *dev = &pdev->dev;
        struct resource  *wdt_mem;
+       struct watchdog_device *wdd;
+       struct davinci_wdt_device *davinci_wdt;
+
+       davinci_wdt = devm_kzalloc(dev, sizeof(*davinci_wdt), GFP_KERNEL);
+       if (!davinci_wdt)
+               return -ENOMEM;
 
-       wdt_clk = devm_clk_get(dev, NULL);
-       if (WARN_ON(IS_ERR(wdt_clk)))
-               return PTR_ERR(wdt_clk);
+       davinci_wdt->clk = devm_clk_get(dev, NULL);
+       if (WARN_ON(IS_ERR(davinci_wdt->clk)))
+               return PTR_ERR(davinci_wdt->clk);
 
-       clk_prepare_enable(wdt_clk);
+       clk_prepare_enable(davinci_wdt->clk);
 
-       if (heartbeat < 1 || heartbeat > MAX_HEARTBEAT)
-               heartbeat = DEFAULT_HEARTBEAT;
+       platform_set_drvdata(pdev, davinci_wdt);
 
-       dev_info(dev, "heartbeat %d sec\n", heartbeat);
+       wdd                     = &davinci_wdt->wdd;
+       wdd->info               = &davinci_wdt_info;
+       wdd->ops                = &davinci_wdt_ops;
+       wdd->min_timeout        = 1;
+       wdd->max_timeout        = MAX_HEARTBEAT;
+       wdd->timeout            = DEFAULT_HEARTBEAT;
+
+       watchdog_init_timeout(wdd, heartbeat, dev);
+
+       dev_info(dev, "heartbeat %d sec\n", wdd->timeout);
+
+       watchdog_set_drvdata(wdd, davinci_wdt);
+       watchdog_set_nowayout(wdd, 1);
 
        wdt_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       wdt_base = devm_ioremap_resource(dev, wdt_mem);
-       if (IS_ERR(wdt_base))
-               return PTR_ERR(wdt_base);
+       davinci_wdt->base = devm_ioremap_resource(dev, wdt_mem);
+       if (IS_ERR(davinci_wdt->base))
+               return PTR_ERR(davinci_wdt->base);
 
-       ret = misc_register(&davinci_wdt_miscdev);
-       if (ret < 0) {
-               dev_err(dev, "cannot register misc device\n");
-       } else {
-               set_bit(WDT_DEVICE_INITED, &wdt_status);
-       }
+       ret = watchdog_register_device(wdd);
+       if (ret < 0)
+               dev_err(dev, "cannot register watchdog device\n");
 
        return ret;
 }
 
 static int davinci_wdt_remove(struct platform_device *pdev)
 {
-       misc_deregister(&davinci_wdt_miscdev);
-       clk_disable_unprepare(wdt_clk);
+       struct davinci_wdt_device *davinci_wdt = platform_get_drvdata(pdev);
+
+       watchdog_unregister_device(&davinci_wdt->wdd);
+       clk_disable_unprepare(davinci_wdt->clk);
 
        return 0;
 }
index a46f5c7ee7ff4e6c11eceb36a59ca7438949e5b5..ee4f86ba83eca1856dc85a0ad777e11732e4e5ea 100644 (file)
@@ -8,7 +8,7 @@
  * 2 of the License, or (at your option) any later version.
  *
  * This file implements a driver for the Synopsys DesignWare watchdog device
- * in the many ARM subsystems. The watchdog has 16 different timeout periods
+ * in the many subsystems. The watchdog has 16 different timeout periods
  * and these are a function of the input clock frequency.
  *
  * The DesignWare watchdog cannot be stopped once it has been started so we
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
new file mode 100644 (file)
index 0000000..220a9e0
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Driver for watchdog device controlled through GPIO-line
+ *
+ * Author: 2013, Alexander Shiyan <shc_work@mail.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.
+ */
+
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+
+#define SOFT_TIMEOUT_MIN       1
+#define SOFT_TIMEOUT_DEF       60
+#define SOFT_TIMEOUT_MAX       0xffff
+
+enum {
+       HW_ALGO_TOGGLE,
+       HW_ALGO_LEVEL,
+};
+
+struct gpio_wdt_priv {
+       int                     gpio;
+       bool                    active_low;
+       bool                    state;
+       unsigned int            hw_algo;
+       unsigned int            hw_margin;
+       unsigned long           last_jiffies;
+       struct notifier_block   notifier;
+       struct timer_list       timer;
+       struct watchdog_device  wdd;
+};
+
+static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
+{
+       gpio_set_value_cansleep(priv->gpio, !priv->active_low);
+
+       /* Put GPIO back to tristate */
+       if (priv->hw_algo == HW_ALGO_TOGGLE)
+               gpio_direction_input(priv->gpio);
+}
+
+static int gpio_wdt_start(struct watchdog_device *wdd)
+{
+       struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+       priv->state = priv->active_low;
+       gpio_direction_output(priv->gpio, priv->state);
+       priv->last_jiffies = jiffies;
+       mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin);
+
+       return 0;
+}
+
+static int gpio_wdt_stop(struct watchdog_device *wdd)
+{
+       struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+       mod_timer(&priv->timer, 0);
+       gpio_wdt_disable(priv);
+
+       return 0;
+}
+
+static int gpio_wdt_ping(struct watchdog_device *wdd)
+{
+       struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+       priv->last_jiffies = jiffies;
+
+       return 0;
+}
+
+static int gpio_wdt_set_timeout(struct watchdog_device *wdd, unsigned int t)
+{
+       wdd->timeout = t;
+
+       return gpio_wdt_ping(wdd);
+}
+
+static void gpio_wdt_hwping(unsigned long data)
+{
+       struct watchdog_device *wdd = (struct watchdog_device *)data;
+       struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+       if (time_after(jiffies, priv->last_jiffies +
+                      msecs_to_jiffies(wdd->timeout * 1000))) {
+               dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n");
+               return;
+       }
+
+       /* Restart timer */
+       mod_timer(&priv->timer, jiffies + priv->hw_margin);
+
+       switch (priv->hw_algo) {
+       case HW_ALGO_TOGGLE:
+               /* Toggle output pin */
+               priv->state = !priv->state;
+               gpio_set_value_cansleep(priv->gpio, priv->state);
+               break;
+       case HW_ALGO_LEVEL:
+               /* Pulse */
+               gpio_set_value_cansleep(priv->gpio, !priv->active_low);
+               udelay(1);
+               gpio_set_value_cansleep(priv->gpio, priv->active_low);
+               break;
+       }
+}
+
+static int gpio_wdt_notify_sys(struct notifier_block *nb, unsigned long code,
+                              void *unused)
+{
+       struct gpio_wdt_priv *priv = container_of(nb, struct gpio_wdt_priv,
+                                                 notifier);
+
+       mod_timer(&priv->timer, 0);
+
+       switch (code) {
+       case SYS_HALT:
+       case SYS_POWER_OFF:
+               gpio_wdt_disable(priv);
+               break;
+       default:
+               break;
+       }
+
+       return NOTIFY_DONE;
+}
+
+static const struct watchdog_info gpio_wdt_ident = {
+       .options        = WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING |
+                         WDIOF_SETTIMEOUT,
+       .identity       = "GPIO Watchdog",
+};
+
+static const struct watchdog_ops gpio_wdt_ops = {
+       .owner          = THIS_MODULE,
+       .start          = gpio_wdt_start,
+       .stop           = gpio_wdt_stop,
+       .ping           = gpio_wdt_ping,
+       .set_timeout    = gpio_wdt_set_timeout,
+};
+
+static int gpio_wdt_probe(struct platform_device *pdev)
+{
+       struct gpio_wdt_priv *priv;
+       enum of_gpio_flags flags;
+       unsigned int hw_margin;
+       unsigned long f = 0;
+       const char *algo;
+       int ret;
+
+       priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+       if (!priv)
+               return -ENOMEM;
+
+       priv->gpio = of_get_gpio_flags(pdev->dev.of_node, 0, &flags);
+       if (!gpio_is_valid(priv->gpio))
+               return priv->gpio;
+
+       priv->active_low = flags & OF_GPIO_ACTIVE_LOW;
+
+       ret = of_property_read_string(pdev->dev.of_node, "hw_algo", &algo);
+       if (ret)
+               return ret;
+       if (!strncmp(algo, "toggle", 6)) {
+               priv->hw_algo = HW_ALGO_TOGGLE;
+               f = GPIOF_IN;
+       } else if (!strncmp(algo, "level", 5)) {
+               priv->hw_algo = HW_ALGO_LEVEL;
+               f = priv->active_low ? GPIOF_OUT_INIT_HIGH : GPIOF_OUT_INIT_LOW;
+       } else {
+               return -EINVAL;
+       }
+
+       ret = devm_gpio_request_one(&pdev->dev, priv->gpio, f,
+                                   dev_name(&pdev->dev));
+       if (ret)
+               return ret;
+
+       ret = of_property_read_u32(pdev->dev.of_node,
+                                  "hw_margin_ms", &hw_margin);
+       if (ret)
+               return ret;
+       /* Disallow values lower than 2 and higher than 65535 ms */
+       if (hw_margin < 2 || hw_margin > 65535)
+               return -EINVAL;
+
+       /* Use safe value (1/2 of real timeout) */
+       priv->hw_margin = msecs_to_jiffies(hw_margin / 2);
+
+       watchdog_set_drvdata(&priv->wdd, priv);
+
+       priv->wdd.info          = &gpio_wdt_ident;
+       priv->wdd.ops           = &gpio_wdt_ops;
+       priv->wdd.min_timeout   = SOFT_TIMEOUT_MIN;
+       priv->wdd.max_timeout   = SOFT_TIMEOUT_MAX;
+
+       if (watchdog_init_timeout(&priv->wdd, 0, &pdev->dev) < 0)
+               priv->wdd.timeout = SOFT_TIMEOUT_DEF;
+
+       setup_timer(&priv->timer, gpio_wdt_hwping, (unsigned long)&priv->wdd);
+
+       ret = watchdog_register_device(&priv->wdd);
+       if (ret)
+               return ret;
+
+       priv->notifier.notifier_call = gpio_wdt_notify_sys;
+       ret = register_reboot_notifier(&priv->notifier);
+       if (ret)
+               watchdog_unregister_device(&priv->wdd);
+
+       return ret;
+}
+
+static int gpio_wdt_remove(struct platform_device *pdev)
+{
+       struct gpio_wdt_priv *priv = platform_get_drvdata(pdev);
+
+       del_timer_sync(&priv->timer);
+       unregister_reboot_notifier(&priv->notifier);
+       watchdog_unregister_device(&priv->wdd);
+
+       return 0;
+}
+
+static const struct of_device_id gpio_wdt_dt_ids[] = {
+       { .compatible = "linux,wdt-gpio", },
+       { }
+};
+MODULE_DEVICE_TABLE(of, gpio_wdt_dt_ids);
+
+static struct platform_driver gpio_wdt_driver = {
+       .driver = {
+               .name           = "gpio-wdt",
+               .owner          = THIS_MODULE,
+               .of_match_table = gpio_wdt_dt_ids,
+       },
+       .probe  = gpio_wdt_probe,
+       .remove = gpio_wdt_remove,
+};
+module_platform_driver(gpio_wdt_driver);
+
+MODULE_AUTHOR("Alexander Shiyan <shc_work@mail.ru>");
+MODULE_DESCRIPTION("GPIO Watchdog");
+MODULE_LICENSE("GPL");
index 45b979d9dd13acf223ac4ede12262c51fe6e1e9d..2b75e8b472796e987c3651599b7583442d5b1089 100644 (file)
@@ -39,7 +39,7 @@
 #endif /* CONFIG_HPWDT_NMI_DECODING */
 #include <asm/nmi.h>
 
-#define HPWDT_VERSION                  "1.3.2"
+#define HPWDT_VERSION                  "1.3.3"
 #define SECS_TO_TICKS(secs)            ((secs) * 1000 / 128)
 #define TICKS_TO_SECS(ticks)           ((ticks) * 128 / 1000)
 #define HPWDT_MAX_TIMER                        TICKS_TO_SECS(65535)
@@ -55,7 +55,7 @@ static void __iomem *pci_mem_addr;            /* the PCI-memory address */
 static unsigned long __iomem *hpwdt_timer_reg;
 static unsigned long __iomem *hpwdt_timer_con;
 
-static DEFINE_PCI_DEVICE_TABLE(hpwdt_devices) = {
+static const struct pci_device_id hpwdt_devices[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) },   /* iLO2 */
        { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) },       /* iLO3 */
        {0},                    /* terminate list */
@@ -501,8 +501,13 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs)
                                "but unable to determine source.\n");
                }
        }
-       panic("An NMI occurred, please see the Integrated "
-               "Management Log for details.\n");
+       panic("An NMI occurred. Depending on your system the reason "
+               "for the NMI is logged in any one of the following "
+               "resources:\n"
+               "1. Integrated Management Log (IML)\n"
+               "2. OA Syslog\n"
+               "3. OA Forward Progress Log\n"
+               "4. iLO Event Log");
 
 out:
        return NMI_DONE;
index a72fe9361ddf028ef717959183cc5bdfc3ea0478..25a2bfdb4e9d2e41812b676e4b93b0c4219c47a9 100644 (file)
@@ -334,7 +334,7 @@ static struct miscdevice esb_miscdev = {
 /*
  * Data for PCI driver interface
  */
-static DEFINE_PCI_DEVICE_TABLE(esb_pci_tbl) = {
+static const struct pci_device_id esb_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ESB_9), },
        { 0, },                 /* End of list */
 };
index b4786bccc42c3c062153ef06ce2419900d84a76d..dd51d9539b33df6ea6b9aa9960d9f0fa5fe7c169 100644 (file)
@@ -2,6 +2,7 @@
  * Watchdog driver for IMX2 and later processors
  *
  *  Copyright (C) 2010 Wolfram Sang, Pengutronix e.K. <w.sang@pengutronix.de>
+ *  Copyright (C) 2014 Freescale Semiconductor, Inc.
  *
  * some parts adapted by similar drivers from Darius Augulis and Vladimir
  * Zapolskiy, additional improvements by Wim Van Sebroeck.
@@ -40,6 +41,7 @@
 #define IMX2_WDT_WCR_WT                (0xFF << 8)     /* -> Watchdog Timeout Field */
 #define IMX2_WDT_WCR_WRE       (1 << 3)        /* -> WDOG Reset Enable */
 #define IMX2_WDT_WCR_WDE       (1 << 2)        /* -> Watchdog Enable */
+#define IMX2_WDT_WCR_WDZST     (1 << 0)        /* -> Watchdog timer Suspend */
 
 #define IMX2_WDT_WSR           0x02            /* Service Register */
 #define IMX2_WDT_SEQ1          0x5555          /* -> service sequence 1 */
@@ -87,6 +89,8 @@ static inline void imx2_wdt_setup(void)
 {
        u16 val = __raw_readw(imx2_wdt.base + IMX2_WDT_WCR);
 
+       /* Suspend timer in low power mode, write once-only */
+       val |= IMX2_WDT_WCR_WDZST;
        /* Strip the old watchdog Time-Out value */
        val &= ~IMX2_WDT_WCR_WT;
        /* Generate reset if WDOG times out */
index 4166e4d116a8e1c73b91f305e9216dc47cdf4c4e..4aa3a8a876fe84f109a211b560e453ccf879172b 100644 (file)
@@ -19,6 +19,8 @@
 #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,8 +31,17 @@ struct moxart_wdt_dev {
        unsigned int clock_frequency;
 };
 
+static struct moxart_wdt_dev *moxart_restart_ctx;
+
 static int heartbeat;
 
+static void moxart_wdt_restart(enum reboot_mode reboot_mode, const char *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);
+}
+
 static int moxart_wdt_stop(struct watchdog_device *wdt_dev)
 {
        struct moxart_wdt_dev *moxart_wdt = watchdog_get_drvdata(wdt_dev);
@@ -125,6 +136,9 @@ static int moxart_wdt_probe(struct platform_device *pdev)
        if (err)
                return err;
 
+       moxart_restart_ctx = moxart_wdt;
+       arm_pm_restart = moxart_wdt_restart;
+
        dev_dbg(dev, "Watchdog enabled (heartbeat=%d sec, nowayout=%d)\n",
                moxart_wdt->dev.timeout, nowayout);
 
@@ -135,6 +149,7 @@ static int moxart_wdt_remove(struct platform_device *pdev)
 {
        struct moxart_wdt_dev *moxart_wdt = platform_get_drvdata(pdev);
 
+       arm_pm_restart = NULL;
        moxart_wdt_stop(&moxart_wdt->dev);
        watchdog_unregister_device(&moxart_wdt->dev);
 
index d82152077fd9fb1c512145c92a8700cb0ccaf385..c1f65b4c0aa4050442bd1742d32a0883e68537dd 100644 (file)
@@ -73,9 +73,7 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
  * to 0
  */
 static int prescale = 1;
-static unsigned int timeout_sec;
 
-static unsigned long wdt_is_open;
 static DEFINE_SPINLOCK(wdt_spinlock);
 
 static void mpc8xxx_wdt_keepalive(void)
@@ -87,39 +85,23 @@ static void mpc8xxx_wdt_keepalive(void)
        spin_unlock(&wdt_spinlock);
 }
 
+static struct watchdog_device mpc8xxx_wdt_dev;
 static void mpc8xxx_wdt_timer_ping(unsigned long arg);
-static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0, 0);
+static DEFINE_TIMER(wdt_timer, mpc8xxx_wdt_timer_ping, 0,
+               (unsigned long)&mpc8xxx_wdt_dev);
 
 static void mpc8xxx_wdt_timer_ping(unsigned long arg)
 {
+       struct watchdog_device *w = (struct watchdog_device *)arg;
+
        mpc8xxx_wdt_keepalive();
        /* We're pinging it twice faster than needed, just to be sure. */
-       mod_timer(&wdt_timer, jiffies + HZ * timeout_sec / 2);
-}
-
-static void mpc8xxx_wdt_pr_warn(const char *msg)
-{
-       pr_crit("%s, expect the %s soon!\n", msg,
-               reset ? "reset" : "machine check exception");
+       mod_timer(&wdt_timer, jiffies + HZ * w->timeout / 2);
 }
 
-static ssize_t mpc8xxx_wdt_write(struct file *file, const char __user *buf,
-                                size_t count, loff_t *ppos)
-{
-       if (count)
-               mpc8xxx_wdt_keepalive();
-       return count;
-}
-
-static int mpc8xxx_wdt_open(struct inode *inode, struct file *file)
+static int mpc8xxx_wdt_start(struct watchdog_device *w)
 {
        u32 tmp = SWCRR_SWEN;
-       if (test_and_set_bit(0, &wdt_is_open))
-               return -EBUSY;
-
-       /* Once we start the watchdog we can't stop it */
-       if (nowayout)
-               __module_get(THIS_MODULE);
 
        /* Good, fire up the show */
        if (prescale)
@@ -133,59 +115,37 @@ static int mpc8xxx_wdt_open(struct inode *inode, struct file *file)
 
        del_timer_sync(&wdt_timer);
 
-       return nonseekable_open(inode, file);
+       return 0;
 }
 
-static int mpc8xxx_wdt_release(struct inode *inode, struct file *file)
+static int mpc8xxx_wdt_ping(struct watchdog_device *w)
 {
-       if (!nowayout)
-               mpc8xxx_wdt_timer_ping(0);
-       else
-               mpc8xxx_wdt_pr_warn("watchdog closed");
-       clear_bit(0, &wdt_is_open);
+       mpc8xxx_wdt_keepalive();
        return 0;
 }
 
-static long mpc8xxx_wdt_ioctl(struct file *file, unsigned int cmd,
-                                                       unsigned long arg)
+static int mpc8xxx_wdt_stop(struct watchdog_device *w)
 {
-       void __user *argp = (void __user *)arg;
-       int __user *p = argp;
-       static const struct watchdog_info ident = {
-               .options = WDIOF_KEEPALIVEPING,
-               .firmware_version = 1,
-               .identity = "MPC8xxx",
-       };
-
-       switch (cmd) {
-       case WDIOC_GETSUPPORT:
-               return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
-       case WDIOC_GETSTATUS:
-       case WDIOC_GETBOOTSTATUS:
-               return put_user(0, p);
-       case WDIOC_KEEPALIVE:
-               mpc8xxx_wdt_keepalive();
-               return 0;
-       case WDIOC_GETTIMEOUT:
-               return put_user(timeout_sec, p);
-       default:
-               return -ENOTTY;
-       }
+       mod_timer(&wdt_timer, jiffies);
+       return 0;
 }
 
-static const struct file_operations mpc8xxx_wdt_fops = {
-       .owner          = THIS_MODULE,
-       .llseek         = no_llseek,
-       .write          = mpc8xxx_wdt_write,
-       .unlocked_ioctl = mpc8xxx_wdt_ioctl,
-       .open           = mpc8xxx_wdt_open,
-       .release        = mpc8xxx_wdt_release,
+static struct watchdog_info mpc8xxx_wdt_info = {
+       .options = WDIOF_KEEPALIVEPING,
+       .firmware_version = 1,
+       .identity = "MPC8xxx",
 };
 
-static struct miscdevice mpc8xxx_wdt_miscdev = {
-       .minor  = WATCHDOG_MINOR,
-       .name   = "watchdog",
-       .fops   = &mpc8xxx_wdt_fops,
+static struct watchdog_ops mpc8xxx_wdt_ops = {
+       .owner = THIS_MODULE,
+       .start = mpc8xxx_wdt_start,
+       .ping = mpc8xxx_wdt_ping,
+       .stop = mpc8xxx_wdt_stop,
+};
+
+static struct watchdog_device mpc8xxx_wdt_dev = {
+       .info = &mpc8xxx_wdt_info,
+       .ops = &mpc8xxx_wdt_ops,
 };
 
 static const struct of_device_id mpc8xxx_wdt_match[];
@@ -197,6 +157,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
        const struct mpc8xxx_wdt_type *wdt_type;
        u32 freq = fsl_get_sys_freq();
        bool enabled;
+       unsigned int timeout_sec;
 
        match = of_match_device(mpc8xxx_wdt_match, &ofdev->dev);
        if (!match)
@@ -223,6 +184,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
        else
                timeout_sec = timeout / freq;
 
+       mpc8xxx_wdt_dev.timeout = timeout_sec;
 #ifdef MODULE
        ret = mpc8xxx_wdt_init_late();
        if (ret)
@@ -238,7 +200,7 @@ static int mpc8xxx_wdt_probe(struct platform_device *ofdev)
         * userspace handles it.
         */
        if (enabled)
-               mpc8xxx_wdt_timer_ping(0);
+               mod_timer(&wdt_timer, jiffies);
        return 0;
 err_unmap:
        iounmap(wd_base);
@@ -248,9 +210,10 @@ err_unmap:
 
 static int mpc8xxx_wdt_remove(struct platform_device *ofdev)
 {
-       mpc8xxx_wdt_pr_warn("watchdog removed");
+       pr_crit("Watchdog removed, expect the %s soon!\n",
+               reset ? "reset" : "machine check exception");
        del_timer_sync(&wdt_timer);
-       misc_deregister(&mpc8xxx_wdt_miscdev);
+       watchdog_unregister_device(&mpc8xxx_wdt_dev);
        iounmap(wd_base);
 
        return 0;
@@ -302,10 +265,11 @@ static int mpc8xxx_wdt_init_late(void)
        if (!wd_base)
                return -ENODEV;
 
-       ret = misc_register(&mpc8xxx_wdt_miscdev);
+       watchdog_set_nowayout(&mpc8xxx_wdt_dev, nowayout);
+
+       ret = watchdog_register_device(&mpc8xxx_wdt_dev);
        if (ret) {
-               pr_err("cannot register miscdev on minor=%d (err=%d)\n",
-                      WATCHDOG_MINOR, ret);
+               pr_err("cannot register watchdog device (err=%d)\n", ret);
                return ret;
        }
        return 0;
index 231e5b9d5c8e079ec424b9331aca90912f42efae..0b9ec61e131330524e417197304702baaebdf272 100644 (file)
@@ -289,7 +289,7 @@ static struct miscdevice nv_tco_miscdev = {
  * register a pci_driver, because someone else might one day
  * want to register another driver on the same PCI id.
  */
-static DEFINE_PCI_DEVICE_TABLE(tco_pci_tbl) = {
+static const struct pci_device_id tco_pci_tbl[] = {
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SMBUS,
          PCI_ANY_ID, PCI_ANY_ID, },
        { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SMBUS,
index b4864f254b48940b7fd9b7febb368b6608af4716..c0d07eef2640b9cb0f2469acda6a579e57a16d94 100644 (file)
@@ -801,7 +801,7 @@ static void pcipcwd_card_exit(struct pci_dev *pdev)
        cards_found--;
 }
 
-static DEFINE_PCI_DEVICE_TABLE(pcipcwd_pci_tbl) = {
+static const struct pci_device_id pcipcwd_pci_tbl[] = {
        { PCI_VENDOR_ID_QUICKLOGIC, PCI_DEVICE_ID_WATCHDOG_PCIPCWD,
                PCI_ANY_ID, PCI_ANY_ID, },
        { 0 },                  /* End of list */
index 7d8fd041ee250d3759fc2b86519012a09ded76e2..aec946df6ed976d2479762dc51d69060a5504382 100644 (file)
@@ -40,6 +40,8 @@
 #include <linux/slab.h>
 #include <linux/err.h>
 #include <linux/of.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
 
 #define S3C2410_WTCON          0x00
 #define S3C2410_WTDAT          0x04
 #define CONFIG_S3C2410_WATCHDOG_ATBOOT         (0)
 #define CONFIG_S3C2410_WATCHDOG_DEFAULT_TIME   (15)
 
+#define EXYNOS5_RST_STAT_REG_OFFSET            0x0404
+#define EXYNOS5_WDT_DISABLE_REG_OFFSET         0x0408
+#define EXYNOS5_WDT_MASK_RESET_REG_OFFSET      0x040c
+#define QUIRK_HAS_PMU_CONFIG                   (1 << 0)
+#define QUIRK_HAS_RST_STAT                     (1 << 1)
+
+/* These quirks require that we have a PMU register map */
+#define QUIRKS_HAVE_PMUREG                     (QUIRK_HAS_PMU_CONFIG | \
+                                                QUIRK_HAS_RST_STAT)
+
 static bool nowayout   = WATCHDOG_NOWAYOUT;
 static int tmr_margin;
 static int tmr_atboot  = CONFIG_S3C2410_WATCHDOG_ATBOOT;
@@ -83,6 +95,30 @@ MODULE_PARM_DESC(soft_noboot, "Watchdog action, set to 1 to ignore reboots, "
                        "0 to reboot (default 0)");
 MODULE_PARM_DESC(debug, "Watchdog debug, set to >1 for debug (default 0)");
 
+/**
+ * struct s3c2410_wdt_variant - Per-variant config data
+ *
+ * @disable_reg: Offset in pmureg for the register that disables the watchdog
+ * timer reset functionality.
+ * @mask_reset_reg: Offset in pmureg for the register that masks the watchdog
+ * timer reset functionality.
+ * @mask_bit: Bit number for the watchdog timer in the disable register and the
+ * mask reset register.
+ * @rst_stat_reg: Offset in pmureg for the register that has the reset status.
+ * @rst_stat_bit: Bit number in the rst_stat register indicating a watchdog
+ * reset.
+ * @quirks: A bitfield of quirks.
+ */
+
+struct s3c2410_wdt_variant {
+       int disable_reg;
+       int mask_reset_reg;
+       int mask_bit;
+       int rst_stat_reg;
+       int rst_stat_bit;
+       u32 quirks;
+};
+
 struct s3c2410_wdt {
        struct device           *dev;
        struct clk              *clock;
@@ -93,8 +129,54 @@ struct s3c2410_wdt {
        unsigned long           wtdat_save;
        struct watchdog_device  wdt_device;
        struct notifier_block   freq_transition;
+       struct s3c2410_wdt_variant *drv_data;
+       struct regmap *pmureg;
 };
 
+static const struct s3c2410_wdt_variant drv_data_s3c2410 = {
+       .quirks = 0
+};
+
+#ifdef CONFIG_OF
+static const struct s3c2410_wdt_variant drv_data_exynos5250  = {
+       .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
+       .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
+       .mask_bit = 20,
+       .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
+       .rst_stat_bit = 20,
+       .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
+};
+
+static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
+       .disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
+       .mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
+       .mask_bit = 0,
+       .rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
+       .rst_stat_bit = 9,
+       .quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
+};
+
+static const struct of_device_id s3c2410_wdt_match[] = {
+       { .compatible = "samsung,s3c2410-wdt",
+         .data = &drv_data_s3c2410 },
+       { .compatible = "samsung,exynos5250-wdt",
+         .data = &drv_data_exynos5250 },
+       { .compatible = "samsung,exynos5420-wdt",
+         .data = &drv_data_exynos5420 },
+       {},
+};
+MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
+#endif
+
+static const struct platform_device_id s3c2410_wdt_ids[] = {
+       {
+               .name = "s3c2410-wdt",
+               .driver_data = (unsigned long)&drv_data_s3c2410,
+       },
+       {}
+};
+MODULE_DEVICE_TABLE(platform, s3c2410_wdt_ids);
+
 /* watchdog control routines */
 
 #define DBG(fmt, ...)                                  \
@@ -110,6 +192,35 @@ static inline struct s3c2410_wdt *freq_to_wdt(struct notifier_block *nb)
        return container_of(nb, struct s3c2410_wdt, freq_transition);
 }
 
+static int s3c2410wdt_mask_and_disable_reset(struct s3c2410_wdt *wdt, bool mask)
+{
+       int ret;
+       u32 mask_val = 1 << wdt->drv_data->mask_bit;
+       u32 val = 0;
+
+       /* No need to do anything if no PMU CONFIG needed */
+       if (!(wdt->drv_data->quirks & QUIRK_HAS_PMU_CONFIG))
+               return 0;
+
+       if (mask)
+               val = mask_val;
+
+       ret = regmap_update_bits(wdt->pmureg,
+                       wdt->drv_data->disable_reg,
+                       mask_val, val);
+       if (ret < 0)
+               goto error;
+
+       ret = regmap_update_bits(wdt->pmureg,
+                       wdt->drv_data->mask_reset_reg,
+                       mask_val, val);
+ error:
+       if (ret < 0)
+               dev_err(wdt->dev, "failed to update reg(%d)\n", ret);
+
+       return ret;
+}
+
 static int s3c2410wdt_keepalive(struct watchdog_device *wdd)
 {
        struct s3c2410_wdt *wdt = watchdog_get_drvdata(wdd);
@@ -188,7 +299,7 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
        if (timeout < 1)
                return -EINVAL;
 
-       freq /= 128;
+       freq = DIV_ROUND_UP(freq, 128);
        count = timeout * freq;
 
        DBG("%s: count=%d, timeout=%d, freq=%lu\n",
@@ -200,21 +311,18 @@ static int s3c2410wdt_set_heartbeat(struct watchdog_device *wdd, unsigned timeou
        */
 
        if (count >= 0x10000) {
-               for (divisor = 1; divisor <= 0x100; divisor++) {
-                       if ((count / divisor) < 0x10000)
-                               break;
-               }
+               divisor = DIV_ROUND_UP(count, 0xffff);
 
-               if ((count / divisor) >= 0x10000) {
+               if (divisor > 0x100) {
                        dev_err(wdt->dev, "timeout %d too big\n", timeout);
                        return -EINVAL;
                }
        }
 
        DBG("%s: timeout=%d, divisor=%d, count=%d (%08x)\n",
-           __func__, timeout, divisor, count, count/divisor);
+           __func__, timeout, divisor, count, DIV_ROUND_UP(count, divisor));
 
-       count /= divisor;
+       count = DIV_ROUND_UP(count, divisor);
        wdt->count = count;
 
        /* update the pre-scaler */
@@ -264,7 +372,7 @@ static irqreturn_t s3c2410wdt_irq(int irqno, void *param)
        return IRQ_HANDLED;
 }
 
-#ifdef CONFIG_CPU_FREQ
+#ifdef CONFIG_ARM_S3C24XX_CPUFREQ
 
 static int s3c2410wdt_cpufreq_transition(struct notifier_block *nb,
                                          unsigned long val, void *data)
@@ -331,6 +439,37 @@ static inline void s3c2410wdt_cpufreq_deregister(struct s3c2410_wdt *wdt)
 }
 #endif
 
+static inline unsigned int s3c2410wdt_get_bootstatus(struct s3c2410_wdt *wdt)
+{
+       unsigned int rst_stat;
+       int ret;
+
+       if (!(wdt->drv_data->quirks & QUIRK_HAS_RST_STAT))
+               return 0;
+
+       ret = regmap_read(wdt->pmureg, wdt->drv_data->rst_stat_reg, &rst_stat);
+       if (ret)
+               dev_warn(wdt->dev, "Couldn't get RST_STAT register\n");
+       else if (rst_stat & BIT(wdt->drv_data->rst_stat_bit))
+               return WDIOF_CARDRESET;
+
+       return 0;
+}
+
+/* s3c2410_get_wdt_driver_data */
+static inline struct s3c2410_wdt_variant *
+get_wdt_drv_data(struct platform_device *pdev)
+{
+       if (pdev->dev.of_node) {
+               const struct of_device_id *match;
+               match = of_match_node(s3c2410_wdt_match, pdev->dev.of_node);
+               return (struct s3c2410_wdt_variant *)match->data;
+       } else {
+               return (struct s3c2410_wdt_variant *)
+                       platform_get_device_id(pdev)->driver_data;
+       }
+}
+
 static int s3c2410wdt_probe(struct platform_device *pdev)
 {
        struct device *dev;
@@ -353,6 +492,16 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
        spin_lock_init(&wdt->lock);
        wdt->wdt_device = s3c2410_wdd;
 
+       wdt->drv_data = get_wdt_drv_data(pdev);
+       if (wdt->drv_data->quirks & QUIRKS_HAVE_PMUREG) {
+               wdt->pmureg = syscon_regmap_lookup_by_phandle(dev->of_node,
+                                               "samsung,syscon-phandle");
+               if (IS_ERR(wdt->pmureg)) {
+                       dev_err(dev, "syscon regmap lookup failed.\n");
+                       return PTR_ERR(wdt->pmureg);
+               }
+       }
+
        wdt_irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
        if (wdt_irq == NULL) {
                dev_err(dev, "no irq resource specified\n");
@@ -415,12 +564,18 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
        watchdog_set_nowayout(&wdt->wdt_device, nowayout);
 
+       wdt->wdt_device.bootstatus = s3c2410wdt_get_bootstatus(wdt);
+
        ret = watchdog_register_device(&wdt->wdt_device);
        if (ret) {
                dev_err(dev, "cannot register watchdog (%d)\n", ret);
                goto err_cpufreq;
        }
 
+       ret = s3c2410wdt_mask_and_disable_reset(wdt, false);
+       if (ret < 0)
+               goto err_unregister;
+
        if (tmr_atboot && started == 0) {
                dev_info(dev, "starting watchdog timer\n");
                s3c2410wdt_start(&wdt->wdt_device);
@@ -445,6 +600,9 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
        return 0;
 
+ err_unregister:
+       watchdog_unregister_device(&wdt->wdt_device);
+
  err_cpufreq:
        s3c2410wdt_cpufreq_deregister(wdt);
 
@@ -458,8 +616,13 @@ static int s3c2410wdt_probe(struct platform_device *pdev)
 
 static int s3c2410wdt_remove(struct platform_device *dev)
 {
+       int ret;
        struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
 
+       ret = s3c2410wdt_mask_and_disable_reset(wdt, true);
+       if (ret < 0)
+               return ret;
+
        watchdog_unregister_device(&wdt->wdt_device);
 
        s3c2410wdt_cpufreq_deregister(wdt);
@@ -474,6 +637,8 @@ static void s3c2410wdt_shutdown(struct platform_device *dev)
 {
        struct s3c2410_wdt *wdt = platform_get_drvdata(dev);
 
+       s3c2410wdt_mask_and_disable_reset(wdt, true);
+
        s3c2410wdt_stop(&wdt->wdt_device);
 }
 
@@ -481,12 +646,17 @@ static void s3c2410wdt_shutdown(struct platform_device *dev)
 
 static int s3c2410wdt_suspend(struct device *dev)
 {
+       int ret;
        struct s3c2410_wdt *wdt = dev_get_drvdata(dev);
 
        /* Save watchdog state, and turn it off. */
        wdt->wtcon_save = readl(wdt->reg_base + S3C2410_WTCON);
        wdt->wtdat_save = readl(wdt->reg_base + S3C2410_WTDAT);
 
+       ret = s3c2410wdt_mask_and_disable_reset(wdt, true);
+       if (ret < 0)
+               return ret;
+
        /* Note that WTCNT doesn't need to be saved. */
        s3c2410wdt_stop(&wdt->wdt_device);
 
@@ -495,6 +665,7 @@ static int s3c2410wdt_suspend(struct device *dev)
 
 static int s3c2410wdt_resume(struct device *dev)
 {
+       int ret;
        struct s3c2410_wdt *wdt = dev_get_drvdata(dev);
 
        /* Restore watchdog state. */
@@ -502,6 +673,10 @@ static int s3c2410wdt_resume(struct device *dev)
        writel(wdt->wtdat_save, wdt->reg_base + S3C2410_WTCNT);/* Reset count */
        writel(wdt->wtcon_save, wdt->reg_base + S3C2410_WTCON);
 
+       ret = s3c2410wdt_mask_and_disable_reset(wdt, false);
+       if (ret < 0)
+               return ret;
+
        dev_info(dev, "watchdog %sabled\n",
                (wdt->wtcon_save & S3C2410_WTCON_ENABLE) ? "en" : "dis");
 
@@ -512,18 +687,11 @@ static int s3c2410wdt_resume(struct device *dev)
 static SIMPLE_DEV_PM_OPS(s3c2410wdt_pm_ops, s3c2410wdt_suspend,
                        s3c2410wdt_resume);
 
-#ifdef CONFIG_OF
-static const struct of_device_id s3c2410_wdt_match[] = {
-       { .compatible = "samsung,s3c2410-wdt" },
-       {},
-};
-MODULE_DEVICE_TABLE(of, s3c2410_wdt_match);
-#endif
-
 static struct platform_driver s3c2410wdt_driver = {
        .probe          = s3c2410wdt_probe,
        .remove         = s3c2410wdt_remove,
        .shutdown       = s3c2410wdt_shutdown,
+       .id_table       = s3c2410_wdt_ids,
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "s3c2410-wdt",
@@ -538,4 +706,3 @@ MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>, "
              "Dimitry Andric <dimitry.andric@tomtom.com>");
 MODULE_DESCRIPTION("S3C2410 Watchdog Device Driver");
 MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:s3c2410-wdt");
index ced3edc95957b471419f069e838084428a67f26b..702d07870808311b36d859570cbf03c096026faa 100644 (file)
@@ -212,7 +212,7 @@ static struct platform_driver sirfsoc_wdt_driver = {
                .name = "sirfsoc-wdt",
                .owner = THIS_MODULE,
                .pm = &sirfsoc_wdt_pm_ops,
-               .of_match_table = of_match_ptr(sirfsoc_wdt_of_match),
+               .of_match_table = sirfsoc_wdt_of_match,
        },
        .probe = sirfsoc_wdt_probe,
        .remove = sirfsoc_wdt_remove,
index ce63a1bbf395fa94ea5833aa0eb98d84aaa5dc75..5cca9cddb87d188f19a33e8e3b6a2fc2851f8a36 100644 (file)
@@ -303,7 +303,7 @@ static struct miscdevice sp5100_tco_miscdev = {
  * register a pci_driver, because someone else might
  * want to register another driver on the same PCI id.
  */
-static DEFINE_PCI_DEVICE_TABLE(sp5100_tco_pci_tbl) = {
+static const struct pci_device_id sp5100_tco_pci_tbl[] = {
        { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_SBX00_SMBUS, PCI_ANY_ID,
          PCI_ANY_ID, },
        { 0, },                 /* End of list */
index 1a68f760cf866a1da43ce6d6a9978daf7ec0d736..d2cd9f0bcb9a2df915472446f295139f04fc0ede 100644 (file)
@@ -239,7 +239,7 @@ static void wdt_remove(struct pci_dev *pdev)
        pci_disable_device(pdev);
 }
 
-static DEFINE_PCI_DEVICE_TABLE(wdt_pci_table) = {
+static const struct pci_device_id wdt_pci_table[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_CX700) },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX800) },
        { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_VX855) },
index e24b2108287483803c82709d0feec1dae8b29907..b1da0c18fd1ac4b9d02cdb9bf9245699a83d3e3c 100644 (file)
 #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT"
 #define WATCHDOG_TIMEOUT 60            /* 60 sec default timeout */
 
-/* You must set this - there is no sane way to probe for this board. */
-static int wdt_io = 0x2E;
-module_param(wdt_io, int, 0);
-MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)");
+static int wdt_io;
+static int cr_wdt_timeout;     /* WDT timeout register */
+static int cr_wdt_control;     /* WDT control register */
+
+enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
+            w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p,
+            w83667hg_b, nct6775, nct6776, nct6779 };
 
 static int timeout;                    /* in seconds */
 module_param(timeout, int, 0);
@@ -72,6 +75,29 @@ MODULE_PARM_DESC(nowayout,
 
 #define W83627HF_LD_WDT                0x08
 
+#define W83627HF_ID            0x52
+#define W83627S_ID             0x59
+#define W83697HF_ID            0x60
+#define W83697UG_ID            0x68
+#define W83637HF_ID            0x70
+#define W83627THF_ID           0x82
+#define W83687THF_ID           0x85
+#define W83627EHF_ID           0x88
+#define W83627DHG_ID           0xa0
+#define W83627UHG_ID           0xa2
+#define W83667HG_ID            0xa5
+#define W83627DHG_P_ID         0xb0
+#define W83667HG_B_ID          0xb3
+#define NCT6775_ID             0xb4
+#define NCT6776_ID             0xc3
+#define NCT6779_ID             0xc5
+
+#define W83627HF_WDT_TIMEOUT   0xf6
+#define W83697HF_WDT_TIMEOUT   0xf4
+
+#define W83627HF_WDT_CONTROL   0xf5
+#define W83697HF_WDT_CONTROL   0xf3
+
 static void superio_outb(int reg, int val)
 {
        outb(reg, WDT_EFER);
@@ -106,10 +132,7 @@ static void superio_exit(void)
        release_region(wdt_io, 2);
 }
 
-/* tyan motherboards seem to set F5 to 0x4C ?
- * So explicitly init to appropriate value. */
-
-static int w83627hf_init(struct watchdog_device *wdog)
+static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
 {
        int ret;
        unsigned char t;
@@ -119,35 +142,83 @@ static int w83627hf_init(struct watchdog_device *wdog)
                return ret;
 
        superio_select(W83627HF_LD_WDT);
-       t = superio_inb(0x20);  /* check chip version   */
-       if (t == 0x82) {        /* W83627THF            */
-               t = (superio_inb(0x2b) & 0xf7);
-               superio_outb(0x2b, t | 0x04); /* set GPIO3 to WDT0 */
-       } else if (t == 0x88 || t == 0xa0) {    /* W83627EHF / W83627DHG */
-               t = superio_inb(0x2d);
-               superio_outb(0x2d, t & ~0x01);  /* set GPIO5 to WDT0 */
-       }
 
        /* set CR30 bit 0 to activate GPIO2 */
        t = superio_inb(0x30);
        if (!(t & 0x01))
                superio_outb(0x30, t | 0x01);
 
-       t = superio_inb(0xF6);
+       switch (chip) {
+       case w83627hf:
+       case w83627s:
+               t = superio_inb(0x2B) & ~0x10;
+               superio_outb(0x2B, t); /* set GPIO24 to WDT0 */
+               break;
+       case w83697hf:
+               /* Set pin 119 to WDTO# mode (= CR29, WDT0) */
+               t = superio_inb(0x29) & ~0x60;
+               t |= 0x20;
+               superio_outb(0x29, t);
+               break;
+       case w83697ug:
+               /* Set pin 118 to WDTO# mode */
+               t = superio_inb(0x2b) & ~0x04;
+               superio_outb(0x2b, t);
+               break;
+       case w83627thf:
+               t = (superio_inb(0x2B) & ~0x08) | 0x04;
+               superio_outb(0x2B, t); /* set GPIO3 to WDT0 */
+               break;
+       case w83627dhg:
+       case w83627dhg_p:
+               t = superio_inb(0x2D) & ~0x01; /* PIN77 -> WDT0# */
+               superio_outb(0x2D, t); /* set GPIO5 to WDT0 */
+               t = superio_inb(cr_wdt_control);
+               t |= 0x02;      /* enable the WDTO# output low pulse
+                                * to the KBRST# pin */
+               superio_outb(cr_wdt_control, t);
+               break;
+       case w83637hf:
+               break;
+       case w83687thf:
+               t = superio_inb(0x2C) & ~0x80; /* PIN47 -> WDT0# */
+               superio_outb(0x2C, t);
+               break;
+       case w83627ehf:
+       case w83627uhg:
+       case w83667hg:
+       case w83667hg_b:
+       case nct6775:
+       case nct6776:
+       case nct6779:
+               /*
+                * These chips have a fixed WDTO# output pin (W83627UHG),
+                * or support more than one WDTO# output pin.
+                * Don't touch its configuration, and hope the BIOS
+                * does the right thing.
+                */
+               t = superio_inb(cr_wdt_control);
+               t |= 0x02;      /* enable the WDTO# output low pulse
+                                * to the KBRST# pin */
+               superio_outb(cr_wdt_control, t);
+               break;
+       default:
+               break;
+       }
+
+       t = superio_inb(cr_wdt_timeout);
        if (t != 0) {
                pr_info("Watchdog already running. Resetting timeout to %d sec\n",
                        wdog->timeout);
-               superio_outb(0xF6, wdog->timeout);
+               superio_outb(cr_wdt_timeout, wdog->timeout);
        }
 
        /* set second mode & disable keyboard turning off watchdog */
-       t = superio_inb(0xF5) & ~0x0C;
-       /* enable the WDTO# output low pulse to the KBRST# pin */
-       t |= 0x02;
-       superio_outb(0xF5, t);
+       t = superio_inb(cr_wdt_control) & ~0x0C;
+       superio_outb(cr_wdt_control, t);
 
-       /* disable keyboard & mouse turning off watchdog */
-       t = superio_inb(0xF7) & ~0xC0;
+       /* reset trigger, disable keyboard & mouse turning off watchdog */
+       t = superio_inb(0xF7) & ~0xD0;
        superio_outb(0xF7, t);
 
        superio_exit();
@@ -164,7 +235,7 @@ static int wdt_set_time(unsigned int timeout)
                return ret;
 
        superio_select(W83627HF_LD_WDT);
-       superio_outb(0xF6, timeout);
+       superio_outb(cr_wdt_timeout, timeout);
        superio_exit();
 
        return 0;
@@ -197,7 +268,7 @@ static unsigned int wdt_get_time(struct watchdog_device *wdog)
                return 0;
 
        superio_select(W83627HF_LD_WDT);
-       timeleft = superio_inb(0xF6);
+       timeleft = superio_inb(cr_wdt_timeout);
        superio_exit();
 
        return timeleft;
@@ -249,16 +320,123 @@ static struct notifier_block wdt_notifier = {
        .notifier_call = wdt_notify_sys,
 };
 
+static int wdt_find(int addr)
+{
+       u8 val;
+       int ret;
+
+       cr_wdt_timeout = W83627HF_WDT_TIMEOUT;
+       cr_wdt_control = W83627HF_WDT_CONTROL;
+
+       ret = superio_enter();
+       if (ret)
+               return ret;
+       superio_select(W83627HF_LD_WDT);
+       val = superio_inb(0x20);
+       switch (val) {
+       case W83627HF_ID:
+               ret = w83627hf;
+               break;
+       case W83627S_ID:
+               ret = w83627s;
+               break;
+       case W83697HF_ID:
+               ret = w83697hf;
+               cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
+               cr_wdt_control = W83697HF_WDT_CONTROL;
+               break;
+       case W83697UG_ID:
+               ret = w83697ug;
+               cr_wdt_timeout = W83697HF_WDT_TIMEOUT;
+               cr_wdt_control = W83697HF_WDT_CONTROL;
+               break;
+       case W83637HF_ID:
+               ret = w83637hf;
+               break;
+       case W83627THF_ID:
+               ret = w83627thf;
+               break;
+       case W83687THF_ID:
+               ret = w83687thf;
+               break;
+       case W83627EHF_ID:
+               ret = w83627ehf;
+               break;
+       case W83627DHG_ID:
+               ret = w83627dhg;
+               break;
+       case W83627DHG_P_ID:
+               ret = w83627dhg_p;
+               break;
+       case W83627UHG_ID:
+               ret = w83627uhg;
+               break;
+       case W83667HG_ID:
+               ret = w83667hg;
+               break;
+       case W83667HG_B_ID:
+               ret = w83667hg_b;
+               break;
+       case NCT6775_ID:
+               ret = nct6775;
+               break;
+       case NCT6776_ID:
+               ret = nct6776;
+               break;
+       case NCT6779_ID:
+               ret = nct6779;
+               break;
+       case 0xff:
+               ret = -ENODEV;
+               break;
+       default:
+               ret = -ENODEV;
+               pr_err("Unsupported chip ID: 0x%02x\n", val);
+               break;
+       }
+       superio_exit();
+       return ret;
+}
+
 static int __init wdt_init(void)
 {
        int ret;
+       int chip;
+       const char * const chip_name[] = {
+               "W83627HF",
+               "W83627S",
+               "W83697HF",
+               "W83697UG",
+               "W83637HF",
+               "W83627THF",
+               "W83687THF",
+               "W83627EHF",
+               "W83627DHG",
+               "W83627UHG",
+               "W83667HG",
+               "W83667DHG-P",
+               "W83667HG-B",
+               "NCT6775",
+               "NCT6776",
+               "NCT6779",
+       };
+
+       wdt_io = 0x2e;
+       chip = wdt_find(0x2e);
+       if (chip < 0) {
+               wdt_io = 0x4e;
+               chip = wdt_find(0x4e);
+               if (chip < 0)
+                       return chip;
+       }
 
-       pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n");
+       pr_info("WDT driver for %s Super I/O chip initialising\n",
+               chip_name[chip]);
 
        watchdog_init_timeout(&wdt_dev, timeout, NULL);
        watchdog_set_nowayout(&wdt_dev, nowayout);
 
-       ret = w83627hf_init(&wdt_dev);
+       ret = w83627hf_init(&wdt_dev, chip);
        if (ret) {
                pr_err("failed to initialize watchdog (err=%d)\n", ret);
                return ret;
index 461336c4519faf3acee6dad759030a6f0778876d..cec9b559647dee675439058efb07138fe866edb7 100644 (file)
@@ -78,7 +78,7 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
        watchdog_check_min_max_timeout(wdd);
 
        /* try to get the timeout module parameter first */
-       if (!watchdog_timeout_invalid(wdd, timeout_parm)) {
+       if (!watchdog_timeout_invalid(wdd, timeout_parm) && timeout_parm) {
                wdd->timeout = timeout_parm;
                return ret;
        }
@@ -89,7 +89,7 @@ int watchdog_init_timeout(struct watchdog_device *wdd,
        if (dev == NULL || dev->of_node == NULL)
                return ret;
        of_property_read_u32(dev->of_node, "timeout-sec", &t);
-       if (!watchdog_timeout_invalid(wdd, t))
+       if (!watchdog_timeout_invalid(wdd, t) && t)
                wdd->timeout = t;
        else
                ret = -EINVAL;
index ee89ba4dea63c932ecad137b49712191b9a9b799..3dc578e7121110bea28748b16c7a44b6817a566f 100644 (file)
@@ -720,7 +720,7 @@ static void wdtpci_remove_one(struct pci_dev *pdev)
 }
 
 
-static DEFINE_PCI_DEVICE_TABLE(wdtpci_pci_tbl) = {
+static const struct pci_device_id wdtpci_pci_tbl[] = {
        {
                .vendor    = PCI_VENDOR_ID_ACCESSIO,
                .device    = PCI_DEVICE_ID_ACCESSIO_WDG_CSM,
index 073b4a19a8b0796bf320130201ec8e7e98f2cff4..34a2704fbc8856a6a112f9f41392adfd8f04c6bb 100644 (file)
@@ -284,8 +284,10 @@ static int map_grant_pages(struct grant_map *map)
        }
 
        pr_debug("map %d+%d\n", map->index, map->count);
-       err = gnttab_map_refs(map->map_ops, use_ptemod ? map->kmap_ops : NULL,
-                       map->pages, map->count);
+       err = gnttab_map_refs_userspace(map->map_ops,
+                                       use_ptemod ? map->kmap_ops : NULL,
+                                       map->pages,
+                                       map->count);
        if (err)
                return err;
 
@@ -315,9 +317,10 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
                }
        }
 
-       err = gnttab_unmap_refs(map->unmap_ops + offset,
-                       use_ptemod ? map->kmap_ops + offset : NULL, map->pages + offset,
-                       pages);
+       err = gnttab_unmap_refs_userspace(map->unmap_ops + offset,
+                                         use_ptemod ? map->kmap_ops + offset : NULL,
+                                         map->pages + offset,
+                                         pages);
        if (err)
                return err;
 
index 1ce1c40331f32568f6db0888cdabe5f73498922a..8ee13e2e45e2f8a5a29bb91eba7af714027d254d 100644 (file)
@@ -837,7 +837,7 @@ unsigned int gnttab_max_grant_frames(void)
 }
 EXPORT_SYMBOL_GPL(gnttab_max_grant_frames);
 
-int gnttab_setup_auto_xlat_frames(unsigned long addr)
+int gnttab_setup_auto_xlat_frames(phys_addr_t addr)
 {
        xen_pfn_t *pfn;
        unsigned int max_nr_gframes = __max_nr_grant_frames();
@@ -849,8 +849,8 @@ int gnttab_setup_auto_xlat_frames(unsigned long addr)
 
        vaddr = xen_remap(addr, PAGE_SIZE * max_nr_gframes);
        if (vaddr == NULL) {
-               pr_warn("Failed to ioremap gnttab share frames (addr=0x%08lx)!\n",
-                       addr);
+               pr_warn("Failed to ioremap gnttab share frames (addr=%pa)!\n",
+                       &addr);
                return -ENOMEM;
        }
        pfn = kcalloc(max_nr_gframes, sizeof(pfn[0]), GFP_KERNEL);
@@ -928,15 +928,17 @@ void gnttab_batch_copy(struct gnttab_copy *batch, unsigned count)
 }
 EXPORT_SYMBOL_GPL(gnttab_batch_copy);
 
-int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
+int __gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
                    struct gnttab_map_grant_ref *kmap_ops,
-                   struct page **pages, unsigned int count)
+                   struct page **pages, unsigned int count,
+                   bool m2p_override)
 {
        int i, ret;
        bool lazy = false;
        pte_t *pte;
-       unsigned long mfn;
+       unsigned long mfn, pfn;
 
+       BUG_ON(kmap_ops && !m2p_override);
        ret = HYPERVISOR_grant_table_op(GNTTABOP_map_grant_ref, map_ops, count);
        if (ret)
                return ret;
@@ -955,10 +957,12 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
                        set_phys_to_machine(map_ops[i].host_addr >> PAGE_SHIFT,
                                        map_ops[i].dev_bus_addr >> PAGE_SHIFT);
                }
-               return ret;
+               return 0;
        }
 
-       if (!in_interrupt() && paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) {
+       if (m2p_override &&
+           !in_interrupt() &&
+           paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) {
                arch_enter_lazy_mmu_mode();
                lazy = true;
        }
@@ -975,8 +979,20 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
                } else {
                        mfn = PFN_DOWN(map_ops[i].dev_bus_addr);
                }
-               ret = m2p_add_override(mfn, pages[i], kmap_ops ?
-                                      &kmap_ops[i] : NULL);
+               pfn = page_to_pfn(pages[i]);
+
+               WARN_ON(PagePrivate(pages[i]));
+               SetPagePrivate(pages[i]);
+               set_page_private(pages[i], mfn);
+
+               pages[i]->index = pfn_to_mfn(pfn);
+               if (unlikely(!set_phys_to_machine(pfn, FOREIGN_FRAME(mfn)))) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               if (m2p_override)
+                       ret = m2p_add_override(mfn, pages[i], kmap_ops ?
+                                              &kmap_ops[i] : NULL);
                if (ret)
                        goto out;
        }
@@ -987,15 +1003,32 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
 
        return ret;
 }
+
+int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
+                   struct page **pages, unsigned int count)
+{
+       return __gnttab_map_refs(map_ops, NULL, pages, count, false);
+}
 EXPORT_SYMBOL_GPL(gnttab_map_refs);
 
-int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
+int gnttab_map_refs_userspace(struct gnttab_map_grant_ref *map_ops,
+                             struct gnttab_map_grant_ref *kmap_ops,
+                             struct page **pages, unsigned int count)
+{
+       return __gnttab_map_refs(map_ops, kmap_ops, pages, count, true);
+}
+EXPORT_SYMBOL_GPL(gnttab_map_refs_userspace);
+
+int __gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
                      struct gnttab_map_grant_ref *kmap_ops,
-                     struct page **pages, unsigned int count)
+                     struct page **pages, unsigned int count,
+                     bool m2p_override)
 {
        int i, ret;
        bool lazy = false;
+       unsigned long pfn, mfn;
 
+       BUG_ON(kmap_ops && !m2p_override);
        ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count);
        if (ret)
                return ret;
@@ -1006,17 +1039,33 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
                        set_phys_to_machine(unmap_ops[i].host_addr >> PAGE_SHIFT,
                                        INVALID_P2M_ENTRY);
                }
-               return ret;
+               return 0;
        }
 
-       if (!in_interrupt() && paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) {
+       if (m2p_override &&
+           !in_interrupt() &&
+           paravirt_get_lazy_mode() == PARAVIRT_LAZY_NONE) {
                arch_enter_lazy_mmu_mode();
                lazy = true;
        }
 
        for (i = 0; i < count; i++) {
-               ret = m2p_remove_override(pages[i], kmap_ops ?
-                                      &kmap_ops[i] : NULL);
+               pfn = page_to_pfn(pages[i]);
+               mfn = get_phys_to_machine(pfn);
+               if (mfn == INVALID_P2M_ENTRY || !(mfn & FOREIGN_FRAME_BIT)) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               set_page_private(pages[i], INVALID_P2M_ENTRY);
+               WARN_ON(!PagePrivate(pages[i]));
+               ClearPagePrivate(pages[i]);
+               set_phys_to_machine(pfn, pages[i]->index);
+               if (m2p_override)
+                       ret = m2p_remove_override(pages[i],
+                                                 kmap_ops ?
+                                                  &kmap_ops[i] : NULL,
+                                                 mfn);
                if (ret)
                        goto out;
        }
@@ -1027,8 +1076,22 @@ int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
 
        return ret;
 }
+
+int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *map_ops,
+                   struct page **pages, unsigned int count)
+{
+       return __gnttab_unmap_refs(map_ops, NULL, pages, count, false);
+}
 EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
 
+int gnttab_unmap_refs_userspace(struct gnttab_unmap_grant_ref *map_ops,
+                               struct gnttab_map_grant_ref *kmap_ops,
+                               struct page **pages, unsigned int count)
+{
+       return __gnttab_unmap_refs(map_ops, kmap_ops, pages, count, true);
+}
+EXPORT_SYMBOL_GPL(gnttab_unmap_refs_userspace);
+
 static unsigned nr_status_frames(unsigned nr_grant_frames)
 {
        BUG_ON(grefs_per_grant_frame == 0);
index 1eac0731c349f2067b42dea6e01f292453096d4b..ebd8f218a788b619f65438223cc85306e381caa7 100644 (file)
@@ -75,14 +75,32 @@ static unsigned long xen_io_tlb_nslabs;
 
 static u64 start_dma_addr;
 
+/*
+ * Both of these functions should avoid PFN_PHYS because phys_addr_t
+ * can be 32bit when dma_addr_t is 64bit leading to a loss in
+ * information if the shift is done before casting to 64bit.
+ */
 static inline dma_addr_t xen_phys_to_bus(phys_addr_t paddr)
 {
-       return phys_to_machine(XPADDR(paddr)).maddr;
+       unsigned long mfn = pfn_to_mfn(PFN_DOWN(paddr));
+       dma_addr_t dma = (dma_addr_t)mfn << PAGE_SHIFT;
+
+       dma |= paddr & ~PAGE_MASK;
+
+       return dma;
 }
 
 static inline phys_addr_t xen_bus_to_phys(dma_addr_t baddr)
 {
-       return machine_to_phys(XMADDR(baddr)).paddr;
+       unsigned long pfn = mfn_to_pfn(PFN_DOWN(baddr));
+       dma_addr_t dma = (dma_addr_t)pfn << PAGE_SHIFT;
+       phys_addr_t paddr = dma;
+
+       BUG_ON(paddr != dma); /* truncation has occurred, should never happen */
+
+       paddr |= baddr & ~PAGE_MASK;
+
+       return paddr;
 }
 
 static inline dma_addr_t xen_virt_to_bus(void *address)
index 21e18c18c7a17e6c1befc5f4447a0a814a8ab398..745ad79c1d8e3e85255717b470eb13aac44c4fcb 100644 (file)
@@ -175,6 +175,7 @@ static void frontswap_selfshrink(void)
 #endif /* CONFIG_FRONTSWAP */
 
 #define MB2PAGES(mb)   ((mb) << (20 - PAGE_SHIFT))
+#define PAGES2MB(pages) ((pages) >> (20 - PAGE_SHIFT))
 
 /*
  * Use current balloon size, the goal (vm_committed_as), and hysteresis
@@ -525,6 +526,7 @@ EXPORT_SYMBOL(register_xen_selfballooning);
 int xen_selfballoon_init(bool use_selfballooning, bool use_frontswap_selfshrink)
 {
        bool enable = false;
+       unsigned long reserve_pages;
 
        if (!xen_domain())
                return -ENODEV;
@@ -549,6 +551,26 @@ int xen_selfballoon_init(bool use_selfballooning, bool use_frontswap_selfshrink)
        if (!enable)
                return -ENODEV;
 
+       /*
+        * Give selfballoon_reserved_mb a default value(10% of total ram pages)
+        * to make selfballoon not so aggressive.
+        *
+        * There are mainly two reasons:
+        * 1) The original goal_page didn't consider some pages used by kernel
+        *    space, like slab pages and memory used by device drivers.
+        *
+        * 2) The balloon driver may not give back memory to guest OS fast
+        *    enough when the workload suddenly aquries a lot of physical memory.
+        *
+        * In both cases, the guest OS will suffer from memory pressure and
+        * OOM killer may be triggered.
+        * By reserving extra 10% of total ram pages, we can keep the system
+        * much more reliably and response faster in some cases.
+        */
+       if (!selfballoon_reserved_mb) {
+               reserve_pages = totalram_pages / 10;
+               selfballoon_reserved_mb = PAGES2MB(reserve_pages);
+       }
        schedule_delayed_work(&selfballoon_worker, selfballoon_interval * HZ);
 
        return 0;
index 7af425f53beef91a6d21dc86b76e161ff7ed1696..8482f2d1160667ba1255ee5b48434287bc51da65 100644 (file)
@@ -156,7 +156,7 @@ int v9fs_acl_chmod(struct inode *inode, struct p9_fid *fid)
                return -EOPNOTSUPP;
        acl = v9fs_get_cached_acl(inode, ACL_TYPE_ACCESS);
        if (acl) {
-               retval = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
+               retval = __posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
                if (retval)
                        return retval;
                set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
@@ -200,7 +200,7 @@ int v9fs_acl_mode(struct inode *dir, umode_t *modep,
        if (acl) {
                if (S_ISDIR(mode))
                        *dpacl = posix_acl_dup(acl);
-               retval = posix_acl_create(&acl, GFP_NOFS, &mode);
+               retval = __posix_acl_create(&acl, GFP_NOFS, &mode);
                if (retval < 0)
                        return retval;
                if (retval > 0)
index c229f828eb012ea32a13c306cf1953ae85e3ca2a..7385e54be4b9adbdd8a4c2d0ed3cafd3b516820a 100644 (file)
@@ -68,10 +68,6 @@ source "fs/quota/Kconfig"
 source "fs/autofs4/Kconfig"
 source "fs/fuse/Kconfig"
 
-config GENERIC_ACL
-       bool
-       select FS_POSIX_ACL
-
 menu "Caches"
 
 source "fs/fscache/Kconfig"
@@ -119,7 +115,7 @@ config TMPFS_POSIX_ACL
        bool "Tmpfs POSIX Access Control Lists"
        depends on TMPFS
        select TMPFS_XATTR
-       select GENERIC_ACL
+       select FS_POSIX_ACL
        help
          POSIX Access Control Lists (ACLs) support additional access rights
          for users and groups beyond the standard owner/group/world scheme,
index 39a824f44e7c17c807988ca970a2eefbe2113ece..47ac07bb4acc6b44b318776c44e7a6cd7bf79113 100644 (file)
@@ -42,9 +42,8 @@ obj-$(CONFIG_BINFMT_SOM)      += binfmt_som.o
 obj-$(CONFIG_BINFMT_FLAT)      += binfmt_flat.o
 
 obj-$(CONFIG_FS_MBCACHE)       += mbcache.o
-obj-$(CONFIG_FS_POSIX_ACL)     += posix_acl.o xattr_acl.o
+obj-$(CONFIG_FS_POSIX_ACL)     += posix_acl.o
 obj-$(CONFIG_NFS_COMMON)       += nfs_common/
-obj-$(CONFIG_GENERIC_ACL)      += generic_acl.o
 obj-$(CONFIG_COREDUMP)         += coredump.o
 obj-$(CONFIG_SYSCTL)           += drop_caches.o
 
index 45161a832bbc9e4aa2d7f6b72a950273e0af7062..d098731b82ffa794853e66ff0bcb4e05aa59fcbc 100644 (file)
@@ -49,11 +49,6 @@ affs_put_super(struct super_block *sb)
        pr_debug("AFFS: put_super()\n");
 
        cancel_delayed_work_sync(&sbi->sb_work);
-       kfree(sbi->s_prefix);
-       affs_free_bitmap(sb);
-       affs_brelse(sbi->s_root_bh);
-       kfree(sbi);
-       sb->s_fs_info = NULL;
 }
 
 static int
@@ -316,7 +311,7 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
        unsigned long            mount_flags;
        int                      tmp_flags;     /* fix remount prototype... */
        u8                       sig[4];
-       int                      ret = -EINVAL;
+       int                      ret;
 
        save_mount_options(sb, data);
 
@@ -412,17 +407,19 @@ static int affs_fill_super(struct super_block *sb, void *data, int silent)
        if (!silent)
                printk(KERN_ERR "AFFS: No valid root block on device %s\n",
                        sb->s_id);
-       goto out_error;
+       return -EINVAL;
 
        /* N.B. after this point bh must be released */
 got_root:
+       /* Keep super block in cache */
+       sbi->s_root_bh = root_bh;
        root_block = sbi->s_root_block;
 
        /* Find out which kind of FS we have */
        boot_bh = sb_bread(sb, 0);
        if (!boot_bh) {
                printk(KERN_ERR "AFFS: Cannot read boot block\n");
-               goto out_error;
+               return -EINVAL;
        }
        memcpy(sig, boot_bh->b_data, 4);
        brelse(boot_bh);
@@ -471,7 +468,7 @@ got_root:
                default:
                        printk(KERN_ERR "AFFS: Unknown filesystem on device %s: %08X\n",
                                sb->s_id, chksum);
-                       goto out_error;
+                       return -EINVAL;
        }
 
        if (mount_flags & SF_VERBOSE) {
@@ -488,22 +485,17 @@ got_root:
        if (sbi->s_flags & SF_OFS)
                sbi->s_data_blksize -= 24;
 
-       /* Keep super block in cache */
-       sbi->s_root_bh = root_bh;
-       /* N.B. after this point s_root_bh must be released */
-
        tmp_flags = sb->s_flags;
-       if (affs_init_bitmap(sb, &tmp_flags))
-               goto out_error;
+       ret = affs_init_bitmap(sb, &tmp_flags);
+       if (ret)
+               return ret;
        sb->s_flags = tmp_flags;
 
        /* set up enough so that it can read an inode */
 
        root_inode = affs_iget(sb, root_block);
-       if (IS_ERR(root_inode)) {
-               ret = PTR_ERR(root_inode);
-               goto out_error;
-       }
+       if (IS_ERR(root_inode))
+               return PTR_ERR(root_inode);
 
        if (AFFS_SB(sb)->s_flags & SF_INTL)
                sb->s_d_op = &affs_intl_dentry_operations;
@@ -513,22 +505,11 @@ got_root:
        sb->s_root = d_make_root(root_inode);
        if (!sb->s_root) {
                printk(KERN_ERR "AFFS: Get root inode failed\n");
-               goto out_error;
+               return -ENOMEM;
        }
 
        pr_debug("AFFS: s_flags=%lX\n",sb->s_flags);
        return 0;
-
-       /*
-        * Begin the cascaded cleanup ...
-        */
-out_error:
-       kfree(sbi->s_bitmap);
-       affs_brelse(root_bh);
-       kfree(sbi->s_prefix);
-       kfree(sbi);
-       sb->s_fs_info = NULL;
-       return ret;
 }
 
 static int
@@ -615,11 +596,23 @@ static struct dentry *affs_mount(struct file_system_type *fs_type,
        return mount_bdev(fs_type, flags, dev_name, data, affs_fill_super);
 }
 
+static void affs_kill_sb(struct super_block *sb)
+{
+       struct affs_sb_info *sbi = AFFS_SB(sb);
+       kill_block_super(sb);
+       if (sbi) {
+               affs_free_bitmap(sb);
+               affs_brelse(sbi->s_root_bh);
+               kfree(sbi->s_prefix);
+               kfree(sbi);
+       }
+}
+
 static struct file_system_type affs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "affs",
        .mount          = affs_mount,
-       .kill_sb        = kill_block_super,
+       .kill_sb        = affs_kill_sb,
        .fs_flags       = FS_REQUIRES_DEV,
 };
 MODULE_ALIAS_FS("affs");
index a306bb6d88d9937badc2a1df1462d3bb0f469829..6621f800812287f6f0fc27cdc7f71a2a32287af2 100644 (file)
@@ -195,7 +195,6 @@ struct afs_cell {
        struct list_head        link;           /* main cell list link */
        struct key              *anonymous_key; /* anonymous user key for this cell */
        struct list_head        proc_link;      /* /proc cell list link */
-       struct proc_dir_entry   *proc_dir;      /* /proc dir for this cell */
 #ifdef CONFIG_AFS_FSCACHE
        struct fscache_cookie   *cache;         /* caching cookie */
 #endif
index 526e4bbbde59e4936f91367101adac8c7373053e..bddc5120ed4089caa19bef3c2420725c63ef7f37 100644 (file)
@@ -41,11 +41,8 @@ static const struct file_operations afs_proc_cells_fops = {
        .write          = afs_proc_cells_write,
        .llseek         = seq_lseek,
        .release        = seq_release,
-       .owner          = THIS_MODULE,
 };
 
-static int afs_proc_rootcell_open(struct inode *inode, struct file *file);
-static int afs_proc_rootcell_release(struct inode *inode, struct file *file);
 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
                                      size_t size, loff_t *_pos);
 static ssize_t afs_proc_rootcell_write(struct file *file,
@@ -53,17 +50,12 @@ static ssize_t afs_proc_rootcell_write(struct file *file,
                                       size_t size, loff_t *_pos);
 
 static const struct file_operations afs_proc_rootcell_fops = {
-       .open           = afs_proc_rootcell_open,
        .read           = afs_proc_rootcell_read,
        .write          = afs_proc_rootcell_write,
        .llseek         = no_llseek,
-       .release        = afs_proc_rootcell_release,
-       .owner          = THIS_MODULE,
 };
 
 static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
-static int afs_proc_cell_volumes_release(struct inode *inode,
-                                        struct file *file);
 static void *afs_proc_cell_volumes_start(struct seq_file *p, loff_t *pos);
 static void *afs_proc_cell_volumes_next(struct seq_file *p, void *v,
                                        loff_t *pos);
@@ -81,14 +73,11 @@ static const struct file_operations afs_proc_cell_volumes_fops = {
        .open           = afs_proc_cell_volumes_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = afs_proc_cell_volumes_release,
-       .owner          = THIS_MODULE,
+       .release        = seq_release,
 };
 
 static int afs_proc_cell_vlservers_open(struct inode *inode,
                                        struct file *file);
-static int afs_proc_cell_vlservers_release(struct inode *inode,
-                                          struct file *file);
 static void *afs_proc_cell_vlservers_start(struct seq_file *p, loff_t *pos);
 static void *afs_proc_cell_vlservers_next(struct seq_file *p, void *v,
                                          loff_t *pos);
@@ -106,13 +95,10 @@ static const struct file_operations afs_proc_cell_vlservers_fops = {
        .open           = afs_proc_cell_vlservers_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = afs_proc_cell_vlservers_release,
-       .owner          = THIS_MODULE,
+       .release        = seq_release,
 };
 
 static int afs_proc_cell_servers_open(struct inode *inode, struct file *file);
-static int afs_proc_cell_servers_release(struct inode *inode,
-                                        struct file *file);
 static void *afs_proc_cell_servers_start(struct seq_file *p, loff_t *pos);
 static void *afs_proc_cell_servers_next(struct seq_file *p, void *v,
                                        loff_t *pos);
@@ -130,8 +116,7 @@ static const struct file_operations afs_proc_cell_servers_fops = {
        .open           = afs_proc_cell_servers_open,
        .read           = seq_read,
        .llseek         = seq_lseek,
-       .release        = afs_proc_cell_servers_release,
-       .owner          = THIS_MODULE,
+       .release        = seq_release,
 };
 
 /*
@@ -139,29 +124,21 @@ static const struct file_operations afs_proc_cell_servers_fops = {
  */
 int afs_proc_init(void)
 {
-       struct proc_dir_entry *p;
-
        _enter("");
 
        proc_afs = proc_mkdir("fs/afs", NULL);
        if (!proc_afs)
                goto error_dir;
 
-       p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops);
-       if (!p)
-               goto error_cells;
-
-       p = proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops);
-       if (!p)
-               goto error_rootcell;
+       if (!proc_create("cells", 0, proc_afs, &afs_proc_cells_fops) ||
+           !proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops))
+               goto error_tree;
 
        _leave(" = 0");
        return 0;
 
-error_rootcell:
-       remove_proc_entry("cells", proc_afs);
-error_cells:
-       remove_proc_entry("fs/afs", NULL);
+error_tree:
+       remove_proc_subtree("fs/afs", NULL);
 error_dir:
        _leave(" = -ENOMEM");
        return -ENOMEM;
@@ -172,9 +149,7 @@ error_dir:
  */
 void afs_proc_cleanup(void)
 {
-       remove_proc_entry("rootcell", proc_afs);
-       remove_proc_entry("cells", proc_afs);
-       remove_proc_entry("fs/afs", NULL);
+       remove_proc_subtree("fs/afs", NULL);
 }
 
 /*
@@ -319,19 +294,6 @@ inval:
        goto done;
 }
 
-/*
- * Stubs for /proc/fs/afs/rootcell
- */
-static int afs_proc_rootcell_open(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
-static int afs_proc_rootcell_release(struct inode *inode, struct file *file)
-{
-       return 0;
-}
-
 static ssize_t afs_proc_rootcell_read(struct file *file, char __user *buf,
                                      size_t size, loff_t *_pos)
 {
@@ -387,38 +349,27 @@ nomem:
  */
 int afs_proc_cell_setup(struct afs_cell *cell)
 {
-       struct proc_dir_entry *p;
+       struct proc_dir_entry *dir;
 
        _enter("%p{%s}", cell, cell->name);
 
-       cell->proc_dir = proc_mkdir(cell->name, proc_afs);
-       if (!cell->proc_dir)
+       dir = proc_mkdir(cell->name, proc_afs);
+       if (!dir)
                goto error_dir;
 
-       p = proc_create_data("servers", 0, cell->proc_dir,
-                            &afs_proc_cell_servers_fops, cell);
-       if (!p)
-               goto error_servers;
-
-       p = proc_create_data("vlservers", 0, cell->proc_dir,
-                            &afs_proc_cell_vlservers_fops, cell);
-       if (!p)
-               goto error_vlservers;
-
-       p = proc_create_data("volumes", 0, cell->proc_dir,
-                            &afs_proc_cell_volumes_fops, cell);
-       if (!p)
-               goto error_volumes;
+       if (!proc_create_data("servers", 0, dir,
+                            &afs_proc_cell_servers_fops, cell) ||
+           !proc_create_data("vlservers", 0, dir,
+                            &afs_proc_cell_vlservers_fops, cell) ||
+           !proc_create_data("volumes", 0, dir,
+                            &afs_proc_cell_volumes_fops, cell))
+               goto error_tree;
 
        _leave(" = 0");
        return 0;
 
-error_volumes:
-       remove_proc_entry("vlservers", cell->proc_dir);
-error_vlservers:
-       remove_proc_entry("servers", cell->proc_dir);
-error_servers:
-       remove_proc_entry(cell->name, proc_afs);
+error_tree:
+       remove_proc_subtree(cell->name, proc_afs);
 error_dir:
        _leave(" = -ENOMEM");
        return -ENOMEM;
@@ -431,10 +382,7 @@ void afs_proc_cell_remove(struct afs_cell *cell)
 {
        _enter("");
 
-       remove_proc_entry("volumes", cell->proc_dir);
-       remove_proc_entry("vlservers", cell->proc_dir);
-       remove_proc_entry("servers", cell->proc_dir);
-       remove_proc_entry(cell->name, proc_afs);
+       remove_proc_subtree(cell->name, proc_afs);
 
        _leave("");
 }
@@ -462,14 +410,6 @@ static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-/*
- * close the file and release the ref to the cell
- */
-static int afs_proc_cell_volumes_release(struct inode *inode, struct file *file)
-{
-       return seq_release(inode, file);
-}
-
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -568,15 +508,6 @@ static int afs_proc_cell_vlservers_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-/*
- * close the file and release the ref to the cell
- */
-static int afs_proc_cell_vlservers_release(struct inode *inode,
-                                          struct file *file)
-{
-       return seq_release(inode, file);
-}
-
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
@@ -672,15 +603,6 @@ static int afs_proc_cell_servers_open(struct inode *inode, struct file *file)
        return 0;
 }
 
-/*
- * close the file and release the ref to the cell
- */
-static int afs_proc_cell_servers_release(struct inode *inode,
-                                        struct file *file)
-{
-       return seq_release(inode, file);
-}
-
 /*
  * set up the iterator to start reading from the cells list and return the
  * first item
index daa15d6ba45077755d2bc859cfffb44f6a82bfd0..845d2d690ce2dc2becddef70041a3e6b69440d62 100644 (file)
@@ -324,8 +324,8 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
        befs_debug(sb, "---> befs_read_inode() " "inode = %lu", ino);
 
        inode = iget_locked(sb, ino);
-       if (IS_ERR(inode))
-               return inode;
+       if (!inode)
+               return ERR_PTR(-ENOMEM);
        if (!(inode->i_state & I_NEW))
                return inode;
 
index fc60b31453eefbbdcc234c7df78c5504da655980..0bad24ddc2e7a39abf29547f24173cc050017d15 100644 (file)
@@ -134,8 +134,7 @@ int bio_integrity_add_page(struct bio *bio, struct page *page,
                return 0;
        }
 
-       iv = bip_vec_idx(bip, bip->bip_vcnt);
-       BUG_ON(iv == NULL);
+       iv = bip->bip_vec + bip->bip_vcnt;
 
        iv->bv_page = page;
        iv->bv_len = len;
@@ -203,6 +202,12 @@ static inline unsigned int bio_integrity_hw_sectors(struct blk_integrity *bi,
        return sectors;
 }
 
+static inline unsigned int bio_integrity_bytes(struct blk_integrity *bi,
+                                              unsigned int sectors)
+{
+       return bio_integrity_hw_sectors(bi, sectors) * bi->tuple_size;
+}
+
 /**
  * bio_integrity_tag_size - Retrieve integrity tag space
  * @bio:       bio to inspect
@@ -215,9 +220,9 @@ unsigned int bio_integrity_tag_size(struct bio *bio)
 {
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
 
-       BUG_ON(bio->bi_size == 0);
+       BUG_ON(bio->bi_iter.bi_size == 0);
 
-       return bi->tag_size * (bio->bi_size / bi->sector_size);
+       return bi->tag_size * (bio->bi_iter.bi_size / bi->sector_size);
 }
 EXPORT_SYMBOL(bio_integrity_tag_size);
 
@@ -235,9 +240,9 @@ int bio_integrity_tag(struct bio *bio, void *tag_buf, unsigned int len, int set)
        nr_sectors = bio_integrity_hw_sectors(bi,
                                        DIV_ROUND_UP(len, bi->tag_size));
 
-       if (nr_sectors * bi->tuple_size > bip->bip_size) {
-               printk(KERN_ERR "%s: tag too big for bio: %u > %u\n",
-                      __func__, nr_sectors * bi->tuple_size, bip->bip_size);
+       if (nr_sectors * bi->tuple_size > bip->bip_iter.bi_size) {
+               printk(KERN_ERR "%s: tag too big for bio: %u > %u\n", __func__,
+                      nr_sectors * bi->tuple_size, bip->bip_iter.bi_size);
                return -1;
        }
 
@@ -299,29 +304,30 @@ static void bio_integrity_generate(struct bio *bio)
 {
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
        struct blk_integrity_exchg bix;
-       struct bio_vec *bv;
-       sector_t sector = bio->bi_sector;
-       unsigned int i, sectors, total;
+       struct bio_vec bv;
+       struct bvec_iter iter;
+       sector_t sector = bio->bi_iter.bi_sector;
+       unsigned int sectors, total;
        void *prot_buf = bio->bi_integrity->bip_buf;
 
        total = 0;
        bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
        bix.sector_size = bi->sector_size;
 
-       bio_for_each_segment(bv, bio, i) {
-               void *kaddr = kmap_atomic(bv->bv_page);
-               bix.data_buf = kaddr + bv->bv_offset;
-               bix.data_size = bv->bv_len;
+       bio_for_each_segment(bv, bio, iter) {
+               void *kaddr = kmap_atomic(bv.bv_page);
+               bix.data_buf = kaddr + bv.bv_offset;
+               bix.data_size = bv.bv_len;
                bix.prot_buf = prot_buf;
                bix.sector = sector;
 
                bi->generate_fn(&bix);
 
-               sectors = bv->bv_len / bi->sector_size;
+               sectors = bv.bv_len / bi->sector_size;
                sector += sectors;
                prot_buf += sectors * bi->tuple_size;
                total += sectors * bi->tuple_size;
-               BUG_ON(total > bio->bi_integrity->bip_size);
+               BUG_ON(total > bio->bi_integrity->bip_iter.bi_size);
 
                kunmap_atomic(kaddr);
        }
@@ -386,8 +392,8 @@ int bio_integrity_prep(struct bio *bio)
 
        bip->bip_owns_buf = 1;
        bip->bip_buf = buf;
-       bip->bip_size = len;
-       bip->bip_sector = bio->bi_sector;
+       bip->bip_iter.bi_size = len;
+       bip->bip_iter.bi_sector = bio->bi_iter.bi_sector;
 
        /* Map it */
        offset = offset_in_page(buf);
@@ -442,16 +448,18 @@ static int bio_integrity_verify(struct bio *bio)
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
        struct blk_integrity_exchg bix;
        struct bio_vec *bv;
-       sector_t sector = bio->bi_integrity->bip_sector;
-       unsigned int i, sectors, total, ret;
+       sector_t sector = bio->bi_integrity->bip_iter.bi_sector;
+       unsigned int sectors, total, ret;
        void *prot_buf = bio->bi_integrity->bip_buf;
+       int i;
 
        ret = total = 0;
        bix.disk_name = bio->bi_bdev->bd_disk->disk_name;
        bix.sector_size = bi->sector_size;
 
-       bio_for_each_segment(bv, bio, i) {
+       bio_for_each_segment_all(bv, bio, i) {
                void *kaddr = kmap_atomic(bv->bv_page);
+
                bix.data_buf = kaddr + bv->bv_offset;
                bix.data_size = bv->bv_len;
                bix.prot_buf = prot_buf;
@@ -468,7 +476,7 @@ static int bio_integrity_verify(struct bio *bio)
                sector += sectors;
                prot_buf += sectors * bi->tuple_size;
                total += sectors * bi->tuple_size;
-               BUG_ON(total > bio->bi_integrity->bip_size);
+               BUG_ON(total > bio->bi_integrity->bip_iter.bi_size);
 
                kunmap_atomic(kaddr);
        }
@@ -495,7 +503,7 @@ static void bio_integrity_verify_fn(struct work_struct *work)
 
        /* Restore original bio completion handler */
        bio->bi_end_io = bip->bip_end_io;
-       bio_endio(bio, error);
+       bio_endio_nodec(bio, error);
 }
 
 /**
@@ -532,56 +540,6 @@ void bio_integrity_endio(struct bio *bio, int error)
 }
 EXPORT_SYMBOL(bio_integrity_endio);
 
-/**
- * bio_integrity_mark_head - Advance bip_vec skip bytes
- * @bip:       Integrity vector to advance
- * @skip:      Number of bytes to advance it
- */
-void bio_integrity_mark_head(struct bio_integrity_payload *bip,
-                            unsigned int skip)
-{
-       struct bio_vec *iv;
-       unsigned int i;
-
-       bip_for_each_vec(iv, bip, i) {
-               if (skip == 0) {
-                       bip->bip_idx = i;
-                       return;
-               } else if (skip >= iv->bv_len) {
-                       skip -= iv->bv_len;
-               } else { /* skip < iv->bv_len) */
-                       iv->bv_offset += skip;
-                       iv->bv_len -= skip;
-                       bip->bip_idx = i;
-                       return;
-               }
-       }
-}
-
-/**
- * bio_integrity_mark_tail - Truncate bip_vec to be len bytes long
- * @bip:       Integrity vector to truncate
- * @len:       New length of integrity vector
- */
-void bio_integrity_mark_tail(struct bio_integrity_payload *bip,
-                            unsigned int len)
-{
-       struct bio_vec *iv;
-       unsigned int i;
-
-       bip_for_each_vec(iv, bip, i) {
-               if (len == 0) {
-                       bip->bip_vcnt = i;
-                       return;
-               } else if (len >= iv->bv_len) {
-                       len -= iv->bv_len;
-               } else { /* len < iv->bv_len) */
-                       iv->bv_len = len;
-                       len = 0;
-               }
-       }
-}
-
 /**
  * bio_integrity_advance - Advance integrity vector
  * @bio:       bio whose integrity vector to update
@@ -595,13 +553,9 @@ void bio_integrity_advance(struct bio *bio, unsigned int bytes_done)
 {
        struct bio_integrity_payload *bip = bio->bi_integrity;
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
-       unsigned int nr_sectors;
+       unsigned bytes = bio_integrity_bytes(bi, bytes_done >> 9);
 
-       BUG_ON(bip == NULL);
-       BUG_ON(bi == NULL);
-
-       nr_sectors = bio_integrity_hw_sectors(bi, bytes_done >> 9);
-       bio_integrity_mark_head(bip, nr_sectors * bi->tuple_size);
+       bvec_iter_advance(bip->bip_vec, &bip->bip_iter, bytes);
 }
 EXPORT_SYMBOL(bio_integrity_advance);
 
@@ -621,63 +575,12 @@ void bio_integrity_trim(struct bio *bio, unsigned int offset,
 {
        struct bio_integrity_payload *bip = bio->bi_integrity;
        struct blk_integrity *bi = bdev_get_integrity(bio->bi_bdev);
-       unsigned int nr_sectors;
-
-       BUG_ON(bip == NULL);
-       BUG_ON(bi == NULL);
-       BUG_ON(!bio_flagged(bio, BIO_CLONED));
 
-       nr_sectors = bio_integrity_hw_sectors(bi, sectors);
-       bip->bip_sector = bip->bip_sector + offset;
-       bio_integrity_mark_head(bip, offset * bi->tuple_size);
-       bio_integrity_mark_tail(bip, sectors * bi->tuple_size);
+       bio_integrity_advance(bio, offset << 9);
+       bip->bip_iter.bi_size = bio_integrity_bytes(bi, sectors);
 }
 EXPORT_SYMBOL(bio_integrity_trim);
 
-/**
- * bio_integrity_split - Split integrity metadata
- * @bio:       Protected bio
- * @bp:                Resulting bio_pair
- * @sectors:   Offset
- *
- * Description: Splits an integrity page into a bio_pair.
- */
-void bio_integrity_split(struct bio *bio, struct bio_pair *bp, int sectors)
-{
-       struct blk_integrity *bi;
-       struct bio_integrity_payload *bip = bio->bi_integrity;
-       unsigned int nr_sectors;
-
-       if (bio_integrity(bio) == 0)
-               return;
-
-       bi = bdev_get_integrity(bio->bi_bdev);
-       BUG_ON(bi == NULL);
-       BUG_ON(bip->bip_vcnt != 1);
-
-       nr_sectors = bio_integrity_hw_sectors(bi, sectors);
-
-       bp->bio1.bi_integrity = &bp->bip1;
-       bp->bio2.bi_integrity = &bp->bip2;
-
-       bp->iv1 = bip->bip_vec[bip->bip_idx];
-       bp->iv2 = bip->bip_vec[bip->bip_idx];
-
-       bp->bip1.bip_vec = &bp->iv1;
-       bp->bip2.bip_vec = &bp->iv2;
-
-       bp->iv1.bv_len = sectors * bi->tuple_size;
-       bp->iv2.bv_offset += sectors * bi->tuple_size;
-       bp->iv2.bv_len -= sectors * bi->tuple_size;
-
-       bp->bip1.bip_sector = bio->bi_integrity->bip_sector;
-       bp->bip2.bip_sector = bio->bi_integrity->bip_sector + nr_sectors;
-
-       bp->bip1.bip_vcnt = bp->bip2.bip_vcnt = 1;
-       bp->bip1.bip_idx = bp->bip2.bip_idx = 0;
-}
-EXPORT_SYMBOL(bio_integrity_split);
-
 /**
  * bio_integrity_clone - Callback for cloning bios with integrity metadata
  * @bio:       New bio
@@ -702,9 +605,8 @@ int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
        memcpy(bip->bip_vec, bip_src->bip_vec,
               bip_src->bip_vcnt * sizeof(struct bio_vec));
 
-       bip->bip_sector = bip_src->bip_sector;
        bip->bip_vcnt = bip_src->bip_vcnt;
-       bip->bip_idx = bip_src->bip_idx;
+       bip->bip_iter = bip_src->bip_iter;
 
        return 0;
 }
index 33d79a4eb92d6e623aa90e2291af39b2b2689d83..75c49a38223969c1f7256868cb3b09fc7d3bd286 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -38,8 +38,6 @@
  */
 #define BIO_INLINE_VECS                4
 
-static mempool_t *bio_split_pool __read_mostly;
-
 /*
  * if you change this list, also change bvec_alloc or things will
  * break badly! cannot be bigger than what you can fit into an
@@ -273,6 +271,7 @@ void bio_init(struct bio *bio)
 {
        memset(bio, 0, sizeof(*bio));
        bio->bi_flags = 1 << BIO_UPTODATE;
+       atomic_set(&bio->bi_remaining, 1);
        atomic_set(&bio->bi_cnt, 1);
 }
 EXPORT_SYMBOL(bio_init);
@@ -295,9 +294,35 @@ void bio_reset(struct bio *bio)
 
        memset(bio, 0, BIO_RESET_BYTES);
        bio->bi_flags = flags|(1 << BIO_UPTODATE);
+       atomic_set(&bio->bi_remaining, 1);
 }
 EXPORT_SYMBOL(bio_reset);
 
+static void bio_chain_endio(struct bio *bio, int error)
+{
+       bio_endio(bio->bi_private, error);
+       bio_put(bio);
+}
+
+/**
+ * bio_chain - chain bio completions
+ *
+ * The caller won't have a bi_end_io called when @bio completes - instead,
+ * @parent's bi_end_io won't be called until both @parent and @bio have
+ * completed; the chained bio will also be freed when it completes.
+ *
+ * The caller must not set bi_private or bi_end_io in @bio.
+ */
+void bio_chain(struct bio *bio, struct bio *parent)
+{
+       BUG_ON(bio->bi_private || bio->bi_end_io);
+
+       bio->bi_private = parent;
+       bio->bi_end_io  = bio_chain_endio;
+       atomic_inc(&parent->bi_remaining);
+}
+EXPORT_SYMBOL(bio_chain);
+
 static void bio_alloc_rescue(struct work_struct *work)
 {
        struct bio_set *bs = container_of(work, struct bio_set, rescue_work);
@@ -473,13 +498,13 @@ EXPORT_SYMBOL(bio_alloc_bioset);
 void zero_fill_bio(struct bio *bio)
 {
        unsigned long flags;
-       struct bio_vec *bv;
-       int i;
+       struct bio_vec bv;
+       struct bvec_iter iter;
 
-       bio_for_each_segment(bv, bio, i) {
-               char *data = bvec_kmap_irq(bv, &flags);
-               memset(data, 0, bv->bv_len);
-               flush_dcache_page(bv->bv_page);
+       bio_for_each_segment(bv, bio, iter) {
+               char *data = bvec_kmap_irq(&bv, &flags);
+               memset(data, 0, bv.bv_len);
+               flush_dcache_page(bv.bv_page);
                bvec_kunmap_irq(data, &flags);
        }
 }
@@ -515,51 +540,49 @@ inline int bio_phys_segments(struct request_queue *q, struct bio *bio)
 EXPORT_SYMBOL(bio_phys_segments);
 
 /**
- *     __bio_clone     -       clone a bio
+ *     __bio_clone_fast - clone a bio that shares the original bio's biovec
  *     @bio: destination bio
  *     @bio_src: bio to clone
  *
  *     Clone a &bio. Caller will own the returned bio, but not
  *     the actual data it points to. Reference count of returned
  *     bio will be one.
+ *
+ *     Caller must ensure that @bio_src is not freed before @bio.
  */
-void __bio_clone(struct bio *bio, struct bio *bio_src)
+void __bio_clone_fast(struct bio *bio, struct bio *bio_src)
 {
-       memcpy(bio->bi_io_vec, bio_src->bi_io_vec,
-               bio_src->bi_max_vecs * sizeof(struct bio_vec));
+       BUG_ON(bio->bi_pool && BIO_POOL_IDX(bio) != BIO_POOL_NONE);
 
        /*
         * most users will be overriding ->bi_bdev with a new target,
         * so we don't set nor calculate new physical/hw segment counts here
         */
-       bio->bi_sector = bio_src->bi_sector;
        bio->bi_bdev = bio_src->bi_bdev;
        bio->bi_flags |= 1 << BIO_CLONED;
        bio->bi_rw = bio_src->bi_rw;
-       bio->bi_vcnt = bio_src->bi_vcnt;
-       bio->bi_size = bio_src->bi_size;
-       bio->bi_idx = bio_src->bi_idx;
+       bio->bi_iter = bio_src->bi_iter;
+       bio->bi_io_vec = bio_src->bi_io_vec;
 }
-EXPORT_SYMBOL(__bio_clone);
+EXPORT_SYMBOL(__bio_clone_fast);
 
 /**
- *     bio_clone_bioset -      clone a bio
+ *     bio_clone_fast - clone a bio that shares the original bio's biovec
  *     @bio: bio to clone
  *     @gfp_mask: allocation priority
  *     @bs: bio_set to allocate from
  *
- *     Like __bio_clone, only also allocates the returned bio
+ *     Like __bio_clone_fast, only also allocates the returned bio
  */
-struct bio *bio_clone_bioset(struct bio *bio, gfp_t gfp_mask,
-                            struct bio_set *bs)
+struct bio *bio_clone_fast(struct bio *bio, gfp_t gfp_mask, struct bio_set *bs)
 {
        struct bio *b;
 
-       b = bio_alloc_bioset(gfp_mask, bio->bi_max_vecs, bs);
+       b = bio_alloc_bioset(gfp_mask, 0, bs);
        if (!b)
                return NULL;
 
-       __bio_clone(b, bio);
+       __bio_clone_fast(b, bio);
 
        if (bio_integrity(bio)) {
                int ret;
@@ -574,6 +597,74 @@ struct bio *bio_clone_bioset(struct bio *bio, gfp_t gfp_mask,
 
        return b;
 }
+EXPORT_SYMBOL(bio_clone_fast);
+
+/**
+ *     bio_clone_bioset - clone a bio
+ *     @bio_src: bio to clone
+ *     @gfp_mask: allocation priority
+ *     @bs: bio_set to allocate from
+ *
+ *     Clone bio. Caller will own the returned bio, but not the actual data it
+ *     points to. Reference count of returned bio will be one.
+ */
+struct bio *bio_clone_bioset(struct bio *bio_src, gfp_t gfp_mask,
+                            struct bio_set *bs)
+{
+       unsigned nr_iovecs = 0;
+       struct bvec_iter iter;
+       struct bio_vec bv;
+       struct bio *bio;
+
+       /*
+        * Pre immutable biovecs, __bio_clone() used to just do a memcpy from
+        * bio_src->bi_io_vec to bio->bi_io_vec.
+        *
+        * We can't do that anymore, because:
+        *
+        *  - The point of cloning the biovec is to produce a bio with a biovec
+        *    the caller can modify: bi_idx and bi_bvec_done should be 0.
+        *
+        *  - The original bio could've had more than BIO_MAX_PAGES biovecs; if
+        *    we tried to clone the whole thing bio_alloc_bioset() would fail.
+        *    But the clone should succeed as long as the number of biovecs we
+        *    actually need to allocate is fewer than BIO_MAX_PAGES.
+        *
+        *  - Lastly, bi_vcnt should not be looked at or relied upon by code
+        *    that does not own the bio - reason being drivers don't use it for
+        *    iterating over the biovec anymore, so expecting it to be kept up
+        *    to date (i.e. for clones that share the parent biovec) is just
+        *    asking for trouble and would force extra work on
+        *    __bio_clone_fast() anyways.
+        */
+
+       bio_for_each_segment(bv, bio_src, iter)
+               nr_iovecs++;
+
+       bio = bio_alloc_bioset(gfp_mask, nr_iovecs, bs);
+       if (!bio)
+               return NULL;
+
+       bio->bi_bdev            = bio_src->bi_bdev;
+       bio->bi_rw              = bio_src->bi_rw;
+       bio->bi_iter.bi_sector  = bio_src->bi_iter.bi_sector;
+       bio->bi_iter.bi_size    = bio_src->bi_iter.bi_size;
+
+       bio_for_each_segment(bv, bio_src, iter)
+               bio->bi_io_vec[bio->bi_vcnt++] = bv;
+
+       if (bio_integrity(bio_src)) {
+               int ret;
+
+               ret = bio_integrity_clone(bio, bio_src, gfp_mask);
+               if (ret < 0) {
+                       bio_put(bio);
+                       return NULL;
+               }
+       }
+
+       return bio;
+}
 EXPORT_SYMBOL(bio_clone_bioset);
 
 /**
@@ -612,7 +703,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
        if (unlikely(bio_flagged(bio, BIO_CLONED)))
                return 0;
 
-       if (((bio->bi_size + len) >> 9) > max_sectors)
+       if (((bio->bi_iter.bi_size + len) >> 9) > max_sectors)
                return 0;
 
        /*
@@ -635,8 +726,9 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
                                           simulate merging updated prev_bvec
                                           as new bvec. */
                                        .bi_bdev = bio->bi_bdev,
-                                       .bi_sector = bio->bi_sector,
-                                       .bi_size = bio->bi_size - prev_bv_len,
+                                       .bi_sector = bio->bi_iter.bi_sector,
+                                       .bi_size = bio->bi_iter.bi_size -
+                                               prev_bv_len,
                                        .bi_rw = bio->bi_rw,
                                };
 
@@ -684,8 +776,8 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
        if (q->merge_bvec_fn) {
                struct bvec_merge_data bvm = {
                        .bi_bdev = bio->bi_bdev,
-                       .bi_sector = bio->bi_sector,
-                       .bi_size = bio->bi_size,
+                       .bi_sector = bio->bi_iter.bi_sector,
+                       .bi_size = bio->bi_iter.bi_size,
                        .bi_rw = bio->bi_rw,
                };
 
@@ -708,7 +800,7 @@ static int __bio_add_page(struct request_queue *q, struct bio *bio, struct page
        bio->bi_vcnt++;
        bio->bi_phys_segments++;
  done:
-       bio->bi_size += len;
+       bio->bi_iter.bi_size += len;
        return len;
 }
 
@@ -807,28 +899,7 @@ void bio_advance(struct bio *bio, unsigned bytes)
        if (bio_integrity(bio))
                bio_integrity_advance(bio, bytes);
 
-       bio->bi_sector += bytes >> 9;
-       bio->bi_size -= bytes;
-
-       if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK)
-               return;
-
-       while (bytes) {
-               if (unlikely(bio->bi_idx >= bio->bi_vcnt)) {
-                       WARN_ONCE(1, "bio idx %d >= vcnt %d\n",
-                                 bio->bi_idx, bio->bi_vcnt);
-                       break;
-               }
-
-               if (bytes >= bio_iovec(bio)->bv_len) {
-                       bytes -= bio_iovec(bio)->bv_len;
-                       bio->bi_idx++;
-               } else {
-                       bio_iovec(bio)->bv_len -= bytes;
-                       bio_iovec(bio)->bv_offset += bytes;
-                       bytes = 0;
-               }
-       }
+       bio_advance_iter(bio, &bio->bi_iter, bytes);
 }
 EXPORT_SYMBOL(bio_advance);
 
@@ -874,117 +945,80 @@ EXPORT_SYMBOL(bio_alloc_pages);
  */
 void bio_copy_data(struct bio *dst, struct bio *src)
 {
-       struct bio_vec *src_bv, *dst_bv;
-       unsigned src_offset, dst_offset, bytes;
+       struct bvec_iter src_iter, dst_iter;
+       struct bio_vec src_bv, dst_bv;
        void *src_p, *dst_p;
+       unsigned bytes;
 
-       src_bv = bio_iovec(src);
-       dst_bv = bio_iovec(dst);
-
-       src_offset = src_bv->bv_offset;
-       dst_offset = dst_bv->bv_offset;
+       src_iter = src->bi_iter;
+       dst_iter = dst->bi_iter;
 
        while (1) {
-               if (src_offset == src_bv->bv_offset + src_bv->bv_len) {
-                       src_bv++;
-                       if (src_bv == bio_iovec_idx(src, src->bi_vcnt)) {
-                               src = src->bi_next;
-                               if (!src)
-                                       break;
-
-                               src_bv = bio_iovec(src);
-                       }
+               if (!src_iter.bi_size) {
+                       src = src->bi_next;
+                       if (!src)
+                               break;
 
-                       src_offset = src_bv->bv_offset;
+                       src_iter = src->bi_iter;
                }
 
-               if (dst_offset == dst_bv->bv_offset + dst_bv->bv_len) {
-                       dst_bv++;
-                       if (dst_bv == bio_iovec_idx(dst, dst->bi_vcnt)) {
-                               dst = dst->bi_next;
-                               if (!dst)
-                                       break;
-
-                               dst_bv = bio_iovec(dst);
-                       }
+               if (!dst_iter.bi_size) {
+                       dst = dst->bi_next;
+                       if (!dst)
+                               break;
 
-                       dst_offset = dst_bv->bv_offset;
+                       dst_iter = dst->bi_iter;
                }
 
-               bytes = min(dst_bv->bv_offset + dst_bv->bv_len - dst_offset,
-                           src_bv->bv_offset + src_bv->bv_len - src_offset);
+               src_bv = bio_iter_iovec(src, src_iter);
+               dst_bv = bio_iter_iovec(dst, dst_iter);
+
+               bytes = min(src_bv.bv_len, dst_bv.bv_len);
 
-               src_p = kmap_atomic(src_bv->bv_page);
-               dst_p = kmap_atomic(dst_bv->bv_page);
+               src_p = kmap_atomic(src_bv.bv_page);
+               dst_p = kmap_atomic(dst_bv.bv_page);
 
-               memcpy(dst_p + dst_offset,
-                      src_p + src_offset,
+               memcpy(dst_p + dst_bv.bv_offset,
+                      src_p + src_bv.bv_offset,
                       bytes);
 
                kunmap_atomic(dst_p);
                kunmap_atomic(src_p);
 
-               src_offset += bytes;
-               dst_offset += bytes;
+               bio_advance_iter(src, &src_iter, bytes);
+               bio_advance_iter(dst, &dst_iter, bytes);
        }
 }
 EXPORT_SYMBOL(bio_copy_data);
 
 struct bio_map_data {
-       struct bio_vec *iovecs;
-       struct sg_iovec *sgvecs;
        int nr_sgvecs;
        int is_our_pages;
+       struct sg_iovec sgvecs[];
 };
 
 static void bio_set_map_data(struct bio_map_data *bmd, struct bio *bio,
                             struct sg_iovec *iov, int iov_count,
                             int is_our_pages)
 {
-       memcpy(bmd->iovecs, bio->bi_io_vec, sizeof(struct bio_vec) * bio->bi_vcnt);
        memcpy(bmd->sgvecs, iov, sizeof(struct sg_iovec) * iov_count);
        bmd->nr_sgvecs = iov_count;
        bmd->is_our_pages = is_our_pages;
        bio->bi_private = bmd;
 }
 
-static void bio_free_map_data(struct bio_map_data *bmd)
-{
-       kfree(bmd->iovecs);
-       kfree(bmd->sgvecs);
-       kfree(bmd);
-}
-
 static struct bio_map_data *bio_alloc_map_data(int nr_segs,
                                               unsigned int iov_count,
                                               gfp_t gfp_mask)
 {
-       struct bio_map_data *bmd;
-
        if (iov_count > UIO_MAXIOV)
                return NULL;
 
-       bmd = kmalloc(sizeof(*bmd), gfp_mask);
-       if (!bmd)
-               return NULL;
-
-       bmd->iovecs = kmalloc(sizeof(struct bio_vec) * nr_segs, gfp_mask);
-       if (!bmd->iovecs) {
-               kfree(bmd);
-               return NULL;
-       }
-
-       bmd->sgvecs = kmalloc(sizeof(struct sg_iovec) * iov_count, gfp_mask);
-       if (bmd->sgvecs)
-               return bmd;
-
-       kfree(bmd->iovecs);
-       kfree(bmd);
-       return NULL;
+       return kmalloc(sizeof(struct bio_map_data) +
+                      sizeof(struct sg_iovec) * iov_count, gfp_mask);
 }
 
-static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
-                         struct sg_iovec *iov, int iov_count,
+static int __bio_copy_iov(struct bio *bio, struct sg_iovec *iov, int iov_count,
                          int to_user, int from_user, int do_free_page)
 {
        int ret = 0, i;
@@ -994,7 +1028,7 @@ static int __bio_copy_iov(struct bio *bio, struct bio_vec *iovecs,
 
        bio_for_each_segment_all(bvec, bio, i) {
                char *bv_addr = page_address(bvec->bv_page);
-               unsigned int bv_len = iovecs[i].bv_len;
+               unsigned int bv_len = bvec->bv_len;
 
                while (bv_len && iov_idx < iov_count) {
                        unsigned int bytes;
@@ -1054,14 +1088,14 @@ int bio_uncopy_user(struct bio *bio)
                 * don't copy into a random user address space, just free.
                 */
                if (current->mm)
-                       ret = __bio_copy_iov(bio, bmd->iovecs, bmd->sgvecs,
-                                            bmd->nr_sgvecs, bio_data_dir(bio) == READ,
+                       ret = __bio_copy_iov(bio, bmd->sgvecs, bmd->nr_sgvecs,
+                                            bio_data_dir(bio) == READ,
                                             0, bmd->is_our_pages);
                else if (bmd->is_our_pages)
                        bio_for_each_segment_all(bvec, bio, i)
                                __free_page(bvec->bv_page);
        }
-       bio_free_map_data(bmd);
+       kfree(bmd);
        bio_put(bio);
        return ret;
 }
@@ -1175,7 +1209,7 @@ struct bio *bio_copy_user_iov(struct request_queue *q,
         */
        if ((!write_to_vm && (!map_data || !map_data->null_mapped)) ||
            (map_data && map_data->from_user)) {
-               ret = __bio_copy_iov(bio, bio->bi_io_vec, iov, iov_count, 0, 1, 0);
+               ret = __bio_copy_iov(bio, iov, iov_count, 0, 1, 0);
                if (ret)
                        goto cleanup;
        }
@@ -1189,7 +1223,7 @@ cleanup:
 
        bio_put(bio);
 out_bmd:
-       bio_free_map_data(bmd);
+       kfree(bmd);
        return ERR_PTR(ret);
 }
 
@@ -1485,7 +1519,7 @@ struct bio *bio_map_kern(struct request_queue *q, void *data, unsigned int len,
        if (IS_ERR(bio))
                return bio;
 
-       if (bio->bi_size == len)
+       if (bio->bi_iter.bi_size == len)
                return bio;
 
        /*
@@ -1506,16 +1540,15 @@ static void bio_copy_kern_endio(struct bio *bio, int err)
 
        bio_for_each_segment_all(bvec, bio, i) {
                char *addr = page_address(bvec->bv_page);
-               int len = bmd->iovecs[i].bv_len;
 
                if (read)
-                       memcpy(p, addr, len);
+                       memcpy(p, addr, bvec->bv_len);
 
                __free_page(bvec->bv_page);
-               p += len;
+               p += bvec->bv_len;
        }
 
-       bio_free_map_data(bmd);
+       kfree(bmd);
        bio_put(bio);
 }
 
@@ -1686,11 +1719,11 @@ void bio_check_pages_dirty(struct bio *bio)
 #if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
 void bio_flush_dcache_pages(struct bio *bi)
 {
-       int i;
-       struct bio_vec *bvec;
+       struct bio_vec bvec;
+       struct bvec_iter iter;
 
-       bio_for_each_segment(bvec, bi, i)
-               flush_dcache_page(bvec->bv_page);
+       bio_for_each_segment(bvec, bi, iter)
+               flush_dcache_page(bvec.bv_page);
 }
 EXPORT_SYMBOL(bio_flush_dcache_pages);
 #endif
@@ -1711,96 +1744,86 @@ EXPORT_SYMBOL(bio_flush_dcache_pages);
  **/
 void bio_endio(struct bio *bio, int error)
 {
-       if (error)
-               clear_bit(BIO_UPTODATE, &bio->bi_flags);
-       else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
-               error = -EIO;
+       while (bio) {
+               BUG_ON(atomic_read(&bio->bi_remaining) <= 0);
 
-       if (bio->bi_end_io)
-               bio->bi_end_io(bio, error);
-}
-EXPORT_SYMBOL(bio_endio);
+               if (error)
+                       clear_bit(BIO_UPTODATE, &bio->bi_flags);
+               else if (!test_bit(BIO_UPTODATE, &bio->bi_flags))
+                       error = -EIO;
 
-void bio_pair_release(struct bio_pair *bp)
-{
-       if (atomic_dec_and_test(&bp->cnt)) {
-               struct bio *master = bp->bio1.bi_private;
+               if (!atomic_dec_and_test(&bio->bi_remaining))
+                       return;
 
-               bio_endio(master, bp->error);
-               mempool_free(bp, bp->bio2.bi_private);
+               /*
+                * Need to have a real endio function for chained bios,
+                * otherwise various corner cases will break (like stacking
+                * block devices that save/restore bi_end_io) - however, we want
+                * to avoid unbounded recursion and blowing the stack. Tail call
+                * optimization would handle this, but compiling with frame
+                * pointers also disables gcc's sibling call optimization.
+                */
+               if (bio->bi_end_io == bio_chain_endio) {
+                       struct bio *parent = bio->bi_private;
+                       bio_put(bio);
+                       bio = parent;
+               } else {
+                       if (bio->bi_end_io)
+                               bio->bi_end_io(bio, error);
+                       bio = NULL;
+               }
        }
 }
-EXPORT_SYMBOL(bio_pair_release);
+EXPORT_SYMBOL(bio_endio);
 
-static void bio_pair_end_1(struct bio *bi, int err)
+/**
+ * bio_endio_nodec - end I/O on a bio, without decrementing bi_remaining
+ * @bio:       bio
+ * @error:     error, if any
+ *
+ * For code that has saved and restored bi_end_io; thing hard before using this
+ * function, probably you should've cloned the entire bio.
+ **/
+void bio_endio_nodec(struct bio *bio, int error)
 {
-       struct bio_pair *bp = container_of(bi, struct bio_pair, bio1);
-
-       if (err)
-               bp->error = err;
-
-       bio_pair_release(bp);
+       atomic_inc(&bio->bi_remaining);
+       bio_endio(bio, error);
 }
+EXPORT_SYMBOL(bio_endio_nodec);
 
-static void bio_pair_end_2(struct bio *bi, int err)
-{
-       struct bio_pair *bp = container_of(bi, struct bio_pair, bio2);
-
-       if (err)
-               bp->error = err;
-
-       bio_pair_release(bp);
-}
-
-/*
- * split a bio - only worry about a bio with a single page in its iovec
+/**
+ * bio_split - split a bio
+ * @bio:       bio to split
+ * @sectors:   number of sectors to split from the front of @bio
+ * @gfp:       gfp mask
+ * @bs:                bio set to allocate from
+ *
+ * Allocates and returns a new bio which represents @sectors from the start of
+ * @bio, and updates @bio to represent the remaining sectors.
+ *
+ * The newly allocated bio will point to @bio's bi_io_vec; it is the caller's
+ * responsibility to ensure that @bio is not freed before the split.
  */
-struct bio_pair *bio_split(struct bio *bi, int first_sectors)
+struct bio *bio_split(struct bio *bio, int sectors,
+                     gfp_t gfp, struct bio_set *bs)
 {
-       struct bio_pair *bp = mempool_alloc(bio_split_pool, GFP_NOIO);
-
-       if (!bp)
-               return bp;
-
-       trace_block_split(bdev_get_queue(bi->bi_bdev), bi,
-                               bi->bi_sector + first_sectors);
-
-       BUG_ON(bio_segments(bi) > 1);
-       atomic_set(&bp->cnt, 3);
-       bp->error = 0;
-       bp->bio1 = *bi;
-       bp->bio2 = *bi;
-       bp->bio2.bi_sector += first_sectors;
-       bp->bio2.bi_size -= first_sectors << 9;
-       bp->bio1.bi_size = first_sectors << 9;
-
-       if (bi->bi_vcnt != 0) {
-               bp->bv1 = *bio_iovec(bi);
-               bp->bv2 = *bio_iovec(bi);
-
-               if (bio_is_rw(bi)) {
-                       bp->bv2.bv_offset += first_sectors << 9;
-                       bp->bv2.bv_len -= first_sectors << 9;
-                       bp->bv1.bv_len = first_sectors << 9;
-               }
+       struct bio *split = NULL;
 
-               bp->bio1.bi_io_vec = &bp->bv1;
-               bp->bio2.bi_io_vec = &bp->bv2;
+       BUG_ON(sectors <= 0);
+       BUG_ON(sectors >= bio_sectors(bio));
 
-               bp->bio1.bi_max_vecs = 1;
-               bp->bio2.bi_max_vecs = 1;
-       }
+       split = bio_clone_fast(bio, gfp, bs);
+       if (!split)
+               return NULL;
 
-       bp->bio1.bi_end_io = bio_pair_end_1;
-       bp->bio2.bi_end_io = bio_pair_end_2;
+       split->bi_iter.bi_size = sectors << 9;
 
-       bp->bio1.bi_private = bi;
-       bp->bio2.bi_private = bio_split_pool;
+       if (bio_integrity(split))
+               bio_integrity_trim(split, 0, sectors);
 
-       if (bio_integrity(bi))
-               bio_integrity_split(bi, bp, first_sectors);
+       bio_advance(bio, split->bi_iter.bi_size);
 
-       return bp;
+       return split;
 }
 EXPORT_SYMBOL(bio_split);
 
@@ -1814,80 +1837,20 @@ void bio_trim(struct bio *bio, int offset, int size)
 {
        /* 'bio' is a cloned bio which we need to trim to match
         * the given offset and size.
-        * This requires adjusting bi_sector, bi_size, and bi_io_vec
         */
-       int i;
-       struct bio_vec *bvec;
-       int sofar = 0;
 
        size <<= 9;
-       if (offset == 0 && size == bio->bi_size)
+       if (offset == 0 && size == bio->bi_iter.bi_size)
                return;
 
        clear_bit(BIO_SEG_VALID, &bio->bi_flags);
 
        bio_advance(bio, offset << 9);
 
-       bio->bi_size = size;
-
-       /* avoid any complications with bi_idx being non-zero*/
-       if (bio->bi_idx) {
-               memmove(bio->bi_io_vec, bio->bi_io_vec+bio->bi_idx,
-                       (bio->bi_vcnt - bio->bi_idx) * sizeof(struct bio_vec));
-               bio->bi_vcnt -= bio->bi_idx;
-               bio->bi_idx = 0;
-       }
-       /* Make sure vcnt and last bv are not too big */
-       bio_for_each_segment(bvec, bio, i) {
-               if (sofar + bvec->bv_len > size)
-                       bvec->bv_len = size - sofar;
-               if (bvec->bv_len == 0) {
-                       bio->bi_vcnt = i;
-                       break;
-               }
-               sofar += bvec->bv_len;
-       }
+       bio->bi_iter.bi_size = size;
 }
 EXPORT_SYMBOL_GPL(bio_trim);
 
-/**
- *      bio_sector_offset - Find hardware sector offset in bio
- *      @bio:           bio to inspect
- *      @index:         bio_vec index
- *      @offset:        offset in bv_page
- *
- *      Return the number of hardware sectors between beginning of bio
- *      and an end point indicated by a bio_vec index and an offset
- *      within that vector's page.
- */
-sector_t bio_sector_offset(struct bio *bio, unsigned short index,
-                          unsigned int offset)
-{
-       unsigned int sector_sz;
-       struct bio_vec *bv;
-       sector_t sectors;
-       int i;
-
-       sector_sz = queue_logical_block_size(bio->bi_bdev->bd_disk->queue);
-       sectors = 0;
-
-       if (index >= bio->bi_idx)
-               index = bio->bi_vcnt - 1;
-
-       bio_for_each_segment_all(bv, bio, i) {
-               if (i == index) {
-                       if (offset > bv->bv_offset)
-                               sectors += (offset - bv->bv_offset) / sector_sz;
-                       break;
-               }
-
-               sectors += bv->bv_len / sector_sz;
-       }
-
-       return sectors;
-}
-EXPORT_SYMBOL(bio_sector_offset);
-
 /*
  * create memory pools for biovec's in a bio_set.
  * use the global biovec slabs created for general use.
@@ -2065,11 +2028,6 @@ static int __init init_bio(void)
        if (bioset_integrity_create(fs_bio_set, BIO_POOL_SIZE))
                panic("bio: can't create integrity pool\n");
 
-       bio_split_pool = mempool_create_kmalloc_pool(BIO_SPLIT_ENTRIES,
-                                                    sizeof(struct bio_pair));
-       if (!bio_split_pool)
-               panic("bio: can't create split pool\n");
-
        return 0;
 }
 subsys_initcall(init_bio);
index aa976eced2d2ea8dfa9c0e97ea84da7438626d62..a66768ebc8d19d394f2cd0818d56178a50f84803 100644 (file)
@@ -1,6 +1,7 @@
 config BTRFS_FS
        tristate "Btrfs filesystem support"
-       select LIBCRC32C
+       select CRYPTO
+       select CRYPTO_CRC32C
        select ZLIB_INFLATE
        select ZLIB_DEFLATE
        select LZO_COMPRESS
index 1a44e42d602a1b41f60a04ea9a1a290273f7e7dd..f341a98031d2e080522239c99392b47b849b9c2e 100644 (file)
@@ -9,7 +9,7 @@ btrfs-y += super.o ctree.o extent-tree.o print-tree.o root-tree.o dir-item.o \
           export.o tree-log.o free-space-cache.o zlib.o lzo.o \
           compression.o delayed-ref.o relocation.o delayed-inode.o scrub.o \
           reada.o backref.o ulist.o qgroup.o send.o dev-replace.o raid56.o \
-          uuid-tree.o
+          uuid-tree.o props.o hash.o
 
 btrfs-$(CONFIG_BTRFS_FS_POSIX_ACL) += acl.o
 btrfs-$(CONFIG_BTRFS_FS_CHECK_INTEGRITY) += check-integrity.o
index 0890c83643e944f69e43a22f4151e381e7503f04..ff9b3995d45394a607a7973458de3383ccd920ff 100644 (file)
@@ -35,13 +35,6 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
        char *value = NULL;
        struct posix_acl *acl;
 
-       if (!IS_POSIXACL(inode))
-               return NULL;
-
-       acl = get_cached_acl(inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
@@ -76,31 +69,10 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type)
        return acl;
 }
 
-static int btrfs_xattr_acl_get(struct dentry *dentry, const char *name,
-               void *value, size_t size, int type)
-{
-       struct posix_acl *acl;
-       int ret = 0;
-
-       if (!IS_POSIXACL(dentry->d_inode))
-               return -EOPNOTSUPP;
-
-       acl = btrfs_get_acl(dentry->d_inode, type);
-
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl == NULL)
-               return -ENODATA;
-       ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
-       posix_acl_release(acl);
-
-       return ret;
-}
-
 /*
  * Needs to be called with fs_mutex held
  */
-static int btrfs_set_acl(struct btrfs_trans_handle *trans,
+static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
                         struct inode *inode, struct posix_acl *acl, int type)
 {
        int ret, size = 0;
@@ -158,35 +130,9 @@ out:
        return ret;
 }
 
-static int btrfs_xattr_acl_set(struct dentry *dentry, const char *name,
-               const void *value, size_t size, int flags, int type)
+int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
-       int ret;
-       struct posix_acl *acl = NULL;
-
-       if (!inode_owner_or_capable(dentry->d_inode))
-               return -EPERM;
-
-       if (!IS_POSIXACL(dentry->d_inode))
-               return -EOPNOTSUPP;
-
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-
-               if (acl) {
-                       ret = posix_acl_valid(acl);
-                       if (ret)
-                               goto out;
-               }
-       }
-
-       ret = btrfs_set_acl(NULL, dentry->d_inode, acl, type);
-out:
-       posix_acl_release(acl);
-
-       return ret;
+       return __btrfs_set_acl(NULL, inode, acl, type);
 }
 
 /*
@@ -197,83 +143,31 @@ out:
 int btrfs_init_acl(struct btrfs_trans_handle *trans,
                   struct inode *inode, struct inode *dir)
 {
-       struct posix_acl *acl = NULL;
+       struct posix_acl *default_acl, *acl;
        int ret = 0;
 
        /* this happens with subvols */
        if (!dir)
                return 0;
 
-       if (!S_ISLNK(inode->i_mode)) {
-               if (IS_POSIXACL(dir)) {
-                       acl = btrfs_get_acl(dir, ACL_TYPE_DEFAULT);
-                       if (IS_ERR(acl))
-                               return PTR_ERR(acl);
-               }
+       ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+       if (ret)
+               return ret;
 
-               if (!acl)
-                       inode->i_mode &= ~current_umask();
+       if (default_acl) {
+               ret = __btrfs_set_acl(trans, inode, default_acl,
+                                     ACL_TYPE_DEFAULT);
+               posix_acl_release(default_acl);
        }
 
-       if (IS_POSIXACL(dir) && acl) {
-               if (S_ISDIR(inode->i_mode)) {
-                       ret = btrfs_set_acl(trans, inode, acl,
-                                           ACL_TYPE_DEFAULT);
-                       if (ret)
-                               goto failed;
-               }
-               ret = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
-               if (ret < 0)
-                       return ret;
-
-               if (ret > 0) {
-                       /* we need an acl */
-                       ret = btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS);
-               } else if (ret < 0) {
-                       cache_no_acl(inode);
-               }
-       } else {
-               cache_no_acl(inode);
+       if (acl) {
+               if (!ret)
+                       ret = __btrfs_set_acl(trans, inode, acl,
+                                             ACL_TYPE_ACCESS);
+               posix_acl_release(acl);
        }
-failed:
-       posix_acl_release(acl);
-
-       return ret;
-}
 
-int btrfs_acl_chmod(struct inode *inode)
-{
-       struct posix_acl *acl;
-       int ret = 0;
-
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
-       if (!IS_POSIXACL(inode))
-               return 0;
-
-       acl = btrfs_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR_OR_NULL(acl))
-               return PTR_ERR(acl);
-
-       ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
-       if (ret)
-               return ret;
-       ret = btrfs_set_acl(NULL, inode, acl, ACL_TYPE_ACCESS);
-       posix_acl_release(acl);
+       if (!default_acl && !acl)
+               cache_no_acl(inode);
        return ret;
 }
-
-const struct xattr_handler btrfs_xattr_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags  = ACL_TYPE_DEFAULT,
-       .get    = btrfs_xattr_acl_get,
-       .set    = btrfs_xattr_acl_set,
-};
-
-const struct xattr_handler btrfs_xattr_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags  = ACL_TYPE_ACCESS,
-       .get    = btrfs_xattr_acl_get,
-       .set    = btrfs_xattr_acl_set,
-};
index 3775947429b28ea07678c4f58877bfcbb5f8bed6..aded3ef3d3d4abfa6d61fa078a51e64e4b80be65 100644 (file)
@@ -66,6 +66,16 @@ static int check_extent_in_eb(struct btrfs_key *key, struct extent_buffer *eb,
        return 0;
 }
 
+static void free_inode_elem_list(struct extent_inode_elem *eie)
+{
+       struct extent_inode_elem *eie_next;
+
+       for (; eie; eie = eie_next) {
+               eie_next = eie->next;
+               kfree(eie);
+       }
+}
+
 static int find_extent_in_eb(struct extent_buffer *eb, u64 wanted_disk_byte,
                                u64 extent_item_pos,
                                struct extent_inode_elem **eie)
@@ -209,18 +219,19 @@ static int __add_prelim_ref(struct list_head *head, u64 root_id,
 }
 
 static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
-                               struct ulist *parents, int level,
-                               struct btrfs_key *key_for_search, u64 time_seq,
-                               u64 wanted_disk_byte,
-                               const u64 *extent_item_pos)
+                          struct ulist *parents, struct __prelim_ref *ref,
+                          int level, u64 time_seq, const u64 *extent_item_pos)
 {
        int ret = 0;
        int slot;
        struct extent_buffer *eb;
        struct btrfs_key key;
+       struct btrfs_key *key_for_search = &ref->key_for_search;
        struct btrfs_file_extent_item *fi;
        struct extent_inode_elem *eie = NULL, *old = NULL;
        u64 disk_byte;
+       u64 wanted_disk_byte = ref->wanted_disk_byte;
+       u64 count = 0;
 
        if (level != 0) {
                eb = path->nodes[level];
@@ -238,7 +249,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
        if (path->slots[0] >= btrfs_header_nritems(path->nodes[0]))
                ret = btrfs_next_old_leaf(root, path, time_seq);
 
-       while (!ret) {
+       while (!ret && count < ref->count) {
                eb = path->nodes[0];
                slot = path->slots[0];
 
@@ -254,6 +265,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
                if (disk_byte == wanted_disk_byte) {
                        eie = NULL;
                        old = NULL;
+                       count++;
                        if (extent_item_pos) {
                                ret = check_extent_in_eb(&key, eb, fi,
                                                *extent_item_pos,
@@ -273,6 +285,7 @@ static int add_all_parents(struct btrfs_root *root, struct btrfs_path *path,
                                        old = old->next;
                                old->next = eie;
                        }
+                       eie = NULL;
                }
 next:
                ret = btrfs_next_old_item(root, path, time_seq);
@@ -280,6 +293,8 @@ next:
 
        if (ret > 0)
                ret = 0;
+       else if (ret < 0)
+               free_inode_elem_list(eie);
        return ret;
 }
 
@@ -299,23 +314,34 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
        int ret = 0;
        int root_level;
        int level = ref->level;
+       int index;
 
        root_key.objectid = ref->root_id;
        root_key.type = BTRFS_ROOT_ITEM_KEY;
        root_key.offset = (u64)-1;
+
+       index = srcu_read_lock(&fs_info->subvol_srcu);
+
        root = btrfs_read_fs_root_no_name(fs_info, &root_key);
        if (IS_ERR(root)) {
+               srcu_read_unlock(&fs_info->subvol_srcu, index);
                ret = PTR_ERR(root);
                goto out;
        }
 
        root_level = btrfs_old_root_level(root, time_seq);
 
-       if (root_level + 1 == level)
+       if (root_level + 1 == level) {
+               srcu_read_unlock(&fs_info->subvol_srcu, index);
                goto out;
+       }
 
        path->lowest_level = level;
        ret = btrfs_search_old_slot(root, &ref->key_for_search, path, time_seq);
+
+       /* root node has been locked, we can release @subvol_srcu safely here */
+       srcu_read_unlock(&fs_info->subvol_srcu, index);
+
        pr_debug("search slot in root %llu (level %d, ref count %d) returned "
                 "%d for key (%llu %u %llu)\n",
                 ref->root_id, level, ref->count, ret,
@@ -334,9 +360,8 @@ static int __resolve_indirect_ref(struct btrfs_fs_info *fs_info,
                eb = path->nodes[level];
        }
 
-       ret = add_all_parents(root, path, parents, level, &ref->key_for_search,
-                               time_seq, ref->wanted_disk_byte,
-                               extent_item_pos);
+       ret = add_all_parents(root, path, parents, ref, level, time_seq,
+                             extent_item_pos);
 out:
        path->lowest_level = 0;
        btrfs_release_path(path);
@@ -376,10 +401,16 @@ static int __resolve_indirect_refs(struct btrfs_fs_info *fs_info,
                        continue;
                err = __resolve_indirect_ref(fs_info, path, time_seq, ref,
                                             parents, extent_item_pos);
-               if (err == -ENOMEM)
-                       goto out;
-               if (err)
+               /*
+                * we can only tolerate ENOENT,otherwise,we should catch error
+                * and return directly.
+                */
+               if (err == -ENOENT) {
                        continue;
+               } else if (err) {
+                       ret = err;
+                       goto out;
+               }
 
                /* we put the first parent into the ref at hand */
                ULIST_ITER_INIT(&uiter);
@@ -538,14 +569,13 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
        if (extent_op && extent_op->update_key)
                btrfs_disk_key_to_cpu(&op_key, &extent_op->key);
 
-       while ((n = rb_prev(n))) {
+       spin_lock(&head->lock);
+       n = rb_first(&head->ref_root);
+       while (n) {
                struct btrfs_delayed_ref_node *node;
                node = rb_entry(n, struct btrfs_delayed_ref_node,
                                rb_node);
-               if (node->bytenr != head->node.bytenr)
-                       break;
-               WARN_ON(node->is_head);
-
+               n = rb_next(n);
                if (node->seq > seq)
                        continue;
 
@@ -612,10 +642,10 @@ static int __add_delayed_refs(struct btrfs_delayed_ref_head *head, u64 seq,
                        WARN_ON(1);
                }
                if (ret)
-                       return ret;
+                       break;
        }
-
-       return 0;
+       spin_unlock(&head->lock);
+       return ret;
 }
 
 /*
@@ -828,6 +858,7 @@ static int find_parent_nodes(struct btrfs_trans_handle *trans,
        struct list_head prefs_delayed;
        struct list_head prefs;
        struct __prelim_ref *ref;
+       struct extent_inode_elem *eie = NULL;
 
        INIT_LIST_HEAD(&prefs);
        INIT_LIST_HEAD(&prefs_delayed);
@@ -882,15 +913,15 @@ again:
                                btrfs_put_delayed_ref(&head->node);
                                goto again;
                        }
+                       spin_unlock(&delayed_refs->lock);
                        ret = __add_delayed_refs(head, time_seq,
                                                 &prefs_delayed);
                        mutex_unlock(&head->mutex);
-                       if (ret) {
-                               spin_unlock(&delayed_refs->lock);
+                       if (ret)
                                goto out;
-                       }
+               } else {
+                       spin_unlock(&delayed_refs->lock);
                }
-               spin_unlock(&delayed_refs->lock);
        }
 
        if (path->slots[0]) {
@@ -941,7 +972,6 @@ again:
                                goto out;
                }
                if (ref->count && ref->parent) {
-                       struct extent_inode_elem *eie = NULL;
                        if (extent_item_pos && !ref->inode_list) {
                                u32 bsz;
                                struct extent_buffer *eb;
@@ -976,6 +1006,7 @@ again:
                                        eie = eie->next;
                                eie->next = ref->inode_list;
                        }
+                       eie = NULL;
                }
                list_del(&ref->list);
                kmem_cache_free(btrfs_prelim_ref_cache, ref);
@@ -994,7 +1025,8 @@ out:
                list_del(&ref->list);
                kmem_cache_free(btrfs_prelim_ref_cache, ref);
        }
-
+       if (ret < 0)
+               free_inode_elem_list(eie);
        return ret;
 }
 
@@ -1002,7 +1034,6 @@ static void free_leaf_list(struct ulist *blocks)
 {
        struct ulist_node *node = NULL;
        struct extent_inode_elem *eie;
-       struct extent_inode_elem *eie_next;
        struct ulist_iterator uiter;
 
        ULIST_ITER_INIT(&uiter);
@@ -1010,10 +1041,7 @@ static void free_leaf_list(struct ulist *blocks)
                if (!node->aux)
                        continue;
                eie = (struct extent_inode_elem *)(uintptr_t)node->aux;
-               for (; eie; eie = eie_next) {
-                       eie_next = eie->next;
-                       kfree(eie);
-               }
+               free_inode_elem_list(eie);
                node->aux = 0;
        }
 
@@ -1101,44 +1129,13 @@ int btrfs_find_all_roots(struct btrfs_trans_handle *trans,
                if (!node)
                        break;
                bytenr = node->val;
+               cond_resched();
        }
 
        ulist_free(tmp);
        return 0;
 }
 
-
-static int __inode_info(u64 inum, u64 ioff, u8 key_type,
-                       struct btrfs_root *fs_root, struct btrfs_path *path,
-                       struct btrfs_key *found_key)
-{
-       int ret;
-       struct btrfs_key key;
-       struct extent_buffer *eb;
-
-       key.type = key_type;
-       key.objectid = inum;
-       key.offset = ioff;
-
-       ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0);
-       if (ret < 0)
-               return ret;
-
-       eb = path->nodes[0];
-       if (ret && path->slots[0] >= btrfs_header_nritems(eb)) {
-               ret = btrfs_next_leaf(fs_root, path);
-               if (ret)
-                       return ret;
-               eb = path->nodes[0];
-       }
-
-       btrfs_item_key_to_cpu(eb, found_key, path->slots[0]);
-       if (found_key->type != key.type || found_key->objectid != key.objectid)
-               return 1;
-
-       return 0;
-}
-
 /*
  * this makes the path point to (inum INODE_ITEM ioff)
  */
@@ -1146,16 +1143,16 @@ int inode_item_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
                        struct btrfs_path *path)
 {
        struct btrfs_key key;
-       return __inode_info(inum, ioff, BTRFS_INODE_ITEM_KEY, fs_root, path,
-                               &key);
+       return btrfs_find_item(fs_root, path, inum, ioff,
+                       BTRFS_INODE_ITEM_KEY, &key);
 }
 
 static int inode_ref_info(u64 inum, u64 ioff, struct btrfs_root *fs_root,
                                struct btrfs_path *path,
                                struct btrfs_key *found_key)
 {
-       return __inode_info(inum, ioff, BTRFS_INODE_REF_KEY, fs_root, path,
-                               found_key);
+       return btrfs_find_item(fs_root, path, inum, ioff,
+                       BTRFS_INODE_REF_KEY, found_key);
 }
 
 int btrfs_find_one_extref(struct btrfs_root *root, u64 inode_objectid,
@@ -1335,20 +1332,45 @@ int extent_from_logical(struct btrfs_fs_info *fs_info, u64 logical,
        ret = btrfs_search_slot(NULL, fs_info->extent_root, &key, path, 0, 0);
        if (ret < 0)
                return ret;
-       ret = btrfs_previous_item(fs_info->extent_root, path,
-                                       0, BTRFS_EXTENT_ITEM_KEY);
-       if (ret < 0)
-               return ret;
 
-       btrfs_item_key_to_cpu(path->nodes[0], found_key, path->slots[0]);
+       while (1) {
+               u32 nritems;
+               if (path->slots[0] == 0) {
+                       btrfs_set_path_blocking(path);
+                       ret = btrfs_prev_leaf(fs_info->extent_root, path);
+                       if (ret != 0) {
+                               if (ret > 0) {
+                                       pr_debug("logical %llu is not within "
+                                                "any extent\n", logical);
+                                       ret = -ENOENT;
+                               }
+                               return ret;
+                       }
+               } else {
+                       path->slots[0]--;
+               }
+               nritems = btrfs_header_nritems(path->nodes[0]);
+               if (nritems == 0) {
+                       pr_debug("logical %llu is not within any extent\n",
+                                logical);
+                       return -ENOENT;
+               }
+               if (path->slots[0] == nritems)
+                       path->slots[0]--;
+
+               btrfs_item_key_to_cpu(path->nodes[0], found_key,
+                                     path->slots[0]);
+               if (found_key->type == BTRFS_EXTENT_ITEM_KEY ||
+                   found_key->type == BTRFS_METADATA_ITEM_KEY)
+                       break;
+       }
+
        if (found_key->type == BTRFS_METADATA_ITEM_KEY)
                size = fs_info->extent_root->leafsize;
        else if (found_key->type == BTRFS_EXTENT_ITEM_KEY)
                size = found_key->offset;
 
-       if ((found_key->type != BTRFS_EXTENT_ITEM_KEY &&
-            found_key->type != BTRFS_METADATA_ITEM_KEY) ||
-           found_key->objectid > logical ||
+       if (found_key->objectid > logical ||
            found_key->objectid + size <= logical) {
                pr_debug("logical %llu is not within any extent\n", logical);
                return -ENOENT;
@@ -1601,7 +1623,6 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
        struct btrfs_key found_key;
 
        while (!ret) {
-               path->leave_spinning = 1;
                ret = inode_ref_info(inum, parent ? parent+1 : 0, fs_root, path,
                                     &found_key);
                if (ret < 0)
@@ -1614,9 +1635,12 @@ static int iterate_inode_refs(u64 inum, struct btrfs_root *fs_root,
 
                parent = found_key.offset;
                slot = path->slots[0];
-               eb = path->nodes[0];
-               /* make sure we can use eb after releasing the path */
-               atomic_inc(&eb->refs);
+               eb = btrfs_clone_extent_buffer(path->nodes[0]);
+               if (!eb) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               extent_buffer_get(eb);
                btrfs_tree_read_lock(eb);
                btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
                btrfs_release_path(path);
@@ -1674,17 +1698,20 @@ static int iterate_inode_extrefs(u64 inum, struct btrfs_root *fs_root,
                ++found;
 
                slot = path->slots[0];
-               eb = path->nodes[0];
-               /* make sure we can use eb after releasing the path */
-               atomic_inc(&eb->refs);
+               eb = btrfs_clone_extent_buffer(path->nodes[0]);
+               if (!eb) {
+                       ret = -ENOMEM;
+                       break;
+               }
+               extent_buffer_get(eb);
 
                btrfs_tree_read_lock(eb);
                btrfs_set_lock_blocking_rw(eb, BTRFS_READ_LOCK);
                btrfs_release_path(path);
 
                leaf = path->nodes[0];
-               item_size = btrfs_item_size_nr(leaf, path->slots[0]);
-               ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+               item_size = btrfs_item_size_nr(leaf, slot);
+               ptr = btrfs_item_ptr_offset(leaf, slot);
                cur_offset = 0;
 
                while (cur_offset < item_size) {
index ac0b39db27d175af15a718a41ac2ebf11c32150f..8fed2125689ed39b928800e78cfbf3b720d52a24 100644 (file)
@@ -43,6 +43,7 @@
 #define BTRFS_INODE_COPY_EVERYTHING            8
 #define BTRFS_INODE_IN_DELALLOC_LIST           9
 #define BTRFS_INODE_READDIO_NEED_LOCK          10
+#define BTRFS_INODE_HAS_PROPS                  11
 
 /* in memory btrfs inode */
 struct btrfs_inode {
@@ -135,6 +136,9 @@ struct btrfs_inode {
         */
        u64 index_cnt;
 
+       /* Cache the directory index number to speed the dir/file remove */
+       u64 dir_index;
+
        /* the fsync log has some corner cases that mean we have to check
         * directories to see if any unlinks have been done before
         * the directory was logged.  See tree-log.c for all the
index 131d82800b3af45778cb8651f5c559bd57cec437..49a62b4dda3b0184ccd30880b8449b967eda5f27 100644 (file)
@@ -1456,10 +1456,14 @@ static int btrfsic_handle_extent_data(
        btrfsic_read_from_block_data(block_ctx, &file_extent_item,
                                     file_extent_item_offset,
                                     sizeof(struct btrfs_file_extent_item));
-       next_bytenr = btrfs_stack_file_extent_disk_bytenr(&file_extent_item) +
-                     btrfs_stack_file_extent_offset(&file_extent_item);
-       generation = btrfs_stack_file_extent_generation(&file_extent_item);
-       num_bytes = btrfs_stack_file_extent_num_bytes(&file_extent_item);
+       next_bytenr = btrfs_stack_file_extent_disk_bytenr(&file_extent_item);
+       if (btrfs_stack_file_extent_compression(&file_extent_item) ==
+           BTRFS_COMPRESS_NONE) {
+               next_bytenr += btrfs_stack_file_extent_offset(&file_extent_item);
+               num_bytes = btrfs_stack_file_extent_num_bytes(&file_extent_item);
+       } else {
+               num_bytes = btrfs_stack_file_extent_disk_num_bytes(&file_extent_item);
+       }
        generation = btrfs_stack_file_extent_generation(&file_extent_item);
 
        if (state->print_mask & BTRFSIC_PRINT_MASK_VERY_VERBOSE)
@@ -1695,7 +1699,7 @@ static int btrfsic_read_block(struct btrfsic_state *state,
                        return -1;
                }
                bio->bi_bdev = block_ctx->dev->bdev;
-               bio->bi_sector = dev_bytenr >> 9;
+               bio->bi_iter.bi_sector = dev_bytenr >> 9;
 
                for (j = i; j < num_pages; j++) {
                        ret = bio_add_page(bio, block_ctx->pagev[j],
@@ -3013,7 +3017,7 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio)
                int bio_is_patched;
                char **mapped_datav;
 
-               dev_bytenr = 512 * bio->bi_sector;
+               dev_bytenr = 512 * bio->bi_iter.bi_sector;
                bio_is_patched = 0;
                if (dev_state->state->print_mask &
                    BTRFSIC_PRINT_MASK_SUBMIT_BIO_BH)
@@ -3021,8 +3025,8 @@ static void __btrfsic_submit_bio(int rw, struct bio *bio)
                               "submit_bio(rw=0x%x, bi_vcnt=%u,"
                               " bi_sector=%llu (bytenr %llu), bi_bdev=%p)\n",
                               rw, bio->bi_vcnt,
-                              (unsigned long long)bio->bi_sector, dev_bytenr,
-                              bio->bi_bdev);
+                              (unsigned long long)bio->bi_iter.bi_sector,
+                              dev_bytenr, bio->bi_bdev);
 
                mapped_datav = kmalloc(sizeof(*mapped_datav) * bio->bi_vcnt,
                                       GFP_NOFS);
index 1499b27b41863e7dfbbe7da134b1a7fb66dece34..e2600cdb6c257e366b873445c396a917249e76f3 100644 (file)
@@ -128,11 +128,10 @@ static int check_compressed_csum(struct inode *inode,
                kunmap_atomic(kaddr);
 
                if (csum != *cb_sum) {
-                       printk(KERN_INFO "btrfs csum failed ino %llu "
-                              "extent %llu csum %u "
-                              "wanted %u mirror %d\n",
-                              btrfs_ino(inode), disk_start, csum, *cb_sum,
-                              cb->mirror_num);
+                       btrfs_info(BTRFS_I(inode)->root->fs_info,
+                          "csum failed ino %llu extent %llu csum %u wanted %u mirror %d",
+                          btrfs_ino(inode), disk_start, csum, *cb_sum,
+                          cb->mirror_num);
                        ret = -EIO;
                        goto fail;
                }
@@ -172,7 +171,8 @@ static void end_compressed_bio_read(struct bio *bio, int err)
                goto out;
 
        inode = cb->inode;
-       ret = check_compressed_csum(inode, cb, (u64)bio->bi_sector << 9);
+       ret = check_compressed_csum(inode, cb,
+                                   (u64)bio->bi_iter.bi_sector << 9);
        if (ret)
                goto csum_failed;
 
@@ -201,18 +201,16 @@ csum_failed:
        if (cb->errors) {
                bio_io_error(cb->orig_bio);
        } else {
-               int bio_index = 0;
-               struct bio_vec *bvec = cb->orig_bio->bi_io_vec;
+               int i;
+               struct bio_vec *bvec;
 
                /*
                 * we have verified the checksum already, set page
                 * checked so the end_io handlers know about it
                 */
-               while (bio_index < cb->orig_bio->bi_vcnt) {
+               bio_for_each_segment_all(bvec, cb->orig_bio, i)
                        SetPageChecked(bvec->bv_page);
-                       bvec++;
-                       bio_index++;
-               }
+
                bio_endio(cb->orig_bio, 0);
        }
 
@@ -372,7 +370,7 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
        for (pg_index = 0; pg_index < cb->nr_pages; pg_index++) {
                page = compressed_pages[pg_index];
                page->mapping = inode->i_mapping;
-               if (bio->bi_size)
+               if (bio->bi_iter.bi_size)
                        ret = io_tree->ops->merge_bio_hook(WRITE, page, 0,
                                                           PAGE_CACHE_SIZE,
                                                           bio, 0);
@@ -412,7 +410,8 @@ int btrfs_submit_compressed_write(struct inode *inode, u64 start,
                        bio_add_page(bio, page, PAGE_CACHE_SIZE, 0);
                }
                if (bytes_left < PAGE_CACHE_SIZE) {
-                       printk("bytes left %lu compress len %lu nr %lu\n",
+                       btrfs_info(BTRFS_I(inode)->root->fs_info,
+                                       "bytes left %lu compress len %lu nr %lu",
                               bytes_left, cb->compressed_len, cb->nr_pages);
                }
                bytes_left -= PAGE_CACHE_SIZE;
@@ -506,7 +505,7 @@ static noinline int add_ra_bio_pages(struct inode *inode,
 
                if (!em || last_offset < em->start ||
                    (last_offset + PAGE_CACHE_SIZE > extent_map_end(em)) ||
-                   (em->block_start >> 9) != cb->orig_bio->bi_sector) {
+                   (em->block_start >> 9) != cb->orig_bio->bi_iter.bi_sector) {
                        free_extent_map(em);
                        unlock_extent(tree, last_offset, end);
                        unlock_page(page);
@@ -552,7 +551,7 @@ next:
  * in it.  We don't actually do IO on those pages but allocate new ones
  * to hold the compressed pages on disk.
  *
- * bio->bi_sector points to the compressed extent on disk
+ * bio->bi_iter.bi_sector points to the compressed extent on disk
  * bio->bi_io_vec points to all of the inode pages
  * bio->bi_vcnt is a count of pages
  *
@@ -573,7 +572,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
        struct page *page;
        struct block_device *bdev;
        struct bio *comp_bio;
-       u64 cur_disk_byte = (u64)bio->bi_sector << 9;
+       u64 cur_disk_byte = (u64)bio->bi_iter.bi_sector << 9;
        u64 em_len;
        u64 em_start;
        struct extent_map *em;
@@ -659,7 +658,7 @@ int btrfs_submit_compressed_read(struct inode *inode, struct bio *bio,
                page->mapping = inode->i_mapping;
                page->index = em_start >> PAGE_CACHE_SHIFT;
 
-               if (comp_bio->bi_size)
+               if (comp_bio->bi_iter.bi_size)
                        ret = tree->ops->merge_bio_hook(READ, page, 0,
                                                        PAGE_CACHE_SIZE,
                                                        comp_bio, 0);
@@ -687,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_size + root->sectorsize - 1) /
-                               root->sectorsize;
+                       sums += (comp_bio->bi_iter.bi_size +
+                                root->sectorsize - 1) / root->sectorsize;
 
                        ret = btrfs_map_bio(root, READ, comp_bio,
                                            mirror_num, 0);
index 316136bd6dd7eb3899bcf060c3e0bd749f674310..cbd3a7d6fa681acfc0b00cb515fcddbcf8880f49 100644 (file)
@@ -39,9 +39,8 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
                              struct extent_buffer *src_buf);
 static void del_ptr(struct btrfs_root *root, struct btrfs_path *path,
                    int level, int slot);
-static void tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
+static int tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
                                 struct extent_buffer *eb);
-static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 
 struct btrfs_path *btrfs_alloc_path(void)
 {
@@ -475,6 +474,8 @@ void btrfs_put_tree_mod_seq(struct btrfs_fs_info *fs_info,
  * the index is the shifted logical of the *new* root node for root replace
  * operations, or the shifted logical of the affected block for all other
  * operations.
+ *
+ * Note: must be called with write lock (tree_mod_log_write_lock).
  */
 static noinline int
 __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
@@ -483,24 +484,9 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
        struct rb_node **new;
        struct rb_node *parent = NULL;
        struct tree_mod_elem *cur;
-       int ret = 0;
 
        BUG_ON(!tm);
 
-       tree_mod_log_write_lock(fs_info);
-       if (list_empty(&fs_info->tree_mod_seq_list)) {
-               tree_mod_log_write_unlock(fs_info);
-               /*
-                * Ok we no longer care about logging modifications, free up tm
-                * and return 0.  Any callers shouldn't be using tm after
-                * calling tree_mod_log_insert, but if they do we can just
-                * change this to return a special error code to let the callers
-                * do their own thing.
-                */
-               kfree(tm);
-               return 0;
-       }
-
        spin_lock(&fs_info->tree_mod_seq_lock);
        tm->seq = btrfs_inc_tree_mod_seq_minor(fs_info);
        spin_unlock(&fs_info->tree_mod_seq_lock);
@@ -518,18 +504,13 @@ __tree_mod_log_insert(struct btrfs_fs_info *fs_info, struct tree_mod_elem *tm)
                        new = &((*new)->rb_left);
                else if (cur->seq > tm->seq)
                        new = &((*new)->rb_right);
-               else {
-                       ret = -EEXIST;
-                       kfree(tm);
-                       goto out;
-               }
+               else
+                       return -EEXIST;
        }
 
        rb_link_node(&tm->node, parent, new);
        rb_insert_color(&tm->node, tm_root);
-out:
-       tree_mod_log_write_unlock(fs_info);
-       return ret;
+       return 0;
 }
 
 /*
@@ -545,19 +526,38 @@ static inline int tree_mod_dont_log(struct btrfs_fs_info *fs_info,
                return 1;
        if (eb && btrfs_header_level(eb) == 0)
                return 1;
+
+       tree_mod_log_write_lock(fs_info);
+       if (list_empty(&(fs_info)->tree_mod_seq_list)) {
+               tree_mod_log_write_unlock(fs_info);
+               return 1;
+       }
+
        return 0;
 }
 
-static inline int
-__tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
-                         struct extent_buffer *eb, int slot,
-                         enum mod_log_op op, gfp_t flags)
+/* Similar to tree_mod_dont_log, but doesn't acquire any locks. */
+static inline int tree_mod_need_log(const struct btrfs_fs_info *fs_info,
+                                   struct extent_buffer *eb)
+{
+       smp_mb();
+       if (list_empty(&(fs_info)->tree_mod_seq_list))
+               return 0;
+       if (eb && btrfs_header_level(eb) == 0)
+               return 0;
+
+       return 1;
+}
+
+static struct tree_mod_elem *
+alloc_tree_mod_elem(struct extent_buffer *eb, int slot,
+                   enum mod_log_op op, gfp_t flags)
 {
        struct tree_mod_elem *tm;
 
        tm = kzalloc(sizeof(*tm), flags);
        if (!tm)
-               return -ENOMEM;
+               return NULL;
 
        tm->index = eb->start >> PAGE_CACHE_SHIFT;
        if (op != MOD_LOG_KEY_ADD) {
@@ -567,8 +567,9 @@ __tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
        tm->op = op;
        tm->slot = slot;
        tm->generation = btrfs_node_ptr_generation(eb, slot);
+       RB_CLEAR_NODE(&tm->node);
 
-       return __tree_mod_log_insert(fs_info, tm);
+       return tm;
 }
 
 static noinline int
@@ -576,10 +577,27 @@ tree_mod_log_insert_key(struct btrfs_fs_info *fs_info,
                        struct extent_buffer *eb, int slot,
                        enum mod_log_op op, gfp_t flags)
 {
-       if (tree_mod_dont_log(fs_info, eb))
+       struct tree_mod_elem *tm;
+       int ret;
+
+       if (!tree_mod_need_log(fs_info, eb))
                return 0;
 
-       return __tree_mod_log_insert_key(fs_info, eb, slot, op, flags);
+       tm = alloc_tree_mod_elem(eb, slot, op, flags);
+       if (!tm)
+               return -ENOMEM;
+
+       if (tree_mod_dont_log(fs_info, eb)) {
+               kfree(tm);
+               return 0;
+       }
+
+       ret = __tree_mod_log_insert(fs_info, tm);
+       tree_mod_log_write_unlock(fs_info);
+       if (ret)
+               kfree(tm);
+
+       return ret;
 }
 
 static noinline int
@@ -587,53 +605,95 @@ tree_mod_log_insert_move(struct btrfs_fs_info *fs_info,
                         struct extent_buffer *eb, int dst_slot, int src_slot,
                         int nr_items, gfp_t flags)
 {
-       struct tree_mod_elem *tm;
-       int ret;
+       struct tree_mod_elem *tm = NULL;
+       struct tree_mod_elem **tm_list = NULL;
+       int ret = 0;
        int i;
+       int locked = 0;
 
-       if (tree_mod_dont_log(fs_info, eb))
+       if (!tree_mod_need_log(fs_info, eb))
                return 0;
 
+       tm_list = kzalloc(nr_items * sizeof(struct tree_mod_elem *), flags);
+       if (!tm_list)
+               return -ENOMEM;
+
+       tm = kzalloc(sizeof(*tm), flags);
+       if (!tm) {
+               ret = -ENOMEM;
+               goto free_tms;
+       }
+
+       tm->index = eb->start >> PAGE_CACHE_SHIFT;
+       tm->slot = src_slot;
+       tm->move.dst_slot = dst_slot;
+       tm->move.nr_items = nr_items;
+       tm->op = MOD_LOG_MOVE_KEYS;
+
+       for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
+               tm_list[i] = alloc_tree_mod_elem(eb, i + dst_slot,
+                   MOD_LOG_KEY_REMOVE_WHILE_MOVING, flags);
+               if (!tm_list[i]) {
+                       ret = -ENOMEM;
+                       goto free_tms;
+               }
+       }
+
+       if (tree_mod_dont_log(fs_info, eb))
+               goto free_tms;
+       locked = 1;
+
        /*
         * When we override something during the move, we log these removals.
         * This can only happen when we move towards the beginning of the
         * buffer, i.e. dst_slot < src_slot.
         */
        for (i = 0; i + dst_slot < src_slot && i < nr_items; i++) {
-               ret = __tree_mod_log_insert_key(fs_info, eb, i + dst_slot,
-                               MOD_LOG_KEY_REMOVE_WHILE_MOVING, GFP_NOFS);
-               BUG_ON(ret < 0);
+               ret = __tree_mod_log_insert(fs_info, tm_list[i]);
+               if (ret)
+                       goto free_tms;
        }
 
-       tm = kzalloc(sizeof(*tm), flags);
-       if (!tm)
-               return -ENOMEM;
+       ret = __tree_mod_log_insert(fs_info, tm);
+       if (ret)
+               goto free_tms;
+       tree_mod_log_write_unlock(fs_info);
+       kfree(tm_list);
 
-       tm->index = eb->start >> PAGE_CACHE_SHIFT;
-       tm->slot = src_slot;
-       tm->move.dst_slot = dst_slot;
-       tm->move.nr_items = nr_items;
-       tm->op = MOD_LOG_MOVE_KEYS;
+       return 0;
+free_tms:
+       for (i = 0; i < nr_items; i++) {
+               if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node))
+                       rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log);
+               kfree(tm_list[i]);
+       }
+       if (locked)
+               tree_mod_log_write_unlock(fs_info);
+       kfree(tm_list);
+       kfree(tm);
 
-       return __tree_mod_log_insert(fs_info, tm);
+       return ret;
 }
 
-static inline void
-__tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
+static inline int
+__tree_mod_log_free_eb(struct btrfs_fs_info *fs_info,
+                      struct tree_mod_elem **tm_list,
+                      int nritems)
 {
-       int i;
-       u32 nritems;
+       int i, j;
        int ret;
 
-       if (btrfs_header_level(eb) == 0)
-               return;
-
-       nritems = btrfs_header_nritems(eb);
        for (i = nritems - 1; i >= 0; i--) {
-               ret = __tree_mod_log_insert_key(fs_info, eb, i,
-                               MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS);
-               BUG_ON(ret < 0);
+               ret = __tree_mod_log_insert(fs_info, tm_list[i]);
+               if (ret) {
+                       for (j = nritems - 1; j > i; j--)
+                               rb_erase(&tm_list[j]->node,
+                                        &fs_info->tree_mod_log);
+                       return ret;
+               }
        }
+
+       return 0;
 }
 
 static noinline int
@@ -642,17 +702,38 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
                         struct extent_buffer *new_root, gfp_t flags,
                         int log_removal)
 {
-       struct tree_mod_elem *tm;
+       struct tree_mod_elem *tm = NULL;
+       struct tree_mod_elem **tm_list = NULL;
+       int nritems = 0;
+       int ret = 0;
+       int i;
 
-       if (tree_mod_dont_log(fs_info, NULL))
+       if (!tree_mod_need_log(fs_info, NULL))
                return 0;
 
-       if (log_removal)
-               __tree_mod_log_free_eb(fs_info, old_root);
+       if (log_removal && btrfs_header_level(old_root) > 0) {
+               nritems = btrfs_header_nritems(old_root);
+               tm_list = kzalloc(nritems * sizeof(struct tree_mod_elem *),
+                                 flags);
+               if (!tm_list) {
+                       ret = -ENOMEM;
+                       goto free_tms;
+               }
+               for (i = 0; i < nritems; i++) {
+                       tm_list[i] = alloc_tree_mod_elem(old_root, i,
+                           MOD_LOG_KEY_REMOVE_WHILE_FREEING, flags);
+                       if (!tm_list[i]) {
+                               ret = -ENOMEM;
+                               goto free_tms;
+                       }
+               }
+       }
 
        tm = kzalloc(sizeof(*tm), flags);
-       if (!tm)
-               return -ENOMEM;
+       if (!tm) {
+               ret = -ENOMEM;
+               goto free_tms;
+       }
 
        tm->index = new_root->start >> PAGE_CACHE_SHIFT;
        tm->old_root.logical = old_root->start;
@@ -660,7 +741,30 @@ tree_mod_log_insert_root(struct btrfs_fs_info *fs_info,
        tm->generation = btrfs_header_generation(old_root);
        tm->op = MOD_LOG_ROOT_REPLACE;
 
-       return __tree_mod_log_insert(fs_info, tm);
+       if (tree_mod_dont_log(fs_info, NULL))
+               goto free_tms;
+
+       if (tm_list)
+               ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems);
+       if (!ret)
+               ret = __tree_mod_log_insert(fs_info, tm);
+
+       tree_mod_log_write_unlock(fs_info);
+       if (ret)
+               goto free_tms;
+       kfree(tm_list);
+
+       return ret;
+
+free_tms:
+       if (tm_list) {
+               for (i = 0; i < nritems; i++)
+                       kfree(tm_list[i]);
+               kfree(tm_list);
+       }
+       kfree(tm);
+
+       return ret;
 }
 
 static struct tree_mod_elem *
@@ -729,31 +833,75 @@ tree_mod_log_search(struct btrfs_fs_info *fs_info, u64 start, u64 min_seq)
        return __tree_mod_log_search(fs_info, start, min_seq, 0);
 }
 
-static noinline void
+static noinline int
 tree_mod_log_eb_copy(struct btrfs_fs_info *fs_info, struct extent_buffer *dst,
                     struct extent_buffer *src, unsigned long dst_offset,
                     unsigned long src_offset, int nr_items)
 {
-       int ret;
+       int ret = 0;
+       struct tree_mod_elem **tm_list = NULL;
+       struct tree_mod_elem **tm_list_add, **tm_list_rem;
        int i;
+       int locked = 0;
 
-       if (tree_mod_dont_log(fs_info, NULL))
-               return;
+       if (!tree_mod_need_log(fs_info, NULL))
+               return 0;
 
        if (btrfs_header_level(dst) == 0 && btrfs_header_level(src) == 0)
-               return;
+               return 0;
+
+       tm_list = kzalloc(nr_items * 2 * sizeof(struct tree_mod_elem *),
+                         GFP_NOFS);
+       if (!tm_list)
+               return -ENOMEM;
 
+       tm_list_add = tm_list;
+       tm_list_rem = tm_list + nr_items;
        for (i = 0; i < nr_items; i++) {
-               ret = __tree_mod_log_insert_key(fs_info, src,
-                                               i + src_offset,
-                                               MOD_LOG_KEY_REMOVE, GFP_NOFS);
-               BUG_ON(ret < 0);
-               ret = __tree_mod_log_insert_key(fs_info, dst,
-                                                    i + dst_offset,
-                                                    MOD_LOG_KEY_ADD,
-                                                    GFP_NOFS);
-               BUG_ON(ret < 0);
+               tm_list_rem[i] = alloc_tree_mod_elem(src, i + src_offset,
+                   MOD_LOG_KEY_REMOVE, GFP_NOFS);
+               if (!tm_list_rem[i]) {
+                       ret = -ENOMEM;
+                       goto free_tms;
+               }
+
+               tm_list_add[i] = alloc_tree_mod_elem(dst, i + dst_offset,
+                   MOD_LOG_KEY_ADD, GFP_NOFS);
+               if (!tm_list_add[i]) {
+                       ret = -ENOMEM;
+                       goto free_tms;
+               }
        }
+
+       if (tree_mod_dont_log(fs_info, NULL))
+               goto free_tms;
+       locked = 1;
+
+       for (i = 0; i < nr_items; i++) {
+               ret = __tree_mod_log_insert(fs_info, tm_list_rem[i]);
+               if (ret)
+                       goto free_tms;
+               ret = __tree_mod_log_insert(fs_info, tm_list_add[i]);
+               if (ret)
+                       goto free_tms;
+       }
+
+       tree_mod_log_write_unlock(fs_info);
+       kfree(tm_list);
+
+       return 0;
+
+free_tms:
+       for (i = 0; i < nr_items * 2; i++) {
+               if (tm_list[i] && !RB_EMPTY_NODE(&tm_list[i]->node))
+                       rb_erase(&tm_list[i]->node, &fs_info->tree_mod_log);
+               kfree(tm_list[i]);
+       }
+       if (locked)
+               tree_mod_log_write_unlock(fs_info);
+       kfree(tm_list);
+
+       return ret;
 }
 
 static inline void
@@ -772,18 +920,58 @@ tree_mod_log_set_node_key(struct btrfs_fs_info *fs_info,
 {
        int ret;
 
-       ret = __tree_mod_log_insert_key(fs_info, eb, slot,
+       ret = tree_mod_log_insert_key(fs_info, eb, slot,
                                        MOD_LOG_KEY_REPLACE,
                                        atomic ? GFP_ATOMIC : GFP_NOFS);
        BUG_ON(ret < 0);
 }
 
-static noinline void
+static noinline int
 tree_mod_log_free_eb(struct btrfs_fs_info *fs_info, struct extent_buffer *eb)
 {
+       struct tree_mod_elem **tm_list = NULL;
+       int nritems = 0;
+       int i;
+       int ret = 0;
+
+       if (btrfs_header_level(eb) == 0)
+               return 0;
+
+       if (!tree_mod_need_log(fs_info, NULL))
+               return 0;
+
+       nritems = btrfs_header_nritems(eb);
+       tm_list = kzalloc(nritems * sizeof(struct tree_mod_elem *),
+                         GFP_NOFS);
+       if (!tm_list)
+               return -ENOMEM;
+
+       for (i = 0; i < nritems; i++) {
+               tm_list[i] = alloc_tree_mod_elem(eb, i,
+                   MOD_LOG_KEY_REMOVE_WHILE_FREEING, GFP_NOFS);
+               if (!tm_list[i]) {
+                       ret = -ENOMEM;
+                       goto free_tms;
+               }
+       }
+
        if (tree_mod_dont_log(fs_info, eb))
-               return;
-       __tree_mod_log_free_eb(fs_info, eb);
+               goto free_tms;
+
+       ret = __tree_mod_log_free_eb(fs_info, tm_list, nritems);
+       tree_mod_log_write_unlock(fs_info);
+       if (ret)
+               goto free_tms;
+       kfree(tm_list);
+
+       return 0;
+
+free_tms:
+       for (i = 0; i < nritems; i++)
+               kfree(tm_list[i]);
+       kfree(tm_list);
+
+       return ret;
 }
 
 static noinline void
@@ -1041,8 +1229,13 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                btrfs_set_node_ptr_generation(parent, parent_slot,
                                              trans->transid);
                btrfs_mark_buffer_dirty(parent);
-               if (last_ref)
-                       tree_mod_log_free_eb(root->fs_info, buf);
+               if (last_ref) {
+                       ret = tree_mod_log_free_eb(root->fs_info, buf);
+                       if (ret) {
+                               btrfs_abort_transaction(trans, root, ret);
+                               return ret;
+                       }
+               }
                btrfs_free_tree_block(trans, root, buf, parent_start,
                                      last_ref);
        }
@@ -1287,8 +1480,8 @@ get_old_root(struct btrfs_root *root, u64 time_seq)
                old = read_tree_block(root, logical, blocksize, 0);
                if (WARN_ON(!old || !extent_buffer_uptodate(old))) {
                        free_extent_buffer(old);
-                       pr_warn("btrfs: failed to read tree block %llu from get_old_root\n",
-                               logical);
+                       btrfs_warn(root->fs_info,
+                               "failed to read tree block %llu from get_old_root", logical);
                } else {
                        eb = btrfs_clone_extent_buffer(old);
                        free_extent_buffer(old);
@@ -2462,6 +2655,49 @@ static int key_search(struct extent_buffer *b, struct btrfs_key *key,
        return 0;
 }
 
+int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *found_path,
+               u64 iobjectid, u64 ioff, u8 key_type,
+               struct btrfs_key *found_key)
+{
+       int ret;
+       struct btrfs_key key;
+       struct extent_buffer *eb;
+       struct btrfs_path *path;
+
+       key.type = key_type;
+       key.objectid = iobjectid;
+       key.offset = ioff;
+
+       if (found_path == NULL) {
+               path = btrfs_alloc_path();
+               if (!path)
+                       return -ENOMEM;
+       } else
+               path = found_path;
+
+       ret = btrfs_search_slot(NULL, fs_root, &key, path, 0, 0);
+       if ((ret < 0) || (found_key == NULL)) {
+               if (path != found_path)
+                       btrfs_free_path(path);
+               return ret;
+       }
+
+       eb = path->nodes[0];
+       if (ret && path->slots[0] >= btrfs_header_nritems(eb)) {
+               ret = btrfs_next_leaf(fs_root, path);
+               if (ret)
+                       return ret;
+               eb = path->nodes[0];
+       }
+
+       btrfs_item_key_to_cpu(eb, found_key, path->slots[0]);
+       if (found_key->type != key.type ||
+                       found_key->objectid != key.objectid)
+               return 1;
+
+       return 0;
+}
+
 /*
  * look for key in the tree.  path is filled in with nodes along the way
  * if key is found, we return zero and you can find the item in the leaf
@@ -2495,6 +2731,7 @@ int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
        lowest_level = p->lowest_level;
        WARN_ON(lowest_level && ins_len > 0);
        WARN_ON(p->nodes[0] != NULL);
+       BUG_ON(!cow && ins_len);
 
        if (ins_len < 0) {
                lowest_unlock = 2;
@@ -2603,8 +2840,6 @@ again:
                        }
                }
 cow_done:
-               BUG_ON(!cow && ins_len);
-
                p->nodes[level] = b;
                btrfs_clear_path_blocking(p, NULL, 0);
 
@@ -2614,13 +2849,19 @@ cow_done:
                 * It is safe to drop the lock on our parent before we
                 * go through the expensive btree search on b.
                 *
-                * If cow is true, then we might be changing slot zero,
-                * which may require changing the parent.  So, we can't
-                * drop the lock until after we know which slot we're
-                * operating on.
+                * If we're inserting or deleting (ins_len != 0), then we might
+                * be changing slot zero, which may require changing the parent.
+                * So, we can't drop the lock until after we know which slot
+                * we're operating on.
                 */
-               if (!cow)
-                       btrfs_unlock_up_safe(p, level + 1);
+               if (!ins_len && !p->keep_locks) {
+                       int u = level + 1;
+
+                       if (u < BTRFS_MAX_LEVEL && p->locks[u]) {
+                               btrfs_tree_unlock_rw(p->nodes[u], p->locks[u]);
+                               p->locks[u] = 0;
+                       }
+               }
 
                ret = key_search(b, key, level, &prev_cmp, &slot);
 
@@ -2648,7 +2889,7 @@ cow_done:
                         * which means we must have a write lock
                         * on the parent
                         */
-                       if (slot == 0 && cow &&
+                       if (slot == 0 && ins_len &&
                            write_lock_level < level + 1) {
                                write_lock_level = level + 1;
                                btrfs_release_path(p);
@@ -2901,7 +3142,9 @@ again:
                        if (ret < 0)
                                return ret;
                        if (!ret) {
-                               p->slots[0] = btrfs_header_nritems(leaf) - 1;
+                               leaf = p->nodes[0];
+                               if (p->slots[0] == btrfs_header_nritems(leaf))
+                                       p->slots[0]--;
                                return 0;
                        }
                        if (!return_any)
@@ -3022,8 +3265,12 @@ static int push_node_left(struct btrfs_trans_handle *trans,
        } else
                push_items = min(src_nritems - 8, push_items);
 
-       tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0,
-                            push_items);
+       ret = tree_mod_log_eb_copy(root->fs_info, dst, src, dst_nritems, 0,
+                                  push_items);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               return ret;
+       }
        copy_extent_buffer(dst, src,
                           btrfs_node_key_ptr_offset(dst_nritems),
                           btrfs_node_key_ptr_offset(0),
@@ -3093,8 +3340,12 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
                                      (dst_nritems) *
                                      sizeof(struct btrfs_key_ptr));
 
-       tree_mod_log_eb_copy(root->fs_info, dst, src, 0,
-                            src_nritems - push_items, push_items);
+       ret = tree_mod_log_eb_copy(root->fs_info, dst, src, 0,
+                                  src_nritems - push_items, push_items);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               return ret;
+       }
        copy_extent_buffer(dst, src,
                           btrfs_node_key_ptr_offset(0),
                           btrfs_node_key_ptr_offset(src_nritems - push_items),
@@ -3295,7 +3546,12 @@ static noinline int split_node(struct btrfs_trans_handle *trans,
                            btrfs_header_chunk_tree_uuid(split),
                            BTRFS_UUID_SIZE);
 
-       tree_mod_log_eb_copy(root->fs_info, split, c, 0, mid, c_nritems - mid);
+       ret = tree_mod_log_eb_copy(root->fs_info, split, c, 0,
+                                  mid, c_nritems - mid);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               return ret;
+       }
        copy_extent_buffer(split, c,
                           btrfs_node_key_ptr_offset(0),
                           btrfs_node_key_ptr_offset(mid),
@@ -3362,8 +3618,8 @@ noinline int btrfs_leaf_free_space(struct btrfs_root *root,
        int ret;
        ret = BTRFS_LEAF_DATA_SIZE(root) - leaf_space_used(leaf, 0, nritems);
        if (ret < 0) {
-               printk(KERN_CRIT "leaf free space ret %d, leaf data size %lu, "
-                      "used %d nritems %d\n",
+               btrfs_crit(root->fs_info,
+                       "leaf free space ret %d, leaf data size %lu, used %d nritems %d",
                       ret, (unsigned long) BTRFS_LEAF_DATA_SIZE(root),
                       leaf_space_used(leaf, 0, nritems), nritems);
        }
@@ -3571,6 +3827,19 @@ static int push_leaf_right(struct btrfs_trans_handle *trans, struct btrfs_root
        if (left_nritems == 0)
                goto out_unlock;
 
+       if (path->slots[0] == left_nritems && !empty) {
+               /* Key greater than all keys in the leaf, right neighbor has
+                * enough room for it and we're not emptying our leaf to delete
+                * it, therefore use right neighbor to insert the new item and
+                * no need to touch/dirty our left leaft. */
+               btrfs_tree_unlock(left);
+               free_extent_buffer(left);
+               path->nodes[0] = right;
+               path->slots[0] = 0;
+               path->slots[1]++;
+               return 0;
+       }
+
        return __push_leaf_right(trans, root, path, min_data_size, empty,
                                right, free_space, left_nritems, min_slot);
 out_unlock:
@@ -3887,14 +4156,17 @@ static noinline int push_for_double_split(struct btrfs_trans_handle *trans,
        int progress = 0;
        int slot;
        u32 nritems;
+       int space_needed = data_size;
 
        slot = path->slots[0];
+       if (slot < btrfs_header_nritems(path->nodes[0]))
+               space_needed -= btrfs_leaf_free_space(root, path->nodes[0]);
 
        /*
         * try to push all the items after our slot into the
         * right leaf
         */
-       ret = push_leaf_right(trans, root, path, 1, data_size, 0, slot);
+       ret = push_leaf_right(trans, root, path, 1, space_needed, 0, slot);
        if (ret < 0)
                return ret;
 
@@ -3914,7 +4186,7 @@ static noinline int push_for_double_split(struct btrfs_trans_handle *trans,
 
        /* try to push all the items before our slot into the next leaf */
        slot = path->slots[0];
-       ret = push_leaf_left(trans, root, path, 1, data_size, 0, slot);
+       ret = push_leaf_left(trans, root, path, 1, space_needed, 0, slot);
        if (ret < 0)
                return ret;
 
@@ -3958,13 +4230,18 @@ static noinline int split_leaf(struct btrfs_trans_handle *trans,
 
        /* first try to make some room by pushing left and right */
        if (data_size && path->nodes[1]) {
-               wret = push_leaf_right(trans, root, path, data_size,
-                                      data_size, 0, 0);
+               int space_needed = data_size;
+
+               if (slot < btrfs_header_nritems(l))
+                       space_needed -= btrfs_leaf_free_space(root, l);
+
+               wret = push_leaf_right(trans, root, path, space_needed,
+                                      space_needed, 0, 0);
                if (wret < 0)
                        return wret;
                if (wret) {
-                       wret = push_leaf_left(trans, root, path, data_size,
-                                             data_size, 0, (u32)-1);
+                       wret = push_leaf_left(trans, root, path, space_needed,
+                                             space_needed, 0, (u32)-1);
                        if (wret < 0)
                                return wret;
                }
@@ -4432,7 +4709,7 @@ void btrfs_extend_item(struct btrfs_root *root, struct btrfs_path *path,
        BUG_ON(slot < 0);
        if (slot >= nritems) {
                btrfs_print_leaf(root, leaf);
-               printk(KERN_CRIT "slot %d too large, nritems %d\n",
+               btrfs_crit(root->fs_info, "slot %d too large, nritems %d",
                       slot, nritems);
                BUG_ON(1);
        }
@@ -4495,7 +4772,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
 
        if (btrfs_leaf_free_space(root, leaf) < total_size) {
                btrfs_print_leaf(root, leaf);
-               printk(KERN_CRIT "not enough freespace need %u have %d\n",
+               btrfs_crit(root->fs_info, "not enough freespace need %u have %d",
                       total_size, btrfs_leaf_free_space(root, leaf));
                BUG();
        }
@@ -4505,7 +4782,7 @@ void setup_items_for_insert(struct btrfs_root *root, struct btrfs_path *path,
 
                if (old_data < data_end) {
                        btrfs_print_leaf(root, leaf);
-                       printk(KERN_CRIT "slot %d old_data %d data_end %d\n",
+                       btrfs_crit(root->fs_info, "slot %d old_data %d data_end %d",
                               slot, old_data, data_end);
                        BUG_ON(1);
                }
@@ -4817,7 +5094,7 @@ int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
  * This may release the path, and so you may lose any locks held at the
  * time you call it.
  */
-static int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
+int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path)
 {
        struct btrfs_key key;
        struct btrfs_disk_key found_key;
@@ -5240,7 +5517,7 @@ int btrfs_compare_trees(struct btrfs_root *left_root,
 
                        if (!left_start_ctransid || !right_start_ctransid) {
                                WARN(1, KERN_WARNING
-                                       "btrfs: btrfs_compare_tree detected "
+                                       "BTRFS: btrfs_compare_tree detected "
                                        "a change in one of the trees while "
                                        "iterating. This is probably a "
                                        "bug.\n");
@@ -5680,3 +5957,46 @@ int btrfs_previous_item(struct btrfs_root *root,
        }
        return 1;
 }
+
+/*
+ * search in extent tree to find a previous Metadata/Data extent item with
+ * min objecitd.
+ *
+ * returns 0 if something is found, 1 if nothing was found and < 0 on error
+ */
+int btrfs_previous_extent_item(struct btrfs_root *root,
+                       struct btrfs_path *path, u64 min_objectid)
+{
+       struct btrfs_key found_key;
+       struct extent_buffer *leaf;
+       u32 nritems;
+       int ret;
+
+       while (1) {
+               if (path->slots[0] == 0) {
+                       btrfs_set_path_blocking(path);
+                       ret = btrfs_prev_leaf(root, path);
+                       if (ret != 0)
+                               return ret;
+               } else {
+                       path->slots[0]--;
+               }
+               leaf = path->nodes[0];
+               nritems = btrfs_header_nritems(leaf);
+               if (nritems == 0)
+                       return 1;
+               if (path->slots[0] == nritems)
+                       path->slots[0]--;
+
+               btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
+               if (found_key.objectid < min_objectid)
+                       break;
+               if (found_key.type == BTRFS_EXTENT_ITEM_KEY ||
+                   found_key.type == BTRFS_METADATA_ITEM_KEY)
+                       return 0;
+               if (found_key.objectid == min_objectid &&
+                   found_key.type < BTRFS_EXTENT_ITEM_KEY)
+                       break;
+       }
+       return 1;
+}
index 54ab86127f7af49500f6a0bf2bf4b63cd6074c40..2c1a42ca519f43a8dd85ce95a24fc6ed0a22d07d 100644 (file)
@@ -521,9 +521,15 @@ struct btrfs_super_block {
 #define BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF   (1ULL << 6)
 #define BTRFS_FEATURE_INCOMPAT_RAID56          (1ULL << 7)
 #define BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA (1ULL << 8)
+#define BTRFS_FEATURE_INCOMPAT_NO_HOLES                (1ULL << 9)
 
 #define BTRFS_FEATURE_COMPAT_SUPP              0ULL
+#define BTRFS_FEATURE_COMPAT_SAFE_SET          0ULL
+#define BTRFS_FEATURE_COMPAT_SAFE_CLEAR                0ULL
 #define BTRFS_FEATURE_COMPAT_RO_SUPP           0ULL
+#define BTRFS_FEATURE_COMPAT_RO_SAFE_SET       0ULL
+#define BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR     0ULL
+
 #define BTRFS_FEATURE_INCOMPAT_SUPP                    \
        (BTRFS_FEATURE_INCOMPAT_MIXED_BACKREF |         \
         BTRFS_FEATURE_INCOMPAT_DEFAULT_SUBVOL |        \
@@ -532,7 +538,12 @@ struct btrfs_super_block {
         BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO |          \
         BTRFS_FEATURE_INCOMPAT_RAID56 |                \
         BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF |         \
-        BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA)
+        BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA |       \
+        BTRFS_FEATURE_INCOMPAT_NO_HOLES)
+
+#define BTRFS_FEATURE_INCOMPAT_SAFE_SET                        \
+       (BTRFS_FEATURE_INCOMPAT_EXTENDED_IREF)
+#define BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR              0ULL
 
 /*
  * A leaf is full of items. offset and size tell us where to find
@@ -1094,7 +1105,7 @@ struct btrfs_qgroup_limit_item {
 } __attribute__ ((__packed__));
 
 struct btrfs_space_info {
-       u64 flags;
+       spinlock_t lock;
 
        u64 total_bytes;        /* total bytes in the space,
                                   this doesn't take mirrors into account */
@@ -1104,14 +1115,25 @@ struct btrfs_space_info {
                                   transaction finishes */
        u64 bytes_reserved;     /* total bytes the allocator has reserved for
                                   current allocations */
-       u64 bytes_readonly;     /* total bytes that are read only */
-
        u64 bytes_may_use;      /* number of bytes that may be used for
                                   delalloc/allocations */
+       u64 bytes_readonly;     /* total bytes that are read only */
+
+       unsigned int full:1;    /* indicates that we cannot allocate any more
+                                  chunks for this space */
+       unsigned int chunk_alloc:1;     /* set if we are allocating a chunk */
+
+       unsigned int flush:1;           /* set if we are trying to make space */
+
+       unsigned int force_alloc;       /* set if we need to force a chunk
+                                          alloc for this space */
+
        u64 disk_used;          /* total bytes used on disk */
        u64 disk_total;         /* total bytes on disk, takes mirrors into
                                   account */
 
+       u64 flags;
+
        /*
         * bytes_pinned is kept in line with what is actually pinned, as in
         * we've called update_block_group and dropped the bytes_used counter
@@ -1124,22 +1146,15 @@ struct btrfs_space_info {
         */
        struct percpu_counter total_bytes_pinned;
 
-       unsigned int full:1;    /* indicates that we cannot allocate any more
-                                  chunks for this space */
-       unsigned int chunk_alloc:1;     /* set if we are allocating a chunk */
-
-       unsigned int flush:1;           /* set if we are trying to make space */
-
-       unsigned int force_alloc;       /* set if we need to force a chunk
-                                          alloc for this space */
-
        struct list_head list;
 
+       struct rw_semaphore groups_sem;
        /* for block groups in our same type */
        struct list_head block_groups[BTRFS_NR_RAID_TYPES];
-       spinlock_t lock;
-       struct rw_semaphore groups_sem;
        wait_queue_head_t wait;
+
+       struct kobject kobj;
+       struct kobject block_group_kobjs[BTRFS_NR_RAID_TYPES];
 };
 
 #define        BTRFS_BLOCK_RSV_GLOBAL          1
@@ -1346,6 +1361,7 @@ struct btrfs_fs_info {
 
        u64 generation;
        u64 last_trans_committed;
+       u64 avg_delayed_ref_runtime;
 
        /*
         * this is updated to the current trans every time a full commit
@@ -1448,7 +1464,6 @@ struct btrfs_fs_info {
        spinlock_t tree_mod_seq_lock;
        atomic64_t tree_mod_seq;
        struct list_head tree_mod_seq_list;
-       struct seq_list tree_mod_seq_elem;
 
        /* this protects tree_mod_log */
        rwlock_t tree_mod_log_lock;
@@ -1515,6 +1530,8 @@ struct btrfs_fs_info {
        int thread_pool_size;
 
        struct kobject super_kobj;
+       struct kobject *space_info_kobj;
+       struct kobject *device_dir_kobj;
        struct completion kobj_unregister;
        int do_barriers;
        int closing;
@@ -1643,6 +1660,10 @@ struct btrfs_fs_info {
        spinlock_t reada_lock;
        struct radix_tree_root reada_tree;
 
+       /* Extent buffer radix tree */
+       spinlock_t buffer_lock;
+       struct radix_tree_root buffer_radix;
+
        /* next backup root to be overwritten */
        int backup_root_index;
 
@@ -1795,6 +1816,12 @@ struct btrfs_root {
        struct list_head ordered_extents;
        struct list_head ordered_root;
        u64 nr_ordered_extents;
+
+       /*
+        * Number of currently running SEND ioctls to prevent
+        * manipulation with the read-only status via SUBVOL_SETFLAGS
+        */
+       int send_in_progress;
 };
 
 struct btrfs_ioctl_defrag_range_args {
@@ -1997,6 +2024,7 @@ struct btrfs_ioctl_defrag_range_args {
 #define BTRFS_MOUNT_CHECK_INTEGRITY_INCLUDING_EXTENT_DATA (1 << 21)
 #define BTRFS_MOUNT_PANIC_ON_FATAL_ERROR       (1 << 22)
 #define BTRFS_MOUNT_RESCAN_UUID_TREE   (1 << 23)
+#define        BTRFS_MOUNT_CHANGE_INODE_CACHE  (1 << 24)
 
 #define BTRFS_DEFAULT_COMMIT_INTERVAL  (30)
 
@@ -2925,6 +2953,10 @@ BTRFS_SETGET_STACK_FUNCS(stack_file_extent_generation,
                         struct btrfs_file_extent_item, generation, 64);
 BTRFS_SETGET_STACK_FUNCS(stack_file_extent_num_bytes,
                         struct btrfs_file_extent_item, num_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_disk_num_bytes,
+                        struct btrfs_file_extent_item, disk_num_bytes, 64);
+BTRFS_SETGET_STACK_FUNCS(stack_file_extent_compression,
+                        struct btrfs_file_extent_item, compression, 8);
 
 static inline unsigned long
 btrfs_file_extent_inline_start(struct btrfs_file_extent_item *e)
@@ -2958,15 +2990,6 @@ BTRFS_SETGET_FUNCS(file_extent_encryption, struct btrfs_file_extent_item,
 BTRFS_SETGET_FUNCS(file_extent_other_encoding, struct btrfs_file_extent_item,
                   other_encoding, 16);
 
-/* this returns the number of file bytes represented by the inline item.
- * If an item is compressed, this is the uncompressed size
- */
-static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
-                                              struct btrfs_file_extent_item *e)
-{
-       return btrfs_file_extent_ram_bytes(eb, e);
-}
-
 /*
  * this returns the number of bytes used by the item on disk, minus the
  * size of any extent headers.  If a file is compressed on disk, this is
@@ -2980,6 +3003,32 @@ static inline u32 btrfs_file_extent_inline_item_len(struct extent_buffer *eb,
        return btrfs_item_size(eb, e) - offset;
 }
 
+/* this returns the number of file bytes represented by the inline item.
+ * If an item is compressed, this is the uncompressed size
+ */
+static inline u32 btrfs_file_extent_inline_len(struct extent_buffer *eb,
+                                              int slot,
+                                              struct btrfs_file_extent_item *fi)
+{
+       struct btrfs_map_token token;
+
+       btrfs_init_map_token(&token);
+       /*
+        * return the space used on disk if this item isn't
+        * compressed or encoded
+        */
+       if (btrfs_token_file_extent_compression(eb, fi, &token) == 0 &&
+           btrfs_token_file_extent_encryption(eb, fi, &token) == 0 &&
+           btrfs_token_file_extent_other_encoding(eb, fi, &token) == 0) {
+               return btrfs_file_extent_inline_item_len(eb,
+                                                        btrfs_item_nr(slot));
+       }
+
+       /* otherwise use the ram bytes field */
+       return btrfs_token_file_extent_ram_bytes(eb, fi, &token);
+}
+
+
 /* btrfs_dev_stats_item */
 static inline u64 btrfs_dev_stats_value(struct extent_buffer *eb,
                                        struct btrfs_dev_stats_item *ptr,
@@ -3143,6 +3192,8 @@ static inline u64 btrfs_calc_trunc_metadata_size(struct btrfs_root *root,
 
 int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans,
                                       struct btrfs_root *root);
+int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans,
+                                      struct btrfs_root *root);
 void btrfs_put_block_group(struct btrfs_block_group_cache *cache);
 int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root, unsigned long count);
@@ -3163,6 +3214,7 @@ struct btrfs_block_group_cache *btrfs_lookup_block_group(
                                                 struct btrfs_fs_info *info,
                                                 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,
@@ -3301,6 +3353,8 @@ int btrfs_comp_cpu_keys(struct btrfs_key *k1, struct btrfs_key *k2);
 int btrfs_previous_item(struct btrfs_root *root,
                        struct btrfs_path *path, u64 min_objectid,
                        int type);
+int btrfs_previous_extent_item(struct btrfs_root *root,
+                       struct btrfs_path *path, u64 min_objectid);
 void btrfs_set_item_key_safe(struct btrfs_root *root, struct btrfs_path *path,
                             struct btrfs_key *new_key);
 struct extent_buffer *btrfs_root_node(struct btrfs_root *root);
@@ -3350,6 +3404,8 @@ int btrfs_duplicate_item(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root,
                         struct btrfs_path *path,
                         struct btrfs_key *new_key);
+int btrfs_find_item(struct btrfs_root *fs_root, struct btrfs_path *path,
+               u64 inum, u64 ioff, u8 key_type, struct btrfs_key *found_key);
 int btrfs_search_slot(struct btrfs_trans_handle *trans, struct btrfs_root
                      *root, struct btrfs_key *key, struct btrfs_path *p, int
                      ins_len, int cow);
@@ -3399,6 +3455,7 @@ static inline int btrfs_insert_empty_item(struct btrfs_trans_handle *trans,
 }
 
 int btrfs_next_leaf(struct btrfs_root *root, struct btrfs_path *path);
+int btrfs_prev_leaf(struct btrfs_root *root, struct btrfs_path *path);
 int btrfs_next_old_leaf(struct btrfs_root *root, struct btrfs_path *path,
                        u64 time_seq);
 static inline int btrfs_next_old_item(struct btrfs_root *root,
@@ -3563,12 +3620,6 @@ int btrfs_del_inode_ref(struct btrfs_trans_handle *trans,
                           struct btrfs_root *root,
                           const char *name, int name_len,
                           u64 inode_objectid, u64 ref_objectid, u64 *index);
-int btrfs_get_inode_ref_index(struct btrfs_trans_handle *trans,
-                             struct btrfs_root *root,
-                             struct btrfs_path *path,
-                             const char *name, int name_len,
-                             u64 inode_objectid, u64 ref_objectid, int mod,
-                             u64 *ret_index);
 int btrfs_insert_empty_inode(struct btrfs_trans_handle *trans,
                             struct btrfs_root *root,
                             struct btrfs_path *path, u64 objectid);
@@ -3676,7 +3727,9 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput);
 int btrfs_set_extent_delalloc(struct inode *inode, u64 start, u64 end,
                              struct extent_state **cached_state);
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *new_root, u64 new_dirid);
+                            struct btrfs_root *new_root,
+                            struct btrfs_root *parent_root,
+                            u64 new_dirid);
 int btrfs_merge_bio_hook(int rw, struct page *page, unsigned long offset,
                         size_t size, struct bio *bio,
                         unsigned long bio_flags);
@@ -3745,7 +3798,10 @@ extern const struct file_operations btrfs_file_operations;
 int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root, struct inode *inode,
                         struct btrfs_path *path, u64 start, u64 end,
-                        u64 *drop_end, int drop_cache);
+                        u64 *drop_end, int drop_cache,
+                        int replace_extent,
+                        u32 extent_item_size,
+                        int *key_inserted);
 int btrfs_drop_extents(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root, struct inode *inode, u64 start,
                       u64 end, int drop_cache);
@@ -3764,6 +3820,8 @@ int btrfs_defrag_leaves(struct btrfs_trans_handle *trans,
 /* sysfs.c */
 int btrfs_init_sysfs(void);
 void btrfs_exit_sysfs(void);
+int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info);
+void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info);
 
 /* xattr.c */
 ssize_t btrfs_listxattr(struct dentry *dentry, char *buffer, size_t size);
@@ -3796,14 +3854,20 @@ void btrfs_printk(const struct btrfs_fs_info *fs_info, const char *fmt, ...)
        btrfs_printk(fs_info, KERN_NOTICE fmt, ##args)
 #define btrfs_info(fs_info, fmt, args...) \
        btrfs_printk(fs_info, KERN_INFO fmt, ##args)
+
+#ifdef DEBUG
 #define btrfs_debug(fs_info, fmt, args...) \
        btrfs_printk(fs_info, KERN_DEBUG fmt, ##args)
+#else
+#define btrfs_debug(fs_info, fmt, args...) \
+    no_printk(KERN_DEBUG fmt, ##args)
+#endif
 
 #ifdef CONFIG_BTRFS_ASSERT
 
 static inline void assfail(char *expr, char *file, int line)
 {
-       printk(KERN_ERR "BTRFS assertion failed: %s, file: %s, line: %d",
+       pr_err("BTRFS: assertion failed: %s, file: %s, line: %d",
               expr, file, line);
        BUG();
 }
@@ -3841,7 +3905,7 @@ static inline void __btrfs_set_fs_incompat(struct btrfs_fs_info *fs_info,
                if (!(features & flag)) {
                        features |= flag;
                        btrfs_set_super_incompat_flags(disk_super, features);
-                       printk(KERN_INFO "btrfs: setting %llu feature flag\n",
+                       btrfs_info(fs_info, "setting %llu feature flag",
                                         flag);
                }
                spin_unlock(&fs_info->super_lock);
@@ -3899,20 +3963,17 @@ do {                                                                    \
 /* acl.c */
 #ifdef CONFIG_BTRFS_FS_POSIX_ACL
 struct posix_acl *btrfs_get_acl(struct inode *inode, int type);
+int btrfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 int btrfs_init_acl(struct btrfs_trans_handle *trans,
                   struct inode *inode, struct inode *dir);
-int btrfs_acl_chmod(struct inode *inode);
 #else
 #define btrfs_get_acl NULL
+#define btrfs_set_acl NULL
 static inline int btrfs_init_acl(struct btrfs_trans_handle *trans,
                                 struct inode *inode, struct inode *dir)
 {
        return 0;
 }
-static inline int btrfs_acl_chmod(struct inode *inode)
-{
-       return 0;
-}
 #endif
 
 /* relocation.c */
index 8d292fbae659eff6a65bd7a8c255d741d998635e..451b00c86f6c0a038ed532f29855009abaa1d8a3 100644 (file)
@@ -55,8 +55,7 @@ static inline void btrfs_init_delayed_node(
        delayed_node->inode_id = inode_id;
        atomic_set(&delayed_node->refs, 0);
        delayed_node->count = 0;
-       delayed_node->in_list = 0;
-       delayed_node->inode_dirty = 0;
+       delayed_node->flags = 0;
        delayed_node->ins_root = RB_ROOT;
        delayed_node->del_root = RB_ROOT;
        mutex_init(&delayed_node->mutex);
@@ -172,7 +171,7 @@ static void btrfs_queue_delayed_node(struct btrfs_delayed_root *root,
                                     int mod)
 {
        spin_lock(&root->lock);
-       if (node->in_list) {
+       if (test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) {
                if (!list_empty(&node->p_list))
                        list_move_tail(&node->p_list, &root->prepare_list);
                else if (mod)
@@ -182,7 +181,7 @@ static void btrfs_queue_delayed_node(struct btrfs_delayed_root *root,
                list_add_tail(&node->p_list, &root->prepare_list);
                atomic_inc(&node->refs);        /* inserted into list */
                root->nodes++;
-               node->in_list = 1;
+               set_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags);
        }
        spin_unlock(&root->lock);
 }
@@ -192,13 +191,13 @@ static void btrfs_dequeue_delayed_node(struct btrfs_delayed_root *root,
                                       struct btrfs_delayed_node *node)
 {
        spin_lock(&root->lock);
-       if (node->in_list) {
+       if (test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) {
                root->nodes--;
                atomic_dec(&node->refs);        /* not in the list */
                list_del_init(&node->n_list);
                if (!list_empty(&node->p_list))
                        list_del_init(&node->p_list);
-               node->in_list = 0;
+               clear_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags);
        }
        spin_unlock(&root->lock);
 }
@@ -231,7 +230,8 @@ static struct btrfs_delayed_node *btrfs_next_delayed_node(
 
        delayed_root = node->root->fs_info->delayed_root;
        spin_lock(&delayed_root->lock);
-       if (!node->in_list) {   /* not in the list */
+       if (!test_bit(BTRFS_DELAYED_NODE_IN_LIST, &node->flags)) {
+               /* not in the list */
                if (list_empty(&delayed_root->node_list))
                        goto out;
                p = delayed_root->node_list.next;
@@ -1004,9 +1004,10 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node)
 {
        struct btrfs_delayed_root *delayed_root;
 
-       if (delayed_node && delayed_node->inode_dirty) {
+       if (delayed_node &&
+           test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
                BUG_ON(!delayed_node->root);
-               delayed_node->inode_dirty = 0;
+               clear_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags);
                delayed_node->count--;
 
                delayed_root = delayed_node->root->fs_info->delayed_root;
@@ -1014,6 +1015,18 @@ static void btrfs_release_delayed_inode(struct btrfs_delayed_node *delayed_node)
        }
 }
 
+static void btrfs_release_delayed_iref(struct btrfs_delayed_node *delayed_node)
+{
+       struct btrfs_delayed_root *delayed_root;
+
+       ASSERT(delayed_node->root);
+       clear_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags);
+       delayed_node->count--;
+
+       delayed_root = delayed_node->root->fs_info->delayed_root;
+       finish_one_item(delayed_root);
+}
+
 static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
                                        struct btrfs_root *root,
                                        struct btrfs_path *path,
@@ -1022,13 +1035,19 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
        struct btrfs_key key;
        struct btrfs_inode_item *inode_item;
        struct extent_buffer *leaf;
+       int mod;
        int ret;
 
        key.objectid = node->inode_id;
        btrfs_set_key_type(&key, BTRFS_INODE_ITEM_KEY);
        key.offset = 0;
 
-       ret = btrfs_lookup_inode(trans, root, path, &key, 1);
+       if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags))
+               mod = -1;
+       else
+               mod = 1;
+
+       ret = btrfs_lookup_inode(trans, root, path, &key, mod);
        if (ret > 0) {
                btrfs_release_path(path);
                return -ENOENT;
@@ -1036,19 +1055,58 @@ static int __btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
                return ret;
        }
 
-       btrfs_unlock_up_safe(path, 1);
        leaf = path->nodes[0];
        inode_item = btrfs_item_ptr(leaf, path->slots[0],
                                    struct btrfs_inode_item);
        write_extent_buffer(leaf, &node->inode_item, (unsigned long)inode_item,
                            sizeof(struct btrfs_inode_item));
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_release_path(path);
 
+       if (!test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &node->flags))
+               goto no_iref;
+
+       path->slots[0]++;
+       if (path->slots[0] >= btrfs_header_nritems(leaf))
+               goto search;
+again:
+       btrfs_item_key_to_cpu(leaf, &key, path->slots[0]);
+       if (key.objectid != node->inode_id)
+               goto out;
+
+       if (key.type != BTRFS_INODE_REF_KEY &&
+           key.type != BTRFS_INODE_EXTREF_KEY)
+               goto out;
+
+       /*
+        * Delayed iref deletion is for the inode who has only one link,
+        * so there is only one iref. The case that several irefs are
+        * in the same item doesn't exist.
+        */
+       btrfs_del_item(trans, root, path);
+out:
+       btrfs_release_delayed_iref(node);
+no_iref:
+       btrfs_release_path(path);
+err_out:
        btrfs_delayed_inode_release_metadata(root, node);
        btrfs_release_delayed_inode(node);
 
-       return 0;
+       return ret;
+
+search:
+       btrfs_release_path(path);
+
+       btrfs_set_key_type(&key, BTRFS_INODE_EXTREF_KEY);
+       key.offset = -1;
+       ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
+       if (ret < 0)
+               goto err_out;
+       ASSERT(ret);
+
+       ret = 0;
+       leaf = path->nodes[0];
+       path->slots[0]--;
+       goto again;
 }
 
 static inline int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
@@ -1059,7 +1117,7 @@ static inline int btrfs_update_delayed_inode(struct btrfs_trans_handle *trans,
        int ret;
 
        mutex_lock(&node->mutex);
-       if (!node->inode_dirty) {
+       if (!test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &node->flags)) {
                mutex_unlock(&node->mutex);
                return 0;
        }
@@ -1203,7 +1261,7 @@ int btrfs_commit_inode_delayed_inode(struct inode *inode)
                return 0;
 
        mutex_lock(&delayed_node->mutex);
-       if (!delayed_node->inode_dirty) {
+       if (!test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
                mutex_unlock(&delayed_node->mutex);
                btrfs_release_delayed_node(delayed_node);
                return 0;
@@ -1227,7 +1285,7 @@ int btrfs_commit_inode_delayed_inode(struct inode *inode)
        trans->block_rsv = &delayed_node->root->fs_info->delayed_block_rsv;
 
        mutex_lock(&delayed_node->mutex);
-       if (delayed_node->inode_dirty)
+       if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags))
                ret = __btrfs_update_delayed_inode(trans, delayed_node->root,
                                                   path, delayed_node);
        else
@@ -1300,36 +1358,9 @@ again:
        trans->block_rsv = &root->fs_info->delayed_block_rsv;
 
        __btrfs_commit_inode_delayed_items(trans, path, delayed_node);
-       /*
-        * Maybe new delayed items have been inserted, so we need requeue
-        * the work. Besides that, we must dequeue the empty delayed nodes
-        * to avoid the race between delayed items balance and the worker.
-        * The race like this:
-        *      Task1                           Worker thread
-        *                                      count == 0, needn't requeue
-        *                                        also needn't insert the
-        *                                        delayed node into prepare
-        *                                        list again.
-        *      add lots of delayed items
-        *      queue the delayed node
-        *        already in the list,
-        *        and not in the prepare
-        *        list, it means the delayed
-        *        node is being dealt with
-        *        by the worker.
-        *      do delayed items balance
-        *        the delayed node is being
-        *        dealt with by the worker
-        *        now, just wait.
-        *                                      the worker goto idle.
-        * Task1 will sleep until the transaction is commited.
-        */
-       mutex_lock(&delayed_node->mutex);
-       btrfs_dequeue_delayed_node(root->fs_info->delayed_root, delayed_node);
-       mutex_unlock(&delayed_node->mutex);
 
        trans->block_rsv = block_rsv;
-       btrfs_end_transaction_dmeta(trans, root);
+       btrfs_end_transaction(trans, root);
        btrfs_btree_balance_dirty_nodelay(root);
 
 release_path:
@@ -1376,52 +1407,41 @@ void btrfs_assert_delayed_root_empty(struct btrfs_root *root)
        WARN_ON(btrfs_first_delayed_node(delayed_root));
 }
 
-static int refs_newer(struct btrfs_delayed_root *delayed_root,
-                     int seq, int count)
+static int could_end_wait(struct btrfs_delayed_root *delayed_root, int seq)
 {
        int val = atomic_read(&delayed_root->items_seq);
 
-       if (val < seq || val >= seq + count)
+       if (val < seq || val >= seq + BTRFS_DELAYED_BATCH)
+               return 1;
+
+       if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND)
                return 1;
+
        return 0;
 }
 
 void btrfs_balance_delayed_items(struct btrfs_root *root)
 {
        struct btrfs_delayed_root *delayed_root;
-       int seq;
 
        delayed_root = btrfs_get_delayed_root(root);
 
        if (atomic_read(&delayed_root->items) < BTRFS_DELAYED_BACKGROUND)
                return;
 
-       seq = atomic_read(&delayed_root->items_seq);
-
        if (atomic_read(&delayed_root->items) >= BTRFS_DELAYED_WRITEBACK) {
+               int seq;
                int ret;
-               DEFINE_WAIT(__wait);
+
+               seq = atomic_read(&delayed_root->items_seq);
 
                ret = btrfs_wq_run_delayed_node(delayed_root, root, 0);
                if (ret)
                        return;
 
-               while (1) {
-                       prepare_to_wait(&delayed_root->wait, &__wait,
-                                       TASK_INTERRUPTIBLE);
-
-                       if (refs_newer(delayed_root, seq,
-                                      BTRFS_DELAYED_BATCH) ||
-                           atomic_read(&delayed_root->items) <
-                           BTRFS_DELAYED_BACKGROUND) {
-                               break;
-                       }
-                       if (!signal_pending(current))
-                               schedule();
-                       else
-                               break;
-               }
-               finish_wait(&delayed_root->wait, &__wait);
+               wait_event_interruptible(delayed_root->wait,
+                                        could_end_wait(delayed_root, seq));
+               return;
        }
 
        btrfs_wq_run_delayed_node(delayed_root, root, BTRFS_DELAYED_BATCH);
@@ -1472,9 +1492,9 @@ int btrfs_insert_delayed_dir_index(struct btrfs_trans_handle *trans,
        mutex_lock(&delayed_node->mutex);
        ret = __btrfs_add_delayed_insertion_item(delayed_node, delayed_item);
        if (unlikely(ret)) {
-               printk(KERN_ERR "err add delayed dir index item(name: %.*s) "
+               btrfs_err(root->fs_info, "err add delayed dir index item(name: %.*s) "
                                "into the insertion tree of the delayed node"
-                               "(root id: %llu, inode id: %llu, errno: %d)\n",
+                               "(root id: %llu, inode id: %llu, errno: %d)",
                                name_len, name, delayed_node->root->objectid,
                                delayed_node->inode_id, ret);
                BUG();
@@ -1544,9 +1564,9 @@ int btrfs_delete_delayed_dir_index(struct btrfs_trans_handle *trans,
        mutex_lock(&node->mutex);
        ret = __btrfs_add_delayed_deletion_item(node, item);
        if (unlikely(ret)) {
-               printk(KERN_ERR "err add delayed dir index item(index: %llu) "
+               btrfs_err(root->fs_info, "err add delayed dir index item(index: %llu) "
                                "into the deletion tree of the delayed node"
-                               "(root id: %llu, inode id: %llu, errno: %d)\n",
+                               "(root id: %llu, inode id: %llu, errno: %d)",
                                index, node->root->objectid, node->inode_id,
                                ret);
                BUG();
@@ -1759,7 +1779,7 @@ int btrfs_fill_inode(struct inode *inode, u32 *rdev)
                return -ENOENT;
 
        mutex_lock(&delayed_node->mutex);
-       if (!delayed_node->inode_dirty) {
+       if (!test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
                mutex_unlock(&delayed_node->mutex);
                btrfs_release_delayed_node(delayed_node);
                return -ENOENT;
@@ -1810,7 +1830,7 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
                return PTR_ERR(delayed_node);
 
        mutex_lock(&delayed_node->mutex);
-       if (delayed_node->inode_dirty) {
+       if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
                fill_stack_inode_item(trans, &delayed_node->inode_item, inode);
                goto release_node;
        }
@@ -1821,7 +1841,7 @@ int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
                goto release_node;
 
        fill_stack_inode_item(trans, &delayed_node->inode_item, inode);
-       delayed_node->inode_dirty = 1;
+       set_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags);
        delayed_node->count++;
        atomic_inc(&root->fs_info->delayed_root->items);
 release_node:
@@ -1830,6 +1850,41 @@ release_node:
        return ret;
 }
 
+int btrfs_delayed_delete_inode_ref(struct inode *inode)
+{
+       struct btrfs_delayed_node *delayed_node;
+
+       delayed_node = btrfs_get_or_create_delayed_node(inode);
+       if (IS_ERR(delayed_node))
+               return PTR_ERR(delayed_node);
+
+       /*
+        * We don't reserve space for inode ref deletion is because:
+        * - We ONLY do async inode ref deletion for the inode who has only
+        *   one link(i_nlink == 1), it means there is only one inode ref.
+        *   And in most case, the inode ref and the inode item are in the
+        *   same leaf, and we will deal with them at the same time.
+        *   Since we are sure we will reserve the space for the inode item,
+        *   it is unnecessary to reserve space for inode ref deletion.
+        * - If the inode ref and the inode item are not in the same leaf,
+        *   We also needn't worry about enospc problem, because we reserve
+        *   much more space for the inode update than it needs.
+        * - At the worst, we can steal some space from the global reservation.
+        *   It is very rare.
+        */
+       mutex_lock(&delayed_node->mutex);
+       if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags))
+               goto release_node;
+
+       set_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags);
+       delayed_node->count++;
+       atomic_inc(&BTRFS_I(inode)->root->fs_info->delayed_root->items);
+release_node:
+       mutex_unlock(&delayed_node->mutex);
+       btrfs_release_delayed_node(delayed_node);
+       return 0;
+}
+
 static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
 {
        struct btrfs_root *root = delayed_node->root;
@@ -1852,7 +1907,10 @@ static void __btrfs_kill_delayed_node(struct btrfs_delayed_node *delayed_node)
                btrfs_release_delayed_item(prev_item);
        }
 
-       if (delayed_node->inode_dirty) {
+       if (test_bit(BTRFS_DELAYED_NODE_DEL_IREF, &delayed_node->flags))
+               btrfs_release_delayed_iref(delayed_node);
+
+       if (test_bit(BTRFS_DELAYED_NODE_INODE_DIRTY, &delayed_node->flags)) {
                btrfs_delayed_inode_release_metadata(root, delayed_node);
                btrfs_release_delayed_inode(delayed_node);
        }
index a4b38f934d1471c3518c6d1e8e6f887adfdb7a70..f70119f254216583f3c7317085ec209eceb03d0f 100644 (file)
@@ -48,6 +48,10 @@ struct btrfs_delayed_root {
        wait_queue_head_t wait;
 };
 
+#define BTRFS_DELAYED_NODE_IN_LIST     0
+#define BTRFS_DELAYED_NODE_INODE_DIRTY 1
+#define BTRFS_DELAYED_NODE_DEL_IREF    2
+
 struct btrfs_delayed_node {
        u64 inode_id;
        u64 bytes_reserved;
@@ -65,8 +69,7 @@ struct btrfs_delayed_node {
        struct btrfs_inode_item inode_item;
        atomic_t refs;
        u64 index_cnt;
-       bool in_list;
-       bool inode_dirty;
+       unsigned long flags;
        int count;
 };
 
@@ -125,6 +128,7 @@ int btrfs_commit_inode_delayed_inode(struct inode *inode);
 int btrfs_delayed_update_inode(struct btrfs_trans_handle *trans,
                               struct btrfs_root *root, struct inode *inode);
 int btrfs_fill_inode(struct inode *inode, u32 *rdev);
+int btrfs_delayed_delete_inode_ref(struct inode *inode);
 
 /* Used for drop dead root */
 void btrfs_kill_all_delayed_nodes(struct btrfs_root *root);
index e4d467be2dd44d131977d64c3029af3fc9d99ce3..f3bff89eecf09346e2eb49b4ffeb861f35e33d4b 100644 (file)
@@ -161,35 +161,61 @@ static struct btrfs_delayed_ref_node *tree_insert(struct rb_root *root,
        return NULL;
 }
 
+/* insert a new ref to head ref rbtree */
+static struct btrfs_delayed_ref_head *htree_insert(struct rb_root *root,
+                                                  struct rb_node *node)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent_node = NULL;
+       struct btrfs_delayed_ref_head *entry;
+       struct btrfs_delayed_ref_head *ins;
+       u64 bytenr;
+
+       ins = rb_entry(node, struct btrfs_delayed_ref_head, href_node);
+       bytenr = ins->node.bytenr;
+       while (*p) {
+               parent_node = *p;
+               entry = rb_entry(parent_node, struct btrfs_delayed_ref_head,
+                                href_node);
+
+               if (bytenr < entry->node.bytenr)
+                       p = &(*p)->rb_left;
+               else if (bytenr > entry->node.bytenr)
+                       p = &(*p)->rb_right;
+               else
+                       return entry;
+       }
+
+       rb_link_node(node, parent_node, p);
+       rb_insert_color(node, root);
+       return NULL;
+}
+
 /*
  * find an head entry based on bytenr. This returns the delayed ref
  * head if it was able to find one, or NULL if nothing was in that spot.
  * If return_bigger is given, the next bigger entry is returned if no exact
  * match is found.
  */
-static struct btrfs_delayed_ref_node *find_ref_head(struct rb_root *root,
-                                 u64 bytenr,
-                                 struct btrfs_delayed_ref_node **last,
-                                 int return_bigger)
+static struct btrfs_delayed_ref_head *
+find_ref_head(struct rb_root *root, u64 bytenr,
+             struct btrfs_delayed_ref_head **last, int return_bigger)
 {
        struct rb_node *n;
-       struct btrfs_delayed_ref_node *entry;
+       struct btrfs_delayed_ref_head *entry;
        int cmp = 0;
 
 again:
        n = root->rb_node;
        entry = NULL;
        while (n) {
-               entry = rb_entry(n, struct btrfs_delayed_ref_node, rb_node);
-               WARN_ON(!entry->in_tree);
+               entry = rb_entry(n, struct btrfs_delayed_ref_head, href_node);
                if (last)
                        *last = entry;
 
-               if (bytenr < entry->bytenr)
+               if (bytenr < entry->node.bytenr)
                        cmp = -1;
-               else if (bytenr > entry->bytenr)
-                       cmp = 1;
-               else if (!btrfs_delayed_ref_is_head(entry))
+               else if (bytenr > entry->node.bytenr)
                        cmp = 1;
                else
                        cmp = 0;
@@ -203,12 +229,12 @@ again:
        }
        if (entry && return_bigger) {
                if (cmp > 0) {
-                       n = rb_next(&entry->rb_node);
+                       n = rb_next(&entry->href_node);
                        if (!n)
                                n = rb_first(root);
-                       entry = rb_entry(n, struct btrfs_delayed_ref_node,
-                                        rb_node);
-                       bytenr = entry->bytenr;
+                       entry = rb_entry(n, struct btrfs_delayed_ref_head,
+                                        href_node);
+                       bytenr = entry->node.bytenr;
                        return_bigger = 0;
                        goto again;
                }
@@ -243,33 +269,38 @@ int btrfs_delayed_ref_lock(struct btrfs_trans_handle *trans,
 
 static inline void drop_delayed_ref(struct btrfs_trans_handle *trans,
                                    struct btrfs_delayed_ref_root *delayed_refs,
+                                   struct btrfs_delayed_ref_head *head,
                                    struct btrfs_delayed_ref_node *ref)
 {
-       rb_erase(&ref->rb_node, &delayed_refs->root);
+       if (btrfs_delayed_ref_is_head(ref)) {
+               head = btrfs_delayed_node_to_head(ref);
+               rb_erase(&head->href_node, &delayed_refs->href_root);
+       } else {
+               assert_spin_locked(&head->lock);
+               rb_erase(&ref->rb_node, &head->ref_root);
+       }
        ref->in_tree = 0;
        btrfs_put_delayed_ref(ref);
-       delayed_refs->num_entries--;
+       atomic_dec(&delayed_refs->num_entries);
        if (trans->delayed_ref_updates)
                trans->delayed_ref_updates--;
 }
 
 static int merge_ref(struct btrfs_trans_handle *trans,
                     struct btrfs_delayed_ref_root *delayed_refs,
+                    struct btrfs_delayed_ref_head *head,
                     struct btrfs_delayed_ref_node *ref, u64 seq)
 {
        struct rb_node *node;
-       int merged = 0;
        int mod = 0;
        int done = 0;
 
-       node = rb_prev(&ref->rb_node);
-       while (node) {
+       node = rb_next(&ref->rb_node);
+       while (!done && node) {
                struct btrfs_delayed_ref_node *next;
 
                next = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
-               node = rb_prev(node);
-               if (next->bytenr != ref->bytenr)
-                       break;
+               node = rb_next(node);
                if (seq && next->seq >= seq)
                        break;
                if (comp_entry(ref, next, 0))
@@ -289,12 +320,11 @@ static int merge_ref(struct btrfs_trans_handle *trans,
                        mod = -next->ref_mod;
                }
 
-               merged++;
-               drop_delayed_ref(trans, delayed_refs, next);
+               drop_delayed_ref(trans, delayed_refs, head, next);
                ref->ref_mod += mod;
                if (ref->ref_mod == 0) {
-                       drop_delayed_ref(trans, delayed_refs, ref);
-                       break;
+                       drop_delayed_ref(trans, delayed_refs, head, ref);
+                       done = 1;
                } else {
                        /*
                         * You can't have multiples of the same ref on a tree
@@ -303,13 +333,8 @@ static int merge_ref(struct btrfs_trans_handle *trans,
                        WARN_ON(ref->type == BTRFS_TREE_BLOCK_REF_KEY ||
                                ref->type == BTRFS_SHARED_BLOCK_REF_KEY);
                }
-
-               if (done)
-                       break;
-               node = rb_prev(&ref->rb_node);
        }
-
-       return merged;
+       return done;
 }
 
 void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans,
@@ -320,6 +345,14 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans,
        struct rb_node *node;
        u64 seq = 0;
 
+       assert_spin_locked(&head->lock);
+       /*
+        * We don't have too much refs to merge in the case of delayed data
+        * refs.
+        */
+       if (head->is_data)
+               return;
+
        spin_lock(&fs_info->tree_mod_seq_lock);
        if (!list_empty(&fs_info->tree_mod_seq_list)) {
                struct seq_list *elem;
@@ -330,22 +363,19 @@ void btrfs_merge_delayed_refs(struct btrfs_trans_handle *trans,
        }
        spin_unlock(&fs_info->tree_mod_seq_lock);
 
-       node = rb_prev(&head->node.rb_node);
+       node = rb_first(&head->ref_root);
        while (node) {
                struct btrfs_delayed_ref_node *ref;
 
                ref = rb_entry(node, struct btrfs_delayed_ref_node,
                               rb_node);
-               if (ref->bytenr != head->node.bytenr)
-                       break;
-
                /* We can't merge refs that are outside of our seq count */
                if (seq && ref->seq >= seq)
                        break;
-               if (merge_ref(trans, delayed_refs, ref, seq))
-                       node = rb_prev(&head->node.rb_node);
+               if (merge_ref(trans, delayed_refs, head, ref, seq))
+                       node = rb_first(&head->ref_root);
                else
-                       node = rb_prev(node);
+                       node = rb_next(&ref->rb_node);
        }
 }
 
@@ -373,71 +403,52 @@ int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,
        return ret;
 }
 
-int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
-                          struct list_head *cluster, u64 start)
+struct btrfs_delayed_ref_head *
+btrfs_select_ref_head(struct btrfs_trans_handle *trans)
 {
-       int count = 0;
        struct btrfs_delayed_ref_root *delayed_refs;
-       struct rb_node *node;
-       struct btrfs_delayed_ref_node *ref;
        struct btrfs_delayed_ref_head *head;
+       u64 start;
+       bool loop = false;
 
        delayed_refs = &trans->transaction->delayed_refs;
-       if (start == 0) {
-               node = rb_first(&delayed_refs->root);
-       } else {
-               ref = NULL;
-               find_ref_head(&delayed_refs->root, start + 1, &ref, 1);
-               if (ref) {
-                       node = &ref->rb_node;
-               } else
-                       node = rb_first(&delayed_refs->root);
-       }
+
 again:
-       while (node && count < 32) {
-               ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
-               if (btrfs_delayed_ref_is_head(ref)) {
-                       head = btrfs_delayed_node_to_head(ref);
-                       if (list_empty(&head->cluster)) {
-                               list_add_tail(&head->cluster, cluster);
-                               delayed_refs->run_delayed_start =
-                                       head->node.bytenr;
-                               count++;
-
-                               WARN_ON(delayed_refs->num_heads_ready == 0);
-                               delayed_refs->num_heads_ready--;
-                       } else if (count) {
-                               /* the goal of the clustering is to find extents
-                                * that are likely to end up in the same extent
-                                * leaf on disk.  So, we don't want them spread
-                                * all over the tree.  Stop now if we've hit
-                                * a head that was already in use
-                                */
-                               break;
-                       }
-               }
-               node = rb_next(node);
-       }
-       if (count) {
-               return 0;
-       } else if (start) {
-               /*
-                * we've gone to the end of the rbtree without finding any
-                * clusters.  start from the beginning and try again
-                */
+       start = delayed_refs->run_delayed_start;
+       head = find_ref_head(&delayed_refs->href_root, start, NULL, 1);
+       if (!head && !loop) {
+               delayed_refs->run_delayed_start = 0;
                start = 0;
-               node = rb_first(&delayed_refs->root);
-               goto again;
+               loop = true;
+               head = find_ref_head(&delayed_refs->href_root, start, NULL, 1);
+               if (!head)
+                       return NULL;
+       } else if (!head && loop) {
+               return NULL;
        }
-       return 1;
-}
 
-void btrfs_release_ref_cluster(struct list_head *cluster)
-{
-       struct list_head *pos, *q;
+       while (head->processing) {
+               struct rb_node *node;
+
+               node = rb_next(&head->href_node);
+               if (!node) {
+                       if (loop)
+                               return NULL;
+                       delayed_refs->run_delayed_start = 0;
+                       start = 0;
+                       loop = true;
+                       goto again;
+               }
+               head = rb_entry(node, struct btrfs_delayed_ref_head,
+                               href_node);
+       }
 
-       list_for_each_safe(pos, q, cluster)
-               list_del_init(pos);
+       head->processing = 1;
+       WARN_ON(delayed_refs->num_heads_ready == 0);
+       delayed_refs->num_heads_ready--;
+       delayed_refs->run_delayed_start = head->node.bytenr +
+               head->node.num_bytes;
+       return head;
 }
 
 /*
@@ -451,6 +462,7 @@ void btrfs_release_ref_cluster(struct list_head *cluster)
 static noinline void
 update_existing_ref(struct btrfs_trans_handle *trans,
                    struct btrfs_delayed_ref_root *delayed_refs,
+                   struct btrfs_delayed_ref_head *head,
                    struct btrfs_delayed_ref_node *existing,
                    struct btrfs_delayed_ref_node *update)
 {
@@ -463,7 +475,7 @@ update_existing_ref(struct btrfs_trans_handle *trans,
                 */
                existing->ref_mod--;
                if (existing->ref_mod == 0)
-                       drop_delayed_ref(trans, delayed_refs, existing);
+                       drop_delayed_ref(trans, delayed_refs, head, existing);
                else
                        WARN_ON(existing->type == BTRFS_TREE_BLOCK_REF_KEY ||
                                existing->type == BTRFS_SHARED_BLOCK_REF_KEY);
@@ -533,9 +545,13 @@ update_existing_head_ref(struct btrfs_delayed_ref_node *existing,
                }
        }
        /*
-        * update the reference mod on the head to reflect this new operation
+        * update the reference mod on the head to reflect this new operation,
+        * only need the lock for this case cause we could be processing it
+        * currently, for refs we just added we know we're a-ok.
         */
+       spin_lock(&existing_ref->lock);
        existing->ref_mod += update->ref_mod;
+       spin_unlock(&existing_ref->lock);
 }
 
 /*
@@ -543,13 +559,13 @@ update_existing_head_ref(struct btrfs_delayed_ref_node *existing,
  * this does all the dirty work in terms of maintaining the correct
  * overall modification count.
  */
-static noinline void add_delayed_ref_head(struct btrfs_fs_info *fs_info,
-                                       struct btrfs_trans_handle *trans,
-                                       struct btrfs_delayed_ref_node *ref,
-                                       u64 bytenr, u64 num_bytes,
-                                       int action, int is_data)
+static noinline struct btrfs_delayed_ref_head *
+add_delayed_ref_head(struct btrfs_fs_info *fs_info,
+                    struct btrfs_trans_handle *trans,
+                    struct btrfs_delayed_ref_node *ref, u64 bytenr,
+                    u64 num_bytes, int action, int is_data)
 {
-       struct btrfs_delayed_ref_node *existing;
+       struct btrfs_delayed_ref_head *existing;
        struct btrfs_delayed_ref_head *head_ref = NULL;
        struct btrfs_delayed_ref_root *delayed_refs;
        int count_mod = 1;
@@ -596,38 +612,43 @@ static noinline void add_delayed_ref_head(struct btrfs_fs_info *fs_info,
        head_ref = btrfs_delayed_node_to_head(ref);
        head_ref->must_insert_reserved = must_insert_reserved;
        head_ref->is_data = is_data;
+       head_ref->ref_root = RB_ROOT;
+       head_ref->processing = 0;
 
-       INIT_LIST_HEAD(&head_ref->cluster);
+       spin_lock_init(&head_ref->lock);
        mutex_init(&head_ref->mutex);
 
        trace_add_delayed_ref_head(ref, head_ref, action);
 
-       existing = tree_insert(&delayed_refs->root, &ref->rb_node);
-
+       existing = htree_insert(&delayed_refs->href_root,
+                               &head_ref->href_node);
        if (existing) {
-               update_existing_head_ref(existing, ref);
+               update_existing_head_ref(&existing->node, ref);
                /*
                 * we've updated the existing ref, free the newly
                 * allocated ref
                 */
                kmem_cache_free(btrfs_delayed_ref_head_cachep, head_ref);
+               head_ref = existing;
        } else {
                delayed_refs->num_heads++;
                delayed_refs->num_heads_ready++;
-               delayed_refs->num_entries++;
+               atomic_inc(&delayed_refs->num_entries);
                trans->delayed_ref_updates++;
        }
+       return head_ref;
 }
 
 /*
  * helper to insert a delayed tree ref into the rbtree.
  */
-static noinline void add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
-                                        struct btrfs_trans_handle *trans,
-                                        struct btrfs_delayed_ref_node *ref,
-                                        u64 bytenr, u64 num_bytes, u64 parent,
-                                        u64 ref_root, int level, int action,
-                                        int for_cow)
+static noinline void
+add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
+                    struct btrfs_trans_handle *trans,
+                    struct btrfs_delayed_ref_head *head_ref,
+                    struct btrfs_delayed_ref_node *ref, u64 bytenr,
+                    u64 num_bytes, u64 parent, u64 ref_root, int level,
+                    int action, int for_cow)
 {
        struct btrfs_delayed_ref_node *existing;
        struct btrfs_delayed_tree_ref *full_ref;
@@ -663,30 +684,33 @@ static noinline void add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
 
        trace_add_delayed_tree_ref(ref, full_ref, action);
 
-       existing = tree_insert(&delayed_refs->root, &ref->rb_node);
-
+       spin_lock(&head_ref->lock);
+       existing = tree_insert(&head_ref->ref_root, &ref->rb_node);
        if (existing) {
-               update_existing_ref(trans, delayed_refs, existing, ref);
+               update_existing_ref(trans, delayed_refs, head_ref, existing,
+                                   ref);
                /*
                 * we've updated the existing ref, free the newly
                 * allocated ref
                 */
                kmem_cache_free(btrfs_delayed_tree_ref_cachep, full_ref);
        } else {
-               delayed_refs->num_entries++;
+               atomic_inc(&delayed_refs->num_entries);
                trans->delayed_ref_updates++;
        }
+       spin_unlock(&head_ref->lock);
 }
 
 /*
  * helper to insert a delayed data ref into the rbtree.
  */
-static noinline void add_delayed_data_ref(struct btrfs_fs_info *fs_info,
-                                        struct btrfs_trans_handle *trans,
-                                        struct btrfs_delayed_ref_node *ref,
-                                        u64 bytenr, u64 num_bytes, u64 parent,
-                                        u64 ref_root, u64 owner, u64 offset,
-                                        int action, int for_cow)
+static noinline void
+add_delayed_data_ref(struct btrfs_fs_info *fs_info,
+                    struct btrfs_trans_handle *trans,
+                    struct btrfs_delayed_ref_head *head_ref,
+                    struct btrfs_delayed_ref_node *ref, u64 bytenr,
+                    u64 num_bytes, u64 parent, u64 ref_root, u64 owner,
+                    u64 offset, int action, int for_cow)
 {
        struct btrfs_delayed_ref_node *existing;
        struct btrfs_delayed_data_ref *full_ref;
@@ -724,19 +748,21 @@ static noinline void add_delayed_data_ref(struct btrfs_fs_info *fs_info,
 
        trace_add_delayed_data_ref(ref, full_ref, action);
 
-       existing = tree_insert(&delayed_refs->root, &ref->rb_node);
-
+       spin_lock(&head_ref->lock);
+       existing = tree_insert(&head_ref->ref_root, &ref->rb_node);
        if (existing) {
-               update_existing_ref(trans, delayed_refs, existing, ref);
+               update_existing_ref(trans, delayed_refs, head_ref, existing,
+                                   ref);
                /*
                 * we've updated the existing ref, free the newly
                 * allocated ref
                 */
                kmem_cache_free(btrfs_delayed_data_ref_cachep, full_ref);
        } else {
-               delayed_refs->num_entries++;
+               atomic_inc(&delayed_refs->num_entries);
                trans->delayed_ref_updates++;
        }
+       spin_unlock(&head_ref->lock);
 }
 
 /*
@@ -775,10 +801,10 @@ int btrfs_add_delayed_tree_ref(struct btrfs_fs_info *fs_info,
         * insert both the head node and the new ref without dropping
         * the spin lock
         */
-       add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
-                                  num_bytes, action, 0);
+       head_ref = add_delayed_ref_head(fs_info, trans, &head_ref->node,
+                                       bytenr, num_bytes, action, 0);
 
-       add_delayed_tree_ref(fs_info, trans, &ref->node, bytenr,
+       add_delayed_tree_ref(fs_info, trans, head_ref, &ref->node, bytenr,
                                   num_bytes, parent, ref_root, level, action,
                                   for_cow);
        spin_unlock(&delayed_refs->lock);
@@ -823,10 +849,10 @@ int btrfs_add_delayed_data_ref(struct btrfs_fs_info *fs_info,
         * insert both the head node and the new ref without dropping
         * the spin lock
         */
-       add_delayed_ref_head(fs_info, trans, &head_ref->node, bytenr,
-                                  num_bytes, action, 1);
+       head_ref = add_delayed_ref_head(fs_info, trans, &head_ref->node,
+                                       bytenr, num_bytes, action, 1);
 
-       add_delayed_data_ref(fs_info, trans, &ref->node, bytenr,
+       add_delayed_data_ref(fs_info, trans, head_ref, &ref->node, bytenr,
                                   num_bytes, parent, ref_root, owner, offset,
                                   action, for_cow);
        spin_unlock(&delayed_refs->lock);
@@ -869,14 +895,10 @@ int btrfs_add_delayed_extent_op(struct btrfs_fs_info *fs_info,
 struct btrfs_delayed_ref_head *
 btrfs_find_delayed_ref_head(struct btrfs_trans_handle *trans, u64 bytenr)
 {
-       struct btrfs_delayed_ref_node *ref;
        struct btrfs_delayed_ref_root *delayed_refs;
 
        delayed_refs = &trans->transaction->delayed_refs;
-       ref = find_ref_head(&delayed_refs->root, bytenr, NULL, 0);
-       if (ref)
-               return btrfs_delayed_node_to_head(ref);
-       return NULL;
+       return find_ref_head(&delayed_refs->href_root, bytenr, NULL, 0);
 }
 
 void btrfs_delayed_ref_exit(void)
index 70b962cc177d973688b0d2deb56965bffbc423ae..4ba9b93022ffd4e70e862e67674fdacbfb899e1c 100644 (file)
@@ -81,7 +81,10 @@ struct btrfs_delayed_ref_head {
         */
        struct mutex mutex;
 
-       struct list_head cluster;
+       spinlock_t lock;
+       struct rb_root ref_root;
+
+       struct rb_node href_node;
 
        struct btrfs_delayed_extent_op *extent_op;
        /*
@@ -98,6 +101,7 @@ struct btrfs_delayed_ref_head {
         */
        unsigned int must_insert_reserved:1;
        unsigned int is_data:1;
+       unsigned int processing:1;
 };
 
 struct btrfs_delayed_tree_ref {
@@ -116,7 +120,8 @@ struct btrfs_delayed_data_ref {
 };
 
 struct btrfs_delayed_ref_root {
-       struct rb_root root;
+       /* head ref rbtree */
+       struct rb_root href_root;
 
        /* this spin lock protects the rbtree and the entries inside */
        spinlock_t lock;
@@ -124,7 +129,7 @@ struct btrfs_delayed_ref_root {
        /* how many delayed ref updates we've queued, used by the
         * throttling code
         */
-       unsigned long num_entries;
+       atomic_t num_entries;
 
        /* total number of head nodes in tree */
        unsigned long num_heads;
@@ -132,15 +137,6 @@ struct btrfs_delayed_ref_root {
        /* total number of head nodes ready for processing */
        unsigned long num_heads_ready;
 
-       /*
-        * bumped when someone is making progress on the delayed
-        * refs, so that other procs know they are just adding to
-        * contention intead of helping
-        */
-       atomic_t procs_running_refs;
-       atomic_t ref_seq;
-       wait_queue_head_t wait;
-
        /*
         * set when the tree is flushing before a transaction commit,
         * used by the throttling code to decide if new updates need
@@ -226,9 +222,9 @@ static inline void btrfs_delayed_ref_unlock(struct btrfs_delayed_ref_head *head)
        mutex_unlock(&head->mutex);
 }
 
-int btrfs_find_ref_cluster(struct btrfs_trans_handle *trans,
-                          struct list_head *cluster, u64 search_start);
-void btrfs_release_ref_cluster(struct list_head *cluster);
+
+struct btrfs_delayed_ref_head *
+btrfs_select_ref_head(struct btrfs_trans_handle *trans);
 
 int btrfs_check_delayed_seq(struct btrfs_fs_info *fs_info,
                            struct btrfs_delayed_ref_root *delayed_refs,
index 2cfc3dfff64f5708f71ec83af691b425b9f01b01..564c92638b20a8d4929a920eb843c4f4fe71745b 100644 (file)
@@ -102,7 +102,8 @@ no_valid_dev_replace_entry_found:
        ptr = btrfs_item_ptr(eb, slot, struct btrfs_dev_replace_item);
 
        if (item_size != sizeof(struct btrfs_dev_replace_item)) {
-               pr_warn("btrfs: dev_replace entry found has unexpected size, ignore entry\n");
+               btrfs_warn(fs_info,
+                       "dev_replace entry found has unexpected size, ignore entry");
                goto no_valid_dev_replace_entry_found;
        }
 
@@ -145,13 +146,19 @@ no_valid_dev_replace_entry_found:
                if (!dev_replace->srcdev &&
                    !btrfs_test_opt(dev_root, DEGRADED)) {
                        ret = -EIO;
-                       pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "srcdev (devid %llu) is missing, need to run 'btrfs dev scan'?\n",
-                               src_devid);
+                       btrfs_warn(fs_info,
+                          "cannot mount because device replace operation is ongoing and");
+                       btrfs_warn(fs_info,
+                          "srcdev (devid %llu) is missing, need to run 'btrfs dev scan'?",
+                          src_devid);
                }
                if (!dev_replace->tgtdev &&
                    !btrfs_test_opt(dev_root, DEGRADED)) {
                        ret = -EIO;
-                       pr_warn("btrfs: cannot mount because device replace operation is ongoing and\n" "tgtdev (devid %llu) is missing, need to run btrfs dev scan?\n",
+                       btrfs_warn(fs_info,
+                          "cannot mount because device replace operation is ongoing and");
+                       btrfs_warn(fs_info,
+                          "tgtdev (devid %llu) is missing, need to run 'btrfs dev scan'?",
                                BTRFS_DEV_REPLACE_DEVID);
                }
                if (dev_replace->tgtdev) {
@@ -210,7 +217,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
        }
        ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1);
        if (ret < 0) {
-               pr_warn("btrfs: error %d while searching for dev_replace item!\n",
+               btrfs_warn(fs_info, "error %d while searching for dev_replace item!",
                        ret);
                goto out;
        }
@@ -230,7 +237,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
                 */
                ret = btrfs_del_item(trans, dev_root, path);
                if (ret != 0) {
-                       pr_warn("btrfs: delete too small dev_replace item failed %d!\n",
+                       btrfs_warn(fs_info, "delete too small dev_replace item failed %d!",
                                ret);
                        goto out;
                }
@@ -243,7 +250,7 @@ int btrfs_run_dev_replace(struct btrfs_trans_handle *trans,
                ret = btrfs_insert_empty_item(trans, dev_root, path,
                                              &key, sizeof(*ptr));
                if (ret < 0) {
-                       pr_warn("btrfs: insert dev_replace item failed %d!\n",
+                       btrfs_warn(fs_info, "insert dev_replace item failed %d!",
                                ret);
                        goto out;
                }
@@ -305,7 +312,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
        struct btrfs_device *src_device = NULL;
 
        if (btrfs_fs_incompat(fs_info, RAID56)) {
-               pr_warn("btrfs: dev_replace cannot yet handle RAID5/RAID6\n");
+               btrfs_warn(fs_info, "dev_replace cannot yet handle RAID5/RAID6");
                return -EINVAL;
        }
 
@@ -325,7 +332,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
        ret = btrfs_init_dev_replace_tgtdev(root, args->start.tgtdev_name,
                                            &tgt_device);
        if (ret) {
-               pr_err("btrfs: target device %s is invalid!\n",
+               btrfs_err(fs_info, "target device %s is invalid!",
                       args->start.tgtdev_name);
                mutex_unlock(&fs_info->volume_mutex);
                return -EINVAL;
@@ -341,7 +348,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
        }
 
        if (tgt_device->total_bytes < src_device->total_bytes) {
-               pr_err("btrfs: target device is smaller than source device!\n");
+               btrfs_err(fs_info, "target device is smaller than source device!");
                ret = -EINVAL;
                goto leave_no_lock;
        }
@@ -366,7 +373,7 @@ int btrfs_dev_replace_start(struct btrfs_root *root,
        dev_replace->tgtdev = tgt_device;
 
        printk_in_rcu(KERN_INFO
-                     "btrfs: dev_replace from %s (devid %llu) to %s started\n",
+                     "BTRFS: dev_replace from %s (devid %llu) to %s started\n",
                      src_device->missing ? "<missing disk>" :
                        rcu_str_deref(src_device->name),
                      src_device->devid,
@@ -489,7 +496,7 @@ static int btrfs_dev_replace_finishing(struct btrfs_fs_info *fs_info,
 
        if (scrub_ret) {
                printk_in_rcu(KERN_ERR
-                             "btrfs: btrfs_scrub_dev(%s, %llu, %s) failed %d\n",
+                             "BTRFS: btrfs_scrub_dev(%s, %llu, %s) failed %d\n",
                              src_device->missing ? "<missing disk>" :
                                rcu_str_deref(src_device->name),
                              src_device->devid,
@@ -504,7 +511,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,
@@ -699,7 +706,7 @@ void btrfs_dev_replace_suspend_for_unmount(struct btrfs_fs_info *fs_info)
                        BTRFS_IOCTL_DEV_REPLACE_STATE_SUSPENDED;
                dev_replace->time_stopped = get_seconds();
                dev_replace->item_needs_writeback = 1;
-               pr_info("btrfs: suspending dev_replace for unmount\n");
+               btrfs_info(fs_info, "suspending dev_replace for unmount");
                break;
        }
 
@@ -728,8 +735,9 @@ int btrfs_resume_dev_replace_async(struct btrfs_fs_info *fs_info)
                break;
        }
        if (!dev_replace->tgtdev || !dev_replace->tgtdev->bdev) {
-               pr_info("btrfs: cannot continue dev_replace, tgtdev is missing\n"
-                       "btrfs: you may cancel the operation after 'mount -o degraded'\n");
+               btrfs_info(fs_info, "cannot continue dev_replace, tgtdev is missing");
+               btrfs_info(fs_info,
+                       "you may cancel the operation after 'mount -o degraded'");
                btrfs_dev_replace_unlock(dev_replace);
                return 0;
        }
@@ -755,14 +763,14 @@ static int btrfs_dev_replace_kthread(void *data)
                kfree(status_args);
                do_div(progress, 10);
                printk_in_rcu(KERN_INFO
-                             "btrfs: continuing dev_replace from %s (devid %llu) to %s @%u%%\n",
-                             dev_replace->srcdev->missing ? "<missing disk>" :
-                               rcu_str_deref(dev_replace->srcdev->name),
-                             dev_replace->srcdev->devid,
-                             dev_replace->tgtdev ?
-                               rcu_str_deref(dev_replace->tgtdev->name) :
-                               "<missing target disk>",
-                             (unsigned int)progress);
+                       "BTRFS: continuing dev_replace from %s (devid %llu) to %s @%u%%\n",
+                       dev_replace->srcdev->missing ? "<missing disk>" :
+                       rcu_str_deref(dev_replace->srcdev->name),
+                       dev_replace->srcdev->devid,
+                       dev_replace->tgtdev ?
+                       rcu_str_deref(dev_replace->tgtdev->name) :
+                       "<missing target disk>",
+                       (unsigned int)progress);
        }
        btrfs_dev_replace_continue_on_mount(fs_info);
        atomic_set(&fs_info->mutually_exclusive_operation_running, 0);
index c031ea3fd70f70d64452a3529d3ef99c830a57bf..a0691df5dceaa9dfdb3100732bf82ee81793f32c 100644 (file)
@@ -261,7 +261,7 @@ int btrfs_check_dir_item_collision(struct btrfs_root *root, u64 dir,
         * see if there is room in the item to insert this
         * name
         */
-       data_size = sizeof(*di) + name_len + sizeof(struct btrfs_item);
+       data_size = sizeof(*di) + name_len;
        leaf = path->nodes[0];
        slot = path->slots[0];
        if (data_size + btrfs_item_size_nr(leaf, slot) +
@@ -459,7 +459,7 @@ int verify_dir_item(struct btrfs_root *root,
        u8 type = btrfs_dir_type(leaf, dir_item);
 
        if (type >= BTRFS_FT_MAX) {
-               printk(KERN_CRIT "btrfs: invalid dir item type: %d\n",
+               btrfs_crit(root->fs_info, "invalid dir item type: %d",
                       (int)type);
                return 1;
        }
@@ -468,7 +468,7 @@ int verify_dir_item(struct btrfs_root *root,
                namelen = XATTR_NAME_MAX;
 
        if (btrfs_dir_name_len(leaf, dir_item) > namelen) {
-               printk(KERN_CRIT "btrfs: invalid dir item name len: %u\n",
+               btrfs_crit(root->fs_info, "invalid dir item name len: %u",
                       (unsigned)btrfs_dir_data_len(leaf, dir_item));
                return 1;
        }
@@ -476,7 +476,7 @@ int verify_dir_item(struct btrfs_root *root,
        /* BTRFS_MAX_XATTR_SIZE is the same for all dir items */
        if ((btrfs_dir_data_len(leaf, dir_item) +
             btrfs_dir_name_len(leaf, dir_item)) > BTRFS_MAX_XATTR_SIZE(root)) {
-               printk(KERN_CRIT "btrfs: invalid dir item name + data len: %u + %u\n",
+               btrfs_crit(root->fs_info, "invalid dir item name + data len: %u + %u",
                       (unsigned)btrfs_dir_name_len(leaf, dir_item),
                       (unsigned)btrfs_dir_data_len(leaf, dir_item));
                return 1;
index 8072cfa8a3b16c075e5c381f481e7cb874d9c531..0e69295d0031e558eb3ebb257ff2d4bb2f79772f 100644 (file)
@@ -48,6 +48,7 @@
 #include "rcu-string.h"
 #include "dev-replace.h"
 #include "raid56.h"
+#include "sysfs.h"
 
 #ifdef CONFIG_X86
 #include <asm/cpufeature.h>
@@ -299,11 +300,11 @@ static int csum_tree_block(struct btrfs_root *root, struct extent_buffer *buf,
                        memcpy(&found, result, csum_size);
 
                        read_extent_buffer(buf, &val, 0, csum_size);
-                       printk_ratelimited(KERN_INFO "btrfs: %s checksum verify "
-                                      "failed on %llu wanted %X found %X "
-                                      "level %d\n",
-                                      root->fs_info->sb->s_id, buf->start,
-                                      val, found, btrfs_header_level(buf));
+                       printk_ratelimited(KERN_INFO
+                               "BTRFS: %s checksum verify failed on %llu wanted %X found %X "
+                               "level %d\n",
+                               root->fs_info->sb->s_id, buf->start,
+                               val, found, btrfs_header_level(buf));
                        if (result != (char *)&inline_result)
                                kfree(result);
                        return 1;
@@ -382,13 +383,14 @@ static int btrfs_check_super_csum(char *raw_disk_sb)
                        ret = 1;
 
                if (ret && btrfs_super_generation(disk_sb) < 10) {
-                       printk(KERN_WARNING "btrfs: super block crcs don't match, older mkfs detected\n");
+                       printk(KERN_WARNING
+                               "BTRFS: super block crcs don't match, older mkfs detected\n");
                        ret = 0;
                }
        }
 
        if (csum_type >= ARRAY_SIZE(btrfs_csum_sizes)) {
-               printk(KERN_ERR "btrfs: unsupported checksum algorithm %u\n",
+               printk(KERN_ERR "BTRFS: unsupported checksum algorithm %u\n",
                                csum_type);
                ret = 1;
        }
@@ -464,13 +466,10 @@ static int btree_read_extent_buffer_pages(struct btrfs_root *root,
 
 static int csum_dirty_buffer(struct btrfs_root *root, struct page *page)
 {
-       struct extent_io_tree *tree;
        u64 start = page_offset(page);
        u64 found_start;
        struct extent_buffer *eb;
 
-       tree = &BTRFS_I(page->mapping->host)->io_tree;
-
        eb = (struct extent_buffer *)page->private;
        if (page != eb->pages[0])
                return 0;
@@ -500,8 +499,8 @@ static int check_tree_block_fsid(struct btrfs_root *root,
 }
 
 #define CORRUPT(reason, eb, root, slot)                                \
-       printk(KERN_CRIT "btrfs: corrupt leaf, %s: block=%llu," \
-              "root=%llu, slot=%d\n", reason,                  \
+       btrfs_crit(root->fs_info, "corrupt leaf, %s: block=%llu,"       \
+                  "root=%llu, slot=%d", reason,                        \
               btrfs_header_bytenr(eb), root->objectid, slot)
 
 static noinline int check_leaf(struct btrfs_root *root,
@@ -569,7 +568,6 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
                                      u64 phy_offset, struct page *page,
                                      u64 start, u64 end, int mirror)
 {
-       struct extent_io_tree *tree;
        u64 found_start;
        int found_level;
        struct extent_buffer *eb;
@@ -580,7 +578,6 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
        if (!page->private)
                goto out;
 
-       tree = &BTRFS_I(page->mapping->host)->io_tree;
        eb = (struct extent_buffer *)page->private;
 
        /* the pending IO might have been the only thing that kept this buffer
@@ -600,21 +597,21 @@ static int btree_readpage_end_io_hook(struct btrfs_io_bio *io_bio,
 
        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: bad tree block start "
                               "%llu %llu\n",
                               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",
+               printk_ratelimited(KERN_INFO "BTRFS: bad fsid on block %llu\n",
                               eb->start);
                ret = -EIO;
                goto err;
        }
        found_level = btrfs_header_level(eb);
        if (found_level >= BTRFS_MAX_LEVEL) {
-               btrfs_info(root->fs_info, "bad tree block level %d\n",
+               btrfs_info(root->fs_info, "bad tree block level %d",
                           (int)btrfs_header_level(eb));
                ret = -EIO;
                goto err;
@@ -842,20 +839,17 @@ int btrfs_wq_submit_bio(struct btrfs_fs_info *fs_info, struct inode *inode,
 
 static int btree_csum_one_bio(struct bio *bio)
 {
-       struct bio_vec *bvec = bio->bi_io_vec;
-       int bio_index = 0;
+       struct bio_vec *bvec;
        struct btrfs_root *root;
-       int ret = 0;
+       int i, ret = 0;
 
-       WARN_ON(bio->bi_vcnt <= 0);
-       while (bio_index < bio->bi_vcnt) {
+       bio_for_each_segment_all(bvec, bio, i) {
                root = BTRFS_I(bvec->bv_page->mapping->host)->root;
                ret = csum_dirty_buffer(root, bvec->bv_page);
                if (ret)
                        break;
-               bio_index++;
-               bvec++;
        }
+
        return ret;
 }
 
@@ -967,11 +961,9 @@ static int btree_migratepage(struct address_space *mapping,
 static int btree_writepages(struct address_space *mapping,
                            struct writeback_control *wbc)
 {
-       struct extent_io_tree *tree;
        struct btrfs_fs_info *fs_info;
        int ret;
 
-       tree = &BTRFS_I(mapping->host)->io_tree;
        if (wbc->sync_mode == WB_SYNC_NONE) {
 
                if (wbc->for_kupdate)
@@ -1010,8 +1002,9 @@ static void btree_invalidatepage(struct page *page, unsigned int offset,
        extent_invalidatepage(tree, page, offset);
        btree_releasepage(page, GFP_NOFS);
        if (PagePrivate(page)) {
-               printk(KERN_WARNING "btrfs warning page private not zero "
-                      "on page %llu\n", (unsigned long long)page_offset(page));
+               btrfs_warn(BTRFS_I(page->mapping->host)->root->fs_info,
+                          "page private not zero on page %llu",
+                          (unsigned long long)page_offset(page));
                ClearPagePrivate(page);
                set_page_private(page, 0);
                page_cache_release(page);
@@ -1095,21 +1088,13 @@ 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)
 {
-       struct inode *btree_inode = root->fs_info->btree_inode;
-       struct extent_buffer *eb;
-       eb = find_extent_buffer(&BTRFS_I(btree_inode)->io_tree, bytenr);
-       return eb;
+       return find_extent_buffer(root->fs_info, bytenr);
 }
 
 struct extent_buffer *btrfs_find_create_tree_block(struct btrfs_root *root,
                                                 u64 bytenr, u32 blocksize)
 {
-       struct inode *btree_inode = root->fs_info->btree_inode;
-       struct extent_buffer *eb;
-
-       eb = alloc_extent_buffer(&BTRFS_I(btree_inode)->io_tree,
-                                bytenr, blocksize);
-       return eb;
+       return alloc_extent_buffer(root->fs_info, bytenr, blocksize);
 }
 
 
@@ -1273,7 +1258,6 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
        struct btrfs_root *root;
        struct btrfs_key key;
        int ret = 0;
-       u64 bytenr;
        uuid_le uuid;
 
        root = btrfs_alloc_root(fs_info);
@@ -1295,7 +1279,6 @@ struct btrfs_root *btrfs_create_tree(struct btrfs_trans_handle *trans,
                goto fail;
        }
 
-       bytenr = leaf->start;
        memset_extent_buffer(leaf, 0, 0, sizeof(struct btrfs_header));
        btrfs_set_header_bytenr(leaf, leaf->start);
        btrfs_set_header_generation(leaf, trans->transid);
@@ -1616,7 +1599,8 @@ again:
        if (ret)
                goto fail;
 
-       ret = btrfs_find_orphan_item(fs_info->tree_root, location->objectid);
+       ret = btrfs_find_item(fs_info->tree_root, NULL, BTRFS_ORPHAN_OBJECTID,
+                       location->objectid, BTRFS_ORPHAN_ITEM_KEY, NULL);
        if (ret < 0)
                goto fail;
        if (ret == 0)
@@ -1684,18 +1668,16 @@ static void end_workqueue_fn(struct btrfs_work *work)
 {
        struct bio *bio;
        struct end_io_wq *end_io_wq;
-       struct btrfs_fs_info *fs_info;
        int error;
 
        end_io_wq = container_of(work, struct end_io_wq, work);
        bio = end_io_wq->bio;
-       fs_info = end_io_wq->info;
 
        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);
-       bio_endio(bio, error);
+       bio_endio_nodec(bio, error);
 }
 
 static int cleaner_kthread(void *arg)
@@ -2080,6 +2062,12 @@ static void del_fs_roots(struct btrfs_fs_info *fs_info)
                for (i = 0; i < ret; i++)
                        btrfs_drop_and_free_fs_root(fs_info, gang[i]);
        }
+
+       if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
+               btrfs_free_log_root_tree(NULL, fs_info);
+               btrfs_destroy_pinned_extent(fs_info->tree_root,
+                                           fs_info->pinned_extents);
+       }
 }
 
 int open_ctree(struct super_block *sb,
@@ -2154,6 +2142,7 @@ int open_ctree(struct super_block *sb,
        mapping_set_gfp_mask(fs_info->btree_inode->i_mapping, GFP_NOFS);
 
        INIT_RADIX_TREE(&fs_info->fs_roots_radix, GFP_ATOMIC);
+       INIT_RADIX_TREE(&fs_info->buffer_radix, GFP_ATOMIC);
        INIT_LIST_HEAD(&fs_info->trans_list);
        INIT_LIST_HEAD(&fs_info->dead_roots);
        INIT_LIST_HEAD(&fs_info->delayed_iputs);
@@ -2167,6 +2156,7 @@ int open_ctree(struct super_block *sb,
        spin_lock_init(&fs_info->free_chunk_lock);
        spin_lock_init(&fs_info->tree_mod_seq_lock);
        spin_lock_init(&fs_info->super_lock);
+       spin_lock_init(&fs_info->buffer_lock);
        rwlock_init(&fs_info->tree_mod_log_lock);
        mutex_init(&fs_info->reloc_mutex);
        seqlock_init(&fs_info->profiles_lock);
@@ -2198,7 +2188,7 @@ int open_ctree(struct super_block *sb,
        fs_info->free_chunk_space = 0;
        fs_info->tree_mod_log = RB_ROOT;
        fs_info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
-
+       fs_info->avg_delayed_ref_runtime = div64_u64(NSEC_PER_SEC, 64);
        /* readahead state */
        INIT_RADIX_TREE(&fs_info->reada_tree, GFP_NOFS & ~__GFP_WAIT);
        spin_lock_init(&fs_info->reada_lock);
@@ -2337,7 +2327,7 @@ int open_ctree(struct super_block *sb,
         * Pass the whole disk block of size BTRFS_SUPER_INFO_SIZE (4k).
         */
        if (btrfs_check_super_csum(bh->b_data)) {
-               printk(KERN_ERR "btrfs: superblock checksum mismatch\n");
+               printk(KERN_ERR "BTRFS: superblock checksum mismatch\n");
                err = -EINVAL;
                goto fail_alloc;
        }
@@ -2356,7 +2346,7 @@ int open_ctree(struct super_block *sb,
 
        ret = btrfs_check_super_valid(fs_info, sb->s_flags & MS_RDONLY);
        if (ret) {
-               printk(KERN_ERR "btrfs: superblock contains fatal errors\n");
+               printk(KERN_ERR "BTRFS: superblock contains fatal errors\n");
                err = -EINVAL;
                goto fail_alloc;
        }
@@ -2421,7 +2411,7 @@ int open_ctree(struct super_block *sb,
                features |= BTRFS_FEATURE_INCOMPAT_COMPRESS_LZO;
 
        if (features & BTRFS_FEATURE_INCOMPAT_SKINNY_METADATA)
-               printk(KERN_ERR "btrfs: has skinny extents\n");
+               printk(KERN_ERR "BTRFS: has skinny extents\n");
 
        /*
         * flag our filesystem as having big metadata blocks if
@@ -2429,7 +2419,7 @@ int open_ctree(struct super_block *sb,
         */
        if (btrfs_super_leafsize(disk_super) > PAGE_CACHE_SIZE) {
                if (!(features & BTRFS_FEATURE_INCOMPAT_BIG_METADATA))
-                       printk(KERN_INFO "btrfs flagging fs with big metadata feature\n");
+                       printk(KERN_INFO "BTRFS: flagging fs with big metadata feature\n");
                features |= BTRFS_FEATURE_INCOMPAT_BIG_METADATA;
        }
 
@@ -2446,7 +2436,7 @@ int open_ctree(struct super_block *sb,
         */
        if ((features & BTRFS_FEATURE_INCOMPAT_MIXED_GROUPS) &&
            (sectorsize != leafsize)) {
-               printk(KERN_WARNING "btrfs: unequal leaf/node/sector sizes "
+               printk(KERN_WARNING "BTRFS: unequal leaf/node/sector sizes "
                                "are not allowed for mixed block groups on %s\n",
                                sb->s_id);
                goto fail_alloc;
@@ -2583,12 +2573,12 @@ int open_ctree(struct super_block *sb,
        sb->s_blocksize_bits = blksize_bits(sectorsize);
 
        if (btrfs_super_magic(disk_super) != BTRFS_MAGIC) {
-               printk(KERN_INFO "btrfs: valid FS not found on %s\n", sb->s_id);
+               printk(KERN_INFO "BTRFS: valid FS not found on %s\n", sb->s_id);
                goto fail_sb_buffer;
        }
 
        if (sectorsize != PAGE_SIZE) {
-               printk(KERN_WARNING "btrfs: Incompatible sector size(%lu) "
+               printk(KERN_WARNING "BTRFS: Incompatible sector size(%lu) "
                       "found on %s\n", (unsigned long)sectorsize, sb->s_id);
                goto fail_sb_buffer;
        }
@@ -2597,7 +2587,7 @@ int open_ctree(struct super_block *sb,
        ret = btrfs_read_sys_array(tree_root);
        mutex_unlock(&fs_info->chunk_mutex);
        if (ret) {
-               printk(KERN_WARNING "btrfs: failed to read the system "
+               printk(KERN_WARNING "BTRFS: failed to read the system "
                       "array on %s\n", sb->s_id);
                goto fail_sb_buffer;
        }
@@ -2614,7 +2604,7 @@ int open_ctree(struct super_block *sb,
                                           blocksize, 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",
+               printk(KERN_WARNING "BTRFS: failed to read chunk root on %s\n",
                       sb->s_id);
                goto fail_tree_roots;
        }
@@ -2626,7 +2616,7 @@ int open_ctree(struct super_block *sb,
 
        ret = btrfs_read_chunk_tree(chunk_root);
        if (ret) {
-               printk(KERN_WARNING "btrfs: failed to read chunk tree on %s\n",
+               printk(KERN_WARNING "BTRFS: failed to read chunk tree on %s\n",
                       sb->s_id);
                goto fail_tree_roots;
        }
@@ -2638,7 +2628,7 @@ int open_ctree(struct super_block *sb,
        btrfs_close_extra_devices(fs_info, fs_devices, 0);
 
        if (!fs_devices->latest_bdev) {
-               printk(KERN_CRIT "btrfs: failed to read devices on %s\n",
+               printk(KERN_CRIT "BTRFS: failed to read devices on %s\n",
                       sb->s_id);
                goto fail_tree_roots;
        }
@@ -2653,7 +2643,7 @@ retry_root_backup:
                                          blocksize, 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",
+               printk(KERN_WARNING "BTRFS: failed to read tree root on %s\n",
                       sb->s_id);
 
                goto recovery_tree_root;
@@ -2724,50 +2714,56 @@ retry_root_backup:
 
        ret = btrfs_recover_balance(fs_info);
        if (ret) {
-               printk(KERN_WARNING "btrfs: failed to recover balance\n");
+               printk(KERN_WARNING "BTRFS: failed to recover balance\n");
                goto fail_block_groups;
        }
 
        ret = btrfs_init_dev_stats(fs_info);
        if (ret) {
-               printk(KERN_ERR "btrfs: failed to init dev_stats: %d\n",
+               printk(KERN_ERR "BTRFS: failed to init dev_stats: %d\n",
                       ret);
                goto fail_block_groups;
        }
 
        ret = btrfs_init_dev_replace(fs_info);
        if (ret) {
-               pr_err("btrfs: failed to init dev_replace: %d\n", ret);
+               pr_err("BTRFS: failed to init dev_replace: %d\n", ret);
                goto fail_block_groups;
        }
 
        btrfs_close_extra_devices(fs_info, fs_devices, 1);
 
-       ret = btrfs_init_space_info(fs_info);
+       ret = btrfs_sysfs_add_one(fs_info);
        if (ret) {
-               printk(KERN_ERR "Failed to initial space info: %d\n", ret);
+               pr_err("BTRFS: failed to init sysfs interface: %d\n", ret);
                goto fail_block_groups;
        }
 
+       ret = btrfs_init_space_info(fs_info);
+       if (ret) {
+               printk(KERN_ERR "BTRFS: Failed to initial space info: %d\n", ret);
+               goto fail_sysfs;
+       }
+
        ret = btrfs_read_block_groups(extent_root);
        if (ret) {
-               printk(KERN_ERR "Failed to read block groups: %d\n", ret);
-               goto fail_block_groups;
+               printk(KERN_ERR "BTRFS: Failed to read block groups: %d\n", ret);
+               goto fail_sysfs;
        }
        fs_info->num_tolerated_disk_barrier_failures =
                btrfs_calc_num_tolerated_disk_barrier_failures(fs_info);
        if (fs_info->fs_devices->missing_devices >
             fs_info->num_tolerated_disk_barrier_failures &&
            !(sb->s_flags & MS_RDONLY)) {
-               printk(KERN_WARNING
-                      "Btrfs: too many missing devices, writeable mount is not allowed\n");
-               goto fail_block_groups;
+               printk(KERN_WARNING "BTRFS: "
+                       "too many missing devices, writeable mount is not allowed\n");
+               goto fail_sysfs;
        }
 
        fs_info->cleaner_kthread = kthread_run(cleaner_kthread, tree_root,
                                               "btrfs-cleaner");
        if (IS_ERR(fs_info->cleaner_kthread))
-               goto fail_block_groups;
+               goto fail_sysfs;
 
        fs_info->transaction_kthread = kthread_run(transaction_kthread,
                                                   tree_root,
@@ -2778,11 +2774,15 @@ retry_root_backup:
        if (!btrfs_test_opt(tree_root, SSD) &&
            !btrfs_test_opt(tree_root, NOSSD) &&
            !fs_info->fs_devices->rotating) {
-               printk(KERN_INFO "Btrfs detected SSD devices, enabling SSD "
+               printk(KERN_INFO "BTRFS: detected SSD devices, enabling SSD "
                       "mode\n");
                btrfs_set_opt(fs_info->mount_opt, SSD);
        }
 
+       /* Set the real inode map cache flag */
+       if (btrfs_test_opt(tree_root, CHANGE_INODE_CACHE))
+               btrfs_set_opt(tree_root->fs_info->mount_opt, INODE_MAP_CACHE);
+
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
        if (btrfs_test_opt(tree_root, CHECK_INTEGRITY)) {
                ret = btrfsic_mount(tree_root, fs_devices,
@@ -2791,7 +2791,7 @@ retry_root_backup:
                                    1 : 0,
                                    fs_info->check_integrity_print_mask);
                if (ret)
-                       printk(KERN_WARNING "btrfs: failed to initialize"
+                       printk(KERN_WARNING "BTRFS: failed to initialize"
                               " integrity check module %s\n", sb->s_id);
        }
 #endif
@@ -2804,7 +2804,7 @@ retry_root_backup:
                u64 bytenr = btrfs_super_log_root(disk_super);
 
                if (fs_devices->rw_devices == 0) {
-                       printk(KERN_WARNING "Btrfs log replay required "
+                       printk(KERN_WARNING "BTRFS: log replay required "
                               "on RO media\n");
                        err = -EIO;
                        goto fail_qgroup;
@@ -2827,7 +2827,7 @@ retry_root_backup:
                                                      generation + 1);
                if (!log_tree_root->node ||
                    !extent_buffer_uptodate(log_tree_root->node)) {
-                       printk(KERN_ERR "btrfs: failed to read log tree\n");
+                       printk(KERN_ERR "BTRFS: failed to read log tree\n");
                        free_extent_buffer(log_tree_root->node);
                        kfree(log_tree_root);
                        goto fail_trans_kthread;
@@ -2861,7 +2861,7 @@ retry_root_backup:
                ret = btrfs_recover_relocation(tree_root);
                if (ret < 0) {
                        printk(KERN_WARNING
-                              "btrfs: failed to recover relocation\n");
+                              "BTRFS: failed to recover relocation\n");
                        err = -EINVAL;
                        goto fail_qgroup;
                }
@@ -2891,14 +2891,14 @@ retry_root_backup:
 
        ret = btrfs_resume_balance_async(fs_info);
        if (ret) {
-               printk(KERN_WARNING "btrfs: failed to resume balance\n");
+               printk(KERN_WARNING "BTRFS: failed to resume balance\n");
                close_ctree(tree_root);
                return ret;
        }
 
        ret = btrfs_resume_dev_replace_async(fs_info);
        if (ret) {
-               pr_warn("btrfs: failed to resume dev_replace\n");
+               pr_warn("BTRFS: failed to resume dev_replace\n");
                close_ctree(tree_root);
                return ret;
        }
@@ -2906,20 +2906,20 @@ retry_root_backup:
        btrfs_qgroup_rescan_resume(fs_info);
 
        if (create_uuid_tree) {
-               pr_info("btrfs: creating UUID tree\n");
+               pr_info("BTRFS: creating UUID tree\n");
                ret = btrfs_create_uuid_tree(fs_info);
                if (ret) {
-                       pr_warn("btrfs: failed to create the UUID tree %d\n",
+                       pr_warn("BTRFS: failed to create the UUID tree %d\n",
                                ret);
                        close_ctree(tree_root);
                        return ret;
                }
        } else if (check_uuid_tree ||
                   btrfs_test_opt(tree_root, RESCAN_UUID_TREE)) {
-               pr_info("btrfs: checking UUID tree\n");
+               pr_info("BTRFS: checking UUID tree\n");
                ret = btrfs_check_uuid_tree(fs_info);
                if (ret) {
-                       pr_warn("btrfs: failed to check the UUID tree %d\n",
+                       pr_warn("BTRFS: failed to check the UUID tree %d\n",
                                ret);
                        close_ctree(tree_root);
                        return ret;
@@ -2945,6 +2945,9 @@ fail_cleaner:
         */
        filemap_write_and_wait(fs_info->btree_inode->i_mapping);
 
+fail_sysfs:
+       btrfs_sysfs_remove_one(fs_info);
+
 fail_block_groups:
        btrfs_put_block_group_cache(fs_info);
        btrfs_free_block_groups(fs_info);
@@ -3000,7 +3003,7 @@ static void btrfs_end_buffer_write_sync(struct buffer_head *bh, int uptodate)
                struct btrfs_device *device = (struct btrfs_device *)
                        bh->b_private;
 
-               printk_ratelimited_in_rcu(KERN_WARNING "lost page write due to "
+               printk_ratelimited_in_rcu(KERN_WARNING "BTRFS: lost page write due to "
                                          "I/O error on %s\n",
                                          rcu_str_deref(device->name));
                /* note, we dont' set_buffer_write_io_error because we have
@@ -3119,7 +3122,7 @@ static int write_dev_supers(struct btrfs_device *device,
                        bh = __getblk(device->bdev, bytenr / 4096,
                                      BTRFS_SUPER_INFO_SIZE);
                        if (!bh) {
-                               printk(KERN_ERR "btrfs: couldn't get super "
+                               printk(KERN_ERR "BTRFS: couldn't get super "
                                       "buffer head for bytenr %Lu\n", bytenr);
                                errors++;
                                continue;
@@ -3140,7 +3143,10 @@ static int write_dev_supers(struct btrfs_device *device,
                 * we fua the first super.  The others we allow
                 * to go down lazy.
                 */
-               ret = btrfsic_submit_bh(WRITE_FUA, bh);
+               if (i == 0)
+                       ret = btrfsic_submit_bh(WRITE_FUA, bh);
+               else
+                       ret = btrfsic_submit_bh(WRITE_SYNC, bh);
                if (ret)
                        errors++;
        }
@@ -3186,7 +3192,7 @@ static int write_dev_flush(struct btrfs_device *device, int wait)
                wait_for_completion(&device->flush_wait);
 
                if (bio_flagged(bio, BIO_EOPNOTSUPP)) {
-                       printk_in_rcu("btrfs: disabling barriers on dev %s\n",
+                       printk_in_rcu("BTRFS: disabling barriers on dev %s\n",
                                      rcu_str_deref(device->name));
                        device->nobarriers = 1;
                } else if (!bio_flagged(bio, BIO_UPTODATE)) {
@@ -3407,7 +3413,7 @@ static int write_all_supers(struct btrfs_root *root, int max_mirrors)
                        total_errors++;
        }
        if (total_errors > max_errors) {
-               printk(KERN_ERR "btrfs: %d errors while writing supers\n",
+               btrfs_err(root->fs_info, "%d errors while writing supers",
                       total_errors);
                mutex_unlock(&root->fs_info->fs_devices->device_list_mutex);
 
@@ -3455,10 +3461,8 @@ void btrfs_drop_and_free_fs_root(struct btrfs_fs_info *fs_info,
        if (btrfs_root_refs(&root->root_item) == 0)
                synchronize_srcu(&fs_info->subvol_srcu);
 
-       if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state)) {
+       if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
                btrfs_free_log(NULL, root);
-               btrfs_free_log_root_tree(NULL, fs_info);
-       }
 
        __btrfs_remove_free_space_cache(root->free_ino_pinned);
        __btrfs_remove_free_space_cache(root->free_ino_ctl);
@@ -3563,14 +3567,12 @@ int close_ctree(struct btrfs_root *root)
        if (!(fs_info->sb->s_flags & MS_RDONLY)) {
                ret = btrfs_commit_super(root);
                if (ret)
-                       printk(KERN_ERR "btrfs: commit super ret %d\n", ret);
+                       btrfs_err(root->fs_info, "commit super ret %d", ret);
        }
 
        if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
                btrfs_error_commit_super(root);
 
-       btrfs_put_block_group_cache(fs_info);
-
        kthread_stop(fs_info->transaction_kthread);
        kthread_stop(fs_info->cleaner_kthread);
 
@@ -3580,12 +3582,16 @@ int close_ctree(struct btrfs_root *root)
        btrfs_free_qgroup_config(root->fs_info);
 
        if (percpu_counter_sum(&fs_info->delalloc_bytes)) {
-               printk(KERN_INFO "btrfs: at unmount delalloc count %lld\n",
+               btrfs_info(root->fs_info, "at unmount delalloc count %lld",
                       percpu_counter_sum(&fs_info->delalloc_bytes));
        }
 
+       btrfs_sysfs_remove_one(fs_info);
+
        del_fs_roots(fs_info);
 
+       btrfs_put_block_group_cache(fs_info);
+
        btrfs_free_block_groups(fs_info);
 
        btrfs_stop_all_workers(fs_info);
@@ -3803,55 +3809,55 @@ static int btrfs_destroy_delayed_refs(struct btrfs_transaction *trans,
        delayed_refs = &trans->delayed_refs;
 
        spin_lock(&delayed_refs->lock);
-       if (delayed_refs->num_entries == 0) {
+       if (atomic_read(&delayed_refs->num_entries) == 0) {
                spin_unlock(&delayed_refs->lock);
-               printk(KERN_INFO "delayed_refs has NO entry\n");
+               btrfs_info(root->fs_info, "delayed_refs has NO entry");
                return ret;
        }
 
-       while ((node = rb_first(&delayed_refs->root)) != NULL) {
-               struct btrfs_delayed_ref_head *head = NULL;
+       while ((node = rb_first(&delayed_refs->href_root)) != NULL) {
+               struct btrfs_delayed_ref_head *head;
                bool pin_bytes = false;
 
-               ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
-               atomic_set(&ref->refs, 1);
-               if (btrfs_delayed_ref_is_head(ref)) {
-
-                       head = btrfs_delayed_node_to_head(ref);
-                       if (!mutex_trylock(&head->mutex)) {
-                               atomic_inc(&ref->refs);
-                               spin_unlock(&delayed_refs->lock);
-
-                               /* Need to wait for the delayed ref to run */
-                               mutex_lock(&head->mutex);
-                               mutex_unlock(&head->mutex);
-                               btrfs_put_delayed_ref(ref);
-
-                               spin_lock(&delayed_refs->lock);
-                               continue;
-                       }
+               head = rb_entry(node, struct btrfs_delayed_ref_head,
+                               href_node);
+               if (!mutex_trylock(&head->mutex)) {
+                       atomic_inc(&head->node.refs);
+                       spin_unlock(&delayed_refs->lock);
 
-                       if (head->must_insert_reserved)
-                               pin_bytes = true;
-                       btrfs_free_delayed_extent_op(head->extent_op);
-                       delayed_refs->num_heads--;
-                       if (list_empty(&head->cluster))
-                               delayed_refs->num_heads_ready--;
-                       list_del_init(&head->cluster);
-               }
-
-               ref->in_tree = 0;
-               rb_erase(&ref->rb_node, &delayed_refs->root);
-               delayed_refs->num_entries--;
-               spin_unlock(&delayed_refs->lock);
-               if (head) {
-                       if (pin_bytes)
-                               btrfs_pin_extent(root, ref->bytenr,
-                                                ref->num_bytes, 1);
+                       mutex_lock(&head->mutex);
                        mutex_unlock(&head->mutex);
+                       btrfs_put_delayed_ref(&head->node);
+                       spin_lock(&delayed_refs->lock);
+                       continue;
+               }
+               spin_lock(&head->lock);
+               while ((node = rb_first(&head->ref_root)) != NULL) {
+                       ref = rb_entry(node, struct btrfs_delayed_ref_node,
+                                      rb_node);
+                       ref->in_tree = 0;
+                       rb_erase(&ref->rb_node, &head->ref_root);
+                       atomic_dec(&delayed_refs->num_entries);
+                       btrfs_put_delayed_ref(ref);
+                       cond_resched_lock(&head->lock);
                }
-               btrfs_put_delayed_ref(ref);
+               if (head->must_insert_reserved)
+                       pin_bytes = true;
+               btrfs_free_delayed_extent_op(head->extent_op);
+               delayed_refs->num_heads--;
+               if (head->processing == 0)
+                       delayed_refs->num_heads_ready--;
+               atomic_dec(&delayed_refs->num_entries);
+               head->node.in_tree = 0;
+               rb_erase(&head->href_node, &delayed_refs->href_root);
+               spin_unlock(&head->lock);
+               spin_unlock(&delayed_refs->lock);
+               mutex_unlock(&head->mutex);
 
+               if (pin_bytes)
+                       btrfs_pin_extent(root, head->node.bytenr,
+                                        head->node.num_bytes, 1);
+               btrfs_put_delayed_ref(&head->node);
                cond_resched();
                spin_lock(&delayed_refs->lock);
        }
index 9c01509dd8abfb0fddc5480b7f4cb3b73002aad4..9c9ecc93ae2c3152d85cb2e15eeabd7bec95160f 100644 (file)
@@ -35,6 +35,7 @@
 #include "locking.h"
 #include "free-space-cache.h"
 #include "math.h"
+#include "sysfs.h"
 
 #undef SCRAMBLE_DELAYED_REFS
 
@@ -441,7 +442,8 @@ next:
                        if (ret)
                                break;
 
-                       if (need_resched()) {
+                       if (need_resched() ||
+                           rwsem_is_contended(&fs_info->extent_commit_sem)) {
                                caching_ctl->progress = last;
                                btrfs_release_path(path);
                                up_read(&fs_info->extent_commit_sem);
@@ -855,12 +857,14 @@ again:
                        btrfs_put_delayed_ref(&head->node);
                        goto search_again;
                }
+               spin_lock(&head->lock);
                if (head->extent_op && head->extent_op->update_flags)
                        extent_flags |= head->extent_op->flags_to_set;
                else
                        BUG_ON(num_refs == 0);
 
                num_refs += head->node.ref_mod;
+               spin_unlock(&head->lock);
                mutex_unlock(&head->mutex);
        }
        spin_unlock(&delayed_refs->lock);
@@ -1070,11 +1074,11 @@ static u64 hash_extent_data_ref(u64 root_objectid, u64 owner, u64 offset)
        __le64 lenum;
 
        lenum = cpu_to_le64(root_objectid);
-       high_crc = crc32c(high_crc, &lenum, sizeof(lenum));
+       high_crc = btrfs_crc32c(high_crc, &lenum, sizeof(lenum));
        lenum = cpu_to_le64(owner);
-       low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
+       low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum));
        lenum = cpu_to_le64(offset);
-       low_crc = crc32c(low_crc, &lenum, sizeof(lenum));
+       low_crc = btrfs_crc32c(low_crc, &lenum, sizeof(lenum));
 
        return ((u64)high_crc << 31) ^ (u64)low_crc;
 }
@@ -2285,64 +2289,62 @@ static noinline struct btrfs_delayed_ref_node *
 select_delayed_ref(struct btrfs_delayed_ref_head *head)
 {
        struct rb_node *node;
-       struct btrfs_delayed_ref_node *ref;
-       int action = BTRFS_ADD_DELAYED_REF;
-again:
+       struct btrfs_delayed_ref_node *ref, *last = NULL;;
+
        /*
         * select delayed ref of type BTRFS_ADD_DELAYED_REF first.
         * this prevents ref count from going down to zero when
         * there still are pending delayed ref.
         */
-       node = rb_prev(&head->node.rb_node);
-       while (1) {
-               if (!node)
-                       break;
+       node = rb_first(&head->ref_root);
+       while (node) {
                ref = rb_entry(node, struct btrfs_delayed_ref_node,
                                rb_node);
-               if (ref->bytenr != head->node.bytenr)
-                       break;
-               if (ref->action == action)
+               if (ref->action == BTRFS_ADD_DELAYED_REF)
                        return ref;
-               node = rb_prev(node);
-       }
-       if (action == BTRFS_ADD_DELAYED_REF) {
-               action = BTRFS_DROP_DELAYED_REF;
-               goto again;
+               else if (last == NULL)
+                       last = ref;
+               node = rb_next(node);
        }
-       return NULL;
+       return last;
 }
 
 /*
  * Returns 0 on success or if called with an already aborted transaction.
  * Returns -ENOMEM or -EIO on failure and will abort the transaction.
  */
-static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
-                                      struct btrfs_root *root,
-                                      struct list_head *cluster)
+static noinline int __btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
+                                            struct btrfs_root *root,
+                                            unsigned long nr)
 {
        struct btrfs_delayed_ref_root *delayed_refs;
        struct btrfs_delayed_ref_node *ref;
        struct btrfs_delayed_ref_head *locked_ref = NULL;
        struct btrfs_delayed_extent_op *extent_op;
        struct btrfs_fs_info *fs_info = root->fs_info;
+       ktime_t start = ktime_get();
        int ret;
-       int count = 0;
+       unsigned long count = 0;
+       unsigned long actual_count = 0;
        int must_insert_reserved = 0;
 
        delayed_refs = &trans->transaction->delayed_refs;
        while (1) {
                if (!locked_ref) {
-                       /* pick a new head ref from the cluster list */
-                       if (list_empty(cluster))
+                       if (count >= nr)
                                break;
 
-                       locked_ref = list_entry(cluster->next,
-                                    struct btrfs_delayed_ref_head, cluster);
+                       spin_lock(&delayed_refs->lock);
+                       locked_ref = btrfs_select_ref_head(trans);
+                       if (!locked_ref) {
+                               spin_unlock(&delayed_refs->lock);
+                               break;
+                       }
 
                        /* grab the lock that says we are going to process
                         * all the refs for this head */
                        ret = btrfs_delayed_ref_lock(trans, locked_ref);
-
+                       spin_unlock(&delayed_refs->lock);
                        /*
                         * we may have dropped the spin lock to get the head
                         * mutex lock, and that might have given someone else
@@ -2363,6 +2365,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                 * finish.  If we merged anything we need to re-loop so we can
                 * get a good ref.
                 */
+               spin_lock(&locked_ref->lock);
                btrfs_merge_delayed_refs(trans, fs_info, delayed_refs,
                                         locked_ref);
 
@@ -2374,17 +2377,14 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
 
                if (ref && ref->seq &&
                    btrfs_check_delayed_seq(fs_info, delayed_refs, ref->seq)) {
-                       /*
-                        * there are still refs with lower seq numbers in the
-                        * process of being added. Don't run this ref yet.
-                        */
-                       list_del_init(&locked_ref->cluster);
+                       spin_unlock(&locked_ref->lock);
                        btrfs_delayed_ref_unlock(locked_ref);
-                       locked_ref = NULL;
+                       spin_lock(&delayed_refs->lock);
+                       locked_ref->processing = 0;
                        delayed_refs->num_heads_ready++;
                        spin_unlock(&delayed_refs->lock);
+                       locked_ref = NULL;
                        cond_resched();
-                       spin_lock(&delayed_refs->lock);
                        continue;
                }
 
@@ -2399,6 +2399,8 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                locked_ref->extent_op = NULL;
 
                if (!ref) {
+
+
                        /* All delayed refs have been processed, Go ahead
                         * and send the head node to run_one_delayed_ref,
                         * so that any accounting fixes can happen
@@ -2411,8 +2413,7 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                        }
 
                        if (extent_op) {
-                               spin_unlock(&delayed_refs->lock);
-
+                               spin_unlock(&locked_ref->lock);
                                ret = run_delayed_extent_op(trans, root,
                                                            ref, extent_op);
                                btrfs_free_delayed_extent_op(extent_op);
@@ -2426,19 +2427,39 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                                         */
                                        if (must_insert_reserved)
                                                locked_ref->must_insert_reserved = 1;
+                                       locked_ref->processing = 0;
                                        btrfs_debug(fs_info, "run_delayed_extent_op returned %d", ret);
-                                       spin_lock(&delayed_refs->lock);
                                        btrfs_delayed_ref_unlock(locked_ref);
                                        return ret;
                                }
+                               continue;
+                       }
 
-                               goto next;
+                       /*
+                        * Need to drop our head ref lock and re-aqcuire the
+                        * delayed ref lock and then re-check to make sure
+                        * nobody got added.
+                        */
+                       spin_unlock(&locked_ref->lock);
+                       spin_lock(&delayed_refs->lock);
+                       spin_lock(&locked_ref->lock);
+                       if (rb_first(&locked_ref->ref_root)) {
+                               spin_unlock(&locked_ref->lock);
+                               spin_unlock(&delayed_refs->lock);
+                               continue;
                        }
+                       ref->in_tree = 0;
+                       delayed_refs->num_heads--;
+                       rb_erase(&locked_ref->href_node,
+                                &delayed_refs->href_root);
+                       spin_unlock(&delayed_refs->lock);
+               } else {
+                       actual_count++;
+                       ref->in_tree = 0;
+                       rb_erase(&ref->rb_node, &locked_ref->ref_root);
                }
+               atomic_dec(&delayed_refs->num_entries);
 
-               ref->in_tree = 0;
-               rb_erase(&ref->rb_node, &delayed_refs->root);
-               delayed_refs->num_entries--;
                if (!btrfs_delayed_ref_is_head(ref)) {
                        /*
                         * when we play the delayed ref, also correct the
@@ -2455,20 +2476,18 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                        default:
                                WARN_ON(1);
                        }
-               } else {
-                       list_del_init(&locked_ref->cluster);
                }
-               spin_unlock(&delayed_refs->lock);
+               spin_unlock(&locked_ref->lock);
 
                ret = run_one_delayed_ref(trans, root, ref, extent_op,
                                          must_insert_reserved);
 
                btrfs_free_delayed_extent_op(extent_op);
                if (ret) {
+                       locked_ref->processing = 0;
                        btrfs_delayed_ref_unlock(locked_ref);
                        btrfs_put_delayed_ref(ref);
                        btrfs_debug(fs_info, "run_one_delayed_ref returned %d", ret);
-                       spin_lock(&delayed_refs->lock);
                        return ret;
                }
 
@@ -2484,11 +2503,29 @@ static noinline int run_clustered_refs(struct btrfs_trans_handle *trans,
                }
                btrfs_put_delayed_ref(ref);
                count++;
-next:
                cond_resched();
+       }
+
+       /*
+        * We don't want to include ref heads since we can have empty ref heads
+        * and those will drastically skew our runtime down since we just do
+        * accounting, no actual extent tree updates.
+        */
+       if (actual_count > 0) {
+               u64 runtime = ktime_to_ns(ktime_sub(ktime_get(), start));
+               u64 avg;
+
+               /*
+                * We weigh the current average higher than our current runtime
+                * to avoid large swings in the average.
+                */
                spin_lock(&delayed_refs->lock);
+               avg = fs_info->avg_delayed_ref_runtime * 3 + runtime;
+               avg = div64_u64(avg, 4);
+               fs_info->avg_delayed_ref_runtime = avg;
+               spin_unlock(&delayed_refs->lock);
        }
-       return count;
+       return 0;
 }
 
 #ifdef SCRAMBLE_DELAYED_REFS
@@ -2570,16 +2607,6 @@ int btrfs_delayed_refs_qgroup_accounting(struct btrfs_trans_handle *trans,
        return ret;
 }
 
-static int refs_newer(struct btrfs_delayed_ref_root *delayed_refs, int seq,
-                     int count)
-{
-       int val = atomic_read(&delayed_refs->ref_seq);
-
-       if (val < seq || val >= seq + count)
-               return 1;
-       return 0;
-}
-
 static inline u64 heads_to_leaves(struct btrfs_root *root, u64 heads)
 {
        u64 num_bytes;
@@ -2596,7 +2623,7 @@ static inline u64 heads_to_leaves(struct btrfs_root *root, u64 heads)
        return div64_u64(num_bytes, BTRFS_LEAF_DATA_SIZE(root));
 }
 
-int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans,
+int btrfs_check_space_for_delayed_refs(struct btrfs_trans_handle *trans,
                                       struct btrfs_root *root)
 {
        struct btrfs_block_rsv *global_rsv;
@@ -2625,6 +2652,22 @@ int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans,
        return ret;
 }
 
+int btrfs_should_throttle_delayed_refs(struct btrfs_trans_handle *trans,
+                                      struct btrfs_root *root)
+{
+       struct btrfs_fs_info *fs_info = root->fs_info;
+       u64 num_entries =
+               atomic_read(&trans->transaction->delayed_refs.num_entries);
+       u64 avg_runtime;
+
+       smp_mb();
+       avg_runtime = fs_info->avg_delayed_ref_runtime;
+       if (num_entries * avg_runtime >= NSEC_PER_SEC)
+               return 1;
+
+       return btrfs_check_space_for_delayed_refs(trans, root);
+}
+
 /*
  * this starts processing the delayed reference count updates and
  * extent insertions we have queued up so far.  count can be
@@ -2640,13 +2683,10 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
 {
        struct rb_node *node;
        struct btrfs_delayed_ref_root *delayed_refs;
-       struct btrfs_delayed_ref_node *ref;
-       struct list_head cluster;
+       struct btrfs_delayed_ref_head *head;
        int ret;
-       u64 delayed_start;
        int run_all = count == (unsigned long)-1;
        int run_most = 0;
-       int loops;
 
        /* We'll clean this up in btrfs_cleanup_transaction */
        if (trans->aborted)
@@ -2658,130 +2698,40 @@ int btrfs_run_delayed_refs(struct btrfs_trans_handle *trans,
        btrfs_delayed_refs_qgroup_accounting(trans, root->fs_info);
 
        delayed_refs = &trans->transaction->delayed_refs;
-       INIT_LIST_HEAD(&cluster);
        if (count == 0) {
-               count = delayed_refs->num_entries * 2;
+               count = atomic_read(&delayed_refs->num_entries) * 2;
                run_most = 1;
        }
 
-       if (!run_all && !run_most) {
-               int old;
-               int seq = atomic_read(&delayed_refs->ref_seq);
-
-progress:
-               old = atomic_cmpxchg(&delayed_refs->procs_running_refs, 0, 1);
-               if (old) {
-                       DEFINE_WAIT(__wait);
-                       if (delayed_refs->flushing ||
-                           !btrfs_should_throttle_delayed_refs(trans, root))
-                               return 0;
-
-                       prepare_to_wait(&delayed_refs->wait, &__wait,
-                                       TASK_UNINTERRUPTIBLE);
-
-                       old = atomic_cmpxchg(&delayed_refs->procs_running_refs, 0, 1);
-                       if (old) {
-                               schedule();
-                               finish_wait(&delayed_refs->wait, &__wait);
-
-                               if (!refs_newer(delayed_refs, seq, 256))
-                                       goto progress;
-                               else
-                                       return 0;
-                       } else {
-                               finish_wait(&delayed_refs->wait, &__wait);
-                               goto again;
-                       }
-               }
-
-       } else {
-               atomic_inc(&delayed_refs->procs_running_refs);
-       }
-
 again:
-       loops = 0;
-       spin_lock(&delayed_refs->lock);
-
 #ifdef SCRAMBLE_DELAYED_REFS
        delayed_refs->run_delayed_start = find_middle(&delayed_refs->root);
 #endif
-
-       while (1) {
-               if (!(run_all || run_most) &&
-                   !btrfs_should_throttle_delayed_refs(trans, root))
-                       break;
-
-               /*
-                * go find something we can process in the rbtree.  We start at
-                * the beginning of the tree, and then build a cluster
-                * of refs to process starting at the first one we are able to
-                * lock
-                */
-               delayed_start = delayed_refs->run_delayed_start;
-               ret = btrfs_find_ref_cluster(trans, &cluster,
-                                            delayed_refs->run_delayed_start);
-               if (ret)
-                       break;
-
-               ret = run_clustered_refs(trans, root, &cluster);
-               if (ret < 0) {
-                       btrfs_release_ref_cluster(&cluster);
-                       spin_unlock(&delayed_refs->lock);
-                       btrfs_abort_transaction(trans, root, ret);
-                       atomic_dec(&delayed_refs->procs_running_refs);
-                       wake_up(&delayed_refs->wait);
-                       return ret;
-               }
-
-               atomic_add(ret, &delayed_refs->ref_seq);
-
-               count -= min_t(unsigned long, ret, count);
-
-               if (count == 0)
-                       break;
-
-               if (delayed_start >= delayed_refs->run_delayed_start) {
-                       if (loops == 0) {
-                               /*
-                                * btrfs_find_ref_cluster looped. let's do one
-                                * more cycle. if we don't run any delayed ref
-                                * during that cycle (because we can't because
-                                * all of them are blocked), bail out.
-                                */
-                               loops = 1;
-                       } else {
-                               /*
-                                * no runnable refs left, stop trying
-                                */
-                               BUG_ON(run_all);
-                               break;
-                       }
-               }
-               if (ret) {
-                       /* refs were run, let's reset staleness detection */
-                       loops = 0;
-               }
+       ret = __btrfs_run_delayed_refs(trans, root, count);
+       if (ret < 0) {
+               btrfs_abort_transaction(trans, root, ret);
+               return ret;
        }
 
        if (run_all) {
-               if (!list_empty(&trans->new_bgs)) {
-                       spin_unlock(&delayed_refs->lock);
+               if (!list_empty(&trans->new_bgs))
                        btrfs_create_pending_block_groups(trans, root);
-                       spin_lock(&delayed_refs->lock);
-               }
 
-               node = rb_first(&delayed_refs->root);
-               if (!node)
+               spin_lock(&delayed_refs->lock);
+               node = rb_first(&delayed_refs->href_root);
+               if (!node) {
+                       spin_unlock(&delayed_refs->lock);
                        goto out;
+               }
                count = (unsigned long)-1;
 
                while (node) {
-                       ref = rb_entry(node, struct btrfs_delayed_ref_node,
-                                      rb_node);
-                       if (btrfs_delayed_ref_is_head(ref)) {
-                               struct btrfs_delayed_ref_head *head;
+                       head = rb_entry(node, struct btrfs_delayed_ref_head,
+                                       href_node);
+                       if (btrfs_delayed_ref_is_head(&head->node)) {
+                               struct btrfs_delayed_ref_node *ref;
 
-                               head = btrfs_delayed_node_to_head(ref);
+                               ref = &head->node;
                                atomic_inc(&ref->refs);
 
                                spin_unlock(&delayed_refs->lock);
@@ -2795,20 +2745,16 @@ again:
                                btrfs_put_delayed_ref(ref);
                                cond_resched();
                                goto again;
+                       } else {
+                               WARN_ON(1);
                        }
                        node = rb_next(node);
                }
                spin_unlock(&delayed_refs->lock);
-               schedule_timeout(1);
+               cond_resched();
                goto again;
        }
 out:
-       atomic_dec(&delayed_refs->procs_running_refs);
-       smp_mb();
-       if (waitqueue_active(&delayed_refs->wait))
-               wake_up(&delayed_refs->wait);
-
-       spin_unlock(&delayed_refs->lock);
        assert_qgroups_uptodate(trans);
        return 0;
 }
@@ -2850,12 +2796,13 @@ static noinline int check_delayed_ref(struct btrfs_trans_handle *trans,
        struct rb_node *node;
        int ret = 0;
 
-       ret = -ENOENT;
        delayed_refs = &trans->transaction->delayed_refs;
        spin_lock(&delayed_refs->lock);
        head = btrfs_find_delayed_ref_head(trans, bytenr);
-       if (!head)
-               goto out;
+       if (!head) {
+               spin_unlock(&delayed_refs->lock);
+               return 0;
+       }
 
        if (!mutex_trylock(&head->mutex)) {
                atomic_inc(&head->node.refs);
@@ -2872,40 +2819,35 @@ static noinline int check_delayed_ref(struct btrfs_trans_handle *trans,
                btrfs_put_delayed_ref(&head->node);
                return -EAGAIN;
        }
+       spin_unlock(&delayed_refs->lock);
 
-       node = rb_prev(&head->node.rb_node);
-       if (!node)
-               goto out_unlock;
-
-       ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
-
-       if (ref->bytenr != bytenr)
-               goto out_unlock;
-
-       ret = 1;
-       if (ref->type != BTRFS_EXTENT_DATA_REF_KEY)
-               goto out_unlock;
+       spin_lock(&head->lock);
+       node = rb_first(&head->ref_root);
+       while (node) {
+               ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
+               node = rb_next(node);
 
-       data_ref = btrfs_delayed_node_to_data_ref(ref);
+               /* If it's a shared ref we know a cross reference exists */
+               if (ref->type != BTRFS_EXTENT_DATA_REF_KEY) {
+                       ret = 1;
+                       break;
+               }
 
-       node = rb_prev(node);
-       if (node) {
-               int seq = ref->seq;
+               data_ref = btrfs_delayed_node_to_data_ref(ref);
 
-               ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
-               if (ref->bytenr == bytenr && ref->seq == seq)
-                       goto out_unlock;
+               /*
+                * If our ref doesn't match the one we're currently looking at
+                * then we have a cross reference.
+                */
+               if (data_ref->root != root->root_key.objectid ||
+                   data_ref->objectid != objectid ||
+                   data_ref->offset != offset) {
+                       ret = 1;
+                       break;
+               }
        }
-
-       if (data_ref->root != root->root_key.objectid ||
-           data_ref->objectid != objectid || data_ref->offset != offset)
-               goto out_unlock;
-
-       ret = 0;
-out_unlock:
+       spin_unlock(&head->lock);
        mutex_unlock(&head->mutex);
-out:
-       spin_unlock(&delayed_refs->lock);
        return ret;
 }
 
@@ -3402,6 +3344,23 @@ int btrfs_extent_readonly(struct btrfs_root *root, u64 bytenr)
        return readonly;
 }
 
+static const char *alloc_name(u64 flags)
+{
+       switch (flags) {
+       case BTRFS_BLOCK_GROUP_METADATA|BTRFS_BLOCK_GROUP_DATA:
+               return "mixed";
+       case BTRFS_BLOCK_GROUP_METADATA:
+               return "metadata";
+       case BTRFS_BLOCK_GROUP_DATA:
+               return "data";
+       case BTRFS_BLOCK_GROUP_SYSTEM:
+               return "system";
+       default:
+               WARN_ON(1);
+               return "invalid-combination";
+       };
+}
+
 static int update_space_info(struct btrfs_fs_info *info, u64 flags,
                             u64 total_bytes, u64 bytes_used,
                             struct btrfs_space_info **space_info)
@@ -3439,8 +3398,10 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
                return ret;
        }
 
-       for (i = 0; i < BTRFS_NR_RAID_TYPES; i++)
+       for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
                INIT_LIST_HEAD(&found->block_groups[i]);
+               kobject_init(&found->block_group_kobjs[i], &btrfs_raid_ktype);
+       }
        init_rwsem(&found->groups_sem);
        spin_lock_init(&found->lock);
        found->flags = flags & BTRFS_BLOCK_GROUP_TYPE_MASK;
@@ -3457,11 +3418,21 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
        found->chunk_alloc = 0;
        found->flush = 0;
        init_waitqueue_head(&found->wait);
+
+       ret = kobject_init_and_add(&found->kobj, &space_info_ktype,
+                                   info->space_info_kobj, "%s",
+                                   alloc_name(found->flags));
+       if (ret) {
+               kfree(found);
+               return ret;
+       }
+
        *space_info = found;
        list_add_rcu(&found->list, &info->space_info);
        if (flags & BTRFS_BLOCK_GROUP_DATA)
                info->data_sinfo = found;
-       return 0;
+
+       return ret;
 }
 
 static void set_avail_alloc_bits(struct btrfs_fs_info *fs_info, u64 flags)
@@ -4637,7 +4608,7 @@ void btrfs_block_rsv_release(struct btrfs_root *root,
                             u64 num_bytes)
 {
        struct btrfs_block_rsv *global_rsv = &root->fs_info->global_block_rsv;
-       if (global_rsv->full || global_rsv == block_rsv ||
+       if (global_rsv == block_rsv ||
            block_rsv->space_info != global_rsv->space_info)
                global_rsv = NULL;
        block_rsv_release_bytes(root->fs_info, block_rsv, global_rsv,
@@ -5916,24 +5887,16 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
 {
        struct btrfs_delayed_ref_head *head;
        struct btrfs_delayed_ref_root *delayed_refs;
-       struct btrfs_delayed_ref_node *ref;
-       struct rb_node *node;
        int ret = 0;
 
        delayed_refs = &trans->transaction->delayed_refs;
        spin_lock(&delayed_refs->lock);
        head = btrfs_find_delayed_ref_head(trans, bytenr);
        if (!head)
-               goto out;
+               goto out_delayed_unlock;
 
-       node = rb_prev(&head->node.rb_node);
-       if (!node)
-               goto out;
-
-       ref = rb_entry(node, struct btrfs_delayed_ref_node, rb_node);
-
-       /* there are still entries for this ref, we can't drop it */
-       if (ref->bytenr == bytenr)
+       spin_lock(&head->lock);
+       if (rb_first(&head->ref_root))
                goto out;
 
        if (head->extent_op) {
@@ -5955,19 +5918,19 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
         * ahead and process it.
         */
        head->node.in_tree = 0;
-       rb_erase(&head->node.rb_node, &delayed_refs->root);
+       rb_erase(&head->href_node, &delayed_refs->href_root);
 
-       delayed_refs->num_entries--;
+       atomic_dec(&delayed_refs->num_entries);
 
        /*
         * we don't take a ref on the node because we're removing it from the
         * tree, so we just steal the ref the tree was holding.
         */
        delayed_refs->num_heads--;
-       if (list_empty(&head->cluster))
+       if (head->processing == 0)
                delayed_refs->num_heads_ready--;
-
-       list_del_init(&head->cluster);
+       head->processing = 0;
+       spin_unlock(&head->lock);
        spin_unlock(&delayed_refs->lock);
 
        BUG_ON(head->extent_op);
@@ -5978,6 +5941,9 @@ static noinline int check_ref_cleanup(struct btrfs_trans_handle *trans,
        btrfs_put_delayed_ref(&head->node);
        return ret;
 out:
+       spin_unlock(&head->lock);
+
+out_delayed_unlock:
        spin_unlock(&delayed_refs->lock);
        return 0;
 }
@@ -6145,11 +6111,29 @@ int __get_raid_index(u64 flags)
        return BTRFS_RAID_SINGLE; /* BTRFS_BLOCK_GROUP_SINGLE */
 }
 
-static int get_block_group_index(struct btrfs_block_group_cache *cache)
+int get_block_group_index(struct btrfs_block_group_cache *cache)
 {
        return __get_raid_index(cache->flags);
 }
 
+static const char *btrfs_raid_type_names[BTRFS_NR_RAID_TYPES] = {
+       [BTRFS_RAID_RAID10]     = "raid10",
+       [BTRFS_RAID_RAID1]      = "raid1",
+       [BTRFS_RAID_DUP]        = "dup",
+       [BTRFS_RAID_RAID0]      = "raid0",
+       [BTRFS_RAID_SINGLE]     = "single",
+       [BTRFS_RAID_RAID5]      = "raid5",
+       [BTRFS_RAID_RAID6]      = "raid6",
+};
+
+static const char *get_raid_name(enum btrfs_raid_types type)
+{
+       if (type >= BTRFS_NR_RAID_TYPES)
+               return NULL;
+
+       return btrfs_raid_type_names[type];
+}
+
 enum btrfs_loop_type {
        LOOP_CACHING_NOWAIT = 0,
        LOOP_CACHING_WAIT = 1,
@@ -6177,7 +6161,6 @@ static noinline int find_free_extent(struct btrfs_root *orig_root,
        struct btrfs_root *root = orig_root->fs_info->extent_root;
        struct btrfs_free_cluster *last_ptr = NULL;
        struct btrfs_block_group_cache *block_group = NULL;
-       struct btrfs_block_group_cache *used_block_group;
        u64 search_start = 0;
        u64 max_extent_size = 0;
        int empty_cluster = 2 * 1024 * 1024;
@@ -6186,7 +6169,6 @@ static noinline int find_free_extent(struct btrfs_root *orig_root,
        int index = __get_raid_index(flags);
        int alloc_type = (flags & BTRFS_BLOCK_GROUP_DATA) ?
                RESERVE_ALLOC_NO_ACCOUNT : RESERVE_ALLOC;
-       bool found_uncached_bg = false;
        bool failed_cluster_refill = false;
        bool failed_alloc = false;
        bool use_cluster = true;
@@ -6239,7 +6221,6 @@ static noinline int find_free_extent(struct btrfs_root *orig_root,
        if (search_start == hint_byte) {
                block_group = btrfs_lookup_block_group(root->fs_info,
                                                       search_start);
-               used_block_group = block_group;
                /*
                 * we don't want to use the block group if it doesn't match our
                 * allocation bits, or if its not cached.
@@ -6276,7 +6257,6 @@ search:
                u64 offset;
                int cached;
 
-               used_block_group = block_group;
                btrfs_get_block_group(block_group);
                search_start = block_group->key.objectid;
 
@@ -6304,7 +6284,6 @@ search:
 have_block_group:
                cached = block_group_cache_done(block_group);
                if (unlikely(!cached)) {
-                       found_uncached_bg = true;
                        ret = cache_block_group(block_group, 0);
                        BUG_ON(ret < 0);
                        ret = 0;
@@ -6320,6 +6299,7 @@ have_block_group:
                 * lets look there
                 */
                if (last_ptr) {
+                       struct btrfs_block_group_cache *used_block_group;
                        unsigned long aligned_cluster;
                        /*
                         * the refill lock keeps out other
@@ -6330,10 +6310,8 @@ have_block_group:
                        if (used_block_group != block_group &&
                            (!used_block_group ||
                             used_block_group->ro ||
-                            !block_group_bits(used_block_group, flags))) {
-                               used_block_group = block_group;
+                            !block_group_bits(used_block_group, flags)))
                                goto refill_cluster;
-                       }
 
                        if (used_block_group != block_group)
                                btrfs_get_block_group(used_block_group);
@@ -6347,17 +6325,19 @@ have_block_group:
                                /* we have a block, we're done */
                                spin_unlock(&last_ptr->refill_lock);
                                trace_btrfs_reserve_extent_cluster(root,
-                                       block_group, search_start, num_bytes);
+                                               used_block_group,
+                                               search_start, num_bytes);
+                               if (used_block_group != block_group) {
+                                       btrfs_put_block_group(block_group);
+                                       block_group = used_block_group;
+                               }
                                goto checks;
                        }
 
                        WARN_ON(last_ptr->block_group != used_block_group);
-                       if (used_block_group != block_group) {
+                       if (used_block_group != block_group)
                                btrfs_put_block_group(used_block_group);
-                               used_block_group = block_group;
-                       }
 refill_cluster:
-                       BUG_ON(used_block_group != block_group);
                        /* If we are on LOOP_NO_EMPTY_SIZE, we can't
                         * set up a new clusters, so lets just skip it
                         * and let the allocator find whatever block
@@ -6476,25 +6456,25 @@ unclustered_alloc:
                        goto loop;
                }
 checks:
-               search_start = stripe_align(root, used_block_group,
+               search_start = stripe_align(root, block_group,
                                            offset, num_bytes);
 
                /* move on to the next group */
                if (search_start + num_bytes >
-                   used_block_group->key.objectid + used_block_group->key.offset) {
-                       btrfs_add_free_space(used_block_group, offset, num_bytes);
+                   block_group->key.objectid + block_group->key.offset) {
+                       btrfs_add_free_space(block_group, offset, num_bytes);
                        goto loop;
                }
 
                if (offset < search_start)
-                       btrfs_add_free_space(used_block_group, offset,
+                       btrfs_add_free_space(block_group, offset,
                                             search_start - offset);
                BUG_ON(offset > search_start);
 
-               ret = btrfs_update_reserved_bytes(used_block_group, num_bytes,
+               ret = btrfs_update_reserved_bytes(block_group, num_bytes,
                                                  alloc_type);
                if (ret == -EAGAIN) {
-                       btrfs_add_free_space(used_block_group, offset, num_bytes);
+                       btrfs_add_free_space(block_group, offset, num_bytes);
                        goto loop;
                }
 
@@ -6504,16 +6484,12 @@ checks:
 
                trace_btrfs_reserve_extent(orig_root, block_group,
                                           search_start, num_bytes);
-               if (used_block_group != block_group)
-                       btrfs_put_block_group(used_block_group);
                btrfs_put_block_group(block_group);
                break;
 loop:
                failed_cluster_refill = false;
                failed_alloc = false;
                BUG_ON(index != get_block_group_index(block_group));
-               if (used_block_group != block_group)
-                       btrfs_put_block_group(used_block_group);
                btrfs_put_block_group(block_group);
        }
        up_read(&space_info->groups_sem);
@@ -6584,12 +6560,12 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
        int index = 0;
 
        spin_lock(&info->lock);
-       printk(KERN_INFO "space_info %llu has %llu free, is %sfull\n",
+       printk(KERN_INFO "BTRFS: space_info %llu has %llu free, is %sfull\n",
               info->flags,
               info->total_bytes - info->bytes_used - info->bytes_pinned -
               info->bytes_reserved - info->bytes_readonly,
               (info->full) ? "" : "not ");
-       printk(KERN_INFO "space_info total=%llu, used=%llu, pinned=%llu, "
+       printk(KERN_INFO "BTRFS: space_info total=%llu, used=%llu, pinned=%llu, "
               "reserved=%llu, may_use=%llu, readonly=%llu\n",
               info->total_bytes, info->bytes_used, info->bytes_pinned,
               info->bytes_reserved, info->bytes_may_use,
@@ -6603,7 +6579,9 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes,
 again:
        list_for_each_entry(cache, &info->block_groups[index], list) {
                spin_lock(&cache->lock);
-               printk(KERN_INFO "block group %llu has %llu bytes, %llu used %llu pinned %llu reserved %s\n",
+               printk(KERN_INFO "BTRFS: "
+                          "block group %llu has %llu bytes, "
+                          "%llu used %llu pinned %llu reserved %s\n",
                       cache->key.objectid, cache->key.offset,
                       btrfs_block_group_used(&cache->item), cache->pinned,
                       cache->reserved, cache->ro ? "[readonly]" : "");
@@ -6966,7 +6944,7 @@ again:
                                /*DEFAULT_RATELIMIT_BURST*/ 1);
                if (__ratelimit(&_rs))
                        WARN(1, KERN_DEBUG
-                               "btrfs: block rsv returned %d\n", ret);
+                               "BTRFS: block rsv returned %d\n", ret);
        }
 try_reserve:
        ret = reserve_metadata_bytes(root, block_rsv, blocksize,
@@ -7714,7 +7692,7 @@ int btrfs_drop_snapshot(struct btrfs_root *root,
 
                        btrfs_end_transaction_throttle(trans, tree_root);
                        if (!for_reloc && btrfs_need_cleaner_sleep(root)) {
-                               pr_debug("btrfs: drop snapshot early exit\n");
+                               pr_debug("BTRFS: drop snapshot early exit\n");
                                err = -EAGAIN;
                                goto out_free;
                        }
@@ -7779,7 +7757,7 @@ out:
         */
        if (!for_reloc && root_dropped == false)
                btrfs_add_dead_root(root);
-       if (err)
+       if (err && err != -EAGAIN)
                btrfs_std_error(root->fs_info, err);
        return err;
 }
@@ -8333,6 +8311,8 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
        release_global_block_rsv(info);
 
        while (!list_empty(&info->space_info)) {
+               int i;
+
                space_info = list_entry(info->space_info.next,
                                        struct btrfs_space_info,
                                        list);
@@ -8343,9 +8323,17 @@ int btrfs_free_block_groups(struct btrfs_fs_info *info)
                                dump_space_info(space_info, 0, 0);
                        }
                }
-               percpu_counter_destroy(&space_info->total_bytes_pinned);
                list_del(&space_info->list);
-               kfree(space_info);
+               for (i = 0; i < BTRFS_NR_RAID_TYPES; i++) {
+                       struct kobject *kobj;
+                       kobj = &space_info->block_group_kobjs[i];
+                       if (kobj->parent) {
+                               kobject_del(kobj);
+                               kobject_put(kobj);
+                       }
+               }
+               kobject_del(&space_info->kobj);
+               kobject_put(&space_info->kobj);
        }
        return 0;
 }
@@ -8356,10 +8344,57 @@ static void __link_block_group(struct btrfs_space_info *space_info,
        int index = get_block_group_index(cache);
 
        down_write(&space_info->groups_sem);
+       if (list_empty(&space_info->block_groups[index])) {
+               struct kobject *kobj = &space_info->block_group_kobjs[index];
+               int ret;
+
+               kobject_get(&space_info->kobj); /* put in release */
+               ret = kobject_add(kobj, &space_info->kobj, "%s",
+                                 get_raid_name(index));
+               if (ret) {
+                       pr_warn("BTRFS: failed to add kobject for block cache. ignoring.\n");
+                       kobject_put(&space_info->kobj);
+               }
+       }
        list_add_tail(&cache->list, &space_info->block_groups[index]);
        up_write(&space_info->groups_sem);
 }
 
+static struct btrfs_block_group_cache *
+btrfs_create_block_group_cache(struct btrfs_root *root, u64 start, u64 size)
+{
+       struct btrfs_block_group_cache *cache;
+
+       cache = kzalloc(sizeof(*cache), GFP_NOFS);
+       if (!cache)
+               return NULL;
+
+       cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
+                                       GFP_NOFS);
+       if (!cache->free_space_ctl) {
+               kfree(cache);
+               return NULL;
+       }
+
+       cache->key.objectid = start;
+       cache->key.offset = size;
+       cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
+
+       cache->sectorsize = root->sectorsize;
+       cache->fs_info = root->fs_info;
+       cache->full_stripe_len = btrfs_full_stripe_len(root,
+                                              &root->fs_info->mapping_tree,
+                                              start);
+       atomic_set(&cache->count, 1);
+       spin_lock_init(&cache->lock);
+       INIT_LIST_HEAD(&cache->list);
+       INIT_LIST_HEAD(&cache->cluster_list);
+       INIT_LIST_HEAD(&cache->new_bg_list);
+       btrfs_init_free_space_ctl(cache);
+
+       return cache;
+}
+
 int btrfs_read_block_groups(struct btrfs_root *root)
 {
        struct btrfs_path *path;
@@ -8395,26 +8430,16 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                        break;
                if (ret != 0)
                        goto error;
+
                leaf = path->nodes[0];
                btrfs_item_key_to_cpu(leaf, &found_key, path->slots[0]);
-               cache = kzalloc(sizeof(*cache), GFP_NOFS);
+
+               cache = btrfs_create_block_group_cache(root, found_key.objectid,
+                                                      found_key.offset);
                if (!cache) {
                        ret = -ENOMEM;
                        goto error;
                }
-               cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
-                                               GFP_NOFS);
-               if (!cache->free_space_ctl) {
-                       kfree(cache);
-                       ret = -ENOMEM;
-                       goto error;
-               }
-
-               atomic_set(&cache->count, 1);
-               spin_lock_init(&cache->lock);
-               cache->fs_info = info;
-               INIT_LIST_HEAD(&cache->list);
-               INIT_LIST_HEAD(&cache->cluster_list);
 
                if (need_clear) {
                        /*
@@ -8435,16 +8460,10 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                read_extent_buffer(leaf, &cache->item,
                                   btrfs_item_ptr_offset(leaf, path->slots[0]),
                                   sizeof(cache->item));
-               memcpy(&cache->key, &found_key, sizeof(found_key));
+               cache->flags = btrfs_block_group_flags(&cache->item);
 
                key.objectid = found_key.objectid + found_key.offset;
                btrfs_release_path(path);
-               cache->flags = btrfs_block_group_flags(&cache->item);
-               cache->sectorsize = root->sectorsize;
-               cache->full_stripe_len = btrfs_full_stripe_len(root,
-                                              &root->fs_info->mapping_tree,
-                                              found_key.objectid);
-               btrfs_init_free_space_ctl(cache);
 
                /*
                 * We need to exclude the super stripes now so that the space
@@ -8458,8 +8477,7 @@ int btrfs_read_block_groups(struct btrfs_root *root)
                         * case.
                         */
                        free_excluded_extents(root, cache);
-                       kfree(cache->free_space_ctl);
-                       kfree(cache);
+                       btrfs_put_block_group(cache);
                        goto error;
                }
 
@@ -8590,38 +8608,15 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
 
        root->fs_info->last_trans_log_full_commit = trans->transid;
 
-       cache = kzalloc(sizeof(*cache), GFP_NOFS);
+       cache = btrfs_create_block_group_cache(root, chunk_offset, size);
        if (!cache)
                return -ENOMEM;
-       cache->free_space_ctl = kzalloc(sizeof(*cache->free_space_ctl),
-                                       GFP_NOFS);
-       if (!cache->free_space_ctl) {
-               kfree(cache);
-               return -ENOMEM;
-       }
-
-       cache->key.objectid = chunk_offset;
-       cache->key.offset = size;
-       cache->key.type = BTRFS_BLOCK_GROUP_ITEM_KEY;
-       cache->sectorsize = root->sectorsize;
-       cache->fs_info = root->fs_info;
-       cache->full_stripe_len = btrfs_full_stripe_len(root,
-                                              &root->fs_info->mapping_tree,
-                                              chunk_offset);
-
-       atomic_set(&cache->count, 1);
-       spin_lock_init(&cache->lock);
-       INIT_LIST_HEAD(&cache->list);
-       INIT_LIST_HEAD(&cache->cluster_list);
-       INIT_LIST_HEAD(&cache->new_bg_list);
-
-       btrfs_init_free_space_ctl(cache);
 
        btrfs_set_block_group_used(&cache->item, bytes_used);
        btrfs_set_block_group_chunk_objectid(&cache->item, chunk_objectid);
-       cache->flags = type;
        btrfs_set_block_group_flags(&cache->item, type);
 
+       cache->flags = type;
        cache->last_byte_to_unpin = (u64)-1;
        cache->cached = BTRFS_CACHE_FINISHED;
        ret = exclude_super_stripes(root, cache);
@@ -8631,8 +8626,7 @@ int btrfs_make_block_group(struct btrfs_trans_handle *trans,
                 * case.
                 */
                free_excluded_extents(root, cache);
-               kfree(cache->free_space_ctl);
-               kfree(cache);
+               btrfs_put_block_group(cache);
                return ret;
        }
 
@@ -8796,8 +8790,11 @@ int btrfs_remove_block_group(struct btrfs_trans_handle *trans,
         * are still on the list after taking the semaphore
         */
        list_del_init(&block_group->list);
-       if (list_empty(&block_group->space_info->block_groups[index]))
+       if (list_empty(&block_group->space_info->block_groups[index])) {
+               kobject_del(&block_group->space_info->block_group_kobjs[index]);
+               kobject_put(&block_group->space_info->block_group_kobjs[index]);
                clear_avail_alloc_bits(root->fs_info, block_group->flags);
+       }
        up_write(&block_group->space_info->groups_sem);
 
        if (block_group->cached == BTRFS_CACHE_STARTED)
index ff43802a7c886088e37c5c1c16427f2b522cad30..85bbd01f1271379de6b3bcf41f4a42bd9d30320a 100644 (file)
@@ -59,7 +59,7 @@ 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 "
+               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,
                       atomic_read(&state->refs));
@@ -69,7 +69,7 @@ void btrfs_leak_debug_check(void)
 
        while (!list_empty(&buffers)) {
                eb = list_entry(buffers.next, struct extent_buffer, leak_list);
-               printk(KERN_ERR "btrfs buffer leak start %llu len %lu "
+               printk(KERN_ERR "BTRFS: buffer leak start %llu len %lu "
                       "refs %d\n",
                       eb->start, eb->len, atomic_read(&eb->refs));
                list_del(&eb->leak_list);
@@ -77,16 +77,22 @@ void btrfs_leak_debug_check(void)
        }
 }
 
-#define btrfs_debug_check_extent_io_range(inode, start, end)           \
-       __btrfs_debug_check_extent_io_range(__func__, (inode), (start), (end))
+#define btrfs_debug_check_extent_io_range(tree, start, end)            \
+       __btrfs_debug_check_extent_io_range(__func__, (tree), (start), (end))
 static inline void __btrfs_debug_check_extent_io_range(const char *caller,
-               struct inode *inode, u64 start, u64 end)
+               struct extent_io_tree *tree, u64 start, u64 end)
 {
-       u64 isize = i_size_read(inode);
+       struct inode *inode;
+       u64 isize;
+
+       if (!tree->mapping)
+               return;
 
+       inode = tree->mapping->host;
+       isize = i_size_read(inode);
        if (end >= PAGE_SIZE && (end % 2) == 0 && end != isize - 1) {
                printk_ratelimited(KERN_DEBUG
-                   "btrfs: %s: ino %llu isize %llu odd range [%llu,%llu]\n",
+                   "BTRFS: %s: ino %llu isize %llu odd range [%llu,%llu]\n",
                                caller, btrfs_ino(inode), isize, start, end);
        }
 }
@@ -124,6 +130,8 @@ static noinline void flush_write_bio(void *data);
 static inline struct btrfs_fs_info *
 tree_fs_info(struct extent_io_tree *tree)
 {
+       if (!tree->mapping)
+               return NULL;
        return btrfs_sb(tree->mapping->host->i_sb);
 }
 
@@ -186,11 +194,9 @@ void extent_io_tree_init(struct extent_io_tree *tree,
                         struct address_space *mapping)
 {
        tree->state = RB_ROOT;
-       INIT_RADIX_TREE(&tree->buffer, GFP_ATOMIC);
        tree->ops = NULL;
        tree->dirty_bytes = 0;
        spin_lock_init(&tree->lock);
-       spin_lock_init(&tree->buffer_lock);
        tree->mapping = mapping;
 }
 
@@ -224,12 +230,20 @@ void free_extent_state(struct extent_state *state)
 }
 
 static struct rb_node *tree_insert(struct rb_root *root, u64 offset,
-                                  struct rb_node *node)
+                                  struct rb_node *node,
+                                  struct rb_node ***p_in,
+                                  struct rb_node **parent_in)
 {
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
        struct tree_entry *entry;
 
+       if (p_in && parent_in) {
+               p = *p_in;
+               parent = *parent_in;
+               goto do_insert;
+       }
+
        while (*p) {
                parent = *p;
                entry = rb_entry(parent, struct tree_entry, rb_node);
@@ -242,35 +256,43 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 offset,
                        return parent;
        }
 
+do_insert:
        rb_link_node(node, parent, p);
        rb_insert_color(node, root);
        return NULL;
 }
 
 static struct rb_node *__etree_search(struct extent_io_tree *tree, u64 offset,
-                                    struct rb_node **prev_ret,
-                                    struct rb_node **next_ret)
+                                     struct rb_node **prev_ret,
+                                     struct rb_node **next_ret,
+                                     struct rb_node ***p_ret,
+                                     struct rb_node **parent_ret)
 {
        struct rb_root *root = &tree->state;
-       struct rb_node *n = root->rb_node;
+       struct rb_node **n = &root->rb_node;
        struct rb_node *prev = NULL;
        struct rb_node *orig_prev = NULL;
        struct tree_entry *entry;
        struct tree_entry *prev_entry = NULL;
 
-       while (n) {
-               entry = rb_entry(n, struct tree_entry, rb_node);
-               prev = n;
+       while (*n) {
+               prev = *n;
+               entry = rb_entry(prev, struct tree_entry, rb_node);
                prev_entry = entry;
 
                if (offset < entry->start)
-                       n = n->rb_left;
+                       n = &(*n)->rb_left;
                else if (offset > entry->end)
-                       n = n->rb_right;
+                       n = &(*n)->rb_right;
                else
-                       return n;
+                       return *n;
        }
 
+       if (p_ret)
+               *p_ret = n;
+       if (parent_ret)
+               *parent_ret = prev;
+
        if (prev_ret) {
                orig_prev = prev;
                while (prev && offset > prev_entry->end) {
@@ -292,18 +314,27 @@ static struct rb_node *__etree_search(struct extent_io_tree *tree, u64 offset,
        return NULL;
 }
 
-static inline struct rb_node *tree_search(struct extent_io_tree *tree,
-                                         u64 offset)
+static inline struct rb_node *
+tree_search_for_insert(struct extent_io_tree *tree,
+                      u64 offset,
+                      struct rb_node ***p_ret,
+                      struct rb_node **parent_ret)
 {
        struct rb_node *prev = NULL;
        struct rb_node *ret;
 
-       ret = __etree_search(tree, offset, &prev, NULL);
+       ret = __etree_search(tree, offset, &prev, NULL, p_ret, parent_ret);
        if (!ret)
                return prev;
        return ret;
 }
 
+static inline struct rb_node *tree_search(struct extent_io_tree *tree,
+                                         u64 offset)
+{
+       return tree_search_for_insert(tree, offset, NULL, NULL);
+}
+
 static void merge_cb(struct extent_io_tree *tree, struct extent_state *new,
                     struct extent_state *other)
 {
@@ -385,23 +416,25 @@ static void set_state_bits(struct extent_io_tree *tree,
  */
 static int insert_state(struct extent_io_tree *tree,
                        struct extent_state *state, u64 start, u64 end,
+                       struct rb_node ***p,
+                       struct rb_node **parent,
                        unsigned long *bits)
 {
        struct rb_node *node;
 
        if (end < start)
-               WARN(1, KERN_ERR "btrfs end < start %llu %llu\n",
+               WARN(1, KERN_ERR "BTRFS: end < start %llu %llu\n",
                       end, start);
        state->start = start;
        state->end = end;
 
        set_state_bits(tree, state, bits);
 
-       node = tree_insert(&tree->state, end, &state->rb_node);
+       node = tree_insert(&tree->state, end, &state->rb_node, p, parent);
        if (node) {
                struct extent_state *found;
                found = rb_entry(node, struct extent_state, rb_node);
-               printk(KERN_ERR "btrfs found node %llu %llu on insert of "
+               printk(KERN_ERR "BTRFS: found node %llu %llu on insert of "
                       "%llu %llu\n",
                       found->start, found->end, start, end);
                return -EEXIST;
@@ -444,7 +477,8 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig,
        prealloc->state = orig->state;
        orig->start = split;
 
-       node = tree_insert(&tree->state, prealloc->end, &prealloc->rb_node);
+       node = tree_insert(&tree->state, prealloc->end, &prealloc->rb_node,
+                          NULL, NULL);
        if (node) {
                free_extent_state(prealloc);
                return -EEXIST;
@@ -542,7 +576,7 @@ int clear_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
        int err;
        int clear = 0;
 
-       btrfs_debug_check_extent_io_range(tree->mapping->host, start, end);
+       btrfs_debug_check_extent_io_range(tree, start, end);
 
        if (bits & EXTENT_DELALLOC)
                bits |= EXTENT_NORESERVE;
@@ -702,7 +736,7 @@ static void wait_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
        struct extent_state *state;
        struct rb_node *node;
 
-       btrfs_debug_check_extent_io_range(tree->mapping->host, start, end);
+       btrfs_debug_check_extent_io_range(tree, start, end);
 
        spin_lock(&tree->lock);
 again:
@@ -783,11 +817,13 @@ __set_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
        struct extent_state *state;
        struct extent_state *prealloc = NULL;
        struct rb_node *node;
+       struct rb_node **p;
+       struct rb_node *parent;
        int err = 0;
        u64 last_start;
        u64 last_end;
 
-       btrfs_debug_check_extent_io_range(tree->mapping->host, start, end);
+       btrfs_debug_check_extent_io_range(tree, start, end);
 
        bits |= EXTENT_FIRST_DELALLOC;
 again:
@@ -809,14 +845,16 @@ again:
         * this search will find all the extents that end after
         * our range starts.
         */
-       node = tree_search(tree, start);
+       node = tree_search_for_insert(tree, start, &p, &parent);
        if (!node) {
                prealloc = alloc_extent_state_atomic(prealloc);
                BUG_ON(!prealloc);
-               err = insert_state(tree, prealloc, start, end, &bits);
+               err = insert_state(tree, prealloc, start, end,
+                                  &p, &parent, &bits);
                if (err)
                        extent_io_tree_panic(tree, err);
 
+               cache_state(prealloc, cached_state);
                prealloc = NULL;
                goto out;
        }
@@ -919,7 +957,7 @@ hit_next:
                 * the later extent.
                 */
                err = insert_state(tree, prealloc, start, this_end,
-                                  &bits);
+                                  NULL, NULL, &bits);
                if (err)
                        extent_io_tree_panic(tree, err);
 
@@ -1005,11 +1043,13 @@ int convert_extent_bit(struct extent_io_tree *tree, u64 start, u64 end,
        struct extent_state *state;
        struct extent_state *prealloc = NULL;
        struct rb_node *node;
+       struct rb_node **p;
+       struct rb_node *parent;
        int err = 0;
        u64 last_start;
        u64 last_end;
 
-       btrfs_debug_check_extent_io_range(tree->mapping->host, start, end);
+       btrfs_debug_check_extent_io_range(tree, start, end);
 
 again:
        if (!prealloc && (mask & __GFP_WAIT)) {
@@ -1032,17 +1072,19 @@ again:
         * this search will find all the extents that end after
         * our range starts.
         */
-       node = tree_search(tree, start);
+       node = tree_search_for_insert(tree, start, &p, &parent);
        if (!node) {
                prealloc = alloc_extent_state_atomic(prealloc);
                if (!prealloc) {
                        err = -ENOMEM;
                        goto out;
                }
-               err = insert_state(tree, prealloc, start, end, &bits);
-               prealloc = NULL;
+               err = insert_state(tree, prealloc, start, end,
+                                  &p, &parent, &bits);
                if (err)
                        extent_io_tree_panic(tree, err);
+               cache_state(prealloc, cached_state);
+               prealloc = NULL;
                goto out;
        }
        state = rb_entry(node, struct extent_state, rb_node);
@@ -1135,7 +1177,7 @@ hit_next:
                 * the later extent.
                 */
                err = insert_state(tree, prealloc, start, this_end,
-                                  &bits);
+                                  NULL, NULL, &bits);
                if (err)
                        extent_io_tree_panic(tree, err);
                cache_state(prealloc, cached_state);
@@ -1984,7 +2026,7 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
        bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
        if (!bio)
                return -EIO;
-       bio->bi_size = 0;
+       bio->bi_iter.bi_size = 0;
        map_length = length;
 
        ret = btrfs_map_block(fs_info, WRITE, logical,
@@ -1995,7 +2037,7 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
        }
        BUG_ON(mirror_num != bbio->mirror_num);
        sector = bbio->stripes[mirror_num-1].physical >> 9;
-       bio->bi_sector = sector;
+       bio->bi_iter.bi_sector = sector;
        dev = bbio->stripes[mirror_num-1].dev;
        kfree(bbio);
        if (!dev || !dev->bdev || !dev->writeable) {
@@ -2012,9 +2054,10 @@ int repair_io_failure(struct btrfs_fs_info *fs_info, u64 start,
                return -EIO;
        }
 
-       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);
+       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);
 
        bio_put(bio);
        return 0;
@@ -2156,7 +2199,7 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                        return -EIO;
                }
 
-               if (em->start > start || em->start + em->len < start) {
+               if (em->start > start || em->start + em->len <= start) {
                        free_extent_map(em);
                        em = NULL;
                }
@@ -2268,9 +2311,9 @@ static int bio_readpage_error(struct bio *failed_bio, u64 phy_offset,
                return -EIO;
        }
        bio->bi_end_io = failed_bio->bi_end_io;
-       bio->bi_sector = failrec->logical >> 9;
+       bio->bi_iter.bi_sector = failrec->logical >> 9;
        bio->bi_bdev = BTRFS_I(inode)->root->fs_info->fs_devices->latest_bdev;
-       bio->bi_size = 0;
+       bio->bi_iter.bi_size = 0;
 
        btrfs_failed_bio = btrfs_io_bio(failed_bio);
        if (btrfs_failed_bio->csum) {
@@ -2332,37 +2375,39 @@ int end_extent_writepage(struct page *page, int err, u64 start, u64 end)
  */
 static void end_bio_extent_writepage(struct bio *bio, int err)
 {
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
-       struct extent_io_tree *tree;
+       struct bio_vec *bvec;
        u64 start;
        u64 end;
+       int i;
 
-       do {
+       bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
-               tree = &BTRFS_I(page->mapping->host)->io_tree;
 
                /* We always issue full-page reads, but if some block
                 * in a page fails to read, blk_update_request() will
                 * advance bv_offset and adjust bv_len to compensate.
                 * Print a warning for nonzero offsets, and an error
                 * if they don't add up to a full page.  */
-               if (bvec->bv_offset || bvec->bv_len != PAGE_CACHE_SIZE)
-                       printk("%s page write in btrfs with offset %u and length %u\n",
-                              bvec->bv_offset + bvec->bv_len != PAGE_CACHE_SIZE
-                              ? KERN_ERR "partial" : KERN_INFO "incomplete",
-                              bvec->bv_offset, bvec->bv_len);
+               if (bvec->bv_offset || bvec->bv_len != PAGE_CACHE_SIZE) {
+                       if (bvec->bv_offset + bvec->bv_len != PAGE_CACHE_SIZE)
+                               btrfs_err(BTRFS_I(page->mapping->host)->root->fs_info,
+                                  "partial page write in btrfs with offset %u and length %u",
+                                       bvec->bv_offset, bvec->bv_len);
+                       else
+                               btrfs_info(BTRFS_I(page->mapping->host)->root->fs_info,
+                                  "incomplete page write in btrfs with offset %u and "
+                                  "length %u",
+                                       bvec->bv_offset, bvec->bv_len);
+               }
 
                start = page_offset(page);
                end = start + bvec->bv_offset + bvec->bv_len - 1;
 
-               if (--bvec >= bio->bi_io_vec)
-                       prefetchw(&bvec->bv_page->flags);
-
                if (end_extent_writepage(page, err, start, end))
                        continue;
 
                end_page_writeback(page);
-       } while (bvec >= bio->bi_io_vec);
+       }
 
        bio_put(bio);
 }
@@ -2392,9 +2437,8 @@ endio_readpage_release_extent(struct extent_io_tree *tree, u64 start, u64 len,
  */
 static void end_bio_extent_readpage(struct bio *bio, int err)
 {
+       struct bio_vec *bvec;
        int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1;
-       struct bio_vec *bvec = bio->bi_io_vec;
        struct btrfs_io_bio *io_bio = btrfs_io_bio(bio);
        struct extent_io_tree *tree;
        u64 offset = 0;
@@ -2405,16 +2449,17 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
        u64 extent_len = 0;
        int mirror;
        int ret;
+       int i;
 
        if (err)
                uptodate = 0;
 
-       do {
+       bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
                struct inode *inode = page->mapping->host;
 
                pr_debug("end_bio_extent_readpage: bi_sector=%llu, err=%d, "
-                        "mirror=%lu\n", (u64)bio->bi_sector, err,
+                        "mirror=%lu\n", (u64)bio->bi_iter.bi_sector, err,
                         io_bio->mirror_num);
                tree = &BTRFS_I(inode)->io_tree;
 
@@ -2423,19 +2468,22 @@ static void end_bio_extent_readpage(struct bio *bio, int err)
                 * advance bv_offset and adjust bv_len to compensate.
                 * Print a warning for nonzero offsets, and an error
                 * if they don't add up to a full page.  */
-               if (bvec->bv_offset || bvec->bv_len != PAGE_CACHE_SIZE)
-                       printk("%s page read in btrfs with offset %u and length %u\n",
-                              bvec->bv_offset + bvec->bv_len != PAGE_CACHE_SIZE
-                              ? KERN_ERR "partial" : KERN_INFO "incomplete",
-                              bvec->bv_offset, bvec->bv_len);
+               if (bvec->bv_offset || bvec->bv_len != PAGE_CACHE_SIZE) {
+                       if (bvec->bv_offset + bvec->bv_len != PAGE_CACHE_SIZE)
+                               btrfs_err(BTRFS_I(page->mapping->host)->root->fs_info,
+                                  "partial page read in btrfs with offset %u and length %u",
+                                       bvec->bv_offset, bvec->bv_len);
+                       else
+                               btrfs_info(BTRFS_I(page->mapping->host)->root->fs_info,
+                                  "incomplete page read in btrfs with offset %u and "
+                                  "length %u",
+                                       bvec->bv_offset, bvec->bv_len);
+               }
 
                start = page_offset(page);
                end = start + bvec->bv_offset + bvec->bv_len - 1;
                len = bvec->bv_len;
 
-               if (++bvec <= bvec_end)
-                       prefetchw(&bvec->bv_page->flags);
-
                mirror = io_bio->mirror_num;
                if (likely(uptodate && tree->ops &&
                           tree->ops->readpage_end_io_hook)) {
@@ -2516,7 +2564,7 @@ readpage_ok:
                        extent_start = start;
                        extent_len = end + 1 - start;
                }
-       } while (bvec <= bvec_end);
+       }
 
        if (extent_len)
                endio_readpage_release_extent(tree, extent_start, extent_len,
@@ -2547,9 +2595,8 @@ btrfs_bio_alloc(struct block_device *bdev, u64 first_sector, int nr_vecs,
        }
 
        if (bio) {
-               bio->bi_size = 0;
                bio->bi_bdev = bdev;
-               bio->bi_sector = first_sector;
+               bio->bi_iter.bi_sector = first_sector;
                btrfs_bio = btrfs_io_bio(bio);
                btrfs_bio->csum = NULL;
                btrfs_bio->csum_allocated = NULL;
@@ -2643,7 +2690,7 @@ static int submit_extent_page(int rw, struct extent_io_tree *tree,
        if (bio_ret && *bio_ret) {
                bio = *bio_ret;
                if (old_compressed)
-                       contig = bio->bi_sector == sector;
+                       contig = bio->bi_iter.bi_sector == sector;
                else
                        contig = bio_end_sector(bio) == sector;
 
@@ -3287,8 +3334,8 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
 
                        set_range_writeback(tree, cur, cur + iosize - 1);
                        if (!PageWriteback(page)) {
-                               printk(KERN_ERR "btrfs warning page %lu not "
-                                      "writeback, cur %llu end %llu\n",
+                               btrfs_err(BTRFS_I(inode)->root->fs_info,
+                                          "page %lu not writeback, cur %llu end %llu",
                                       page->index, cur, end);
                        }
 
@@ -3410,20 +3457,18 @@ static void end_extent_buffer_writeback(struct extent_buffer *eb)
 
 static void end_bio_extent_buffer_writepage(struct bio *bio, int err)
 {
-       int uptodate = err == 0;
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bvec;
        struct extent_buffer *eb;
-       int done;
+       int i, done;
 
-       do {
+       bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
 
-               bvec--;
                eb = (struct extent_buffer *)page->private;
                BUG_ON(!eb);
                done = atomic_dec_and_test(&eb->io_pages);
 
-               if (!uptodate || test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) {
+               if (err || test_bit(EXTENT_BUFFER_IOERR, &eb->bflags)) {
                        set_bit(EXTENT_BUFFER_IOERR, &eb->bflags);
                        ClearPageUptodate(page);
                        SetPageError(page);
@@ -3435,10 +3480,9 @@ static void end_bio_extent_buffer_writepage(struct bio *bio, int err)
                        continue;
 
                end_extent_buffer_writeback(eb);
-       } while (bvec >= bio->bi_io_vec);
+       }
 
        bio_put(bio);
-
 }
 
 static int write_one_eb(struct extent_buffer *eb,
@@ -3447,6 +3491,7 @@ static int write_one_eb(struct extent_buffer *eb,
                        struct extent_page_data *epd)
 {
        struct block_device *bdev = fs_info->fs_devices->latest_bdev;
+       struct extent_io_tree *tree = &BTRFS_I(fs_info->btree_inode)->io_tree;
        u64 offset = eb->start;
        unsigned long i, num_pages;
        unsigned long bio_flags = 0;
@@ -3464,7 +3509,7 @@ static int write_one_eb(struct extent_buffer *eb,
 
                clear_page_dirty_for_io(p);
                set_page_writeback(p);
-               ret = submit_extent_page(rw, eb->tree, p, offset >> 9,
+               ret = submit_extent_page(rw, tree, p, offset >> 9,
                                         PAGE_CACHE_SIZE, 0, bdev, &epd->bio,
                                         -1, end_bio_extent_buffer_writepage,
                                         0, epd->bio_flags, bio_flags);
@@ -4082,12 +4127,10 @@ 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_file_extent_item *item;
        int end = 0;
        u64 em_start = 0;
        u64 em_len = 0;
        u64 em_end = 0;
-       unsigned long emflags;
 
        if (len == 0)
                return -EINVAL;
@@ -4112,8 +4155,6 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
        }
        WARN_ON(!ret);
        path->slots[0]--;
-       item = btrfs_item_ptr(path->nodes[0], path->slots[0],
-                             struct btrfs_file_extent_item);
        btrfs_item_key_to_cpu(path->nodes[0], &found_key, path->slots[0]);
        found_type = btrfs_key_type(&found_key);
 
@@ -4181,7 +4222,6 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
                        offset_in_extent = em_start - em->start;
                em_end = extent_map_end(em);
                em_len = em_end - em_start;
-               emflags = em->flags;
                disko = 0;
                flags = 0;
 
@@ -4333,10 +4373,9 @@ static inline void btrfs_release_extent_buffer(struct extent_buffer *eb)
        __free_extent_buffer(eb);
 }
 
-static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
-                                                  u64 start,
-                                                  unsigned long len,
-                                                  gfp_t mask)
+static struct extent_buffer *
+__alloc_extent_buffer(struct btrfs_fs_info *fs_info, u64 start,
+                     unsigned long len, gfp_t mask)
 {
        struct extent_buffer *eb = NULL;
 
@@ -4345,7 +4384,7 @@ static struct extent_buffer *__alloc_extent_buffer(struct extent_io_tree *tree,
                return NULL;
        eb->start = start;
        eb->len = len;
-       eb->tree = tree;
+       eb->fs_info = fs_info;
        eb->bflags = 0;
        rwlock_init(&eb->lock);
        atomic_set(&eb->write_locks, 0);
@@ -4477,13 +4516,14 @@ static void mark_extent_buffer_accessed(struct extent_buffer *eb)
        }
 }
 
-struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
-                                                       u64 start)
+struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
+                                        u64 start)
 {
        struct extent_buffer *eb;
 
        rcu_read_lock();
-       eb = radix_tree_lookup(&tree->buffer, start >> PAGE_CACHE_SHIFT);
+       eb = radix_tree_lookup(&fs_info->buffer_radix,
+                              start >> PAGE_CACHE_SHIFT);
        if (eb && atomic_inc_not_zero(&eb->refs)) {
                rcu_read_unlock();
                mark_extent_buffer_accessed(eb);
@@ -4494,7 +4534,7 @@ struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
        return NULL;
 }
 
-struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
+struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
                                          u64 start, unsigned long len)
 {
        unsigned long num_pages = num_extent_pages(start, len);
@@ -4503,16 +4543,15 @@ struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
        struct extent_buffer *eb;
        struct extent_buffer *exists = NULL;
        struct page *p;
-       struct address_space *mapping = tree->mapping;
+       struct address_space *mapping = fs_info->btree_inode->i_mapping;
        int uptodate = 1;
        int ret;
 
-
-       eb = find_extent_buffer(tree, start);
+       eb = find_extent_buffer(fs_info, start);
        if (eb)
                return eb;
 
-       eb = __alloc_extent_buffer(tree, start, len, GFP_NOFS);
+       eb = __alloc_extent_buffer(fs_info, start, len, GFP_NOFS);
        if (!eb)
                return NULL;
 
@@ -4567,12 +4606,13 @@ again:
        if (ret)
                goto free_eb;
 
-       spin_lock(&tree->buffer_lock);
-       ret = radix_tree_insert(&tree->buffer, start >> PAGE_CACHE_SHIFT, eb);
-       spin_unlock(&tree->buffer_lock);
+       spin_lock(&fs_info->buffer_lock);
+       ret = radix_tree_insert(&fs_info->buffer_radix,
+                               start >> PAGE_CACHE_SHIFT, eb);
+       spin_unlock(&fs_info->buffer_lock);
        radix_tree_preload_end();
        if (ret == -EEXIST) {
-               exists = find_extent_buffer(tree, start);
+               exists = find_extent_buffer(fs_info, start);
                if (exists)
                        goto free_eb;
                else
@@ -4580,6 +4620,7 @@ again:
        }
        /* add one reference for the tree */
        check_buffer_tree_ref(eb);
+       set_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags);
 
        /*
         * there is a race where release page may have
@@ -4623,17 +4664,17 @@ static int release_extent_buffer(struct extent_buffer *eb)
 {
        WARN_ON(atomic_read(&eb->refs) == 0);
        if (atomic_dec_and_test(&eb->refs)) {
-               if (test_bit(EXTENT_BUFFER_DUMMY, &eb->bflags)) {
-                       spin_unlock(&eb->refs_lock);
-               } else {
-                       struct extent_io_tree *tree = eb->tree;
+               if (test_and_clear_bit(EXTENT_BUFFER_IN_TREE, &eb->bflags)) {
+                       struct btrfs_fs_info *fs_info = eb->fs_info;
 
                        spin_unlock(&eb->refs_lock);
 
-                       spin_lock(&tree->buffer_lock);
-                       radix_tree_delete(&tree->buffer,
+                       spin_lock(&fs_info->buffer_lock);
+                       radix_tree_delete(&fs_info->buffer_radix,
                                          eb->start >> PAGE_CACHE_SHIFT);
-                       spin_unlock(&tree->buffer_lock);
+                       spin_unlock(&fs_info->buffer_lock);
+               } else {
+                       spin_unlock(&eb->refs_lock);
                }
 
                /* Should be safe to release our pages at this point */
@@ -5112,12 +5153,12 @@ void memcpy_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
        unsigned long src_i;
 
        if (src_offset + len > dst->len) {
-               printk(KERN_ERR "btrfs memmove bogus src_offset %lu move "
+               printk(KERN_ERR "BTRFS: memmove bogus src_offset %lu move "
                       "len %lu dst len %lu\n", src_offset, len, dst->len);
                BUG_ON(1);
        }
        if (dst_offset + len > dst->len) {
-               printk(KERN_ERR "btrfs memmove bogus dst_offset %lu move "
+               printk(KERN_ERR "BTRFS: memmove bogus dst_offset %lu move "
                       "len %lu dst len %lu\n", dst_offset, len, dst->len);
                BUG_ON(1);
        }
@@ -5159,12 +5200,12 @@ void memmove_extent_buffer(struct extent_buffer *dst, unsigned long dst_offset,
        unsigned long src_i;
 
        if (src_offset + len > dst->len) {
-               printk(KERN_ERR "btrfs memmove bogus src_offset %lu move "
+               printk(KERN_ERR "BTRFS: memmove bogus src_offset %lu move "
                       "len %lu len %lu\n", src_offset, len, dst->len);
                BUG_ON(1);
        }
        if (dst_offset + len > dst->len) {
-               printk(KERN_ERR "btrfs memmove bogus dst_offset %lu move "
+               printk(KERN_ERR "BTRFS: memmove bogus dst_offset %lu move "
                       "len %lu len %lu\n", dst_offset, len, dst->len);
                BUG_ON(1);
        }
index 19620c58f096ef2dd8f0a5810ff632c575e0f5ee..58b27e5ab52158a2d03a1bf7d7d612878489a9ac 100644 (file)
@@ -43,6 +43,7 @@
 #define EXTENT_BUFFER_WRITEBACK 7
 #define EXTENT_BUFFER_IOERR 8
 #define EXTENT_BUFFER_DUMMY 9
+#define EXTENT_BUFFER_IN_TREE 10
 
 /* these are flags for extent_clear_unlock_delalloc */
 #define PAGE_UNLOCK            (1 << 0)
@@ -94,12 +95,10 @@ struct extent_io_ops {
 
 struct extent_io_tree {
        struct rb_root state;
-       struct radix_tree_root buffer;
        struct address_space *mapping;
        u64 dirty_bytes;
        int track_uptodate;
        spinlock_t lock;
-       spinlock_t buffer_lock;
        struct extent_io_ops *ops;
 };
 
@@ -130,7 +129,7 @@ struct extent_buffer {
        unsigned long map_start;
        unsigned long map_len;
        unsigned long bflags;
-       struct extent_io_tree *tree;
+       struct btrfs_fs_info *fs_info;
        spinlock_t refs_lock;
        atomic_t refs;
        atomic_t io_pages;
@@ -266,11 +265,11 @@ int extent_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
 int get_state_private(struct extent_io_tree *tree, u64 start, u64 *private);
 void set_page_extent_mapped(struct page *page);
 
-struct extent_buffer *alloc_extent_buffer(struct extent_io_tree *tree,
+struct extent_buffer *alloc_extent_buffer(struct btrfs_fs_info *fs_info,
                                          u64 start, unsigned long len);
 struct extent_buffer *alloc_dummy_extent_buffer(u64 start, unsigned long len);
 struct extent_buffer *btrfs_clone_extent_buffer(struct extent_buffer *src);
-struct extent_buffer *find_extent_buffer(struct extent_io_tree *tree,
+struct extent_buffer *find_extent_buffer(struct btrfs_fs_info *fs_info,
                                         u64 start);
 void free_extent_buffer(struct extent_buffer *eb);
 void free_extent_buffer_stale(struct extent_buffer *eb);
index a4a7a1a8da95c4c1e7571d99e0d58a7b5209f4ee..996ad56b57db64bbc0516f4674d8ad3fd2d43976 100644 (file)
@@ -79,12 +79,21 @@ void free_extent_map(struct extent_map *em)
        }
 }
 
-static struct rb_node *tree_insert(struct rb_root *root, u64 offset,
-                                  struct rb_node *node)
+/* simple helper to do math around the end of an extent, handling wrap */
+static u64 range_end(u64 start, u64 len)
+{
+       if (start + len < start)
+               return (u64)-1;
+       return start + len;
+}
+
+static int tree_insert(struct rb_root *root, struct extent_map *em)
 {
        struct rb_node **p = &root->rb_node;
        struct rb_node *parent = NULL;
-       struct extent_map *entry;
+       struct extent_map *entry = NULL;
+       struct rb_node *orig_parent = NULL;
+       u64 end = range_end(em->start, em->len);
 
        while (*p) {
                parent = *p;
@@ -92,19 +101,37 @@ static struct rb_node *tree_insert(struct rb_root *root, u64 offset,
 
                WARN_ON(!entry->in_tree);
 
-               if (offset < entry->start)
+               if (em->start < entry->start)
                        p = &(*p)->rb_left;
-               else if (offset >= extent_map_end(entry))
+               else if (em->start >= extent_map_end(entry))
                        p = &(*p)->rb_right;
                else
-                       return parent;
+                       return -EEXIST;
        }
 
-       entry = rb_entry(node, struct extent_map, rb_node);
-       entry->in_tree = 1;
-       rb_link_node(node, parent, p);
-       rb_insert_color(node, root);
-       return NULL;
+       orig_parent = parent;
+       while (parent && em->start >= extent_map_end(entry)) {
+               parent = rb_next(parent);
+               entry = rb_entry(parent, struct extent_map, rb_node);
+       }
+       if (parent)
+               if (end > entry->start && em->start < extent_map_end(entry))
+                       return -EEXIST;
+
+       parent = orig_parent;
+       entry = rb_entry(parent, struct extent_map, rb_node);
+       while (parent && em->start < entry->start) {
+               parent = rb_prev(parent);
+               entry = rb_entry(parent, struct extent_map, rb_node);
+       }
+       if (parent)
+               if (end > entry->start && em->start < extent_map_end(entry))
+                       return -EEXIST;
+
+       em->in_tree = 1;
+       rb_link_node(&em->rb_node, orig_parent, p);
+       rb_insert_color(&em->rb_node, root);
+       return 0;
 }
 
 /*
@@ -228,7 +255,7 @@ static void try_merge_map(struct extent_map_tree *tree, struct extent_map *em)
                merge = rb_entry(rb, struct extent_map, rb_node);
        if (rb && mergable_maps(em, merge)) {
                em->len += merge->len;
-               em->block_len += merge->len;
+               em->block_len += merge->block_len;
                rb_erase(&merge->rb_node, &tree->map);
                merge->in_tree = 0;
                em->mod_len = (merge->mod_start + merge->mod_len) - em->mod_start;
@@ -310,20 +337,11 @@ int add_extent_mapping(struct extent_map_tree *tree,
                       struct extent_map *em, int modified)
 {
        int ret = 0;
-       struct rb_node *rb;
-       struct extent_map *exist;
 
-       exist = lookup_extent_mapping(tree, em->start, em->len);
-       if (exist) {
-               free_extent_map(exist);
-               ret = -EEXIST;
-               goto out;
-       }
-       rb = tree_insert(&tree->map, em->start, &em->rb_node);
-       if (rb) {
-               ret = -EEXIST;
+       ret = tree_insert(&tree->map, em);
+       if (ret)
                goto out;
-       }
+
        atomic_inc(&em->refs);
 
        em->mod_start = em->start;
@@ -337,14 +355,6 @@ out:
        return ret;
 }
 
-/* simple helper to do math around the end of an extent, handling wrap */
-static u64 range_end(u64 start, u64 len)
-{
-       if (start + len < start)
-               return (u64)-1;
-       return start + len;
-}
-
 static struct extent_map *
 __lookup_extent_mapping(struct extent_map_tree *tree,
                        u64 start, u64 len, int strict)
index 6f384886028386f2f069756ef18e757b10ba9dbf..127555b29f587fab26de53b9a52f137f958ce3f5 100644 (file)
@@ -182,7 +182,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
        if (!path)
                return -ENOMEM;
 
-       nblocks = bio->bi_size >> inode->i_sb->s_blocksize_bits;
+       nblocks = bio->bi_iter.bi_size >> inode->i_sb->s_blocksize_bits;
        if (!dst) {
                if (nblocks * csum_size > BTRFS_BIO_INLINE_CSUM_SIZE) {
                        btrfs_bio->csum_allocated = kmalloc(nblocks * csum_size,
@@ -201,7 +201,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                csum = (u8 *)dst;
        }
 
-       if (bio->bi_size > PAGE_CACHE_SIZE * 8)
+       if (bio->bi_iter.bi_size > PAGE_CACHE_SIZE * 8)
                path->reada = 2;
 
        WARN_ON(bio->bi_vcnt <= 0);
@@ -217,7 +217,7 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                path->skip_locking = 1;
        }
 
-       disk_bytenr = (u64)bio->bi_sector << 9;
+       disk_bytenr = (u64)bio->bi_iter.bi_sector << 9;
        if (dio)
                offset = logical_offset;
        while (bio_index < bio->bi_vcnt) {
@@ -246,8 +246,8 @@ static int __btrfs_lookup_bio_sums(struct btrfs_root *root,
                                                offset + bvec->bv_len - 1,
                                                EXTENT_NODATASUM, GFP_NOFS);
                                } else {
-                                       printk(KERN_INFO "btrfs no csum found "
-                                              "for inode %llu start %llu\n",
+                                       btrfs_info(BTRFS_I(inode)->root->fs_info,
+                                                  "no csum found for inode %llu start %llu",
                                               btrfs_ino(inode), offset);
                                }
                                item = NULL;
@@ -302,7 +302,7 @@ int btrfs_lookup_bio_sums_dio(struct btrfs_root *root, struct inode *inode,
                              struct btrfs_dio_private *dip, struct bio *bio,
                              u64 offset)
 {
-       int len = (bio->bi_sector << 9) - dip->disk_bytenr;
+       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;
 
@@ -447,11 +447,12 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
        u64 offset;
 
        WARN_ON(bio->bi_vcnt <= 0);
-       sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_size), GFP_NOFS);
+       sums = kzalloc(btrfs_ordered_sum_size(root, bio->bi_iter.bi_size),
+                      GFP_NOFS);
        if (!sums)
                return -ENOMEM;
 
-       sums->len = bio->bi_size;
+       sums->len = bio->bi_iter.bi_size;
        INIT_LIST_HEAD(&sums->list);
 
        if (contig)
@@ -461,7 +462,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
 
        ordered = btrfs_lookup_ordered_extent(inode, offset);
        BUG_ON(!ordered); /* Logic error */
-       sums->bytenr = (u64)bio->bi_sector << 9;
+       sums->bytenr = (u64)bio->bi_iter.bi_sector << 9;
        index = 0;
 
        while (bio_index < bio->bi_vcnt) {
@@ -476,7 +477,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
                        btrfs_add_ordered_sum(inode, ordered, sums);
                        btrfs_put_ordered_extent(ordered);
 
-                       bytes_left = bio->bi_size - total_bytes;
+                       bytes_left = bio->bi_iter.bi_size - total_bytes;
 
                        sums = kzalloc(btrfs_ordered_sum_size(root, bytes_left),
                                       GFP_NOFS);
@@ -484,7 +485,7 @@ int btrfs_csum_one_bio(struct btrfs_root *root, struct inode *inode,
                        sums->len = bytes_left;
                        ordered = btrfs_lookup_ordered_extent(inode, offset);
                        BUG_ON(!ordered); /* Logic error */
-                       sums->bytenr = ((u64)bio->bi_sector << 9) +
+                       sums->bytenr = ((u64)bio->bi_iter.bi_sector << 9) +
                                       total_bytes;
                        index = 0;
                }
index 82d0342763c54d652982d2818ab3b9b7f8ffc1ec..0165b8672f099c49f96400fc0c87cc0b7cfc4532 100644 (file)
@@ -692,7 +692,10 @@ next:
 int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root, struct inode *inode,
                         struct btrfs_path *path, u64 start, u64 end,
-                        u64 *drop_end, int drop_cache)
+                        u64 *drop_end, int drop_cache,
+                        int replace_extent,
+                        u32 extent_item_size,
+                        int *key_inserted)
 {
        struct extent_buffer *leaf;
        struct btrfs_file_extent_item *fi;
@@ -712,6 +715,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
        int modify_tree = -1;
        int update_refs = (root->ref_cows || root == root->fs_info->tree_root);
        int found = 0;
+       int leafs_visited = 0;
 
        if (drop_cache)
                btrfs_drop_extent_cache(inode, start, end - 1, 0);
@@ -733,6 +737,7 @@ int __btrfs_drop_extents(struct btrfs_trans_handle *trans,
                                path->slots[0]--;
                }
                ret = 0;
+               leafs_visited++;
 next_slot:
                leaf = path->nodes[0];
                if (path->slots[0] >= btrfs_header_nritems(leaf)) {
@@ -744,6 +749,7 @@ next_slot:
                                ret = 0;
                                break;
                        }
+                       leafs_visited++;
                        leaf = path->nodes[0];
                        recow = 1;
                }
@@ -766,7 +772,8 @@ next_slot:
                                btrfs_file_extent_num_bytes(leaf, fi);
                } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
                        extent_end = key.offset +
-                               btrfs_file_extent_inline_len(leaf, fi);
+                               btrfs_file_extent_inline_len(leaf,
+                                                    path->slots[0], fi);
                } else {
                        WARN_ON(1);
                        extent_end = search_start;
@@ -927,14 +934,44 @@ next_slot:
        }
 
        if (!ret && del_nr > 0) {
+               /*
+                * Set path->slots[0] to first slot, so that after the delete
+                * if items are move off from our leaf to its immediate left or
+                * right neighbor leafs, we end up with a correct and adjusted
+                * path->slots[0] for our insertion.
+                */
+               path->slots[0] = del_slot;
                ret = btrfs_del_items(trans, root, path, del_slot, del_nr);
                if (ret)
                        btrfs_abort_transaction(trans, root, ret);
+
+               leaf = path->nodes[0];
+               /*
+                * leaf eb has flag EXTENT_BUFFER_STALE if it was deleted (that
+                * is, its contents got pushed to its neighbors), in which case
+                * it means path->locks[0] == 0
+                */
+               if (!ret && replace_extent && leafs_visited == 1 &&
+                   path->locks[0] &&
+                   btrfs_leaf_free_space(root, leaf) >=
+                   sizeof(struct btrfs_item) + extent_item_size) {
+
+                       key.objectid = ino;
+                       key.type = BTRFS_EXTENT_DATA_KEY;
+                       key.offset = start;
+                       setup_items_for_insert(root, path, &key,
+                                              &extent_item_size,
+                                              extent_item_size,
+                                              sizeof(struct btrfs_item) +
+                                              extent_item_size, 1);
+                       *key_inserted = 1;
+               }
        }
 
+       if (!replace_extent || !(*key_inserted))
+               btrfs_release_path(path);
        if (drop_end)
                *drop_end = found ? min(end, extent_end) : end;
-       btrfs_release_path(path);
        return ret;
 }
 
@@ -949,7 +986,7 @@ int btrfs_drop_extents(struct btrfs_trans_handle *trans,
        if (!path)
                return -ENOMEM;
        ret = __btrfs_drop_extents(trans, root, inode, path, start, end, NULL,
-                                  drop_cache);
+                                  drop_cache, 0, 0, NULL);
        btrfs_free_path(path);
        return ret;
 }
@@ -1235,29 +1272,18 @@ static int prepare_uptodate_page(struct page *page, u64 pos,
 }
 
 /*
- * this gets pages into the page cache and locks them down, it also properly
- * waits for data=ordered extents to finish before allowing the pages to be
- * modified.
+ * this just gets pages into the page cache and locks them down.
  */
-static noinline int prepare_pages(struct btrfs_root *root, struct file *file,
-                        struct page **pages, size_t num_pages,
-                        loff_t pos, unsigned long first_index,
-                        size_t write_bytes, bool force_uptodate)
+static noinline int prepare_pages(struct inode *inode, struct page **pages,
+                                 size_t num_pages, loff_t pos,
+                                 size_t write_bytes, bool force_uptodate)
 {
-       struct extent_state *cached_state = NULL;
        int i;
        unsigned long index = pos >> PAGE_CACHE_SHIFT;
-       struct inode *inode = file_inode(file);
        gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
        int err = 0;
-       int faili = 0;
-       u64 start_pos;
-       u64 last_pos;
-
-       start_pos = pos & ~((u64)root->sectorsize - 1);
-       last_pos = ((u64)index + num_pages) << PAGE_CACHE_SHIFT;
+       int faili;
 
-again:
        for (i = 0; i < num_pages; i++) {
                pages[i] = find_or_create_page(inode->i_mapping, index + i,
                                               mask | __GFP_WRITE);
@@ -1280,57 +1306,85 @@ again:
                }
                wait_on_page_writeback(pages[i]);
        }
-       faili = num_pages - 1;
-       err = 0;
+
+       return 0;
+fail:
+       while (faili >= 0) {
+               unlock_page(pages[faili]);
+               page_cache_release(pages[faili]);
+               faili--;
+       }
+       return err;
+
+}
+
+/*
+ * This function locks the extent and properly waits for data=ordered extents
+ * to finish before allowing the pages to be modified if need.
+ *
+ * The return value:
+ * 1 - the extent is locked
+ * 0 - the extent is not locked, and everything is OK
+ * -EAGAIN - need re-prepare the pages
+ * the other < 0 number - Something wrong happens
+ */
+static noinline int
+lock_and_cleanup_extent_if_need(struct inode *inode, struct page **pages,
+                               size_t num_pages, loff_t pos,
+                               u64 *lockstart, u64 *lockend,
+                               struct extent_state **cached_state)
+{
+       u64 start_pos;
+       u64 last_pos;
+       int i;
+       int ret = 0;
+
+       start_pos = pos & ~((u64)PAGE_CACHE_SIZE - 1);
+       last_pos = start_pos + ((u64)num_pages << PAGE_CACHE_SHIFT) - 1;
+
        if (start_pos < inode->i_size) {
                struct btrfs_ordered_extent *ordered;
                lock_extent_bits(&BTRFS_I(inode)->io_tree,
-                                start_pos, last_pos - 1, 0, &cached_state);
-               ordered = btrfs_lookup_first_ordered_extent(inode,
-                                                           last_pos - 1);
+                                start_pos, last_pos, 0, cached_state);
+               ordered = btrfs_lookup_first_ordered_extent(inode, last_pos);
                if (ordered &&
                    ordered->file_offset + ordered->len > start_pos &&
-                   ordered->file_offset < last_pos) {
+                   ordered->file_offset <= last_pos) {
                        btrfs_put_ordered_extent(ordered);
                        unlock_extent_cached(&BTRFS_I(inode)->io_tree,
-                                            start_pos, last_pos - 1,
-                                            &cached_state, GFP_NOFS);
+                                            start_pos, last_pos,
+                                            cached_state, GFP_NOFS);
                        for (i = 0; i < num_pages; i++) {
                                unlock_page(pages[i]);
                                page_cache_release(pages[i]);
                        }
-                       err = btrfs_wait_ordered_range(inode, start_pos,
-                                                      last_pos - start_pos);
-                       if (err)
-                               goto fail;
-                       goto again;
+                       ret = btrfs_wait_ordered_range(inode, start_pos,
+                                               last_pos - start_pos + 1);
+                       if (ret)
+                               return ret;
+                       else
+                               return -EAGAIN;
                }
                if (ordered)
                        btrfs_put_ordered_extent(ordered);
 
                clear_extent_bit(&BTRFS_I(inode)->io_tree, start_pos,
-                                 last_pos - 1, EXTENT_DIRTY | EXTENT_DELALLOC |
+                                 last_pos, EXTENT_DIRTY | EXTENT_DELALLOC |
                                  EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG,
-                                 0, 0, &cached_state, GFP_NOFS);
-               unlock_extent_cached(&BTRFS_I(inode)->io_tree,
-                                    start_pos, last_pos - 1, &cached_state,
-                                    GFP_NOFS);
+                                 0, 0, cached_state, GFP_NOFS);
+               *lockstart = start_pos;
+               *lockend = last_pos;
+               ret = 1;
        }
+
        for (i = 0; i < num_pages; i++) {
                if (clear_page_dirty_for_io(pages[i]))
                        account_page_redirty(pages[i]);
                set_page_extent_mapped(pages[i]);
                WARN_ON(!PageLocked(pages[i]));
        }
-       return 0;
-fail:
-       while (faili >= 0) {
-               unlock_page(pages[faili]);
-               page_cache_release(pages[faili]);
-               faili--;
-       }
-       return err;
 
+       return ret;
 }
 
 static noinline int check_can_nocow(struct inode *inode, loff_t pos,
@@ -1381,13 +1435,17 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
        struct inode *inode = file_inode(file);
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct page **pages = NULL;
+       struct extent_state *cached_state = NULL;
        u64 release_bytes = 0;
+       u64 lockstart;
+       u64 lockend;
        unsigned long first_index;
        size_t num_written = 0;
        int nrptrs;
        int ret = 0;
        bool only_release_metadata = false;
        bool force_page_uptodate = false;
+       bool need_unlock;
 
        nrptrs = min((iov_iter_count(i) + PAGE_CACHE_SIZE - 1) /
                     PAGE_CACHE_SIZE, PAGE_CACHE_SIZE /
@@ -1456,18 +1514,31 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                }
 
                release_bytes = reserve_bytes;
-
+               need_unlock = false;
+again:
                /*
                 * This is going to setup the pages array with the number of
                 * pages we want, so we don't really need to worry about the
                 * contents of pages from loop to loop
                 */
-               ret = prepare_pages(root, file, pages, num_pages,
-                                   pos, first_index, write_bytes,
+               ret = prepare_pages(inode, pages, num_pages,
+                                   pos, write_bytes,
                                    force_page_uptodate);
                if (ret)
                        break;
 
+               ret = lock_and_cleanup_extent_if_need(inode, pages, num_pages,
+                                                     pos, &lockstart, &lockend,
+                                                     &cached_state);
+               if (ret < 0) {
+                       if (ret == -EAGAIN)
+                               goto again;
+                       break;
+               } else if (ret > 0) {
+                       need_unlock = true;
+                       ret = 0;
+               }
+
                copied = btrfs_copy_from_user(pos, num_pages,
                                           write_bytes, pages, i);
 
@@ -1512,19 +1583,21 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                }
 
                release_bytes = dirty_pages << PAGE_CACHE_SHIFT;
-               if (copied > 0) {
+
+               if (copied > 0)
                        ret = btrfs_dirty_pages(root, inode, pages,
                                                dirty_pages, pos, copied,
                                                NULL);
-                       if (ret) {
-                               btrfs_drop_pages(pages, num_pages);
-                               break;
-                       }
+               if (need_unlock)
+                       unlock_extent_cached(&BTRFS_I(inode)->io_tree,
+                                            lockstart, lockend, &cached_state,
+                                            GFP_NOFS);
+               if (ret) {
+                       btrfs_drop_pages(pages, num_pages);
+                       break;
                }
 
                release_bytes = 0;
-               btrfs_drop_pages(pages, num_pages);
-
                if (only_release_metadata && copied > 0) {
                        u64 lockstart = round_down(pos, root->sectorsize);
                        u64 lockend = lockstart +
@@ -1536,6 +1609,8 @@ static noinline ssize_t __btrfs_buffered_write(struct file *file,
                        only_release_metadata = false;
                }
 
+               btrfs_drop_pages(pages, num_pages);
+
                cond_resched();
 
                balance_dirty_pages_ratelimited(inode->i_mapping);
@@ -1857,12 +1932,24 @@ int btrfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
        if (file->private_data)
                btrfs_ioctl_trans_end(file);
 
+       /*
+        * We use start here because we will need to wait on the IO to complete
+        * in btrfs_sync_log, which could require joining a transaction (for
+        * example checking cross references in the nocow path).  If we use join
+        * here we could get into a situation where we're waiting on IO to
+        * happen that is blocked on a transaction trying to commit.  With start
+        * we inc the extwriter counter, so we wait for all extwriters to exit
+        * before we start blocking join'ers.  This comment is to keep somebody
+        * from thinking they are super smart and changing this to
+        * btrfs_join_transaction *cough*Josef*cough*.
+        */
        trans = btrfs_start_transaction(root, 0);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
                mutex_unlock(&inode->i_mutex);
                goto out;
        }
+       trans->sync = true;
 
        ret = btrfs_log_dentry_safe(trans, root, dentry);
        if (ret < 0) {
@@ -1963,11 +2050,13 @@ static int fill_holes(struct btrfs_trans_handle *trans, struct inode *inode,
        struct btrfs_key key;
        int ret;
 
+       if (btrfs_fs_incompat(root->fs_info, NO_HOLES))
+               goto out;
+
        key.objectid = btrfs_ino(inode);
        key.type = BTRFS_EXTENT_DATA_KEY;
        key.offset = offset;
 
-
        ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
        if (ret < 0)
                return ret;
@@ -2064,8 +2153,10 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        u64 drop_end;
        int ret = 0;
        int err = 0;
+       int rsv_count;
        bool same_page = ((offset >> PAGE_CACHE_SHIFT) ==
                          ((offset + len - 1) >> PAGE_CACHE_SHIFT));
+       bool no_holes = btrfs_fs_incompat(root->fs_info, NO_HOLES);
 
        ret = btrfs_wait_ordered_range(inode, offset, len);
        if (ret)
@@ -2125,7 +2216,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                 * we need to try again.
                 */
                if ((!ordered ||
-                   (ordered->file_offset + ordered->len < lockstart ||
+                   (ordered->file_offset + ordered->len <= lockstart ||
                     ordered->file_offset > lockend)) &&
                     !test_range_bit(&BTRFS_I(inode)->io_tree, lockstart,
                                     lockend, EXTENT_UPTODATE, 0,
@@ -2163,9 +2254,10 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        /*
         * 1 - update the inode
         * 1 - removing the extents in the range
-        * 1 - adding the hole extent
+        * 1 - adding the hole extent if no_holes isn't set
         */
-       trans = btrfs_start_transaction(root, 3);
+       rsv_count = no_holes ? 2 : 3;
+       trans = btrfs_start_transaction(root, rsv_count);
        if (IS_ERR(trans)) {
                err = PTR_ERR(trans);
                goto out_free;
@@ -2179,7 +2271,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
        while (cur_offset < lockend) {
                ret = __btrfs_drop_extents(trans, root, inode, path,
                                           cur_offset, lockend + 1,
-                                          &drop_end, 1);
+                                          &drop_end, 1, 0, 0, NULL);
                if (ret != -ENOSPC)
                        break;
 
@@ -2202,7 +2294,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
                btrfs_end_transaction(trans, root);
                btrfs_btree_balance_dirty(root);
 
-               trans = btrfs_start_transaction(root, 3);
+               trans = btrfs_start_transaction(root, rsv_count);
                if (IS_ERR(trans)) {
                        ret = PTR_ERR(trans);
                        trans = NULL;
index 057be95b1e1e5894bdbe3525d0f5f8f2b3860650..73f3de7a083c2aab0b48e0e0a53f61044dba794e 100644 (file)
@@ -347,8 +347,8 @@ static int io_ctl_prepare_pages(struct io_ctl *io_ctl, struct inode *inode,
                        btrfs_readpage(NULL, page);
                        lock_page(page);
                        if (!PageUptodate(page)) {
-                               printk(KERN_ERR "btrfs: error reading free "
-                                      "space cache\n");
+                               btrfs_err(BTRFS_I(inode)->root->fs_info,
+                                          "error reading free space cache");
                                io_ctl_drop_pages(io_ctl);
                                return -EIO;
                        }
@@ -405,7 +405,7 @@ static int io_ctl_check_generation(struct io_ctl *io_ctl, u64 generation)
 
        gen = io_ctl->cur;
        if (le64_to_cpu(*gen) != generation) {
-               printk_ratelimited(KERN_ERR "btrfs: space cache generation "
+               printk_ratelimited(KERN_ERR "BTRFS: space cache generation "
                                   "(%Lu) does not match inode (%Lu)\n", *gen,
                                   generation);
                io_ctl_unmap_page(io_ctl);
@@ -463,7 +463,7 @@ static int io_ctl_check_crc(struct io_ctl *io_ctl, int index)
                              PAGE_CACHE_SIZE - offset);
        btrfs_csum_final(crc, (char *)&crc);
        if (val != crc) {
-               printk_ratelimited(KERN_ERR "btrfs: csum mismatch on free "
+               printk_ratelimited(KERN_ERR "BTRFS: csum mismatch on free "
                                   "space cache\n");
                io_ctl_unmap_page(io_ctl);
                return -EIO;
@@ -1902,7 +1902,7 @@ out:
        spin_unlock(&ctl->tree_lock);
 
        if (ret) {
-               printk(KERN_CRIT "btrfs: unable to add free space :%d\n", ret);
+               printk(KERN_CRIT "BTRFS: unable to add free space :%d\n", ret);
                ASSERT(ret != -EEXIST);
        }
 
@@ -2011,14 +2011,15 @@ void btrfs_dump_free_space(struct btrfs_block_group_cache *block_group,
                info = rb_entry(n, struct btrfs_free_space, offset_index);
                if (info->bytes >= bytes && !block_group->ro)
                        count++;
-               printk(KERN_CRIT "entry offset %llu, bytes %llu, bitmap %s\n",
-                      info->offset, info->bytes,
+               btrfs_crit(block_group->fs_info,
+                          "entry offset %llu, bytes %llu, bitmap %s",
+                          info->offset, info->bytes,
                       (info->bitmap) ? "yes" : "no");
        }
-       printk(KERN_INFO "block group has cluster?: %s\n",
+       btrfs_info(block_group->fs_info, "block group has cluster?: %s",
               list_empty(&block_group->cluster_list) ? "no" : "yes");
-       printk(KERN_INFO "%d blocks of free space at or bigger than bytes is"
-              "\n", count);
+       btrfs_info(block_group->fs_info,
+                  "%d blocks of free space at or bigger than bytes is", count);
 }
 
 void btrfs_init_free_space_ctl(struct btrfs_block_group_cache *block_group)
@@ -2421,7 +2422,6 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
        struct btrfs_free_space *entry = NULL;
        struct btrfs_free_space *last;
        struct rb_node *node;
-       u64 window_start;
        u64 window_free;
        u64 max_extent;
        u64 total_size = 0;
@@ -2443,7 +2443,6 @@ setup_cluster_no_bitmap(struct btrfs_block_group_cache *block_group,
                entry = rb_entry(node, struct btrfs_free_space, offset_index);
        }
 
-       window_start = entry->offset;
        window_free = entry->bytes;
        max_extent = entry->bytes;
        first = entry;
diff --git a/fs/btrfs/hash.c b/fs/btrfs/hash.c
new file mode 100644 (file)
index 0000000..85889aa
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2014 Filipe David Borba Manana <fdmanana@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ */
+
+#include <crypto/hash.h>
+#include <linux/err.h>
+#include "hash.h"
+
+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;
+}
+
+void btrfs_hash_exit(void)
+{
+       crypto_free_shash(tfm);
+}
+
+u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length)
+{
+       struct {
+               struct shash_desc shash;
+               char ctx[crypto_shash_descsize(tfm)];
+       } desc;
+       int err;
+
+       desc.shash.tfm = tfm;
+       desc.shash.flags = 0;
+       *(u32 *)desc.ctx = crc;
+
+       err = crypto_shash_update(&desc.shash, address, length);
+       BUG_ON(err);
+
+       return *(u32 *)desc.ctx;
+}
index 1d982812ab6761077673985dea55970f418cedf7..118a2316e5d39f51cc6293e912ed9d2598d6afd8 100644 (file)
 #ifndef __HASH__
 #define __HASH__
 
-#include <linux/crc32c.h>
+int __init btrfs_hash_init(void);
+
+void btrfs_hash_exit(void);
+
+u32 btrfs_crc32c(u32 crc, const void *address, unsigned int length);
+
 static inline u64 btrfs_name_hash(const char *name, int len)
 {
-       return crc32c((u32)~1, name, len);
+       return btrfs_crc32c((u32)~1, name, len);
 }
 
 /*
@@ -31,7 +36,7 @@ static inline u64 btrfs_name_hash(const char *name, int len)
 static inline u64 btrfs_extref_hash(u64 parent_objectid, const char *name,
                                    int len)
 {
-       return (u64) crc32c(parent_objectid, name, len);
+       return (u64) btrfs_crc32c(parent_objectid, name, len);
 }
 
 #endif
index ec82fae070975fcdb6d60879ba34cc001884afbf..2be38df703c9b095f35ed5e887fa2c37c7fb0e7c 100644 (file)
@@ -91,32 +91,6 @@ int btrfs_find_name_in_ext_backref(struct btrfs_path *path, u64 ref_objectid,
        return 0;
 }
 
-static struct btrfs_inode_ref *
-btrfs_lookup_inode_ref(struct btrfs_trans_handle *trans,
-                      struct btrfs_root *root,
-                      struct btrfs_path *path,
-                      const char *name, int name_len,
-                      u64 inode_objectid, u64 ref_objectid, int ins_len,
-                      int cow)
-{
-       int ret;
-       struct btrfs_key key;
-       struct btrfs_inode_ref *ref;
-
-       key.objectid = inode_objectid;
-       key.type = BTRFS_INODE_REF_KEY;
-       key.offset = ref_objectid;
-
-       ret = btrfs_search_slot(trans, root, &key, path, ins_len, cow);
-       if (ret < 0)
-               return ERR_PTR(ret);
-       if (ret > 0)
-               return NULL;
-       if (!find_name_in_backref(path, name, name_len, &ref))
-               return NULL;
-       return ref;
-}
-
 /* Returns NULL if no extref found */
 struct btrfs_inode_extref *
 btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
@@ -144,45 +118,6 @@ btrfs_lookup_inode_extref(struct btrfs_trans_handle *trans,
        return extref;
 }
 
-int btrfs_get_inode_ref_index(struct btrfs_trans_handle *trans,
-                             struct btrfs_root *root,
-                             struct btrfs_path *path,
-                             const char *name, int name_len,
-                             u64 inode_objectid, u64 ref_objectid, int mod,
-                             u64 *ret_index)
-{
-       struct btrfs_inode_ref *ref;
-       struct btrfs_inode_extref *extref;
-       int ins_len = mod < 0 ? -1 : 0;
-       int cow = mod != 0;
-
-       ref = btrfs_lookup_inode_ref(trans, root, path, name, name_len,
-                                    inode_objectid, ref_objectid, ins_len,
-                                    cow);
-       if (IS_ERR(ref))
-               return PTR_ERR(ref);
-
-       if (ref != NULL) {
-               *ret_index = btrfs_inode_ref_index(path->nodes[0], ref);
-               return 0;
-       }
-
-       btrfs_release_path(path);
-
-       extref = btrfs_lookup_inode_extref(trans, root, path, name,
-                                          name_len, inode_objectid,
-                                          ref_objectid, ins_len, cow);
-       if (IS_ERR(extref))
-               return PTR_ERR(extref);
-
-       if (extref) {
-               *ret_index = btrfs_inode_extref_index(path->nodes[0], extref);
-               return 0;
-       }
-
-       return -ENOENT;
-}
-
 static int btrfs_del_inode_extref(struct btrfs_trans_handle *trans,
                                  struct btrfs_root *root,
                                  const char *name, int name_len,
index 471a4f7f4044d4171f823e996ff89b68d237abb0..5c4ab9c18940cc7827a75df6e02a84370cae3edd 100644 (file)
 #include "inode-map.h"
 #include "backref.h"
 #include "hash.h"
+#include "props.h"
 
 struct btrfs_iget_args {
-       u64 ino;
+       struct btrfs_key *location;
        struct btrfs_root *root;
 };
 
@@ -125,13 +126,12 @@ static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
  * no overlapping inline items exist in the btree
  */
 static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
+                               struct btrfs_path *path, int extent_inserted,
                                struct btrfs_root *root, struct inode *inode,
                                u64 start, size_t size, size_t compressed_size,
                                int compress_type,
                                struct page **compressed_pages)
 {
-       struct btrfs_key key;
-       struct btrfs_path *path;
        struct extent_buffer *leaf;
        struct page *page = NULL;
        char *kaddr;
@@ -140,29 +140,29 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
        int err = 0;
        int ret;
        size_t cur_size = size;
-       size_t datasize;
        unsigned long offset;
 
        if (compressed_size && compressed_pages)
                cur_size = compressed_size;
 
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
+       inode_add_bytes(inode, size);
 
-       path->leave_spinning = 1;
+       if (!extent_inserted) {
+               struct btrfs_key key;
+               size_t datasize;
 
-       key.objectid = btrfs_ino(inode);
-       key.offset = start;
-       btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
-       datasize = btrfs_file_extent_calc_inline_size(cur_size);
+               key.objectid = btrfs_ino(inode);
+               key.offset = start;
+               btrfs_set_key_type(&key, BTRFS_EXTENT_DATA_KEY);
 
-       inode_add_bytes(inode, size);
-       ret = btrfs_insert_empty_item(trans, root, path, &key,
-                                     datasize);
-       if (ret) {
-               err = ret;
-               goto fail;
+               datasize = btrfs_file_extent_calc_inline_size(cur_size);
+               path->leave_spinning = 1;
+               ret = btrfs_insert_empty_item(trans, root, path, &key,
+                                             datasize);
+               if (ret) {
+                       err = ret;
+                       goto fail;
+               }
        }
        leaf = path->nodes[0];
        ei = btrfs_item_ptr(leaf, path->slots[0],
@@ -203,7 +203,7 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
                page_cache_release(page);
        }
        btrfs_mark_buffer_dirty(leaf);
-       btrfs_free_path(path);
+       btrfs_release_path(path);
 
        /*
         * we're an inline extent, so nobody can
@@ -219,7 +219,6 @@ static noinline int insert_inline_extent(struct btrfs_trans_handle *trans,
 
        return ret;
 fail:
-       btrfs_free_path(path);
        return err;
 }
 
@@ -242,6 +241,9 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
        u64 aligned_end = ALIGN(end, root->sectorsize);
        u64 data_len = inline_len;
        int ret;
+       struct btrfs_path *path;
+       int extent_inserted = 0;
+       u32 extent_item_size;
 
        if (compressed_size)
                data_len = compressed_size;
@@ -256,12 +258,27 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
                return 1;
        }
 
+       path = btrfs_alloc_path();
+       if (!path)
+               return -ENOMEM;
+
        trans = btrfs_join_transaction(root);
-       if (IS_ERR(trans))
+       if (IS_ERR(trans)) {
+               btrfs_free_path(path);
                return PTR_ERR(trans);
+       }
        trans->block_rsv = &root->fs_info->delalloc_block_rsv;
 
-       ret = btrfs_drop_extents(trans, root, inode, start, aligned_end, 1);
+       if (compressed_size && compressed_pages)
+               extent_item_size = btrfs_file_extent_calc_inline_size(
+                  compressed_size);
+       else
+               extent_item_size = btrfs_file_extent_calc_inline_size(
+                   inline_len);
+
+       ret = __btrfs_drop_extents(trans, root, inode, path,
+                                  start, aligned_end, NULL,
+                                  1, 1, extent_item_size, &extent_inserted);
        if (ret) {
                btrfs_abort_transaction(trans, root, ret);
                goto out;
@@ -269,7 +286,8 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
 
        if (isize > actual_end)
                inline_len = min_t(u64, isize, actual_end);
-       ret = insert_inline_extent(trans, root, inode, start,
+       ret = insert_inline_extent(trans, path, extent_inserted,
+                                  root, inode, start,
                                   inline_len, compressed_size,
                                   compress_type, compressed_pages);
        if (ret && ret != -ENOSPC) {
@@ -284,6 +302,7 @@ static noinline int cow_file_range_inline(struct btrfs_root *root,
        btrfs_delalloc_release_metadata(inode, end + 1 - start);
        btrfs_drop_extent_cache(inode, start, aligned_end - 1, 0);
 out:
+       btrfs_free_path(path);
        btrfs_end_transaction(trans, root);
        return ret;
 }
@@ -1262,7 +1281,8 @@ next_slot:
                        nocow = 1;
                } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
                        extent_end = found_key.offset +
-                               btrfs_file_extent_inline_len(leaf, fi);
+                               btrfs_file_extent_inline_len(leaf,
+                                                    path->slots[0], fi);
                        extent_end = ALIGN(extent_end, root->sectorsize);
                } else {
                        BUG_ON(1);
@@ -1577,7 +1597,7 @@ int btrfs_merge_bio_hook(int rw, struct page *page, unsigned long offset,
                         unsigned long bio_flags)
 {
        struct btrfs_root *root = BTRFS_I(page->mapping->host)->root;
-       u64 logical = (u64)bio->bi_sector << 9;
+       u64 logical = (u64)bio->bi_iter.bi_sector << 9;
        u64 length = 0;
        u64 map_length;
        int ret;
@@ -1585,7 +1605,7 @@ int btrfs_merge_bio_hook(int rw, struct page *page, unsigned long offset,
        if (bio_flags & EXTENT_BIO_COMPRESSED)
                return 0;
 
-       length = bio->bi_size;
+       length = bio->bi_iter.bi_size;
        map_length = length;
        ret = btrfs_map_block(root->fs_info, rw, logical,
                              &map_length, NULL, 0);
@@ -1841,14 +1861,13 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
        struct btrfs_path *path;
        struct extent_buffer *leaf;
        struct btrfs_key ins;
+       int extent_inserted = 0;
        int ret;
 
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
 
-       path->leave_spinning = 1;
-
        /*
         * we may be replacing one extent in the tree with another.
         * The new extent is pinned in the extent map, and we don't want
@@ -1858,17 +1877,23 @@ static int insert_reserved_file_extent(struct btrfs_trans_handle *trans,
         * the caller is expected to unpin it and allow it to be merged
         * with the others.
         */
-       ret = btrfs_drop_extents(trans, root, inode, file_pos,
-                                file_pos + num_bytes, 0);
+       ret = __btrfs_drop_extents(trans, root, inode, path, file_pos,
+                                  file_pos + num_bytes, NULL, 0,
+                                  1, sizeof(*fi), &extent_inserted);
        if (ret)
                goto out;
 
-       ins.objectid = btrfs_ino(inode);
-       ins.offset = file_pos;
-       ins.type = BTRFS_EXTENT_DATA_KEY;
-       ret = btrfs_insert_empty_item(trans, root, path, &ins, sizeof(*fi));
-       if (ret)
-               goto out;
+       if (!extent_inserted) {
+               ins.objectid = btrfs_ino(inode);
+               ins.offset = file_pos;
+               ins.type = BTRFS_EXTENT_DATA_KEY;
+
+               path->leave_spinning = 1;
+               ret = btrfs_insert_empty_item(trans, root, path, &ins,
+                                             sizeof(*fi));
+               if (ret)
+                       goto out;
+       }
        leaf = path->nodes[0];
        fi = btrfs_item_ptr(leaf, path->slots[0],
                            struct btrfs_file_extent_item);
@@ -2290,7 +2315,7 @@ again:
                u64 extent_len;
                struct btrfs_key found_key;
 
-               ret = btrfs_search_slot(trans, root, &key, path, 1, 1);
+               ret = btrfs_search_slot(trans, root, &key, path, 0, 1);
                if (ret < 0)
                        goto out_free_path;
 
@@ -2543,12 +2568,6 @@ out_kfree:
        return NULL;
 }
 
-/*
- * helper function for btrfs_finish_ordered_io, this
- * just reads in some of the csum leaves to prime them into ram
- * before we start the transaction.  It limits the amount of btree
- * reads required while inside the transaction.
- */
 /* as ordered data IO finishes, this gets called so we can finish
  * an ordered extent if the range of bytes in the file it covers are
  * fully written.
@@ -3248,7 +3267,8 @@ out:
  * slot is the slot the inode is in, objectid is the objectid of the inode
  */
 static noinline int acls_after_inode_item(struct extent_buffer *leaf,
-                                         int slot, u64 objectid)
+                                         int slot, u64 objectid,
+                                         int *first_xattr_slot)
 {
        u32 nritems = btrfs_header_nritems(leaf);
        struct btrfs_key found_key;
@@ -3264,6 +3284,7 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf,
        }
 
        slot++;
+       *first_xattr_slot = -1;
        while (slot < nritems) {
                btrfs_item_key_to_cpu(leaf, &found_key, slot);
 
@@ -3273,6 +3294,8 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf,
 
                /* we found an xattr, assume we've got an acl */
                if (found_key.type == BTRFS_XATTR_ITEM_KEY) {
+                       if (*first_xattr_slot == -1)
+                               *first_xattr_slot = slot;
                        if (found_key.offset == xattr_access ||
                            found_key.offset == xattr_default)
                                return 1;
@@ -3301,6 +3324,8 @@ static noinline int acls_after_inode_item(struct extent_buffer *leaf,
         * something larger than an xattr.  We have to assume the inode
         * has acls
         */
+       if (*first_xattr_slot == -1)
+               *first_xattr_slot = slot;
        return 1;
 }
 
@@ -3315,10 +3340,12 @@ static void btrfs_read_locked_inode(struct inode *inode)
        struct btrfs_timespec *tspec;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct btrfs_key location;
+       unsigned long ptr;
        int maybe_acls;
        u32 rdev;
        int ret;
        bool filled = false;
+       int first_xattr_slot;
 
        ret = btrfs_fill_inode(inode, &rdev);
        if (!ret)
@@ -3328,7 +3355,6 @@ static void btrfs_read_locked_inode(struct inode *inode)
        if (!path)
                goto make_bad;
 
-       path->leave_spinning = 1;
        memcpy(&location, &BTRFS_I(inode)->location, sizeof(location));
 
        ret = btrfs_lookup_inode(NULL, root, path, &location, 0);
@@ -3338,7 +3364,7 @@ static void btrfs_read_locked_inode(struct inode *inode)
        leaf = path->nodes[0];
 
        if (filled)
-               goto cache_acl;
+               goto cache_index;
 
        inode_item = btrfs_item_ptr(leaf, path->slots[0],
                                    struct btrfs_inode_item);
@@ -3381,18 +3407,51 @@ static void btrfs_read_locked_inode(struct inode *inode)
 
        BTRFS_I(inode)->index_cnt = (u64)-1;
        BTRFS_I(inode)->flags = btrfs_inode_flags(leaf, inode_item);
+
+cache_index:
+       path->slots[0]++;
+       if (inode->i_nlink != 1 ||
+           path->slots[0] >= btrfs_header_nritems(leaf))
+               goto cache_acl;
+
+       btrfs_item_key_to_cpu(leaf, &location, path->slots[0]);
+       if (location.objectid != btrfs_ino(inode))
+               goto cache_acl;
+
+       ptr = btrfs_item_ptr_offset(leaf, path->slots[0]);
+       if (location.type == BTRFS_INODE_REF_KEY) {
+               struct btrfs_inode_ref *ref;
+
+               ref = (struct btrfs_inode_ref *)ptr;
+               BTRFS_I(inode)->dir_index = btrfs_inode_ref_index(leaf, ref);
+       } else if (location.type == BTRFS_INODE_EXTREF_KEY) {
+               struct btrfs_inode_extref *extref;
+
+               extref = (struct btrfs_inode_extref *)ptr;
+               BTRFS_I(inode)->dir_index = btrfs_inode_extref_index(leaf,
+                                                                    extref);
+       }
 cache_acl:
        /*
         * try to precache a NULL acl entry for files that don't have
         * any xattrs or acls
         */
        maybe_acls = acls_after_inode_item(leaf, path->slots[0],
-                                          btrfs_ino(inode));
+                                          btrfs_ino(inode), &first_xattr_slot);
+       if (first_xattr_slot != -1) {
+               path->slots[0] = first_xattr_slot;
+               ret = btrfs_load_inode_props(inode, path);
+               if (ret)
+                       btrfs_err(root->fs_info,
+                                 "error loading props for ino %llu (root %llu): %d\n",
+                                 btrfs_ino(inode),
+                                 root->root_key.objectid, ret);
+       }
+       btrfs_free_path(path);
+
        if (!maybe_acls)
                cache_no_acl(inode);
 
-       btrfs_free_path(path);
-
        switch (inode->i_mode & S_IFMT) {
        case S_IFREG:
                inode->i_mapping->a_ops = &btrfs_aops;
@@ -3496,7 +3555,6 @@ static noinline int btrfs_update_inode_item(struct btrfs_trans_handle *trans,
                goto failed;
        }
 
-       btrfs_unlock_up_safe(path, 1);
        leaf = path->nodes[0];
        inode_item = btrfs_item_ptr(leaf, path->slots[0],
                                    struct btrfs_inode_item);
@@ -3593,6 +3651,24 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
                goto err;
        btrfs_release_path(path);
 
+       /*
+        * If we don't have dir index, we have to get it by looking up
+        * the inode ref, since we get the inode ref, remove it directly,
+        * it is unnecessary to do delayed deletion.
+        *
+        * But if we have dir index, needn't search inode ref to get it.
+        * Since the inode ref is close to the inode item, it is better
+        * that we delay to delete it, and just do this deletion when
+        * we update the inode item.
+        */
+       if (BTRFS_I(inode)->dir_index) {
+               ret = btrfs_delayed_delete_inode_ref(inode);
+               if (!ret) {
+                       index = BTRFS_I(inode)->dir_index;
+                       goto skip_backref;
+               }
+       }
+
        ret = btrfs_del_inode_ref(trans, root, name, name_len, ino,
                                  dir_ino, &index);
        if (ret) {
@@ -3602,7 +3678,7 @@ static int __btrfs_unlink_inode(struct btrfs_trans_handle *trans,
                btrfs_abort_transaction(trans, root, ret);
                goto err;
        }
-
+skip_backref:
        ret = btrfs_delete_delayed_dir_index(trans, root, dir, index);
        if (ret) {
                btrfs_abort_transaction(trans, root, ret);
@@ -3948,7 +4024,7 @@ search_again:
                                    btrfs_file_extent_num_bytes(leaf, fi);
                        } else if (extent_type == BTRFS_FILE_EXTENT_INLINE) {
                                item_end += btrfs_file_extent_inline_len(leaf,
-                                                                        fi);
+                                                        path->slots[0], fi);
                        }
                        item_end--;
                }
@@ -4018,6 +4094,12 @@ search_again:
                                        inode_sub_bytes(inode, item_end + 1 -
                                                        new_size);
                                }
+
+                               /*
+                                * update the ram bytes to properly reflect
+                                * the new size of our item
+                                */
+                               btrfs_set_file_extent_ram_bytes(leaf, fi, size);
                                size =
                                    btrfs_file_extent_calc_inline_size(size);
                                btrfs_truncate_item(root, path, size, 1);
@@ -4203,6 +4285,49 @@ out:
        return ret;
 }
 
+static int maybe_insert_hole(struct btrfs_root *root, struct inode *inode,
+                            u64 offset, u64 len)
+{
+       struct btrfs_trans_handle *trans;
+       int ret;
+
+       /*
+        * Still need to make sure the inode looks like it's been updated so
+        * that any holes get logged if we fsync.
+        */
+       if (btrfs_fs_incompat(root->fs_info, NO_HOLES)) {
+               BTRFS_I(inode)->last_trans = root->fs_info->generation;
+               BTRFS_I(inode)->last_sub_trans = root->log_transid;
+               BTRFS_I(inode)->last_log_commit = root->last_log_commit;
+               return 0;
+       }
+
+       /*
+        * 1 - for the one we're dropping
+        * 1 - for the one we're adding
+        * 1 - for updating the inode.
+        */
+       trans = btrfs_start_transaction(root, 3);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+
+       ret = btrfs_drop_extents(trans, root, inode, offset, offset + len, 1);
+       if (ret) {
+               btrfs_abort_transaction(trans, root, ret);
+               btrfs_end_transaction(trans, root);
+               return ret;
+       }
+
+       ret = btrfs_insert_file_extent(trans, root, btrfs_ino(inode), offset,
+                                      0, 0, len, 0, len, 0, 0, 0);
+       if (ret)
+               btrfs_abort_transaction(trans, root, ret);
+       else
+               btrfs_update_inode(trans, root, inode);
+       btrfs_end_transaction(trans, root);
+       return ret;
+}
+
 /*
  * This function puts in dummy file extents for the area we're creating a hole
  * for.  So if we are truncating this file to a larger size we need to insert
@@ -4211,7 +4336,6 @@ out:
  */
 int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
 {
-       struct btrfs_trans_handle *trans;
        struct btrfs_root *root = BTRFS_I(inode)->root;
        struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
        struct extent_map *em = NULL;
@@ -4266,31 +4390,10 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
                        struct extent_map *hole_em;
                        hole_size = last_byte - cur_offset;
 
-                       trans = btrfs_start_transaction(root, 3);
-                       if (IS_ERR(trans)) {
-                               err = PTR_ERR(trans);
-                               break;
-                       }
-
-                       err = btrfs_drop_extents(trans, root, inode,
-                                                cur_offset,
-                                                cur_offset + hole_size, 1);
-                       if (err) {
-                               btrfs_abort_transaction(trans, root, err);
-                               btrfs_end_transaction(trans, root);
-                               break;
-                       }
-
-                       err = btrfs_insert_file_extent(trans, root,
-                                       btrfs_ino(inode), cur_offset, 0,
-                                       0, hole_size, 0, hole_size,
-                                       0, 0, 0);
-                       if (err) {
-                               btrfs_abort_transaction(trans, root, err);
-                               btrfs_end_transaction(trans, root);
+                       err = maybe_insert_hole(root, inode, cur_offset,
+                                               hole_size);
+                       if (err)
                                break;
-                       }
-
                        btrfs_drop_extent_cache(inode, cur_offset,
                                                cur_offset + hole_size - 1, 0);
                        hole_em = alloc_extent_map();
@@ -4309,7 +4412,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
                        hole_em->ram_bytes = hole_size;
                        hole_em->bdev = root->fs_info->fs_devices->latest_bdev;
                        hole_em->compress_type = BTRFS_COMPRESS_NONE;
-                       hole_em->generation = trans->transid;
+                       hole_em->generation = root->fs_info->generation;
 
                        while (1) {
                                write_lock(&em_tree->lock);
@@ -4322,17 +4425,14 @@ int btrfs_cont_expand(struct inode *inode, loff_t oldsize, loff_t size)
                                                        hole_size - 1, 0);
                        }
                        free_extent_map(hole_em);
-next:
-                       btrfs_update_inode(trans, root, inode);
-                       btrfs_end_transaction(trans, root);
                }
+next:
                free_extent_map(em);
                em = NULL;
                cur_offset = last_byte;
                if (cur_offset >= block_end)
                        break;
        }
-
        free_extent_map(em);
        unlock_extent_cached(io_tree, hole_start, block_end - 1, &cached_state,
                             GFP_NOFS);
@@ -4468,12 +4568,70 @@ static int btrfs_setattr(struct dentry *dentry, struct iattr *attr)
                err = btrfs_dirty_inode(inode);
 
                if (!err && attr->ia_valid & ATTR_MODE)
-                       err = btrfs_acl_chmod(inode);
+                       err = posix_acl_chmod(inode, inode->i_mode);
        }
 
        return err;
 }
 
+/*
+ * While truncating the inode pages during eviction, we get the VFS calling
+ * btrfs_invalidatepage() against each page of the inode. This is slow because
+ * the calls to btrfs_invalidatepage() result in a huge amount of calls to
+ * lock_extent_bits() and clear_extent_bit(), which keep merging and splitting
+ * extent_state structures over and over, wasting lots of time.
+ *
+ * Therefore if the inode is being evicted, let btrfs_invalidatepage() skip all
+ * those expensive operations on a per page basis and do only the ordered io
+ * finishing, while we release here the extent_map and extent_state structures,
+ * without the excessive merging and splitting.
+ */
+static void evict_inode_truncate_pages(struct inode *inode)
+{
+       struct extent_io_tree *io_tree = &BTRFS_I(inode)->io_tree;
+       struct extent_map_tree *map_tree = &BTRFS_I(inode)->extent_tree;
+       struct rb_node *node;
+
+       ASSERT(inode->i_state & I_FREEING);
+       truncate_inode_pages(&inode->i_data, 0);
+
+       write_lock(&map_tree->lock);
+       while (!RB_EMPTY_ROOT(&map_tree->map)) {
+               struct extent_map *em;
+
+               node = rb_first(&map_tree->map);
+               em = rb_entry(node, struct extent_map, rb_node);
+               clear_bit(EXTENT_FLAG_PINNED, &em->flags);
+               clear_bit(EXTENT_FLAG_LOGGING, &em->flags);
+               remove_extent_mapping(map_tree, em);
+               free_extent_map(em);
+       }
+       write_unlock(&map_tree->lock);
+
+       spin_lock(&io_tree->lock);
+       while (!RB_EMPTY_ROOT(&io_tree->state)) {
+               struct extent_state *state;
+               struct extent_state *cached_state = NULL;
+
+               node = rb_first(&io_tree->state);
+               state = rb_entry(node, struct extent_state, rb_node);
+               atomic_inc(&state->refs);
+               spin_unlock(&io_tree->lock);
+
+               lock_extent_bits(io_tree, state->start, state->end,
+                                0, &cached_state);
+               clear_extent_bit(io_tree, state->start, state->end,
+                                EXTENT_LOCKED | EXTENT_DIRTY |
+                                EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
+                                EXTENT_DEFRAG, 1, 1,
+                                &cached_state, GFP_NOFS);
+               free_extent_state(state);
+
+               spin_lock(&io_tree->lock);
+       }
+       spin_unlock(&io_tree->lock);
+}
+
 void btrfs_evict_inode(struct inode *inode)
 {
        struct btrfs_trans_handle *trans;
@@ -4484,7 +4642,8 @@ void btrfs_evict_inode(struct inode *inode)
 
        trace_btrfs_inode_evict(inode);
 
-       truncate_inode_pages(&inode->i_data, 0);
+       evict_inode_truncate_pages(inode);
+
        if (inode->i_nlink &&
            ((btrfs_root_refs(&root->root_item) != 0 &&
              root->root_key.objectid != BTRFS_ROOT_TREE_OBJECTID) ||
@@ -4659,9 +4818,9 @@ static int fixup_tree_root_location(struct btrfs_root *root,
        }
 
        err = -ENOENT;
-       ret = btrfs_find_root_ref(root->fs_info->tree_root, path,
-                                 BTRFS_I(dir)->root->root_key.objectid,
-                                 location->objectid);
+       ret = btrfs_find_item(root->fs_info->tree_root, path,
+                               BTRFS_I(dir)->root->root_key.objectid,
+                               location->objectid, BTRFS_ROOT_REF_KEY, NULL);
        if (ret) {
                if (ret < 0)
                        err = ret;
@@ -4822,7 +4981,9 @@ again:
 static int btrfs_init_locked_inode(struct inode *inode, void *p)
 {
        struct btrfs_iget_args *args = p;
-       inode->i_ino = args->ino;
+       inode->i_ino = args->location->objectid;
+       memcpy(&BTRFS_I(inode)->location, args->location,
+              sizeof(*args->location));
        BTRFS_I(inode)->root = args->root;
        return 0;
 }
@@ -4830,19 +4991,19 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
 static int btrfs_find_actor(struct inode *inode, void *opaque)
 {
        struct btrfs_iget_args *args = opaque;
-       return args->ino == btrfs_ino(inode) &&
+       return args->location->objectid == BTRFS_I(inode)->location.objectid &&
                args->root == BTRFS_I(inode)->root;
 }
 
 static struct inode *btrfs_iget_locked(struct super_block *s,
-                                      u64 objectid,
+                                      struct btrfs_key *location,
                                       struct btrfs_root *root)
 {
        struct inode *inode;
        struct btrfs_iget_args args;
-       unsigned long hashval = btrfs_inode_hash(objectid, root);
+       unsigned long hashval = btrfs_inode_hash(location->objectid, root);
 
-       args.ino = objectid;
+       args.location = location;
        args.root = root;
 
        inode = iget5_locked(s, hashval, btrfs_find_actor,
@@ -4859,13 +5020,11 @@ struct inode *btrfs_iget(struct super_block *s, struct btrfs_key *location,
 {
        struct inode *inode;
 
-       inode = btrfs_iget_locked(s, location->objectid, root);
+       inode = btrfs_iget_locked(s, location, root);
        if (!inode)
                return ERR_PTR(-ENOMEM);
 
        if (inode->i_state & I_NEW) {
-               BTRFS_I(inode)->root = root;
-               memcpy(&BTRFS_I(inode)->location, location, sizeof(*location));
                btrfs_read_locked_inode(inode);
                if (!is_bad_inode(inode)) {
                        inode_tree_add(inode);
@@ -4921,7 +5080,7 @@ struct inode *btrfs_lookup_dentry(struct inode *dir, struct dentry *dentry)
                return ERR_PTR(ret);
 
        if (location.objectid == 0)
-               return NULL;
+               return ERR_PTR(-ENOENT);
 
        if (location.type == BTRFS_INODE_ITEM_KEY) {
                inode = btrfs_iget(dir->i_sb, &location, root, NULL);
@@ -4985,10 +5144,17 @@ static void btrfs_dentry_release(struct dentry *dentry)
 static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
                                   unsigned int flags)
 {
-       struct dentry *ret;
+       struct inode *inode;
 
-       ret = d_splice_alias(btrfs_lookup_dentry(dir, dentry), dentry);
-       return ret;
+       inode = btrfs_lookup_dentry(dir, dentry);
+       if (IS_ERR(inode)) {
+               if (PTR_ERR(inode) == -ENOENT)
+                       inode = NULL;
+               else
+                       return ERR_CAST(inode);
+       }
+
+       return d_splice_alias(inode, dentry);
 }
 
 unsigned char btrfs_filetype_table[] = {
@@ -5358,7 +5524,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        u32 sizes[2];
        unsigned long ptr;
        int ret;
-       int owner;
 
        path = btrfs_alloc_path();
        if (!path)
@@ -5392,6 +5557,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
         * number
         */
        BTRFS_I(inode)->index_cnt = 2;
+       BTRFS_I(inode)->dir_index = *index;
        BTRFS_I(inode)->root = root;
        BTRFS_I(inode)->generation = trans->transid;
        inode->i_generation = BTRFS_I(inode)->generation;
@@ -5404,11 +5570,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
         */
        set_bit(BTRFS_INODE_NEEDS_FULL_SYNC, &BTRFS_I(inode)->runtime_flags);
 
-       if (S_ISDIR(mode))
-               owner = 0;
-       else
-               owner = 1;
-
        key[0].objectid = objectid;
        btrfs_set_key_type(&key[0], BTRFS_INODE_ITEM_KEY);
        key[0].offset = 0;
@@ -5473,6 +5634,12 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 
        btrfs_update_root_times(trans, root);
 
+       ret = btrfs_inode_inherit_props(trans, inode, dir);
+       if (ret)
+               btrfs_err(root->fs_info,
+                         "error inheriting props for ino %llu (root %llu): %d",
+                         btrfs_ino(inode), root->root_key.objectid, ret);
+
        return inode;
 fail:
        if (dir)
@@ -5741,6 +5908,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                goto fail;
        }
 
+       /* There are several dir indexes for this inode, clear the cache. */
+       BTRFS_I(inode)->dir_index = 0ULL;
        inc_nlink(inode);
        inode_inc_iversion(inode);
        inode->i_ctime = CURRENT_TIME;
@@ -6004,7 +6173,7 @@ again:
                       btrfs_file_extent_num_bytes(leaf, item);
        } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
                size_t size;
-               size = btrfs_file_extent_inline_len(leaf, item);
+               size = btrfs_file_extent_inline_len(leaf, path->slots[0], item);
                extent_end = ALIGN(extent_start + size, root->sectorsize);
        }
 next:
@@ -6073,7 +6242,7 @@ next:
                        goto out;
                }
 
-               size = btrfs_file_extent_inline_len(leaf, item);
+               size = btrfs_file_extent_inline_len(leaf, path->slots[0], item);
                extent_offset = page_offset(page) + pg_offset - extent_start;
                copy_size = min_t(u64, PAGE_CACHE_SIZE - pg_offset,
                                size - extent_offset);
@@ -6390,6 +6559,7 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
        int slot;
        int found_type;
        bool nocow = (BTRFS_I(inode)->flags & BTRFS_INODE_NODATACOW);
+
        path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
@@ -6433,6 +6603,10 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
        if (!nocow && found_type == BTRFS_FILE_EXTENT_REG)
                goto out;
 
+       extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi);
+       if (extent_end <= offset)
+               goto out;
+
        disk_bytenr = btrfs_file_extent_disk_bytenr(leaf, fi);
        if (disk_bytenr == 0)
                goto out;
@@ -6450,8 +6624,6 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
                *ram_bytes = btrfs_file_extent_ram_bytes(leaf, fi);
        }
 
-       extent_end = key.offset + btrfs_file_extent_num_bytes(leaf, fi);
-
        if (btrfs_extent_readonly(root, disk_bytenr))
                goto out;
        btrfs_release_path(path);
@@ -6783,17 +6955,16 @@ unlock_err:
 static void btrfs_endio_direct_read(struct bio *bio, int err)
 {
        struct btrfs_dio_private *dip = bio->bi_private;
-       struct bio_vec *bvec_end = bio->bi_io_vec + bio->bi_vcnt - 1;
-       struct bio_vec *bvec = bio->bi_io_vec;
+       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 index = 0;
        u64 start;
+       int i;
 
        start = dip->logical_offset;
-       do {
+       bio_for_each_segment_all(bvec, bio, i) {
                if (!(BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM)) {
                        struct page *page = bvec->bv_page;
                        char *kaddr;
@@ -6809,18 +6980,16 @@ static void btrfs_endio_direct_read(struct bio *bio, int err)
                        local_irq_restore(flags);
 
                        flush_dcache_page(bvec->bv_page);
-                       if (csum != csums[index]) {
+                       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[index]);
+                                         csums[i]);
                                err = -EIO;
                        }
                }
 
                start += bvec->bv_len;
-               bvec++;
-               index++;
-       } while (bvec <= bvec_end);
+       }
 
        unlock_extent(&BTRFS_I(inode)->io_tree, dip->logical_offset,
                      dip->logical_offset + dip->bytes - 1);
@@ -6898,10 +7067,11 @@ static void btrfs_end_dio_bio(struct bio *bio, int err)
        struct btrfs_dio_private *dip = bio->bi_private;
 
        if (err) {
-               printk(KERN_ERR "btrfs direct IO failed ino %llu rw %lu "
-                     "sector %#Lx len %u err no %d\n",
+               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_sector, bio->bi_size, err);
+                     (unsigned long long)bio->bi_iter.bi_sector,
+                     bio->bi_iter.bi_size, err);
                dip->errors = 1;
 
                /*
@@ -6992,7 +7162,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
        struct bio *bio;
        struct bio *orig_bio = dip->orig_bio;
        struct bio_vec *bvec = orig_bio->bi_io_vec;
-       u64 start_sector = orig_bio->bi_sector;
+       u64 start_sector = orig_bio->bi_iter.bi_sector;
        u64 file_offset = dip->logical_offset;
        u64 submit_len = 0;
        u64 map_length;
@@ -7000,7 +7170,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
        int ret = 0;
        int async_submit = 0;
 
-       map_length = orig_bio->bi_size;
+       map_length = orig_bio->bi_iter.bi_size;
        ret = btrfs_map_block(root->fs_info, rw, start_sector << 9,
                              &map_length, NULL, 0);
        if (ret) {
@@ -7008,7 +7178,7 @@ static int btrfs_submit_direct_hook(int rw, struct btrfs_dio_private *dip,
                return -EIO;
        }
 
-       if (map_length >= orig_bio->bi_size) {
+       if (map_length >= orig_bio->bi_iter.bi_size) {
                bio = orig_bio;
                goto submit;
        }
@@ -7060,7 +7230,7 @@ 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;
 
-                       map_length = orig_bio->bi_size;
+                       map_length = orig_bio->bi_iter.bi_size;
                        ret = btrfs_map_block(root->fs_info, rw,
                                              start_sector << 9,
                                              &map_length, NULL, 0);
@@ -7118,7 +7288,8 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
 
        if (!skip_sum && !write) {
                csum_size = btrfs_super_csum_size(root->fs_info->super_copy);
-               sum_len = dio_bio->bi_size >> inode->i_sb->s_blocksize_bits;
+               sum_len = dio_bio->bi_iter.bi_size >>
+                       inode->i_sb->s_blocksize_bits;
                sum_len *= csum_size;
        } else {
                sum_len = 0;
@@ -7133,8 +7304,8 @@ static void btrfs_submit_direct(int rw, struct bio *dio_bio,
        dip->private = dio_bio->bi_private;
        dip->inode = inode;
        dip->logical_offset = file_offset;
-       dip->bytes = dio_bio->bi_size;
-       dip->disk_bytenr = (u64)dio_bio->bi_sector << 9;
+       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;
@@ -7371,6 +7542,7 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
        struct extent_state *cached_state = NULL;
        u64 page_start = page_offset(page);
        u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
+       int inode_evicting = inode->i_state & I_FREEING;
 
        /*
         * we have the page locked, so new writeback can't start,
@@ -7386,17 +7558,21 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
                btrfs_releasepage(page, GFP_NOFS);
                return;
        }
-       lock_extent_bits(tree, page_start, page_end, 0, &cached_state);
-       ordered = btrfs_lookup_ordered_extent(inode, page_offset(page));
+
+       if (!inode_evicting)
+               lock_extent_bits(tree, page_start, page_end, 0, &cached_state);
+       ordered = btrfs_lookup_ordered_extent(inode, page_start);
        if (ordered) {
                /*
                 * IO on this page will never be started, so we need
                 * to account for any ordered extents now
                 */
-               clear_extent_bit(tree, page_start, page_end,
-                                EXTENT_DIRTY | EXTENT_DELALLOC |
-                                EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
-                                EXTENT_DEFRAG, 1, 0, &cached_state, GFP_NOFS);
+               if (!inode_evicting)
+                       clear_extent_bit(tree, page_start, page_end,
+                                        EXTENT_DIRTY | EXTENT_DELALLOC |
+                                        EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
+                                        EXTENT_DEFRAG, 1, 0, &cached_state,
+                                        GFP_NOFS);
                /*
                 * whoever cleared the private bit is responsible
                 * for the finish_ordered_io
@@ -7420,14 +7596,22 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
                                btrfs_finish_ordered_io(ordered);
                }
                btrfs_put_ordered_extent(ordered);
-               cached_state = NULL;
-               lock_extent_bits(tree, page_start, page_end, 0, &cached_state);
+               if (!inode_evicting) {
+                       cached_state = NULL;
+                       lock_extent_bits(tree, page_start, page_end, 0,
+                                        &cached_state);
+               }
+       }
+
+       if (!inode_evicting) {
+               clear_extent_bit(tree, page_start, page_end,
+                                EXTENT_LOCKED | EXTENT_DIRTY |
+                                EXTENT_DELALLOC | EXTENT_DO_ACCOUNTING |
+                                EXTENT_DEFRAG, 1, 1,
+                                &cached_state, GFP_NOFS);
+
+               __btrfs_releasepage(page, GFP_NOFS);
        }
-       clear_extent_bit(tree, page_start, page_end,
-                EXTENT_LOCKED | EXTENT_DIRTY | EXTENT_DELALLOC |
-                EXTENT_DO_ACCOUNTING | EXTENT_DEFRAG, 1, 1,
-                &cached_state, GFP_NOFS);
-       __btrfs_releasepage(page, GFP_NOFS);
 
        ClearPageChecked(page);
        if (PagePrivate(page)) {
@@ -7737,7 +7921,9 @@ out:
  * create a new subvolume directory/inode (helper for the ioctl).
  */
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-                            struct btrfs_root *new_root, u64 new_dirid)
+                            struct btrfs_root *new_root,
+                            struct btrfs_root *parent_root,
+                            u64 new_dirid)
 {
        struct inode *inode;
        int err;
@@ -7755,6 +7941,12 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
        set_nlink(inode, 1);
        btrfs_i_size_write(inode, 0);
 
+       err = btrfs_subvol_inherit_props(trans, new_root, parent_root);
+       if (err)
+               btrfs_err(new_root->fs_info,
+                         "error inheriting subvolume %llu properties: %d\n",
+                         new_root->root_key.objectid, err);
+
        err = btrfs_update_inode(trans, new_root, inode);
 
        iput(inode);
@@ -7780,6 +7972,7 @@ struct inode *btrfs_alloc_inode(struct super_block *sb)
        ei->flags = 0;
        ei->csum_bytes = 0;
        ei->index_cnt = (u64)-1;
+       ei->dir_index = 0;
        ei->last_unlink_trans = 0;
        ei->last_log_commit = 0;
 
@@ -8067,6 +8260,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (ret)
                goto out_fail;
 
+       BTRFS_I(old_inode)->dir_index = 0ULL;
        if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
                /* force full log commit if subvolume involved. */
                root->fs_info->last_trans_log_full_commit = trans->transid;
@@ -8155,6 +8349,9 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
                goto out_fail;
        }
 
+       if (old_inode->i_nlink == 1)
+               BTRFS_I(old_inode)->dir_index = index;
+
        if (old_ino != BTRFS_FIRST_FREE_OBJECTID) {
                struct dentry *parent = new_dentry->d_parent;
                btrfs_log_new_name(trans, old_inode, old_dir, parent);
@@ -8290,7 +8487,7 @@ int btrfs_start_delalloc_inodes(struct btrfs_root *root, int delay_iput)
 {
        int ret;
 
-       if (root->fs_info->sb->s_flags & MS_RDONLY)
+       if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state))
                return -EROFS;
 
        ret = __start_delalloc_inodes(root, delay_iput);
@@ -8316,7 +8513,7 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, int delay_iput)
        struct list_head splice;
        int ret;
 
-       if (fs_info->sb->s_flags & MS_RDONLY)
+       if (test_bit(BTRFS_FS_STATE_ERROR, &fs_info->fs_state))
                return -EROFS;
 
        INIT_LIST_HEAD(&splice);
@@ -8653,12 +8850,14 @@ static const struct inode_operations btrfs_dir_inode_operations = {
        .removexattr    = btrfs_removexattr,
        .permission     = btrfs_permission,
        .get_acl        = btrfs_get_acl,
+       .set_acl        = btrfs_set_acl,
        .update_time    = btrfs_update_time,
 };
 static const struct inode_operations btrfs_dir_ro_inode_operations = {
        .lookup         = btrfs_lookup,
        .permission     = btrfs_permission,
        .get_acl        = btrfs_get_acl,
+       .set_acl        = btrfs_set_acl,
        .update_time    = btrfs_update_time,
 };
 
@@ -8728,6 +8927,7 @@ static const struct inode_operations btrfs_file_inode_operations = {
        .permission     = btrfs_permission,
        .fiemap         = btrfs_fiemap,
        .get_acl        = btrfs_get_acl,
+       .set_acl        = btrfs_set_acl,
        .update_time    = btrfs_update_time,
 };
 static const struct inode_operations btrfs_special_inode_operations = {
@@ -8739,6 +8939,7 @@ static const struct inode_operations btrfs_special_inode_operations = {
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
        .get_acl        = btrfs_get_acl,
+       .set_acl        = btrfs_set_acl,
        .update_time    = btrfs_update_time,
 };
 static const struct inode_operations btrfs_symlink_inode_operations = {
@@ -8752,7 +8953,6 @@ static const struct inode_operations btrfs_symlink_inode_operations = {
        .getxattr       = btrfs_getxattr,
        .listxattr      = btrfs_listxattr,
        .removexattr    = btrfs_removexattr,
-       .get_acl        = btrfs_get_acl,
        .update_time    = btrfs_update_time,
 };
 
index 21da5762b0b1b33d193f3bd7f664995a43062bd6..b0134892dc70cdf69be04ad44e3e52183a86fcb0 100644 (file)
@@ -56,6 +56,8 @@
 #include "rcu-string.h"
 #include "send.h"
 #include "dev-replace.h"
+#include "props.h"
+#include "sysfs.h"
 
 static int btrfs_clone(struct inode *src, struct inode *inode,
                       u64 off, u64 olen, u64 olen_aligned, u64 destoff);
@@ -190,6 +192,9 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
        unsigned int i_oldflags;
        umode_t mode;
 
+       if (!inode_owner_or_capable(inode))
+               return -EPERM;
+
        if (btrfs_root_readonly(root))
                return -EROFS;
 
@@ -200,9 +205,6 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
        if (ret)
                return ret;
 
-       if (!inode_owner_or_capable(inode))
-               return -EACCES;
-
        ret = mnt_want_write_file(file);
        if (ret)
                return ret;
@@ -280,9 +282,25 @@ static int btrfs_ioctl_setflags(struct file *file, void __user *arg)
        if (flags & FS_NOCOMP_FL) {
                ip->flags &= ~BTRFS_INODE_COMPRESS;
                ip->flags |= BTRFS_INODE_NOCOMPRESS;
+
+               ret = btrfs_set_prop(inode, "btrfs.compression", NULL, 0, 0);
+               if (ret && ret != -ENODATA)
+                       goto out_drop;
        } else if (flags & FS_COMPR_FL) {
+               const char *comp;
+
                ip->flags |= BTRFS_INODE_COMPRESS;
                ip->flags &= ~BTRFS_INODE_NOCOMPRESS;
+
+               if (root->fs_info->compress_type == BTRFS_COMPRESS_LZO)
+                       comp = "lzo";
+               else
+                       comp = "zlib";
+               ret = btrfs_set_prop(inode, "btrfs.compression",
+                                    comp, strlen(comp), 0);
+               if (ret)
+                       goto out_drop;
+
        } else {
                ip->flags &= ~(BTRFS_INODE_COMPRESS | BTRFS_INODE_NOCOMPRESS);
        }
@@ -392,6 +410,7 @@ static noinline int create_subvol(struct inode *dir,
        struct btrfs_root *new_root;
        struct btrfs_block_rsv block_rsv;
        struct timespec cur_time = CURRENT_TIME;
+       struct inode *inode;
        int ret;
        int err;
        u64 objectid;
@@ -417,7 +436,9 @@ static noinline int create_subvol(struct inode *dir,
        trans = btrfs_start_transaction(root, 0);
        if (IS_ERR(trans)) {
                ret = PTR_ERR(trans);
-               goto out;
+               btrfs_subvolume_release_metadata(root, &block_rsv,
+                                                qgroup_reserved);
+               return ret;
        }
        trans->block_rsv = &block_rsv;
        trans->bytes_reserved = block_rsv.size;
@@ -500,7 +521,7 @@ static noinline int create_subvol(struct inode *dir,
 
        btrfs_record_root_in_trans(trans, new_root);
 
-       ret = btrfs_create_subvol_root(trans, new_root, new_dirid);
+       ret = btrfs_create_subvol_root(trans, new_root, root, new_dirid);
        if (ret) {
                /* We potentially lose an unused inode item here */
                btrfs_abort_transaction(trans, root, ret);
@@ -542,6 +563,8 @@ static noinline int create_subvol(struct inode *dir,
 fail:
        trans->block_rsv = NULL;
        trans->bytes_reserved = 0;
+       btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved);
+
        if (async_transid) {
                *async_transid = trans->transid;
                err = btrfs_commit_transaction_async(trans, root, 1);
@@ -553,10 +576,12 @@ fail:
        if (err && !ret)
                ret = err;
 
-       if (!ret)
-               d_instantiate(dentry, btrfs_lookup_dentry(dir, dentry));
-out:
-       btrfs_subvolume_release_metadata(root, &block_rsv, qgroup_reserved);
+       if (!ret) {
+               inode = btrfs_lookup_dentry(dir, dentry);
+               if (IS_ERR(inode))
+                       return PTR_ERR(inode);
+               d_instantiate(dentry, inode);
+       }
        return ret;
 }
 
@@ -642,7 +667,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
                ret = PTR_ERR(inode);
                goto fail;
        }
-       BUG_ON(!inode);
+
        d_instantiate(dentry, inode);
        ret = 0;
 fail:
@@ -1011,7 +1036,7 @@ out:
 static int cluster_pages_for_defrag(struct inode *inode,
                                    struct page **pages,
                                    unsigned long start_index,
-                                   int num_pages)
+                                   unsigned long num_pages)
 {
        unsigned long file_end;
        u64 isize = i_size_read(inode);
@@ -1169,8 +1194,8 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
        int defrag_count = 0;
        int compress_type = BTRFS_COMPRESS_ZLIB;
        int extent_thresh = range->extent_thresh;
-       int max_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT;
-       int cluster = max_cluster;
+       unsigned long max_cluster = (256 * 1024) >> PAGE_CACHE_SHIFT;
+       unsigned long cluster = max_cluster;
        u64 new_align = ~((u64)128 * 1024 - 1);
        struct page **pages = NULL;
 
@@ -1254,7 +1279,7 @@ int btrfs_defrag_file(struct inode *inode, struct file *file,
                        break;
 
                if (btrfs_defrag_cancelled(root->fs_info)) {
-                       printk(KERN_DEBUG "btrfs: defrag_file cancelled\n");
+                       printk(KERN_DEBUG "BTRFS: defrag_file cancelled\n");
                        ret = -EAGAIN;
                        break;
                }
@@ -1416,20 +1441,20 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                        ret = -EINVAL;
                        goto out_free;
                }
-               printk(KERN_INFO "btrfs: resizing devid %llu\n", devid);
+               btrfs_info(root->fs_info, "resizing devid %llu", devid);
        }
 
        device = btrfs_find_device(root->fs_info, devid, NULL, NULL);
        if (!device) {
-               printk(KERN_INFO "btrfs: resizer unable to find device %llu\n",
+               btrfs_info(root->fs_info, "resizer unable to find device %llu",
                       devid);
                ret = -ENODEV;
                goto out_free;
        }
 
        if (!device->writeable) {
-               printk(KERN_INFO "btrfs: resizer unable to apply on "
-                      "readonly device %llu\n",
+               btrfs_info(root->fs_info,
+                          "resizer unable to apply on readonly device %llu",
                       devid);
                ret = -EPERM;
                goto out_free;
@@ -1466,6 +1491,10 @@ static noinline int btrfs_ioctl_resize(struct file *file,
                }
                new_size = old_size - new_size;
        } else if (mod > 0) {
+               if (new_size > ULLONG_MAX - old_size) {
+                       ret = -EINVAL;
+                       goto out_free;
+               }
                new_size = old_size + new_size;
        }
 
@@ -1481,7 +1510,7 @@ static noinline int btrfs_ioctl_resize(struct file *file,
        do_div(new_size, root->sectorsize);
        new_size *= root->sectorsize;
 
-       printk_in_rcu(KERN_INFO "btrfs: new size for %s is %llu\n",
+       printk_in_rcu(KERN_INFO "BTRFS: new size for %s is %llu\n",
                      rcu_str_deref(device->name), new_size);
 
        if (new_size > old_size) {
@@ -1542,9 +1571,15 @@ static noinline int btrfs_ioctl_snap_create_transid(struct file *file,
 
                src_inode = file_inode(src.file);
                if (src_inode->i_sb != file_inode(file)->i_sb) {
-                       printk(KERN_INFO "btrfs: Snapshot src from "
-                              "another FS\n");
+                       btrfs_info(BTRFS_I(src_inode)->root->fs_info,
+                                  "Snapshot src from another FS");
                        ret = -EINVAL;
+               } else if (!inode_owner_or_capable(src_inode)) {
+                       /*
+                        * Subvolume creation is not restricted, but snapshots
+                        * are limited to own subvolumes only
+                        */
+                       ret = -EPERM;
                } else {
                        ret = btrfs_mksubvol(&file->f_path, name, namelen,
                                             BTRFS_I(src_inode)->root,
@@ -1662,6 +1697,9 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
        u64 flags;
        int ret = 0;
 
+       if (!inode_owner_or_capable(inode))
+               return -EPERM;
+
        ret = mnt_want_write_file(file);
        if (ret)
                goto out;
@@ -1686,11 +1724,6 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
                goto out_drop_write;
        }
 
-       if (!inode_owner_or_capable(inode)) {
-               ret = -EACCES;
-               goto out_drop_write;
-       }
-
        down_write(&root->fs_info->subvol_sem);
 
        /* nothing to do */
@@ -1698,12 +1731,28 @@ static noinline int btrfs_ioctl_subvol_setflags(struct file *file,
                goto out_drop_sem;
 
        root_flags = btrfs_root_flags(&root->root_item);
-       if (flags & BTRFS_SUBVOL_RDONLY)
+       if (flags & BTRFS_SUBVOL_RDONLY) {
                btrfs_set_root_flags(&root->root_item,
                                     root_flags | BTRFS_ROOT_SUBVOL_RDONLY);
-       else
-               btrfs_set_root_flags(&root->root_item,
+       } else {
+               /*
+                * Block RO -> RW transition if this subvolume is involved in
+                * send
+                */
+               spin_lock(&root->root_item_lock);
+               if (root->send_in_progress == 0) {
+                       btrfs_set_root_flags(&root->root_item,
                                     root_flags & ~BTRFS_ROOT_SUBVOL_RDONLY);
+                       spin_unlock(&root->root_item_lock);
+               } else {
+                       spin_unlock(&root->root_item_lock);
+                       btrfs_warn(root->fs_info,
+                       "Attempt to set subvolume %llu read-write during send",
+                                       root->root_key.objectid);
+                       ret = -EPERM;
+                       goto out_drop_sem;
+               }
+       }
 
        trans = btrfs_start_transaction(root, 1);
        if (IS_ERR(trans)) {
@@ -1910,7 +1959,7 @@ static noinline int search_ioctl(struct inode *inode,
                key.offset = (u64)-1;
                root = btrfs_read_fs_root_no_name(info, &key);
                if (IS_ERR(root)) {
-                       printk(KERN_ERR "could not find root %llu\n",
+                       printk(KERN_ERR "BTRFS: could not find root %llu\n",
                               sk->tree_id);
                        btrfs_free_path(path);
                        return -ENOENT;
@@ -2000,7 +2049,7 @@ static noinline int btrfs_search_path_in_tree(struct btrfs_fs_info *info,
        key.offset = (u64)-1;
        root = btrfs_read_fs_root_no_name(info, &key);
        if (IS_ERR(root)) {
-               printk(KERN_ERR "could not find root %llu\n", tree_id);
+               printk(KERN_ERR "BTRFS: could not find root %llu\n", tree_id);
                ret = -ENOENT;
                goto out;
        }
@@ -2686,14 +2735,11 @@ out_unlock:
 #define BTRFS_MAX_DEDUPE_LEN   (16 * 1024 * 1024)
 
 static long btrfs_ioctl_file_extent_same(struct file *file,
-                                        void __user *argp)
+                       struct btrfs_ioctl_same_args __user *argp)
 {
-       struct btrfs_ioctl_same_args tmp;
        struct btrfs_ioctl_same_args *same;
        struct btrfs_ioctl_same_extent_info *info;
-       struct inode *src = file->f_dentry->d_inode;
-       struct file *dst_file = NULL;
-       struct inode *dst;
+       struct inode *src = file_inode(file);
        u64 off;
        u64 len;
        int i;
@@ -2701,6 +2747,7 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
        unsigned long size;
        u64 bs = BTRFS_I(src)->root->fs_info->sb->s_blocksize;
        bool is_admin = capable(CAP_SYS_ADMIN);
+       u16 count;
 
        if (!(file->f_mode & FMODE_READ))
                return -EINVAL;
@@ -2709,17 +2756,14 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
        if (ret)
                return ret;
 
-       if (copy_from_user(&tmp,
-                          (struct btrfs_ioctl_same_args __user *)argp,
-                          sizeof(tmp))) {
+       if (get_user(count, &argp->dest_count)) {
                ret = -EFAULT;
                goto out;
        }
 
-       size = sizeof(tmp) +
-               tmp.dest_count * sizeof(struct btrfs_ioctl_same_extent_info);
+       size = offsetof(struct btrfs_ioctl_same_args __user, info[count]);
 
-       same = memdup_user((struct btrfs_ioctl_same_args __user *)argp, size);
+       same = memdup_user(argp, size);
 
        if (IS_ERR(same)) {
                ret = PTR_ERR(same);
@@ -2756,52 +2800,35 @@ static long btrfs_ioctl_file_extent_same(struct file *file,
                goto out;
 
        /* pre-format output fields to sane values */
-       for (i = 0; i < same->dest_count; i++) {
+       for (i = 0; i < count; i++) {
                same->info[i].bytes_deduped = 0ULL;
                same->info[i].status = 0;
        }
 
-       ret = 0;
-       for (i = 0; i < same->dest_count; i++) {
-               info = &same->info[i];
-
-               dst_file = fget(info->fd);
-               if (!dst_file) {
+       for (i = 0, info = same->info; i < count; i++, info++) {
+               struct inode *dst;
+               struct fd dst_file = fdget(info->fd);
+               if (!dst_file.file) {
                        info->status = -EBADF;
-                       goto next;
+                       continue;
                }
+               dst = file_inode(dst_file.file);
 
-               if (!(is_admin || (dst_file->f_mode & FMODE_WRITE))) {
+               if (!(is_admin || (dst_file.file->f_mode & FMODE_WRITE))) {
                        info->status = -EINVAL;
-                       goto next;
-               }
-
-               info->status = -EXDEV;
-               if (file->f_path.mnt != dst_file->f_path.mnt)
-                       goto next;
-
-               dst = dst_file->f_dentry->d_inode;
-               if (src->i_sb != dst->i_sb)
-                       goto next;
-
-               if (S_ISDIR(dst->i_mode)) {
+               } else if (file->f_path.mnt != dst_file.file->f_path.mnt) {
+                       info->status = -EXDEV;
+               } else if (S_ISDIR(dst->i_mode)) {
                        info->status = -EISDIR;
-                       goto next;
-               }
-
-               if (!S_ISREG(dst->i_mode)) {
+               } else if (!S_ISREG(dst->i_mode)) {
                        info->status = -EACCES;
-                       goto next;
+               } else {
+                       info->status = btrfs_extent_same(src, off, len, dst,
+                                                       info->logical_offset);
+                       if (info->status == 0)
+                               info->bytes_deduped += len;
                }
-
-               info->status = btrfs_extent_same(src, off, len, dst,
-                                               info->logical_offset);
-               if (info->status == 0)
-                       info->bytes_deduped += len;
-
-next:
-               if (dst_file)
-                       fput(dst_file);
+               fdput(dst_file);
        }
 
        ret = copy_to_user(argp, same, size);
@@ -2860,12 +2887,14 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
                 * note the key will change type as we walk through the
                 * tree.
                 */
+               path->leave_spinning = 1;
                ret = btrfs_search_slot(NULL, BTRFS_I(src)->root, &key, path,
                                0, 0);
                if (ret < 0)
                        goto out;
 
                nritems = btrfs_header_nritems(path->nodes[0]);
+process_slot:
                if (path->slots[0] >= nritems) {
                        ret = btrfs_next_leaf(BTRFS_I(src)->root, path);
                        if (ret < 0)
@@ -2892,11 +2921,6 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
                        u8 comp;
                        u64 endoff;
 
-                       size = btrfs_item_size_nr(leaf, slot);
-                       read_extent_buffer(leaf, buf,
-                                          btrfs_item_ptr_offset(leaf, slot),
-                                          size);
-
                        extent = btrfs_item_ptr(leaf, slot,
                                                struct btrfs_file_extent_item);
                        comp = btrfs_file_extent_compression(leaf, extent);
@@ -2915,11 +2939,20 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
                                datal = btrfs_file_extent_ram_bytes(leaf,
                                                                    extent);
                        }
-                       btrfs_release_path(path);
 
                        if (key.offset + datal <= off ||
-                           key.offset >= off + len - 1)
-                               goto next;
+                           key.offset >= off + len - 1) {
+                               path->slots[0]++;
+                               goto process_slot;
+                       }
+
+                       size = btrfs_item_size_nr(leaf, slot);
+                       read_extent_buffer(leaf, buf,
+                                          btrfs_item_ptr_offset(leaf, slot),
+                                          size);
+
+                       btrfs_release_path(path);
+                       path->leave_spinning = 0;
 
                        memcpy(&new_key, &key, sizeof(new_key));
                        new_key.objectid = btrfs_ino(inode);
@@ -3090,7 +3123,6 @@ static int btrfs_clone(struct inode *src, struct inode *inode,
                        }
                        ret = btrfs_end_transaction(trans, root);
                }
-next:
                btrfs_release_path(path);
                key.offset++;
        }
@@ -3218,9 +3250,17 @@ static noinline long btrfs_ioctl_clone(struct file *file, unsigned long srcfd,
 
        unlock_extent(&BTRFS_I(src)->io_tree, off, off + len - 1);
 out_unlock:
-       mutex_unlock(&src->i_mutex);
-       if (!same_inode)
-               mutex_unlock(&inode->i_mutex);
+       if (!same_inode) {
+               if (inode < src) {
+                       mutex_unlock(&src->i_mutex);
+                       mutex_unlock(&inode->i_mutex);
+               } else {
+                       mutex_unlock(&inode->i_mutex);
+                       mutex_unlock(&src->i_mutex);
+               }
+       } else {
+               mutex_unlock(&src->i_mutex);
+       }
 out_fput:
        fdput(src_file);
 out_drop_write:
@@ -3343,8 +3383,8 @@ static long btrfs_ioctl_default_subvol(struct file *file, void __user *argp)
        if (IS_ERR_OR_NULL(di)) {
                btrfs_free_path(path);
                btrfs_end_transaction(trans, root);
-               printk(KERN_ERR "Umm, you don't have the default dir item, "
-                      "this isn't going to work\n");
+               btrfs_err(new_root->fs_info, "Umm, you don't have the default dir"
+                          "item, this isn't going to work");
                ret = -ENOENT;
                goto out;
        }
@@ -3497,6 +3537,20 @@ out:
        return ret;
 }
 
+static long btrfs_ioctl_global_rsv(struct btrfs_root *root, void __user *arg)
+{
+       struct btrfs_block_rsv *block_rsv = &root->fs_info->global_block_rsv;
+       u64 reserved;
+
+       spin_lock(&block_rsv->lock);
+       reserved = block_rsv->reserved;
+       spin_unlock(&block_rsv->lock);
+
+       if (arg && copy_to_user(arg, &reserved, sizeof(reserved)))
+               return -EFAULT;
+       return 0;
+}
+
 /*
  * there are many ways the trans_start and trans_end ioctls can lead
  * to deadlocks.  They should only be used by applications that
@@ -4325,6 +4379,9 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
        int ret = 0;
        int received_uuid_changed;
 
+       if (!inode_owner_or_capable(inode))
+               return -EPERM;
+
        ret = mnt_want_write_file(file);
        if (ret < 0)
                return ret;
@@ -4341,11 +4398,6 @@ static long btrfs_ioctl_set_received_subvol(struct file *file,
                goto out;
        }
 
-       if (!inode_owner_or_capable(inode)) {
-               ret = -EACCES;
-               goto out;
-       }
-
        sa = memdup_user(arg, sizeof(*sa));
        if (IS_ERR(sa)) {
                ret = PTR_ERR(sa);
@@ -4431,8 +4483,8 @@ static int btrfs_ioctl_get_fslabel(struct file *file, void __user *arg)
        len = strnlen(label, BTRFS_LABEL_SIZE);
 
        if (len == BTRFS_LABEL_SIZE) {
-               pr_warn("btrfs: label is too long, return the first %zu bytes\n",
-                       --len);
+               btrfs_warn(root->fs_info,
+                       "label is too long, return the first %zu bytes", --len);
        }
 
        ret = copy_to_user(arg, label, len);
@@ -4455,7 +4507,7 @@ static int btrfs_ioctl_set_fslabel(struct file *file, void __user *arg)
                return -EFAULT;
 
        if (strnlen(label, BTRFS_LABEL_SIZE) == BTRFS_LABEL_SIZE) {
-               pr_err("btrfs: unable to set label with more than %d bytes\n",
+               btrfs_err(root->fs_info, "unable to set label with more than %d bytes",
                       BTRFS_LABEL_SIZE - 1);
                return -EINVAL;
        }
@@ -4480,6 +4532,166 @@ out_unlock:
        return ret;
 }
 
+#define INIT_FEATURE_FLAGS(suffix) \
+       { .compat_flags = BTRFS_FEATURE_COMPAT_##suffix, \
+         .compat_ro_flags = BTRFS_FEATURE_COMPAT_RO_##suffix, \
+         .incompat_flags = BTRFS_FEATURE_INCOMPAT_##suffix }
+
+static int btrfs_ioctl_get_supported_features(struct file *file,
+                                             void __user *arg)
+{
+       static struct btrfs_ioctl_feature_flags features[3] = {
+               INIT_FEATURE_FLAGS(SUPP),
+               INIT_FEATURE_FLAGS(SAFE_SET),
+               INIT_FEATURE_FLAGS(SAFE_CLEAR)
+       };
+
+       if (copy_to_user(arg, &features, sizeof(features)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int btrfs_ioctl_get_features(struct file *file, void __user *arg)
+{
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
+       struct btrfs_super_block *super_block = root->fs_info->super_copy;
+       struct btrfs_ioctl_feature_flags features;
+
+       features.compat_flags = btrfs_super_compat_flags(super_block);
+       features.compat_ro_flags = btrfs_super_compat_ro_flags(super_block);
+       features.incompat_flags = btrfs_super_incompat_flags(super_block);
+
+       if (copy_to_user(arg, &features, sizeof(features)))
+               return -EFAULT;
+
+       return 0;
+}
+
+static int check_feature_bits(struct btrfs_root *root,
+                             enum btrfs_feature_set set,
+                             u64 change_mask, u64 flags, u64 supported_flags,
+                             u64 safe_set, u64 safe_clear)
+{
+       const char *type = btrfs_feature_set_names[set];
+       char *names;
+       u64 disallowed, unsupported;
+       u64 set_mask = flags & change_mask;
+       u64 clear_mask = ~flags & change_mask;
+
+       unsupported = set_mask & ~supported_flags;
+       if (unsupported) {
+               names = btrfs_printable_features(set, unsupported);
+               if (names) {
+                       btrfs_warn(root->fs_info,
+                          "this kernel does not support the %s feature bit%s",
+                          names, strchr(names, ',') ? "s" : "");
+                       kfree(names);
+               } else
+                       btrfs_warn(root->fs_info,
+                          "this kernel does not support %s bits 0x%llx",
+                          type, unsupported);
+               return -EOPNOTSUPP;
+       }
+
+       disallowed = set_mask & ~safe_set;
+       if (disallowed) {
+               names = btrfs_printable_features(set, disallowed);
+               if (names) {
+                       btrfs_warn(root->fs_info,
+                          "can't set the %s feature bit%s while mounted",
+                          names, strchr(names, ',') ? "s" : "");
+                       kfree(names);
+               } else
+                       btrfs_warn(root->fs_info,
+                          "can't set %s bits 0x%llx while mounted",
+                          type, disallowed);
+               return -EPERM;
+       }
+
+       disallowed = clear_mask & ~safe_clear;
+       if (disallowed) {
+               names = btrfs_printable_features(set, disallowed);
+               if (names) {
+                       btrfs_warn(root->fs_info,
+                          "can't clear the %s feature bit%s while mounted",
+                          names, strchr(names, ',') ? "s" : "");
+                       kfree(names);
+               } else
+                       btrfs_warn(root->fs_info,
+                          "can't clear %s bits 0x%llx while mounted",
+                          type, disallowed);
+               return -EPERM;
+       }
+
+       return 0;
+}
+
+#define check_feature(root, change_mask, flags, mask_base)     \
+check_feature_bits(root, FEAT_##mask_base, change_mask, flags, \
+                  BTRFS_FEATURE_ ## mask_base ## _SUPP,        \
+                  BTRFS_FEATURE_ ## mask_base ## _SAFE_SET,    \
+                  BTRFS_FEATURE_ ## mask_base ## _SAFE_CLEAR)
+
+static int btrfs_ioctl_set_features(struct file *file, void __user *arg)
+{
+       struct btrfs_root *root = BTRFS_I(file_inode(file))->root;
+       struct btrfs_super_block *super_block = root->fs_info->super_copy;
+       struct btrfs_ioctl_feature_flags flags[2];
+       struct btrfs_trans_handle *trans;
+       u64 newflags;
+       int ret;
+
+       if (!capable(CAP_SYS_ADMIN))
+               return -EPERM;
+
+       if (copy_from_user(flags, arg, sizeof(flags)))
+               return -EFAULT;
+
+       /* Nothing to do */
+       if (!flags[0].compat_flags && !flags[0].compat_ro_flags &&
+           !flags[0].incompat_flags)
+               return 0;
+
+       ret = check_feature(root, flags[0].compat_flags,
+                           flags[1].compat_flags, COMPAT);
+       if (ret)
+               return ret;
+
+       ret = check_feature(root, flags[0].compat_ro_flags,
+                           flags[1].compat_ro_flags, COMPAT_RO);
+       if (ret)
+               return ret;
+
+       ret = check_feature(root, flags[0].incompat_flags,
+                           flags[1].incompat_flags, INCOMPAT);
+       if (ret)
+               return ret;
+
+       trans = btrfs_start_transaction(root, 1);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+
+       spin_lock(&root->fs_info->super_lock);
+       newflags = btrfs_super_compat_flags(super_block);
+       newflags |= flags[0].compat_flags & flags[1].compat_flags;
+       newflags &= ~(flags[0].compat_flags & ~flags[1].compat_flags);
+       btrfs_set_super_compat_flags(super_block, newflags);
+
+       newflags = btrfs_super_compat_ro_flags(super_block);
+       newflags |= flags[0].compat_ro_flags & flags[1].compat_ro_flags;
+       newflags &= ~(flags[0].compat_ro_flags & ~flags[1].compat_ro_flags);
+       btrfs_set_super_compat_ro_flags(super_block, newflags);
+
+       newflags = btrfs_super_incompat_flags(super_block);
+       newflags |= flags[0].incompat_flags & flags[1].incompat_flags;
+       newflags &= ~(flags[0].incompat_flags & ~flags[1].incompat_flags);
+       btrfs_set_super_incompat_flags(super_block, newflags);
+       spin_unlock(&root->fs_info->super_lock);
+
+       return btrfs_end_transaction(trans, root);
+}
+
 long btrfs_ioctl(struct file *file, unsigned int
                cmd, unsigned long arg)
 {
@@ -4545,6 +4757,8 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_logical_to_ino(root, argp);
        case BTRFS_IOC_SPACE_INFO:
                return btrfs_ioctl_space_info(root, argp);
+       case BTRFS_IOC_GLOBAL_RSV:
+               return btrfs_ioctl_global_rsv(root, argp);
        case BTRFS_IOC_SYNC: {
                int ret;
 
@@ -4598,6 +4812,12 @@ long btrfs_ioctl(struct file *file, unsigned int
                return btrfs_ioctl_set_fslabel(file, argp);
        case BTRFS_IOC_FILE_EXTENT_SAME:
                return btrfs_ioctl_file_extent_same(file, argp);
+       case BTRFS_IOC_GET_SUPPORTED_FEATURES:
+               return btrfs_ioctl_get_supported_features(file, argp);
+       case BTRFS_IOC_GET_FEATURES:
+               return btrfs_ioctl_get_features(file, argp);
+       case BTRFS_IOC_SET_FEATURES:
+               return btrfs_ioctl_set_features(file, argp);
        }
 
        return -ENOTTY;
index b6a6f07c5ce20fe4cecf6917497a6e705be26c9c..b47f669aca758e8ed0f4d3911dfacaa12b3c941f 100644 (file)
@@ -141,7 +141,7 @@ static int lzo_compress_pages(struct list_head *ws,
                ret = lzo1x_1_compress(data_in, in_len, workspace->cbuf,
                                       &out_len, workspace->mem);
                if (ret != LZO_E_OK) {
-                       printk(KERN_DEBUG "btrfs deflate in loop returned %d\n",
+                       printk(KERN_DEBUG "BTRFS: deflate in loop returned %d\n",
                               ret);
                        ret = -1;
                        goto out;
@@ -357,7 +357,7 @@ cont:
                if (need_unmap)
                        kunmap(pages_in[page_in_index - 1]);
                if (ret != LZO_E_OK) {
-                       printk(KERN_WARNING "btrfs decompress failed\n");
+                       printk(KERN_WARNING "BTRFS: decompress failed\n");
                        ret = -1;
                        break;
                }
@@ -401,7 +401,7 @@ static int lzo_decompress(struct list_head *ws, unsigned char *data_in,
        out_len = PAGE_CACHE_SIZE;
        ret = lzo1x_decompress_safe(data_in, in_len, workspace->buf, &out_len);
        if (ret != LZO_E_OK) {
-               printk(KERN_WARNING "btrfs decompress failed!\n");
+               printk(KERN_WARNING "BTRFS: decompress failed!\n");
                ret = -1;
                goto out;
        }
index 69582d5b69d1f6064a77a409760a3ba1886b6d92..b16450b840e73be00d42e217e0fcecb2fae1894d 100644 (file)
@@ -336,13 +336,14 @@ int btrfs_dec_test_first_ordered_pending(struct inode *inode,
                      entry->len);
        *file_offset = dec_end;
        if (dec_start > dec_end) {
-               printk(KERN_CRIT "bad ordering dec_start %llu end %llu\n",
-                      dec_start, dec_end);
+               btrfs_crit(BTRFS_I(inode)->root->fs_info,
+                       "bad ordering dec_start %llu end %llu", dec_start, dec_end);
        }
        to_dec = dec_end - dec_start;
        if (to_dec > entry->bytes_left) {
-               printk(KERN_CRIT "bad ordered accounting left %llu size %llu\n",
-                      entry->bytes_left, to_dec);
+               btrfs_crit(BTRFS_I(inode)->root->fs_info,
+                       "bad ordered accounting left %llu size %llu",
+                       entry->bytes_left, to_dec);
        }
        entry->bytes_left -= to_dec;
        if (!uptodate)
@@ -401,7 +402,8 @@ have_entry:
        }
 
        if (io_size > entry->bytes_left) {
-               printk(KERN_CRIT "bad ordered accounting left %llu size %llu\n",
+               btrfs_crit(BTRFS_I(inode)->root->fs_info,
+                          "bad ordered accounting left %llu size %llu",
                       entry->bytes_left, io_size);
        }
        entry->bytes_left -= io_size;
@@ -520,7 +522,8 @@ void btrfs_remove_ordered_extent(struct inode *inode,
        spin_lock_irq(&tree->lock);
        node = &entry->rb_node;
        rb_erase(node, &tree->tree);
-       tree->last = NULL;
+       if (tree->last == node)
+               tree->last = NULL;
        set_bit(BTRFS_ORDERED_COMPLETE, &entry->flags);
        spin_unlock_irq(&tree->lock);
 
index 24cad1695af74790ecc18182db35a0ed5c8cce7a..65793edb38ca881a3f82f49101bc4b079574ed4c 100644 (file)
@@ -69,23 +69,3 @@ out:
        btrfs_free_path(path);
        return ret;
 }
-
-int btrfs_find_orphan_item(struct btrfs_root *root, u64 offset)
-{
-       struct btrfs_path *path;
-       struct btrfs_key key;
-       int ret;
-
-       key.objectid = BTRFS_ORPHAN_OBJECTID;
-       key.type = BTRFS_ORPHAN_ITEM_KEY;
-       key.offset = offset;
-
-       path = btrfs_alloc_path();
-       if (!path)
-               return -ENOMEM;
-
-       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
-
-       btrfs_free_path(path);
-       return ret;
-}
index 417053b171817742e64e53e579d1daf8c1a9b7cc..6efd70d3b64f785e23d0bb3323d4905825406c62 100644 (file)
@@ -154,7 +154,7 @@ static void print_uuid_item(struct extent_buffer *l, unsigned long offset,
                            u32 item_size)
 {
        if (!IS_ALIGNED(item_size, sizeof(u64))) {
-               pr_warn("btrfs: uuid item with illegal size %lu!\n",
+               pr_warn("BTRFS: uuid item with illegal size %lu!\n",
                        (unsigned long)item_size);
                return;
        }
@@ -249,7 +249,7 @@ void btrfs_print_leaf(struct btrfs_root *root, struct extent_buffer *l)
                            BTRFS_FILE_EXTENT_INLINE) {
                                printk(KERN_INFO "\t\tinline extent data "
                                       "size %u\n",
-                                      btrfs_file_extent_inline_len(l, fi));
+                                      btrfs_file_extent_inline_len(l, i, fi));
                                break;
                        }
                        printk(KERN_INFO "\t\textent data disk bytenr %llu "
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
new file mode 100644 (file)
index 0000000..129b1dd
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * Copyright (C) 2014 Filipe David Borba Manana <fdmanana@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/hashtable.h>
+#include "props.h"
+#include "btrfs_inode.h"
+#include "hash.h"
+#include "transaction.h"
+#include "xattr.h"
+
+#define BTRFS_PROP_HANDLERS_HT_BITS 8
+static DEFINE_HASHTABLE(prop_handlers_ht, BTRFS_PROP_HANDLERS_HT_BITS);
+
+struct prop_handler {
+       struct hlist_node node;
+       const char *xattr_name;
+       int (*validate)(const char *value, size_t len);
+       int (*apply)(struct inode *inode, const char *value, size_t len);
+       const char *(*extract)(struct inode *inode);
+       int inheritable;
+};
+
+static int prop_compression_validate(const char *value, size_t len);
+static int prop_compression_apply(struct inode *inode,
+                                 const char *value,
+                                 size_t len);
+static const char *prop_compression_extract(struct inode *inode);
+
+static struct prop_handler prop_handlers[] = {
+       {
+               .xattr_name = XATTR_BTRFS_PREFIX "compression",
+               .validate = prop_compression_validate,
+               .apply = prop_compression_apply,
+               .extract = prop_compression_extract,
+               .inheritable = 1
+       },
+       {
+               .xattr_name = NULL
+       }
+};
+
+void __init btrfs_props_init(void)
+{
+       struct prop_handler *p;
+
+       hash_init(prop_handlers_ht);
+
+       for (p = &prop_handlers[0]; p->xattr_name; p++) {
+               u64 h = btrfs_name_hash(p->xattr_name, strlen(p->xattr_name));
+
+               hash_add(prop_handlers_ht, &p->node, h);
+       }
+}
+
+static const struct hlist_head *find_prop_handlers_by_hash(const u64 hash)
+{
+       struct hlist_head *h;
+
+       h = &prop_handlers_ht[hash_min(hash, BTRFS_PROP_HANDLERS_HT_BITS)];
+       if (hlist_empty(h))
+               return NULL;
+
+       return h;
+}
+
+static const struct prop_handler *
+find_prop_handler(const char *name,
+                 const struct hlist_head *handlers)
+{
+       struct prop_handler *h;
+
+       if (!handlers) {
+               u64 hash = btrfs_name_hash(name, strlen(name));
+
+               handlers = find_prop_handlers_by_hash(hash);
+               if (!handlers)
+                       return NULL;
+       }
+
+       hlist_for_each_entry(h, handlers, node)
+               if (!strcmp(h->xattr_name, name))
+                       return h;
+
+       return NULL;
+}
+
+static int __btrfs_set_prop(struct btrfs_trans_handle *trans,
+                           struct inode *inode,
+                           const char *name,
+                           const char *value,
+                           size_t value_len,
+                           int flags)
+{
+       const struct prop_handler *handler;
+       int ret;
+
+       if (strlen(name) <= XATTR_BTRFS_PREFIX_LEN)
+               return -EINVAL;
+
+       handler = find_prop_handler(name, NULL);
+       if (!handler)
+               return -EINVAL;
+
+       if (value_len == 0) {
+               ret = __btrfs_setxattr(trans, inode, handler->xattr_name,
+                                      NULL, 0, flags);
+               if (ret)
+                       return ret;
+
+               ret = handler->apply(inode, NULL, 0);
+               ASSERT(ret == 0);
+
+               return ret;
+       }
+
+       ret = handler->validate(value, value_len);
+       if (ret)
+               return ret;
+       ret = __btrfs_setxattr(trans, inode, handler->xattr_name,
+                              value, value_len, flags);
+       if (ret)
+               return ret;
+       ret = handler->apply(inode, value, value_len);
+       if (ret) {
+               __btrfs_setxattr(trans, inode, handler->xattr_name,
+                                NULL, 0, flags);
+               return ret;
+       }
+
+       set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
+
+       return 0;
+}
+
+int btrfs_set_prop(struct inode *inode,
+                  const char *name,
+                  const char *value,
+                  size_t value_len,
+                  int flags)
+{
+       return __btrfs_set_prop(NULL, inode, name, value, value_len, flags);
+}
+
+static int iterate_object_props(struct btrfs_root *root,
+                               struct btrfs_path *path,
+                               u64 objectid,
+                               void (*iterator)(void *,
+                                                const struct prop_handler *,
+                                                const char *,
+                                                size_t),
+                               void *ctx)
+{
+       int ret;
+       char *name_buf = NULL;
+       char *value_buf = NULL;
+       int name_buf_len = 0;
+       int value_buf_len = 0;
+
+       while (1) {
+               struct btrfs_key key;
+               struct btrfs_dir_item *di;
+               struct extent_buffer *leaf;
+               u32 total_len, cur, this_len;
+               int slot;
+               const struct hlist_head *handlers;
+
+               slot = path->slots[0];
+               leaf = path->nodes[0];
+
+               if (slot >= btrfs_header_nritems(leaf)) {
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret < 0)
+                               goto out;
+                       else if (ret > 0)
+                               break;
+                       continue;
+               }
+
+               btrfs_item_key_to_cpu(leaf, &key, slot);
+               if (key.objectid != objectid)
+                       break;
+               if (key.type != BTRFS_XATTR_ITEM_KEY)
+                       break;
+
+               handlers = find_prop_handlers_by_hash(key.offset);
+               if (!handlers)
+                       goto next_slot;
+
+               di = btrfs_item_ptr(leaf, slot, struct btrfs_dir_item);
+               cur = 0;
+               total_len = btrfs_item_size_nr(leaf, slot);
+
+               while (cur < total_len) {
+                       u32 name_len = btrfs_dir_name_len(leaf, di);
+                       u32 data_len = btrfs_dir_data_len(leaf, di);
+                       unsigned long name_ptr, data_ptr;
+                       const struct prop_handler *handler;
+
+                       this_len = sizeof(*di) + name_len + data_len;
+                       name_ptr = (unsigned long)(di + 1);
+                       data_ptr = name_ptr + name_len;
+
+                       if (name_len <= XATTR_BTRFS_PREFIX_LEN ||
+                           memcmp_extent_buffer(leaf, XATTR_BTRFS_PREFIX,
+                                                name_ptr,
+                                                XATTR_BTRFS_PREFIX_LEN))
+                               goto next_dir_item;
+
+                       if (name_len >= name_buf_len) {
+                               kfree(name_buf);
+                               name_buf_len = name_len + 1;
+                               name_buf = kmalloc(name_buf_len, GFP_NOFS);
+                               if (!name_buf) {
+                                       ret = -ENOMEM;
+                                       goto out;
+                               }
+                       }
+                       read_extent_buffer(leaf, name_buf, name_ptr, name_len);
+                       name_buf[name_len] = '\0';
+
+                       handler = find_prop_handler(name_buf, handlers);
+                       if (!handler)
+                               goto next_dir_item;
+
+                       if (data_len > value_buf_len) {
+                               kfree(value_buf);
+                               value_buf_len = data_len;
+                               value_buf = kmalloc(data_len, GFP_NOFS);
+                               if (!value_buf) {
+                                       ret = -ENOMEM;
+                                       goto out;
+                               }
+                       }
+                       read_extent_buffer(leaf, value_buf, data_ptr, data_len);
+
+                       iterator(ctx, handler, value_buf, data_len);
+next_dir_item:
+                       cur += this_len;
+                       di = (struct btrfs_dir_item *)((char *) di + this_len);
+               }
+
+next_slot:
+               path->slots[0]++;
+       }
+
+       ret = 0;
+out:
+       btrfs_release_path(path);
+       kfree(name_buf);
+       kfree(value_buf);
+
+       return ret;
+}
+
+static void inode_prop_iterator(void *ctx,
+                               const struct prop_handler *handler,
+                               const char *value,
+                               size_t len)
+{
+       struct inode *inode = ctx;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int ret;
+
+       ret = handler->apply(inode, value, len);
+       if (unlikely(ret))
+               btrfs_warn(root->fs_info,
+                          "error applying prop %s to ino %llu (root %llu): %d",
+                          handler->xattr_name, btrfs_ino(inode),
+                          root->root_key.objectid, ret);
+       else
+               set_bit(BTRFS_INODE_HAS_PROPS, &BTRFS_I(inode)->runtime_flags);
+}
+
+int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path)
+{
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       u64 ino = btrfs_ino(inode);
+       int ret;
+
+       ret = iterate_object_props(root, path, ino, inode_prop_iterator, inode);
+
+       return ret;
+}
+
+static int inherit_props(struct btrfs_trans_handle *trans,
+                        struct inode *inode,
+                        struct inode *parent)
+{
+       const struct prop_handler *h;
+       struct btrfs_root *root = BTRFS_I(inode)->root;
+       int ret;
+
+       if (!test_bit(BTRFS_INODE_HAS_PROPS,
+                     &BTRFS_I(parent)->runtime_flags))
+               return 0;
+
+       for (h = &prop_handlers[0]; h->xattr_name; h++) {
+               const char *value;
+               u64 num_bytes;
+
+               if (!h->inheritable)
+                       continue;
+
+               value = h->extract(parent);
+               if (!value)
+                       continue;
+
+               num_bytes = btrfs_calc_trans_metadata_size(root, 1);
+               ret = btrfs_block_rsv_add(root, trans->block_rsv,
+                                         num_bytes, BTRFS_RESERVE_NO_FLUSH);
+               if (ret)
+                       goto out;
+               ret = __btrfs_set_prop(trans, inode, h->xattr_name,
+                                      value, strlen(value), 0);
+               btrfs_block_rsv_release(root, trans->block_rsv, num_bytes);
+               if (ret)
+                       goto out;
+       }
+       ret = 0;
+out:
+       return ret;
+}
+
+int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
+                             struct inode *inode,
+                             struct inode *dir)
+{
+       if (!dir)
+               return 0;
+
+       return inherit_props(trans, inode, dir);
+}
+
+int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root,
+                              struct btrfs_root *parent_root)
+{
+       struct btrfs_key key;
+       struct inode *parent_inode, *child_inode;
+       int ret;
+
+       key.objectid = BTRFS_FIRST_FREE_OBJECTID;
+       key.type = BTRFS_INODE_ITEM_KEY;
+       key.offset = 0;
+
+       parent_inode = btrfs_iget(parent_root->fs_info->sb, &key,
+                                 parent_root, NULL);
+       if (IS_ERR(parent_inode))
+               return PTR_ERR(parent_inode);
+
+       child_inode = btrfs_iget(root->fs_info->sb, &key, root, NULL);
+       if (IS_ERR(child_inode)) {
+               iput(parent_inode);
+               return PTR_ERR(child_inode);
+       }
+
+       ret = inherit_props(trans, child_inode, parent_inode);
+       iput(child_inode);
+       iput(parent_inode);
+
+       return ret;
+}
+
+static int prop_compression_validate(const char *value, size_t len)
+{
+       if (!strncmp("lzo", value, len))
+               return 0;
+       else if (!strncmp("zlib", value, len))
+               return 0;
+
+       return -EINVAL;
+}
+
+static int prop_compression_apply(struct inode *inode,
+                                 const char *value,
+                                 size_t len)
+{
+       int type;
+
+       if (len == 0) {
+               BTRFS_I(inode)->flags |= BTRFS_INODE_NOCOMPRESS;
+               BTRFS_I(inode)->flags &= ~BTRFS_INODE_COMPRESS;
+               BTRFS_I(inode)->force_compress = BTRFS_COMPRESS_NONE;
+
+               return 0;
+       }
+
+       if (!strncmp("lzo", value, len))
+               type = BTRFS_COMPRESS_LZO;
+       else if (!strncmp("zlib", value, len))
+               type = BTRFS_COMPRESS_ZLIB;
+       else
+               return -EINVAL;
+
+       BTRFS_I(inode)->flags &= ~BTRFS_INODE_NOCOMPRESS;
+       BTRFS_I(inode)->flags |= BTRFS_INODE_COMPRESS;
+       BTRFS_I(inode)->force_compress = type;
+
+       return 0;
+}
+
+static const char *prop_compression_extract(struct inode *inode)
+{
+       switch (BTRFS_I(inode)->force_compress) {
+       case BTRFS_COMPRESS_ZLIB:
+               return "zlib";
+       case BTRFS_COMPRESS_LZO:
+               return "lzo";
+       }
+
+       return NULL;
+}
diff --git a/fs/btrfs/props.h b/fs/btrfs/props.h
new file mode 100644 (file)
index 0000000..100f188
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2014 Filipe David Borba Manana <fdmanana@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#ifndef __BTRFS_PROPS_H
+#define __BTRFS_PROPS_H
+
+#include "ctree.h"
+
+void __init btrfs_props_init(void);
+
+int btrfs_set_prop(struct inode *inode,
+                  const char *name,
+                  const char *value,
+                  size_t value_len,
+                  int flags);
+
+int btrfs_load_inode_props(struct inode *inode, struct btrfs_path *path);
+
+int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
+                             struct inode *inode,
+                             struct inode *dir);
+
+int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
+                              struct btrfs_root *root,
+                              struct btrfs_root *parent_root);
+
+#endif
index 4e6ef490619e59b90fb64bf2cca251d6f11eae80..472302a2d745646a2d3a051da57fb95f2865cd0f 100644 (file)
@@ -301,16 +301,16 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
 
                        if (btrfs_qgroup_status_version(l, ptr) !=
                            BTRFS_QGROUP_STATUS_VERSION) {
-                               printk(KERN_ERR
-                                "btrfs: old qgroup version, quota disabled\n");
+                               btrfs_err(fs_info,
+                                "old qgroup version, quota disabled");
                                goto out;
                        }
                        if (btrfs_qgroup_status_generation(l, ptr) !=
                            fs_info->generation) {
                                flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
-                               printk(KERN_ERR
-                                       "btrfs: qgroup generation mismatch, "
-                                       "marked as inconsistent\n");
+                               btrfs_err(fs_info,
+                                       "qgroup generation mismatch, "
+                                       "marked as inconsistent");
                        }
                        fs_info->qgroup_flags = btrfs_qgroup_status_flags(l,
                                                                          ptr);
@@ -325,7 +325,7 @@ int btrfs_read_qgroup_config(struct btrfs_fs_info *fs_info)
                qgroup = find_qgroup_rb(fs_info, found_key.offset);
                if ((qgroup && found_key.type == BTRFS_QGROUP_INFO_KEY) ||
                    (!qgroup && found_key.type == BTRFS_QGROUP_LIMIT_KEY)) {
-                       printk(KERN_ERR "btrfs: inconsitent qgroup config\n");
+                       btrfs_err(fs_info, "inconsitent qgroup config");
                        flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
                }
                if (!qgroup) {
@@ -396,8 +396,8 @@ next1:
                ret = add_relation_rb(fs_info, found_key.objectid,
                                      found_key.offset);
                if (ret == -ENOENT) {
-                       printk(KERN_WARNING
-                               "btrfs: orphan qgroup relation 0x%llx->0x%llx\n",
+                       btrfs_warn(fs_info,
+                               "orphan qgroup relation 0x%llx->0x%llx",
                                found_key.objectid, found_key.offset);
                        ret = 0;        /* ignore the error */
                }
@@ -644,8 +644,7 @@ static int update_qgroup_limit_item(struct btrfs_trans_handle *trans,
 
        l = path->nodes[0];
        slot = path->slots[0];
-       qgroup_limit = btrfs_item_ptr(l, path->slots[0],
-                                     struct btrfs_qgroup_limit_item);
+       qgroup_limit = btrfs_item_ptr(l, slot, struct btrfs_qgroup_limit_item);
        btrfs_set_qgroup_limit_flags(l, qgroup_limit, flags);
        btrfs_set_qgroup_limit_max_rfer(l, qgroup_limit, max_rfer);
        btrfs_set_qgroup_limit_max_excl(l, qgroup_limit, max_excl);
@@ -687,8 +686,7 @@ static int update_qgroup_info_item(struct btrfs_trans_handle *trans,
 
        l = path->nodes[0];
        slot = path->slots[0];
-       qgroup_info = btrfs_item_ptr(l, path->slots[0],
-                                struct btrfs_qgroup_info_item);
+       qgroup_info = btrfs_item_ptr(l, slot, struct btrfs_qgroup_info_item);
        btrfs_set_qgroup_info_generation(l, qgroup_info, trans->transid);
        btrfs_set_qgroup_info_rfer(l, qgroup_info, qgroup->rfer);
        btrfs_set_qgroup_info_rfer_cmpr(l, qgroup_info, qgroup->rfer_cmpr);
@@ -1161,7 +1159,7 @@ int btrfs_limit_qgroup(struct btrfs_trans_handle *trans,
                                       limit->rsv_excl);
        if (ret) {
                fs_info->qgroup_flags |= BTRFS_QGROUP_STATUS_FLAG_INCONSISTENT;
-               printk(KERN_INFO "unable to update quota limit for %llu\n",
+               btrfs_info(fs_info, "unable to update quota limit for %llu",
                       qgroupid);
        }
 
@@ -1349,7 +1347,6 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
                             struct btrfs_delayed_ref_node *node,
                             struct btrfs_delayed_extent_op *extent_op)
 {
-       struct btrfs_key ins;
        struct btrfs_root *quota_root;
        u64 ref_root;
        struct btrfs_qgroup *qgroup;
@@ -1363,10 +1360,6 @@ int btrfs_qgroup_account_ref(struct btrfs_trans_handle *trans,
 
        BUG_ON(!fs_info->quota_root);
 
-       ins.objectid = node->bytenr;
-       ins.offset = node->num_bytes;
-       ins.type = BTRFS_EXTENT_ITEM_KEY;
-
        if (node->type == BTRFS_TREE_BLOCK_REF_KEY ||
            node->type == BTRFS_SHARED_BLOCK_REF_KEY) {
                struct btrfs_delayed_tree_ref *ref;
@@ -1840,7 +1833,9 @@ void assert_qgroups_uptodate(struct btrfs_trans_handle *trans)
 {
        if (list_empty(&trans->qgroup_ref_list) && !trans->delayed_ref_elem.seq)
                return;
-       pr_err("btrfs: qgroups not uptodate in trans handle %p: list is%s empty, seq is %#x.%x\n",
+       btrfs_err(trans->root->fs_info,
+               "qgroups not uptodate in trans handle %p:  list is%s empty, "
+               "seq is %#x.%x",
                trans, list_empty(&trans->qgroup_ref_list) ? "" : " not",
                (u32)(trans->delayed_ref_elem.seq >> 32),
                (u32)trans->delayed_ref_elem.seq);
@@ -1902,9 +1897,17 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
        mutex_unlock(&fs_info->qgroup_rescan_lock);
 
        for (; slot < btrfs_header_nritems(scratch_leaf); ++slot) {
+               u64 num_bytes;
+
                btrfs_item_key_to_cpu(scratch_leaf, &found, slot);
-               if (found.type != BTRFS_EXTENT_ITEM_KEY)
+               if (found.type != BTRFS_EXTENT_ITEM_KEY &&
+                   found.type != BTRFS_METADATA_ITEM_KEY)
                        continue;
+               if (found.type == BTRFS_METADATA_ITEM_KEY)
+                       num_bytes = fs_info->extent_root->leafsize;
+               else
+                       num_bytes = found.offset;
+
                ret = btrfs_find_all_roots(trans, fs_info, found.objectid,
                                           tree_mod_seq_elem.seq, &roots);
                if (ret < 0)
@@ -1949,12 +1952,12 @@ qgroup_rescan_leaf(struct btrfs_fs_info *fs_info, struct btrfs_path *path,
                        struct btrfs_qgroup_list *glist;
 
                        qg = (struct btrfs_qgroup *)(uintptr_t) unode->aux;
-                       qg->rfer += found.offset;
-                       qg->rfer_cmpr += found.offset;
+                       qg->rfer += num_bytes;
+                       qg->rfer_cmpr += num_bytes;
                        WARN_ON(qg->tag >= seq);
                        if (qg->refcnt - seq == roots->nnodes) {
-                               qg->excl += found.offset;
-                               qg->excl_cmpr += found.offset;
+                               qg->excl += num_bytes;
+                               qg->excl_cmpr += num_bytes;
                        }
                        qgroup_dirty(fs_info, qg);
 
@@ -2037,10 +2040,10 @@ out:
        mutex_unlock(&fs_info->qgroup_rescan_lock);
 
        if (err >= 0) {
-               pr_info("btrfs: qgroup scan completed%s\n",
+               btrfs_info(fs_info, "qgroup scan completed%s",
                        err == 2 ? " (inconsistency flag cleared)" : "");
        } else {
-               pr_err("btrfs: qgroup scan failed with %d\n", err);
+               btrfs_err(fs_info, "qgroup scan failed with %d", err);
        }
 
        complete_all(&fs_info->qgroup_rescan_completion);
@@ -2096,7 +2099,7 @@ qgroup_rescan_init(struct btrfs_fs_info *fs_info, u64 progress_objectid,
 
        if (ret) {
 err:
-               pr_info("btrfs: qgroup_rescan_init failed with %d\n", ret);
+               btrfs_info(fs_info, "qgroup_rescan_init failed with %d", ret);
                return ret;
        }
 
index 24ac21840a9a0797cdb086a58e90e64a3c1481ad..9af0b25d991a8c64653b4fa20f4dc31c2794b943 100644 (file)
@@ -1032,8 +1032,8 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio,
 
        /* see if we can add this page onto our existing bio */
        if (last) {
-               last_end = (u64)last->bi_sector << 9;
-               last_end += last->bi_size;
+               last_end = (u64)last->bi_iter.bi_sector << 9;
+               last_end += last->bi_iter.bi_size;
 
                /*
                 * we can't merge these if they are from different
@@ -1053,9 +1053,9 @@ static int rbio_add_io_page(struct btrfs_raid_bio *rbio,
        if (!bio)
                return -ENOMEM;
 
-       bio->bi_size = 0;
+       bio->bi_iter.bi_size = 0;
        bio->bi_bdev = stripe->dev->bdev;
-       bio->bi_sector = disk_start >> 9;
+       bio->bi_iter.bi_sector = disk_start >> 9;
        set_bit(BIO_UPTODATE, &bio->bi_flags);
 
        bio_add_page(bio, page, PAGE_CACHE_SIZE, 0);
@@ -1111,7 +1111,7 @@ static void index_rbio_pages(struct btrfs_raid_bio *rbio)
 
        spin_lock_irq(&rbio->bio_list_lock);
        bio_list_for_each(bio, &rbio->bio_list) {
-               start = (u64)bio->bi_sector << 9;
+               start = (u64)bio->bi_iter.bi_sector << 9;
                stripe_offset = start - rbio->raid_map[0];
                page_index = stripe_offset >> PAGE_CACHE_SHIFT;
 
@@ -1272,7 +1272,7 @@ cleanup:
 static int find_bio_stripe(struct btrfs_raid_bio *rbio,
                           struct bio *bio)
 {
-       u64 physical = bio->bi_sector;
+       u64 physical = bio->bi_iter.bi_sector;
        u64 stripe_start;
        int i;
        struct btrfs_bio_stripe *stripe;
@@ -1298,7 +1298,7 @@ static int find_bio_stripe(struct btrfs_raid_bio *rbio,
 static int find_logical_bio_stripe(struct btrfs_raid_bio *rbio,
                                   struct bio *bio)
 {
-       u64 logical = bio->bi_sector;
+       u64 logical = bio->bi_iter.bi_sector;
        u64 stripe_start;
        int i;
 
@@ -1602,8 +1602,8 @@ static int plug_cmp(void *priv, struct list_head *a, struct list_head *b)
                                                 plug_list);
        struct btrfs_raid_bio *rb = container_of(b, struct btrfs_raid_bio,
                                                 plug_list);
-       u64 a_sector = ra->bio_list.head->bi_sector;
-       u64 b_sector = rb->bio_list.head->bi_sector;
+       u64 a_sector = ra->bio_list.head->bi_iter.bi_sector;
+       u64 b_sector = rb->bio_list.head->bi_iter.bi_sector;
 
        if (a_sector < b_sector)
                return -1;
@@ -1691,7 +1691,7 @@ int raid56_parity_write(struct btrfs_root *root, struct bio *bio,
        if (IS_ERR(rbio))
                return PTR_ERR(rbio);
        bio_list_add(&rbio->bio_list, bio);
-       rbio->bio_list_bytes = bio->bi_size;
+       rbio->bio_list_bytes = bio->bi_iter.bi_size;
 
        /*
         * don't plug on full rbios, just get them out the door
@@ -2044,7 +2044,7 @@ int raid56_parity_recover(struct btrfs_root *root, struct bio *bio,
 
        rbio->read_rebuild = 1;
        bio_list_add(&rbio->bio_list, bio);
-       rbio->bio_list_bytes = bio->bi_size;
+       rbio->bio_list_bytes = bio->bi_iter.bi_size;
 
        rbio->faila = find_logical_bio_stripe(rbio, bio);
        if (rbio->faila == -1) {
index 1031b69252c5a235046e7732d378e14865e54b50..31c797c48c3ecdf9273473a7c0669adf86f5870a 100644 (file)
@@ -189,8 +189,8 @@ static int __readahead_hook(struct btrfs_root *root, struct extent_buffer *eb,
                         */
 #ifdef DEBUG
                        if (rec->generation != generation) {
-                               printk(KERN_DEBUG "generation mismatch for "
-                                               "(%llu,%d,%llu) %llu != %llu\n",
+                               btrfs_debug(root->fs_info,
+                                          "generation mismatch for (%llu,%d,%llu) %llu != %llu",
                                       key.objectid, key.type, key.offset,
                                       rec->generation, generation);
                        }
@@ -365,8 +365,9 @@ static struct reada_extent *reada_find_extent(struct btrfs_root *root,
                goto error;
 
        if (bbio->num_stripes > BTRFS_MAX_MIRRORS) {
-               printk(KERN_ERR "btrfs readahead: more than %d copies not "
-                               "supported", BTRFS_MAX_MIRRORS);
+               btrfs_err(root->fs_info,
+                          "readahead: more than %d copies not supported",
+                          BTRFS_MAX_MIRRORS);
                goto error;
        }
 
index 429c73c374b84f9bcd468067221bf99e0b9f67db..07b3b36f40ee51657b248112a6d1f028cea9e364 100644 (file)
@@ -94,6 +94,7 @@ struct backref_edge {
 
 #define LOWER  0
 #define UPPER  1
+#define RELOCATION_RESERVED_NODES      256
 
 struct backref_cache {
        /* red black tree of all backref nodes in the cache */
@@ -176,6 +177,8 @@ struct reloc_control {
        u64 merging_rsv_size;
        /* size of relocated tree nodes */
        u64 nodes_relocated;
+       /* reserved size for block group relocation*/
+       u64 reserved_bytes;
 
        u64 search_start;
        u64 extents_found;
@@ -184,7 +187,6 @@ struct reloc_control {
        unsigned int create_reloc_tree:1;
        unsigned int merge_reloc_tree:1;
        unsigned int found_file_extent:1;
-       unsigned int commit_transaction:1;
 };
 
 /* stages of data relocation */
@@ -2309,9 +2311,6 @@ void free_reloc_roots(struct list_head *list)
                reloc_root = list_entry(list->next, struct btrfs_root,
                                        root_list);
                __del_reloc_root(reloc_root);
-               free_extent_buffer(reloc_root->node);
-               free_extent_buffer(reloc_root->commit_root);
-               kfree(reloc_root);
        }
 }
 
@@ -2353,10 +2352,9 @@ again:
 
                        ret = merge_reloc_root(rc, root);
                        if (ret) {
-                               __del_reloc_root(reloc_root);
-                               free_extent_buffer(reloc_root->node);
-                               free_extent_buffer(reloc_root->commit_root);
-                               kfree(reloc_root);
+                               if (list_empty(&reloc_root->root_list))
+                                       list_add_tail(&reloc_root->root_list,
+                                                     &reloc_roots);
                                goto out;
                        }
                } else {
@@ -2452,7 +2450,7 @@ static noinline_for_stack
 struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,
                                     struct reloc_control *rc,
                                     struct backref_node *node,
-                                    struct backref_edge *edges[], int *nr)
+                                    struct backref_edge *edges[])
 {
        struct backref_node *next;
        struct btrfs_root *root;
@@ -2494,7 +2492,6 @@ struct btrfs_root *select_reloc_root(struct btrfs_trans_handle *trans,
        if (!root)
                return NULL;
 
-       *nr = index;
        next = node;
        /* setup backref node path for btrfs_reloc_cow_block */
        while (1) {
@@ -2590,28 +2587,36 @@ static int reserve_metadata_space(struct btrfs_trans_handle *trans,
        struct btrfs_root *root = rc->extent_root;
        u64 num_bytes;
        int ret;
+       u64 tmp;
 
        num_bytes = calcu_metadata_size(rc, node, 1) * 2;
 
        trans->block_rsv = rc->block_rsv;
-       ret = btrfs_block_rsv_add(root, rc->block_rsv, num_bytes,
-                                 BTRFS_RESERVE_FLUSH_ALL);
+       rc->reserved_bytes += num_bytes;
+       ret = btrfs_block_rsv_refill(root, rc->block_rsv, num_bytes,
+                               BTRFS_RESERVE_FLUSH_ALL);
        if (ret) {
-               if (ret == -EAGAIN)
-                       rc->commit_transaction = 1;
+               if (ret == -EAGAIN) {
+                       tmp = rc->extent_root->nodesize *
+                               RELOCATION_RESERVED_NODES;
+                       while (tmp <= rc->reserved_bytes)
+                               tmp <<= 1;
+                       /*
+                        * only one thread can access block_rsv at this point,
+                        * so we don't need hold lock to protect block_rsv.
+                        * we expand more reservation size here to allow enough
+                        * space for relocation and we will return eailer in
+                        * enospc case.
+                        */
+                       rc->block_rsv->size = tmp + rc->extent_root->nodesize *
+                                             RELOCATION_RESERVED_NODES;
+               }
                return ret;
        }
 
        return 0;
 }
 
-static void release_metadata_space(struct reloc_control *rc,
-                                  struct backref_node *node)
-{
-       u64 num_bytes = calcu_metadata_size(rc, node, 0) * 2;
-       btrfs_block_rsv_release(rc->extent_root, rc->block_rsv, num_bytes);
-}
-
 /*
  * relocate a block tree, and then update pointers in upper level
  * blocks that reference the block to point to the new location.
@@ -2633,7 +2638,6 @@ static int do_relocation(struct btrfs_trans_handle *trans,
        u32 blocksize;
        u64 bytenr;
        u64 generation;
-       int nr;
        int slot;
        int ret;
        int err = 0;
@@ -2646,7 +2650,7 @@ static int do_relocation(struct btrfs_trans_handle *trans,
                cond_resched();
 
                upper = edge->node[UPPER];
-               root = select_reloc_root(trans, rc, upper, edges, &nr);
+               root = select_reloc_root(trans, rc, upper, edges);
                BUG_ON(!root);
 
                if (upper->eb && !upper->locked) {
@@ -2898,7 +2902,6 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
                                struct btrfs_path *path)
 {
        struct btrfs_root *root;
-       int release = 0;
        int ret = 0;
 
        if (!node)
@@ -2915,7 +2918,6 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
                ret = reserve_metadata_space(trans, rc, node);
                if (ret)
                        goto out;
-               release = 1;
        }
 
        if (root) {
@@ -2940,11 +2942,8 @@ static int relocate_tree_block(struct btrfs_trans_handle *trans,
                ret = do_relocation(trans, rc, node, key, path, 1);
        }
 out:
-       if (ret || node->level == 0 || node->cowonly) {
-               if (release)
-                       release_metadata_space(rc, node);
+       if (ret || node->level == 0 || node->cowonly)
                remove_backref_node(&rc->backref_cache, node);
-       }
        return ret;
 }
 
@@ -3867,29 +3866,20 @@ static noinline_for_stack
 int prepare_to_relocate(struct reloc_control *rc)
 {
        struct btrfs_trans_handle *trans;
-       int ret;
 
        rc->block_rsv = btrfs_alloc_block_rsv(rc->extent_root,
                                              BTRFS_BLOCK_RSV_TEMP);
        if (!rc->block_rsv)
                return -ENOMEM;
 
-       /*
-        * reserve some space for creating reloc trees.
-        * btrfs_init_reloc_root will use them when there
-        * is no reservation in transaction handle.
-        */
-       ret = btrfs_block_rsv_add(rc->extent_root, rc->block_rsv,
-                                 rc->extent_root->nodesize * 256,
-                                 BTRFS_RESERVE_FLUSH_ALL);
-       if (ret)
-               return ret;
-
        memset(&rc->cluster, 0, sizeof(rc->cluster));
        rc->search_start = rc->block_group->key.objectid;
        rc->extents_found = 0;
        rc->nodes_relocated = 0;
        rc->merging_rsv_size = 0;
+       rc->reserved_bytes = 0;
+       rc->block_rsv->size = rc->extent_root->nodesize *
+                             RELOCATION_RESERVED_NODES;
 
        rc->create_reloc_tree = 1;
        set_reloc_control(rc);
@@ -3933,6 +3923,14 @@ static noinline_for_stack int relocate_block_group(struct reloc_control *rc)
        }
 
        while (1) {
+               rc->reserved_bytes = 0;
+               ret = btrfs_block_rsv_refill(rc->extent_root,
+                                       rc->block_rsv, rc->block_rsv->size,
+                                       BTRFS_RESERVE_FLUSH_ALL);
+               if (ret) {
+                       err = ret;
+                       break;
+               }
                progress++;
                trans = btrfs_start_transaction(rc->extent_root, 0);
                if (IS_ERR(trans)) {
@@ -4011,6 +4009,12 @@ restart:
                if (!RB_EMPTY_ROOT(&blocks)) {
                        ret = relocate_tree_blocks(trans, rc, &blocks);
                        if (ret < 0) {
+                               /*
+                                * if we fail to relocate tree blocks, force to update
+                                * backref cache when committing transaction.
+                                */
+                               rc->backref_cache.last_trans = trans->transid - 1;
+
                                if (ret != -EAGAIN) {
                                        err = ret;
                                        break;
@@ -4020,14 +4024,8 @@ restart:
                        }
                }
 
-               if (rc->commit_transaction) {
-                       rc->commit_transaction = 0;
-                       ret = btrfs_commit_transaction(trans, rc->extent_root);
-                       BUG_ON(ret);
-               } else {
-                       btrfs_end_transaction_throttle(trans, rc->extent_root);
-                       btrfs_btree_balance_dirty(rc->extent_root);
-               }
+               btrfs_end_transaction_throttle(trans, rc->extent_root);
+               btrfs_btree_balance_dirty(rc->extent_root);
                trans = NULL;
 
                if (rc->stage == MOVE_DATA_EXTENTS &&
@@ -4247,7 +4245,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
                goto out;
        }
 
-       printk(KERN_INFO "btrfs: relocating block group %llu flags %llu\n",
+       btrfs_info(extent_root->fs_info, "relocating block group %llu flags %llu",
               rc->block_group->key.objectid, rc->block_group->flags);
 
        ret = btrfs_start_delalloc_roots(fs_info, 0);
@@ -4269,7 +4267,7 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
                if (rc->extents_found == 0)
                        break;
 
-               printk(KERN_INFO "btrfs: found %llu extents\n",
+               btrfs_info(extent_root->fs_info, "found %llu extents",
                        rc->extents_found);
 
                if (rc->stage == MOVE_DATA_EXTENTS && rc->found_file_extent) {
@@ -4285,11 +4283,6 @@ int btrfs_relocate_block_group(struct btrfs_root *extent_root, u64 group_start)
                }
        }
 
-       filemap_write_and_wait_range(fs_info->btree_inode->i_mapping,
-                                    rc->block_group->key.objectid,
-                                    rc->block_group->key.objectid +
-                                    rc->block_group->key.offset - 1);
-
        WARN_ON(rc->block_group->pinned > 0);
        WARN_ON(rc->block_group->reserved > 0);
        WARN_ON(btrfs_block_group_used(&rc->block_group->item) > 0);
index ec71ea44d2b4626c9a2bcc73b5fb94af666eaf5b..1389b69059de3ba33dcccbcb9474fa7d6537afd1 100644 (file)
@@ -44,7 +44,7 @@ static void btrfs_read_root_item(struct extent_buffer *eb, int slot,
        if (!need_reset && btrfs_root_generation(item)
                != btrfs_root_generation_v2(item)) {
                if (btrfs_root_generation_v2(item) != 0) {
-                       printk(KERN_WARNING "btrfs: mismatching "
+                       printk(KERN_WARNING "BTRFS: mismatching "
                                        "generation and generation_v2 "
                                        "found in root item. This root "
                                        "was probably mounted with an "
@@ -154,7 +154,7 @@ int btrfs_update_root(struct btrfs_trans_handle *trans, struct btrfs_root
 
        if (ret != 0) {
                btrfs_print_leaf(root, path->nodes[0]);
-               printk(KERN_CRIT "unable to update root key %llu %u %llu\n",
+               btrfs_crit(root->fs_info, "unable to update root key %llu %u %llu",
                       key->objectid, key->type, key->offset);
                BUG_ON(1);
        }
@@ -400,21 +400,6 @@ out:
        return err;
 }
 
-int btrfs_find_root_ref(struct btrfs_root *tree_root,
-                  struct btrfs_path *path,
-                  u64 root_id, u64 ref_id)
-{
-       struct btrfs_key key;
-       int ret;
-
-       key.objectid = root_id;
-       key.type = BTRFS_ROOT_REF_KEY;
-       key.offset = ref_id;
-
-       ret = btrfs_search_slot(NULL, tree_root, &key, path, 0, 0);
-       return ret;
-}
-
 /*
  * add a btrfs_root_ref item.  type is either BTRFS_ROOT_REF_KEY
  * or BTRFS_ROOT_BACKREF_KEY.
index 1fd3f33c330abe930fbd03de1deb5968e32fd7b5..efba5d1282ee40addd128cf05427181a0aade83f 100644 (file)
@@ -256,6 +256,8 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root,
 static int copy_nocow_pages(struct scrub_ctx *sctx, u64 logical, u64 len,
                            int mirror_num, u64 physical_for_dev_replace);
 static void copy_nocow_pages_worker(struct btrfs_work *work);
+static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info);
+static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info);
 
 
 static void scrub_pending_bio_inc(struct scrub_ctx *sctx)
@@ -269,6 +271,29 @@ static void scrub_pending_bio_dec(struct scrub_ctx *sctx)
        wake_up(&sctx->list_wait);
 }
 
+static void __scrub_blocked_if_needed(struct btrfs_fs_info *fs_info)
+{
+       while (atomic_read(&fs_info->scrub_pause_req)) {
+               mutex_unlock(&fs_info->scrub_lock);
+               wait_event(fs_info->scrub_pause_wait,
+                  atomic_read(&fs_info->scrub_pause_req) == 0);
+               mutex_lock(&fs_info->scrub_lock);
+       }
+}
+
+static void scrub_blocked_if_needed(struct btrfs_fs_info *fs_info)
+{
+       atomic_inc(&fs_info->scrubs_paused);
+       wake_up(&fs_info->scrub_pause_wait);
+
+       mutex_lock(&fs_info->scrub_lock);
+       __scrub_blocked_if_needed(fs_info);
+       atomic_dec(&fs_info->scrubs_paused);
+       mutex_unlock(&fs_info->scrub_lock);
+
+       wake_up(&fs_info->scrub_pause_wait);
+}
+
 /*
  * used for workers that require transaction commits (i.e., for the
  * NOCOW case)
@@ -480,7 +505,7 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
         * hold all of the paths here
         */
        for (i = 0; i < ipath->fspath->elem_cnt; ++i)
-               printk_in_rcu(KERN_WARNING "btrfs: %s at logical %llu on dev "
+               printk_in_rcu(KERN_WARNING "BTRFS: %s at logical %llu on dev "
                        "%s, sector %llu, root %llu, inode %llu, offset %llu, "
                        "length %llu, links %u (path: %s)\n", swarn->errstr,
                        swarn->logical, rcu_str_deref(swarn->dev->name),
@@ -492,7 +517,7 @@ static int scrub_print_warning_inode(u64 inum, u64 offset, u64 root,
        return 0;
 
 err:
-       printk_in_rcu(KERN_WARNING "btrfs: %s at logical %llu on dev "
+       printk_in_rcu(KERN_WARNING "BTRFS: %s at logical %llu on dev "
                "%s, sector %llu, root %llu, inode %llu, offset %llu: path "
                "resolving failed with ret=%d\n", swarn->errstr,
                swarn->logical, rcu_str_deref(swarn->dev->name),
@@ -555,7 +580,7 @@ static void scrub_print_warning(const char *errstr, struct scrub_block *sblock)
                        ret = tree_backref_for_extent(&ptr, eb, ei, item_size,
                                                        &ref_root, &ref_level);
                        printk_in_rcu(KERN_WARNING
-                               "btrfs: %s at logical %llu on dev %s, "
+                               "BTRFS: %s at logical %llu on dev %s, "
                                "sector %llu: metadata %s (level %d) in tree "
                                "%llu\n", errstr, swarn.logical,
                                rcu_str_deref(dev->name),
@@ -704,13 +729,11 @@ static void scrub_fixup_nodatasum(struct btrfs_work *work)
        struct scrub_fixup_nodatasum *fixup;
        struct scrub_ctx *sctx;
        struct btrfs_trans_handle *trans = NULL;
-       struct btrfs_fs_info *fs_info;
        struct btrfs_path *path;
        int uncorrectable = 0;
 
        fixup = container_of(work, struct scrub_fixup_nodatasum, work);
        sctx = fixup->sctx;
-       fs_info = fixup->root->fs_info;
 
        path = btrfs_alloc_path();
        if (!path) {
@@ -759,8 +782,8 @@ out:
                btrfs_dev_replace_stats_inc(
                        &sctx->dev_root->fs_info->dev_replace.
                        num_uncorrectable_read_errors);
-               printk_ratelimited_in_rcu(KERN_ERR
-                       "btrfs: unable to fixup (nodatasum) error at logical %llu on dev %s\n",
+               printk_ratelimited_in_rcu(KERN_ERR "BTRFS: "
+                   "unable to fixup (nodatasum) error at logical %llu on dev %s\n",
                        fixup->logical, rcu_str_deref(fixup->dev->name));
        }
 
@@ -1161,7 +1184,7 @@ corrected_error:
                        sctx->stat.corrected_errors++;
                        spin_unlock(&sctx->stat_lock);
                        printk_ratelimited_in_rcu(KERN_ERR
-                               "btrfs: fixed up error at logical %llu on dev %s\n",
+                               "BTRFS: fixed up error at logical %llu on dev %s\n",
                                logical, rcu_str_deref(dev->name));
                }
        } else {
@@ -1170,7 +1193,7 @@ did_not_correct_error:
                sctx->stat.uncorrectable_errors++;
                spin_unlock(&sctx->stat_lock);
                printk_ratelimited_in_rcu(KERN_ERR
-                       "btrfs: unable to fixup (regular) error at logical %llu on dev %s\n",
+                       "BTRFS: unable to fixup (regular) error at logical %llu on dev %s\n",
                        logical, rcu_str_deref(dev->name));
        }
 
@@ -1308,7 +1331,7 @@ static void scrub_recheck_block(struct btrfs_fs_info *fs_info,
                        continue;
                }
                bio->bi_bdev = page->dev->bdev;
-               bio->bi_sector = page->physical >> 9;
+               bio->bi_iter.bi_sector = page->physical >> 9;
 
                bio_add_page(bio, page->page, PAGE_SIZE, 0);
                if (btrfsic_submit_bio_wait(READ, bio))
@@ -1418,8 +1441,9 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
                int ret;
 
                if (!page_bad->dev->bdev) {
-                       printk_ratelimited(KERN_WARNING
-                               "btrfs: scrub_repair_page_from_good_copy(bdev == NULL) is unexpected!\n");
+                       printk_ratelimited(KERN_WARNING "BTRFS: "
+                               "scrub_repair_page_from_good_copy(bdev == NULL) "
+                               "is unexpected!\n");
                        return -EIO;
                }
 
@@ -1427,7 +1451,7 @@ static int scrub_repair_page_from_good_copy(struct scrub_block *sblock_bad,
                if (!bio)
                        return -EIO;
                bio->bi_bdev = page_bad->dev->bdev;
-               bio->bi_sector = page_bad->physical >> 9;
+               bio->bi_iter.bi_sector = page_bad->physical >> 9;
 
                ret = bio_add_page(bio, page_good->page, PAGE_SIZE, 0);
                if (PAGE_SIZE != ret) {
@@ -1520,7 +1544,7 @@ again:
                bio->bi_private = sbio;
                bio->bi_end_io = scrub_wr_bio_end_io;
                bio->bi_bdev = sbio->dev->bdev;
-               bio->bi_sector = sbio->physical >> 9;
+               bio->bi_iter.bi_sector = sbio->physical >> 9;
                sbio->err = 0;
        } else if (sbio->physical + sbio->page_count * PAGE_SIZE !=
                   spage->physical_for_dev_replace ||
@@ -1877,7 +1901,7 @@ static void scrub_submit(struct scrub_ctx *sctx)
                 * This case is handled correctly (but _very_ slowly).
                 */
                printk_ratelimited(KERN_WARNING
-                       "btrfs: scrub_submit(bio bdev == NULL) is unexpected!\n");
+                       "BTRFS: scrub_submit(bio bdev == NULL) is unexpected!\n");
                bio_endio(sbio->bio, -EIO);
        } else {
                btrfsic_submit_bio(READ, sbio->bio);
@@ -1926,7 +1950,7 @@ again:
                bio->bi_private = sbio;
                bio->bi_end_io = scrub_bio_end_io;
                bio->bi_bdev = sbio->dev->bdev;
-               bio->bi_sector = sbio->physical >> 9;
+               bio->bi_iter.bi_sector = sbio->physical >> 9;
                sbio->err = 0;
        } else if (sbio->physical + sbio->page_count * PAGE_SIZE !=
                   spage->physical ||
@@ -2286,8 +2310,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
 
        wait_event(sctx->list_wait,
                   atomic_read(&sctx->bios_in_flight) == 0);
-       atomic_inc(&fs_info->scrubs_paused);
-       wake_up(&fs_info->scrub_pause_wait);
+       scrub_blocked_if_needed(fs_info);
 
        /* FIXME it might be better to start readahead at commit root */
        key_start.objectid = logical;
@@ -2311,16 +2334,6 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
        if (!IS_ERR(reada2))
                btrfs_reada_wait(reada2);
 
-       mutex_lock(&fs_info->scrub_lock);
-       while (atomic_read(&fs_info->scrub_pause_req)) {
-               mutex_unlock(&fs_info->scrub_lock);
-               wait_event(fs_info->scrub_pause_wait,
-                  atomic_read(&fs_info->scrub_pause_req) == 0);
-               mutex_lock(&fs_info->scrub_lock);
-       }
-       atomic_dec(&fs_info->scrubs_paused);
-       mutex_unlock(&fs_info->scrub_lock);
-       wake_up(&fs_info->scrub_pause_wait);
 
        /*
         * collect all data csums for the stripe to avoid seeking during
@@ -2357,22 +2370,14 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
                        wait_event(sctx->list_wait,
                                   atomic_read(&sctx->bios_in_flight) == 0);
                        atomic_set(&sctx->wr_ctx.flush_all_writes, 0);
-                       atomic_inc(&fs_info->scrubs_paused);
-                       wake_up(&fs_info->scrub_pause_wait);
-                       mutex_lock(&fs_info->scrub_lock);
-                       while (atomic_read(&fs_info->scrub_pause_req)) {
-                               mutex_unlock(&fs_info->scrub_lock);
-                               wait_event(fs_info->scrub_pause_wait,
-                                  atomic_read(&fs_info->scrub_pause_req) == 0);
-                               mutex_lock(&fs_info->scrub_lock);
-                       }
-                       atomic_dec(&fs_info->scrubs_paused);
-                       mutex_unlock(&fs_info->scrub_lock);
-                       wake_up(&fs_info->scrub_pause_wait);
+                       scrub_blocked_if_needed(fs_info);
                }
 
+               if (btrfs_fs_incompat(fs_info, SKINNY_METADATA))
+                       key.type = BTRFS_METADATA_ITEM_KEY;
+               else
+                       key.type = BTRFS_EXTENT_ITEM_KEY;
                key.objectid = logical;
-               key.type = BTRFS_EXTENT_ITEM_KEY;
                key.offset = (u64)-1;
 
                ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
@@ -2380,8 +2385,7 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
                        goto out;
 
                if (ret > 0) {
-                       ret = btrfs_previous_item(root, path, 0,
-                                                 BTRFS_EXTENT_ITEM_KEY);
+                       ret = btrfs_previous_extent_item(root, path, 0);
                        if (ret < 0)
                                goto out;
                        if (ret > 0) {
@@ -2439,9 +2443,9 @@ static noinline_for_stack int scrub_stripe(struct scrub_ctx *sctx,
 
                        if (key.objectid < logical &&
                            (flags & BTRFS_EXTENT_FLAG_TREE_BLOCK)) {
-                               printk(KERN_ERR
-                                      "btrfs scrub: tree block %llu spanning "
-                                      "stripes, ignored. logical=%llu\n",
+                               btrfs_err(fs_info,
+                                          "scrub: tree block %llu spanning "
+                                          "stripes, ignored. logical=%llu",
                                       key.objectid, logical);
                                goto next;
                        }
@@ -2683,21 +2687,9 @@ int scrub_enumerate_chunks(struct scrub_ctx *sctx,
                wait_event(sctx->list_wait,
                           atomic_read(&sctx->bios_in_flight) == 0);
                atomic_set(&sctx->wr_ctx.flush_all_writes, 0);
-               atomic_inc(&fs_info->scrubs_paused);
-               wake_up(&fs_info->scrub_pause_wait);
                wait_event(sctx->list_wait,
                           atomic_read(&sctx->workers_pending) == 0);
-
-               mutex_lock(&fs_info->scrub_lock);
-               while (atomic_read(&fs_info->scrub_pause_req)) {
-                       mutex_unlock(&fs_info->scrub_lock);
-                       wait_event(fs_info->scrub_pause_wait,
-                          atomic_read(&fs_info->scrub_pause_req) == 0);
-                       mutex_lock(&fs_info->scrub_lock);
-               }
-               atomic_dec(&fs_info->scrubs_paused);
-               mutex_unlock(&fs_info->scrub_lock);
-               wake_up(&fs_info->scrub_pause_wait);
+               scrub_blocked_if_needed(fs_info);
 
                btrfs_put_block_group(cache);
                if (ret)
@@ -2823,8 +2815,8 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
         * check some assumptions
         */
        if (fs_info->chunk_root->nodesize != fs_info->chunk_root->leafsize) {
-               printk(KERN_ERR
-                      "btrfs_scrub: size assumption nodesize == leafsize (%d == %d) fails\n",
+               btrfs_err(fs_info,
+                          "scrub: size assumption nodesize == leafsize (%d == %d) fails",
                       fs_info->chunk_root->nodesize,
                       fs_info->chunk_root->leafsize);
                return -EINVAL;
@@ -2836,16 +2828,17 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                 * the way scrub is implemented. Do not handle this
                 * situation at all because it won't ever happen.
                 */
-               printk(KERN_ERR
-                      "btrfs_scrub: size assumption nodesize <= BTRFS_STRIPE_LEN (%d <= %d) fails\n",
+               btrfs_err(fs_info,
+                          "scrub: size assumption nodesize <= BTRFS_STRIPE_LEN (%d <= %d) fails",
                       fs_info->chunk_root->nodesize, BTRFS_STRIPE_LEN);
                return -EINVAL;
        }
 
        if (fs_info->chunk_root->sectorsize != PAGE_SIZE) {
                /* not supported for data w/o checksums */
-               printk(KERN_ERR
-                      "btrfs_scrub: size assumption sectorsize != PAGE_SIZE (%d != %lu) fails\n",
+               btrfs_err(fs_info,
+                          "scrub: size assumption sectorsize != PAGE_SIZE "
+                          "(%d != %lu) fails",
                       fs_info->chunk_root->sectorsize, PAGE_SIZE);
                return -EINVAL;
        }
@@ -2858,7 +2851,8 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                 * would exhaust the array bounds of pagev member in
                 * struct scrub_block
                 */
-               pr_err("btrfs_scrub: size assumption nodesize and sectorsize <= SCRUB_MAX_PAGES_PER_BLOCK (%d <= %d && %d <= %d) fails\n",
+               btrfs_err(fs_info, "scrub: size assumption nodesize and sectorsize "
+                          "<= SCRUB_MAX_PAGES_PER_BLOCK (%d <= %d && %d <= %d) fails",
                       fs_info->chunk_root->nodesize,
                       SCRUB_MAX_PAGES_PER_BLOCK,
                       fs_info->chunk_root->sectorsize,
@@ -2908,7 +2902,13 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
        }
        sctx->readonly = readonly;
        dev->scrub_device = sctx;
+       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
 
+       /*
+        * checking @scrub_pause_req here, we can avoid
+        * race between committing transaction and scrubbing.
+        */
+       __scrub_blocked_if_needed(fs_info);
        atomic_inc(&fs_info->scrubs_running);
        mutex_unlock(&fs_info->scrub_lock);
 
@@ -2917,9 +2917,10 @@ int btrfs_scrub_dev(struct btrfs_fs_info *fs_info, u64 devid, u64 start,
                 * by holding device list mutex, we can
                 * kick off writing super in log tree sync.
                 */
+               mutex_lock(&fs_info->fs_devices->device_list_mutex);
                ret = scrub_supers(sctx, dev);
+               mutex_unlock(&fs_info->fs_devices->device_list_mutex);
        }
-       mutex_unlock(&fs_info->fs_devices->device_list_mutex);
 
        if (!ret)
                ret = scrub_enumerate_chunks(sctx, dev, start, end,
@@ -3167,7 +3168,8 @@ static void copy_nocow_pages_worker(struct btrfs_work *work)
        ret = iterate_inodes_from_logical(logical, fs_info, path,
                                          record_inode_for_nocow, nocow_ctx);
        if (ret != 0 && ret != -ENOENT) {
-               pr_warn("iterate_inodes_from_logical() failed: log %llu, phys %llu, len %llu, mir %u, ret %d\n",
+               btrfs_warn(fs_info, "iterate_inodes_from_logical() failed: log %llu, "
+                       "phys %llu, len %llu, mir %u, ret %d",
                        logical, physical_for_dev_replace, len, mirror_num,
                        ret);
                not_written = 1;
@@ -3289,7 +3291,7 @@ static int copy_nocow_pages_for_inode(u64 inum, u64 offset, u64 root,
 again:
                page = find_or_create_page(inode->i_mapping, index, GFP_NOFS);
                if (!page) {
-                       pr_err("find_or_create_page() failed\n");
+                       btrfs_err(fs_info, "find_or_create_page() failed");
                        ret = -ENOMEM;
                        goto out;
                }
@@ -3361,7 +3363,7 @@ static int write_page_nocow(struct scrub_ctx *sctx,
                return -EIO;
        if (!dev->bdev) {
                printk_ratelimited(KERN_WARNING
-                       "btrfs: scrub write_page_nocow(bdev == NULL) is unexpected!\n");
+                       "BTRFS: scrub write_page_nocow(bdev == NULL) is unexpected!\n");
                return -EIO;
        }
        bio = btrfs_io_bio_alloc(GFP_NOFS, 1);
@@ -3371,8 +3373,8 @@ static int write_page_nocow(struct scrub_ctx *sctx,
                spin_unlock(&sctx->stat_lock);
                return -ENOMEM;
        }
-       bio->bi_size = 0;
-       bio->bi_sector = physical_for_dev_replace >> 9;
+       bio->bi_iter.bi_size = 0;
+       bio->bi_iter.bi_sector = physical_for_dev_replace >> 9;
        bio->bi_bdev = dev->bdev;
        ret = bio_add_page(bio, page, PAGE_CACHE_SIZE, 0);
        if (ret != PAGE_CACHE_SIZE) {
index 945d1db98f26968ec051a6ff6116f971f18e7303..730dce395858a6e4c86a43b4a8fa41779d719e0d 100644 (file)
@@ -88,8 +88,6 @@ struct send_ctx {
        u64 cmd_send_size[BTRFS_SEND_C_MAX + 1];
        u64 flags;      /* 'flags' member of btrfs_ioctl_send_args is u64 */
 
-       struct vfsmount *mnt;
-
        struct btrfs_root *send_root;
        struct btrfs_root *parent_root;
        struct clone_root *clone_roots;
@@ -111,6 +109,7 @@ struct send_ctx {
        int cur_inode_deleted;
        u64 cur_inode_size;
        u64 cur_inode_mode;
+       u64 cur_inode_last_extent;
 
        u64 send_progress;
 
@@ -122,6 +121,74 @@ struct send_ctx {
        int name_cache_size;
 
        char *read_buf;
+
+       /*
+        * We process inodes by their increasing order, so if before an
+        * incremental send we reverse the parent/child relationship of
+        * directories such that a directory with a lower inode number was
+        * the parent of a directory with a higher inode number, and the one
+        * becoming the new parent got renamed too, we can't rename/move the
+        * directory with lower inode number when we finish processing it - we
+        * must process the directory with higher inode number first, then
+        * rename/move it and then rename/move the directory with lower inode
+        * number. Example follows.
+        *
+        * Tree state when the first send was performed:
+        *
+        * .
+        * |-- a                   (ino 257)
+        *     |-- b               (ino 258)
+        *         |
+        *         |
+        *         |-- c           (ino 259)
+        *         |   |-- d       (ino 260)
+        *         |
+        *         |-- c2          (ino 261)
+        *
+        * Tree state when the second (incremental) send is performed:
+        *
+        * .
+        * |-- a                   (ino 257)
+        *     |-- b               (ino 258)
+        *         |-- c2          (ino 261)
+        *             |-- d2      (ino 260)
+        *                 |-- cc  (ino 259)
+        *
+        * The sequence of steps that lead to the second state was:
+        *
+        * mv /a/b/c/d /a/b/c2/d2
+        * mv /a/b/c /a/b/c2/d2/cc
+        *
+        * "c" has lower inode number, but we can't move it (2nd mv operation)
+        * before we move "d", which has higher inode number.
+        *
+        * So we just memorize which move/rename operations must be performed
+        * later when their respective parent is processed and moved/renamed.
+        */
+
+       /* Indexed by parent directory inode number. */
+       struct rb_root pending_dir_moves;
+
+       /*
+        * Reverse index, indexed by the inode number of a directory that
+        * is waiting for the move/rename of its immediate parent before its
+        * own move/rename can be performed.
+        */
+       struct rb_root waiting_dir_moves;
+};
+
+struct pending_dir_move {
+       struct rb_node node;
+       struct list_head list;
+       u64 parent_ino;
+       u64 ino;
+       u64 gen;
+       struct list_head update_refs;
+};
+
+struct waiting_dir_move {
+       struct rb_node node;
+       u64 ino;
 };
 
 struct name_cache_entry {
@@ -145,6 +212,15 @@ struct name_cache_entry {
        char name[];
 };
 
+static int is_waiting_for_move(struct send_ctx *sctx, u64 ino);
+
+static int need_send_hole(struct send_ctx *sctx)
+{
+       return (sctx->parent_root && !sctx->cur_inode_new &&
+               !sctx->cur_inode_new_gen && !sctx->cur_inode_deleted &&
+               S_ISREG(sctx->cur_inode_mode));
+}
+
 static void fs_path_reset(struct fs_path *p)
 {
        if (p->reversed) {
@@ -336,16 +412,6 @@ out:
        return ret;
 }
 
-#if 0
-static void fs_path_remove(struct fs_path *p)
-{
-       BUG_ON(p->reversed);
-       while (p->start != p->end && *p->end != '/')
-               p->end--;
-       *p->end = 0;
-}
-#endif
-
 static int fs_path_copy(struct fs_path *p, struct fs_path *from)
 {
        int ret;
@@ -436,30 +502,15 @@ static int tlv_put(struct send_ctx *sctx, u16 attr, const void *data, int len)
        return 0;
 }
 
-#if 0
-static int tlv_put_u8(struct send_ctx *sctx, u16 attr, u8 value)
-{
-       return tlv_put(sctx, attr, &value, sizeof(value));
-}
-
-static int tlv_put_u16(struct send_ctx *sctx, u16 attr, u16 value)
-{
-       __le16 tmp = cpu_to_le16(value);
-       return tlv_put(sctx, attr, &tmp, sizeof(tmp));
-}
-
-static int tlv_put_u32(struct send_ctx *sctx, u16 attr, u32 value)
-{
-       __le32 tmp = cpu_to_le32(value);
-       return tlv_put(sctx, attr, &tmp, sizeof(tmp));
-}
-#endif
+#define TLV_PUT_DEFINE_INT(bits) \
+       static int tlv_put_u##bits(struct send_ctx *sctx,               \
+                       u##bits attr, u##bits value)                    \
+       {                                                               \
+               __le##bits __tmp = cpu_to_le##bits(value);              \
+               return tlv_put(sctx, attr, &__tmp, sizeof(__tmp));      \
+       }
 
-static int tlv_put_u64(struct send_ctx *sctx, u16 attr, u64 value)
-{
-       __le64 tmp = cpu_to_le64(value);
-       return tlv_put(sctx, attr, &tmp, sizeof(tmp));
-}
+TLV_PUT_DEFINE_INT(64)
 
 static int tlv_put_string(struct send_ctx *sctx, u16 attr,
                          const char *str, int len)
@@ -475,17 +526,6 @@ static int tlv_put_uuid(struct send_ctx *sctx, u16 attr,
        return tlv_put(sctx, attr, uuid, BTRFS_UUID_SIZE);
 }
 
-#if 0
-static int tlv_put_timespec(struct send_ctx *sctx, u16 attr,
-                           struct timespec *ts)
-{
-       struct btrfs_timespec bts;
-       bts.sec = cpu_to_le64(ts->tv_sec);
-       bts.nsec = cpu_to_le32(ts->tv_nsec);
-       return tlv_put(sctx, attr, &bts, sizeof(bts));
-}
-#endif
-
 static int tlv_put_btrfs_timespec(struct send_ctx *sctx, u16 attr,
                                  struct extent_buffer *eb,
                                  struct btrfs_timespec *ts)
@@ -533,12 +573,6 @@ static int tlv_put_btrfs_timespec(struct send_ctx *sctx, u16 attr,
                if (ret < 0) \
                        goto tlv_put_failure; \
        } while (0)
-#define TLV_PUT_TIMESPEC(sctx, attrtype, ts) \
-       do { \
-               ret = tlv_put_timespec(sctx, attrtype, ts); \
-               if (ret < 0) \
-                       goto tlv_put_failure; \
-       } while (0)
 #define TLV_PUT_BTRFS_TIMESPEC(sctx, attrtype, eb, ts) \
        do { \
                ret = tlv_put_btrfs_timespec(sctx, attrtype, eb, ts); \
@@ -1270,7 +1304,7 @@ static int find_extent_clone(struct send_ctx *sctx,
        if (!backref_ctx->found_itself) {
                /* found a bug in backref code? */
                ret = -EIO;
-               printk(KERN_ERR "btrfs: ERROR did not find backref in "
+               btrfs_err(sctx->send_root->fs_info, "did not find backref in "
                                "send_root. inode=%llu, offset=%llu, "
                                "disk_byte=%llu found extent=%llu\n",
                                ino, data_offset, disk_byte, found_key.objectid);
@@ -1343,7 +1377,7 @@ static int read_symlink(struct btrfs_root *root,
        BUG_ON(compression);
 
        off = btrfs_file_extent_inline_start(ei);
-       len = btrfs_file_extent_inline_len(path->nodes[0], ei);
+       len = btrfs_file_extent_inline_len(path->nodes[0], path->slots[0], ei);
 
        ret = fs_path_add_from_extent_buffer(dest, path->nodes[0], off, len);
 
@@ -1372,7 +1406,7 @@ static int gen_unique_name(struct send_ctx *sctx,
                return -ENOMEM;
 
        while (1) {
-               len = snprintf(tmp, sizeof(tmp) - 1, "o%llu-%llu-%llu",
+               len = snprintf(tmp, sizeof(tmp), "o%llu-%llu-%llu",
                                ino, gen, idx);
                if (len >= sizeof(tmp)) {
                        /* should really not happen */
@@ -1933,6 +1967,7 @@ static void name_cache_free(struct send_ctx *sctx)
  */
 static int __get_cur_name_and_parent(struct send_ctx *sctx,
                                     u64 ino, u64 gen,
+                                    int skip_name_cache,
                                     u64 *parent_ino,
                                     u64 *parent_gen,
                                     struct fs_path *dest)
@@ -1942,6 +1977,8 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
        struct btrfs_path *path = NULL;
        struct name_cache_entry *nce = NULL;
 
+       if (skip_name_cache)
+               goto get_ref;
        /*
         * First check if we already did a call to this function with the same
         * ino/gen. If yes, check if the cache entry is still up-to-date. If yes
@@ -1986,11 +2023,12 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
                goto out_cache;
        }
 
+get_ref:
        /*
         * Depending on whether the inode was already processed or not, use
         * send_root or parent_root for ref lookup.
         */
-       if (ino < sctx->send_progress)
+       if (ino < sctx->send_progress && !skip_name_cache)
                ret = get_first_ref(sctx->send_root, ino,
                                    parent_ino, parent_gen, dest);
        else
@@ -2014,6 +2052,8 @@ static int __get_cur_name_and_parent(struct send_ctx *sctx,
                        goto out;
                ret = 1;
        }
+       if (skip_name_cache)
+               goto out;
 
 out_cache:
        /*
@@ -2081,6 +2121,9 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
        u64 parent_inode = 0;
        u64 parent_gen = 0;
        int stop = 0;
+       u64 start_ino = ino;
+       u64 start_gen = gen;
+       int skip_name_cache = 0;
 
        name = fs_path_alloc();
        if (!name) {
@@ -2088,19 +2131,32 @@ static int get_cur_path(struct send_ctx *sctx, u64 ino, u64 gen,
                goto out;
        }
 
+       if (is_waiting_for_move(sctx, ino))
+               skip_name_cache = 1;
+
+again:
        dest->reversed = 1;
        fs_path_reset(dest);
 
        while (!stop && ino != BTRFS_FIRST_FREE_OBJECTID) {
                fs_path_reset(name);
 
-               ret = __get_cur_name_and_parent(sctx, ino, gen,
+               ret = __get_cur_name_and_parent(sctx, ino, gen, skip_name_cache,
                                &parent_inode, &parent_gen, name);
                if (ret < 0)
                        goto out;
                if (ret)
                        stop = 1;
 
+               if (!skip_name_cache &&
+                   is_waiting_for_move(sctx, parent_inode)) {
+                       ino = start_ino;
+                       gen = start_gen;
+                       stop = 0;
+                       skip_name_cache = 1;
+                       goto again;
+               }
+
                ret = fs_path_add_path(dest, name);
                if (ret < 0)
                        goto out;
@@ -2131,7 +2187,7 @@ static int send_subvol_begin(struct send_ctx *sctx)
        char *name = NULL;
        int namelen;
 
-       path = alloc_path_for_send();
+       path = btrfs_alloc_path();
        if (!path)
                return -ENOMEM;
 
@@ -2180,12 +2236,12 @@ static int send_subvol_begin(struct send_ctx *sctx)
        TLV_PUT_UUID(sctx, BTRFS_SEND_A_UUID,
                        sctx->send_root->root_item.uuid);
        TLV_PUT_U64(sctx, BTRFS_SEND_A_CTRANSID,
-                       sctx->send_root->root_item.ctransid);
+                   le64_to_cpu(sctx->send_root->root_item.ctransid));
        if (parent_root) {
                TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID,
                                sctx->parent_root->root_item.uuid);
                TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID,
-                               sctx->parent_root->root_item.ctransid);
+                           le64_to_cpu(sctx->parent_root->root_item.ctransid));
        }
 
        ret = send_cmd(sctx);
@@ -2672,10 +2728,349 @@ out:
        return ret;
 }
 
+static int is_waiting_for_move(struct send_ctx *sctx, u64 ino)
+{
+       struct rb_node *n = sctx->waiting_dir_moves.rb_node;
+       struct waiting_dir_move *entry;
+
+       while (n) {
+               entry = rb_entry(n, struct waiting_dir_move, node);
+               if (ino < entry->ino)
+                       n = n->rb_left;
+               else if (ino > entry->ino)
+                       n = n->rb_right;
+               else
+                       return 1;
+       }
+       return 0;
+}
+
+static int add_waiting_dir_move(struct send_ctx *sctx, u64 ino)
+{
+       struct rb_node **p = &sctx->waiting_dir_moves.rb_node;
+       struct rb_node *parent = NULL;
+       struct waiting_dir_move *entry, *dm;
+
+       dm = kmalloc(sizeof(*dm), GFP_NOFS);
+       if (!dm)
+               return -ENOMEM;
+       dm->ino = ino;
+
+       while (*p) {
+               parent = *p;
+               entry = rb_entry(parent, struct waiting_dir_move, node);
+               if (ino < entry->ino) {
+                       p = &(*p)->rb_left;
+               } else if (ino > entry->ino) {
+                       p = &(*p)->rb_right;
+               } else {
+                       kfree(dm);
+                       return -EEXIST;
+               }
+       }
+
+       rb_link_node(&dm->node, parent, p);
+       rb_insert_color(&dm->node, &sctx->waiting_dir_moves);
+       return 0;
+}
+
+#ifdef CONFIG_BTRFS_ASSERT
+
+static int del_waiting_dir_move(struct send_ctx *sctx, u64 ino)
+{
+       struct rb_node *n = sctx->waiting_dir_moves.rb_node;
+       struct waiting_dir_move *entry;
+
+       while (n) {
+               entry = rb_entry(n, struct waiting_dir_move, node);
+               if (ino < entry->ino) {
+                       n = n->rb_left;
+               } else if (ino > entry->ino) {
+                       n = n->rb_right;
+               } else {
+                       rb_erase(&entry->node, &sctx->waiting_dir_moves);
+                       kfree(entry);
+                       return 0;
+               }
+       }
+       return -ENOENT;
+}
+
+#endif
+
+static int add_pending_dir_move(struct send_ctx *sctx, u64 parent_ino)
+{
+       struct rb_node **p = &sctx->pending_dir_moves.rb_node;
+       struct rb_node *parent = NULL;
+       struct pending_dir_move *entry, *pm;
+       struct recorded_ref *cur;
+       int exists = 0;
+       int ret;
+
+       pm = kmalloc(sizeof(*pm), GFP_NOFS);
+       if (!pm)
+               return -ENOMEM;
+       pm->parent_ino = parent_ino;
+       pm->ino = sctx->cur_ino;
+       pm->gen = sctx->cur_inode_gen;
+       INIT_LIST_HEAD(&pm->list);
+       INIT_LIST_HEAD(&pm->update_refs);
+       RB_CLEAR_NODE(&pm->node);
+
+       while (*p) {
+               parent = *p;
+               entry = rb_entry(parent, struct pending_dir_move, node);
+               if (parent_ino < entry->parent_ino) {
+                       p = &(*p)->rb_left;
+               } else if (parent_ino > entry->parent_ino) {
+                       p = &(*p)->rb_right;
+               } else {
+                       exists = 1;
+                       break;
+               }
+       }
+
+       list_for_each_entry(cur, &sctx->deleted_refs, list) {
+               ret = dup_ref(cur, &pm->update_refs);
+               if (ret < 0)
+                       goto out;
+       }
+       list_for_each_entry(cur, &sctx->new_refs, list) {
+               ret = dup_ref(cur, &pm->update_refs);
+               if (ret < 0)
+                       goto out;
+       }
+
+       ret = add_waiting_dir_move(sctx, pm->ino);
+       if (ret)
+               goto out;
+
+       if (exists) {
+               list_add_tail(&pm->list, &entry->list);
+       } else {
+               rb_link_node(&pm->node, parent, p);
+               rb_insert_color(&pm->node, &sctx->pending_dir_moves);
+       }
+       ret = 0;
+out:
+       if (ret) {
+               __free_recorded_refs(&pm->update_refs);
+               kfree(pm);
+       }
+       return ret;
+}
+
+static struct pending_dir_move *get_pending_dir_moves(struct send_ctx *sctx,
+                                                     u64 parent_ino)
+{
+       struct rb_node *n = sctx->pending_dir_moves.rb_node;
+       struct pending_dir_move *entry;
+
+       while (n) {
+               entry = rb_entry(n, struct pending_dir_move, node);
+               if (parent_ino < entry->parent_ino)
+                       n = n->rb_left;
+               else if (parent_ino > entry->parent_ino)
+                       n = n->rb_right;
+               else
+                       return entry;
+       }
+       return NULL;
+}
+
+static int apply_dir_move(struct send_ctx *sctx, struct pending_dir_move *pm)
+{
+       struct fs_path *from_path = NULL;
+       struct fs_path *to_path = NULL;
+       u64 orig_progress = sctx->send_progress;
+       struct recorded_ref *cur;
+       int ret;
+
+       from_path = fs_path_alloc();
+       if (!from_path)
+               return -ENOMEM;
+
+       sctx->send_progress = pm->ino;
+       ret = get_cur_path(sctx, pm->ino, pm->gen, from_path);
+       if (ret < 0)
+               goto out;
+
+       to_path = fs_path_alloc();
+       if (!to_path) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       sctx->send_progress = sctx->cur_ino + 1;
+       ASSERT(del_waiting_dir_move(sctx, pm->ino) == 0);
+       ret = get_cur_path(sctx, pm->ino, pm->gen, to_path);
+       if (ret < 0)
+               goto out;
+
+       ret = send_rename(sctx, from_path, to_path);
+       if (ret < 0)
+               goto out;
+
+       ret = send_utimes(sctx, pm->ino, pm->gen);
+       if (ret < 0)
+               goto out;
+
+       /*
+        * After rename/move, need to update the utimes of both new parent(s)
+        * and old parent(s).
+        */
+       list_for_each_entry(cur, &pm->update_refs, list) {
+               ret = send_utimes(sctx, cur->dir, cur->dir_gen);
+               if (ret < 0)
+                       goto out;
+       }
+
+out:
+       fs_path_free(from_path);
+       fs_path_free(to_path);
+       sctx->send_progress = orig_progress;
+
+       return ret;
+}
+
+static void free_pending_move(struct send_ctx *sctx, struct pending_dir_move *m)
+{
+       if (!list_empty(&m->list))
+               list_del(&m->list);
+       if (!RB_EMPTY_NODE(&m->node))
+               rb_erase(&m->node, &sctx->pending_dir_moves);
+       __free_recorded_refs(&m->update_refs);
+       kfree(m);
+}
+
+static void tail_append_pending_moves(struct pending_dir_move *moves,
+                                     struct list_head *stack)
+{
+       if (list_empty(&moves->list)) {
+               list_add_tail(&moves->list, stack);
+       } else {
+               LIST_HEAD(list);
+               list_splice_init(&moves->list, &list);
+               list_add_tail(&moves->list, stack);
+               list_splice_tail(&list, stack);
+       }
+}
+
+static int apply_children_dir_moves(struct send_ctx *sctx)
+{
+       struct pending_dir_move *pm;
+       struct list_head stack;
+       u64 parent_ino = sctx->cur_ino;
+       int ret = 0;
+
+       pm = get_pending_dir_moves(sctx, parent_ino);
+       if (!pm)
+               return 0;
+
+       INIT_LIST_HEAD(&stack);
+       tail_append_pending_moves(pm, &stack);
+
+       while (!list_empty(&stack)) {
+               pm = list_first_entry(&stack, struct pending_dir_move, list);
+               parent_ino = pm->ino;
+               ret = apply_dir_move(sctx, pm);
+               free_pending_move(sctx, pm);
+               if (ret)
+                       goto out;
+               pm = get_pending_dir_moves(sctx, parent_ino);
+               if (pm)
+                       tail_append_pending_moves(pm, &stack);
+       }
+       return 0;
+
+out:
+       while (!list_empty(&stack)) {
+               pm = list_first_entry(&stack, struct pending_dir_move, list);
+               free_pending_move(sctx, pm);
+       }
+       return ret;
+}
+
+static int wait_for_parent_move(struct send_ctx *sctx,
+                               struct recorded_ref *parent_ref)
+{
+       int ret;
+       u64 ino = parent_ref->dir;
+       u64 parent_ino_before, parent_ino_after;
+       u64 new_gen, old_gen;
+       struct fs_path *path_before = NULL;
+       struct fs_path *path_after = NULL;
+       int len1, len2;
+
+       if (parent_ref->dir <= sctx->cur_ino)
+               return 0;
+
+       if (is_waiting_for_move(sctx, ino))
+               return 1;
+
+       ret = get_inode_info(sctx->parent_root, ino, NULL, &old_gen,
+                            NULL, NULL, NULL, NULL);
+       if (ret == -ENOENT)
+               return 0;
+       else if (ret < 0)
+               return ret;
+
+       ret = get_inode_info(sctx->send_root, ino, NULL, &new_gen,
+                            NULL, NULL, NULL, NULL);
+       if (ret < 0)
+               return ret;
+
+       if (new_gen != old_gen)
+               return 0;
+
+       path_before = fs_path_alloc();
+       if (!path_before)
+               return -ENOMEM;
+
+       ret = get_first_ref(sctx->parent_root, ino, &parent_ino_before,
+                           NULL, path_before);
+       if (ret == -ENOENT) {
+               ret = 0;
+               goto out;
+       } else if (ret < 0) {
+               goto out;
+       }
+
+       path_after = fs_path_alloc();
+       if (!path_after) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       ret = get_first_ref(sctx->send_root, ino, &parent_ino_after,
+                           NULL, path_after);
+       if (ret == -ENOENT) {
+               ret = 0;
+               goto out;
+       } else if (ret < 0) {
+               goto out;
+       }
+
+       len1 = fs_path_len(path_before);
+       len2 = fs_path_len(path_after);
+       if ((parent_ino_before != parent_ino_after) && (len1 != len2 ||
+            memcmp(path_before->start, path_after->start, len1))) {
+               ret = 1;
+               goto out;
+       }
+       ret = 0;
+
+out:
+       fs_path_free(path_before);
+       fs_path_free(path_after);
+
+       return ret;
+}
+
 /*
  * This does all the move/link/unlink/rmdir magic.
  */
-static int process_recorded_refs(struct send_ctx *sctx)
+static int process_recorded_refs(struct send_ctx *sctx, int *pending_move)
 {
        int ret = 0;
        struct recorded_ref *cur;
@@ -2824,11 +3219,17 @@ verbose_printk("btrfs: process_recorded_refs %llu\n", sctx->cur_ino);
                                 * dirs, we always have one new and one deleted
                                 * ref. The deleted ref is ignored later.
                                 */
-                               ret = send_rename(sctx, valid_path,
-                                               cur->full_path);
-                               if (ret < 0)
-                                       goto out;
-                               ret = fs_path_copy(valid_path, cur->full_path);
+                               if (wait_for_parent_move(sctx, cur)) {
+                                       ret = add_pending_dir_move(sctx,
+                                                                  cur->dir);
+                                       *pending_move = 1;
+                               } else {
+                                       ret = send_rename(sctx, valid_path,
+                                                         cur->full_path);
+                                       if (!ret)
+                                               ret = fs_path_copy(valid_path,
+                                                              cur->full_path);
+                               }
                                if (ret < 0)
                                        goto out;
                        } else {
@@ -3197,6 +3598,7 @@ static int process_all_refs(struct send_ctx *sctx,
        struct extent_buffer *eb;
        int slot;
        iterate_inode_ref_t cb;
+       int pending_move = 0;
 
        path = alloc_path_for_send();
        if (!path)
@@ -3240,7 +3642,9 @@ static int process_all_refs(struct send_ctx *sctx,
        }
        btrfs_release_path(path);
 
-       ret = process_recorded_refs(sctx);
+       ret = process_recorded_refs(sctx, &pending_move);
+       /* Only applicable to an incremental send. */
+       ASSERT(pending_move == 0);
 
 out:
        btrfs_free_path(path);
@@ -3706,7 +4110,7 @@ verbose_printk("btrfs: send_clone offset=%llu, len=%d, clone_root=%llu, "
        TLV_PUT_UUID(sctx, BTRFS_SEND_A_CLONE_UUID,
                        clone_root->root->root_item.uuid);
        TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_CTRANSID,
-                       clone_root->root->root_item.ctransid);
+                   le64_to_cpu(clone_root->root->root_item.ctransid));
        TLV_PUT_PATH(sctx, BTRFS_SEND_A_CLONE_PATH, p);
        TLV_PUT_U64(sctx, BTRFS_SEND_A_CLONE_OFFSET,
                        clone_root->offset);
@@ -3752,6 +4156,39 @@ out:
        return ret;
 }
 
+static int send_hole(struct send_ctx *sctx, u64 end)
+{
+       struct fs_path *p = NULL;
+       u64 offset = sctx->cur_inode_last_extent;
+       u64 len;
+       int ret = 0;
+
+       p = fs_path_alloc();
+       if (!p)
+               return -ENOMEM;
+       memset(sctx->read_buf, 0, BTRFS_SEND_READ_SIZE);
+       while (offset < end) {
+               len = min_t(u64, end - offset, BTRFS_SEND_READ_SIZE);
+
+               ret = begin_cmd(sctx, BTRFS_SEND_C_WRITE);
+               if (ret < 0)
+                       break;
+               ret = get_cur_path(sctx, sctx->cur_ino, sctx->cur_inode_gen, p);
+               if (ret < 0)
+                       break;
+               TLV_PUT_PATH(sctx, BTRFS_SEND_A_PATH, p);
+               TLV_PUT_U64(sctx, BTRFS_SEND_A_FILE_OFFSET, offset);
+               TLV_PUT(sctx, BTRFS_SEND_A_DATA, sctx->read_buf, len);
+               ret = send_cmd(sctx);
+               if (ret < 0)
+                       break;
+               offset += len;
+       }
+tlv_put_failure:
+       fs_path_free(p);
+       return ret;
+}
+
 static int send_write_or_clone(struct send_ctx *sctx,
                               struct btrfs_path *path,
                               struct btrfs_key *key,
@@ -3764,12 +4201,14 @@ static int send_write_or_clone(struct send_ctx *sctx,
        u64 len;
        u32 l;
        u8 type;
+       u64 bs = sctx->send_root->fs_info->sb->s_blocksize;
 
        ei = btrfs_item_ptr(path->nodes[0], path->slots[0],
                        struct btrfs_file_extent_item);
        type = btrfs_file_extent_type(path->nodes[0], ei);
        if (type == BTRFS_FILE_EXTENT_INLINE) {
-               len = btrfs_file_extent_inline_len(path->nodes[0], ei);
+               len = btrfs_file_extent_inline_len(path->nodes[0],
+                                                  path->slots[0], ei);
                /*
                 * it is possible the inline item won't cover the whole page,
                 * but there may be items after this page.  Make
@@ -3787,7 +4226,7 @@ static int send_write_or_clone(struct send_ctx *sctx,
                goto out;
        }
 
-       if (clone_root) {
+       if (clone_root && IS_ALIGNED(offset + len, bs)) {
                ret = send_clone(sctx, offset, len, clone_root);
        } else if (sctx->flags & BTRFS_SEND_FLAG_NO_FILE_DATA) {
                ret = send_update_extent(sctx, offset, len);
@@ -3979,6 +4418,101 @@ out:
        return ret;
 }
 
+static int get_last_extent(struct send_ctx *sctx, u64 offset)
+{
+       struct btrfs_path *path;
+       struct btrfs_root *root = sctx->send_root;
+       struct btrfs_file_extent_item *fi;
+       struct btrfs_key key;
+       u64 extent_end;
+       u8 type;
+       int ret;
+
+       path = alloc_path_for_send();
+       if (!path)
+               return -ENOMEM;
+
+       sctx->cur_inode_last_extent = 0;
+
+       key.objectid = sctx->cur_ino;
+       key.type = BTRFS_EXTENT_DATA_KEY;
+       key.offset = offset;
+       ret = btrfs_search_slot_for_read(root, &key, path, 0, 1);
+       if (ret < 0)
+               goto out;
+       ret = 0;
+       btrfs_item_key_to_cpu(path->nodes[0], &key, path->slots[0]);
+       if (key.objectid != sctx->cur_ino || key.type != BTRFS_EXTENT_DATA_KEY)
+               goto out;
+
+       fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                           struct btrfs_file_extent_item);
+       type = btrfs_file_extent_type(path->nodes[0], fi);
+       if (type == BTRFS_FILE_EXTENT_INLINE) {
+               u64 size = btrfs_file_extent_inline_len(path->nodes[0],
+                                                       path->slots[0], fi);
+               extent_end = ALIGN(key.offset + size,
+                                  sctx->send_root->sectorsize);
+       } else {
+               extent_end = key.offset +
+                       btrfs_file_extent_num_bytes(path->nodes[0], fi);
+       }
+       sctx->cur_inode_last_extent = extent_end;
+out:
+       btrfs_free_path(path);
+       return ret;
+}
+
+static int maybe_send_hole(struct send_ctx *sctx, struct btrfs_path *path,
+                          struct btrfs_key *key)
+{
+       struct btrfs_file_extent_item *fi;
+       u64 extent_end;
+       u8 type;
+       int ret = 0;
+
+       if (sctx->cur_ino != key->objectid || !need_send_hole(sctx))
+               return 0;
+
+       if (sctx->cur_inode_last_extent == (u64)-1) {
+               ret = get_last_extent(sctx, key->offset - 1);
+               if (ret)
+                       return ret;
+       }
+
+       fi = btrfs_item_ptr(path->nodes[0], path->slots[0],
+                           struct btrfs_file_extent_item);
+       type = btrfs_file_extent_type(path->nodes[0], fi);
+       if (type == BTRFS_FILE_EXTENT_INLINE) {
+               u64 size = btrfs_file_extent_inline_len(path->nodes[0],
+                                                       path->slots[0], fi);
+               extent_end = ALIGN(key->offset + size,
+                                  sctx->send_root->sectorsize);
+       } else {
+               extent_end = key->offset +
+                       btrfs_file_extent_num_bytes(path->nodes[0], fi);
+       }
+
+       if (path->slots[0] == 0 &&
+           sctx->cur_inode_last_extent < key->offset) {
+               /*
+                * We might have skipped entire leafs that contained only
+                * file extent items for our current inode. These leafs have
+                * a generation number smaller (older) than the one in the
+                * current leaf and the leaf our last extent came from, and
+                * are located between these 2 leafs.
+                */
+               ret = get_last_extent(sctx, key->offset - 1);
+               if (ret)
+                       return ret;
+       }
+
+       if (sctx->cur_inode_last_extent < key->offset)
+               ret = send_hole(sctx, key->offset);
+       sctx->cur_inode_last_extent = extent_end;
+       return ret;
+}
+
 static int process_extent(struct send_ctx *sctx,
                          struct btrfs_path *path,
                          struct btrfs_key *key)
@@ -3995,7 +4529,7 @@ static int process_extent(struct send_ctx *sctx,
                        goto out;
                if (ret) {
                        ret = 0;
-                       goto out;
+                       goto out_hole;
                }
        } else {
                struct btrfs_file_extent_item *ei;
@@ -4031,7 +4565,10 @@ static int process_extent(struct send_ctx *sctx,
                goto out;
 
        ret = send_write_or_clone(sctx, path, key, found_clone);
-
+       if (ret)
+               goto out;
+out_hole:
+       ret = maybe_send_hole(sctx, path, key);
 out:
        return ret;
 }
@@ -4054,17 +4591,25 @@ static int process_all_extents(struct send_ctx *sctx)
        key.objectid = sctx->cmp_key->objectid;
        key.type = BTRFS_EXTENT_DATA_KEY;
        key.offset = 0;
-       while (1) {
-               ret = btrfs_search_slot_for_read(root, &key, path, 1, 0);
-               if (ret < 0)
-                       goto out;
-               if (ret) {
-                       ret = 0;
-                       goto out;
-               }
+       ret = btrfs_search_slot(NULL, root, &key, path, 0, 0);
+       if (ret < 0)
+               goto out;
 
+       while (1) {
                eb = path->nodes[0];
                slot = path->slots[0];
+
+               if (slot >= btrfs_header_nritems(eb)) {
+                       ret = btrfs_next_leaf(root, path);
+                       if (ret < 0) {
+                               goto out;
+                       } else if (ret > 0) {
+                               ret = 0;
+                               break;
+                       }
+                       continue;
+               }
+
                btrfs_item_key_to_cpu(eb, &found_key, slot);
 
                if (found_key.objectid != key.objectid ||
@@ -4077,8 +4622,7 @@ static int process_all_extents(struct send_ctx *sctx)
                if (ret < 0)
                        goto out;
 
-               btrfs_release_path(path);
-               key.offset = found_key.offset + 1;
+               path->slots[0]++;
        }
 
 out:
@@ -4086,7 +4630,9 @@ out:
        return ret;
 }
 
-static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end)
+static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end,
+                                          int *pending_move,
+                                          int *refs_processed)
 {
        int ret = 0;
 
@@ -4098,17 +4644,11 @@ static int process_recorded_refs_if_needed(struct send_ctx *sctx, int at_end)
        if (list_empty(&sctx->new_refs) && list_empty(&sctx->deleted_refs))
                goto out;
 
-       ret = process_recorded_refs(sctx);
+       ret = process_recorded_refs(sctx, pending_move);
        if (ret < 0)
                goto out;
 
-       /*
-        * We have processed the refs and thus need to advance send_progress.
-        * Now, calls to get_cur_xxx will take the updated refs of the current
-        * inode into account.
-        */
-       sctx->send_progress = sctx->cur_ino + 1;
-
+       *refs_processed = 1;
 out:
        return ret;
 }
@@ -4124,11 +4664,29 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
        u64 right_gid;
        int need_chmod = 0;
        int need_chown = 0;
+       int pending_move = 0;
+       int refs_processed = 0;
 
-       ret = process_recorded_refs_if_needed(sctx, at_end);
+       ret = process_recorded_refs_if_needed(sctx, at_end, &pending_move,
+                                             &refs_processed);
        if (ret < 0)
                goto out;
 
+       /*
+        * We have processed the refs and thus need to advance send_progress.
+        * Now, calls to get_cur_xxx will take the updated refs of the current
+        * inode into account.
+        *
+        * On the other hand, if our current inode is a directory and couldn't
+        * be moved/renamed because its parent was renamed/moved too and it has
+        * a higher inode number, we can only move/rename our current inode
+        * after we moved/renamed its parent. Therefore in this case operate on
+        * the old path (pre move/rename) of our current inode, and the
+        * move/rename will be performed later.
+        */
+       if (refs_processed && !pending_move)
+               sctx->send_progress = sctx->cur_ino + 1;
+
        if (sctx->cur_ino == 0 || sctx->cur_inode_deleted)
                goto out;
        if (!at_end && sctx->cmp_key->objectid == sctx->cur_ino)
@@ -4157,6 +4715,19 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
        }
 
        if (S_ISREG(sctx->cur_inode_mode)) {
+               if (need_send_hole(sctx)) {
+                       if (sctx->cur_inode_last_extent == (u64)-1) {
+                               ret = get_last_extent(sctx, (u64)-1);
+                               if (ret)
+                                       goto out;
+                       }
+                       if (sctx->cur_inode_last_extent <
+                           sctx->cur_inode_size) {
+                               ret = send_hole(sctx, sctx->cur_inode_size);
+                               if (ret)
+                                       goto out;
+                       }
+               }
                ret = send_truncate(sctx, sctx->cur_ino, sctx->cur_inode_gen,
                                sctx->cur_inode_size);
                if (ret < 0)
@@ -4177,9 +4748,21 @@ static int finish_inode_if_needed(struct send_ctx *sctx, int at_end)
        }
 
        /*
-        * Need to send that every time, no matter if it actually changed
-        * between the two trees as we have done changes to the inode before.
+        * If other directory inodes depended on our current directory
+        * inode's move/rename, now do their move/rename operations.
+        */
+       if (!is_waiting_for_move(sctx, sctx->cur_ino)) {
+               ret = apply_children_dir_moves(sctx);
+               if (ret)
+                       goto out;
+       }
+
+       /*
+        * Need to send that every time, no matter if it actually
+        * changed between the two trees as we have done changes to
+        * the inode before.
         */
+       sctx->send_progress = sctx->cur_ino + 1;
        ret = send_utimes(sctx, sctx->cur_ino, sctx->cur_inode_gen);
        if (ret < 0)
                goto out;
@@ -4200,6 +4783,7 @@ static int changed_inode(struct send_ctx *sctx,
 
        sctx->cur_ino = key->objectid;
        sctx->cur_inode_new_gen = 0;
+       sctx->cur_inode_last_extent = (u64)-1;
 
        /*
         * Set send_progress to current inode. This will tell all get_cur_xxx
@@ -4480,14 +5064,18 @@ static int changed_cb(struct btrfs_root *left_root,
        struct send_ctx *sctx = ctx;
 
        if (result == BTRFS_COMPARE_TREE_SAME) {
-               if (key->type != BTRFS_INODE_REF_KEY &&
-                   key->type != BTRFS_INODE_EXTREF_KEY)
-                       return 0;
-               ret = compare_refs(sctx, left_path, key);
-               if (!ret)
+               if (key->type == BTRFS_INODE_REF_KEY ||
+                   key->type == BTRFS_INODE_EXTREF_KEY) {
+                       ret = compare_refs(sctx, left_path, key);
+                       if (!ret)
+                               return 0;
+                       if (ret < 0)
+                               return ret;
+               } else if (key->type == BTRFS_EXTENT_DATA_KEY) {
+                       return maybe_send_hole(sctx, left_path, key);
+               } else {
                        return 0;
-               if (ret < 0)
-                       return ret;
+               }
                result = BTRFS_COMPARE_TREE_CHANGED;
                ret = 0;
        }
@@ -4522,7 +5110,6 @@ out:
 static int full_send_tree(struct send_ctx *sctx)
 {
        int ret;
-       struct btrfs_trans_handle *trans = NULL;
        struct btrfs_root *send_root = sctx->send_root;
        struct btrfs_key key;
        struct btrfs_key found_key;
@@ -4544,19 +5131,6 @@ static int full_send_tree(struct send_ctx *sctx)
        key.type = BTRFS_INODE_ITEM_KEY;
        key.offset = 0;
 
-join_trans:
-       /*
-        * We need to make sure the transaction does not get committed
-        * while we do anything on commit roots. Join a transaction to prevent
-        * this.
-        */
-       trans = btrfs_join_transaction(send_root);
-       if (IS_ERR(trans)) {
-               ret = PTR_ERR(trans);
-               trans = NULL;
-               goto out;
-       }
-
        /*
         * Make sure the tree has not changed after re-joining. We detect this
         * by comparing start_ctransid and ctransid. They should always match.
@@ -4566,7 +5140,7 @@ join_trans:
        spin_unlock(&send_root->root_item_lock);
 
        if (ctransid != start_ctransid) {
-               WARN(1, KERN_WARNING "btrfs: the root that you're trying to "
+               WARN(1, KERN_WARNING "BTRFS: the root that you're trying to "
                                     "send was modified in between. This is "
                                     "probably a bug.\n");
                ret = -EIO;
@@ -4580,19 +5154,6 @@ join_trans:
                goto out_finish;
 
        while (1) {
-               /*
-                * When someone want to commit while we iterate, end the
-                * joined transaction and rejoin.
-                */
-               if (btrfs_should_end_transaction(trans, send_root)) {
-                       ret = btrfs_end_transaction(trans, send_root);
-                       trans = NULL;
-                       if (ret < 0)
-                               goto out;
-                       btrfs_release_path(path);
-                       goto join_trans;
-               }
-
                eb = path->nodes[0];
                slot = path->slots[0];
                btrfs_item_key_to_cpu(eb, &found_key, slot);
@@ -4620,12 +5181,6 @@ out_finish:
 
 out:
        btrfs_free_path(path);
-       if (trans) {
-               if (!ret)
-                       ret = btrfs_end_transaction(trans, send_root);
-               else
-                       btrfs_end_transaction(trans, send_root);
-       }
        return ret;
 }
 
@@ -4662,6 +5217,21 @@ out:
        return ret;
 }
 
+static void btrfs_root_dec_send_in_progress(struct btrfs_root* root)
+{
+       spin_lock(&root->root_item_lock);
+       root->send_in_progress--;
+       /*
+        * Not much left to do, we don't know why it's unbalanced and
+        * can't blindly reset it to 0.
+        */
+       if (root->send_in_progress < 0)
+               btrfs_err(root->fs_info,
+                       "send_in_progres unbalanced %d root %llu\n",
+                       root->send_in_progress, root->root_key.objectid);
+       spin_unlock(&root->root_item_lock);
+}
+
 long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
 {
        int ret = 0;
@@ -4673,6 +5243,9 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
        struct send_ctx *sctx = NULL;
        u32 i;
        u64 *clone_sources_tmp = NULL;
+       int clone_sources_to_rollback = 0;
+       int sort_clone_roots = 0;
+       int index;
 
        if (!capable(CAP_SYS_ADMIN))
                return -EPERM;
@@ -4680,6 +5253,14 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
        send_root = BTRFS_I(file_inode(mnt_file))->root;
        fs_info = send_root->fs_info;
 
+       /*
+        * The subvolume must remain read-only during send, protect against
+        * making it RW.
+        */
+       spin_lock(&send_root->root_item_lock);
+       send_root->send_in_progress++;
+       spin_unlock(&send_root->root_item_lock);
+
        /*
         * This is done when we lookup the root, it should already be complete
         * by the time we get here.
@@ -4687,32 +5268,12 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
        WARN_ON(send_root->orphan_cleanup_state != ORPHAN_CLEANUP_DONE);
 
        /*
-        * If we just created this root we need to make sure that the orphan
-        * cleanup has been done and committed since we search the commit root,
-        * so check its commit root transid with our otransid and if they match
-        * commit the transaction to make sure everything is updated.
+        * Userspace tools do the checks and warn the user if it's
+        * not RO.
         */
-       down_read(&send_root->fs_info->extent_commit_sem);
-       if (btrfs_header_generation(send_root->commit_root) ==
-           btrfs_root_otransid(&send_root->root_item)) {
-               struct btrfs_trans_handle *trans;
-
-               up_read(&send_root->fs_info->extent_commit_sem);
-
-               trans = btrfs_attach_transaction_barrier(send_root);
-               if (IS_ERR(trans)) {
-                       if (PTR_ERR(trans) != -ENOENT) {
-                               ret = PTR_ERR(trans);
-                               goto out;
-                       }
-                       /* ENOENT means theres no transaction */
-               } else {
-                       ret = btrfs_commit_transaction(trans, send_root);
-                       if (ret)
-                               goto out;
-               }
-       } else {
-               up_read(&send_root->fs_info->extent_commit_sem);
+       if (!btrfs_root_readonly(send_root)) {
+               ret = -EPERM;
+               goto out;
        }
 
        arg = memdup_user(arg_, sizeof(*arg));
@@ -4753,8 +5314,6 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
                goto out;
        }
 
-       sctx->mnt = mnt_file->f_path.mnt;
-
        sctx->send_root = send_root;
        sctx->clone_roots_cnt = arg->clone_sources_count;
 
@@ -4771,6 +5330,9 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
                goto out;
        }
 
+       sctx->pending_dir_moves = RB_ROOT;
+       sctx->waiting_dir_moves = RB_ROOT;
+
        sctx->clone_roots = vzalloc(sizeof(struct clone_root) *
                        (arg->clone_sources_count + 1));
        if (!sctx->clone_roots) {
@@ -4798,11 +5360,27 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
                        key.objectid = clone_sources_tmp[i];
                        key.type = BTRFS_ROOT_ITEM_KEY;
                        key.offset = (u64)-1;
+
+                       index = srcu_read_lock(&fs_info->subvol_srcu);
+
                        clone_root = btrfs_read_fs_root_no_name(fs_info, &key);
                        if (IS_ERR(clone_root)) {
+                               srcu_read_unlock(&fs_info->subvol_srcu, index);
                                ret = PTR_ERR(clone_root);
                                goto out;
                        }
+                       clone_sources_to_rollback = i + 1;
+                       spin_lock(&clone_root->root_item_lock);
+                       clone_root->send_in_progress++;
+                       if (!btrfs_root_readonly(clone_root)) {
+                               spin_unlock(&clone_root->root_item_lock);
+                               srcu_read_unlock(&fs_info->subvol_srcu, index);
+                               ret = -EPERM;
+                               goto out;
+                       }
+                       spin_unlock(&clone_root->root_item_lock);
+                       srcu_read_unlock(&fs_info->subvol_srcu, index);
+
                        sctx->clone_roots[i].root = clone_root;
                }
                vfree(clone_sources_tmp);
@@ -4813,11 +5391,27 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
                key.objectid = arg->parent_root;
                key.type = BTRFS_ROOT_ITEM_KEY;
                key.offset = (u64)-1;
+
+               index = srcu_read_lock(&fs_info->subvol_srcu);
+
                sctx->parent_root = btrfs_read_fs_root_no_name(fs_info, &key);
                if (IS_ERR(sctx->parent_root)) {
+                       srcu_read_unlock(&fs_info->subvol_srcu, index);
                        ret = PTR_ERR(sctx->parent_root);
                        goto out;
                }
+
+               spin_lock(&sctx->parent_root->root_item_lock);
+               sctx->parent_root->send_in_progress++;
+               if (!btrfs_root_readonly(sctx->parent_root)) {
+                       spin_unlock(&sctx->parent_root->root_item_lock);
+                       srcu_read_unlock(&fs_info->subvol_srcu, index);
+                       ret = -EPERM;
+                       goto out;
+               }
+               spin_unlock(&sctx->parent_root->root_item_lock);
+
+               srcu_read_unlock(&fs_info->subvol_srcu, index);
        }
 
        /*
@@ -4831,6 +5425,7 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
        sort(sctx->clone_roots, sctx->clone_roots_cnt,
                        sizeof(*sctx->clone_roots), __clone_root_cmp_sort,
                        NULL);
+       sort_clone_roots = 1;
 
        ret = send_subvol(sctx);
        if (ret < 0)
@@ -4846,6 +5441,48 @@ long btrfs_ioctl_send(struct file *mnt_file, void __user *arg_)
        }
 
 out:
+       WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->pending_dir_moves));
+       while (sctx && !RB_EMPTY_ROOT(&sctx->pending_dir_moves)) {
+               struct rb_node *n;
+               struct pending_dir_move *pm;
+
+               n = rb_first(&sctx->pending_dir_moves);
+               pm = rb_entry(n, struct pending_dir_move, node);
+               while (!list_empty(&pm->list)) {
+                       struct pending_dir_move *pm2;
+
+                       pm2 = list_first_entry(&pm->list,
+                                              struct pending_dir_move, list);
+                       free_pending_move(sctx, pm2);
+               }
+               free_pending_move(sctx, pm);
+       }
+
+       WARN_ON(sctx && !ret && !RB_EMPTY_ROOT(&sctx->waiting_dir_moves));
+       while (sctx && !RB_EMPTY_ROOT(&sctx->waiting_dir_moves)) {
+               struct rb_node *n;
+               struct waiting_dir_move *dm;
+
+               n = rb_first(&sctx->waiting_dir_moves);
+               dm = rb_entry(n, struct waiting_dir_move, node);
+               rb_erase(&dm->node, &sctx->waiting_dir_moves);
+               kfree(dm);
+       }
+
+       if (sort_clone_roots) {
+               for (i = 0; i < sctx->clone_roots_cnt; i++)
+                       btrfs_root_dec_send_in_progress(
+                                       sctx->clone_roots[i].root);
+       } else {
+               for (i = 0; sctx && i < clone_sources_to_rollback; i++)
+                       btrfs_root_dec_send_in_progress(
+                                       sctx->clone_roots[i].root);
+
+               btrfs_root_dec_send_in_progress(send_root);
+       }
+       if (sctx && !IS_ERR_OR_NULL(sctx->parent_root))
+               btrfs_root_dec_send_in_progress(sctx->parent_root);
+
        kfree(arg);
        vfree(clone_sources_tmp);
 
index d71a11d13dfaa8b3065222c87ce964d8ba28e5b5..c02f63356895ff7fc5b59f36748e7aeb36840e04 100644 (file)
@@ -48,6 +48,8 @@
 #include "transaction.h"
 #include "btrfs_inode.h"
 #include "print-tree.h"
+#include "hash.h"
+#include "props.h"
 #include "xattr.h"
 #include "volumes.h"
 #include "export.h"
@@ -152,11 +154,12 @@ void __btrfs_std_error(struct btrfs_fs_info *fs_info, const char *function,
                vaf.fmt = fmt;
                vaf.va = &args;
 
-               printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: errno=%d %s (%pV)\n",
+               printk(KERN_CRIT
+                       "BTRFS: error (device %s) in %s:%d: errno=%d %s (%pV)\n",
                        sb->s_id, function, line, errno, errstr, &vaf);
                va_end(args);
        } else {
-               printk(KERN_CRIT "BTRFS error (device %s) in %s:%d: errno=%d %s\n",
+               printk(KERN_CRIT "BTRFS: error (device %s) in %s:%d: errno=%d %s\n",
                        sb->s_id, function, line, errno, errstr);
        }
 
@@ -250,7 +253,7 @@ void __btrfs_abort_transaction(struct btrfs_trans_handle *trans,
         */
        if (!test_and_set_bit(BTRFS_FS_STATE_TRANS_ABORTED,
                                &root->fs_info->fs_state)) {
-               WARN(1, KERN_DEBUG "btrfs: Transaction aborted (error %d)\n",
+               WARN(1, KERN_DEBUG "BTRFS: Transaction aborted (error %d)\n",
                                errno);
        }
        trans->aborted = errno;
@@ -294,8 +297,8 @@ void __btrfs_panic(struct btrfs_fs_info *fs_info, const char *function,
                panic(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (errno=%d %s)\n",
                        s_id, function, line, &vaf, errno, errstr);
 
-       printk(KERN_CRIT "BTRFS panic (device %s) in %s:%d: %pV (errno=%d %s)\n",
-              s_id, function, line, &vaf, errno, errstr);
+       btrfs_crit(fs_info, "panic in %s:%d: %pV (errno=%d %s)",
+                  function, line, &vaf, errno, errstr);
        va_end(args);
        /* Caller calls BUG() */
 }
@@ -322,7 +325,9 @@ enum {
        Opt_no_space_cache, Opt_recovery, Opt_skip_balance,
        Opt_check_integrity, Opt_check_integrity_including_extent_data,
        Opt_check_integrity_print_mask, Opt_fatal_errors, Opt_rescan_uuid_tree,
-       Opt_commit_interval,
+       Opt_commit_interval, Opt_barrier, Opt_nodefrag, Opt_nodiscard,
+       Opt_noenospc_debug, Opt_noflushoncommit, Opt_acl, Opt_datacow,
+       Opt_datasum, Opt_treelog, Opt_noinode_cache,
        Opt_err,
 };
 
@@ -332,8 +337,11 @@ static match_table_t tokens = {
        {Opt_subvolid, "subvolid=%s"},
        {Opt_device, "device=%s"},
        {Opt_nodatasum, "nodatasum"},
+       {Opt_datasum, "datasum"},
        {Opt_nodatacow, "nodatacow"},
+       {Opt_datacow, "datacow"},
        {Opt_nobarrier, "nobarrier"},
+       {Opt_barrier, "barrier"},
        {Opt_max_inline, "max_inline=%s"},
        {Opt_alloc_start, "alloc_start=%s"},
        {Opt_thread_pool, "thread_pool=%d"},
@@ -344,18 +352,25 @@ static match_table_t tokens = {
        {Opt_ssd, "ssd"},
        {Opt_ssd_spread, "ssd_spread"},
        {Opt_nossd, "nossd"},
+       {Opt_acl, "acl"},
        {Opt_noacl, "noacl"},
        {Opt_notreelog, "notreelog"},
+       {Opt_treelog, "treelog"},
        {Opt_flushoncommit, "flushoncommit"},
+       {Opt_noflushoncommit, "noflushoncommit"},
        {Opt_ratio, "metadata_ratio=%d"},
        {Opt_discard, "discard"},
+       {Opt_nodiscard, "nodiscard"},
        {Opt_space_cache, "space_cache"},
        {Opt_clear_cache, "clear_cache"},
        {Opt_user_subvol_rm_allowed, "user_subvol_rm_allowed"},
        {Opt_enospc_debug, "enospc_debug"},
+       {Opt_noenospc_debug, "noenospc_debug"},
        {Opt_subvolrootid, "subvolrootid=%d"},
        {Opt_defrag, "autodefrag"},
+       {Opt_nodefrag, "noautodefrag"},
        {Opt_inode_cache, "inode_cache"},
+       {Opt_noinode_cache, "noinode_cache"},
        {Opt_no_space_cache, "nospace_cache"},
        {Opt_recovery, "recovery"},
        {Opt_skip_balance, "skip_balance"},
@@ -368,6 +383,20 @@ static match_table_t tokens = {
        {Opt_err, NULL},
 };
 
+#define btrfs_set_and_info(root, opt, fmt, args...)                    \
+{                                                                      \
+       if (!btrfs_test_opt(root, opt))                                 \
+               btrfs_info(root->fs_info, fmt, ##args);                 \
+       btrfs_set_opt(root->fs_info->mount_opt, opt);                   \
+}
+
+#define btrfs_clear_and_info(root, opt, fmt, args...)                  \
+{                                                                      \
+       if (btrfs_test_opt(root, opt))                                  \
+               btrfs_info(root->fs_info, fmt, ##args);                 \
+       btrfs_clear_opt(root->fs_info->mount_opt, opt);                 \
+}
+
 /*
  * Regular mount options parser.  Everything that is needed only when
  * reading in a new superblock is parsed here.
@@ -383,6 +412,7 @@ 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)
@@ -409,7 +439,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                token = match_token(p, tokens, args);
                switch (token) {
                case Opt_degraded:
-                       printk(KERN_INFO "btrfs: allowing degraded mounts\n");
+                       btrfs_info(root->fs_info, "allowing degraded mounts");
                        btrfs_set_opt(info->mount_opt, DEGRADED);
                        break;
                case Opt_subvol:
@@ -422,27 +452,45 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                         */
                        break;
                case Opt_nodatasum:
-                       printk(KERN_INFO "btrfs: setting nodatasum\n");
-                       btrfs_set_opt(info->mount_opt, NODATASUM);
+                       btrfs_set_and_info(root, NODATASUM,
+                                          "setting nodatasum");
+                       break;
+               case Opt_datasum:
+                       if (btrfs_test_opt(root, NODATASUM)) {
+                               if (btrfs_test_opt(root, NODATACOW))
+                                       btrfs_info(root->fs_info, "setting datasum, datacow enabled");
+                               else
+                                       btrfs_info(root->fs_info, "setting datasum");
+                       }
+                       btrfs_clear_opt(info->mount_opt, NODATACOW);
+                       btrfs_clear_opt(info->mount_opt, NODATASUM);
                        break;
                case Opt_nodatacow:
-                       if (!btrfs_test_opt(root, COMPRESS) ||
-                               !btrfs_test_opt(root, FORCE_COMPRESS)) {
-                                       printk(KERN_INFO "btrfs: setting nodatacow, compression disabled\n");
-                       } else {
-                               printk(KERN_INFO "btrfs: setting nodatacow\n");
+                       if (!btrfs_test_opt(root, NODATACOW)) {
+                               if (!btrfs_test_opt(root, COMPRESS) ||
+                                   !btrfs_test_opt(root, FORCE_COMPRESS)) {
+                                       btrfs_info(root->fs_info,
+                                                  "setting nodatacow, compression disabled");
+                               } else {
+                                       btrfs_info(root->fs_info, "setting nodatacow");
+                               }
                        }
                        btrfs_clear_opt(info->mount_opt, COMPRESS);
                        btrfs_clear_opt(info->mount_opt, FORCE_COMPRESS);
                        btrfs_set_opt(info->mount_opt, NODATACOW);
                        btrfs_set_opt(info->mount_opt, NODATASUM);
                        break;
+               case Opt_datacow:
+                       btrfs_clear_and_info(root, NODATACOW,
+                                            "setting datacow");
+                       break;
                case Opt_compress_force:
                case Opt_compress_force_type:
                        compress_force = true;
                        /* Fallthrough */
                case Opt_compress:
                case Opt_compress_type:
+                       compress = true;
                        if (token == Opt_compress ||
                            token == Opt_compress_force ||
                            strcmp(args[0].from, "zlib") == 0) {
@@ -469,34 +517,36 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        }
 
                        if (compress_force) {
-                               btrfs_set_opt(info->mount_opt, FORCE_COMPRESS);
-                               pr_info("btrfs: force %s compression\n",
-                                       compress_type);
-                       } else if (btrfs_test_opt(root, COMPRESS)) {
-                               pr_info("btrfs: use %s compression\n",
-                                       compress_type);
+                               btrfs_set_and_info(root, FORCE_COMPRESS,
+                                                  "force %s compression",
+                                                  compress_type);
+                       } else if (compress) {
+                               if (!btrfs_test_opt(root, COMPRESS))
+                                       btrfs_info(root->fs_info,
+                                                  "btrfs: use %s compression\n",
+                                                  compress_type);
                        }
                        break;
                case Opt_ssd:
-                       printk(KERN_INFO "btrfs: use ssd allocation scheme\n");
-                       btrfs_set_opt(info->mount_opt, SSD);
+                       btrfs_set_and_info(root, SSD,
+                                          "use ssd allocation scheme");
                        break;
                case Opt_ssd_spread:
-                       printk(KERN_INFO "btrfs: use spread ssd "
-                              "allocation scheme\n");
-                       btrfs_set_opt(info->mount_opt, SSD);
-                       btrfs_set_opt(info->mount_opt, SSD_SPREAD);
+                       btrfs_set_and_info(root, SSD_SPREAD,
+                                          "use spread ssd allocation scheme");
                        break;
                case Opt_nossd:
-                       printk(KERN_INFO "btrfs: not using ssd allocation "
-                              "scheme\n");
-                       btrfs_set_opt(info->mount_opt, NOSSD);
+                       btrfs_clear_and_info(root, NOSSD,
+                                            "not using ssd allocation scheme");
                        btrfs_clear_opt(info->mount_opt, SSD);
-                       btrfs_clear_opt(info->mount_opt, SSD_SPREAD);
+                       break;
+               case Opt_barrier:
+                       btrfs_clear_and_info(root, NOBARRIER,
+                                            "turning on barriers");
                        break;
                case Opt_nobarrier:
-                       printk(KERN_INFO "btrfs: turning off barriers\n");
-                       btrfs_set_opt(info->mount_opt, NOBARRIER);
+                       btrfs_set_and_info(root, NOBARRIER,
+                                          "turning off barriers");
                        break;
                case Opt_thread_pool:
                        ret = match_int(&args[0], &intarg);
@@ -520,7 +570,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                                info->max_inline,
                                                root->sectorsize);
                                }
-                               printk(KERN_INFO "btrfs: max_inline at %llu\n",
+                               btrfs_info(root->fs_info, "max_inline at %llu",
                                        info->max_inline);
                        } else {
                                ret = -ENOMEM;
@@ -534,24 +584,34 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                info->alloc_start = memparse(num, NULL);
                                mutex_unlock(&info->chunk_mutex);
                                kfree(num);
-                               printk(KERN_INFO
-                                       "btrfs: allocations start at %llu\n",
+                               btrfs_info(root->fs_info, "allocations start at %llu",
                                        info->alloc_start);
                        } else {
                                ret = -ENOMEM;
                                goto out;
                        }
                        break;
+               case Opt_acl:
+                       root->fs_info->sb->s_flags |= MS_POSIXACL;
+                       break;
                case Opt_noacl:
                        root->fs_info->sb->s_flags &= ~MS_POSIXACL;
                        break;
                case Opt_notreelog:
-                       printk(KERN_INFO "btrfs: disabling tree log\n");
-                       btrfs_set_opt(info->mount_opt, NOTREELOG);
+                       btrfs_set_and_info(root, NOTREELOG,
+                                          "disabling tree log");
+                       break;
+               case Opt_treelog:
+                       btrfs_clear_and_info(root, NOTREELOG,
+                                            "enabling tree log");
                        break;
                case Opt_flushoncommit:
-                       printk(KERN_INFO "btrfs: turning on flush-on-commit\n");
-                       btrfs_set_opt(info->mount_opt, FLUSHONCOMMIT);
+                       btrfs_set_and_info(root, FLUSHONCOMMIT,
+                                          "turning on flush-on-commit");
+                       break;
+               case Opt_noflushoncommit:
+                       btrfs_clear_and_info(root, FLUSHONCOMMIT,
+                                            "turning off flush-on-commit");
                        break;
                case Opt_ratio:
                        ret = match_int(&args[0], &intarg);
@@ -559,7 +619,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                goto out;
                        } else if (intarg >= 0) {
                                info->metadata_ratio = intarg;
-                               printk(KERN_INFO "btrfs: metadata ratio %d\n",
+                               btrfs_info(root->fs_info, "metadata ratio %d",
                                       info->metadata_ratio);
                        } else {
                                ret = -EINVAL;
@@ -567,25 +627,35 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        }
                        break;
                case Opt_discard:
-                       btrfs_set_opt(info->mount_opt, DISCARD);
+                       btrfs_set_and_info(root, DISCARD,
+                                          "turning on discard");
+                       break;
+               case Opt_nodiscard:
+                       btrfs_clear_and_info(root, DISCARD,
+                                            "turning off discard");
                        break;
                case Opt_space_cache:
-                       btrfs_set_opt(info->mount_opt, SPACE_CACHE);
+                       btrfs_set_and_info(root, SPACE_CACHE,
+                                          "enabling disk space caching");
                        break;
                case Opt_rescan_uuid_tree:
                        btrfs_set_opt(info->mount_opt, RESCAN_UUID_TREE);
                        break;
                case Opt_no_space_cache:
-                       printk(KERN_INFO "btrfs: disabling disk space caching\n");
-                       btrfs_clear_opt(info->mount_opt, SPACE_CACHE);
+                       btrfs_clear_and_info(root, SPACE_CACHE,
+                                            "disabling disk space caching");
                        break;
                case Opt_inode_cache:
-                       printk(KERN_INFO "btrfs: enabling inode map caching\n");
-                       btrfs_set_opt(info->mount_opt, INODE_MAP_CACHE);
+                       btrfs_set_and_info(root, CHANGE_INODE_CACHE,
+                                          "enabling inode map caching");
+                       break;
+               case Opt_noinode_cache:
+                       btrfs_clear_and_info(root, CHANGE_INODE_CACHE,
+                                            "disabling inode map caching");
                        break;
                case Opt_clear_cache:
-                       printk(KERN_INFO "btrfs: force clearing of disk cache\n");
-                       btrfs_set_opt(info->mount_opt, CLEAR_CACHE);
+                       btrfs_set_and_info(root, CLEAR_CACHE,
+                                          "force clearing of disk cache");
                        break;
                case Opt_user_subvol_rm_allowed:
                        btrfs_set_opt(info->mount_opt, USER_SUBVOL_RM_ALLOWED);
@@ -593,12 +663,19 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_enospc_debug:
                        btrfs_set_opt(info->mount_opt, ENOSPC_DEBUG);
                        break;
+               case Opt_noenospc_debug:
+                       btrfs_clear_opt(info->mount_opt, ENOSPC_DEBUG);
+                       break;
                case Opt_defrag:
-                       printk(KERN_INFO "btrfs: enabling auto defrag\n");
-                       btrfs_set_opt(info->mount_opt, AUTO_DEFRAG);
+                       btrfs_set_and_info(root, AUTO_DEFRAG,
+                                          "enabling auto defrag");
+                       break;
+               case Opt_nodefrag:
+                       btrfs_clear_and_info(root, AUTO_DEFRAG,
+                                            "disabling auto defrag");
                        break;
                case Opt_recovery:
-                       printk(KERN_INFO "btrfs: enabling auto recovery\n");
+                       btrfs_info(root->fs_info, "enabling auto recovery");
                        btrfs_set_opt(info->mount_opt, RECOVERY);
                        break;
                case Opt_skip_balance:
@@ -606,14 +683,14 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        break;
 #ifdef CONFIG_BTRFS_FS_CHECK_INTEGRITY
                case Opt_check_integrity_including_extent_data:
-                       printk(KERN_INFO "btrfs: enabling check integrity"
-                              " including extent data\n");
+                       btrfs_info(root->fs_info,
+                                  "enabling check integrity including extent data");
                        btrfs_set_opt(info->mount_opt,
                                      CHECK_INTEGRITY_INCLUDING_EXTENT_DATA);
                        btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY);
                        break;
                case Opt_check_integrity:
-                       printk(KERN_INFO "btrfs: enabling check integrity\n");
+                       btrfs_info(root->fs_info, "enabling check integrity");
                        btrfs_set_opt(info->mount_opt, CHECK_INTEGRITY);
                        break;
                case Opt_check_integrity_print_mask:
@@ -622,8 +699,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                                goto out;
                        } else if (intarg >= 0) {
                                info->check_integrity_print_mask = intarg;
-                               printk(KERN_INFO "btrfs:"
-                                      " check_integrity_print_mask 0x%x\n",
+                               btrfs_info(root->fs_info, "check_integrity_print_mask 0x%x",
                                       info->check_integrity_print_mask);
                        } else {
                                ret = -EINVAL;
@@ -634,8 +710,8 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                case Opt_check_integrity_including_extent_data:
                case Opt_check_integrity:
                case Opt_check_integrity_print_mask:
-                       printk(KERN_ERR "btrfs: support for check_integrity*"
-                              " not compiled in!\n");
+                       btrfs_err(root->fs_info,
+                               "support for check_integrity* not compiled in!");
                        ret = -EINVAL;
                        goto out;
 #endif
@@ -655,28 +731,24 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
                        intarg = 0;
                        ret = match_int(&args[0], &intarg);
                        if (ret < 0) {
-                               printk(KERN_ERR
-                                       "btrfs: invalid commit interval\n");
+                               btrfs_err(root->fs_info, "invalid commit interval");
                                ret = -EINVAL;
                                goto out;
                        }
                        if (intarg > 0) {
                                if (intarg > 300) {
-                                       printk(KERN_WARNING
-                                           "btrfs: excessive commit interval %d\n",
+                                       btrfs_warn(root->fs_info, "excessive commit interval %d",
                                                        intarg);
                                }
                                info->commit_interval = intarg;
                        } else {
-                               printk(KERN_INFO
-                                   "btrfs: using default commit interval %ds\n",
+                               btrfs_info(root->fs_info, "using default commit interval %ds",
                                    BTRFS_DEFAULT_COMMIT_INTERVAL);
                                info->commit_interval = BTRFS_DEFAULT_COMMIT_INTERVAL;
                        }
                        break;
                case Opt_err:
-                       printk(KERN_INFO "btrfs: unrecognized mount option "
-                              "'%s'\n", p);
+                       btrfs_info(root->fs_info, "unrecognized mount option '%s'", p);
                        ret = -EINVAL;
                        goto out;
                default:
@@ -685,7 +757,7 @@ int btrfs_parse_options(struct btrfs_root *root, char *options)
        }
 out:
        if (!ret && btrfs_test_opt(root, SPACE_CACHE))
-               printk(KERN_INFO "btrfs: disk space caching is enabled\n");
+               btrfs_info(root->fs_info, "disk space caching is enabled");
        kfree(orig);
        return ret;
 }
@@ -748,7 +820,8 @@ static int btrfs_parse_early_options(const char *options, fmode_t flags,
                        break;
                case Opt_subvolrootid:
                        printk(KERN_WARNING
-                               "btrfs: 'subvolrootid' mount option is deprecated and has no effect\n");
+                               "BTRFS: 'subvolrootid' mount option is deprecated and has "
+                               "no effect\n");
                        break;
                case Opt_device:
                        device_name = match_strdup(&args[0]);
@@ -877,7 +950,7 @@ static int btrfs_fill_super(struct super_block *sb,
        sb->s_flags |= MS_I_VERSION;
        err = open_ctree(sb, fs_devices, (char *)data);
        if (err) {
-               printk("btrfs: open_ctree failed\n");
+               printk(KERN_ERR "BTRFS: open_ctree failed\n");
                return err;
        }
 
@@ -1115,7 +1188,7 @@ static struct dentry *mount_subvol(const char *subvol_name, int flags,
                dput(root);
                root = ERR_PTR(-EINVAL);
                deactivate_locked_super(s);
-               printk(KERN_ERR "btrfs: '%s' is not a valid subvolume\n",
+               printk(KERN_ERR "BTRFS: '%s' is not a valid subvolume\n",
                                subvol_name);
        }
 
@@ -1240,7 +1313,7 @@ static void btrfs_resize_thread_pool(struct btrfs_fs_info *fs_info,
 
        fs_info->thread_pool_size = new_pool_size;
 
-       printk(KERN_INFO "btrfs: resize thread pool %d -> %d\n",
+       btrfs_info(fs_info, "resize thread pool %d -> %d",
               old_pool_size, new_pool_size);
 
        btrfs_set_max_workers(&fs_info->generic_worker, new_pool_size);
@@ -1346,7 +1419,7 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
        } else {
                if (test_bit(BTRFS_FS_STATE_ERROR, &root->fs_info->fs_state)) {
                        btrfs_err(fs_info,
-                               "Remounting read-write after error is not allowed\n");
+                               "Remounting read-write after error is not allowed");
                        ret = -EINVAL;
                        goto restore;
                }
@@ -1358,8 +1431,8 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
                if (fs_info->fs_devices->missing_devices >
                     fs_info->num_tolerated_disk_barrier_failures &&
                    !(*flags & MS_RDONLY)) {
-                       printk(KERN_WARNING
-                              "Btrfs: too many missing devices, writeable remount is not allowed\n");
+                       btrfs_warn(fs_info,
+                               "too many missing devices, writeable remount is not allowed");
                        ret = -EACCES;
                        goto restore;
                }
@@ -1384,16 +1457,15 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
 
                ret = btrfs_resume_dev_replace_async(fs_info);
                if (ret) {
-                       pr_warn("btrfs: failed to resume dev_replace\n");
+                       btrfs_warn(fs_info, "failed to resume dev_replace");
                        goto restore;
                }
 
                if (!fs_info->uuid_root) {
-                       pr_info("btrfs: creating UUID tree\n");
+                       btrfs_info(fs_info, "creating UUID tree");
                        ret = btrfs_create_uuid_tree(fs_info);
                        if (ret) {
-                               pr_warn("btrfs: failed to create the uuid tree"
-                                       "%d\n", ret);
+                               btrfs_warn(fs_info, "failed to create the UUID tree %d", ret);
                                goto restore;
                        }
                }
@@ -1773,7 +1845,7 @@ static int btrfs_interface_init(void)
 static void btrfs_interface_exit(void)
 {
        if (misc_deregister(&btrfs_misc) < 0)
-               printk(KERN_INFO "btrfs: misc_deregister failed for control device\n");
+               printk(KERN_INFO "BTRFS: misc_deregister failed for control device\n");
 }
 
 static void btrfs_print_info(void)
@@ -1818,10 +1890,16 @@ static int __init init_btrfs_fs(void)
 {
        int err;
 
-       err = btrfs_init_sysfs();
+       err = btrfs_hash_init();
        if (err)
                return err;
 
+       btrfs_props_init();
+
+       err = btrfs_init_sysfs();
+       if (err)
+               goto free_hash;
+
        btrfs_init_compress();
 
        err = btrfs_init_cachep();
@@ -1895,6 +1973,8 @@ free_cachep:
 free_compress:
        btrfs_exit_compress();
        btrfs_exit_sysfs();
+free_hash:
+       btrfs_hash_exit();
        return err;
 }
 
@@ -1913,6 +1993,7 @@ static void __exit exit_btrfs_fs(void)
        btrfs_exit_sysfs();
        btrfs_cleanup_fs_uuids();
        btrfs_exit_compress();
+       btrfs_hash_exit();
 }
 
 module_init(init_btrfs_fs)
index 5b326cd60a4aa3c048eefe730312248d73cf47ba..782374d8fd1970ee9d6b4742fc2e213dc4d2e637 100644 (file)
 #include <linux/completion.h>
 #include <linux/buffer_head.h>
 #include <linux/kobject.h>
+#include <linux/bug.h>
+#include <linux/genhd.h>
 
 #include "ctree.h"
 #include "disk-io.h"
 #include "transaction.h"
+#include "sysfs.h"
+#include "volumes.h"
+
+static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj);
+
+static u64 get_features(struct btrfs_fs_info *fs_info,
+                       enum btrfs_feature_set set)
+{
+       struct btrfs_super_block *disk_super = fs_info->super_copy;
+       if (set == FEAT_COMPAT)
+               return btrfs_super_compat_flags(disk_super);
+       else if (set == FEAT_COMPAT_RO)
+               return btrfs_super_compat_ro_flags(disk_super);
+       else
+               return btrfs_super_incompat_flags(disk_super);
+}
+
+static void set_features(struct btrfs_fs_info *fs_info,
+                        enum btrfs_feature_set set, u64 features)
+{
+       struct btrfs_super_block *disk_super = fs_info->super_copy;
+       if (set == FEAT_COMPAT)
+               btrfs_set_super_compat_flags(disk_super, features);
+       else if (set == FEAT_COMPAT_RO)
+               btrfs_set_super_compat_ro_flags(disk_super, features);
+       else
+               btrfs_set_super_incompat_flags(disk_super, features);
+}
+
+static int can_modify_feature(struct btrfs_feature_attr *fa)
+{
+       int val = 0;
+       u64 set, clear;
+       switch (fa->feature_set) {
+       case FEAT_COMPAT:
+               set = BTRFS_FEATURE_COMPAT_SAFE_SET;
+               clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR;
+               break;
+       case FEAT_COMPAT_RO:
+               set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET;
+               clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR;
+               break;
+       case FEAT_INCOMPAT:
+               set = BTRFS_FEATURE_INCOMPAT_SAFE_SET;
+               clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR;
+               break;
+       default:
+               printk(KERN_WARNING "btrfs: sysfs: unknown feature set %d\n",
+                               fa->feature_set);
+               return 0;
+       }
+
+       if (set & fa->feature_bit)
+               val |= 1;
+       if (clear & fa->feature_bit)
+               val |= 2;
+
+       return val;
+}
+
+static ssize_t btrfs_feature_attr_show(struct kobject *kobj,
+                                      struct kobj_attribute *a, char *buf)
+{
+       int val = 0;
+       struct btrfs_fs_info *fs_info = to_fs_info(kobj);
+       struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
+       if (fs_info) {
+               u64 features = get_features(fs_info, fa->feature_set);
+               if (features & fa->feature_bit)
+                       val = 1;
+       } else
+               val = can_modify_feature(fa);
+
+       return snprintf(buf, PAGE_SIZE, "%d\n", val);
+}
+
+static ssize_t btrfs_feature_attr_store(struct kobject *kobj,
+                                       struct kobj_attribute *a,
+                                       const char *buf, size_t count)
+{
+       struct btrfs_fs_info *fs_info;
+       struct btrfs_feature_attr *fa = to_btrfs_feature_attr(a);
+       struct btrfs_trans_handle *trans;
+       u64 features, set, clear;
+       unsigned long val;
+       int ret;
+
+       fs_info = to_fs_info(kobj);
+       if (!fs_info)
+               return -EPERM;
+
+       ret = kstrtoul(skip_spaces(buf), 0, &val);
+       if (ret)
+               return ret;
+
+       if (fa->feature_set == FEAT_COMPAT) {
+               set = BTRFS_FEATURE_COMPAT_SAFE_SET;
+               clear = BTRFS_FEATURE_COMPAT_SAFE_CLEAR;
+       } else if (fa->feature_set == FEAT_COMPAT_RO) {
+               set = BTRFS_FEATURE_COMPAT_RO_SAFE_SET;
+               clear = BTRFS_FEATURE_COMPAT_RO_SAFE_CLEAR;
+       } else {
+               set = BTRFS_FEATURE_INCOMPAT_SAFE_SET;
+               clear = BTRFS_FEATURE_INCOMPAT_SAFE_CLEAR;
+       }
+
+       features = get_features(fs_info, fa->feature_set);
+
+       /* Nothing to do */
+       if ((val && (features & fa->feature_bit)) ||
+           (!val && !(features & fa->feature_bit)))
+               return count;
+
+       if ((val && !(set & fa->feature_bit)) ||
+           (!val && !(clear & fa->feature_bit))) {
+               btrfs_info(fs_info,
+                       "%sabling feature %s on mounted fs is not supported.",
+                       val ? "En" : "Dis", fa->kobj_attr.attr.name);
+               return -EPERM;
+       }
+
+       btrfs_info(fs_info, "%s %s feature flag",
+                  val ? "Setting" : "Clearing", fa->kobj_attr.attr.name);
+
+       trans = btrfs_start_transaction(fs_info->fs_root, 0);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+
+       spin_lock(&fs_info->super_lock);
+       features = get_features(fs_info, fa->feature_set);
+       if (val)
+               features |= fa->feature_bit;
+       else
+               features &= ~fa->feature_bit;
+       set_features(fs_info, fa->feature_set, features);
+       spin_unlock(&fs_info->super_lock);
+
+       ret = btrfs_commit_transaction(trans, fs_info->fs_root);
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static umode_t btrfs_feature_visible(struct kobject *kobj,
+                                    struct attribute *attr, int unused)
+{
+       struct btrfs_fs_info *fs_info = to_fs_info(kobj);
+       umode_t mode = attr->mode;
+
+       if (fs_info) {
+               struct btrfs_feature_attr *fa;
+               u64 features;
+
+               fa = attr_to_btrfs_feature_attr(attr);
+               features = get_features(fs_info, fa->feature_set);
+
+               if (can_modify_feature(fa))
+                       mode |= S_IWUSR;
+               else if (!(features & fa->feature_bit))
+                       mode = 0;
+       }
+
+       return mode;
+}
+
+BTRFS_FEAT_ATTR_INCOMPAT(mixed_backref, MIXED_BACKREF);
+BTRFS_FEAT_ATTR_INCOMPAT(default_subvol, DEFAULT_SUBVOL);
+BTRFS_FEAT_ATTR_INCOMPAT(mixed_groups, MIXED_GROUPS);
+BTRFS_FEAT_ATTR_INCOMPAT(compress_lzo, COMPRESS_LZO);
+BTRFS_FEAT_ATTR_INCOMPAT(big_metadata, BIG_METADATA);
+BTRFS_FEAT_ATTR_INCOMPAT(extended_iref, EXTENDED_IREF);
+BTRFS_FEAT_ATTR_INCOMPAT(raid56, RAID56);
+BTRFS_FEAT_ATTR_INCOMPAT(skinny_metadata, SKINNY_METADATA);
+BTRFS_FEAT_ATTR_INCOMPAT(no_holes, NO_HOLES);
+
+static struct attribute *btrfs_supported_feature_attrs[] = {
+       BTRFS_FEAT_ATTR_PTR(mixed_backref),
+       BTRFS_FEAT_ATTR_PTR(default_subvol),
+       BTRFS_FEAT_ATTR_PTR(mixed_groups),
+       BTRFS_FEAT_ATTR_PTR(compress_lzo),
+       BTRFS_FEAT_ATTR_PTR(big_metadata),
+       BTRFS_FEAT_ATTR_PTR(extended_iref),
+       BTRFS_FEAT_ATTR_PTR(raid56),
+       BTRFS_FEAT_ATTR_PTR(skinny_metadata),
+       BTRFS_FEAT_ATTR_PTR(no_holes),
+       NULL
+};
+
+static const struct attribute_group btrfs_feature_attr_group = {
+       .name = "features",
+       .is_visible = btrfs_feature_visible,
+       .attrs = btrfs_supported_feature_attrs,
+};
+
+static ssize_t btrfs_show_u64(u64 *value_ptr, spinlock_t *lock, char *buf)
+{
+       u64 val;
+       if (lock)
+               spin_lock(lock);
+       val = *value_ptr;
+       if (lock)
+               spin_unlock(lock);
+       return snprintf(buf, PAGE_SIZE, "%llu\n", val);
+}
+
+static ssize_t global_rsv_size_show(struct kobject *kobj,
+                                   struct kobj_attribute *ka, char *buf)
+{
+       struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
+       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);
+
+static ssize_t global_rsv_reserved_show(struct kobject *kobj,
+                                       struct kobj_attribute *a, char *buf)
+{
+       struct btrfs_fs_info *fs_info = to_fs_info(kobj->parent);
+       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);
+
+#define to_space_info(_kobj) container_of(_kobj, struct btrfs_space_info, kobj)
+
+static ssize_t raid_bytes_show(struct kobject *kobj,
+                              struct kobj_attribute *attr, char *buf);
+BTRFS_RAID_ATTR(total_bytes, raid_bytes_show);
+BTRFS_RAID_ATTR(used_bytes, raid_bytes_show);
+
+static ssize_t raid_bytes_show(struct kobject *kobj,
+                              struct kobj_attribute *attr, char *buf)
+
+{
+       struct btrfs_space_info *sinfo = to_space_info(kobj->parent);
+       struct btrfs_block_group_cache *block_group;
+       int index = kobj - sinfo->block_group_kobjs;
+       u64 val = 0;
+
+       down_read(&sinfo->groups_sem);
+       list_for_each_entry(block_group, &sinfo->block_groups[index], list) {
+               if (&attr->attr == BTRFS_RAID_ATTR_PTR(total_bytes))
+                       val += block_group->key.offset;
+               else
+                       val += btrfs_block_group_used(&block_group->item);
+       }
+       up_read(&sinfo->groups_sem);
+       return snprintf(buf, PAGE_SIZE, "%llu\n", val);
+}
+
+static struct attribute *raid_attributes[] = {
+       BTRFS_RAID_ATTR_PTR(total_bytes),
+       BTRFS_RAID_ATTR_PTR(used_bytes),
+       NULL
+};
+
+static void release_raid_kobj(struct kobject *kobj)
+{
+       kobject_put(kobj->parent);
+}
+
+struct kobj_type btrfs_raid_ktype = {
+       .sysfs_ops = &kobj_sysfs_ops,
+       .release = release_raid_kobj,
+       .default_attrs = raid_attributes,
+};
+
+#define SPACE_INFO_ATTR(field)                                         \
+static ssize_t btrfs_space_info_show_##field(struct kobject *kobj,     \
+                                            struct kobj_attribute *a,  \
+                                            char *buf)                 \
+{                                                                      \
+       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)
+
+static ssize_t btrfs_space_info_show_total_bytes_pinned(struct kobject *kobj,
+                                                      struct kobj_attribute *a,
+                                                      char *buf)
+{
+       struct btrfs_space_info *sinfo = to_space_info(kobj);
+       s64 val = percpu_counter_sum(&sinfo->total_bytes_pinned);
+       return snprintf(buf, PAGE_SIZE, "%lld\n", val);
+}
+
+SPACE_INFO_ATTR(flags);
+SPACE_INFO_ATTR(total_bytes);
+SPACE_INFO_ATTR(bytes_used);
+SPACE_INFO_ATTR(bytes_pinned);
+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);
+
+static struct attribute *space_info_attrs[] = {
+       BTRFS_ATTR_PTR(flags),
+       BTRFS_ATTR_PTR(total_bytes),
+       BTRFS_ATTR_PTR(bytes_used),
+       BTRFS_ATTR_PTR(bytes_pinned),
+       BTRFS_ATTR_PTR(bytes_reserved),
+       BTRFS_ATTR_PTR(bytes_may_use),
+       BTRFS_ATTR_PTR(disk_used),
+       BTRFS_ATTR_PTR(disk_total),
+       BTRFS_ATTR_PTR(total_bytes_pinned),
+       NULL,
+};
+
+static void space_info_release(struct kobject *kobj)
+{
+       struct btrfs_space_info *sinfo = to_space_info(kobj);
+       percpu_counter_destroy(&sinfo->total_bytes_pinned);
+       kfree(sinfo);
+}
+
+struct kobj_type space_info_ktype = {
+       .sysfs_ops = &kobj_sysfs_ops,
+       .release = space_info_release,
+       .default_attrs = space_info_attrs,
+};
+
+static const struct attribute *allocation_attrs[] = {
+       BTRFS_ATTR_PTR(global_rsv_reserved),
+       BTRFS_ATTR_PTR(global_rsv_size),
+       NULL,
+};
+
+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);
+}
+
+static ssize_t btrfs_label_store(struct kobject *kobj,
+                                struct kobj_attribute *a,
+                                const char *buf, size_t len)
+{
+       struct btrfs_fs_info *fs_info = to_fs_info(kobj);
+       struct btrfs_trans_handle *trans;
+       struct btrfs_root *root = fs_info->fs_root;
+       int ret;
+
+       if (len >= BTRFS_LABEL_SIZE) {
+               pr_err("BTRFS: unable to set label with more than %d bytes\n",
+                      BTRFS_LABEL_SIZE - 1);
+               return -EINVAL;
+       }
+
+       trans = btrfs_start_transaction(root, 0);
+       if (IS_ERR(trans))
+               return PTR_ERR(trans);
+
+       spin_lock(&root->fs_info->super_lock);
+       strcpy(fs_info->super_copy->label, buf);
+       spin_unlock(&root->fs_info->super_lock);
+       ret = btrfs_commit_transaction(trans, root);
+
+       if (!ret)
+               return len;
+
+       return ret;
+}
+BTRFS_ATTR_RW(label, 0644, btrfs_label_show, btrfs_label_store);
+
+static struct attribute *btrfs_attrs[] = {
+       BTRFS_ATTR_PTR(label),
+       NULL,
+};
+
+static void btrfs_release_super_kobj(struct kobject *kobj)
+{
+       struct btrfs_fs_info *fs_info = to_fs_info(kobj);
+       complete(&fs_info->kobj_unregister);
+}
+
+static struct kobj_type btrfs_ktype = {
+       .sysfs_ops      = &kobj_sysfs_ops,
+       .release        = btrfs_release_super_kobj,
+       .default_attrs  = btrfs_attrs,
+};
+
+static inline struct btrfs_fs_info *to_fs_info(struct kobject *kobj)
+{
+       if (kobj->ktype != &btrfs_ktype)
+               return NULL;
+       return container_of(kobj, struct btrfs_fs_info, super_kobj);
+}
+
+#define NUM_FEATURE_BITS 64
+static char btrfs_unknown_feature_names[3][NUM_FEATURE_BITS][13];
+static struct btrfs_feature_attr btrfs_feature_attrs[3][NUM_FEATURE_BITS];
+
+static u64 supported_feature_masks[3] = {
+       [FEAT_COMPAT]    = BTRFS_FEATURE_COMPAT_SUPP,
+       [FEAT_COMPAT_RO] = BTRFS_FEATURE_COMPAT_RO_SUPP,
+       [FEAT_INCOMPAT]  = BTRFS_FEATURE_INCOMPAT_SUPP,
+};
+
+static int addrm_unknown_feature_attrs(struct btrfs_fs_info *fs_info, bool add)
+{
+       int set;
+
+       for (set = 0; set < FEAT_MAX; set++) {
+               int i;
+               struct attribute *attrs[2];
+               struct attribute_group agroup = {
+                       .name = "features",
+                       .attrs = attrs,
+               };
+               u64 features = get_features(fs_info, set);
+               features &= ~supported_feature_masks[set];
+
+               if (!features)
+                       continue;
+
+               attrs[1] = NULL;
+               for (i = 0; i < NUM_FEATURE_BITS; i++) {
+                       struct btrfs_feature_attr *fa;
+
+                       if (!(features & (1ULL << i)))
+                               continue;
+
+                       fa = &btrfs_feature_attrs[set][i];
+                       attrs[0] = &fa->kobj_attr.attr;
+                       if (add) {
+                               int ret;
+                               ret = sysfs_merge_group(&fs_info->super_kobj,
+                                                       &agroup);
+                               if (ret)
+                                       return ret;
+                       } else
+                               sysfs_unmerge_group(&fs_info->super_kobj,
+                                                   &agroup);
+               }
+
+       }
+       return 0;
+}
+
+static void __btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
+{
+       kobject_del(&fs_info->super_kobj);
+       kobject_put(&fs_info->super_kobj);
+       wait_for_completion(&fs_info->kobj_unregister);
+}
+
+void btrfs_sysfs_remove_one(struct btrfs_fs_info *fs_info)
+{
+       if (fs_info->space_info_kobj) {
+               sysfs_remove_files(fs_info->space_info_kobj, allocation_attrs);
+               kobject_del(fs_info->space_info_kobj);
+               kobject_put(fs_info->space_info_kobj);
+       }
+       kobject_del(fs_info->device_dir_kobj);
+       kobject_put(fs_info->device_dir_kobj);
+       addrm_unknown_feature_attrs(fs_info, false);
+       sysfs_remove_group(&fs_info->super_kobj, &btrfs_feature_attr_group);
+       __btrfs_sysfs_remove_one(fs_info);
+}
+
+const char * const btrfs_feature_set_names[3] = {
+       [FEAT_COMPAT]    = "compat",
+       [FEAT_COMPAT_RO] = "compat_ro",
+       [FEAT_INCOMPAT]  = "incompat",
+};
+
+char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags)
+{
+       size_t bufsize = 4096; /* safe max, 64 names * 64 bytes */
+       int len = 0;
+       int i;
+       char *str;
+
+       str = kmalloc(bufsize, GFP_KERNEL);
+       if (!str)
+               return str;
+
+       for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
+               const char *name;
+
+               if (!(flags & (1ULL << i)))
+                       continue;
+
+               name = btrfs_feature_attrs[set][i].kobj_attr.attr.name;
+               len += snprintf(str + len, bufsize - len, "%s%s",
+                               len ? "," : "", name);
+       }
+
+       return str;
+}
+
+static void init_feature_attrs(void)
+{
+       struct btrfs_feature_attr *fa;
+       int set, i;
+
+       BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names) !=
+                    ARRAY_SIZE(btrfs_feature_attrs));
+       BUILD_BUG_ON(ARRAY_SIZE(btrfs_unknown_feature_names[0]) !=
+                    ARRAY_SIZE(btrfs_feature_attrs[0]));
+
+       memset(btrfs_feature_attrs, 0, sizeof(btrfs_feature_attrs));
+       memset(btrfs_unknown_feature_names, 0,
+              sizeof(btrfs_unknown_feature_names));
+
+       for (i = 0; btrfs_supported_feature_attrs[i]; i++) {
+               struct btrfs_feature_attr *sfa;
+               struct attribute *a = btrfs_supported_feature_attrs[i];
+               int bit;
+               sfa = attr_to_btrfs_feature_attr(a);
+               bit = ilog2(sfa->feature_bit);
+               fa = &btrfs_feature_attrs[sfa->feature_set][bit];
+
+               fa->kobj_attr.attr.name = sfa->kobj_attr.attr.name;
+       }
+
+       for (set = 0; set < FEAT_MAX; set++) {
+               for (i = 0; i < ARRAY_SIZE(btrfs_feature_attrs[set]); i++) {
+                       char *name = btrfs_unknown_feature_names[set][i];
+                       fa = &btrfs_feature_attrs[set][i];
+
+                       if (fa->kobj_attr.attr.name)
+                               continue;
+
+                       snprintf(name, 13, "%s:%u",
+                                btrfs_feature_set_names[set], i);
+
+                       fa->kobj_attr.attr.name = name;
+                       fa->kobj_attr.attr.mode = S_IRUGO;
+                       fa->feature_set = set;
+                       fa->feature_bit = 1ULL << i;
+               }
+       }
+}
+
+static int add_device_membership(struct btrfs_fs_info *fs_info)
+{
+       int error = 0;
+       struct btrfs_fs_devices *fs_devices = fs_info->fs_devices;
+       struct btrfs_device *dev;
+
+       fs_info->device_dir_kobj = kobject_create_and_add("devices",
+                                               &fs_info->super_kobj);
+       if (!fs_info->device_dir_kobj)
+               return -ENOMEM;
+
+       list_for_each_entry(dev, &fs_devices->devices, dev_list) {
+               struct hd_struct *disk = dev->bdev->bd_part;
+               struct kobject *disk_kobj = &part_to_dev(disk)->kobj;
+
+               error = sysfs_create_link(fs_info->device_dir_kobj,
+                                         disk_kobj, disk_kobj->name);
+               if (error)
+                       break;
+       }
+
+       return error;
+}
 
 /* /sys/fs/btrfs/ entry */
 static struct kset *btrfs_kset;
 
+int btrfs_sysfs_add_one(struct btrfs_fs_info *fs_info)
+{
+       int error;
+
+       init_completion(&fs_info->kobj_unregister);
+       fs_info->super_kobj.kset = btrfs_kset;
+       error = kobject_init_and_add(&fs_info->super_kobj, &btrfs_ktype, NULL,
+                                    "%pU", fs_info->fsid);
+       if (error)
+               return error;
+
+       error = sysfs_create_group(&fs_info->super_kobj,
+                                  &btrfs_feature_attr_group);
+       if (error) {
+               __btrfs_sysfs_remove_one(fs_info);
+               return error;
+       }
+
+       error = addrm_unknown_feature_attrs(fs_info, true);
+       if (error)
+               goto failure;
+
+       error = add_device_membership(fs_info);
+       if (error)
+               goto failure;
+
+       fs_info->space_info_kobj = kobject_create_and_add("allocation",
+                                                 &fs_info->super_kobj);
+       if (!fs_info->space_info_kobj) {
+               error = -ENOMEM;
+               goto failure;
+       }
+
+       error = sysfs_create_files(fs_info->space_info_kobj, allocation_attrs);
+       if (error)
+               goto failure;
+
+       return 0;
+failure:
+       btrfs_sysfs_remove_one(fs_info);
+       return error;
+}
+
 int btrfs_init_sysfs(void)
 {
+       int ret;
        btrfs_kset = kset_create_and_add("btrfs", NULL, fs_kobj);
        if (!btrfs_kset)
                return -ENOMEM;
+
+       init_feature_attrs();
+
+       ret = sysfs_create_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
+       if (ret) {
+               kset_unregister(btrfs_kset);
+               return ret;
+       }
+
        return 0;
 }
 
 void btrfs_exit_sysfs(void)
 {
+       sysfs_remove_group(&btrfs_kset->kobj, &btrfs_feature_attr_group);
        kset_unregister(btrfs_kset);
 }
 
diff --git a/fs/btrfs/sysfs.h b/fs/btrfs/sysfs.h
new file mode 100644 (file)
index 0000000..f3cea37
--- /dev/null
@@ -0,0 +1,64 @@
+#ifndef _BTRFS_SYSFS_H_
+#define _BTRFS_SYSFS_H_
+
+enum btrfs_feature_set {
+       FEAT_COMPAT,
+       FEAT_COMPAT_RO,
+       FEAT_INCOMPAT,
+       FEAT_MAX
+};
+
+#define __INIT_KOBJ_ATTR(_name, _mode, _show, _store)                  \
+{                                                                      \
+       .attr   = { .name = __stringify(_name), .mode = _mode },        \
+       .show   = _show,                                                \
+       .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_PTR(_name)    (&btrfs_attr_##_name.attr)
+
+#define BTRFS_RAID_ATTR(_name, _show)                                  \
+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)
+
+
+struct btrfs_feature_attr {
+       struct kobj_attribute kobj_attr;
+       enum btrfs_feature_set feature_set;
+       u64 feature_bit;
+};
+
+#define BTRFS_FEAT_ATTR(_name, _feature_set, _prefix, _feature_bit)         \
+static struct btrfs_feature_attr btrfs_attr_##_name = {                             \
+       .kobj_attr = __INIT_KOBJ_ATTR(_name, S_IRUGO,                        \
+                                     btrfs_feature_attr_show,               \
+                                     btrfs_feature_attr_store),             \
+       .feature_set    = _feature_set,                                      \
+       .feature_bit    = _prefix ##_## _feature_bit,                        \
+}
+#define BTRFS_FEAT_ATTR_PTR(_name)    (&btrfs_attr_##_name.kobj_attr.attr)
+
+#define BTRFS_FEAT_ATTR_COMPAT(name, feature) \
+       BTRFS_FEAT_ATTR(name, FEAT_COMPAT, BTRFS_FEATURE_COMPAT, feature)
+#define BTRFS_FEAT_ATTR_COMPAT_RO(name, feature) \
+       BTRFS_FEAT_ATTR(name, FEAT_COMPAT_RO, BTRFS_FEATURE_COMPAT, feature)
+#define BTRFS_FEAT_ATTR_INCOMPAT(name, feature) \
+       BTRFS_FEAT_ATTR(name, FEAT_INCOMPAT, BTRFS_FEATURE_INCOMPAT, feature)
+
+/* convert from attribute */
+#define to_btrfs_feature_attr(a) \
+                       container_of(a, struct btrfs_feature_attr, kobj_attr)
+#define attr_to_btrfs_attr(a) container_of(a, struct kobj_attribute, attr)
+#define attr_to_btrfs_feature_attr(a) \
+                       to_btrfs_feature_attr(attr_to_btrfs_attr(a))
+char *btrfs_printable_features(enum btrfs_feature_set set, u64 flags);
+extern const char * const btrfs_feature_set_names[3];
+extern struct kobj_type space_info_ktype;
+extern struct kobj_type btrfs_raid_ktype;
+#endif /* _BTRFS_SYSFS_H_ */
index b353bc806ca066be17600283ccc5d1a181af3426..312560a9123dedc69542b33c4931b71901125d12 100644 (file)
@@ -21,7 +21,7 @@
 
 #ifdef CONFIG_BTRFS_FS_RUN_SANITY_TESTS
 
-#define test_msg(fmt, ...) pr_info("btrfs: selftest: " fmt, ##__VA_ARGS__)
+#define test_msg(fmt, ...) pr_info("BTRFS: selftest: " fmt, ##__VA_ARGS__)
 
 int btrfs_test_free_space_cache(void);
 int btrfs_test_extent_buffer_operations(void);
index c6a872a8a46862948e93c343cdd0c7479caf3883..34cd83184c4ad2ff7ce85bb13fea48dfb61198b4 100644 (file)
@@ -62,7 +62,7 @@ void btrfs_put_transaction(struct btrfs_transaction *transaction)
        WARN_ON(atomic_read(&transaction->use_count) == 0);
        if (atomic_dec_and_test(&transaction->use_count)) {
                BUG_ON(!list_empty(&transaction->list));
-               WARN_ON(transaction->delayed_refs.root.rb_node);
+               WARN_ON(!RB_EMPTY_ROOT(&transaction->delayed_refs.href_root));
                while (!list_empty(&transaction->pending_chunks)) {
                        struct extent_map *em;
 
@@ -183,8 +183,8 @@ loop:
        atomic_set(&cur_trans->use_count, 2);
        cur_trans->start_time = get_seconds();
 
-       cur_trans->delayed_refs.root = RB_ROOT;
-       cur_trans->delayed_refs.num_entries = 0;
+       cur_trans->delayed_refs.href_root = RB_ROOT;
+       atomic_set(&cur_trans->delayed_refs.num_entries, 0);
        cur_trans->delayed_refs.num_heads_ready = 0;
        cur_trans->delayed_refs.num_heads = 0;
        cur_trans->delayed_refs.flushing = 0;
@@ -196,17 +196,14 @@ loop:
         */
        smp_mb();
        if (!list_empty(&fs_info->tree_mod_seq_list))
-               WARN(1, KERN_ERR "btrfs: tree_mod_seq_list not empty when "
+               WARN(1, KERN_ERR "BTRFS: tree_mod_seq_list not empty when "
                        "creating a fresh transaction\n");
        if (!RB_EMPTY_ROOT(&fs_info->tree_mod_log))
-               WARN(1, KERN_ERR "btrfs: tree_mod_log rb tree not empty when "
+               WARN(1, KERN_ERR "BTRFS: tree_mod_log rb tree not empty when "
                        "creating a fresh transaction\n");
        atomic64_set(&fs_info->tree_mod_seq, 0);
 
        spin_lock_init(&cur_trans->delayed_refs.lock);
-       atomic_set(&cur_trans->delayed_refs.procs_running_refs, 0);
-       atomic_set(&cur_trans->delayed_refs.ref_seq, 0);
-       init_waitqueue_head(&cur_trans->delayed_refs.wait);
 
        INIT_LIST_HEAD(&cur_trans->pending_snapshots);
        INIT_LIST_HEAD(&cur_trans->ordered_operations);
@@ -472,6 +469,7 @@ again:
        h->type = type;
        h->allocating_chunk = false;
        h->reloc_reserved = false;
+       h->sync = false;
        INIT_LIST_HEAD(&h->qgroup_ref_list);
        INIT_LIST_HEAD(&h->new_bgs);
 
@@ -647,7 +645,7 @@ static int should_end_transaction(struct btrfs_trans_handle *trans,
                                  struct btrfs_root *root)
 {
        if (root->fs_info->global_block_rsv.space_info->full &&
-           btrfs_should_throttle_delayed_refs(trans, root))
+           btrfs_check_space_for_delayed_refs(trans, root))
                return 1;
 
        return !!btrfs_block_rsv_check(root, &root->fs_info->global_block_rsv, 5);
@@ -711,8 +709,8 @@ static int __btrfs_end_transaction(struct btrfs_trans_handle *trans,
                btrfs_create_pending_block_groups(trans, root);
 
        trans->delayed_ref_updates = 0;
-       if (btrfs_should_throttle_delayed_refs(trans, root)) {
-               cur = max_t(unsigned long, cur, 1);
+       if (!trans->sync && btrfs_should_throttle_delayed_refs(trans, root)) {
+               cur = max_t(unsigned long, cur, 32);
                trans->delayed_ref_updates = 0;
                btrfs_run_delayed_refs(trans, root, cur);
        }
@@ -788,12 +786,6 @@ int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
        return __btrfs_end_transaction(trans, root, 1);
 }
 
-int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
-                               struct btrfs_root *root)
-{
-       return __btrfs_end_transaction(trans, root, 1);
-}
-
 /*
  * when btree blocks are allocated, they have some corresponding bits set for
  * them in one of two extent_io trees.  This is used to make sure all of
@@ -1105,7 +1097,7 @@ int btrfs_defrag_root(struct btrfs_root *root)
                        break;
 
                if (btrfs_defrag_cancelled(root->fs_info)) {
-                       printk(KERN_DEBUG "btrfs: defrag_root cancelled\n");
+                       pr_debug("BTRFS: defrag_root cancelled\n");
                        ret = -EAGAIN;
                        break;
                }
@@ -1746,6 +1738,8 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                goto cleanup_transaction;
 
        btrfs_wait_delalloc_flush(root->fs_info);
+
+       btrfs_scrub_pause(root);
        /*
         * Ok now we need to make sure to block out any other joins while we
         * commit the transaction.  We could have started a join before setting
@@ -1810,7 +1804,6 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
 
        WARN_ON(cur_trans != trans->transaction);
 
-       btrfs_scrub_pause(root);
        /* btrfs_commit_tree_roots is responsible for getting the
         * various roots consistent with each other.  Every pointer
         * in the tree of tree roots has to point to the most up to date
@@ -1833,6 +1826,15 @@ int btrfs_commit_transaction(struct btrfs_trans_handle *trans,
                goto cleanup_transaction;
        }
 
+       /*
+        * Since the transaction is done, we should set the inode map cache flag
+        * before any other comming transaction.
+        */
+       if (btrfs_test_opt(root, CHANGE_INODE_CACHE))
+               btrfs_set_opt(root->fs_info->mount_opt, INODE_MAP_CACHE);
+       else
+               btrfs_clear_opt(root->fs_info->mount_opt, INODE_MAP_CACHE);
+
        /* commit_fs_roots gets rid of all the tree log roots, it is now
         * safe to free the root of tree log roots
         */
@@ -1975,10 +1977,23 @@ int btrfs_clean_one_deleted_snapshot(struct btrfs_root *root)
        }
        root = list_first_entry(&fs_info->dead_roots,
                        struct btrfs_root, root_list);
+       /*
+        * Make sure root is not involved in send,
+        * if we fail with first root, we return
+        * directly rather than continue.
+        */
+       spin_lock(&root->root_item_lock);
+       if (root->send_in_progress) {
+               spin_unlock(&fs_info->trans_lock);
+               spin_unlock(&root->root_item_lock);
+               return 0;
+       }
+       spin_unlock(&root->root_item_lock);
+
        list_del_init(&root->root_list);
        spin_unlock(&fs_info->trans_lock);
 
-       pr_debug("btrfs: cleaner removing %llu\n", root->objectid);
+       pr_debug("BTRFS: cleaner removing %llu\n", root->objectid);
 
        btrfs_kill_all_delayed_nodes(root);
 
index 7657d115067d3f8ae1d5cc39a53410d8a1011673..6ac037e9f9f0557524b7ed29b6b72a768f7a23cf 100644 (file)
@@ -93,6 +93,7 @@ struct btrfs_trans_handle {
        short adding_csums;
        bool allocating_chunk;
        bool reloc_reserved;
+       bool sync;
        unsigned int type;
        /*
         * this root is only needed to validate that the root passed to
@@ -154,8 +155,6 @@ int btrfs_commit_transaction_async(struct btrfs_trans_handle *trans,
                                   int wait_for_unblock);
 int btrfs_end_transaction_throttle(struct btrfs_trans_handle *trans,
                                   struct btrfs_root *root);
-int btrfs_end_transaction_dmeta(struct btrfs_trans_handle *trans,
-                               struct btrfs_root *root);
 int btrfs_should_end_transaction(struct btrfs_trans_handle *trans,
                                 struct btrfs_root *root);
 void btrfs_throttle(struct btrfs_root *root);
index 9f7fc51ca334864b72336e127d786047dfb1f5de..39d83da03e0398db90428e52b98524982da469b5 100644 (file)
@@ -570,7 +570,7 @@ static noinline int replay_one_extent(struct btrfs_trans_handle *trans,
                if (btrfs_file_extent_disk_bytenr(eb, item) == 0)
                        nbytes = 0;
        } else if (found_type == BTRFS_FILE_EXTENT_INLINE) {
-               size = btrfs_file_extent_inline_len(eb, item);
+               size = btrfs_file_extent_inline_len(eb, slot, item);
                nbytes = btrfs_file_extent_ram_bytes(eb, item);
                extent_end = ALIGN(start + size, root->sectorsize);
        } else {
@@ -1238,7 +1238,8 @@ static int insert_orphan_item(struct btrfs_trans_handle *trans,
                              struct btrfs_root *root, u64 offset)
 {
        int ret;
-       ret = btrfs_find_orphan_item(root, offset);
+       ret = btrfs_find_item(root, NULL, BTRFS_ORPHAN_OBJECTID,
+                       offset, BTRFS_ORPHAN_ITEM_KEY, NULL);
        if (ret > 0)
                ret = btrfs_insert_orphan_item(trans, root, offset);
        return ret;
@@ -3194,7 +3195,7 @@ static int log_inode_item(struct btrfs_trans_handle *trans,
 static noinline int copy_items(struct btrfs_trans_handle *trans,
                               struct inode *inode,
                               struct btrfs_path *dst_path,
-                              struct extent_buffer *src,
+                              struct btrfs_path *src_path, u64 *last_extent,
                               int start_slot, int nr, int inode_only)
 {
        unsigned long src_offset;
@@ -3202,6 +3203,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
        struct btrfs_root *log = BTRFS_I(inode)->root->log_root;
        struct btrfs_file_extent_item *extent;
        struct btrfs_inode_item *inode_item;
+       struct extent_buffer *src = src_path->nodes[0];
+       struct btrfs_key first_key, last_key, key;
        int ret;
        struct btrfs_key *ins_keys;
        u32 *ins_sizes;
@@ -3209,6 +3212,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
        int i;
        struct list_head ordered_sums;
        int skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
+       bool has_extents = false;
+       bool need_find_last_extent = (*last_extent == 0);
+       bool done = false;
 
        INIT_LIST_HEAD(&ordered_sums);
 
@@ -3217,6 +3223,8 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
        if (!ins_data)
                return -ENOMEM;
 
+       first_key.objectid = (u64)-1;
+
        ins_sizes = (u32 *)ins_data;
        ins_keys = (struct btrfs_key *)(ins_data + nr * sizeof(u32));
 
@@ -3237,6 +3245,9 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
 
                src_offset = btrfs_item_ptr_offset(src, start_slot + i);
 
+               if ((i == (nr - 1)))
+                       last_key = ins_keys[i];
+
                if (ins_keys[i].type == BTRFS_INODE_ITEM_KEY) {
                        inode_item = btrfs_item_ptr(dst_path->nodes[0],
                                                    dst_path->slots[0],
@@ -3248,6 +3259,21 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                                           src_offset, ins_sizes[i]);
                }
 
+               /*
+                * We set need_find_last_extent here in case we know we were
+                * processing other items and then walk into the first extent in
+                * the inode.  If we don't hit an extent then nothing changes,
+                * we'll do the last search the next time around.
+                */
+               if (ins_keys[i].type == BTRFS_EXTENT_DATA_KEY) {
+                       has_extents = true;
+                       if (need_find_last_extent &&
+                           first_key.objectid == (u64)-1)
+                               first_key = ins_keys[i];
+               } else {
+                       need_find_last_extent = false;
+               }
+
                /* take a reference on file data extents so that truncates
                 * or deletes of this inode don't have to relog the inode
                 * again
@@ -3312,6 +3338,128 @@ static noinline int copy_items(struct btrfs_trans_handle *trans,
                list_del(&sums->list);
                kfree(sums);
        }
+
+       if (!has_extents)
+               return ret;
+
+       /*
+        * Because we use btrfs_search_forward we could skip leaves that were
+        * not modified and then assume *last_extent is valid when it really
+        * isn't.  So back up to the previous leaf and read the end of the last
+        * extent before we go and fill in holes.
+        */
+       if (need_find_last_extent) {
+               u64 len;
+
+               ret = btrfs_prev_leaf(BTRFS_I(inode)->root, src_path);
+               if (ret < 0)
+                       return ret;
+               if (ret)
+                       goto fill_holes;
+               if (src_path->slots[0])
+                       src_path->slots[0]--;
+               src = src_path->nodes[0];
+               btrfs_item_key_to_cpu(src, &key, src_path->slots[0]);
+               if (key.objectid != btrfs_ino(inode) ||
+                   key.type != BTRFS_EXTENT_DATA_KEY)
+                       goto fill_holes;
+               extent = btrfs_item_ptr(src, src_path->slots[0],
+                                       struct btrfs_file_extent_item);
+               if (btrfs_file_extent_type(src, extent) ==
+                   BTRFS_FILE_EXTENT_INLINE) {
+                       len = btrfs_file_extent_inline_len(src,
+                                                          src_path->slots[0],
+                                                          extent);
+                       *last_extent = ALIGN(key.offset + len,
+                                            log->sectorsize);
+               } else {
+                       len = btrfs_file_extent_num_bytes(src, extent);
+                       *last_extent = key.offset + len;
+               }
+       }
+fill_holes:
+       /* So we did prev_leaf, now we need to move to the next leaf, but a few
+        * things could have happened
+        *
+        * 1) A merge could have happened, so we could currently be on a leaf
+        * that holds what we were copying in the first place.
+        * 2) A split could have happened, and now not all of the items we want
+        * are on the same leaf.
+        *
+        * So we need to adjust how we search for holes, we need to drop the
+        * path and re-search for the first extent key we found, and then walk
+        * forward until we hit the last one we copied.
+        */
+       if (need_find_last_extent) {
+               /* btrfs_prev_leaf could return 1 without releasing the path */
+               btrfs_release_path(src_path);
+               ret = btrfs_search_slot(NULL, BTRFS_I(inode)->root, &first_key,
+                                       src_path, 0, 0);
+               if (ret < 0)
+                       return ret;
+               ASSERT(ret == 0);
+               src = src_path->nodes[0];
+               i = src_path->slots[0];
+       } else {
+               i = start_slot;
+       }
+
+       /*
+        * Ok so here we need to go through and fill in any holes we may have
+        * to make sure that holes are punched for those areas in case they had
+        * extents previously.
+        */
+       while (!done) {
+               u64 offset, len;
+               u64 extent_end;
+
+               if (i >= btrfs_header_nritems(src_path->nodes[0])) {
+                       ret = btrfs_next_leaf(BTRFS_I(inode)->root, src_path);
+                       if (ret < 0)
+                               return ret;
+                       ASSERT(ret == 0);
+                       src = src_path->nodes[0];
+                       i = 0;
+               }
+
+               btrfs_item_key_to_cpu(src, &key, i);
+               if (!btrfs_comp_cpu_keys(&key, &last_key))
+                       done = true;
+               if (key.objectid != btrfs_ino(inode) ||
+                   key.type != BTRFS_EXTENT_DATA_KEY) {
+                       i++;
+                       continue;
+               }
+               extent = btrfs_item_ptr(src, i, struct btrfs_file_extent_item);
+               if (btrfs_file_extent_type(src, extent) ==
+                   BTRFS_FILE_EXTENT_INLINE) {
+                       len = btrfs_file_extent_inline_len(src, i, extent);
+                       extent_end = ALIGN(key.offset + len, log->sectorsize);
+               } else {
+                       len = btrfs_file_extent_num_bytes(src, extent);
+                       extent_end = key.offset + len;
+               }
+               i++;
+
+               if (*last_extent == key.offset) {
+                       *last_extent = extent_end;
+                       continue;
+               }
+               offset = *last_extent;
+               len = key.offset - *last_extent;
+               ret = btrfs_insert_file_extent(trans, log, btrfs_ino(inode),
+                                              offset, 0, 0, len, 0, len, 0,
+                                              0, 0);
+               if (ret)
+                       break;
+               *last_extent = offset + len;
+       }
+       /*
+        * Need to let the callers know we dropped the path so they should
+        * re-search.
+        */
+       if (!ret && need_find_last_extent)
+               ret = 1;
        return ret;
 }
 
@@ -3349,21 +3497,27 @@ static int log_one_extent(struct btrfs_trans_handle *trans,
        int ret;
        int index = log->log_transid % 2;
        bool skip_csum = BTRFS_I(inode)->flags & BTRFS_INODE_NODATASUM;
-
-       ret = __btrfs_drop_extents(trans, log, inode, path, em->start,
-                                  em->start + em->len, NULL, 0);
-       if (ret)
-               return ret;
+       int extent_inserted = 0;
 
        INIT_LIST_HEAD(&ordered_sums);
        btrfs_init_map_token(&token);
-       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));
+       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);
@@ -3485,7 +3639,11 @@ again:
                 * start over after this.
                 */
 
-               wait_event(ordered->wait, ordered->csum_bytes_left == 0);
+               if (ordered->csum_bytes_left) {
+                       btrfs_start_ordered_extent(inode, ordered, 0);
+                       wait_event(ordered->wait,
+                                  ordered->csum_bytes_left == 0);
+               }
 
                list_for_each_entry(sum, &ordered->list, list) {
                        ret = btrfs_csum_file_blocks(trans, log, sum);
@@ -3630,6 +3788,7 @@ static int btrfs_log_inode(struct btrfs_trans_handle *trans,
        struct btrfs_key max_key;
        struct btrfs_root *log = root->log_root;
        struct extent_buffer *src = NULL;
+       u64 last_extent = 0;
        int err = 0;
        int ret;
        int nritems;
@@ -3745,11 +3904,15 @@ again:
                        goto next_slot;
                }
 
-               ret = copy_items(trans, inode, dst_path, src, ins_start_slot,
-                                ins_nr, inode_only);
-               if (ret) {
+               ret = copy_items(trans, inode, dst_path, path, &last_extent,
+                                ins_start_slot, ins_nr, inode_only);
+               if (ret < 0) {
                        err = ret;
                        goto out_unlock;
+               } if (ret) {
+                       ins_nr = 0;
+                       btrfs_release_path(path);
+                       continue;
                }
                ins_nr = 1;
                ins_start_slot = path->slots[0];
@@ -3763,13 +3926,14 @@ next_slot:
                        goto again;
                }
                if (ins_nr) {
-                       ret = copy_items(trans, inode, dst_path, src,
-                                        ins_start_slot,
+                       ret = copy_items(trans, inode, dst_path, path,
+                                        &last_extent, ins_start_slot,
                                         ins_nr, inode_only);
-                       if (ret) {
+                       if (ret < 0) {
                                err = ret;
                                goto out_unlock;
                        }
+                       ret = 0;
                        ins_nr = 0;
                }
                btrfs_release_path(path);
@@ -3784,12 +3948,13 @@ next_slot:
                }
        }
        if (ins_nr) {
-               ret = copy_items(trans, inode, dst_path, src, ins_start_slot,
-                                ins_nr, inode_only);
-               if (ret) {
+               ret = copy_items(trans, inode, dst_path, path, &last_extent,
+                                ins_start_slot, ins_nr, inode_only);
+               if (ret < 0) {
                        err = ret;
                        goto out_unlock;
                }
+               ret = 0;
                ins_nr = 0;
        }
 
index b0a523b2c60ee8e73cd5165382892918ddad269e..840a38b2778a6e97ee013f0d2333e179c3c475e3 100644 (file)
@@ -5,8 +5,8 @@
  */
 
 #include <linux/slab.h>
-#include <linux/export.h>
 #include "ulist.h"
+#include "ctree.h"
 
 /*
  * ulist is a generic data structure to hold a collection of unique u64
  * enumerating it.
  * It is possible to store an auxiliary value along with the key.
  *
- * The implementation is preliminary and can probably be sped up
- * significantly. A first step would be to store the values in an rbtree
- * as soon as ULIST_SIZE is exceeded.
- *
  * A sample usage for ulists is the enumeration of directed graphs without
  * visiting a node twice. The pseudo-code could look like this:
  *
  */
 void ulist_init(struct ulist *ulist)
 {
-       ulist->nnodes = 0;
-       ulist->nodes = ulist->int_nodes;
-       ulist->nodes_alloced = ULIST_SIZE;
+       INIT_LIST_HEAD(&ulist->nodes);
        ulist->root = RB_ROOT;
+       ulist->nnodes = 0;
 }
-EXPORT_SYMBOL(ulist_init);
 
 /**
  * ulist_fini - free up additionally allocated memory for the ulist
@@ -64,18 +58,17 @@ EXPORT_SYMBOL(ulist_init);
  * This is useful in cases where the base 'struct ulist' has been statically
  * allocated.
  */
-void ulist_fini(struct ulist *ulist)
+static void ulist_fini(struct ulist *ulist)
 {
-       /*
-        * The first ULIST_SIZE elements are stored inline in struct ulist.
-        * Only if more elements are alocated they need to be freed.
-        */
-       if (ulist->nodes_alloced > ULIST_SIZE)
-               kfree(ulist->nodes);
-       ulist->nodes_alloced = 0;       /* in case ulist_fini is called twice */
+       struct ulist_node *node;
+       struct ulist_node *next;
+
+       list_for_each_entry_safe(node, next, &ulist->nodes, list) {
+               kfree(node);
+       }
        ulist->root = RB_ROOT;
+       INIT_LIST_HEAD(&ulist->nodes);
 }
-EXPORT_SYMBOL(ulist_fini);
 
 /**
  * ulist_reinit - prepare a ulist for reuse
@@ -89,7 +82,6 @@ void ulist_reinit(struct ulist *ulist)
        ulist_fini(ulist);
        ulist_init(ulist);
 }
-EXPORT_SYMBOL(ulist_reinit);
 
 /**
  * ulist_alloc - dynamically allocate a ulist
@@ -108,7 +100,6 @@ struct ulist *ulist_alloc(gfp_t gfp_mask)
 
        return ulist;
 }
-EXPORT_SYMBOL(ulist_alloc);
 
 /**
  * ulist_free - free dynamically allocated ulist
@@ -123,7 +114,6 @@ void ulist_free(struct ulist *ulist)
        ulist_fini(ulist);
        kfree(ulist);
 }
-EXPORT_SYMBOL(ulist_free);
 
 static struct ulist_node *ulist_rbtree_search(struct ulist *ulist, u64 val)
 {
@@ -192,63 +182,32 @@ int ulist_add(struct ulist *ulist, u64 val, u64 aux, gfp_t gfp_mask)
 int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
                    u64 *old_aux, gfp_t gfp_mask)
 {
-       int ret = 0;
-       struct ulist_node *node = NULL;
+       int ret;
+       struct ulist_node *node;
+
        node = ulist_rbtree_search(ulist, val);
        if (node) {
                if (old_aux)
                        *old_aux = node->aux;
                return 0;
        }
+       node = kmalloc(sizeof(*node), gfp_mask);
+       if (!node)
+               return -ENOMEM;
 
-       if (ulist->nnodes >= ulist->nodes_alloced) {
-               u64 new_alloced = ulist->nodes_alloced + 128;
-               struct ulist_node *new_nodes;
-               void *old = NULL;
-               int i;
-
-               for (i = 0; i < ulist->nnodes; i++)
-                       rb_erase(&ulist->nodes[i].rb_node, &ulist->root);
-
-               /*
-                * if nodes_alloced == ULIST_SIZE no memory has been allocated
-                * yet, so pass NULL to krealloc
-                */
-               if (ulist->nodes_alloced > ULIST_SIZE)
-                       old = ulist->nodes;
+       node->val = val;
+       node->aux = aux;
+#ifdef CONFIG_BTRFS_DEBUG
+       node->seqnum = ulist->nnodes;
+#endif
 
-               new_nodes = krealloc(old, sizeof(*new_nodes) * new_alloced,
-                                    gfp_mask);
-               if (!new_nodes)
-                       return -ENOMEM;
-
-               if (!old)
-                       memcpy(new_nodes, ulist->int_nodes,
-                              sizeof(ulist->int_nodes));
-
-               ulist->nodes = new_nodes;
-               ulist->nodes_alloced = new_alloced;
-
-               /*
-                * krealloc actually uses memcpy, which does not copy rb_node
-                * pointers, so we have to do it ourselves.  Otherwise we may
-                * be bitten by crashes.
-                */
-               for (i = 0; i < ulist->nnodes; i++) {
-                       ret = ulist_rbtree_insert(ulist, &ulist->nodes[i]);
-                       if (ret < 0)
-                               return ret;
-               }
-       }
-       ulist->nodes[ulist->nnodes].val = val;
-       ulist->nodes[ulist->nnodes].aux = aux;
-       ret = ulist_rbtree_insert(ulist, &ulist->nodes[ulist->nnodes]);
-       BUG_ON(ret);
-       ++ulist->nnodes;
+       ret = ulist_rbtree_insert(ulist, node);
+       ASSERT(!ret);
+       list_add_tail(&node->list, &ulist->nodes);
+       ulist->nnodes++;
 
        return 1;
 }
-EXPORT_SYMBOL(ulist_add);
 
 /**
  * ulist_next - iterate ulist
@@ -268,11 +227,25 @@ EXPORT_SYMBOL(ulist_add);
  */
 struct ulist_node *ulist_next(struct ulist *ulist, struct ulist_iterator *uiter)
 {
-       if (ulist->nnodes == 0)
+       struct ulist_node *node;
+
+       if (list_empty(&ulist->nodes))
                return NULL;
-       if (uiter->i < 0 || uiter->i >= ulist->nnodes)
+       if (uiter->cur_list && uiter->cur_list->next == &ulist->nodes)
                return NULL;
-
-       return &ulist->nodes[uiter->i++];
+       if (uiter->cur_list) {
+               uiter->cur_list = uiter->cur_list->next;
+       } else {
+               uiter->cur_list = ulist->nodes.next;
+#ifdef CONFIG_BTRFS_DEBUG
+               uiter->i = 0;
+#endif
+       }
+       node = list_entry(uiter->cur_list, struct ulist_node, list);
+#ifdef CONFIG_BTRFS_DEBUG
+       ASSERT(node->seqnum == uiter->i);
+       ASSERT(uiter->i >= 0 && uiter->i < ulist->nnodes);
+       uiter->i++;
+#endif
+       return node;
 }
-EXPORT_SYMBOL(ulist_next);
index fb36731074b5fa6ed5e27be3cca08caf329631ee..7f78cbf5cf413636e7b6072efca05110dce8b211 100644 (file)
  * enumerating it.
  * It is possible to store an auxiliary value along with the key.
  *
- * The implementation is preliminary and can probably be sped up
- * significantly. A first step would be to store the values in an rbtree
- * as soon as ULIST_SIZE is exceeded.
  */
-
-/*
- * number of elements statically allocated inside struct ulist
- */
-#define ULIST_SIZE 16
-
 struct ulist_iterator {
+#ifdef CONFIG_BTRFS_DEBUG
        int i;
+#endif
+       struct list_head *cur_list;  /* hint to start search */
 };
 
 /*
@@ -37,6 +31,12 @@ struct ulist_iterator {
 struct ulist_node {
        u64 val;                /* value to store */
        u64 aux;                /* auxiliary value saved along with the val */
+
+#ifdef CONFIG_BTRFS_DEBUG
+       int seqnum;             /* sequence number this node is added */
+#endif
+
+       struct list_head list;  /* used to link node */
        struct rb_node rb_node; /* used to speed up search */
 };
 
@@ -46,28 +46,11 @@ struct ulist {
         */
        unsigned long nnodes;
 
-       /*
-        * number of nodes we already have room for
-        */
-       unsigned long nodes_alloced;
-
-       /*
-        * pointer to the array storing the elements. The first ULIST_SIZE
-        * elements are stored inline. In this case the it points to int_nodes.
-        * After exceeding ULIST_SIZE, dynamic memory is allocated.
-        */
-       struct ulist_node *nodes;
-
+       struct list_head nodes;
        struct rb_root root;
-
-       /*
-        * inline storage space for the first ULIST_SIZE entries
-        */
-       struct ulist_node int_nodes[ULIST_SIZE];
 };
 
 void ulist_init(struct ulist *ulist);
-void ulist_fini(struct ulist *ulist);
 void ulist_reinit(struct ulist *ulist);
 struct ulist *ulist_alloc(gfp_t gfp_mask);
 void ulist_free(struct ulist *ulist);
@@ -77,6 +60,6 @@ int ulist_add_merge(struct ulist *ulist, u64 val, u64 aux,
 struct ulist_node *ulist_next(struct ulist *ulist,
                              struct ulist_iterator *uiter);
 
-#define ULIST_ITER_INIT(uiter) ((uiter)->i = 0)
+#define ULIST_ITER_INIT(uiter) ((uiter)->cur_list = NULL)
 
 #endif
index fbda90004fe9ef08ab0b93b628485c63ee33d1e0..f6a4c03ee7d8fc1cf3aedc3f2b8edf0007992ff7 100644 (file)
@@ -69,7 +69,7 @@ static int btrfs_uuid_tree_lookup(struct btrfs_root *uuid_root, u8 *uuid,
        ret = -ENOENT;
 
        if (!IS_ALIGNED(item_size, sizeof(u64))) {
-               pr_warn("btrfs: uuid item with illegal size %lu!\n",
+               btrfs_warn(uuid_root->fs_info, "uuid item with illegal size %lu!",
                        (unsigned long)item_size);
                goto out;
        }
@@ -137,7 +137,8 @@ int btrfs_uuid_tree_add(struct btrfs_trans_handle *trans,
                offset = btrfs_item_ptr_offset(eb, slot);
                offset += btrfs_item_size_nr(eb, slot) - sizeof(subid_le);
        } else if (ret < 0) {
-               pr_warn("btrfs: insert uuid item failed %d (0x%016llx, 0x%016llx) type %u!\n",
+               btrfs_warn(uuid_root->fs_info, "insert uuid item failed %d "
+                       "(0x%016llx, 0x%016llx) type %u!",
                        ret, (unsigned long long)key.objectid,
                        (unsigned long long)key.offset, type);
                goto out;
@@ -183,7 +184,7 @@ int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans,
 
        ret = btrfs_search_slot(trans, uuid_root, &key, path, -1, 1);
        if (ret < 0) {
-               pr_warn("btrfs: error %d while searching for uuid item!\n",
+               btrfs_warn(uuid_root->fs_info, "error %d while searching for uuid item!",
                        ret);
                goto out;
        }
@@ -197,7 +198,7 @@ int btrfs_uuid_tree_rem(struct btrfs_trans_handle *trans,
        offset = btrfs_item_ptr_offset(eb, slot);
        item_size = btrfs_item_size_nr(eb, slot);
        if (!IS_ALIGNED(item_size, sizeof(u64))) {
-               pr_warn("btrfs: uuid item with illegal size %lu!\n",
+               btrfs_warn(uuid_root->fs_info, "uuid item with illegal size %lu!",
                        (unsigned long)item_size);
                ret = -ENOENT;
                goto out;
@@ -299,7 +300,7 @@ again_search_slot:
                offset = btrfs_item_ptr_offset(leaf, slot);
                item_size = btrfs_item_size_nr(leaf, slot);
                if (!IS_ALIGNED(item_size, sizeof(u64))) {
-                       pr_warn("btrfs: uuid item with illegal size %lu!\n",
+                       btrfs_warn(fs_info, "uuid item with illegal size %lu!",
                                (unsigned long)item_size);
                        goto skip;
                }
@@ -349,6 +350,6 @@ skip:
 out:
        btrfs_free_path(path);
        if (ret)
-               pr_warn("btrfs: btrfs_uuid_tree_iterate failed %d\n", ret);
+               btrfs_warn(fs_info, "btrfs_uuid_tree_iterate failed %d", ret);
        return 0;
 }
index 92303f42baaa92d5d845edddff1f8600fc46518e..bab0b84d8f806adf711b797c0909cb9dd664cc95 100644 (file)
@@ -125,7 +125,7 @@ static void btrfs_kobject_uevent(struct block_device *bdev,
 
        ret = kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, action);
        if (ret)
-               pr_warn("Sending event '%d' to kobject: '%s' (%p): failed\n",
+               pr_warn("BTRFS: Sending event '%d' to kobject: '%s' (%p): failed\n",
                        action,
                        kobject_name(&disk_to_dev(bdev->bd_disk)->kobj),
                        &disk_to_dev(bdev->bd_disk)->kobj);
@@ -200,7 +200,7 @@ btrfs_get_bdev_and_sb(const char *device_path, fmode_t flags, void *holder,
 
        if (IS_ERR(*bdev)) {
                ret = PTR_ERR(*bdev);
-               printk(KERN_INFO "btrfs: open %s failed\n", device_path);
+               printk(KERN_INFO "BTRFS: open %s failed\n", device_path);
                goto error;
        }
 
@@ -912,9 +912,9 @@ int btrfs_scan_one_device(const char *path, fmode_t flags, void *holder,
        if (disk_super->label[0]) {
                if (disk_super->label[BTRFS_LABEL_SIZE - 1])
                        disk_super->label[BTRFS_LABEL_SIZE - 1] = '\0';
-               printk(KERN_INFO "btrfs: device label %s ", disk_super->label);
+               printk(KERN_INFO "BTRFS: device label %s ", disk_super->label);
        } else {
-               printk(KERN_INFO "btrfs: device fsid %pU ", disk_super->fsid);
+               printk(KERN_INFO "BTRFS: device fsid %pU ", disk_super->fsid);
        }
 
        printk(KERN_CONT "devid %llu transid %llu %s\n", devid, transid, path);
@@ -1813,7 +1813,7 @@ int btrfs_find_device_missing_or_by_path(struct btrfs_root *root,
                }
 
                if (!*device) {
-                       pr_err("btrfs: no missing device found\n");
+                       btrfs_err(root->fs_info, "no missing device found");
                        return -ENOENT;
                }
 
@@ -3052,7 +3052,7 @@ loop:
 error:
        btrfs_free_path(path);
        if (enospc_errors) {
-               printk(KERN_INFO "btrfs: %d enospc errors during balance\n",
+               btrfs_info(fs_info, "%d enospc errors during balance",
                       enospc_errors);
                if (!ret)
                        ret = -ENOSPC;
@@ -3138,8 +3138,8 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
                if (!(bctl->flags & BTRFS_BALANCE_DATA) ||
                    !(bctl->flags & BTRFS_BALANCE_METADATA) ||
                    memcmp(&bctl->data, &bctl->meta, sizeof(bctl->data))) {
-                       printk(KERN_ERR "btrfs: with mixed groups data and "
-                              "metadata balance options must be the same\n");
+                       btrfs_err(fs_info, "with mixed groups data and "
+                                  "metadata balance options must be the same");
                        ret = -EINVAL;
                        goto out;
                }
@@ -3165,8 +3165,8 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
        if ((bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
            (!alloc_profile_is_valid(bctl->data.target, 1) ||
             (bctl->data.target & ~allowed))) {
-               printk(KERN_ERR "btrfs: unable to start balance with target "
-                      "data profile %llu\n",
+               btrfs_err(fs_info, "unable to start balance with target "
+                          "data profile %llu",
                       bctl->data.target);
                ret = -EINVAL;
                goto out;
@@ -3174,8 +3174,8 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
        if ((bctl->meta.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
            (!alloc_profile_is_valid(bctl->meta.target, 1) ||
             (bctl->meta.target & ~allowed))) {
-               printk(KERN_ERR "btrfs: unable to start balance with target "
-                      "metadata profile %llu\n",
+               btrfs_err(fs_info,
+                          "unable to start balance with target metadata profile %llu",
                       bctl->meta.target);
                ret = -EINVAL;
                goto out;
@@ -3183,8 +3183,8 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
        if ((bctl->sys.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
            (!alloc_profile_is_valid(bctl->sys.target, 1) ||
             (bctl->sys.target & ~allowed))) {
-               printk(KERN_ERR "btrfs: unable to start balance with target "
-                      "system profile %llu\n",
+               btrfs_err(fs_info,
+                          "unable to start balance with target system profile %llu",
                       bctl->sys.target);
                ret = -EINVAL;
                goto out;
@@ -3193,7 +3193,7 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
        /* allow dup'ed data chunks only in mixed mode */
        if (!mixed && (bctl->data.flags & BTRFS_BALANCE_ARGS_CONVERT) &&
            (bctl->data.target & BTRFS_BLOCK_GROUP_DUP)) {
-               printk(KERN_ERR "btrfs: dup for data is not allowed\n");
+               btrfs_err(fs_info, "dup for data is not allowed");
                ret = -EINVAL;
                goto out;
        }
@@ -3213,11 +3213,10 @@ int btrfs_balance(struct btrfs_balance_control *bctl,
                     (fs_info->avail_metadata_alloc_bits & allowed) &&
                     !(bctl->meta.target & allowed))) {
                        if (bctl->flags & BTRFS_BALANCE_FORCE) {
-                               printk(KERN_INFO "btrfs: force reducing metadata "
-                                      "integrity\n");
+                               btrfs_info(fs_info, "force reducing metadata integrity");
                        } else {
-                               printk(KERN_ERR "btrfs: balance will reduce metadata "
-                                      "integrity, use force if you want this\n");
+                               btrfs_err(fs_info, "balance will reduce metadata "
+                                          "integrity, use force if you want this");
                                ret = -EINVAL;
                                goto out;
                        }
@@ -3303,7 +3302,7 @@ static int balance_kthread(void *data)
        mutex_lock(&fs_info->balance_mutex);
 
        if (fs_info->balance_ctl) {
-               printk(KERN_INFO "btrfs: continuing balance\n");
+               btrfs_info(fs_info, "continuing balance");
                ret = btrfs_balance(fs_info->balance_ctl, NULL);
        }
 
@@ -3325,7 +3324,7 @@ int btrfs_resume_balance_async(struct btrfs_fs_info *fs_info)
        spin_unlock(&fs_info->balance_lock);
 
        if (btrfs_test_opt(fs_info->tree_root, SKIP_BALANCE)) {
-               printk(KERN_INFO "btrfs: force skipping balance\n");
+               btrfs_info(fs_info, "force skipping balance");
                return 0;
        }
 
@@ -3543,7 +3542,7 @@ update_tree:
                                                  BTRFS_UUID_KEY_SUBVOL,
                                                  key.objectid);
                        if (ret < 0) {
-                               pr_warn("btrfs: uuid_tree_add failed %d\n",
+                               btrfs_warn(fs_info, "uuid_tree_add failed %d",
                                        ret);
                                break;
                        }
@@ -3555,7 +3554,7 @@ update_tree:
                                                 BTRFS_UUID_KEY_RECEIVED_SUBVOL,
                                                  key.objectid);
                        if (ret < 0) {
-                               pr_warn("btrfs: uuid_tree_add failed %d\n",
+                               btrfs_warn(fs_info, "uuid_tree_add failed %d",
                                        ret);
                                break;
                        }
@@ -3590,7 +3589,7 @@ out:
        if (trans && !IS_ERR(trans))
                btrfs_end_transaction(trans, fs_info->uuid_root);
        if (ret)
-               pr_warn("btrfs: btrfs_uuid_scan_kthread failed %d\n", ret);
+               btrfs_warn(fs_info, "btrfs_uuid_scan_kthread failed %d", ret);
        else
                fs_info->update_uuid_tree_gen = 1;
        up(&fs_info->uuid_tree_rescan_sem);
@@ -3654,7 +3653,7 @@ static int btrfs_uuid_rescan_kthread(void *data)
         */
        ret = btrfs_uuid_tree_iterate(fs_info, btrfs_check_uuid_tree_entry);
        if (ret < 0) {
-               pr_warn("btrfs: iterating uuid_tree failed %d\n", ret);
+               btrfs_warn(fs_info, "iterating uuid_tree failed %d", ret);
                up(&fs_info->uuid_tree_rescan_sem);
                return ret;
        }
@@ -3695,7 +3694,7 @@ int btrfs_create_uuid_tree(struct btrfs_fs_info *fs_info)
        task = kthread_run(btrfs_uuid_scan_kthread, fs_info, "btrfs-uuid");
        if (IS_ERR(task)) {
                /* fs_info->update_uuid_tree_gen remains 0 in all error case */
-               pr_warn("btrfs: failed to start uuid_scan task\n");
+               btrfs_warn(fs_info, "failed to start uuid_scan task");
                up(&fs_info->uuid_tree_rescan_sem);
                return PTR_ERR(task);
        }
@@ -3711,7 +3710,7 @@ int btrfs_check_uuid_tree(struct btrfs_fs_info *fs_info)
        task = kthread_run(btrfs_uuid_rescan_kthread, fs_info, "btrfs-uuid");
        if (IS_ERR(task)) {
                /* fs_info->update_uuid_tree_gen remains 0 in all error case */
-               pr_warn("btrfs: failed to start uuid_rescan task\n");
+               btrfs_warn(fs_info, "failed to start uuid_rescan task");
                up(&fs_info->uuid_tree_rescan_sem);
                return PTR_ERR(task);
        }
@@ -4033,7 +4032,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
                max_stripe_size = 32 * 1024 * 1024;
                max_chunk_size = 2 * max_stripe_size;
        } else {
-               printk(KERN_ERR "btrfs: invalid chunk type 0x%llx requested\n",
+               btrfs_err(info, "invalid chunk type 0x%llx requested\n",
                       type);
                BUG_ON(1);
        }
@@ -4065,7 +4064,7 @@ static int __btrfs_alloc_chunk(struct btrfs_trans_handle *trans,
 
                if (!device->writeable) {
                        WARN(1, KERN_ERR
-                              "btrfs: read-only device in alloc_list\n");
+                              "BTRFS: read-only device in alloc_list\n");
                        continue;
                }
 
@@ -5193,13 +5192,13 @@ int btrfs_rmap_block(struct btrfs_mapping_tree *map_tree,
        read_unlock(&em_tree->lock);
 
        if (!em) {
-               printk(KERN_ERR "btrfs: couldn't find em for chunk %Lu\n",
+               printk(KERN_ERR "BTRFS: couldn't find em for chunk %Lu\n",
                       chunk_start);
                return -EIO;
        }
 
        if (em->start != chunk_start) {
-               printk(KERN_ERR "btrfs: bad chunk start, em=%Lu, wanted=%Lu\n",
+               printk(KERN_ERR "BTRFS: bad chunk start, em=%Lu, wanted=%Lu\n",
                       em->start, chunk_start);
                free_extent_map(em);
                return -EIO;
@@ -5298,6 +5297,13 @@ static void btrfs_end_bio(struct bio *bio, int err)
                        bio_put(bio);
                        bio = bbio->orig_bio;
                }
+
+               /*
+                * We have original bio now. So increment bi_remaining to
+                * account for it in endio
+                */
+               atomic_inc(&bio->bi_remaining);
+
                bio->bi_private = bbio->private;
                bio->bi_end_io = bbio->end_io;
                btrfs_io_bio(bio)->mirror_num = bbio->mirror_num;
@@ -5411,7 +5417,7 @@ static int bio_size_ok(struct block_device *bdev, struct bio *bio,
        if (!q->merge_bvec_fn)
                return 1;
 
-       bvm.bi_size = bio->bi_size - prev->bv_len;
+       bvm.bi_size = bio->bi_iter.bi_size - prev->bv_len;
        if (q->merge_bvec_fn(q, &bvm, prev) < prev->bv_len)
                return 0;
        return 1;
@@ -5426,7 +5432,7 @@ static void submit_stripe_bio(struct btrfs_root *root, struct btrfs_bio *bbio,
        bio->bi_private = bbio;
        btrfs_io_bio(bio)->stripe_index = dev_nr;
        bio->bi_end_io = btrfs_end_bio;
-       bio->bi_sector = physical >> 9;
+       bio->bi_iter.bi_sector = physical >> 9;
 #ifdef DEBUG
        {
                struct rcu_string *name;
@@ -5464,7 +5470,7 @@ again:
        while (bvec <= (first_bio->bi_io_vec + first_bio->bi_vcnt - 1)) {
                if (bio_add_page(bio, bvec->bv_page, bvec->bv_len,
                                 bvec->bv_offset) < bvec->bv_len) {
-                       u64 len = bio->bi_size;
+                       u64 len = bio->bi_iter.bi_size;
 
                        atomic_inc(&bbio->stripes_pending);
                        submit_stripe_bio(root, bbio, bio, physical, dev_nr,
@@ -5486,7 +5492,7 @@ static void bbio_error(struct btrfs_bio *bbio, struct bio *bio, u64 logical)
                bio->bi_private = bbio->private;
                bio->bi_end_io = bbio->end_io;
                btrfs_io_bio(bio)->mirror_num = bbio->mirror_num;
-               bio->bi_sector = logical >> 9;
+               bio->bi_iter.bi_sector = logical >> 9;
                kfree(bbio);
                bio_endio(bio, -EIO);
        }
@@ -5497,7 +5503,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
 {
        struct btrfs_device *dev;
        struct bio *first_bio = bio;
-       u64 logical = (u64)bio->bi_sector << 9;
+       u64 logical = (u64)bio->bi_iter.bi_sector << 9;
        u64 length = 0;
        u64 map_length;
        u64 *raid_map = NULL;
@@ -5506,7 +5512,7 @@ int btrfs_map_bio(struct btrfs_root *root, int rw, struct bio *bio,
        int total_devs = 1;
        struct btrfs_bio *bbio = NULL;
 
-       length = bio->bi_size;
+       length = bio->bi_iter.bi_size;
        map_length = length;
 
        ret = __btrfs_map_block(root->fs_info, rw, logical, &map_length, &bbio,
@@ -6123,7 +6129,8 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,
        BUG_ON(!path);
        ret = btrfs_search_slot(trans, dev_root, &key, path, -1, 1);
        if (ret < 0) {
-               printk_in_rcu(KERN_WARNING "btrfs: error %d while searching for dev_stats item for device %s!\n",
+               printk_in_rcu(KERN_WARNING "BTRFS: "
+                       "error %d while searching for dev_stats item for device %s!\n",
                              ret, rcu_str_deref(device->name));
                goto out;
        }
@@ -6133,7 +6140,8 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,
                /* need to delete old one and insert a new one */
                ret = btrfs_del_item(trans, dev_root, path);
                if (ret != 0) {
-                       printk_in_rcu(KERN_WARNING "btrfs: delete too small dev_stats item for device %s failed %d!\n",
+                       printk_in_rcu(KERN_WARNING "BTRFS: "
+                               "delete too small dev_stats item for device %s failed %d!\n",
                                      rcu_str_deref(device->name), ret);
                        goto out;
                }
@@ -6146,7 +6154,8 @@ static int update_dev_stat_item(struct btrfs_trans_handle *trans,
                ret = btrfs_insert_empty_item(trans, dev_root, path,
                                              &key, sizeof(*ptr));
                if (ret < 0) {
-                       printk_in_rcu(KERN_WARNING "btrfs: insert dev_stats item for device %s failed %d!\n",
+                       printk_in_rcu(KERN_WARNING "BTRFS: "
+                                         "insert dev_stats item for device %s failed %d!\n",
                                      rcu_str_deref(device->name), ret);
                        goto out;
                }
@@ -6199,16 +6208,14 @@ static void btrfs_dev_stat_print_on_error(struct btrfs_device *dev)
 {
        if (!dev->dev_stats_valid)
                return;
-       printk_ratelimited_in_rcu(KERN_ERR
-                          "btrfs: bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n",
+       printk_ratelimited_in_rcu(KERN_ERR "BTRFS: "
+                          "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n",
                           rcu_str_deref(dev->name),
                           btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS),
                           btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS),
                           btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_FLUSH_ERRS),
-                          btrfs_dev_stat_read(dev,
-                                              BTRFS_DEV_STAT_CORRUPTION_ERRS),
-                          btrfs_dev_stat_read(dev,
-                                              BTRFS_DEV_STAT_GENERATION_ERRS));
+                          btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_CORRUPTION_ERRS),
+                          btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_GENERATION_ERRS));
 }
 
 static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev)
@@ -6221,7 +6228,8 @@ static void btrfs_dev_stat_print_on_load(struct btrfs_device *dev)
        if (i == BTRFS_DEV_STAT_VALUES_MAX)
                return; /* all values == 0, suppress message */
 
-       printk_in_rcu(KERN_INFO "btrfs: bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n",
+       printk_in_rcu(KERN_INFO "BTRFS: "
+                  "bdev %s errs: wr %u, rd %u, flush %u, corrupt %u, gen %u\n",
               rcu_str_deref(dev->name),
               btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_WRITE_ERRS),
               btrfs_dev_stat_read(dev, BTRFS_DEV_STAT_READ_ERRS),
@@ -6242,12 +6250,10 @@ int btrfs_get_dev_stats(struct btrfs_root *root,
        mutex_unlock(&fs_devices->device_list_mutex);
 
        if (!dev) {
-               printk(KERN_WARNING
-                      "btrfs: get dev_stats failed, device not found\n");
+               btrfs_warn(root->fs_info, "get dev_stats failed, device not found");
                return -ENODEV;
        } else if (!dev->dev_stats_valid) {
-               printk(KERN_WARNING
-                      "btrfs: get dev_stats failed, not yet valid\n");
+               btrfs_warn(root->fs_info, "get dev_stats failed, not yet valid");
                return -ENODEV;
        } else if (stats->flags & BTRFS_DEV_STATS_RESET) {
                for (i = 0; i < BTRFS_DEV_STAT_VALUES_MAX; i++) {
index 05740b9789e4f97dd92b65f0d000e87dac7558e6..ad8328d797ea9910c21f0ecd5db6051d347a4571 100644 (file)
 #include <linux/rwsem.h>
 #include <linux/xattr.h>
 #include <linux/security.h>
+#include <linux/posix_acl_xattr.h>
 #include "ctree.h"
 #include "btrfs_inode.h"
 #include "transaction.h"
 #include "xattr.h"
 #include "disk-io.h"
+#include "props.h"
 
 
 ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
@@ -313,8 +315,8 @@ err:
  */
 const struct xattr_handler *btrfs_xattr_handlers[] = {
 #ifdef CONFIG_BTRFS_FS_POSIX_ACL
-       &btrfs_xattr_acl_access_handler,
-       &btrfs_xattr_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
        NULL,
 };
@@ -331,7 +333,8 @@ static bool btrfs_is_valid_xattr(const char *name)
                        XATTR_SECURITY_PREFIX_LEN) ||
               !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) ||
               !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
-              !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
+              !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) ||
+               !strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN);
 }
 
 ssize_t btrfs_getxattr(struct dentry *dentry, const char *name,
@@ -373,6 +376,10 @@ int btrfs_setxattr(struct dentry *dentry, const char *name, const void *value,
        if (!btrfs_is_valid_xattr(name))
                return -EOPNOTSUPP;
 
+       if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
+               return btrfs_set_prop(dentry->d_inode, name,
+                                     value, size, flags);
+
        if (size == 0)
                value = "";  /* empty EA, do not remove */
 
@@ -402,6 +409,10 @@ int btrfs_removexattr(struct dentry *dentry, const char *name)
        if (!btrfs_is_valid_xattr(name))
                return -EOPNOTSUPP;
 
+       if (!strncmp(name, XATTR_BTRFS_PREFIX, XATTR_BTRFS_PREFIX_LEN))
+               return btrfs_set_prop(dentry->d_inode, name,
+                                     NULL, 0, XATTR_REPLACE);
+
        return __btrfs_setxattr(NULL, dentry->d_inode, name, NULL, 0,
                                XATTR_REPLACE);
 }
index b3cc8039134bc4ed59420f51b48ab72c04f2eedc..5049608d13889e1e647cdb447851a6b30319990d 100644 (file)
@@ -21,8 +21,6 @@
 
 #include <linux/xattr.h>
 
-extern const struct xattr_handler btrfs_xattr_acl_access_handler;
-extern const struct xattr_handler btrfs_xattr_acl_default_handler;
 extern const struct xattr_handler *btrfs_xattr_handlers[];
 
 extern ssize_t __btrfs_getxattr(struct inode *inode, const char *name,
index 9acb846c3e7f775e78684d2117c861c70b9890bc..8e57191950cb60072944e58fbb9ca0f07f9d4315 100644 (file)
@@ -97,7 +97,7 @@ static int zlib_compress_pages(struct list_head *ws,
        *total_in = 0;
 
        if (Z_OK != zlib_deflateInit(&workspace->def_strm, 3)) {
-               printk(KERN_WARNING "btrfs: deflateInit failed\n");
+               printk(KERN_WARNING "BTRFS: deflateInit failed\n");
                ret = -1;
                goto out;
        }
@@ -125,7 +125,7 @@ static int zlib_compress_pages(struct list_head *ws,
        while (workspace->def_strm.total_in < len) {
                ret = zlib_deflate(&workspace->def_strm, Z_SYNC_FLUSH);
                if (ret != Z_OK) {
-                       printk(KERN_DEBUG "btrfs: deflate in loop returned %d\n",
+                       printk(KERN_DEBUG "BTRFS: deflate in loop returned %d\n",
                               ret);
                        zlib_deflateEnd(&workspace->def_strm);
                        ret = -1;
@@ -252,7 +252,7 @@ static int zlib_decompress_biovec(struct list_head *ws, struct page **pages_in,
        }
 
        if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
-               printk(KERN_WARNING "btrfs: inflateInit failed\n");
+               printk(KERN_WARNING "BTRFS: inflateInit failed\n");
                return -1;
        }
        while (workspace->inf_strm.total_in < srclen) {
@@ -336,7 +336,7 @@ static int zlib_decompress(struct list_head *ws, unsigned char *data_in,
        }
 
        if (Z_OK != zlib_inflateInit2(&workspace->inf_strm, wbits)) {
-               printk(KERN_WARNING "btrfs: inflateInit failed\n");
+               printk(KERN_WARNING "BTRFS: inflateInit failed\n");
                return -1;
        }
 
index 6024877335caf2a9dfa6af1018c5da19b0e8a2ae..651dba10b9c2b5468af528ad3114166b90d8c067 100644 (file)
@@ -1312,7 +1312,7 @@ static void bh_lru_install(struct buffer_head *bh)
                }
                while (out < BH_LRU_SIZE)
                        bhs[out++] = NULL;
-               memcpy(__this_cpu_ptr(&bh_lrus.bhs), bhs, sizeof(bhs));
+               memcpy(this_cpu_ptr(&bh_lrus.bhs), bhs, sizeof(bhs));
        }
        bh_lru_unlock();
 
@@ -2982,11 +2982,11 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh)
         * let it through, and the IO layer will turn it into
         * an EIO.
         */
-       if (unlikely(bio->bi_sector >= maxsector))
+       if (unlikely(bio->bi_iter.bi_sector >= maxsector))
                return;
 
-       maxsector -= bio->bi_sector;
-       bytes = bio->bi_size;
+       maxsector -= bio->bi_iter.bi_sector;
+       bytes = bio->bi_iter.bi_size;
        if (likely((bytes >> 9) <= maxsector))
                return;
 
@@ -2994,7 +2994,7 @@ static void guard_bh_eod(int rw, struct bio *bio, struct buffer_head *bh)
        bytes = maxsector << 9;
 
        /* Truncate the bio.. */
-       bio->bi_size = bytes;
+       bio->bi_iter.bi_size = bytes;
        bio->bi_io_vec[0].bv_len = bytes;
 
        /* ..and clear the end of the buffer for reads */
@@ -3029,14 +3029,14 @@ int _submit_bh(int rw, struct buffer_head *bh, unsigned long bio_flags)
         */
        bio = bio_alloc(GFP_NOIO, 1);
 
-       bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
+       bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
        bio->bi_bdev = bh->b_bdev;
        bio->bi_io_vec[0].bv_page = bh->b_page;
        bio->bi_io_vec[0].bv_len = bh->b_size;
        bio->bi_io_vec[0].bv_offset = bh_offset(bh);
 
        bio->bi_vcnt = 1;
-       bio->bi_size = bh->b_size;
+       bio->bi_iter.bi_size = bh->b_size;
 
        bio->bi_end_io = end_bio_bh_io_sync;
        bio->bi_private = bh;
index ac9a2ef5bb9b8f0e8638c0d594e1cd51b5719c91..264e9bf83ff3f2ffe2e040f7032771bdcc23903f 100644 (file)
@@ -25,3 +25,16 @@ config CEPH_FSCACHE
          caching support for Ceph clients using FS-Cache
 
 endif
+
+config CEPH_FS_POSIX_ACL
+       bool "Ceph POSIX Access Control Lists"
+       depends on CEPH_FS
+       select FS_POSIX_ACL
+       help
+         POSIX Access Control Lists (ACLs) support permissions for users and
+         groups beyond the owner/group/world scheme.
+
+         To learn more about Access Control Lists, visit the POSIX ACLs for
+         Linux website <http://acl.bestbits.at/>.
+
+         If you don't know what Access Control Lists are, say N
index 32e30106a2f01e8bf62138981e1c4b678a509cfc..85a4230b9bffd5ca311d7b37bfc97e409ccc30ee 100644 (file)
@@ -10,3 +10,4 @@ ceph-y := super.o inode.o dir.o file.o locks.o addr.o ioctl.o \
        debugfs.o
 
 ceph-$(CONFIG_CEPH_FSCACHE) += cache.o
+ceph-$(CONFIG_CEPH_FS_POSIX_ACL) += acl.o
diff --git a/fs/ceph/acl.c b/fs/ceph/acl.c
new file mode 100644 (file)
index 0000000..4c2d452
--- /dev/null
@@ -0,0 +1,209 @@
+/*
+ * linux/fs/ceph/acl.c
+ *
+ * Copyright (C) 2013 Guangliang Zhao, <lucienchao@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 021110-1307, USA.
+ */
+
+#include <linux/ceph/ceph_debug.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
+#include <linux/posix_acl.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+
+#include "super.h"
+
+static inline void ceph_set_cached_acl(struct inode *inode,
+                                       int type, struct posix_acl *acl)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+
+       spin_lock(&ci->i_ceph_lock);
+       if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0))
+               set_cached_acl(inode, type, acl);
+       spin_unlock(&ci->i_ceph_lock);
+}
+
+static inline struct posix_acl *ceph_get_cached_acl(struct inode *inode,
+                                                       int type)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct posix_acl *acl = ACL_NOT_CACHED;
+
+       spin_lock(&ci->i_ceph_lock);
+       if (__ceph_caps_issued_mask(ci, CEPH_CAP_XATTR_SHARED, 0))
+               acl = get_cached_acl(inode, type);
+       spin_unlock(&ci->i_ceph_lock);
+
+       return acl;
+}
+
+void ceph_forget_all_cached_acls(struct inode *inode)
+{
+       forget_all_cached_acls(inode);
+}
+
+struct posix_acl *ceph_get_acl(struct inode *inode, int type)
+{
+       int size;
+       const char *name;
+       char *value = NULL;
+       struct posix_acl *acl;
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name = POSIX_ACL_XATTR_ACCESS;
+               break;
+       case ACL_TYPE_DEFAULT:
+               name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
+               BUG();
+       }
+
+       size = __ceph_getxattr(inode, name, "", 0);
+       if (size > 0) {
+               value = kzalloc(size, GFP_NOFS);
+               if (!value)
+                       return ERR_PTR(-ENOMEM);
+               size = __ceph_getxattr(inode, name, value, size);
+       }
+
+       if (size > 0)
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
+       else if (size == -ERANGE || size == -ENODATA || size == 0)
+               acl = NULL;
+       else
+               acl = ERR_PTR(-EIO);
+
+       kfree(value);
+
+       if (!IS_ERR(acl))
+               ceph_set_cached_acl(inode, type, acl);
+
+       return acl;
+}
+
+int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+       int ret = 0, size = 0;
+       const char *name = NULL;
+       char *value = NULL;
+       struct iattr newattrs;
+       umode_t new_mode = inode->i_mode, old_mode = inode->i_mode;
+       struct dentry *dentry;
+
+       if (acl) {
+               ret = posix_acl_valid(acl);
+               if (ret < 0)
+                       goto out;
+       }
+
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               name = POSIX_ACL_XATTR_ACCESS;
+               if (acl) {
+                       ret = posix_acl_equiv_mode(acl, &new_mode);
+                       if (ret < 0)
+                               goto out;
+                       if (ret == 0)
+                               acl = NULL;
+               }
+               break;
+       case ACL_TYPE_DEFAULT:
+               if (!S_ISDIR(inode->i_mode)) {
+                       ret = acl ? -EINVAL : 0;
+                       goto out;
+               }
+               name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (acl) {
+               size = posix_acl_xattr_size(acl->a_count);
+               value = kmalloc(size, GFP_NOFS);
+               if (!value) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+
+               ret = posix_acl_to_xattr(&init_user_ns, acl, value, size);
+               if (ret < 0)
+                       goto out_free;
+       }
+
+       dentry = d_find_alias(inode);
+       if (new_mode != old_mode) {
+               newattrs.ia_mode = new_mode;
+               newattrs.ia_valid = ATTR_MODE;
+               ret = ceph_setattr(dentry, &newattrs);
+               if (ret)
+                       goto out_dput;
+       }
+
+       if (value)
+               ret = __ceph_setxattr(dentry, name, value, size, 0);
+       else
+               ret = __ceph_removexattr(dentry, name);
+
+       if (ret) {
+               if (new_mode != old_mode) {
+                       newattrs.ia_mode = old_mode;
+                       newattrs.ia_valid = ATTR_MODE;
+                       ceph_setattr(dentry, &newattrs);
+               }
+               goto out_dput;
+       }
+
+       ceph_set_cached_acl(inode, type, acl);
+
+out_dput:
+       dput(dentry);
+out_free:
+       kfree(value);
+out:
+       return ret;
+}
+
+int ceph_init_acl(struct dentry *dentry, struct inode *inode, struct inode *dir)
+{
+       struct posix_acl *default_acl, *acl;
+       int error;
+
+       error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+       if (error)
+               return error;
+
+       if (!default_acl && !acl)
+               cache_no_acl(inode);
+
+       if (default_acl) {
+               error = ceph_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+               posix_acl_release(default_acl);
+       }
+       if (acl) {
+               if (!error)
+                       error = ceph_set_acl(inode, acl, ACL_TYPE_ACCESS);
+               posix_acl_release(acl);
+       }
+       return error;
+}
index ec3ba43b9faae73fba6d6352da9515a812ec9f36..b53278c9fd9718509e96d91d3ea1027581714214 100644 (file)
@@ -209,6 +209,7 @@ static int readpage_nounlock(struct file *filp, struct page *page)
                err = 0;
        if (err < 0) {
                SetPageError(page);
+               ceph_fscache_readpage_cancel(inode, page);
                goto out;
        } else {
                if (err < PAGE_CACHE_SIZE) {
@@ -256,6 +257,8 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg)
        for (i = 0; i < num_pages; i++) {
                struct page *page = osd_data->pages[i];
 
+               if (rc < 0)
+                       goto unlock;
                if (bytes < (int)PAGE_CACHE_SIZE) {
                        /* zero (remainder of) page */
                        int s = bytes < 0 ? 0 : bytes;
@@ -266,6 +269,7 @@ static void finish_read(struct ceph_osd_request *req, struct ceph_msg *msg)
                flush_dcache_page(page);
                SetPageUptodate(page);
                ceph_readpage_to_fscache(inode, page);
+unlock:
                unlock_page(page);
                page_cache_release(page);
                bytes -= PAGE_CACHE_SIZE;
@@ -1207,6 +1211,41 @@ const struct address_space_operations ceph_aops = {
 /*
  * vm ops
  */
+static int ceph_filemap_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       struct inode *inode = file_inode(vma->vm_file);
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_file_info *fi = vma->vm_file->private_data;
+       loff_t off = vmf->pgoff << PAGE_CACHE_SHIFT;
+       int want, got, ret;
+
+       dout("filemap_fault %p %llx.%llx %llu~%zd trying to get caps\n",
+            inode, ceph_vinop(inode), off, (size_t)PAGE_CACHE_SIZE);
+       if (fi->fmode & CEPH_FILE_MODE_LAZY)
+               want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO;
+       else
+               want = CEPH_CAP_FILE_CACHE;
+       while (1) {
+               got = 0;
+               ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1);
+               if (ret == 0)
+                       break;
+               if (ret != -ERESTARTSYS) {
+                       WARN_ON(1);
+                       return VM_FAULT_SIGBUS;
+               }
+       }
+       dout("filemap_fault %p %llu~%zd got cap refs on %s\n",
+            inode, off, (size_t)PAGE_CACHE_SIZE, ceph_cap_string(got));
+
+       ret = filemap_fault(vma, vmf);
+
+       dout("filemap_fault %p %llu~%zd dropping cap refs on %s ret %d\n",
+            inode, off, (size_t)PAGE_CACHE_SIZE, ceph_cap_string(got), ret);
+       ceph_put_cap_refs(ci, got);
+
+       return ret;
+}
 
 /*
  * Reuse write_begin here for simplicity.
@@ -1214,23 +1253,41 @@ const struct address_space_operations ceph_aops = {
 static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
 {
        struct inode *inode = file_inode(vma->vm_file);
-       struct page *page = vmf->page;
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_file_info *fi = vma->vm_file->private_data;
        struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
+       struct page *page = vmf->page;
        loff_t off = page_offset(page);
-       loff_t size, len;
-       int ret;
-
-       /* Update time before taking page lock */
-       file_update_time(vma->vm_file);
+       loff_t size = i_size_read(inode);
+       size_t len;
+       int want, got, ret;
 
-       size = i_size_read(inode);
        if (off + PAGE_CACHE_SIZE <= size)
                len = PAGE_CACHE_SIZE;
        else
                len = size & ~PAGE_CACHE_MASK;
 
-       dout("page_mkwrite %p %llu~%llu page %p idx %lu\n", inode,
-            off, len, page, page->index);
+       dout("page_mkwrite %p %llx.%llx %llu~%zd getting caps i_size %llu\n",
+            inode, ceph_vinop(inode), off, len, size);
+       if (fi->fmode & CEPH_FILE_MODE_LAZY)
+               want = CEPH_CAP_FILE_BUFFER | CEPH_CAP_FILE_LAZYIO;
+       else
+               want = CEPH_CAP_FILE_BUFFER;
+       while (1) {
+               got = 0;
+               ret = ceph_get_caps(ci, CEPH_CAP_FILE_WR, want, &got, off + len);
+               if (ret == 0)
+                       break;
+               if (ret != -ERESTARTSYS) {
+                       WARN_ON(1);
+                       return VM_FAULT_SIGBUS;
+               }
+       }
+       dout("page_mkwrite %p %llu~%zd got cap refs on %s\n",
+            inode, off, len, ceph_cap_string(got));
+
+       /* Update time before taking page lock */
+       file_update_time(vma->vm_file);
 
        lock_page(page);
 
@@ -1252,14 +1309,26 @@ static int ceph_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
                        ret = VM_FAULT_SIGBUS;
        }
 out:
-       dout("page_mkwrite %p %llu~%llu = %d\n", inode, off, len, ret);
-       if (ret != VM_FAULT_LOCKED)
+       if (ret != VM_FAULT_LOCKED) {
                unlock_page(page);
+       } else {
+               int dirty;
+               spin_lock(&ci->i_ceph_lock);
+               dirty = __ceph_mark_dirty_caps(ci, CEPH_CAP_FILE_WR);
+               spin_unlock(&ci->i_ceph_lock);
+               if (dirty)
+                       __mark_inode_dirty(inode, dirty);
+       }
+
+       dout("page_mkwrite %p %llu~%zd dropping cap refs on %s ret %d\n",
+            inode, off, len, ceph_cap_string(got), ret);
+       ceph_put_cap_refs(ci, got);
+
        return ret;
 }
 
 static struct vm_operations_struct ceph_vmops = {
-       .fault          = filemap_fault,
+       .fault          = ceph_filemap_fault,
        .page_mkwrite   = ceph_page_mkwrite,
        .remap_pages    = generic_file_remap_pages,
 };
index ba949408a336e663e018e5a2b9d0da040d9346f7..da95f61b7a09e850e6d28de88aceb4493d7157b8 100644 (file)
@@ -67,6 +67,14 @@ static inline int ceph_release_fscache_page(struct page *page, gfp_t gfp)
        return fscache_maybe_release_page(ci->fscache, page, gfp);
 }
 
+static inline void ceph_fscache_readpage_cancel(struct inode *inode,
+                                               struct page *page)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       if (fscache_cookie_valid(ci->fscache) && PageFsCache(page))
+               __fscache_uncache_page(ci->fscache, page);
+}
+
 static inline void ceph_fscache_readpages_cancel(struct inode *inode,
                                                 struct list_head *pages)
 {
@@ -145,6 +153,11 @@ static inline int ceph_release_fscache_page(struct page *page, gfp_t gfp)
        return 1;
 }
 
+static inline void ceph_fscache_readpage_cancel(struct inode *inode,
+                                               struct page *page)
+{
+}
+
 static inline void ceph_fscache_readpages_cancel(struct inode *inode,
                                                 struct list_head *pages)
 {
index 3c0a4bd7499645ca8bf90fd1a6ba16f6831c164c..17543383545c162f58425fbc8629a99f1c5a717e 100644 (file)
@@ -555,21 +555,34 @@ retry:
                cap->ci = ci;
                __insert_cap_node(ci, cap);
 
-               /* clear out old exporting info?  (i.e. on cap import) */
-               if (ci->i_cap_exporting_mds == mds) {
-                       ci->i_cap_exporting_issued = 0;
-                       ci->i_cap_exporting_mseq = 0;
-                       ci->i_cap_exporting_mds = -1;
-               }
-
                /* add to session cap list */
                cap->session = session;
                spin_lock(&session->s_cap_lock);
                list_add_tail(&cap->session_caps, &session->s_caps);
                session->s_nr_caps++;
                spin_unlock(&session->s_cap_lock);
-       } else if (new_cap)
-               ceph_put_cap(mdsc, new_cap);
+       } else {
+               if (new_cap)
+                       ceph_put_cap(mdsc, new_cap);
+
+               /*
+                * auth mds of the inode changed. we received the cap export
+                * message, but still haven't received the cap import message.
+                * handle_cap_export() updated the new auth MDS' cap.
+                *
+                * "ceph_seq_cmp(seq, cap->seq) <= 0" means we are processing
+                * a message that was send before the cap import message. So
+                * don't remove caps.
+                */
+               if (ceph_seq_cmp(seq, cap->seq) <= 0) {
+                       WARN_ON(cap != ci->i_auth_cap);
+                       WARN_ON(cap->cap_id != cap_id);
+                       seq = cap->seq;
+                       mseq = cap->mseq;
+                       issued |= cap->issued;
+                       flags |= CEPH_CAP_FLAG_AUTH;
+               }
+       }
 
        if (!ci->i_snap_realm) {
                /*
@@ -611,15 +624,9 @@ retry:
                if (ci->i_auth_cap == NULL ||
                    ceph_seq_cmp(ci->i_auth_cap->mseq, mseq) < 0)
                        ci->i_auth_cap = cap;
-       } else if (ci->i_auth_cap == cap) {
-               ci->i_auth_cap = NULL;
-               spin_lock(&mdsc->cap_dirty_lock);
-               if (!list_empty(&ci->i_dirty_item)) {
-                       dout(" moving %p to cap_dirty_migrating\n", inode);
-                       list_move(&ci->i_dirty_item,
-                                 &mdsc->cap_dirty_migrating);
-               }
-               spin_unlock(&mdsc->cap_dirty_lock);
+               ci->i_cap_exporting_issued = 0;
+       } else {
+               WARN_ON(ci->i_auth_cap == cap);
        }
 
        dout("add_cap inode %p (%llx.%llx) cap %p %s now %s seq %d mds%d\n",
@@ -628,7 +635,7 @@ retry:
        cap->cap_id = cap_id;
        cap->issued = issued;
        cap->implemented |= issued;
-       if (mseq > cap->mseq)
+       if (ceph_seq_cmp(mseq, cap->mseq) > 0)
                cap->mds_wanted = wanted;
        else
                cap->mds_wanted |= wanted;
@@ -816,7 +823,7 @@ int __ceph_caps_revoking_other(struct ceph_inode_info *ci,
 
        for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
                cap = rb_entry(p, struct ceph_cap, ci_node);
-               if (cap != ocap && __cap_is_valid(cap) &&
+               if (cap != ocap &&
                    (cap->implemented & ~cap->issued & mask))
                        return 1;
        }
@@ -888,7 +895,19 @@ int __ceph_caps_mds_wanted(struct ceph_inode_info *ci)
  */
 static int __ceph_is_any_caps(struct ceph_inode_info *ci)
 {
-       return !RB_EMPTY_ROOT(&ci->i_caps) || ci->i_cap_exporting_mds >= 0;
+       return !RB_EMPTY_ROOT(&ci->i_caps) || ci->i_cap_exporting_issued;
+}
+
+int ceph_is_any_caps(struct inode *inode)
+{
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       int ret;
+
+       spin_lock(&ci->i_ceph_lock);
+       ret = __ceph_is_any_caps(ci);
+       spin_unlock(&ci->i_ceph_lock);
+
+       return ret;
 }
 
 /*
@@ -1383,13 +1402,10 @@ int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask)
                                ci->i_snap_realm->cached_context);
                dout(" inode %p now dirty snapc %p auth cap %p\n",
                     &ci->vfs_inode, ci->i_head_snapc, ci->i_auth_cap);
+               WARN_ON(!ci->i_auth_cap);
                BUG_ON(!list_empty(&ci->i_dirty_item));
                spin_lock(&mdsc->cap_dirty_lock);
-               if (ci->i_auth_cap)
-                       list_add(&ci->i_dirty_item, &mdsc->cap_dirty);
-               else
-                       list_add(&ci->i_dirty_item,
-                                &mdsc->cap_dirty_migrating);
+               list_add(&ci->i_dirty_item, &mdsc->cap_dirty);
                spin_unlock(&mdsc->cap_dirty_lock);
                if (ci->i_flushing_caps == 0) {
                        ihold(inode);
@@ -1735,13 +1751,12 @@ ack:
 /*
  * Try to flush dirty caps back to the auth mds.
  */
-static int try_flush_caps(struct inode *inode, struct ceph_mds_session *session,
-                         unsigned *flush_tid)
+static int try_flush_caps(struct inode *inode, unsigned *flush_tid)
 {
        struct ceph_mds_client *mdsc = ceph_sb_to_client(inode->i_sb)->mdsc;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int unlock_session = session ? 0 : 1;
        int flushing = 0;
+       struct ceph_mds_session *session = NULL;
 
 retry:
        spin_lock(&ci->i_ceph_lock);
@@ -1755,13 +1770,14 @@ retry:
                int want = __ceph_caps_wanted(ci);
                int delayed;
 
-               if (!session) {
+               if (!session || session != cap->session) {
                        spin_unlock(&ci->i_ceph_lock);
+                       if (session)
+                               mutex_unlock(&session->s_mutex);
                        session = cap->session;
                        mutex_lock(&session->s_mutex);
                        goto retry;
                }
-               BUG_ON(session != cap->session);
                if (cap->session->s_state < CEPH_MDS_SESSION_OPEN)
                        goto out;
 
@@ -1780,7 +1796,7 @@ retry:
 out:
        spin_unlock(&ci->i_ceph_lock);
 out_unlocked:
-       if (session && unlock_session)
+       if (session)
                mutex_unlock(&session->s_mutex);
        return flushing;
 }
@@ -1865,7 +1881,7 @@ int ceph_fsync(struct file *file, loff_t start, loff_t end, int datasync)
                return ret;
        mutex_lock(&inode->i_mutex);
 
-       dirty = try_flush_caps(inode, NULL, &flush_tid);
+       dirty = try_flush_caps(inode, &flush_tid);
        dout("fsync dirty caps are %s\n", ceph_cap_string(dirty));
 
        /*
@@ -1900,7 +1916,7 @@ int ceph_write_inode(struct inode *inode, struct writeback_control *wbc)
 
        dout("write_inode %p wait=%d\n", inode, wait);
        if (wait) {
-               dirty = try_flush_caps(inode, NULL, &flush_tid);
+               dirty = try_flush_caps(inode, &flush_tid);
                if (dirty)
                        err = wait_event_interruptible(ci->i_cap_wq,
                                       caps_are_flushed(inode, flush_tid));
@@ -2350,11 +2366,11 @@ static void invalidate_aliases(struct inode *inode)
        d_prune_aliases(inode);
        /*
         * For non-directory inode, d_find_alias() only returns
-        * connected dentry. After calling d_invalidate(), the
-        * dentry become disconnected.
+        * hashed dentry. After calling d_invalidate(), the
+        * dentry becomes unhashed.
         *
         * For directory inode, d_find_alias() can return
-        * disconnected dentry. But directory inode should have
+        * unhashed dentry. But directory inode should have
         * one alias at most.
         */
        while ((dn = d_find_alias(inode))) {
@@ -2408,6 +2424,22 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
        dout(" size %llu max_size %llu, i_size %llu\n", size, max_size,
                inode->i_size);
 
+
+       /*
+        * auth mds of the inode changed. we received the cap export message,
+        * but still haven't received the cap import message. handle_cap_export
+        * updated the new auth MDS' cap.
+        *
+        * "ceph_seq_cmp(seq, cap->seq) <= 0" means we are processing a message
+        * that was sent before the cap import message. So don't remove caps.
+        */
+       if (ceph_seq_cmp(seq, cap->seq) <= 0) {
+               WARN_ON(cap != ci->i_auth_cap);
+               WARN_ON(cap->cap_id != le64_to_cpu(grant->cap_id));
+               seq = cap->seq;
+               newcaps |= cap->issued;
+       }
+
        /*
         * If CACHE is being revoked, and we have no dirty buffers,
         * try to invalidate (once).  (If there are dirty buffers, we
@@ -2434,6 +2466,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
        issued |= implemented | __ceph_caps_dirty(ci);
 
        cap->cap_gen = session->s_cap_gen;
+       cap->seq = seq;
 
        __check_cap_issue(ci, cap, newcaps);
 
@@ -2464,6 +2497,7 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
                                ceph_buffer_put(ci->i_xattrs.blob);
                        ci->i_xattrs.blob = ceph_buffer_get(xattr_buf);
                        ci->i_xattrs.version = version;
+                       ceph_forget_all_cached_acls(inode);
                }
        }
 
@@ -2483,6 +2517,10 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
                            le32_to_cpu(grant->time_warp_seq), &ctime, &mtime,
                            &atime);
 
+
+       /* file layout may have changed */
+       ci->i_layout = grant->layout;
+
        /* max size increase? */
        if (ci->i_auth_cap == cap && max_size != ci->i_max_size) {
                dout("max_size %lld -> %llu\n", ci->i_max_size, max_size);
@@ -2511,11 +2549,6 @@ static void handle_cap_grant(struct inode *inode, struct ceph_mds_caps *grant,
                        check_caps = 1;
        }
 
-       cap->seq = seq;
-
-       /* file layout may have changed */
-       ci->i_layout = grant->layout;
-
        /* revocation, grant, or no-op? */
        if (cap->issued & ~newcaps) {
                int revoking = cap->issued & ~newcaps;
@@ -2741,65 +2774,114 @@ static void handle_cap_trunc(struct inode *inode,
  * caller holds s_mutex
  */
 static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex,
-                             struct ceph_mds_session *session,
-                             int *open_target_sessions)
+                             struct ceph_mds_cap_peer *ph,
+                             struct ceph_mds_session *session)
 {
        struct ceph_mds_client *mdsc = ceph_inode_to_client(inode)->mdsc;
+       struct ceph_mds_session *tsession = NULL;
+       struct ceph_cap *cap, *tcap;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int mds = session->s_mds;
+       u64 t_cap_id;
        unsigned mseq = le32_to_cpu(ex->migrate_seq);
-       struct ceph_cap *cap = NULL, *t;
-       struct rb_node *p;
-       int remember = 1;
+       unsigned t_seq, t_mseq;
+       int target, issued;
+       int mds = session->s_mds;
 
-       dout("handle_cap_export inode %p ci %p mds%d mseq %d\n",
-            inode, ci, mds, mseq);
+       if (ph) {
+               t_cap_id = le64_to_cpu(ph->cap_id);
+               t_seq = le32_to_cpu(ph->seq);
+               t_mseq = le32_to_cpu(ph->mseq);
+               target = le32_to_cpu(ph->mds);
+       } else {
+               t_cap_id = t_seq = t_mseq = 0;
+               target = -1;
+       }
 
+       dout("handle_cap_export inode %p ci %p mds%d mseq %d target %d\n",
+            inode, ci, mds, mseq, target);
+retry:
        spin_lock(&ci->i_ceph_lock);
+       cap = __get_cap_for_mds(ci, mds);
+       if (!cap)
+               goto out_unlock;
 
-       /* make sure we haven't seen a higher mseq */
-       for (p = rb_first(&ci->i_caps); p; p = rb_next(p)) {
-               t = rb_entry(p, struct ceph_cap, ci_node);
-               if (ceph_seq_cmp(t->mseq, mseq) > 0) {
-                       dout(" higher mseq on cap from mds%d\n",
-                            t->session->s_mds);
-                       remember = 0;
-               }
-               if (t->session->s_mds == mds)
-                       cap = t;
+       if (target < 0) {
+               __ceph_remove_cap(cap, false);
+               goto out_unlock;
        }
 
-       if (cap) {
-               if (remember) {
-                       /* make note */
-                       ci->i_cap_exporting_mds = mds;
-                       ci->i_cap_exporting_mseq = mseq;
-                       ci->i_cap_exporting_issued = cap->issued;
-
-                       /*
-                        * make sure we have open sessions with all possible
-                        * export targets, so that we get the matching IMPORT
-                        */
-                       *open_target_sessions = 1;
+       /*
+        * now we know we haven't received the cap import message yet
+        * because the exported cap still exist.
+        */
 
-                       /*
-                        * we can't flush dirty caps that we've seen the
-                        * EXPORT but no IMPORT for
-                        */
-                       spin_lock(&mdsc->cap_dirty_lock);
-                       if (!list_empty(&ci->i_dirty_item)) {
-                               dout(" moving %p to cap_dirty_migrating\n",
-                                    inode);
-                               list_move(&ci->i_dirty_item,
-                                         &mdsc->cap_dirty_migrating);
+       issued = cap->issued;
+       WARN_ON(issued != cap->implemented);
+
+       tcap = __get_cap_for_mds(ci, target);
+       if (tcap) {
+               /* already have caps from the target */
+               if (tcap->cap_id != t_cap_id ||
+                   ceph_seq_cmp(tcap->seq, t_seq) < 0) {
+                       dout(" updating import cap %p mds%d\n", tcap, target);
+                       tcap->cap_id = t_cap_id;
+                       tcap->seq = t_seq - 1;
+                       tcap->issue_seq = t_seq - 1;
+                       tcap->mseq = t_mseq;
+                       tcap->issued |= issued;
+                       tcap->implemented |= issued;
+                       if (cap == ci->i_auth_cap)
+                               ci->i_auth_cap = tcap;
+                       if (ci->i_flushing_caps && ci->i_auth_cap == tcap) {
+                               spin_lock(&mdsc->cap_dirty_lock);
+                               list_move_tail(&ci->i_flushing_item,
+                                              &tcap->session->s_cap_flushing);
+                               spin_unlock(&mdsc->cap_dirty_lock);
                        }
-                       spin_unlock(&mdsc->cap_dirty_lock);
                }
                __ceph_remove_cap(cap, false);
+               goto out_unlock;
        }
-       /* else, we already released it */
 
+       if (tsession) {
+               int flag = (cap == ci->i_auth_cap) ? CEPH_CAP_FLAG_AUTH : 0;
+               spin_unlock(&ci->i_ceph_lock);
+               /* add placeholder for the export tagert */
+               ceph_add_cap(inode, tsession, t_cap_id, -1, issued, 0,
+                            t_seq - 1, t_mseq, (u64)-1, flag, NULL);
+               goto retry;
+       }
+
+       spin_unlock(&ci->i_ceph_lock);
+       mutex_unlock(&session->s_mutex);
+
+       /* open target session */
+       tsession = ceph_mdsc_open_export_target_session(mdsc, target);
+       if (!IS_ERR(tsession)) {
+               if (mds > target) {
+                       mutex_lock(&session->s_mutex);
+                       mutex_lock_nested(&tsession->s_mutex,
+                                         SINGLE_DEPTH_NESTING);
+               } else {
+                       mutex_lock(&tsession->s_mutex);
+                       mutex_lock_nested(&session->s_mutex,
+                                         SINGLE_DEPTH_NESTING);
+               }
+               ceph_add_cap_releases(mdsc, tsession);
+       } else {
+               WARN_ON(1);
+               tsession = NULL;
+               target = -1;
+       }
+       goto retry;
+
+out_unlock:
        spin_unlock(&ci->i_ceph_lock);
+       mutex_unlock(&session->s_mutex);
+       if (tsession) {
+               mutex_unlock(&tsession->s_mutex);
+               ceph_put_mds_session(tsession);
+       }
 }
 
 /*
@@ -2810,10 +2892,12 @@ static void handle_cap_export(struct inode *inode, struct ceph_mds_caps *ex,
  */
 static void handle_cap_import(struct ceph_mds_client *mdsc,
                              struct inode *inode, struct ceph_mds_caps *im,
+                             struct ceph_mds_cap_peer *ph,
                              struct ceph_mds_session *session,
                              void *snaptrace, int snaptrace_len)
 {
        struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_cap *cap;
        int mds = session->s_mds;
        unsigned issued = le32_to_cpu(im->caps);
        unsigned wanted = le32_to_cpu(im->wanted);
@@ -2821,28 +2905,44 @@ static void handle_cap_import(struct ceph_mds_client *mdsc,
        unsigned mseq = le32_to_cpu(im->migrate_seq);
        u64 realmino = le64_to_cpu(im->realm);
        u64 cap_id = le64_to_cpu(im->cap_id);
+       u64 p_cap_id;
+       int peer;
 
-       if (ci->i_cap_exporting_mds >= 0 &&
-           ceph_seq_cmp(ci->i_cap_exporting_mseq, mseq) < 0) {
-               dout("handle_cap_import inode %p ci %p mds%d mseq %d"
-                    " - cleared exporting from mds%d\n",
-                    inode, ci, mds, mseq,
-                    ci->i_cap_exporting_mds);
-               ci->i_cap_exporting_issued = 0;
-               ci->i_cap_exporting_mseq = 0;
-               ci->i_cap_exporting_mds = -1;
+       if (ph) {
+               p_cap_id = le64_to_cpu(ph->cap_id);
+               peer = le32_to_cpu(ph->mds);
+       } else {
+               p_cap_id = 0;
+               peer = -1;
+       }
 
-               spin_lock(&mdsc->cap_dirty_lock);
-               if (!list_empty(&ci->i_dirty_item)) {
-                       dout(" moving %p back to cap_dirty\n", inode);
-                       list_move(&ci->i_dirty_item, &mdsc->cap_dirty);
+       dout("handle_cap_import inode %p ci %p mds%d mseq %d peer %d\n",
+            inode, ci, mds, mseq, peer);
+
+       spin_lock(&ci->i_ceph_lock);
+       cap = peer >= 0 ? __get_cap_for_mds(ci, peer) : NULL;
+       if (cap && cap->cap_id == p_cap_id) {
+               dout(" remove export cap %p mds%d flags %d\n",
+                    cap, peer, ph->flags);
+               if ((ph->flags & CEPH_CAP_FLAG_AUTH) &&
+                   (cap->seq != le32_to_cpu(ph->seq) ||
+                    cap->mseq != le32_to_cpu(ph->mseq))) {
+                       pr_err("handle_cap_import: mismatched seq/mseq: "
+                              "ino (%llx.%llx) mds%d seq %d mseq %d "
+                              "importer mds%d has peer seq %d mseq %d\n",
+                              ceph_vinop(inode), peer, cap->seq,
+                              cap->mseq, mds, le32_to_cpu(ph->seq),
+                              le32_to_cpu(ph->mseq));
                }
-               spin_unlock(&mdsc->cap_dirty_lock);
-       } else {
-               dout("handle_cap_import inode %p ci %p mds%d mseq %d\n",
-                    inode, ci, mds, mseq);
+               ci->i_cap_exporting_issued = cap->issued;
+               __ceph_remove_cap(cap, (ph->flags & CEPH_CAP_FLAG_RELEASE));
        }
 
+       /* make sure we re-request max_size, if necessary */
+       ci->i_wanted_max_size = 0;
+       ci->i_requested_max_size = 0;
+       spin_unlock(&ci->i_ceph_lock);
+
        down_write(&mdsc->snap_rwsem);
        ceph_update_snap_trace(mdsc, snaptrace, snaptrace+snaptrace_len,
                               false);
@@ -2853,11 +2953,6 @@ static void handle_cap_import(struct ceph_mds_client *mdsc,
        kick_flushing_inode_caps(mdsc, session, inode);
        up_read(&mdsc->snap_rwsem);
 
-       /* make sure we re-request max_size, if necessary */
-       spin_lock(&ci->i_ceph_lock);
-       ci->i_wanted_max_size = 0;  /* reset */
-       ci->i_requested_max_size = 0;
-       spin_unlock(&ci->i_ceph_lock);
 }
 
 /*
@@ -2875,6 +2970,7 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        struct ceph_inode_info *ci;
        struct ceph_cap *cap;
        struct ceph_mds_caps *h;
+       struct ceph_mds_cap_peer *peer = NULL;
        int mds = session->s_mds;
        int op;
        u32 seq, mseq;
@@ -2885,12 +2981,13 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        void *snaptrace;
        size_t snaptrace_len;
        void *flock;
+       void *end;
        u32 flock_len;
-       int open_target_sessions = 0;
 
        dout("handle_caps from mds%d\n", mds);
 
        /* decode */
+       end = msg->front.iov_base + msg->front.iov_len;
        tid = le64_to_cpu(msg->hdr.tid);
        if (msg->front.iov_len < sizeof(*h))
                goto bad;
@@ -2908,17 +3005,28 @@ void ceph_handle_caps(struct ceph_mds_session *session,
        snaptrace_len = le32_to_cpu(h->snap_trace_len);
 
        if (le16_to_cpu(msg->hdr.version) >= 2) {
-               void *p, *end;
-
-               p = snaptrace + snaptrace_len;
-               end = msg->front.iov_base + msg->front.iov_len;
+               void *p = snaptrace + snaptrace_len;
                ceph_decode_32_safe(&p, end, flock_len, bad);
+               if (p + flock_len > end)
+                       goto bad;
                flock = p;
        } else {
                flock = NULL;
                flock_len = 0;
        }
 
+       if (le16_to_cpu(msg->hdr.version) >= 3) {
+               if (op == CEPH_CAP_OP_IMPORT) {
+                       void *p = flock + flock_len;
+                       if (p + sizeof(*peer) > end)
+                               goto bad;
+                       peer = p;
+               } else if (op == CEPH_CAP_OP_EXPORT) {
+                       /* recorded in unused fields */
+                       peer = (void *)&h->size;
+               }
+       }
+
        mutex_lock(&session->s_mutex);
        session->s_seq++;
        dout(" mds%d seq %lld cap seq %u\n", session->s_mds, session->s_seq,
@@ -2951,11 +3059,11 @@ void ceph_handle_caps(struct ceph_mds_session *session,
                goto done;
 
        case CEPH_CAP_OP_EXPORT:
-               handle_cap_export(inode, h, session, &open_target_sessions);
-               goto done;
+               handle_cap_export(inode, h, peer, session);
+               goto done_unlocked;
 
        case CEPH_CAP_OP_IMPORT:
-               handle_cap_import(mdsc, inode, h, session,
+               handle_cap_import(mdsc, inode, h, peer, session,
                                  snaptrace, snaptrace_len);
        }
 
@@ -3007,8 +3115,6 @@ done:
 done_unlocked:
        if (inode)
                iput(inode);
-       if (open_target_sessions)
-               ceph_mdsc_open_export_target_sessions(mdsc, session);
        return;
 
 bad:
index 2a0bcaeb189acd18b124aff8d54619667fd97bf2..6da4df84ba300824a8a6afdea9f2a20121600765 100644 (file)
@@ -693,6 +693,10 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
        if (!err && !req->r_reply_info.head->is_dentry)
                err = ceph_handle_notrace_create(dir, dentry);
        ceph_mdsc_put_request(req);
+
+       if (!err)
+               err = ceph_init_acl(dentry, dentry->d_inode, dir);
+
        if (err)
                d_drop(dentry);
        return err;
@@ -1037,14 +1041,19 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
                valid = 1;
        } else if (dentry_lease_is_valid(dentry) ||
                   dir_lease_is_valid(dir, dentry)) {
-               valid = 1;
+               if (dentry->d_inode)
+                       valid = ceph_is_any_caps(dentry->d_inode);
+               else
+                       valid = 1;
        }
 
        dout("d_revalidate %p %s\n", dentry, valid ? "valid" : "invalid");
-       if (valid)
+       if (valid) {
                ceph_dentry_lru_touch(dentry);
-       else
+       } else {
+               ceph_dir_clear_complete(dir);
                d_drop(dentry);
+       }
        iput(dir);
        return valid;
 }
@@ -1293,6 +1302,8 @@ const struct inode_operations ceph_dir_iops = {
        .getxattr = ceph_getxattr,
        .listxattr = ceph_listxattr,
        .removexattr = ceph_removexattr,
+       .get_acl = ceph_get_acl,
+       .set_acl = ceph_set_acl,
        .mknod = ceph_mknod,
        .symlink = ceph_symlink,
        .mkdir = ceph_mkdir,
index 3de89829e2a162ab6bce2a58296b25aef9235c43..dfd2ce3419f812f71769406023d0ff33cea3a35b 100644 (file)
@@ -408,51 +408,92 @@ more:
  *
  * If the read spans object boundary, just do multiple reads.
  */
-static ssize_t ceph_sync_read(struct file *file, char __user *data,
-                             unsigned len, loff_t *poff, int *checkeof)
+static ssize_t ceph_sync_read(struct kiocb *iocb, struct iov_iter *i,
+                               int *checkeof)
 {
+       struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
        struct page **pages;
-       u64 off = *poff;
+       u64 off = iocb->ki_pos;
        int num_pages, ret;
+       size_t len = i->count;
 
-       dout("sync_read on file %p %llu~%u %s\n", file, off, len,
+       dout("sync_read on file %p %llu~%u %s\n", file, off,
+            (unsigned)len,
             (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
-
-       if (file->f_flags & O_DIRECT) {
-               num_pages = calc_pages_for((unsigned long)data, len);
-               pages = ceph_get_direct_page_vector(data, num_pages, true);
-       } else {
-               num_pages = calc_pages_for(off, len);
-               pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
-       }
-       if (IS_ERR(pages))
-               return PTR_ERR(pages);
-
        /*
         * flush any page cache pages in this range.  this
         * will make concurrent normal and sync io slow,
         * but it will at least behave sensibly when they are
         * in sequence.
         */
-       ret = filemap_write_and_wait(inode->i_mapping);
+       ret = filemap_write_and_wait_range(inode->i_mapping, off,
+                                               off + len);
        if (ret < 0)
-               goto done;
+               return ret;
 
-       ret = striped_read(inode, off, len, pages, num_pages, checkeof,
-                          file->f_flags & O_DIRECT,
-                          (unsigned long)data & ~PAGE_MASK);
+       if (file->f_flags & O_DIRECT) {
+               while (iov_iter_count(i)) {
+                       void __user *data = i->iov[0].iov_base + i->iov_offset;
+                       size_t len = i->iov[0].iov_len - i->iov_offset;
+
+                       num_pages = calc_pages_for((unsigned long)data, len);
+                       pages = ceph_get_direct_page_vector(data,
+                                                           num_pages, true);
+                       if (IS_ERR(pages))
+                               return PTR_ERR(pages);
+
+                       ret = striped_read(inode, off, len,
+                                          pages, num_pages, checkeof,
+                                          1, (unsigned long)data & ~PAGE_MASK);
+                       ceph_put_page_vector(pages, num_pages, true);
+
+                       if (ret <= 0)
+                               break;
+                       off += ret;
+                       iov_iter_advance(i, ret);
+                       if (ret < len)
+                               break;
+               }
+       } else {
+               num_pages = calc_pages_for(off, len);
+               pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
+               if (IS_ERR(pages))
+                       return PTR_ERR(pages);
+               ret = striped_read(inode, off, len, pages,
+                                       num_pages, checkeof, 0, 0);
+               if (ret > 0) {
+                       int l, k = 0;
+                       size_t left = len = ret;
+
+                       while (left) {
+                               void __user *data = i->iov[0].iov_base
+                                                       + i->iov_offset;
+                               l = min(i->iov[0].iov_len - i->iov_offset,
+                                       left);
+
+                               ret = ceph_copy_page_vector_to_user(&pages[k],
+                                                                   data, off,
+                                                                   l);
+                               if (ret > 0) {
+                                       iov_iter_advance(i, ret);
+                                       left -= ret;
+                                       off += ret;
+                                       k = calc_pages_for(iocb->ki_pos,
+                                                          len - left + 1) - 1;
+                                       BUG_ON(k >= num_pages && left);
+                               } else
+                                       break;
+                       }
+               }
+               ceph_release_page_vector(pages, num_pages);
+       }
 
-       if (ret >= 0 && (file->f_flags & O_DIRECT) == 0)
-               ret = ceph_copy_page_vector_to_user(pages, data, off, ret);
-       if (ret >= 0)
-               *poff = off + ret;
+       if (off > iocb->ki_pos) {
+               ret = off - iocb->ki_pos;
+               iocb->ki_pos = off;
+       }
 
-done:
-       if (file->f_flags & O_DIRECT)
-               ceph_put_page_vector(pages, num_pages, true);
-       else
-               ceph_release_page_vector(pages, num_pages);
        dout("sync_read result %d\n", ret);
        return ret;
 }
@@ -489,83 +530,79 @@ static void ceph_sync_write_unsafe(struct ceph_osd_request *req, bool unsafe)
        }
 }
 
+
 /*
- * Synchronous write, straight from __user pointer or user pages (if
- * O_DIRECT).
+ * Synchronous write, straight from __user pointer or user pages.
  *
  * If write spans object boundary, just do multiple writes.  (For a
  * correct atomic write, we should e.g. take write locks on all
  * objects, rollback on failure, etc.)
  */
-static ssize_t ceph_sync_write(struct file *file, const char __user *data,
-                              size_t left, loff_t pos, loff_t *ppos)
+static ssize_t
+ceph_sync_direct_write(struct kiocb *iocb, const struct iovec *iov,
+                      unsigned long nr_segs, size_t count)
 {
+       struct file *file = iocb->ki_filp;
        struct inode *inode = file_inode(file);
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
        struct ceph_snap_context *snapc;
        struct ceph_vino vino;
        struct ceph_osd_request *req;
-       int num_ops = 1;
        struct page **pages;
        int num_pages;
-       u64 len;
        int written = 0;
        int flags;
        int check_caps = 0;
-       int page_align, io_align;
-       unsigned long buf_align;
+       int page_align;
        int ret;
        struct timespec mtime = CURRENT_TIME;
-       bool own_pages = false;
+       loff_t pos = iocb->ki_pos;
+       struct iov_iter i;
 
        if (ceph_snap(file_inode(file)) != CEPH_NOSNAP)
                return -EROFS;
 
-       dout("sync_write on file %p %lld~%u %s\n", file, pos,
-            (unsigned)left, (file->f_flags & O_DIRECT) ? "O_DIRECT" : "");
+       dout("sync_direct_write on file %p %lld~%u\n", file, pos,
+            (unsigned)count);
 
-       ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + left);
+       ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + count);
        if (ret < 0)
                return ret;
 
        ret = invalidate_inode_pages2_range(inode->i_mapping,
                                            pos >> PAGE_CACHE_SHIFT,
-                                           (pos + left) >> PAGE_CACHE_SHIFT);
+                                           (pos + count) >> PAGE_CACHE_SHIFT);
        if (ret < 0)
                dout("invalidate_inode_pages2_range returned %d\n", ret);
 
        flags = CEPH_OSD_FLAG_ORDERSNAP |
                CEPH_OSD_FLAG_ONDISK |
                CEPH_OSD_FLAG_WRITE;
-       if ((file->f_flags & (O_SYNC|O_DIRECT)) == 0)
-               flags |= CEPH_OSD_FLAG_ACK;
-       else
-               num_ops++;      /* Also include a 'startsync' command. */
 
-       /*
-        * we may need to do multiple writes here if we span an object
-        * boundary.  this isn't atomic, unfortunately.  :(
-        */
-more:
-       io_align = pos & ~PAGE_MASK;
-       buf_align = (unsigned long)data & ~PAGE_MASK;
-       len = left;
-
-       snapc = ci->i_snap_realm->cached_context;
-       vino = ceph_vino(inode);
-       req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
-                                   vino, pos, &len, num_ops,
-                                   CEPH_OSD_OP_WRITE, flags, snapc,
-                                   ci->i_truncate_seq, ci->i_truncate_size,
-                                   false);
-       if (IS_ERR(req))
-               return PTR_ERR(req);
+       iov_iter_init(&i, iov, nr_segs, count, 0);
+
+       while (iov_iter_count(&i) > 0) {
+               void __user *data = i.iov->iov_base + i.iov_offset;
+               u64 len = i.iov->iov_len - i.iov_offset;
+
+               page_align = (unsigned long)data & ~PAGE_MASK;
+
+               snapc = ci->i_snap_realm->cached_context;
+               vino = ceph_vino(inode);
+               req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
+                                           vino, pos, &len,
+                                           2,/*include a 'startsync' command*/
+                                           CEPH_OSD_OP_WRITE, flags, snapc,
+                                           ci->i_truncate_seq,
+                                           ci->i_truncate_size,
+                                           false);
+               if (IS_ERR(req)) {
+                       ret = PTR_ERR(req);
+                       goto out;
+               }
 
-       /* write from beginning of first page, regardless of io alignment */
-       page_align = file->f_flags & O_DIRECT ? buf_align : io_align;
-       num_pages = calc_pages_for(page_align, len);
-       if (file->f_flags & O_DIRECT) {
+               num_pages = calc_pages_for(page_align, len);
                pages = ceph_get_direct_page_vector(data, num_pages, false);
                if (IS_ERR(pages)) {
                        ret = PTR_ERR(pages);
@@ -577,60 +614,175 @@ more:
                 * may block.
                 */
                truncate_inode_pages_range(inode->i_mapping, pos,
-                                          (pos+len) | (PAGE_CACHE_SIZE-1));
-       } else {
+                                  (pos+len) | (PAGE_CACHE_SIZE-1));
+               osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_align,
+                                               false, false);
+
+               /* BUG_ON(vino.snap != CEPH_NOSNAP); */
+               ceph_osdc_build_request(req, pos, snapc, vino.snap, &mtime);
+
+               ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
+               if (!ret)
+                       ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
+
+               ceph_put_page_vector(pages, num_pages, false);
+
+out:
+               ceph_osdc_put_request(req);
+               if (ret == 0) {
+                       pos += len;
+                       written += len;
+                       iov_iter_advance(&i, (size_t)len);
+
+                       if (pos > i_size_read(inode)) {
+                               check_caps = ceph_inode_set_size(inode, pos);
+                               if (check_caps)
+                                       ceph_check_caps(ceph_inode(inode),
+                                                       CHECK_CAPS_AUTHONLY,
+                                                       NULL);
+                       }
+               } else
+                       break;
+       }
+
+       if (ret != -EOLDSNAPC && written > 0) {
+               iocb->ki_pos = pos;
+               ret = written;
+       }
+       return ret;
+}
+
+
+/*
+ * Synchronous write, straight from __user pointer or user pages.
+ *
+ * If write spans object boundary, just do multiple writes.  (For a
+ * correct atomic write, we should e.g. take write locks on all
+ * objects, rollback on failure, etc.)
+ */
+static ssize_t ceph_sync_write(struct kiocb *iocb, const struct iovec *iov,
+                              unsigned long nr_segs, size_t count)
+{
+       struct file *file = iocb->ki_filp;
+       struct inode *inode = file_inode(file);
+       struct ceph_inode_info *ci = ceph_inode(inode);
+       struct ceph_fs_client *fsc = ceph_inode_to_client(inode);
+       struct ceph_snap_context *snapc;
+       struct ceph_vino vino;
+       struct ceph_osd_request *req;
+       struct page **pages;
+       u64 len;
+       int num_pages;
+       int written = 0;
+       int flags;
+       int check_caps = 0;
+       int ret;
+       struct timespec mtime = CURRENT_TIME;
+       loff_t pos = iocb->ki_pos;
+       struct iov_iter i;
+
+       if (ceph_snap(file_inode(file)) != CEPH_NOSNAP)
+               return -EROFS;
+
+       dout("sync_write on file %p %lld~%u\n", file, pos, (unsigned)count);
+
+       ret = filemap_write_and_wait_range(inode->i_mapping, pos, pos + count);
+       if (ret < 0)
+               return ret;
+
+       ret = invalidate_inode_pages2_range(inode->i_mapping,
+                                           pos >> PAGE_CACHE_SHIFT,
+                                           (pos + count) >> PAGE_CACHE_SHIFT);
+       if (ret < 0)
+               dout("invalidate_inode_pages2_range returned %d\n", ret);
+
+       flags = CEPH_OSD_FLAG_ORDERSNAP |
+               CEPH_OSD_FLAG_ONDISK |
+               CEPH_OSD_FLAG_WRITE |
+               CEPH_OSD_FLAG_ACK;
+
+       iov_iter_init(&i, iov, nr_segs, count, 0);
+
+       while ((len = iov_iter_count(&i)) > 0) {
+               size_t left;
+               int n;
+
+               snapc = ci->i_snap_realm->cached_context;
+               vino = ceph_vino(inode);
+               req = ceph_osdc_new_request(&fsc->client->osdc, &ci->i_layout,
+                                           vino, pos, &len, 1,
+                                           CEPH_OSD_OP_WRITE, flags, snapc,
+                                           ci->i_truncate_seq,
+                                           ci->i_truncate_size,
+                                           false);
+               if (IS_ERR(req)) {
+                       ret = PTR_ERR(req);
+                       goto out;
+               }
+
+               /*
+                * write from beginning of first page,
+                * regardless of io alignment
+                */
+               num_pages = (len + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
+
                pages = ceph_alloc_page_vector(num_pages, GFP_NOFS);
                if (IS_ERR(pages)) {
                        ret = PTR_ERR(pages);
                        goto out;
                }
-               ret = ceph_copy_user_to_page_vector(pages, data, pos, len);
+
+               left = len;
+               for (n = 0; n < num_pages; n++) {
+                       size_t plen = min_t(size_t, left, PAGE_SIZE);
+                       ret = iov_iter_copy_from_user(pages[n], &i, 0, plen);
+                       if (ret != plen) {
+                               ret = -EFAULT;
+                               break;
+                       }
+                       left -= ret;
+                       iov_iter_advance(&i, ret);
+               }
+
                if (ret < 0) {
                        ceph_release_page_vector(pages, num_pages);
                        goto out;
                }
 
-               if ((file->f_flags & O_SYNC) == 0) {
-                       /* get a second commit callback */
-                       req->r_unsafe_callback = ceph_sync_write_unsafe;
-                       req->r_inode = inode;
-                       own_pages = true;
-               }
-       }
-       osd_req_op_extent_osd_data_pages(req, 0, pages, len, page_align,
-                                       false, own_pages);
+               /* get a second commit callback */
+               req->r_unsafe_callback = ceph_sync_write_unsafe;
+               req->r_inode = inode;
 
-       /* BUG_ON(vino.snap != CEPH_NOSNAP); */
-       ceph_osdc_build_request(req, pos, snapc, vino.snap, &mtime);
+               osd_req_op_extent_osd_data_pages(req, 0, pages, len, 0,
+                                               false, true);
 
-       ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
-       if (!ret)
-               ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
+               /* BUG_ON(vino.snap != CEPH_NOSNAP); */
+               ceph_osdc_build_request(req, pos, snapc, vino.snap, &mtime);
 
-       if (file->f_flags & O_DIRECT)
-               ceph_put_page_vector(pages, num_pages, false);
-       else if (file->f_flags & O_SYNC)
-               ceph_release_page_vector(pages, num_pages);
+               ret = ceph_osdc_start_request(&fsc->client->osdc, req, false);
+               if (!ret)
+                       ret = ceph_osdc_wait_request(&fsc->client->osdc, req);
 
 out:
-       ceph_osdc_put_request(req);
-       if (ret == 0) {
-               pos += len;
-               written += len;
-               left -= len;
-               data += len;
-               if (left)
-                       goto more;
+               ceph_osdc_put_request(req);
+               if (ret == 0) {
+                       pos += len;
+                       written += len;
+
+                       if (pos > i_size_read(inode)) {
+                               check_caps = ceph_inode_set_size(inode, pos);
+                               if (check_caps)
+                                       ceph_check_caps(ceph_inode(inode),
+                                                       CHECK_CAPS_AUTHONLY,
+                                                       NULL);
+                       }
+               } else
+                       break;
+       }
 
+       if (ret != -EOLDSNAPC && written > 0) {
                ret = written;
-               *ppos = pos;
-               if (pos > i_size_read(inode))
-                       check_caps = ceph_inode_set_size(inode, pos);
-               if (check_caps)
-                       ceph_check_caps(ceph_inode(inode), CHECK_CAPS_AUTHONLY,
-                                       NULL);
-       } else if (ret != -EOLDSNAPC && written > 0) {
-               ret = written;
+               iocb->ki_pos = pos;
        }
        return ret;
 }
@@ -647,55 +799,84 @@ static ssize_t ceph_aio_read(struct kiocb *iocb, const struct iovec *iov,
 {
        struct file *filp = iocb->ki_filp;
        struct ceph_file_info *fi = filp->private_data;
-       loff_t *ppos = &iocb->ki_pos;
-       size_t len = iov->iov_len;
+       size_t len = iocb->ki_nbytes;
        struct inode *inode = file_inode(filp);
        struct ceph_inode_info *ci = ceph_inode(inode);
-       void __user *base = iov->iov_base;
        ssize_t ret;
        int want, got = 0;
        int checkeof = 0, read = 0;
 
-       dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n",
-            inode, ceph_vinop(inode), pos, (unsigned)len, inode);
 again:
+       dout("aio_read %p %llx.%llx %llu~%u trying to get caps on %p\n",
+            inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len, inode);
+
        if (fi->fmode & CEPH_FILE_MODE_LAZY)
                want = CEPH_CAP_FILE_CACHE | CEPH_CAP_FILE_LAZYIO;
        else
                want = CEPH_CAP_FILE_CACHE;
        ret = ceph_get_caps(ci, CEPH_CAP_FILE_RD, want, &got, -1);
        if (ret < 0)
-               goto out;
-       dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
-            inode, ceph_vinop(inode), pos, (unsigned)len,
-            ceph_cap_string(got));
+               return ret;
 
        if ((got & (CEPH_CAP_FILE_CACHE|CEPH_CAP_FILE_LAZYIO)) == 0 ||
            (iocb->ki_filp->f_flags & O_DIRECT) ||
-           (fi->flags & CEPH_F_SYNC))
+           (fi->flags & CEPH_F_SYNC)) {
+               struct iov_iter i;
+
+               dout("aio_sync_read %p %llx.%llx %llu~%u got cap refs on %s\n",
+                    inode, ceph_vinop(inode), iocb->ki_pos, (unsigned)len,
+                    ceph_cap_string(got));
+
+               if (!read) {
+                       ret = generic_segment_checks(iov, &nr_segs,
+                                                       &len, VERIFY_WRITE);
+                       if (ret)
+                               goto out;
+               }
+
+               iov_iter_init(&i, iov, nr_segs, len, read);
+
                /* hmm, this isn't really async... */
-               ret = ceph_sync_read(filp, base, len, ppos, &checkeof);
-       else
-               ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
+               ret = ceph_sync_read(iocb, &i, &checkeof);
+       } else {
+               /*
+                * We can't modify the content of iov,
+                * so we only read from beginning.
+                */
+               if (read) {
+                       iocb->ki_pos = pos;
+                       len = iocb->ki_nbytes;
+                       read = 0;
+               }
+               dout("aio_read %p %llx.%llx %llu~%u got cap refs on %s\n",
+                    inode, ceph_vinop(inode), pos, (unsigned)len,
+                    ceph_cap_string(got));
 
+               ret = generic_file_aio_read(iocb, iov, nr_segs, pos);
+       }
 out:
        dout("aio_read %p %llx.%llx dropping cap refs on %s = %d\n",
             inode, ceph_vinop(inode), ceph_cap_string(got), (int)ret);
        ceph_put_cap_refs(ci, got);
 
        if (checkeof && ret >= 0) {
-               int statret = ceph_do_getattr(inode, CEPH_STAT_CAP_SIZE);
+               int statret = ceph_do_getattr(inode,
+                                             CEPH_STAT_CAP_SIZE);
 
                /* hit EOF or hole? */
-               if (statret == 0 && *ppos < inode->i_size) {
-                       dout("aio_read sync_read hit hole, ppos %lld < size %lld, reading more\n", *ppos, inode->i_size);
+               if (statret == 0 && iocb->ki_pos < inode->i_size &&
+                       ret < len) {
+                       dout("sync_read hit hole, ppos %lld < size %lld"
+                            ", reading more\n", iocb->ki_pos,
+                            inode->i_size);
+
                        read += ret;
-                       base += ret;
                        len -= ret;
                        checkeof = 0;
                        goto again;
                }
        }
+
        if (ret >= 0)
                ret += read;
 
@@ -772,11 +953,13 @@ retry_snap:
             inode, ceph_vinop(inode), pos, count, ceph_cap_string(got));
 
        if ((got & (CEPH_CAP_FILE_BUFFER|CEPH_CAP_FILE_LAZYIO)) == 0 ||
-           (iocb->ki_filp->f_flags & O_DIRECT) ||
-           (fi->flags & CEPH_F_SYNC)) {
+           (file->f_flags & O_DIRECT) || (fi->flags & CEPH_F_SYNC)) {
                mutex_unlock(&inode->i_mutex);
-               written = ceph_sync_write(file, iov->iov_base, count,
-                                         pos, &iocb->ki_pos);
+               if (file->f_flags & O_DIRECT)
+                       written = ceph_sync_direct_write(iocb, iov,
+                                                        nr_segs, count);
+               else
+                       written = ceph_sync_write(iocb, iov, nr_segs, count);
                if (written == -EOLDSNAPC) {
                        dout("aio_write %p %llx.%llx %llu~%u"
                                "got EOLDSNAPC, retrying\n",
@@ -1018,7 +1201,7 @@ static long ceph_fallocate(struct file *file, int mode,
                                loff_t offset, loff_t length)
 {
        struct ceph_file_info *fi = file->private_data;
-       struct inode *inode = file->f_dentry->d_inode;
+       struct inode *inode = file_inode(file);
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_osd_client *osdc =
                &ceph_inode_to_client(inode)->client->osdc;
index 278fd28912880b5cc09989ed7dcb8e7fbbfcb3ef..32d519d8a2e210316fbf2af3b2c0a842d47a13b2 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/namei.h>
 #include <linux/writeback.h>
 #include <linux/vmalloc.h>
+#include <linux/posix_acl.h>
 
 #include "super.h"
 #include "mds_client.h"
@@ -95,6 +96,8 @@ const struct inode_operations ceph_file_iops = {
        .getxattr = ceph_getxattr,
        .listxattr = ceph_listxattr,
        .removexattr = ceph_removexattr,
+       .get_acl = ceph_get_acl,
+       .set_acl = ceph_set_acl,
 };
 
 
@@ -335,12 +338,10 @@ struct inode *ceph_alloc_inode(struct super_block *sb)
        ci->i_hold_caps_min = 0;
        ci->i_hold_caps_max = 0;
        INIT_LIST_HEAD(&ci->i_cap_delay_list);
-       ci->i_cap_exporting_mds = 0;
-       ci->i_cap_exporting_mseq = 0;
-       ci->i_cap_exporting_issued = 0;
        INIT_LIST_HEAD(&ci->i_cap_snaps);
        ci->i_head_snapc = NULL;
        ci->i_snap_caps = 0;
+       ci->i_cap_exporting_issued = 0;
 
        for (i = 0; i < CEPH_FILE_MODE_NUM; i++)
                ci->i_nr_by_mode[i] = 0;
@@ -436,6 +437,16 @@ void ceph_destroy_inode(struct inode *inode)
        call_rcu(&inode->i_rcu, ceph_i_callback);
 }
 
+int ceph_drop_inode(struct inode *inode)
+{
+       /*
+        * Positve dentry and corresponding inode are always accompanied
+        * in MDS reply. So no need to keep inode in the cache after
+        * dropping all its aliases.
+        */
+       return 1;
+}
+
 /*
  * Helpers to fill in size, ctime, mtime, and atime.  We have to be
  * careful because either the client or MDS may have more up to date
@@ -670,6 +681,7 @@ static int fill_inode(struct inode *inode,
                        memcpy(ci->i_xattrs.blob->vec.iov_base,
                               iinfo->xattr_data, iinfo->xattr_len);
                ci->i_xattrs.version = le64_to_cpu(info->xattr_version);
+               ceph_forget_all_cached_acls(inode);
                xattr_blob = NULL;
        }
 
@@ -1454,7 +1466,8 @@ static void ceph_invalidate_work(struct work_struct *work)
        dout("invalidate_pages %p gen %d revoking %d\n", inode,
             ci->i_rdcache_gen, ci->i_rdcache_revoking);
        if (ci->i_rdcache_revoking != ci->i_rdcache_gen) {
-               /* nevermind! */
+               if (__ceph_caps_revoking_other(ci, NULL, CEPH_CAP_FILE_CACHE))
+                       check = 1;
                spin_unlock(&ci->i_ceph_lock);
                mutex_unlock(&ci->i_truncate_mutex);
                goto out;
@@ -1475,13 +1488,14 @@ static void ceph_invalidate_work(struct work_struct *work)
                dout("invalidate_pages %p gen %d raced, now %d revoking %d\n",
                     inode, orig_gen, ci->i_rdcache_gen,
                     ci->i_rdcache_revoking);
+               if (__ceph_caps_revoking_other(ci, NULL, CEPH_CAP_FILE_CACHE))
+                       check = 1;
        }
        spin_unlock(&ci->i_ceph_lock);
        mutex_unlock(&ci->i_truncate_mutex);
-
+out:
        if (check)
                ceph_check_caps(ci, 0, NULL);
-out:
        iput(inode);
 }
 
@@ -1602,6 +1616,8 @@ static const struct inode_operations ceph_symlink_iops = {
        .getxattr = ceph_getxattr,
        .listxattr = ceph_listxattr,
        .removexattr = ceph_removexattr,
+       .get_acl = ceph_get_acl,
+       .set_acl = ceph_set_acl,
 };
 
 /*
@@ -1675,6 +1691,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
                        dirtied |= CEPH_CAP_AUTH_EXCL;
                } else if ((issued & CEPH_CAP_AUTH_SHARED) == 0 ||
                           attr->ia_mode != inode->i_mode) {
+                       inode->i_mode = attr->ia_mode;
                        req->r_args.setattr.mode = cpu_to_le32(attr->ia_mode);
                        mask |= CEPH_SETATTR_MODE;
                        release |= CEPH_CAP_AUTH_SHARED;
@@ -1790,6 +1807,12 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        if (inode_dirty_flags)
                __mark_inode_dirty(inode, inode_dirty_flags);
 
+       if (ia_valid & ATTR_MODE) {
+               err = posix_acl_chmod(inode, attr->ia_mode);
+               if (err)
+                       goto out_put;
+       }
+
        if (mask) {
                req->r_inode = inode;
                ihold(inode);
@@ -1809,6 +1832,7 @@ int ceph_setattr(struct dentry *dentry, struct iattr *attr)
        return err;
 out:
        spin_unlock(&ci->i_ceph_lock);
+out_put:
        ceph_mdsc_put_request(req);
        return err;
 }
index 669622fd1ae3d52af418cc4c283a5f22513bca73..dc66c9e023e4f3aee170db98d2bb549819d99abc 100644 (file)
@@ -183,6 +183,8 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
        struct ceph_inode_info *ci = ceph_inode(inode);
        struct ceph_osd_client *osdc =
                &ceph_sb_to_client(inode->i_sb)->client->osdc;
+       struct ceph_object_locator oloc;
+       struct ceph_object_id oid;
        u64 len = 1, olen;
        u64 tmp;
        struct ceph_pg pgid;
@@ -211,8 +213,10 @@ static long ceph_ioctl_get_dataloc(struct file *file, void __user *arg)
        snprintf(dl.object_name, sizeof(dl.object_name), "%llx.%08llx",
                 ceph_ino(inode), dl.object_no);
 
-       r = ceph_calc_ceph_pg(&pgid, dl.object_name, osdc->osdmap,
-                               ceph_file_layout_pg_pool(ci->i_layout));
+       oloc.pool = ceph_file_layout_pg_pool(ci->i_layout);
+       ceph_oid_set_name(&oid, dl.object_name);
+
+       r = ceph_oloc_oid_to_pg(osdc->osdmap, &oloc, &oid, &pgid);
        if (r < 0) {
                up_read(&osdc->map_sem);
                return r;
index d90861f452107cc47b7242e8ea66dc1257f7c235..f4f050a69a48fff9a707c28d4a024691a5bdc814 100644 (file)
@@ -63,7 +63,7 @@ static const struct ceph_connection_operations mds_con_ops;
  */
 static int parse_reply_info_in(void **p, void *end,
                               struct ceph_mds_reply_info_in *info,
-                              int features)
+                              u64 features)
 {
        int err = -EIO;
 
@@ -98,7 +98,7 @@ bad:
  */
 static int parse_reply_info_trace(void **p, void *end,
                                  struct ceph_mds_reply_info_parsed *info,
-                                 int features)
+                                 u64 features)
 {
        int err;
 
@@ -145,7 +145,7 @@ out_bad:
  */
 static int parse_reply_info_dir(void **p, void *end,
                                struct ceph_mds_reply_info_parsed *info,
-                               int features)
+                               u64 features)
 {
        u32 num, i = 0;
        int err;
@@ -217,7 +217,7 @@ out_bad:
  */
 static int parse_reply_info_filelock(void **p, void *end,
                                     struct ceph_mds_reply_info_parsed *info,
-                                    int features)
+                                    u64 features)
 {
        if (*p + sizeof(*info->filelock_reply) > end)
                goto bad;
@@ -238,7 +238,7 @@ bad:
  */
 static int parse_reply_info_create(void **p, void *end,
                                  struct ceph_mds_reply_info_parsed *info,
-                                 int features)
+                                 u64 features)
 {
        if (features & CEPH_FEATURE_REPLY_CREATE_INODE) {
                if (*p == end) {
@@ -262,7 +262,7 @@ bad:
  */
 static int parse_reply_info_extra(void **p, void *end,
                                  struct ceph_mds_reply_info_parsed *info,
-                                 int features)
+                                 u64 features)
 {
        if (info->head->op == CEPH_MDS_OP_GETFILELOCK)
                return parse_reply_info_filelock(p, end, info, features);
@@ -280,7 +280,7 @@ static int parse_reply_info_extra(void **p, void *end,
  */
 static int parse_reply_info(struct ceph_msg *msg,
                            struct ceph_mds_reply_info_parsed *info,
-                           int features)
+                           u64 features)
 {
        void *p, *end;
        u32 len;
@@ -713,14 +713,15 @@ static int __choose_mds(struct ceph_mds_client *mdsc,
                        struct dentry *dn = get_nonsnap_parent(parent);
                        inode = dn->d_inode;
                        dout("__choose_mds using nonsnap parent %p\n", inode);
-               } else if (req->r_dentry->d_inode) {
+               } else {
                        /* dentry target */
                        inode = req->r_dentry->d_inode;
-               } else {
-                       /* dir + name */
-                       inode = dir;
-                       hash = ceph_dentry_hash(dir, req->r_dentry);
-                       is_hash = true;
+                       if (!inode || mode == USE_AUTH_MDS) {
+                               /* dir + name */
+                               inode = dir;
+                               hash = ceph_dentry_hash(dir, req->r_dentry);
+                               is_hash = true;
+                       }
                }
        }
 
@@ -846,35 +847,56 @@ static int __open_session(struct ceph_mds_client *mdsc,
  *
  * called under mdsc->mutex
  */
+static struct ceph_mds_session *
+__open_export_target_session(struct ceph_mds_client *mdsc, int target)
+{
+       struct ceph_mds_session *session;
+
+       session = __ceph_lookup_mds_session(mdsc, target);
+       if (!session) {
+               session = register_session(mdsc, target);
+               if (IS_ERR(session))
+                       return session;
+       }
+       if (session->s_state == CEPH_MDS_SESSION_NEW ||
+           session->s_state == CEPH_MDS_SESSION_CLOSING)
+               __open_session(mdsc, session);
+
+       return session;
+}
+
+struct ceph_mds_session *
+ceph_mdsc_open_export_target_session(struct ceph_mds_client *mdsc, int target)
+{
+       struct ceph_mds_session *session;
+
+       dout("open_export_target_session to mds%d\n", target);
+
+       mutex_lock(&mdsc->mutex);
+       session = __open_export_target_session(mdsc, target);
+       mutex_unlock(&mdsc->mutex);
+
+       return session;
+}
+
 static void __open_export_target_sessions(struct ceph_mds_client *mdsc,
                                          struct ceph_mds_session *session)
 {
        struct ceph_mds_info *mi;
        struct ceph_mds_session *ts;
        int i, mds = session->s_mds;
-       int target;
 
        if (mds >= mdsc->mdsmap->m_max_mds)
                return;
+
        mi = &mdsc->mdsmap->m_info[mds];
        dout("open_export_target_sessions for mds%d (%d targets)\n",
             session->s_mds, mi->num_export_targets);
 
        for (i = 0; i < mi->num_export_targets; i++) {
-               target = mi->export_targets[i];
-               ts = __ceph_lookup_mds_session(mdsc, target);
-               if (!ts) {
-                       ts = register_session(mdsc, target);
-                       if (IS_ERR(ts))
-                               return;
-               }
-               if (session->s_state == CEPH_MDS_SESSION_NEW ||
-                   session->s_state == CEPH_MDS_SESSION_CLOSING)
-                       __open_session(mdsc, session);
-               else
-                       dout(" mds%d target mds%d %p is %s\n", session->s_mds,
-                            i, ts, session_state_name(ts->s_state));
-               ceph_put_mds_session(ts);
+               ts = __open_export_target_session(mdsc, mi->export_targets[i]);
+               if (!IS_ERR(ts))
+                       ceph_put_mds_session(ts);
        }
 }
 
@@ -1136,6 +1158,21 @@ static int send_renew_caps(struct ceph_mds_client *mdsc,
        return 0;
 }
 
+static int send_flushmsg_ack(struct ceph_mds_client *mdsc,
+                            struct ceph_mds_session *session, u64 seq)
+{
+       struct ceph_msg *msg;
+
+       dout("send_flushmsg_ack to mds%d (%s)s seq %lld\n",
+            session->s_mds, session_state_name(session->s_state), seq);
+       msg = create_session_msg(CEPH_SESSION_FLUSHMSG_ACK, seq);
+       if (!msg)
+               return -ENOMEM;
+       ceph_con_send(&session->s_con, msg);
+       return 0;
+}
+
+
 /*
  * Note new cap ttl, and any transition from stale -> not stale (fresh?).
  *
@@ -1214,7 +1251,7 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
 {
        struct ceph_mds_session *session = arg;
        struct ceph_inode_info *ci = ceph_inode(inode);
-       int used, oissued, mine;
+       int used, wanted, oissued, mine;
 
        if (session->s_trim_caps <= 0)
                return -1;
@@ -1222,14 +1259,19 @@ static int trim_caps_cb(struct inode *inode, struct ceph_cap *cap, void *arg)
        spin_lock(&ci->i_ceph_lock);
        mine = cap->issued | cap->implemented;
        used = __ceph_caps_used(ci);
+       wanted = __ceph_caps_file_wanted(ci);
        oissued = __ceph_caps_issued_other(ci, cap);
 
-       dout("trim_caps_cb %p cap %p mine %s oissued %s used %s\n",
+       dout("trim_caps_cb %p cap %p mine %s oissued %s used %s wanted %s\n",
             inode, cap, ceph_cap_string(mine), ceph_cap_string(oissued),
-            ceph_cap_string(used));
-       if (ci->i_dirty_caps)
-               goto out;   /* dirty caps */
-       if ((used & ~oissued) & mine)
+            ceph_cap_string(used), ceph_cap_string(wanted));
+       if (cap == ci->i_auth_cap) {
+               if (ci->i_dirty_caps | ci->i_flushing_caps)
+                       goto out;
+               if ((used | wanted) & CEPH_CAP_ANY_WR)
+                       goto out;
+       }
+       if ((used | wanted) & ~oissued & mine)
                goto out;   /* we need these caps */
 
        session->s_trim_caps--;
@@ -2156,26 +2198,16 @@ static void handle_reply(struct ceph_mds_session *session, struct ceph_msg *msg)
         */
        if (result == -ESTALE) {
                dout("got ESTALE on request %llu", req->r_tid);
-               if (!req->r_inode) {
-                       /* do nothing; not an authority problem */
-               } else if (req->r_direct_mode != USE_AUTH_MDS) {
+               if (req->r_direct_mode != USE_AUTH_MDS) {
                        dout("not using auth, setting for that now");
                        req->r_direct_mode = USE_AUTH_MDS;
                        __do_request(mdsc, req);
                        mutex_unlock(&mdsc->mutex);
                        goto out;
                } else  {
-                       struct ceph_inode_info *ci = ceph_inode(req->r_inode);
-                       struct ceph_cap *cap = NULL;
-
-                       if (req->r_session)
-                               cap = ceph_get_cap_for_mds(ci,
-                                                  req->r_session->s_mds);
-
-                       dout("already using auth");
-                       if ((!cap || cap != ci->i_auth_cap) ||
-                           (cap->mseq != req->r_sent_on_mseq)) {
-                               dout("but cap changed, so resending");
+                       int mds = __choose_mds(mdsc, req);
+                       if (mds >= 0 && mds != req->r_session->s_mds) {
+                               dout("but auth changed, so resending");
                                __do_request(mdsc, req);
                                mutex_unlock(&mdsc->mutex);
                                goto out;
@@ -2400,6 +2432,10 @@ static void handle_session(struct ceph_mds_session *session,
                trim_caps(mdsc, session, le32_to_cpu(h->max_caps));
                break;
 
+       case CEPH_SESSION_FLUSHMSG:
+               send_flushmsg_ack(mdsc, session, seq);
+               break;
+
        default:
                pr_err("mdsc_handle_session bad op %d mds%d\n", op, mds);
                WARN_ON(1);
index 4c053d099ae4e60400dbcbdcce21844138ba8a47..68288917c7371fbebc314a0085e691580f57a711 100644 (file)
@@ -383,6 +383,8 @@ extern void ceph_mdsc_lease_send_msg(struct ceph_mds_session *session,
 extern void ceph_mdsc_handle_map(struct ceph_mds_client *mdsc,
                                 struct ceph_msg *msg);
 
+extern struct ceph_mds_session *
+ceph_mdsc_open_export_target_session(struct ceph_mds_client *mdsc, int target);
 extern void ceph_mdsc_open_export_target_sessions(struct ceph_mds_client *mdsc,
                                          struct ceph_mds_session *session);
 
index 89fa4a940a0ffff7b9cea94bfebb1bb62f8721df..4440f447fd3f2329b28f8e88e44e10141e4b30c4 100644 (file)
@@ -41,6 +41,8 @@ const char *ceph_session_op_name(int op)
        case CEPH_SESSION_RENEWCAPS: return "renewcaps";
        case CEPH_SESSION_STALE: return "stale";
        case CEPH_SESSION_RECALL_STATE: return "recall_state";
+       case CEPH_SESSION_FLUSHMSG: return "flushmsg";
+       case CEPH_SESSION_FLUSHMSG_ACK: return "flushmsg_ack";
        }
        return "???";
 }
index 6a0951e4304441a241ca8fe550aba36cc097c271..2df963f1cf5a3b84615772e793cd45eeddec801f 100644 (file)
@@ -490,10 +490,10 @@ static struct ceph_fs_client *create_fs_client(struct ceph_mount_options *fsopt,
                                        struct ceph_options *opt)
 {
        struct ceph_fs_client *fsc;
-       const unsigned supported_features =
+       const u64 supported_features =
                CEPH_FEATURE_FLOCK |
                CEPH_FEATURE_DIRLAYOUTHASH;
-       const unsigned required_features = 0;
+       const u64 required_features = 0;
        int page_count;
        size_t size;
        int err = -ENOMEM;
@@ -686,6 +686,7 @@ static const struct super_operations ceph_super_ops = {
        .alloc_inode    = ceph_alloc_inode,
        .destroy_inode  = ceph_destroy_inode,
        .write_inode    = ceph_write_inode,
+       .drop_inode     = ceph_drop_inode,
        .sync_fs        = ceph_sync_fs,
        .put_super      = ceph_put_super,
        .show_options   = ceph_show_options,
@@ -818,7 +819,11 @@ static int ceph_set_super(struct super_block *s, void *data)
 
        s->s_flags = fsc->mount_options->sb_flags;
        s->s_maxbytes = 1ULL << 40;  /* temp value until we get mdsmap */
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       s->s_flags |= MS_POSIXACL;
+#endif
 
+       s->s_xattr = ceph_xattr_handlers;
        s->s_fs_info = fsc;
        fsc->sb = s;
 
index ef4ac38bb614a911680668fe52f6e7fa272d94ce..19793b56d0a7d3a90330c36a218312728b42e45e 100644 (file)
@@ -287,14 +287,12 @@ struct ceph_inode_info {
        unsigned long i_hold_caps_min; /* jiffies */
        unsigned long i_hold_caps_max; /* jiffies */
        struct list_head i_cap_delay_list;  /* for delayed cap release to mds */
-       int i_cap_exporting_mds;         /* to handle cap migration between */
-       unsigned i_cap_exporting_mseq;   /*  mds's. */
-       unsigned i_cap_exporting_issued;
        struct ceph_cap_reservation i_cap_migration_resv;
        struct list_head i_cap_snaps;   /* snapped state pending flush to mds */
        struct ceph_snap_context *i_head_snapc;  /* set if wr_buffer_head > 0 or
                                                    dirty|flushing caps */
        unsigned i_snap_caps;           /* cap bits for snapped files */
+       unsigned i_cap_exporting_issued;
 
        int i_nr_by_mode[CEPH_FILE_MODE_NUM];  /* open file counts */
 
@@ -335,7 +333,6 @@ struct ceph_inode_info {
        u32 i_fscache_gen; /* sequence, for delayed fscache validate */
        struct work_struct i_revalidate_work;
 #endif
-
        struct inode vfs_inode; /* at end */
 };
 
@@ -529,6 +526,8 @@ static inline int __ceph_caps_dirty(struct ceph_inode_info *ci)
 }
 extern int __ceph_mark_dirty_caps(struct ceph_inode_info *ci, int mask);
 
+extern int __ceph_caps_revoking_other(struct ceph_inode_info *ci,
+                                     struct ceph_cap *ocap, int mask);
 extern int ceph_caps_revoking(struct ceph_inode_info *ci, int mask);
 extern int __ceph_caps_used(struct ceph_inode_info *ci);
 
@@ -691,6 +690,7 @@ extern const struct inode_operations ceph_file_iops;
 
 extern struct inode *ceph_alloc_inode(struct super_block *sb);
 extern void ceph_destroy_inode(struct inode *inode);
+extern int ceph_drop_inode(struct inode *inode);
 
 extern struct inode *ceph_get_inode(struct super_block *sb,
                                    struct ceph_vino vino);
@@ -724,6 +724,9 @@ extern int ceph_getattr(struct vfsmount *mnt, struct dentry *dentry,
 /* xattr.c */
 extern int ceph_setxattr(struct dentry *, const char *, const void *,
                         size_t, int);
+int __ceph_setxattr(struct dentry *, const char *, const void *, size_t, int);
+ssize_t __ceph_getxattr(struct inode *, const char *, void *, size_t);
+int __ceph_removexattr(struct dentry *, const char *);
 extern ssize_t ceph_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t ceph_listxattr(struct dentry *, char *, size_t);
 extern int ceph_removexattr(struct dentry *, const char *);
@@ -732,6 +735,38 @@ extern void __ceph_destroy_xattrs(struct ceph_inode_info *ci);
 extern void __init ceph_xattr_init(void);
 extern void ceph_xattr_exit(void);
 
+/* acl.c */
+extern const struct xattr_handler *ceph_xattr_handlers[];
+
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+
+struct posix_acl *ceph_get_acl(struct inode *, int);
+int ceph_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+int ceph_init_acl(struct dentry *, struct inode *, struct inode *);
+void ceph_forget_all_cached_acls(struct inode *inode);
+
+#else
+
+#define ceph_get_acl NULL
+#define ceph_set_acl NULL
+
+static inline int ceph_init_acl(struct dentry *dentry, struct inode *inode,
+                               struct inode *dir)
+{
+       return 0;
+}
+
+static inline int ceph_acl_chmod(struct dentry *dentry, struct inode *inode)
+{
+       return 0;
+}
+
+static inline void ceph_forget_all_cached_acls(struct inode *inode)
+{
+}
+
+#endif
+
 /* caps.c */
 extern const char *ceph_cap_string(int c);
 extern void ceph_handle_caps(struct ceph_mds_session *session,
@@ -744,6 +779,7 @@ extern int ceph_add_cap(struct inode *inode,
 extern void __ceph_remove_cap(struct ceph_cap *cap, bool queue_release);
 extern void ceph_put_cap(struct ceph_mds_client *mdsc,
                         struct ceph_cap *cap);
+extern int ceph_is_any_caps(struct inode *inode);
 
 extern void __queue_cap_release(struct ceph_mds_session *session, u64 ino,
                                u64 cap_id, u32 migrate_seq, u32 issue_seq);
index be661d8f532adcea4b44d2b42aae52b788d4753e..898b6565ad3e2c114baca0282fafea6a5643071a 100644 (file)
@@ -6,16 +6,30 @@
 #include <linux/ceph/decode.h>
 
 #include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
 #include <linux/slab.h>
 
 #define XATTR_CEPH_PREFIX "ceph."
 #define XATTR_CEPH_PREFIX_LEN (sizeof (XATTR_CEPH_PREFIX) - 1)
 
+/*
+ * List of handlers for synthetic system.* attributes. Other
+ * attributes are handled directly.
+ */
+const struct xattr_handler *ceph_xattr_handlers[] = {
+#ifdef CONFIG_CEPH_FS_POSIX_ACL
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
+#endif
+       NULL,
+};
+
 static bool ceph_is_valid_xattr(const char *name)
 {
        return !strncmp(name, XATTR_CEPH_PREFIX, XATTR_CEPH_PREFIX_LEN) ||
               !strncmp(name, XATTR_SECURITY_PREFIX,
                        XATTR_SECURITY_PREFIX_LEN) ||
+              !strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN) ||
               !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) ||
               !strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
 }
@@ -663,10 +677,9 @@ void __ceph_build_xattrs_blob(struct ceph_inode_info *ci)
        }
 }
 
-ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value,
+ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
                      size_t size)
 {
-       struct inode *inode = dentry->d_inode;
        struct ceph_inode_info *ci = ceph_inode(inode);
        int err;
        struct ceph_inode_xattr *xattr;
@@ -675,7 +688,6 @@ ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value,
        if (!ceph_is_valid_xattr(name))
                return -ENODATA;
 
-
        /* let's see if a virtual xattr was requested */
        vxattr = ceph_match_vxattr(inode, name);
        if (vxattr && !(vxattr->exists_cb && !vxattr->exists_cb(ci))) {
@@ -725,6 +737,15 @@ out:
        return err;
 }
 
+ssize_t ceph_getxattr(struct dentry *dentry, const char *name, void *value,
+                     size_t size)
+{
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_getxattr(dentry, name, value, size);
+
+       return __ceph_getxattr(dentry->d_inode, name, value, size);
+}
+
 ssize_t ceph_listxattr(struct dentry *dentry, char *names, size_t size)
 {
        struct inode *inode = dentry->d_inode;
@@ -863,8 +884,8 @@ out:
        return err;
 }
 
-int ceph_setxattr(struct dentry *dentry, const char *name,
-                 const void *value, size_t size, int flags)
+int __ceph_setxattr(struct dentry *dentry, const char *name,
+                       const void *value, size_t size, int flags)
 {
        struct inode *inode = dentry->d_inode;
        struct ceph_vxattr *vxattr;
@@ -879,9 +900,6 @@ int ceph_setxattr(struct dentry *dentry, const char *name,
        struct ceph_inode_xattr *xattr = NULL;
        int required_blob_size;
 
-       if (ceph_snap(inode) != CEPH_NOSNAP)
-               return -EROFS;
-
        if (!ceph_is_valid_xattr(name))
                return -EOPNOTSUPP;
 
@@ -958,6 +976,18 @@ out:
        return err;
 }
 
+int ceph_setxattr(struct dentry *dentry, const char *name,
+                 const void *value, size_t size, int flags)
+{
+       if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP)
+               return -EROFS;
+
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_setxattr(dentry, name, value, size, flags);
+
+       return __ceph_setxattr(dentry, name, value, size, flags);
+}
+
 static int ceph_send_removexattr(struct dentry *dentry, const char *name)
 {
        struct ceph_fs_client *fsc = ceph_sb_to_client(dentry->d_sb);
@@ -984,7 +1014,7 @@ static int ceph_send_removexattr(struct dentry *dentry, const char *name)
        return err;
 }
 
-int ceph_removexattr(struct dentry *dentry, const char *name)
+int __ceph_removexattr(struct dentry *dentry, const char *name)
 {
        struct inode *inode = dentry->d_inode;
        struct ceph_vxattr *vxattr;
@@ -994,9 +1024,6 @@ int ceph_removexattr(struct dentry *dentry, const char *name)
        int required_blob_size;
        int dirty;
 
-       if (ceph_snap(inode) != CEPH_NOSNAP)
-               return -EROFS;
-
        if (!ceph_is_valid_xattr(name))
                return -EOPNOTSUPP;
 
@@ -1053,3 +1080,13 @@ out:
        return err;
 }
 
+int ceph_removexattr(struct dentry *dentry, const char *name)
+{
+       if (ceph_snap(dentry->d_inode) != CEPH_NOSNAP)
+               return -EROFS;
+
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_removexattr(dentry, name);
+
+       return __ceph_removexattr(dentry, name);
+}
index e501ac3a49ff7380a1bd2644ecc8abc3f648ce64..06610cf94d579a8da72a5d6af53b098ec43e482d 100644 (file)
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/blkdev.h>
-#include <linux/cramfs_fs.h>
 #include <linux/slab.h>
-#include <linux/cramfs_fs_sb.h>
 #include <linux/vfs.h>
 #include <linux/mutex.h>
-
+#include <uapi/linux/cramfs_fs.h>
 #include <asm/uaccess.h>
 
+#include "internal.h"
+
+/*
+ * cramfs super-block data in memory
+ */
+struct cramfs_sb_info {
+       unsigned long magic;
+       unsigned long size;
+       unsigned long blocks;
+       unsigned long files;
+       unsigned long flags;
+};
+
+static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb)
+{
+       return sb->s_fs_info;
+}
+
 static const struct super_operations cramfs_ops;
 static const struct inode_operations cramfs_dir_inode_operations;
 static const struct file_operations cramfs_directory_operations;
@@ -219,10 +235,11 @@ static void *cramfs_read(struct super_block *sb, unsigned int offset, unsigned i
        return read_buffers[buffer] + offset;
 }
 
-static void cramfs_put_super(struct super_block *sb)
+static void cramfs_kill_sb(struct super_block *sb)
 {
-       kfree(sb->s_fs_info);
-       sb->s_fs_info = NULL;
+       struct cramfs_sb_info *sbi = CRAMFS_SB(sb);
+       kill_block_super(sb);
+       kfree(sbi);
 }
 
 static int cramfs_remount(struct super_block *sb, int *flags, char *data)
@@ -261,7 +278,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
                if (super.magic == CRAMFS_MAGIC_WEND) {
                        if (!silent)
                                printk(KERN_ERR "cramfs: wrong endianness\n");
-                       goto out;
+                       return -EINVAL;
                }
 
                /* check at 512 byte offset */
@@ -273,20 +290,20 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
                                printk(KERN_ERR "cramfs: wrong endianness\n");
                        else if (!silent)
                                printk(KERN_ERR "cramfs: wrong magic\n");
-                       goto out;
+                       return -EINVAL;
                }
        }
 
        /* get feature flags first */
        if (super.flags & ~CRAMFS_SUPPORTED_FLAGS) {
                printk(KERN_ERR "cramfs: unsupported filesystem features\n");
-               goto out;
+               return -EINVAL;
        }
 
        /* Check that the root inode is in a sane state */
        if (!S_ISDIR(super.root.mode)) {
                printk(KERN_ERR "cramfs: root is not a directory\n");
-               goto out;
+               return -EINVAL;
        }
        /* correct strange, hard-coded permissions of mkcramfs */
        super.root.mode |= (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
@@ -310,22 +327,18 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent)
                  (root_offset != 512 + sizeof(struct cramfs_super))))
        {
                printk(KERN_ERR "cramfs: bad root offset %lu\n", root_offset);
-               goto out;
+               return -EINVAL;
        }
 
        /* Set it all up.. */
        sb->s_op = &cramfs_ops;
        root = get_cramfs_inode(sb, &super.root, 0);
        if (IS_ERR(root))
-               goto out;
+               return PTR_ERR(root);
        sb->s_root = d_make_root(root);
        if (!sb->s_root)
-               goto out;
+               return -ENOMEM;
        return 0;
-out:
-       kfree(sbi);
-       sb->s_fs_info = NULL;
-       return -EINVAL;
 }
 
 static int cramfs_statfs(struct dentry *dentry, struct kstatfs *buf)
@@ -550,7 +563,6 @@ static const struct inode_operations cramfs_dir_inode_operations = {
 };
 
 static const struct super_operations cramfs_ops = {
-       .put_super      = cramfs_put_super,
        .remount_fs     = cramfs_remount,
        .statfs         = cramfs_statfs,
 };
@@ -565,7 +577,7 @@ static struct file_system_type cramfs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "cramfs",
        .mount          = cramfs_mount,
-       .kill_sb        = kill_block_super,
+       .kill_sb        = cramfs_kill_sb,
        .fs_flags       = FS_REQUIRES_DEV,
 };
 MODULE_ALIAS_FS("cramfs");
similarity index 70%
rename from include/linux/cramfs_fs.h
rename to fs/cramfs/internal.h
index 133789609f239e5f25edfade82be8fe7f6ddb381..349d71272157ab8678805b0eb49902b3a96b50ec 100644 (file)
@@ -1,10 +1,4 @@
-#ifndef __CRAMFS_H
-#define __CRAMFS_H
-
-#include <uapi/linux/cramfs_fs.h>
-
 /* Uncompression interfaces to the underlying zlib */
 int cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen);
 int cramfs_uncompress_init(void);
 void cramfs_uncompress_exit(void);
-#endif
index 023329800d2e42152fec5a531f91f4310cae1729..1760c1b84d9787cc27cc23e22387147ad65129e7 100644 (file)
@@ -19,7 +19,7 @@
 #include <linux/errno.h>
 #include <linux/vmalloc.h>
 #include <linux/zlib.h>
-#include <linux/cramfs_fs.h>
+#include "internal.h"
 
 static z_stream stream;
 static int initialized;
index cb4a10690868263cb58e28012ee8f9abc4880da5..265e0ce9769c70db65d5f9df11c4365f44c6dd29 100644 (file)
@@ -3116,26 +3116,28 @@ char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
 /*
  * Write full pathname from the root of the filesystem into the buffer.
  */
-static char *__dentry_path(struct dentry *dentry, char *buf, int buflen)
+static char *__dentry_path(struct dentry *d, char *buf, int buflen)
 {
+       struct dentry *dentry;
        char *end, *retval;
        int len, seq = 0;
        int error = 0;
 
+       if (buflen < 2)
+               goto Elong;
+
        rcu_read_lock();
 restart:
+       dentry = d;
        end = buf + buflen;
        len = buflen;
        prepend(&end, &len, "\0", 1);
-       if (buflen < 1)
-               goto Elong;
        /* Get '/' right */
        retval = end-1;
        *retval = '/';
        read_seqbegin_or_lock(&rename_lock, &seq);
        while (!IS_ROOT(dentry)) {
                struct dentry *parent = dentry->d_parent;
-               int error;
 
                prefetch(parent);
                error = prepend_name(&end, &len, &dentry->d_name);
index ab5954b50267d29afa219bbaec128af2304f59e2..ac44a69fbea9a533dbcc27cdc27771f4f7795f1e 100644 (file)
@@ -204,7 +204,7 @@ out:
 }
 
 #ifdef CONFIG_COMPAT
-COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, size_t, len)
+COMPAT_SYSCALL_DEFINE4(lookup_dcookie, u32, w0, u32, w1, char __user *, buf, compat_size_t, len)
 {
 #ifdef __BIG_ENDIAN
        return sys_lookup_dcookie(((u64)w0 << 32) | w1, buf, len);
index 0e04142d5962312fcb055738479247b2364a252e..160a5489a93936372c85683ee8cfd6da5185007b 100644 (file)
@@ -375,7 +375,7 @@ dio_bio_alloc(struct dio *dio, struct dio_submit *sdio,
        bio = bio_alloc(GFP_KERNEL, nr_vecs);
 
        bio->bi_bdev = bdev;
-       bio->bi_sector = first_sector;
+       bio->bi_iter.bi_sector = first_sector;
        if (dio->is_async)
                bio->bi_end_io = dio_bio_end_aio;
        else
@@ -719,7 +719,7 @@ static inline int dio_send_cur_page(struct dio *dio, struct dio_submit *sdio,
        if (sdio->bio) {
                loff_t cur_offset = sdio->cur_page_fs_offset;
                loff_t bio_next_offset = sdio->logical_offset_in_bio +
-                       sdio->bio->bi_size;
+                       sdio->bio->bi_iter.bi_size;
 
                /*
                 * See whether this new request is contiguous with the old.
index c36c4482447159c219a4d4f56506087229ebb276..b167ca48b8eef4984dec79a609644012421e6fea 100644 (file)
@@ -659,19 +659,17 @@ out_lock:
        return rc;
 }
 
-static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
-                                  size_t *bufsiz)
+static char *ecryptfs_readlink_lower(struct dentry *dentry, size_t *bufsiz)
 {
        struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);
        char *lower_buf;
+       char *buf;
        mm_segment_t old_fs;
        int rc;
 
        lower_buf = kmalloc(PATH_MAX, GFP_KERNEL);
-       if (!lower_buf) {
-               rc = -ENOMEM;
-               goto out;
-       }
+       if (!lower_buf)
+               return ERR_PTR(-ENOMEM);
        old_fs = get_fs();
        set_fs(get_ds());
        rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,
@@ -680,21 +678,18 @@ static int ecryptfs_readlink_lower(struct dentry *dentry, char **buf,
        set_fs(old_fs);
        if (rc < 0)
                goto out;
-       rc = ecryptfs_decode_and_decrypt_filename(buf, bufsiz, dentry->d_sb,
+       rc = ecryptfs_decode_and_decrypt_filename(&buf, bufsiz, dentry->d_sb,
                                                  lower_buf, rc);
 out:
        kfree(lower_buf);
-       return rc;
+       return rc ? ERR_PTR(rc) : buf;
 }
 
 static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
 {
-       char *buf;
-       size_t len = PATH_MAX;
-       int rc;
-
-       rc = ecryptfs_readlink_lower(dentry, &buf, &len);
-       if (rc)
+       size_t len;
+       char *buf = ecryptfs_readlink_lower(dentry, &len);
+       if (IS_ERR(buf))
                goto out;
        fsstack_copy_attr_atime(dentry->d_inode,
                                ecryptfs_dentry_to_lower(dentry)->d_inode);
@@ -1003,10 +998,12 @@ static int ecryptfs_getattr_link(struct vfsmount *mnt, struct dentry *dentry,
                char *target;
                size_t targetsiz;
 
-               rc = ecryptfs_readlink_lower(dentry, &target, &targetsiz);
-               if (!rc) {
+               target = ecryptfs_readlink_lower(dentry, &targetsiz);
+               if (!IS_ERR(target)) {
                        kfree(target);
                        stat->size = targetsiz;
+               } else {
+                       rc = PTR_ERR(target);
                }
        }
        return rc;
index c6f57a74a559da265bc8f062eab06488d8d7c00a..50215bbd646313fdad24ae3b521af017b834bcf9 100644 (file)
@@ -26,11 +26,18 @@ static struct dentry *efs_mount(struct file_system_type *fs_type,
        return mount_bdev(fs_type, flags, dev_name, data, efs_fill_super);
 }
 
+static void efs_kill_sb(struct super_block *s)
+{
+       struct efs_sb_info *sbi = SUPER_INFO(s);
+       kill_block_super(s);
+       kfree(sbi);
+}
+
 static struct file_system_type efs_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "efs",
        .mount          = efs_mount,
-       .kill_sb        = kill_block_super,
+       .kill_sb        = efs_kill_sb,
        .fs_flags       = FS_REQUIRES_DEV,
 };
 MODULE_ALIAS_FS("efs");
@@ -105,12 +112,6 @@ static void destroy_inodecache(void)
        kmem_cache_destroy(efs_inode_cachep);
 }
 
-static void efs_put_super(struct super_block *s)
-{
-       kfree(s->s_fs_info);
-       s->s_fs_info = NULL;
-}
-
 static int efs_remount(struct super_block *sb, int *flags, char *data)
 {
        *flags |= MS_RDONLY;
@@ -120,7 +121,6 @@ static int efs_remount(struct super_block *sb, int *flags, char *data)
 static const struct super_operations efs_superblock_operations = {
        .alloc_inode    = efs_alloc_inode,
        .destroy_inode  = efs_destroy_inode,
-       .put_super      = efs_put_super,
        .statfs         = efs_statfs,
        .remount_fs     = efs_remount,
 };
@@ -259,7 +259,6 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
        struct efs_sb_info *sb;
        struct buffer_head *bh;
        struct inode *root;
-       int ret = -EINVAL;
 
        sb = kzalloc(sizeof(struct efs_sb_info), GFP_KERNEL);
        if (!sb)
@@ -270,7 +269,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
        if (!sb_set_blocksize(s, EFS_BLOCKSIZE)) {
                printk(KERN_ERR "EFS: device does not support %d byte blocks\n",
                        EFS_BLOCKSIZE);
-               goto out_no_fs_ul;
+               return -EINVAL;
        }
   
        /* read the vh (volume header) block */
@@ -278,7 +277,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
 
        if (!bh) {
                printk(KERN_ERR "EFS: cannot read volume header\n");
-               goto out_no_fs_ul;
+               return -EINVAL;
        }
 
        /*
@@ -290,13 +289,13 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
        brelse(bh);
 
        if (sb->fs_start == -1) {
-               goto out_no_fs_ul;
+               return -EINVAL;
        }
 
        bh = sb_bread(s, sb->fs_start + EFS_SUPER);
        if (!bh) {
                printk(KERN_ERR "EFS: cannot read superblock\n");
-               goto out_no_fs_ul;
+               return -EINVAL;
        }
                
        if (efs_validate_super(sb, (struct efs_super *) bh->b_data)) {
@@ -304,7 +303,7 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
                printk(KERN_WARNING "EFS: invalid superblock at block %u\n", sb->fs_start + EFS_SUPER);
 #endif
                brelse(bh);
-               goto out_no_fs_ul;
+               return -EINVAL;
        }
        brelse(bh);
 
@@ -319,24 +318,16 @@ static int efs_fill_super(struct super_block *s, void *d, int silent)
        root = efs_iget(s, EFS_ROOTINODE);
        if (IS_ERR(root)) {
                printk(KERN_ERR "EFS: get root inode failed\n");
-               ret = PTR_ERR(root);
-               goto out_no_fs;
+               return PTR_ERR(root);
        }
 
        s->s_root = d_make_root(root);
        if (!(s->s_root)) {
                printk(KERN_ERR "EFS: get root dentry failed\n");
-               ret = -ENOMEM;
-               goto out_no_fs;
+               return -ENOMEM;
        }
 
        return 0;
-
-out_no_fs_ul:
-out_no_fs:
-       s->s_fs_info = NULL;
-       kfree(sb);
-       return ret;
 }
 
 static int efs_statfs(struct dentry *dentry, struct kstatfs *buf) {
index 35470d9b96e68951de6f1a63fe3657f09a8296c4..d6a88e7812f3e68a84888ce104cce4285ea50538 100644 (file)
@@ -349,15 +349,12 @@ EXPORT_SYMBOL_GPL(eventfd_fget);
  */
 struct eventfd_ctx *eventfd_ctx_fdget(int fd)
 {
-       struct file *file;
        struct eventfd_ctx *ctx;
-
-       file = eventfd_fget(fd);
-       if (IS_ERR(file))
-               return (struct eventfd_ctx *) file;
-       ctx = eventfd_ctx_get(file->private_data);
-       fput(file);
-
+       struct fd f = fdget(fd);
+       if (!f.file)
+               return ERR_PTR(-EBADF);
+       ctx = eventfd_ctx_fileget(f.file);
+       fdput(f);
        return ctx;
 }
 EXPORT_SYMBOL_GPL(eventfd_ctx_fdget);
index a52a5d23c30bcfac672df7197c51b966cc087787..ee4317faccb1951852b483d825a5ccec7efa8a24 100644 (file)
@@ -577,7 +577,7 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
 
                if (offset >= i_size) {
                        *uptodate = true;
-                       EXOFS_DBGMSG("offset >= i_size index=0x%lx\n", index);
+                       EXOFS_DBGMSG2("offset >= i_size index=0x%lx\n", index);
                        return ZERO_PAGE(0);
                }
 
@@ -596,10 +596,10 @@ static struct page *__r4w_get_page(void *priv, u64 offset, bool *uptodate)
                        *uptodate = true;
                else
                        *uptodate = PageUptodate(page);
-               EXOFS_DBGMSG("index=0x%lx uptodate=%d\n", index, *uptodate);
+               EXOFS_DBGMSG2("index=0x%lx uptodate=%d\n", index, *uptodate);
                return page;
        } else {
-               EXOFS_DBGMSG("YES that_locked_page index=0x%lx\n",
+               EXOFS_DBGMSG2("YES that_locked_page index=0x%lx\n",
                             pcol->that_locked_page->index);
                *uptodate = true;
                return pcol->that_locked_page;
@@ -611,11 +611,11 @@ static void __r4w_put_page(void *priv, struct page *page)
        struct page_collect *pcol = priv;
 
        if ((pcol->that_locked_page != page) && (ZERO_PAGE(0) != page)) {
-               EXOFS_DBGMSG("index=0x%lx\n", page->index);
+               EXOFS_DBGMSG2("index=0x%lx\n", page->index);
                page_cache_release(page);
                return;
        }
-       EXOFS_DBGMSG("that_locked_page index=0x%lx\n",
+       EXOFS_DBGMSG2("that_locked_page index=0x%lx\n",
                     ZERO_PAGE(0) == page ? -1 : page->index);
 }
 
@@ -961,6 +961,14 @@ static void exofs_invalidatepage(struct page *page, unsigned int offset,
        WARN_ON(1);
 }
 
+
+ /* TODO: Should be easy enough to do proprly */
+static ssize_t exofs_direct_IO(int rw, struct kiocb *iocb,
+               const struct iovec *iov, loff_t offset, unsigned long nr_segs)
+{
+       return 0;
+}
+
 const struct address_space_operations exofs_aops = {
        .readpage       = exofs_readpage,
        .readpages      = exofs_readpages,
@@ -974,7 +982,7 @@ const struct address_space_operations exofs_aops = {
 
        /* Not implemented Yet */
        .bmap           = NULL, /* TODO: use osd's OSD_ACT_READ_MAP */
-       .direct_IO      = NULL, /* TODO: Should be trivial to do */
+       .direct_IO      = exofs_direct_IO,
 
        /* With these NULL has special meaning or default is not exported */
        .get_xip_mem    = NULL,
@@ -1010,7 +1018,7 @@ static int _do_truncate(struct inode *inode, loff_t newsize)
        if (likely(!ret))
                truncate_setsize(inode, newsize);
 
-       EXOFS_DBGMSG("(0x%lx) size=0x%llx ret=>%d\n",
+       EXOFS_DBGMSG2("(0x%lx) size=0x%llx ret=>%d\n",
                     inode->i_ino, newsize, ret);
        return ret;
 }
@@ -1094,14 +1102,13 @@ static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi,
                /* If object is lost on target we might as well enable it's
                 * delete.
                 */
-               if ((ret == -ENOENT) || (ret == -EINVAL))
-                       ret = 0;
+               ret = 0;
                goto out;
        }
 
        ret = extract_attr_from_ios(ios, &attrs[0]);
        if (ret) {
-               EXOFS_ERR("%s: extract_attr of inode_data failed\n", __func__);
+               EXOFS_ERR("%s: extract_attr 0 of inode failed\n", __func__);
                goto out;
        }
        WARN_ON(attrs[0].len != EXOFS_INO_ATTR_SIZE);
@@ -1109,7 +1116,7 @@ static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi,
 
        ret = extract_attr_from_ios(ios, &attrs[1]);
        if (ret) {
-               EXOFS_ERR("%s: extract_attr of inode_data failed\n", __func__);
+               EXOFS_ERR("%s: extract_attr 1 of inode failed\n", __func__);
                goto out;
        }
        if (attrs[1].len) {
@@ -1124,7 +1131,7 @@ static int exofs_get_inode(struct super_block *sb, struct exofs_i_info *oi,
 
        ret = extract_attr_from_ios(ios, &attrs[2]);
        if (ret) {
-               EXOFS_ERR("%s: extract_attr of inode_data failed\n", __func__);
+               EXOFS_ERR("%s: extract_attr 2 of inode failed\n", __func__);
                goto out;
        }
        if (attrs[2].len) {
index b744228886043d522fa15a32ff98cc80d29db3c9..dae884694bd99cd82643a5427c4981ea05c9639b 100644 (file)
@@ -103,7 +103,7 @@ int ore_verify_layout(unsigned total_comps, struct ore_layout *layout)
 
        layout->max_io_length =
                (BIO_MAX_PAGES_KMALLOC * PAGE_SIZE - layout->stripe_unit) *
-                                                       layout->group_width;
+                                       (layout->group_width - layout->parity);
        if (layout->parity) {
                unsigned stripe_length =
                                (layout->group_width - layout->parity) *
@@ -286,7 +286,8 @@ int  ore_get_rw_state(struct ore_layout *layout, struct ore_components *oc,
        if (length) {
                ore_calc_stripe_info(layout, offset, length, &ios->si);
                ios->length = ios->si.length;
-               ios->nr_pages = (ios->length + PAGE_SIZE - 1) / PAGE_SIZE;
+               ios->nr_pages = ((ios->offset & (PAGE_SIZE - 1)) +
+                                ios->length + PAGE_SIZE - 1) / PAGE_SIZE;
                if (layout->parity)
                        _ore_post_alloc_raid_stuff(ios);
        }
@@ -430,8 +431,12 @@ int ore_check_io(struct ore_io_state *ios, ore_on_dev_error on_dev_error)
                if (likely(!ret))
                        continue;
 
-               if (OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) {
-                       /* start read offset passed endof file */
+               if ((OSD_ERR_PRI_CLEAR_PAGES == osi.osd_err_pri) &&
+                   per_dev->bio) {
+                       /* start read offset passed endof file.
+                        * Note: if we do not have bio it means read-attributes
+                        * In this case we should return error to caller.
+                        */
                        _clear_bio(per_dev->bio);
                        ORE_DBGMSG("start read offset passed end of file "
                                "offset=0x%llx, length=0x%llx\n",
@@ -536,6 +541,7 @@ void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset,
        u64     H = LmodS - G * T;
 
        u32     N = div_u64(H, U);
+       u32     Nlast;
 
        /* "H - (N * U)" is just "H % U" so it's bound to u32 */
        u32     C = (u32)(H - (N * U)) / stripe_unit + G * group_width;
@@ -568,6 +574,10 @@ void ore_calc_stripe_info(struct ore_layout *layout, u64 file_offset,
        si->length = T - H;
        if (si->length > length)
                si->length = length;
+
+       Nlast = div_u64(H + si->length + U - 1, U);
+       si->maxdevUnits = Nlast - N;
+
        si->M = M;
 }
 EXPORT_SYMBOL(ore_calc_stripe_info);
@@ -583,13 +593,16 @@ int _ore_add_stripe_unit(struct ore_io_state *ios,  unsigned *cur_pg,
        int ret;
 
        if (per_dev->bio == NULL) {
-               unsigned pages_in_stripe = ios->layout->group_width *
-                                       (ios->layout->stripe_unit / PAGE_SIZE);
-               unsigned nr_pages = ios->nr_pages * ios->layout->group_width /
-                                       (ios->layout->group_width -
-                                        ios->layout->parity);
-               unsigned bio_size = (nr_pages + pages_in_stripe) /
-                                       ios->layout->group_width;
+               unsigned bio_size;
+
+               if (!ios->reading) {
+                       bio_size = ios->si.maxdevUnits;
+               } else {
+                       bio_size = (ios->si.maxdevUnits + 1) *
+                            (ios->layout->group_width - ios->layout->parity) /
+                            ios->layout->group_width;
+               }
+               bio_size *= (ios->layout->stripe_unit / PAGE_SIZE);
 
                per_dev->bio = bio_kmalloc(GFP_KERNEL, bio_size);
                if (unlikely(!per_dev->bio)) {
@@ -609,8 +622,12 @@ int _ore_add_stripe_unit(struct ore_io_state *ios,  unsigned *cur_pg,
                added_len = bio_add_pc_page(q, per_dev->bio, pages[pg],
                                            pglen, pgbase);
                if (unlikely(pglen != added_len)) {
-                       ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=%u\n",
-                                  per_dev->bio->bi_vcnt);
+                       /* If bi_vcnt == bi_max then this is a SW BUG */
+                       ORE_DBGMSG("Failed bio_add_pc_page bi_vcnt=0x%x "
+                                  "bi_max=0x%x BIO_MAX=0x%x cur_len=0x%x\n",
+                                  per_dev->bio->bi_vcnt,
+                                  per_dev->bio->bi_max_vecs,
+                                  BIO_MAX_PAGES_KMALLOC, cur_len);
                        ret = -ENOMEM;
                        goto out;
                }
@@ -1098,7 +1115,7 @@ int ore_truncate(struct ore_layout *layout, struct ore_components *oc,
                size_attr->attr = g_attr_logical_length;
                size_attr->attr.val_ptr = &size_attr->newsize;
 
-               ORE_DBGMSG("trunc(0x%llx) obj_offset=0x%llx dev=%d\n",
+               ORE_DBGMSG2("trunc(0x%llx) obj_offset=0x%llx dev=%d\n",
                             _LLU(oc->comps->obj.id), _LLU(obj_size), i);
                ret = _truncate_mirrors(ios, i * ios->layout->mirrors_p1,
                                        &size_attr->attr);
index 110b6b371a4edc353fc1904bcc79299580087184..1b8001bbe94778ec09cfab5ecd8d08136d384a5a 100644 (file)
@@ -148,13 +148,6 @@ ext2_get_acl(struct inode *inode, int type)
        struct posix_acl *acl;
        int retval;
 
-       if (!test_opt(inode->i_sb, POSIX_ACL))
-               return NULL;
-
-       acl = get_cached_acl(inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
@@ -189,19 +182,14 @@ ext2_get_acl(struct inode *inode, int type)
 /*
  * inode->i_mutex: down
  */
-static int
-ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+int
+ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        int name_index;
        void *value = NULL;
        size_t size = 0;
        int error;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-       if (!test_opt(inode->i_sb, POSIX_ACL))
-               return 0;
-
        switch(type) {
                case ACL_TYPE_ACCESS:
                        name_index = EXT2_XATTR_INDEX_POSIX_ACL_ACCESS;
@@ -250,169 +238,21 @@ ext2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 int
 ext2_init_acl(struct inode *inode, struct inode *dir)
 {
-       struct posix_acl *acl = NULL;
-       int error = 0;
-
-       if (!S_ISLNK(inode->i_mode)) {
-               if (test_opt(dir->i_sb, POSIX_ACL)) {
-                       acl = ext2_get_acl(dir, ACL_TYPE_DEFAULT);
-                       if (IS_ERR(acl))
-                               return PTR_ERR(acl);
-               }
-               if (!acl)
-                       inode->i_mode &= ~current_umask();
-       }
-       if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
-               if (S_ISDIR(inode->i_mode)) {
-                       error = ext2_set_acl(inode, ACL_TYPE_DEFAULT, acl);
-                       if (error)
-                               goto cleanup;
-               }
-               error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
-               if (error < 0)
-                       return error;
-               if (error > 0) {
-                       /* This is an extended ACL */
-                       error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl);
-               }
-       }
-cleanup:
-       posix_acl_release(acl);
-       return error;
-}
-
-/*
- * Does chmod for an inode that may have an Access Control List. The
- * inode->i_mode field must be updated to the desired value by the caller
- * before calling this function.
- * Returns 0 on success, or a negative error number.
- *
- * We change the ACL rather than storing some ACL entries in the file
- * mode permission bits (which would be more efficient), because that
- * would break once additional permissions (like  ACL_APPEND, ACL_DELETE
- * for directories) are added. There are no more bits available in the
- * file mode.
- *
- * inode->i_mutex: down
- */
-int
-ext2_acl_chmod(struct inode *inode)
-{
-       struct posix_acl *acl;
-        int error;
+       struct posix_acl *default_acl, *acl;
+       int error;
 
-       if (!test_opt(inode->i_sb, POSIX_ACL))
-               return 0;
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-       acl = ext2_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
-       error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
+       error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
        if (error)
                return error;
-       error = ext2_set_acl(inode, ACL_TYPE_ACCESS, acl);
-       posix_acl_release(acl);
-       return error;
-}
 
-/*
- * Extended attribut handlers
- */
-static size_t
-ext2_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_size,
-                          const char *name, size_t name_len, int type)
-{
-       const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
-
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return 0;
-       if (list && size <= list_size)
-               memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
-       return size;
-}
-
-static size_t
-ext2_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_size,
-                           const char *name, size_t name_len, int type)
-{
-       const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
-
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return 0;
-       if (list && size <= list_size)
-               memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
-       return size;
-}
-
-static int
-ext2_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
-                  size_t size, int type)
-{
-       struct posix_acl *acl;
-       int error;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return -EOPNOTSUPP;
-
-       acl = ext2_get_acl(dentry->d_inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl == NULL)
-               return -ENODATA;
-       error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
-       return error;
-}
-
-static int
-ext2_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
-                  size_t size, int flags, int type)
-{
-       struct posix_acl *acl;
-       int error;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return -EOPNOTSUPP;
-       if (!inode_owner_or_capable(dentry->d_inode))
-               return -EPERM;
-
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               else if (acl) {
-                       error = posix_acl_valid(acl);
-                       if (error)
-                               goto release_and_out;
-               }
-       } else
-               acl = NULL;
-
-       error = ext2_set_acl(dentry->d_inode, type, acl);
-
-release_and_out:
-       posix_acl_release(acl);
+       if (default_acl) {
+               error = ext2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+               posix_acl_release(default_acl);
+       }
+       if (acl) {
+               if (!error)
+                       error = ext2_set_acl(inode, acl, ACL_TYPE_ACCESS);
+               posix_acl_release(acl);
+       }
        return error;
 }
-
-const struct xattr_handler ext2_xattr_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags  = ACL_TYPE_ACCESS,
-       .list   = ext2_xattr_list_acl_access,
-       .get    = ext2_xattr_get_acl,
-       .set    = ext2_xattr_set_acl,
-};
-
-const struct xattr_handler ext2_xattr_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags  = ACL_TYPE_DEFAULT,
-       .list   = ext2_xattr_list_acl_default,
-       .get    = ext2_xattr_get_acl,
-       .set    = ext2_xattr_set_acl,
-};
index 503bfb0ed79b208365c50a0695243d55c43bca19..44937f9fcf327522bb65fe4d2463c1cb2f8bc3b8 100644 (file)
@@ -55,7 +55,7 @@ static inline int ext2_acl_count(size_t size)
 
 /* acl.c */
 extern struct posix_acl *ext2_get_acl(struct inode *inode, int type);
-extern int ext2_acl_chmod (struct inode *);
+extern int ext2_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 extern int ext2_init_acl (struct inode *, struct inode *);
 
 #else
@@ -63,12 +63,6 @@ extern int ext2_init_acl (struct inode *, struct inode *);
 #define ext2_get_acl   NULL
 #define ext2_set_acl   NULL
 
-static inline int
-ext2_acl_chmod (struct inode *inode)
-{
-       return 0;
-}
-
 static inline int ext2_init_acl (struct inode *inode, struct inode *dir)
 {
        return 0;
index a5b3a5db31206f8f3c84781362f7c45e919ddf0e..44c36e5907655982cc10e26b822cc1061312fbd1 100644 (file)
@@ -103,5 +103,6 @@ const struct inode_operations ext2_file_inode_operations = {
 #endif
        .setattr        = ext2_setattr,
        .get_acl        = ext2_get_acl,
+       .set_acl        = ext2_set_acl,
        .fiemap         = ext2_fiemap,
 };
index 8a337640a46a06fec154fe9ae1fef1e054000c23..94ed36849b717bb83d3824527b9ae4f2f7d4b90a 100644 (file)
@@ -1566,7 +1566,7 @@ int ext2_setattr(struct dentry *dentry, struct iattr *iattr)
        }
        setattr_copy(inode, iattr);
        if (iattr->ia_valid & ATTR_MODE)
-               error = ext2_acl_chmod(inode);
+               error = posix_acl_chmod(inode, inode->i_mode);
        mark_inode_dirty(inode);
 
        return error;
index 256dd5f4c1c4ade3f1ba160726ed0defabfccaf8..c268d0af1db93c5c9b3db0dd93dd6819d977b42e 100644 (file)
@@ -421,6 +421,7 @@ const struct inode_operations ext2_dir_inode_operations = {
 #endif
        .setattr        = ext2_setattr,
        .get_acl        = ext2_get_acl,
+       .set_acl        = ext2_set_acl,
        .tmpfile        = ext2_tmpfile,
 };
 
@@ -433,4 +434,5 @@ const struct inode_operations ext2_special_inode_operations = {
 #endif
        .setattr        = ext2_setattr,
        .get_acl        = ext2_get_acl,
+       .set_acl        = ext2_set_acl,
 };
index 2d7557db3ae855b614b0c70d2803adafb0f64181..91426141c33a32a1bd37bb95fa2414da5bcbad92 100644 (file)
@@ -103,8 +103,8 @@ static struct mb_cache *ext2_xattr_cache;
 static const struct xattr_handler *ext2_xattr_handler_map[] = {
        [EXT2_XATTR_INDEX_USER]              = &ext2_xattr_user_handler,
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
-       [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext2_xattr_acl_access_handler,
-       [EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext2_xattr_acl_default_handler,
+       [EXT2_XATTR_INDEX_POSIX_ACL_ACCESS]  = &posix_acl_access_xattr_handler,
+       [EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler,
 #endif
        [EXT2_XATTR_INDEX_TRUSTED]           = &ext2_xattr_trusted_handler,
 #ifdef CONFIG_EXT2_FS_SECURITY
@@ -116,8 +116,8 @@ const struct xattr_handler *ext2_xattr_handlers[] = {
        &ext2_xattr_user_handler,
        &ext2_xattr_trusted_handler,
 #ifdef CONFIG_EXT2_FS_POSIX_ACL
-       &ext2_xattr_acl_access_handler,
-       &ext2_xattr_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
 #ifdef CONFIG_EXT2_FS_SECURITY
        &ext2_xattr_security_handler,
index 5e41cccff7622a212fec0a8f2a43fe7e38d8b2d9..60edf298644ea2ad9a45b960425392697cbdf373 100644 (file)
@@ -57,8 +57,6 @@ struct ext2_xattr_entry {
 
 extern const struct xattr_handler ext2_xattr_user_handler;
 extern const struct xattr_handler ext2_xattr_trusted_handler;
-extern const struct xattr_handler ext2_xattr_acl_access_handler;
-extern const struct xattr_handler ext2_xattr_acl_default_handler;
 extern const struct xattr_handler ext2_xattr_security_handler;
 
 extern ssize_t ext2_listxattr(struct dentry *, char *, size_t);
index dbb5ad59a7fc3c22380ce30b9034f8942bec967b..8bbaf5bcf9820c6d538298a0a5d6922a52f3d231 100644 (file)
@@ -145,13 +145,6 @@ ext3_get_acl(struct inode *inode, int type)
        struct posix_acl *acl;
        int retval;
 
-       if (!test_opt(inode->i_sb, POSIX_ACL))
-               return NULL;
-
-       acl = get_cached_acl(inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
@@ -190,7 +183,7 @@ ext3_get_acl(struct inode *inode, int type)
  * inode->i_mutex: down unless called from ext3_new_inode
  */
 static int
-ext3_set_acl(handle_t *handle, struct inode *inode, int type,
+__ext3_set_acl(handle_t *handle, struct inode *inode, int type,
             struct posix_acl *acl)
 {
        int name_index;
@@ -198,9 +191,6 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
        size_t size = 0;
        int error;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
        switch(type) {
                case ACL_TYPE_ACCESS:
                        name_index = EXT3_XATTR_INDEX_POSIX_ACL_ACCESS;
@@ -243,204 +233,49 @@ ext3_set_acl(handle_t *handle, struct inode *inode, int type,
        return error;
 }
 
-/*
- * Initialize the ACLs of a new inode. Called from ext3_new_inode.
- *
- * dir->i_mutex: down
- * inode->i_mutex: up (access to inode is still exclusive)
- */
 int
-ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
+ext3_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
-       struct posix_acl *acl = NULL;
-       int error = 0;
-
-       if (!S_ISLNK(inode->i_mode)) {
-               if (test_opt(dir->i_sb, POSIX_ACL)) {
-                       acl = ext3_get_acl(dir, ACL_TYPE_DEFAULT);
-                       if (IS_ERR(acl))
-                               return PTR_ERR(acl);
-               }
-               if (!acl)
-                       inode->i_mode &= ~current_umask();
-       }
-       if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
-               if (S_ISDIR(inode->i_mode)) {
-                       error = ext3_set_acl(handle, inode,
-                                            ACL_TYPE_DEFAULT, acl);
-                       if (error)
-                               goto cleanup;
-               }
-               error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
-               if (error < 0)
-                       return error;
-
-               if (error > 0) {
-                       /* This is an extended ACL */
-                       error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
-               }
-       }
-cleanup:
-       posix_acl_release(acl);
-       return error;
-}
-
-/*
- * Does chmod for an inode that may have an Access Control List. The
- * inode->i_mode field must be updated to the desired value by the caller
- * before calling this function.
- * Returns 0 on success, or a negative error number.
- *
- * We change the ACL rather than storing some ACL entries in the file
- * mode permission bits (which would be more efficient), because that
- * would break once additional permissions (like  ACL_APPEND, ACL_DELETE
- * for directories) are added. There are no more bits available in the
- * file mode.
- *
- * inode->i_mutex: down
- */
-int
-ext3_acl_chmod(struct inode *inode)
-{
-       struct posix_acl *acl;
        handle_t *handle;
-       int retries = 0;
-        int error;
+       int error, retries = 0;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-       if (!test_opt(inode->i_sb, POSIX_ACL))
-               return 0;
-       acl = ext3_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
-       error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
-       if (error)
-               return error;
 retry:
-       handle = ext3_journal_start(inode,
-                       EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
-       if (IS_ERR(handle)) {
-               error = PTR_ERR(handle);
-               ext3_std_error(inode->i_sb, error);
-               goto out;
-       }
-       error = ext3_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
+       handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+       error = __ext3_set_acl(handle, inode, type, acl);
        ext3_journal_stop(handle);
-       if (error == -ENOSPC &&
-           ext3_should_retry_alloc(inode->i_sb, &retries))
+       if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
                goto retry;
-out:
-       posix_acl_release(acl);
        return error;
 }
 
 /*
- * Extended attribute handlers
+ * Initialize the ACLs of a new inode. Called from ext3_new_inode.
+ *
+ * dir->i_mutex: down
+ * inode->i_mutex: up (access to inode is still exclusive)
  */
-static size_t
-ext3_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
-                          const char *name, size_t name_len, int type)
-{
-       const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
-
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return 0;
-       if (list && size <= list_len)
-               memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
-       return size;
-}
-
-static size_t
-ext3_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
-                           const char *name, size_t name_len, int type)
-{
-       const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
-
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return 0;
-       if (list && size <= list_len)
-               memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
-       return size;
-}
-
-static int
-ext3_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
-                  size_t size, int type)
+int
+ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
 {
-       struct posix_acl *acl;
+       struct posix_acl *default_acl, *acl;
        int error;
 
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return -EOPNOTSUPP;
-
-       acl = ext3_get_acl(dentry->d_inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl == NULL)
-               return -ENODATA;
-       error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
-       return error;
-}
-
-static int
-ext3_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
-                  size_t size, int flags, int type)
-{
-       struct inode *inode = dentry->d_inode;
-       handle_t *handle;
-       struct posix_acl *acl;
-       int error, retries = 0;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!test_opt(inode->i_sb, POSIX_ACL))
-               return -EOPNOTSUPP;
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               else if (acl) {
-                       error = posix_acl_valid(acl);
-                       if (error)
-                               goto release_and_out;
-               }
-       } else
-               acl = NULL;
-
-retry:
-       handle = ext3_journal_start(inode, EXT3_DATA_TRANS_BLOCKS(inode->i_sb));
-       if (IS_ERR(handle))
-               return PTR_ERR(handle);
-       error = ext3_set_acl(handle, inode, type, acl);
-       ext3_journal_stop(handle);
-       if (error == -ENOSPC && ext3_should_retry_alloc(inode->i_sb, &retries))
-               goto retry;
+       error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+       if (error)
+               return error;
 
-release_and_out:
-       posix_acl_release(acl);
+       if (default_acl) {
+               error = __ext3_set_acl(handle, inode, ACL_TYPE_DEFAULT,
+                                      default_acl);
+               posix_acl_release(default_acl);
+       }
+       if (acl) {
+               if (!error)
+                       error = __ext3_set_acl(handle, inode, ACL_TYPE_ACCESS,
+                                              acl);
+               posix_acl_release(acl);
+       }
        return error;
 }
-
-const struct xattr_handler ext3_xattr_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags  = ACL_TYPE_ACCESS,
-       .list   = ext3_xattr_list_acl_access,
-       .get    = ext3_xattr_get_acl,
-       .set    = ext3_xattr_set_acl,
-};
-
-const struct xattr_handler ext3_xattr_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags  = ACL_TYPE_DEFAULT,
-       .list   = ext3_xattr_list_acl_default,
-       .get    = ext3_xattr_get_acl,
-       .set    = ext3_xattr_set_acl,
-};
index dbc921e458c5599177fb86fc6e3fc95481cf06ab..ea1c69edab9e15dd1a9447f2be4a0e83650252c7 100644 (file)
@@ -55,18 +55,13 @@ static inline int ext3_acl_count(size_t size)
 
 /* acl.c */
 extern struct posix_acl *ext3_get_acl(struct inode *inode, int type);
-extern int ext3_acl_chmod (struct inode *);
+extern int ext3_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 extern int ext3_init_acl (handle_t *, struct inode *, struct inode *);
 
 #else  /* CONFIG_EXT3_FS_POSIX_ACL */
 #include <linux/sched.h>
 #define ext3_get_acl NULL
-
-static inline int
-ext3_acl_chmod(struct inode *inode)
-{
-       return 0;
-}
+#define ext3_set_acl NULL
 
 static inline int
 ext3_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
index 25cb413277e906edb1f037ba625ece7aa92903bb..aad05311392a046f3df724102580c511185c0fa2 100644 (file)
@@ -75,6 +75,7 @@ const struct inode_operations ext3_file_inode_operations = {
        .removexattr    = generic_removexattr,
 #endif
        .get_acl        = ext3_get_acl,
+       .set_acl        = ext3_set_acl,
        .fiemap         = ext3_fiemap,
 };
 
index 2bd85486b87974b390892a2280676a49d8eb274e..384b6ebb655f1aefa21e53b6b28f6598c40db1b2 100644 (file)
@@ -3365,7 +3365,7 @@ int ext3_setattr(struct dentry *dentry, struct iattr *attr)
        mark_inode_dirty(inode);
 
        if (ia_valid & ATTR_MODE)
-               rc = ext3_acl_chmod(inode);
+               rc = posix_acl_chmod(inode, inode->i_mode);
 
 err_out:
        ext3_std_error(inode->i_sb, error);
index f8cde46de9cd77c3047182e94164bdfdac4a317d..f197736dccfa16cca207fecb81e6445a18e96973 100644 (file)
@@ -2569,6 +2569,7 @@ const struct inode_operations ext3_dir_inode_operations = {
        .removexattr    = generic_removexattr,
 #endif
        .get_acl        = ext3_get_acl,
+       .set_acl        = ext3_set_acl,
 };
 
 const struct inode_operations ext3_special_inode_operations = {
@@ -2580,4 +2581,5 @@ const struct inode_operations ext3_special_inode_operations = {
        .removexattr    = generic_removexattr,
 #endif
        .get_acl        = ext3_get_acl,
+       .set_acl        = ext3_set_acl,
 };
index b1fc96383e087157879e853b2affbf0cb87982ec..c6874be6d58b41f02bcaa3b93cf182845bd85bec 100644 (file)
@@ -102,8 +102,8 @@ static struct mb_cache *ext3_xattr_cache;
 static const struct xattr_handler *ext3_xattr_handler_map[] = {
        [EXT3_XATTR_INDEX_USER]              = &ext3_xattr_user_handler,
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
-       [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext3_xattr_acl_access_handler,
-       [EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext3_xattr_acl_default_handler,
+       [EXT3_XATTR_INDEX_POSIX_ACL_ACCESS]  = &posix_acl_access_xattr_handler,
+       [EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler,
 #endif
        [EXT3_XATTR_INDEX_TRUSTED]           = &ext3_xattr_trusted_handler,
 #ifdef CONFIG_EXT3_FS_SECURITY
@@ -115,8 +115,8 @@ const struct xattr_handler *ext3_xattr_handlers[] = {
        &ext3_xattr_user_handler,
        &ext3_xattr_trusted_handler,
 #ifdef CONFIG_EXT3_FS_POSIX_ACL
-       &ext3_xattr_acl_access_handler,
-       &ext3_xattr_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
 #ifdef CONFIG_EXT3_FS_SECURITY
        &ext3_xattr_security_handler,
index 2be4f69bfa64b301d437e5130868f433a01d5f50..32e93ebf80315bed89dd5e919202a4de2d2f4de3 100644 (file)
@@ -60,8 +60,6 @@ struct ext3_xattr_entry {
 
 extern const struct xattr_handler ext3_xattr_user_handler;
 extern const struct xattr_handler ext3_xattr_trusted_handler;
-extern const struct xattr_handler ext3_xattr_acl_access_handler;
-extern const struct xattr_handler ext3_xattr_acl_default_handler;
 extern const struct xattr_handler ext3_xattr_security_handler;
 
 extern ssize_t ext3_listxattr(struct dentry *, char *, size_t);
index 39a54a0e9fe4a9a6290f75b961cde9ccea06f669..d40c8dbbb0d66a3622915c68dc104841ab1f5753 100644 (file)
@@ -152,13 +152,6 @@ ext4_get_acl(struct inode *inode, int type)
        struct posix_acl *acl;
        int retval;
 
-       if (!test_opt(inode->i_sb, POSIX_ACL))
-               return NULL;
-
-       acl = get_cached_acl(inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
@@ -196,7 +189,7 @@ ext4_get_acl(struct inode *inode, int type)
  * inode->i_mutex: down unless called from ext4_new_inode
  */
 static int
-ext4_set_acl(handle_t *handle, struct inode *inode, int type,
+__ext4_set_acl(handle_t *handle, struct inode *inode, int type,
             struct posix_acl *acl)
 {
        int name_index;
@@ -204,9 +197,6 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
        size_t size = 0;
        int error;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                name_index = EXT4_XATTR_INDEX_POSIX_ACL_ACCESS;
@@ -248,208 +238,51 @@ ext4_set_acl(handle_t *handle, struct inode *inode, int type,
        return error;
 }
 
-/*
- * Initialize the ACLs of a new inode. Called from ext4_new_inode.
- *
- * dir->i_mutex: down
- * inode->i_mutex: up (access to inode is still exclusive)
- */
 int
-ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
+ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
-       struct posix_acl *acl = NULL;
-       int error = 0;
-
-       if (!S_ISLNK(inode->i_mode)) {
-               if (test_opt(dir->i_sb, POSIX_ACL)) {
-                       acl = ext4_get_acl(dir, ACL_TYPE_DEFAULT);
-                       if (IS_ERR(acl))
-                               return PTR_ERR(acl);
-               }
-               if (!acl)
-                       inode->i_mode &= ~current_umask();
-       }
-       if (test_opt(inode->i_sb, POSIX_ACL) && acl) {
-               if (S_ISDIR(inode->i_mode)) {
-                       error = ext4_set_acl(handle, inode,
-                                            ACL_TYPE_DEFAULT, acl);
-                       if (error)
-                               goto cleanup;
-               }
-               error = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
-               if (error < 0)
-                       return error;
-
-               if (error > 0) {
-                       /* This is an extended ACL */
-                       error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
-               }
-       }
-cleanup:
-       posix_acl_release(acl);
-       return error;
-}
-
-/*
- * Does chmod for an inode that may have an Access Control List. The
- * inode->i_mode field must be updated to the desired value by the caller
- * before calling this function.
- * Returns 0 on success, or a negative error number.
- *
- * We change the ACL rather than storing some ACL entries in the file
- * mode permission bits (which would be more efficient), because that
- * would break once additional permissions (like  ACL_APPEND, ACL_DELETE
- * for directories) are added. There are no more bits available in the
- * file mode.
- *
- * inode->i_mutex: down
- */
-int
-ext4_acl_chmod(struct inode *inode)
-{
-       struct posix_acl *acl;
        handle_t *handle;
-       int retries = 0;
-       int error;
-
+       int error, retries = 0;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-       if (!test_opt(inode->i_sb, POSIX_ACL))
-               return 0;
-       acl = ext4_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
-       error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
-       if (error)
-               return error;
 retry:
        handle = ext4_journal_start(inode, EXT4_HT_XATTR,
                                    ext4_jbd2_credits_xattr(inode));
-       if (IS_ERR(handle)) {
-               error = PTR_ERR(handle);
-               ext4_std_error(inode->i_sb, error);
-               goto out;
-       }
-       error = ext4_set_acl(handle, inode, ACL_TYPE_ACCESS, acl);
+       if (IS_ERR(handle))
+               return PTR_ERR(handle);
+
+       error = __ext4_set_acl(handle, inode, type, acl);
        ext4_journal_stop(handle);
-       if (error == -ENOSPC &&
-           ext4_should_retry_alloc(inode->i_sb, &retries))
+       if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
                goto retry;
-out:
-       posix_acl_release(acl);
        return error;
 }
 
 /*
- * Extended attribute handlers
+ * Initialize the ACLs of a new inode. Called from ext4_new_inode.
+ *
+ * dir->i_mutex: down
+ * inode->i_mutex: up (access to inode is still exclusive)
  */
-static size_t
-ext4_xattr_list_acl_access(struct dentry *dentry, char *list, size_t list_len,
-                          const char *name, size_t name_len, int type)
-{
-       const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
-
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return 0;
-       if (list && size <= list_len)
-               memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
-       return size;
-}
-
-static size_t
-ext4_xattr_list_acl_default(struct dentry *dentry, char *list, size_t list_len,
-                           const char *name, size_t name_len, int type)
-{
-       const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
-
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return 0;
-       if (list && size <= list_len)
-               memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
-       return size;
-}
-
-static int
-ext4_xattr_get_acl(struct dentry *dentry, const char *name, void *buffer,
-                  size_t size, int type)
+int
+ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
 {
-       struct posix_acl *acl;
+       struct posix_acl *default_acl, *acl;
        int error;
 
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!test_opt(dentry->d_sb, POSIX_ACL))
-               return -EOPNOTSUPP;
-
-       acl = ext4_get_acl(dentry->d_inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl == NULL)
-               return -ENODATA;
-       error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
-       return error;
-}
-
-static int
-ext4_xattr_set_acl(struct dentry *dentry, const char *name, const void *value,
-                  size_t size, int flags, int type)
-{
-       struct inode *inode = dentry->d_inode;
-       handle_t *handle;
-       struct posix_acl *acl;
-       int error, retries = 0;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!test_opt(inode->i_sb, POSIX_ACL))
-               return -EOPNOTSUPP;
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               else if (acl) {
-                       error = posix_acl_valid(acl);
-                       if (error)
-                               goto release_and_out;
-               }
-       } else
-               acl = NULL;
+       error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+       if (error)
+               return error;
 
-retry:
-       handle = ext4_journal_start(inode, EXT4_HT_XATTR,
-                                   ext4_jbd2_credits_xattr(inode));
-       if (IS_ERR(handle)) {
-               error = PTR_ERR(handle);
-               goto release_and_out;
+       if (default_acl) {
+               error = __ext4_set_acl(handle, inode, ACL_TYPE_DEFAULT,
+                                      default_acl);
+               posix_acl_release(default_acl);
+       }
+       if (acl) {
+               if (!error)
+                       error = __ext4_set_acl(handle, inode, ACL_TYPE_ACCESS,
+                                              acl);
+               posix_acl_release(acl);
        }
-       error = ext4_set_acl(handle, inode, type, acl);
-       ext4_journal_stop(handle);
-       if (error == -ENOSPC && ext4_should_retry_alloc(inode->i_sb, &retries))
-               goto retry;
-
-release_and_out:
-       posix_acl_release(acl);
        return error;
 }
-
-const struct xattr_handler ext4_xattr_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags  = ACL_TYPE_ACCESS,
-       .list   = ext4_xattr_list_acl_access,
-       .get    = ext4_xattr_get_acl,
-       .set    = ext4_xattr_set_acl,
-};
-
-const struct xattr_handler ext4_xattr_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags  = ACL_TYPE_DEFAULT,
-       .list   = ext4_xattr_list_acl_default,
-       .get    = ext4_xattr_get_acl,
-       .set    = ext4_xattr_set_acl,
-};
index 18cb39ed7c7bbb88dfb72f67150b40cf859e2a58..da2c79577d724ae14e7fbf3b5adb4cb3e2848e5d 100644 (file)
@@ -55,18 +55,13 @@ static inline int ext4_acl_count(size_t size)
 
 /* acl.c */
 struct posix_acl *ext4_get_acl(struct inode *inode, int type);
-extern int ext4_acl_chmod(struct inode *);
+int ext4_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 extern int ext4_init_acl(handle_t *, struct inode *, struct inode *);
 
 #else  /* CONFIG_EXT4_FS_POSIX_ACL */
 #include <linux/sched.h>
 #define ext4_get_acl NULL
-
-static inline int
-ext4_acl_chmod(struct inode *inode)
-{
-       return 0;
-}
+#define ext4_set_acl NULL
 
 static inline int
 ext4_init_acl(handle_t *handle, struct inode *inode, struct inode *dir)
index 3384dc4bed4034921beffb84783327024e4cf22e..10cff4736b116185f9d0a2cea73dca9423c6fb92 100644 (file)
@@ -3477,7 +3477,7 @@ static int ext4_ext_convert_to_initialized(handle_t *handle,
        WARN_ON(map->m_lblk < ee_block);
        /*
         * It is safe to convert extent to initialized via explicit
-        * zeroout only if extent is fully insde i_size or new_size.
+        * zeroout only if extent is fully inside i_size or new_size.
         */
        split_flag |= ee_block + ee_len <= eof_block ? EXT4_EXT_MAY_ZEROOUT : 0;
 
index 3da21945ff1fff3e16b8b70b332a0a6ee330c93e..43e64f6022eb4af22e7ac95eb6aaa34e7e6735a9 100644 (file)
@@ -617,6 +617,7 @@ const struct inode_operations ext4_file_inode_operations = {
        .listxattr      = ext4_listxattr,
        .removexattr    = generic_removexattr,
        .get_acl        = ext4_get_acl,
+       .set_acl        = ext4_set_acl,
        .fiemap         = ext4_fiemap,
 };
 
index bae987549dc367736eaf0beeedb29e8e514e46e6..82edf5b9335277b8f508be2105b6944a9d57ce5c 100644 (file)
@@ -849,15 +849,16 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
        handle_t *handle;
        struct page *page;
        struct ext4_iloc iloc;
+       int retries;
 
        ret = ext4_get_inode_loc(inode, &iloc);
        if (ret)
                return ret;
 
+retry_journal:
        handle = ext4_journal_start(inode, EXT4_HT_INODE, 1);
        if (IS_ERR(handle)) {
                ret = PTR_ERR(handle);
-               handle = NULL;
                goto out;
        }
 
@@ -867,7 +868,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
        if (inline_size >= pos + len) {
                ret = ext4_prepare_inline_data(handle, inode, pos + len);
                if (ret && ret != -ENOSPC)
-                       goto out;
+                       goto out_journal;
        }
 
        if (ret == -ENOSPC) {
@@ -875,6 +876,10 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
                                                            inode,
                                                            flags,
                                                            fsdata);
+               ext4_journal_stop(handle);
+               if (ret == -ENOSPC &&
+                   ext4_should_retry_alloc(inode->i_sb, &retries))
+                       goto retry_journal;
                goto out;
        }
 
@@ -887,7 +892,7 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
        page = grab_cache_page_write_begin(mapping, 0, flags);
        if (!page) {
                ret = -ENOMEM;
-               goto out;
+               goto out_journal;
        }
 
        down_read(&EXT4_I(inode)->xattr_sem);
@@ -904,16 +909,15 @@ int ext4_da_write_inline_data_begin(struct address_space *mapping,
 
        up_read(&EXT4_I(inode)->xattr_sem);
        *pagep = page;
-       handle = NULL;
        brelse(iloc.bh);
        return 1;
 out_release_page:
        up_read(&EXT4_I(inode)->xattr_sem);
        unlock_page(page);
        page_cache_release(page);
+out_journal:
+       ext4_journal_stop(handle);
 out:
-       if (handle)
-               ext4_journal_stop(handle);
        brelse(iloc.bh);
        return ret;
 }
@@ -1837,7 +1841,6 @@ int ext4_try_to_evict_inline_data(handle_t *handle,
 {
        int error;
        struct ext4_xattr_entry *entry;
-       struct ext4_xattr_ibody_header *header;
        struct ext4_inode *raw_inode;
        struct ext4_iloc iloc;
 
@@ -1846,7 +1849,6 @@ int ext4_try_to_evict_inline_data(handle_t *handle,
                return error;
 
        raw_inode = ext4_raw_inode(&iloc);
-       header = IHDR(inode, raw_inode);
        entry = (struct ext4_xattr_entry *)((void *)raw_inode +
                                            EXT4_I(inode)->i_inline_off);
        if (EXT4_XATTR_LEN(entry->e_name_len) +
@@ -1924,9 +1926,11 @@ void ext4_inline_data_truncate(struct inode *inode, int *has_inline)
                }
 
                /* Clear the content within i_blocks. */
-               if (i_size < EXT4_MIN_INLINE_DATA_SIZE)
-                       memset(ext4_raw_inode(&is.iloc)->i_block + i_size, 0,
-                                       EXT4_MIN_INLINE_DATA_SIZE - i_size);
+               if (i_size < EXT4_MIN_INLINE_DATA_SIZE) {
+                       void *p = (void *) ext4_raw_inode(&is.iloc)->i_block;
+                       memset(p + i_size, 0,
+                              EXT4_MIN_INLINE_DATA_SIZE - i_size);
+               }
 
                EXT4_I(inode)->i_inline_size = i_size <
                                        EXT4_MIN_INLINE_DATA_SIZE ?
index 31fa964742bcba1b0f9dbd494e469feb56ee8428..6e39895a91b80aaae3914cc3a51756b3fa48a4c8 100644 (file)
@@ -144,8 +144,8 @@ static int ext4_meta_trans_blocks(struct inode *inode, int lblocks,
  */
 static int ext4_inode_is_fast_symlink(struct inode *inode)
 {
-       int ea_blocks = EXT4_I(inode)->i_file_acl ?
-               (inode->i_sb->s_blocksize >> 9) : 0;
+        int ea_blocks = EXT4_I(inode)->i_file_acl ?
+               EXT4_CLUSTER_SIZE(inode->i_sb) >> 9 : 0;
 
        return (S_ISLNK(inode->i_mode) && inode->i_blocks - ea_blocks == 0);
 }
@@ -1772,7 +1772,7 @@ static int __ext4_journalled_writepage(struct page *page,
                ret = err;
 
        if (!ext4_has_inline_data(inode))
-               ext4_walk_page_buffers(handle, page_bufs, 0, len,
+               ext4_walk_page_buffers(NULL, page_bufs, 0, len,
                                       NULL, bput_one);
        ext4_set_inode_state(inode, EXT4_STATE_JDATA);
 out:
@@ -3501,11 +3501,6 @@ int ext4_punch_hole(struct inode *inode, loff_t offset, loff_t length)
        if (!S_ISREG(inode->i_mode))
                return -EOPNOTSUPP;
 
-       if (EXT4_SB(sb)->s_cluster_ratio > 1) {
-               /* TODO: Add support for bigalloc file systems */
-               return -EOPNOTSUPP;
-       }
-
        trace_ext4_punch_hole(inode, offset, length);
 
        /*
@@ -4667,7 +4662,7 @@ int ext4_setattr(struct dentry *dentry, struct iattr *attr)
                ext4_orphan_del(NULL, inode);
 
        if (!rc && (ia_valid & ATTR_MODE))
-               rc = ext4_acl_chmod(inode);
+               rc = posix_acl_chmod(inode, inode->i_mode);
 
 err_out:
        ext4_std_error(inode->i_sb, error);
index 60589b60e9b04936cb2d27c9615b2b8caee246fb..6bea80614d77c19c6ca7b1ac9160d64f1115b36e 100644 (file)
@@ -101,9 +101,8 @@ static long swap_inode_boot_loader(struct super_block *sb,
        handle_t *handle;
        int err;
        struct inode *inode_bl;
-       struct ext4_inode_info *ei;
        struct ext4_inode_info *ei_bl;
-       struct ext4_sb_info *sbi;
+       struct ext4_sb_info *sbi = EXT4_SB(sb);
 
        if (inode->i_nlink != 1 || !S_ISREG(inode->i_mode)) {
                err = -EINVAL;
@@ -115,9 +114,6 @@ static long swap_inode_boot_loader(struct super_block *sb,
                goto swap_boot_out;
        }
 
-       sbi = EXT4_SB(sb);
-       ei = EXT4_I(inode);
-
        inode_bl = ext4_iget(sb, EXT4_BOOT_LOADER_INO);
        if (IS_ERR(inode_bl)) {
                err = PTR_ERR(inode_bl);
index 5a0408d7b1147094c3e82b6d11750b33396b7732..d050e043e884c19120c8062a2ab2991ba71a9a86 100644 (file)
@@ -1425,9 +1425,8 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsi
                        return ERR_PTR(-EIO);
                }
                if (unlikely(ino == dir->i_ino)) {
-                       EXT4_ERROR_INODE(dir, "'%.*s' linked to parent dir",
-                                        dentry->d_name.len,
-                                        dentry->d_name.name);
+                       EXT4_ERROR_INODE(dir, "'%pd' linked to parent dir",
+                                        dentry);
                        return ERR_PTR(-EIO);
                }
                inode = ext4_iget(dir->i_sb, ino);
@@ -3225,6 +3224,7 @@ const struct inode_operations ext4_dir_inode_operations = {
        .listxattr      = ext4_listxattr,
        .removexattr    = generic_removexattr,
        .get_acl        = ext4_get_acl,
+       .set_acl        = ext4_set_acl,
        .fiemap         = ext4_fiemap,
 };
 
@@ -3235,4 +3235,5 @@ const struct inode_operations ext4_special_inode_operations = {
        .listxattr      = ext4_listxattr,
        .removexattr    = generic_removexattr,
        .get_acl        = ext4_get_acl,
+       .set_acl        = ext4_set_acl,
 };
index d488f80ee32df1137e91df0aed72bef2f61b49ac..ab95508e3d4018eab92647c6d2308e98524080d1 100644 (file)
@@ -65,9 +65,9 @@ static void ext4_finish_bio(struct bio *bio)
 {
        int i;
        int error = !test_bit(BIO_UPTODATE, &bio->bi_flags);
+       struct bio_vec *bvec;
 
-       for (i = 0; i < bio->bi_vcnt; i++) {
-               struct bio_vec *bvec = &bio->bi_io_vec[i];
+       bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
                struct buffer_head *bh, *head;
                unsigned bio_start = bvec->bv_offset;
@@ -298,7 +298,7 @@ ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end)
 static void ext4_end_bio(struct bio *bio, int error)
 {
        ext4_io_end_t *io_end = bio->bi_private;
-       sector_t bi_sector = bio->bi_sector;
+       sector_t bi_sector = bio->bi_iter.bi_sector;
 
        BUG_ON(!io_end);
        bio->bi_end_io = NULL;
@@ -366,7 +366,7 @@ static int io_submit_init_bio(struct ext4_io_submit *io,
        bio = bio_alloc(GFP_NOIO, min(nvecs, BIO_MAX_PAGES));
        if (!bio)
                return -ENOMEM;
-       bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
+       bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
        bio->bi_bdev = bh->b_bdev;
        bio->bi_end_io = ext4_end_bio;
        bio->bi_private = ext4_get_io_end(io->io_end);
index 1423c4816a4783da4208b6d51fc33815b25597f4..e175e94116acefdc7685896e5c8744f7bd677dc4 100644 (file)
@@ -95,8 +95,8 @@ static struct mb_cache *ext4_xattr_cache;
 static const struct xattr_handler *ext4_xattr_handler_map[] = {
        [EXT4_XATTR_INDEX_USER]              = &ext4_xattr_user_handler,
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
-       [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS]  = &ext4_xattr_acl_access_handler,
-       [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &ext4_xattr_acl_default_handler,
+       [EXT4_XATTR_INDEX_POSIX_ACL_ACCESS]  = &posix_acl_access_xattr_handler,
+       [EXT4_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler,
 #endif
        [EXT4_XATTR_INDEX_TRUSTED]           = &ext4_xattr_trusted_handler,
 #ifdef CONFIG_EXT4_FS_SECURITY
@@ -108,8 +108,8 @@ const struct xattr_handler *ext4_xattr_handlers[] = {
        &ext4_xattr_user_handler,
        &ext4_xattr_trusted_handler,
 #ifdef CONFIG_EXT4_FS_POSIX_ACL
-       &ext4_xattr_acl_access_handler,
-       &ext4_xattr_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
 #ifdef CONFIG_EXT4_FS_SECURITY
        &ext4_xattr_security_handler,
index c767dbdd7fc495e5a4fd4a5c581455db73c5c1c3..819d6398833f9d98ea7a9e78552381f63f7b83fd 100644 (file)
@@ -96,8 +96,6 @@ struct ext4_xattr_ibody_find {
 
 extern const struct xattr_handler ext4_xattr_user_handler;
 extern const struct xattr_handler ext4_xattr_trusted_handler;
-extern const struct xattr_handler ext4_xattr_acl_access_handler;
-extern const struct xattr_handler ext4_xattr_acl_default_handler;
 extern const struct xattr_handler ext4_xattr_security_handler;
 
 extern ssize_t ext4_listxattr(struct dentry *, char *, size_t);
index d0fc287efeff4511fa7f4e84369cf77f0ae31538..fa8da4cb8c4b9a3aa647f2a4f51467fc86549fc5 100644 (file)
@@ -17,9 +17,6 @@
 #include "xattr.h"
 #include "acl.h"
 
-#define get_inode_mode(i)      ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \
-                                       (F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
-
 static inline size_t f2fs_acl_size(int count)
 {
        if (count <= 4) {
@@ -167,19 +164,11 @@ fail:
 
 struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
 {
-       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT;
        void *value = NULL;
        struct posix_acl *acl;
        int retval;
 
-       if (!test_opt(sbi, POSIX_ACL))
-               return NULL;
-
-       acl = get_cached_acl(inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
-
        if (type == ACL_TYPE_ACCESS)
                name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
 
@@ -205,21 +194,15 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
        return acl;
 }
 
-static int f2fs_set_acl(struct inode *inode, int type,
+static int __f2fs_set_acl(struct inode *inode, int type,
                        struct posix_acl *acl, struct page *ipage)
 {
-       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
        struct f2fs_inode_info *fi = F2FS_I(inode);
        int name_index;
        void *value = NULL;
        size_t size = 0;
        int error;
 
-       if (!test_opt(sbi, POSIX_ACL))
-               return 0;
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
@@ -261,154 +244,31 @@ static int f2fs_set_acl(struct inode *inode, int type,
        return error;
 }
 
-int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage)
+int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
-       struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
-       struct posix_acl *acl = NULL;
-       int error = 0;
-
-       if (!S_ISLNK(inode->i_mode)) {
-               if (test_opt(sbi, POSIX_ACL)) {
-                       acl = f2fs_get_acl(dir, ACL_TYPE_DEFAULT);
-                       if (IS_ERR(acl))
-                               return PTR_ERR(acl);
-               }
-               if (!acl)
-                       inode->i_mode &= ~current_umask();
-       }
-
-       if (!test_opt(sbi, POSIX_ACL) || !acl)
-               goto cleanup;
-
-       if (S_ISDIR(inode->i_mode)) {
-               error = f2fs_set_acl(inode, ACL_TYPE_DEFAULT, acl, ipage);
-               if (error)
-                       goto cleanup;
-       }
-       error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
-       if (error < 0)
-               return error;
-       if (error > 0)
-               error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, ipage);
-cleanup:
-       posix_acl_release(acl);
-       return error;
+       return __f2fs_set_acl(inode, type, acl, NULL);
 }
 
-int f2fs_acl_chmod(struct inode *inode)
+int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage)
 {
-       struct f2fs_sb_info *sbi = F2FS_SB(inode->i_sb);
-       struct posix_acl *acl;
-       int error;
-       umode_t mode = get_inode_mode(inode);
-
-       if (!test_opt(sbi, POSIX_ACL))
-               return 0;
-       if (S_ISLNK(mode))
-               return -EOPNOTSUPP;
-
-       acl = f2fs_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
+       struct posix_acl *default_acl, *acl;
+       int error = 0;
 
-       error = posix_acl_chmod(&acl, GFP_KERNEL, mode);
+       error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
        if (error)
                return error;
 
-       error = f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl, NULL);
-       posix_acl_release(acl);
-       return error;
-}
-
-static size_t f2fs_xattr_list_acl(struct dentry *dentry, char *list,
-               size_t list_size, const char *name, size_t name_len, int type)
-{
-       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
-       const char *xname = POSIX_ACL_XATTR_DEFAULT;
-       size_t size;
-
-       if (!test_opt(sbi, POSIX_ACL))
-               return 0;
-
-       if (type == ACL_TYPE_ACCESS)
-               xname = POSIX_ACL_XATTR_ACCESS;
-
-       size = strlen(xname) + 1;
-       if (list && size <= list_size)
-               memcpy(list, xname, size);
-       return size;
-}
-
-static int f2fs_xattr_get_acl(struct dentry *dentry, const char *name,
-               void *buffer, size_t size, int type)
-{
-       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
-       struct posix_acl *acl;
-       int error;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!test_opt(sbi, POSIX_ACL))
-               return -EOPNOTSUPP;
-
-       acl = f2fs_get_acl(dentry->d_inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (!acl)
-               return -ENODATA;
-       error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
-       return error;
-}
-
-static int f2fs_xattr_set_acl(struct dentry *dentry, const char *name,
-               const void *value, size_t size, int flags, int type)
-{
-       struct f2fs_sb_info *sbi = F2FS_SB(dentry->d_sb);
-       struct inode *inode = dentry->d_inode;
-       struct posix_acl *acl = NULL;
-       int error;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!test_opt(sbi, POSIX_ACL))
-               return -EOPNOTSUPP;
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               if (acl) {
-                       error = posix_acl_valid(acl);
-                       if (error)
-                               goto release_and_out;
-               }
-       } else {
-               acl = NULL;
+       if (default_acl) {
+               error = __f2fs_set_acl(inode, ACL_TYPE_DEFAULT, default_acl,
+                                      ipage);
+               posix_acl_release(default_acl);
+       }
+       if (acl) {
+               if (error)
+                       error = __f2fs_set_acl(inode, ACL_TYPE_ACCESS, acl,
+                                              ipage);
+               posix_acl_release(acl);
        }
 
-       error = f2fs_set_acl(inode, type, acl, NULL);
-
-release_and_out:
-       posix_acl_release(acl);
        return error;
 }
-
-const struct xattr_handler f2fs_xattr_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags = ACL_TYPE_DEFAULT,
-       .list = f2fs_xattr_list_acl,
-       .get = f2fs_xattr_get_acl,
-       .set = f2fs_xattr_set_acl,
-};
-
-const struct xattr_handler f2fs_xattr_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags = ACL_TYPE_ACCESS,
-       .list = f2fs_xattr_list_acl,
-       .get = f2fs_xattr_get_acl,
-       .set = f2fs_xattr_set_acl,
-};
index 49633131e038db76e14d21803538f1701a93d873..e0864651cdc1c09661e9d28c094c79c12603846f 100644 (file)
@@ -37,18 +37,13 @@ struct f2fs_acl_header {
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
 
 extern struct posix_acl *f2fs_get_acl(struct inode *, int);
-extern int f2fs_acl_chmod(struct inode *);
+extern int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 extern int f2fs_init_acl(struct inode *, struct inode *, struct page *);
 #else
 #define f2fs_check_acl NULL
 #define f2fs_get_acl   NULL
 #define f2fs_set_acl   NULL
 
-static inline int f2fs_acl_chmod(struct inode *inode)
-{
-       return 0;
-}
-
 static inline int f2fs_init_acl(struct inode *inode, struct inode *dir,
                                                        struct page *page)
 {
index 0ae558723506e1a8a96f5653444dc11f5a8feb27..2261ccdd0b5f04a37be390f1b28c8703fafa86b4 100644 (file)
 
 static void f2fs_read_end_io(struct bio *bio, int err)
 {
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bvec;
+       int i;
 
-       do {
+       bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
 
-               if (--bvec >= bio->bi_io_vec)
-                       prefetchw(&bvec->bv_page->flags);
-
-               if (unlikely(!uptodate)) {
+               if (!err) {
+                       SetPageUptodate(page);
+               } else {
                        ClearPageUptodate(page);
                        SetPageError(page);
-               } else {
-                       SetPageUptodate(page);
                }
                unlock_page(page);
-       } while (bvec >= bio->bi_io_vec);
-
+       }
        bio_put(bio);
 }
 
 static void f2fs_write_end_io(struct bio *bio, int err)
 {
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
-       struct f2fs_sb_info *sbi = F2FS_SB(bvec->bv_page->mapping->host->i_sb);
+       struct f2fs_sb_info *sbi = F2FS_SB(bio->bi_io_vec->bv_page->mapping->host->i_sb);
+       struct bio_vec *bvec;
+       int i;
 
-       do {
+       bio_for_each_segment_all(bvec, bio, i) {
                struct page *page = bvec->bv_page;
 
-               if (--bvec >= bio->bi_io_vec)
-                       prefetchw(&bvec->bv_page->flags);
-
-               if (unlikely(!uptodate)) {
+               if (unlikely(err)) {
                        SetPageError(page);
                        set_bit(AS_EIO, &page->mapping->flags);
                        set_ckpt_flags(sbi->ckpt, CP_ERROR_FLAG);
@@ -67,7 +60,7 @@ static void f2fs_write_end_io(struct bio *bio, int err)
                }
                end_page_writeback(page);
                dec_page_count(sbi, F2FS_WRITEBACK);
-       } while (bvec >= bio->bi_io_vec);
+       }
 
        if (bio->bi_private)
                complete(bio->bi_private);
@@ -91,7 +84,7 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
        bio = bio_alloc(GFP_NOIO, npages);
 
        bio->bi_bdev = sbi->sb->s_bdev;
-       bio->bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
+       bio->bi_iter.bi_sector = SECTOR_FROM_BLOCK(sbi, blk_addr);
        bio->bi_end_io = is_read ? f2fs_read_end_io : f2fs_write_end_io;
 
        return bio;
index af51a0bd2dee4c267e715d8d39c38b917b115743..fc3c558cb4f3d5a71b8ed03016e838cf5ec84cdf 100644 (file)
@@ -1023,6 +1023,10 @@ static inline int f2fs_readonly(struct super_block *sb)
        return sb->s_flags & MS_RDONLY;
 }
 
+#define get_inode_mode(i) \
+       ((is_inode_flag_set(F2FS_I(i), FI_ACL_MODE)) ? \
+        (F2FS_I(i)->i_acl_mode) : ((i)->i_mode))
+
 /*
  * file.c
  */
index 85e91ca88d5791835d25dffe6fc0932f9640203b..0dfcef53a6ed830e442f8c174ea166b0d1b2eabd 100644 (file)
@@ -382,7 +382,7 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
        __setattr_copy(inode, attr);
 
        if (attr->ia_valid & ATTR_MODE) {
-               err = f2fs_acl_chmod(inode);
+               err = posix_acl_chmod(inode, get_inode_mode(inode));
                if (err || is_inode_flag_set(fi, FI_ACL_MODE)) {
                        inode->i_mode = fi->i_acl_mode;
                        clear_inode_flag(fi, FI_ACL_MODE);
@@ -397,6 +397,7 @@ const struct inode_operations f2fs_file_inode_operations = {
        .getattr        = f2fs_getattr,
        .setattr        = f2fs_setattr,
        .get_acl        = f2fs_get_acl,
+       .set_acl        = f2fs_set_acl,
 #ifdef CONFIG_F2FS_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
index 3d32f2969c5e047f54ffe9aec4b73dc132d9a8ca..397d459e97bf9f1ee2107c1079f02a282a47e5fa 100644 (file)
@@ -501,6 +501,7 @@ const struct inode_operations f2fs_dir_inode_operations = {
        .getattr        = f2fs_getattr,
        .setattr        = f2fs_setattr,
        .get_acl        = f2fs_get_acl,
+       .set_acl        = f2fs_set_acl,
 #ifdef CONFIG_F2FS_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
@@ -527,6 +528,7 @@ const struct inode_operations f2fs_special_inode_operations = {
        .getattr        = f2fs_getattr,
        .setattr        = f2fs_setattr,
        .get_acl        = f2fs_get_acl,
+       .set_acl        = f2fs_set_acl,
 #ifdef CONFIG_F2FS_FS_XATTR
        .setxattr       = generic_setxattr,
        .getxattr       = generic_getxattr,
index b0fb8a27f3da6fe3b810eca732361953aeebc030..89d0422a91a88fea51ecf5935d31c2920545f8a6 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/rwsem.h>
 #include <linux/f2fs_fs.h>
 #include <linux/security.h>
+#include <linux/posix_acl_xattr.h>
 #include "f2fs.h"
 #include "xattr.h"
 
@@ -216,8 +217,8 @@ const struct xattr_handler f2fs_xattr_security_handler = {
 static const struct xattr_handler *f2fs_xattr_handler_map[] = {
        [F2FS_XATTR_INDEX_USER] = &f2fs_xattr_user_handler,
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
-       [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &f2fs_xattr_acl_access_handler,
-       [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &f2fs_xattr_acl_default_handler,
+       [F2FS_XATTR_INDEX_POSIX_ACL_ACCESS] = &posix_acl_access_xattr_handler,
+       [F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT] = &posix_acl_default_xattr_handler,
 #endif
        [F2FS_XATTR_INDEX_TRUSTED] = &f2fs_xattr_trusted_handler,
 #ifdef CONFIG_F2FS_FS_SECURITY
@@ -229,8 +230,8 @@ static const struct xattr_handler *f2fs_xattr_handler_map[] = {
 const struct xattr_handler *f2fs_xattr_handlers[] = {
        &f2fs_xattr_user_handler,
 #ifdef CONFIG_F2FS_FS_POSIX_ACL
-       &f2fs_xattr_acl_access_handler,
-       &f2fs_xattr_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
        &f2fs_xattr_trusted_handler,
 #ifdef CONFIG_F2FS_FS_SECURITY
index 02a08fb88a151c9b38a4e5aabc78decb2f0b4101..b21d9ebdeff39efdf64485116bf53ce17263bb7e 100644 (file)
@@ -108,8 +108,6 @@ struct f2fs_xattr_entry {
 #ifdef CONFIG_F2FS_FS_XATTR
 extern const struct xattr_handler f2fs_xattr_user_handler;
 extern const struct xattr_handler f2fs_xattr_trusted_handler;
-extern const struct xattr_handler f2fs_xattr_acl_access_handler;
-extern const struct xattr_handler f2fs_xattr_acl_default_handler;
 extern const struct xattr_handler f2fs_xattr_advise_handler;
 extern const struct xattr_handler f2fs_xattr_security_handler;
 
index 4a78f981557a4b012919458993506f61fd5187a4..771578b33fb6c7fee9a7c28d01138e4670e07e59 100644 (file)
--- a/fs/file.c
+++ b/fs/file.c
@@ -348,21 +348,16 @@ out:
        return NULL;
 }
 
-static void close_files(struct files_struct * files)
+static struct fdtable *close_files(struct files_struct * files)
 {
-       int i, j;
-       struct fdtable *fdt;
-
-       j = 0;
-
        /*
         * It is safe to dereference the fd table without RCU or
         * ->file_lock because this is the last reference to the
-        * files structure.  But use RCU to shut RCU-lockdep up.
+        * files structure.
         */
-       rcu_read_lock();
-       fdt = files_fdtable(files);
-       rcu_read_unlock();
+       struct fdtable *fdt = rcu_dereference_raw(files->fdt);
+       int i, j = 0;
+
        for (;;) {
                unsigned long set;
                i = j * BITS_PER_LONG;
@@ -381,6 +376,8 @@ static void close_files(struct files_struct * files)
                        set >>= 1;
                }
        }
+
+       return fdt;
 }
 
 struct files_struct *get_files_struct(struct task_struct *task)
@@ -398,14 +395,9 @@ struct files_struct *get_files_struct(struct task_struct *task)
 
 void put_files_struct(struct files_struct *files)
 {
-       struct fdtable *fdt;
-
        if (atomic_dec_and_test(&files->count)) {
-               close_files(files);
-               /* not really needed, since nobody can see us */
-               rcu_read_lock();
-               fdt = files_fdtable(files);
-               rcu_read_unlock();
+               struct fdtable *fdt = close_files(files);
+
                /* free the arrays if they are not embedded */
                if (fdt != &files->fdtab)
                        __free_fdtable(fdt);
@@ -645,16 +637,16 @@ void do_close_on_exec(struct files_struct *files)
        spin_unlock(&files->file_lock);
 }
 
-struct file *fget(unsigned int fd)
+static struct file *__fget(unsigned int fd, fmode_t mask)
 {
-       struct file *file;
        struct files_struct *files = current->files;
+       struct file *file;
 
        rcu_read_lock();
        file = fcheck_files(files, fd);
        if (file) {
                /* File object ref couldn't be taken */
-               if (file->f_mode & FMODE_PATH ||
+               if ((file->f_mode & mask) ||
                    !atomic_long_inc_not_zero(&file->f_count))
                        file = NULL;
        }
@@ -663,25 +655,16 @@ struct file *fget(unsigned int fd)
        return file;
 }
 
+struct file *fget(unsigned int fd)
+{
+       return __fget(fd, FMODE_PATH);
+}
 EXPORT_SYMBOL(fget);
 
 struct file *fget_raw(unsigned int fd)
 {
-       struct file *file;
-       struct files_struct *files = current->files;
-
-       rcu_read_lock();
-       file = fcheck_files(files, fd);
-       if (file) {
-               /* File object ref couldn't be taken */
-               if (!atomic_long_inc_not_zero(&file->f_count))
-                       file = NULL;
-       }
-       rcu_read_unlock();
-
-       return file;
+       return __fget(fd, 0);
 }
-
 EXPORT_SYMBOL(fget_raw);
 
 /*
@@ -700,56 +683,33 @@ EXPORT_SYMBOL(fget_raw);
  * The fput_needed flag returned by fget_light should be passed to the
  * corresponding fput_light.
  */
-struct file *fget_light(unsigned int fd, int *fput_needed)
+struct file *__fget_light(unsigned int fd, fmode_t mask, int *fput_needed)
 {
-       struct file *file;
        struct files_struct *files = current->files;
+       struct file *file;
 
        *fput_needed = 0;
        if (atomic_read(&files->count) == 1) {
-               file = fcheck_files(files, fd);
-               if (file && (file->f_mode & FMODE_PATH))
+               file = __fcheck_files(files, fd);
+               if (file && (file->f_mode & mask))
                        file = NULL;
        } else {
-               rcu_read_lock();
-               file = fcheck_files(files, fd);
-               if (file) {
-                       if (!(file->f_mode & FMODE_PATH) &&
-                           atomic_long_inc_not_zero(&file->f_count))
-                               *fput_needed = 1;
-                       else
-                               /* Didn't get the reference, someone's freed */
-                               file = NULL;
-               }
-               rcu_read_unlock();
+               file = __fget(fd, mask);
+               if (file)
+                       *fput_needed = 1;
        }
 
        return file;
 }
+struct file *fget_light(unsigned int fd, int *fput_needed)
+{
+       return __fget_light(fd, FMODE_PATH, fput_needed);
+}
 EXPORT_SYMBOL(fget_light);
 
 struct file *fget_raw_light(unsigned int fd, int *fput_needed)
 {
-       struct file *file;
-       struct files_struct *files = current->files;
-
-       *fput_needed = 0;
-       if (atomic_read(&files->count) == 1) {
-               file = fcheck_files(files, fd);
-       } else {
-               rcu_read_lock();
-               file = fcheck_files(files, fd);
-               if (file) {
-                       if (atomic_long_inc_not_zero(&file->f_count))
-                               *fput_needed = 1;
-                       else
-                               /* Didn't get the reference, someone's freed */
-                               file = NULL;
-               }
-               rcu_read_unlock();
-       }
-
-       return file;
+       return __fget_light(fd, 0, fput_needed);
 }
 
 void set_close_on_exec(unsigned int fd, int flag)
index 74f6ca50050447832b4fbe41d8ee2f2a8bf4fa1f..77bcc303c3aeb9214ba4b13098da14fb8bcbe20b 100644 (file)
@@ -2727,6 +2727,9 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
        inode = file->f_mapping->host;
        i_size = i_size_read(inode);
 
+       if ((rw == READ) && (offset > i_size))
+               return 0;
+
        /* optimization for short read */
        if (async_dio && rw != WRITE && offset + count > i_size) {
                if (offset >= i_size)
diff --git a/fs/generic_acl.c b/fs/generic_acl.c
deleted file mode 100644 (file)
index b3f3676..0000000
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * (C) 2005 Andreas Gruenbacher <agruen@suse.de>
- *
- * This file is released under the GPL.
- *
- * Generic ACL support for in-memory filesystems.
- */
-
-#include <linux/sched.h>
-#include <linux/gfp.h>
-#include <linux/fs.h>
-#include <linux/generic_acl.h>
-#include <linux/posix_acl.h>
-#include <linux/posix_acl_xattr.h>
-
-
-static size_t
-generic_acl_list(struct dentry *dentry, char *list, size_t list_size,
-               const char *name, size_t name_len, int type)
-{
-       struct posix_acl *acl;
-       const char *xname;
-       size_t size;
-
-       acl = get_cached_acl(dentry->d_inode, type);
-       if (!acl)
-               return 0;
-       posix_acl_release(acl);
-
-       switch (type) {
-       case ACL_TYPE_ACCESS:
-               xname = POSIX_ACL_XATTR_ACCESS;
-               break;
-       case ACL_TYPE_DEFAULT:
-               xname = POSIX_ACL_XATTR_DEFAULT;
-               break;
-       default:
-               return 0;
-       }
-       size = strlen(xname) + 1;
-       if (list && size <= list_size)
-               memcpy(list, xname, size);
-       return size;
-}
-
-static int
-generic_acl_get(struct dentry *dentry, const char *name, void *buffer,
-                    size_t size, int type)
-{
-       struct posix_acl *acl;
-       int error;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-
-       acl = get_cached_acl(dentry->d_inode, type);
-       if (!acl)
-               return -ENODATA;
-       error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
-       return error;
-}
-
-static int
-generic_acl_set(struct dentry *dentry, const char *name, const void *value,
-                    size_t size, int flags, int type)
-{
-       struct inode *inode = dentry->d_inode;
-       struct posix_acl *acl = NULL;
-       int error;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-       }
-       if (acl) {
-               error = posix_acl_valid(acl);
-               if (error)
-                       goto failed;
-               switch (type) {
-               case ACL_TYPE_ACCESS:
-                       error = posix_acl_equiv_mode(acl, &inode->i_mode);
-                       if (error < 0)
-                               goto failed;
-                       inode->i_ctime = CURRENT_TIME;
-                       if (error == 0) {
-                               posix_acl_release(acl);
-                               acl = NULL;
-                       }
-                       break;
-               case ACL_TYPE_DEFAULT:
-                       if (!S_ISDIR(inode->i_mode)) {
-                               error = -EINVAL;
-                               goto failed;
-                       }
-                       break;
-               }
-       }
-       set_cached_acl(inode, type, acl);
-       error = 0;
-failed:
-       posix_acl_release(acl);
-       return error;
-}
-
-/**
- * generic_acl_init  -  Take care of acl inheritance at @inode create time
- *
- * Files created inside a directory with a default ACL inherit the
- * directory's default ACL.
- */
-int
-generic_acl_init(struct inode *inode, struct inode *dir)
-{
-       struct posix_acl *acl = NULL;
-       int error;
-
-       if (!S_ISLNK(inode->i_mode))
-               acl = get_cached_acl(dir, ACL_TYPE_DEFAULT);
-       if (acl) {
-               if (S_ISDIR(inode->i_mode))
-                       set_cached_acl(inode, ACL_TYPE_DEFAULT, acl);
-               error = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
-               if (error < 0)
-                       return error;
-               if (error > 0)
-                       set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
-       } else {
-               inode->i_mode &= ~current_umask();
-       }
-       error = 0;
-
-       posix_acl_release(acl);
-       return error;
-}
-
-/**
- * generic_acl_chmod  -  change the access acl of @inode upon chmod()
- *
- * A chmod also changes the permissions of the owner, group/mask, and
- * other ACL entries.
- */
-int
-generic_acl_chmod(struct inode *inode)
-{
-       struct posix_acl *acl;
-       int error = 0;
-
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-       acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
-       if (acl) {
-               error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
-               if (error)
-                       return error;
-               set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
-               posix_acl_release(acl);
-       }
-       return error;
-}
-
-const struct xattr_handler generic_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags  = ACL_TYPE_ACCESS,
-       .list   = generic_acl_list,
-       .get    = generic_acl_get,
-       .set    = generic_acl_set,
-};
-
-const struct xattr_handler generic_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags  = ACL_TYPE_DEFAULT,
-       .list   = generic_acl_list,
-       .get    = generic_acl_get,
-       .set    = generic_acl_set,
-};
index f69ac0af5496cd456bf6df4d0c932747b6767779..ba9456685f47d761d51afae92a55328e2d54d78a 100644 (file)
@@ -49,10 +49,6 @@ struct posix_acl *gfs2_get_acl(struct inode *inode, int type)
        if (!ip->i_eattr)
                return NULL;
 
-       acl = get_cached_acl(&ip->i_inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
-
        name = gfs2_acl_name(type);
        if (name == NULL)
                return ERR_PTR(-EINVAL);
@@ -80,7 +76,7 @@ static int gfs2_set_mode(struct inode *inode, umode_t mode)
        return error;
 }
 
-static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl)
+int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        int error;
        int len;
@@ -88,219 +84,49 @@ static int gfs2_acl_set(struct inode *inode, int type, struct posix_acl *acl)
        const char *name = gfs2_acl_name(type);
 
        BUG_ON(name == NULL);
-       len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0);
-       if (len == 0)
-               return 0;
-       data = kmalloc(len, GFP_NOFS);
-       if (data == NULL)
-               return -ENOMEM;
-       error = posix_acl_to_xattr(&init_user_ns, acl, data, len);
-       if (error < 0)
-               goto out;
-       error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS);
-       if (!error)
-               set_cached_acl(inode, type, acl);
-out:
-       kfree(data);
-       return error;
-}
-
-int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode)
-{
-       struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
-       struct posix_acl *acl;
-       umode_t mode = inode->i_mode;
-       int error = 0;
-
-       if (!sdp->sd_args.ar_posix_acl)
-               return 0;
-       if (S_ISLNK(inode->i_mode))
-               return 0;
-
-       acl = gfs2_get_acl(&dip->i_inode, ACL_TYPE_DEFAULT);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (!acl) {
-               mode &= ~current_umask();
-               return gfs2_set_mode(inode, mode);
-       }
-
-       if (S_ISDIR(inode->i_mode)) {
-               error = gfs2_acl_set(inode, ACL_TYPE_DEFAULT, acl);
-               if (error)
-                       goto out;
-       }
-
-       error = posix_acl_create(&acl, GFP_NOFS, &mode);
-       if (error < 0)
-               return error;
 
-       if (error == 0)
-               goto munge;
-
-       error = gfs2_acl_set(inode, ACL_TYPE_ACCESS, acl);
-       if (error)
-               goto out;
-munge:
-       error = gfs2_set_mode(inode, mode);
-out:
-       posix_acl_release(acl);
-       return error;
-}
-
-int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr)
-{
-       struct inode *inode = &ip->i_inode;
-       struct posix_acl *acl;
-       char *data;
-       unsigned int len;
-       int error;
-
-       acl = gfs2_get_acl(&ip->i_inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (!acl)
-               return gfs2_setattr_simple(inode, attr);
-
-       error = posix_acl_chmod(&acl, GFP_NOFS, attr->ia_mode);
-       if (error)
-               return error;
-
-       len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0);
-       data = kmalloc(len, GFP_NOFS);
-       error = -ENOMEM;
-       if (data == NULL)
-               goto out;
-       posix_acl_to_xattr(&init_user_ns, acl, data, len);
-       error = gfs2_xattr_acl_chmod(ip, attr, data);
-       kfree(data);
-       set_cached_acl(&ip->i_inode, ACL_TYPE_ACCESS, acl);
-
-out:
-       posix_acl_release(acl);
-       return error;
-}
-
-static int gfs2_acl_type(const char *name)
-{
-       if (strcmp(name, GFS2_POSIX_ACL_ACCESS) == 0)
-               return ACL_TYPE_ACCESS;
-       if (strcmp(name, GFS2_POSIX_ACL_DEFAULT) == 0)
-               return ACL_TYPE_DEFAULT;
-       return -EINVAL;
-}
-
-static int gfs2_xattr_system_get(struct dentry *dentry, const char *name,
-                                void *buffer, size_t size, int xtype)
-{
-       struct inode *inode = dentry->d_inode;
-       struct gfs2_sbd *sdp = GFS2_SB(inode);
-       struct posix_acl *acl;
-       int type;
-       int error;
-
-       if (!sdp->sd_args.ar_posix_acl)
-               return -EOPNOTSUPP;
-
-       type = gfs2_acl_type(name);
-       if (type < 0)
-               return type;
-
-       acl = gfs2_get_acl(inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl == NULL)
-               return -ENODATA;
-
-       error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
-       return error;
-}
-
-static int gfs2_xattr_system_set(struct dentry *dentry, const char *name,
-                                const void *value, size_t size, int flags,
-                                int xtype)
-{
-       struct inode *inode = dentry->d_inode;
-       struct gfs2_sbd *sdp = GFS2_SB(inode);
-       struct posix_acl *acl = NULL;
-       int error = 0, type;
-
-       if (!sdp->sd_args.ar_posix_acl)
-               return -EOPNOTSUPP;
-
-       type = gfs2_acl_type(name);
-       if (type < 0)
-               return type;
-       if (flags & XATTR_CREATE)
-               return -EINVAL;
-       if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
-               return value ? -EACCES : 0;
-       if (!uid_eq(current_fsuid(), inode->i_uid) && !capable(CAP_FOWNER))
-               return -EPERM;
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
-       if (!value)
-               goto set_acl;
-
-       acl = posix_acl_from_xattr(&init_user_ns, value, size);
-       if (!acl) {
-               /*
-                * acl_set_file(3) may request that we set default ACLs with
-                * zero length -- defend (gracefully) against that here.
-                */
-               goto out;
-       }
-       if (IS_ERR(acl)) {
-               error = PTR_ERR(acl);
-               goto out;
-       }
-
-       error = posix_acl_valid(acl);
-       if (error)
-               goto out_release;
-
-       error = -EINVAL;
        if (acl->a_count > GFS2_ACL_MAX_ENTRIES)
-               goto out_release;
+               return -EINVAL;
 
        if (type == ACL_TYPE_ACCESS) {
                umode_t mode = inode->i_mode;
+
                error = posix_acl_equiv_mode(acl, &mode);
+               if (error < 0)
+                       return error;
 
-               if (error <= 0) {
-                       posix_acl_release(acl);
+               if (error == 0)
                        acl = NULL;
 
-                       if (error < 0)
-                               return error;
-               }
-
                error = gfs2_set_mode(inode, mode);
                if (error)
-                       goto out_release;
+                       return error;
        }
 
-set_acl:
-       error = __gfs2_xattr_set(inode, name, value, size, 0, GFS2_EATYPE_SYS);
-       if (!error) {
-               if (acl)
-                       set_cached_acl(inode, type, acl);
-               else
-                       forget_cached_acl(inode, type);
+       if (acl) {
+               len = posix_acl_to_xattr(&init_user_ns, acl, NULL, 0);
+               if (len == 0)
+                       return 0;
+               data = kmalloc(len, GFP_NOFS);
+               if (data == NULL)
+                       return -ENOMEM;
+               error = posix_acl_to_xattr(&init_user_ns, acl, data, len);
+               if (error < 0)
+                       goto out;
+       } else {
+               data = NULL;
+               len = 0;
        }
-out_release:
-       posix_acl_release(acl);
+
+       error = __gfs2_xattr_set(inode, name, data, len, 0, GFS2_EATYPE_SYS);
+       if (error)
+               goto out;
+
+       if (acl)
+               set_cached_acl(inode, type, acl);
+       else
+               forget_cached_acl(inode, type);
 out:
+       kfree(data);
        return error;
 }
-
-const struct xattr_handler gfs2_xattr_system_handler = {
-       .prefix = XATTR_SYSTEM_PREFIX,
-       .flags  = GFS2_EATYPE_SYS,
-       .get    = gfs2_xattr_system_get,
-       .set    = gfs2_xattr_system_set,
-};
-
index 0da38dc7efec24959a1ad656ff2cda8b561db1e0..301260c999ba994bbcab3af270962cd93058dcd9 100644 (file)
@@ -17,8 +17,6 @@
 #define GFS2_ACL_MAX_ENTRIES           25
 
 extern struct posix_acl *gfs2_get_acl(struct inode *inode, int type);
-extern int gfs2_acl_create(struct gfs2_inode *dip, struct inode *inode);
-extern int gfs2_acl_chmod(struct gfs2_inode *ip, struct iattr *attr);
-extern const struct xattr_handler gfs2_xattr_system_handler;
+extern int gfs2_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 
 #endif /* __ACL_DOT_H__ */
index 890588c7fb33f79208c3f4203eaf88dadeba8772..5c524180c98e85a50e8e4c63ce233f71ff82ea39 100644 (file)
@@ -571,6 +571,7 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
                             unsigned int size, int excl, int *opened)
 {
        const struct qstr *name = &dentry->d_name;
+       struct posix_acl *default_acl, *acl;
        struct gfs2_holder ghs[2];
        struct inode *inode = NULL;
        struct gfs2_inode *dip = GFS2_I(dir), *ip;
@@ -633,10 +634,14 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
        if (!inode)
                goto fail_gunlock;
 
+       error = posix_acl_create(dir, &mode, &default_acl, &acl);
+       if (error)
+               goto fail_free_vfs_inode;
+
        ip = GFS2_I(inode);
        error = gfs2_rs_alloc(ip);
        if (error)
-               goto fail_free_inode;
+               goto fail_free_acls;
 
        inode->i_mode = mode;
        set_nlink(inode, S_ISDIR(mode) ? 2 : 1);
@@ -704,7 +709,16 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
        gfs2_set_iop(inode);
        insert_inode_hash(inode);
 
-       error = gfs2_acl_create(dip, inode);
+       if (default_acl) {
+               error = gfs2_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+               posix_acl_release(default_acl);
+       }
+       if (acl) {
+               if (!error)
+                       error = gfs2_set_acl(inode, acl, ACL_TYPE_ACCESS);
+               posix_acl_release(acl);
+       }
+
        if (error)
                goto fail_gunlock3;
 
@@ -738,6 +752,12 @@ fail_free_inode:
        if (ip->i_gl)
                gfs2_glock_put(ip->i_gl);
        gfs2_rs_delete(ip, NULL);
+fail_free_acls:
+       if (default_acl)
+               posix_acl_release(default_acl);
+       if (acl)
+               posix_acl_release(acl);
+fail_free_vfs_inode:
        free_inode_nonrcu(inode);
        inode = NULL;
 fail_gunlock:
@@ -1716,10 +1736,11 @@ static int gfs2_setattr(struct dentry *dentry, struct iattr *attr)
                error = gfs2_setattr_size(inode, attr->ia_size);
        else if (attr->ia_valid & (ATTR_UID | ATTR_GID))
                error = setattr_chown(inode, attr);
-       else if ((attr->ia_valid & ATTR_MODE) && IS_POSIXACL(inode))
-               error = gfs2_acl_chmod(ip, attr);
-       else
+       else {
                error = gfs2_setattr_simple(inode, attr);
+               if (!error && attr->ia_valid & ATTR_MODE)
+                       error = posix_acl_chmod(inode, inode->i_mode);
+       }
 
 out:
        if (!error)
@@ -1879,6 +1900,7 @@ const struct inode_operations gfs2_file_iops = {
        .removexattr = gfs2_removexattr,
        .fiemap = gfs2_fiemap,
        .get_acl = gfs2_get_acl,
+       .set_acl = gfs2_set_acl,
 };
 
 const struct inode_operations gfs2_dir_iops = {
@@ -1900,6 +1922,7 @@ const struct inode_operations gfs2_dir_iops = {
        .removexattr = gfs2_removexattr,
        .fiemap = gfs2_fiemap,
        .get_acl = gfs2_get_acl,
+       .set_acl = gfs2_set_acl,
        .atomic_open = gfs2_atomic_open,
 };
 
@@ -1915,6 +1938,5 @@ const struct inode_operations gfs2_symlink_iops = {
        .listxattr = gfs2_listxattr,
        .removexattr = gfs2_removexattr,
        .fiemap = gfs2_fiemap,
-       .get_acl = gfs2_get_acl,
 };
 
index 58f06400b7b8dcece9597b51b05ebf9ebc092396..76693793ceddfe7f936c360a6c3494d1882a849a 100644 (file)
@@ -273,7 +273,7 @@ static struct bio *gfs2_log_alloc_bio(struct gfs2_sbd *sdp, u64 blkno)
                nrvecs = max(nrvecs/2, 1U);
        }
 
-       bio->bi_sector = blkno * (sb->s_blocksize >> 9);
+       bio->bi_iter.bi_sector = blkno * (sb->s_blocksize >> 9);
        bio->bi_bdev = sb->s_bdev;
        bio->bi_end_io = gfs2_end_log_write;
        bio->bi_private = sdp;
index 1e712b566d76a74435b4d2faa5417956815cec78..c6872d09561a2d53c8e57374eb700f4fb578ae78 100644 (file)
@@ -238,7 +238,7 @@ static int gfs2_read_super(struct gfs2_sbd *sdp, sector_t sector, int silent)
        lock_page(page);
 
        bio = bio_alloc(GFP_NOFS, 1);
-       bio->bi_sector = sector * (sb->s_blocksize >> 9);
+       bio->bi_iter.bi_sector = sector * (sb->s_blocksize >> 9);
        bio->bi_bdev = sb->s_bdev;
        bio_add_page(bio, page, PAGE_SIZE, 0);
 
index 8c6a6f6bdba978f9c3b37703a79d4c409516557b..0b81f783f78724293b174cd997d7f7b7321468b9 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/buffer_head.h>
 #include <linux/xattr.h>
 #include <linux/gfs2_ondisk.h>
+#include <linux/posix_acl_xattr.h>
 #include <asm/uaccess.h>
 
 #include "gfs2.h"
@@ -1500,7 +1501,8 @@ static const struct xattr_handler gfs2_xattr_security_handler = {
 const struct xattr_handler *gfs2_xattr_handlers[] = {
        &gfs2_xattr_user_handler,
        &gfs2_xattr_security_handler,
-       &gfs2_xattr_system_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
        NULL,
 };
 
index 07c0d4947527f33f46b433686e4a996dbb4aa984..95c8ed9ec17f7006940cf9c0fccdfe3c07a7868f 100644 (file)
 
 /* posix_acl.c */
 struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type);
-extern int hfsplus_posix_acl_chmod(struct inode *);
+int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
+               int type);
 extern int hfsplus_init_posix_acl(struct inode *, struct inode *);
 
 #else  /* CONFIG_HFSPLUS_FS_POSIX_ACL */
 #define hfsplus_get_posix_acl NULL
-
-static inline int hfsplus_posix_acl_chmod(struct inode *inode)
-{
-       return 0;
-}
+#define hfsplus_set_posix_acl NULL
 
 static inline int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
 {
index 4a4fea0026735c8fb365d031c57165888e9bb079..9ee62985e739eba797e01318278712be6ee0dfac 100644 (file)
@@ -532,6 +532,7 @@ const struct inode_operations hfsplus_dir_inode_operations = {
        .removexattr            = hfsplus_removexattr,
 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
        .get_acl                = hfsplus_get_posix_acl,
+       .set_acl                = hfsplus_set_posix_acl,
 #endif
 };
 
index 3ebda928229cb375486da2a05f15e860b5380fbc..4551cbd6bd43aaaebbde666c22c726c76112ab6e 100644 (file)
@@ -261,7 +261,7 @@ static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
        mark_inode_dirty(inode);
 
        if (attr->ia_valid & ATTR_MODE) {
-               error = hfsplus_posix_acl_chmod(inode);
+               error = posix_acl_chmod(inode, inode->i_mode);
                if (unlikely(error))
                        return error;
        }
@@ -334,6 +334,7 @@ static const struct inode_operations hfsplus_file_inode_operations = {
        .removexattr    = hfsplus_removexattr,
 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
        .get_acl        = hfsplus_get_posix_acl,
+       .set_acl        = hfsplus_set_posix_acl,
 #endif
 };
 
index b609cc14c72e03c21063abbda72372c4ef94b1c7..df0c9af68d05ef0df5a127d53562677bc8a2d882 100644 (file)
@@ -17,9 +17,7 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
        char *value = NULL;
        ssize_t size;
 
-       acl = get_cached_acl(inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
+       hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
 
        switch (type) {
        case ACL_TYPE_ACCESS:
@@ -56,17 +54,15 @@ struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
        return acl;
 }
 
-static int hfsplus_set_posix_acl(struct inode *inode,
-                                       int type,
-                                       struct posix_acl *acl)
+int hfsplus_set_posix_acl(struct inode *inode, struct posix_acl *acl,
+               int type)
 {
        int err;
        char *xattr_name;
        size_t size = 0;
        char *value = NULL;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
+       hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
 
        switch (type) {
        case ACL_TYPE_ACCESS:
@@ -115,7 +111,7 @@ end_set_acl:
 int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
 {
        int err = 0;
-       struct posix_acl *acl = NULL;
+       struct posix_acl *default_acl, *acl;
 
        hfs_dbg(ACL_MOD,
                "[%s]: ino %lu, dir->ino %lu\n",
@@ -124,151 +120,21 @@ int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
        if (S_ISLNK(inode->i_mode))
                return 0;
 
-       acl = hfsplus_get_posix_acl(dir, ACL_TYPE_DEFAULT);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-
-       if (acl) {
-               if (S_ISDIR(inode->i_mode)) {
-                       err = hfsplus_set_posix_acl(inode,
-                                                       ACL_TYPE_DEFAULT,
-                                                       acl);
-                       if (unlikely(err))
-                               goto init_acl_cleanup;
-               }
-
-               err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
-               if (unlikely(err < 0))
-                       return err;
-
-               if (err > 0)
-                       err = hfsplus_set_posix_acl(inode,
-                                                       ACL_TYPE_ACCESS,
-                                                       acl);
-       } else
-               inode->i_mode &= ~current_umask();
-
-init_acl_cleanup:
-       posix_acl_release(acl);
-       return err;
-}
-
-int hfsplus_posix_acl_chmod(struct inode *inode)
-{
-       int err;
-       struct posix_acl *acl;
-
-       hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
-
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
-       acl = hfsplus_get_posix_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
-
-       err = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
-       if (unlikely(err))
+       err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+       if (err)
                return err;
 
-       err = hfsplus_set_posix_acl(inode, ACL_TYPE_ACCESS, acl);
-       posix_acl_release(acl);
-       return err;
-}
-
-static int hfsplus_xattr_get_posix_acl(struct dentry *dentry,
-                                       const char *name,
-                                       void *buffer,
-                                       size_t size,
-                                       int type)
-{
-       int err = 0;
-       struct posix_acl *acl;
-
-       hfs_dbg(ACL_MOD,
-               "[%s]: ino %lu, buffer %p, size %zu, type %#x\n",
-               __func__, dentry->d_inode->i_ino, buffer, size, type);
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-
-       acl = hfsplus_get_posix_acl(dentry->d_inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl == NULL)
-               return -ENODATA;
-
-       err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
-       return err;
-}
-
-static int hfsplus_xattr_set_posix_acl(struct dentry *dentry,
-                                       const char *name,
-                                       const void *value,
-                                       size_t size,
-                                       int flags,
-                                       int type)
-{
-       int err = 0;
-       struct inode *inode = dentry->d_inode;
-       struct posix_acl *acl = NULL;
-
-       hfs_dbg(ACL_MOD,
-               "[%s]: ino %lu, value %p, size %zu, flags %#x, type %#x\n",
-               __func__, inode->i_ino, value, size, flags, type);
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               else if (acl) {
-                       err = posix_acl_valid(acl);
-                       if (err)
-                               goto end_xattr_set_acl;
-               }
+       if (default_acl) {
+               err = hfsplus_set_posix_acl(inode, default_acl,
+                                           ACL_TYPE_DEFAULT);
+               posix_acl_release(default_acl);
        }
 
-       err = hfsplus_set_posix_acl(inode, type, acl);
-
-end_xattr_set_acl:
-       posix_acl_release(acl);
+       if (acl) {
+               if (!err)
+                       err = hfsplus_set_posix_acl(inode, acl,
+                                                   ACL_TYPE_ACCESS);
+               posix_acl_release(acl);
+       }
        return err;
 }
-
-static size_t hfsplus_xattr_list_posix_acl(struct dentry *dentry,
-                                               char *list,
-                                               size_t list_size,
-                                               const char *name,
-                                               size_t name_len,
-                                               int type)
-{
-       /*
-        * This method is not used.
-        * It is used hfsplus_listxattr() instead of generic_listxattr().
-        */
-       return -EOPNOTSUPP;
-}
-
-const struct xattr_handler hfsplus_xattr_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags  = ACL_TYPE_ACCESS,
-       .list   = hfsplus_xattr_list_posix_acl,
-       .get    = hfsplus_xattr_get_posix_acl,
-       .set    = hfsplus_xattr_set_posix_acl,
-};
-
-const struct xattr_handler hfsplus_xattr_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags  = ACL_TYPE_DEFAULT,
-       .list   = hfsplus_xattr_list_posix_acl,
-       .get    = hfsplus_xattr_get_posix_acl,
-       .set    = hfsplus_xattr_set_posix_acl,
-};
index e9a97a0d431480616043410a51567730bebafda3..3f999649587ff8185ebd326c3672acee83542de4 100644 (file)
@@ -63,7 +63,7 @@ int hfsplus_submit_bio(struct super_block *sb, sector_t sector,
        sector &= ~((io_size >> HFSPLUS_SECTOR_SHIFT) - 1);
 
        bio = bio_alloc(GFP_NOIO, 1);
-       bio->bi_sector = sector;
+       bio->bi_iter.bi_sector = sector;
        bio->bi_bdev = sb->s_bdev;
 
        if (!(rw & WRITE) && data)
index 3c6136f98c737a8d0dc58f2a0cf41712e381ae92..0b4a5c9b93c44ad415f9378c3ec1e3914761c6ef 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include "hfsplus_fs.h"
+#include <linux/posix_acl_xattr.h>
 #include "xattr.h"
 #include "acl.h"
 
@@ -15,8 +16,8 @@ const struct xattr_handler *hfsplus_xattr_handlers[] = {
        &hfsplus_xattr_user_handler,
        &hfsplus_xattr_trusted_handler,
 #ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
-       &hfsplus_xattr_acl_access_handler,
-       &hfsplus_xattr_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
        &hfsplus_xattr_security_handler,
        NULL
@@ -51,82 +52,6 @@ static inline int is_known_namespace(const char *name)
        return true;
 }
 
-static int can_set_system_xattr(struct inode *inode, const char *name,
-                               const void *value, size_t size)
-{
-#ifdef CONFIG_HFSPLUS_FS_POSIX_ACL
-       struct posix_acl *acl;
-       int err;
-
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-
-       /*
-        * POSIX_ACL_XATTR_ACCESS is tied to i_mode
-        */
-       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               if (acl) {
-                       err = posix_acl_equiv_mode(acl, &inode->i_mode);
-                       posix_acl_release(acl);
-                       if (err < 0)
-                               return err;
-                       mark_inode_dirty(inode);
-               }
-               /*
-                * We're changing the ACL.  Get rid of the cached one
-                */
-               forget_cached_acl(inode, ACL_TYPE_ACCESS);
-
-               return 0;
-       } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               posix_acl_release(acl);
-
-               /*
-                * We're changing the default ACL.  Get rid of the cached one
-                */
-               forget_cached_acl(inode, ACL_TYPE_DEFAULT);
-
-               return 0;
-       }
-#endif /* CONFIG_HFSPLUS_FS_POSIX_ACL */
-       return -EOPNOTSUPP;
-}
-
-static int can_set_xattr(struct inode *inode, const char *name,
-                               const void *value, size_t value_len)
-{
-       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               return can_set_system_xattr(inode, name, value, value_len);
-
-       if (!strncmp(name, XATTR_MAC_OSX_PREFIX, XATTR_MAC_OSX_PREFIX_LEN)) {
-               /*
-                * This makes sure that we aren't trying to set an
-                * attribute in a different namespace by prefixing it
-                * with "osx."
-                */
-               if (is_known_namespace(name + XATTR_MAC_OSX_PREFIX_LEN))
-                       return -EOPNOTSUPP;
-
-               return 0;
-       }
-
-       /*
-        * Don't allow setting an attribute in an unknown namespace.
-        */
-       if (strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) &&
-           strncmp(name, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) &&
-           strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN))
-               return -EOPNOTSUPP;
-
-       return 0;
-}
-
 static void hfsplus_init_header_node(struct inode *attr_file,
                                        u32 clump_size,
                                        char *buf, u16 node_size)
@@ -349,10 +274,6 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
                                HFSPLUS_IS_RSRC(inode))
                return -EOPNOTSUPP;
 
-       err = can_set_xattr(inode, name, value, size);
-       if (err)
-               return err;
-
        if (strncmp(name, XATTR_MAC_OSX_PREFIX,
                                XATTR_MAC_OSX_PREFIX_LEN) == 0)
                name += XATTR_MAC_OSX_PREFIX_LEN;
@@ -840,10 +761,6 @@ int hfsplus_removexattr(struct dentry *dentry, const char *name)
        if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
                return -EOPNOTSUPP;
 
-       err = can_set_xattr(inode, name, NULL, 0);
-       if (err)
-               return err;
-
        if (strncmp(name, XATTR_MAC_OSX_PREFIX,
                                XATTR_MAC_OSX_PREFIX_LEN) == 0)
                name += XATTR_MAC_OSX_PREFIX_LEN;
@@ -940,6 +857,9 @@ static int hfsplus_osx_setxattr(struct dentry *dentry, const char *name,
        if (len > HFSPLUS_ATTR_MAX_STRLEN)
                return -EOPNOTSUPP;
 
+       if (is_known_namespace(name))
+               return -EOPNOTSUPP;
+
        strcpy(xattr_name, XATTR_MAC_OSX_PREFIX);
        strcpy(xattr_name + XATTR_MAC_OSX_PREFIX_LEN, name);
 
index 841b5698c0fc4b5375c8d5e153fea62bdc931da9..9e214490c313f6b61204db43e7317f2aac086e5c 100644 (file)
@@ -14,8 +14,6 @@
 extern const struct xattr_handler hfsplus_xattr_osx_handler;
 extern const struct xattr_handler hfsplus_xattr_user_handler;
 extern const struct xattr_handler hfsplus_xattr_trusted_handler;
-extern const struct xattr_handler hfsplus_xattr_acl_access_handler;
-extern const struct xattr_handler hfsplus_xattr_acl_default_handler;
 extern const struct xattr_handler hfsplus_xattr_security_handler;
 
 extern const struct xattr_handler *hfsplus_xattr_handlers[];
index 223283c301116f3d8d88cb70cf30aa030a54c456..009ec0b5993da879846ba7a733864116684026ca 100644 (file)
@@ -178,10 +178,6 @@ struct posix_acl *jffs2_get_acl(struct inode *inode, int type)
        char *value = NULL;
        int rc, xprefix;
 
-       acl = get_cached_acl(inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                xprefix = JFFS2_XPREFIX_ACL_ACCESS;
@@ -232,13 +228,10 @@ static int __jffs2_set_acl(struct inode *inode, int xprefix, struct posix_acl *a
        return rc;
 }
 
-static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        int rc, xprefix;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                xprefix = JFFS2_XPREFIX_ACL_ACCESS;
@@ -277,30 +270,21 @@ static int jffs2_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 
 int jffs2_init_acl_pre(struct inode *dir_i, struct inode *inode, umode_t *i_mode)
 {
-       struct posix_acl *acl;
+       struct posix_acl *default_acl, *acl;
        int rc;
 
        cache_no_acl(inode);
 
-       if (S_ISLNK(*i_mode))
-               return 0;       /* Symlink always has no-ACL */
-
-       acl = jffs2_get_acl(dir_i, ACL_TYPE_DEFAULT);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-
-       if (!acl) {
-               *i_mode &= ~current_umask();
-       } else {
-               if (S_ISDIR(*i_mode))
-                       set_cached_acl(inode, ACL_TYPE_DEFAULT, acl);
-
-               rc = posix_acl_create(&acl, GFP_KERNEL, i_mode);
-               if (rc < 0)
-                       return rc;
-               if (rc > 0)
-                       set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
+       rc = posix_acl_create(dir_i, i_mode, &default_acl, &acl);
+       if (rc)
+               return rc;
 
+       if (default_acl) {
+               set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl);
+               posix_acl_release(default_acl);
+       }
+       if (acl) {
+               set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
                posix_acl_release(acl);
        }
        return 0;
@@ -324,106 +308,3 @@ int jffs2_init_acl_post(struct inode *inode)
 
        return 0;
 }
-
-int jffs2_acl_chmod(struct inode *inode)
-{
-       struct posix_acl *acl;
-       int rc;
-
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-       acl = jffs2_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
-       rc = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
-       if (rc)
-               return rc;
-       rc = jffs2_set_acl(inode, ACL_TYPE_ACCESS, acl);
-       posix_acl_release(acl);
-       return rc;
-}
-
-static size_t jffs2_acl_access_listxattr(struct dentry *dentry, char *list,
-               size_t list_size, const char *name, size_t name_len, int type)
-{
-       const int retlen = sizeof(POSIX_ACL_XATTR_ACCESS);
-
-       if (list && retlen <= list_size)
-               strcpy(list, POSIX_ACL_XATTR_ACCESS);
-       return retlen;
-}
-
-static size_t jffs2_acl_default_listxattr(struct dentry *dentry, char *list,
-               size_t list_size, const char *name, size_t name_len, int type)
-{
-       const int retlen = sizeof(POSIX_ACL_XATTR_DEFAULT);
-
-       if (list && retlen <= list_size)
-               strcpy(list, POSIX_ACL_XATTR_DEFAULT);
-       return retlen;
-}
-
-static int jffs2_acl_getxattr(struct dentry *dentry, const char *name,
-               void *buffer, size_t size, int type)
-{
-       struct posix_acl *acl;
-       int rc;
-
-       if (name[0] != '\0')
-               return -EINVAL;
-
-       acl = jffs2_get_acl(dentry->d_inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (!acl)
-               return -ENODATA;
-       rc = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
-       return rc;
-}
-
-static int jffs2_acl_setxattr(struct dentry *dentry, const char *name,
-               const void *value, size_t size, int flags, int type)
-{
-       struct posix_acl *acl;
-       int rc;
-
-       if (name[0] != '\0')
-               return -EINVAL;
-       if (!inode_owner_or_capable(dentry->d_inode))
-               return -EPERM;
-
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               if (acl) {
-                       rc = posix_acl_valid(acl);
-                       if (rc)
-                               goto out;
-               }
-       } else {
-               acl = NULL;
-       }
-       rc = jffs2_set_acl(dentry->d_inode, type, acl);
- out:
-       posix_acl_release(acl);
-       return rc;
-}
-
-const struct xattr_handler jffs2_acl_access_xattr_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags  = ACL_TYPE_DEFAULT,
-       .list   = jffs2_acl_access_listxattr,
-       .get    = jffs2_acl_getxattr,
-       .set    = jffs2_acl_setxattr,
-};
-
-const struct xattr_handler jffs2_acl_default_xattr_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags  = ACL_TYPE_DEFAULT,
-       .list   = jffs2_acl_default_listxattr,
-       .get    = jffs2_acl_getxattr,
-       .set    = jffs2_acl_setxattr,
-};
index 9b477246f2a6ec1c0e0f0b9a34c870f44e6ba734..2e2b5745c3b75d42caea23256ccc4bfc6dacb039 100644 (file)
@@ -27,17 +27,14 @@ struct jffs2_acl_header {
 #ifdef CONFIG_JFFS2_FS_POSIX_ACL
 
 struct posix_acl *jffs2_get_acl(struct inode *inode, int type);
-extern int jffs2_acl_chmod(struct inode *);
+int jffs2_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 extern int jffs2_init_acl_pre(struct inode *, struct inode *, umode_t *);
 extern int jffs2_init_acl_post(struct inode *);
 
-extern const struct xattr_handler jffs2_acl_access_xattr_handler;
-extern const struct xattr_handler jffs2_acl_default_xattr_handler;
-
 #else
 
 #define jffs2_get_acl                          (NULL)
-#define jffs2_acl_chmod(inode)                 (0)
+#define jffs2_set_acl                          (NULL)
 #define jffs2_init_acl_pre(dir_i,inode,mode)   (0)
 #define jffs2_init_acl_post(inode)             (0)
 
index e3aac222472e1f06e9d998f46323b4d8be0e1071..938556025d643349b5166e54b5cfc55ea4767dbe 100644 (file)
@@ -59,6 +59,7 @@ const struct inode_operations jffs2_dir_inode_operations =
        .mknod =        jffs2_mknod,
        .rename =       jffs2_rename,
        .get_acl =      jffs2_get_acl,
+       .set_acl =      jffs2_set_acl,
        .setattr =      jffs2_setattr,
        .setxattr =     jffs2_setxattr,
        .getxattr =     jffs2_getxattr,
index 1506673c087e11ae820245baadc8ae74cb9f01b2..256cd19a3b78c006a1439f893b1b51a0341c938a 100644 (file)
@@ -66,6 +66,7 @@ const struct file_operations jffs2_file_operations =
 const struct inode_operations jffs2_file_inode_operations =
 {
        .get_acl =      jffs2_get_acl,
+       .set_acl =      jffs2_set_acl,
        .setattr =      jffs2_setattr,
        .setxattr =     jffs2_setxattr,
        .getxattr =     jffs2_getxattr,
index 09b3ed45572475feb68b117fcf5b420a1a5e4d8f..a69e426435ddc3d2d207701df7a5b06264c1c481 100644 (file)
@@ -190,15 +190,16 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr)
 
 int jffs2_setattr(struct dentry *dentry, struct iattr *iattr)
 {
+       struct inode *inode = dentry->d_inode;
        int rc;
 
-       rc = inode_change_ok(dentry->d_inode, iattr);
+       rc = inode_change_ok(inode, iattr);
        if (rc)
                return rc;
 
-       rc = jffs2_do_setattr(dentry->d_inode, iattr);
+       rc = jffs2_do_setattr(inode, iattr);
        if (!rc && (iattr->ia_valid & ATTR_MODE))
-               rc = jffs2_acl_chmod(dentry->d_inode);
+               rc = posix_acl_chmod(inode, inode->i_mode);
 
        return rc;
 }
index 4f47aa24b5562001cf8983d6c7634c373d50206b..b8fd651307a42e2fce3d15dfcc1976e2526932ab 100644 (file)
@@ -288,6 +288,8 @@ struct jffs2_xattr_datum *jffs2_alloc_xattr_datum(void)
        struct jffs2_xattr_datum *xd;
        xd = kmem_cache_zalloc(xattr_datum_cache, GFP_KERNEL);
        dbg_memalloc("%p\n", xd);
+       if (!xd)
+               return NULL;
 
        xd->class = RAWNODE_CLASS_XATTR_DATUM;
        xd->node = (void *)xd;
@@ -306,6 +308,8 @@ struct jffs2_xattr_ref *jffs2_alloc_xattr_ref(void)
        struct jffs2_xattr_ref *ref;
        ref = kmem_cache_zalloc(xattr_ref_cache, GFP_KERNEL);
        dbg_memalloc("%p\n", ref);
+       if (!ref)
+               return NULL;
 
        ref->class = RAWNODE_CLASS_XATTR_REF;
        ref->node = (void *)ref;
index 6e563332bb242e2d4214026fa4ff608bcd69cf94..c7c77b0dfccde2fe5dedb619500fb8f4f4a1f866 100644 (file)
@@ -22,7 +22,6 @@ const struct inode_operations jffs2_symlink_inode_operations =
 {
        .readlink =     generic_readlink,
        .follow_link =  jffs2_follow_link,
-       .get_acl =      jffs2_get_acl,
        .setattr =      jffs2_setattr,
        .setxattr =     jffs2_setxattr,
        .getxattr =     jffs2_getxattr,
index 3034e970eb9a130cea79d7d413aa2463070408ff..ad0f2e2a1700835d596e656b540ec0ac06cafd90 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/crc32.h>
 #include <linux/jffs2.h>
 #include <linux/xattr.h>
+#include <linux/posix_acl_xattr.h>
 #include <linux/mtd/mtd.h>
 #include "nodelist.h"
 /* -------- xdatum related functions ----------------
@@ -921,8 +922,8 @@ const struct xattr_handler *jffs2_xattr_handlers[] = {
        &jffs2_security_xattr_handler,
 #endif
 #ifdef CONFIG_JFFS2_FS_POSIX_ACL
-       &jffs2_acl_access_xattr_handler,
-       &jffs2_acl_default_xattr_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
        &jffs2_trusted_xattr_handler,
        NULL
@@ -942,10 +943,10 @@ static const struct xattr_handler *xprefix_to_handler(int xprefix) {
 #endif
 #ifdef CONFIG_JFFS2_FS_POSIX_ACL
        case JFFS2_XPREFIX_ACL_ACCESS:
-               ret = &jffs2_acl_access_xattr_handler;
+               ret = &posix_acl_access_xattr_handler;
                break;
        case JFFS2_XPREFIX_ACL_DEFAULT:
-               ret = &jffs2_acl_default_xattr_handler;
+               ret = &posix_acl_default_xattr_handler;
                break;
 #endif
        case JFFS2_XPREFIX_TRUSTED:
index d254d6d3599565fbca59621cf840d105d9cd4971..e973b85d6afd9f136bcae002cbe70432000e5a15 100644 (file)
@@ -72,7 +72,7 @@ struct posix_acl *jfs_get_acl(struct inode *inode, int type)
        return acl;
 }
 
-static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
+static int __jfs_set_acl(tid_t tid, struct inode *inode, int type,
                       struct posix_acl *acl)
 {
        char *ea_name;
@@ -80,21 +80,22 @@ static int jfs_set_acl(tid_t tid, struct inode *inode, int type,
        int size = 0;
        char *value = NULL;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
-       switch(type) {
-               case ACL_TYPE_ACCESS:
-                       ea_name = POSIX_ACL_XATTR_ACCESS;
-                       break;
-               case ACL_TYPE_DEFAULT:
-                       ea_name = POSIX_ACL_XATTR_DEFAULT;
-                       if (!S_ISDIR(inode->i_mode))
-                               return acl ? -EACCES : 0;
-                       break;
-               default:
-                       return -EINVAL;
+       switch (type) {
+       case ACL_TYPE_ACCESS:
+               ea_name = POSIX_ACL_XATTR_ACCESS;
+               rc = posix_acl_equiv_mode(acl, &inode->i_mode);
+               if (rc < 0)
+                       return rc;
+               if (rc == 0)
+                       acl = NULL;
+               break;
+       case ACL_TYPE_DEFAULT:
+               ea_name = POSIX_ACL_XATTR_DEFAULT;
+               break;
+       default:
+               return -EINVAL;
        }
+
        if (acl) {
                size = posix_acl_xattr_size(acl->a_count);
                value = kmalloc(size, GFP_KERNEL);
@@ -114,65 +115,43 @@ out:
        return rc;
 }
 
+int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+       int rc;
+       tid_t tid;
+
+       tid = txBegin(inode->i_sb, 0);
+       mutex_lock(&JFS_IP(inode)->commit_mutex);
+       rc = __jfs_set_acl(tid, inode, type, acl);
+       if (!rc)
+               rc = txCommit(tid, 1, &inode, 0);
+       txEnd(tid);
+       mutex_unlock(&JFS_IP(inode)->commit_mutex);
+       return rc;
+}
+
 int jfs_init_acl(tid_t tid, struct inode *inode, struct inode *dir)
 {
-       struct posix_acl *acl = NULL;
+       struct posix_acl *default_acl, *acl;
        int rc = 0;
 
-       if (S_ISLNK(inode->i_mode))
-               return 0;
+       rc = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+       if (rc)
+               return rc;
 
-       acl = jfs_get_acl(dir, ACL_TYPE_DEFAULT);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
+       if (default_acl) {
+               rc = __jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, default_acl);
+               posix_acl_release(default_acl);
+       }
 
        if (acl) {
-               if (S_ISDIR(inode->i_mode)) {
-                       rc = jfs_set_acl(tid, inode, ACL_TYPE_DEFAULT, acl);
-                       if (rc)
-                               goto cleanup;
-               }
-               rc = posix_acl_create(&acl, GFP_KERNEL, &inode->i_mode);
-               if (rc < 0)
-                       goto cleanup; /* posix_acl_release(NULL) is no-op */
-               if (rc > 0)
-                       rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl);
-cleanup:
+               if (!rc)
+                       rc = __jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl);
                posix_acl_release(acl);
-       } else
-               inode->i_mode &= ~current_umask();
+       }
 
        JFS_IP(inode)->mode2 = (JFS_IP(inode)->mode2 & 0xffff0000) |
                               inode->i_mode;
 
        return rc;
 }
-
-int jfs_acl_chmod(struct inode *inode)
-{
-       struct posix_acl *acl;
-       int rc;
-       tid_t tid;
-
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
-       acl = jfs_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
-
-       rc = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
-       if (rc)
-               return rc;
-
-       tid = txBegin(inode->i_sb, 0);
-       mutex_lock(&JFS_IP(inode)->commit_mutex);
-       rc = jfs_set_acl(tid, inode, ACL_TYPE_ACCESS, acl);
-       if (!rc)
-               rc = txCommit(tid, 1, &inode, 0);
-       txEnd(tid);
-       mutex_unlock(&JFS_IP(inode)->commit_mutex);
-
-       posix_acl_release(acl);
-       return rc;
-}
index dd7442c5835864b0e04bdff5befbd0f020232bfb..794da944d5cd29c63d8db31040340e83d7079d87 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/mm.h>
 #include <linux/fs.h>
+#include <linux/posix_acl.h>
 #include <linux/quotaops.h>
 #include "jfs_incore.h"
 #include "jfs_inode.h"
@@ -131,7 +132,7 @@ int jfs_setattr(struct dentry *dentry, struct iattr *iattr)
        mark_inode_dirty(inode);
 
        if (iattr->ia_valid & ATTR_MODE)
-               rc = jfs_acl_chmod(inode);
+               rc = posix_acl_chmod(inode, inode->i_mode);
        return rc;
 }
 
@@ -143,6 +144,7 @@ const struct inode_operations jfs_file_inode_operations = {
        .setattr        = jfs_setattr,
 #ifdef CONFIG_JFS_POSIX_ACL
        .get_acl        = jfs_get_acl,
+       .set_acl        = jfs_set_acl,
 #endif
 };
 
index ad84fe50ca9e897362caa12101d63a590b56073f..489f993b7b137060a9df603bffbab24ba75d4d66 100644 (file)
@@ -21,8 +21,8 @@
 #ifdef CONFIG_JFS_POSIX_ACL
 
 struct posix_acl *jfs_get_acl(struct inode *inode, int type);
+int jfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 int jfs_init_acl(tid_t, struct inode *, struct inode *);
-int jfs_acl_chmod(struct inode *inode);
 
 #else
 
@@ -32,10 +32,5 @@ static inline int jfs_init_acl(tid_t tid, struct inode *inode,
        return 0;
 }
 
-static inline int jfs_acl_chmod(struct inode *inode)
-{
-       return 0;
-}
-
 #endif
 #endif         /* _H_JFS_ACL */
index 360d27c488873825fed5c04f8bb2320a51a39d62..8d811e02b4b92bb26d28367c727fcbe909fa95d5 100644 (file)
@@ -1998,20 +1998,20 @@ static int lbmRead(struct jfs_log * log, int pn, struct lbuf ** bpp)
 
        bio = bio_alloc(GFP_NOFS, 1);
 
-       bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
+       bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9);
        bio->bi_bdev = log->bdev;
        bio->bi_io_vec[0].bv_page = bp->l_page;
        bio->bi_io_vec[0].bv_len = LOGPSIZE;
        bio->bi_io_vec[0].bv_offset = bp->l_offset;
 
        bio->bi_vcnt = 1;
-       bio->bi_size = LOGPSIZE;
+       bio->bi_iter.bi_size = LOGPSIZE;
 
        bio->bi_end_io = lbmIODone;
        bio->bi_private = bp;
        /*check if journaling to disk has been disabled*/
        if (log->no_integrity) {
-               bio->bi_size = 0;
+               bio->bi_iter.bi_size = 0;
                lbmIODone(bio, 0);
        } else {
                submit_bio(READ_SYNC, bio);
@@ -2144,21 +2144,21 @@ static void lbmStartIO(struct lbuf * bp)
        jfs_info("lbmStartIO\n");
 
        bio = bio_alloc(GFP_NOFS, 1);
-       bio->bi_sector = bp->l_blkno << (log->l2bsize - 9);
+       bio->bi_iter.bi_sector = bp->l_blkno << (log->l2bsize - 9);
        bio->bi_bdev = log->bdev;
        bio->bi_io_vec[0].bv_page = bp->l_page;
        bio->bi_io_vec[0].bv_len = LOGPSIZE;
        bio->bi_io_vec[0].bv_offset = bp->l_offset;
 
        bio->bi_vcnt = 1;
-       bio->bi_size = LOGPSIZE;
+       bio->bi_iter.bi_size = LOGPSIZE;
 
        bio->bi_end_io = lbmIODone;
        bio->bi_private = bp;
 
        /* check if journaling to disk has been disabled */
        if (log->no_integrity) {
-               bio->bi_size = 0;
+               bio->bi_iter.bi_size = 0;
                lbmIODone(bio, 0);
        } else {
                submit_bio(WRITE_SYNC, bio);
index d165cde0c68dda885c2f5bb512f48465f521c4a1..49ba7ff1bbb9a15d8939128df2021354f2db6c52 100644 (file)
@@ -416,7 +416,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
                         * count from hitting zero before we're through
                         */
                        inc_io(page);
-                       if (!bio->bi_size)
+                       if (!bio->bi_iter.bi_size)
                                goto dump_bio;
                        submit_bio(WRITE, bio);
                        nr_underway++;
@@ -438,7 +438,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
 
                bio = bio_alloc(GFP_NOFS, 1);
                bio->bi_bdev = inode->i_sb->s_bdev;
-               bio->bi_sector = pblock << (inode->i_blkbits - 9);
+               bio->bi_iter.bi_sector = pblock << (inode->i_blkbits - 9);
                bio->bi_end_io = metapage_write_end_io;
                bio->bi_private = page;
 
@@ -452,7 +452,7 @@ static int metapage_writepage(struct page *page, struct writeback_control *wbc)
        if (bio) {
                if (bio_add_page(bio, page, bio_bytes, bio_offset) < bio_bytes)
                                goto add_failed;
-               if (!bio->bi_size)
+               if (!bio->bi_iter.bi_size)
                        goto dump_bio;
 
                submit_bio(WRITE, bio);
@@ -517,7 +517,8 @@ static int metapage_readpage(struct file *fp, struct page *page)
 
                        bio = bio_alloc(GFP_NOFS, 1);
                        bio->bi_bdev = inode->i_sb->s_bdev;
-                       bio->bi_sector = pblock << (inode->i_blkbits - 9);
+                       bio->bi_iter.bi_sector =
+                               pblock << (inode->i_blkbits - 9);
                        bio->bi_end_io = metapage_read_end_io;
                        bio->bi_private = page;
                        len = xlen << inode->i_blkbits;
index e9e100fd7c09a90a7ba603e7f1282ae9ba15e164..e8d717dabca3eb5a2e3bcff902c34b8376b8450d 100644 (file)
@@ -61,6 +61,8 @@ extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t);
 extern ssize_t jfs_listxattr(struct dentry *, char *, size_t);
 extern int jfs_removexattr(struct dentry *, const char *);
 
+extern const struct xattr_handler *jfs_xattr_handlers[];
+
 #ifdef CONFIG_JFS_SECURITY
 extern int jfs_init_security(tid_t, struct inode *, struct inode *,
                             const struct qstr *);
index aa8a3370631bd8da9475394ef9f571ed90c620ff..d59c7defb1efea8bb46bea33ddffe2c384db390b 100644 (file)
@@ -1524,6 +1524,7 @@ const struct inode_operations jfs_dir_inode_operations = {
        .setattr        = jfs_setattr,
 #ifdef CONFIG_JFS_POSIX_ACL
        .get_acl        = jfs_get_acl,
+       .set_acl        = jfs_set_acl,
 #endif
 };
 
index 6669aa2042c30154e0ad318ff5d6d657a2b60f61..e2b7483444fd0dc7163cf1d4ab651917b824965e 100644 (file)
@@ -44,6 +44,7 @@
 #include "jfs_imap.h"
 #include "jfs_acl.h"
 #include "jfs_debug.h"
+#include "jfs_xattr.h"
 
 MODULE_DESCRIPTION("The Journaled Filesystem (JFS)");
 MODULE_AUTHOR("Steve Best/Dave Kleikamp/Barry Arndt, IBM");
@@ -522,6 +523,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
         */
        sb->s_op = &jfs_super_operations;
        sb->s_export_op = &jfs_export_operations;
+       sb->s_xattr = jfs_xattr_handlers;
 #ifdef CONFIG_QUOTA
        sb->dq_op = &dquot_operations;
        sb->s_qcop = &dquot_quotactl_ops;
index d3472f4cd5301e1c3ac48817755a0c62f8f6975c..3bd5ee45f7b3a13cf3dcc65f824fd8dad5ac6960 100644 (file)
@@ -665,82 +665,13 @@ static int ea_put(tid_t tid, struct inode *inode, struct ea_buffer *ea_buf,
        return 0;
 }
 
-/*
- * can_set_system_xattr
- *
- * This code is specific to the system.* namespace.  It contains policy
- * which doesn't belong in the main xattr codepath.
- */
-static int can_set_system_xattr(struct inode *inode, const char *name,
-                               const void *value, size_t value_len)
-{
-#ifdef CONFIG_JFS_POSIX_ACL
-       struct posix_acl *acl;
-       int rc;
-
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-
-       /*
-        * POSIX_ACL_XATTR_ACCESS is tied to i_mode
-        */
-       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, value_len);
-               if (IS_ERR(acl)) {
-                       rc = PTR_ERR(acl);
-                       printk(KERN_ERR "posix_acl_from_xattr returned %d\n",
-                              rc);
-                       return rc;
-               }
-               if (acl) {
-                       rc = posix_acl_equiv_mode(acl, &inode->i_mode);
-                       posix_acl_release(acl);
-                       if (rc < 0) {
-                               printk(KERN_ERR
-                                      "posix_acl_equiv_mode returned %d\n",
-                                      rc);
-                               return rc;
-                       }
-                       mark_inode_dirty(inode);
-               }
-               /*
-                * We're changing the ACL.  Get rid of the cached one
-                */
-               forget_cached_acl(inode, ACL_TYPE_ACCESS);
-
-               return 0;
-       } else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, value_len);
-               if (IS_ERR(acl)) {
-                       rc = PTR_ERR(acl);
-                       printk(KERN_ERR "posix_acl_from_xattr returned %d\n",
-                              rc);
-                       return rc;
-               }
-               posix_acl_release(acl);
-
-               /*
-                * We're changing the default ACL.  Get rid of the cached one
-                */
-               forget_cached_acl(inode, ACL_TYPE_DEFAULT);
-
-               return 0;
-       }
-#endif                 /* CONFIG_JFS_POSIX_ACL */
-       return -EOPNOTSUPP;
-}
-
 /*
  * Most of the permission checking is done by xattr_permission in the vfs.
- * The local file system is responsible for handling the system.* namespace.
  * We also need to verify that this is a namespace that we recognize.
  */
 static int can_set_xattr(struct inode *inode, const char *name,
                         const void *value, size_t value_len)
 {
-       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
-               return can_set_system_xattr(inode, name, value, value_len);
-
        if (!strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) {
                /*
                 * This makes sure that we aren't trying to set an
@@ -748,7 +679,7 @@ static int can_set_xattr(struct inode *inode, const char *name,
                 * with "os2."
                 */
                if (is_known_namespace(name + XATTR_OS2_PREFIX_LEN))
-                               return -EOPNOTSUPP;
+                       return -EOPNOTSUPP;
                return 0;
        }
 
@@ -860,6 +791,19 @@ int __jfs_setxattr(tid_t tid, struct inode *inode, const char *name,
                        /* Completely new ea list */
                        xattr_size = sizeof (struct jfs_ea_list);
 
+               /*
+                * The size of EA value is limitted by on-disk format up to
+                *  __le16, there would be an overflow if the size is equal
+                * to XATTR_SIZE_MAX (65536).  In order to avoid this issue,
+                * we can pre-checkup the value size against USHRT_MAX, and
+                * return -E2BIG in this case, which is consistent with the
+                * VFS setxattr interface.
+                */
+               if (value_len >= USHRT_MAX) {
+                       rc = -E2BIG;
+                       goto release;
+               }
+
                ea = (struct jfs_ea *) ((char *) ealist + xattr_size);
                ea->flag = 0;
                ea->namelen = namelen;
@@ -874,7 +818,7 @@ int __jfs_setxattr(tid_t tid, struct inode *inode, const char *name,
        /* DEBUG - If we did this right, these number match */
        if (xattr_size != new_size) {
                printk(KERN_ERR
-                      "jfs_xsetattr: xattr_size = %d, new_size = %d\n",
+                      "__jfs_setxattr: xattr_size = %d, new_size = %d\n",
                       xattr_size, new_size);
 
                rc = -EINVAL;
@@ -913,6 +857,14 @@ int jfs_setxattr(struct dentry *dentry, const char *name, const void *value,
        if ((rc = can_set_xattr(inode, name, value, value_len)))
                return rc;
 
+       /*
+        * If this is a request for a synthetic attribute in the system.*
+        * namespace use the generic infrastructure to resolve a handler
+        * for it via sb->s_xattr.
+        */
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_setxattr(dentry, name, value, value_len, flags);
+
        if (value == NULL) {    /* empty EA, do not remove */
                value = "";
                value_len = 0;
@@ -986,6 +938,14 @@ ssize_t jfs_getxattr(struct dentry *dentry, const char *name, void *data,
 {
        int err;
 
+       /*
+        * If this is a request for a synthetic attribute in the system.*
+        * namespace use the generic infrastructure to resolve a handler
+        * for it via sb->s_xattr.
+        */
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_getxattr(dentry, name, data, buf_size);
+
        if (strncmp(name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) {
                /*
                 * skip past "os2." prefix
@@ -1077,6 +1037,14 @@ int jfs_removexattr(struct dentry *dentry, const char *name)
        if ((rc = can_set_xattr(inode, name, NULL, 0)))
                return rc;
 
+       /*
+        * If this is a request for a synthetic attribute in the system.*
+        * namespace use the generic infrastructure to resolve a handler
+        * for it via sb->s_xattr.
+        */
+       if (!strncmp(name, XATTR_SYSTEM_PREFIX, XATTR_SYSTEM_PREFIX_LEN))
+               return generic_removexattr(dentry, name);
+
        tid = txBegin(inode->i_sb, 0);
        mutex_lock(&ji->commit_mutex);
        rc = __jfs_setxattr(tid, dentry->d_inode, name, NULL, 0, XATTR_REPLACE);
@@ -1088,6 +1056,19 @@ int jfs_removexattr(struct dentry *dentry, const char *name)
        return rc;
 }
 
+/*
+ * List of handlers for synthetic system.* attributes.  All real ondisk
+ * attributes are handled directly.
+ */
+const struct xattr_handler *jfs_xattr_handlers[] = {
+#ifdef JFS_POSIX_ACL
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
+#endif
+       NULL,
+};
+
+
 #ifdef CONFIG_JFS_SECURITY
 static int jfs_initxattrs(struct inode *inode, const struct xattr *xattr_array,
                          void *fs_info)
index 0f95f0d0b3133e9b3129e3807a842438e162a245..76279e11982d854c9b22312cf51b3bd3a97e256d 100644 (file)
@@ -26,9 +26,9 @@ static int sync_request(struct page *page, struct block_device *bdev, int rw)
        bio_vec.bv_len = PAGE_SIZE;
        bio_vec.bv_offset = 0;
        bio.bi_vcnt = 1;
-       bio.bi_size = PAGE_SIZE;
        bio.bi_bdev = bdev;
-       bio.bi_sector = page->index * (PAGE_SIZE >> 9);
+       bio.bi_iter.bi_sector = page->index * (PAGE_SIZE >> 9);
+       bio.bi_iter.bi_size = PAGE_SIZE;
 
        return submit_bio_wait(rw, &bio);
 }
@@ -56,22 +56,18 @@ static DECLARE_WAIT_QUEUE_HEAD(wq);
 static void writeseg_end_io(struct bio *bio, int err)
 {
        const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bvec;
+       int i;
        struct super_block *sb = bio->bi_private;
        struct logfs_super *super = logfs_super(sb);
-       struct page *page;
 
        BUG_ON(!uptodate); /* FIXME: Retry io or write elsewhere */
        BUG_ON(err);
-       BUG_ON(bio->bi_vcnt == 0);
-       do {
-               page = bvec->bv_page;
-               if (--bvec >= bio->bi_io_vec)
-                       prefetchw(&bvec->bv_page->flags);
-
-               end_page_writeback(page);
-               page_cache_release(page);
-       } while (bvec >= bio->bi_io_vec);
+
+       bio_for_each_segment_all(bvec, bio, i) {
+               end_page_writeback(bvec->bv_page);
+               page_cache_release(bvec->bv_page);
+       }
        bio_put(bio);
        if (atomic_dec_and_test(&super->s_pending_writes))
                wake_up(&wq);
@@ -96,9 +92,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index,
                if (i >= max_pages) {
                        /* Block layer cannot split bios :( */
                        bio->bi_vcnt = i;
-                       bio->bi_size = i * PAGE_SIZE;
+                       bio->bi_iter.bi_size = i * PAGE_SIZE;
                        bio->bi_bdev = super->s_bdev;
-                       bio->bi_sector = ofs >> 9;
+                       bio->bi_iter.bi_sector = ofs >> 9;
                        bio->bi_private = sb;
                        bio->bi_end_io = writeseg_end_io;
                        atomic_inc(&super->s_pending_writes);
@@ -123,9 +119,9 @@ static int __bdev_writeseg(struct super_block *sb, u64 ofs, pgoff_t index,
                unlock_page(page);
        }
        bio->bi_vcnt = nr_pages;
-       bio->bi_size = nr_pages * PAGE_SIZE;
+       bio->bi_iter.bi_size = nr_pages * PAGE_SIZE;
        bio->bi_bdev = super->s_bdev;
-       bio->bi_sector = ofs >> 9;
+       bio->bi_iter.bi_sector = ofs >> 9;
        bio->bi_private = sb;
        bio->bi_end_io = writeseg_end_io;
        atomic_inc(&super->s_pending_writes);
@@ -188,9 +184,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index,
                if (i >= max_pages) {
                        /* Block layer cannot split bios :( */
                        bio->bi_vcnt = i;
-                       bio->bi_size = i * PAGE_SIZE;
+                       bio->bi_iter.bi_size = i * PAGE_SIZE;
                        bio->bi_bdev = super->s_bdev;
-                       bio->bi_sector = ofs >> 9;
+                       bio->bi_iter.bi_sector = ofs >> 9;
                        bio->bi_private = sb;
                        bio->bi_end_io = erase_end_io;
                        atomic_inc(&super->s_pending_writes);
@@ -209,9 +205,9 @@ static int do_erase(struct super_block *sb, u64 ofs, pgoff_t index,
                bio->bi_io_vec[i].bv_offset = 0;
        }
        bio->bi_vcnt = nr_pages;
-       bio->bi_size = nr_pages * PAGE_SIZE;
+       bio->bi_iter.bi_size = nr_pages * PAGE_SIZE;
        bio->bi_bdev = super->s_bdev;
-       bio->bi_sector = ofs >> 9;
+       bio->bi_iter.bi_sector = ofs >> 9;
        bio->bi_private = sb;
        bio->bi_end_io = erase_end_io;
        atomic_inc(&super->s_pending_writes);
index d64c594be6c47baf29a70ffe63671f307cba4b7e..a17458ca6f29e4dbf1f1a1b8bb9e97949b279d29 100644 (file)
@@ -74,7 +74,7 @@ static inline int mnt_has_parent(struct mount *mnt)
 static inline int is_mounted(struct vfsmount *mnt)
 {
        /* neither detached nor internal? */
-       return !IS_ERR_OR_NULL(real_mount(mnt));
+       return !IS_ERR_OR_NULL(real_mount(mnt)->mnt_ns);
 }
 
 extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *);
index 0face1c4d4c6bd4ea33cb60e45b8c7fad8235acf..4979ffa60aaabfd36839adec6feafcb17a876d98 100644 (file)
  */
 static void mpage_end_io(struct bio *bio, int err)
 {
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bv;
+       int i;
 
-       do {
-               struct page *page = bvec->bv_page;
+       bio_for_each_segment_all(bv, bio, i) {
+               struct page *page = bv->bv_page;
 
-               if (--bvec >= bio->bi_io_vec)
-                       prefetchw(&bvec->bv_page->flags);
                if (bio_data_dir(bio) == READ) {
-                       if (uptodate) {
+                       if (!err) {
                                SetPageUptodate(page);
                        } else {
                                ClearPageUptodate(page);
@@ -60,14 +58,15 @@ static void mpage_end_io(struct bio *bio, int err)
                        }
                        unlock_page(page);
                } else { /* bio_data_dir(bio) == WRITE */
-                       if (!uptodate) {
+                       if (err) {
                                SetPageError(page);
                                if (page->mapping)
                                        set_bit(AS_EIO, &page->mapping->flags);
                        }
                        end_page_writeback(page);
                }
-       } while (bvec >= bio->bi_io_vec);
+       }
+
        bio_put(bio);
 }
 
@@ -94,7 +93,7 @@ mpage_alloc(struct block_device *bdev,
 
        if (bio) {
                bio->bi_bdev = bdev;
-               bio->bi_sector = first_sector;
+               bio->bi_iter.bi_sector = first_sector;
        }
        return bio;
 }
index 3531deebad3084104e6a9fca7116ba68890ad5af..bcb838e2e52f24593da609abba67dc5ab5336947 100644 (file)
@@ -235,27 +235,9 @@ static int check_acl(struct inode *inode, int mask)
                return posix_acl_permission(inode, acl, mask & ~MAY_NOT_BLOCK);
        }
 
-       acl = get_cached_acl(inode, ACL_TYPE_ACCESS);
-
-       /*
-        * A filesystem can force a ACL callback by just never filling the
-        * ACL cache. But normally you'd fill the cache either at inode
-        * instantiation time, or on the first ->get_acl call.
-        *
-        * If the filesystem doesn't have a get_acl() function at all, we'll
-        * just create the negative cache entry.
-        */
-       if (acl == ACL_NOT_CACHED) {
-               if (inode->i_op->get_acl) {
-                       acl = inode->i_op->get_acl(inode, ACL_TYPE_ACCESS);
-                       if (IS_ERR(acl))
-                               return PTR_ERR(acl);
-               } else {
-                       set_cached_acl(inode, ACL_TYPE_ACCESS, NULL);
-                       return -EAGAIN;
-               }
-       }
-
+       acl = get_acl(inode, ACL_TYPE_ACCESS);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
        if (acl) {
                int error = posix_acl_permission(inode, acl, mask);
                posix_acl_release(acl);
index e242bbf729723d1d45ae0cac7370952167b026cd..56ff823ca82e0979f08355f80aaf75ae4a019393 100644 (file)
@@ -134,8 +134,8 @@ bl_submit_bio(int rw, struct bio *bio)
        if (bio) {
                get_parallel(bio->bi_private);
                dprintk("%s submitting %s bio %u@%llu\n", __func__,
-                       rw == READ ? "read" : "write",
-                       bio->bi_size, (unsigned long long)bio->bi_sector);
+                       rw == READ ? "read" : "write", bio->bi_iter.bi_size,
+                       (unsigned long long)bio->bi_iter.bi_sector);
                submit_bio(rw, bio);
        }
        return NULL;
@@ -156,7 +156,8 @@ static struct bio *bl_alloc_init_bio(int npg, sector_t isect,
        }
 
        if (bio) {
-               bio->bi_sector = isect - be->be_f_offset + be->be_v_offset;
+               bio->bi_iter.bi_sector = isect - be->be_f_offset +
+                       be->be_v_offset;
                bio->bi_bdev = be->be_mdev;
                bio->bi_end_io = end_io;
                bio->bi_private = par;
@@ -201,18 +202,14 @@ static struct bio *bl_add_page_to_bio(struct bio *bio, int npg, int rw,
 static void bl_end_io_read(struct bio *bio, int err)
 {
        struct parallel_io *par = bio->bi_private;
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
+       struct bio_vec *bvec;
+       int i;
 
-       do {
-               struct page *page = bvec->bv_page;
+       if (!err)
+               bio_for_each_segment_all(bvec, bio, i)
+                       SetPageUptodate(bvec->bv_page);
 
-               if (--bvec >= bio->bi_io_vec)
-                       prefetchw(&bvec->bv_page->flags);
-               if (uptodate)
-                       SetPageUptodate(page);
-       } while (bvec >= bio->bi_io_vec);
-       if (!uptodate) {
+       if (err) {
                struct nfs_read_data *rdata = par->data;
                struct nfs_pgio_header *header = rdata->header;
 
@@ -383,20 +380,16 @@ static void mark_extents_written(struct pnfs_block_layout *bl,
 static void bl_end_io_write_zero(struct bio *bio, int err)
 {
        struct parallel_io *par = bio->bi_private;
-       const int uptodate = test_bit(BIO_UPTODATE, &bio->bi_flags);
-       struct bio_vec *bvec = bio->bi_io_vec + bio->bi_vcnt - 1;
-
-       do {
-               struct page *page = bvec->bv_page;
+       struct bio_vec *bvec;
+       int i;
 
-               if (--bvec >= bio->bi_io_vec)
-                       prefetchw(&bvec->bv_page->flags);
+       bio_for_each_segment_all(bvec, bio, i) {
                /* This is the zeroing page we added */
-               end_page_writeback(page);
-               page_cache_release(page);
-       } while (bvec >= bio->bi_io_vec);
+               end_page_writeback(bvec->bv_page);
+               page_cache_release(bvec->bv_page);
+       }
 
-       if (unlikely(!uptodate)) {
+       if (unlikely(err)) {
                struct nfs_write_data *data = par->data;
                struct nfs_pgio_header *header = data->header;
 
@@ -519,7 +512,7 @@ bl_do_readpage_sync(struct page *page, struct pnfs_block_extent *be,
        isect = (page->index << PAGE_CACHE_SECTOR_SHIFT) +
                (offset / SECTOR_SIZE);
 
-       bio->bi_sector = isect - be->be_f_offset + be->be_v_offset;
+       bio->bi_iter.bi_sector = isect - be->be_f_offset + be->be_v_offset;
        bio->bi_bdev = be->be_mdev;
        bio->bi_end_io = bl_read_single_end_io;
 
index 812154aff9818ccb6bcb79e88587478d9fe54fd6..be38b573495a78ddf281629da6e5f85f98eed17b 100644 (file)
@@ -274,6 +274,15 @@ out_eof:
        return -EBADCOOKIE;
 }
 
+static bool
+nfs_readdir_inode_mapping_valid(struct nfs_inode *nfsi)
+{
+       if (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))
+               return false;
+       smp_rmb();
+       return !test_bit(NFS_INO_INVALIDATING, &nfsi->flags);
+}
+
 static
 int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_descriptor_t *desc)
 {
@@ -287,8 +296,8 @@ int nfs_readdir_search_for_cookie(struct nfs_cache_array *array, nfs_readdir_des
                        struct nfs_open_dir_context *ctx = desc->file->private_data;
 
                        new_pos = desc->current_index + i;
-                       if (ctx->attr_gencount != nfsi->attr_gencount
-                           || (nfsi->cache_validity & (NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA))) {
+                       if (ctx->attr_gencount != nfsi->attr_gencount ||
+                           !nfs_readdir_inode_mapping_valid(nfsi)) {
                                ctx->duped = 0;
                                ctx->attr_gencount = nfsi->attr_gencount;
                        } else if (new_pos < desc->ctx->pos) {
@@ -1404,7 +1413,7 @@ int nfs_atomic_open(struct inode *dir, struct dentry *dentry,
        /* Expect a negative dentry */
        BUG_ON(dentry->d_inode);
 
-       dfprintk(VFS, "NFS: atomic_open(%s/%ld), %pd\n",
+       dfprintk(VFS, "NFS: atomic_open(%s/%lu), %pd\n",
                        dir->i_sb->s_id, dir->i_ino, dentry);
 
        err = nfs_check_flags(open_flags);
@@ -1594,7 +1603,7 @@ int nfs_create(struct inode *dir, struct dentry *dentry,
        int open_flags = excl ? O_CREAT | O_EXCL : O_CREAT;
        int error;
 
-       dfprintk(VFS, "NFS: create(%s/%ld), %pd\n",
+       dfprintk(VFS, "NFS: create(%s/%lu), %pd\n",
                        dir->i_sb->s_id, dir->i_ino, dentry);
 
        attr.ia_mode = mode;
@@ -1621,7 +1630,7 @@ nfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
        struct iattr attr;
        int status;
 
-       dfprintk(VFS, "NFS: mknod(%s/%ld), %pd\n",
+       dfprintk(VFS, "NFS: mknod(%s/%lu), %pd\n",
                        dir->i_sb->s_id, dir->i_ino, dentry);
 
        if (!new_valid_dev(rdev))
@@ -1650,7 +1659,7 @@ int nfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
        struct iattr attr;
        int error;
 
-       dfprintk(VFS, "NFS: mkdir(%s/%ld), %pd\n",
+       dfprintk(VFS, "NFS: mkdir(%s/%lu), %pd\n",
                        dir->i_sb->s_id, dir->i_ino, dentry);
 
        attr.ia_valid = ATTR_MODE;
@@ -1678,7 +1687,7 @@ int nfs_rmdir(struct inode *dir, struct dentry *dentry)
 {
        int error;
 
-       dfprintk(VFS, "NFS: rmdir(%s/%ld), %pd\n",
+       dfprintk(VFS, "NFS: rmdir(%s/%lu), %pd\n",
                        dir->i_sb->s_id, dir->i_ino, dentry);
 
        trace_nfs_rmdir_enter(dir, dentry);
@@ -1747,7 +1756,7 @@ int nfs_unlink(struct inode *dir, struct dentry *dentry)
        int error;
        int need_rehash = 0;
 
-       dfprintk(VFS, "NFS: unlink(%s/%ld, %pd)\n", dir->i_sb->s_id,
+       dfprintk(VFS, "NFS: unlink(%s/%lu, %pd)\n", dir->i_sb->s_id,
                dir->i_ino, dentry);
 
        trace_nfs_unlink_enter(dir, dentry);
@@ -1798,7 +1807,7 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
        unsigned int pathlen = strlen(symname);
        int error;
 
-       dfprintk(VFS, "NFS: symlink(%s/%ld, %pd, %s)\n", dir->i_sb->s_id,
+       dfprintk(VFS, "NFS: symlink(%s/%lu, %pd, %s)\n", dir->i_sb->s_id,
                dir->i_ino, dentry, symname);
 
        if (pathlen > PAGE_SIZE)
@@ -1821,7 +1830,7 @@ int nfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
        error = NFS_PROTO(dir)->symlink(dir, dentry, page, pathlen, &attr);
        trace_nfs_symlink_exit(dir, dentry, error);
        if (error != 0) {
-               dfprintk(VFS, "NFS: symlink(%s/%ld, %pd, %s) error %d\n",
+               dfprintk(VFS, "NFS: symlink(%s/%lu, %pd, %s) error %d\n",
                        dir->i_sb->s_id, dir->i_ino,
                        dentry, symname, error);
                d_drop(dentry);
@@ -2304,7 +2313,7 @@ out:
        if (!res && (mask & MAY_EXEC) && !execute_ok(inode))
                res = -EACCES;
 
-       dfprintk(VFS, "NFS: permission(%s/%ld), mask=0x%x, res=%d\n",
+       dfprintk(VFS, "NFS: permission(%s/%lu), mask=0x%x, res=%d\n",
                inode->i_sb->s_id, inode->i_ino, mask, res);
        return res;
 out_notsup:
index d71d66c9e0a1e6235cacdcdc41be6c045c65c554..b8797ae6831ff3e1be4c4b3f85c2c38e34252498 100644 (file)
@@ -222,14 +222,31 @@ out:
  * Synchronous I/O uses a stack-allocated iocb.  Thus we can't trust
  * the iocb is still valid here if this is a synchronous request.
  */
-static void nfs_direct_complete(struct nfs_direct_req *dreq)
+static void nfs_direct_complete(struct nfs_direct_req *dreq, bool write)
 {
+       struct inode *inode = dreq->inode;
+
+       if (dreq->iocb && write) {
+               loff_t pos = dreq->iocb->ki_pos + dreq->count;
+
+               spin_lock(&inode->i_lock);
+               if (i_size_read(inode) < pos)
+                       i_size_write(inode, pos);
+               spin_unlock(&inode->i_lock);
+       }
+
+       if (write)
+               nfs_zap_mapping(inode, inode->i_mapping);
+
+       inode_dio_done(inode);
+
        if (dreq->iocb) {
                long res = (long) dreq->error;
                if (!res)
                        res = (long) dreq->count;
                aio_complete(dreq->iocb, res, 0);
        }
+
        complete_all(&dreq->completion);
 
        nfs_direct_req_release(dreq);
@@ -237,9 +254,9 @@ static void nfs_direct_complete(struct nfs_direct_req *dreq)
 
 static void nfs_direct_readpage_release(struct nfs_page *req)
 {
-       dprintk("NFS: direct read done (%s/%lld %d@%lld)\n",
+       dprintk("NFS: direct read done (%s/%llu %d@%lld)\n",
                req->wb_context->dentry->d_inode->i_sb->s_id,
-               (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+               (unsigned long long)NFS_FILEID(req->wb_context->dentry->d_inode),
                req->wb_bytes,
                (long long)req_offset(req));
        nfs_release_request(req);
@@ -272,7 +289,7 @@ static void nfs_direct_read_completion(struct nfs_pgio_header *hdr)
        }
 out_put:
        if (put_dreq(dreq))
-               nfs_direct_complete(dreq);
+               nfs_direct_complete(dreq, false);
        hdr->release(hdr);
 }
 
@@ -402,6 +419,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
                                              loff_t pos, bool uio)
 {
        struct nfs_pageio_descriptor desc;
+       struct inode *inode = dreq->inode;
        ssize_t result = -EINVAL;
        size_t requested_bytes = 0;
        unsigned long seg;
@@ -410,6 +428,7 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
                             &nfs_direct_read_completion_ops);
        get_dreq(dreq);
        desc.pg_dreq = dreq;
+       atomic_inc(&inode->i_dio_count);
 
        for (seg = 0; seg < nr_segs; seg++) {
                const struct iovec *vec = &iov[seg];
@@ -429,26 +448,69 @@ static ssize_t nfs_direct_read_schedule_iovec(struct nfs_direct_req *dreq,
         * generic layer handle the completion.
         */
        if (requested_bytes == 0) {
+               inode_dio_done(inode);
                nfs_direct_req_release(dreq);
                return result < 0 ? result : -EIO;
        }
 
        if (put_dreq(dreq))
-               nfs_direct_complete(dreq);
+               nfs_direct_complete(dreq, false);
        return 0;
 }
 
-static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
-                              unsigned long nr_segs, loff_t pos, bool uio)
+/**
+ * nfs_file_direct_read - file direct read operation for NFS files
+ * @iocb: target I/O control block
+ * @iov: vector of user buffers into which to read data
+ * @nr_segs: size of iov vector
+ * @pos: byte offset in file where reading starts
+ *
+ * We use this function for direct reads instead of calling
+ * generic_file_aio_read() in order to avoid gfar's check to see if
+ * the request starts before the end of the file.  For that check
+ * to work, we must generate a GETATTR before each direct read, and
+ * even then there is a window between the GETATTR and the subsequent
+ * READ where the file size could change.  Our preference is simply
+ * to do all reads the application wants, and the server will take
+ * care of managing the end of file boundary.
+ *
+ * This function also eliminates unnecessarily updating the file's
+ * atime locally, as the NFS server sets the file's atime, and this
+ * client must read the updated atime from the server back into its
+ * cache.
+ */
+ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
+                               unsigned long nr_segs, loff_t pos, bool uio)
 {
-       ssize_t result = -ENOMEM;
-       struct inode *inode = iocb->ki_filp->f_mapping->host;
+       struct file *file = iocb->ki_filp;
+       struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
        struct nfs_direct_req *dreq;
        struct nfs_lock_context *l_ctx;
+       ssize_t result = -EINVAL;
+       size_t count;
 
+       count = iov_length(iov, nr_segs);
+       nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
+
+       dfprintk(FILE, "NFS: direct read(%pD2, %zd@%Ld)\n",
+               file, count, (long long) pos);
+
+       result = 0;
+       if (!count)
+               goto out;
+
+       mutex_lock(&inode->i_mutex);
+       result = nfs_sync_mapping(mapping);
+       if (result)
+               goto out_unlock;
+
+       task_io_account_read(count);
+
+       result = -ENOMEM;
        dreq = nfs_direct_req_alloc();
        if (dreq == NULL)
-               goto out;
+               goto out_unlock;
 
        dreq->inode = inode;
        dreq->bytes_left = iov_length(iov, nr_segs);
@@ -464,20 +526,26 @@ static ssize_t nfs_direct_read(struct kiocb *iocb, const struct iovec *iov,
 
        NFS_I(inode)->read_io += iov_length(iov, nr_segs);
        result = nfs_direct_read_schedule_iovec(dreq, iov, nr_segs, pos, uio);
-       if (!result)
+
+       mutex_unlock(&inode->i_mutex);
+
+       if (!result) {
                result = nfs_direct_wait(dreq);
+               if (result > 0)
+                       iocb->ki_pos = pos + result;
+       }
+
+       nfs_direct_req_release(dreq);
+       return result;
+
 out_release:
        nfs_direct_req_release(dreq);
+out_unlock:
+       mutex_unlock(&inode->i_mutex);
 out:
        return result;
 }
 
-static void nfs_inode_dio_write_done(struct inode *inode)
-{
-       nfs_zap_mapping(inode, inode->i_mapping);
-       inode_dio_done(inode);
-}
-
 #if IS_ENABLED(CONFIG_NFS_V3) || IS_ENABLED(CONFIG_NFS_V4)
 static void nfs_direct_write_reschedule(struct nfs_direct_req *dreq)
 {
@@ -593,8 +661,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
                        nfs_direct_write_reschedule(dreq);
                        break;
                default:
-                       nfs_inode_dio_write_done(dreq->inode);
-                       nfs_direct_complete(dreq);
+                       nfs_direct_complete(dreq, true);
        }
 }
 
@@ -610,8 +677,7 @@ static void nfs_direct_write_schedule_work(struct work_struct *work)
 
 static void nfs_direct_write_complete(struct nfs_direct_req *dreq, struct inode *inode)
 {
-       nfs_inode_dio_write_done(inode);
-       nfs_direct_complete(dreq);
+       nfs_direct_complete(dreq, true);
 }
 #endif
 
@@ -842,93 +908,6 @@ static ssize_t nfs_direct_write_schedule_iovec(struct nfs_direct_req *dreq,
        return 0;
 }
 
-static ssize_t nfs_direct_write(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos,
-                               size_t count, bool uio)
-{
-       ssize_t result = -ENOMEM;
-       struct inode *inode = iocb->ki_filp->f_mapping->host;
-       struct nfs_direct_req *dreq;
-       struct nfs_lock_context *l_ctx;
-
-       dreq = nfs_direct_req_alloc();
-       if (!dreq)
-               goto out;
-
-       dreq->inode = inode;
-       dreq->bytes_left = count;
-       dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
-       l_ctx = nfs_get_lock_context(dreq->ctx);
-       if (IS_ERR(l_ctx)) {
-               result = PTR_ERR(l_ctx);
-               goto out_release;
-       }
-       dreq->l_ctx = l_ctx;
-       if (!is_sync_kiocb(iocb))
-               dreq->iocb = iocb;
-
-       result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, uio);
-       if (!result)
-               result = nfs_direct_wait(dreq);
-out_release:
-       nfs_direct_req_release(dreq);
-out:
-       return result;
-}
-
-/**
- * nfs_file_direct_read - file direct read operation for NFS files
- * @iocb: target I/O control block
- * @iov: vector of user buffers into which to read data
- * @nr_segs: size of iov vector
- * @pos: byte offset in file where reading starts
- *
- * We use this function for direct reads instead of calling
- * generic_file_aio_read() in order to avoid gfar's check to see if
- * the request starts before the end of the file.  For that check
- * to work, we must generate a GETATTR before each direct read, and
- * even then there is a window between the GETATTR and the subsequent
- * READ where the file size could change.  Our preference is simply
- * to do all reads the application wants, and the server will take
- * care of managing the end of file boundary.
- *
- * This function also eliminates unnecessarily updating the file's
- * atime locally, as the NFS server sets the file's atime, and this
- * client must read the updated atime from the server back into its
- * cache.
- */
-ssize_t nfs_file_direct_read(struct kiocb *iocb, const struct iovec *iov,
-                               unsigned long nr_segs, loff_t pos, bool uio)
-{
-       ssize_t retval = -EINVAL;
-       struct file *file = iocb->ki_filp;
-       struct address_space *mapping = file->f_mapping;
-       size_t count;
-
-       count = iov_length(iov, nr_segs);
-       nfs_add_stats(mapping->host, NFSIOS_DIRECTREADBYTES, count);
-
-       dfprintk(FILE, "NFS: direct read(%pD2, %zd@%Ld)\n",
-               file, count, (long long) pos);
-
-       retval = 0;
-       if (!count)
-               goto out;
-
-       retval = nfs_sync_mapping(mapping);
-       if (retval)
-               goto out;
-
-       task_io_account_read(count);
-
-       retval = nfs_direct_read(iocb, iov, nr_segs, pos, uio);
-       if (retval > 0)
-               iocb->ki_pos = pos + retval;
-
-out:
-       return retval;
-}
-
 /**
  * nfs_file_direct_write - file direct write operation for NFS files
  * @iocb: target I/O control block
@@ -954,46 +933,96 @@ out:
 ssize_t nfs_file_direct_write(struct kiocb *iocb, const struct iovec *iov,
                                unsigned long nr_segs, loff_t pos, bool uio)
 {
-       ssize_t retval = -EINVAL;
+       ssize_t result = -EINVAL;
        struct file *file = iocb->ki_filp;
        struct address_space *mapping = file->f_mapping;
+       struct inode *inode = mapping->host;
+       struct nfs_direct_req *dreq;
+       struct nfs_lock_context *l_ctx;
+       loff_t end;
        size_t count;
 
        count = iov_length(iov, nr_segs);
+       end = (pos + count - 1) >> PAGE_CACHE_SHIFT;
+
        nfs_add_stats(mapping->host, NFSIOS_DIRECTWRITTENBYTES, count);
 
        dfprintk(FILE, "NFS: direct write(%pD2, %zd@%Ld)\n",
                file, count, (long long) pos);
 
-       retval = generic_write_checks(file, &pos, &count, 0);
-       if (retval)
+       result = generic_write_checks(file, &pos, &count, 0);
+       if (result)
                goto out;
 
-       retval = -EINVAL;
+       result = -EINVAL;
        if ((ssize_t) count < 0)
                goto out;
-       retval = 0;
+       result = 0;
        if (!count)
                goto out;
 
-       retval = nfs_sync_mapping(mapping);
-       if (retval)
-               goto out;
+       mutex_lock(&inode->i_mutex);
+
+       result = nfs_sync_mapping(mapping);
+       if (result)
+               goto out_unlock;
+
+       if (mapping->nrpages) {
+               result = invalidate_inode_pages2_range(mapping,
+                                       pos >> PAGE_CACHE_SHIFT, end);
+               if (result)
+                       goto out_unlock;
+       }
 
        task_io_account_write(count);
 
-       retval = nfs_direct_write(iocb, iov, nr_segs, pos, count, uio);
-       if (retval > 0) {
-               struct inode *inode = mapping->host;
+       result = -ENOMEM;
+       dreq = nfs_direct_req_alloc();
+       if (!dreq)
+               goto out_unlock;
 
-               iocb->ki_pos = pos + retval;
-               spin_lock(&inode->i_lock);
-               if (i_size_read(inode) < iocb->ki_pos)
-                       i_size_write(inode, iocb->ki_pos);
-               spin_unlock(&inode->i_lock);
+       dreq->inode = inode;
+       dreq->bytes_left = count;
+       dreq->ctx = get_nfs_open_context(nfs_file_open_context(iocb->ki_filp));
+       l_ctx = nfs_get_lock_context(dreq->ctx);
+       if (IS_ERR(l_ctx)) {
+               result = PTR_ERR(l_ctx);
+               goto out_release;
+       }
+       dreq->l_ctx = l_ctx;
+       if (!is_sync_kiocb(iocb))
+               dreq->iocb = iocb;
+
+       result = nfs_direct_write_schedule_iovec(dreq, iov, nr_segs, pos, uio);
+
+       if (mapping->nrpages) {
+               invalidate_inode_pages2_range(mapping,
+                                             pos >> PAGE_CACHE_SHIFT, end);
        }
+
+       mutex_unlock(&inode->i_mutex);
+
+       if (!result) {
+               result = nfs_direct_wait(dreq);
+               if (result > 0) {
+                       struct inode *inode = mapping->host;
+
+                       iocb->ki_pos = pos + result;
+                       spin_lock(&inode->i_lock);
+                       if (i_size_read(inode) < iocb->ki_pos)
+                               i_size_write(inode, iocb->ki_pos);
+                       spin_unlock(&inode->i_lock);
+               }
+       }
+       nfs_direct_req_release(dreq);
+       return result;
+
+out_release:
+       nfs_direct_req_release(dreq);
+out_unlock:
+       mutex_unlock(&inode->i_mutex);
 out:
-       return retval;
+       return result;
 }
 
 /**
index e2fcacf07de349c6d937991744fbcbbd4c4c91fc..5bb790a69c7165fd8319104ebbdc2a09848ab8b3 100644 (file)
@@ -354,7 +354,7 @@ static int nfs_write_begin(struct file *file, struct address_space *mapping,
        struct page *page;
        int once_thru = 0;
 
-       dfprintk(PAGECACHE, "NFS: write_begin(%pD2(%ld), %u@%lld)\n",
+       dfprintk(PAGECACHE, "NFS: write_begin(%pD2(%lu), %u@%lld)\n",
                file, mapping->host->i_ino, len, (long long) pos);
 
 start:
@@ -395,7 +395,7 @@ static int nfs_write_end(struct file *file, struct address_space *mapping,
        struct nfs_open_context *ctx = nfs_file_open_context(file);
        int status;
 
-       dfprintk(PAGECACHE, "NFS: write_end(%pD2(%ld), %u@%lld)\n",
+       dfprintk(PAGECACHE, "NFS: write_end(%pD2(%lu), %u@%lld)\n",
                file, mapping->host->i_ino, len, (long long) pos);
 
        /*
@@ -585,7 +585,7 @@ static int nfs_vm_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
        int ret = VM_FAULT_NOPAGE;
        struct address_space *mapping;
 
-       dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%pD2(%ld), offset %lld)\n",
+       dfprintk(PAGECACHE, "NFS: vm_page_mkwrite(%pD2(%lu), offset %lld)\n",
                filp, filp->f_mapping->host->i_ino,
                (long long)page_offset(page));
 
index 00ad1c2b217ded2338c0ac4154681f83963581ab..28a0a3cbd3b7818ee255f3a3c57b738d098e48c3 100644 (file)
@@ -458,9 +458,9 @@ nfs_fhget(struct super_block *sb, struct nfs_fh *fh, struct nfs_fattr *fattr, st
                unlock_new_inode(inode);
        } else
                nfs_refresh_inode(inode, fattr);
-       dprintk("NFS: nfs_fhget(%s/%Ld fh_crc=0x%08x ct=%d)\n",
+       dprintk("NFS: nfs_fhget(%s/%Lu fh_crc=0x%08x ct=%d)\n",
                inode->i_sb->s_id,
-               (long long)NFS_FILEID(inode),
+               (unsigned long long)NFS_FILEID(inode),
                nfs_display_fhandle_hash(fh),
                atomic_read(&inode->i_count));
 
@@ -870,8 +870,8 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
        struct nfs_fattr *fattr = NULL;
        struct nfs_inode *nfsi = NFS_I(inode);
 
-       dfprintk(PAGECACHE, "NFS: revalidating (%s/%Ld)\n",
-               inode->i_sb->s_id, (long long)NFS_FILEID(inode));
+       dfprintk(PAGECACHE, "NFS: revalidating (%s/%Lu)\n",
+               inode->i_sb->s_id, (unsigned long long)NFS_FILEID(inode));
 
        trace_nfs_revalidate_inode_enter(inode);
 
@@ -895,9 +895,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 
        status = NFS_PROTO(inode)->getattr(server, NFS_FH(inode), fattr, label);
        if (status != 0) {
-               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) getattr failed, error=%d\n",
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) getattr failed, error=%d\n",
                         inode->i_sb->s_id,
-                        (long long)NFS_FILEID(inode), status);
+                        (unsigned long long)NFS_FILEID(inode), status);
                if (status == -ESTALE) {
                        nfs_zap_caches(inode);
                        if (!S_ISDIR(inode->i_mode))
@@ -908,9 +908,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 
        status = nfs_refresh_inode(inode, fattr);
        if (status) {
-               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Ld) refresh failed, error=%d\n",
+               dfprintk(PAGECACHE, "nfs_revalidate_inode: (%s/%Lu) refresh failed, error=%d\n",
                         inode->i_sb->s_id,
-                        (long long)NFS_FILEID(inode), status);
+                        (unsigned long long)NFS_FILEID(inode), status);
                goto err_out;
        }
 
@@ -919,9 +919,9 @@ __nfs_revalidate_inode(struct nfs_server *server, struct inode *inode)
 
        nfs_setsecurity(inode, fattr, label);
 
-       dfprintk(PAGECACHE, "NFS: (%s/%Ld) revalidation complete\n",
+       dfprintk(PAGECACHE, "NFS: (%s/%Lu) revalidation complete\n",
                inode->i_sb->s_id,
-               (long long)NFS_FILEID(inode));
+               (unsigned long long)NFS_FILEID(inode));
 
 err_out:
        nfs4_label_free(label);
@@ -977,16 +977,17 @@ static int nfs_invalidate_mapping(struct inode *inode, struct address_space *map
                if (ret < 0)
                        return ret;
        }
-       spin_lock(&inode->i_lock);
-       nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
-       if (S_ISDIR(inode->i_mode))
+       if (S_ISDIR(inode->i_mode)) {
+               spin_lock(&inode->i_lock);
                memset(nfsi->cookieverf, 0, sizeof(nfsi->cookieverf));
-       spin_unlock(&inode->i_lock);
+               spin_unlock(&inode->i_lock);
+       }
        nfs_inc_stats(inode, NFSIOS_DATAINVALIDATE);
        nfs_fscache_wait_on_invalidate(inode);
 
-       dfprintk(PAGECACHE, "NFS: (%s/%Ld) data cache invalidated\n",
-                       inode->i_sb->s_id, (long long)NFS_FILEID(inode));
+       dfprintk(PAGECACHE, "NFS: (%s/%Lu) data cache invalidated\n",
+                       inode->i_sb->s_id,
+                       (unsigned long long)NFS_FILEID(inode));
        return 0;
 }
 
@@ -1007,6 +1008,7 @@ static bool nfs_mapping_need_revalidate_inode(struct inode *inode)
 int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
 {
        struct nfs_inode *nfsi = NFS_I(inode);
+       unsigned long *bitlock = &nfsi->flags;
        int ret = 0;
 
        /* swapfiles are not supposed to be shared. */
@@ -1018,12 +1020,46 @@ int nfs_revalidate_mapping(struct inode *inode, struct address_space *mapping)
                if (ret < 0)
                        goto out;
        }
-       if (nfsi->cache_validity & NFS_INO_INVALID_DATA) {
-               trace_nfs_invalidate_mapping_enter(inode);
-               ret = nfs_invalidate_mapping(inode, mapping);
-               trace_nfs_invalidate_mapping_exit(inode, ret);
+
+       /*
+        * We must clear NFS_INO_INVALID_DATA first to ensure that
+        * invalidations that come in while we're shooting down the mappings
+        * are respected. But, that leaves a race window where one revalidator
+        * can clear the flag, and then another checks it before the mapping
+        * gets invalidated. Fix that by serializing access to this part of
+        * the function.
+        *
+        * At the same time, we need to allow other tasks to see whether we
+        * might be in the middle of invalidating the pages, so we only set
+        * the bit lock here if it looks like we're going to be doing that.
+        */
+       for (;;) {
+               ret = wait_on_bit(bitlock, NFS_INO_INVALIDATING,
+                                 nfs_wait_bit_killable, TASK_KILLABLE);
+               if (ret)
+                       goto out;
+               spin_lock(&inode->i_lock);
+               if (test_bit(NFS_INO_INVALIDATING, bitlock)) {
+                       spin_unlock(&inode->i_lock);
+                       continue;
+               }
+               if (nfsi->cache_validity & NFS_INO_INVALID_DATA)
+                       break;
+               spin_unlock(&inode->i_lock);
+               goto out;
        }
 
+       set_bit(NFS_INO_INVALIDATING, bitlock);
+       smp_wmb();
+       nfsi->cache_validity &= ~NFS_INO_INVALID_DATA;
+       spin_unlock(&inode->i_lock);
+       trace_nfs_invalidate_mapping_enter(inode);
+       ret = nfs_invalidate_mapping(inode, mapping);
+       trace_nfs_invalidate_mapping_exit(inode, ret);
+
+       clear_bit_unlock(NFS_INO_INVALIDATING, bitlock);
+       smp_mb__after_clear_bit();
+       wake_up_bit(bitlock, NFS_INO_INVALIDATING);
 out:
        return ret;
 }
@@ -1282,12 +1318,28 @@ static int nfs_inode_attrs_need_update(const struct inode *inode, const struct n
                ((long)nfsi->attr_gencount - (long)nfs_read_attr_generation_counter() > 0);
 }
 
+/*
+ * Don't trust the change_attribute, mtime, ctime or size if
+ * a pnfs LAYOUTCOMMIT is outstanding
+ */
+static void nfs_inode_attrs_handle_layoutcommit(struct inode *inode,
+               struct nfs_fattr *fattr)
+{
+       if (pnfs_layoutcommit_outstanding(inode))
+               fattr->valid &= ~(NFS_ATTR_FATTR_CHANGE |
+                               NFS_ATTR_FATTR_MTIME |
+                               NFS_ATTR_FATTR_CTIME |
+                               NFS_ATTR_FATTR_SIZE);
+}
+
 static int nfs_refresh_inode_locked(struct inode *inode, struct nfs_fattr *fattr)
 {
        int ret;
 
        trace_nfs_refresh_inode_enter(inode);
 
+       nfs_inode_attrs_handle_layoutcommit(inode, fattr);
+
        if (nfs_inode_attrs_need_update(inode, fattr))
                ret = nfs_update_inode(inode, fattr);
        else
@@ -1434,7 +1486,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
        unsigned long now = jiffies;
        unsigned long save_cache_validity;
 
-       dfprintk(VFS, "NFS: %s(%s/%ld fh_crc=0x%08x ct=%d info=0x%x)\n",
+       dfprintk(VFS, "NFS: %s(%s/%lu fh_crc=0x%08x ct=%d info=0x%x)\n",
                        __func__, inode->i_sb->s_id, inode->i_ino,
                        nfs_display_fhandle_hash(NFS_FH(inode)),
                        atomic_read(&inode->i_count), fattr->valid);
@@ -1455,7 +1507,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                /*
                * Big trouble! The inode has become a different object.
                */
-               printk(KERN_DEBUG "NFS: %s: inode %ld mode changed, %07o to %07o\n",
+               printk(KERN_DEBUG "NFS: %s: inode %lu mode changed, %07o to %07o\n",
                                __func__, inode->i_ino, inode->i_mode, fattr->mode);
                goto out_err;
        }
@@ -1517,8 +1569,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
                if (new_isize != cur_isize) {
                        /* Do we perhaps have any outstanding writes, or has
                         * the file grown beyond our last write? */
-                       if ((nfsi->npages == 0 && !test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) ||
-                            new_isize > cur_isize) {
+                       if ((nfsi->npages == 0) || new_isize > cur_isize) {
                                i_size_write(inode, new_isize);
                                invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
                        }
@@ -1641,10 +1692,6 @@ struct inode *nfs_alloc_inode(struct super_block *sb)
                return NULL;
        nfsi->flags = 0UL;
        nfsi->cache_validity = 0UL;
-#ifdef CONFIG_NFS_V3_ACL
-       nfsi->acl_access = ERR_PTR(-EAGAIN);
-       nfsi->acl_default = ERR_PTR(-EAGAIN);
-#endif
 #if IS_ENABLED(CONFIG_NFS_V4)
        nfsi->nfs4_acl = NULL;
 #endif /* CONFIG_NFS_V4 */
index 4a1aafba6a20030532ba589ac9db021b10c21ceb..9a5ca03fa539fc5fb61ea4516b0ce0b6f4ae10ea 100644 (file)
 
 #define NFSDBG_FACILITY        NFSDBG_PROC
 
-ssize_t nfs3_listxattr(struct dentry *dentry, char *buffer, size_t size)
-{
-       struct inode *inode = dentry->d_inode;
-       struct posix_acl *acl;
-       int pos=0, len=0;
-
-#      define output(s) do {                                           \
-                       if (pos + sizeof(s) <= size) {                  \
-                               memcpy(buffer + pos, s, sizeof(s));     \
-                               pos += sizeof(s);                       \
-                       }                                               \
-                       len += sizeof(s);                               \
-               } while(0)
-
-       acl = nfs3_proc_getacl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl) {
-               output("system.posix_acl_access");
-               posix_acl_release(acl);
-       }
-
-       if (S_ISDIR(inode->i_mode)) {
-               acl = nfs3_proc_getacl(inode, ACL_TYPE_DEFAULT);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               if (acl) {
-                       output("system.posix_acl_default");
-                       posix_acl_release(acl);
-               }
-       }
-
-#      undef output
-
-       if (!buffer || len <= size)
-               return len;
-       return -ERANGE;
-}
-
-ssize_t nfs3_getxattr(struct dentry *dentry, const char *name,
-               void *buffer, size_t size)
-{
-       struct inode *inode = dentry->d_inode;
-       struct posix_acl *acl;
-       int type, error = 0;
-
-       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
-               type = ACL_TYPE_ACCESS;
-       else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
-               type = ACL_TYPE_DEFAULT;
-       else
-               return -EOPNOTSUPP;
-
-       acl = nfs3_proc_getacl(inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       else if (acl) {
-               if (type == ACL_TYPE_ACCESS && acl->a_count == 0)
-                       error = -ENODATA;
-               else
-                       error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-               posix_acl_release(acl);
-       } else
-               error = -ENODATA;
-
-       return error;
-}
-
-int nfs3_setxattr(struct dentry *dentry, const char *name,
-            const void *value, size_t size, int flags)
-{
-       struct inode *inode = dentry->d_inode;
-       struct posix_acl *acl;
-       int type, error;
-
-       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
-               type = ACL_TYPE_ACCESS;
-       else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
-               type = ACL_TYPE_DEFAULT;
-       else
-               return -EOPNOTSUPP;
-
-       acl = posix_acl_from_xattr(&init_user_ns, value, size);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       error = nfs3_proc_setacl(inode, type, acl);
-       posix_acl_release(acl);
-
-       return error;
-}
-
-int nfs3_removexattr(struct dentry *dentry, const char *name)
-{
-       struct inode *inode = dentry->d_inode;
-       int type;
-
-       if (strcmp(name, POSIX_ACL_XATTR_ACCESS) == 0)
-               type = ACL_TYPE_ACCESS;
-       else if (strcmp(name, POSIX_ACL_XATTR_DEFAULT) == 0)
-               type = ACL_TYPE_DEFAULT;
-       else
-               return -EOPNOTSUPP;
-
-       return nfs3_proc_setacl(inode, type, NULL);
-}
-
-static void __nfs3_forget_cached_acls(struct nfs_inode *nfsi)
-{
-       if (!IS_ERR(nfsi->acl_access)) {
-               posix_acl_release(nfsi->acl_access);
-               nfsi->acl_access = ERR_PTR(-EAGAIN);
-       }
-       if (!IS_ERR(nfsi->acl_default)) {
-               posix_acl_release(nfsi->acl_default);
-               nfsi->acl_default = ERR_PTR(-EAGAIN);
-       }
-}
-
-void nfs3_forget_cached_acls(struct inode *inode)
-{
-       dprintk("NFS: nfs3_forget_cached_acls(%s/%ld)\n", inode->i_sb->s_id,
-               inode->i_ino);
-       spin_lock(&inode->i_lock);
-       __nfs3_forget_cached_acls(NFS_I(inode));
-       spin_unlock(&inode->i_lock);
-}
-
-static struct posix_acl *nfs3_get_cached_acl(struct inode *inode, int type)
-{
-       struct nfs_inode *nfsi = NFS_I(inode);
-       struct posix_acl *acl = ERR_PTR(-EINVAL);
-
-       spin_lock(&inode->i_lock);
-       switch(type) {
-               case ACL_TYPE_ACCESS:
-                       acl = nfsi->acl_access;
-                       break;
-
-               case ACL_TYPE_DEFAULT:
-                       acl = nfsi->acl_default;
-                       break;
-
-               default:
-                       goto out;
-       }
-       if (IS_ERR(acl))
-               acl = ERR_PTR(-EAGAIN);
-       else
-               acl = posix_acl_dup(acl);
-out:
-       spin_unlock(&inode->i_lock);
-       dprintk("NFS: nfs3_get_cached_acl(%s/%ld, %d) = %p\n", inode->i_sb->s_id,
-               inode->i_ino, type, acl);
-       return acl;
-}
-
-static void nfs3_cache_acls(struct inode *inode, struct posix_acl *acl,
-                   struct posix_acl *dfacl)
-{
-       struct nfs_inode *nfsi = NFS_I(inode);
-
-       dprintk("nfs3_cache_acls(%s/%ld, %p, %p)\n", inode->i_sb->s_id,
-               inode->i_ino, acl, dfacl);
-       spin_lock(&inode->i_lock);
-       __nfs3_forget_cached_acls(NFS_I(inode));
-       if (!IS_ERR(acl))
-               nfsi->acl_access = posix_acl_dup(acl);
-       if (!IS_ERR(dfacl))
-               nfsi->acl_default = posix_acl_dup(dfacl);
-       spin_unlock(&inode->i_lock);
-}
-
-struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
+struct posix_acl *nfs3_get_acl(struct inode *inode, int type)
 {
        struct nfs_server *server = NFS_SERVER(inode);
        struct page *pages[NFSACL_MAXPAGES] = { };
@@ -198,7 +26,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
                .rpc_argp       = &args,
                .rpc_resp       = &res,
        };
-       struct posix_acl *acl;
        int status, count;
 
        if (!nfs_server_capable(inode, NFS_CAP_ACLS))
@@ -207,10 +34,6 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
        status = nfs_revalidate_inode(server, inode);
        if (status < 0)
                return ERR_PTR(status);
-       acl = nfs3_get_cached_acl(inode, type);
-       if (acl != ERR_PTR(-EAGAIN))
-               return acl;
-       acl = NULL;
 
        /*
         * Only get the access acl when explicitly requested: We don't
@@ -257,40 +80,41 @@ struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type)
        }
 
        if (res.acl_access != NULL) {
-               if (posix_acl_equiv_mode(res.acl_access, NULL) == 0) {
+               if (posix_acl_equiv_mode(res.acl_access, NULL) ||
+                   res.acl_access->a_count == 0) {
                        posix_acl_release(res.acl_access);
                        res.acl_access = NULL;
                }
        }
-       nfs3_cache_acls(inode,
-               (res.mask & NFS_ACL)   ? res.acl_access  : ERR_PTR(-EINVAL),
-               (res.mask & NFS_DFACL) ? res.acl_default : ERR_PTR(-EINVAL));
 
-       switch(type) {
-               case ACL_TYPE_ACCESS:
-                       acl = res.acl_access;
-                       res.acl_access = NULL;
-                       break;
+       if (res.mask & NFS_ACL)
+               set_cached_acl(inode, ACL_TYPE_ACCESS, res.acl_access);
+       else
+               forget_cached_acl(inode, ACL_TYPE_ACCESS);
 
-               case ACL_TYPE_DEFAULT:
-                       acl = res.acl_default;
-                       res.acl_default = NULL;
+       if (res.mask & NFS_DFACL)
+               set_cached_acl(inode, ACL_TYPE_DEFAULT, res.acl_default);
+       else
+               forget_cached_acl(inode, ACL_TYPE_DEFAULT);
+
+       nfs_free_fattr(res.fattr);
+       if (type == ACL_TYPE_ACCESS) {
+               posix_acl_release(res.acl_default);
+               return res.acl_access;
+       } else {
+               posix_acl_release(res.acl_access);
+               return res.acl_default;
        }
 
 getout:
        posix_acl_release(res.acl_access);
        posix_acl_release(res.acl_default);
        nfs_free_fattr(res.fattr);
-
-       if (status != 0) {
-               posix_acl_release(acl);
-               acl = ERR_PTR(status);
-       }
-       return acl;
+       return ERR_PTR(status);
 }
 
-static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
-                 struct posix_acl *dfacl)
+int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
+               struct posix_acl *dfacl)
 {
        struct nfs_server *server = NFS_SERVER(inode);
        struct nfs_fattr *fattr;
@@ -353,7 +177,8 @@ static int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
        switch (status) {
                case 0:
                        status = nfs_refresh_inode(inode, fattr);
-                       nfs3_cache_acls(inode, acl, dfacl);
+                       set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
+                       set_cached_acl(inode, ACL_TYPE_DEFAULT, dfacl);
                        break;
                case -EPFNOSUPPORT:
                case -EPROTONOSUPPORT:
@@ -373,33 +198,27 @@ out:
        return status;
 }
 
-int nfs3_proc_setacl(struct inode *inode, int type, struct posix_acl *acl)
+int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
        struct posix_acl *alloc = NULL, *dfacl = NULL;
        int status;
 
        if (S_ISDIR(inode->i_mode)) {
                switch(type) {
-                       case ACL_TYPE_ACCESS:
-                               alloc = dfacl = nfs3_proc_getacl(inode,
-                                               ACL_TYPE_DEFAULT);
-                               if (IS_ERR(alloc))
-                                       goto fail;
-                               break;
-
-                       case ACL_TYPE_DEFAULT:
-                               dfacl = acl;
-                               alloc = acl = nfs3_proc_getacl(inode,
-                                               ACL_TYPE_ACCESS);
-                               if (IS_ERR(alloc))
-                                       goto fail;
-                               break;
-
-                       default:
-                               return -EINVAL;
+               case ACL_TYPE_ACCESS:
+                       alloc = dfacl = get_acl(inode, ACL_TYPE_DEFAULT);
+                       if (IS_ERR(alloc))
+                               goto fail;
+                       break;
+
+               case ACL_TYPE_DEFAULT:
+                       dfacl = acl;
+                       alloc = acl = get_acl(inode, ACL_TYPE_ACCESS);
+                       if (IS_ERR(alloc))
+                               goto fail;
+                       break;
                }
-       } else if (type != ACL_TYPE_ACCESS)
-                       return -EINVAL;
+       }
 
        if (acl == NULL) {
                alloc = acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
@@ -417,24 +236,24 @@ fail:
 int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
                umode_t mode)
 {
-       struct posix_acl *dfacl, *acl;
-       int error = 0;
+       struct posix_acl *default_acl, *acl;
+       int error;
 
-       dfacl = nfs3_proc_getacl(dir, ACL_TYPE_DEFAULT);
-       if (IS_ERR(dfacl)) {
-               error = PTR_ERR(dfacl);
+       error = posix_acl_create(dir, &mode, &default_acl, &acl);
+       if (error)
                return (error == -EOPNOTSUPP) ? 0 : error;
-       }
-       if (!dfacl)
-               return 0;
-       acl = posix_acl_dup(dfacl);
-       error = posix_acl_create(&acl, GFP_KERNEL, &mode);
-       if (error < 0)
-               goto out_release_dfacl;
-       error = nfs3_proc_setacls(inode, acl, S_ISDIR(inode->i_mode) ?
-                                                     dfacl : NULL);
-       posix_acl_release(acl);
-out_release_dfacl:
-       posix_acl_release(dfacl);
+
+       error = nfs3_proc_setacls(inode, acl, default_acl);
+
+       if (acl)
+               posix_acl_release(acl);
+       if (default_acl)
+               posix_acl_release(default_acl);
        return error;
 }
+
+const struct xattr_handler *nfs3_xattr_handlers[] = {
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
+       NULL,
+};
index 01b6f6a49d162ef0ea8720786e259fd5f66aa9d3..aa9bc973f36a31eacbca297c71f2cd9bb5fb81e9 100644 (file)
@@ -317,8 +317,8 @@ static int
 nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                 int flags)
 {
+       struct posix_acl *default_acl, *acl;
        struct nfs3_createdata *data;
-       umode_t mode = sattr->ia_mode;
        int status = -ENOMEM;
 
        dprintk("NFS call  create %pd\n", dentry);
@@ -340,7 +340,9 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                data->arg.create.verifier[1] = cpu_to_be32(current->pid);
        }
 
-       sattr->ia_mode &= ~current_umask();
+       status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
+       if (status)
+               goto out;
 
        for (;;) {
                status = nfs3_do_create(dir, dentry, data);
@@ -366,7 +368,7 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
        }
 
        if (status != 0)
-               goto out;
+               goto out_release_acls;
 
        /* When we created the file with exclusive semantics, make
         * sure we set the attributes afterwards. */
@@ -385,9 +387,14 @@ nfs3_proc_create(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                nfs_post_op_update_inode(dentry->d_inode, data->res.fattr);
                dprintk("NFS reply setattr (post-create): %d\n", status);
                if (status != 0)
-                       goto out;
+                       goto out_release_acls;
        }
-       status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
+
+       status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl);
+
+out_release_acls:
+       posix_acl_release(acl);
+       posix_acl_release(default_acl);
 out:
        nfs3_free_createdata(data);
        dprintk("NFS reply create: %d\n", status);
@@ -572,18 +579,20 @@ out:
 static int
 nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
 {
+       struct posix_acl *default_acl, *acl;
        struct nfs3_createdata *data;
-       umode_t mode = sattr->ia_mode;
        int status = -ENOMEM;
 
        dprintk("NFS call  mkdir %pd\n", dentry);
 
-       sattr->ia_mode &= ~current_umask();
-
        data = nfs3_alloc_createdata();
        if (data == NULL)
                goto out;
 
+       status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
+       if (status)
+               goto out;
+
        data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKDIR];
        data->arg.mkdir.fh = NFS_FH(dir);
        data->arg.mkdir.name = dentry->d_name.name;
@@ -592,9 +601,13 @@ nfs3_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr)
 
        status = nfs3_do_create(dir, dentry, data);
        if (status != 0)
-               goto out;
+               goto out_release_acls;
 
-       status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
+       status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl);
+
+out_release_acls:
+       posix_acl_release(acl);
+       posix_acl_release(default_acl);
 out:
        nfs3_free_createdata(data);
        dprintk("NFS reply mkdir: %d\n", status);
@@ -691,19 +704,21 @@ static int
 nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
                dev_t rdev)
 {
+       struct posix_acl *default_acl, *acl;
        struct nfs3_createdata *data;
-       umode_t mode = sattr->ia_mode;
        int status = -ENOMEM;
 
        dprintk("NFS call  mknod %pd %u:%u\n", dentry,
                        MAJOR(rdev), MINOR(rdev));
 
-       sattr->ia_mode &= ~current_umask();
-
        data = nfs3_alloc_createdata();
        if (data == NULL)
                goto out;
 
+       status = posix_acl_create(dir, &sattr->ia_mode, &default_acl, &acl);
+       if (status)
+               goto out;
+
        data->msg.rpc_proc = &nfs3_procedures[NFS3PROC_MKNOD];
        data->arg.mknod.fh = NFS_FH(dir);
        data->arg.mknod.name = dentry->d_name.name;
@@ -731,8 +746,13 @@ nfs3_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr,
 
        status = nfs3_do_create(dir, dentry, data);
        if (status != 0)
-               goto out;
-       status = nfs3_proc_set_default_acl(dir, dentry->d_inode, mode);
+               goto out_release_acls;
+
+       status = nfs3_proc_setacls(dentry->d_inode, acl, default_acl);
+
+out_release_acls:
+       posix_acl_release(acl);
+       posix_acl_release(default_acl);
 out:
        nfs3_free_createdata(data);
        dprintk("NFS reply mknod: %d\n", status);
@@ -904,20 +924,28 @@ static const struct inode_operations nfs3_dir_inode_operations = {
        .permission     = nfs_permission,
        .getattr        = nfs_getattr,
        .setattr        = nfs_setattr,
-       .listxattr      = nfs3_listxattr,
-       .getxattr       = nfs3_getxattr,
-       .setxattr       = nfs3_setxattr,
-       .removexattr    = nfs3_removexattr,
+#ifdef CONFIG_NFS_V3_ACL
+       .listxattr      = generic_listxattr,
+       .getxattr       = generic_getxattr,
+       .setxattr       = generic_setxattr,
+       .removexattr    = generic_removexattr,
+       .get_acl        = nfs3_get_acl,
+       .set_acl        = nfs3_set_acl,
+#endif
 };
 
 static const struct inode_operations nfs3_file_inode_operations = {
        .permission     = nfs_permission,
        .getattr        = nfs_getattr,
        .setattr        = nfs_setattr,
-       .listxattr      = nfs3_listxattr,
-       .getxattr       = nfs3_getxattr,
-       .setxattr       = nfs3_setxattr,
-       .removexattr    = nfs3_removexattr,
+#ifdef CONFIG_NFS_V3_ACL
+       .listxattr      = generic_listxattr,
+       .getxattr       = generic_getxattr,
+       .setxattr       = generic_setxattr,
+       .removexattr    = generic_removexattr,
+       .get_acl        = nfs3_get_acl,
+       .set_acl        = nfs3_set_acl,
+#endif
 };
 
 const struct nfs_rpc_ops nfs_v3_clientops = {
@@ -965,7 +993,7 @@ const struct nfs_rpc_ops nfs_v3_clientops = {
        .commit_rpc_prepare = nfs3_proc_commit_rpc_prepare,
        .commit_done    = nfs3_commit_done,
        .lock           = nfs3_proc_lock,
-       .clear_acl_cache = nfs3_forget_cached_acls,
+       .clear_acl_cache = forget_all_cached_acls,
        .close_context  = nfs_close_context,
        .have_delegation = nfs3_have_delegation,
        .return_delegation = nfs3_return_delegation,
index cc471c7252300060c4dae042f77c0190762961f5..d6a98949af191e5e79e8cf74adb26f2b8f3cc462 100644 (file)
@@ -12,6 +12,9 @@ static struct nfs_subversion nfs_v3 = {
        .rpc_vers = &nfs_version3,
        .rpc_ops  = &nfs_v3_clientops,
        .sops     = &nfs_sops,
+#ifdef CONFIG_NFS_V3_ACL
+       .xattr    = nfs3_xattr_handlers,
+#endif
 };
 
 static int __init init_nfs_v3(void)
index 5609edc742a0fc42568c73e7d26b4c2feb336c33..a5b27c2d9689f86704857b55365347e2f5c515d6 100644 (file)
@@ -270,6 +270,7 @@ static inline struct nfs4_session *nfs4_get_session(const struct nfs_server *ser
 extern int nfs41_setup_sequence(struct nfs4_session *session,
                struct nfs4_sequence_args *args, struct nfs4_sequence_res *res,
                struct rpc_task *task);
+extern int nfs41_sequence_done(struct rpc_task *, struct nfs4_sequence_res *);
 extern int nfs4_proc_create_session(struct nfs_client *, struct rpc_cred *);
 extern int nfs4_proc_destroy_session(struct nfs4_session *, struct rpc_cred *);
 extern int nfs4_proc_get_lease_time(struct nfs_client *clp,
index b4a160a405ce2b60f64255433c1555a4284c61e9..dbb3e1f30c68e25ea5a7905ffeb552fd8954cb81 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/sunrpc/auth.h>
 #include <linux/sunrpc/xprt.h>
 #include <linux/sunrpc/bc_xprt.h>
+#include <linux/sunrpc/rpc_pipe_fs.h>
 #include "internal.h"
 #include "callback.h"
 #include "delegation.h"
@@ -370,6 +371,7 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
                __set_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags);
        __set_bit(NFS_CS_DISCRTRY, &clp->cl_flags);
        __set_bit(NFS_CS_NO_RETRANS_TIMEOUT, &clp->cl_flags);
+
        error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_GSS_KRB5I);
        if (error == -EINVAL)
                error = nfs_create_rpc_client(clp, timeparms, RPC_AUTH_UNIX);
@@ -409,13 +411,11 @@ struct nfs_client *nfs4_init_client(struct nfs_client *clp,
        error = nfs4_discover_server_trunking(clp, &old);
        if (error < 0)
                goto error;
-       nfs_put_client(clp);
-       if (clp != old) {
-               clp->cl_preserve_clid = true;
-               clp = old;
-       }
 
-       return clp;
+       if (clp != old)
+               clp->cl_preserve_clid = true;
+       nfs_put_client(clp);
+       return old;
 
 error:
        nfs_mark_client_ready(clp, error);
@@ -493,9 +493,10 @@ int nfs40_walk_client_list(struct nfs_client *new,
                        prev = pos;
 
                        status = nfs_wait_client_init_complete(pos);
-                       spin_lock(&nn->nfs_client_lock);
                        if (status < 0)
-                               continue;
+                               goto out;
+                       status = -NFS4ERR_STALE_CLIENTID;
+                       spin_lock(&nn->nfs_client_lock);
                }
                if (pos->cl_cons_state != NFS_CS_READY)
                        continue;
@@ -633,7 +634,8 @@ int nfs41_walk_client_list(struct nfs_client *new,
                        }
                        spin_lock(&nn->nfs_client_lock);
                        if (status < 0)
-                               continue;
+                               break;
+                       status = -NFS4ERR_STALE_CLIENTID;
                }
                if (pos->cl_cons_state != NFS_CS_READY)
                        continue;
index b86464ba25e119711142e2b2959c1647d563f3e6..12c8132ad4081a3937c12ceebc991d1f61048093 100644 (file)
@@ -91,10 +91,10 @@ static void filelayout_reset_write(struct nfs_write_data *data)
 
        if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
                dprintk("%s Reset task %5u for i/o through MDS "
-                       "(req %s/%lld, %u bytes @ offset %llu)\n", __func__,
+                       "(req %s/%llu, %u bytes @ offset %llu)\n", __func__,
                        data->task.tk_pid,
                        hdr->inode->i_sb->s_id,
-                       (long long)NFS_FILEID(hdr->inode),
+                       (unsigned long long)NFS_FILEID(hdr->inode),
                        data->args.count,
                        (unsigned long long)data->args.offset);
 
@@ -112,10 +112,10 @@ static void filelayout_reset_read(struct nfs_read_data *data)
 
        if (!test_and_set_bit(NFS_IOHDR_REDO, &hdr->flags)) {
                dprintk("%s Reset task %5u for i/o through MDS "
-                       "(req %s/%lld, %u bytes @ offset %llu)\n", __func__,
+                       "(req %s/%llu, %u bytes @ offset %llu)\n", __func__,
                        data->task.tk_pid,
                        hdr->inode->i_sb->s_id,
-                       (long long)NFS_FILEID(hdr->inode),
+                       (unsigned long long)NFS_FILEID(hdr->inode),
                        data->args.count,
                        (unsigned long long)data->args.offset);
 
@@ -335,8 +335,10 @@ static void filelayout_read_call_done(struct rpc_task *task, void *data)
        dprintk("--> %s task->tk_status %d\n", __func__, task->tk_status);
 
        if (test_bit(NFS_IOHDR_REDO, &rdata->header->flags) &&
-           task->tk_status == 0)
+           task->tk_status == 0) {
+               nfs41_sequence_done(task, &rdata->res.seq_res);
                return;
+       }
 
        /* Note this may cause RPC to be resent */
        rdata->header->mds_ops->rpc_call_done(task, data);
@@ -442,8 +444,10 @@ static void filelayout_write_call_done(struct rpc_task *task, void *data)
        struct nfs_write_data *wdata = data;
 
        if (test_bit(NFS_IOHDR_REDO, &wdata->header->flags) &&
-           task->tk_status == 0)
+           task->tk_status == 0) {
+               nfs41_sequence_done(task, &wdata->res.seq_res);
                return;
+       }
 
        /* Note this may cause RPC to be resent */
        wdata->header->mds_ops->rpc_call_done(task, data);
@@ -1216,17 +1220,17 @@ static void filelayout_recover_commit_reqs(struct list_head *dst,
        struct pnfs_commit_bucket *b;
        int i;
 
-       /* NOTE cinfo->lock is NOT held, relying on fact that this is
-        * only called on single thread per dreq.
-        * Can't take the lock because need to do pnfs_put_lseg
-        */
+       spin_lock(cinfo->lock);
        for (i = 0, b = cinfo->ds->buckets; i < cinfo->ds->nbuckets; i++, b++) {
                if (transfer_commit_list(&b->written, dst, cinfo, 0)) {
+                       spin_unlock(cinfo->lock);
                        pnfs_put_lseg(b->wlseg);
                        b->wlseg = NULL;
+                       spin_lock(cinfo->lock);
                }
        }
        cinfo->ds->nwritten = 0;
+       spin_unlock(cinfo->lock);
 }
 
 static unsigned int
index c7c295e556ed87501c069053d0c133e44dcadc97..efac602edb37027a944601621baa8361c09f9fc9 100644 (file)
@@ -95,7 +95,7 @@ same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2)
                b6 = (struct sockaddr_in6 *)addr2;
 
                /* LINKLOCAL addresses must have matching scope_id */
-               if (ipv6_addr_scope(&a6->sin6_addr) ==
+               if (ipv6_addr_src_scope(&a6->sin6_addr) ==
                    IPV6_ADDR_SCOPE_LINKLOCAL &&
                    a6->sin6_scope_id != b6->sin6_scope_id)
                        return false;
index 15052b81df4245e4f797adb0d0b2e523338b23cc..42da6af77587bef4972ef8a84fc005b07aa4136f 100644 (file)
@@ -539,7 +539,7 @@ static int nfs40_sequence_done(struct rpc_task *task,
        struct nfs4_slot *slot = res->sr_slot;
        struct nfs4_slot_table *tbl;
 
-       if (!RPC_WAS_SENT(task))
+       if (slot == NULL)
                goto out;
 
        tbl = slot->table;
@@ -559,15 +559,10 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
 {
        struct nfs4_session *session;
        struct nfs4_slot_table *tbl;
+       struct nfs4_slot *slot = res->sr_slot;
        bool send_new_highest_used_slotid = false;
 
-       if (!res->sr_slot) {
-               /* just wake up the next guy waiting since
-                * we may have not consumed a slot after all */
-               dprintk("%s: No slot\n", __func__);
-               return;
-       }
-       tbl = res->sr_slot->table;
+       tbl = slot->table;
        session = tbl->session;
 
        spin_lock(&tbl->slot_tbl_lock);
@@ -577,11 +572,11 @@ static void nfs41_sequence_free_slot(struct nfs4_sequence_res *res)
        if (tbl->highest_used_slotid > tbl->target_highest_slotid)
                send_new_highest_used_slotid = true;
 
-       if (nfs41_wake_and_assign_slot(tbl, res->sr_slot)) {
+       if (nfs41_wake_and_assign_slot(tbl, slot)) {
                send_new_highest_used_slotid = false;
                goto out_unlock;
        }
-       nfs4_free_slot(tbl, res->sr_slot);
+       nfs4_free_slot(tbl, slot);
 
        if (tbl->highest_used_slotid != NFS4_NO_SLOT)
                send_new_highest_used_slotid = false;
@@ -592,19 +587,20 @@ out_unlock:
                nfs41_server_notify_highest_slotid_update(session->clp);
 }
 
-static int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
+int nfs41_sequence_done(struct rpc_task *task, struct nfs4_sequence_res *res)
 {
        struct nfs4_session *session;
-       struct nfs4_slot *slot;
+       struct nfs4_slot *slot = res->sr_slot;
        struct nfs_client *clp;
        bool interrupted = false;
        int ret = 1;
 
+       if (slot == NULL)
+               goto out_noaction;
        /* don't increment the sequence number if the task wasn't sent */
        if (!RPC_WAS_SENT(task))
                goto out;
 
-       slot = res->sr_slot;
        session = slot->table->session;
 
        if (slot->interrupted) {
@@ -679,6 +675,7 @@ out:
        /* The session may be reset by one of the error handlers. */
        dprintk("%s: Error %d free the slot \n", __func__, res->sr_status);
        nfs41_sequence_free_slot(res);
+out_noaction:
        return ret;
 retry_nowait:
        if (rpc_restart_call_prepare(task)) {
@@ -692,6 +689,7 @@ out_retry:
        rpc_delay(task, NFS4_POLL_RETRY_MAX);
        return 0;
 }
+EXPORT_SYMBOL_GPL(nfs41_sequence_done);
 
 static int nfs4_sequence_done(struct rpc_task *task,
                               struct nfs4_sequence_res *res)
@@ -2744,7 +2742,8 @@ static int _nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *f
                                NFS_CAP_OWNER_GROUP|NFS_CAP_ATIME|
                                NFS_CAP_CTIME|NFS_CAP_MTIME|
                                NFS_CAP_SECURITY_LABEL);
-               if (res.attr_bitmask[0] & FATTR4_WORD0_ACL)
+               if (res.attr_bitmask[0] & FATTR4_WORD0_ACL &&
+                               res.acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
                        server->caps |= NFS_CAP_ACLS;
                if (res.has_links != 0)
                        server->caps |= NFS_CAP_HARDLINKS;
@@ -4321,9 +4320,7 @@ static int nfs4_proc_renew(struct nfs_client *clp, struct rpc_cred *cred)
 
 static inline int nfs4_server_supports_acls(struct nfs_server *server)
 {
-       return (server->caps & NFS_CAP_ACLS)
-               && (server->acl_bitmask & ACL4_SUPPORT_ALLOW_ACL)
-               && (server->acl_bitmask & ACL4_SUPPORT_DENY_ACL);
+       return server->caps & NFS_CAP_ACLS;
 }
 
 /* Assuming that XATTR_SIZE_MAX is a multiple of PAGE_SIZE, and that
@@ -7409,9 +7406,9 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
        struct nfs_server *server = NFS_SERVER(inode);
        struct pnfs_layout_hdr *lo;
        struct nfs4_state *state = NULL;
-       unsigned long timeo, giveup;
+       unsigned long timeo, now, giveup;
 
-       dprintk("--> %s\n", __func__);
+       dprintk("--> %s tk_status => %d\n", __func__, -task->tk_status);
 
        if (!nfs41_sequence_done(task, &lgp->res.seq_res))
                goto out;
@@ -7419,12 +7416,38 @@ static void nfs4_layoutget_done(struct rpc_task *task, void *calldata)
        switch (task->tk_status) {
        case 0:
                goto out;
+       /*
+        * NFS4ERR_LAYOUTTRYLATER is a conflict with another client
+        * (or clients) writing to the same RAID stripe
+        */
        case -NFS4ERR_LAYOUTTRYLATER:
+       /*
+        * NFS4ERR_RECALLCONFLICT is when conflict with self (must recall
+        * existing layout before getting a new one).
+        */
        case -NFS4ERR_RECALLCONFLICT:
                timeo = rpc_get_timeout(task->tk_client);
                giveup = lgp->args.timestamp + timeo;
-               if (time_after(giveup, jiffies))
-                       task->tk_status = -NFS4ERR_DELAY;
+               now = jiffies;
+               if (time_after(giveup, now)) {
+                       unsigned long delay;
+
+                       /* Delay for:
+                        * - Not less then NFS4_POLL_RETRY_MIN.
+                        * - One last time a jiffie before we give up
+                        * - exponential backoff (time_now minus start_attempt)
+                        */
+                       delay = max_t(unsigned long, NFS4_POLL_RETRY_MIN,
+                                   min((giveup - now - 1),
+                                       now - lgp->args.timestamp));
+
+                       dprintk("%s: NFS4ERR_RECALLCONFLICT waiting %lu\n",
+                               __func__, delay);
+                       rpc_delay(task, delay);
+                       task->tk_status = 0;
+                       rpc_restart_call_prepare(task);
+                       goto out; /* Do not call nfs4_async_handle_error() */
+               }
                break;
        case -NFS4ERR_EXPIRED:
        case -NFS4ERR_BAD_STATEID:
@@ -7780,10 +7803,7 @@ nfs4_layoutcommit_done(struct rpc_task *task, void *calldata)
        case -NFS4ERR_BADLAYOUT:     /* no layout */
        case -NFS4ERR_GRACE:        /* loca_recalim always false */
                task->tk_status = 0;
-               break;
        case 0:
-               nfs_post_op_update_inode_force_wcc(data->args.inode,
-                                                  data->res.fattr);
                break;
        default:
                if (nfs4_async_handle_error(task, server, NULL) == -EAGAIN) {
@@ -7798,6 +7818,8 @@ static void nfs4_layoutcommit_release(void *calldata)
        struct nfs4_layoutcommit_data *data = calldata;
 
        pnfs_cleanup_layoutcommit(data);
+       nfs_post_op_update_inode_force_wcc(data->args.inode,
+                                          data->res.fattr);
        put_rpccred(data->cred);
        kfree(data);
 }
@@ -7920,7 +7942,7 @@ nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle,
                switch (err) {
                case 0:
                case -NFS4ERR_WRONGSEC:
-               case -NFS4ERR_NOTSUPP:
+               case -ENOTSUPP:
                        goto out;
                default:
                        err = nfs4_handle_exception(server, err, &exception);
@@ -7954,7 +7976,7 @@ nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle,
         * Fall back on "guess and check" method if
         * the server doesn't support SECINFO_NO_NAME
         */
-       if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) {
+       if (err == -NFS4ERR_WRONGSEC || err == -ENOTSUPP) {
                err = nfs4_find_root_sec(server, fhandle, info);
                goto out_freepage;
        }
index 059c01b67a7164a6d782139fb7b66b0d3976ad21..e5be72518bd7ebe813522b1c24f7fa16b539421e 100644 (file)
@@ -1071,7 +1071,7 @@ void nfs_free_seqid(struct nfs_seqid *seqid)
 /*
  * Increment the seqid if the OPEN/OPEN_DOWNGRADE/CLOSE succeeded, or
  * failed with a seqid incrementing error -
- * see comments nfs_fs.h:seqid_mutating_error()
+ * see comments nfs4.h:seqid_mutating_error()
  */
 static void nfs_increment_seqid(int status, struct nfs_seqid *seqid)
 {
@@ -1116,7 +1116,7 @@ void nfs_increment_open_seqid(int status, struct nfs_seqid *seqid)
 /*
  * Increment the seqid if the LOCK/LOCKU succeeded, or
  * failed with a seqid incrementing error -
- * see comments nfs_fs.h:seqid_mutating_error()
+ * see comments nfs4.h:seqid_mutating_error()
  */
 void nfs_increment_lock_seqid(int status, struct nfs_seqid *seqid)
 {
index 65ab0a0ca1c47242090bc14dc97e9cf1fcec525a..808f295744127918313fa497c1c5347a850e329f 100644 (file)
@@ -77,17 +77,9 @@ static int nfs4_write_inode(struct inode *inode, struct writeback_control *wbc)
 {
        int ret = nfs_write_inode(inode, wbc);
 
-       if (ret >= 0 && test_bit(NFS_INO_LAYOUTCOMMIT, &NFS_I(inode)->flags)) {
-               int status;
-               bool sync = true;
-
-               if (wbc->sync_mode == WB_SYNC_NONE)
-                       sync = false;
-
-               status = pnfs_layoutcommit_inode(inode, sync);
-               if (status < 0)
-                       return status;
-       }
+       if (ret == 0)
+               ret = pnfs_layoutcommit_inode(inode,
+                               wbc->sync_mode == WB_SYNC_ALL);
        return ret;
 }
 
index 5be2868c02f15e63c33eaea848f077e1e7b3d889..72f3bf1754ef770c3c7b2f1346225e1440ec968b 100644 (file)
@@ -3097,7 +3097,8 @@ out_overflow:
        return -EIO;
 }
 
-static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
+static bool __decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected,
+               int *nfs_retval)
 {
        __be32 *p;
        uint32_t opnum;
@@ -3107,19 +3108,32 @@ static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
        if (unlikely(!p))
                goto out_overflow;
        opnum = be32_to_cpup(p++);
-       if (opnum != expected) {
-               dprintk("nfs: Server returned operation"
-                       " %d but we issued a request for %d\n",
-                               opnum, expected);
-               return -EIO;
-       }
+       if (unlikely(opnum != expected))
+               goto out_bad_operation;
        nfserr = be32_to_cpup(p);
-       if (nfserr != NFS_OK)
-               return nfs4_stat_to_errno(nfserr);
-       return 0;
+       if (nfserr == NFS_OK)
+               *nfs_retval = 0;
+       else
+               *nfs_retval = nfs4_stat_to_errno(nfserr);
+       return true;
+out_bad_operation:
+       dprintk("nfs: Server returned operation"
+               " %d but we issued a request for %d\n",
+                       opnum, expected);
+       *nfs_retval = -EREMOTEIO;
+       return false;
 out_overflow:
        print_overflow_msg(__func__, xdr);
-       return -EIO;
+       *nfs_retval = -EIO;
+       return false;
+}
+
+static int decode_op_hdr(struct xdr_stream *xdr, enum nfs_opnum4 expected)
+{
+       int retval;
+
+       __decode_op_hdr(xdr, expected, &retval);
+       return retval;
 }
 
 /* Dummy routine */
@@ -3435,7 +3449,7 @@ static int decode_attr_aclsupport(struct xdr_stream *xdr, uint32_t *bitmap, uint
 {
        __be32 *p;
 
-       *res = ACL4_SUPPORT_ALLOW_ACL|ACL4_SUPPORT_DENY_ACL;
+       *res = 0;
        if (unlikely(bitmap[0] & (FATTR4_WORD0_ACLSUPPORT - 1U)))
                return -EIO;
        if (likely(bitmap[0] & FATTR4_WORD0_ACLSUPPORT)) {
@@ -5001,11 +5015,12 @@ static int decode_open(struct xdr_stream *xdr, struct nfs_openres *res)
        uint32_t savewords, bmlen, i;
        int status;
 
-       status = decode_op_hdr(xdr, OP_OPEN);
-       if (status != -EIO)
-               nfs_increment_open_seqid(status, res->seqid);
-       if (!status)
-               status = decode_stateid(xdr, &res->stateid);
+       if (!__decode_op_hdr(xdr, OP_OPEN, &status))
+               return status;
+       nfs_increment_open_seqid(status, res->seqid);
+       if (status)
+               return status;
+       status = decode_stateid(xdr, &res->stateid);
        if (unlikely(status))
                return status;
 
index 89fe741e58b1f7280f44e882f640259b8a8af144..59f838cdc009307f539bb94ee75f3447bfd79a56 100644 (file)
@@ -36,6 +36,7 @@
        __print_flags(v, "|", \
                        { 1 << NFS_INO_ADVISE_RDPLUS, "ADVISE_RDPLUS" }, \
                        { 1 << NFS_INO_STALE, "STALE" }, \
+                       { 1 << NFS_INO_INVALIDATING, "INVALIDATING" }, \
                        { 1 << NFS_INO_FLUSHING, "FLUSHING" }, \
                        { 1 << NFS_INO_FSCACHE, "FSCACHE" }, \
                        { 1 << NFS_INO_COMMIT, "COMMIT" }, \
index d75d938d36cbff83bee4f905e142eeaf95c9b33b..4755858e37a0b93f64643811f683b0de7f0d6def 100644 (file)
@@ -1790,6 +1790,15 @@ pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc)
 }
 EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages);
 
+static void pnfs_clear_layoutcommitting(struct inode *inode)
+{
+       unsigned long *bitlock = &NFS_I(inode)->flags;
+
+       clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
+       smp_mb__after_clear_bit();
+       wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
+}
+
 /*
  * There can be multiple RW segments.
  */
@@ -1807,7 +1816,6 @@ static void pnfs_list_write_lseg(struct inode *inode, struct list_head *listp)
 static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *listp)
 {
        struct pnfs_layout_segment *lseg, *tmp;
-       unsigned long *bitlock = &NFS_I(inode)->flags;
 
        /* Matched by references in pnfs_set_layoutcommit */
        list_for_each_entry_safe(lseg, tmp, listp, pls_lc_list) {
@@ -1815,9 +1823,7 @@ static void pnfs_list_write_lseg_done(struct inode *inode, struct list_head *lis
                pnfs_put_lseg(lseg);
        }
 
-       clear_bit_unlock(NFS_INO_LAYOUTCOMMITTING, bitlock);
-       smp_mb__after_clear_bit();
-       wake_up_bit(bitlock, NFS_INO_LAYOUTCOMMITTING);
+       pnfs_clear_layoutcommitting(inode);
 }
 
 void pnfs_set_lo_fail(struct pnfs_layout_segment *lseg)
@@ -1881,43 +1887,37 @@ pnfs_layoutcommit_inode(struct inode *inode, bool sync)
        struct nfs4_layoutcommit_data *data;
        struct nfs_inode *nfsi = NFS_I(inode);
        loff_t end_pos;
-       int status = 0;
+       int status;
 
-       dprintk("--> %s inode %lu\n", __func__, inode->i_ino);
-
-       if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
+       if (!pnfs_layoutcommit_outstanding(inode))
                return 0;
 
-       /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */
-       data = kzalloc(sizeof(*data), GFP_NOFS);
-       if (!data) {
-               status = -ENOMEM;
-               goto out;
-       }
-
-       if (!test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
-               goto out_free;
+       dprintk("--> %s inode %lu\n", __func__, inode->i_ino);
 
+       status = -EAGAIN;
        if (test_and_set_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags)) {
-               if (!sync) {
-                       status = -EAGAIN;
-                       goto out_free;
-               }
-               status = wait_on_bit_lock(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING,
-                                       nfs_wait_bit_killable, TASK_KILLABLE);
+               if (!sync)
+                       goto out;
+               status = wait_on_bit_lock(&nfsi->flags,
+                               NFS_INO_LAYOUTCOMMITTING,
+                               nfs_wait_bit_killable,
+                               TASK_KILLABLE);
                if (status)
-                       goto out_free;
+                       goto out;
        }
 
-       INIT_LIST_HEAD(&data->lseg_list);
+       status = -ENOMEM;
+       /* Note kzalloc ensures data->res.seq_res.sr_slot == NULL */
+       data = kzalloc(sizeof(*data), GFP_NOFS);
+       if (!data)
+               goto clear_layoutcommitting;
+
+       status = 0;
        spin_lock(&inode->i_lock);
-       if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags)) {
-               clear_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags);
-               spin_unlock(&inode->i_lock);
-               wake_up_bit(&nfsi->flags, NFS_INO_LAYOUTCOMMITTING);
-               goto out_free;
-       }
+       if (!test_and_clear_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags))
+               goto out_unlock;
 
+       INIT_LIST_HEAD(&data->lseg_list);
        pnfs_list_write_lseg(inode, &data->lseg_list);
 
        end_pos = nfsi->layout->plh_lwb;
@@ -1940,8 +1940,11 @@ out:
                mark_inode_dirty_sync(inode);
        dprintk("<-- %s status %d\n", __func__, status);
        return status;
-out_free:
+out_unlock:
+       spin_unlock(&inode->i_lock);
        kfree(data);
+clear_layoutcommitting:
+       pnfs_clear_layoutcommitting(inode);
        goto out;
 }
 
index a4f41810a7f497fbe5b34d497d8c1a5078a44524..023793909778ef975b3441d19b8d8632845bc2c4 100644 (file)
@@ -359,6 +359,15 @@ pnfs_ld_layoutret_on_setattr(struct inode *inode)
                PNFS_LAYOUTRET_ON_SETATTR;
 }
 
+static inline bool
+pnfs_layoutcommit_outstanding(struct inode *inode)
+{
+       struct nfs_inode *nfsi = NFS_I(inode);
+
+       return test_bit(NFS_INO_LAYOUTCOMMIT, &nfsi->flags) != 0 ||
+               test_bit(NFS_INO_LAYOUTCOMMITTING, &nfsi->flags) != 0;
+}
+
 static inline int pnfs_return_layout(struct inode *ino)
 {
        struct nfs_inode *nfsi = NFS_I(ino);
@@ -515,6 +524,13 @@ pnfs_use_threshold(struct nfs4_threshold **dst, struct nfs4_threshold *src,
        return false;
 }
 
+static inline bool
+pnfs_layoutcommit_outstanding(struct inode *inode)
+{
+       return false;
+}
+
+
 static inline struct nfs4_threshold *pnfs_mdsthreshold_alloc(void)
 {
        return NULL;
index 31db5c366b816e4c18d806ae0ae80d0c9207905e..411aedda14bb70c413fc771eb2a44e60817ed8ff 100644 (file)
@@ -163,9 +163,9 @@ static void nfs_readpage_release(struct nfs_page *req)
 
        unlock_page(req->wb_page);
 
-       dprintk("NFS: read done (%s/%Ld %d@%Ld)\n",
+       dprintk("NFS: read done (%s/%Lu %d@%Ld)\n",
                        req->wb_context->dentry->d_inode->i_sb->s_id,
-                       (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+                       (unsigned long long)NFS_FILEID(req->wb_context->dentry->d_inode),
                        req->wb_bytes,
                        (long long)req_offset(req));
        nfs_release_request(req);
@@ -228,11 +228,11 @@ int nfs_initiate_read(struct rpc_clnt *clnt,
        /* Set up the initial task struct. */
        NFS_PROTO(inode)->read_setup(data, &msg);
 
-       dprintk("NFS: %5u initiated read call (req %s/%lld, %u bytes @ "
+       dprintk("NFS: %5u initiated read call (req %s/%llu, %u bytes @ "
                        "offset %llu)\n",
                        data->task.tk_pid,
                        inode->i_sb->s_id,
-                       (long long)NFS_FILEID(inode),
+                       (unsigned long long)NFS_FILEID(inode),
                        data->args.count,
                        (unsigned long long)data->args.offset);
 
@@ -630,9 +630,9 @@ int nfs_readpages(struct file *filp, struct address_space *mapping,
        unsigned long npages;
        int ret = -ESTALE;
 
-       dprintk("NFS: nfs_readpages (%s/%Ld %d)\n",
+       dprintk("NFS: nfs_readpages (%s/%Lu %d)\n",
                        inode->i_sb->s_id,
-                       (long long)NFS_FILEID(inode),
+                       (unsigned long long)NFS_FILEID(inode),
                        nr_pages);
        nfs_inc_stats(inode, NFSIOS_VFSREADPAGES);
 
index c1d548211c31dfab94dec9252cc3d929cfe42daa..9a3b6a4cd6b9581a037f2508e5b6d4aca565cd93 100644 (file)
@@ -909,9 +909,14 @@ bool nfs_ctx_key_to_expire(struct nfs_open_context *ctx)
  */
 static bool nfs_write_pageuptodate(struct page *page, struct inode *inode)
 {
+       struct nfs_inode *nfsi = NFS_I(inode);
+
        if (nfs_have_delegated_attributes(inode))
                goto out;
-       if (NFS_I(inode)->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE))
+       if (nfsi->cache_validity & (NFS_INO_INVALID_DATA|NFS_INO_REVAL_PAGECACHE))
+               return false;
+       smp_rmb();
+       if (test_bit(NFS_INO_INVALIDATING, &nfsi->flags))
                return false;
 out:
        return PageUptodate(page) != 0;
@@ -922,19 +927,20 @@ out:
  * extend the write to cover the entire page in order to avoid fragmentation
  * inefficiencies.
  *
- * If the file is opened for synchronous writes or if we have a write delegation
- * from the server then we can just skip the rest of the checks.
+ * If the file is opened for synchronous writes then we can just skip the rest
+ * of the checks.
  */
 static int nfs_can_extend_write(struct file *file, struct page *page, struct inode *inode)
 {
        if (file->f_flags & O_DSYNC)
                return 0;
+       if (!nfs_write_pageuptodate(page, inode))
+               return 0;
        if (NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
                return 1;
-       if (nfs_write_pageuptodate(page, inode) && (inode->i_flock == NULL ||
-                       (inode->i_flock->fl_start == 0 &&
+       if (inode->i_flock == NULL || (inode->i_flock->fl_start == 0 &&
                        inode->i_flock->fl_end == OFFSET_MAX &&
-                       inode->i_flock->fl_type != F_RDLCK)))
+                       inode->i_flock->fl_type != F_RDLCK))
                return 1;
        return 0;
 }
@@ -1013,10 +1019,10 @@ int nfs_initiate_write(struct rpc_clnt *clnt,
        NFS_PROTO(inode)->write_setup(data, &msg);
 
        dprintk("NFS: %5u initiated write call "
-               "(req %s/%lld, %u bytes @ offset %llu)\n",
+               "(req %s/%llu, %u bytes @ offset %llu)\n",
                data->task.tk_pid,
                inode->i_sb->s_id,
-               (long long)NFS_FILEID(inode),
+               (unsigned long long)NFS_FILEID(inode),
                data->args.count,
                (unsigned long long)data->args.offset);
 
@@ -1606,9 +1612,9 @@ static void nfs_commit_release_pages(struct nfs_commit_data *data)
                nfs_list_remove_request(req);
                nfs_clear_page_commit(req->wb_page);
 
-               dprintk("NFS:       commit (%s/%lld %d@%lld)",
+               dprintk("NFS:       commit (%s/%llu %d@%lld)",
                        req->wb_context->dentry->d_sb->s_id,
-                       (long long)NFS_FILEID(req->wb_context->dentry->d_inode),
+                       (unsigned long long)NFS_FILEID(req->wb_context->dentry->d_inode),
                        req->wb_bytes,
                        (long long)req_offset(req));
                if (status < 0) {
index 8b186a4955cc8c1cd5c84e3aadc2397370ea1086..a812fd1b92a4593fc744606e5ae15ff128c8e2c7 100644 (file)
@@ -35,7 +35,9 @@
 #ifndef LINUX_NFS4_ACL_H
 #define LINUX_NFS4_ACL_H
 
-#include <linux/posix_acl.h>
+struct nfs4_acl;
+struct svc_fh;
+struct svc_rqst;
 
 /* Maximum ACL we'll accept from client; chosen (somewhat arbitrarily) to
  * fit in a page: */
 
 struct nfs4_acl *nfs4_acl_new(int);
 int nfs4_acl_get_whotype(char *, u32);
-int nfs4_acl_write_who(int who, char *p);
+__be32 nfs4_acl_write_who(int who, __be32 **p, int *len);
 
-#define NFS4_ACL_TYPE_DEFAULT  0x01
-#define NFS4_ACL_DIR           0x02
-#define NFS4_ACL_OWNER         0x04
-
-struct nfs4_acl *nfs4_acl_posix_to_nfsv4(struct posix_acl *,
-                               struct posix_acl *, unsigned int flags);
-int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *, struct posix_acl **,
-                               struct posix_acl **, unsigned int flags);
+int nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
+               struct nfs4_acl **acl);
+__be32 nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               struct nfs4_acl *acl);
 
 #endif /* LINUX_NFS4_ACL_H */
index d5c5b3e00266219320720944a17a7e7be6feb811..b582f9ab6b2a9a492a31abc60625ec56ab5d3912 100644 (file)
@@ -84,12 +84,4 @@ int  nfsd_cache_lookup(struct svc_rqst *);
 void   nfsd_cache_update(struct svc_rqst *, int, __be32 *);
 int    nfsd_reply_cache_stats_open(struct inode *, struct file *);
 
-#ifdef CONFIG_NFSD_V4
-void   nfsd4_set_statp(struct svc_rqst *rqstp, __be32 *statp);
-#else  /* CONFIG_NFSD_V4 */
-static inline void nfsd4_set_statp(struct svc_rqst *rqstp, __be32 *statp)
-{
-}
-#endif /* CONFIG_NFSD_V4 */
-
 #endif /* NFSCACHE_H */
index bf95f6b817a49c36ceb3b1be4af4ab7ea9eaf19b..66e58db019369cc95f9881702b4791e274396787 100644 (file)
@@ -56,7 +56,7 @@ static inline void nfsd_idmap_shutdown(struct net *net)
 
 __be32 nfsd_map_name_to_uid(struct svc_rqst *, const char *, size_t, kuid_t *);
 __be32 nfsd_map_name_to_gid(struct svc_rqst *, const char *, size_t, kgid_t *);
-int nfsd_map_uid_to_name(struct svc_rqst *, kuid_t, char *);
-int nfsd_map_gid_to_name(struct svc_rqst *, kgid_t, char *);
+__be32 nfsd4_encode_user(struct svc_rqst *, kuid_t, __be32 **, int *);
+__be32 nfsd4_encode_group(struct svc_rqst *, kgid_t, __be32 **, int *);
 
 #endif /* LINUX_NFSD_IDMAP_H */
index 849a7c3ced22cbacf33c3fa3e33802b43e3fb798..d32b3aa6600da986ab964ec2c30a4493c24eb5cb 100644 (file)
@@ -95,6 +95,7 @@ struct nfsd_net {
        time_t nfsd4_grace;
 
        bool nfsd_net_up;
+       bool lockd_up;
 
        /*
         * Time of server startup
index 95d76dc6c5da5bf313c4778eaa8220eb91ac1665..11c1fba293124f0eba92a066262ab60f7bd9c600 100644 (file)
@@ -30,8 +30,9 @@ nfsacld_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
                struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
 {
-       svc_fh *fh;
        struct posix_acl *acl;
+       struct inode *inode;
+       svc_fh *fh;
        __be32 nfserr = 0;
 
        dprintk("nfsd: GETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
@@ -41,6 +42,8 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
        if (nfserr)
                RETURN_STATUS(nfserr);
 
+       inode = fh->fh_dentry->d_inode;
+
        if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
                RETURN_STATUS(nfserr_inval);
        resp->mask = argp->mask;
@@ -50,21 +53,13 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
                goto fail;
 
        if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
-               acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
+               acl = get_acl(inode, ACL_TYPE_ACCESS);
                if (IS_ERR(acl)) {
-                       int err = PTR_ERR(acl);
-
-                       if (err == -ENODATA || err == -EOPNOTSUPP)
-                               acl = NULL;
-                       else {
-                               nfserr = nfserrno(err);
-                               goto fail;
-                       }
+                       nfserr = nfserrno(PTR_ERR(acl));
+                       goto fail;
                }
                if (acl == NULL) {
                        /* Solaris returns the inode's minimum ACL. */
-
-                       struct inode *inode = fh->fh_dentry->d_inode;
                        acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
                }
                resp->acl_access = acl;
@@ -72,17 +67,10 @@ static __be32 nfsacld_proc_getacl(struct svc_rqst * rqstp,
        if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
                /* Check how Solaris handles requests for the Default ACL
                   of a non-directory! */
-
-               acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
+               acl = get_acl(inode, ACL_TYPE_DEFAULT);
                if (IS_ERR(acl)) {
-                       int err = PTR_ERR(acl);
-
-                       if (err == -ENODATA || err == -EOPNOTSUPP)
-                               acl = NULL;
-                       else {
-                               nfserr = nfserrno(err);
-                               goto fail;
-                       }
+                       nfserr = nfserrno(PTR_ERR(acl));
+                       goto fail;
                }
                resp->acl_default = acl;
        }
@@ -103,31 +91,51 @@ static __be32 nfsacld_proc_setacl(struct svc_rqst * rqstp,
                struct nfsd3_setaclargs *argp,
                struct nfsd_attrstat *resp)
 {
+       struct inode *inode;
        svc_fh *fh;
        __be32 nfserr = 0;
+       int error;
 
        dprintk("nfsd: SETACL(2acl)   %s\n", SVCFH_fmt(&argp->fh));
 
        fh = fh_copy(&resp->fh, &argp->fh);
        nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
+       if (nfserr)
+               goto out;
 
-       if (!nfserr) {
-               nfserr = nfserrno( nfsd_set_posix_acl(
-                       fh, ACL_TYPE_ACCESS, argp->acl_access) );
-       }
-       if (!nfserr) {
-               nfserr = nfserrno( nfsd_set_posix_acl(
-                       fh, ACL_TYPE_DEFAULT, argp->acl_default) );
-       }
-       if (!nfserr) {
-               nfserr = fh_getattr(fh, &resp->stat);
+       inode = fh->fh_dentry->d_inode;
+       if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) {
+               error = -EOPNOTSUPP;
+               goto out_errno;
        }
 
+       error = fh_want_write(fh);
+       if (error)
+               goto out_errno;
+
+       error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS);
+       if (error)
+               goto out_drop_write;
+       error = inode->i_op->set_acl(inode, argp->acl_default,
+                                    ACL_TYPE_DEFAULT);
+       if (error)
+               goto out_drop_write;
+
+       fh_drop_write(fh);
+
+       nfserr = fh_getattr(fh, &resp->stat);
+
+out:
        /* argp->acl_{access,default} may have been allocated in
           nfssvc_decode_setaclargs. */
        posix_acl_release(argp->acl_access);
        posix_acl_release(argp->acl_default);
        return nfserr;
+out_drop_write:
+       fh_drop_write(fh);
+out_errno:
+       nfserr = nfserrno(error);
+       goto out;
 }
 
 /*
index 9cbc1a841f87b39d47e81f40cf1e8eac6161a3d2..adc5f1b1dc2677eda3eae5ee895e6df915d4f5cd 100644 (file)
@@ -29,8 +29,9 @@ nfsd3_proc_null(struct svc_rqst *rqstp, void *argp, void *resp)
 static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
                struct nfsd3_getaclargs *argp, struct nfsd3_getaclres *resp)
 {
-       svc_fh *fh;
        struct posix_acl *acl;
+       struct inode *inode;
+       svc_fh *fh;
        __be32 nfserr = 0;
 
        fh = fh_copy(&resp->fh, &argp->fh);
@@ -38,26 +39,20 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
        if (nfserr)
                RETURN_STATUS(nfserr);
 
+       inode = fh->fh_dentry->d_inode;
+
        if (argp->mask & ~(NFS_ACL|NFS_ACLCNT|NFS_DFACL|NFS_DFACLCNT))
                RETURN_STATUS(nfserr_inval);
        resp->mask = argp->mask;
 
        if (resp->mask & (NFS_ACL|NFS_ACLCNT)) {
-               acl = nfsd_get_posix_acl(fh, ACL_TYPE_ACCESS);
+               acl = get_acl(inode, ACL_TYPE_ACCESS);
                if (IS_ERR(acl)) {
-                       int err = PTR_ERR(acl);
-
-                       if (err == -ENODATA || err == -EOPNOTSUPP)
-                               acl = NULL;
-                       else {
-                               nfserr = nfserrno(err);
-                               goto fail;
-                       }
+                       nfserr = nfserrno(PTR_ERR(acl));
+                       goto fail;
                }
                if (acl == NULL) {
                        /* Solaris returns the inode's minimum ACL. */
-
-                       struct inode *inode = fh->fh_dentry->d_inode;
                        acl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
                }
                resp->acl_access = acl;
@@ -65,17 +60,10 @@ static __be32 nfsd3_proc_getacl(struct svc_rqst * rqstp,
        if (resp->mask & (NFS_DFACL|NFS_DFACLCNT)) {
                /* Check how Solaris handles requests for the Default ACL
                   of a non-directory! */
-
-               acl = nfsd_get_posix_acl(fh, ACL_TYPE_DEFAULT);
+               acl = get_acl(inode, ACL_TYPE_DEFAULT);
                if (IS_ERR(acl)) {
-                       int err = PTR_ERR(acl);
-
-                       if (err == -ENODATA || err == -EOPNOTSUPP)
-                               acl = NULL;
-                       else {
-                               nfserr = nfserrno(err);
-                               goto fail;
-                       }
+                       nfserr = nfserrno(PTR_ERR(acl));
+                       goto fail;
                }
                resp->acl_default = acl;
        }
@@ -96,21 +84,37 @@ static __be32 nfsd3_proc_setacl(struct svc_rqst * rqstp,
                struct nfsd3_setaclargs *argp,
                struct nfsd3_attrstat *resp)
 {
+       struct inode *inode;
        svc_fh *fh;
        __be32 nfserr = 0;
+       int error;
 
        fh = fh_copy(&resp->fh, &argp->fh);
        nfserr = fh_verify(rqstp, &resp->fh, 0, NFSD_MAY_SATTR);
+       if (nfserr)
+               goto out;
 
-       if (!nfserr) {
-               nfserr = nfserrno( nfsd_set_posix_acl(
-                       fh, ACL_TYPE_ACCESS, argp->acl_access) );
-       }
-       if (!nfserr) {
-               nfserr = nfserrno( nfsd_set_posix_acl(
-                       fh, ACL_TYPE_DEFAULT, argp->acl_default) );
+       inode = fh->fh_dentry->d_inode;
+       if (!IS_POSIXACL(inode) || !inode->i_op->set_acl) {
+               error = -EOPNOTSUPP;
+               goto out_errno;
        }
 
+       error = fh_want_write(fh);
+       if (error)
+               goto out_errno;
+
+       error = inode->i_op->set_acl(inode, argp->acl_access, ACL_TYPE_ACCESS);
+       if (error)
+               goto out_drop_write;
+       error = inode->i_op->set_acl(inode, argp->acl_default,
+                                    ACL_TYPE_DEFAULT);
+
+out_drop_write:
+       fh_drop_write(fh);
+out_errno:
+       nfserr = nfserrno(error);
+out:
        /* argp->acl_{access,default} may have been allocated in
           nfs3svc_decode_setaclargs. */
        posix_acl_release(argp->acl_access);
index 14d9ecb96cff0ba476549467fbc321f94ea55ff3..de6e39e12cb3e4655ab2017cda8bea11383335ed 100644 (file)
@@ -168,7 +168,7 @@ encode_fattr3(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
              struct kstat *stat)
 {
        *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]);
-       *p++ = htonl((u32) stat->mode);
+       *p++ = htonl((u32) (stat->mode & S_IALLUGO));
        *p++ = htonl((u32) stat->nlink);
        *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
        *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
@@ -842,21 +842,21 @@ out:
 
 static __be32 *encode_entryplus_baggage(struct nfsd3_readdirres *cd, __be32 *p, const char *name, int namlen)
 {
-       struct svc_fh   fh;
+       struct svc_fh   *fh = &cd->scratch;
        __be32 err;
 
-       fh_init(&fh, NFS3_FHSIZE);
-       err = compose_entry_fh(cd, &fh, name, namlen);
+       fh_init(fh, NFS3_FHSIZE);
+       err = compose_entry_fh(cd, fh, name, namlen);
        if (err) {
                *p++ = 0;
                *p++ = 0;
                goto out;
        }
-       p = encode_post_op_attr(cd->rqstp, p, &fh);
+       p = encode_post_op_attr(cd->rqstp, p, fh);
        *p++ = xdr_one;                 /* yes, a file handle follows */
-       p = encode_fh(p, &fh);
+       p = encode_fh(p, fh);
 out:
-       fh_put(&fh);
+       fh_put(fh);
        return p;
 }
 
index 8a50b3c18093b0bc3a6bd04bc80d7767ef8b7ae7..d3a587144222b56becd0ce82597fb95bc8767592 100644 (file)
 #include <linux/slab.h>
 #include <linux/nfs_fs.h>
 #include <linux/export.h>
+#include "nfsfh.h"
+#include "nfsd.h"
 #include "acl.h"
+#include "vfs.h"
 
+#define NFS4_ACL_TYPE_DEFAULT  0x01
+#define NFS4_ACL_DIR           0x02
+#define NFS4_ACL_OWNER         0x04
 
 /* mode bit translations: */
 #define NFS4_READ_MODE (NFS4_ACE_READ_DATA)
@@ -130,36 +136,50 @@ static short ace2type(struct nfs4_ace *);
 static void _posix_to_nfsv4_one(struct posix_acl *, struct nfs4_acl *,
                                unsigned int);
 
-struct nfs4_acl *
-nfs4_acl_posix_to_nfsv4(struct posix_acl *pacl, struct posix_acl *dpacl,
-                       unsigned int flags)
+int
+nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry,
+               struct nfs4_acl **acl)
 {
-       struct nfs4_acl *acl;
+       struct inode *inode = dentry->d_inode;
+       int error = 0;
+       struct posix_acl *pacl = NULL, *dpacl = NULL;
+       unsigned int flags = 0;
        int size = 0;
 
-       if (pacl) {
-               if (posix_acl_valid(pacl) < 0)
-                       return ERR_PTR(-EINVAL);
-               size += 2*pacl->a_count;
+       pacl = get_acl(inode, ACL_TYPE_ACCESS);
+       if (!pacl) {
+               pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
+               if (IS_ERR(pacl))
+                       return PTR_ERR(pacl);
+               /* allocate for worst case: one (deny, allow) pair each: */
+               size += 2 * pacl->a_count;
        }
-       if (dpacl) {
-               if (posix_acl_valid(dpacl) < 0)
-                       return ERR_PTR(-EINVAL);
-               size += 2*dpacl->a_count;
+
+       if (S_ISDIR(inode->i_mode)) {
+               flags = NFS4_ACL_DIR;
+               dpacl = get_acl(inode, ACL_TYPE_DEFAULT);
+               if (dpacl)
+                       size += 2 * dpacl->a_count;
+       } else {
+               dpacl = NULL;
        }
 
-       /* Allocate for worst case: one (deny, allow) pair each: */
-       acl = nfs4_acl_new(size);
-       if (acl == NULL)
-               return ERR_PTR(-ENOMEM);
+       *acl = nfs4_acl_new(size);
+       if (*acl == NULL) {
+               error = -ENOMEM;
+               goto out;
+       }
 
        if (pacl)
-               _posix_to_nfsv4_one(pacl, acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
+               _posix_to_nfsv4_one(pacl, *acl, flags & ~NFS4_ACL_TYPE_DEFAULT);
 
        if (dpacl)
-               _posix_to_nfsv4_one(dpacl, acl, flags | NFS4_ACL_TYPE_DEFAULT);
+               _posix_to_nfsv4_one(dpacl, *acl, flags | NFS4_ACL_TYPE_DEFAULT);
 
-       return acl;
+ out:
+       posix_acl_release(pacl);
+       posix_acl_release(dpacl);
+       return error;
 }
 
 struct posix_acl_summary {
@@ -719,8 +739,9 @@ static void process_one_v4_ace(struct posix_acl_state *state,
        }
 }
 
-int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl, struct posix_acl **pacl,
-                           struct posix_acl **dpacl, unsigned int flags)
+static int nfs4_acl_nfsv4_to_posix(struct nfs4_acl *acl,
+               struct posix_acl **pacl, struct posix_acl **dpacl,
+               unsigned int flags)
 {
        struct posix_acl_state effective_acl_state, default_acl_state;
        struct nfs4_ace *ace;
@@ -780,6 +801,57 @@ out_estate:
        return ret;
 }
 
+__be32
+nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
+               struct nfs4_acl *acl)
+{
+       __be32 error;
+       int host_error;
+       struct dentry *dentry;
+       struct inode *inode;
+       struct posix_acl *pacl = NULL, *dpacl = NULL;
+       unsigned int flags = 0;
+
+       /* Get inode */
+       error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
+       if (error)
+               return error;
+
+       dentry = fhp->fh_dentry;
+       inode = dentry->d_inode;
+
+       if (!inode->i_op->set_acl || !IS_POSIXACL(inode))
+               return nfserr_attrnotsupp;
+
+       if (S_ISDIR(inode->i_mode))
+               flags = NFS4_ACL_DIR;
+
+       host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
+       if (host_error == -EINVAL)
+               return nfserr_attrnotsupp;
+       if (host_error < 0)
+               goto out_nfserr;
+
+       host_error = inode->i_op->set_acl(inode, pacl, ACL_TYPE_ACCESS);
+       if (host_error < 0)
+               goto out_release;
+
+       if (S_ISDIR(inode->i_mode)) {
+               host_error = inode->i_op->set_acl(inode, dpacl,
+                                                 ACL_TYPE_DEFAULT);
+       }
+
+out_release:
+       posix_acl_release(pacl);
+       posix_acl_release(dpacl);
+out_nfserr:
+       if (host_error == -EOPNOTSUPP)
+               return nfserr_attrnotsupp;
+       else
+               return nfserrno(host_error);
+}
+
+
 static short
 ace2type(struct nfs4_ace *ace)
 {
@@ -798,9 +870,6 @@ ace2type(struct nfs4_ace *ace)
        return -1;
 }
 
-EXPORT_SYMBOL(nfs4_acl_posix_to_nfsv4);
-EXPORT_SYMBOL(nfs4_acl_nfsv4_to_posix);
-
 struct nfs4_acl *
 nfs4_acl_new(int n)
 {
@@ -848,21 +917,22 @@ nfs4_acl_get_whotype(char *p, u32 len)
        return NFS4_ACL_WHO_NAMED;
 }
 
-int
-nfs4_acl_write_who(int who, char *p)
+__be32 nfs4_acl_write_who(int who, __be32 **p, int *len)
 {
        int i;
+       int bytes;
 
        for (i = 0; i < ARRAY_SIZE(s2t_map); i++) {
-               if (s2t_map[i].type == who) {
-                       memcpy(p, s2t_map[i].string, s2t_map[i].stringlen);
-                       return s2t_map[i].stringlen;
-               }
+               if (s2t_map[i].type != who)
+                       continue;
+               bytes = 4 + (XDR_QUADLEN(s2t_map[i].stringlen) << 2);
+               if (bytes > *len)
+                       return nfserr_resource;
+               *p = xdr_encode_opaque(*p, s2t_map[i].string,
+                                       s2t_map[i].stringlen);
+               *len -= bytes;
+               return 0;
        }
-       BUG();
+       WARN_ON_ONCE(1);
        return -1;
 }
-
-EXPORT_SYMBOL(nfs4_acl_new);
-EXPORT_SYMBOL(nfs4_acl_get_whotype);
-EXPORT_SYMBOL(nfs4_acl_write_who);
index 4832fd819f884f4a6b436a70369fea4ea9bfcf93..c0dfde68742e463256cd76e7661b439adca849eb 100644 (file)
@@ -551,27 +551,46 @@ idmap_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen
        return 0;
 }
 
-static int
-idmap_id_to_name(struct svc_rqst *rqstp, int type, u32 id, char *name)
+static __be32 encode_ascii_id(u32 id, __be32 **p, int *buflen)
+{
+       char buf[11];
+       int len;
+       int bytes;
+
+       len = sprintf(buf, "%u", id);
+       bytes = 4 + (XDR_QUADLEN(len) << 2);
+       if (bytes > *buflen)
+               return nfserr_resource;
+       *p = xdr_encode_opaque(*p, buf, len);
+       *buflen -= bytes;
+       return 0;
+}
+
+static __be32 idmap_id_to_name(struct svc_rqst *rqstp, int type, u32 id, __be32 **p, int *buflen)
 {
        struct ent *item, key = {
                .id = id,
                .type = type,
        };
        int ret;
+       int bytes;
        struct nfsd_net *nn = net_generic(SVC_NET(rqstp), nfsd_net_id);
 
        strlcpy(key.authname, rqst_authname(rqstp), sizeof(key.authname));
        ret = idmap_lookup(rqstp, idtoname_lookup, &key, nn->idtoname_cache, &item);
        if (ret == -ENOENT)
-               return sprintf(name, "%u", id);
+               return encode_ascii_id(id, p, buflen);
        if (ret)
-               return ret;
+               return nfserrno(ret);
        ret = strlen(item->name);
-       BUG_ON(ret > IDMAP_NAMESZ);
-       memcpy(name, item->name, ret);
+       WARN_ON_ONCE(ret > IDMAP_NAMESZ);
+       bytes = 4 + (XDR_QUADLEN(ret) << 2);
+       if (bytes > *buflen)
+               return nfserr_resource;
+       *p = xdr_encode_opaque(*p, item->name, ret);
+       *buflen -= bytes;
        cache_put(&item->h, nn->idtoname_cache);
-       return ret;
+       return 0;
 }
 
 static bool
@@ -603,12 +622,11 @@ do_name_to_id(struct svc_rqst *rqstp, int type, const char *name, u32 namelen, u
        return idmap_name_to_id(rqstp, type, name, namelen, id);
 }
 
-static int
-do_id_to_name(struct svc_rqst *rqstp, int type, u32 id, char *name)
+static __be32 encode_name_from_id(struct svc_rqst *rqstp, int type, u32 id, __be32 **p, int *buflen)
 {
        if (nfs4_disable_idmapping && rqstp->rq_cred.cr_flavor < RPC_AUTH_GSS)
-               return sprintf(name, "%u", id);
-       return idmap_id_to_name(rqstp, type, id, name);
+               return encode_ascii_id(id, p, buflen);
+       return idmap_id_to_name(rqstp, type, id, p, buflen);
 }
 
 __be32
@@ -637,16 +655,14 @@ nfsd_map_name_to_gid(struct svc_rqst *rqstp, const char *name, size_t namelen,
        return status;
 }
 
-int
-nfsd_map_uid_to_name(struct svc_rqst *rqstp, kuid_t uid, char *name)
+__be32 nfsd4_encode_user(struct svc_rqst *rqstp, kuid_t uid,  __be32 **p, int *buflen)
 {
        u32 id = from_kuid(&init_user_ns, uid);
-       return do_id_to_name(rqstp, IDMAP_TYPE_USER, id, name);
+       return encode_name_from_id(rqstp, IDMAP_TYPE_USER, id, p, buflen);
 }
 
-int
-nfsd_map_gid_to_name(struct svc_rqst *rqstp, kgid_t gid, char *name)
+__be32 nfsd4_encode_group(struct svc_rqst *rqstp, kgid_t gid, __be32 **p, int *buflen)
 {
        u32 id = from_kgid(&init_user_ns, gid);
-       return do_id_to_name(rqstp, IDMAP_TYPE_GROUP, id, name);
+       return encode_name_from_id(rqstp, IDMAP_TYPE_GROUP, id, p, buflen);
 }
index 419572f33b72dafaf04a770fb53e29e250e5f42b..82189b208af31700418217e62d8339f13dce6565 100644 (file)
@@ -41,6 +41,7 @@
 #include "vfs.h"
 #include "current_stateid.h"
 #include "netns.h"
+#include "acl.h"
 
 #ifdef CONFIG_NFSD_V4_SECURITY_LABEL
 #include <linux/security.h>
@@ -230,17 +231,16 @@ static void nfsd4_set_open_owner_reply_cache(struct nfsd4_compound_state *cstate
 }
 
 static __be32
-do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open)
+do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, struct nfsd4_open *open, struct svc_fh **resfh)
 {
        struct svc_fh *current_fh = &cstate->current_fh;
-       struct svc_fh *resfh;
        int accmode;
        __be32 status;
 
-       resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
-       if (!resfh)
+       *resfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
+       if (!*resfh)
                return nfserr_jukebox;
-       fh_init(resfh, NFS4_FHSIZE);
+       fh_init(*resfh, NFS4_FHSIZE);
        open->op_truncate = 0;
 
        if (open->op_create) {
@@ -265,12 +265,12 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
                 */
                status = do_nfsd_create(rqstp, current_fh, open->op_fname.data,
                                        open->op_fname.len, &open->op_iattr,
-                                       resfh, open->op_createmode,
+                                       *resfh, open->op_createmode,
                                        (u32 *)open->op_verf.data,
                                        &open->op_truncate, &open->op_created);
 
                if (!status && open->op_label.len)
-                       nfsd4_security_inode_setsecctx(resfh, &open->op_label, open->op_bmval);
+                       nfsd4_security_inode_setsecctx(*resfh, &open->op_label, open->op_bmval);
 
                /*
                 * Following rfc 3530 14.2.16, use the returned bitmask
@@ -280,31 +280,32 @@ do_open_lookup(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate, stru
                if (open->op_createmode == NFS4_CREATE_EXCLUSIVE && status == 0)
                        open->op_bmval[1] = (FATTR4_WORD1_TIME_ACCESS |
                                                        FATTR4_WORD1_TIME_MODIFY);
-       } else {
+       } else
+               /*
+                * Note this may exit with the parent still locked.
+                * We will hold the lock until nfsd4_open's final
+                * lookup, to prevent renames or unlinks until we've had
+                * a chance to an acquire a delegation if appropriate.
+                */
                status = nfsd_lookup(rqstp, current_fh,
-                                    open->op_fname.data, open->op_fname.len, resfh);
-               fh_unlock(current_fh);
-       }
+                                    open->op_fname.data, open->op_fname.len, *resfh);
        if (status)
                goto out;
-       status = nfsd_check_obj_isreg(resfh);
+       status = nfsd_check_obj_isreg(*resfh);
        if (status)
                goto out;
 
        if (is_create_with_attrs(open) && open->op_acl != NULL)
-               do_set_nfs4_acl(rqstp, resfh, open->op_acl, open->op_bmval);
+               do_set_nfs4_acl(rqstp, *resfh, open->op_acl, open->op_bmval);
 
-       nfsd4_set_open_owner_reply_cache(cstate, open, resfh);
+       nfsd4_set_open_owner_reply_cache(cstate, open, *resfh);
        accmode = NFSD_MAY_NOP;
        if (open->op_created ||
                        open->op_claim_type == NFS4_OPEN_CLAIM_DELEGATE_CUR)
                accmode |= NFSD_MAY_OWNER_OVERRIDE;
-       status = do_open_permission(rqstp, resfh, open, accmode);
+       status = do_open_permission(rqstp, *resfh, open, accmode);
        set_change_info(&open->op_cinfo, current_fh);
-       fh_dup2(current_fh, resfh);
 out:
-       fh_put(resfh);
-       kfree(resfh);
        return status;
 }
 
@@ -357,6 +358,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
           struct nfsd4_open *open)
 {
        __be32 status;
+       struct svc_fh *resfh = NULL;
        struct nfsd4_compoundres *resp;
        struct net *net = SVC_NET(rqstp);
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
@@ -423,7 +425,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
        switch (open->op_claim_type) {
                case NFS4_OPEN_CLAIM_DELEGATE_CUR:
                case NFS4_OPEN_CLAIM_NULL:
-                       status = do_open_lookup(rqstp, cstate, open);
+                       status = do_open_lookup(rqstp, cstate, open, &resfh);
                        if (status)
                                goto out;
                        break;
@@ -439,6 +441,7 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                        status = do_open_fhandle(rqstp, cstate, open);
                        if (status)
                                goto out;
+                       resfh = &cstate->current_fh;
                        break;
                case NFS4_OPEN_CLAIM_DELEG_PREV_FH:
                case NFS4_OPEN_CLAIM_DELEGATE_PREV:
@@ -458,9 +461,14 @@ nfsd4_open(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
         * successful, it (1) truncates the file if open->op_truncate was
         * set, (2) sets open->op_stateid, (3) sets open->op_delegation.
         */
-       status = nfsd4_process_open2(rqstp, &cstate->current_fh, open);
+       status = nfsd4_process_open2(rqstp, resfh, open);
        WARN_ON(status && open->op_created);
 out:
+       if (resfh && resfh != &cstate->current_fh) {
+               fh_dup2(&cstate->current_fh, resfh);
+               fh_put(resfh);
+               kfree(resfh);
+       }
        nfsd4_cleanup_open_state(open, status);
        if (open->op_openowner && !nfsd4_has_session(cstate))
                cstate->replay_owner = &open->op_openowner->oo_owner;
@@ -1069,8 +1077,10 @@ _nfsd4_verify(struct svc_rqst *rqstp, struct nfsd4_compound_state *cstate,
                                    cstate->current_fh.fh_dentry, &p,
                                    count, verify->ve_bmval,
                                    rqstp, 0);
-
-       /* this means that nfsd4_encode_fattr() ran out of space */
+       /*
+        * If nfsd4_encode_fattr() ran out of space, assume that's because
+        * the attributes are longer (hence different) than those given:
+        */
        if (status == nfserr_resource)
                status = nfserr_not_same;
        if (status)
@@ -1524,7 +1534,8 @@ static inline u32 nfsd4_write_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 static inline u32 nfsd4_exchange_id_rsize(struct svc_rqst *rqstp, struct nfsd4_op *op)
 {
        return (op_encode_hdr_size + 2 + 1 + /* eir_clientid, eir_sequenceid */\
-               1 + 1 + 2 + /* eir_flags, spr_how, spo_must_enforce & _allow */\
+               1 + 1 + /* eir_flags, spr_how */\
+               4 + /* spo_must_enforce & _allow with bitmap */\
                2 + /*eir_server_owner.so_minor_id */\
                /* eir_server_owner.so_major_id<> */\
                XDR_QUADLEN(NFS4_OPAQUE_LIMIT) + 1 +\
@@ -1881,6 +1892,7 @@ struct svc_version        nfsd_version4 = {
                .vs_proc        = nfsd_procedures4,
                .vs_dispatch    = nfsd_dispatch,
                .vs_xdrsize     = NFS4_SVC_XDRSIZE,
+               .vs_rpcb_optnl  = 1,
 };
 
 /*
index 105d6fa7c5149ab496cf614763a4c3145f52c74e..d5d070fbeb35a98f6053ae4299c225f57a8bdd74 100644 (file)
@@ -832,10 +832,11 @@ static void nfsd4_put_drc_mem(struct nfsd4_channel_attrs *ca)
        spin_unlock(&nfsd_drc_lock);
 }
 
-static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs)
+static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *fattrs,
+                                          struct nfsd4_channel_attrs *battrs)
 {
-       int numslots = attrs->maxreqs;
-       int slotsize = slot_bytes(attrs);
+       int numslots = fattrs->maxreqs;
+       int slotsize = slot_bytes(fattrs);
        struct nfsd4_session *new;
        int mem, i;
 
@@ -852,6 +853,10 @@ static struct nfsd4_session *alloc_session(struct nfsd4_channel_attrs *attrs)
                if (!new->se_slots[i])
                        goto out_free;
        }
+
+       memcpy(&new->se_fchannel, fattrs, sizeof(struct nfsd4_channel_attrs));
+       memcpy(&new->se_bchannel, battrs, sizeof(struct nfsd4_channel_attrs));
+
        return new;
 out_free:
        while (i--)
@@ -997,8 +1002,7 @@ static void init_session(struct svc_rqst *rqstp, struct nfsd4_session *new, stru
        list_add(&new->se_perclnt, &clp->cl_sessions);
        spin_unlock(&clp->cl_lock);
        spin_unlock(&nn->client_lock);
-       memcpy(&new->se_fchannel, &cses->fore_channel,
-                       sizeof(struct nfsd4_channel_attrs));
+
        if (cses->flags & SESSION4_BACK_CHAN) {
                struct sockaddr *sa = svc_addr(rqstp);
                /*
@@ -1851,6 +1855,11 @@ static __be32 check_forechannel_attrs(struct nfsd4_channel_attrs *ca, struct nfs
        return nfs_ok;
 }
 
+#define NFSD_CB_MAX_REQ_SZ     ((NFS4_enc_cb_recall_sz + \
+                                RPC_MAX_HEADER_WITH_AUTH) * sizeof(__be32))
+#define NFSD_CB_MAX_RESP_SZ    ((NFS4_dec_cb_recall_sz + \
+                                RPC_MAX_REPHEADER_WITH_AUTH) * sizeof(__be32))
+
 static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
 {
        ca->headerpadsz = 0;
@@ -1861,9 +1870,9 @@ static __be32 check_backchannel_attrs(struct nfsd4_channel_attrs *ca)
         * less than 1k.  Tighten up this estimate in the unlikely event
         * it turns out to be a problem for some client:
         */
-       if (ca->maxreq_sz < NFS4_enc_cb_recall_sz + RPC_MAX_HEADER_WITH_AUTH)
+       if (ca->maxreq_sz < NFSD_CB_MAX_REQ_SZ)
                return nfserr_toosmall;
-       if (ca->maxresp_sz < NFS4_dec_cb_recall_sz + RPC_MAX_REPHEADER_WITH_AUTH)
+       if (ca->maxresp_sz < NFSD_CB_MAX_RESP_SZ)
                return nfserr_toosmall;
        ca->maxresp_cached = 0;
        if (ca->maxops < 2)
@@ -1913,9 +1922,9 @@ nfsd4_create_session(struct svc_rqst *rqstp,
                return status;
        status = check_backchannel_attrs(&cr_ses->back_channel);
        if (status)
-               return status;
+               goto out_release_drc_mem;
        status = nfserr_jukebox;
-       new = alloc_session(&cr_ses->fore_channel);
+       new = alloc_session(&cr_ses->fore_channel, &cr_ses->back_channel);
        if (!new)
                goto out_release_drc_mem;
        conn = alloc_conn_from_crses(rqstp, cr_ses);
@@ -3034,18 +3043,18 @@ static int nfs4_setlease(struct nfs4_delegation *dp)
        if (!fl)
                return -ENOMEM;
        fl->fl_file = find_readable_file(fp);
-       list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
        status = vfs_setlease(fl->fl_file, fl->fl_type, &fl);
-       if (status) {
-               list_del_init(&dp->dl_perclnt);
-               locks_free_lock(fl);
-               return status;
-       }
+       if (status)
+               goto out_free;
+       list_add(&dp->dl_perclnt, &dp->dl_stid.sc_client->cl_delegations);
        fp->fi_lease = fl;
        fp->fi_deleg_file = get_file(fl->fl_file);
        atomic_set(&fp->fi_delegees, 1);
        list_add(&dp->dl_perfile, &fp->fi_delegations);
        return 0;
+out_free:
+       locks_free_lock(fl);
+       return status;
 }
 
 static int nfs4_set_delegation(struct nfs4_delegation *dp, struct nfs4_file *fp)
@@ -3125,6 +3134,7 @@ nfs4_open_delegation(struct net *net, struct svc_fh *fh,
                                goto out_no_deleg;
                        break;
                case NFS4_OPEN_CLAIM_NULL:
+               case NFS4_OPEN_CLAIM_FH:
                        /*
                         * Let's not give out any delegations till everyone's
                         * had the chance to reclaim theirs....
index ee7237f99f54cd413dba6375dbc344084d0ece56..63f2395c57ed72bcb55cab62e1234d3c27bea0be 100644 (file)
@@ -103,11 +103,6 @@ xdr_error:                                 \
        (x) = (u64)ntohl(*p++) << 32;           \
        (x) |= ntohl(*p++);                     \
 } while (0)
-#define READTIME(x)       do {                 \
-       p++;                                    \
-       (x) = ntohl(*p++);                      \
-       p++;                                    \
-} while (0)
 #define READMEM(x,nbytes) do {                 \
        x = (char *)p;                          \
        p += XDR_QUADLEN(nbytes);               \
@@ -190,6 +185,15 @@ static int zero_clientid(clientid_t *clid)
        return (clid->cl_boot == 0) && (clid->cl_id == 0);
 }
 
+/**
+ * defer_free - mark an allocation as deferred freed
+ * @argp: NFSv4 compound argument structure to be freed with
+ * @release: release callback to free @p, typically kfree()
+ * @p: pointer to be freed
+ *
+ * Marks @p to be freed when processing the compound operation
+ * described in @argp finishes.
+ */
 static int
 defer_free(struct nfsd4_compoundargs *argp,
                void (*release)(const void *), void *p)
@@ -206,6 +210,16 @@ defer_free(struct nfsd4_compoundargs *argp,
        return 0;
 }
 
+/**
+ * savemem - duplicate a chunk of memory for later processing
+ * @argp: NFSv4 compound argument structure to be freed with
+ * @p: pointer to be duplicated
+ * @nbytes: length to be duplicated
+ *
+ * Returns a pointer to a copy of @nbytes bytes of memory at @p
+ * that are preserved until processing of the NFSv4 compound
+ * operation described by @argp finishes.
+ */
 static char *savemem(struct nfsd4_compoundargs *argp, __be32 *p, int nbytes)
 {
        if (p == argp->tmp) {
@@ -257,7 +271,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
        int expected_len, len = 0;
        u32 dummy32;
        char *buf;
-       int host_err;
 
        DECODE_HEAD;
        iattr->ia_valid = 0;
@@ -284,10 +297,9 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                        return nfserr_resource;
 
                *acl = nfs4_acl_new(nace);
-               if (*acl == NULL) {
-                       host_err = -ENOMEM;
-                       goto out_nfserr;
-               }
+               if (*acl == NULL)
+                       return nfserr_jukebox;
+
                defer_free(argp, kfree, *acl);
 
                (*acl)->naces = nace;
@@ -425,10 +437,6 @@ nfsd4_decode_fattr(struct nfsd4_compoundargs *argp, u32 *bmval,
                goto xdr_error;
 
        DECODE_TAIL;
-
-out_nfserr:
-       status = nfserrno(host_err);
-       goto out;
 }
 
 static __be32
@@ -1957,56 +1965,16 @@ static u32 nfs4_file_type(umode_t mode)
        };
 }
 
-static __be32
-nfsd4_encode_name(struct svc_rqst *rqstp, int whotype, kuid_t uid, kgid_t gid,
-                       __be32 **p, int *buflen)
-{
-       int status;
-
-       if (*buflen < (XDR_QUADLEN(IDMAP_NAMESZ) << 2) + 4)
-               return nfserr_resource;
-       if (whotype != NFS4_ACL_WHO_NAMED)
-               status = nfs4_acl_write_who(whotype, (u8 *)(*p + 1));
-       else if (gid_valid(gid))
-               status = nfsd_map_gid_to_name(rqstp, gid, (u8 *)(*p + 1));
-       else
-               status = nfsd_map_uid_to_name(rqstp, uid, (u8 *)(*p + 1));
-       if (status < 0)
-               return nfserrno(status);
-       *p = xdr_encode_opaque(*p, NULL, status);
-       *buflen -= (XDR_QUADLEN(status) << 2) + 4;
-       BUG_ON(*buflen < 0);
-       return 0;
-}
-
-static inline __be32
-nfsd4_encode_user(struct svc_rqst *rqstp, kuid_t user, __be32 **p, int *buflen)
-{
-       return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, user, INVALID_GID,
-                                p, buflen);
-}
-
-static inline __be32
-nfsd4_encode_group(struct svc_rqst *rqstp, kgid_t group, __be32 **p, int *buflen)
-{
-       return nfsd4_encode_name(rqstp, NFS4_ACL_WHO_NAMED, INVALID_UID, group,
-                                p, buflen);
-}
-
 static inline __be32
 nfsd4_encode_aclname(struct svc_rqst *rqstp, struct nfs4_ace *ace,
                __be32 **p, int *buflen)
 {
-       kuid_t uid = INVALID_UID;
-       kgid_t gid = INVALID_GID;
-
-       if (ace->whotype == NFS4_ACL_WHO_NAMED) {
-               if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
-                       gid = ace->who_gid;
-               else
-                       uid = ace->who_uid;
-       }
-       return nfsd4_encode_name(rqstp, ace->whotype, uid, gid, p, buflen);
+       if (ace->whotype != NFS4_ACL_WHO_NAMED)
+               return nfs4_acl_write_who(ace->whotype, p, buflen);
+       else if (ace->flag & NFS4_ACE_IDENTIFIER_GROUP)
+               return nfsd4_encode_group(rqstp, ace->who_gid, p, buflen);
+       else
+               return nfsd4_encode_user(rqstp, ace->who_uid, p, buflen);
 }
 
 #define WORD0_ABSENT_FS_ATTRS (FATTR4_WORD0_FS_LOCATIONS | FATTR4_WORD0_FSID | \
@@ -2090,7 +2058,7 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
        u32 bmval1 = bmval[1];
        u32 bmval2 = bmval[2];
        struct kstat stat;
-       struct svc_fh tempfh;
+       struct svc_fh *tempfh = NULL;
        struct kstatfs statfs;
        int buflen = count << 2;
        __be32 *attrlenp;
@@ -2137,11 +2105,15 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                        goto out_nfserr;
        }
        if ((bmval0 & (FATTR4_WORD0_FILEHANDLE | FATTR4_WORD0_FSID)) && !fhp) {
-               fh_init(&tempfh, NFS4_FHSIZE);
-               status = fh_compose(&tempfh, exp, dentry, NULL);
+               tempfh = kmalloc(sizeof(struct svc_fh), GFP_KERNEL);
+               status = nfserr_jukebox;
+               if (!tempfh)
+                       goto out;
+               fh_init(tempfh, NFS4_FHSIZE);
+               status = fh_compose(tempfh, exp, dentry, NULL);
                if (status)
                        goto out;
-               fhp = &tempfh;
+               fhp = tempfh;
        }
        if (bmval0 & (FATTR4_WORD0_ACL | FATTR4_WORD0_ACLSUPPORT
                        | FATTR4_WORD0_SUPPORTED_ATTRS)) {
@@ -2222,8 +2194,10 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                if ((buflen -= 4) < 0)
                        goto out_resource;
                dummy = nfs4_file_type(stat.mode);
-               if (dummy == NF4BAD)
-                       goto out_serverfault;
+               if (dummy == NF4BAD) {
+                       status = nfserr_serverfault;
+                       goto out;
+               }
                WRITE32(dummy);
        }
        if (bmval0 & FATTR4_WORD0_FH_EXPIRE_TYPE) {
@@ -2317,8 +2291,6 @@ nfsd4_encode_fattr(struct svc_fh *fhp, struct svc_export *exp,
                        WRITE32(ace->flag);
                        WRITE32(ace->access_mask & NFS4_ACE_MASK_ALL);
                        status = nfsd4_encode_aclname(rqstp, ace, &p, &buflen);
-                       if (status == nfserr_resource)
-                               goto out_resource;
                        if (status)
                                goto out;
                }
@@ -2379,8 +2351,6 @@ out_acl:
        }
        if (bmval0 & FATTR4_WORD0_FS_LOCATIONS) {
                status = nfsd4_encode_fs_locations(rqstp, exp, &p, &buflen);
-               if (status == nfserr_resource)
-                       goto out_resource;
                if (status)
                        goto out;
        }
@@ -2431,15 +2401,11 @@ out_acl:
        }
        if (bmval1 & FATTR4_WORD1_OWNER) {
                status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen);
-               if (status == nfserr_resource)
-                       goto out_resource;
                if (status)
                        goto out;
        }
        if (bmval1 & FATTR4_WORD1_OWNER_GROUP) {
                status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen);
-               if (status == nfserr_resource)
-                       goto out_resource;
                if (status)
                        goto out;
        }
@@ -2533,8 +2499,8 @@ out:
                security_release_secctx(context, contextlen);
 #endif /* CONFIG_NFSD_V4_SECURITY_LABEL */
        kfree(acl);
-       if (fhp == &tempfh)
-               fh_put(&tempfh);
+       if (tempfh)
+               fh_put(tempfh);
        return status;
 out_nfserr:
        status = nfserrno(err);
@@ -2542,9 +2508,6 @@ out_nfserr:
 out_resource:
        status = nfserr_resource;
        goto out;
-out_serverfault:
-       status = nfserr_serverfault;
-       goto out;
 }
 
 static inline int attributes_need_mount(u32 *bmval)
@@ -2621,17 +2584,14 @@ out_put:
 static __be32 *
 nfsd4_encode_rdattr_error(__be32 *p, int buflen, __be32 nfserr)
 {
-       __be32 *attrlenp;
-
        if (buflen < 6)
                return NULL;
        *p++ = htonl(2);
        *p++ = htonl(FATTR4_WORD0_RDATTR_ERROR); /* bmval0 */
        *p++ = htonl(0);                         /* bmval1 */
 
-       attrlenp = p++;
+       *p++ = htonl(4);     /* attribute length */
        *p++ = nfserr;       /* no htonl */
-       *attrlenp = htonl((char *)p - (char *)attrlenp - 4);
        return p;
 }
 
@@ -3244,7 +3204,7 @@ nfsd4_do_encode_secinfo(struct nfsd4_compoundres *resp,
 
                if (rpcauth_get_gssinfo(pf, &info) == 0) {
                        supported++;
-                       RESERVE_SPACE(4 + 4 + info.oid.len + 4 + 4);
+                       RESERVE_SPACE(4 + 4 + XDR_LEN(info.oid.len) + 4 + 4);
                        WRITE32(RPC_AUTH_GSS);
                        WRITE32(info.oid.len);
                        WRITEMEM(info.oid.data, info.oid.len);
@@ -3379,35 +3339,43 @@ nfsd4_encode_exchange_id(struct nfsd4_compoundres *resp, __be32 nfserr,
                8 /* eir_clientid */ +
                4 /* eir_sequenceid */ +
                4 /* eir_flags */ +
-               4 /* spr_how */ +
-               8 /* spo_must_enforce, spo_must_allow */ +
-               8 /* so_minor_id */ +
-               4 /* so_major_id.len */ +
-               (XDR_QUADLEN(major_id_sz) * 4) +
-               4 /* eir_server_scope.len */ +
-               (XDR_QUADLEN(server_scope_sz) * 4) +
-               4 /* eir_server_impl_id.count (0) */);
+               4 /* spr_how */);
 
        WRITEMEM(&exid->clientid, 8);
        WRITE32(exid->seqid);
        WRITE32(exid->flags);
 
        WRITE32(exid->spa_how);
+       ADJUST_ARGS();
+
        switch (exid->spa_how) {
        case SP4_NONE:
                break;
        case SP4_MACH_CRED:
+               /* spo_must_enforce, spo_must_allow */
+               RESERVE_SPACE(16);
+
                /* spo_must_enforce bitmap: */
                WRITE32(2);
                WRITE32(nfs4_minimal_spo_must_enforce[0]);
                WRITE32(nfs4_minimal_spo_must_enforce[1]);
                /* empty spo_must_allow bitmap: */
                WRITE32(0);
+
+               ADJUST_ARGS();
                break;
        default:
                WARN_ON_ONCE(1);
        }
 
+       RESERVE_SPACE(
+               8 /* so_minor_id */ +
+               4 /* so_major_id.len */ +
+               (XDR_QUADLEN(major_id_sz) * 4) +
+               4 /* eir_server_scope.len */ +
+               (XDR_QUADLEN(server_scope_sz) * 4) +
+               4 /* eir_server_impl_id.count (0) */);
+
        /* The server_owner struct */
        WRITE64(minor_id);      /* Minor id */
        /* major id */
@@ -3473,28 +3441,6 @@ nfsd4_encode_create_session(struct nfsd4_compoundres *resp, __be32 nfserr,
        return 0;
 }
 
-static __be32
-nfsd4_encode_destroy_session(struct nfsd4_compoundres *resp, __be32 nfserr,
-                            struct nfsd4_destroy_session *destroy_session)
-{
-       return nfserr;
-}
-
-static __be32
-nfsd4_encode_free_stateid(struct nfsd4_compoundres *resp, __be32 nfserr,
-                         struct nfsd4_free_stateid *free_stateid)
-{
-       __be32 *p;
-
-       if (nfserr)
-               return nfserr;
-
-       RESERVE_SPACE(4);
-       *p++ = nfserr;
-       ADJUST_ARGS();
-       return nfserr;
-}
-
 static __be32
 nfsd4_encode_sequence(struct nfsd4_compoundres *resp, __be32 nfserr,
                      struct nfsd4_sequence *seq)
@@ -3593,8 +3539,8 @@ static nfsd4_enc nfsd4_enc_ops[] = {
        [OP_BIND_CONN_TO_SESSION] = (nfsd4_enc)nfsd4_encode_bind_conn_to_session,
        [OP_EXCHANGE_ID]        = (nfsd4_enc)nfsd4_encode_exchange_id,
        [OP_CREATE_SESSION]     = (nfsd4_enc)nfsd4_encode_create_session,
-       [OP_DESTROY_SESSION]    = (nfsd4_enc)nfsd4_encode_destroy_session,
-       [OP_FREE_STATEID]       = (nfsd4_enc)nfsd4_encode_free_stateid,
+       [OP_DESTROY_SESSION]    = (nfsd4_enc)nfsd4_encode_noop,
+       [OP_FREE_STATEID]       = (nfsd4_enc)nfsd4_encode_noop,
        [OP_GET_DIR_DELEGATION] = (nfsd4_enc)nfsd4_encode_noop,
        [OP_GETDEVICEINFO]      = (nfsd4_enc)nfsd4_encode_noop,
        [OP_GETDEVICELIST]      = (nfsd4_enc)nfsd4_encode_noop,
index b6af150c96b8cdf616950c1bd0f4f8403eeae5c8..f8f060ffbf4f173888db46dc0c000ce8c1ea34c6 100644 (file)
@@ -131,13 +131,6 @@ nfsd_reply_cache_alloc(void)
        return rp;
 }
 
-static void
-nfsd_reply_cache_unhash(struct svc_cacherep *rp)
-{
-       hlist_del_init(&rp->c_hash);
-       list_del_init(&rp->c_lru);
-}
-
 static void
 nfsd_reply_cache_free_locked(struct svc_cacherep *rp)
 {
@@ -416,22 +409,8 @@ nfsd_cache_lookup(struct svc_rqst *rqstp)
 
        /*
         * Since the common case is a cache miss followed by an insert,
-        * preallocate an entry. First, try to reuse the first entry on the LRU
-        * if it works, then go ahead and prune the LRU list.
+        * preallocate an entry.
         */
-       spin_lock(&cache_lock);
-       if (!list_empty(&lru_head)) {
-               rp = list_first_entry(&lru_head, struct svc_cacherep, c_lru);
-               if (nfsd_cache_entry_expired(rp) ||
-                   num_drc_entries >= max_drc_entries) {
-                       nfsd_reply_cache_unhash(rp);
-                       prune_cache_entries();
-                       goto search_cache;
-               }
-       }
-
-       /* No expired ones available, allocate a new one. */
-       spin_unlock(&cache_lock);
        rp = nfsd_reply_cache_alloc();
        spin_lock(&cache_lock);
        if (likely(rp)) {
@@ -439,7 +418,9 @@ nfsd_cache_lookup(struct svc_rqst *rqstp)
                drc_mem_usage += sizeof(*rp);
        }
 
-search_cache:
+       /* go ahead and prune the cache */
+       prune_cache_entries();
+
        found = nfsd_cache_search(rqstp, csum);
        if (found) {
                if (likely(rp))
@@ -453,15 +434,6 @@ search_cache:
                goto out;
        }
 
-       /*
-        * We're keeping the one we just allocated. Are we now over the
-        * limit? Prune one off the tip of the LRU in trade for the one we
-        * just allocated if so.
-        */
-       if (num_drc_entries >= max_drc_entries)
-               nfsd_reply_cache_free_locked(list_first_entry(&lru_head,
-                                               struct svc_cacherep, c_lru));
-
        nfsdstats.rcmisses++;
        rqstp->rq_cacherep = rp;
        rp->c_state = RC_INPROG;
index 760c85a6f534a45b0eb396a62acc305484163109..9a4a5f9e7468748f7195ac92f86d7317c83e0822 100644 (file)
@@ -241,6 +241,15 @@ static void nfsd_shutdown_generic(void)
        nfsd_racache_shutdown();
 }
 
+static bool nfsd_needs_lockd(void)
+{
+#if defined(CONFIG_NFSD_V3)
+       return (nfsd_versions[2] != NULL) || (nfsd_versions[3] != NULL);
+#else
+       return (nfsd_versions[2] != NULL);
+#endif
+}
+
 static int nfsd_startup_net(int nrservs, struct net *net)
 {
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
@@ -255,9 +264,14 @@ static int nfsd_startup_net(int nrservs, struct net *net)
        ret = nfsd_init_socks(net);
        if (ret)
                goto out_socks;
-       ret = lockd_up(net);
-       if (ret)
-               goto out_socks;
+
+       if (nfsd_needs_lockd() && !nn->lockd_up) {
+               ret = lockd_up(net);
+               if (ret)
+                       goto out_socks;
+               nn->lockd_up = 1;
+       }
+
        ret = nfs4_state_start_net(net);
        if (ret)
                goto out_lockd;
@@ -266,7 +280,10 @@ static int nfsd_startup_net(int nrservs, struct net *net)
        return 0;
 
 out_lockd:
-       lockd_down(net);
+       if (nn->lockd_up) {
+               lockd_down(net);
+               nn->lockd_up = 0;
+       }
 out_socks:
        nfsd_shutdown_generic();
        return ret;
@@ -277,7 +294,10 @@ static void nfsd_shutdown_net(struct net *net)
        struct nfsd_net *nn = net_generic(net, nfsd_net_id);
 
        nfs4_state_shutdown_net(net);
-       lockd_down(net);
+       if (nn->lockd_up) {
+               lockd_down(net);
+               nn->lockd_up = 0;
+       }
        nn->nfsd_net_up = false;
        nfsd_shutdown_generic();
 }
index 9c769a47ac5ab7efc9a2b939305ffbad45ed988f..b17d93214d0153b426282b1f23e3414768fb6ca0 100644 (file)
@@ -152,7 +152,7 @@ encode_fattr(struct svc_rqst *rqstp, __be32 *p, struct svc_fh *fhp,
        type = (stat->mode & S_IFMT);
 
        *p++ = htonl(nfs_ftypes[type >> 12]);
-       *p++ = htonl((u32) stat->mode);
+       *p++ = htonl((u32) (stat->mode & S_IALLUGO));
        *p++ = htonl((u32) stat->nlink);
        *p++ = htonl((u32) from_kuid(&init_user_ns, stat->uid));
        *p++ = htonl((u32) from_kgid(&init_user_ns, stat->gid));
index 7eea63cada1d4a3ea5f9dd95401f83714689fcb0..017d3cb5e99b4391027fe37b7c56c23966754e2d 100644 (file)
@@ -207,7 +207,12 @@ nfsd_lookup_dentry(struct svc_rqst *rqstp, struct svc_fh *fhp,
                                goto out_nfserr;
                }
        } else {
-               fh_lock(fhp);
+               /*
+                * In the nfsd4_open() case, this may be held across
+                * subsequent open and delegation acquisition which may
+                * need to take the child's i_mutex:
+                */
+               fh_lock_nested(fhp, I_MUTEX_PARENT);
                dentry = lookup_one_len(name, dparent, len);
                host_err = PTR_ERR(dentry);
                if (IS_ERR(dentry))
@@ -273,13 +278,6 @@ out:
        return err;
 }
 
-static int nfsd_break_lease(struct inode *inode)
-{
-       if (!S_ISREG(inode->i_mode))
-               return 0;
-       return break_lease(inode, O_WRONLY | O_NONBLOCK);
-}
-
 /*
  * Commit metadata changes to stable storage.
  */
@@ -348,8 +346,7 @@ nfsd_sanitize_attrs(struct inode *inode, struct iattr *iap)
 
        /* Revoke setuid/setgid on chown */
        if (!S_ISDIR(inode->i_mode) &&
-           (((iap->ia_valid & ATTR_UID) && !uid_eq(iap->ia_uid, inode->i_uid)) ||
-            ((iap->ia_valid & ATTR_GID) && !gid_eq(iap->ia_gid, inode->i_gid)))) {
+           ((iap->ia_valid & ATTR_UID) || (iap->ia_valid & ATTR_GID))) {
                iap->ia_valid |= ATTR_KILL_PRIV;
                if (iap->ia_valid & ATTR_MODE) {
                        /* we're setting mode too, just clear the s*id bits */
@@ -449,16 +446,10 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
                goto out_put_write_access;
        }
 
-       host_err = nfsd_break_lease(inode);
-       if (host_err)
-               goto out_put_write_access_nfserror;
-
        fh_lock(fhp);
        host_err = notify_change(dentry, iap, NULL);
        fh_unlock(fhp);
 
-out_put_write_access_nfserror:
-       err = nfserrno(host_err);
 out_put_write_access:
        if (size_change)
                put_write_access(inode);
@@ -468,158 +459,7 @@ out:
        return err;
 }
 
-#if defined(CONFIG_NFSD_V2_ACL) || \
-    defined(CONFIG_NFSD_V3_ACL) || \
-    defined(CONFIG_NFSD_V4)
-static ssize_t nfsd_getxattr(struct dentry *dentry, char *key, void **buf)
-{
-       ssize_t buflen;
-       ssize_t ret;
-
-       buflen = vfs_getxattr(dentry, key, NULL, 0);
-       if (buflen <= 0)
-               return buflen;
-
-       *buf = kmalloc(buflen, GFP_KERNEL);
-       if (!*buf)
-               return -ENOMEM;
-
-       ret = vfs_getxattr(dentry, key, *buf, buflen);
-       if (ret < 0)
-               kfree(*buf);
-       return ret;
-}
-#endif
-
 #if defined(CONFIG_NFSD_V4)
-static int
-set_nfsv4_acl_one(struct dentry *dentry, struct posix_acl *pacl, char *key)
-{
-       int len;
-       size_t buflen;
-       char *buf = NULL;
-       int error = 0;
-
-       buflen = posix_acl_xattr_size(pacl->a_count);
-       buf = kmalloc(buflen, GFP_KERNEL);
-       error = -ENOMEM;
-       if (buf == NULL)
-               goto out;
-
-       len = posix_acl_to_xattr(&init_user_ns, pacl, buf, buflen);
-       if (len < 0) {
-               error = len;
-               goto out;
-       }
-
-       error = vfs_setxattr(dentry, key, buf, len, 0);
-out:
-       kfree(buf);
-       return error;
-}
-
-__be32
-nfsd4_set_nfs4_acl(struct svc_rqst *rqstp, struct svc_fh *fhp,
-    struct nfs4_acl *acl)
-{
-       __be32 error;
-       int host_error;
-       struct dentry *dentry;
-       struct inode *inode;
-       struct posix_acl *pacl = NULL, *dpacl = NULL;
-       unsigned int flags = 0;
-
-       /* Get inode */
-       error = fh_verify(rqstp, fhp, 0, NFSD_MAY_SATTR);
-       if (error)
-               return error;
-
-       dentry = fhp->fh_dentry;
-       inode = dentry->d_inode;
-       if (S_ISDIR(inode->i_mode))
-               flags = NFS4_ACL_DIR;
-
-       host_error = nfs4_acl_nfsv4_to_posix(acl, &pacl, &dpacl, flags);
-       if (host_error == -EINVAL) {
-               return nfserr_attrnotsupp;
-       } else if (host_error < 0)
-               goto out_nfserr;
-
-       host_error = set_nfsv4_acl_one(dentry, pacl, POSIX_ACL_XATTR_ACCESS);
-       if (host_error < 0)
-               goto out_release;
-
-       if (S_ISDIR(inode->i_mode))
-               host_error = set_nfsv4_acl_one(dentry, dpacl, POSIX_ACL_XATTR_DEFAULT);
-
-out_release:
-       posix_acl_release(pacl);
-       posix_acl_release(dpacl);
-out_nfserr:
-       if (host_error == -EOPNOTSUPP)
-               return nfserr_attrnotsupp;
-       else
-               return nfserrno(host_error);
-}
-
-static struct posix_acl *
-_get_posix_acl(struct dentry *dentry, char *key)
-{
-       void *buf = NULL;
-       struct posix_acl *pacl = NULL;
-       int buflen;
-
-       buflen = nfsd_getxattr(dentry, key, &buf);
-       if (!buflen)
-               buflen = -ENODATA;
-       if (buflen <= 0)
-               return ERR_PTR(buflen);
-
-       pacl = posix_acl_from_xattr(&init_user_ns, buf, buflen);
-       kfree(buf);
-       return pacl;
-}
-
-int
-nfsd4_get_nfs4_acl(struct svc_rqst *rqstp, struct dentry *dentry, struct nfs4_acl **acl)
-{
-       struct inode *inode = dentry->d_inode;
-       int error = 0;
-       struct posix_acl *pacl = NULL, *dpacl = NULL;
-       unsigned int flags = 0;
-
-       pacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_ACCESS);
-       if (IS_ERR(pacl) && PTR_ERR(pacl) == -ENODATA)
-               pacl = posix_acl_from_mode(inode->i_mode, GFP_KERNEL);
-       if (IS_ERR(pacl)) {
-               error = PTR_ERR(pacl);
-               pacl = NULL;
-               goto out;
-       }
-
-       if (S_ISDIR(inode->i_mode)) {
-               dpacl = _get_posix_acl(dentry, POSIX_ACL_XATTR_DEFAULT);
-               if (IS_ERR(dpacl) && PTR_ERR(dpacl) == -ENODATA)
-                       dpacl = NULL;
-               else if (IS_ERR(dpacl)) {
-                       error = PTR_ERR(dpacl);
-                       dpacl = NULL;
-                       goto out;
-               }
-               flags = NFS4_ACL_DIR;
-       }
-
-       *acl = nfs4_acl_posix_to_nfsv4(pacl, dpacl, flags);
-       if (IS_ERR(*acl)) {
-               error = PTR_ERR(*acl);
-               *acl = NULL;
-       }
- out:
-       posix_acl_release(pacl);
-       posix_acl_release(dpacl);
-       return error;
-}
-
 /*
  * NFS junction information is stored in an extended attribute.
  */
@@ -1760,11 +1600,6 @@ nfsd_link(struct svc_rqst *rqstp, struct svc_fh *ffhp,
        err = nfserr_noent;
        if (!dold->d_inode)
                goto out_dput;
-       host_err = nfsd_break_lease(dold->d_inode);
-       if (host_err) {
-               err = nfserrno(host_err);
-               goto out_dput;
-       }
        host_err = vfs_link(dold, dirp, dnew, NULL);
        if (!host_err) {
                err = nfserrno(commit_metadata(ffhp));
@@ -1858,14 +1693,6 @@ nfsd_rename(struct svc_rqst *rqstp, struct svc_fh *ffhp, char *fname, int flen,
        if (ffhp->fh_export->ex_path.dentry != tfhp->fh_export->ex_path.dentry)
                goto out_dput_new;
 
-       host_err = nfsd_break_lease(odentry->d_inode);
-       if (host_err)
-               goto out_dput_new;
-       if (ndentry->d_inode) {
-               host_err = nfsd_break_lease(ndentry->d_inode);
-               if (host_err)
-                       goto out_dput_new;
-       }
        host_err = vfs_rename(fdir, odentry, tdir, ndentry, NULL);
        if (!host_err) {
                host_err = commit_metadata(tfhp);
@@ -1935,16 +1762,12 @@ nfsd_unlink(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
        if (!type)
                type = rdentry->d_inode->i_mode & S_IFMT;
 
-       host_err = nfsd_break_lease(rdentry->d_inode);
-       if (host_err)
-               goto out_put;
        if (type != S_IFDIR)
                host_err = vfs_unlink(dirp, rdentry, NULL);
        else
                host_err = vfs_rmdir(dirp, rdentry);
        if (!host_err)
                host_err = commit_metadata(fhp);
-out_put:
        dput(rdentry);
 
 out_nfserr:
@@ -2284,93 +2107,3 @@ out_nomem:
        nfsd_racache_shutdown();
        return -ENOMEM;
 }
-
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-struct posix_acl *
-nfsd_get_posix_acl(struct svc_fh *fhp, int type)
-{
-       struct inode *inode = fhp->fh_dentry->d_inode;
-       char *name;
-       void *value = NULL;
-       ssize_t size;
-       struct posix_acl *acl;
-
-       if (!IS_POSIXACL(inode))
-               return ERR_PTR(-EOPNOTSUPP);
-
-       switch (type) {
-       case ACL_TYPE_ACCESS:
-               name = POSIX_ACL_XATTR_ACCESS;
-               break;
-       case ACL_TYPE_DEFAULT:
-               name = POSIX_ACL_XATTR_DEFAULT;
-               break;
-       default:
-               return ERR_PTR(-EOPNOTSUPP);
-       }
-
-       size = nfsd_getxattr(fhp->fh_dentry, name, &value);
-       if (size < 0)
-               return ERR_PTR(size);
-
-       acl = posix_acl_from_xattr(&init_user_ns, value, size);
-       kfree(value);
-       return acl;
-}
-
-int
-nfsd_set_posix_acl(struct svc_fh *fhp, int type, struct posix_acl *acl)
-{
-       struct inode *inode = fhp->fh_dentry->d_inode;
-       char *name;
-       void *value = NULL;
-       size_t size;
-       int error;
-
-       if (!IS_POSIXACL(inode) ||
-           !inode->i_op->setxattr || !inode->i_op->removexattr)
-               return -EOPNOTSUPP;
-       switch(type) {
-               case ACL_TYPE_ACCESS:
-                       name = POSIX_ACL_XATTR_ACCESS;
-                       break;
-               case ACL_TYPE_DEFAULT:
-                       name = POSIX_ACL_XATTR_DEFAULT;
-                       break;
-               default:
-                       return -EOPNOTSUPP;
-       }
-
-       if (acl && acl->a_count) {
-               size = posix_acl_xattr_size(acl->a_count);
-               value = kmalloc(size, GFP_KERNEL);
-               if (!value)
-                       return -ENOMEM;
-               error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
-               if (error < 0)
-                       goto getout;
-               size = error;
-       } else
-               size = 0;
-
-       error = fh_want_write(fhp);
-       if (error)
-               goto getout;
-       if (size)
-               error = vfs_setxattr(fhp->fh_dentry, name, value, size, 0);
-       else {
-               if (!S_ISDIR(inode->i_mode) && type == ACL_TYPE_DEFAULT)
-                       error = 0;
-               else {
-                       error = vfs_removexattr(fhp->fh_dentry, name);
-                       if (error == -ENODATA)
-                               error = 0;
-               }
-       }
-       fh_drop_write(fhp);
-
-getout:
-       kfree(value);
-       return error;
-}
-#endif  /* defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL) */
index a4be2e3896704047f1aae87ac924990fb2d0f834..fbe90bdb2214e976fa49b50ee8903d25089c2177 100644 (file)
@@ -52,9 +52,6 @@ __be32                nfsd_setattr(struct svc_rqst *, struct svc_fh *,
                                struct iattr *, int, time_t);
 int nfsd_mountpoint(struct dentry *, struct svc_export *);
 #ifdef CONFIG_NFSD_V4
-__be32          nfsd4_set_nfs4_acl(struct svc_rqst *, struct svc_fh *,
-                    struct nfs4_acl *);
-int             nfsd4_get_nfs4_acl(struct svc_rqst *, struct dentry *, struct nfs4_acl **);
 __be32          nfsd4_set_nfs4_label(struct svc_rqst *, struct svc_fh *,
                    struct xdr_netobj *);
 #endif /* CONFIG_NFSD_V4 */
@@ -89,8 +86,6 @@ __be32                nfsd_link(struct svc_rqst *, struct svc_fh *,
 __be32         nfsd_rename(struct svc_rqst *,
                                struct svc_fh *, char *, int,
                                struct svc_fh *, char *, int);
-__be32         nfsd_remove(struct svc_rqst *,
-                               struct svc_fh *, char *, int);
 __be32         nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
                                char *name, int len);
 __be32         nfsd_readdir(struct svc_rqst *, struct svc_fh *,
@@ -101,11 +96,6 @@ __be32              nfsd_statfs(struct svc_rqst *, struct svc_fh *,
 __be32         nfsd_permission(struct svc_rqst *, struct svc_export *,
                                struct dentry *, int);
 
-#if defined(CONFIG_NFSD_V2_ACL) || defined(CONFIG_NFSD_V3_ACL)
-struct posix_acl *nfsd_get_posix_acl(struct svc_fh *, int);
-int nfsd_set_posix_acl(struct svc_fh *, int, struct posix_acl *);
-#endif
-
 static inline int fh_want_write(struct svc_fh *fh)
 {
        int ret = mnt_want_write(fh->fh_export->ex_path.mnt);
index b6d5542a4ac8e185e48d9d7c64fab36f5068dd88..335e04aaf7db18842fb63923feebfb31e26e4353 100644 (file)
@@ -174,6 +174,9 @@ struct nfsd3_linkres {
 struct nfsd3_readdirres {
        __be32                  status;
        struct svc_fh           fh;
+       /* Just to save kmalloc on every readdirplus entry (svc_fh is a
+        * little large for the stack): */
+       struct svc_fh           scratch;
        int                     count;
        __be32                  verf[2];
 
index b3ed6446ed8e9a420fedfc2ccbe861c5b46664ed..d278a0d034968d3bdb57b7f942048af7e2ed6712 100644 (file)
@@ -228,7 +228,7 @@ struct nfsd4_open {
        u32             op_create;          /* request */
        u32             op_createmode;      /* request */
        u32             op_bmval[3];        /* request */
-       struct iattr    iattr;              /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */
+       struct iattr    op_iattr;           /* UNCHECKED4, GUARDED4, EXCLUSIVE4_1 */
        nfs4_verifier   op_verf __attribute__((aligned(32)));
                                            /* EXCLUSIVE4 */
        clientid_t      op_clientid;        /* request */
@@ -250,7 +250,6 @@ struct nfsd4_open {
        struct nfs4_acl *op_acl;
        struct xdr_netobj op_label;
 };
-#define op_iattr       iattr
 
 struct nfsd4_open_confirm {
        stateid_t       oc_req_stateid          /* request */;
@@ -374,7 +373,6 @@ struct nfsd4_test_stateid {
 
 struct nfsd4_free_stateid {
        stateid_t       fr_stateid;         /* request */
-       __be32          fr_status;          /* response */
 };
 
 /* also used for NVERIFY */
index 2d8be51f90dc9257bf74cad77b719d17f781c739..dc3a9efdaab87751e47edcf9ef3a807fed4573db 100644 (file)
@@ -416,7 +416,8 @@ static struct bio *nilfs_alloc_seg_bio(struct the_nilfs *nilfs, sector_t start,
        }
        if (likely(bio)) {
                bio->bi_bdev = nilfs->ns_bdev;
-               bio->bi_sector = start << (nilfs->ns_blocksize_bits - 9);
+               bio->bi_iter.bi_sector =
+                       start << (nilfs->ns_blocksize_bits - 9);
        }
        return bio;
 }
index 634a8b717b02199ee310180ba35c9f8947a5e897..266c2d7d50bdaed476be1a44fc0a12f3ac8b9625 100644 (file)
@@ -583,7 +583,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_macceltic(void)
index 979e6265ac5e823d355ca9171d8a8debe6195347..9789c6057551a3c16a7de3d9b5cf7302ade3a85f 100644 (file)
@@ -513,7 +513,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_maccenteuro(void)
index dd3f675911ee3716a9a835f5fd428db3d723cd8f..bb19e7a07d436496b5ad2f4833dfb1da7c50f588 100644 (file)
@@ -583,7 +583,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_maccroatian(void)
index 1112c84dd8bb7183d5fec826cea8c06e866d0ee8..2a7dea36acba0e13d706a255868ce82af88dbd51 100644 (file)
@@ -478,7 +478,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_maccyrillic(void)
index 2de9158409c85ec468619e5f93289c5e133af66b..77b001653588076ea42a71a254bd2c42aa0e279d 100644 (file)
@@ -548,7 +548,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_macgaelic(void)
index a863100828028f5f9d98a62f1dbacb1c62fa4ca0..1eccf499e2ebc5bb2aff772b17a834fec615d802 100644 (file)
@@ -478,7 +478,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_macgreek(void)
index babe2998d5ced2d0a1a8d237edb4fe5a2cd25604..cbd0875c6d6948b3a7ada49d75c909c69da347ba 100644 (file)
@@ -583,7 +583,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_maciceland(void)
index 312364f010dcc7e5a8af3d95f9763c54f37f85d2..fba8357aaf03899d3929902070f8e2c01e91b541 100644 (file)
@@ -513,7 +513,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_macinuit(void)
index 53ce0809cbd28eec842fab86b808c19b91c5dcc7..b6a98a5208cd6196b48b7d703c1a4a6ad953201e 100644 (file)
@@ -618,7 +618,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_macroman(void)
index add6f7a0c6663c6ddf251bf749fc13812548d181..25547f023638453396876470e74cd66ba2b34ce1 100644 (file)
@@ -583,7 +583,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_macromanian(void)
index dffa96d5de00243d29940c68dd613666d7fad25c..b5454bc7b7fa390b34f758d0ef49a54c9ece70ad 100644 (file)
@@ -583,7 +583,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_macturkish(void)
index 7020e940f74e9dbcb4f7a420d67391fa6532f779..a2620650d5e45f6d6a9e4113fbae7fcf29a5e25d 100644 (file)
@@ -148,7 +148,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_ascii(void)
index fea6bd5831dce3d84868316c424266c1232949fd..52ccd34b1e792370597b77f7d228c4d79bf96600 100644 (file)
@@ -232,13 +232,14 @@ int utf16s_to_utf8s(const wchar_t *pwcs, int inlen, enum utf16_endian endian,
 }
 EXPORT_SYMBOL(utf16s_to_utf8s);
 
-int register_nls(struct nls_table * nls)
+int __register_nls(struct nls_table *nls, struct module *owner)
 {
        struct nls_table ** tmp = &tables;
 
        if (nls->next)
                return -EBUSY;
 
+       nls->owner = owner;
        spin_lock(&nls_lock);
        while (*tmp) {
                if (nls == *tmp) {
@@ -252,6 +253,7 @@ int register_nls(struct nls_table * nls)
        spin_unlock(&nls_lock);
        return 0;       
 }
+EXPORT_SYMBOL(__register_nls);
 
 int unregister_nls(struct nls_table * nls)
 {
@@ -538,7 +540,6 @@ struct nls_table *load_nls_default(void)
                return &default_table;
 }
 
-EXPORT_SYMBOL(register_nls);
 EXPORT_SYMBOL(unregister_nls);
 EXPORT_SYMBOL(unload_nls);
 EXPORT_SYMBOL(load_nls);
index c8471fe78e4e5893dade5b391b2d60dda9197bc6..ace3e19d3407671f36eaa5a43aaa27f341028e3c 100644 (file)
@@ -329,7 +329,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp1250(void)
index 1939b46e772f42a6c5ba0377bd6b8c1939030aa9..9273ddfd08a1eec6f2801101897150a46e947c48 100644 (file)
@@ -283,7 +283,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp1251(void)
index 8120ae2e091a78ebe3ee240c0bf35133ceff9a54..1caf5dfed85b7ec9c06688cfd97282ad6b807e36 100644 (file)
@@ -365,7 +365,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp1255(void)
index ff37a4628ce48e5c9e86d4febdeea81565dec65b..7ddb830da3fdb78a9384b026060f6633a32d4e21 100644 (file)
@@ -369,7 +369,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp437(void)
index f5576b8be1b92bb3e43f6a01226f5acae3e641e2..c593f683a0cd2139c68d82b7dd7bd8baffc36e01 100644 (file)
@@ -332,7 +332,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp737(void)
index 4905635d1c00986735d49df059cb0f2efab5b1c0..554c863745f2b6e12ae31afee3935b6fce825c1c 100644 (file)
@@ -301,7 +301,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp775(void)
index fe5bdad50e2b39ac4783653e8666b1c2be9a92de..56cccd14b40be93a1a49abe57aedfb472c2d9259 100644 (file)
@@ -297,7 +297,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp850(void)
index ceb1c0166dd8988909cfee453b79d94ab30213ff..7cdc05ac1d402e8d5a5eca44ec74eb06483abe45 100644 (file)
@@ -319,7 +319,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp852(void)
index cc7f5fb2e0c24849f401b47018270609d29ee5ab..7426eea05663731dd90b25b96902c31214a633ec 100644 (file)
@@ -281,7 +281,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp855(void)
index e418e198e8d866586e8317f7327dfdfc924c8188..098309733ebd1406316b7c7fb9dcd86f6a88b04c 100644 (file)
@@ -283,7 +283,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp857(void)
index a86c97d1aa3484747df369573918cbf01aa97a88..84224478e731a5f9f4e3c566cf78464479dfad3b 100644 (file)
@@ -346,7 +346,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp860(void)
index bd920227acdfd0869b450c8d0b58105cf9ae5037..dc873e4be092a233698a0b9fb5e45361af1cf64d 100644 (file)
@@ -369,7 +369,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp861(void)
index e9b68eb3daf04d21cb39ed60ab1d4b6120bbf24d..d5263e3c5566cf51f2d0892f2d57e735b62f8b52 100644 (file)
@@ -403,7 +403,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp862(void)
index f8a9b07ab4e2f64cc80d247b567250d90b034fea..051c9832e36a96e19da30441a95ce5688071d35a 100644 (file)
@@ -363,7 +363,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp863(void)
index 8d31f435fc6f9a31f662d929d6870402766688af..97eb1273b2f7456b10c172ab5e229b745f1e7f01 100644 (file)
@@ -389,7 +389,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp864(void)
index 4bd902fe3ec94065d05f3ab36515efac885f3e13..11121422852513544cba0d316668cdfc08225f4a 100644 (file)
@@ -369,7 +369,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp865(void)
index bdc7cb391398828330db1cfedb8c47d7174f3d3b..ffdcbc3fc38d71f2b4e258b660c3eb32c2a387f7 100644 (file)
@@ -287,7 +287,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp866(void)
index 9f283a2b151a2c2f7004ecdfceae58b5f3c53a06..3b5a345893543fb2702023c6796a72216efbdfd8 100644 (file)
@@ -297,7 +297,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp869(void)
index 0b3c4886f8c03d2927ecd9a16a13d964f5cb97e4..8dfaa10710fa7165c4b6261b0b0081a4f37357cf 100644 (file)
@@ -256,7 +256,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp874(void)
index 0ffed6f1cebb6cb8d9c5618cc4876c6f053457d3..67b7398e84832bcacd334a65e60cda21f0a045b4 100644 (file)
@@ -7914,7 +7914,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp932(void)
index 82770301bc3da82849a2118db40aaeb1e4b92d7c..c96546cfec9fd81b5c726121501ba7e4c1640690 100644 (file)
@@ -11092,7 +11092,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp936(void)
index 8a7a2fe85c65a7ca551f6417e0a3d181d9aa7e46..199171e97aa4a014ae0bdaecbf05759bad99b76b 100644 (file)
@@ -13927,7 +13927,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp949(void)
index ef2536829aa589a393d1b5d9528d1e28ab2ac47e..8e14187082098216c78d7bb9b39d269dd544eec5 100644 (file)
@@ -9463,7 +9463,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_cp950(void)
index 7424929a278b0088ba92772ffb1b3a7644864906..162b3f160353c6ab076644079c861a2b4f1fd736 100644 (file)
@@ -553,7 +553,6 @@ static struct nls_table table = {
        .charset        = "euc-jp",
        .uni2char       = uni2char,
        .char2uni       = char2uni,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_euc_jp(void)
index 7b951bb5849cb52e48a30dc8c3f3187949c581bb..69ac020d43b1ce0dc7fc640476faee082a91b6fc 100644 (file)
@@ -239,7 +239,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_1(void)
index c4d52ea9f0921a6530bc96de8e02529643856f9e..afb3f8f275f079df23746a779bcf0223fbba81b8 100644 (file)
@@ -267,7 +267,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_13(void)
index dc02600c7fe16828d3bb4688652bd46be363e485..046370f0b6f0ca1284aa70cadcc041fd1386be87 100644 (file)
@@ -323,7 +323,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_14(void)
index 3c7dfc832ef1309fb095d445a33ad529ebdd3a11..7e34a841a056727cd647784ef1eeca625fd3ea7e 100644 (file)
@@ -289,7 +289,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_15(void)
index a2d2197e4c7740e5ea808e196945b8806e74fbc8..7dd5711817414d2bc03564d28ca2249d15bcd0bf 100644 (file)
@@ -290,7 +290,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_2(void)
index a61e0daa3a860a6472e52b29f1b640b599f9b0a4..740b75ec44936919b7458f89e34f02fd83d914e4 100644 (file)
@@ -290,7 +290,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_3(void)
index e8ff555483b673526845585366b71ba573b27d04..8826021e32f59a2cf6323ecbbd2d8f4da1aa27ad 100644 (file)
@@ -290,7 +290,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_4(void)
index 4721e89301249c2e7e765ac19efdabee4cb9baec..7c04057a1ad82c44cc9903abbac1ddb6336086d8 100644 (file)
@@ -254,7 +254,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_5(void)
index 01a517d6d306a18fe7d48b811529a00a59c5eb39..d4a881400d74951308788241b1d7240c81d02c7a 100644 (file)
@@ -245,7 +245,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_6(void)
index 2d27b93ef19e152bd4415e6e9f62e8bcc2472394..37b75d825a754ec2690a62cf7f0a2ee2d28058ec 100644 (file)
@@ -299,7 +299,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_7(void)
index 694bf070c72102535c122499bfd0e88bb6adacf7..557b98250d3790b89a3883f9cb8a6cecbe201eaf 100644 (file)
@@ -254,7 +254,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_iso8859_9(void)
index 43875310540dd83d3cf354013fdc0b91bbf35140..811f232fccfba77f79627f26aa338553d1cf3a6e 100644 (file)
@@ -305,7 +305,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_koi8_r(void)
index e7bc1d75c78c4e9a79a373707559ab51f091d456..a80a741a8676dc5a6ead28c9a584169050fc3c79 100644 (file)
@@ -55,7 +55,6 @@ static struct nls_table table = {
        .charset        = "koi8-ru",
        .uni2char       = uni2char,
        .char2uni       = char2uni,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_koi8_ru(void)
index 8c9f0292b5ae88318249c53708b31ae600dafa81..7e029e4c188a241ef37de1e2e419bf61dbf8eba3 100644 (file)
@@ -312,7 +312,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = charset2lower,
        .charset2upper  = charset2upper,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_koi8_u(void)
index 0d60a44acacd42b7eee10349a672a9ec9a74240a..afcfbc4a14dbf82c6d8b171477d8f5e0eb0dc00f 100644 (file)
@@ -46,7 +46,6 @@ static struct nls_table table = {
        .char2uni       = char2uni,
        .charset2lower  = identity,     /* no conversion */
        .charset2upper  = identity,
-       .owner          = THIS_MODULE,
 };
 
 static int __init init_nls_utf8(void)
index 58772623f02a90e7e7c4355921ba0c8457024175..0e792f5e3147c3cfcf38a980716075ea509b0e46 100644 (file)
@@ -16,12 +16,6 @@ static bool should_merge(struct fsnotify_event *old_fsn,
 {
        struct fanotify_event_info *old, *new;
 
-#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
-       /* dont merge two permission events */
-       if ((old_fsn->mask & FAN_ALL_PERM_EVENTS) &&
-           (new_fsn->mask & FAN_ALL_PERM_EVENTS))
-               return false;
-#endif
        pr_debug("%s: old=%p new=%p\n", __func__, old_fsn, new_fsn);
        old = FANOTIFY_E(old_fsn);
        new = FANOTIFY_E(new_fsn);
@@ -34,14 +28,23 @@ static bool should_merge(struct fsnotify_event *old_fsn,
 }
 
 /* and the list better be locked by something too! */
-static struct fsnotify_event *fanotify_merge(struct list_head *list,
-                                            struct fsnotify_event *event)
+static int fanotify_merge(struct list_head *list, struct fsnotify_event *event)
 {
        struct fsnotify_event *test_event;
        bool do_merge = false;
 
        pr_debug("%s: list=%p event=%p\n", __func__, list, event);
 
+#ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
+       /*
+        * Don't merge a permission event with any other event so that we know
+        * the event structure we have created in fanotify_handle_event() is the
+        * one we should check for permission response.
+        */
+       if (event->mask & FAN_ALL_PERM_EVENTS)
+               return 0;
+#endif
+
        list_for_each_entry_reverse(test_event, list, list) {
                if (should_merge(test_event, event)) {
                        do_merge = true;
@@ -50,10 +53,10 @@ static struct fsnotify_event *fanotify_merge(struct list_head *list,
        }
 
        if (!do_merge)
-               return NULL;
+               return 0;
 
        test_event->mask |= event->mask;
-       return test_event;
+       return 1;
 }
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
@@ -149,7 +152,6 @@ static int fanotify_handle_event(struct fsnotify_group *group,
        int ret = 0;
        struct fanotify_event_info *event;
        struct fsnotify_event *fsn_event;
-       struct fsnotify_event *notify_fsn_event;
 
        BUILD_BUG_ON(FAN_ACCESS != FS_ACCESS);
        BUILD_BUG_ON(FAN_MODIFY != FS_MODIFY);
@@ -188,21 +190,19 @@ static int fanotify_handle_event(struct fsnotify_group *group,
        event->response = 0;
 #endif
 
-       notify_fsn_event = fsnotify_add_notify_event(group, fsn_event,
-                                                    fanotify_merge);
-       if (notify_fsn_event) {
+       ret = fsnotify_add_notify_event(group, fsn_event, fanotify_merge);
+       if (ret) {
+               BUG_ON(mask & FAN_ALL_PERM_EVENTS);
                /* Our event wasn't used in the end. Free it. */
                fsnotify_destroy_event(group, fsn_event);
-               if (IS_ERR(notify_fsn_event))
-                       return PTR_ERR(notify_fsn_event);
-               /* We need to ask about a different events after a merge... */
-               event = FANOTIFY_E(notify_fsn_event);
-               fsn_event = notify_fsn_event;
+               ret = 0;
        }
 
 #ifdef CONFIG_FANOTIFY_ACCESS_PERMISSIONS
-       if (fsn_event->mask & FAN_ALL_PERM_EVENTS)
+       if (mask & FAN_ALL_PERM_EVENTS) {
                ret = fanotify_get_response_from_access(group, event);
+               fsnotify_destroy_event(group, fsn_event);
+       }
 #endif
        return ret;
 }
index 0e90174a116a2c337f77af9e11760f1c21e00e43..32a2f034fb94b5915d1e8362ecbac21f362653fb 100644 (file)
@@ -4,6 +4,13 @@
 
 extern struct kmem_cache *fanotify_event_cachep;
 
+/*
+ * Lifetime of the structure differs for normal and permission events. In both
+ * cases the structure is allocated in fanotify_handle_event(). For normal
+ * events the structure is freed immediately after reporting it to userspace.
+ * For permission events we free it only after we receive response from
+ * userspace.
+ */
 struct fanotify_event_info {
        struct fsnotify_event fse;
        /*
index 57d7c083cb4b89c9c49858680a05e69c36b7ef09..b6175fa11bf856809d1ee6a43ee9b861980e9160 100644 (file)
@@ -319,7 +319,12 @@ static ssize_t fanotify_read(struct file *file, char __user *buf,
                        if (IS_ERR(kevent))
                                break;
                        ret = copy_event_to_user(group, kevent, buf);
-                       fsnotify_destroy_event(group, kevent);
+                       /*
+                        * Permission events get destroyed after we
+                        * receive response
+                        */
+                       if (!(kevent->mask & FAN_ALL_PERM_EVENTS))
+                               fsnotify_destroy_event(group, kevent);
                        if (ret < 0)
                                break;
                        buf += ret;
@@ -886,9 +891,9 @@ COMPAT_SYSCALL_DEFINE6(fanotify_mark,
 {
        return sys_fanotify_mark(fanotify_fd, flags,
 #ifdef __BIG_ENDIAN
-                               ((__u64)mask1 << 32) | mask0,
-#else
                                ((__u64)mask0 << 32) | mask1,
+#else
+                               ((__u64)mask1 << 32) | mask0,
 #endif
                                 dfd, pathname);
 }
index aad1a35e9af117fdc397cca897ba6f192f2de7a0..d5ee56348bb803fd0ddff46d4f3da7d0fa7016d1 100644 (file)
@@ -53,15 +53,13 @@ static bool event_compare(struct fsnotify_event *old_fsn,
        return false;
 }
 
-static struct fsnotify_event *inotify_merge(struct list_head *list,
-                                           struct fsnotify_event *event)
+static int inotify_merge(struct list_head *list,
+                         struct fsnotify_event *event)
 {
        struct fsnotify_event *last_event;
 
        last_event = list_entry(list->prev, struct fsnotify_event, list);
-       if (!event_compare(last_event, event))
-               return NULL;
-       return last_event;
+       return event_compare(last_event, event);
 }
 
 int inotify_handle_event(struct fsnotify_group *group,
@@ -73,9 +71,8 @@ int inotify_handle_event(struct fsnotify_group *group,
 {
        struct inotify_inode_mark *i_mark;
        struct inotify_event_info *event;
-       struct fsnotify_event *added_event;
        struct fsnotify_event *fsn_event;
-       int ret = 0;
+       int ret;
        int len = 0;
        int alloc_len = sizeof(struct inotify_event_info);
 
@@ -110,18 +107,16 @@ int inotify_handle_event(struct fsnotify_group *group,
        if (len)
                strcpy(event->name, file_name);
 
-       added_event = fsnotify_add_notify_event(group, fsn_event, inotify_merge);
-       if (added_event) {
+       ret = fsnotify_add_notify_event(group, fsn_event, inotify_merge);
+       if (ret) {
                /* Our event wasn't used in the end. Free it. */
                fsnotify_destroy_event(group, fsn_event);
-               if (IS_ERR(added_event))
-                       ret = PTR_ERR(added_event);
        }
 
        if (inode_mark->mask & IN_ONESHOT)
                fsnotify_destroy_mark(inode_mark, group);
 
-       return ret;
+       return 0;
 }
 
 static void inotify_freeing_mark(struct fsnotify_mark *fsn_mark, struct fsnotify_group *group)
index 952237b8e2d27bbea9466bf41db33ba854b937c6..18b3c4427dcac0f2c9125581cc171be3f1eb3a9f 100644 (file)
@@ -79,15 +79,15 @@ void fsnotify_destroy_event(struct fsnotify_group *group,
 
 /*
  * Add an event to the group notification queue.  The group can later pull this
- * event off the queue to deal with.  If the event is successfully added to the
- * group's notification queue, a reference is taken on event.
+ * event off the queue to deal with.  The function returns 0 if the event was
+ * added to the queue, 1 if the event was merged with some other queued event.
  */
-struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group,
-                                                struct fsnotify_event *event,
-                                                struct fsnotify_event *(*merge)(struct list_head *,
-                                                                                struct fsnotify_event *))
+int fsnotify_add_notify_event(struct fsnotify_group *group,
+                             struct fsnotify_event *event,
+                             int (*merge)(struct list_head *,
+                                          struct fsnotify_event *))
 {
-       struct fsnotify_event *return_event = NULL;
+       int ret = 0;
        struct list_head *list = &group->notification_list;
 
        pr_debug("%s: group=%p event=%p\n", __func__, group, event);
@@ -98,14 +98,14 @@ struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group,
                /* Queue overflow event only if it isn't already queued */
                if (list_empty(&group->overflow_event.list))
                        event = &group->overflow_event;
-               return_event = event;
+               ret = 1;
        }
 
        if (!list_empty(list) && merge) {
-               return_event = merge(list, event);
-               if (return_event) {
+               ret = merge(list, event);
+               if (ret) {
                        mutex_unlock(&group->notification_mutex);
-                       return return_event;
+                       return ret;
                }
        }
 
@@ -115,7 +115,7 @@ struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group,
 
        wake_up(&group->notification_waitq);
        kill_fasync(&group->fsn_fa, SIGIO, POLL_IN);
-       return return_event;
+       return ret;
 }
 
 /*
index b4f788e0ca318955ab797f2350f8dffa320a53cb..555f4cddefe3a913d7c1d05fba89a1ea36fdd3c1 100644 (file)
@@ -160,36 +160,6 @@ static struct posix_acl *ocfs2_get_acl_nolock(struct inode *inode,
        return acl;
 }
 
-
-/*
- * Get posix acl.
- */
-static struct posix_acl *ocfs2_get_acl(struct inode *inode, int type)
-{
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       struct buffer_head *di_bh = NULL;
-       struct posix_acl *acl;
-       int ret;
-
-       if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
-               return NULL;
-
-       ret = ocfs2_inode_lock(inode, &di_bh, 0);
-       if (ret < 0) {
-               mlog_errno(ret);
-               acl = ERR_PTR(ret);
-               return acl;
-       }
-
-       acl = ocfs2_get_acl_nolock(inode, type, di_bh);
-
-       ocfs2_inode_unlock(inode, 0);
-
-       brelse(di_bh);
-
-       return acl;
-}
-
 /*
  * Helper function to set i_mode in memory and disk. Some call paths
  * will not have di_bh or a journal handle to pass, in which case it
@@ -250,7 +220,7 @@ out:
 /*
  * Set the access or default ACL of an inode.
  */
-static int ocfs2_set_acl(handle_t *handle,
+int ocfs2_set_acl(handle_t *handle,
                         struct inode *inode,
                         struct buffer_head *di_bh,
                         int type,
@@ -313,6 +283,11 @@ static int ocfs2_set_acl(handle_t *handle,
        return ret;
 }
 
+int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+       return ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL);
+}
+
 struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type)
 {
        struct ocfs2_super *osb;
@@ -334,200 +309,3 @@ struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type)
 
        return acl;
 }
-
-int ocfs2_acl_chmod(struct inode *inode)
-{
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       struct posix_acl *acl;
-       int ret;
-
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
-       if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
-               return 0;
-
-       acl = ocfs2_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
-       ret = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
-       if (ret)
-               return ret;
-       ret = ocfs2_set_acl(NULL, inode, NULL, ACL_TYPE_ACCESS,
-                           acl, NULL, NULL);
-       posix_acl_release(acl);
-       return ret;
-}
-
-/*
- * Initialize the ACLs of a new inode. If parent directory has default ACL,
- * then clone to new inode. Called from ocfs2_mknod.
- */
-int ocfs2_init_acl(handle_t *handle,
-                  struct inode *inode,
-                  struct inode *dir,
-                  struct buffer_head *di_bh,
-                  struct buffer_head *dir_bh,
-                  struct ocfs2_alloc_context *meta_ac,
-                  struct ocfs2_alloc_context *data_ac)
-{
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       struct posix_acl *acl = NULL;
-       int ret = 0, ret2;
-       umode_t mode;
-
-       if (!S_ISLNK(inode->i_mode)) {
-               if (osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) {
-                       acl = ocfs2_get_acl_nolock(dir, ACL_TYPE_DEFAULT,
-                                                  dir_bh);
-                       if (IS_ERR(acl))
-                               return PTR_ERR(acl);
-               }
-               if (!acl) {
-                       mode = inode->i_mode & ~current_umask();
-                       ret = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
-                       if (ret) {
-                               mlog_errno(ret);
-                               goto cleanup;
-                       }
-               }
-       }
-       if ((osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL) && acl) {
-               if (S_ISDIR(inode->i_mode)) {
-                       ret = ocfs2_set_acl(handle, inode, di_bh,
-                                           ACL_TYPE_DEFAULT, acl,
-                                           meta_ac, data_ac);
-                       if (ret)
-                               goto cleanup;
-               }
-               mode = inode->i_mode;
-               ret = posix_acl_create(&acl, GFP_NOFS, &mode);
-               if (ret < 0)
-                       return ret;
-
-               ret2 = ocfs2_acl_set_mode(inode, di_bh, handle, mode);
-               if (ret2) {
-                       mlog_errno(ret2);
-                       ret = ret2;
-                       goto cleanup;
-               }
-               if (ret > 0) {
-                       ret = ocfs2_set_acl(handle, inode,
-                                           di_bh, ACL_TYPE_ACCESS,
-                                           acl, meta_ac, data_ac);
-               }
-       }
-cleanup:
-       posix_acl_release(acl);
-       return ret;
-}
-
-static size_t ocfs2_xattr_list_acl_access(struct dentry *dentry,
-                                         char *list,
-                                         size_t list_len,
-                                         const char *name,
-                                         size_t name_len,
-                                         int type)
-{
-       struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
-       const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
-
-       if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
-               return 0;
-
-       if (list && size <= list_len)
-               memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
-       return size;
-}
-
-static size_t ocfs2_xattr_list_acl_default(struct dentry *dentry,
-                                          char *list,
-                                          size_t list_len,
-                                          const char *name,
-                                          size_t name_len,
-                                          int type)
-{
-       struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
-       const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
-
-       if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
-               return 0;
-
-       if (list && size <= list_len)
-               memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
-       return size;
-}
-
-static int ocfs2_xattr_get_acl(struct dentry *dentry, const char *name,
-               void *buffer, size_t size, int type)
-{
-       struct ocfs2_super *osb = OCFS2_SB(dentry->d_sb);
-       struct posix_acl *acl;
-       int ret;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
-               return -EOPNOTSUPP;
-
-       acl = ocfs2_get_acl(dentry->d_inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl == NULL)
-               return -ENODATA;
-       ret = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
-       return ret;
-}
-
-static int ocfs2_xattr_set_acl(struct dentry *dentry, const char *name,
-               const void *value, size_t size, int flags, int type)
-{
-       struct inode *inode = dentry->d_inode;
-       struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
-       struct posix_acl *acl;
-       int ret = 0;
-
-       if (strcmp(name, "") != 0)
-               return -EINVAL;
-       if (!(osb->s_mount_opt & OCFS2_MOUNT_POSIX_ACL))
-               return -EOPNOTSUPP;
-
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-               else if (acl) {
-                       ret = posix_acl_valid(acl);
-                       if (ret)
-                               goto cleanup;
-               }
-       } else
-               acl = NULL;
-
-       ret = ocfs2_set_acl(NULL, inode, NULL, type, acl, NULL, NULL);
-
-cleanup:
-       posix_acl_release(acl);
-       return ret;
-}
-
-const struct xattr_handler ocfs2_xattr_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags  = ACL_TYPE_ACCESS,
-       .list   = ocfs2_xattr_list_acl_access,
-       .get    = ocfs2_xattr_get_acl,
-       .set    = ocfs2_xattr_set_acl,
-};
-
-const struct xattr_handler ocfs2_xattr_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags  = ACL_TYPE_DEFAULT,
-       .list   = ocfs2_xattr_list_acl_default,
-       .get    = ocfs2_xattr_get_acl,
-       .set    = ocfs2_xattr_set_acl,
-};
index 071fbd380f2f52889fe4ddc459df3bf603d7629e..3fce68d086251a6e26ea9805361e3a1ccb351d46 100644 (file)
@@ -27,10 +27,13 @@ struct ocfs2_acl_entry {
 };
 
 struct posix_acl *ocfs2_iop_get_acl(struct inode *inode, int type);
-extern int ocfs2_acl_chmod(struct inode *);
-extern int ocfs2_init_acl(handle_t *, struct inode *, struct inode *,
-                         struct buffer_head *, struct buffer_head *,
-                         struct ocfs2_alloc_context *,
-                         struct ocfs2_alloc_context *);
+int ocfs2_iop_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+int ocfs2_set_acl(handle_t *handle,
+                        struct inode *inode,
+                        struct buffer_head *di_bh,
+                        int type,
+                        struct posix_acl *acl,
+                        struct ocfs2_alloc_context *meta_ac,
+                        struct ocfs2_alloc_context *data_ac);
 
 #endif /* OCFS2_ACL_H */
index 73920ffda05b331c85ef1760d97083d1590a4a16..bf482dfed14fecf17406a6aa2d517929d6834800 100644 (file)
@@ -413,7 +413,7 @@ static struct bio *o2hb_setup_one_bio(struct o2hb_region *reg,
        }
 
        /* Must put everything in 512 byte sectors for the bio... */
-       bio->bi_sector = (reg->hr_start_block + cs) << (bits - 9);
+       bio->bi_iter.bi_sector = (reg->hr_start_block + cs) << (bits - 9);
        bio->bi_bdev = reg->hr_bdev;
        bio->bi_private = wc;
        bio->bi_end_io = o2hb_bio_end_io;
index f42eecef64781ecac5af385adbb9a91b19f02e51..d77d71ead8d12071a52b1f0f63c66f1077c93f84 100644 (file)
@@ -1236,7 +1236,7 @@ bail:
                dqput(transfer_to[qtype]);
 
        if (!status && attr->ia_valid & ATTR_MODE) {
-               status = ocfs2_acl_chmod(inode);
+               status = posix_acl_chmod(inode, inode->i_mode);
                if (status < 0)
                        mlog_errno(status);
        }
@@ -2662,6 +2662,7 @@ const struct inode_operations ocfs2_file_iops = {
        .removexattr    = generic_removexattr,
        .fiemap         = ocfs2_fiemap,
        .get_acl        = ocfs2_iop_get_acl,
+       .set_acl        = ocfs2_iop_set_acl,
 };
 
 const struct inode_operations ocfs2_special_file_iops = {
@@ -2669,6 +2670,7 @@ const struct inode_operations ocfs2_special_file_iops = {
        .getattr        = ocfs2_getattr,
        .permission     = ocfs2_permission,
        .get_acl        = ocfs2_iop_get_acl,
+       .set_acl        = ocfs2_iop_set_acl,
 };
 
 /*
index 4f791f6d27d0463f8bef77dc20a5f5274df8ddea..f4d609be940086794ff8e64b1ed7cd832ba517f5 100644 (file)
@@ -230,6 +230,7 @@ static int ocfs2_mknod(struct inode *dir,
        struct ocfs2_dir_lookup_result lookup = { NULL, };
        sigset_t oldset;
        int did_block_signals = 0;
+       struct posix_acl *default_acl = NULL, *acl = NULL;
 
        trace_ocfs2_mknod(dir, dentry, dentry->d_name.len, dentry->d_name.name,
                          (unsigned long long)OCFS2_I(dir)->ip_blkno,
@@ -331,6 +332,12 @@ static int ocfs2_mknod(struct inode *dir,
                goto leave;
        }
 
+       status = posix_acl_create(dir, &mode, &default_acl, &acl);
+       if (status) {
+               mlog_errno(status);
+               goto leave;
+       }
+
        handle = ocfs2_start_trans(osb, ocfs2_mknod_credits(osb->sb,
                                                            S_ISDIR(mode),
                                                            xattr_credits));
@@ -379,8 +386,17 @@ static int ocfs2_mknod(struct inode *dir,
                inc_nlink(dir);
        }
 
-       status = ocfs2_init_acl(handle, inode, dir, new_fe_bh, parent_fe_bh,
-                               meta_ac, data_ac);
+       if (default_acl) {
+               status = ocfs2_set_acl(handle, inode, new_fe_bh,
+                                      ACL_TYPE_DEFAULT, default_acl,
+                                      meta_ac, data_ac);
+       }
+       if (!status && acl) {
+               status = ocfs2_set_acl(handle, inode, new_fe_bh,
+                                      ACL_TYPE_ACCESS, acl,
+                                      meta_ac, data_ac);
+       }
+
        if (status < 0) {
                mlog_errno(status);
                goto leave;
@@ -419,6 +435,10 @@ static int ocfs2_mknod(struct inode *dir,
        d_instantiate(dentry, inode);
        status = 0;
 leave:
+       if (default_acl)
+               posix_acl_release(default_acl);
+       if (acl)
+               posix_acl_release(acl);
        if (status < 0 && did_quota_inode)
                dquot_free_inode(inode);
        if (handle)
@@ -948,7 +968,7 @@ leave:
        ocfs2_free_dir_lookup_result(&orphan_insert);
        ocfs2_free_dir_lookup_result(&lookup);
 
-       if (status && (status != -ENOTEMPTY))
+       if (status && (status != -ENOTEMPTY) && (status != -ENOENT))
                mlog_errno(status);
 
        return status;
@@ -2504,4 +2524,5 @@ const struct inode_operations ocfs2_dir_iops = {
        .removexattr    = generic_removexattr,
        .fiemap         = ocfs2_fiemap,
        .get_acl        = ocfs2_iop_get_acl,
+       .set_acl        = ocfs2_iop_set_acl,
 };
index 55767e1ba72492431dcb3ae9fe204526d93f28d2..6ba4bcbc479601bcad6a98ba7a73ccc80dc40710 100644 (file)
@@ -46,6 +46,7 @@
 #include <linux/quotaops.h>
 #include <linux/namei.h>
 #include <linux/mount.h>
+#include <linux/posix_acl.h>
 
 struct ocfs2_cow_context {
        struct inode *inode;
@@ -4268,11 +4269,20 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir,
        struct inode *inode = old_dentry->d_inode;
        struct buffer_head *old_bh = NULL;
        struct inode *new_orphan_inode = NULL;
+       struct posix_acl *default_acl, *acl;
+       umode_t mode;
 
        if (!ocfs2_refcount_tree(OCFS2_SB(inode->i_sb)))
                return -EOPNOTSUPP;
 
-       error = ocfs2_create_inode_in_orphan(dir, inode->i_mode,
+       mode = inode->i_mode;
+       error = posix_acl_create(dir, &mode, &default_acl, &acl);
+       if (error) {
+               mlog_errno(error);
+               goto out;
+       }
+
+       error = ocfs2_create_inode_in_orphan(dir, mode,
                                             &new_orphan_inode);
        if (error) {
                mlog_errno(error);
@@ -4303,11 +4313,16 @@ static int ocfs2_reflink(struct dentry *old_dentry, struct inode *dir,
        /* If the security isn't preserved, we need to re-initialize them. */
        if (!preserve) {
                error = ocfs2_init_security_and_acl(dir, new_orphan_inode,
-                                                   &new_dentry->d_name);
+                                                   &new_dentry->d_name,
+                                                   default_acl, acl);
                if (error)
                        mlog_errno(error);
        }
 out:
+       if (default_acl)
+               posix_acl_release(default_acl);
+       if (acl)
+               posix_acl_release(acl);
        if (!error) {
                error = ocfs2_mv_orphaned_inode_to_new(dir, new_orphan_inode,
                                                       new_dentry);
index f0a1326d9bba89812f5ae736938ca3cfbee1284d..185fa3b7f962a482f06f9926cca946185672c7d6 100644 (file)
@@ -99,8 +99,8 @@ static struct ocfs2_xattr_def_value_root def_xv = {
 
 const struct xattr_handler *ocfs2_xattr_handlers[] = {
        &ocfs2_xattr_user_handler,
-       &ocfs2_xattr_acl_access_handler,
-       &ocfs2_xattr_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
        &ocfs2_xattr_trusted_handler,
        &ocfs2_xattr_security_handler,
        NULL
@@ -109,9 +109,9 @@ const struct xattr_handler *ocfs2_xattr_handlers[] = {
 static const struct xattr_handler *ocfs2_xattr_handler_map[OCFS2_XATTR_MAX] = {
        [OCFS2_XATTR_INDEX_USER]        = &ocfs2_xattr_user_handler,
        [OCFS2_XATTR_INDEX_POSIX_ACL_ACCESS]
-                                       = &ocfs2_xattr_acl_access_handler,
+                                       = &posix_acl_access_xattr_handler,
        [OCFS2_XATTR_INDEX_POSIX_ACL_DEFAULT]
-                                       = &ocfs2_xattr_acl_default_handler,
+                                       = &posix_acl_default_xattr_handler,
        [OCFS2_XATTR_INDEX_TRUSTED]     = &ocfs2_xattr_trusted_handler,
        [OCFS2_XATTR_INDEX_SECURITY]    = &ocfs2_xattr_security_handler,
 };
@@ -7190,10 +7190,12 @@ out:
  */
 int ocfs2_init_security_and_acl(struct inode *dir,
                                struct inode *inode,
-                               const struct qstr *qstr)
+                               const struct qstr *qstr,
+                               struct posix_acl *default_acl,
+                               struct posix_acl *acl)
 {
-       int ret = 0;
        struct buffer_head *dir_bh = NULL;
+       int ret = 0;
 
        ret = ocfs2_init_security_get(inode, dir, qstr, NULL);
        if (ret) {
@@ -7207,9 +7209,10 @@ int ocfs2_init_security_and_acl(struct inode *dir,
                goto leave;
        }
 
-       ret = ocfs2_init_acl(NULL, inode, dir, NULL, dir_bh, NULL, NULL);
-       if (ret)
-               mlog_errno(ret);
+       if (!ret && default_acl)
+               ret = ocfs2_iop_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+       if (!ret && acl)
+               ret = ocfs2_iop_set_acl(inode, acl, ACL_TYPE_ACCESS);
 
        ocfs2_inode_unlock(dir, 0);
        brelse(dir_bh);
index 19f134e896a9a8bdd69a387015819e4ebc3c2705..f10d5b93c366c8a7d12ddc1c90766ea88ed3dc56 100644 (file)
@@ -40,8 +40,6 @@ struct ocfs2_security_xattr_info {
 extern const struct xattr_handler ocfs2_xattr_user_handler;
 extern const struct xattr_handler ocfs2_xattr_trusted_handler;
 extern const struct xattr_handler ocfs2_xattr_security_handler;
-extern const struct xattr_handler ocfs2_xattr_acl_access_handler;
-extern const struct xattr_handler ocfs2_xattr_acl_default_handler;
 extern const struct xattr_handler *ocfs2_xattr_handlers[];
 
 ssize_t ocfs2_listxattr(struct dentry *, char *, size_t);
@@ -96,5 +94,7 @@ int ocfs2_reflink_xattrs(struct inode *old_inode,
                         bool preserve_security);
 int ocfs2_init_security_and_acl(struct inode *dir,
                                struct inode *inode,
-                               const struct qstr *qstr);
+                               const struct qstr *qstr,
+                               struct posix_acl *default_acl,
+                               struct posix_acl *acl);
 #endif /* OCFS2_XATTR_H */
index 551e61ba15b6047c909594968163eaf26c8cb605..38bae5a0ea257ebc414aef89727f3a652d904c96 100644 (file)
@@ -1,10 +1,8 @@
 /*
- * linux/fs/posix_acl.c
+ * Copyright (C) 2002,2003 by Andreas Gruenbacher <a.gruenbacher@computer.org>
  *
- *  Copyright (C) 2002 by Andreas Gruenbacher <a.gruenbacher@computer.org>
- *
- *  Fixes from William Schumacher incorporated on 15 March 2001.
- *     (Reported by Charles Bertsch, <CBertsch@microtest.com>).
+ * Fixes from William Schumacher incorporated on 15 March 2001.
+ *    (Reported by Charles Bertsch, <CBertsch@microtest.com>).
  */
 
 /*
 #include <linux/fs.h>
 #include <linux/sched.h>
 #include <linux/posix_acl.h>
+#include <linux/posix_acl_xattr.h>
+#include <linux/xattr.h>
 #include <linux/export.h>
-
-#include <linux/errno.h>
+#include <linux/user_namespace.h>
 
 struct posix_acl **acl_by_type(struct inode *inode, int type)
 {
@@ -97,6 +96,33 @@ void forget_all_cached_acls(struct inode *inode)
 }
 EXPORT_SYMBOL(forget_all_cached_acls);
 
+struct posix_acl *get_acl(struct inode *inode, int type)
+{
+       struct posix_acl *acl;
+
+       acl = get_cached_acl(inode, type);
+       if (acl != ACL_NOT_CACHED)
+               return acl;
+
+       if (!IS_POSIXACL(inode))
+               return NULL;
+
+       /*
+        * A filesystem can force a ACL callback by just never filling the
+        * ACL cache. But normally you'd fill the cache either at inode
+        * instantiation time, or on the first ->get_acl call.
+        *
+        * If the filesystem doesn't have a get_acl() function at all, we'll
+        * just create the negative cache entry.
+        */
+       if (!inode->i_op->get_acl) {
+               set_cached_acl(inode, type, NULL);
+               return NULL;
+       }
+       return inode->i_op->get_acl(inode, type);
+}
+EXPORT_SYMBOL(get_acl);
+
 /*
  * Init a fresh posix_acl
  */
@@ -402,7 +428,7 @@ static int posix_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
 /*
  * Modify the ACL for the chmod syscall.
  */
-static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
+static int __posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
 {
        struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
        struct posix_acl_entry *pa, *pe;
@@ -448,7 +474,7 @@ static int posix_acl_chmod_masq(struct posix_acl *acl, umode_t mode)
 }
 
 int
-posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
+__posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
 {
        struct posix_acl *clone = posix_acl_clone(*acl, gfp);
        int err = -ENOMEM;
@@ -463,15 +489,15 @@ posix_acl_create(struct posix_acl **acl, gfp_t gfp, umode_t *mode_p)
        *acl = clone;
        return err;
 }
-EXPORT_SYMBOL(posix_acl_create);
+EXPORT_SYMBOL(__posix_acl_create);
 
 int
-posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
+__posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
 {
        struct posix_acl *clone = posix_acl_clone(*acl, gfp);
        int err = -ENOMEM;
        if (clone) {
-               err = posix_acl_chmod_masq(clone, mode);
+               err = __posix_acl_chmod_masq(clone, mode);
                if (err) {
                        posix_acl_release(clone);
                        clone = NULL;
@@ -481,4 +507,382 @@ posix_acl_chmod(struct posix_acl **acl, gfp_t gfp, umode_t mode)
        *acl = clone;
        return err;
 }
+EXPORT_SYMBOL(__posix_acl_chmod);
+
+int
+posix_acl_chmod(struct inode *inode, umode_t mode)
+{
+       struct posix_acl *acl;
+       int ret = 0;
+
+       if (!IS_POSIXACL(inode))
+               return 0;
+       if (!inode->i_op->set_acl)
+               return -EOPNOTSUPP;
+
+       acl = get_acl(inode, ACL_TYPE_ACCESS);
+       if (IS_ERR_OR_NULL(acl))
+               return PTR_ERR(acl);
+
+       ret = __posix_acl_chmod(&acl, GFP_KERNEL, mode);
+       if (ret)
+               return ret;
+       ret = inode->i_op->set_acl(inode, acl, ACL_TYPE_ACCESS);
+       posix_acl_release(acl);
+       return ret;
+}
 EXPORT_SYMBOL(posix_acl_chmod);
+
+int
+posix_acl_create(struct inode *dir, umode_t *mode,
+               struct posix_acl **default_acl, struct posix_acl **acl)
+{
+       struct posix_acl *p;
+       int ret;
+
+       if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
+               goto no_acl;
+
+       p = get_acl(dir, ACL_TYPE_DEFAULT);
+       if (IS_ERR(p))
+               return PTR_ERR(p);
+
+       if (!p) {
+               *mode &= ~current_umask();
+               goto no_acl;
+       }
+
+       *acl = posix_acl_clone(p, GFP_NOFS);
+       if (!*acl)
+               return -ENOMEM;
+
+       ret = posix_acl_create_masq(*acl, mode);
+       if (ret < 0) {
+               posix_acl_release(*acl);
+               return -ENOMEM;
+       }
+
+       if (ret == 0) {
+               posix_acl_release(*acl);
+               *acl = NULL;
+       }
+
+       if (!S_ISDIR(*mode)) {
+               posix_acl_release(p);
+               *default_acl = NULL;
+       } else {
+               *default_acl = p;
+       }
+       return 0;
+
+no_acl:
+       *default_acl = NULL;
+       *acl = NULL;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(posix_acl_create);
+
+/*
+ * Fix up the uids and gids in posix acl extended attributes in place.
+ */
+static void posix_acl_fix_xattr_userns(
+       struct user_namespace *to, struct user_namespace *from,
+       void *value, size_t size)
+{
+       posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
+       posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
+       int count;
+       kuid_t uid;
+       kgid_t gid;
+
+       if (!value)
+               return;
+       if (size < sizeof(posix_acl_xattr_header))
+               return;
+       if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
+               return;
+
+       count = posix_acl_xattr_count(size);
+       if (count < 0)
+               return;
+       if (count == 0)
+               return;
+
+       for (end = entry + count; entry != end; entry++) {
+               switch(le16_to_cpu(entry->e_tag)) {
+               case ACL_USER:
+                       uid = make_kuid(from, le32_to_cpu(entry->e_id));
+                       entry->e_id = cpu_to_le32(from_kuid(to, uid));
+                       break;
+               case ACL_GROUP:
+                       gid = make_kgid(from, le32_to_cpu(entry->e_id));
+                       entry->e_id = cpu_to_le32(from_kgid(to, gid));
+                       break;
+               default:
+                       break;
+               }
+       }
+}
+
+void posix_acl_fix_xattr_from_user(void *value, size_t size)
+{
+       struct user_namespace *user_ns = current_user_ns();
+       if (user_ns == &init_user_ns)
+               return;
+       posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
+}
+
+void posix_acl_fix_xattr_to_user(void *value, size_t size)
+{
+       struct user_namespace *user_ns = current_user_ns();
+       if (user_ns == &init_user_ns)
+               return;
+       posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
+}
+
+/*
+ * Convert from extended attribute to in-memory representation.
+ */
+struct posix_acl *
+posix_acl_from_xattr(struct user_namespace *user_ns,
+                    const void *value, size_t size)
+{
+       posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
+       posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
+       int count;
+       struct posix_acl *acl;
+       struct posix_acl_entry *acl_e;
+
+       if (!value)
+               return NULL;
+       if (size < sizeof(posix_acl_xattr_header))
+                return ERR_PTR(-EINVAL);
+       if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
+               return ERR_PTR(-EOPNOTSUPP);
+
+       count = posix_acl_xattr_count(size);
+       if (count < 0)
+               return ERR_PTR(-EINVAL);
+       if (count == 0)
+               return NULL;
+       
+       acl = posix_acl_alloc(count, GFP_NOFS);
+       if (!acl)
+               return ERR_PTR(-ENOMEM);
+       acl_e = acl->a_entries;
+       
+       for (end = entry + count; entry != end; acl_e++, entry++) {
+               acl_e->e_tag  = le16_to_cpu(entry->e_tag);
+               acl_e->e_perm = le16_to_cpu(entry->e_perm);
+
+               switch(acl_e->e_tag) {
+                       case ACL_USER_OBJ:
+                       case ACL_GROUP_OBJ:
+                       case ACL_MASK:
+                       case ACL_OTHER:
+                               break;
+
+                       case ACL_USER:
+                               acl_e->e_uid =
+                                       make_kuid(user_ns,
+                                                 le32_to_cpu(entry->e_id));
+                               if (!uid_valid(acl_e->e_uid))
+                                       goto fail;
+                               break;
+                       case ACL_GROUP:
+                               acl_e->e_gid =
+                                       make_kgid(user_ns,
+                                                 le32_to_cpu(entry->e_id));
+                               if (!gid_valid(acl_e->e_gid))
+                                       goto fail;
+                               break;
+
+                       default:
+                               goto fail;
+               }
+       }
+       return acl;
+
+fail:
+       posix_acl_release(acl);
+       return ERR_PTR(-EINVAL);
+}
+EXPORT_SYMBOL (posix_acl_from_xattr);
+
+/*
+ * Convert from in-memory to extended attribute representation.
+ */
+int
+posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
+                  void *buffer, size_t size)
+{
+       posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer;
+       posix_acl_xattr_entry *ext_entry = ext_acl->a_entries;
+       int real_size, n;
+
+       real_size = posix_acl_xattr_size(acl->a_count);
+       if (!buffer)
+               return real_size;
+       if (real_size > size)
+               return -ERANGE;
+       
+       ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
+
+       for (n=0; n < acl->a_count; n++, ext_entry++) {
+               const struct posix_acl_entry *acl_e = &acl->a_entries[n];
+               ext_entry->e_tag  = cpu_to_le16(acl_e->e_tag);
+               ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
+               switch(acl_e->e_tag) {
+               case ACL_USER:
+                       ext_entry->e_id =
+                               cpu_to_le32(from_kuid(user_ns, acl_e->e_uid));
+                       break;
+               case ACL_GROUP:
+                       ext_entry->e_id =
+                               cpu_to_le32(from_kgid(user_ns, acl_e->e_gid));
+                       break;
+               default:
+                       ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
+                       break;
+               }
+       }
+       return real_size;
+}
+EXPORT_SYMBOL (posix_acl_to_xattr);
+
+static int
+posix_acl_xattr_get(struct dentry *dentry, const char *name,
+               void *value, size_t size, int type)
+{
+       struct posix_acl *acl;
+       int error;
+
+       if (!IS_POSIXACL(dentry->d_inode))
+               return -EOPNOTSUPP;
+       if (S_ISLNK(dentry->d_inode->i_mode))
+               return -EOPNOTSUPP;
+
+       acl = get_acl(dentry->d_inode, type);
+       if (IS_ERR(acl))
+               return PTR_ERR(acl);
+       if (acl == NULL)
+               return -ENODATA;
+
+       error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
+       posix_acl_release(acl);
+
+       return error;
+}
+
+static int
+posix_acl_xattr_set(struct dentry *dentry, const char *name,
+               const void *value, size_t size, int flags, int type)
+{
+       struct inode *inode = dentry->d_inode;
+       struct posix_acl *acl = NULL;
+       int ret;
+
+       if (!IS_POSIXACL(inode))
+               return -EOPNOTSUPP;
+       if (!inode->i_op->set_acl)
+               return -EOPNOTSUPP;
+
+       if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
+               return value ? -EACCES : 0;
+       if (!inode_owner_or_capable(inode))
+               return -EPERM;
+
+       if (value) {
+               acl = posix_acl_from_xattr(&init_user_ns, value, size);
+               if (IS_ERR(acl))
+                       return PTR_ERR(acl);
+
+               if (acl) {
+                       ret = posix_acl_valid(acl);
+                       if (ret)
+                               goto out;
+               }
+       }
+
+       ret = inode->i_op->set_acl(inode, acl, type);
+out:
+       posix_acl_release(acl);
+       return ret;
+}
+
+static size_t
+posix_acl_xattr_list(struct dentry *dentry, char *list, size_t list_size,
+               const char *name, size_t name_len, int type)
+{
+       const char *xname;
+       size_t size;
+
+       if (!IS_POSIXACL(dentry->d_inode))
+               return -EOPNOTSUPP;
+       if (S_ISLNK(dentry->d_inode->i_mode))
+               return -EOPNOTSUPP;
+
+       if (type == ACL_TYPE_ACCESS)
+               xname = POSIX_ACL_XATTR_ACCESS;
+       else
+               xname = POSIX_ACL_XATTR_DEFAULT;
+
+       size = strlen(xname) + 1;
+       if (list && size <= list_size)
+               memcpy(list, xname, size);
+       return size;
+}
+
+const struct xattr_handler posix_acl_access_xattr_handler = {
+       .prefix = POSIX_ACL_XATTR_ACCESS,
+       .flags = ACL_TYPE_ACCESS,
+       .list = posix_acl_xattr_list,
+       .get = posix_acl_xattr_get,
+       .set = posix_acl_xattr_set,
+};
+EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler);
+
+const struct xattr_handler posix_acl_default_xattr_handler = {
+       .prefix = POSIX_ACL_XATTR_DEFAULT,
+       .flags = ACL_TYPE_DEFAULT,
+       .list = posix_acl_xattr_list,
+       .get = posix_acl_xattr_get,
+       .set = posix_acl_xattr_set,
+};
+EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler);
+
+int simple_set_acl(struct inode *inode, struct posix_acl *acl, int type)
+{
+       int error;
+
+       if (type == ACL_TYPE_ACCESS) {
+               error = posix_acl_equiv_mode(acl, &inode->i_mode);
+               if (error < 0)
+                       return 0;
+               if (error == 0)
+                       acl = NULL;
+       }
+
+       inode->i_ctime = CURRENT_TIME;
+       set_cached_acl(inode, type, acl);
+       return 0;
+}
+
+int simple_acl_create(struct inode *dir, struct inode *inode)
+{
+       struct posix_acl *default_acl, *acl;
+       int error;
+
+       error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+       if (error)
+               return error;
+
+       set_cached_acl(inode, ACL_TYPE_DEFAULT, default_acl);
+       set_cached_acl(inode, ACL_TYPE_ACCESS, acl);
+
+       if (default_acl)
+               posix_acl_release(default_acl);
+       if (acl)
+               posix_acl_release(acl);
+       return 0;
+}
index 2e8caa62da78a71cc1ee46ce49634aab9408a779..89558810381c497389c184856d30efd0a2ce9717 100644 (file)
@@ -27,7 +27,6 @@
 
 static const struct super_operations qnx4_sops;
 
-static void qnx4_put_super(struct super_block *sb);
 static struct inode *qnx4_alloc_inode(struct super_block *sb);
 static void qnx4_destroy_inode(struct inode *inode);
 static int qnx4_remount(struct super_block *sb, int *flags, char *data);
@@ -37,7 +36,6 @@ static const struct super_operations qnx4_sops =
 {
        .alloc_inode    = qnx4_alloc_inode,
        .destroy_inode  = qnx4_destroy_inode,
-       .put_super      = qnx4_put_super,
        .statfs         = qnx4_statfs,
        .remount_fs     = qnx4_remount,
 };
@@ -148,18 +146,19 @@ static int qnx4_statfs(struct dentry *dentry, struct kstatfs *buf)
  * it really _is_ a qnx4 filesystem, and to check the size
  * of the directory entry.
  */
-static const char *qnx4_checkroot(struct super_block *sb)
+static const char *qnx4_checkroot(struct super_block *sb,
+                                 struct qnx4_super_block *s)
 {
        struct buffer_head *bh;
        struct qnx4_inode_entry *rootdir;
        int rd, rl;
        int i, j;
 
-       if (*(qnx4_sb(sb)->sb->RootDir.di_fname) != '/')
+       if (s->RootDir.di_fname[0] != '/' || s->RootDir.di_fname[1] != '\0')
                return "no qnx4 filesystem (no root dir).";
        QNX4DEBUG((KERN_NOTICE "QNX4 filesystem found on dev %s.\n", sb->s_id));
-       rd = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_blk) - 1;
-       rl = le32_to_cpu(qnx4_sb(sb)->sb->RootDir.di_first_xtnt.xtnt_size);
+       rd = le32_to_cpu(s->RootDir.di_first_xtnt.xtnt_blk) - 1;
+       rl = le32_to_cpu(s->RootDir.di_first_xtnt.xtnt_size);
        for (j = 0; j < rl; j++) {
                bh = sb_bread(sb, rd + j);      /* root dir, first block */
                if (bh == NULL)
@@ -189,7 +188,6 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
        struct inode *root;
        const char *errmsg;
        struct qnx4_sb_info *qs;
-       int ret = -EINVAL;
 
        qs = kzalloc(sizeof(struct qnx4_sb_info), GFP_KERNEL);
        if (!qs)
@@ -198,67 +196,50 @@ static int qnx4_fill_super(struct super_block *s, void *data, int silent)
 
        sb_set_blocksize(s, QNX4_BLOCK_SIZE);
 
+       s->s_op = &qnx4_sops;
+       s->s_magic = QNX4_SUPER_MAGIC;
+       s->s_flags |= MS_RDONLY;        /* Yup, read-only yet */
+
        /* Check the superblock signature. Since the qnx4 code is
           dangerous, we should leave as quickly as possible
           if we don't belong here... */
        bh = sb_bread(s, 1);
        if (!bh) {
                printk(KERN_ERR "qnx4: unable to read the superblock\n");
-               goto outnobh;
+               return -EINVAL;
        }
-       if ( le32_to_cpup((__le32*) bh->b_data) != QNX4_SUPER_MAGIC ) {
-               if (!silent)
-                       printk(KERN_ERR "qnx4: wrong fsid in superblock.\n");
-               goto out;
-       }
-       s->s_op = &qnx4_sops;
-       s->s_magic = QNX4_SUPER_MAGIC;
-       s->s_flags |= MS_RDONLY;        /* Yup, read-only yet */
-       qnx4_sb(s)->sb_buf = bh;
-       qnx4_sb(s)->sb = (struct qnx4_super_block *) bh->b_data;
-
 
        /* check before allocating dentries, inodes, .. */
-       errmsg = qnx4_checkroot(s);
+       errmsg = qnx4_checkroot(s, (struct qnx4_super_block *) bh->b_data);
+       brelse(bh);
        if (errmsg != NULL) {
                if (!silent)
                        printk(KERN_ERR "qnx4: %s\n", errmsg);
-               goto out;
+               return -EINVAL;
        }
 
        /* does root not have inode number QNX4_ROOT_INO ?? */
        root = qnx4_iget(s, QNX4_ROOT_INO * QNX4_INODES_PER_BLOCK);
        if (IS_ERR(root)) {
                printk(KERN_ERR "qnx4: get inode failed\n");
-               ret = PTR_ERR(root);
-               goto outb;
+               return PTR_ERR(root);
        }
 
-       ret = -ENOMEM;
        s->s_root = d_make_root(root);
        if (s->s_root == NULL)
-               goto outb;
+               return -ENOMEM;
 
-       brelse(bh);
        return 0;
-
-      outb:
-       kfree(qs->BitMap);
-      out:
-       brelse(bh);
-      outnobh:
-       kfree(qs);
-       s->s_fs_info = NULL;
-       return ret;
 }
 
-static void qnx4_put_super(struct super_block *sb)
+static void qnx4_kill_sb(struct super_block *sb)
 {
        struct qnx4_sb_info *qs = qnx4_sb(sb);
-       kfree( qs->BitMap );
-       kfree( qs );
-       sb->s_fs_info = NULL;
-       return;
+       kill_block_super(sb);
+       if (qs) {
+               kfree(qs->BitMap);
+               kfree(qs);
+       }
 }
 
 static int qnx4_readpage(struct file *file, struct page *page)
@@ -409,7 +390,7 @@ static struct file_system_type qnx4_fs_type = {
        .owner          = THIS_MODULE,
        .name           = "qnx4",
        .mount          = qnx4_mount,
-       .kill_sb        = kill_block_super,
+       .kill_sb        = qnx4_kill_sb,
        .fs_flags       = FS_REQUIRES_DEV,
 };
 MODULE_ALIAS_FS("qnx4");
index 34e2d329c97e057f330d83f835fd111f931607be..c9b1be2c164dd9339b94cddd2a9d21ad2abd7577 100644 (file)
@@ -10,8 +10,6 @@
 #endif
 
 struct qnx4_sb_info {
-       struct buffer_head      *sb_buf;        /* superblock buffer */
-       struct qnx4_super_block *sb;            /* our superblock */
        unsigned int            Version;        /* may be useful */
        struct qnx4_inode_entry *BitMap;        /* useful */
 };
index 1193ffd0356547b63cdf0a503a2eb68ae84d8ba6..edc5746a902a090ce4dbda6b8b1205e729dff5b3 100644 (file)
@@ -964,9 +964,9 @@ out:
        return ret;
 }
 
-COMPAT_SYSCALL_DEFINE3(readv, unsigned long, fd,
+COMPAT_SYSCALL_DEFINE3(readv, compat_ulong_t, fd,
                const struct compat_iovec __user *,vec,
-               unsigned long, vlen)
+               compat_ulong_t, vlen)
 {
        struct fd f = fdget(fd);
        ssize_t ret;
@@ -1001,9 +1001,9 @@ COMPAT_SYSCALL_DEFINE4(preadv64, unsigned long, fd,
        return ret;
 }
 
-COMPAT_SYSCALL_DEFINE5(preadv, unsigned long, fd,
+COMPAT_SYSCALL_DEFINE5(preadv, compat_ulong_t, fd,
                const struct compat_iovec __user *,vec,
-               unsigned long, vlen, u32, pos_low, u32, pos_high)
+               compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
 {
        loff_t pos = ((loff_t)pos_high << 32) | pos_low;
        return compat_sys_preadv64(fd, vec, vlen, pos);
@@ -1031,9 +1031,9 @@ out:
        return ret;
 }
 
-COMPAT_SYSCALL_DEFINE3(writev, unsigned long, fd,
+COMPAT_SYSCALL_DEFINE3(writev, compat_ulong_t, fd,
                const struct compat_iovec __user *, vec,
-               unsigned long, vlen)
+               compat_ulong_t, vlen)
 {
        struct fd f = fdget(fd);
        ssize_t ret;
@@ -1068,9 +1068,9 @@ COMPAT_SYSCALL_DEFINE4(pwritev64, unsigned long, fd,
        return ret;
 }
 
-COMPAT_SYSCALL_DEFINE5(pwritev, unsigned long, fd,
+COMPAT_SYSCALL_DEFINE5(pwritev, compat_ulong_t, fd,
                const struct compat_iovec __user *,vec,
-               unsigned long, vlen, u32, pos_low, u32, pos_high)
+               compat_ulong_t, vlen, u32, pos_low, u32, pos_high)
 {
        loff_t pos = ((loff_t)pos_high << 32) | pos_low;
        return compat_sys_pwritev64(fd, vec, vlen, pos);
index f096b80e73d8145dc35bcdb36f008d29a61f07d9..4a211f5b34b81f00dc123c251a3adc7aff9dcf93 100644 (file)
@@ -48,18 +48,18 @@ static inline int reiserfs_acl_count(size_t size)
 
 #ifdef CONFIG_REISERFS_FS_POSIX_ACL
 struct posix_acl *reiserfs_get_acl(struct inode *inode, int type);
+int reiserfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 int reiserfs_acl_chmod(struct inode *inode);
 int reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
                                 struct inode *dir, struct dentry *dentry,
                                 struct inode *inode);
 int reiserfs_cache_default_acl(struct inode *dir);
-extern const struct xattr_handler reiserfs_posix_acl_default_handler;
-extern const struct xattr_handler reiserfs_posix_acl_access_handler;
 
 #else
 
 #define reiserfs_cache_default_acl(inode) 0
 #define reiserfs_get_acl NULL
+#define reiserfs_set_acl NULL
 
 static inline int reiserfs_acl_chmod(struct inode *inode)
 {
index dcaafcfc23b007c845f490a4f293cc485c324b51..ed58d843d57856ac3cdc87288465d0d5156708e9 100644 (file)
@@ -260,4 +260,5 @@ const struct inode_operations reiserfs_file_inode_operations = {
        .removexattr = reiserfs_removexattr,
        .permission = reiserfs_permission,
        .get_acl = reiserfs_get_acl,
+       .set_acl = reiserfs_set_acl,
 };
index dc5236f6de1be129e44caf8f78f16d010d7ad7fb..e825f8b63e6b7433c125e040117de525a2d0cf31 100644 (file)
@@ -1522,6 +1522,7 @@ const struct inode_operations reiserfs_dir_inode_operations = {
        .removexattr = reiserfs_removexattr,
        .permission = reiserfs_permission,
        .get_acl = reiserfs_get_acl,
+       .set_acl = reiserfs_set_acl,
 };
 
 /*
@@ -1538,8 +1539,6 @@ const struct inode_operations reiserfs_symlink_inode_operations = {
        .listxattr = reiserfs_listxattr,
        .removexattr = reiserfs_removexattr,
        .permission = reiserfs_permission,
-       .get_acl = reiserfs_get_acl,
-
 };
 
 /*
@@ -1553,4 +1552,5 @@ const struct inode_operations reiserfs_special_inode_operations = {
        .removexattr = reiserfs_removexattr,
        .permission = reiserfs_permission,
        .get_acl = reiserfs_get_acl,
+       .set_acl = reiserfs_set_acl,
 };
index a958444a75fc310627d56de6a37e28a15a99273a..02b0b7d0f7d532e0ed0238161118ae627f5d9b7c 100644 (file)
@@ -419,7 +419,7 @@ int reiserfs_proc_info_init(struct super_block *sb)
        char *s;
 
        /* Some block devices use /'s */
-       strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE);
+       strlcpy(b, sb->s_id, BDEVNAME_SIZE);
        s = strchr(b, '/');
        if (s)
                *s = '!';
@@ -449,7 +449,7 @@ int reiserfs_proc_info_done(struct super_block *sb)
                char *s;
 
                /* Some block devices use /'s */
-               strlcpy(b, reiserfs_bdevname(sb), BDEVNAME_SIZE);
+               strlcpy(b, sb->s_id, BDEVNAME_SIZE);
                s = strchr(b, '/');
                if (s)
                        *s = '!';
index dfb617b2bad2ae1ada39a9ff36684793cfed51f1..8d06adf899488a53e13e97b5d2973ca536e430b0 100644 (file)
@@ -608,14 +608,6 @@ int reiserfs_resize(struct super_block *, unsigned long);
 
 #define SB_DISK_JOURNAL_HEAD(s) (SB_JOURNAL(s)->j_header_bh->)
 
-/* A safe version of the "bdevname", which returns the "s_id" field of
- * a superblock or else "Null superblock" if the super block is NULL.
- */
-static inline char *reiserfs_bdevname(struct super_block *s)
-{
-       return (s == NULL) ? "Null superblock" : s->s_id;
-}
-
 #define reiserfs_is_journal_aborted(journal) (unlikely (__reiserfs_is_journal_aborted (journal)))
 static inline int __reiserfs_is_journal_aborted(struct reiserfs_journal
                                                *journal)
index 3ead145dadc406646f742f519befe3ef9a2db6b9..2c803353f8ac4f70099f7cef6a590c46556c21d6 100644 (file)
@@ -1479,7 +1479,7 @@ static int read_super_block(struct super_block *s, int offset)
        if (!bh) {
                reiserfs_warning(s, "sh-2006",
                                 "bread failed (dev %s, block %lu, size %lu)",
-                                reiserfs_bdevname(s), offset / s->s_blocksize,
+                                s->s_id, offset / s->s_blocksize,
                                 s->s_blocksize);
                return 1;
        }
@@ -1500,7 +1500,7 @@ static int read_super_block(struct super_block *s, int offset)
        if (!bh) {
                reiserfs_warning(s, "sh-2007",
                                 "bread failed (dev %s, block %lu, size %lu)",
-                                reiserfs_bdevname(s), offset / s->s_blocksize,
+                                s->s_id, offset / s->s_blocksize,
                                 s->s_blocksize);
                return 1;
        }
@@ -1509,7 +1509,7 @@ static int read_super_block(struct super_block *s, int offset)
        if (sb_blocksize(rs) != s->s_blocksize) {
                reiserfs_warning(s, "sh-2011", "can't find a reiserfs "
                                 "filesystem on (dev %s, block %Lu, size %lu)",
-                                reiserfs_bdevname(s),
+                                s->s_id,
                                 (unsigned long long)bh->b_blocknr,
                                 s->s_blocksize);
                brelse(bh);
@@ -1825,7 +1825,7 @@ static int reiserfs_fill_super(struct super_block *s, void *data, int silent)
        /* try new format (64-th 1k block), which can contain reiserfs super block */
        else if (read_super_block(s, REISERFS_DISK_OFFSET_IN_BYTES)) {
                SWARN(silent, s, "sh-2021", "can not find reiserfs on %s",
-                     reiserfs_bdevname(s));
+                     s->s_id);
                goto error_unlocked;
        }
 
index 8a9e2dcfe004919da6fe48e4c292c7ddfeef8476..5cdfbd638b5c929382d844d358105619301eed48 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/stat.h>
 #include <linux/quotaops.h>
 #include <linux/security.h>
+#include <linux/posix_acl_xattr.h>
 
 #define PRIVROOT_NAME ".reiserfs_priv"
 #define XAROOT_NAME   "xattrs"
@@ -904,8 +905,8 @@ static const struct xattr_handler *reiserfs_xattr_handlers[] = {
        &reiserfs_xattr_security_handler,
 #endif
 #ifdef CONFIG_REISERFS_FS_POSIX_ACL
-       &reiserfs_posix_acl_access_handler,
-       &reiserfs_posix_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
        NULL
 };
index 06c04f73da6529d012ee0c8b0d364cef939709ea..a6ce532402dc7ec9851e18fe572c3ad1faf14a2a 100644 (file)
 #include "acl.h"
 #include <asm/uaccess.h>
 
-static int reiserfs_set_acl(struct reiserfs_transaction_handle *th,
+static int __reiserfs_set_acl(struct reiserfs_transaction_handle *th,
                            struct inode *inode, int type,
                            struct posix_acl *acl);
 
-static int
-posix_acl_set(struct dentry *dentry, const char *name, const void *value,
-               size_t size, int flags, int type)
+
+int
+reiserfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
-       struct inode *inode = dentry->d_inode;
-       struct posix_acl *acl;
        int error, error2;
        struct reiserfs_transaction_handle th;
        size_t jcreate_blocks;
-       if (!reiserfs_posixacl(inode->i_sb))
-               return -EOPNOTSUPP;
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-
-       if (value) {
-               acl = posix_acl_from_xattr(&init_user_ns, value, size);
-               if (IS_ERR(acl)) {
-                       return PTR_ERR(acl);
-               } else if (acl) {
-                       error = posix_acl_valid(acl);
-                       if (error)
-                               goto release_and_out;
-               }
-       } else
-               acl = NULL;
+       int size = acl ? posix_acl_xattr_size(acl->a_count) : 0;
+
 
        /* Pessimism: We can't assume that anything from the xattr root up
         * has been created. */
@@ -51,7 +35,7 @@ posix_acl_set(struct dentry *dentry, const char *name, const void *value,
        error = journal_begin(&th, inode->i_sb, jcreate_blocks);
        reiserfs_write_unlock(inode->i_sb);
        if (error == 0) {
-               error = reiserfs_set_acl(&th, inode, type, acl);
+               error = __reiserfs_set_acl(&th, inode, type, acl);
                reiserfs_write_lock(inode->i_sb);
                error2 = journal_end(&th, inode->i_sb, jcreate_blocks);
                reiserfs_write_unlock(inode->i_sb);
@@ -59,36 +43,13 @@ posix_acl_set(struct dentry *dentry, const char *name, const void *value,
                        error = error2;
        }
 
-      release_and_out:
-       posix_acl_release(acl);
-       return error;
-}
-
-static int
-posix_acl_get(struct dentry *dentry, const char *name, void *buffer,
-               size_t size, int type)
-{
-       struct posix_acl *acl;
-       int error;
-
-       if (!reiserfs_posixacl(dentry->d_sb))
-               return -EOPNOTSUPP;
-
-       acl = reiserfs_get_acl(dentry->d_inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl == NULL)
-               return -ENODATA;
-       error = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
-       posix_acl_release(acl);
-
        return error;
 }
 
 /*
  * Convert from filesystem to in-memory representation.
  */
-static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
+static struct posix_acl *reiserfs_posix_acl_from_disk(const void *value, size_t size)
 {
        const char *end = (char *)value + size;
        int n, count;
@@ -158,7 +119,7 @@ static struct posix_acl *posix_acl_from_disk(const void *value, size_t size)
 /*
  * Convert from in-memory to filesystem representation.
  */
-static void *posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
+static void *reiserfs_posix_acl_to_disk(const struct posix_acl *acl, size_t * size)
 {
        reiserfs_acl_header *ext_acl;
        char *e;
@@ -221,10 +182,6 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
        int size;
        int retval;
 
-       acl = get_cached_acl(inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
@@ -257,7 +214,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
        } else if (retval < 0) {
                acl = ERR_PTR(retval);
        } else {
-               acl = posix_acl_from_disk(value, retval);
+               acl = reiserfs_posix_acl_from_disk(value, retval);
        }
        if (!IS_ERR(acl))
                set_cached_acl(inode, type, acl);
@@ -273,7 +230,7 @@ struct posix_acl *reiserfs_get_acl(struct inode *inode, int type)
  * BKL held [before 2.5.x]
  */
 static int
-reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
+__reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
                 int type, struct posix_acl *acl)
 {
        char *name;
@@ -281,9 +238,6 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
        size_t size = 0;
        int error;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                name = POSIX_ACL_XATTR_ACCESS;
@@ -307,7 +261,7 @@ reiserfs_set_acl(struct reiserfs_transaction_handle *th, struct inode *inode,
        }
 
        if (acl) {
-               value = posix_acl_to_disk(acl, &size);
+               value = reiserfs_posix_acl_to_disk(acl, &size);
                if (IS_ERR(value))
                        return (int)PTR_ERR(value);
        }
@@ -343,7 +297,7 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
                             struct inode *dir, struct dentry *dentry,
                             struct inode *inode)
 {
-       struct posix_acl *acl;
+       struct posix_acl *default_acl, *acl;
        int err = 0;
 
        /* ACLs only get applied to files and directories */
@@ -363,37 +317,28 @@ reiserfs_inherit_default_acl(struct reiserfs_transaction_handle *th,
                goto apply_umask;
        }
 
-       acl = reiserfs_get_acl(dir, ACL_TYPE_DEFAULT);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
+       err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+       if (err)
+               return err;
 
+       if (default_acl) {
+               err = __reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
+                                        default_acl);
+               posix_acl_release(default_acl);
+       }
        if (acl) {
-               /* Copy the default ACL to the default ACL of a new directory */
-               if (S_ISDIR(inode->i_mode)) {
-                       err = reiserfs_set_acl(th, inode, ACL_TYPE_DEFAULT,
-                                              acl);
-                       if (err)
-                               goto cleanup;
-               }
-
-               /* Now we reconcile the new ACL and the mode,
-                  potentially modifying both */
-               err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
-               if (err < 0)
-                       return err;
-
-               /* If we need an ACL.. */
-               if (err > 0)
-                       err = reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS, acl);
-             cleanup:
+               if (!err)
+                       err = __reiserfs_set_acl(th, inode, ACL_TYPE_ACCESS,
+                                                acl);
                posix_acl_release(acl);
-       } else {
-             apply_umask:
-               /* no ACL, apply umask */
-               inode->i_mode &= ~current_umask();
        }
 
        return err;
+
+      apply_umask:
+       /* no ACL, apply umask */
+       inode->i_mode &= ~current_umask();
+       return err;
 }
 
 /* This is used to cache the default acl before a new object is created.
@@ -442,84 +387,11 @@ int reiserfs_cache_default_acl(struct inode *inode)
  */
 int reiserfs_acl_chmod(struct inode *inode)
 {
-       struct reiserfs_transaction_handle th;
-       struct posix_acl *acl;
-       size_t size;
-       int error;
-
        if (IS_PRIVATE(inode))
                return 0;
-
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
        if (get_inode_sd_version(inode) == STAT_DATA_V1 ||
-           !reiserfs_posixacl(inode->i_sb)) {
+           !reiserfs_posixacl(inode->i_sb))
                return 0;
-       }
 
-       acl = reiserfs_get_acl(inode, ACL_TYPE_ACCESS);
-       if (!acl)
-               return 0;
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       error = posix_acl_chmod(&acl, GFP_NOFS, inode->i_mode);
-       if (error)
-               return error;
-
-       size = reiserfs_xattr_nblocks(inode, reiserfs_acl_size(acl->a_count));
-       reiserfs_write_lock(inode->i_sb);
-       error = journal_begin(&th, inode->i_sb, size * 2);
-       reiserfs_write_unlock(inode->i_sb);
-       if (!error) {
-               int error2;
-               error = reiserfs_set_acl(&th, inode, ACL_TYPE_ACCESS, acl);
-               reiserfs_write_lock(inode->i_sb);
-               error2 = journal_end(&th, inode->i_sb, size * 2);
-               reiserfs_write_unlock(inode->i_sb);
-               if (error2)
-                       error = error2;
-       }
-       posix_acl_release(acl);
-       return error;
-}
-
-static size_t posix_acl_access_list(struct dentry *dentry, char *list,
-                                   size_t list_size, const char *name,
-                                   size_t name_len, int type)
-{
-       const size_t size = sizeof(POSIX_ACL_XATTR_ACCESS);
-       if (!reiserfs_posixacl(dentry->d_sb))
-               return 0;
-       if (list && size <= list_size)
-               memcpy(list, POSIX_ACL_XATTR_ACCESS, size);
-       return size;
+       return posix_acl_chmod(inode, inode->i_mode);
 }
-
-const struct xattr_handler reiserfs_posix_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags = ACL_TYPE_ACCESS,
-       .get = posix_acl_get,
-       .set = posix_acl_set,
-       .list = posix_acl_access_list,
-};
-
-static size_t posix_acl_default_list(struct dentry *dentry, char *list,
-                                    size_t list_size, const char *name,
-                                    size_t name_len, int type)
-{
-       const size_t size = sizeof(POSIX_ACL_XATTR_DEFAULT);
-       if (!reiserfs_posixacl(dentry->d_sb))
-               return 0;
-       if (list && size <= list_size)
-               memcpy(list, POSIX_ACL_XATTR_DEFAULT, size);
-       return size;
-}
-
-const struct xattr_handler reiserfs_posix_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags = ACL_TYPE_DEFAULT,
-       .get = posix_acl_get,
-       .set = posix_acl_set,
-       .list = posix_acl_default_list,
-};
diff --git a/fs/xattr_acl.c b/fs/xattr_acl.c
deleted file mode 100644 (file)
index 9fbea87..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * linux/fs/xattr_acl.c
- *
- * Almost all from linux/fs/ext2/acl.c:
- * Copyright (C) 2001 by Andreas Gruenbacher, <a.gruenbacher@computer.org>
- */
-
-#include <linux/export.h>
-#include <linux/fs.h>
-#include <linux/posix_acl_xattr.h>
-#include <linux/gfp.h>
-#include <linux/user_namespace.h>
-
-/*
- * Fix up the uids and gids in posix acl extended attributes in place.
- */
-static void posix_acl_fix_xattr_userns(
-       struct user_namespace *to, struct user_namespace *from,
-       void *value, size_t size)
-{
-       posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
-       posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
-       int count;
-       kuid_t uid;
-       kgid_t gid;
-
-       if (!value)
-               return;
-       if (size < sizeof(posix_acl_xattr_header))
-               return;
-       if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
-               return;
-
-       count = posix_acl_xattr_count(size);
-       if (count < 0)
-               return;
-       if (count == 0)
-               return;
-
-       for (end = entry + count; entry != end; entry++) {
-               switch(le16_to_cpu(entry->e_tag)) {
-               case ACL_USER:
-                       uid = make_kuid(from, le32_to_cpu(entry->e_id));
-                       entry->e_id = cpu_to_le32(from_kuid(to, uid));
-                       break;
-               case ACL_GROUP:
-                       gid = make_kgid(from, le32_to_cpu(entry->e_id));
-                       entry->e_id = cpu_to_le32(from_kgid(to, gid));
-                       break;
-               default:
-                       break;
-               }
-       }
-}
-
-void posix_acl_fix_xattr_from_user(void *value, size_t size)
-{
-       struct user_namespace *user_ns = current_user_ns();
-       if (user_ns == &init_user_ns)
-               return;
-       posix_acl_fix_xattr_userns(&init_user_ns, user_ns, value, size);
-}
-
-void posix_acl_fix_xattr_to_user(void *value, size_t size)
-{
-       struct user_namespace *user_ns = current_user_ns();
-       if (user_ns == &init_user_ns)
-               return;
-       posix_acl_fix_xattr_userns(user_ns, &init_user_ns, value, size);
-}
-
-/*
- * Convert from extended attribute to in-memory representation.
- */
-struct posix_acl *
-posix_acl_from_xattr(struct user_namespace *user_ns,
-                    const void *value, size_t size)
-{
-       posix_acl_xattr_header *header = (posix_acl_xattr_header *)value;
-       posix_acl_xattr_entry *entry = (posix_acl_xattr_entry *)(header+1), *end;
-       int count;
-       struct posix_acl *acl;
-       struct posix_acl_entry *acl_e;
-
-       if (!value)
-               return NULL;
-       if (size < sizeof(posix_acl_xattr_header))
-                return ERR_PTR(-EINVAL);
-       if (header->a_version != cpu_to_le32(POSIX_ACL_XATTR_VERSION))
-               return ERR_PTR(-EOPNOTSUPP);
-
-       count = posix_acl_xattr_count(size);
-       if (count < 0)
-               return ERR_PTR(-EINVAL);
-       if (count == 0)
-               return NULL;
-       
-       acl = posix_acl_alloc(count, GFP_NOFS);
-       if (!acl)
-               return ERR_PTR(-ENOMEM);
-       acl_e = acl->a_entries;
-       
-       for (end = entry + count; entry != end; acl_e++, entry++) {
-               acl_e->e_tag  = le16_to_cpu(entry->e_tag);
-               acl_e->e_perm = le16_to_cpu(entry->e_perm);
-
-               switch(acl_e->e_tag) {
-                       case ACL_USER_OBJ:
-                       case ACL_GROUP_OBJ:
-                       case ACL_MASK:
-                       case ACL_OTHER:
-                               break;
-
-                       case ACL_USER:
-                               acl_e->e_uid =
-                                       make_kuid(user_ns,
-                                                 le32_to_cpu(entry->e_id));
-                               if (!uid_valid(acl_e->e_uid))
-                                       goto fail;
-                               break;
-                       case ACL_GROUP:
-                               acl_e->e_gid =
-                                       make_kgid(user_ns,
-                                                 le32_to_cpu(entry->e_id));
-                               if (!gid_valid(acl_e->e_gid))
-                                       goto fail;
-                               break;
-
-                       default:
-                               goto fail;
-               }
-       }
-       return acl;
-
-fail:
-       posix_acl_release(acl);
-       return ERR_PTR(-EINVAL);
-}
-EXPORT_SYMBOL (posix_acl_from_xattr);
-
-/*
- * Convert from in-memory to extended attribute representation.
- */
-int
-posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl,
-                  void *buffer, size_t size)
-{
-       posix_acl_xattr_header *ext_acl = (posix_acl_xattr_header *)buffer;
-       posix_acl_xattr_entry *ext_entry = ext_acl->a_entries;
-       int real_size, n;
-
-       real_size = posix_acl_xattr_size(acl->a_count);
-       if (!buffer)
-               return real_size;
-       if (real_size > size)
-               return -ERANGE;
-       
-       ext_acl->a_version = cpu_to_le32(POSIX_ACL_XATTR_VERSION);
-
-       for (n=0; n < acl->a_count; n++, ext_entry++) {
-               const struct posix_acl_entry *acl_e = &acl->a_entries[n];
-               ext_entry->e_tag  = cpu_to_le16(acl_e->e_tag);
-               ext_entry->e_perm = cpu_to_le16(acl_e->e_perm);
-               switch(acl_e->e_tag) {
-               case ACL_USER:
-                       ext_entry->e_id =
-                               cpu_to_le32(from_kuid(user_ns, acl_e->e_uid));
-                       break;
-               case ACL_GROUP:
-                       ext_entry->e_id =
-                               cpu_to_le32(from_kgid(user_ns, acl_e->e_gid));
-                       break;
-               default:
-                       ext_entry->e_id = cpu_to_le32(ACL_UNDEFINED_ID);
-                       break;
-               }
-       }
-       return real_size;
-}
-EXPORT_SYMBOL (posix_acl_to_xattr);
index 370eb3e121d1b2f292c65ddabd660ad08ae65537..0ecec1896f25439f198c53c93bc058ff3bff9c89 100644 (file)
@@ -124,16 +124,12 @@ struct posix_acl *
 xfs_get_acl(struct inode *inode, int type)
 {
        struct xfs_inode *ip = XFS_I(inode);
-       struct posix_acl *acl;
+       struct posix_acl *acl = NULL;
        struct xfs_acl *xfs_acl;
        unsigned char *ea_name;
        int error;
        int len;
 
-       acl = get_cached_acl(inode, type);
-       if (acl != ACL_NOT_CACHED)
-               return acl;
-
        trace_xfs_get_acl(ip);
 
        switch (type) {
@@ -164,10 +160,8 @@ xfs_get_acl(struct inode *inode, int type)
                 * cache entry, for any other error assume it is transient and
                 * leave the cache entry as ACL_NOT_CACHED.
                 */
-               if (error == -ENOATTR) {
-                       acl = NULL;
+               if (error == -ENOATTR)
                        goto out_update_cache;
-               }
                goto out;
        }
 
@@ -183,15 +177,12 @@ out:
 }
 
 STATIC int
-xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
+__xfs_set_acl(struct inode *inode, int type, struct posix_acl *acl)
 {
        struct xfs_inode *ip = XFS_I(inode);
        unsigned char *ea_name;
        int error;
 
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
        switch (type) {
        case ACL_TYPE_ACCESS:
                ea_name = SGI_ACL_FILE;
@@ -282,131 +273,23 @@ posix_acl_default_exists(struct inode *inode)
        return xfs_acl_exists(inode, SGI_ACL_DEFAULT);
 }
 
-/*
- * No need for i_mutex because the inode is not yet exposed to the VFS.
- */
 int
-xfs_inherit_acl(struct inode *inode, struct posix_acl *acl)
+xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
-       umode_t mode = inode->i_mode;
-       int error = 0, inherit = 0;
-
-       if (S_ISDIR(inode->i_mode)) {
-               error = xfs_set_acl(inode, ACL_TYPE_DEFAULT, acl);
-               if (error)
-                       goto out;
-       }
-
-       error = posix_acl_create(&acl, GFP_KERNEL, &mode);
-       if (error < 0)
-               return error;
-
-       /*
-        * If posix_acl_create returns a positive value we need to
-        * inherit a permission that can't be represented using the Unix
-        * mode bits and we actually need to set an ACL.
-        */
-       if (error > 0)
-               inherit = 1;
-
-       error = xfs_set_mode(inode, mode);
-       if (error)
-               goto out;
-
-       if (inherit)
-               error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl);
-
-out:
-       posix_acl_release(acl);
-       return error;
-}
-
-int
-xfs_acl_chmod(struct inode *inode)
-{
-       struct posix_acl *acl;
-       int error;
-
-       if (S_ISLNK(inode->i_mode))
-               return -EOPNOTSUPP;
-
-       acl = xfs_get_acl(inode, ACL_TYPE_ACCESS);
-       if (IS_ERR(acl) || !acl)
-               return PTR_ERR(acl);
-
-       error = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
-       if (error)
-               return error;
-
-       error = xfs_set_acl(inode, ACL_TYPE_ACCESS, acl);
-       posix_acl_release(acl);
-       return error;
-}
-
-static int
-xfs_xattr_acl_get(struct dentry *dentry, const char *name,
-               void *value, size_t size, int type)
-{
-       struct posix_acl *acl;
-       int error;
-
-       acl = xfs_get_acl(dentry->d_inode, type);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-       if (acl == NULL)
-               return -ENODATA;
-
-       error = posix_acl_to_xattr(&init_user_ns, acl, value, size);
-       posix_acl_release(acl);
-
-       return error;
-}
-
-static int
-xfs_xattr_acl_set(struct dentry *dentry, const char *name,
-               const void *value, size_t size, int flags, int type)
-{
-       struct inode *inode = dentry->d_inode;
-       struct posix_acl *acl = NULL;
        int error = 0;
 
-       if (flags & XATTR_CREATE)
-               return -EINVAL;
-       if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode))
-               return value ? -EACCES : 0;
-       if (!inode_owner_or_capable(inode))
-               return -EPERM;
-
-       if (!value)
+       if (!acl)
                goto set_acl;
 
-       acl = posix_acl_from_xattr(&init_user_ns, value, size);
-       if (!acl) {
-               /*
-                * acl_set_file(3) may request that we set default ACLs with
-                * zero length -- defend (gracefully) against that here.
-                */
-               goto out;
-       }
-       if (IS_ERR(acl)) {
-               error = PTR_ERR(acl);
-               goto out;
-       }
-
-       error = posix_acl_valid(acl);
-       if (error)
-               goto out_release;
-
        error = -EINVAL;
        if (acl->a_count > XFS_ACL_MAX_ENTRIES(XFS_M(inode->i_sb)))
-               goto out_release;
+               return error;
 
        if (type == ACL_TYPE_ACCESS) {
                umode_t mode = inode->i_mode;
                error = posix_acl_equiv_mode(acl, &mode);
 
                if (error <= 0) {
-                       posix_acl_release(acl);
                        acl = NULL;
 
                        if (error < 0)
@@ -415,27 +298,9 @@ xfs_xattr_acl_set(struct dentry *dentry, const char *name,
 
                error = xfs_set_mode(inode, mode);
                if (error)
-                       goto out_release;
+                       return error;
        }
 
  set_acl:
-       error = xfs_set_acl(inode, type, acl);
- out_release:
-       posix_acl_release(acl);
- out:
-       return error;
+       return __xfs_set_acl(inode, type, acl);
 }
-
-const struct xattr_handler xfs_xattr_acl_access_handler = {
-       .prefix = POSIX_ACL_XATTR_ACCESS,
-       .flags  = ACL_TYPE_ACCESS,
-       .get    = xfs_xattr_acl_get,
-       .set    = xfs_xattr_acl_set,
-};
-
-const struct xattr_handler xfs_xattr_acl_default_handler = {
-       .prefix = POSIX_ACL_XATTR_DEFAULT,
-       .flags  = ACL_TYPE_DEFAULT,
-       .get    = xfs_xattr_acl_get,
-       .set    = xfs_xattr_acl_set,
-};
index 4016a567b83cc2e00d46b5f4629bfc83785a7dff..5dc163744511b7c4de1f93e1dd33080d8becd062 100644 (file)
@@ -60,20 +60,15 @@ struct xfs_acl {
 
 #ifdef CONFIG_XFS_POSIX_ACL
 extern struct posix_acl *xfs_get_acl(struct inode *inode, int type);
-extern int xfs_inherit_acl(struct inode *inode, struct posix_acl *default_acl);
-extern int xfs_acl_chmod(struct inode *inode);
+extern int xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
 extern int posix_acl_access_exists(struct inode *inode);
 extern int posix_acl_default_exists(struct inode *inode);
-
-extern const struct xattr_handler xfs_xattr_acl_access_handler;
-extern const struct xattr_handler xfs_xattr_acl_default_handler;
 #else
 static inline struct posix_acl *xfs_get_acl(struct inode *inode, int type)
 {
        return NULL;
 }
-# define xfs_inherit_acl(inode, default_acl)           0
-# define xfs_acl_chmod(inode)                          0
+# define xfs_set_acl                                   NULL
 # define posix_acl_access_exists(inode)                        0
 # define posix_acl_default_exists(inode)               0
 #endif /* CONFIG_XFS_POSIX_ACL */
index a26739451b535cf02a8016c423583f76a26bac72..db2cfb067d0b1ea88f8b64875ceb174d3ae582d2 100644 (file)
@@ -407,7 +407,7 @@ xfs_alloc_ioend_bio(
        struct bio              *bio = bio_alloc(GFP_NOIO, nvecs);
 
        ASSERT(bio->bi_private == NULL);
-       bio->bi_sector = bh->b_blocknr * (bh->b_size >> 9);
+       bio->bi_iter.bi_sector = bh->b_blocknr * (bh->b_size >> 9);
        bio->bi_bdev = bh->b_bdev;
        return bio;
 }
index 9fccfb59429119be16786e1fd2d9b6104546ef93..9c061ef2b0d973c913a1baaee4a43bc27523b244 100644 (file)
@@ -445,8 +445,8 @@ _xfs_buf_find(
        numbytes = BBTOB(numblks);
 
        /* Check for IOs smaller than the sector size / not sector aligned */
-       ASSERT(!(numbytes < (1 << btp->bt_sshift)));
-       ASSERT(!(BBTOB(blkno) & (xfs_off_t)btp->bt_smask));
+       ASSERT(!(numbytes < btp->bt_meta_sectorsize));
+       ASSERT(!(BBTOB(blkno) & (xfs_off_t)btp->bt_meta_sectormask));
 
        /*
         * Corrupted block numbers can get through to here, unfortunately, so we
@@ -1240,7 +1240,7 @@ next_chunk:
 
        bio = bio_alloc(GFP_NOIO, nr_pages);
        bio->bi_bdev = bp->b_target->bt_bdev;
-       bio->bi_sector = sector;
+       bio->bi_iter.bi_sector = sector;
        bio->bi_end_io = xfs_buf_bio_end_io;
        bio->bi_private = bp;
 
@@ -1262,7 +1262,7 @@ next_chunk:
                total_nr_pages--;
        }
 
-       if (likely(bio->bi_size)) {
+       if (likely(bio->bi_iter.bi_size)) {
                if (xfs_buf_is_vmapped(bp)) {
                        flush_kernel_vmap_range(bp->b_addr,
                                                xfs_buf_vmap_len(bp));
@@ -1599,9 +1599,9 @@ xfs_setsize_buftarg(
        unsigned int            blocksize,
        unsigned int            sectorsize)
 {
-       btp->bt_bsize = blocksize;
-       btp->bt_sshift = ffs(sectorsize) - 1;
-       btp->bt_smask = sectorsize - 1;
+       /* Set up metadata sector size info */
+       btp->bt_meta_sectorsize = sectorsize;
+       btp->bt_meta_sectormask = sectorsize - 1;
 
        if (set_blocksize(btp->bt_bdev, sectorsize)) {
                char name[BDEVNAME_SIZE];
@@ -1614,6 +1614,10 @@ xfs_setsize_buftarg(
                return EINVAL;
        }
 
+       /* Set up device logical sector size mask */
+       btp->bt_logical_sectorsize = bdev_logical_block_size(btp->bt_bdev);
+       btp->bt_logical_sectormask = bdev_logical_block_size(btp->bt_bdev) - 1;
+
        return 0;
 }
 
index 1cf21a4a9f221de465299bf820fa710c3b3aa40e..995339534db6a4b65c6ec332055734f7415ca621 100644 (file)
@@ -88,14 +88,28 @@ typedef unsigned int xfs_buf_flags_t;
  */
 #define XFS_BSTATE_DISPOSE      (1 << 0)       /* buffer being discarded */
 
+/*
+ * The xfs_buftarg contains 2 notions of "sector size" -
+ *
+ * 1) The metadata sector size, which is the minimum unit and
+ *    alignment of IO which will be performed by metadata operations.
+ * 2) The device logical sector size
+ *
+ * The first is specified at mkfs time, and is stored on-disk in the
+ * superblock's sb_sectsize.
+ *
+ * The latter is derived from the underlying device, and controls direct IO
+ * alignment constraints.
+ */
 typedef struct xfs_buftarg {
        dev_t                   bt_dev;
        struct block_device     *bt_bdev;
        struct backing_dev_info *bt_bdi;
        struct xfs_mount        *bt_mount;
-       unsigned int            bt_bsize;
-       unsigned int            bt_sshift;
-       size_t                  bt_smask;
+       unsigned int            bt_meta_sectorsize;
+       size_t                  bt_meta_sectormask;
+       size_t                  bt_logical_sectorsize;
+       size_t                  bt_logical_sectormask;
 
        /* LRU control structures */
        struct shrinker         bt_shrinker;
index e001215926326c6a87ce1d5d9887a11aafeb84ca..2e7989e3a2d67374d17e5086ec3b15bfbcb32e2d 100644 (file)
@@ -261,7 +261,8 @@ xfs_file_aio_read(
                xfs_buftarg_t   *target =
                        XFS_IS_REALTIME_INODE(ip) ?
                                mp->m_rtdev_targp : mp->m_ddev_targp;
-               if ((pos & target->bt_smask) || (size & target->bt_smask)) {
+               /* DIO must be aligned to device logical sector size */
+               if ((pos | size) & target->bt_logical_sectormask) {
                        if (pos == i_size_read(inode))
                                return 0;
                        return -XFS_ERROR(EINVAL);
@@ -641,9 +642,11 @@ xfs_file_dio_aio_write(
        struct xfs_buftarg      *target = XFS_IS_REALTIME_INODE(ip) ?
                                        mp->m_rtdev_targp : mp->m_ddev_targp;
 
-       if ((pos & target->bt_smask) || (count & target->bt_smask))
+       /* DIO must be aligned to device logical sector size */
+       if ((pos | count) & target->bt_logical_sectormask)
                return -XFS_ERROR(EINVAL);
 
+       /* "unaligned" here means not aligned to a filesystem block */
        if ((pos & mp->m_blockmask) || ((pos + count) & mp->m_blockmask))
                unaligned_io = 1;
 
index 518aa56b8f2e46d1602bb800c03f5c3d06b9fb38..bcfe61202115510b22509ad49aadc16bcbbb4368 100644 (file)
@@ -1583,7 +1583,7 @@ xfs_file_ioctl(
                        XFS_IS_REALTIME_INODE(ip) ?
                        mp->m_rtdev_targp : mp->m_ddev_targp;
 
-               da.d_mem = da.d_miniosz = 1 << target->bt_sshift;
+               da.d_mem =  da.d_miniosz = target->bt_logical_sectorsize;
                da.d_maxiosz = INT_MAX & ~(da.d_miniosz - 1);
 
                if (copy_to_user(arg, &da, sizeof(da)))
index 0ce1d759156e48ae092d566d30e713d7e597f29c..f35d5c953ff953dcde133c4b55568d1920db3589 100644 (file)
@@ -123,7 +123,7 @@ xfs_vn_mknod(
 {
        struct inode    *inode;
        struct xfs_inode *ip = NULL;
-       struct posix_acl *default_acl = NULL;
+       struct posix_acl *default_acl, *acl;
        struct xfs_name name;
        int             error;
 
@@ -139,14 +139,9 @@ xfs_vn_mknod(
                rdev = 0;
        }
 
-       if (IS_POSIXACL(dir)) {
-               default_acl = xfs_get_acl(dir, ACL_TYPE_DEFAULT);
-               if (IS_ERR(default_acl))
-                       return PTR_ERR(default_acl);
-
-               if (!default_acl)
-                       mode &= ~current_umask();
-       }
+       error = posix_acl_create(dir, &mode, &default_acl, &acl);
+       if (error)
+               return error;
 
        xfs_dentry_to_name(&name, dentry, mode);
        error = xfs_create(XFS_I(dir), &name, mode, rdev, &ip);
@@ -159,22 +154,30 @@ xfs_vn_mknod(
        if (unlikely(error))
                goto out_cleanup_inode;
 
+#ifdef CONFIG_XFS_POSIX_ACL
        if (default_acl) {
-               error = -xfs_inherit_acl(inode, default_acl);
-               default_acl = NULL;
-               if (unlikely(error))
+               error = xfs_set_acl(inode, default_acl, ACL_TYPE_DEFAULT);
+               if (error)
                        goto out_cleanup_inode;
        }
-
+       if (acl) {
+               error = xfs_set_acl(inode, acl, ACL_TYPE_ACCESS);
+               if (error)
+                       goto out_cleanup_inode;
+       }
+#endif
 
        d_instantiate(dentry, inode);
+ out_free_acl:
+       if (default_acl)
+               posix_acl_release(default_acl);
+       if (acl)
+               posix_acl_release(acl);
        return -error;
 
  out_cleanup_inode:
        xfs_cleanup_inode(dir, inode, dentry);
- out_free_acl:
-       posix_acl_release(default_acl);
-       return -error;
+       goto out_free_acl;
 }
 
 STATIC int
@@ -391,18 +394,6 @@ xfs_vn_follow_link(
        return NULL;
 }
 
-STATIC void
-xfs_vn_put_link(
-       struct dentry   *dentry,
-       struct nameidata *nd,
-       void            *p)
-{
-       char            *s = nd_get_link(nd);
-
-       if (!IS_ERR(s))
-               kfree(s);
-}
-
 STATIC int
 xfs_vn_getattr(
        struct vfsmount         *mnt,
@@ -688,7 +679,7 @@ xfs_setattr_nonsize(
         *           Posix ACL code seems to care about this issue either.
         */
        if ((mask & ATTR_MODE) && !(flags & XFS_ATTR_NOACL)) {
-               error = -xfs_acl_chmod(inode);
+               error = -posix_acl_chmod(inode, inode->i_mode);
                if (error)
                        return XFS_ERROR(error);
        }
@@ -1045,6 +1036,7 @@ xfs_vn_fiemap(
 
 static const struct inode_operations xfs_inode_operations = {
        .get_acl                = xfs_get_acl,
+       .set_acl                = xfs_set_acl,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
        .setxattr               = generic_setxattr,
@@ -1072,6 +1064,7 @@ static const struct inode_operations xfs_dir_inode_operations = {
        .mknod                  = xfs_vn_mknod,
        .rename                 = xfs_vn_rename,
        .get_acl                = xfs_get_acl,
+       .set_acl                = xfs_set_acl,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
        .setxattr               = generic_setxattr,
@@ -1098,6 +1091,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
        .mknod                  = xfs_vn_mknod,
        .rename                 = xfs_vn_rename,
        .get_acl                = xfs_get_acl,
+       .set_acl                = xfs_set_acl,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
        .setxattr               = generic_setxattr,
@@ -1110,8 +1104,7 @@ static const struct inode_operations xfs_dir_ci_inode_operations = {
 static const struct inode_operations xfs_symlink_inode_operations = {
        .readlink               = generic_readlink,
        .follow_link            = xfs_vn_follow_link,
-       .put_link               = xfs_vn_put_link,
-       .get_acl                = xfs_get_acl,
+       .put_link               = kfree_put_link,
        .getattr                = xfs_vn_getattr,
        .setattr                = xfs_vn_setattr,
        .setxattr               = generic_setxattr,
index d2c5057b5cc4b4b701d05478e045cbf02a3ed408..1c34e4335920021d5829c5507be2f2c6c6bf60e1 100644 (file)
@@ -30,7 +30,7 @@ extern void xfs_setup_inode(struct xfs_inode *);
 /*
  * Internal setattr interfaces.
  */
-#define XFS_ATTR_NOACL         0x01    /* Don't call xfs_acl_chmod */
+#define XFS_ATTR_NOACL         0x01    /* Don't call posix_acl_chmod */
 
 extern int xfs_setattr_nonsize(struct xfs_inode *ip, struct iattr *vap,
                               int flags);
index 9d479073ba415d6b482fbecbf160b6b99e4e859c..78ed92a46fdd3323c9bada9a35257f839285c630 100644 (file)
@@ -102,8 +102,8 @@ const struct xattr_handler *xfs_xattr_handlers[] = {
        &xfs_xattr_trusted_handler,
        &xfs_xattr_security_handler,
 #ifdef CONFIG_XFS_POSIX_ACL
-       &xfs_xattr_acl_access_handler,
-       &xfs_xattr_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
        NULL
 };
index d2f16f14b419c26ba08b976e4ab8ba5b7a510915..fea6773f87fc7f5fe8e3141579ebd63b4b8efcc8 100644 (file)
@@ -77,7 +77,7 @@ extern u8 acpi_gbl_create_osi_method;
 extern u8 acpi_gbl_disable_auto_repair;
 extern u8 acpi_gbl_disable_ssdt_table_load;
 extern u8 acpi_gbl_do_not_use_xsdt;
-extern bool acpi_gbl_enable_aml_debug_object;
+extern u8 acpi_gbl_enable_aml_debug_object;
 extern u8 acpi_gbl_enable_interpreter_slack;
 extern u32 acpi_gbl_trace_flags;
 extern acpi_name acpi_gbl_trace_method_name;
index db09234589409760b91cb9e696472a3e828476f9..8e4f41d9af4d47279e13a33edd317ce5de32e451 100644 (file)
@@ -558,6 +558,18 @@ static inline pmd_t pmd_read_atomic(pmd_t *pmdp)
 }
 #endif
 
+#ifndef pmd_move_must_withdraw
+static inline int pmd_move_must_withdraw(spinlock_t *new_pmd_ptl,
+                                        spinlock_t *old_pmd_ptl)
+{
+       /*
+        * With split pmd lock we also need to move preallocated
+        * PTE page table if new_pmd is on different PMD page table.
+        */
+       return new_pmd_ptl != old_pmd_ptl;
+}
+#endif
+
 /*
  * This function is meant to be used by sites walking pagetables with
  * the mmap_sem hold in read mode to protect against MADV_DONTNEED and
index 1d4a920ef7ff4ffea56470ef24c2e6cf8a7b0696..04086c5be930e2941f8be91cb0a47107da73ad08 100644 (file)
@@ -56,6 +56,7 @@
 #include <linux/mutex.h>
 #include <linux/io.h>
 #include <linux/slab.h>
+#include <linux/ratelimit.h>
 #if defined(__alpha__) || defined(__powerpc__)
 #include <asm/pgtable.h>       /* For pte_wrprotect */
 #endif
@@ -136,7 +137,6 @@ int drm_err(const char *func, const char *format, ...);
 
 /* driver capabilities and requirements mask */
 #define DRIVER_USE_AGP     0x1
-#define DRIVER_REQUIRE_AGP 0x2
 #define DRIVER_PCI_DMA     0x8
 #define DRIVER_SG          0x10
 #define DRIVER_HAVE_DMA    0x20
@@ -180,6 +180,22 @@ int drm_err(const char *func, const char *format, ...);
 #define DRM_ERROR(fmt, ...)                            \
        drm_err(__func__, fmt, ##__VA_ARGS__)
 
+/**
+ * Rate limited error output.  Like DRM_ERROR() but won't flood the log.
+ *
+ * \param fmt printf() like format string.
+ * \param arg arguments
+ */
+#define DRM_ERROR_RATELIMITED(fmt, ...)                                \
+({                                                                     \
+       static DEFINE_RATELIMIT_STATE(_rs,                              \
+                                     DEFAULT_RATELIMIT_INTERVAL,       \
+                                     DEFAULT_RATELIMIT_BURST);         \
+                                                                       \
+       if (__ratelimit(&_rs))                                          \
+               drm_err(__func__, fmt, ##__VA_ARGS__);                  \
+})
+
 #define DRM_INFO(fmt, ...)                             \
        printk(KERN_INFO "[" DRM_NAME "] " fmt, ##__VA_ARGS__)
 
@@ -422,7 +438,6 @@ struct drm_file {
        struct pid *pid;
        kuid_t uid;
        drm_magic_t magic;
-       unsigned long ioctl_count;
        struct list_head lhead;
        struct drm_minor *minor;
        unsigned long lock_count;
@@ -511,7 +526,7 @@ struct drm_device_dma {
  */
 struct drm_agp_mem {
        unsigned long handle;           /**< handle */
-       DRM_AGP_MEM *memory;
+       struct agp_memory *memory;
        unsigned long bound;            /**< address */
        int pages;
        struct list_head head;
@@ -523,7 +538,7 @@ struct drm_agp_mem {
  * \sa drm_agp_init() and drm_device::agp.
  */
 struct drm_agp_head {
-       DRM_AGP_KERN agp_info;          /**< AGP device information */
+       struct agp_kern_info agp_info;          /**< AGP device information */
        struct list_head memory;
        unsigned long mode;             /**< AGP mode */
        struct agp_bridge_data *bridge;
@@ -606,13 +621,6 @@ struct drm_ati_pcigart_info {
        int table_size;
 };
 
-/**
- * GEM specific mm private for tracking GEM objects
- */
-struct drm_gem_mm {
-       struct drm_vma_offset_manager vma_manager;
-};
-
 /**
  * This structure defines the drm_mm memory object, which will be used by the
  * DRM for its buffer objects.
@@ -750,10 +758,6 @@ struct drm_bus {
        int (*set_unique)(struct drm_device *dev, struct drm_master *master,
                          struct drm_unique *unique);
        int (*irq_by_busid)(struct drm_device *dev, struct drm_irq_busid *p);
-       /* hooks that are for PCI */
-       int (*agp_init)(struct drm_device *dev);
-       void (*agp_destroy)(struct drm_device *dev);
-
 };
 
 /**
@@ -841,6 +845,7 @@ struct drm_driver {
         *
         * \param dev  DRM device.
         * \param crtc Id of the crtc to query.
+        * \param flags Flags from the caller (DRM_CALLED_FROM_VBLIRQ or 0).
         * \param *vpos Target location for current vertical scanout position.
         * \param *hpos Target location for current horizontal scanout position.
         * \param *stime Target location for timestamp taken immediately before
@@ -863,6 +868,7 @@ struct drm_driver {
         *
         */
        int (*get_scanout_position) (struct drm_device *dev, int crtc,
+                                    unsigned int flags,
                                     int *vpos, int *hpos, ktime_t *stime,
                                     ktime_t *etime);
 
@@ -903,7 +909,7 @@ struct drm_driver {
 
        /* these have to be filled in */
 
-       irqreturn_t(*irq_handler) (DRM_IRQ_ARGS);
+       irqreturn_t(*irq_handler) (int irq, void *arg);
        void (*irq_preinstall) (struct drm_device *dev);
        int (*irq_postinstall) (struct drm_device *dev);
        void (*irq_uninstall) (struct drm_device *dev);
@@ -995,8 +1001,8 @@ struct drm_driver {
        } kdriver;
        struct drm_bus *bus;
 
-       /* List of devices hanging off this driver */
-       struct list_head device_list;
+       /* List of devices hanging off this driver with stealth attach. */
+       struct list_head legacy_dev_list;
 };
 
 #define DRM_MINOR_UNASSIGNED 0
@@ -1085,7 +1091,7 @@ struct drm_vblank_crtc {
  * may contain multiple heads.
  */
 struct drm_device {
-       struct list_head driver_item;   /**< list of devices per driver */
+       struct list_head legacy_dev_list;/**< list of devices per driver for stealth attach cleanup */
        char *devname;                  /**< For /proc/interrupts */
        int if_version;                 /**< Highest interface version set */
 
@@ -1098,8 +1104,6 @@ struct drm_device {
        /** \name Usage Counters */
        /*@{ */
        int open_count;                 /**< Outstanding files open */
-       atomic_t ioctl_count;           /**< Outstanding IOCTLs pending */
-       atomic_t vma_count;             /**< Outstanding vma areas open */
        int buf_use;                    /**< Buffers in use -- cannot alloc */
        atomic_t buf_alloc;             /**< Buffer allocation in progress */
        /*@} */
@@ -1176,7 +1180,6 @@ struct drm_device {
        struct drm_sg_mem *sg;  /**< Scatter gather memory */
        unsigned int num_crtcs;                  /**< Number of CRTCs on this device */
        void *dev_private;              /**< device private data */
-       void *mm_private;
        struct address_space *dev_mapping;
        struct drm_sigdata sigdata;        /**< For block_all_signals */
        sigset_t sigmask;
@@ -1194,6 +1197,7 @@ struct drm_device {
        /*@{ */
        struct mutex object_name_lock;
        struct idr object_name_idr;
+       struct drm_vma_offset_manager *vma_offset_manager;
        /*@} */
        int switch_power_state;
 
@@ -1268,6 +1272,7 @@ 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);
@@ -1398,8 +1403,10 @@ extern int drm_calc_vbltimestamp_from_scanoutpos(struct drm_device *dev,
                                                 int crtc, int *max_error,
                                                 struct timeval *vblank_time,
                                                 unsigned flags,
-                                                struct drm_crtc *refcrtc);
-extern void drm_calc_timestamping_constants(struct drm_crtc *crtc);
+                                                const struct drm_crtc *refcrtc,
+                                                const struct drm_display_mode *mode);
+extern void drm_calc_timestamping_constants(struct drm_crtc *crtc,
+                                           const struct drm_display_mode *mode);
 
 extern bool
 drm_mode_parse_command_line_for_connector(const char *mode_option,
@@ -1461,6 +1468,30 @@ extern int drm_debugfs_create_files(const struct drm_info_list *files,
 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);
+#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)
+{
+       return 0;
+}
+
+static inline int drm_debugfs_remove_files(const struct drm_info_list *files,
+                                          int count, struct drm_minor *minor)
+{
+       return 0;
+}
+
+static inline int drm_debugfs_cleanup(struct drm_minor *minor)
+{
+       return 0;
+}
 #endif
 
                                /* Info file support */
@@ -1645,6 +1676,7 @@ static __inline__ int drm_pci_device_is_agp(struct drm_device *dev)
 
        return pci_find_capability(dev->pdev, PCI_CAP_ID_AGP);
 }
+void drm_pci_agp_destroy(struct drm_device *dev);
 
 extern int drm_pci_init(struct drm_driver *driver, struct pci_driver *pdriver);
 extern void drm_pci_exit(struct drm_driver *driver, struct pci_driver *pdriver);
@@ -1660,7 +1692,6 @@ 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 void drm_platform_exit(struct drm_driver *driver, struct platform_device *platform_device);
 
 /* returns true if currently okay to sleep */
 static __inline__ bool drm_can_sleep(void)
index a184eeee9c96bfb4afc4a1bc8b173a0a71fa1225..86a02188074bcec037714fdb1ea293dfb4ae3ebe 100644 (file)
 
 #if __OS_HAS_AGP
 
-void drm_free_agp(DRM_AGP_MEM * handle, int pages);
-int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start);
-int drm_unbind_agp(DRM_AGP_MEM * handle);
-DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev,
+void drm_free_agp(struct agp_memory * handle, int pages);
+int drm_bind_agp(struct agp_memory * handle, unsigned int start);
+int drm_unbind_agp(struct agp_memory * handle);
+struct agp_memory *drm_agp_bind_pages(struct drm_device *dev,
                                struct page **pages,
                                unsigned long num_pages,
                                uint32_t gtt_offset,
                                uint32_t type);
 
 struct drm_agp_head *drm_agp_init(struct drm_device *dev);
-void drm_agp_destroy(struct drm_agp_head *agp);
 void drm_agp_clear(struct drm_device *dev);
 int drm_agp_acquire(struct drm_device *dev);
 int drm_agp_acquire_ioctl(struct drm_device *dev, void *data,
@@ -46,29 +45,23 @@ 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);
-
-static inline int drm_core_has_AGP(struct drm_device *dev)
-{
-       return drm_core_check_feature(dev, DRIVER_USE_AGP);
-}
-
 #else /* __OS_HAS_AGP */
 
-static inline void drm_free_agp(DRM_AGP_MEM * handle, int pages)
+static inline void drm_free_agp(struct agp_memory * handle, int pages)
 {
 }
 
-static inline int drm_bind_agp(DRM_AGP_MEM * handle, unsigned int start)
+static inline int drm_bind_agp(struct agp_memory * handle, unsigned int start)
 {
        return -ENODEV;
 }
 
-static inline int drm_unbind_agp(DRM_AGP_MEM * handle)
+static inline int drm_unbind_agp(struct agp_memory * handle)
 {
        return -ENODEV;
 }
 
-static inline DRM_AGP_MEM *drm_agp_bind_pages(struct drm_device *dev,
+static inline struct agp_memory *drm_agp_bind_pages(struct drm_device *dev,
                                              struct page **pages,
                                              unsigned long num_pages,
                                              uint32_t gtt_offset,
@@ -82,10 +75,6 @@ static inline struct drm_agp_head *drm_agp_init(struct drm_device *dev)
        return NULL;
 }
 
-static inline void drm_agp_destroy(struct drm_agp_head *agp)
-{
-}
-
 static inline void drm_agp_clear(struct drm_device *dev)
 {
 }
@@ -183,12 +172,6 @@ static inline int drm_agp_bind_ioctl(struct drm_device *dev, void *data,
 {
        return -ENODEV;
 }
-
-static inline int drm_core_has_AGP(struct drm_device *dev)
-{
-       return 0;
-}
-
 #endif /* __OS_HAS_AGP */
 
 #endif /* _DRM_AGPSUPPORT_H_ */
index f32c5cd51f4125a455a81ff60cd190c1383d31e1..71727b6210ae57d5b064be1cab19a4dc660df6f8 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/types.h>
 #include <linux/idr.h>
 #include <linux/fb.h>
+#include <linux/hdmi.h>
 #include <drm/drm_mode.h>
 
 #include <drm/drm_fourcc.h>
@@ -181,6 +182,7 @@ struct drm_display_mode {
 
        int vrefresh;           /* in Hz */
        int hsync;              /* in kHz */
+       enum hdmi_picture_aspect picture_aspect_ratio;
 };
 
 static inline bool drm_mode_is_stereo(const struct drm_display_mode *mode)
@@ -447,7 +449,7 @@ struct drm_crtc {
        uint16_t *gamma_store;
 
        /* Constants needed for precise vblank and swap timestamping. */
-       s64 framedur_ns, linedur_ns, pixeldur_ns;
+       int framedur_ns, linedur_ns, pixeldur_ns;
 
        /* if you are using the helper */
        void *helper_private;
@@ -929,6 +931,19 @@ extern int drm_crtc_init(struct drm_device *dev,
                         struct drm_crtc *crtc,
                         const struct drm_crtc_funcs *funcs);
 extern void drm_crtc_cleanup(struct drm_crtc *crtc);
+extern unsigned int drm_crtc_index(struct drm_crtc *crtc);
+
+/**
+ * drm_crtc_mask - find the mask of a registered CRTC
+ * @crtc: CRTC to find mask for
+ *
+ * Given a registered CRTC, return the mask bit of that CRTC for an
+ * encoder's possible_crtcs field.
+ */
+static inline uint32_t drm_crtc_mask(struct drm_crtc *crtc)
+{
+       return 1 << drm_crtc_index(crtc);
+}
 
 extern void drm_connector_ida_init(void);
 extern void drm_connector_ida_destroy(void);
@@ -950,6 +965,19 @@ extern int drm_encoder_init(struct drm_device *dev,
                            const struct drm_encoder_funcs *funcs,
                            int encoder_type);
 
+/**
+ * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
+ * @encoder: encoder to test
+ * @crtc: crtc to test
+ *
+ * Return false if @encoder can't be driven by @crtc, true otherwise.
+ */
+static inline bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
+                                      struct drm_crtc *crtc)
+{
+       return !!(encoder->possible_crtcs & drm_crtc_mask(crtc));
+}
+
 extern int drm_plane_init(struct drm_device *dev,
                          struct drm_plane *plane,
                          unsigned long possible_crtcs,
index ef6ad3a8e58e517f31624767fb1751f7ada463c5..b1388b5fe7acd7d597f6345f273ce26de61d7535 100644 (file)
@@ -120,8 +120,8 @@ struct drm_encoder_helper_funcs {
  */
 struct drm_connector_helper_funcs {
        int (*get_modes)(struct drm_connector *connector);
-       int (*mode_valid)(struct drm_connector *connector,
-                         struct drm_display_mode *mode);
+       enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
+                                          struct drm_display_mode *mode);
        struct drm_encoder *(*best_encoder)(struct drm_connector *connector);
 };
 
index a92c3754e3bbffe56c286d85bd2212f753ebe2c3..1d09050a8c001749ba26087581b93cb2de1f9153 100644 (file)
  * 1.2 formally includes both eDP and DPI definitions.
  */
 
-#define AUX_NATIVE_WRITE       0x8
-#define AUX_NATIVE_READ                0x9
-#define AUX_I2C_WRITE          0x0
-#define AUX_I2C_READ           0x1
-#define AUX_I2C_STATUS         0x2
-#define AUX_I2C_MOT            0x4
-
-#define AUX_NATIVE_REPLY_ACK   (0x0 << 4)
-#define AUX_NATIVE_REPLY_NACK  (0x1 << 4)
-#define AUX_NATIVE_REPLY_DEFER (0x2 << 4)
-#define AUX_NATIVE_REPLY_MASK  (0x3 << 4)
-
-#define AUX_I2C_REPLY_ACK      (0x0 << 6)
-#define AUX_I2C_REPLY_NACK     (0x1 << 6)
-#define AUX_I2C_REPLY_DEFER    (0x2 << 6)
-#define AUX_I2C_REPLY_MASK     (0x3 << 6)
+#define DP_AUX_I2C_WRITE               0x0
+#define DP_AUX_I2C_READ                        0x1
+#define DP_AUX_I2C_STATUS              0x2
+#define DP_AUX_I2C_MOT                 0x4
+#define DP_AUX_NATIVE_WRITE            0x8
+#define DP_AUX_NATIVE_READ             0x9
+
+#define DP_AUX_NATIVE_REPLY_ACK                (0x0 << 0)
+#define DP_AUX_NATIVE_REPLY_NACK       (0x1 << 0)
+#define DP_AUX_NATIVE_REPLY_DEFER      (0x2 << 0)
+#define DP_AUX_NATIVE_REPLY_MASK       (0x3 << 0)
+
+#define DP_AUX_I2C_REPLY_ACK           (0x0 << 2)
+#define DP_AUX_I2C_REPLY_NACK          (0x1 << 2)
+#define DP_AUX_I2C_REPLY_DEFER         (0x2 << 2)
+#define DP_AUX_I2C_REPLY_MASK          (0x3 << 2)
 
 /* AUX CH addresses */
 /* DPCD */
 
 #define DP_TEST_REQUEST                            0x218
 # define DP_TEST_LINK_TRAINING             (1 << 0)
-# define DP_TEST_LINK_PATTERN              (1 << 1)
+# define DP_TEST_LINK_VIDEO_PATTERN        (1 << 1)
 # define DP_TEST_LINK_EDID_READ                    (1 << 2)
 # define DP_TEST_LINK_PHY_TEST_PATTERN     (1 << 3) /* DPCD >= 1.1 */
+# define DP_TEST_LINK_FAUX_PATTERN         (1 << 4) /* DPCD >= 1.2 */
 
 #define DP_TEST_LINK_RATE                  0x219
 # define DP_LINK_RATE_162                  (0x6)
diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h
new file mode 100644 (file)
index 0000000..d32628a
--- /dev/null
@@ -0,0 +1,158 @@
+/*
+ * MIPI DSI Bus
+ *
+ * Copyright (C) 2012-2013, Samsung Electronics, Co., Ltd.
+ * Andrzej Hajda <a.hajda@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __DRM_MIPI_DSI_H__
+#define __DRM_MIPI_DSI_H__
+
+#include <linux/device.h>
+
+struct mipi_dsi_host;
+struct mipi_dsi_device;
+
+/**
+ * struct mipi_dsi_msg - read/write DSI buffer
+ * @channel: virtual channel id
+ * @type: payload data type
+ * @tx_len: length of @tx_buf
+ * @tx_buf: data to be written
+ * @rx_len: length of @rx_buf
+ * @rx_buf: data to be read, or NULL
+ */
+struct mipi_dsi_msg {
+       u8 channel;
+       u8 type;
+
+       size_t tx_len;
+       const void *tx_buf;
+
+       size_t rx_len;
+       void *rx_buf;
+};
+
+/**
+ * struct mipi_dsi_host_ops - DSI bus operations
+ * @attach: attach DSI device to DSI host
+ * @detach: detach DSI device from DSI host
+ * @transfer: send and/or receive DSI packet, return number of received bytes,
+ *           or error
+ */
+struct mipi_dsi_host_ops {
+       int (*attach)(struct mipi_dsi_host *host,
+                     struct mipi_dsi_device *dsi);
+       int (*detach)(struct mipi_dsi_host *host,
+                     struct mipi_dsi_device *dsi);
+       ssize_t (*transfer)(struct mipi_dsi_host *host,
+                           struct mipi_dsi_msg *msg);
+};
+
+/**
+ * struct mipi_dsi_host - DSI host device
+ * @dev: driver model device node for this DSI host
+ * @ops: DSI host operations
+ */
+struct mipi_dsi_host {
+       struct device *dev;
+       const struct mipi_dsi_host_ops *ops;
+};
+
+int mipi_dsi_host_register(struct mipi_dsi_host *host);
+void mipi_dsi_host_unregister(struct mipi_dsi_host *host);
+
+/* DSI mode flags */
+
+/* video mode */
+#define MIPI_DSI_MODE_VIDEO            BIT(0)
+/* video burst mode */
+#define MIPI_DSI_MODE_VIDEO_BURST      BIT(1)
+/* video pulse mode */
+#define MIPI_DSI_MODE_VIDEO_SYNC_PULSE BIT(2)
+/* enable auto vertical count mode */
+#define MIPI_DSI_MODE_VIDEO_AUTO_VERT  BIT(3)
+/* enable hsync-end packets in vsync-pulse and v-porch area */
+#define MIPI_DSI_MODE_VIDEO_HSE                BIT(4)
+/* disable hfront-porch area */
+#define MIPI_DSI_MODE_VIDEO_HFP                BIT(5)
+/* disable hback-porch area */
+#define MIPI_DSI_MODE_VIDEO_HBP                BIT(6)
+/* disable hsync-active area */
+#define MIPI_DSI_MODE_VIDEO_HSA                BIT(7)
+/* flush display FIFO on vsync pulse */
+#define MIPI_DSI_MODE_VSYNC_FLUSH      BIT(8)
+/* disable EoT packets in HS mode */
+#define MIPI_DSI_MODE_EOT_PACKET       BIT(9)
+
+enum mipi_dsi_pixel_format {
+       MIPI_DSI_FMT_RGB888,
+       MIPI_DSI_FMT_RGB666,
+       MIPI_DSI_FMT_RGB666_PACKED,
+       MIPI_DSI_FMT_RGB565,
+};
+
+/**
+ * struct mipi_dsi_device - DSI peripheral device
+ * @host: DSI host for this peripheral
+ * @dev: driver model device node for this peripheral
+ * @channel: virtual channel assigned to the peripheral
+ * @format: pixel format for video mode
+ * @lanes: number of active data lanes
+ * @mode_flags: DSI operation mode related flags
+ */
+struct mipi_dsi_device {
+       struct mipi_dsi_host *host;
+       struct device dev;
+
+       unsigned int channel;
+       unsigned int lanes;
+       enum mipi_dsi_pixel_format format;
+       unsigned long mode_flags;
+};
+
+#define to_mipi_dsi_device(d) container_of(d, struct mipi_dsi_device, dev)
+
+int mipi_dsi_attach(struct mipi_dsi_device *dsi);
+int mipi_dsi_detach(struct mipi_dsi_device *dsi);
+int mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, unsigned int channel,
+                      const void *data, size_t len);
+ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, unsigned int channel,
+                         u8 cmd, void *data, size_t len);
+
+/**
+ * struct mipi_dsi_driver - DSI driver
+ * @driver: device driver model driver
+ * @probe: callback for device binding
+ * @remove: callback for device unbinding
+ */
+struct mipi_dsi_driver {
+       struct device_driver driver;
+       int(*probe)(struct mipi_dsi_device *dsi);
+       int(*remove)(struct mipi_dsi_device *dsi);
+};
+
+#define to_mipi_dsi_driver(d) container_of(d, struct mipi_dsi_driver, driver)
+
+static inline void *mipi_dsi_get_drvdata(const struct mipi_dsi_device *dsi)
+{
+       return dev_get_drvdata(&dsi->dev);
+}
+
+static inline void mipi_dsi_set_drvdata(struct mipi_dsi_device *dsi, void *data)
+{
+       dev_set_drvdata(&dsi->dev, data);
+}
+
+int mipi_dsi_driver_register(struct mipi_dsi_driver *driver);
+void mipi_dsi_driver_unregister(struct mipi_dsi_driver *driver);
+
+#define module_mipi_dsi_driver(__mipi_dsi_driver) \
+       module_driver(__mipi_dsi_driver, mipi_dsi_driver_register, \
+                       mipi_dsi_driver_unregister)
+
+#endif /* __DRM_MIPI_DSI__ */
index 815fafc6b4adb2f0acc7f4474351b6e56d30cef5..86ab99bc0ac50e560b5f31c55fd3f91231607244 100644 (file)
@@ -21,7 +21,6 @@ static inline void writeq(u64 val, void __iomem *reg)
 
 /** Current process ID */
 #define DRM_CURRENTPID                 task_pid_nr(current)
-#define DRM_SUSER(p)                   capable(CAP_SYS_ADMIN)
 #define DRM_UDELAY(d)                  udelay(d)
 /** Read a byte from a MMIO region */
 #define DRM_READ8(map, offset)         readb(((void __iomem *)(map)->handle) + (offset))
@@ -35,45 +34,12 @@ static inline void writeq(u64 val, void __iomem *reg)
 #define DRM_WRITE16(map, offset, val)   writew(val, ((void __iomem *)(map)->handle) + (offset))
 /** Write a dword into a MMIO region */
 #define DRM_WRITE32(map, offset, val)  writel(val, ((void __iomem *)(map)->handle) + (offset))
-/** Read memory barrier */
 
 /** Read a qword from a MMIO region - be careful using these unless you really understand them */
 #define DRM_READ64(map, offset)                readq(((void __iomem *)(map)->handle) + (offset))
 /** Write a qword into a MMIO region */
 #define DRM_WRITE64(map, offset, val)  writeq(val, ((void __iomem *)(map)->handle) + (offset))
 
-#define DRM_READMEMORYBARRIER()                rmb()
-/** Write memory barrier */
-#define DRM_WRITEMEMORYBARRIER()       wmb()
-/** Read/write memory barrier */
-#define DRM_MEMORYBARRIER()            mb()
-
-/** IRQ handler arguments and return type and values */
-#define DRM_IRQ_ARGS           int irq, void *arg
-
-/** AGP types */
-#if __OS_HAS_AGP
-#define DRM_AGP_MEM            struct agp_memory
-#define DRM_AGP_KERN           struct agp_kern_info
-#else
-/* define some dummy types for non AGP supporting kernels */
-struct no_agp_kern {
-       unsigned long aper_base;
-       unsigned long aper_size;
-};
-#define DRM_AGP_MEM             int
-#define DRM_AGP_KERN            struct no_agp_kern
-#endif
-
-/** Other copying of data to kernel space */
-#define DRM_COPY_FROM_USER(arg1, arg2, arg3)           \
-       copy_from_user(arg1, arg2, arg3)
-/** Other copying of data from kernel space */
-#define DRM_COPY_TO_USER(arg1, arg2, arg3)             \
-       copy_to_user(arg1, arg2, arg3)
-
-#define DRM_HZ HZ
-
 #define DRM_WAIT_ON( ret, queue, timeout, condition )          \
 do {                                                           \
        DECLARE_WAITQUEUE(entry, current);                      \
@@ -97,6 +63,3 @@ do {                                                          \
        __set_current_state(TASK_RUNNING);                      \
        remove_wait_queue(&(queue), &entry);                    \
 } while (0)
-
-#define DRM_WAKEUP( queue ) wake_up( queue )
-#define DRM_INIT_WAITQUEUE( queue ) init_waitqueue_head( queue )
diff --git a/include/drm/drm_panel.h b/include/drm/drm_panel.h
new file mode 100644 (file)
index 0000000..c2ab77a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2013, NVIDIA Corporation.  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 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 __DRM_PANEL_H__
+#define __DRM_PANEL_H__
+
+#include <linux/list.h>
+
+struct drm_connector;
+struct drm_device;
+struct drm_panel;
+
+struct drm_panel_funcs {
+       int (*disable)(struct drm_panel *panel);
+       int (*enable)(struct drm_panel *panel);
+       int (*get_modes)(struct drm_panel *panel);
+};
+
+struct drm_panel {
+       struct drm_device *drm;
+       struct drm_connector *connector;
+       struct device *dev;
+
+       const struct drm_panel_funcs *funcs;
+
+       struct list_head list;
+};
+
+static inline int drm_panel_disable(struct drm_panel *panel)
+{
+       if (panel && panel->funcs && panel->funcs->disable)
+               return panel->funcs->disable(panel);
+
+       return panel ? -ENOSYS : -EINVAL;
+}
+
+static inline int drm_panel_enable(struct drm_panel *panel)
+{
+       if (panel && panel->funcs && panel->funcs->enable)
+               return panel->funcs->enable(panel);
+
+       return panel ? -ENOSYS : -EINVAL;
+}
+
+void drm_panel_init(struct drm_panel *panel);
+
+int drm_panel_add(struct drm_panel *panel);
+void drm_panel_remove(struct drm_panel *panel);
+
+int drm_panel_attach(struct drm_panel *panel, struct drm_connector *connector);
+int drm_panel_detach(struct drm_panel *panel);
+
+#ifdef CONFIG_OF
+struct drm_panel *of_drm_find_panel(struct device_node *np);
+#else
+static inline struct drm_panel *of_drm_find_panel(struct device_node *np)
+{
+       return NULL;
+}
+#endif
+
+#endif
index 8639c85d61c400f4694e99ca7e1282df23f5ef66..32d34ebf0706fa8f73e793b035816fd7cfaa36a3 100644 (file)
@@ -681,6 +681,15 @@ extern int ttm_tt_set_placement_caching(struct ttm_tt *ttm, uint32_t placement);
 extern int ttm_tt_swapout(struct ttm_tt *ttm,
                          struct file *persistent_swap_storage);
 
+/**
+ * ttm_tt_unpopulate - free pages from a ttm
+ *
+ * @ttm: Pointer to the ttm_tt structure
+ *
+ * Calls the driver method to free all pages from a ttm
+ */
+extern void ttm_tt_unpopulate(struct ttm_tt *ttm);
+
 /*
  * ttm_bo.c
  */
index 58b029894eb33ea32dff2ba2977546c097f2b533..0097cc03034e18b10e5ad9cdc34b9019eb821314 100644 (file)
@@ -190,13 +190,25 @@ extern int ttm_base_object_init(struct ttm_object_file *tfile,
  * @key: Hash key
  *
  * Looks up a struct ttm_base_object with the key @key.
- * Also verifies that the object is visible to the application, by
- * comparing the @tfile argument and checking the object shareable flag.
  */
 
 extern struct ttm_base_object *ttm_base_object_lookup(struct ttm_object_file
                                                      *tfile, uint32_t key);
 
+/**
+ * ttm_base_object_lookup_for_ref
+ *
+ * @tdev: Pointer to a struct ttm_object_device.
+ * @key: Hash key
+ *
+ * Looks up a struct ttm_base_object with the key @key.
+ * This function should only be used when the struct tfile associated with the
+ * caller doesn't yet have a reference to the base object.
+ */
+
+extern struct ttm_base_object *
+ttm_base_object_lookup_for_ref(struct ttm_object_device *tdev, uint32_t key);
+
 /**
  * ttm_base_object_unref
  *
@@ -218,6 +230,8 @@ extern void ttm_base_object_unref(struct ttm_base_object **p_base);
  * @existed: Upon completion, indicates that an identical reference object
  * already existed, and the refcount was upped on that object instead.
  *
+ * Checks that the base object is shareable and adds a ref object to it.
+ *
  * Adding a ref object to a base object is basically like referencing the
  * base object, but a user-space application holds the reference. When the
  * file corresponding to @tfile is closed, all its reference objects are
diff --git a/include/dt-bindings/clock/mpc512x-clock.h b/include/dt-bindings/clock/mpc512x-clock.h
new file mode 100644 (file)
index 0000000..4f94919
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * This header provides constants for MPC512x clock specs in DT bindings.
+ */
+
+#ifndef _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+#define _DT_BINDINGS_CLOCK_MPC512x_CLOCK_H
+
+#define MPC512x_CLK_DUMMY              0
+#define MPC512x_CLK_REF                        1
+#define MPC512x_CLK_SYS                        2
+#define MPC512x_CLK_DIU                        3
+#define MPC512x_CLK_VIU                        4
+#define MPC512x_CLK_CSB                        5
+#define MPC512x_CLK_E300               6
+#define MPC512x_CLK_IPS                        7
+#define MPC512x_CLK_FEC                        8
+#define MPC512x_CLK_SATA               9
+#define MPC512x_CLK_PATA               10
+#define MPC512x_CLK_NFC                        11
+#define MPC512x_CLK_LPC                        12
+#define MPC512x_CLK_MBX_BUS            13
+#define MPC512x_CLK_MBX                        14
+#define MPC512x_CLK_MBX_3D             15
+#define MPC512x_CLK_AXE                        16
+#define MPC512x_CLK_USB1               17
+#define MPC512x_CLK_USB2               18
+#define MPC512x_CLK_I2C                        19
+#define MPC512x_CLK_MSCAN0_MCLK                20
+#define MPC512x_CLK_MSCAN1_MCLK                21
+#define MPC512x_CLK_MSCAN2_MCLK                22
+#define MPC512x_CLK_MSCAN3_MCLK                23
+#define MPC512x_CLK_BDLC               24
+#define MPC512x_CLK_SDHC               25
+#define MPC512x_CLK_PCI                        26
+#define MPC512x_CLK_PSC_MCLK_IN                27
+#define MPC512x_CLK_SPDIF_TX           28
+#define MPC512x_CLK_SPDIF_RX           29
+#define MPC512x_CLK_SPDIF_MCLK         30
+#define MPC512x_CLK_SPDIF              31
+#define MPC512x_CLK_AC97               32
+#define MPC512x_CLK_PSC0_MCLK          33
+#define MPC512x_CLK_PSC1_MCLK          34
+#define MPC512x_CLK_PSC2_MCLK          35
+#define MPC512x_CLK_PSC3_MCLK          36
+#define MPC512x_CLK_PSC4_MCLK          37
+#define MPC512x_CLK_PSC5_MCLK          38
+#define MPC512x_CLK_PSC6_MCLK          39
+#define MPC512x_CLK_PSC7_MCLK          40
+#define MPC512x_CLK_PSC8_MCLK          41
+#define MPC512x_CLK_PSC9_MCLK          42
+#define MPC512x_CLK_PSC10_MCLK         43
+#define MPC512x_CLK_PSC11_MCLK         44
+#define MPC512x_CLK_PSC_FIFO           45
+#define MPC512x_CLK_PSC0               46
+#define MPC512x_CLK_PSC1               47
+#define MPC512x_CLK_PSC2               48
+#define MPC512x_CLK_PSC3               49
+#define MPC512x_CLK_PSC4               50
+#define MPC512x_CLK_PSC5               51
+#define MPC512x_CLK_PSC6               52
+#define MPC512x_CLK_PSC7               53
+#define MPC512x_CLK_PSC8               54
+#define MPC512x_CLK_PSC9               55
+#define MPC512x_CLK_PSC10              56
+#define MPC512x_CLK_PSC11              57
+#define MPC512x_CLK_SDHC2              58
+#define MPC512x_CLK_FEC2               59
+#define MPC512x_CLK_OUT0_CLK           60
+#define MPC512x_CLK_OUT1_CLK           61
+#define MPC512x_CLK_OUT2_CLK           62
+#define MPC512x_CLK_OUT3_CLK           63
+#define MPC512x_CLK_CAN_CLK_IN         64
+
+#define MPC512x_CLK_LAST_PUBLIC                64
+
+#endif
index 04d318d1187aa072723b615b05087ae5f4c16bb2..032ed87ef0f332afbe94f79ae3b982f060a181ce 100644 (file)
@@ -57,7 +57,7 @@
 #define EXTPCLK_CLK_SRC                                        40
 #define HDMI_CLK_SRC                                   41
 #define VSYNC_CLK_SRC                                  42
-#define RBCPR_CLK_SRC                                  43
+#define MMSS_RBCPR_CLK_SRC                             43
 #define CAMSS_CCI_CCI_AHB_CLK                          44
 #define CAMSS_CCI_CCI_CLK                              45
 #define CAMSS_CSI0_AHB_CLK                             46
index c49e1a159e6e305599093d09a7f4618f0ff19901..63d105cd14a33fc60048c28c9c3b07ef4f4136ef 100644 (file)
@@ -640,6 +640,7 @@ struct bcma_drv_cc {
        spinlock_t gpio_lock;
 #ifdef CONFIG_BCMA_DRIVER_GPIO
        struct gpio_chip gpio;
+       struct irq_domain *irq_domain;
 #endif
 };
 
index 060ff695085c596f2ddcd2166e7825290d75bd3d..70654521dab69fb03443723550e9b9f8c64a6533 100644 (file)
  * various member access, note that bio_data should of course not be used
  * on highmem page vectors
  */
-#define bio_iovec_idx(bio, idx)        (&((bio)->bi_io_vec[(idx)]))
-#define bio_iovec(bio)         bio_iovec_idx((bio), (bio)->bi_idx)
-#define bio_page(bio)          bio_iovec((bio))->bv_page
-#define bio_offset(bio)                bio_iovec((bio))->bv_offset
-#define bio_segments(bio)      ((bio)->bi_vcnt - (bio)->bi_idx)
-#define bio_sectors(bio)       ((bio)->bi_size >> 9)
-#define bio_end_sector(bio)    ((bio)->bi_sector + bio_sectors((bio)))
+#define __bvec_iter_bvec(bvec, iter)   (&(bvec)[(iter).bi_idx])
+
+#define bvec_iter_page(bvec, iter)                             \
+       (__bvec_iter_bvec((bvec), (iter))->bv_page)
+
+#define bvec_iter_len(bvec, iter)                              \
+       min((iter).bi_size,                                     \
+           __bvec_iter_bvec((bvec), (iter))->bv_len - (iter).bi_bvec_done)
+
+#define bvec_iter_offset(bvec, iter)                           \
+       (__bvec_iter_bvec((bvec), (iter))->bv_offset + (iter).bi_bvec_done)
+
+#define bvec_iter_bvec(bvec, iter)                             \
+((struct bio_vec) {                                            \
+       .bv_page        = bvec_iter_page((bvec), (iter)),       \
+       .bv_len         = bvec_iter_len((bvec), (iter)),        \
+       .bv_offset      = bvec_iter_offset((bvec), (iter)),     \
+})
+
+#define bio_iter_iovec(bio, iter)                              \
+       bvec_iter_bvec((bio)->bi_io_vec, (iter))
+
+#define bio_iter_page(bio, iter)                               \
+       bvec_iter_page((bio)->bi_io_vec, (iter))
+#define bio_iter_len(bio, iter)                                        \
+       bvec_iter_len((bio)->bi_io_vec, (iter))
+#define bio_iter_offset(bio, iter)                             \
+       bvec_iter_offset((bio)->bi_io_vec, (iter))
+
+#define bio_page(bio)          bio_iter_page((bio), (bio)->bi_iter)
+#define bio_offset(bio)                bio_iter_offset((bio), (bio)->bi_iter)
+#define bio_iovec(bio)         bio_iter_iovec((bio), (bio)->bi_iter)
+
+#define bio_multiple_segments(bio)                             \
+       ((bio)->bi_iter.bi_size != bio_iovec(bio).bv_len)
+#define bio_sectors(bio)       ((bio)->bi_iter.bi_size >> 9)
+#define bio_end_sector(bio)    ((bio)->bi_iter.bi_sector + bio_sectors((bio)))
+
+/*
+ * Check whether this bio carries any data or not. A NULL bio is allowed.
+ */
+static inline bool bio_has_data(struct bio *bio)
+{
+       if (bio &&
+           bio->bi_iter.bi_size &&
+           !(bio->bi_rw & REQ_DISCARD))
+               return true;
+
+       return false;
+}
+
+static inline bool bio_is_rw(struct bio *bio)
+{
+       if (!bio_has_data(bio))
+               return false;
+
+       if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK)
+               return false;
+
+       return true;
+}
+
+static inline bool bio_mergeable(struct bio *bio)
+{
+       if (bio->bi_rw & REQ_NOMERGE_FLAGS)
+               return false;
+
+       return true;
+}
 
 static inline unsigned int bio_cur_bytes(struct bio *bio)
 {
-       if (bio->bi_vcnt)
-               return bio_iovec(bio)->bv_len;
+       if (bio_has_data(bio))
+               return bio_iovec(bio).bv_len;
        else /* dataless requests such as discard */
-               return bio->bi_size;
+               return bio->bi_iter.bi_size;
 }
 
 static inline void *bio_data(struct bio *bio)
 {
-       if (bio->bi_vcnt)
+       if (bio_has_data(bio))
                return page_address(bio_page(bio)) + bio_offset(bio);
 
        return NULL;
@@ -97,19 +159,16 @@ static inline void *bio_data(struct bio *bio)
  * permanent PIO fall back, user is probably better off disabling highmem
  * I/O completely on that queue (see ide-dma for example)
  */
-#define __bio_kmap_atomic(bio, idx)                            \
-       (kmap_atomic(bio_iovec_idx((bio), (idx))->bv_page) +    \
-               bio_iovec_idx((bio), (idx))->bv_offset)
+#define __bio_kmap_atomic(bio, iter)                           \
+       (kmap_atomic(bio_iter_iovec((bio), (iter)).bv_page) +   \
+               bio_iter_iovec((bio), (iter)).bv_offset)
 
-#define __bio_kunmap_atomic(addr) kunmap_atomic(addr)
+#define __bio_kunmap_atomic(addr)      kunmap_atomic(addr)
 
 /*
  * merge helpers etc
  */
 
-#define __BVEC_END(bio)                bio_iovec_idx((bio), (bio)->bi_vcnt - 1)
-#define __BVEC_START(bio)      bio_iovec_idx((bio), (bio)->bi_idx)
-
 /* Default implementation of BIOVEC_PHYS_MERGEABLE */
 #define __BIOVEC_PHYS_MERGEABLE(vec1, vec2)    \
        ((bvec_to_phys((vec1)) + (vec1)->bv_len) == bvec_to_phys((vec2)))
@@ -126,33 +185,76 @@ static inline void *bio_data(struct bio *bio)
        (((addr1) | (mask)) == (((addr2) - 1) | (mask)))
 #define BIOVEC_SEG_BOUNDARY(q, b1, b2) \
        __BIO_SEG_BOUNDARY(bvec_to_phys((b1)), bvec_to_phys((b2)) + (b2)->bv_len, queue_segment_boundary((q)))
-#define BIO_SEG_BOUNDARY(q, b1, b2) \
-       BIOVEC_SEG_BOUNDARY((q), __BVEC_END((b1)), __BVEC_START((b2)))
 
 #define bio_io_error(bio) bio_endio((bio), -EIO)
 
-/*
- * drivers should not use the __ version unless they _really_ know what
- * they're doing
- */
-#define __bio_for_each_segment(bvl, bio, i, start_idx)                 \
-       for (bvl = bio_iovec_idx((bio), (start_idx)), i = (start_idx);  \
-            i < (bio)->bi_vcnt;                                        \
-            bvl++, i++)
-
 /*
  * drivers should _never_ use the all version - the bio may have been split
  * before it got to the driver and the driver won't own all of it
  */
 #define bio_for_each_segment_all(bvl, bio, i)                          \
-       for (i = 0;                                                     \
-            bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt;       \
-            i++)
+       for (i = 0, bvl = (bio)->bi_io_vec; i < (bio)->bi_vcnt; i++, bvl++)
+
+static inline void bvec_iter_advance(struct bio_vec *bv, struct bvec_iter *iter,
+                                    unsigned bytes)
+{
+       WARN_ONCE(bytes > iter->bi_size,
+                 "Attempted to advance past end of bvec iter\n");
+
+       while (bytes) {
+               unsigned len = min(bytes, bvec_iter_len(bv, *iter));
+
+               bytes -= len;
+               iter->bi_size -= len;
+               iter->bi_bvec_done += len;
+
+               if (iter->bi_bvec_done == __bvec_iter_bvec(bv, *iter)->bv_len) {
+                       iter->bi_bvec_done = 0;
+                       iter->bi_idx++;
+               }
+       }
+}
+
+#define for_each_bvec(bvl, bio_vec, iter, start)                       \
+       for ((iter) = start;                                            \
+            (bvl) = bvec_iter_bvec((bio_vec), (iter)),                 \
+               (iter).bi_size;                                         \
+            bvec_iter_advance((bio_vec), &(iter), (bvl).bv_len))
+
+
+static inline void bio_advance_iter(struct bio *bio, struct bvec_iter *iter,
+                                   unsigned bytes)
+{
+       iter->bi_sector += bytes >> 9;
+
+       if (bio->bi_rw & BIO_NO_ADVANCE_ITER_MASK)
+               iter->bi_size -= bytes;
+       else
+               bvec_iter_advance(bio->bi_io_vec, iter, bytes);
+}
 
-#define bio_for_each_segment(bvl, bio, i)                              \
-       for (i = (bio)->bi_idx;                                         \
-            bvl = bio_iovec_idx((bio), (i)), i < (bio)->bi_vcnt;       \
-            i++)
+#define __bio_for_each_segment(bvl, bio, iter, start)                  \
+       for (iter = (start);                                            \
+            (iter).bi_size &&                                          \
+               ((bvl = bio_iter_iovec((bio), (iter))), 1);             \
+            bio_advance_iter((bio), &(iter), (bvl).bv_len))
+
+#define bio_for_each_segment(bvl, bio, iter)                           \
+       __bio_for_each_segment(bvl, bio, iter, (bio)->bi_iter)
+
+#define bio_iter_last(bvec, iter) ((iter).bi_size == (bvec).bv_len)
+
+static inline unsigned bio_segments(struct bio *bio)
+{
+       unsigned segs = 0;
+       struct bio_vec bv;
+       struct bvec_iter iter;
+
+       bio_for_each_segment(bv, bio, iter)
+               segs++;
+
+       return segs;
+}
 
 /*
  * get a reference to a bio, so it won't disappear. the intended use is
@@ -177,16 +279,15 @@ static inline void *bio_data(struct bio *bio)
 struct bio_integrity_payload {
        struct bio              *bip_bio;       /* parent bio */
 
-       sector_t                bip_sector;     /* virtual start sector */
+       struct bvec_iter        bip_iter;
 
+       /* kill - should just use bip_vec */
        void                    *bip_buf;       /* generated integrity data */
-       bio_end_io_t            *bip_end_io;    /* saved I/O completion fn */
 
-       unsigned int            bip_size;
+       bio_end_io_t            *bip_end_io;    /* saved I/O completion fn */
 
        unsigned short          bip_slab;       /* slab the bip came from */
        unsigned short          bip_vcnt;       /* # of integrity bio_vecs */
-       unsigned short          bip_idx;        /* current bip_vec index */
        unsigned                bip_owns_buf:1; /* should free bip_buf */
 
        struct work_struct      bip_work;       /* I/O completion */
@@ -196,29 +297,28 @@ struct bio_integrity_payload {
 };
 #endif /* CONFIG_BLK_DEV_INTEGRITY */
 
-/*
- * A bio_pair is used when we need to split a bio.
- * This can only happen for a bio that refers to just one
- * page of data, and in the unusual situation when the
- * page crosses a chunk/device boundary
+extern void bio_trim(struct bio *bio, int offset, int size);
+extern struct bio *bio_split(struct bio *bio, int sectors,
+                            gfp_t gfp, struct bio_set *bs);
+
+/**
+ * bio_next_split - get next @sectors from a bio, splitting if necessary
+ * @bio:       bio to split
+ * @sectors:   number of sectors to split from the front of @bio
+ * @gfp:       gfp mask
+ * @bs:                bio set to allocate from
  *
- * The address of the master bio is stored in bio1.bi_private
- * The address of the pool the pair was allocated from is stored
- *   in bio2.bi_private
+ * Returns a bio representing the next @sectors of @bio - if the bio is smaller
+ * than @sectors, returns the original bio unchanged.
  */
-struct bio_pair {
-       struct bio                      bio1, bio2;
-       struct bio_vec                  bv1, bv2;
-#if defined(CONFIG_BLK_DEV_INTEGRITY)
-       struct bio_integrity_payload    bip1, bip2;
-       struct bio_vec                  iv1, iv2;
-#endif
-       atomic_t                        cnt;
-       int                             error;
-};
-extern struct bio_pair *bio_split(struct bio *bi, int first_sectors);
-extern void bio_pair_release(struct bio_pair *dbio);
-extern void bio_trim(struct bio *bio, int offset, int size);
+static inline struct bio *bio_next_split(struct bio *bio, int sectors,
+                                        gfp_t gfp, struct bio_set *bs)
+{
+       if (sectors >= bio_sectors(bio))
+               return bio;
+
+       return bio_split(bio, sectors, gfp, bs);
+}
 
 extern struct bio_set *bioset_create(unsigned int, unsigned int);
 extern void bioset_free(struct bio_set *);
@@ -227,7 +327,8 @@ extern mempool_t *biovec_create_pool(struct bio_set *bs, int pool_entries);
 extern struct bio *bio_alloc_bioset(gfp_t, int, struct bio_set *);
 extern void bio_put(struct bio *);
 
-extern void __bio_clone(struct bio *, struct bio *);
+extern void __bio_clone_fast(struct bio *, struct bio *);
+extern struct bio *bio_clone_fast(struct bio *, gfp_t, struct bio_set *);
 extern struct bio *bio_clone_bioset(struct bio *, gfp_t, struct bio_set *bs);
 
 extern struct bio_set *fs_bio_set;
@@ -254,6 +355,7 @@ static inline struct bio *bio_clone_kmalloc(struct bio *bio, gfp_t gfp_mask)
 }
 
 extern void bio_endio(struct bio *, int);
+extern void bio_endio_nodec(struct bio *, int);
 struct request_queue;
 extern int bio_phys_segments(struct request_queue *, struct bio *);
 
@@ -262,12 +364,12 @@ extern void bio_advance(struct bio *, unsigned);
 
 extern void bio_init(struct bio *);
 extern void bio_reset(struct bio *);
+void bio_chain(struct bio *, struct bio *);
 
 extern int bio_add_page(struct bio *, struct page *, unsigned int,unsigned int);
 extern int bio_add_pc_page(struct request_queue *, struct bio *, struct page *,
                           unsigned int, unsigned int);
 extern int bio_get_nr_vecs(struct block_device *);
-extern sector_t bio_sector_offset(struct bio *, unsigned short, unsigned int);
 extern struct bio *bio_map_user(struct request_queue *, struct block_device *,
                                unsigned long, unsigned int, int, gfp_t);
 struct sg_iovec;
@@ -357,47 +459,17 @@ static inline void bvec_kunmap_irq(char *buffer, unsigned long *flags)
 }
 #endif
 
-static inline char *__bio_kmap_irq(struct bio *bio, unsigned short idx,
+static inline char *__bio_kmap_irq(struct bio *bio, struct bvec_iter iter,
                                   unsigned long *flags)
 {
-       return bvec_kmap_irq(bio_iovec_idx(bio, idx), flags);
+       return bvec_kmap_irq(&bio_iter_iovec(bio, iter), flags);
 }
 #define __bio_kunmap_irq(buf, flags)   bvec_kunmap_irq(buf, flags)
 
 #define bio_kmap_irq(bio, flags) \
-       __bio_kmap_irq((bio), (bio)->bi_idx, (flags))
+       __bio_kmap_irq((bio), (bio)->bi_iter, (flags))
 #define bio_kunmap_irq(buf,flags)      __bio_kunmap_irq(buf, flags)
 
-/*
- * Check whether this bio carries any data or not. A NULL bio is allowed.
- */
-static inline bool bio_has_data(struct bio *bio)
-{
-       if (bio && bio->bi_vcnt)
-               return true;
-
-       return false;
-}
-
-static inline bool bio_is_rw(struct bio *bio)
-{
-       if (!bio_has_data(bio))
-               return false;
-
-       if (bio->bi_rw & REQ_WRITE_SAME)
-               return false;
-
-       return true;
-}
-
-static inline bool bio_mergeable(struct bio *bio)
-{
-       if (bio->bi_rw & REQ_NOMERGE_FLAGS)
-               return false;
-
-       return true;
-}
-
 /*
  * BIO list management for use by remapping drivers (e.g. DM or MD) and loop.
  *
@@ -559,16 +631,12 @@ struct biovec_slab {
 
 #if defined(CONFIG_BLK_DEV_INTEGRITY)
 
-#define bip_vec_idx(bip, idx)  (&(bip->bip_vec[(idx)]))
-#define bip_vec(bip)           bip_vec_idx(bip, 0)
 
-#define __bip_for_each_vec(bvl, bip, i, start_idx)                     \
-       for (bvl = bip_vec_idx((bip), (start_idx)), i = (start_idx);    \
-            i < (bip)->bip_vcnt;                                       \
-            bvl++, i++)
 
-#define bip_for_each_vec(bvl, bip, i)                                  \
-       __bip_for_each_vec(bvl, bip, i, (bip)->bip_idx)
+#define bip_vec_idx(bip, idx)  (&(bip->bip_vec[(idx)]))
+
+#define bip_for_each_vec(bvl, bip, iter)                               \
+       for_each_bvec(bvl, (bip)->bip_vec, iter, (bip)->bip_iter)
 
 #define bio_for_each_integrity_vec(_bvl, _bio, _iter)                  \
        for_each_bio(_bio)                                              \
@@ -586,7 +654,6 @@ extern int bio_integrity_prep(struct bio *);
 extern void bio_integrity_endio(struct bio *, int);
 extern void bio_integrity_advance(struct bio *, unsigned int);
 extern void bio_integrity_trim(struct bio *, unsigned int, unsigned int);
-extern void bio_integrity_split(struct bio *, struct bio_pair *, int);
 extern int bio_integrity_clone(struct bio *, struct bio *, gfp_t);
 extern int bioset_integrity_create(struct bio_set *, int);
 extern void bioset_integrity_free(struct bio_set *);
@@ -630,12 +697,6 @@ static inline int bio_integrity_clone(struct bio *bio, struct bio *bio_src,
        return 0;
 }
 
-static inline void bio_integrity_split(struct bio *bio, struct bio_pair *bp,
-                                      int sectors)
-{
-       return;
-}
-
 static inline void bio_integrity_advance(struct bio *bio,
                                         unsigned int bytes_done)
 {
index ab0e9b2025b36d401443f213a646fb68fe392605..161b23105b1ec9d90f3520f08fb66d0d9be66358 100644 (file)
@@ -113,7 +113,6 @@ enum {
 };
 
 struct request_queue *blk_mq_init_queue(struct blk_mq_reg *, void *);
-void blk_mq_free_queue(struct request_queue *);
 int blk_mq_register_disk(struct gendisk *);
 void blk_mq_unregister_disk(struct gendisk *);
 void blk_mq_init_commands(struct request_queue *, void (*init)(void *data, struct blk_mq_hw_ctx *, struct request *, unsigned int), void *data);
@@ -159,16 +158,16 @@ static inline struct request *blk_mq_tag_to_rq(struct blk_mq_hw_ctx *hctx,
 }
 
 #define queue_for_each_hw_ctx(q, hctx, i)                              \
-       for ((i) = 0, hctx = (q)->queue_hw_ctx[0];                      \
-            (i) < (q)->nr_hw_queues; (i)++, hctx = (q)->queue_hw_ctx[i])
+       for ((i) = 0; (i) < (q)->nr_hw_queues &&                        \
+            ({ hctx = (q)->queue_hw_ctx[i]; 1; }); (i)++)
 
 #define queue_for_each_ctx(q, ctx, i)                                  \
-       for ((i) = 0, ctx = per_cpu_ptr((q)->queue_ctx, 0);             \
-            (i) < (q)->nr_queues; (i)++, ctx = per_cpu_ptr(q->queue_ctx, (i)))
+       for ((i) = 0; (i) < (q)->nr_queues &&                           \
+            ({ ctx = per_cpu_ptr((q)->queue_ctx, (i)); 1; }); (i)++)
 
 #define hctx_for_each_ctx(hctx, ctx, i)                                        \
-       for ((i) = 0, ctx = (hctx)->ctxs[0];                            \
-            (i) < (hctx)->nr_ctx; (i)++, ctx = (hctx)->ctxs[(i)])
+       for ((i) = 0; (i) < (hctx)->nr_ctx &&                           \
+            ({ ctx = (hctx)->ctxs[(i)]; 1; }); (i)++)
 
 #define blk_ctx_sum(q, sum)                                            \
 ({                                                                     \
index 238ef0ed62f85f18085b6446bc681d8c18d674dc..bbc3a6c88fce3410b954b6c91c407297e2f03e7f 100644 (file)
@@ -28,13 +28,22 @@ struct bio_vec {
        unsigned int    bv_offset;
 };
 
+struct bvec_iter {
+       sector_t                bi_sector;      /* device address in 512 byte
+                                                  sectors */
+       unsigned int            bi_size;        /* residual I/O count */
+
+       unsigned int            bi_idx;         /* current index into bvl_vec */
+
+       unsigned int            bi_bvec_done;   /* number of bytes completed in
+                                                  current bvec */
+};
+
 /*
  * main unit of I/O for the block layer and lower layers (ie drivers and
  * stacking drivers)
  */
 struct bio {
-       sector_t                bi_sector;      /* device address in 512 byte
-                                                  sectors */
        struct bio              *bi_next;       /* request queue link */
        struct block_device     *bi_bdev;
        unsigned long           bi_flags;       /* status, command, etc */
@@ -42,16 +51,13 @@ struct bio {
                                                 * top bits priority
                                                 */
 
-       unsigned short          bi_vcnt;        /* how many bio_vec's */
-       unsigned short          bi_idx;         /* current index into bvl_vec */
+       struct bvec_iter        bi_iter;
 
        /* Number of segments in this BIO after
         * physical address coalescing is performed.
         */
        unsigned int            bi_phys_segments;
 
-       unsigned int            bi_size;        /* residual I/O count */
-
        /*
         * To keep track of the max segment size, we account for the
         * sizes of the first and last mergeable segments in this bio.
@@ -59,6 +65,8 @@ struct bio {
        unsigned int            bi_seg_front_size;
        unsigned int            bi_seg_back_size;
 
+       atomic_t                bi_remaining;
+
        bio_end_io_t            *bi_end_io;
 
        void                    *bi_private;
@@ -74,11 +82,13 @@ struct bio {
        struct bio_integrity_payload *bi_integrity;  /* data integrity */
 #endif
 
+       unsigned short          bi_vcnt;        /* how many bio_vec's */
+
        /*
         * Everything starting with bi_max_vecs will be preserved by bio_reset()
         */
 
-       unsigned int            bi_max_vecs;    /* max bvl_vecs we can hold */
+       unsigned short          bi_max_vecs;    /* max bvl_vecs we can hold */
 
        atomic_t                bi_cnt;         /* pin count */
 
index 1b135d49b27985d3243cdbf92d6002ce5eea8597..8678c4322b4462357266397c5455bc9c6be04fd6 100644 (file)
@@ -95,10 +95,7 @@ enum rq_cmd_type_bits {
  * as well!
  */
 struct request {
-       union {
-               struct list_head queuelist;
-               struct llist_node ll_list;
-       };
+       struct list_head queuelist;
        union {
                struct call_single_data csd;
                struct work_struct mq_flush_data;
@@ -291,6 +288,7 @@ struct queue_limits {
        unsigned char           discard_misaligned;
        unsigned char           cluster;
        unsigned char           discard_zeroes_data;
+       unsigned char           raid_partial_stripes_expensive;
 };
 
 struct request_queue {
@@ -735,7 +733,7 @@ struct rq_map_data {
 };
 
 struct req_iterator {
-       int i;
+       struct bvec_iter iter;
        struct bio *bio;
 };
 
@@ -748,10 +746,11 @@ struct req_iterator {
 
 #define rq_for_each_segment(bvl, _rq, _iter)                   \
        __rq_for_each_bio(_iter.bio, _rq)                       \
-               bio_for_each_segment(bvl, _iter.bio, _iter.i)
+               bio_for_each_segment(bvl, _iter.bio, _iter.iter)
 
-#define rq_iter_last(rq, _iter)                                        \
-               (_iter.bio->bi_next == NULL && _iter.i == _iter.bio->bi_vcnt-1)
+#define rq_iter_last(bvec, _iter)                              \
+               (_iter.bio->bi_next == NULL &&                  \
+                bio_iter_last(bvec, _iter.iter))
 
 #ifndef ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE
 # error        "You should define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE for your platform"
index 2fae55def608b0cc82fba2ac07f2f3c14941d9f6..db51fe4fe3172973a26a9fe739f271ca253bfdc3 100644 (file)
@@ -175,6 +175,27 @@ static inline void * __init memblock_virt_alloc_nopanic(
                                                    NUMA_NO_NODE);
 }
 
+#ifndef ARCH_LOW_ADDRESS_LIMIT
+#define ARCH_LOW_ADDRESS_LIMIT  0xffffffffUL
+#endif
+
+static inline void * __init memblock_virt_alloc_low(
+                                       phys_addr_t size, phys_addr_t align)
+{
+       return memblock_virt_alloc_try_nid(size, align,
+                                                  BOOTMEM_LOW_LIMIT,
+                                                  ARCH_LOW_ADDRESS_LIMIT,
+                                                  NUMA_NO_NODE);
+}
+static inline void * __init memblock_virt_alloc_low_nopanic(
+                                       phys_addr_t size, phys_addr_t align)
+{
+       return memblock_virt_alloc_try_nid_nopanic(size, align,
+                                                  BOOTMEM_LOW_LIMIT,
+                                                  ARCH_LOW_ADDRESS_LIMIT,
+                                                  NUMA_NO_NODE);
+}
+
 static inline void * __init memblock_virt_alloc_from_nopanic(
                phys_addr_t size, phys_addr_t align, phys_addr_t min_addr)
 {
@@ -238,6 +259,22 @@ static inline void * __init memblock_virt_alloc_nopanic(
        return __alloc_bootmem_nopanic(size, align, BOOTMEM_LOW_LIMIT);
 }
 
+static inline void * __init memblock_virt_alloc_low(
+                                       phys_addr_t size, phys_addr_t align)
+{
+       if (!align)
+               align = SMP_CACHE_BYTES;
+       return __alloc_bootmem_low(size, align, 0);
+}
+
+static inline void * __init memblock_virt_alloc_low_nopanic(
+                                       phys_addr_t size, phys_addr_t align)
+{
+       if (!align)
+               align = SMP_CACHE_BYTES;
+       return __alloc_bootmem_low_nopanic(size, align, 0);
+}
+
 static inline void * __init memblock_virt_alloc_from_nopanic(
                phys_addr_t size, phys_addr_t align, phys_addr_t min_addr)
 {
index 58d19014068f29e9feda88f5aecf48cace545211..07ad423cc37fbe4e61febe918d5aed38fdcdf2b7 100644 (file)
@@ -17,7 +17,6 @@ struct ceph_buffer {
        struct kref kref;
        struct kvec vec;
        size_t alloc_len;
-       bool is_vmalloc;
 };
 
 extern struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp);
index 4c42080347aff5d843763dfaedc51c98fe21dfea..138448f766b44fdf2939ac0eff1cad12c205240c 100644 (file)
@@ -4,42 +4,73 @@
 /*
  * feature bits
  */
-#define CEPH_FEATURE_UID            (1<<0)
-#define CEPH_FEATURE_NOSRCADDR      (1<<1)
-#define CEPH_FEATURE_MONCLOCKCHECK  (1<<2)
-#define CEPH_FEATURE_FLOCK          (1<<3)
-#define CEPH_FEATURE_SUBSCRIBE2     (1<<4)
-#define CEPH_FEATURE_MONNAMES       (1<<5)
-#define CEPH_FEATURE_RECONNECT_SEQ  (1<<6)
-#define CEPH_FEATURE_DIRLAYOUTHASH  (1<<7)
-#define CEPH_FEATURE_OBJECTLOCATOR  (1<<8)
-#define CEPH_FEATURE_PGID64         (1<<9)
-#define CEPH_FEATURE_INCSUBOSDMAP   (1<<10)
-#define CEPH_FEATURE_PGPOOL3        (1<<11)
-#define CEPH_FEATURE_OSDREPLYMUX    (1<<12)
-#define CEPH_FEATURE_OSDENC         (1<<13)
-#define CEPH_FEATURE_OMAP           (1<<14)
-#define CEPH_FEATURE_MONENC         (1<<15)
-#define CEPH_FEATURE_QUERY_T        (1<<16)
-#define CEPH_FEATURE_INDEP_PG_MAP   (1<<17)
-#define CEPH_FEATURE_CRUSH_TUNABLES (1<<18)
-#define CEPH_FEATURE_CHUNKY_SCRUB   (1<<19)
-#define CEPH_FEATURE_MON_NULLROUTE  (1<<20)
-#define CEPH_FEATURE_MON_GV         (1<<21)
-#define CEPH_FEATURE_BACKFILL_RESERVATION (1<<22)
-#define CEPH_FEATURE_MSG_AUTH      (1<<23)
-#define CEPH_FEATURE_RECOVERY_RESERVATION (1<<24)
-#define CEPH_FEATURE_CRUSH_TUNABLES2 (1<<25)
-#define CEPH_FEATURE_CREATEPOOLID   (1<<26)
-#define CEPH_FEATURE_REPLY_CREATE_INODE   (1<<27)
-#define CEPH_FEATURE_OSD_HBMSGS     (1<<28)
-#define CEPH_FEATURE_MDSENC         (1<<29)
-#define CEPH_FEATURE_OSDHASHPSPOOL  (1<<30)
+#define CEPH_FEATURE_UID            (1ULL<<0)
+#define CEPH_FEATURE_NOSRCADDR      (1ULL<<1)
+#define CEPH_FEATURE_MONCLOCKCHECK  (1ULL<<2)
+#define CEPH_FEATURE_FLOCK          (1ULL<<3)
+#define CEPH_FEATURE_SUBSCRIBE2     (1ULL<<4)
+#define CEPH_FEATURE_MONNAMES       (1ULL<<5)
+#define CEPH_FEATURE_RECONNECT_SEQ  (1ULL<<6)
+#define CEPH_FEATURE_DIRLAYOUTHASH  (1ULL<<7)
+#define CEPH_FEATURE_OBJECTLOCATOR  (1ULL<<8)
+#define CEPH_FEATURE_PGID64         (1ULL<<9)
+#define CEPH_FEATURE_INCSUBOSDMAP   (1ULL<<10)
+#define CEPH_FEATURE_PGPOOL3        (1ULL<<11)
+#define CEPH_FEATURE_OSDREPLYMUX    (1ULL<<12)
+#define CEPH_FEATURE_OSDENC         (1ULL<<13)
+#define CEPH_FEATURE_OMAP           (1ULL<<14)
+#define CEPH_FEATURE_MONENC         (1ULL<<15)
+#define CEPH_FEATURE_QUERY_T        (1ULL<<16)
+#define CEPH_FEATURE_INDEP_PG_MAP   (1ULL<<17)
+#define CEPH_FEATURE_CRUSH_TUNABLES (1ULL<<18)
+#define CEPH_FEATURE_CHUNKY_SCRUB   (1ULL<<19)
+#define CEPH_FEATURE_MON_NULLROUTE  (1ULL<<20)
+#define CEPH_FEATURE_MON_GV         (1ULL<<21)
+#define CEPH_FEATURE_BACKFILL_RESERVATION (1ULL<<22)
+#define CEPH_FEATURE_MSG_AUTH      (1ULL<<23)
+#define CEPH_FEATURE_RECOVERY_RESERVATION (1ULL<<24)
+#define CEPH_FEATURE_CRUSH_TUNABLES2 (1ULL<<25)
+#define CEPH_FEATURE_CREATEPOOLID   (1ULL<<26)
+#define CEPH_FEATURE_REPLY_CREATE_INODE   (1ULL<<27)
+#define CEPH_FEATURE_OSD_HBMSGS     (1ULL<<28)
+#define CEPH_FEATURE_MDSENC         (1ULL<<29)
+#define CEPH_FEATURE_OSDHASHPSPOOL  (1ULL<<30)
+#define CEPH_FEATURE_MON_SINGLE_PAXOS (1ULL<<31)
+#define CEPH_FEATURE_OSD_SNAPMAPPER (1ULL<<32)
+#define CEPH_FEATURE_MON_SCRUB      (1ULL<<33)
+#define CEPH_FEATURE_OSD_PACKED_RECOVERY (1ULL<<34)
+#define CEPH_FEATURE_OSD_CACHEPOOL (1ULL<<35)
+#define CEPH_FEATURE_CRUSH_V2      (1ULL<<36)  /* new indep; SET_* steps */
+#define CEPH_FEATURE_EXPORT_PEER   (1ULL<<37)
+#define CEPH_FEATURE_OSD_ERASURE_CODES (1ULL<<38)
+
+/*
+ * The introduction of CEPH_FEATURE_OSD_SNAPMAPPER caused the feature
+ * vector to evaluate to 64 bit ~0.  To cope, we designate 1ULL << 63
+ * to mean 33 bit ~0, and introduce a helper below to do the
+ * translation.
+ *
+ * This was introduced by ceph.git commit
+ *   9ea02b84104045c2ffd7e7f4e7af512953855ecd v0.58-657-g9ea02b8
+ * and fixed by ceph.git commit
+ *   4255b5c2fb54ae40c53284b3ab700fdfc7e61748 v0.65-263-g4255b5c
+ */
+#define CEPH_FEATURE_RESERVED (1ULL<<63)
+
+static inline u64 ceph_sanitize_features(u64 features)
+{
+       if (features & CEPH_FEATURE_RESERVED) {
+               /* everything through OSD_SNAPMAPPER */
+               return 0x1ffffffffull;
+       } else {
+               return features;
+       }
+}
 
 /*
  * Features supported.
  */
-#define CEPH_FEATURES_SUPPORTED_DEFAULT  \
+#define CEPH_FEATURES_SUPPORTED_DEFAULT                \
        (CEPH_FEATURE_NOSRCADDR |               \
         CEPH_FEATURE_RECONNECT_SEQ |           \
         CEPH_FEATURE_PGID64 |                  \
         CEPH_FEATURE_CRUSH_TUNABLES |          \
         CEPH_FEATURE_CRUSH_TUNABLES2 |         \
         CEPH_FEATURE_REPLY_CREATE_INODE |      \
-        CEPH_FEATURE_OSDHASHPSPOOL)
+        CEPH_FEATURE_OSDHASHPSPOOL |           \
+        CEPH_FEATURE_OSD_CACHEPOOL |           \
+        CEPH_FEATURE_CRUSH_V2 |                \
+        CEPH_FEATURE_EXPORT_PEER)
 
 #define CEPH_FEATURES_REQUIRED_DEFAULT   \
        (CEPH_FEATURE_NOSRCADDR |        \
@@ -56,4 +90,5 @@
         CEPH_FEATURE_PGID64 |           \
         CEPH_FEATURE_PGPOOL3 |          \
         CEPH_FEATURE_OSDENC)
+
 #endif
index 2ad7b860f06232d76ae5a4f208d081a17825a9ae..2623cffc73a17b32cf9660bf67cf05bd9ae4b45f 100644 (file)
@@ -53,6 +53,29 @@ struct ceph_file_layout {
        __le32 fl_pg_pool;      /* namespace, crush ruleset, rep level */
 } __attribute__ ((packed));
 
+#define ceph_file_layout_su(l) ((__s32)le32_to_cpu((l).fl_stripe_unit))
+#define ceph_file_layout_stripe_count(l) \
+       ((__s32)le32_to_cpu((l).fl_stripe_count))
+#define ceph_file_layout_object_size(l) ((__s32)le32_to_cpu((l).fl_object_size))
+#define ceph_file_layout_cas_hash(l) ((__s32)le32_to_cpu((l).fl_cas_hash))
+#define ceph_file_layout_object_su(l) \
+       ((__s32)le32_to_cpu((l).fl_object_stripe_unit))
+#define ceph_file_layout_pg_pool(l) \
+       ((__s32)le32_to_cpu((l).fl_pg_pool))
+
+static inline unsigned ceph_file_layout_stripe_width(struct ceph_file_layout *l)
+{
+       return le32_to_cpu(l->fl_stripe_unit) *
+               le32_to_cpu(l->fl_stripe_count);
+}
+
+/* "period" == bytes before i start on a new set of objects */
+static inline unsigned ceph_file_layout_period(struct ceph_file_layout *l)
+{
+       return le32_to_cpu(l->fl_object_size) *
+               le32_to_cpu(l->fl_stripe_count);
+}
+
 #define CEPH_MIN_STRIPE_UNIT 65536
 
 int ceph_file_layout_is_valid(const struct ceph_file_layout *layout);
@@ -282,6 +305,8 @@ enum {
        CEPH_SESSION_RENEWCAPS,
        CEPH_SESSION_STALE,
        CEPH_SESSION_RECALL_STATE,
+       CEPH_SESSION_FLUSHMSG,
+       CEPH_SESSION_FLUSHMSG_ACK,
 };
 
 extern const char *ceph_session_op_name(int op);
@@ -457,7 +482,8 @@ struct ceph_mds_reply_cap {
        __u8 flags;                    /* CEPH_CAP_FLAG_* */
 } __attribute__ ((packed));
 
-#define CEPH_CAP_FLAG_AUTH  1          /* cap is issued by auth mds */
+#define CEPH_CAP_FLAG_AUTH     (1 << 0)  /* cap is issued by auth mds */
+#define CEPH_CAP_FLAG_RELEASE  (1 << 1)  /* release the cap */
 
 /* inode record, for bundling with mds reply */
 struct ceph_mds_reply_inode {
@@ -658,6 +684,14 @@ struct ceph_mds_caps {
        __le32 time_warp_seq;
 } __attribute__ ((packed));
 
+struct ceph_mds_cap_peer {
+       __le64 cap_id;
+       __le32 seq;
+       __le32 mseq;
+       __le32 mds;
+       __u8   flags;
+} __attribute__ ((packed));
+
 /* cap release msg head */
 struct ceph_mds_cap_release {
        __le32 num;                /* number of cap_items that follow */
index 2e3024881a5e3e3939264c032b000f1c9d80d367..2f49aa4c4f7f1d2feb361422e2b5f024c55a9519 100644 (file)
@@ -122,8 +122,8 @@ struct ceph_client {
 
        int (*extra_mon_dispatch)(struct ceph_client *, struct ceph_msg *);
 
-       u32 supported_features;
-       u32 required_features;
+       u64 supported_features;
+       u64 required_features;
 
        struct ceph_messenger msgr;   /* messenger instance */
        struct ceph_mon_client monc;
@@ -173,15 +173,18 @@ static inline int calc_pages_for(u64 off, u64 len)
                (off >> PAGE_CACHE_SHIFT);
 }
 
+extern struct kmem_cache *ceph_inode_cachep;
+extern struct kmem_cache *ceph_cap_cachep;
+extern struct kmem_cache *ceph_dentry_cachep;
+extern struct kmem_cache *ceph_file_cachep;
+
 /* ceph_common.c */
 extern bool libceph_compatible(void *data);
 
 extern const char *ceph_msg_type_name(int type);
 extern int ceph_check_fsid(struct ceph_client *client, struct ceph_fsid *fsid);
-extern struct kmem_cache *ceph_inode_cachep;
-extern struct kmem_cache *ceph_cap_cachep;
-extern struct kmem_cache *ceph_dentry_cachep;
-extern struct kmem_cache *ceph_file_cachep;
+extern void *ceph_kvmalloc(size_t size, gfp_t flags);
+extern void ceph_kvfree(const void *ptr);
 
 extern struct ceph_options *ceph_parse_options(char *options,
                              const char *dev_name, const char *dev_name_end,
@@ -192,8 +195,8 @@ extern int ceph_compare_options(struct ceph_options *new_opt,
                                struct ceph_client *client);
 extern struct ceph_client *ceph_create_client(struct ceph_options *opt,
                                              void *private,
-                                             unsigned supported_features,
-                                             unsigned required_features);
+                                             u64 supported_features,
+                                             u64 required_features);
 extern u64 ceph_client_id(struct ceph_client *client);
 extern void ceph_destroy_client(struct ceph_client *client);
 extern int __ceph_open_session(struct ceph_client *client,
index 7c1420bb1dcef40e6f8e4cc571ef5ea2c25df913..d21f2dba07314c48dce2414c4be23d2191180c81 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef __FS_CEPH_MESSENGER_H
 #define __FS_CEPH_MESSENGER_H
 
+#include <linux/blk_types.h>
 #include <linux/kref.h>
 #include <linux/mutex.h>
 #include <linux/net.h>
@@ -60,8 +61,8 @@ struct ceph_messenger {
        u32 global_seq;
        spinlock_t global_seq_lock;
 
-       u32 supported_features;
-       u32 required_features;
+       u64 supported_features;
+       u64 required_features;
 };
 
 enum ceph_msg_data_type {
@@ -119,8 +120,7 @@ struct ceph_msg_data_cursor {
 #ifdef CONFIG_BLOCK
                struct {                                /* bio */
                        struct bio      *bio;           /* bio from list */
-                       unsigned int    vector_index;   /* vector from bio */
-                       unsigned int    vector_offset;  /* bytes from vector */
+                       struct bvec_iter bvec_iter;
                };
 #endif /* CONFIG_BLOCK */
                struct {                                /* pages */
@@ -154,10 +154,9 @@ struct ceph_msg {
        struct list_head list_head;     /* links for connection lists */
 
        struct kref kref;
-       bool front_is_vmalloc;
        bool more_to_follow;
        bool needs_out_seq;
-       int front_max;
+       int front_alloc_len;
        unsigned long ack_stamp;        /* tx: when we were acked */
 
        struct ceph_msgpool *pool;
@@ -192,7 +191,7 @@ struct ceph_connection {
 
        struct ceph_entity_name peer_name; /* peer name */
 
-       unsigned peer_features;
+       u64 peer_features;
        u32 connect_seq;      /* identify the most recent connection
                                 attempt for this connection, client */
        u32 peer_global_seq;  /* peer's global seq for this connection */
@@ -256,8 +255,8 @@ extern void ceph_msgr_flush(void);
 
 extern void ceph_messenger_init(struct ceph_messenger *msgr,
                        struct ceph_entity_addr *myaddr,
-                       u32 supported_features,
-                       u32 required_features,
+                       u64 supported_features,
+                       u64 required_features,
                        bool nocrc);
 
 extern void ceph_con_init(struct ceph_connection *con, void *private,
index 8f47625a06615dbf5cbc79ef5df2e2fd5cee6041..fd47e872ebcc7a35380160dbf2f83ab1563dd878 100644 (file)
 #include <linux/ceph/auth.h>
 #include <linux/ceph/pagelist.h>
 
-/* 
- * Maximum object name size 
- * (must be at least as big as RBD_MAX_MD_NAME_LEN -- currently 100) 
- */
-#define MAX_OBJ_NAME_SIZE 100
-
 struct ceph_msg;
 struct ceph_snap_context;
 struct ceph_osd_request;
@@ -138,6 +132,7 @@ struct ceph_osd_request {
        __le64           *r_request_pool;
        void             *r_request_pgid;
        __le32           *r_request_attempts;
+       bool              r_paused;
        struct ceph_eversion *r_request_reassert_version;
 
        int               r_result;
@@ -158,15 +153,21 @@ struct ceph_osd_request {
        struct inode *r_inode;                /* for use by callbacks */
        void *r_priv;                         /* ditto */
 
-       char              r_oid[MAX_OBJ_NAME_SIZE];          /* object name */
-       int               r_oid_len;
+       struct ceph_object_locator r_base_oloc;
+       struct ceph_object_id r_base_oid;
+       struct ceph_object_locator r_target_oloc;
+       struct ceph_object_id r_target_oid;
+
        u64               r_snapid;
        unsigned long     r_stamp;            /* send OR check time */
 
-       struct ceph_file_layout r_file_layout;
        struct ceph_snap_context *r_snapc;    /* snap context for writes */
 };
 
+struct ceph_request_redirect {
+       struct ceph_object_locator oloc;
+};
+
 struct ceph_osd_event {
        u64 cookie;
        int one_shot;
index d05cc4451af62dd158929b39e6684fc19fd85cb2..49ff69f0746bd6f28ee517ac6146716ff0e27fa5 100644 (file)
@@ -35,13 +35,26 @@ struct ceph_pg_pool_info {
        u8 object_hash;
        u32 pg_num, pgp_num;
        int pg_num_mask, pgp_num_mask;
+       s64 read_tier;
+       s64 write_tier; /* wins for read+write ops */
        u64 flags;
        char *name;
 };
 
 struct ceph_object_locator {
-       uint64_t pool;
-       char *key;
+       s64 pool;
+};
+
+/*
+ * Maximum supported by kernel client object name length
+ *
+ * (probably outdated: must be >= RBD_MAX_MD_NAME_LEN -- currently 100)
+ */
+#define CEPH_MAX_OID_NAME_LEN 100
+
+struct ceph_object_id {
+       char name[CEPH_MAX_OID_NAME_LEN];
+       int name_len;
 };
 
 struct ceph_pg_mapping {
@@ -73,33 +86,30 @@ struct ceph_osdmap {
        struct crush_map *crush;
 };
 
-/*
- * file layout helpers
- */
-#define ceph_file_layout_su(l) ((__s32)le32_to_cpu((l).fl_stripe_unit))
-#define ceph_file_layout_stripe_count(l) \
-       ((__s32)le32_to_cpu((l).fl_stripe_count))
-#define ceph_file_layout_object_size(l) ((__s32)le32_to_cpu((l).fl_object_size))
-#define ceph_file_layout_cas_hash(l) ((__s32)le32_to_cpu((l).fl_cas_hash))
-#define ceph_file_layout_object_su(l) \
-       ((__s32)le32_to_cpu((l).fl_object_stripe_unit))
-#define ceph_file_layout_pg_pool(l) \
-       ((__s32)le32_to_cpu((l).fl_pg_pool))
-
-static inline unsigned ceph_file_layout_stripe_width(struct ceph_file_layout *l)
+static inline void ceph_oid_set_name(struct ceph_object_id *oid,
+                                    const char *name)
 {
-       return le32_to_cpu(l->fl_stripe_unit) *
-               le32_to_cpu(l->fl_stripe_count);
+       int len;
+
+       len = strlen(name);
+       if (len > sizeof(oid->name)) {
+               WARN(1, "ceph_oid_set_name '%s' len %d vs %zu, truncating\n",
+                    name, len, sizeof(oid->name));
+               len = sizeof(oid->name);
+       }
+
+       memcpy(oid->name, name, len);
+       oid->name_len = len;
 }
 
-/* "period" == bytes before i start on a new set of objects */
-static inline unsigned ceph_file_layout_period(struct ceph_file_layout *l)
+static inline void ceph_oid_copy(struct ceph_object_id *dest,
+                                struct ceph_object_id *src)
 {
-       return le32_to_cpu(l->fl_object_size) *
-               le32_to_cpu(l->fl_stripe_count);
+       BUG_ON(src->name_len > sizeof(dest->name));
+       memcpy(dest->name, src->name, src->name_len);
+       dest->name_len = src->name_len;
 }
 
-
 static inline int ceph_osd_is_up(struct ceph_osdmap *map, int osd)
 {
        return (osd < map->max_osd) && (map->osd_state[osd] & CEPH_OSD_UP);
@@ -155,14 +165,20 @@ extern int ceph_calc_file_object_mapping(struct ceph_file_layout *layout,
                                         u64 *bno, u64 *oxoff, u64 *oxlen);
 
 /* calculate mapping of object to a placement group */
-extern int ceph_calc_ceph_pg(struct ceph_pg *pg, const char *oid,
-                         struct ceph_osdmap *osdmap, uint64_t pool);
+extern int ceph_oloc_oid_to_pg(struct ceph_osdmap *osdmap,
+                              struct ceph_object_locator *oloc,
+                              struct ceph_object_id *oid,
+                              struct ceph_pg *pg_out);
+
 extern int ceph_calc_pg_acting(struct ceph_osdmap *osdmap,
                               struct ceph_pg pgid,
                               int *acting);
 extern int ceph_calc_pg_primary(struct ceph_osdmap *osdmap,
                                struct ceph_pg pgid);
 
+extern struct ceph_pg_pool_info *ceph_pg_pool_by_id(struct ceph_osdmap *map,
+                                                   u64 id);
+
 extern const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id);
 extern int ceph_pg_poolid_by_name(struct ceph_osdmap *map, const char *name);
 
index 68c96a508ac20f8ff3aff08b7e29ff9bdf86bccf..96292df4041ba2aaebe32caa2dae5f731b4fb02c 100644 (file)
@@ -344,6 +344,10 @@ enum {
        CEPH_OSD_FLAG_EXEC_PUBLIC =    0x1000,  /* DEPRECATED op may exec (public) */
        CEPH_OSD_FLAG_LOCALIZE_READS = 0x2000,  /* read from nearby replica, if any */
        CEPH_OSD_FLAG_RWORDERED =      0x4000,  /* order wrt concurrent reads */
+       CEPH_OSD_FLAG_IGNORE_CACHE =   0x8000,  /* ignore cache logic */
+       CEPH_OSD_FLAG_SKIPRWLOCKS =   0x10000,  /* skip rw locks */
+       CEPH_OSD_FLAG_IGNORE_OVERLAY = 0x20000, /* ignore pool overlay */
+       CEPH_OSD_FLAG_FLUSH =         0x40000,  /* this is part of flush */
 };
 
 enum {
index 999b28ba38f7270608452cfff436a4e52b22a918..939533da93a7355be0a40422627090f1aad751b2 100644 (file)
@@ -488,6 +488,8 @@ struct clk_onecell_data {
        unsigned int clk_num;
 };
 
+extern struct of_device_id __clk_of_table;
+
 #define CLK_OF_DECLARE(name, compat, fn)                       \
        static const struct of_device_id __clk_of_table_##name  \
                __used __section(__clk_of_table)                \
@@ -542,6 +544,20 @@ static inline const char *of_clk_get_parent_name(struct device_node *np,
  * for improved portability across platforms
  */
 
+#if IS_ENABLED(CONFIG_PPC)
+
+static inline u32 clk_readl(u32 __iomem *reg)
+{
+       return ioread32be(reg);
+}
+
+static inline void clk_writel(u32 val, u32 __iomem *reg)
+{
+       iowrite32be(val, reg);
+}
+
+#else  /* platform dependent I/O accessors */
+
 static inline u32 clk_readl(u32 __iomem *reg)
 {
        return readl(reg);
@@ -552,5 +568,7 @@ static inline void clk_writel(u32 val, u32 __iomem *reg)
        writel(val, reg);
 }
 
+#endif /* platform dependent I/O accessors */
+
 #endif /* CONFIG_COMMON_CLK */
 #endif /* CLK_PROVIDER_H */
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
new file mode 100644 (file)
index 0000000..092b641
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * TI clock drivers support
+ *
+ * Copyright (C) 2013 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+#ifndef __LINUX_CLK_TI_H__
+#define __LINUX_CLK_TI_H__
+
+#include <linux/clkdev.h>
+
+/**
+ * struct dpll_data - DPLL registers and integration data
+ * @mult_div1_reg: register containing the DPLL M and N bitfields
+ * @mult_mask: mask of the DPLL M bitfield in @mult_div1_reg
+ * @div1_mask: mask of the DPLL N bitfield in @mult_div1_reg
+ * @clk_bypass: struct clk pointer to the clock's bypass clock input
+ * @clk_ref: struct clk pointer to the clock's reference clock input
+ * @control_reg: register containing the DPLL mode bitfield
+ * @enable_mask: mask of the DPLL mode bitfield in @control_reg
+ * @last_rounded_rate: cache of the last rate result of omap2_dpll_round_rate()
+ * @last_rounded_m: cache of the last M result of omap2_dpll_round_rate()
+ * @last_rounded_m4xen: cache of the last M4X result of
+ *                     omap4_dpll_regm4xen_round_rate()
+ * @last_rounded_lpmode: cache of the last lpmode result of
+ *                      omap4_dpll_lpmode_recalc()
+ * @max_multiplier: maximum valid non-bypass multiplier value (actual)
+ * @last_rounded_n: cache of the last N result of omap2_dpll_round_rate()
+ * @min_divider: minimum valid non-bypass divider value (actual)
+ * @max_divider: maximum valid non-bypass divider value (actual)
+ * @modes: possible values of @enable_mask
+ * @autoidle_reg: register containing the DPLL autoidle mode bitfield
+ * @idlest_reg: register containing the DPLL idle status bitfield
+ * @autoidle_mask: mask of the DPLL autoidle mode bitfield in @autoidle_reg
+ * @freqsel_mask: mask of the DPLL jitter correction bitfield in @control_reg
+ * @idlest_mask: mask of the DPLL idle status bitfield in @idlest_reg
+ * @lpmode_mask: mask of the DPLL low-power mode bitfield in @control_reg
+ * @m4xen_mask: mask of the DPLL M4X multiplier bitfield in @control_reg
+ * @auto_recal_bit: bitshift of the driftguard enable bit in @control_reg
+ * @recal_en_bit: bitshift of the PRM_IRQENABLE_* bit for recalibration IRQs
+ * @recal_st_bit: bitshift of the PRM_IRQSTATUS_* bit for recalibration IRQs
+ * @flags: DPLL type/features (see below)
+ *
+ * Possible values for @flags:
+ * DPLL_J_TYPE: "J-type DPLL" (only some 36xx, 4xxx DPLLs)
+ *
+ * @freqsel_mask is only used on the OMAP34xx family and AM35xx.
+ *
+ * XXX Some DPLLs have multiple bypass inputs, so it's not technically
+ * correct to only have one @clk_bypass pointer.
+ *
+ * XXX The runtime-variable fields (@last_rounded_rate, @last_rounded_m,
+ * @last_rounded_n) should be separated from the runtime-fixed fields
+ * and placed into a different structure, so that the runtime-fixed data
+ * can be placed into read-only space.
+ */
+struct dpll_data {
+       void __iomem            *mult_div1_reg;
+       u32                     mult_mask;
+       u32                     div1_mask;
+       struct clk              *clk_bypass;
+       struct clk              *clk_ref;
+       void __iomem            *control_reg;
+       u32                     enable_mask;
+       unsigned long           last_rounded_rate;
+       u16                     last_rounded_m;
+       u8                      last_rounded_m4xen;
+       u8                      last_rounded_lpmode;
+       u16                     max_multiplier;
+       u8                      last_rounded_n;
+       u8                      min_divider;
+       u16                     max_divider;
+       u8                      modes;
+       void __iomem            *autoidle_reg;
+       void __iomem            *idlest_reg;
+       u32                     autoidle_mask;
+       u32                     freqsel_mask;
+       u32                     idlest_mask;
+       u32                     dco_mask;
+       u32                     sddiv_mask;
+       u32                     lpmode_mask;
+       u32                     m4xen_mask;
+       u8                      auto_recal_bit;
+       u8                      recal_en_bit;
+       u8                      recal_st_bit;
+       u8                      flags;
+};
+
+struct clk_hw_omap_ops;
+
+/**
+ * struct clk_hw_omap - OMAP struct clk
+ * @node: list_head connecting this clock into the full clock list
+ * @enable_reg: register to write to enable the clock (see @enable_bit)
+ * @enable_bit: bitshift to write to enable/disable the clock (see @enable_reg)
+ * @flags: see "struct clk.flags possibilities" above
+ * @clksel_reg: for clksel clks, register va containing src/divisor select
+ * @clksel_mask: bitmask in @clksel_reg for the src/divisor selector
+ * @clksel: for clksel clks, pointer to struct clksel for this clock
+ * @dpll_data: for DPLLs, pointer to struct dpll_data for this clock
+ * @clkdm_name: clockdomain name that this clock is contained in
+ * @clkdm: pointer to struct clockdomain, resolved from @clkdm_name at runtime
+ * @ops: clock ops for this clock
+ */
+struct clk_hw_omap {
+       struct clk_hw           hw;
+       struct list_head        node;
+       unsigned long           fixed_rate;
+       u8                      fixed_div;
+       void __iomem            *enable_reg;
+       u8                      enable_bit;
+       u8                      flags;
+       void __iomem            *clksel_reg;
+       u32                     clksel_mask;
+       const struct clksel     *clksel;
+       struct dpll_data        *dpll_data;
+       const char              *clkdm_name;
+       struct clockdomain      *clkdm;
+       const struct clk_hw_omap_ops    *ops;
+};
+
+/*
+ * struct clk_hw_omap.flags possibilities
+ *
+ * XXX document the rest of the clock flags here
+ *
+ * ENABLE_REG_32BIT: (OMAP1 only) clock control register must be accessed
+ *     with 32bit ops, by default OMAP1 uses 16bit ops.
+ * CLOCK_IDLE_CONTROL: (OMAP1 only) clock has autoidle support.
+ * CLOCK_NO_IDLE_PARENT: (OMAP1 only) when clock is enabled, its parent
+ *     clock is put to no-idle mode.
+ * ENABLE_ON_INIT: Clock is enabled on init.
+ * INVERT_ENABLE: By default, clock enable bit behavior is '1' enable, '0'
+ *     disable. This inverts the behavior making '0' enable and '1' disable.
+ * CLOCK_CLKOUTX2: (OMAP4 only) DPLL CLKOUT and CLKOUTX2 GATE_CTRL
+ *     bits share the same register.  This flag allows the
+ *     omap4_dpllmx*() code to determine which GATE_CTRL bit field
+ *     should be used.  This is a temporary solution - a better approach
+ *     would be to associate clock type-specific data with the clock,
+ *     similar to the struct dpll_data approach.
+ * MEMMAP_ADDRESSING: Use memmap addressing to access clock registers.
+ */
+#define ENABLE_REG_32BIT       (1 << 0)        /* Use 32-bit access */
+#define CLOCK_IDLE_CONTROL     (1 << 1)
+#define CLOCK_NO_IDLE_PARENT   (1 << 2)
+#define ENABLE_ON_INIT         (1 << 3)        /* Enable upon framework init */
+#define INVERT_ENABLE          (1 << 4)        /* 0 enables, 1 disables */
+#define CLOCK_CLKOUTX2         (1 << 5)
+#define MEMMAP_ADDRESSING      (1 << 6)
+
+/* CM_CLKEN_PLL*.EN* bit values - not all are available for every DPLL */
+#define DPLL_LOW_POWER_STOP    0x1
+#define DPLL_LOW_POWER_BYPASS  0x5
+#define DPLL_LOCKED            0x7
+
+/* DPLL Type and DCO Selection Flags */
+#define DPLL_J_TYPE            0x1
+
+/* Composite clock component types */
+enum {
+       CLK_COMPONENT_TYPE_GATE = 0,
+       CLK_COMPONENT_TYPE_DIVIDER,
+       CLK_COMPONENT_TYPE_MUX,
+       CLK_COMPONENT_TYPE_MAX,
+};
+
+/**
+ * struct ti_dt_clk - OMAP DT clock alias declarations
+ * @lk: clock lookup definition
+ * @node_name: clock DT node to map to
+ */
+struct ti_dt_clk {
+       struct clk_lookup               lk;
+       char                            *node_name;
+};
+
+#define DT_CLK(dev, con, name)         \
+       {                               \
+               .lk = {                 \
+                       .dev_id = dev,  \
+                       .con_id = con,  \
+               },                      \
+               .node_name = name,      \
+       }
+
+/* Maximum number of clock memmaps */
+#define CLK_MAX_MEMMAPS                        4
+
+typedef void (*ti_of_clk_init_cb_t)(struct clk_hw *, struct device_node *);
+
+/**
+ * struct clk_omap_reg - OMAP register declaration
+ * @offset: offset from the master IP module base address
+ * @index: index of the master IP module
+ */
+struct clk_omap_reg {
+       u16 offset;
+       u16 index;
+};
+
+/**
+ * struct ti_clk_ll_ops - low-level register access ops for a clock
+ * @clk_readl: pointer to register read function
+ * @clk_writel: pointer to register write function
+ *
+ * Low-level register access ops are generally used by the basic clock types
+ * (clk-gate, clk-mux, clk-divider etc.) to provide support for various
+ * low-level hardware interfaces (direct MMIO, regmap etc.), but can also be
+ * used by other hardware-specific clock drivers if needed.
+ */
+struct ti_clk_ll_ops {
+       u32     (*clk_readl)(void __iomem *reg);
+       void    (*clk_writel)(u32 val, void __iomem *reg);
+};
+
+extern struct ti_clk_ll_ops *ti_clk_ll_ops;
+
+extern const struct clk_ops ti_clk_divider_ops;
+extern const struct clk_ops ti_clk_mux_ops;
+
+#define to_clk_hw_omap(_hw) container_of(_hw, struct clk_hw_omap, hw)
+
+void omap2_init_clk_hw_omap_clocks(struct clk *clk);
+int omap3_noncore_dpll_enable(struct clk_hw *hw);
+void omap3_noncore_dpll_disable(struct clk_hw *hw);
+int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
+                               unsigned long parent_rate);
+unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
+                                        unsigned long parent_rate);
+long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
+                                   unsigned long target_rate,
+                                   unsigned long *parent_rate);
+u8 omap2_init_dpll_parent(struct clk_hw *hw);
+unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
+long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
+                          unsigned long *parent_rate);
+void omap2_init_clk_clkdm(struct clk_hw *clk);
+unsigned long omap3_clkoutx2_recalc(struct clk_hw *hw,
+                                   unsigned long parent_rate);
+int omap2_clkops_enable_clkdm(struct clk_hw *hw);
+void omap2_clkops_disable_clkdm(struct clk_hw *hw);
+int omap2_clk_disable_autoidle_all(void);
+void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks);
+int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate,
+                        unsigned long parent_rate);
+int omap2_dflt_clk_enable(struct clk_hw *hw);
+void omap2_dflt_clk_disable(struct clk_hw *hw);
+int omap2_dflt_clk_is_enabled(struct clk_hw *hw);
+void omap3_clk_lock_dpll5(void);
+
+void __iomem *ti_clk_get_reg_addr(struct device_node *node, int index);
+void ti_dt_clocks_register(struct ti_dt_clk *oclks);
+void ti_dt_clk_init_provider(struct device_node *np, int index);
+void ti_dt_clockdomains_setup(void);
+int ti_clk_retry_init(struct device_node *node, struct clk_hw *hw,
+                     ti_of_clk_init_cb_t func);
+int of_ti_clk_autoidle_setup(struct device_node *node);
+int ti_clk_add_component(struct device_node *node, struct clk_hw *hw, int type);
+
+int omap3430_dt_clk_init(void);
+int omap3630_dt_clk_init(void);
+int am35xx_dt_clk_init(void);
+int ti81xx_dt_clk_init(void);
+int omap4xxx_dt_clk_init(void);
+int omap5xxx_dt_clk_init(void);
+int dra7xx_dt_clk_init(void);
+int am33xx_dt_clk_init(void);
+int am43xx_dt_clk_init(void);
+
+#ifdef CONFIG_OF
+void of_ti_clk_allow_autoidle_all(void);
+void of_ti_clk_deny_autoidle_all(void);
+#else
+static inline void of_ti_clk_allow_autoidle_all(void) { }
+static inline void of_ti_clk_deny_autoidle_all(void) { }
+#endif
+
+extern const struct clk_hw_omap_ops clkhwops_omap3_dpll;
+extern const struct clk_hw_omap_ops clkhwops_omap4_dpllmx;
+extern const struct clk_hw_omap_ops clkhwops_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_dss_usbhost_wait;
+extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_module_wait;
+extern const struct clk_hw_omap_ops clkhwops_am35xx_ipss_wait;
+extern const struct clk_hw_omap_ops clkhwops_iclk;
+extern const struct clk_hw_omap_ops clkhwops_iclk_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_ssi_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_dss_usbhost_wait;
+extern const struct clk_hw_omap_ops clkhwops_omap3430es2_iclk_hsotgusb_wait;
+
+#endif
index a0f9280421eca511b00e80f51e8e65436ec47e3a..2e6dce6e5c2acf9bae626033c700ec0da012bbcb 100644 (file)
@@ -37,9 +37,9 @@ int cmdline_parts_parse(struct cmdline_parts **parts, const char *cmdline);
 struct cmdline_parts *cmdline_parts_find(struct cmdline_parts *parts,
                                         const char *bdev);
 
-void cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
-                      int slot,
-                      int (*add_part)(int, struct cmdline_subpart *, void *),
-                      void *param);
+int cmdline_parts_set(struct cmdline_parts *parts, sector_t disk_size,
+                     int slot,
+                     int (*add_part)(int, struct cmdline_subpart *, void *),
+                     void *param);
 
 #endif /* CMDLINEPARSEH */
index eb8a49d75ab3155bb6910eab585e5dfed9f64dee..19f6003291def61a40a2305a453838d13c92892f 100644 (file)
@@ -327,16 +327,16 @@ asmlinkage long compat_sys_keyctl(u32 option,
                              u32 arg2, u32 arg3, u32 arg4, u32 arg5);
 asmlinkage long compat_sys_ustat(unsigned dev, struct compat_ustat __user *u32);
 
-asmlinkage ssize_t compat_sys_readv(unsigned long fd,
-               const struct compat_iovec __user *vec, unsigned long vlen);
-asmlinkage ssize_t compat_sys_writev(unsigned long fd,
-               const struct compat_iovec __user *vec, unsigned long vlen);
-asmlinkage ssize_t compat_sys_preadv(unsigned long fd,
+asmlinkage ssize_t compat_sys_readv(compat_ulong_t fd,
+               const struct compat_iovec __user *vec, compat_ulong_t vlen);
+asmlinkage ssize_t compat_sys_writev(compat_ulong_t fd,
+               const struct compat_iovec __user *vec, compat_ulong_t vlen);
+asmlinkage ssize_t compat_sys_preadv(compat_ulong_t fd,
                const struct compat_iovec __user *vec,
-               unsigned long vlen, u32 pos_low, u32 pos_high);
-asmlinkage ssize_t compat_sys_pwritev(unsigned long fd,
+               compat_ulong_t vlen, u32 pos_low, u32 pos_high);
+asmlinkage ssize_t compat_sys_pwritev(compat_ulong_t fd,
                const struct compat_iovec __user *vec,
-               unsigned long vlen, u32 pos_low, u32 pos_high);
+               compat_ulong_t vlen, u32 pos_low, u32 pos_high);
 asmlinkage long comat_sys_lseek(unsigned int, compat_off_t, unsigned int);
 
 asmlinkage long compat_sys_execve(const char __user *filename, const compat_uptr_t __user *argv,
@@ -422,7 +422,7 @@ extern long compat_arch_ptrace(struct task_struct *child, compat_long_t request,
 asmlinkage long compat_sys_ptrace(compat_long_t request, compat_long_t pid,
                                  compat_long_t addr, compat_long_t data);
 
-asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, size_t);
+asmlinkage long compat_sys_lookup_dcookie(u32, u32, char __user *, compat_size_t);
 /*
  * epoll (fs/eventpoll.c) compat bits follow ...
  */
diff --git a/include/linux/cramfs_fs_sb.h b/include/linux/cramfs_fs_sb.h
deleted file mode 100644 (file)
index 8390693..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef _CRAMFS_FS_SB
-#define _CRAMFS_FS_SB
-
-/*
- * cramfs super-block data in memory
- */
-struct cramfs_sb_info {
-                       unsigned long magic;
-                       unsigned long size;
-                       unsigned long blocks;
-                       unsigned long files;
-                       unsigned long flags;
-};
-
-static inline struct cramfs_sb_info *CRAMFS_SB(struct super_block *sb)
-{
-       return sb->s_fs_info;
-}
-
-#endif
index 6a1101f24cfba84eaf6210f96802984009462dbd..acaa5615d6343906ab05e528bb10ea3e76bf0fac 100644 (file)
 
 #define CRUSH_MAGIC 0x00010000ul   /* for detecting algorithm revisions */
 
-
 #define CRUSH_MAX_DEPTH 10  /* max crush hierarchy depth */
-#define CRUSH_MAX_SET   10  /* max size of a mapping result */
 
 
+#define CRUSH_ITEM_UNDEF  0x7ffffffe  /* undefined result (internal use only) */
+#define CRUSH_ITEM_NONE   0x7fffffff  /* no result */
+
 /*
  * CRUSH uses user-defined "rules" to describe how inputs should be
  * mapped to devices.  A rule consists of sequence of steps to perform
@@ -43,8 +44,13 @@ enum {
                                      /* arg2 = type */
        CRUSH_RULE_CHOOSE_INDEP = 3,  /* same */
        CRUSH_RULE_EMIT = 4,          /* no args */
-       CRUSH_RULE_CHOOSE_LEAF_FIRSTN = 6,
-       CRUSH_RULE_CHOOSE_LEAF_INDEP = 7,
+       CRUSH_RULE_CHOOSELEAF_FIRSTN = 6,
+       CRUSH_RULE_CHOOSELEAF_INDEP = 7,
+
+       CRUSH_RULE_SET_CHOOSE_TRIES = 8, /* override choose_total_tries */
+       CRUSH_RULE_SET_CHOOSELEAF_TRIES = 9, /* override chooseleaf_descend_once */
+       CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES = 10,
+       CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES = 11,
 };
 
 /*
@@ -162,7 +168,10 @@ struct crush_map {
        __u32 choose_local_fallback_tries;
        /* choose attempts before giving up */ 
        __u32 choose_total_tries;
-       /* attempt chooseleaf inner descent once; on failure retry outer descent */
+       /* attempt chooseleaf inner descent once for firstn mode; on
+        * reject retry outer descent.  Note that this does *not*
+        * apply to a collision: in that case we will retry as we used
+        * to. */
        __u32 chooseleaf_descend_once;
 };
 
@@ -174,6 +183,7 @@ extern void crush_destroy_bucket_list(struct crush_bucket_list *b);
 extern void crush_destroy_bucket_tree(struct crush_bucket_tree *b);
 extern void crush_destroy_bucket_straw(struct crush_bucket_straw *b);
 extern void crush_destroy_bucket(struct crush_bucket *b);
+extern void crush_destroy_rule(struct crush_rule *r);
 extern void crush_destroy(struct crush_map *map);
 
 static inline int crush_calc_tree_node(int i)
index 5772dee3ecbf236c13b9fdc3e31446d6da495e31..eab367446eea7fa683cb4fd15e74ad3822bb35c8 100644 (file)
@@ -14,6 +14,7 @@ extern int crush_find_rule(const struct crush_map *map, int ruleset, int type, i
 extern int crush_do_rule(const struct crush_map *map,
                         int ruleno,
                         int x, int *result, int result_max,
-                        const __u32 *weights);
+                        const __u32 *weights, int weight_max,
+                        int *scratch);
 
 #endif
index f4b0aa3126f5deae8ff8908375a9da1eca790ecf..a68cbe59e6ad190023e410cb32784b1fb6a67d2a 100644 (file)
@@ -29,7 +29,7 @@ typedef void (*io_notify_fn)(unsigned long error, void *context);
 
 enum dm_io_mem_type {
        DM_IO_PAGE_LIST,/* Page list */
-       DM_IO_BVEC,     /* Bio vector */
+       DM_IO_BIO,      /* Bio vector */
        DM_IO_VMA,      /* Virtual memory area */
        DM_IO_KMEM,     /* Kernel memory */
 };
@@ -41,7 +41,7 @@ struct dm_io_memory {
 
        union {
                struct page_list *pl;
-               struct bio_vec *bvec;
+               struct bio *bio;
                void *vma;
                void *addr;
        } ptr;
index 57c9a8ae4f2df2127dffe7e88aee95b5f2cdce1a..7ac17f57250e48feb5024cb27fe5389972186001 100644 (file)
@@ -27,7 +27,6 @@ struct root_entry;
 
 
 #ifdef CONFIG_INTEL_IOMMU
-extern void free_dmar_iommu(struct intel_iommu *iommu);
 extern int iommu_calculate_agaw(struct intel_iommu *iommu);
 extern int iommu_calculate_max_sagaw(struct intel_iommu *iommu);
 extern int dmar_disabled;
@@ -41,9 +40,6 @@ static inline int iommu_calculate_max_sagaw(struct intel_iommu *iommu)
 {
        return 0;
 }
-static inline void free_dmar_iommu(struct intel_iommu *iommu)
-{
-}
 #define dmar_disabled  (1)
 #define intel_iommu_enabled (0)
 #endif
index 6fd9390ccf91ab541f4aba92ac80da639bdf58ad..c5c92d59e5316820d0ae078fe7ce78e8407f2ede 100644 (file)
@@ -257,7 +257,7 @@ struct dma_chan_percpu {
  * @dev: class device for sysfs
  * @device_node: used to add this to the device chan list
  * @local: per-cpu pointer to a struct dma_chan_percpu
- * @client-count: how many clients are using this channel
+ * @client_count: how many clients are using this channel
  * @table_count: number of appearances in the mem-to-mem allocation table
  * @private: private data for certain client-channel associations
  */
@@ -279,10 +279,10 @@ struct dma_chan {
 
 /**
  * struct dma_chan_dev - relate sysfs device node to backing channel device
- * @chan - driver channel device
- * @device - sysfs device
- * @dev_id - parent dma_device dev_id
- * @idr_ref - reference count to gate release of dma_device dev_id
+ * @chan: driver channel device
+ * @device: sysfs device
+ * @dev_id: parent dma_device dev_id
+ * @idr_ref: reference count to gate release of dma_device dev_id
  */
 struct dma_chan_dev {
        struct dma_chan *chan;
@@ -306,9 +306,8 @@ enum dma_slave_buswidth {
 /**
  * struct dma_slave_config - dma slave channel runtime config
  * @direction: whether the data shall go in or out on this slave
- * channel, right now. DMA_TO_DEVICE and DMA_FROM_DEVICE are
- * legal values, DMA_BIDIRECTIONAL is not acceptable since we
- * need to differentiate source and target addresses.
+ * channel, right now. DMA_MEM_TO_DEV and DMA_DEV_TO_MEM are
+ * legal values.
  * @src_addr: this is the physical address where DMA slave data
  * should be read (RX), if the source is memory this argument is
  * ignored.
index b029d1aa2d12a6d18f38f6472ef63bf44bb44568..eccb0c0c6cf633c35e7a0ebfd5b9b5511a19bf39 100644 (file)
@@ -33,6 +33,7 @@ struct acpi_dmar_header;
 #define DMAR_X2APIC_OPT_OUT    0x2
 
 struct intel_iommu;
+
 #ifdef CONFIG_DMAR_TABLE
 extern struct acpi_table_header *dmar_tbl;
 struct dmar_drhd_unit {
@@ -52,6 +53,10 @@ extern struct list_head dmar_drhd_units;
 #define for_each_drhd_unit(drhd) \
        list_for_each_entry(drhd, &dmar_drhd_units, list)
 
+#define for_each_active_drhd_unit(drhd)                                        \
+       list_for_each_entry(drhd, &dmar_drhd_units, list)               \
+               if (drhd->ignored) {} else
+
 #define for_each_active_iommu(i, drhd)                                 \
        list_for_each_entry(drhd, &dmar_drhd_units, list)               \
                if (i=drhd->iommu, drhd->ignored) {} else
@@ -62,13 +67,13 @@ extern struct list_head dmar_drhd_units;
 
 extern int dmar_table_init(void);
 extern int dmar_dev_scope_init(void);
+extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
+                               struct pci_dev ***devices, u16 segment);
+extern void dmar_free_dev_scope(struct pci_dev ***devices, int *cnt);
 
 /* Intel IOMMU detection */
 extern int detect_intel_iommu(void);
 extern int enable_drhd_fault_handling(void);
-
-extern int parse_ioapics_under_ir(void);
-extern int alloc_iommu(struct dmar_drhd_unit *);
 #else
 static inline int detect_intel_iommu(void)
 {
@@ -157,8 +162,6 @@ struct dmar_atsr_unit {
 int dmar_parse_rmrr_atsr_dev(void);
 extern int dmar_parse_one_rmrr(struct acpi_dmar_header *header);
 extern int dmar_parse_one_atsr(struct acpi_dmar_header *header);
-extern int dmar_parse_dev_scope(void *start, void *end, int *cnt,
-                               struct pci_dev ***devices, u16 segment);
 extern int intel_iommu_init(void);
 #else /* !CONFIG_INTEL_IOMMU: */
 static inline int intel_iommu_init(void) { return -ENODEV; }
index 70c4836e4a9f8fb16dd578bbbcfa25ecfec0b129..fe6ac956550e4e099a04889e9b33bf0f9a917c2e 100644 (file)
@@ -613,8 +613,8 @@ extern ssize_t fb_sys_write(struct fb_info *info, const char __user *buf,
 extern int register_framebuffer(struct fb_info *fb_info);
 extern int unregister_framebuffer(struct fb_info *fb_info);
 extern int unlink_framebuffer(struct fb_info *fb_info);
-extern void remove_conflicting_framebuffers(struct apertures_struct *a,
-                               const char *name, bool primary);
+extern int remove_conflicting_framebuffers(struct apertures_struct *a,
+                                          const char *name, bool primary);
 extern int fb_prepare_logo(struct fb_info *fb_info, int rotate);
 extern int fb_show_logo(struct fb_info *fb_info, int rotate);
 extern char* fb_get_buffer_offset(struct fb_info *info, struct fb_pixmap *buf, u32 size);
index 085197bd88120e945235e3d843360ce99364a274..70e8e21c0a303a3db8b7a59ff3b6f511cf225c46 100644 (file)
@@ -59,29 +59,36 @@ struct files_struct {
        struct file __rcu * fd_array[NR_OPEN_DEFAULT];
 };
 
-#define rcu_dereference_check_fdtable(files, fdtfd) \
-       (rcu_dereference_check((fdtfd), \
-                              lockdep_is_held(&(files)->file_lock) || \
-                              atomic_read(&(files)->count) == 1 || \
-                              rcu_my_thread_group_empty()))
-
-#define files_fdtable(files) \
-               (rcu_dereference_check_fdtable((files), (files)->fdt))
-
 struct file_operations;
 struct vfsmount;
 struct dentry;
 
 extern void __init files_defer_init(void);
 
-static inline struct file * fcheck_files(struct files_struct *files, unsigned int fd)
+#define rcu_dereference_check_fdtable(files, fdtfd) \
+       rcu_dereference_check((fdtfd), lockdep_is_held(&(files)->file_lock))
+
+#define files_fdtable(files) \
+       rcu_dereference_check_fdtable((files), (files)->fdt)
+
+/*
+ * The caller must ensure that fd table isn't shared or hold rcu or file lock
+ */
+static inline struct file *__fcheck_files(struct files_struct *files, unsigned int fd)
 {
-       struct file * file = NULL;
-       struct fdtable *fdt = files_fdtable(files);
+       struct fdtable *fdt = rcu_dereference_raw(files->fdt);
 
        if (fd < fdt->max_fds)
-               file = rcu_dereference_check_fdtable(files, fdt->fd[fd]);
-       return file;
+               return rcu_dereference_raw(fdt->fd[fd]);
+       return NULL;
+}
+
+static inline struct file *fcheck_files(struct files_struct *files, unsigned int fd)
+{
+       rcu_lockdep_assert(rcu_read_lock_held() ||
+                          lockdep_is_held(&files->file_lock),
+                          "suspicious rcu_dereference_check() usage");
+       return __fcheck_files(files, fd);
 }
 
 /*
index 121f11f001c06f1cdcdeb6533234d76626a2915b..09f553c59813a2b2f88991ab0ab854880e07e574 100644 (file)
@@ -1580,6 +1580,7 @@ struct inode_operations {
                           struct file *, unsigned open_flag,
                           umode_t create_mode, int *opened);
        int (*tmpfile) (struct inode *, struct dentry *, umode_t);
+       int (*set_acl)(struct inode *, struct posix_acl *, int);
 } ____cacheline_aligned;
 
 ssize_t rw_copy_check_uvector(int type, const struct iovec __user * uvector,
index 7d8d5e608594c911c2eacc78dbb094c5384fd4af..3d286ff49ab0c82309ec3499bf27cc77f75f3670 100644 (file)
@@ -322,10 +322,10 @@ extern int fsnotify_fasync(int fd, struct file *file, int on);
 extern void fsnotify_destroy_event(struct fsnotify_group *group,
                                   struct fsnotify_event *event);
 /* attach the event to the group notification queue */
-extern struct fsnotify_event *fsnotify_add_notify_event(struct fsnotify_group *group,
-                                                       struct fsnotify_event *event,
-                                                       struct fsnotify_event *(*merge)(struct list_head *,
-                                                                                       struct fsnotify_event *));
+extern int fsnotify_add_notify_event(struct fsnotify_group *group,
+                                    struct fsnotify_event *event,
+                                    int (*merge)(struct list_head *,
+                                                 struct fsnotify_event *));
 /* true if the group notification queue is empty */
 extern bool fsnotify_notify_queue_is_empty(struct fsnotify_group *group);
 /* return, but do not dequeue the first event on the notification queue */
diff --git a/include/linux/generic_acl.h b/include/linux/generic_acl.h
deleted file mode 100644 (file)
index b6d6575..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef LINUX_GENERIC_ACL_H
-#define LINUX_GENERIC_ACL_H
-
-#include <linux/xattr.h>
-
-struct inode;
-
-extern const struct xattr_handler generic_acl_access_handler;
-extern const struct xattr_handler generic_acl_default_handler;
-
-int generic_acl_init(struct inode *, struct inode *);
-int generic_acl_chmod(struct inode *);
-
-#endif /* LINUX_GENERIC_ACL_H */
index f5b9b87ac9a9e807513686f2b97b96ad48432810..3af847273277785332e994aedc2559db74c1623a 100644 (file)
@@ -281,4 +281,10 @@ int host1x_device_exit(struct host1x_device *device);
 int host1x_client_register(struct host1x_client *client);
 int host1x_client_unregister(struct host1x_client *client);
 
+struct tegra_mipi_device;
+
+struct tegra_mipi_device *tegra_mipi_request(struct device *device);
+void tegra_mipi_free(struct tegra_mipi_device *device);
+int tegra_mipi_calibrate(struct tegra_mipi_device *device);
+
 #endif
index 017fb40f702ae241784b68c0b4aa61b496869491..8f1b086ca5bcc962cbd9d509c4235346c46fefbc 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * i2c-smbus.h - SMBus extensions to the I2C protocol
  *
- * Copyright (C) 2010 Jean Delvare <khali@linux-fr.org>
+ * Copyright (C) 2010 Jean Delvare <jdelvare@suse.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
index d9c8dbd3373f90d298ac66001ccdd13fa6f54ddf..deddeb8c337cff2c67d2b9205065741539dbf97c 100644 (file)
@@ -342,11 +342,25 @@ i2c_register_board_info(int busnum, struct i2c_board_info const *info,
 }
 #endif /* I2C_BOARDINFO */
 
-/*
+/**
+ * struct i2c_algorithm - represent I2C transfer method
+ * @master_xfer: Issue a set of i2c transactions to the given I2C adapter
+ *   defined by the msgs array, with num messages available to transfer via
+ *   the adapter specified by adap.
+ * @smbus_xfer: Issue smbus transactions to the given I2C adapter. If this
+ *   is not present, then the bus layer will try and convert the SMBus calls
+ *   into I2C transfers instead.
+ * @functionality: Return the flags that this algorithm/adapter pair supports
+ *   from the I2C_FUNC_* flags.
+ *
  * The following structs are for those who like to implement new bus drivers:
  * i2c_algorithm is the interface to a class of hardware solutions which can
  * be addressed using the same bus algorithms - i.e. bit-banging or the PCF8584
  * to name two of the most common.
+ *
+ * The return codes from the @master_xfer field should indicate the type of
+ * error code that occured during the transfer, as documented in the kernel
+ * Documentation file Documentation/i2c/fault-codes.
  */
 struct i2c_algorithm {
        /* If an adapter algorithm can't do I2C-level access, set master_xfer
index d380c5e680086ec4627c745f86dc197e7110ea58..2c4bed593b32367559cc2aff89e40b88306bab90 100644 (file)
@@ -288,6 +288,7 @@ struct q_inval {
 
 struct ir_table {
        struct irte *base;
+       unsigned long *bitmap;
 };
 #endif
 
@@ -347,8 +348,6 @@ static inline void __iommu_flush_cache(
 extern struct dmar_drhd_unit * dmar_find_matched_drhd_unit(struct pci_dev *dev);
 extern int dmar_find_matched_atsr_unit(struct pci_dev *dev);
 
-extern int alloc_iommu(struct dmar_drhd_unit *drhd);
-extern void free_iommu(struct intel_iommu *iommu);
 extern int dmar_enable_qi(struct intel_iommu *iommu);
 extern void dmar_disable_qi(struct intel_iommu *iommu);
 extern int dmar_reenable_qi(struct intel_iommu *iommu);
index db43b58a3355c7b97d3acb0902fede4a0883790b..0053adde0ed9a37111ffd273c17f6d19956a6a77 100644 (file)
@@ -360,7 +360,7 @@ enum
 /* map softirq index to softirq name. update 'softirq_to_name' in
  * kernel/softirq.c when adding a new softirq.
  */
-extern char *softirq_to_name[NR_SOFTIRQS];
+extern const char * const softirq_to_name[NR_SOFTIRQS];
 
 /* softirq mask and active fields moved to irq_cpustat_t in
  * asm/hardirq.h to get better cache usage.  KAO
index a444c790fa7235e2bc7247313804a5062d0a4db8..b96a5b2136e46be7fbeec8235c10a918df737ae9 100644 (file)
 #include <linux/types.h>
 #include <trace/events/iommu.h>
 
-#define IOMMU_READ     (1)
-#define IOMMU_WRITE    (2)
-#define IOMMU_CACHE    (4) /* DMA cache coherency */
+#define IOMMU_READ     (1 << 0)
+#define IOMMU_WRITE    (1 << 1)
+#define IOMMU_CACHE    (1 << 2) /* DMA cache coherency */
+#define IOMMU_EXEC     (1 << 3)
 
 struct iommu_ops;
 struct iommu_group;
@@ -247,6 +248,11 @@ static inline struct iommu_domain *iommu_domain_alloc(struct bus_type *bus)
        return NULL;
 }
 
+static inline struct iommu_group *iommu_group_get_by_id(int id)
+{
+       return NULL;
+}
+
 static inline void iommu_domain_free(struct iommu_domain *domain)
 {
 }
@@ -291,8 +297,8 @@ static inline phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_ad
        return 0;
 }
 
-static inline int domain_has_cap(struct iommu_domain *domain,
-                                unsigned long cap)
+static inline int iommu_domain_has_cap(struct iommu_domain *domain,
+                                      unsigned long cap)
 {
        return 0;
 }
index 8d861b2651f7b0586edfa0be89adac92d9592746..9d84942ae2e577835a338b8a352f9c93eabe148b 100644 (file)
@@ -11,7 +11,7 @@
 struct kern_ipc_perm
 {
        spinlock_t      lock;
-       int             deleted;
+       bool            deleted;
        int             id;
        key_t           key;
        kuid_t          uid;
index f6c82de125413e8b6076ab91d68f64771641bfd1..e7831d20373776f5c3dc80c5a04147e8aa611c85 100644 (file)
@@ -21,7 +21,6 @@ struct user_namespace;
 struct ipc_ids {
        int in_use;
        unsigned short seq;
-       unsigned short seq_max;
        struct rw_semaphore rwsem;
        struct idr ipcs_idr;
        int next_id;
index d235e88cfd7c41c9998d094dc24b6f0f46ded937..1f44466c1e9d7b056cbdcd4f7c043018f069fad4 100644 (file)
@@ -294,6 +294,12 @@ extern unsigned long preset_lpj;
  */
 extern unsigned int jiffies_to_msecs(const unsigned long j);
 extern unsigned int jiffies_to_usecs(const unsigned long j);
+
+static inline u64 jiffies_to_nsecs(const unsigned long j)
+{
+       return (u64)jiffies_to_usecs(j) * NSEC_PER_USEC;
+}
+
 extern unsigned long msecs_to_jiffies(const unsigned int m);
 extern unsigned long usecs_to_jiffies(const unsigned int u);
 extern unsigned long timespec_to_jiffies(const struct timespec *value);
index dfb4f2ffdaa2e5eccddb6755f08305ff7a449891..6b06d378f3dfed9b6e2876cdd3eb563d4d7483e9 100644 (file)
@@ -310,7 +310,8 @@ extern int
 kgdb_handle_exception(int ex_vector, int signo, int err_code,
                      struct pt_regs *regs);
 extern int kgdb_nmicallback(int cpu, void *regs);
-extern int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *snd_rdy);
+extern int kgdb_nmicallin(int cpu, int trapnr, void *regs, int err_code,
+                         atomic_t *snd_rdy);
 extern void gdbstub_exit(int status);
 
 extern int                     kgdb_single_step;
index d3e8ad23a8e0238645fe553f8183a2ad74bf5fc3..a6a42dd024661324dbeed5b9cfaa028744bae154 100644 (file)
@@ -6,6 +6,11 @@
 #include <linux/export.h>
 #include <asm/linkage.h>
 
+/* Some toolchains use other characters (e.g. '`') to mark new line in macro */
+#ifndef ASM_NL
+#define ASM_NL          ;
+#endif
+
 #ifdef __cplusplus
 #define CPP_ASMLINKAGE extern "C"
 #else
 
 #ifndef ENTRY
 #define ENTRY(name) \
-  .globl name; \
-  ALIGN; \
-  name:
+       .globl name ASM_NL \
+       ALIGN ASM_NL \
+       name:
 #endif
 #endif /* LINKER_SCRIPT */
 
 #ifndef WEAK
 #define WEAK(name)        \
-       .weak name;        \
+       .weak name ASM_NL   \
        name:
 #endif
 
 #ifndef END
 #define END(name) \
-  .size name, .-name
+       .size name, .-name
 #endif
 
 /* If symbol 'name' is treated as a subroutine (gets called, and returns)
  */
 #ifndef ENDPROC
 #define ENDPROC(name) \
-  .type name, @function; \
-  END(name)
+       .type name, @function ASM_NL \
+       END(name)
 #endif
 
 #endif
index 6156686bf108f38b91fcfb09766f73012dac20ea..ac39d910e70bda7c209d783dc6f01464a836e08a 100644 (file)
@@ -110,9 +110,6 @@ struct mc13xxx_led_platform_data {
        int id;
        const char *name;
        const char *default_trigger;
-
-/* Three or two bits current selection depending on the led */
-       char max_current;
 };
 
 #define MAX_LED_CONTROL_REGS   6
@@ -121,7 +118,7 @@ struct mc13xxx_leds_platform_data {
        struct mc13xxx_led_platform_data *led;
        int num_leds;
 
-/* LED Control 0 */
+/* MC13783 LED Control 0 */
 #define MC13783_LED_C0_ENABLE          (1 << 0)
 #define MC13783_LED_C0_TRIODE_MD       (1 << 7)
 #define MC13783_LED_C0_TRIODE_AD       (1 << 8)
@@ -129,21 +126,43 @@ struct mc13xxx_leds_platform_data {
 #define MC13783_LED_C0_BOOST           (1 << 10)
 #define MC13783_LED_C0_ABMODE(x)       (((x) & 0x7) << 11)
 #define MC13783_LED_C0_ABREF(x)                (((x) & 0x3) << 14)
-/* LED Control 1 */
+/* MC13783 LED Control 1 */
 #define MC13783_LED_C1_TC1HALF         (1 << 18)
 #define MC13783_LED_C1_SLEWLIM         (1 << 23)
-/* LED Control 2 */
+/* MC13783 LED Control 2 */
+#define MC13783_LED_C2_CURRENT_MD(x)   (((x) & 0x7) << 0)
+#define MC13783_LED_C2_CURRENT_AD(x)   (((x) & 0x7) << 3)
+#define MC13783_LED_C2_CURRENT_KP(x)   (((x) & 0x7) << 6)
 #define MC13783_LED_C2_PERIOD(x)       (((x) & 0x3) << 21)
 #define MC13783_LED_C2_SLEWLIM         (1 << 23)
-/* LED Control 3 */
+/* MC13783 LED Control 3 */
+#define MC13783_LED_C3_CURRENT_R1(x)   (((x) & 0x3) << 0)
+#define MC13783_LED_C3_CURRENT_G1(x)   (((x) & 0x3) << 2)
+#define MC13783_LED_C3_CURRENT_B1(x)   (((x) & 0x3) << 4)
 #define MC13783_LED_C3_PERIOD(x)       (((x) & 0x3) << 21)
 #define MC13783_LED_C3_TRIODE_TC1      (1 << 23)
-/* LED Control 4 */
+/* MC13783 LED Control 4 */
+#define MC13783_LED_C4_CURRENT_R2(x)   (((x) & 0x3) << 0)
+#define MC13783_LED_C4_CURRENT_G2(x)   (((x) & 0x3) << 2)
+#define MC13783_LED_C4_CURRENT_B2(x)   (((x) & 0x3) << 4)
 #define MC13783_LED_C4_PERIOD(x)       (((x) & 0x3) << 21)
 #define MC13783_LED_C4_TRIODE_TC2      (1 << 23)
-/* LED Control 5 */
+/* MC13783 LED Control 5 */
+#define MC13783_LED_C5_CURRENT_R3(x)   (((x) & 0x3) << 0)
+#define MC13783_LED_C5_CURRENT_G3(x)   (((x) & 0x3) << 2)
+#define MC13783_LED_C5_CURRENT_B3(x)   (((x) & 0x3) << 4)
 #define MC13783_LED_C5_PERIOD(x)       (((x) & 0x3) << 21)
 #define MC13783_LED_C5_TRIODE_TC3      (1 << 23)
+/* MC13892 LED Control 0 */
+#define MC13892_LED_C0_CURRENT_MD(x)   (((x) & 0x7) << 9)
+#define MC13892_LED_C0_CURRENT_AD(x)   (((x) & 0x7) << 21)
+/* MC13892 LED Control 1 */
+#define MC13892_LED_C1_CURRENT_KP(x)   (((x) & 0x7) << 9)
+/* MC13892 LED Control 2 */
+#define MC13892_LED_C2_CURRENT_R(x)    (((x) & 0x7) << 9)
+#define MC13892_LED_C2_CURRENT_G(x)    (((x) & 0x7) << 21)
+/* MC13892 LED Control 3 */
+#define MC13892_LED_C3_CURRENT_B(x)    (((x) & 0x7) << 9)
        u32 led_control[MAX_LED_CONTROL_REGS];
 };
 
index d9992fc128ca6e8e5ea1f485958191e7e335ea7e..f28f46eade6a642873246fea247f3f5455a18acb 100644 (file)
@@ -1895,7 +1895,7 @@ static inline pgprot_t vm_get_page_prot(unsigned long vm_flags)
 }
 #endif
 
-#ifdef CONFIG_ARCH_USES_NUMA_PROT_NONE
+#ifdef CONFIG_NUMA_BALANCING
 unsigned long change_prot_numa(struct vm_area_struct *vma,
                        unsigned long start, unsigned long end);
 #endif
index e21f9d44307f0004baf0146b4d02a20de6a96466..f3f302f9c1975a67ea1c01a828403950fac8a061 100644 (file)
@@ -9,7 +9,7 @@ struct msg_msg {
        struct list_head m_list;
        long m_type;
        size_t m_ts;            /* message text size */
-       struct msg_msgsegnext;
+       struct msg_msgseg *next;
        void *security;
        /* the actual message follows immediately */
 };
index 68891313875d756a4151aa54847214277e62ba79..628a6a21ddf035063c07051c95b25b24686fb246 100644 (file)
@@ -3,6 +3,6 @@
 
 #include <linux/mtd/mtd.h>
 int mtdram_init_device(struct mtd_info *mtd, void *mapped_address,
-                       unsigned long size, char *name);
+                       unsigned long size, const char *name);
 
 #endif /* __MTD_MTDRAM_H__ */
index 9e6c8f9f306e016923a0c32d3ae0e2d9f0ce0d1f..32f8612469d8d2d2c5a659f9326551bcbbd8806b 100644 (file)
@@ -219,6 +219,9 @@ struct nand_chip;
 /* ONFI feature address */
 #define ONFI_FEATURE_ADDR_TIMING_MODE  0x1
 
+/* Vendor-specific feature address (Micron) */
+#define ONFI_FEATURE_ADDR_READ_RETRY   0x89
+
 /* ONFI subfeature parameters length */
 #define ONFI_SUBFEATURE_PARAM_LEN      4
 
@@ -279,16 +282,17 @@ struct nand_onfi_params {
        __le16 io_pin_capacitance_typ;
        __le16 input_pin_capacitance_typ;
        u8 input_pin_capacitance_max;
-       u8 driver_strenght_support;
+       u8 driver_strength_support;
        __le16 t_int_r;
        __le16 t_ald;
        u8 reserved4[7];
 
        /* vendor */
-       u8 reserved5[90];
+       __le16 vendor_revision;
+       u8 vendor[88];
 
        __le16 crc;
-} __attribute__((packed));
+} __packed;
 
 #define ONFI_CRC_BASE  0x4F4E
 
@@ -326,6 +330,26 @@ struct onfi_ext_param_page {
         */
 } __packed;
 
+struct nand_onfi_vendor_micron {
+       u8 two_plane_read;
+       u8 read_cache;
+       u8 read_unique_id;
+       u8 dq_imped;
+       u8 dq_imped_num_settings;
+       u8 dq_imped_feat_addr;
+       u8 rb_pulldown_strength;
+       u8 rb_pulldown_strength_feat_addr;
+       u8 rb_pulldown_strength_num_settings;
+       u8 otp_mode;
+       u8 otp_page_start;
+       u8 otp_data_prot_addr;
+       u8 otp_num_pages;
+       u8 otp_feat_addr;
+       u8 read_retry_options;
+       u8 reserved[72];
+       u8 param_revision;
+} __packed;
+
 /**
  * struct nand_hw_control - Control structure for hardware controller (e.g ECC generator) shared among independent devices
  * @lock:               protection lock
@@ -432,6 +456,8 @@ struct nand_buffers {
  *                     flash device.
  * @read_byte:         [REPLACEABLE] read one byte from the chip
  * @read_word:         [REPLACEABLE] read one word from the chip
+ * @write_byte:                [REPLACEABLE] write a single byte to the chip on the
+ *                     low 8 I/O lines
  * @write_buf:         [REPLACEABLE] write data from the buffer to the chip
  * @read_buf:          [REPLACEABLE] read data from the chip into the buffer
  * @select_chip:       [REPLACEABLE] select chip nr
@@ -451,6 +477,8 @@ struct nand_buffers {
  *                     commands to the chip.
  * @waitfunc:          [REPLACEABLE] hardwarespecific function for wait on
  *                     ready.
+ * @setup_read_retry:  [FLASHSPECIFIC] flash (vendor) specific function for
+ *                     setting the read-retry mode. Mostly needed for MLC NAND.
  * @ecc:               [BOARDSPECIFIC] ECC control structure
  * @buffers:           buffer structure for read/write
  * @hwcontrol:         platform-specific hardware control structure
@@ -497,6 +525,7 @@ struct nand_buffers {
  *                     non 0 if ONFI supported.
  * @onfi_params:       [INTERN] holds the ONFI page parameter when ONFI is
  *                     supported, 0 otherwise.
+ * @read_retries:      [INTERN] the number of read retry modes supported
  * @onfi_set_features: [REPLACEABLE] set the features for ONFI nand
  * @onfi_get_features: [REPLACEABLE] get the features for ONFI nand
  * @bbt:               [INTERN] bad block table pointer
@@ -521,6 +550,7 @@ struct nand_chip {
 
        uint8_t (*read_byte)(struct mtd_info *mtd);
        u16 (*read_word)(struct mtd_info *mtd);
+       void (*write_byte)(struct mtd_info *mtd, uint8_t byte);
        void (*write_buf)(struct mtd_info *mtd, const uint8_t *buf, int len);
        void (*read_buf)(struct mtd_info *mtd, uint8_t *buf, int len);
        void (*select_chip)(struct mtd_info *mtd, int chip);
@@ -544,6 +574,7 @@ struct nand_chip {
                        int feature_addr, uint8_t *subfeature_para);
        int (*onfi_get_features)(struct mtd_info *mtd, struct nand_chip *chip,
                        int feature_addr, uint8_t *subfeature_para);
+       int (*setup_read_retry)(struct mtd_info *mtd, int retry_mode);
 
        int chip_delay;
        unsigned int options;
@@ -568,6 +599,8 @@ struct nand_chip {
        int onfi_version;
        struct nand_onfi_params onfi_params;
 
+       int read_retries;
+
        flstate_t state;
 
        uint8_t *oob_poi;
@@ -600,6 +633,8 @@ struct nand_chip {
 #define NAND_MFR_AMD           0x01
 #define NAND_MFR_MACRONIX      0xc2
 #define NAND_MFR_EON           0x92
+#define NAND_MFR_SANDISK       0x45
+#define NAND_MFR_INTEL         0x89
 
 /* The maximum expected count of bytes in the NAND ID sequence */
 #define NAND_MAX_ID_LEN 8
index 1f8d24bdafdac2bc28789c777315068311368765..6a35e6de5da174fc7b9f82f67be421f4d74a1cc3 100644 (file)
@@ -37,7 +37,7 @@
  */
 
 struct mtd_partition {
-       char *name;                     /* identifier string */
+       const char *name;               /* identifier string */
        uint64_t size;                  /* partition size */
        uint64_t offset;                /* offset within the master MTD space */
        uint32_t mask_flags;            /* master MTD flags to mask out for this partition */
@@ -76,11 +76,11 @@ struct mtd_part_parser {
                        struct mtd_part_parser_data *);
 };
 
-extern int register_mtd_parser(struct mtd_part_parser *parser);
-extern int deregister_mtd_parser(struct mtd_part_parser *parser);
+extern void register_mtd_parser(struct mtd_part_parser *parser);
+extern void deregister_mtd_parser(struct mtd_part_parser *parser);
 
 int mtd_is_partition(const struct mtd_info *mtd);
-int mtd_add_partition(struct mtd_info *master, char *name,
+int mtd_add_partition(struct mtd_info *master, const char *name,
                      long long offset, long long length);
 int mtd_del_partition(struct mtd_info *master, int partno);
 uint64_t mtd_get_device_size(const struct mtd_info *mtd);
index 48997374eaf04eac0d52b8bf8d60c61c35944df3..0ae5807480f466af6fc9de106b29207bc03f9752 100644 (file)
@@ -154,10 +154,6 @@ struct nfs_inode {
        struct rb_root          access_cache;
        struct list_head        access_cache_entry_lru;
        struct list_head        access_cache_inode_lru;
-#ifdef CONFIG_NFS_V3_ACL
-       struct posix_acl        *acl_access;
-       struct posix_acl        *acl_default;
-#endif
 
        /*
         * This is the cookie verifier used for NFSv3 readdir
@@ -215,6 +211,7 @@ struct nfs_inode {
 #define NFS_INO_ADVISE_RDPLUS  (0)             /* advise readdirplus */
 #define NFS_INO_STALE          (1)             /* possible stale inode */
 #define NFS_INO_ACL_LRU_SET    (2)             /* Inode is on the LRU list */
+#define NFS_INO_INVALIDATING   (3)             /* inode is being invalidated */
 #define NFS_INO_FLUSHING       (4)             /* inode is flushing out data */
 #define NFS_INO_FSCACHE                (5)             /* inode can be cached by FS-Cache */
 #define NFS_INO_FSCACHE_LOCK   (6)             /* FS-Cache cookie management lock */
@@ -564,23 +561,17 @@ extern int  nfs_readpage_async(struct nfs_open_context *, struct inode *,
  * linux/fs/nfs3proc.c
  */
 #ifdef CONFIG_NFS_V3_ACL
-extern struct posix_acl *nfs3_proc_getacl(struct inode *inode, int type);
-extern int nfs3_proc_setacl(struct inode *inode, int type,
-                           struct posix_acl *acl);
-extern int nfs3_proc_set_default_acl(struct inode *dir, struct inode *inode,
-               umode_t mode);
-extern void nfs3_forget_cached_acls(struct inode *inode);
+extern struct posix_acl *nfs3_get_acl(struct inode *inode, int type);
+extern int nfs3_set_acl(struct inode *inode, struct posix_acl *acl, int type);
+extern int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
+               struct posix_acl *dfacl);
+extern const struct xattr_handler *nfs3_xattr_handlers[];
 #else
-static inline int nfs3_proc_set_default_acl(struct inode *dir,
-                                           struct inode *inode,
-                                           umode_t mode)
+static inline int nfs3_proc_setacls(struct inode *inode, struct posix_acl *acl,
+               struct posix_acl *dfacl)
 {
        return 0;
 }
-
-static inline void nfs3_forget_cached_acls(struct inode *inode)
-{
-}
 #endif /* CONFIG_NFS_V3_ACL */
 
 /*
index 5dc635f8d79e09a4a6976c3e536cbfb506b16689..520681b6820817b6f08cb304503bf75b8f8f564f 100644 (file)
@@ -44,11 +44,12 @@ enum utf16_endian {
 };
 
 /* nls_base.c */
-extern int register_nls(struct nls_table *);
+extern int __register_nls(struct nls_table *, struct module *);
 extern int unregister_nls(struct nls_table *);
 extern struct nls_table *load_nls(char *);
 extern void unload_nls(struct nls_table *);
 extern struct nls_table *load_nls_default(void);
+#define register_nls(nls) __register_nls((nls), THIS_MODULE)
 
 extern int utf8_to_utf32(const u8 *s, int len, unicode_t *pu);
 extern int utf32_to_utf8(unicode_t u, u8 *s, int maxlen);
index 0beaee9dac1f1480a51c36ade2004d8b3a69cbce..2b77058a73351dec2842e779d35d04dafaf4c5e1 100644 (file)
@@ -116,6 +116,7 @@ extern const void *of_flat_dt_match_machine(const void *default_match,
 extern void unflatten_device_tree(void);
 extern void unflatten_and_copy_device_tree(void);
 extern void early_init_devtree(void *);
+extern void early_get_first_memblock_info(void *, phys_addr_t *);
 #else /* CONFIG_OF_FLATTREE */
 static inline const char *of_flat_dt_get_machine_name(void) { return NULL; }
 static inline void unflatten_device_tree(void) {}
index 6f10e938ff7e74d4db19b991a55193f5073946e7..cb32d9c1e8dc83502e39143a8c25913bab3193d5 100644 (file)
@@ -7,7 +7,7 @@
  */
 
 #ifndef __LINUX_OF_MTD_H
-#define __LINUX_OF_NET_H
+#define __LINUX_OF_MTD_H
 
 #ifdef CONFIG_OF_MTD
 
index 1900bd0fa639ae7a3c72d1c97a4f0758337c1560..f5cfdd6a5539101a0bc57d7815044f9bca3c11c9 100644 (file)
@@ -4,6 +4,7 @@
 #include <linux/types.h>
 #include <linux/bitops.h>
 #include <linux/init.h>
+#include <linux/sched.h>
 #include <linux/spinlock_types.h>
 #include <linux/wait.h>
 #include <linux/cpumask.h>
@@ -61,7 +62,7 @@ struct percpu_ida {
 /* Max size of percpu freelist, */
 #define IDA_DEFAULT_PCPU_SIZE  ((IDA_DEFAULT_PCPU_BATCH_MOVE * 3) / 2)
 
-int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp);
+int percpu_ida_alloc(struct percpu_ida *pool, int state);
 void percpu_ida_free(struct percpu_ida *pool, unsigned tag);
 
 void percpu_ida_destroy(struct percpu_ida *pool);
index 3a3942823c209163501b1dcd49a550d1664c56da..eabac4e2fc993b114ae940b1be960f04015ade0f 100644 (file)
@@ -43,6 +43,11 @@ struct sdma_script_start_addrs {
        s32 dptc_dvfs_addr;
        s32 utra_addr;
        s32 ram_code_start_addr;
+       /* End of v1 array */
+       s32 mcu_2_ssish_addr;
+       s32 ssish_2_mcu_addr;
+       s32 hdmi_dma_addr;
+       /* End of v2 array */
 };
 
 /**
index beac6b8b6a7b3846cf3925cab343da187fc686e1..bcbc6c3c14c0da82547b861e7108ccee41351f71 100644 (file)
@@ -39,6 +39,7 @@ enum sdma_peripheral_type {
        IMX_DMATYPE_IPU_MEMORY, /* IPU Memory */
        IMX_DMATYPE_ASRC,       /* ASRC */
        IMX_DMATYPE_ESAI,       /* ESAI */
+       IMX_DMATYPE_SSI_DUAL,   /* SSI Dual FIFO */
 };
 
 enum imx_dma_prio {
index 239e0fc1bb1f9af55a1abecaf0a68b01d0faa214..66574ea39f97dc8b22e49d6625e0a5c16292b821 100644 (file)
@@ -1,6 +1,4 @@
 /*
- *  linux/arch/arm/mach-mmp/include/mach/sram.h
- *
  *  SRAM Memory Management
  *
  *  Copyright (c) 2011 Marvell Semiconductors Inc.
@@ -11,8 +9,8 @@
  *
  */
 
-#ifndef __ASM_ARCH_SRAM_H
-#define __ASM_ARCH_SRAM_H
+#ifndef __DMA_MMP_TDMA_H
+#define __DMA_MMP_TDMA_H
 
 #include <linux/genalloc.h>
 
@@ -32,4 +30,4 @@ struct sram_platdata {
 
 extern struct gen_pool *sram_get_gpool(char *pool_name);
 
-#endif /* __ASM_ARCH_SRAM_H */
+#endif /* __DMA_MMP_TDMA_H */
index 8ec18f64e3965e68fcf6ffbfae436687987f3466..92ffd3245f76c67bc2c02a36067a77425338be9f 100644 (file)
@@ -1,11 +1,9 @@
 /*
- * arch/arm/plat-orion/include/plat/mv_xor.h
- *
  * Marvell XOR platform device data definition file.
  */
 
-#ifndef __PLAT_MV_XOR_H
-#define __PLAT_MV_XOR_H
+#ifndef __DMA_MV_XOR_H
+#define __DMA_MV_XOR_H
 
 #include <linux/dmaengine.h>
 #include <linux/mbus.h>
index 24b536ebdf13de364c5c5bf0f0106d654eb94d31..d2be19a51acde32102710cdf0db536fe4d364f01 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * arch/arm/mach-kirkwood/include/mach/leds-netxbig.h
- *
  * Platform data structure for netxbig LED driver
  *
  * This file is licensed under the terms of the GNU General Public
@@ -8,8 +6,8 @@
  * warranty of any kind, whether express or implied.
  */
 
-#ifndef __MACH_LEDS_NETXBIG_H
-#define __MACH_LEDS_NETXBIG_H
+#ifndef __LEDS_KIRKWOOD_NETXBIG_H
+#define __LEDS_KIRKWOOD_NETXBIG_H
 
 struct netxbig_gpio_ext {
        unsigned        *addr;
@@ -52,4 +50,4 @@ struct netxbig_led_platform_data {
        int                     num_leds;
 };
 
-#endif /* __MACH_LEDS_NETXBIG_H */
+#endif /* __LEDS_KIRKWOOD_NETXBIG_H */
index e21272e5f66847112a7805ed90730e0eca612b42..6a9fed57f34620c20a931f317150e5a381058e8f 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * arch/arm/mach-kirkwood/include/mach/leds-ns2.h
- *
  * Platform data structure for Network Space v2 LED driver
  *
  * This file is licensed under the terms of the GNU General Public
@@ -8,8 +6,8 @@
  * warranty of any kind, whether express or implied.
  */
 
-#ifndef __MACH_LEDS_NS2_H
-#define __MACH_LEDS_NS2_H
+#ifndef __LEDS_KIRKWOOD_NS2_H
+#define __LEDS_KIRKWOOD_NS2_H
 
 struct ns2_led {
        const char      *name;
@@ -23,4 +21,4 @@ struct ns2_led_platform_data {
        struct ns2_led  *leds;
 };
 
-#endif /* __MACH_LEDS_NS2_H */
+#endif /* __LEDS_KIRKWOOD_NS2_H */
index 4da5bfa2147f245ab980c3a1514647ef40eecf4b..3e9dd6676b9799aba4999d422a624f9a3a991b44 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * arch/arm/plat-omap/include/mach/nand.h
- *
  * Copyright (C) 2006 Micron Technology Inc.
  *
  * This program is free software; you can redistribute it and/or modify
index ffb801998e5dfa10c450f99b2dbb943e8f7a05d4..a941471249299c842a7cfea12de9a4091d2e44e2 100644 (file)
@@ -55,6 +55,9 @@ struct pxa3xx_nand_platform_data {
        /* indicate how many chip selects will be used */
        int     num_cs;
 
+       /* use an flash-based bad block table */
+       bool    flash_bbt;
+
        const struct mtd_partition              *parts[NUM_CHIP_SELECT];
        unsigned int                            nr_parts[NUM_CHIP_SELECT];
 
index e9a9fb188f972555172349a8e0250ac237c7db5d..56ff0e6f5ad1dae5bfe9d774a71cb85a32856afa 100644 (file)
@@ -1,6 +1,4 @@
 /*
- * arch/arm/plat-omap/include/mach/onenand.h
- *
  * Copyright (C) 2006 Nokia Corporation
  * Author: Juha Yrjola
  *
index 9f3c180834d141a269f7c4ec84c8021532029c9c..a7ce77c7c1a8e5d5d7009e9122c1684fa3b70d95 100644 (file)
@@ -1,13 +1,11 @@
 /*
- * arch/arm/plat-orion/include/plat/orion_nand.h
- *
  * This file is licensed under the terms of the GNU General Public
  * License version 2.  This program is licensed "as is" without any
  * warranty of any kind, whether express or implied.
  */
 
-#ifndef __PLAT_ORION_NAND_H
-#define __PLAT_ORION_NAND_H
+#ifndef __MTD_ORION_NAND_H
+#define __MTD_ORION_NAND_H
 
 /*
  * Device bus NAND private data
index 54334393ab926ada9935fa5aba6e1a3756b27a88..a947ab8b441ad968f0953e6ce15d03270325e55b 100644 (file)
@@ -7,20 +7,6 @@
 
 struct clk;
 
-/**
- * enum si5351_variant - SiLabs Si5351 chip variant
- * @SI5351_VARIANT_A: Si5351A (8 output clocks, XTAL input)
- * @SI5351_VARIANT_A3: Si5351A MSOP10 (3 output clocks, XTAL input)
- * @SI5351_VARIANT_B: Si5351B (8 output clocks, XTAL/VXCO input)
- * @SI5351_VARIANT_C: Si5351C (8 output clocks, XTAL/CLKIN input)
- */
-enum si5351_variant {
-       SI5351_VARIANT_A = 1,
-       SI5351_VARIANT_A3 = 2,
-       SI5351_VARIANT_B = 3,
-       SI5351_VARIANT_C = 4,
-};
-
 /**
  * enum si5351_pll_src - Si5351 pll clock source
  * @SI5351_PLL_SRC_DEFAULT: default, do not change eeprom config
@@ -115,14 +101,12 @@ struct si5351_clkout_config {
 
 /**
  * struct si5351_platform_data - Platform data for the Si5351 clock driver
- * @variant: Si5351 chip variant
  * @clk_xtal: xtal input clock
  * @clk_clkin: clkin input clock
  * @pll_src: array of pll source clock setting
  * @clkout: array of clkout configuration
  */
 struct si5351_platform_data {
-       enum si5351_variant variant;
        struct clk *clk_xtal;
        struct clk *clk_clkin;
        enum si5351_pll_src pll_src[2];
index a73a456d7f1195cd70f632848b658ac139342cef..63170e2614b341e9468b3396ebcb740f1b370e21 100644 (file)
@@ -14,6 +14,8 @@
 #define __PLATFORM_VSP1_H__
 
 #define VSP1_HAS_LIF           (1 << 0)
+#define VSP1_HAS_LUT           (1 << 1)
+#define VSP1_HAS_SRU           (1 << 2)
 
 struct vsp1_platform_data {
        unsigned int features;
index 833099bf8090a24f5be28f6b074c918d5d677119..3e96a6a7610338ff8ddd825a21ddc9bc5fe52e8b 100644 (file)
@@ -85,12 +85,20 @@ extern int posix_acl_valid(const struct posix_acl *);
 extern int posix_acl_permission(struct inode *, const struct posix_acl *, int);
 extern struct posix_acl *posix_acl_from_mode(umode_t, gfp_t);
 extern int posix_acl_equiv_mode(const struct posix_acl *, umode_t *);
-extern int posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
-extern int posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
+extern int __posix_acl_create(struct posix_acl **, gfp_t, umode_t *);
+extern int __posix_acl_chmod(struct posix_acl **, gfp_t, umode_t);
 
 extern struct posix_acl *get_posix_acl(struct inode *, int);
 extern int set_posix_acl(struct inode *, int, struct posix_acl *);
 
+#ifdef CONFIG_FS_POSIX_ACL
+extern int posix_acl_chmod(struct inode *, umode_t);
+extern int posix_acl_create(struct inode *, umode_t *, struct posix_acl **,
+               struct posix_acl **);
+
+extern int simple_set_acl(struct inode *, struct posix_acl *, int);
+extern int simple_acl_create(struct inode *, struct inode *);
+
 struct posix_acl **acl_by_type(struct inode *inode, int type);
 struct posix_acl *get_cached_acl(struct inode *inode, int type);
 struct posix_acl *get_cached_acl_rcu(struct inode *inode, int type);
@@ -100,10 +108,37 @@ void forget_all_cached_acls(struct inode *inode);
 
 static inline void cache_no_acl(struct inode *inode)
 {
-#ifdef CONFIG_FS_POSIX_ACL
        inode->i_acl = NULL;
        inode->i_default_acl = NULL;
-#endif
 }
+#else
+static inline int posix_acl_chmod(struct inode *inode, umode_t mode)
+{
+       return 0;
+}
+
+#define simple_set_acl         NULL
+
+static inline int simple_acl_create(struct inode *dir, struct inode *inode)
+{
+       return 0;
+}
+static inline void cache_no_acl(struct inode *inode)
+{
+}
+
+static inline int posix_acl_create(struct inode *inode, umode_t *mode,
+               struct posix_acl **default_acl, struct posix_acl **acl)
+{
+       *default_acl = *acl = NULL;
+       return 0;
+}
+
+static inline void forget_all_cached_acls(struct inode *inode)
+{
+}
+#endif /* CONFIG_FS_POSIX_ACL */
+
+struct posix_acl *get_acl(struct inode *inode, int type);
 
 #endif  /* __LINUX_POSIX_ACL_H */
index ad93ad0f1db0b0afe072d587a6fd1507f2e35d84..6f14ee2958220b03afcb8c41a8fc2cdcad9ea940 100644 (file)
@@ -69,4 +69,7 @@ struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns,
 int posix_acl_to_xattr(struct user_namespace *user_ns,
                       const struct posix_acl *acl, void *buffer, size_t size);
 
+extern const struct xattr_handler posix_acl_access_xattr_handler;
+extern const struct xattr_handler posix_acl_default_xattr_handler;
+
 #endif /* _POSIX_ACL_XATTR_H */
index 3e355c688618e66391d535de3e183bf9c9ec8cba..72bf3a01a4ee67ac8908212c3de3897d383a2161 100644 (file)
@@ -449,8 +449,6 @@ static inline int rcu_read_lock_sched_held(void)
 
 #ifdef CONFIG_PROVE_RCU
 
-int rcu_my_thread_group_empty(void);
-
 /**
  * rcu_lockdep_assert - emit lockdep splat if specified condition not met
  * @c: condition to check
index 0616ffe45702f0c28fd20390ec9b8574c543032b..03f3b05e8ec17dda4d7b8dcefcc1e723bc6e606c 100644 (file)
@@ -74,6 +74,17 @@ do {                                                         \
        __init_rwsem((sem), #sem, &__key);                      \
 } while (0)
 
+/*
+ * This is the same regardless of which rwsem implementation that is being used.
+ * It is just a heuristic meant to be called by somebody alreadying holding the
+ * rwsem to see if somebody from an incompatible type is wanting access to the
+ * lock.
+ */
+static inline int rwsem_is_contended(struct rw_semaphore *sem)
+{
+       return !list_empty(&sem->wait_list);
+}
+
 /*
  * lock for reading
  */
index b13cf430764f76cc4053f1c935e1e417a32188a1..8045a554cafb87074a29ab7e73f9255681744bf5 100644 (file)
@@ -5,7 +5,7 @@
 extern int          sysctl_hung_task_check_count;
 extern unsigned int  sysctl_hung_task_panic;
 extern unsigned long sysctl_hung_task_timeout_secs;
-extern unsigned long sysctl_hung_task_warnings;
+extern int sysctl_hung_task_warnings;
 extern int proc_dohung_task_timeout_secs(struct ctl_table *table, int write,
                                         void __user *buffer,
                                         size_t *lenp, loff_t *ppos);
diff --git a/include/linux/serial_bcm63xx.h b/include/linux/serial_bcm63xx.h
new file mode 100644 (file)
index 0000000..570e964
--- /dev/null
@@ -0,0 +1,119 @@
+#ifndef _LINUX_SERIAL_BCM63XX_H
+#define _LINUX_SERIAL_BCM63XX_H
+
+/* UART Control Register */
+#define UART_CTL_REG                   0x0
+#define UART_CTL_RXTMOUTCNT_SHIFT      0
+#define UART_CTL_RXTMOUTCNT_MASK       (0x1f << UART_CTL_RXTMOUTCNT_SHIFT)
+#define UART_CTL_RSTTXDN_SHIFT         5
+#define UART_CTL_RSTTXDN_MASK          (1 << UART_CTL_RSTTXDN_SHIFT)
+#define UART_CTL_RSTRXFIFO_SHIFT               6
+#define UART_CTL_RSTRXFIFO_MASK                (1 << UART_CTL_RSTRXFIFO_SHIFT)
+#define UART_CTL_RSTTXFIFO_SHIFT               7
+#define UART_CTL_RSTTXFIFO_MASK                (1 << UART_CTL_RSTTXFIFO_SHIFT)
+#define UART_CTL_STOPBITS_SHIFT                8
+#define UART_CTL_STOPBITS_MASK         (0xf << UART_CTL_STOPBITS_SHIFT)
+#define UART_CTL_STOPBITS_1            (0x7 << UART_CTL_STOPBITS_SHIFT)
+#define UART_CTL_STOPBITS_2            (0xf << UART_CTL_STOPBITS_SHIFT)
+#define UART_CTL_BITSPERSYM_SHIFT      12
+#define UART_CTL_BITSPERSYM_MASK       (0x3 << UART_CTL_BITSPERSYM_SHIFT)
+#define UART_CTL_XMITBRK_SHIFT         14
+#define UART_CTL_XMITBRK_MASK          (1 << UART_CTL_XMITBRK_SHIFT)
+#define UART_CTL_RSVD_SHIFT            15
+#define UART_CTL_RSVD_MASK             (1 << UART_CTL_RSVD_SHIFT)
+#define UART_CTL_RXPAREVEN_SHIFT               16
+#define UART_CTL_RXPAREVEN_MASK                (1 << UART_CTL_RXPAREVEN_SHIFT)
+#define UART_CTL_RXPAREN_SHIFT         17
+#define UART_CTL_RXPAREN_MASK          (1 << UART_CTL_RXPAREN_SHIFT)
+#define UART_CTL_TXPAREVEN_SHIFT               18
+#define UART_CTL_TXPAREVEN_MASK                (1 << UART_CTL_TXPAREVEN_SHIFT)
+#define UART_CTL_TXPAREN_SHIFT         18
+#define UART_CTL_TXPAREN_MASK          (1 << UART_CTL_TXPAREN_SHIFT)
+#define UART_CTL_LOOPBACK_SHIFT                20
+#define UART_CTL_LOOPBACK_MASK         (1 << UART_CTL_LOOPBACK_SHIFT)
+#define UART_CTL_RXEN_SHIFT            21
+#define UART_CTL_RXEN_MASK             (1 << UART_CTL_RXEN_SHIFT)
+#define UART_CTL_TXEN_SHIFT            22
+#define UART_CTL_TXEN_MASK             (1 << UART_CTL_TXEN_SHIFT)
+#define UART_CTL_BRGEN_SHIFT           23
+#define UART_CTL_BRGEN_MASK            (1 << UART_CTL_BRGEN_SHIFT)
+
+/* UART Baudword register */
+#define UART_BAUD_REG                  0x4
+
+/* UART Misc Control register */
+#define UART_MCTL_REG                  0x8
+#define UART_MCTL_DTR_SHIFT            0
+#define UART_MCTL_DTR_MASK             (1 << UART_MCTL_DTR_SHIFT)
+#define UART_MCTL_RTS_SHIFT            1
+#define UART_MCTL_RTS_MASK             (1 << UART_MCTL_RTS_SHIFT)
+#define UART_MCTL_RXFIFOTHRESH_SHIFT   8
+#define UART_MCTL_RXFIFOTHRESH_MASK    (0xf << UART_MCTL_RXFIFOTHRESH_SHIFT)
+#define UART_MCTL_TXFIFOTHRESH_SHIFT   12
+#define UART_MCTL_TXFIFOTHRESH_MASK    (0xf << UART_MCTL_TXFIFOTHRESH_SHIFT)
+#define UART_MCTL_RXFIFOFILL_SHIFT     16
+#define UART_MCTL_RXFIFOFILL_MASK      (0x1f << UART_MCTL_RXFIFOFILL_SHIFT)
+#define UART_MCTL_TXFIFOFILL_SHIFT     24
+#define UART_MCTL_TXFIFOFILL_MASK      (0x1f << UART_MCTL_TXFIFOFILL_SHIFT)
+
+/* UART External Input Configuration register */
+#define UART_EXTINP_REG                        0xc
+#define UART_EXTINP_RI_SHIFT           0
+#define UART_EXTINP_RI_MASK            (1 << UART_EXTINP_RI_SHIFT)
+#define UART_EXTINP_CTS_SHIFT          1
+#define UART_EXTINP_CTS_MASK           (1 << UART_EXTINP_CTS_SHIFT)
+#define UART_EXTINP_DCD_SHIFT          2
+#define UART_EXTINP_DCD_MASK           (1 << UART_EXTINP_DCD_SHIFT)
+#define UART_EXTINP_DSR_SHIFT          3
+#define UART_EXTINP_DSR_MASK           (1 << UART_EXTINP_DSR_SHIFT)
+#define UART_EXTINP_IRSTAT(x)          (1 << (x + 4))
+#define UART_EXTINP_IRMASK(x)          (1 << (x + 8))
+#define UART_EXTINP_IR_RI              0
+#define UART_EXTINP_IR_CTS             1
+#define UART_EXTINP_IR_DCD             2
+#define UART_EXTINP_IR_DSR             3
+#define UART_EXTINP_RI_NOSENSE_SHIFT   16
+#define UART_EXTINP_RI_NOSENSE_MASK    (1 << UART_EXTINP_RI_NOSENSE_SHIFT)
+#define UART_EXTINP_CTS_NOSENSE_SHIFT  17
+#define UART_EXTINP_CTS_NOSENSE_MASK   (1 << UART_EXTINP_CTS_NOSENSE_SHIFT)
+#define UART_EXTINP_DCD_NOSENSE_SHIFT  18
+#define UART_EXTINP_DCD_NOSENSE_MASK   (1 << UART_EXTINP_DCD_NOSENSE_SHIFT)
+#define UART_EXTINP_DSR_NOSENSE_SHIFT  19
+#define UART_EXTINP_DSR_NOSENSE_MASK   (1 << UART_EXTINP_DSR_NOSENSE_SHIFT)
+
+/* UART Interrupt register */
+#define UART_IR_REG                    0x10
+#define UART_IR_MASK(x)                        (1 << (x + 16))
+#define UART_IR_STAT(x)                        (1 << (x))
+#define UART_IR_EXTIP                  0
+#define UART_IR_TXUNDER                        1
+#define UART_IR_TXOVER                 2
+#define UART_IR_TXTRESH                        3
+#define UART_IR_TXRDLATCH              4
+#define UART_IR_TXEMPTY                        5
+#define UART_IR_RXUNDER                        6
+#define UART_IR_RXOVER                 7
+#define UART_IR_RXTIMEOUT              8
+#define UART_IR_RXFULL                 9
+#define UART_IR_RXTHRESH               10
+#define UART_IR_RXNOTEMPTY             11
+#define UART_IR_RXFRAMEERR             12
+#define UART_IR_RXPARERR               13
+#define UART_IR_RXBRK                  14
+#define UART_IR_TXDONE                 15
+
+/* UART Fifo register */
+#define UART_FIFO_REG                  0x14
+#define UART_FIFO_VALID_SHIFT          0
+#define UART_FIFO_VALID_MASK           0xff
+#define UART_FIFO_FRAMEERR_SHIFT       8
+#define UART_FIFO_FRAMEERR_MASK                (1 << UART_FIFO_FRAMEERR_SHIFT)
+#define UART_FIFO_PARERR_SHIFT         9
+#define UART_FIFO_PARERR_MASK          (1 << UART_FIFO_PARERR_SHIFT)
+#define UART_FIFO_BRKDET_SHIFT         10
+#define UART_FIFO_BRKDET_MASK          (1 << UART_FIFO_BRKDET_SHIFT)
+#define UART_FIFO_ANYERR_MASK          (UART_FIFO_FRAMEERR_MASK |      \
+                                       UART_FIFO_PARERR_MASK |         \
+                                       UART_FIFO_BRKDET_MASK)
+
+#endif /* _LINUX_SERIAL_BCM63XX_H */
index 429c1995d756634f82906af0ad532d5423ec7622..1e2cd2e6b5407956ab9a70f815a5a521da5ffea2 100644 (file)
@@ -9,7 +9,7 @@
 struct shmid_kernel /* private to the kernel */
 {      
        struct kern_ipc_perm    shm_perm;
-       struct file *           shm_file;
+       struct file             *shm_file;
        unsigned long           shm_nattch;
        unsigned long           shm_segsz;
        time_t                  shm_atim;
index 1f689e62e4cbe58dac7a67e990009bf95e35e99c..f589c9af8cbf1250da1945bac436f27d92987e80 100644 (file)
@@ -2456,6 +2456,7 @@ void skb_zerocopy(struct sk_buff *to, const struct sk_buff *from,
 void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len);
 int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
 void skb_scrub_packet(struct sk_buff *skb, bool xnet);
+unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
 struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
 
 struct skb_checksum_ops {
index 5da22ee42e1635d35c5e70aa16e064af64e696b1..3834f43f9993183cf180d1639d1d9d02c3b2721c 100644 (file)
 #include <linux/list.h>
 #include <linux/cpumask.h>
 #include <linux/init.h>
+#include <linux/llist.h>
 
 extern void cpu_idle(void);
 
 typedef void (*smp_call_func_t)(void *info);
 struct call_single_data {
-       struct list_head list;
+       union {
+               struct list_head list;
+               struct llist_node llist;
+       };
        smp_call_func_t func;
        void *info;
        u16 flags;
index 74575cbf2d6f579c317fec5f1f16e9d3793fab03..0e43906d2fda6dc68cffc6343594178465d6e461 100644 (file)
@@ -24,7 +24,8 @@
  * Passed to the actors
  */
 struct splice_desc {
-       unsigned int len, total_len;    /* current and remaining length */
+       size_t total_len;               /* remaining length */
+       unsigned int len;               /* current length */
        unsigned int flags;             /* splice flags */
        /*
         * actor() private data
index c64999fd1660093c5719fdd93c60ba4c6545c701..07ef9b82b66da9088f0a8811d21d14d8f0b66db2 100644 (file)
@@ -486,6 +486,7 @@ struct ssb_bus {
 #endif /* EMBEDDED */
 #ifdef CONFIG_SSB_DRIVER_GPIO
        struct gpio_chip gpio;
+       struct irq_domain *irq_domain;
 #endif /* DRIVER_GPIO */
 
        /* Internal-only stuff follows. Do not touch. */
index a353e0300b54b97a63cf4b87baf28cacf91428b8..7f490bef9e99f9838294bbb674e3014a7128185b 100644 (file)
@@ -84,7 +84,8 @@ enum {
 
 extern struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
                                      const unsigned char *dir_name);
-extern void rpc_pipefs_init_net(struct net *net);
+extern int rpc_pipefs_init_net(struct net *net);
+extern void rpc_pipefs_exit_net(struct net *net);
 extern struct super_block *rpc_get_sb_net(const struct net *net);
 extern void rpc_put_sb_net(const struct net *net);
 
@@ -130,5 +131,7 @@ extern int rpc_unlink(struct dentry *);
 extern int register_rpc_pipefs(void);
 extern void unregister_rpc_pipefs(void);
 
+extern bool gssd_running(struct net *net);
+
 #endif
 #endif
index 6eecfc2e4f989b8e9511719cee900f75e057850c..04e76322124634af03ec734996184a5b76b5e528 100644 (file)
@@ -368,7 +368,7 @@ struct svc_program {
        struct svc_program *    pg_next;        /* other programs (same xprt) */
        u32                     pg_prog;        /* program number */
        unsigned int            pg_lovers;      /* lowest version */
-       unsigned int            pg_hivers;      /* lowest version */
+       unsigned int            pg_hivers;      /* highest version */
        unsigned int            pg_nvers;       /* number of versions */
        struct svc_version **   pg_vers;        /* version array */
        char *                  pg_name;        /* service name */
@@ -386,8 +386,10 @@ struct svc_version {
        struct svc_procedure *  vs_proc;        /* per-procedure info */
        u32                     vs_xdrsize;     /* xdrsize needed for this version */
 
-       unsigned int            vs_hidden : 1;  /* Don't register with portmapper.
+       unsigned int            vs_hidden : 1,  /* Don't register with portmapper.
                                                 * Only used for nfsacl so far. */
+                               vs_rpcb_optnl:1;/* Don't care the result of register.
+                                                * Only used for nfsv4. */
 
        /* Override dispatch function (e.g. when caching replies).
         * A return value of 0 means drop the request. 
index 0175d8663b6cbd9cb259b5715436fbd09e0ce213..b84773cb9f4c1f3fc480a460ba3c37a2121e1557 100644 (file)
@@ -104,7 +104,7 @@ extern struct cpumask *tick_get_broadcast_oneshot_mask(void);
 extern void tick_clock_notify(void);
 extern int tick_check_oneshot_change(int allow_nohz);
 extern struct tick_sched *tick_get_tick_sched(int cpu);
-extern void tick_check_idle(void);
+extern void tick_irq_enter(void);
 extern int tick_oneshot_mode_active(void);
 #  ifndef arch_needs_cpu
 #   define arch_needs_cpu(cpu) (0)
@@ -112,7 +112,7 @@ extern int tick_oneshot_mode_active(void);
 # else
 static inline void tick_clock_notify(void) { }
 static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
-static inline void tick_check_idle(void) { }
+static inline void tick_irq_enter(void) { }
 static inline int tick_oneshot_mode_active(void) { return 0; }
 # endif
 
@@ -121,7 +121,7 @@ static inline void tick_init(void) { }
 static inline void tick_cancel_sched_timer(int cpu) { }
 static inline void tick_clock_notify(void) { }
 static inline int tick_check_oneshot_change(int allow_nohz) { return 0; }
-static inline void tick_check_idle(void) { }
+static inline void tick_irq_enter(void) { }
 static inline int tick_oneshot_mode_active(void) { return 0; }
 #endif /* !CONFIG_GENERIC_CLOCKEVENTS */
 
index e4b948080d20e7a537c7a83da17b8b5b7fec0008..a67b384157689ec9fda2abfec0173122fc98a4a8 100644 (file)
@@ -142,8 +142,6 @@ static inline unsigned long zone_page_state_snapshot(struct zone *zone,
        return x;
 }
 
-extern unsigned long global_reclaimable_pages(void);
-
 #ifdef CONFIG_NUMA
 /*
  * Determine the per node value of a stat item. This function
similarity index 97%
rename from drivers/staging/zsmalloc/zsmalloc.h
rename to include/linux/zsmalloc.h
index c2eb174b97eef7cf74045be9c6cdf0ac779564ee..e44d634e7fb79bbe55da8153828be1b81e20d722 100644 (file)
@@ -2,6 +2,7 @@
  * zsmalloc memory allocator
  *
  * Copyright (C) 2011  Nitin Gupta
+ * Copyright (C) 2012, 2013 Minchan Kim
  *
  * This code is released using a dual license strategy: BSD/GPL
  * You can choose the license that better fits your requirements.
index 9696a5e2c437f3e33dc8f4d2bd50f8ff8bff6a53..6bdf8c61d221f7267914974958f96f2cc2156460 100644 (file)
@@ -685,7 +685,7 @@ do {                                                                        \
            else                                                                \
              {                                                                 \
                r = 0;                                                          \
-               if (X##_s)                                                      \
+               if (!X##_s)                                                     \
                  r = ~r;                                                       \
              }                                                                 \
            FP_SET_EXCEPTION(FP_EX_INVALID);                                    \
@@ -743,12 +743,17 @@ do {                                                                      \
          }                                                                     \
        else                                                                    \
          {                                                                     \
+           int _lz0, _lz1;                                                     \
            if (X##_e <= -_FP_WORKBITS - 1)                                     \
              _FP_FRAC_SET_##wc(X, _FP_MINFRAC_##wc);                           \
            else                                                                \
              _FP_FRAC_SRS_##wc(X, _FP_FRACBITS_##fs - 1 - X##_e,               \
                                _FP_WFRACBITS_##fs);                            \
+           _FP_FRAC_CLZ_##wc(_lz0, X);                                         \
            _FP_ROUND(wc, X);                                                   \
+           _FP_FRAC_CLZ_##wc(_lz1, X);                                         \
+           if (_lz1 < _lz0)                                                    \
+             X##_e++; /* For overflow detection.  */                           \
            _FP_FRAC_SRL_##wc(X, _FP_WORKBITS);                                 \
            _FP_FRAC_ASSEMBLE_##wc(r, X, rsize);                                \
          }                                                                     \
@@ -762,7 +767,7 @@ do {                                                                        \
            if (!rsigned)                                                       \
              {                                                                 \
                r = 0;                                                          \
-               if (X##_s)                                                      \
+               if (!X##_s)                                                     \
                  r = ~r;                                                       \
              }                                                                 \
            else if (rsigned != 2)                                              \
index dc004bc926c92154729fd89b9c88a1a93d579092..d262a3a922bdd4f0cd0dbf4eaf3e1d3c1769f3b2 100644 (file)
@@ -78,11 +78,14 @@ enum adv7604_op_format_sel {
        ADV7604_OP_FORMAT_SEL_SDR_ITU656_24_MODE2 = 0x8a,
 };
 
+enum adv7604_drive_strength {
+       ADV7604_DR_STR_MEDIUM_LOW = 1,
+       ADV7604_DR_STR_MEDIUM_HIGH = 2,
+       ADV7604_DR_STR_HIGH = 3,
+};
+
 /* Platform dependent definition */
 struct adv7604_platform_data {
-       /* connector - HDMI or DVI? */
-       unsigned connector_hdmi:1;
-
        /* DIS_PWRDNB: 1 if the PWRDNB pin is unused and unconnected */
        unsigned disable_pwrdnb:1;
 
@@ -110,6 +113,15 @@ struct adv7604_platform_data {
        unsigned replicate_av_codes:1;
        unsigned invert_cbcr:1;
 
+       /* IO register 0x06 */
+       unsigned inv_vs_pol:1;
+       unsigned inv_hs_pol:1;
+
+       /* IO register 0x14 */
+       enum adv7604_drive_strength dr_str_data;
+       enum adv7604_drive_strength dr_str_clk;
+       enum adv7604_drive_strength dr_str_sync;
+
        /* IO register 0x30 */
        unsigned output_bus_lsb_to_msb:1;
 
@@ -131,16 +143,20 @@ struct adv7604_platform_data {
        u8 i2c_vdp;
 };
 
-/*
- * Mode of operation.
- * This is used as the input argument of the s_routing video op.
- */
-enum adv7604_mode {
-       ADV7604_MODE_COMP,
-       ADV7604_MODE_GR,
-       ADV7604_MODE_HDMI,
+enum adv7604_input_port {
+       ADV7604_INPUT_HDMI_PORT_A,
+       ADV7604_INPUT_HDMI_PORT_B,
+       ADV7604_INPUT_HDMI_PORT_C,
+       ADV7604_INPUT_HDMI_PORT_D,
+       ADV7604_INPUT_VGA_RGB,
+       ADV7604_INPUT_VGA_COMP,
 };
 
+#define ADV7604_EDID_PORT_A 0
+#define ADV7604_EDID_PORT_B 1
+#define ADV7604_EDID_PORT_C 2
+#define ADV7604_EDID_PORT_D 3
+
 #define V4L2_CID_ADV_RX_ANALOG_SAMPLING_PHASE  (V4L2_CID_DV_CLASS_BASE + 0x1000)
 #define V4L2_CID_ADV_RX_FREE_RUN_COLOR_MANUAL  (V4L2_CID_DV_CLASS_BASE + 0x1001)
 #define V4L2_CID_ADV_RX_FREE_RUN_COLOR         (V4L2_CID_DV_CLASS_BASE + 0x1002)
index c02201d1c0923b6d11ecf28258971c9b52c10d9d..39322091e8b0dc6355ced09aad7cb56a08588157 100644 (file)
@@ -108,6 +108,13 @@ enum adv7842_select_input {
        ADV7842_SELECT_SDP_YC,
 };
 
+enum adv7842_drive_strength {
+       ADV7842_DR_STR_LOW = 0,
+       ADV7842_DR_STR_MEDIUM_LOW = 1,
+       ADV7842_DR_STR_MEDIUM_HIGH = 2,
+       ADV7842_DR_STR_HIGH = 3,
+};
+
 struct adv7842_sdp_csc_coeff {
        bool manual;
        uint16_t scaling;
@@ -131,13 +138,18 @@ struct adv7842_sdp_io_sync_adjustment {
        uint16_t hs_width;
        uint16_t de_beg;
        uint16_t de_end;
+       uint8_t vs_beg_o;
+       uint8_t vs_beg_e;
+       uint8_t vs_end_o;
+       uint8_t vs_end_e;
+       uint8_t de_v_beg_o;
+       uint8_t de_v_beg_e;
+       uint8_t de_v_end_o;
+       uint8_t de_v_end_e;
 };
 
 /* Platform dependent definition */
 struct adv7842_platform_data {
-       /* connector - HDMI or DVI? */
-       unsigned connector_hdmi:1;
-
        /* chip reset during probe */
        unsigned chip_reset:1;
 
@@ -156,12 +168,12 @@ struct adv7842_platform_data {
        /* Default mode */
        enum adv7842_mode mode;
 
+       /* Default input */
+       unsigned input;
+
        /* Video standard */
        enum adv7842_vid_std_select vid_std_select;
 
-       /* Input Color Space */
-       enum adv7842_inp_color_space inp_color_space;
-
        /* Select output format */
        enum adv7842_op_format_sel op_format_sel;
 
@@ -181,22 +193,37 @@ struct adv7842_platform_data {
        unsigned output_bus_lsb_to_msb:1;
 
        /* IO register 0x14 */
-       struct {
-               unsigned data:2;
-               unsigned clock:2;
-               unsigned sync:2;
-       } drive_strength;
+       enum adv7842_drive_strength dr_str_data;
+       enum adv7842_drive_strength dr_str_clk;
+       enum adv7842_drive_strength dr_str_sync;
+
+       /*
+        * IO register 0x19: Adjustment to the LLC DLL phase in
+        * increments of 1/32 of a clock period.
+        */
+       unsigned llc_dll_phase:5;
 
        /* External RAM for 3-D comb or frame synchronizer */
        unsigned sd_ram_size; /* ram size in MB */
        unsigned sd_ram_ddr:1; /* ddr or sdr sdram */
 
-       /* Free run */
-       unsigned hdmi_free_run_mode;
+       /* HDMI free run, CP-reg 0xBA */
+       unsigned hdmi_free_run_enable:1;
+       /* 0 = Mode 0: run when there is no TMDS clock
+          1 = Mode 1: run when there is no TMDS clock or the
+              video resolution does not match programmed one. */
+       unsigned hdmi_free_run_mode:1;
+
+       /* SDP free run, CP-reg 0xDD */
+       unsigned sdp_free_run_auto:1;
+       unsigned sdp_free_run_man_col_en:1;
+       unsigned sdp_free_run_cbar_en:1;
+       unsigned sdp_free_run_force:1;
 
        struct adv7842_sdp_csc_coeff sdp_csc_coeff;
 
-       struct adv7842_sdp_io_sync_adjustment sdp_io_sync;
+       struct adv7842_sdp_io_sync_adjustment sdp_io_sync_625;
+       struct adv7842_sdp_io_sync_adjustment sdp_io_sync_525;
 
        /* i2c addresses */
        u8 i2c_sdp_io;
@@ -223,4 +250,8 @@ struct adv7842_platform_data {
  * deinterlacer. */
 #define ADV7842_CMD_RAM_TEST _IO('V', BASE_VIDIOC_PRIVATE)
 
+#define ADV7842_EDID_PORT_A   0
+#define ADV7842_EDID_PORT_B   1
+#define ADV7842_EDID_PORT_VGA 2
+
 #endif
index 656823075709d6728cc2b2ec182e4827d5b319f1..2b023471ac89177a997d1687278fec3b177ee4a4 100644 (file)
@@ -56,6 +56,7 @@
 #define                ISI_CFG1_FRATE_DIV_6            (5 << 8)
 #define                ISI_CFG1_FRATE_DIV_7            (6 << 8)
 #define                ISI_CFG1_FRATE_DIV_8            (7 << 8)
+#define                ISI_CFG1_FRATE_DIV_MASK         (7 << 8)
 #define ISI_CFG1_DISCR                         (1 << 11)
 #define ISI_CFG1_FULL_MODE                     (1 << 12)
 
@@ -66,6 +67,7 @@
 #define                ISI_CFG2_YCC_SWAP_MODE_1        (1 << 28)
 #define                ISI_CFG2_YCC_SWAP_MODE_2        (2 << 28)
 #define                ISI_CFG2_YCC_SWAP_MODE_3        (3 << 28)
+#define                ISI_CFG2_YCC_SWAP_MODE_MASK     (3 << 28)
 #define ISI_CFG2_IM_VSIZE_OFFSET               0
 #define ISI_CFG2_IM_HSIZE_OFFSET               16
 #define ISI_CFG2_IM_VSIZE_MASK         (0x7FF << ISI_CFG2_IM_VSIZE_OFFSET)
index 10df55187981979be928ede57d2d2d0b903c03c4..e00459185d2079161424b069c9e9c6bece2210c5 100644 (file)
@@ -24,6 +24,7 @@
 #define _MEDIA_ENTITY_H
 
 #include <linux/bitops.h>
+#include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/media.h>
 
diff --git a/include/media/omap4iss.h b/include/media/omap4iss.h
new file mode 100644 (file)
index 0000000..0d7620d
--- /dev/null
@@ -0,0 +1,65 @@
+#ifndef ARCH_ARM_PLAT_OMAP4_ISS_H
+#define ARCH_ARM_PLAT_OMAP4_ISS_H
+
+#include <linux/i2c.h>
+
+struct iss_device;
+
+enum iss_interface_type {
+       ISS_INTERFACE_CSI2A_PHY1,
+       ISS_INTERFACE_CSI2B_PHY2,
+};
+
+/**
+ * struct iss_csiphy_lane: CSI2 lane position and polarity
+ * @pos: position of the lane
+ * @pol: polarity of the lane
+ */
+struct iss_csiphy_lane {
+       u8 pos;
+       u8 pol;
+};
+
+#define ISS_CSIPHY1_NUM_DATA_LANES     4
+#define ISS_CSIPHY2_NUM_DATA_LANES     1
+
+/**
+ * struct iss_csiphy_lanes_cfg - CSI2 lane configuration
+ * @data: Configuration of one or two data lanes
+ * @clk: Clock lane configuration
+ */
+struct iss_csiphy_lanes_cfg {
+       struct iss_csiphy_lane data[ISS_CSIPHY1_NUM_DATA_LANES];
+       struct iss_csiphy_lane clk;
+};
+
+/**
+ * struct iss_csi2_platform_data - CSI2 interface platform data
+ * @crc: Enable the cyclic redundancy check
+ * @vpclk_div: Video port output clock control
+ */
+struct iss_csi2_platform_data {
+       unsigned crc:1;
+       unsigned vpclk_div:2;
+       struct iss_csiphy_lanes_cfg lanecfg;
+};
+
+struct iss_subdev_i2c_board_info {
+       struct i2c_board_info *board_info;
+       int i2c_adapter_id;
+};
+
+struct iss_v4l2_subdevs_group {
+       struct iss_subdev_i2c_board_info *subdevs;
+       enum iss_interface_type interface;
+       union {
+               struct iss_csi2_platform_data csi2;
+       } bus; /* gcc < 4.6.0 chokes on anonymous union initializers */
+};
+
+struct iss_platform_data {
+       struct iss_v4l2_subdevs_group *subdevs;
+       void (*set_constraints)(struct iss_device *iss, bool enable);
+};
+
+#endif
index 6628f5d01f527dd5d3469a2d2b05ab3899e1ff9f..a20ed97d7d8a048374a20db3d8c0b65e4590b502 100644 (file)
@@ -193,6 +193,7 @@ void rc_map_init(void);
 #define RC_MAP_VIDEOMATE_TV_PVR          "rc-videomate-tv-pvr"
 #define RC_MAP_WINFAST                   "rc-winfast"
 #define RC_MAP_WINFAST_USBII_DELUXE      "rc-winfast-usbii-deluxe"
+#define RC_MAP_SU3000                    "rc-su3000"
 
 /*
  * Please, do not just append newer Remote Controller names at the end.
index 2c3c4420a4eb61e42ed0cd8c8606b5a8a32766cd..b5ec1aa60ed552337493d63dda4f3fb0382b5e78 100644 (file)
@@ -27,6 +27,7 @@
 
 struct saa6588_command {
        unsigned int  block_count;
+       bool          nonblocking;
        int           result;
        unsigned char __user *buffer;
        struct file   *instance;
@@ -34,7 +35,6 @@ struct saa6588_command {
 };
 
 /* These ioctls are internal to the kernel */
-#define SAA6588_CMD_OPEN       _IOW('R', 1, int)
 #define SAA6588_CMD_CLOSE      _IOW('R', 2, int)
 #define SAA6588_CMD_READ       _IOR('R', 3, int)
 #define SAA6588_CMD_POLL       _IOR('R', 4, int)
diff --git a/include/media/saa6752hs.h b/include/media/saa6752hs.h
deleted file mode 100644 (file)
index 3b8686e..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
-    saa6752hs.h - definition for saa6752hs MPEG encoder
-
-    Copyright (C) 2003 Andrew de Quincey <adq@lidskialf.net>
-
-    This program is free software; you can redistribute it and/or modify
-    it under the terms of the GNU General Public License as published by
-    the Free Software Foundation; either version 2 of the License, or
-    (at your option) any later version.
-
-    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.
-*/
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
index ed7353e8a982364da16d64801a4463980e5b6d15..f98a0a7af61c0c09b5955e14aa1c3bc7c56aefc3 100644 (file)
@@ -23,6 +23,8 @@
  * Platform dependent definition
  */
 struct si4713_platform_data {
+       const char * const *supply_names;
+       unsigned supplies;
        int gpio_reset; /* < 0 if not used */
 };
 
index 528cdaf622e192aa572ade990b60acf949e74109..803516775162d184d4dbe8cf78e427ec3452e23c 100644 (file)
@@ -45,6 +45,10 @@ struct v4l2_fh {
        struct list_head        available; /* Dequeueable event */
        unsigned int            navailable;
        u32                     sequence;
+
+#if IS_ENABLED(CONFIG_V4L2_MEM2MEM_DEV)
+       struct v4l2_m2m_ctx     *m2m_ctx;
+#endif
 };
 
 /*
index 44542a20ab8126cdcd851a3d369f2b2b956c96ac..12ea5a6a4331c7036341f6bc0ff4cbe48d767a01 100644 (file)
@@ -64,6 +64,9 @@ struct v4l2_m2m_queue_ctx {
 };
 
 struct v4l2_m2m_ctx {
+       /* optional cap/out vb2 queues lock */
+       struct mutex                    *q_lock;
+
 /* private: internal use only */
        struct v4l2_m2m_dev             *m2m_dev;
 
@@ -229,5 +232,26 @@ static inline void *v4l2_m2m_dst_buf_remove(struct v4l2_m2m_ctx *m2m_ctx)
        return v4l2_m2m_buf_remove(&m2m_ctx->cap_q_ctx);
 }
 
+/* v4l2 ioctl helpers */
+
+int v4l2_m2m_ioctl_reqbufs(struct file *file, void *priv,
+                               struct v4l2_requestbuffers *rb);
+int v4l2_m2m_ioctl_create_bufs(struct file *file, void *fh,
+                               struct v4l2_create_buffers *create);
+int v4l2_m2m_ioctl_querybuf(struct file *file, void *fh,
+                               struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_expbuf(struct file *file, void *fh,
+                               struct v4l2_exportbuffer *eb);
+int v4l2_m2m_ioctl_qbuf(struct file *file, void *fh,
+                               struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_dqbuf(struct file *file, void *fh,
+                               struct v4l2_buffer *buf);
+int v4l2_m2m_ioctl_streamon(struct file *file, void *fh,
+                               enum v4l2_buf_type type);
+int v4l2_m2m_ioctl_streamoff(struct file *file, void *fh,
+                               enum v4l2_buf_type type);
+int v4l2_m2m_fop_mmap(struct file *file, struct vm_area_struct *vma);
+unsigned int v4l2_m2m_fop_poll(struct file *file, poll_table *wait);
+
 #endif /* _MEDIA_V4L2_MEM2MEM_H */
 
index 3a8a84124b44a7db7125af82830dd49409ac8c87..541cea4122e90ac56d7549c8aea0d442e44093f2 100644 (file)
@@ -53,7 +53,6 @@ struct v4l2_of_bus_parallel {
  * @port: identifier (value of reg property) of a port this endpoint belongs to
  * @id: identifier (value of reg property) of this endpoint
  * @local_node: pointer to device_node of this endpoint
- * @remote: phandle to remote endpoint node
  * @bus_type: bus type
  * @bus: bus configuration data structure
  * @head: list head for this structure
@@ -62,7 +61,6 @@ struct v4l2_of_endpoint {
        unsigned int port;
        unsigned int id;
        const struct device_node *local_node;
-       const __be32 *remote;
        enum v4l2_mbus_type bus_type;
        union {
                struct v4l2_of_bus_parallel parallel;
@@ -72,8 +70,8 @@ struct v4l2_of_endpoint {
 };
 
 #ifdef CONFIG_OF
-void v4l2_of_parse_endpoint(const struct device_node *node,
-                               struct v4l2_of_endpoint *link);
+int v4l2_of_parse_endpoint(const struct device_node *node,
+                          struct v4l2_of_endpoint *endpoint);
 struct device_node *v4l2_of_get_next_endpoint(const struct device_node *parent,
                                        struct device_node *previous);
 struct device_node *v4l2_of_get_remote_port_parent(
index 941055e9d125af3bfe5a6915ff551e0bb1532445..bef53ce555d2641d9538dad2982856e9677c8dd4 100644 (file)
@@ -142,6 +142,7 @@ enum vb2_fileio_flags {
 /**
  * enum vb2_buffer_state - current video buffer state
  * @VB2_BUF_STATE_DEQUEUED:    buffer under userspace control
+ * @VB2_BUF_STATE_PREPARING:   buffer is being prepared in videobuf
  * @VB2_BUF_STATE_PREPARED:    buffer prepared in videobuf and by the driver
  * @VB2_BUF_STATE_QUEUED:      buffer queued in videobuf, but not in driver
  * @VB2_BUF_STATE_ACTIVE:      buffer queued in driver and possibly used
@@ -154,6 +155,7 @@ enum vb2_fileio_flags {
  */
 enum vb2_buffer_state {
        VB2_BUF_STATE_DEQUEUED,
+       VB2_BUF_STATE_PREPARING,
        VB2_BUF_STATE_PREPARED,
        VB2_BUF_STATE_QUEUED,
        VB2_BUF_STATE_ACTIVE,
@@ -250,10 +252,13 @@ struct vb2_buffer {
  *                     receive buffers with @buf_queue callback before
  *                     @start_streaming is called; the driver gets the number
  *                     of already queued buffers in count parameter; driver
- *                     can return an error if hardware fails or not enough
- *                     buffers has been queued, in such case all buffers that
- *                     have been already given by the @buf_queue callback are
- *                     invalidated.
+ *                     can return an error if hardware fails, in that case all
+ *                     buffers that have been already given by the @buf_queue
+ *                     callback are invalidated.
+ *                     If there were not enough queued buffers to start
+ *                     streaming, then this callback returns -ENOBUFS, and the
+ *                     vb2 core will retry calling @start_streaming when a new
+ *                     buffer is queued.
  * @stop_streaming:    called when 'streaming' state must be disabled; driver
  *                     should stop any DMA transactions or wait until they
  *                     finish and give back all buffers it got from buf_queue()
@@ -321,6 +326,9 @@ struct v4l2_fh;
  * @done_wq:   waitqueue for processes waiting for buffers ready to be dequeued
  * @alloc_ctx: memory type/allocator-specific contexts for each plane
  * @streaming: current streaming state
+ * @retry_start_streaming: start_streaming() was called, but there were not enough
+ *             buffers queued. If set, then retry calling start_streaming when
+ *             queuing a new buffer.
  * @fileio:    file io emulator internal data, used only if emulator is active
  */
 struct vb2_queue {
@@ -353,6 +361,7 @@ struct vb2_queue {
        unsigned int                    plane_sizes[VIDEO_MAX_PLANES];
 
        unsigned int                    streaming:1;
+       unsigned int                    retry_start_streaming:1;
 
        struct vb2_fileio_data          *fileio;
 };
@@ -491,6 +500,7 @@ int vb2_ioctl_expbuf(struct file *file, void *priv,
 
 int vb2_fop_mmap(struct file *file, struct vm_area_struct *vma);
 int vb2_fop_release(struct file *file);
+int _vb2_fop_release(struct file *file, struct mutex *lock);
 ssize_t vb2_fop_write(struct file *file, const char __user *buf,
                size_t count, loff_t *ppos);
 ssize_t vb2_fop_read(struct file *file, char __user *buf,
index a5f9b960dfc8f0ca329c1fc510956f379e817fdd..6ca3265a4dcacaff704e32a329f546a421c2971e 100644 (file)
@@ -102,6 +102,7 @@ struct ore_striping_info {
        unsigned unit_off;
        unsigned cur_pg;
        unsigned cur_comp;
+       unsigned maxdevUnits;
 };
 
 struct ore_io_state;
index 66d42edfb3fc341d8a33a0a0f9e9666b53111ec3..0a4edfe8af510ad7739ea931c559dbef11727b68 100644 (file)
@@ -155,6 +155,7 @@ enum scsi_timeouts {
 /* values for service action in */
 #define        SAI_READ_CAPACITY_16  0x10
 #define SAI_GET_LBA_STATUS    0x12
+#define SAI_REPORT_REFERRALS  0x13
 /* values for VARIABLE_LENGTH_CMD service action codes
  * see spc4r17 Section D.3.5, table D.7 and D.8 */
 #define VLC_SA_RECEIVE_CREDENTIAL 0x1800
index a12589c4ee92b9a044b9fbc3df927164c5e1f813..ae5a17111968c7ca8bc8667a65d16393532ffbde 100644 (file)
@@ -94,7 +94,7 @@ extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *);
 /*
  * From iscsi_target_util.c
  */
-extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t);
+extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, int);
 extern int iscsit_sequence_cmd(struct iscsi_conn *, struct iscsi_cmd *,
                               unsigned char *, __be32);
 extern void iscsit_release_cmd(struct iscsi_cmd *);
index 39e0114d70c54cba70f7180c8c9763529b91ef0f..7020e33e742e595c50d51aa57e83f546c5e57a50 100644 (file)
@@ -41,6 +41,9 @@ struct se_subsystem_api {
        unsigned int (*get_io_opt)(struct se_device *);
        unsigned char *(*get_sense_buffer)(struct se_cmd *);
        bool (*get_write_cache)(struct se_device *);
+       int (*init_prot)(struct se_device *);
+       int (*format_prot)(struct se_device *);
+       void (*free_prot)(struct se_device *);
 };
 
 struct sbc_ops {
@@ -70,6 +73,10 @@ sense_reason_t sbc_execute_unmap(struct se_cmd *cmd,
        sense_reason_t (*do_unmap_fn)(struct se_cmd *cmd, void *priv,
                                      sector_t lba, sector_t nolb),
        void *priv);
+sense_reason_t sbc_dif_verify_write(struct se_cmd *, sector_t, unsigned int,
+                                    unsigned int, struct scatterlist *, int);
+sense_reason_t sbc_dif_verify_read(struct se_cmd *, sector_t, unsigned int,
+                                   unsigned int, struct scatterlist *, int);
 
 void   transport_set_vpd_proto_id(struct t10_vpd *, unsigned char *);
 int    transport_set_vpd_assoc(struct t10_vpd *, unsigned char *);
index 321301c0a643bfb32303b3f48cecae720f3fad87..c9c791209cd18e579c5477b6b1cbe195cba744a0 100644 (file)
@@ -37,6 +37,9 @@
 /* Used by transport_send_check_condition_and_sense() */
 #define SPC_SENSE_KEY_OFFSET                   2
 #define SPC_ADD_SENSE_LEN_OFFSET               7
+#define SPC_DESC_TYPE_OFFSET                   8
+#define SPC_ADDITIONAL_DESC_LEN_OFFSET         9
+#define SPC_VALIDITY_OFFSET                    10
 #define SPC_ASC_KEY_OFFSET                     12
 #define SPC_ASCQ_KEY_OFFSET                    13
 #define TRANSPORT_IQN_LEN                      224
 /* Queue Algorithm Modifier default for restricted reordering in control mode page */
 #define DA_EMULATE_REST_REORD                  0
 
-#define SE_INQUIRY_BUF                         512
+#define SE_INQUIRY_BUF                         1024
 #define SE_MODE_PAGE_BUF                       512
 #define SE_SENSE_BUF                           96
 
@@ -205,6 +208,9 @@ enum tcm_sense_reason_table {
        TCM_OUT_OF_RESOURCES                    = R(0x12),
        TCM_PARAMETER_LIST_LENGTH_ERROR         = R(0x13),
        TCM_MISCOMPARE_VERIFY                   = R(0x14),
+       TCM_LOGICAL_BLOCK_GUARD_CHECK_FAILED    = R(0x15),
+       TCM_LOGICAL_BLOCK_APP_TAG_CHECK_FAILED  = R(0x16),
+       TCM_LOGICAL_BLOCK_REF_TAG_CHECK_FAILED  = R(0x17),
 #undef R
 };
 
@@ -247,10 +253,28 @@ typedef enum {
 
 struct se_cmd;
 
+struct t10_alua_lba_map_member {
+       struct list_head lba_map_mem_list;
+       int lba_map_mem_alua_state;
+       int lba_map_mem_alua_pg_id;
+};
+
+struct t10_alua_lba_map {
+       u64 lba_map_first_lba;
+       u64 lba_map_last_lba;
+       struct list_head lba_map_list;
+       struct list_head lba_map_mem_list;
+};
+
 struct t10_alua {
        /* ALUA Target Port Group ID */
        u16     alua_tg_pt_gps_counter;
        u32     alua_tg_pt_gps_count;
+       /* Referrals support */
+       spinlock_t lba_map_lock;
+       u32     lba_map_segment_size;
+       u32     lba_map_segment_multiplier;
+       struct list_head lba_map_list;
        spinlock_t tg_pt_gps_lock;
        struct se_device *t10_dev;
        /* Used for default ALUA Target Port Group */
@@ -284,6 +308,8 @@ struct t10_alua_tg_pt_gp {
        u16     tg_pt_gp_id;
        int     tg_pt_gp_valid_id;
        int     tg_pt_gp_alua_supported_states;
+       int     tg_pt_gp_alua_pending_state;
+       int     tg_pt_gp_alua_previous_state;
        int     tg_pt_gp_alua_access_status;
        int     tg_pt_gp_alua_access_type;
        int     tg_pt_gp_nonop_delay_msecs;
@@ -291,9 +317,6 @@ struct t10_alua_tg_pt_gp {
        int     tg_pt_gp_implicit_trans_secs;
        int     tg_pt_gp_pref;
        int     tg_pt_gp_write_metadata;
-       /* Used by struct t10_alua_tg_pt_gp->tg_pt_gp_md_buf_len */
-#define ALUA_MD_BUF_LEN                                1024
-       u32     tg_pt_gp_md_buf_len;
        u32     tg_pt_gp_members;
        atomic_t tg_pt_gp_alua_access_state;
        atomic_t tg_pt_gp_ref_cnt;
@@ -303,6 +326,10 @@ struct t10_alua_tg_pt_gp {
        struct config_group tg_pt_gp_group;
        struct list_head tg_pt_gp_list;
        struct list_head tg_pt_gp_mem_list;
+       struct se_port *tg_pt_gp_alua_port;
+       struct se_node_acl *tg_pt_gp_alua_nacl;
+       struct delayed_work tg_pt_gp_transition_work;
+       struct completion *tg_pt_gp_transition_complete;
 };
 
 struct t10_alua_tg_pt_gp_member {
@@ -414,6 +441,34 @@ struct se_tmr_req {
        struct list_head        tmr_list;
 };
 
+enum target_prot_op {
+       TARGET_PROT_NORMAL = 0,
+       TARGET_PROT_DIN_INSERT,
+       TARGET_PROT_DOUT_INSERT,
+       TARGET_PROT_DIN_STRIP,
+       TARGET_PROT_DOUT_STRIP,
+       TARGET_PROT_DIN_PASS,
+       TARGET_PROT_DOUT_PASS,
+};
+
+enum target_prot_ho {
+       PROT_SEPERATED,
+       PROT_INTERLEAVED,
+};
+
+enum target_prot_type {
+       TARGET_DIF_TYPE0_PROT,
+       TARGET_DIF_TYPE1_PROT,
+       TARGET_DIF_TYPE2_PROT,
+       TARGET_DIF_TYPE3_PROT,
+};
+
+struct se_dif_v1_tuple {
+       __be16                  guard_tag;
+       __be16                  app_tag;
+       __be32                  ref_tag;
+};
+
 struct se_cmd {
        /* SAM response code being sent to initiator */
        u8                      scsi_status;
@@ -497,14 +552,24 @@ struct se_cmd {
        void                    *priv;
 
        /* Used for lun->lun_ref counting */
-       bool                    lun_ref_active;
+       int                     lun_ref_active;
+
+       /* DIF related members */
+       enum target_prot_op     prot_op;
+       enum target_prot_type   prot_type;
+       u32                     prot_length;
+       u32                     reftag_seed;
+       struct scatterlist      *t_prot_sg;
+       unsigned int            t_prot_nents;
+       enum target_prot_ho     prot_handover;
+       sense_reason_t          pi_err;
+       sector_t                bad_sector;
 };
 
 struct se_ua {
        u8                      ua_asc;
        u8                      ua_ascq;
        struct se_node_acl      *ua_nacl;
-       struct list_head        ua_dev_list;
        struct list_head        ua_nacl_list;
 };
 
@@ -605,6 +670,9 @@ struct se_dev_attrib {
        int             emulate_tpws;
        int             emulate_caw;
        int             emulate_3pc;
+       int             pi_prot_format;
+       enum target_prot_type pi_prot_type;
+       enum target_prot_type hw_pi_prot_type;
        int             enforce_pr_isids;
        int             is_nonrot;
        int             emulate_rest_reord;
@@ -736,6 +804,8 @@ struct se_device {
        /* Linked list for struct se_hba struct se_device list */
        struct list_head        dev_list;
        struct se_lun           xcopy_lun;
+       /* Protection Information */
+       int                     prot_length;
 };
 
 struct se_hba {
index 4cf4fda404a3ce80b31d02b0b04c209cbb1ca0f0..0218d689b3d787d9d98ecf507de7b4caba6a3146 100644 (file)
@@ -105,7 +105,8 @@ sense_reason_t transport_lookup_cmd_lun(struct se_cmd *, u32);
 sense_reason_t target_setup_cmd_from_cdb(struct se_cmd *, unsigned char *);
 int    target_submit_cmd_map_sgls(struct se_cmd *, struct se_session *,
                unsigned char *, unsigned char *, u32, u32, int, int, int,
-               struct scatterlist *, u32, struct scatterlist *, u32);
+               struct scatterlist *, u32, struct scatterlist *, u32,
+               struct scatterlist *, u32);
 int    target_submit_cmd(struct se_cmd *, struct se_session *, unsigned char *,
                unsigned char *, u32, u32, int, int, int);
 int    target_submit_tmr(struct se_cmd *se_cmd, struct se_session *se_sess,
index e2b9576d00e24772580a601a268e42bdc46e349e..7110897c3dfa595e385b8a946f7547ca05583fec 100644 (file)
@@ -24,10 +24,10 @@ DECLARE_EVENT_CLASS(bcache_request,
                __entry->dev            = bio->bi_bdev->bd_dev;
                __entry->orig_major     = d->disk->major;
                __entry->orig_minor     = d->disk->first_minor;
-               __entry->sector         = bio->bi_sector;
-               __entry->orig_sector    = bio->bi_sector - 16;
-               __entry->nr_sector      = bio->bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               __entry->sector         = bio->bi_iter.bi_sector;
+               __entry->orig_sector    = bio->bi_iter.bi_sector - 16;
+               __entry->nr_sector      = bio->bi_iter.bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
        ),
 
        TP_printk("%d,%d %s %llu + %u (from %d,%d @ %llu)",
@@ -99,9 +99,9 @@ DECLARE_EVENT_CLASS(bcache_bio,
 
        TP_fast_assign(
                __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
-               __entry->nr_sector      = bio->bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               __entry->sector         = bio->bi_iter.bi_sector;
+               __entry->nr_sector      = bio->bi_iter.bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
        ),
 
        TP_printk("%d,%d  %s %llu + %u",
@@ -134,9 +134,9 @@ TRACE_EVENT(bcache_read,
 
        TP_fast_assign(
                __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
-               __entry->nr_sector      = bio->bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               __entry->sector         = bio->bi_iter.bi_sector;
+               __entry->nr_sector      = bio->bi_iter.bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
                __entry->cache_hit = hit;
                __entry->bypass = bypass;
        ),
@@ -162,9 +162,9 @@ TRACE_EVENT(bcache_write,
 
        TP_fast_assign(
                __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
-               __entry->nr_sector      = bio->bi_size >> 9;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               __entry->sector         = bio->bi_iter.bi_sector;
+               __entry->nr_sector      = bio->bi_iter.bi_size >> 9;
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
                __entry->writeback = writeback;
                __entry->bypass = bypass;
        ),
@@ -247,7 +247,7 @@ TRACE_EVENT(bcache_btree_write,
        TP_fast_assign(
                __entry->bucket = PTR_BUCKET_NR(b->c, &b->key, 0);
                __entry->block  = b->written;
-               __entry->keys   = b->sets[b->nsets].data->keys;
+               __entry->keys   = b->keys.set[b->keys.nsets].data->keys;
        ),
 
        TP_printk("bucket %zu", __entry->bucket)
@@ -411,7 +411,7 @@ TRACE_EVENT(bcache_alloc_invalidate,
        ),
 
        TP_fast_assign(
-               __entry->free           = fifo_used(&ca->free);
+               __entry->free           = fifo_used(&ca->free[RESERVE_NONE]);
                __entry->free_inc       = fifo_used(&ca->free_inc);
                __entry->free_inc_size  = ca->free_inc.size;
                __entry->unused         = fifo_used(&ca->unused);
@@ -422,8 +422,8 @@ TRACE_EVENT(bcache_alloc_invalidate,
 );
 
 TRACE_EVENT(bcache_alloc_fail,
-       TP_PROTO(struct cache *ca),
-       TP_ARGS(ca),
+       TP_PROTO(struct cache *ca, unsigned reserve),
+       TP_ARGS(ca, reserve),
 
        TP_STRUCT__entry(
                __field(unsigned,       free                    )
@@ -433,7 +433,7 @@ TRACE_EVENT(bcache_alloc_fail,
        ),
 
        TP_fast_assign(
-               __entry->free           = fifo_used(&ca->free);
+               __entry->free           = fifo_used(&ca->free[reserve]);
                __entry->free_inc       = fifo_used(&ca->free_inc);
                __entry->unused         = fifo_used(&ca->unused);
                __entry->blocked        = atomic_read(&ca->set->prio_blocked);
index 4c2301d2ef1aa979ea0d6594ad1b6404368b920b..e76ae19a8d6fe65705e48104bb8212ed8bddb546 100644 (file)
@@ -243,9 +243,9 @@ TRACE_EVENT(block_bio_bounce,
        TP_fast_assign(
                __entry->dev            = bio->bi_bdev ?
                                          bio->bi_bdev->bd_dev : 0;
-               __entry->sector         = bio->bi_sector;
+               __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio_sectors(bio);
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
 
@@ -280,10 +280,10 @@ TRACE_EVENT(block_bio_complete,
 
        TP_fast_assign(
                __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
+               __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio_sectors(bio);
                __entry->error          = error;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
        ),
 
        TP_printk("%d,%d %s %llu + %u [%d]",
@@ -308,9 +308,9 @@ DECLARE_EVENT_CLASS(block_bio_merge,
 
        TP_fast_assign(
                __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
+               __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio_sectors(bio);
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
 
@@ -375,9 +375,9 @@ TRACE_EVENT(block_bio_queue,
 
        TP_fast_assign(
                __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
+               __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio_sectors(bio);
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
 
@@ -403,7 +403,7 @@ DECLARE_EVENT_CLASS(block_get_rq,
 
        TP_fast_assign(
                __entry->dev            = bio ? bio->bi_bdev->bd_dev : 0;
-               __entry->sector         = bio ? bio->bi_sector : 0;
+               __entry->sector         = bio ? bio->bi_iter.bi_sector : 0;
                __entry->nr_sector      = bio ? bio_sectors(bio) : 0;
                blk_fill_rwbs(__entry->rwbs,
                              bio ? bio->bi_rw : 0, __entry->nr_sector);
@@ -538,9 +538,9 @@ TRACE_EVENT(block_split,
 
        TP_fast_assign(
                __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
+               __entry->sector         = bio->bi_iter.bi_sector;
                __entry->new_sector     = new_sector;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
                memcpy(__entry->comm, current->comm, TASK_COMM_LEN);
        ),
 
@@ -579,11 +579,11 @@ TRACE_EVENT(block_bio_remap,
 
        TP_fast_assign(
                __entry->dev            = bio->bi_bdev->bd_dev;
-               __entry->sector         = bio->bi_sector;
+               __entry->sector         = bio->bi_iter.bi_sector;
                __entry->nr_sector      = bio_sectors(bio);
                __entry->old_dev        = dev;
                __entry->old_sector     = from;
-               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_size);
+               blk_fill_rwbs(__entry->rwbs, bio->bi_rw, bio->bi_iter.bi_size);
        ),
 
        TP_printk("%d,%d %s %llu + %u <- (%d,%d) %llu",
index 4832d75dcbaedb888a2751303fe7d5a4e62b8010..3176cdc32937f4b62cbcd11e878310f1b086f15e 100644 (file)
@@ -208,17 +208,18 @@ TRACE_EVENT_CONDITION(btrfs_get_extent,
                  __entry->refs, __entry->compress_type)
 );
 
-#define show_ordered_flags(flags)                                      \
-       __print_symbolic(flags,                                         \
-               { BTRFS_ORDERED_IO_DONE,        "IO_DONE"       },      \
-               { BTRFS_ORDERED_COMPLETE,       "COMPLETE"      },      \
-               { BTRFS_ORDERED_NOCOW,          "NOCOW"         },      \
-               { BTRFS_ORDERED_COMPRESSED,     "COMPRESSED"    },      \
-               { BTRFS_ORDERED_PREALLOC,       "PREALLOC"      },      \
-               { BTRFS_ORDERED_DIRECT,         "DIRECT"        },      \
-               { BTRFS_ORDERED_IOERR,          "IOERR"         },      \
-               { BTRFS_ORDERED_UPDATED_ISIZE,  "UPDATED_ISIZE" },      \
-               { BTRFS_ORDERED_LOGGED_CSUM,    "LOGGED_CSUM"   })
+#define show_ordered_flags(flags)                                         \
+       __print_flags(flags, "|",                                          \
+               { (1 << BTRFS_ORDERED_IO_DONE),         "IO_DONE"       }, \
+               { (1 << BTRFS_ORDERED_COMPLETE),        "COMPLETE"      }, \
+               { (1 << BTRFS_ORDERED_NOCOW),           "NOCOW"         }, \
+               { (1 << BTRFS_ORDERED_COMPRESSED),      "COMPRESSED"    }, \
+               { (1 << BTRFS_ORDERED_PREALLOC),        "PREALLOC"      }, \
+               { (1 << BTRFS_ORDERED_DIRECT),          "DIRECT"        }, \
+               { (1 << BTRFS_ORDERED_IOERR),           "IOERR"         }, \
+               { (1 << BTRFS_ORDERED_UPDATED_ISIZE),   "UPDATED_ISIZE" }, \
+               { (1 << BTRFS_ORDERED_LOGGED_CSUM),     "LOGGED_CSUM"   }, \
+               { (1 << BTRFS_ORDERED_TRUNCATED),       "TRUNCATED"     })
 
 
 DECLARE_EVENT_CLASS(btrfs__ordered_extent,
index 3b9f28dfc8492160940d28e58acf1dc9dc6e5081..67f38faac589ad52ac5850e5af602799753b8d29 100644 (file)
@@ -629,8 +629,8 @@ DECLARE_EVENT_CLASS(f2fs__submit_bio,
                __entry->dev            = sb->s_dev;
                __entry->rw             = rw;
                __entry->type           = type;
-               __entry->sector         = bio->bi_sector;
-               __entry->size           = bio->bi_size;
+               __entry->sector         = bio->bi_iter.bi_sector;
+               __entry->size           = bio->bi_iter.bi_size;
        ),
 
        TP_printk("dev = (%d,%d), %s%s, %s, sector = %lld, size = %u",
index d51d16c7afd86d64b02092f0a8e4969b4ab5eaa2..ddc179b7a1052aa6c3fb9df408e3b5ad9e50d792 100644 (file)
@@ -301,6 +301,7 @@ DECLARE_EVENT_CLASS(xs_socket_event_done,
 
 DEFINE_RPC_SOCKET_EVENT(rpc_socket_state_change);
 DEFINE_RPC_SOCKET_EVENT_DONE(rpc_socket_connect);
+DEFINE_RPC_SOCKET_EVENT_DONE(rpc_socket_error);
 DEFINE_RPC_SOCKET_EVENT_DONE(rpc_socket_reset_connection);
 DEFINE_RPC_SOCKET_EVENT(rpc_socket_close);
 DEFINE_RPC_SOCKET_EVENT(rpc_socket_shutdown);
diff --git a/include/trace/events/v4l2.h b/include/trace/events/v4l2.h
new file mode 100644 (file)
index 0000000..ef94eca
--- /dev/null
@@ -0,0 +1,157 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM v4l2
+
+#if !defined(_TRACE_V4L2_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_V4L2_H
+
+#include <linux/tracepoint.h>
+
+#define show_type(type)                                                               \
+       __print_symbolic(type,                                                 \
+               { V4L2_BUF_TYPE_VIDEO_CAPTURE,        "VIDEO_CAPTURE" },       \
+               { V4L2_BUF_TYPE_VIDEO_OUTPUT,         "VIDEO_OUTPUT" },        \
+               { V4L2_BUF_TYPE_VIDEO_OVERLAY,        "VIDEO_OVERLAY" },       \
+               { V4L2_BUF_TYPE_VBI_CAPTURE,          "VBI_CAPTURE" },         \
+               { V4L2_BUF_TYPE_VBI_OUTPUT,           "VBI_OUTPUT" },          \
+               { V4L2_BUF_TYPE_SLICED_VBI_CAPTURE,   "SLICED_VBI_CAPTURE" },  \
+               { V4L2_BUF_TYPE_SLICED_VBI_OUTPUT,    "SLICED_VBI_OUTPUT" },   \
+               { V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY, "VIDEO_OUTPUT_OVERLAY" },\
+               { V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE, "VIDEO_CAPTURE_MPLANE" },\
+               { V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,  "VIDEO_OUTPUT_MPLANE" }, \
+               { V4L2_BUF_TYPE_PRIVATE,              "PRIVATE" })
+
+#define show_field(field)                                              \
+       __print_symbolic(field,                                         \
+               { V4L2_FIELD_ANY,               "ANY" },                \
+               { V4L2_FIELD_NONE,              "NONE" },               \
+               { V4L2_FIELD_TOP,               "TOP" },                \
+               { V4L2_FIELD_BOTTOM,            "BOTTOM" },             \
+               { V4L2_FIELD_INTERLACED,        "INTERLACED" },         \
+               { V4L2_FIELD_SEQ_TB,            "SEQ_TB" },             \
+               { V4L2_FIELD_SEQ_BT,            "SEQ_BT" },             \
+               { V4L2_FIELD_ALTERNATE,         "ALTERNATE" },          \
+               { V4L2_FIELD_INTERLACED_TB,     "INTERLACED_TB" },      \
+               { V4L2_FIELD_INTERLACED_BT,     "INTERLACED_BT" })
+
+#define show_timecode_type(type)                                       \
+       __print_symbolic(type,                                          \
+               { V4L2_TC_TYPE_24FPS,           "24FPS" },              \
+               { V4L2_TC_TYPE_25FPS,           "25FPS" },              \
+               { V4L2_TC_TYPE_30FPS,           "30FPS" },              \
+               { V4L2_TC_TYPE_50FPS,           "50FPS" },              \
+               { V4L2_TC_TYPE_60FPS,           "60FPS" })
+
+#define show_flags(flags)                                                    \
+       __print_flags(flags, "|",                                             \
+               { V4L2_BUF_FLAG_MAPPED,              "MAPPED" },              \
+               { V4L2_BUF_FLAG_QUEUED,              "QUEUED" },              \
+               { V4L2_BUF_FLAG_DONE,                "DONE" },                \
+               { V4L2_BUF_FLAG_KEYFRAME,            "KEYFRAME" },            \
+               { V4L2_BUF_FLAG_PFRAME,              "PFRAME" },              \
+               { V4L2_BUF_FLAG_BFRAME,              "BFRAME" },              \
+               { V4L2_BUF_FLAG_ERROR,               "ERROR" },               \
+               { V4L2_BUF_FLAG_TIMECODE,            "TIMECODE" },            \
+               { V4L2_BUF_FLAG_PREPARED,            "PREPARED" },            \
+               { V4L2_BUF_FLAG_NO_CACHE_INVALIDATE, "NO_CACHE_INVALIDATE" }, \
+               { V4L2_BUF_FLAG_NO_CACHE_CLEAN,      "NO_CACHE_CLEAN" },      \
+               { V4L2_BUF_FLAG_TIMESTAMP_MASK,      "TIMESTAMP_MASK" },      \
+               { V4L2_BUF_FLAG_TIMESTAMP_UNKNOWN,   "TIMESTAMP_UNKNOWN" },   \
+               { V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC, "TIMESTAMP_MONOTONIC" }, \
+               { V4L2_BUF_FLAG_TIMESTAMP_COPY,      "TIMESTAMP_COPY" })
+
+#define show_timecode_flags(flags)                                       \
+       __print_flags(flags, "|",                                         \
+               { V4L2_TC_FLAG_DROPFRAME,       "DROPFRAME" },            \
+               { V4L2_TC_FLAG_COLORFRAME,      "COLORFRAME" },           \
+               { V4L2_TC_USERBITS_USERDEFINED, "USERBITS_USERDEFINED" }, \
+               { V4L2_TC_USERBITS_8BITCHARS,   "USERBITS_8BITCHARS" })
+
+#define V4L2_TRACE_EVENT(event_name)                                   \
+       TRACE_EVENT(event_name,                                         \
+               TP_PROTO(int minor, struct v4l2_buffer *buf),           \
+                                                                       \
+               TP_ARGS(minor, buf),                                    \
+                                                                       \
+               TP_STRUCT__entry(                                       \
+                       __field(int, minor)                             \
+                       __field(u32, index)                             \
+                       __field(u32, type)                              \
+                       __field(u32, bytesused)                         \
+                       __field(u32, flags)                             \
+                       __field(u32, field)                             \
+                       __field(s64, timestamp)                         \
+                       __field(u32, timecode_type)                     \
+                       __field(u32, timecode_flags)                    \
+                       __field(u8, timecode_frames)                    \
+                       __field(u8, timecode_seconds)                   \
+                       __field(u8, timecode_minutes)                   \
+                       __field(u8, timecode_hours)                     \
+                       __field(u8, timecode_userbits0)                 \
+                       __field(u8, timecode_userbits1)                 \
+                       __field(u8, timecode_userbits2)                 \
+                       __field(u8, timecode_userbits3)                 \
+                       __field(u32, sequence)                          \
+               ),                                                      \
+                                                                       \
+               TP_fast_assign(                                         \
+                       __entry->minor = minor;                         \
+                       __entry->index = buf->index;                    \
+                       __entry->type = buf->type;                      \
+                       __entry->bytesused = buf->bytesused;            \
+                       __entry->flags = buf->flags;                    \
+                       __entry->field = buf->field;                    \
+                       __entry->timestamp =                            \
+                               timeval_to_ns(&buf->timestamp);         \
+                       __entry->timecode_type = buf->timecode.type;    \
+                       __entry->timecode_flags = buf->timecode.flags;  \
+                       __entry->timecode_frames =                      \
+                               buf->timecode.frames;                   \
+                       __entry->timecode_seconds =                     \
+                               buf->timecode.seconds;                  \
+                       __entry->timecode_minutes =                     \
+                               buf->timecode.minutes;                  \
+                       __entry->timecode_hours = buf->timecode.hours;  \
+                       __entry->timecode_userbits0 =                   \
+                               buf->timecode.userbits[0];              \
+                       __entry->timecode_userbits1 =                   \
+                               buf->timecode.userbits[1];              \
+                       __entry->timecode_userbits2 =                   \
+                               buf->timecode.userbits[2];              \
+                       __entry->timecode_userbits3 =                   \
+                               buf->timecode.userbits[3];              \
+                       __entry->sequence = buf->sequence;              \
+               ),                                                      \
+                                                                       \
+               TP_printk("minor = %d, index = %u, type = %s, "         \
+                         "bytesused = %u, flags = %s, "                \
+                         "field = %s, timestamp = %llu, timecode = { " \
+                         "type = %s, flags = %s, frames = %u, "        \
+                         "seconds = %u, minutes = %u, hours = %u, "    \
+                         "userbits = { %u %u %u %u } }, "              \
+                         "sequence = %u", __entry->minor,              \
+                         __entry->index, show_type(__entry->type),     \
+                         __entry->bytesused,                           \
+                         show_flags(__entry->flags),                   \
+                         show_field(__entry->field),                   \
+                         __entry->timestamp,                           \
+                         show_timecode_type(__entry->timecode_type),   \
+                         show_timecode_flags(__entry->timecode_flags), \
+                         __entry->timecode_frames,                     \
+                         __entry->timecode_seconds,                    \
+                         __entry->timecode_minutes,                    \
+                         __entry->timecode_hours,                      \
+                         __entry->timecode_userbits0,                  \
+                         __entry->timecode_userbits1,                  \
+                         __entry->timecode_userbits2,                  \
+                         __entry->timecode_userbits3,                  \
+                         __entry->sequence                             \
+               )                                                       \
+       )
+
+V4L2_TRACE_EVENT(v4l2_dqbuf);
+V4L2_TRACE_EVENT(v4l2_qbuf);
+
+#endif /* if !defined(_TRACE_V4L2_H) || defined(TRACE_HEADER_MULTI_READ) */
+
+/* This part must be outside protection */
+#include <trace/define_trace.h>
index 76982b2a1b5831d20ce768a274d3f862d6c9e971..3dbcc1e771c03509a3c48906c2f7885416d7ec04 100644 (file)
@@ -27,8 +27,8 @@ struct ipc64_perm {
        unsigned char           __pad1[4 - sizeof(__kernel_mode_t)];
        unsigned short          seq;
        unsigned short          __pad2;
-       unsigned long           __unused1;
-       unsigned long           __unused2;
+       __kernel_ulong_t        __unused1;
+       __kernel_ulong_t        __unused2;
 };
 
 #endif /* __ASM_GENERIC_IPCBUF_H */
index aec850d9159e9a174c90fd954bdef2cf2f19e539..f55ecc43c60fa6124839c5315a5836093a446ceb 100644 (file)
@@ -35,13 +35,13 @@ struct msqid64_ds {
 #if __BITS_PER_LONG != 64
        unsigned long   __unused3;
 #endif
-       unsigned long  msg_cbytes;      /* current number of bytes on queue */
-       unsigned long  msg_qnum;        /* number of messages in queue */
-       unsigned long  msg_qbytes;      /* max number of bytes on queue */
+       __kernel_ulong_t msg_cbytes;    /* current number of bytes on queue */
+       __kernel_ulong_t msg_qnum;      /* number of messages in queue */
+       __kernel_ulong_t msg_qbytes;    /* max number of bytes on queue */
        __kernel_pid_t msg_lspid;       /* pid of last msgsnd */
        __kernel_pid_t msg_lrpid;       /* last receive pid */
-       unsigned long  __unused4;
-       unsigned long  __unused5;
+       __kernel_ulong_t __unused4;
+       __kernel_ulong_t __unused5;
 };
 
 #endif /* __ASM_GENERIC_MSGBUF_H */
index 5768fa60ac8230b2e989d911bed5fe9841b0d791..7e9fb2f0853bc0c7544173cd3874586818a46406 100644 (file)
@@ -39,21 +39,21 @@ struct shmid64_ds {
 #endif
        __kernel_pid_t          shm_cpid;       /* pid of creator */
        __kernel_pid_t          shm_lpid;       /* pid of last operator */
-       unsigned long           shm_nattch;     /* no. of current attaches */
-       unsigned long           __unused4;
-       unsigned long           __unused5;
+       __kernel_ulong_t        shm_nattch;     /* no. of current attaches */
+       __kernel_ulong_t        __unused4;
+       __kernel_ulong_t        __unused5;
 };
 
 struct shminfo64 {
-       unsigned long   shmmax;
-       unsigned long   shmmin;
-       unsigned long   shmmni;
-       unsigned long   shmseg;
-       unsigned long   shmall;
-       unsigned long   __unused1;
-       unsigned long   __unused2;
-       unsigned long   __unused3;
-       unsigned long   __unused4;
+       __kernel_ulong_t        shmmax;
+       __kernel_ulong_t        shmmin;
+       __kernel_ulong_t        shmmni;
+       __kernel_ulong_t        shmseg;
+       __kernel_ulong_t        shmall;
+       __kernel_ulong_t        __unused1;
+       __kernel_ulong_t        __unused2;
+       __kernel_ulong_t        __unused3;
+       __kernel_ulong_t        __unused4;
 };
 
 #endif /* __ASM_GENERIC_SHMBUF_H */
index 9b24d65fed72b9d06843cba89ebeeabff07fb71f..3c9a833992e872f095a4373d6cb5e33602129acc 100644 (file)
@@ -181,7 +181,6 @@ enum drm_map_type {
        _DRM_AGP = 3,             /**< AGP/GART */
        _DRM_SCATTER_GATHER = 4,  /**< Scatter/gather memory for PCI DMA */
        _DRM_CONSISTENT = 5,      /**< Consistent memory for PCI DMA */
-       _DRM_GEM = 6,             /**< GEM object (obsolete) */
 };
 
 /**
index 3a4e97bd860771b6ad8e3b5d026a35200fcad4d3..126bfaa8bb6be45caf723889c077673da8c992f4 100644 (file)
@@ -222,6 +222,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_I915_GEM_SET_CACHING       0x2f
 #define DRM_I915_GEM_GET_CACHING       0x30
 #define DRM_I915_REG_READ              0x31
+#define DRM_I915_GET_RESET_STATS       0x32
 
 #define DRM_IOCTL_I915_INIT            DRM_IOW( DRM_COMMAND_BASE + DRM_I915_INIT, drm_i915_init_t)
 #define DRM_IOCTL_I915_FLUSH           DRM_IO ( DRM_COMMAND_BASE + DRM_I915_FLUSH)
@@ -271,6 +272,7 @@ typedef struct _drm_i915_sarea {
 #define DRM_IOCTL_I915_GEM_CONTEXT_CREATE      DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_CREATE, struct drm_i915_gem_context_create)
 #define DRM_IOCTL_I915_GEM_CONTEXT_DESTROY     DRM_IOW (DRM_COMMAND_BASE + DRM_I915_GEM_CONTEXT_DESTROY, struct drm_i915_gem_context_destroy)
 #define DRM_IOCTL_I915_REG_READ                        DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_REG_READ, struct drm_i915_reg_read)
+#define DRM_IOCTL_I915_GET_RESET_STATS         DRM_IOWR (DRM_COMMAND_BASE + DRM_I915_GET_RESET_STATS, struct drm_i915_reset_stats)
 
 /* Allow drivers to submit batchbuffers directly to hardware, relying
  * on the security mechanisms provided by hardware.
@@ -719,7 +721,7 @@ struct drm_i915_gem_execbuffer2 {
  */
 #define I915_EXEC_IS_PINNED            (1<<10)
 
-/** Provide a hint to the kernel that the command stream and auxilliary
+/** Provide a hint to the kernel that the command stream and auxiliary
  * state buffers already holds the correct presumed addresses and so the
  * relocation process may be skipped if no buffers need to be moved in
  * preparation for the execbuffer.
@@ -1030,4 +1032,21 @@ struct drm_i915_reg_read {
        __u64 offset;
        __u64 val; /* Return value */
 };
+
+struct drm_i915_reset_stats {
+       __u32 ctx_id;
+       __u32 flags;
+
+       /* All resets since boot/module reload, for all contexts */
+       __u32 reset_count;
+
+       /* Number of batches lost when active in GPU, for this context */
+       __u32 batch_active;
+
+       /* Number of batches lost pending for execution, for this context */
+       __u32 batch_pending;
+
+       __u32 pad;
+};
+
 #endif /* _UAPI_I915_DRM_H_ */
index fe421e8a431bcf91dd1d5e845b5d06ce81bbe23d..d9ea3a73afe2d2a4df80ebebd23316df5077c346 100644 (file)
@@ -985,6 +985,8 @@ struct drm_radeon_cs {
 #define RADEON_INFO_CIK_MACROTILE_MODE_ARRAY   0x18
 /* query the number of render backends */
 #define RADEON_INFO_SI_BACKEND_ENABLED_MASK    0x19
+/* max engine clock - needed for OpenCL */
+#define RADEON_INFO_MAX_SCLK           0x1a
 
 
 struct drm_radeon_info {
index f854ca4a1372812dda6f71c20c8a84b3bdcfc19a..9971c560ed9aa42dc841e76b9586f05e25225d96 100644 (file)
 #ifndef __VMWGFX_DRM_H__
 #define __VMWGFX_DRM_H__
 
+#ifndef __KERNEL__
+#include <drm.h>
+#endif
+
 #define DRM_VMW_MAX_SURFACE_FACES 6
 #define DRM_VMW_MAX_MIP_LEVELS 24
 
 #define DRM_VMW_PRESENT              18
 #define DRM_VMW_PRESENT_READBACK     19
 #define DRM_VMW_UPDATE_LAYOUT        20
+#define DRM_VMW_CREATE_SHADER        21
+#define DRM_VMW_UNREF_SHADER         22
+#define DRM_VMW_GB_SURFACE_CREATE    23
+#define DRM_VMW_GB_SURFACE_REF       24
+#define DRM_VMW_SYNCCPU              25
 
 /*************************************************************************/
 /**
@@ -76,6 +85,8 @@
 #define DRM_VMW_PARAM_MAX_FB_SIZE      5
 #define DRM_VMW_PARAM_FIFO_HW_VERSION  6
 #define DRM_VMW_PARAM_MAX_SURF_MEMORY  7
+#define DRM_VMW_PARAM_3D_CAPS_SIZE     8
+#define DRM_VMW_PARAM_MAX_MOB_MEMORY   9
 
 /**
  * struct drm_vmw_getparam_arg
@@ -788,4 +799,253 @@ struct drm_vmw_update_layout_arg {
        uint64_t rects;
 };
 
+
+/*************************************************************************/
+/**
+ * DRM_VMW_CREATE_SHADER - Create shader
+ *
+ * Creates a shader and optionally binds it to a dma buffer containing
+ * the shader byte-code.
+ */
+
+/**
+ * enum drm_vmw_shader_type - Shader types
+ */
+enum drm_vmw_shader_type {
+       drm_vmw_shader_type_vs = 0,
+       drm_vmw_shader_type_ps,
+       drm_vmw_shader_type_gs
+};
+
+
+/**
+ * struct drm_vmw_shader_create_arg
+ *
+ * @shader_type: Shader type of the shader to create.
+ * @size: Size of the byte-code in bytes.
+ * where the shader byte-code starts
+ * @buffer_handle: Buffer handle identifying the buffer containing the
+ * shader byte-code
+ * @shader_handle: On successful completion contains a handle that
+ * can be used to subsequently identify the shader.
+ * @offset: Offset in bytes into the buffer given by @buffer_handle,
+ *
+ * Input / Output argument to the DRM_VMW_CREATE_SHADER Ioctl.
+ */
+struct drm_vmw_shader_create_arg {
+       enum drm_vmw_shader_type shader_type;
+       uint32_t size;
+       uint32_t buffer_handle;
+       uint32_t shader_handle;
+       uint64_t offset;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_UNREF_SHADER - Unreferences a shader
+ *
+ * Destroys a user-space reference to a shader, optionally destroying
+ * it.
+ */
+
+/**
+ * struct drm_vmw_shader_arg
+ *
+ * @handle: Handle identifying the shader to destroy.
+ *
+ * Input argument to the DRM_VMW_UNREF_SHADER ioctl.
+ */
+struct drm_vmw_shader_arg {
+       uint32_t handle;
+       uint32_t pad64;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_GB_SURFACE_CREATE - Create a host guest-backed surface.
+ *
+ * Allocates a surface handle and queues a create surface command
+ * for the host on the first use of the surface. The surface ID can
+ * be used as the surface ID in commands referencing the surface.
+ */
+
+/**
+ * enum drm_vmw_surface_flags
+ *
+ * @drm_vmw_surface_flag_shareable:     Whether the surface is shareable
+ * @drm_vmw_surface_flag_scanout:       Whether the surface is a scanout
+ *                                      surface.
+ * @drm_vmw_surface_flag_create_buffer: Create a backup buffer if none is
+ *                                      given.
+ */
+enum drm_vmw_surface_flags {
+       drm_vmw_surface_flag_shareable = (1 << 0),
+       drm_vmw_surface_flag_scanout = (1 << 1),
+       drm_vmw_surface_flag_create_buffer = (1 << 2)
+};
+
+/**
+ * struct drm_vmw_gb_surface_create_req
+ *
+ * @svga3d_flags:     SVGA3d surface flags for the device.
+ * @format:           SVGA3d format.
+ * @mip_level:        Number of mip levels for all faces.
+ * @drm_surface_flags Flags as described above.
+ * @multisample_count Future use. Set to 0.
+ * @autogen_filter    Future use. Set to 0.
+ * @buffer_handle     Buffer handle of backup buffer. SVGA3D_INVALID_ID
+ *                    if none.
+ * @base_size         Size of the base mip level for all faces.
+ *
+ * Input argument to the  DRM_VMW_GB_SURFACE_CREATE Ioctl.
+ * Part of output argument for the DRM_VMW_GB_SURFACE_REF Ioctl.
+ */
+struct drm_vmw_gb_surface_create_req {
+       uint32_t svga3d_flags;
+       uint32_t format;
+       uint32_t mip_levels;
+       enum drm_vmw_surface_flags drm_surface_flags;
+       uint32_t multisample_count;
+       uint32_t autogen_filter;
+       uint32_t buffer_handle;
+       uint32_t pad64;
+       struct drm_vmw_size base_size;
+};
+
+/**
+ * struct drm_vmw_gb_surface_create_rep
+ *
+ * @handle:            Surface handle.
+ * @backup_size:       Size of backup buffers for this surface.
+ * @buffer_handle:     Handle of backup buffer. SVGA3D_INVALID_ID if none.
+ * @buffer_size:       Actual size of the buffer identified by
+ *                     @buffer_handle
+ * @buffer_map_handle: Offset into device address space for the buffer
+ *                     identified by @buffer_handle.
+ *
+ * Part of output argument for the DRM_VMW_GB_SURFACE_REF ioctl.
+ * Output argument for the DRM_VMW_GB_SURFACE_CREATE ioctl.
+ */
+struct drm_vmw_gb_surface_create_rep {
+       uint32_t handle;
+       uint32_t backup_size;
+       uint32_t buffer_handle;
+       uint32_t buffer_size;
+       uint64_t buffer_map_handle;
+};
+
+/**
+ * union drm_vmw_gb_surface_create_arg
+ *
+ * @req: Input argument as described above.
+ * @rep: Output argument as described above.
+ *
+ * Argument to the DRM_VMW_GB_SURFACE_CREATE ioctl.
+ */
+union drm_vmw_gb_surface_create_arg {
+       struct drm_vmw_gb_surface_create_rep rep;
+       struct drm_vmw_gb_surface_create_req req;
+};
+
+/*************************************************************************/
+/**
+ * DRM_VMW_GB_SURFACE_REF - Reference a host surface.
+ *
+ * Puts a reference on a host surface with a given handle, as previously
+ * returned by the DRM_VMW_GB_SURFACE_CREATE ioctl.
+ * A reference will make sure the surface isn't destroyed while we hold
+ * it and will allow the calling client to use the surface handle in
+ * the command stream.
+ *
+ * On successful return, the Ioctl returns the surface information given
+ * to and returned from the DRM_VMW_GB_SURFACE_CREATE ioctl.
+ */
+
+/**
+ * struct drm_vmw_gb_surface_reference_arg
+ *
+ * @creq: The data used as input when the surface was created, as described
+ *        above at "struct drm_vmw_gb_surface_create_req"
+ * @crep: Additional data output when the surface was created, as described
+ *        above at "struct drm_vmw_gb_surface_create_rep"
+ *
+ * Output Argument to the DRM_VMW_GB_SURFACE_REF ioctl.
+ */
+struct drm_vmw_gb_surface_ref_rep {
+       struct drm_vmw_gb_surface_create_req creq;
+       struct drm_vmw_gb_surface_create_rep crep;
+};
+
+/**
+ * union drm_vmw_gb_surface_reference_arg
+ *
+ * @req: Input data as described above at "struct drm_vmw_surface_arg"
+ * @rep: Output data as described above at "struct drm_vmw_gb_surface_ref_rep"
+ *
+ * Argument to the DRM_VMW_GB_SURFACE_REF Ioctl.
+ */
+union drm_vmw_gb_surface_reference_arg {
+       struct drm_vmw_gb_surface_ref_rep rep;
+       struct drm_vmw_surface_arg req;
+};
+
+
+/*************************************************************************/
+/**
+ * DRM_VMW_SYNCCPU - Sync a DMA buffer / MOB for CPU access.
+ *
+ * Idles any previously submitted GPU operations on the buffer and
+ * by default blocks command submissions that reference the buffer.
+ * If the file descriptor used to grab a blocking CPU sync is closed, the
+ * cpu sync is released.
+ * The flags argument indicates how the grab / release operation should be
+ * performed:
+ */
+
+/**
+ * enum drm_vmw_synccpu_flags - Synccpu flags:
+ *
+ * @drm_vmw_synccpu_read: Sync for read. If sync is done for read only, it's a
+ * hint to the kernel to allow command submissions that references the buffer
+ * for read-only.
+ * @drm_vmw_synccpu_write: Sync for write. Block all command submissions
+ * referencing this buffer.
+ * @drm_vmw_synccpu_dontblock: Dont wait for GPU idle, but rather return
+ * -EBUSY should the buffer be busy.
+ * @drm_vmw_synccpu_allow_cs: Allow command submission that touches the buffer
+ * while the buffer is synced for CPU. This is similar to the GEM bo idle
+ * behavior.
+ */
+enum drm_vmw_synccpu_flags {
+       drm_vmw_synccpu_read = (1 << 0),
+       drm_vmw_synccpu_write = (1 << 1),
+       drm_vmw_synccpu_dontblock = (1 << 2),
+       drm_vmw_synccpu_allow_cs = (1 << 3)
+};
+
+/**
+ * enum drm_vmw_synccpu_op - Synccpu operations:
+ *
+ * @drm_vmw_synccpu_grab:    Grab the buffer for CPU operations
+ * @drm_vmw_synccpu_release: Release a previous grab.
+ */
+enum drm_vmw_synccpu_op {
+       drm_vmw_synccpu_grab,
+       drm_vmw_synccpu_release
+};
+
+/**
+ * struct drm_vmw_synccpu_arg
+ *
+ * @op:                             The synccpu operation as described above.
+ * @handle:                 Handle identifying the buffer object.
+ * @flags:                  Flags as described above.
+ */
+struct drm_vmw_synccpu_arg {
+       enum drm_vmw_synccpu_op op;
+       enum drm_vmw_synccpu_flags flags;
+       uint32_t handle;
+       uint32_t pad64;
+};
+
 #endif
index 164a7e2639886333bded7e9e0c5948c4c0c06da7..22b6ad31c706dae59544286faea5808d7b303342 100644 (file)
@@ -39,6 +39,7 @@ static inline void SET_##name(struct bkey *k, unsigned i, __u64 v)    \
 }
 
 #define KEY_SIZE_BITS          16
+#define KEY_MAX_U64S           8
 
 KEY_FIELD(KEY_PTRS,    high, 60, 3)
 KEY_FIELD(HEADER_SIZE, high, 58, 2)
@@ -118,7 +119,7 @@ static inline struct bkey *bkey_next(const struct bkey *k)
        return (struct bkey *) (d + bkey_u64s(k));
 }
 
-static inline struct bkey *bkey_last(const struct bkey *k, unsigned nr_keys)
+static inline struct bkey *bkey_idx(const struct bkey *k, unsigned nr_keys)
 {
        __u64 *d = (void *) k;
        return (struct bkey *) (d + nr_keys);
index 45e618921c612385c0c1b97f78fe0e19bac86056..1b8a0f4c95900b14e7d6f71fa54523409d3b2be6 100644 (file)
@@ -184,6 +184,12 @@ struct btrfs_ioctl_fs_info_args {
        __u64 reserved[124];                    /* pad to 1k */
 };
 
+struct btrfs_ioctl_feature_flags {
+       __u64 compat_flags;
+       __u64 compat_ro_flags;
+       __u64 incompat_flags;
+};
+
 /* balance control ioctl modes */
 #define BTRFS_BALANCE_CTL_PAUSE                1
 #define BTRFS_BALANCE_CTL_CANCEL       2
@@ -552,6 +558,7 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)
 #define BTRFS_IOC_DEFAULT_SUBVOL _IOW(BTRFS_IOCTL_MAGIC, 19, __u64)
 #define BTRFS_IOC_SPACE_INFO _IOWR(BTRFS_IOCTL_MAGIC, 20, \
                                    struct btrfs_ioctl_space_args)
+#define BTRFS_IOC_GLOBAL_RSV _IOR(BTRFS_IOCTL_MAGIC, 20, __u64)
 #define BTRFS_IOC_START_SYNC _IOR(BTRFS_IOCTL_MAGIC, 24, __u64)
 #define BTRFS_IOC_WAIT_SYNC  _IOW(BTRFS_IOCTL_MAGIC, 22, __u64)
 #define BTRFS_IOC_SNAP_CREATE_V2 _IOW(BTRFS_IOCTL_MAGIC, 23, \
@@ -606,5 +613,11 @@ static inline char *btrfs_err_str(enum btrfs_err_code err_code)
                                    struct btrfs_ioctl_dev_replace_args)
 #define BTRFS_IOC_FILE_EXTENT_SAME _IOWR(BTRFS_IOCTL_MAGIC, 54, \
                                         struct btrfs_ioctl_same_args)
+#define BTRFS_IOC_GET_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
+                                  struct btrfs_ioctl_feature_flags)
+#define BTRFS_IOC_SET_FEATURES _IOW(BTRFS_IOCTL_MAGIC, 57, \
+                                  struct btrfs_ioctl_feature_flags[2])
+#define BTRFS_IOC_GET_SUPPORTED_FEATURES _IOR(BTRFS_IOCTL_MAGIC, 57, \
+                                  struct btrfs_ioctl_feature_flags[3])
 
 #endif /* _UAPI_LINUX_BTRFS_H */
index f1f3dd5981b28ff73d5e52c2fb1606d174c3c5dd..84c517cbce902df6ba75be909c016b2da2fca3d5 100644 (file)
@@ -185,7 +185,8 @@ enum {
                                 * to clear media change status */
        FD_UNUSED_BIT,
        FD_DISK_CHANGED_BIT,    /* disk has been changed since last i/o */
-       FD_DISK_WRITABLE_BIT    /* disk is writable */
+       FD_DISK_WRITABLE_BIT,   /* disk is writable */
+       FD_OPEN_SHOULD_FAIL_BIT
 };
 
 #define FDSETDRVPRM _IOW(2, 0x90, struct floppy_drive_params)
index ed49574ad7573cc446e9ee722554998d3b3c8c34..d847c760e8f09c49fec028cbe3a7b599cee2e60f 100644 (file)
@@ -98,6 +98,7 @@ struct media_entity_desc {
 
 #define MEDIA_PAD_FL_SINK              (1 << 0)
 #define MEDIA_PAD_FL_SOURCE            (1 << 1)
+#define MEDIA_PAD_FL_MUST_CONNECT      (1 << 2)
 
 struct media_pad_desc {
        __u32 entity;           /* entity ID */
index 8b5a79615fbf16aaf21a3912697ddf7562346d81..d0a2b8e89813934725dd217da8081cff7d2ce813 100644 (file)
 #define MQ_BYTES_MAX   819200
 
 struct mq_attr {
-       long    mq_flags;       /* message queue flags                  */
-       long    mq_maxmsg;      /* maximum number of messages           */
-       long    mq_msgsize;     /* maximum message size                 */
-       long    mq_curmsgs;     /* number of messages currently queued  */
-       long    __reserved[4];  /* ignored for input, zeroed for output */
+       __kernel_long_t mq_flags;       /* message queue flags                  */
+       __kernel_long_t mq_maxmsg;      /* maximum number of messages           */
+       __kernel_long_t mq_msgsize;     /* maximum message size                 */
+       __kernel_long_t mq_curmsgs;     /* number of messages currently queued  */
+       __kernel_long_t __reserved[4];  /* ignored for input, zeroed for output */
 };
 
 /*
index 22d95c6854e0cb0fbadaafae1c681ed9ad805780..a70375526578039691cf324a68108b60e4876619 100644 (file)
@@ -34,8 +34,8 @@ struct msqid_ds {
 
 /* message buffer for msgsnd and msgrcv calls */
 struct msgbuf {
-       long mtype;         /* type of message */
-       char mtext[1];      /* message text */
+       __kernel_long_t mtype;          /* type of message */
+       char mtext[1];                  /* message text */
 };
 
 /* buffer for msgctl calls IPC_INFO, MSG_INFO */
index e0ed28477f48fa5fb05e50a8f65aaf8dd636ddb3..36fb3b5fb1817287a86290334a48dcca58801f73 100644 (file)
 struct rusage {
        struct timeval ru_utime;        /* user time used */
        struct timeval ru_stime;        /* system time used */
-       long    ru_maxrss;              /* maximum resident set size */
-       long    ru_ixrss;               /* integral shared memory size */
-       long    ru_idrss;               /* integral unshared data size */
-       long    ru_isrss;               /* integral unshared stack size */
-       long    ru_minflt;              /* page reclaims */
-       long    ru_majflt;              /* page faults */
-       long    ru_nswap;               /* swaps */
-       long    ru_inblock;             /* block input operations */
-       long    ru_oublock;             /* block output operations */
-       long    ru_msgsnd;              /* messages sent */
-       long    ru_msgrcv;              /* messages received */
-       long    ru_nsignals;            /* signals received */
-       long    ru_nvcsw;               /* voluntary context switches */
-       long    ru_nivcsw;              /* involuntary " */
+       __kernel_long_t ru_maxrss;      /* maximum resident set size */
+       __kernel_long_t ru_ixrss;       /* integral shared memory size */
+       __kernel_long_t ru_idrss;       /* integral unshared data size */
+       __kernel_long_t ru_isrss;       /* integral unshared stack size */
+       __kernel_long_t ru_minflt;      /* page reclaims */
+       __kernel_long_t ru_majflt;      /* page faults */
+       __kernel_long_t ru_nswap;       /* swaps */
+       __kernel_long_t ru_inblock;     /* block input operations */
+       __kernel_long_t ru_oublock;     /* block output operations */
+       __kernel_long_t ru_msgsnd;      /* messages sent */
+       __kernel_long_t ru_msgrcv;      /* messages received */
+       __kernel_long_t ru_nsignals;    /* signals received */
+       __kernel_long_t ru_nvcsw;       /* voluntary context switches */
+       __kernel_long_t ru_nivcsw;      /* involuntary " */
 };
 
 struct rlimit {
-       unsigned long   rlim_cur;
-       unsigned long   rlim_max;
+       __kernel_ulong_t        rlim_cur;
+       __kernel_ulong_t        rlim_max;
 };
 
 #define RLIM64_INFINITY                (~0ULL)
index ec36fa1a83a44ce26db2b8f1df203bfb33c85d5f..78b69413f582bec895e06084153c8eae2acfbf2a 100644 (file)
@@ -68,11 +68,11 @@ struct      shminfo {
 
 struct shm_info {
        int used_ids;
-       unsigned long shm_tot;  /* total allocated shm */
-       unsigned long shm_rss;  /* total resident shm */
-       unsigned long shm_swp;  /* total swapped shm */
-       unsigned long swap_attempts;
-       unsigned long swap_successes;
+       __kernel_ulong_t shm_tot;       /* total allocated shm */
+       __kernel_ulong_t shm_rss;       /* total resident shm */
+       __kernel_ulong_t shm_swp;       /* total swapped shm */
+       __kernel_ulong_t swap_attempts;
+       __kernel_ulong_t swap_successes;
 };
 
 
index a7ea81f13711e80f68cf52b6a626d7a09461886e..92685d8264449c515d69652ad6c9fc23eae28344 100644 (file)
  */
 struct timex {
        unsigned int modes;     /* mode selector */
-       long offset;            /* time offset (usec) */
-       long freq;              /* frequency offset (scaled ppm) */
-       long maxerror;          /* maximum error (usec) */
-       long esterror;          /* estimated error (usec) */
+       __kernel_long_t offset; /* time offset (usec) */
+       __kernel_long_t freq;   /* frequency offset (scaled ppm) */
+       __kernel_long_t maxerror;/* maximum error (usec) */
+       __kernel_long_t esterror;/* estimated error (usec) */
        int status;             /* clock command/status */
-       long constant;          /* pll time constant */
-       long precision;         /* clock precision (usec) (read only) */
-       long tolerance;         /* clock frequency tolerance (ppm)
-                                * (read only)
-                                */
+       __kernel_long_t constant;/* pll time constant */
+       __kernel_long_t precision;/* clock precision (usec) (read only) */
+       __kernel_long_t tolerance;/* clock frequency tolerance (ppm)
+                                  * (read only)
+                                  */
        struct timeval time;    /* (read only, except for ADJ_SETOFFSET) */
-       long tick;              /* (modified) usecs between clock ticks */
+       __kernel_long_t tick;   /* (modified) usecs between clock ticks */
 
-       long ppsfreq;           /* pps frequency (scaled ppm) (ro) */
-       long jitter;            /* pps jitter (us) (ro) */
+       __kernel_long_t ppsfreq;/* pps frequency (scaled ppm) (ro) */
+       __kernel_long_t jitter; /* pps jitter (us) (ro) */
        int shift;              /* interval duration (s) (shift) (ro) */
-       long stabil;            /* pps stability (scaled ppm) (ro) */
-       long jitcnt;            /* jitter limit exceeded (ro) */
-       long calcnt;            /* calibration intervals (ro) */
-       long errcnt;            /* calibration errors (ro) */
-       long stbcnt;            /* stability limit exceeded (ro) */
+       __kernel_long_t stabil;            /* pps stability (scaled ppm) (ro) */
+       __kernel_long_t jitcnt; /* jitter limit exceeded (ro) */
+       __kernel_long_t calcnt; /* calibration intervals (ro) */
+       __kernel_long_t errcnt; /* calibration errors (ro) */
+       __kernel_long_t stbcnt; /* stability limit exceeded (ro) */
 
        int tai;                /* TAI offset (ro) */
 
index 1666aabbbb868ae9a215794e36726bd37a6fe2bd..2cbe605bbe04f6d510aff6ac5b70d5d5b82e29dc 100644 (file)
@@ -164,6 +164,10 @@ enum v4l2_colorfx {
  * this driver */
 #define V4L2_CID_USER_TI_VPE_BASE              (V4L2_CID_USER_BASE + 0x1050)
 
+/* The base for the saa7134 driver controls.
+ * We reserve 16 controls for this driver. */
+#define V4L2_CID_USER_SAA7134_BASE             (V4L2_CID_USER_BASE + 0x1060)
+
 /* MPEG-class control IDs */
 /* The MPEG controls are applicable to all codec controls
  * and the 'MPEG' part of the define is historical */
@@ -554,6 +558,11 @@ enum v4l2_vp8_golden_frame_sel {
        V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_PREV           = 0,
        V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_USE_REF_PERIOD     = 1,
 };
+#define V4L2_CID_MPEG_VIDEO_VPX_MIN_QP                 (V4L2_CID_MPEG_BASE+507)
+#define V4L2_CID_MPEG_VIDEO_VPX_MAX_QP                 (V4L2_CID_MPEG_BASE+508)
+#define V4L2_CID_MPEG_VIDEO_VPX_I_FRAME_QP             (V4L2_CID_MPEG_BASE+509)
+#define V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP             (V4L2_CID_MPEG_BASE+510)
+#define V4L2_CID_MPEG_VIDEO_VPX_PROFILE                        (V4L2_CID_MPEG_BASE+511)
 
 /*  MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
 #define V4L2_CID_MPEG_CX2341X_BASE                             (V4L2_CTRL_CLASS_MPEG | 0x1000)
index a9601257bb431536bdcbe83584d5a3cec526cde8..b5c3aab6e82c7f312dacb0933bebb1d62e6b938c 100644 (file)
@@ -110,6 +110,9 @@ enum v4l2_mbus_pixelcode {
 
        /* S5C73M3 sensor specific interleaved UYVY and JPEG */
        V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 = 0x5001,
+
+       /* HSV - next is 0x6002 */
+       V4L2_MBUS_FMT_AHSV8888_1X32 = 0x6001,
 };
 
 /**
index 437f1b0f8937594c67601c3a4bda4505d03826d3..6ae7bbe988cce2dde1d1766a8dd0b86aafe58c9d 100644 (file)
@@ -207,8 +207,8 @@ enum v4l2_priority {
 struct v4l2_rect {
        __s32   left;
        __s32   top;
-       __s32   width;
-       __s32   height;
+       __u32   width;
+       __u32   height;
 };
 
 struct v4l2_fract {
diff --git a/include/uapi/linux/vsp1.h b/include/uapi/linux/vsp1.h
new file mode 100644 (file)
index 0000000..e18858f
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * vsp1.h
+ *
+ * Renesas R-Car VSP1 - User-space API
+ *
+ * Copyright (C) 2013 Renesas Corporation
+ *
+ * Contacts: Laurent Pinchart <laurent.pinchart@ideasonboard.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 __VSP1_USER_H__
+#define __VSP1_USER_H__
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+/*
+ * Private IOCTLs
+ *
+ * VIDIOC_VSP1_LUT_CONFIG - Configure the lookup table
+ */
+
+#define VIDIOC_VSP1_LUT_CONFIG \
+       _IOWR('V', BASE_VIDIOC_PRIVATE + 1, struct vsp1_lut_config)
+
+struct vsp1_lut_config {
+       u32 lut[256];
+};
+
+#endif /* __VSP1_USER_H__ */
index e4629b93bdd671821f1fd90b98d94a60669fa761..40bbc04b6f8162f6dbd51160a1018598c0c79c26 100644 (file)
@@ -20,6 +20,9 @@
 #define XATTR_MAC_OSX_PREFIX "osx."
 #define XATTR_MAC_OSX_PREFIX_LEN (sizeof(XATTR_MAC_OSX_PREFIX) - 1)
 
+#define XATTR_BTRFS_PREFIX "btrfs."
+#define XATTR_BTRFS_PREFIX_LEN (sizeof(XATTR_BTRFS_PREFIX) - 1)
+
 #define XATTR_SECURITY_PREFIX  "security."
 #define XATTR_SECURITY_PREFIX_LEN (sizeof(XATTR_SECURITY_PREFIX) - 1)
 
index 5acb1e4ac0d339cb0e71b62653f4bd5e70cdc638..7ad033dbc845eff5ce58a60dc69cf3f0bc77fe9f 100644 (file)
@@ -185,17 +185,21 @@ struct grant_frames {
 };
 extern struct grant_frames xen_auto_xlat_grant_frames;
 unsigned int gnttab_max_grant_frames(void);
-int gnttab_setup_auto_xlat_frames(unsigned long addr);
+int gnttab_setup_auto_xlat_frames(phys_addr_t addr);
 void gnttab_free_auto_xlat_frames(void);
 
 #define gnttab_map_vaddr(map) ((void *)(map.host_virt_addr))
 
 int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
-                   struct gnttab_map_grant_ref *kmap_ops,
                    struct page **pages, unsigned int count);
+int gnttab_map_refs_userspace(struct gnttab_map_grant_ref *map_ops,
+                             struct gnttab_map_grant_ref *kmap_ops,
+                             struct page **pages, unsigned int count);
 int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
-                     struct gnttab_map_grant_ref *kunmap_ops,
                      struct page **pages, unsigned int count);
+int gnttab_unmap_refs_userspace(struct gnttab_unmap_grant_ref *unmap_ops,
+                               struct gnttab_map_grant_ref *kunmap_ops,
+                               struct page **pages, unsigned int count);
 
 /* Perform a batch of grant map/copy operations. Retry every batch slot
  * for which the hypervisor returns GNTST_eagain. This is typically due
index 34a0a3bf2390dc162ee524c848cf44bd7b5a7a10..009a797dd24272afbe761c33f237287c9420be33 100644 (file)
@@ -284,7 +284,7 @@ config AUDIT
 
 config AUDITSYSCALL
        bool "Enable system-call auditing support"
-       depends on AUDIT && (X86 || PARISC || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || (ARM && AEABI && !OABI_COMPAT))
+       depends on AUDIT && (X86 || PARISC || PPC || S390 || IA64 || UML || SPARC64 || SUPERH || (ARM && AEABI && !OABI_COMPAT) || ALPHA)
        default y if SECURITY_SELINUX
        help
          Enable low-overhead system-call auditing infrastructure that
index 7c098ac9068a582af317596908390ad74011040e..a8227022e3a02210afaab0cc628729f80ca07af8 100644 (file)
@@ -13,7 +13,7 @@
 #include <linux/minix_fs.h>
 #include <linux/ext2_fs.h>
 #include <linux/romfs_fs.h>
-#include <linux/cramfs_fs.h>
+#include <uapi/linux/cramfs_fs.h>
 #include <linux/initrd.h>
 #include <linux/string.h>
 #include <linux/slab.h>
index 3f1f4e4b61f7618452a8c1a93e298bb409c2e054..2fd9cef70ee8aa86261d8e2439b1c2a50f130925 100644 (file)
@@ -92,8 +92,6 @@ static int kernel_init(void *);
 
 extern void init_IRQ(void);
 extern void fork_init(unsigned long);
-extern void mca_init(void);
-extern void sbus_init(void);
 extern void radix_tree_init(void);
 #ifndef CONFIG_DEBUG_RODATA
 static inline void mark_rodata_ro(void) { }
index 892f6585dd6014a7b1fb70cabd8f7ce0d2f9a4ad..f486b0096a67f32fe453cca13b40ad6268a76d45 100644 (file)
@@ -197,7 +197,7 @@ static inline int __put_compat_ipc_perm(struct ipc64_perm *p,
 static inline int get_compat_semid64_ds(struct semid64_ds *s64,
                                        struct compat_semid64_ds __user *up64)
 {
-       if (!access_ok (VERIFY_READ, up64, sizeof(*up64)))
+       if (!access_ok(VERIFY_READ, up64, sizeof(*up64)))
                return -EFAULT;
        return __get_compat_ipc64_perm(&s64->sem_perm, &up64->sem_perm);
 }
@@ -205,7 +205,7 @@ static inline int get_compat_semid64_ds(struct semid64_ds *s64,
 static inline int get_compat_semid_ds(struct semid64_ds *s,
                                      struct compat_semid_ds __user *up)
 {
-       if (!access_ok (VERIFY_READ, up, sizeof(*up)))
+       if (!access_ok(VERIFY_READ, up, sizeof(*up)))
                return -EFAULT;
        return __get_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
 }
@@ -215,7 +215,7 @@ static inline int put_compat_semid64_ds(struct semid64_ds *s64,
 {
        int err;
 
-       if (!access_ok (VERIFY_WRITE, up64, sizeof(*up64)))
+       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);
@@ -229,7 +229,7 @@ static inline int put_compat_semid_ds(struct semid64_ds *s,
 {
        int err;
 
-       if (!access_ok (VERIFY_WRITE, up, sizeof(*up)))
+       if (!access_ok(VERIFY_WRITE, up, sizeof(*up)))
                return -EFAULT;
        err  = __put_compat_ipc_perm(&s->sem_perm, &up->sem_perm);
        err |= __put_user(s->sem_otime, &up->sem_otime);
@@ -288,11 +288,11 @@ static long do_compat_semctl(int first, int second, int third, u32 pad)
                break;
 
        case IPC_SET:
-               if (version == IPC_64) {
+               if (version == IPC_64)
                        err = get_compat_semid64_ds(&s64, compat_ptr(pad));
-               } else {
+               else
                        err = get_compat_semid_ds(&s64, compat_ptr(pad));
-               }
+
                up64 = compat_alloc_user_space(sizeof(s64));
                if (copy_to_user(up64, &s64, sizeof(s64)))
                        err = -EFAULT;
@@ -376,12 +376,12 @@ COMPAT_SYSCALL_DEFINE6(ipc, u32, call, int, first, int, second,
                        struct compat_ipc_kludge ipck;
                        if (!uptr)
                                return -EINVAL;
-                       if (copy_from_user (&ipck, uptr, sizeof(ipck)))
+                       if (copy_from_user(&ipck, uptr, sizeof(ipck)))
                                return -EFAULT;
                        uptr = compat_ptr(ipck.msgp);
                        fifth = ipck.msgtyp;
                }
-               return do_msgrcv(first, uptr, second, fifth, third,
+               return do_msgrcv(first, uptr, second, (s32)fifth, third,
                                 compat_do_msg_fill);
        }
        case MSGGET:
@@ -515,11 +515,11 @@ long compat_sys_msgctl(int first, int second, void __user *uptr)
                break;
 
        case IPC_SET:
-               if (version == IPC_64) {
+               if (version == IPC_64)
                        err = get_compat_msqid64(&m64, uptr);
-               } else {
+               else
                        err = get_compat_msqid(&m64, uptr);
-               }
+
                if (err)
                        break;
                p = compat_alloc_user_space(sizeof(m64));
@@ -702,11 +702,11 @@ long compat_sys_shmctl(int first, int second, void __user *uptr)
 
 
        case IPC_SET:
-               if (version == IPC_64) {
+               if (version == IPC_64)
                        err = get_compat_shmid64_ds(&s64, uptr);
-               } else {
+               else
                        err = get_compat_shmid_ds(&s64, uptr);
-               }
+
                if (err)
                        break;
                p = compat_alloc_user_space(sizeof(s64));
index 380ea4fe08e7151c71c64a39eac8a9e92a2ea7ee..63d7c6de335bd3b4878f8f2cf65d1d9e3f7e9474 100644 (file)
@@ -64,7 +64,7 @@ asmlinkage long compat_sys_mq_open(const char __user *u_name,
        return sys_mq_open(u_name, oflag, mode, p);
 }
 
-static int compat_prepare_timeout(struct timespec __user * *p,
+static int compat_prepare_timeout(struct timespec __user **p,
                                  const struct compat_timespec __user *u)
 {
        struct timespec ts;
index b0e99deb6d05330482c8ec98f1a511f07f9fa5f1..17028648cfeb05fc4b76470ca343cd069a11bb02 100644 (file)
@@ -164,21 +164,21 @@ static struct ctl_table ipc_kern_table[] = {
        {
                .procname       = "shmmax",
                .data           = &init_ipc_ns.shm_ctlmax,
-               .maxlen         = sizeof (init_ipc_ns.shm_ctlmax),
+               .maxlen         = sizeof(init_ipc_ns.shm_ctlmax),
                .mode           = 0644,
                .proc_handler   = proc_ipc_doulongvec_minmax,
        },
        {
                .procname       = "shmall",
                .data           = &init_ipc_ns.shm_ctlall,
-               .maxlen         = sizeof (init_ipc_ns.shm_ctlall),
+               .maxlen         = sizeof(init_ipc_ns.shm_ctlall),
                .mode           = 0644,
                .proc_handler   = proc_ipc_doulongvec_minmax,
        },
        {
                .procname       = "shmmni",
                .data           = &init_ipc_ns.shm_ctlmni,
-               .maxlen         = sizeof (init_ipc_ns.shm_ctlmni),
+               .maxlen         = sizeof(init_ipc_ns.shm_ctlmni),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec,
        },
@@ -194,7 +194,7 @@ static struct ctl_table ipc_kern_table[] = {
        {
                .procname       = "msgmax",
                .data           = &init_ipc_ns.msg_ctlmax,
-               .maxlen         = sizeof (init_ipc_ns.msg_ctlmax),
+               .maxlen         = sizeof(init_ipc_ns.msg_ctlmax),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax,
                .extra1         = &zero,
@@ -203,7 +203,7 @@ static struct ctl_table ipc_kern_table[] = {
        {
                .procname       = "msgmni",
                .data           = &init_ipc_ns.msg_ctlmni,
-               .maxlen         = sizeof (init_ipc_ns.msg_ctlmni),
+               .maxlen         = sizeof(init_ipc_ns.msg_ctlmni),
                .mode           = 0644,
                .proc_handler   = proc_ipc_callback_dointvec_minmax,
                .extra1         = &zero,
@@ -212,7 +212,7 @@ static struct ctl_table ipc_kern_table[] = {
        {
                .procname       =  "msgmnb",
                .data           = &init_ipc_ns.msg_ctlmnb,
-               .maxlen         = sizeof (init_ipc_ns.msg_ctlmnb),
+               .maxlen         = sizeof(init_ipc_ns.msg_ctlmnb),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec_minmax,
                .extra1         = &zero,
@@ -221,7 +221,7 @@ static struct ctl_table ipc_kern_table[] = {
        {
                .procname       = "sem",
                .data           = &init_ipc_ns.sem_ctls,
-               .maxlen         = 4*sizeof (int),
+               .maxlen         = 4*sizeof(int),
                .mode           = 0644,
                .proc_handler   = proc_ipc_dointvec,
        },
index 95827ce2f3c78e76adfdef64278a227402356587..ccf1f9fd263acdfae7dc56a87bceddd3170f69d9 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Spinlocks:               Mohamed Abbas           (abbas.mohamed@intel.com)
  * Lockless receive & send, fd based notify:
- *                         Manfred Spraul          (manfred@colorfullife.com)
+ *                         Manfred Spraul          (manfred@colorfullife.com)
  *
  * Audit:                   George Wilson           (ltcgcw@us.ibm.com)
  *
@@ -73,7 +73,7 @@ struct mqueue_inode_info {
        struct mq_attr attr;
 
        struct sigevent notify;
-       struct pidnotify_owner;
+       struct pid *notify_owner;
        struct user_namespace *notify_user_ns;
        struct user_struct *user;       /* user who created, for accounting */
        struct sock *notify_sock;
@@ -92,7 +92,7 @@ static void remove_notification(struct mqueue_inode_info *info);
 
 static struct kmem_cache *mqueue_inode_cachep;
 
-static struct ctl_table_header * mq_sysctl_table;
+static struct ctl_table_header *mq_sysctl_table;
 
 static inline struct mqueue_inode_info *MQUEUE_I(struct inode *inode)
 {
@@ -466,13 +466,13 @@ out_unlock:
 
 static int mqueue_unlink(struct inode *dir, struct dentry *dentry)
 {
-       struct inode *inode = dentry->d_inode;
+       struct inode *inode = dentry->d_inode;
 
        dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
        dir->i_size -= DIRENT_SIZE;
-       drop_nlink(inode);
-       dput(dentry);
-       return 0;
+       drop_nlink(inode);
+       dput(dentry);
+       return 0;
 }
 
 /*
@@ -622,7 +622,7 @@ static struct ext_wait_queue *wq_get_first_waiter(
 
 static inline void set_cookie(struct sk_buff *skb, char code)
 {
-       ((char*)skb->data)[NOTIFY_COOKIE_LEN-1] = code;
+       ((char *)skb->data)[NOTIFY_COOKIE_LEN-1] = code;
 }
 
 /*
@@ -1303,11 +1303,11 @@ retry:
 out_fput:
        fdput(f);
 out:
-       if (sock) {
+       if (sock)
                netlink_detachskb(sock, nc);
-       } else if (nc) {
+       else if (nc)
                dev_kfree_skb(nc);
-       }
+
        return ret;
 }
 
index 558aa91186b6ced1a27b1e05b65c5ee129e0a175..245db1140ad66a2be47744f02ef0d80deea5006f 100644 (file)
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -253,8 +253,14 @@ static void expunge_all(struct msg_queue *msq, int res)
        struct msg_receiver *msr, *t;
 
        list_for_each_entry_safe(msr, t, &msq->q_receivers, r_list) {
-               msr->r_msg = NULL;
+               msr->r_msg = NULL; /* initialize expunge ordering */
                wake_up_process(msr->r_tsk);
+               /*
+                * Ensure that the wakeup is visible before setting r_msg as
+                * the receiving end depends on it: either spinning on a nil,
+                * or dealing with -EAGAIN cases. See lockless receive part 1
+                * and 2 in do_msgrcv().
+                */
                smp_mb();
                msr->r_msg = ERR_PTR(res);
        }
@@ -318,7 +324,7 @@ SYSCALL_DEFINE2(msgget, key_t, key, int, msgflg)
 static inline unsigned long
 copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
 {
-       switch(version) {
+       switch (version) {
        case IPC_64:
                return copy_to_user(buf, in, sizeof(*in));
        case IPC_OLD:
@@ -363,7 +369,7 @@ copy_msqid_to_user(void __user *buf, struct msqid64_ds *in, int version)
 static inline unsigned long
 copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
 {
-       switch(version) {
+       switch (version) {
        case IPC_64:
                if (copy_from_user(out, buf, sizeof(*out)))
                        return -EFAULT;
@@ -375,9 +381,9 @@ copy_msqid_from_user(struct msqid64_ds *out, void __user *buf, int version)
                if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
                        return -EFAULT;
 
-               out->msg_perm.uid       = tbuf_old.msg_perm.uid;
-               out->msg_perm.gid       = tbuf_old.msg_perm.gid;
-               out->msg_perm.mode      = tbuf_old.msg_perm.mode;
+               out->msg_perm.uid       = tbuf_old.msg_perm.uid;
+               out->msg_perm.gid       = tbuf_old.msg_perm.gid;
+               out->msg_perm.mode      = tbuf_old.msg_perm.mode;
 
                if (tbuf_old.msg_qbytes == 0)
                        out->msg_qbytes = tbuf_old.msg_lqbytes;
@@ -606,13 +612,13 @@ SYSCALL_DEFINE3(msgctl, int, msqid, int, cmd, struct msqid_ds __user *, buf)
 
 static int testmsg(struct msg_msg *msg, long type, int mode)
 {
-       switch(mode)
+       switch (mode)
        {
                case SEARCH_ANY:
                case SEARCH_NUMBER:
                        return 1;
                case SEARCH_LESSEQUAL:
-                       if (msg->m_type <=type)
+                       if (msg->m_type <= type)
                                return 1;
                        break;
                case SEARCH_EQUAL:
@@ -638,15 +644,22 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
 
                        list_del(&msr->r_list);
                        if (msr->r_maxsize < msg->m_ts) {
+                               /* initialize pipelined send ordering */
                                msr->r_msg = NULL;
                                wake_up_process(msr->r_tsk);
-                               smp_mb();
+                               smp_mb(); /* see barrier comment below */
                                msr->r_msg = ERR_PTR(-E2BIG);
                        } else {
                                msr->r_msg = NULL;
                                msq->q_lrpid = task_pid_vnr(msr->r_tsk);
                                msq->q_rtime = get_seconds();
                                wake_up_process(msr->r_tsk);
+                               /*
+                                * Ensure that the wakeup is visible before
+                                * setting r_msg, as the receiving end depends
+                                * on it. See lockless receive part 1 and 2 in
+                                * do_msgrcv().
+                                */
                                smp_mb();
                                msr->r_msg = msg;
 
@@ -654,6 +667,7 @@ static inline int pipelined_send(struct msg_queue *msq, struct msg_msg *msg)
                        }
                }
        }
+
        return 0;
 }
 
@@ -696,7 +710,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                        goto out_unlock0;
 
                /* raced with RMID? */
-               if (msq->q_perm.deleted) {
+               if (!ipc_valid_object(&msq->q_perm)) {
                        err = -EIDRM;
                        goto out_unlock0;
                }
@@ -716,6 +730,7 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                        goto out_unlock0;
                }
 
+               /* enqueue the sender and prepare to block */
                ss_add(msq, &s);
 
                if (!ipc_rcu_getref(msq)) {
@@ -731,7 +746,8 @@ long do_msgsnd(int msqid, long mtype, void __user *mtext,
                ipc_lock_object(&msq->q_perm);
 
                ipc_rcu_putref(msq, ipc_rcu_free);
-               if (msq->q_perm.deleted) {
+               /* raced with RMID? */
+               if (!ipc_valid_object(&msq->q_perm)) {
                        err = -EIDRM;
                        goto out_unlock0;
                }
@@ -909,7 +925,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
                ipc_lock_object(&msq->q_perm);
 
                /* raced with RMID? */
-               if (msq->q_perm.deleted) {
+               if (!ipc_valid_object(&msq->q_perm)) {
                        msg = ERR_PTR(-EIDRM);
                        goto out_unlock0;
                }
@@ -983,7 +999,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
                 * wake_up_process(). There is a race with exit(), see
                 * ipc/mqueue.c for the details.
                 */
-               msg = (struct msg_msg*)msr_d.r_msg;
+               msg = (struct msg_msg *)msr_d.r_msg;
                while (msg == NULL) {
                        cpu_relax();
                        msg = (struct msg_msg *)msr_d.r_msg;
@@ -1004,7 +1020,7 @@ long do_msgrcv(int msqid, void __user *buf, size_t bufsz, long msgtyp, int msgfl
                /* Lockless receive, part 4:
                 * Repeat test after acquiring the spinlock.
                 */
-               msg = (struct msg_msg*)msr_d.r_msg;
+               msg = (struct msg_msg *)msr_d.r_msg;
                if (msg != ERR_PTR(-EAGAIN))
                        goto out_unlock0;
 
index db9d241af133d770cb0a95a22cacf257f79b1215..bee5554173120780374e6b42228d13c786ceb315 100644 (file)
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -188,7 +188,7 @@ void sem_exit_ns(struct ipc_namespace *ns)
 }
 #endif
 
-void __init sem_init (void)
+void __init sem_init(void)
 {
        sem_init_ns(&init_ipc_ns);
        ipc_init_proc_interface("sysvipc/sem",
@@ -225,7 +225,7 @@ static void unmerge_queues(struct sem_array *sma)
 }
 
 /**
- * merge_queues - Merge single semop queues into global queue
+ * merge_queues - merge single semop queues into global queue
  * @sma: semaphore array
  *
  * This function merges all per-semaphore queues into the global queue.
@@ -394,7 +394,7 @@ static inline struct sem_array *sem_obtain_lock(struct ipc_namespace *ns,
        /* ipc_rmid() may have already freed the ID while sem_lock
         * was spinning: verify that the structure is still valid
         */
-       if (!ipcp->deleted)
+       if (ipc_valid_object(ipcp))
                return container_of(ipcp, struct sem_array, sem_perm);
 
        sem_unlock(sma, *locknum);
@@ -445,11 +445,11 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
  *     * call wake_up_process
  *     * set queue.status to the final value.
  * - the previously blocked thread checks queue.status:
- *     * if it's IN_WAKEUP, then it must wait until the value changes
- *     * if it's not -EINTR, then the operation was completed by
- *       update_queue. semtimedop can return queue.status without
- *       performing any operation on the sem array.
- *     * otherwise it must acquire the spinlock and check what's up.
+ *     * if it's IN_WAKEUP, then it must wait until the value changes
+ *     * if it's not -EINTR, then the operation was completed by
+ *       update_queue. semtimedop can return queue.status without
+ *       performing any operation on the sem array.
+ *     * otherwise it must acquire the spinlock and check what's up.
  *
  * The two-stage algorithm is necessary to protect against the following
  * races:
@@ -474,7 +474,6 @@ static inline void sem_rmid(struct ipc_namespace *ns, struct sem_array *s)
  *
  * Called with sem_ids.rwsem held (as a writer)
  */
-
 static int newary(struct ipc_namespace *ns, struct ipc_params *params)
 {
        int id;
@@ -491,12 +490,12 @@ static int newary(struct ipc_namespace *ns, struct ipc_params *params)
        if (ns->used_sems + nsems > ns->sc_semmns)
                return -ENOSPC;
 
-       size = sizeof (*sma) + nsems * sizeof (struct sem);
+       size = sizeof(*sma) + nsems * sizeof(struct sem);
        sma = ipc_rcu_alloc(size);
-       if (!sma) {
+       if (!sma)
                return -ENOMEM;
-       }
-       memset (sma, 0, size);
+
+       memset(sma, 0, size);
 
        sma->sem_perm.mode = (semflg & S_IRWXUGO);
        sma->sem_perm.key = key;
@@ -584,10 +583,11 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
        return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params);
 }
 
-/** perform_atomic_semop - Perform (if possible) a semaphore operation
+/**
+ * perform_atomic_semop - Perform (if possible) a semaphore operation
  * @sma: semaphore array
  * @sops: array with operations that should be checked
- * @nsems: number of sops
+ * @nsops: number of operations
  * @un: undo array
  * @pid: pid that did the change
  *
@@ -595,19 +595,18 @@ SYSCALL_DEFINE3(semget, key_t, key, int, nsems, int, semflg)
  * Returns 1 if the operation is impossible, the caller must sleep.
  * Negative values are error codes.
  */
-
 static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops,
                             int nsops, struct sem_undo *un, int pid)
 {
        int result, sem_op;
        struct sembuf *sop;
-       struct sem * curr;
+       struct sem *curr;
 
        for (sop = sops; sop < sops + nsops; sop++) {
                curr = sma->sem_base + sop->sem_num;
                sem_op = sop->sem_op;
                result = curr->semval;
-  
+
                if (!sem_op && result)
                        goto would_block;
 
@@ -616,25 +615,24 @@ static int perform_atomic_semop(struct sem_array *sma, struct sembuf *sops,
                        goto would_block;
                if (result > SEMVMX)
                        goto out_of_range;
+
                if (sop->sem_flg & SEM_UNDO) {
                        int undo = un->semadj[sop->sem_num] - sem_op;
-                       /*
-                        *      Exceeding the undo range is an error.
-                        */
+                       /* Exceeding the undo range is an error. */
                        if (undo < (-SEMAEM - 1) || undo > SEMAEM)
                                goto out_of_range;
+                       un->semadj[sop->sem_num] = undo;
                }
+
                curr->semval = result;
        }
 
        sop--;
        while (sop >= sops) {
                sma->sem_base[sop->sem_num].sempid = pid;
-               if (sop->sem_flg & SEM_UNDO)
-                       un->semadj[sop->sem_num] -= sop->sem_op;
                sop--;
        }
-       
+
        return 0;
 
 out_of_range:
@@ -650,7 +648,10 @@ would_block:
 undo:
        sop--;
        while (sop >= sops) {
-               sma->sem_base[sop->sem_num].semval -= sop->sem_op;
+               sem_op = sop->sem_op;
+               sma->sem_base[sop->sem_num].semval -= sem_op;
+               if (sop->sem_flg & SEM_UNDO)
+                       un->semadj[sop->sem_num] += sem_op;
                sop--;
        }
 
@@ -680,7 +681,7 @@ static void wake_up_sem_queue_prepare(struct list_head *pt,
 }
 
 /**
- * wake_up_sem_queue_do(pt) - do the actual wake-up
+ * wake_up_sem_queue_do - do the actual wake-up
  * @pt: list of tasks to be woken up
  *
  * Do the actual wake-up.
@@ -746,7 +747,7 @@ static int check_restart(struct sem_array *sma, struct sem_queue *q)
 }
 
 /**
- * wake_const_ops(sma, semnum, pt) - Wake up non-alter tasks
+ * wake_const_ops - wake up non-alter tasks
  * @sma: semaphore array.
  * @semnum: semaphore that was modified.
  * @pt: list head for the tasks that must be woken up.
@@ -796,15 +797,14 @@ static int wake_const_ops(struct sem_array *sma, int semnum,
 }
 
 /**
- * do_smart_wakeup_zero(sma, sops, nsops, pt) - wakeup all wait for zero tasks
+ * do_smart_wakeup_zero - wakeup all wait for zero tasks
  * @sma: semaphore array
  * @sops: operations that were performed
  * @nsops: number of operations
  * @pt: list head of the tasks that must be woken up.
  *
- * do_smart_wakeup_zero() checks all required queue for wait-for-zero
- * operations, based on the actual changes that were performed on the
- * semaphore array.
+ * Checks all required queue for wait-for-zero operations, based
+ * on the actual changes that were performed on the semaphore array.
  * The function returns 1 if at least one operation was completed successfully.
  */
 static int do_smart_wakeup_zero(struct sem_array *sma, struct sembuf *sops,
@@ -848,7 +848,7 @@ static int do_smart_wakeup_zero(struct sem_array *sma, struct sembuf *sops,
 
 
 /**
- * update_queue(sma, semnum): Look for tasks that can be completed.
+ * update_queue - look for tasks that can be completed.
  * @sma: semaphore array.
  * @semnum: semaphore that was modified.
  * @pt: list head for the tasks that must be woken up.
@@ -918,7 +918,7 @@ again:
 }
 
 /**
- * set_semotime(sma, sops) - set sem_otime
+ * set_semotime - set sem_otime
  * @sma: semaphore array
  * @sops: operations that modified the array, may be NULL
  *
@@ -936,7 +936,7 @@ static void set_semotime(struct sem_array *sma, struct sembuf *sops)
 }
 
 /**
- * do_smart_update(sma, sops, nsops, otime, pt) - optimized update_queue
+ * do_smart_update - optimized update_queue
  * @sma: semaphore array
  * @sops: operations that were performed
  * @nsops: number of operations
@@ -998,21 +998,21 @@ static void do_smart_update(struct sem_array *sma, struct sembuf *sops, int nsop
  * The counts we return here are a rough approximation, but still
  * warrant that semncnt+semzcnt>0 if the task is on the pending queue.
  */
-static int count_semncnt (struct sem_array * sma, ushort semnum)
+static int count_semncnt(struct sem_array *sma, ushort semnum)
 {
        int semncnt;
-       struct sem_queue * q;
+       struct sem_queue *q;
 
        semncnt = 0;
        list_for_each_entry(q, &sma->sem_base[semnum].pending_alter, list) {
-               struct sembuf * sops = q->sops;
+               struct sembuf *sops = q->sops;
                BUG_ON(sops->sem_num != semnum);
                if ((sops->sem_op < 0) && !(sops->sem_flg & IPC_NOWAIT))
                        semncnt++;
        }
 
        list_for_each_entry(q, &sma->pending_alter, list) {
-               struct sembuf * sops = q->sops;
+               struct sembuf *sops = q->sops;
                int nsops = q->nsops;
                int i;
                for (i = 0; i < nsops; i++)
@@ -1024,21 +1024,21 @@ static int count_semncnt (struct sem_array * sma, ushort semnum)
        return semncnt;
 }
 
-static int count_semzcnt (struct sem_array * sma, ushort semnum)
+static int count_semzcnt(struct sem_array *sma, ushort semnum)
 {
        int semzcnt;
-       struct sem_queue * q;
+       struct sem_queue *q;
 
        semzcnt = 0;
        list_for_each_entry(q, &sma->sem_base[semnum].pending_const, list) {
-               struct sembuf * sops = q->sops;
+               struct sembuf *sops = q->sops;
                BUG_ON(sops->sem_num != semnum);
                if ((sops->sem_op == 0) && !(sops->sem_flg & IPC_NOWAIT))
                        semzcnt++;
        }
 
        list_for_each_entry(q, &sma->pending_const, list) {
-               struct sembuf * sops = q->sops;
+               struct sembuf *sops = q->sops;
                int nsops = q->nsops;
                int i;
                for (i = 0; i < nsops; i++)
@@ -1108,7 +1108,7 @@ static void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
 
 static unsigned long copy_semid_to_user(void __user *buf, struct semid64_ds *in, int version)
 {
-       switch(version) {
+       switch (version) {
        case IPC_64:
                return copy_to_user(buf, in, sizeof(*in));
        case IPC_OLD:
@@ -1151,7 +1151,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
        int err;
        struct sem_array *sma;
 
-       switch(cmd) {
+       switch (cmd) {
        case IPC_INFO:
        case SEM_INFO:
        {
@@ -1162,7 +1162,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
                if (err)
                        return err;
                
-               memset(&seminfo,0,sizeof(seminfo));
+               memset(&seminfo, 0, sizeof(seminfo));
                seminfo.semmni = ns->sc_semmni;
                seminfo.semmns = ns->sc_semmns;
                seminfo.semmsl = ns->sc_semmsl;
@@ -1183,7 +1183,7 @@ static int semctl_nolock(struct ipc_namespace *ns, int semid,
                up_read(&sem_ids(ns).rwsem);
                if (copy_to_user(p, &seminfo, sizeof(struct seminfo))) 
                        return -EFAULT;
-               return (max_id < 0) ? 0: max_id;
+               return (max_id < 0) ? 0 : max_id;
        }
        case IPC_STAT:
        case SEM_STAT:
@@ -1239,7 +1239,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
 {
        struct sem_undo *un;
        struct sem_array *sma;
-       struct semcurr;
+       struct sem *curr;
        int err;
        struct list_head tasks;
        int val;
@@ -1282,7 +1282,7 @@ static int semctl_setval(struct ipc_namespace *ns, int semid, int semnum,
 
        sem_lock(sma, NULL, -1);
 
-       if (sma->sem_perm.deleted) {
+       if (!ipc_valid_object(&sma->sem_perm)) {
                sem_unlock(sma, -1);
                rcu_read_unlock();
                return -EIDRM;
@@ -1309,10 +1309,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                int cmd, void __user *p)
 {
        struct sem_array *sma;
-       struct semcurr;
+       struct sem *curr;
        int err, nsems;
        ushort fast_sem_io[SEMMSL_FAST];
-       ushortsem_io = fast_sem_io;
+       ushort *sem_io = fast_sem_io;
        struct list_head tasks;
 
        INIT_LIST_HEAD(&tasks);
@@ -1342,11 +1342,11 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                int i;
 
                sem_lock(sma, NULL, -1);
-               if (sma->sem_perm.deleted) {
+               if (!ipc_valid_object(&sma->sem_perm)) {
                        err = -EIDRM;
                        goto out_unlock;
                }
-               if(nsems > SEMMSL_FAST) {
+               if (nsems > SEMMSL_FAST) {
                        if (!ipc_rcu_getref(sma)) {
                                err = -EIDRM;
                                goto out_unlock;
@@ -1354,14 +1354,14 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                        sem_unlock(sma, -1);
                        rcu_read_unlock();
                        sem_io = ipc_alloc(sizeof(ushort)*nsems);
-                       if(sem_io == NULL) {
+                       if (sem_io == NULL) {
                                ipc_rcu_putref(sma, ipc_rcu_free);
                                return -ENOMEM;
                        }
 
                        rcu_read_lock();
                        sem_lock_and_putref(sma);
-                       if (sma->sem_perm.deleted) {
+                       if (!ipc_valid_object(&sma->sem_perm)) {
                                err = -EIDRM;
                                goto out_unlock;
                        }
@@ -1371,7 +1371,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                sem_unlock(sma, -1);
                rcu_read_unlock();
                err = 0;
-               if(copy_to_user(array, sem_io, nsems*sizeof(ushort)))
+               if (copy_to_user(array, sem_io, nsems*sizeof(ushort)))
                        err = -EFAULT;
                goto out_free;
        }
@@ -1386,15 +1386,15 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                }
                rcu_read_unlock();
 
-               if(nsems > SEMMSL_FAST) {
+               if (nsems > SEMMSL_FAST) {
                        sem_io = ipc_alloc(sizeof(ushort)*nsems);
-                       if(sem_io == NULL) {
+                       if (sem_io == NULL) {
                                ipc_rcu_putref(sma, ipc_rcu_free);
                                return -ENOMEM;
                        }
                }
 
-               if (copy_from_user (sem_io, p, nsems*sizeof(ushort))) {
+               if (copy_from_user(sem_io, p, nsems*sizeof(ushort))) {
                        ipc_rcu_putref(sma, ipc_rcu_free);
                        err = -EFAULT;
                        goto out_free;
@@ -1409,7 +1409,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                }
                rcu_read_lock();
                sem_lock_and_putref(sma);
-               if (sma->sem_perm.deleted) {
+               if (!ipc_valid_object(&sma->sem_perm)) {
                        err = -EIDRM;
                        goto out_unlock;
                }
@@ -1435,7 +1435,7 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                goto out_rcu_wakeup;
 
        sem_lock(sma, NULL, -1);
-       if (sma->sem_perm.deleted) {
+       if (!ipc_valid_object(&sma->sem_perm)) {
                err = -EIDRM;
                goto out_unlock;
        }
@@ -1449,10 +1449,10 @@ static int semctl_main(struct ipc_namespace *ns, int semid, int semnum,
                err = curr->sempid;
                goto out_unlock;
        case GETNCNT:
-               err = count_semncnt(sma,semnum);
+               err = count_semncnt(sma, semnum);
                goto out_unlock;
        case GETZCNT:
-               err = count_semzcnt(sma,semnum);
+               err = count_semzcnt(sma, semnum);
                goto out_unlock;
        }
 
@@ -1462,7 +1462,7 @@ out_rcu_wakeup:
        rcu_read_unlock();
        wake_up_sem_queue_do(&tasks);
 out_free:
-       if(sem_io != fast_sem_io)
+       if (sem_io != fast_sem_io)
                ipc_free(sem_io, sizeof(ushort)*nsems);
        return err;
 }
@@ -1470,7 +1470,7 @@ out_free:
 static inline unsigned long
 copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
 {
-       switch(version) {
+       switch (version) {
        case IPC_64:
                if (copy_from_user(out, buf, sizeof(*out)))
                        return -EFAULT;
@@ -1479,7 +1479,7 @@ copy_semid_from_user(struct semid64_ds *out, void __user *buf, int version)
            {
                struct semid_ds tbuf_old;
 
-               if(copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
+               if (copy_from_user(&tbuf_old, buf, sizeof(tbuf_old)))
                        return -EFAULT;
 
                out->sem_perm.uid       = tbuf_old.sem_perm.uid;
@@ -1506,7 +1506,7 @@ static int semctl_down(struct ipc_namespace *ns, int semid,
        struct semid64_ds semid64;
        struct kern_ipc_perm *ipcp;
 
-       if(cmd == IPC_SET) {
+       if (cmd == IPC_SET) {
                if (copy_semid_from_user(&semid64, p, version))
                        return -EFAULT;
        }
@@ -1566,7 +1566,7 @@ SYSCALL_DEFINE4(semctl, int, semid, int, semnum, int, cmd, unsigned long, arg)
        version = ipc_parse_version(&cmd);
        ns = current->nsproxy->ipc_ns;
 
-       switch(cmd) {
+       switch (cmd) {
        case IPC_INFO:
        case SEM_INFO:
        case IPC_STAT:
@@ -1634,7 +1634,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid)
 {
        struct sem_undo *un;
 
-       assert_spin_locked(&ulp->lock);
+       assert_spin_locked(&ulp->lock);
 
        un = __lookup_undo(ulp, semid);
        if (un) {
@@ -1645,7 +1645,7 @@ static struct sem_undo *lookup_undo(struct sem_undo_list *ulp, int semid)
 }
 
 /**
- * find_alloc_undo - Lookup (and if not present create) undo array
+ * find_alloc_undo - lookup (and if not present create) undo array
  * @ns: namespace
  * @semid: semaphore array id
  *
@@ -1670,7 +1670,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        spin_lock(&ulp->lock);
        un = lookup_undo(ulp, semid);
        spin_unlock(&ulp->lock);
-       if (likely(un!=NULL))
+       if (likely(un != NULL))
                goto out;
 
        /* no undo structure around - allocate one. */
@@ -1699,7 +1699,7 @@ static struct sem_undo *find_alloc_undo(struct ipc_namespace *ns, int semid)
        /* step 3: Acquire the lock on semaphore array */
        rcu_read_lock();
        sem_lock_and_putref(sma);
-       if (sma->sem_perm.deleted) {
+       if (!ipc_valid_object(&sma->sem_perm)) {
                sem_unlock(sma, -1);
                rcu_read_unlock();
                kfree(new);
@@ -1735,7 +1735,7 @@ out:
 
 
 /**
- * get_queue_result - Retrieve the result code from sem_queue
+ * get_queue_result - retrieve the result code from sem_queue
  * @q: Pointer to queue structure
  *
  * Retrieve the return code from the pending queue. If IN_WAKEUP is found in
@@ -1765,7 +1765,7 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
        int error = -EINVAL;
        struct sem_array *sma;
        struct sembuf fast_sops[SEMOPM_FAST];
-       struct sembufsops = fast_sops, *sop;
+       struct sembuf *sops = fast_sops, *sop;
        struct sem_undo *un;
        int undos = 0, alter = 0, max, locknum;
        struct sem_queue queue;
@@ -1779,13 +1779,13 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
                return -EINVAL;
        if (nsops > ns->sc_semopm)
                return -E2BIG;
-       if(nsops > SEMOPM_FAST) {
-               sops = kmalloc(sizeof(*sops)*nsops,GFP_KERNEL);
-               if(sops==NULL)
+       if (nsops > SEMOPM_FAST) {
+               sops = kmalloc(sizeof(*sops)*nsops, GFP_KERNEL);
+               if (sops == NULL)
                        return -ENOMEM;
        }
-       if (copy_from_user (sops, tsops, nsops * sizeof(*tsops))) {
-               error=-EFAULT;
+       if (copy_from_user(sops, tsops, nsops * sizeof(*tsops))) {
+               error =  -EFAULT;
                goto out_free;
        }
        if (timeout) {
@@ -1846,7 +1846,15 @@ SYSCALL_DEFINE4(semtimedop, int, semid, struct sembuf __user *, tsops,
 
        error = -EIDRM;
        locknum = sem_lock(sma, sops, nsops);
-       if (sma->sem_perm.deleted)
+       /*
+        * We eventually might perform the following check in a lockless
+        * fashion, considering ipc_valid_object() locking constraints.
+        * If nsops == 1 and there is no contention for sem_perm.lock, then
+        * only a per-semaphore lock is held and it's OK to proceed with the
+        * check below. More details on the fine grained locking scheme
+        * entangled here and why it's RMID race safe on comments at sem_lock()
+        */
+       if (!ipc_valid_object(&sma->sem_perm))
                goto out_unlock_free;
        /*
         * semid identifiers are not unique - find_alloc_undo may have
@@ -1959,10 +1967,8 @@ sleep_again:
         * If queue.status != -EINTR we are woken up by another process.
         * Leave without unlink_queue(), but with sem_unlock().
         */
-
-       if (error != -EINTR) {
+       if (error != -EINTR)
                goto out_unlock_free;
-       }
 
        /*
         * If an interrupt occurred we have to clean up the queue
@@ -1984,7 +1990,7 @@ out_rcu_wakeup:
        rcu_read_unlock();
        wake_up_sem_queue_do(&tasks);
 out_free:
-       if(sops != fast_sops)
+       if (sops != fast_sops)
                kfree(sops);
        return error;
 }
@@ -2068,7 +2074,7 @@ void exit_sem(struct task_struct *tsk)
 
                sem_lock(sma, NULL, -1);
                /* exit_sem raced with IPC_RMID, nothing to do */
-               if (sma->sem_perm.deleted) {
+               if (!ipc_valid_object(&sma->sem_perm)) {
                        sem_unlock(sma, -1);
                        rcu_read_unlock();
                        continue;
@@ -2093,7 +2099,7 @@ void exit_sem(struct task_struct *tsk)
 
                /* perform adjustments registered in un */
                for (i = 0; i < sma->sem_nsems; i++) {
-                       struct sem * semaphore = &sma->sem_base[i];
+                       struct sem *semaphore = &sma->sem_base[i];
                        if (un->semadj[i]) {
                                semaphore->semval += un->semadj[i];
                                /*
@@ -2107,7 +2113,7 @@ void exit_sem(struct task_struct *tsk)
                                 * Linux caps the semaphore value, both at 0
                                 * and at SEMVMX.
                                 *
-                                *      Manfred <manfred@colorfullife.com>
+                                *      Manfred <manfred@colorfullife.com>
                                 */
                                if (semaphore->semval < 0)
                                        semaphore->semval = 0;
index 7a51443a51d6421bd2a02a66ec18db98f6796dd3..76459616a7fafe7581d713a245c63e861a4cf631 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -67,7 +67,7 @@ static const struct vm_operations_struct shm_vm_ops;
 static int newseg(struct ipc_namespace *, struct ipc_params *);
 static void shm_open(struct vm_area_struct *vma);
 static void shm_close(struct vm_area_struct *vma);
-static void shm_destroy (struct ipc_namespace *ns, struct shmid_kernel *shp);
+static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp);
 #ifdef CONFIG_PROC_FS
 static int sysvipc_shm_proc_show(struct seq_file *s, void *it);
 #endif
@@ -91,7 +91,7 @@ static void do_shm_rmid(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp)
        struct shmid_kernel *shp;
        shp = container_of(ipcp, struct shmid_kernel, shm_perm);
 
-       if (shp->shm_nattch){
+       if (shp->shm_nattch) {
                shp->shm_perm.mode |= SHM_DEST;
                /* Do not find it any more */
                shp->shm_perm.key = IPC_PRIVATE;
@@ -116,7 +116,7 @@ static int __init ipc_ns_init(void)
 
 pure_initcall(ipc_ns_init);
 
-void __init shm_init (void)
+void __init shm_init(void)
 {
        ipc_init_proc_interface("sysvipc/shm",
 #if BITS_PER_LONG <= 32
@@ -248,7 +248,7 @@ static bool shm_may_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp)
  */
 static void shm_close(struct vm_area_struct *vma)
 {
-       struct file * file = vma->vm_file;
+       struct file *file = vma->vm_file;
        struct shm_file_data *sfd = shm_file_data(file);
        struct shmid_kernel *shp;
        struct ipc_namespace *ns = sfd->ns;
@@ -379,7 +379,7 @@ static struct mempolicy *shm_get_policy(struct vm_area_struct *vma,
 }
 #endif
 
-static int shm_mmap(struct file * file, struct vm_area_struct * vma)
+static int shm_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct shm_file_data *sfd = shm_file_data(file);
        int ret;
@@ -477,7 +477,6 @@ static const struct vm_operations_struct shm_vm_ops = {
  *
  * Called with shm_ids.rwsem held as a writer.
  */
-
 static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
 {
        key_t key = params->key;
@@ -486,7 +485,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        int error;
        struct shmid_kernel *shp;
        size_t numpages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
-       struct file * file;
+       struct file *file;
        char name[13];
        int id;
        vm_flags_t acctflag = 0;
@@ -512,7 +511,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
                return error;
        }
 
-       sprintf (name, "SYSV%08x", key);
+       sprintf(name, "SYSV%08x", key);
        if (shmflg & SHM_HUGETLB) {
                struct hstate *hs;
                size_t hugesize;
@@ -533,7 +532,7 @@ static int newseg(struct ipc_namespace *ns, struct ipc_params *params)
        } else {
                /*
                 * Do not allow no accounting for OVERCOMMIT_NEVER, even
-                * if it's asked for.
+                * if it's asked for.
                 */
                if  ((shmflg & SHM_NORESERVE) &&
                                sysctl_overcommit_memory != OVERCOMMIT_NEVER)
@@ -628,7 +627,7 @@ SYSCALL_DEFINE3(shmget, key_t, key, size_t, size, int, shmflg)
 
 static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version)
 {
-       switch(version) {
+       switch (version) {
        case IPC_64:
                return copy_to_user(buf, in, sizeof(*in));
        case IPC_OLD:
@@ -655,7 +654,7 @@ static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_
 static inline unsigned long
 copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version)
 {
-       switch(version) {
+       switch (version) {
        case IPC_64:
                if (copy_from_user(out, buf, sizeof(*out)))
                        return -EFAULT;
@@ -680,14 +679,14 @@ copy_shmid_from_user(struct shmid64_ds *out, void __user *buf, int version)
 
 static inline unsigned long copy_shminfo_to_user(void __user *buf, struct shminfo64 *in, int version)
 {
-       switch(version) {
+       switch (version) {
        case IPC_64:
                return copy_to_user(buf, in, sizeof(*in));
        case IPC_OLD:
            {
                struct shminfo out;
 
-               if(in->shmmax > INT_MAX)
+               if (in->shmmax > INT_MAX)
                        out.shmmax = INT_MAX;
                else
                        out.shmmax = (int)in->shmmax;
@@ -846,14 +845,14 @@ static int shmctl_nolock(struct ipc_namespace *ns, int shmid,
                shminfo.shmall = ns->shm_ctlall;
 
                shminfo.shmmin = SHMMIN;
-               if(copy_shminfo_to_user (buf, &shminfo, version))
+               if (copy_shminfo_to_user(buf, &shminfo, version))
                        return -EFAULT;
 
                down_read(&shm_ids(ns).rwsem);
                err = ipc_get_maxid(&shm_ids(ns));
                up_read(&shm_ids(ns).rwsem);
 
-               if(err<0)
+               if (err < 0)
                        err = 0;
                goto out;
        }
@@ -864,7 +863,7 @@ static int shmctl_nolock(struct ipc_namespace *ns, int shmid,
                memset(&shm_info, 0, sizeof(shm_info));
                down_read(&shm_ids(ns).rwsem);
                shm_info.used_ids = shm_ids(ns).in_use;
-               shm_get_stat (ns, &shm_info.shm_rss, &shm_info.shm_swp);
+               shm_get_stat(ns, &shm_info.shm_rss, &shm_info.shm_swp);
                shm_info.shm_tot = ns->shm_tot;
                shm_info.swap_attempts = 0;
                shm_info.swap_successes = 0;
@@ -975,6 +974,13 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
                        goto out_unlock1;
 
                ipc_lock_object(&shp->shm_perm);
+
+               /* check if shm_destroy() is tearing down shp */
+               if (!ipc_valid_object(&shp->shm_perm)) {
+                       err = -EIDRM;
+                       goto out_unlock0;
+               }
+
                if (!ns_capable(ns->user_ns, CAP_IPC_LOCK)) {
                        kuid_t euid = current_euid();
                        if (!uid_eq(euid, shp->shm_perm.uid) &&
@@ -989,13 +995,6 @@ SYSCALL_DEFINE3(shmctl, int, shmid, int, cmd, struct shmid_ds __user *, buf)
                }
 
                shm_file = shp->shm_file;
-
-               /* check if shm_destroy() is tearing down shp */
-               if (shm_file == NULL) {
-                       err = -EIDRM;
-                       goto out_unlock0;
-               }
-
                if (is_file_hugepages(shm_file))
                        goto out_unlock0;
 
@@ -1047,7 +1046,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
        struct shmid_kernel *shp;
        unsigned long addr;
        unsigned long size;
-       struct file * file;
+       struct file *file;
        int    err;
        unsigned long flags;
        unsigned long prot;
@@ -1116,7 +1115,7 @@ long do_shmat(int shmid, char __user *shmaddr, int shmflg, ulong *raddr,
        ipc_lock_object(&shp->shm_perm);
 
        /* check if shm_destroy() is tearing down shp */
-       if (shp->shm_file == NULL) {
+       if (!ipc_valid_object(&shp->shm_perm)) {
                ipc_unlock_object(&shp->shm_perm);
                err = -EIDRM;
                goto out_unlock;
index 3ae17a4ace5b9ba242fd1aa42543d64145e5cb7f..e1b4c6db8aa042d2a896426391b10af913ac7b4f 100644 (file)
@@ -110,15 +110,15 @@ static struct notifier_block ipc_memory_nb = {
 };
 
 /**
- *     ipc_init        -       initialise IPC subsystem
+ * ipc_init - initialise ipc subsystem
  *
- *     The various system5 IPC resources (semaphores, messages and shared
- *     memory) are initialised
- *     A callback routine is registered into the memory hotplug notifier
- *     chain: since msgmni scales to lowmem this callback routine will be
- *     called upon successful memory add / remove to recompute msmgni.
+ * The various sysv ipc resources (semaphores, messages and shared
+ * memory) are initialised.
+ *
+ * A callback routine is registered into the memory hotplug notifier
+ * chain: since msgmni scales to lowmem this callback routine will be
+ * called upon successful memory add / remove to recompute msmgni.
  */
 static int __init ipc_init(void)
 {
        sem_init();
@@ -131,39 +131,29 @@ static int __init ipc_init(void)
 __initcall(ipc_init);
 
 /**
- *     ipc_init_ids            -       initialise IPC identifiers
- *     @ids: Identifier set
+ * ipc_init_ids        - initialise ipc identifiers
+ * @ids: ipc identifier set
  *
- *     Set up the sequence range to use for the ipc identifier range (limited
- *     below IPCMNI) then initialise the ids idr.
+ * Set up the sequence range to use for the ipc identifier range (limited
+ * below IPCMNI) then initialise the ids idr.
  */
 void ipc_init_ids(struct ipc_ids *ids)
 {
-       init_rwsem(&ids->rwsem);
-
        ids->in_use = 0;
        ids->seq = 0;
        ids->next_id = -1;
-       {
-               int seq_limit = INT_MAX/SEQ_MULTIPLIER;
-               if (seq_limit > USHRT_MAX)
-                       ids->seq_max = USHRT_MAX;
-                else
-                       ids->seq_max = seq_limit;
-       }
-
+       init_rwsem(&ids->rwsem);
        idr_init(&ids->ipcs_idr);
 }
 
 #ifdef CONFIG_PROC_FS
 static const struct file_operations sysvipc_proc_fops;
 /**
- *     ipc_init_proc_interface -  Create a proc interface for sysipc types using a seq_file interface.
- *     @path: Path in procfs
- *     @header: Banner to be printed at the beginning of the file.
- *     @ids: ipc id table to iterate.
- *     @show: show routine.
+ * ipc_init_proc_interface -  create a proc interface for sysipc types using a seq_file interface.
+ * @path: Path in procfs
+ * @header: Banner to be printed at the beginning of the file.
+ * @ids: ipc id table to iterate.
+ * @show: show routine.
  */
 void __init ipc_init_proc_interface(const char *path, const char *header,
                int ids, int (*show)(struct seq_file *, void *))
@@ -184,23 +174,21 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
                               NULL,           /* parent dir */
                               &sysvipc_proc_fops,
                               iface);
-       if (!pde) {
+       if (!pde)
                kfree(iface);
-       }
 }
 #endif
 
 /**
- *     ipc_findkey     -       find a key in an ipc identifier set     
- *     @ids: Identifier set
- *     @key: The key to find
+ * ipc_findkey - find a key in an ipc identifier set
+ * @ids: ipc identifier set
+ * @key: key to find
  *     
- *     Requires ipc_ids.rwsem locked.
- *     Returns the LOCKED pointer to the ipc structure if found or NULL
- *     if not.
- *     If key is found ipc points to the owning ipc structure
+ * Returns the locked pointer to the ipc structure if found or NULL
+ * otherwise. If key is found ipc points to the owning ipc structure
+ *
+ * Called with ipc_ids.rwsem held.
  */
 static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
 {
        struct kern_ipc_perm *ipc;
@@ -227,12 +215,11 @@ static struct kern_ipc_perm *ipc_findkey(struct ipc_ids *ids, key_t key)
 }
 
 /**
- *     ipc_get_maxid   -       get the last assigned id
- *     @ids: IPC identifier set
+ * ipc_get_maxid - get the last assigned id
+ * @ids: ipc identifier set
  *
- *     Called with ipc_ids.rwsem held.
+ * Called with ipc_ids.rwsem held.
  */
-
 int ipc_get_maxid(struct ipc_ids *ids)
 {
        struct kern_ipc_perm *ipc;
@@ -258,19 +245,19 @@ int ipc_get_maxid(struct ipc_ids *ids)
 }
 
 /**
- *     ipc_addid       -       add an IPC identifier
- *     @ids: IPC identifier set
- *     @new: new IPC permission set
- *     @size: limit for the number of used ids
+ * ipc_addid - add an ipc identifier
+ * @ids: ipc identifier set
+ * @new: new ipc permission set
+ * @size: limit for the number of used ids
  *
- *     Add an entry 'new' to the IPC ids idr. The permissions object is
- *     initialised and the first free entry is set up and the id assigned
- *     is returned. The 'new' entry is returned in a locked state on success.
- *     On failure the entry is not locked and a negative err-code is returned.
+ * Add an entry 'new' to the ipc ids idr. The permissions object is
+ * initialised and the first free entry is set up and the id assigned
+ * is returned. The 'new' entry is returned in a locked state on success.
+ * On failure the entry is not locked and a negative err-code is returned.
  *
- *     Called with writer ipc_ids.rwsem held.
+ * Called with writer ipc_ids.rwsem held.
  */
-int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
+int ipc_addid(struct ipc_ids *ids, struct kern_ipc_perm *new, int size)
 {
        kuid_t euid;
        kgid_t egid;
@@ -286,7 +273,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
        idr_preload(GFP_KERNEL);
 
        spin_lock_init(&new->lock);
-       new->deleted = 0;
+       new->deleted = false;
        rcu_read_lock();
        spin_lock(&new->lock);
 
@@ -308,7 +295,7 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 
        if (next_id < 0) {
                new->seq = ids->seq++;
-               if (ids->seq > ids->seq_max)
+               if (ids->seq > IPCID_SEQ_MAX)
                        ids->seq = 0;
        } else {
                new->seq = ipcid_to_seqx(next_id);
@@ -320,14 +307,14 @@ int ipc_addid(struct ipc_ids* ids, struct kern_ipc_perm* new, int size)
 }
 
 /**
- *     ipcget_new      -       create a new ipc object
- *     @ns: namespace
- *     @ids: IPC identifer set
- *     @ops: the actual creation routine to call
- *     @params: its parameters
- *
- *     This routine is called by sys_msgget, sys_semget() and sys_shmget()
- *     when the key is IPC_PRIVATE.
+ * ipcget_new -        create a new ipc object
+ * @ns: ipc namespace
+ * @ids: ipc identifer set
+ * @ops: the actual creation routine to call
+ * @params: its parameters
+ *
+ * This routine is called by sys_msgget, sys_semget() and sys_shmget()
+ * when the key is IPC_PRIVATE.
  */
 static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
                struct ipc_ops *ops, struct ipc_params *params)
@@ -341,19 +328,19 @@ static int ipcget_new(struct ipc_namespace *ns, struct ipc_ids *ids,
 }
 
 /**
- *     ipc_check_perms -       check security and permissions for an IPC
- *     @ns: IPC namespace
- *     @ipcp: ipc permission set
- *     @ops: the actual security routine to call
- *     @params: its parameters
+ * ipc_check_perms - check security and permissions for an ipc object
+ * @ns: ipc namespace
+ * @ipcp: ipc permission set
+ * @ops: the actual security routine to call
+ * @params: its parameters
  *
- *     This routine is called by sys_msgget(), sys_semget() and sys_shmget()
- *      when the key is not IPC_PRIVATE and that key already exists in the
- *      ids IDR.
+ * This routine is called by sys_msgget(), sys_semget() and sys_shmget()
+ * when the key is not IPC_PRIVATE and that key already exists in the
+ * ds IDR.
  *
- *     On success, the IPC id is returned.
+ * On success, the ipc id is returned.
  *
- *     It is called with ipc_ids.rwsem and ipcp->lock held.
+ * It is called with ipc_ids.rwsem and ipcp->lock held.
  */
 static int ipc_check_perms(struct ipc_namespace *ns,
                           struct kern_ipc_perm *ipcp,
@@ -374,18 +361,18 @@ static int ipc_check_perms(struct ipc_namespace *ns,
 }
 
 /**
- *     ipcget_public   -       get an ipc object or create a new one
- *     @ns: namespace
- *     @ids: IPC identifer set
- *     @ops: the actual creation routine to call
- *     @params: its parameters
- *
- *     This routine is called by sys_msgget, sys_semget() and sys_shmget()
- *     when the key is not IPC_PRIVATE.
- *     It adds a new entry if the key is not found and does some permission
- *      / security checkings if the key is found.
- *
- *     On success, the ipc id is returned.
+ * ipcget_public - get an ipc object or create a new one
+ * @ns: ipc namespace
+ * @ids: ipc identifer set
+ * @ops: the actual creation routine to call
+ * @params: its parameters
+ *
+ * This routine is called by sys_msgget, sys_semget() and sys_shmget()
+ * when the key is not IPC_PRIVATE.
+ * It adds a new entry if the key is not found and does some permission
+ * / security checkings if the key is found.
+ *
+ * On success, the ipc id is returned.
  */
 static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
                struct ipc_ops *ops, struct ipc_params *params)
@@ -431,39 +418,33 @@ static int ipcget_public(struct ipc_namespace *ns, struct ipc_ids *ids,
 
 
 /**
- *     ipc_rmid        -       remove an IPC identifier
- *     @ids: IPC identifier set
- *     @ipcp: ipc perm structure containing the identifier to remove
+ * ipc_rmid - remove an ipc identifier
+ * @ids: ipc identifier set
+ * @ipcp: ipc perm structure containing the identifier to remove
  *
- *     ipc_ids.rwsem (as a writer) and the spinlock for this ID are held
- *     before this function is called, and remain locked on the exit.
+ * ipc_ids.rwsem (as a writer) and the spinlock for this ID are held
+ * before this function is called, and remain locked on the exit.
  */
 void ipc_rmid(struct ipc_ids *ids, struct kern_ipc_perm *ipcp)
 {
        int lid = ipcid_to_idx(ipcp->id);
 
        idr_remove(&ids->ipcs_idr, lid);
-
        ids->in_use--;
-
-       ipcp->deleted = 1;
-
-       return;
+       ipcp->deleted = true;
 }
 
 /**
- *     ipc_alloc       -       allocate ipc space
- *     @size: size desired
+ * ipc_alloc - allocate ipc space
+ * @size: size desired
  *
- *     Allocate memory from the appropriate pools and return a pointer to it.
- *     NULL is returned if the allocation fails
+ * Allocate memory from the appropriate pools and return a pointer to it.
+ * NULL is returned if the allocation fails
  */
 void *ipc_alloc(int size)
 {
        void *out;
-       if(size > PAGE_SIZE)
+       if (size > PAGE_SIZE)
                out = vmalloc(size);
        else
                out = kmalloc(size, GFP_KERNEL);
@@ -471,28 +452,27 @@ void *ipc_alloc(int size)
 }
 
 /**
- *     ipc_free        -       free ipc space
- *     @ptr: pointer returned by ipc_alloc
- *     @size: size of block
+ * ipc_free - free ipc space
+ * @ptr: pointer returned by ipc_alloc
+ * @size: size of block
  *
- *     Free a block created with ipc_alloc(). The caller must know the size
- *     used in the allocation call.
+ * Free a block created with ipc_alloc(). The caller must know the size
+ * used in the allocation call.
  */
-
-void ipc_free(void* ptr, int size)
+void ipc_free(void *ptr, int size)
 {
-       if(size > PAGE_SIZE)
+       if (size > PAGE_SIZE)
                vfree(ptr);
        else
                kfree(ptr);
 }
 
 /**
- *     ipc_rcu_alloc   -       allocate ipc and rcu space 
- *     @size: size desired
+ * ipc_rcu_alloc - allocate ipc and rcu space
+ * @size: size desired
  *
- *     Allocate memory for the rcu header structure +  the object.
- *     Returns the pointer to the object or NULL upon failure.
+ * Allocate memory for the rcu header structure +  the object.
+ * Returns the pointer to the object or NULL upon failure.
  */
 void *ipc_rcu_alloc(int size)
 {
@@ -534,17 +514,16 @@ void ipc_rcu_free(struct rcu_head *head)
 }
 
 /**
- *     ipcperms        -       check IPC permissions
- *     @ns: IPC namespace
- *     @ipcp: IPC permission set
- *     @flag: desired permission set.
+ * ipcperms - check ipc permissions
+ * @ns: ipc namespace
+ * @ipcp: ipc permission set
+ * @flag: desired permission set
  *
- *     Check user, group, other permissions for access
- *     to ipc resources. return 0 if allowed
+ * Check user, group, other permissions for access
+ * to ipc resources. return 0 if allowed
  *
- *     @flag will most probably be 0 or S_...UGO from <linux/stat.h>
+ * @flag will most probably be 0 or S_...UGO from <linux/stat.h>
  */
 int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
 {
        kuid_t euid = current_euid();
@@ -572,16 +551,14 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flag)
  */
 
 /**
- *     kernel_to_ipc64_perm    -       convert kernel ipc permissions to user
- *     @in: kernel permissions
- *     @out: new style IPC permissions
+ * kernel_to_ipc64_perm        - convert kernel ipc permissions to user
+ * @in: kernel permissions
+ * @out: new style ipc permissions
  *
- *     Turn the kernel object @in into a set of permissions descriptions
- *     for returning to userspace (@out).
+ * Turn the kernel object @in into a set of permissions descriptions
+ * for returning to userspace (@out).
  */
-
-void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
+void kernel_to_ipc64_perm(struct kern_ipc_perm *in, struct ipc64_perm *out)
 {
        out->key        = in->key;
        out->uid        = from_kuid_munged(current_user_ns(), in->uid);
@@ -593,15 +570,14 @@ void kernel_to_ipc64_perm (struct kern_ipc_perm *in, struct ipc64_perm *out)
 }
 
 /**
- *     ipc64_perm_to_ipc_perm  -       convert new ipc permissions to old
- *     @in: new style IPC permissions
- *     @out: old style IPC permissions
+ * ipc64_perm_to_ipc_perm - convert new ipc permissions to old
+ * @in: new style ipc permissions
+ * @out: old style ipc permissions
  *
- *     Turn the new style permissions object @in into a compatibility
- *     object and store it into the @out pointer.
+ * Turn the new style permissions object @in into a compatibility
+ * object and store it into the @out pointer.
  */
-void ipc64_perm_to_ipc_perm (struct ipc64_perm *in, struct ipc_perm *out)
+void ipc64_perm_to_ipc_perm(struct ipc64_perm *in, struct ipc_perm *out)
 {
        out->key        = in->key;
        SET_UID(out->uid, in->uid);
@@ -635,8 +611,8 @@ struct kern_ipc_perm *ipc_obtain_object(struct ipc_ids *ids, int id)
 }
 
 /**
- * ipc_lock - Lock an ipc structure without rwsem held
- * @ids: IPC identifier set
+ * ipc_lock - lock an ipc structure without rwsem held
+ * @ids: ipc identifier set
  * @id: ipc id to look for
  *
  * Look for an id in the ipc ids idr and lock the associated ipc object.
@@ -657,7 +633,7 @@ struct kern_ipc_perm *ipc_lock(struct ipc_ids *ids, int id)
        /* ipc_rmid() may have already freed the ID while ipc_lock
         * was spinning: here verify that the structure is still valid
         */
-       if (!out->deleted)
+       if (ipc_valid_object(out))
                return out;
 
        spin_unlock(&out->lock);
@@ -693,11 +669,11 @@ out:
 
 /**
  * ipcget - Common sys_*get() code
- * @ns : namsepace
- * @ids : IPC identifier set
- * @ops : operations to be called on ipc object creation, permission checks
- *        and further checks
- * @params : the parameters needed by the previous operations.
+ * @ns: namsepace
+ * @ids: ipc identifier set
+ * @ops: operations to be called on ipc object creation, permission checks
+ *       and further checks
+ * @params: the parameters needed by the previous operations.
  *
  * Common routine called by sys_msgget(), sys_semget() and sys_shmget().
  */
@@ -711,7 +687,7 @@ int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
 }
 
 /**
- * ipc_update_perm - update the permissions of an IPC.
+ * ipc_update_perm - update the permissions of an ipc object
  * @in:  the permission given as input.
  * @out: the permission of the ipc to set.
  */
@@ -732,7 +708,7 @@ int ipc_update_perm(struct ipc64_perm *in, struct kern_ipc_perm *out)
 
 /**
  * ipcctl_pre_down_nolock - retrieve an ipc and check permissions for some IPC_XXX cmd
- * @ns:  the ipc namespace
+ * @ns:  ipc namespace
  * @ids:  the table of ids where to look for the ipc
  * @id:   the id of the ipc to retrieve
  * @cmd:  the cmd to check
@@ -779,15 +755,14 @@ err:
 
 
 /**
- *     ipc_parse_version       -       IPC call version
- *     @cmd: pointer to command
+ * ipc_parse_version - ipc call version
+ * @cmd: pointer to command
  *
- *     Return IPC_64 for new style IPC and IPC_OLD for old style IPC. 
- *     The @cmd value is turned from an encoding command and version into
- *     just the command code.
+ * Return IPC_64 for new style IPC and IPC_OLD for old style IPC.
+ * The @cmd value is turned from an encoding command and version into
+ * just the command code.
  */
-int ipc_parse_version (int *cmd)
+int ipc_parse_version(int *cmd)
 {
        if (*cmd & IPC_64) {
                *cmd ^= IPC_64;
@@ -824,7 +799,7 @@ static struct kern_ipc_perm *sysvipc_find_ipc(struct ipc_ids *ids, loff_t pos,
        if (total >= ids->in_use)
                return NULL;
 
-       for ( ; pos < IPCMNI; pos++) {
+       for (; pos < IPCMNI; pos++) {
                ipc = idr_find(&ids->ipcs_idr, pos);
                if (ipc != NULL) {
                        *new_pos = pos + 1;
@@ -927,8 +902,10 @@ static int sysvipc_proc_open(struct inode *inode, struct file *file)
                goto out;
 
        ret = seq_open(file, &sysvipc_proc_seqops);
-       if (ret)
-               goto out_kfree;
+       if (ret) {
+               kfree(iter);
+               goto out;
+       }
 
        seq = file->private_data;
        seq->private = iter;
@@ -937,9 +914,6 @@ static int sysvipc_proc_open(struct inode *inode, struct file *file)
        iter->ns    = get_ipc_ns(current->nsproxy->ipc_ns);
 out:
        return ret;
-out_kfree:
-       kfree(iter);
-       goto out;
 }
 
 static int sysvipc_proc_release(struct inode *inode, struct file *file)
index 59d78aa949874aff138845ce13fb55c764205f9d..9c47d6f6c7b4b6c63b05b8a7c246ea3efcdeb0dc 100644 (file)
@@ -15,9 +15,9 @@
 
 #define SEQ_MULTIPLIER (IPCMNI)
 
-void sem_init (void);
-void msg_init (void);
-void shm_init (void);
+void sem_init(void);
+void msg_init(void);
+void shm_init(void);
 
 struct ipc_namespace;
 
@@ -100,6 +100,7 @@ void __init ipc_init_proc_interface(const char *path, const char *header,
 
 #define ipcid_to_idx(id) ((id) % SEQ_MULTIPLIER)
 #define ipcid_to_seqx(id) ((id) / SEQ_MULTIPLIER)
+#define IPCID_SEQ_MAX min_t(int, INT_MAX/SEQ_MULTIPLIER, USHRT_MAX)
 
 /* must be called with ids->rwsem acquired for writing */
 int ipc_addid(struct ipc_ids *, struct kern_ipc_perm *, int);
@@ -116,8 +117,8 @@ int ipcperms(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp, short flg);
 /* for rare, potentially huge allocations.
  * both function can sleep
  */
-voidipc_alloc(int size);
-void ipc_free(voidptr, int size);
+void *ipc_alloc(int size);
+void ipc_free(void *ptr, int size);
 
 /*
  * For allocation that need to be freed by RCU.
@@ -125,7 +126,7 @@ void ipc_free(void* ptr, int size);
  * getref increases the refcount, the putref call that reduces the recount
  * to 0 schedules the rcu destruction. Caller must guarantee locking.
  */
-voidipc_rcu_alloc(int size);
+void *ipc_rcu_alloc(int size);
 int ipc_rcu_getref(void *ptr);
 void ipc_rcu_putref(void *ptr, void (*func)(struct rcu_head *head));
 void ipc_rcu_free(struct rcu_head *head);
@@ -144,7 +145,7 @@ struct kern_ipc_perm *ipcctl_pre_down_nolock(struct ipc_namespace *ns,
   /* On IA-64, we always use the "64-bit version" of the IPC structures.  */ 
 # define ipc_parse_version(cmd)        IPC_64
 #else
-int ipc_parse_version (int *cmd);
+int ipc_parse_version(int *cmd);
 #endif
 
 extern void free_msg(struct msg_msg *msg);
@@ -185,6 +186,19 @@ static inline void ipc_unlock(struct kern_ipc_perm *perm)
        rcu_read_unlock();
 }
 
+/*
+ * ipc_valid_object() - helper to sort out IPC_RMID races for codepaths
+ * where the respective ipc_ids.rwsem is not being held down.
+ * Checks whether the ipc object is still around or if it's gone already, as
+ * ipc_rmid() may have already freed the ID while the ipc lock was spinning.
+ * Needs to be called with kern_ipc_perm.lock held -- exception made for one
+ * checkpoint case at sys_semtimedop() as noted in code commentary.
+ */
+static inline bool ipc_valid_object(struct kern_ipc_perm *perm)
+{
+       return !perm->deleted;
+}
+
 struct kern_ipc_perm *ipc_obtain_object_check(struct ipc_ids *ids, int id);
 int ipcget(struct ipc_namespace *ns, struct ipc_ids *ids,
                        struct ipc_ops *ops, struct ipc_params *params);
index 7d2f35e5df2f91c1ad0ec7a37741582929c22fec..334b3980ffc14d396e25ccb11644f7f038cbe6e4 100644 (file)
@@ -736,7 +736,8 @@ int kgdb_nmicallback(int cpu, void *regs)
        return 1;
 }
 
-int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *send_ready)
+int kgdb_nmicallin(int cpu, int trapnr, void *regs, int err_code,
+                                                       atomic_t *send_ready)
 {
 #ifdef CONFIG_SMP
        if (!kgdb_io_ready(0) || !send_ready)
@@ -750,7 +751,7 @@ int kgdb_nmicallin(int cpu, int trapnr, void *regs, atomic_t *send_ready)
                ks->cpu                 = cpu;
                ks->ex_vector           = trapnr;
                ks->signo               = SIGTRAP;
-               ks->err_code            = KGDB_KDB_REASON_SYSTEM_NMI;
+               ks->err_code            = err_code;
                ks->linux_regs          = regs;
                ks->send_ready          = send_ready;
                kgdb_cpu_enter(ks, regs, DCPU_WANT_MASTER);
index 572aa4f5677cb7c6034a72e040a6c0b9bd4fcb34..127d9bc49fb4b24ea6824b12f73befc7fe870012 100644 (file)
@@ -75,13 +75,11 @@ extern int kdb_stub(struct kgdb_state *ks);
 extern int kdb_parse(const char *cmdstr);
 extern int kdb_common_init_state(struct kgdb_state *ks);
 extern int kdb_common_deinit_state(void);
-#define KGDB_KDB_REASON_SYSTEM_NMI KDB_REASON_SYSTEM_NMI
 #else /* ! CONFIG_KGDB_KDB */
 static inline int kdb_stub(struct kgdb_state *ks)
 {
        return DBG_PASS_EVENT;
 }
-#define KGDB_KDB_REASON_SYSTEM_NMI 0
 #endif /* CONFIG_KGDB_KDB */
 
 #endif /* _DEBUG_CORE_H_ */
index 9328b80eaf14c347bb188bee856154ea07b86168..0b9c169d577f967ab04750d32d2639a5e7d2bc6f 100644 (file)
@@ -37,7 +37,7 @@ int __read_mostly sysctl_hung_task_check_count = PID_MAX_LIMIT;
  */
 unsigned long __read_mostly sysctl_hung_task_timeout_secs = CONFIG_DEFAULT_HUNG_TASK_TIMEOUT;
 
-unsigned long __read_mostly sysctl_hung_task_warnings = 10;
+int __read_mostly sysctl_hung_task_warnings = 10;
 
 static int __read_mostly did_panic;
 
@@ -98,7 +98,9 @@ static void check_hung_task(struct task_struct *t, unsigned long timeout)
 
        if (!sysctl_hung_task_warnings)
                return;
-       sysctl_hung_task_warnings--;
+
+       if (sysctl_hung_task_warnings > 0)
+               sysctl_hung_task_warnings--;
 
        /*
         * Ok, the task did not get scheduled for more than 2 minutes,
index ac738781d35686601e793a6901f7d677086357c0..60bafbed06abd7a7b2defd0c031ca18b7287a37e 100644 (file)
@@ -1537,7 +1537,7 @@ void vmcoreinfo_append_str(const char *fmt, ...)
        size_t r;
 
        va_start(args, fmt);
-       r = vsnprintf(buf, sizeof(buf), fmt, args);
+       r = vscnprintf(buf, sizeof(buf), fmt, args);
        va_end(args);
 
        r = min(r, vmcoreinfo_max_size - vmcoreinfo_size);
index d09dd10c5a5efc2c206a85bd31a431268e37cc7f..9a58bc2588105900d79ec27c46bdcb8374c32cbc 100644 (file)
@@ -32,7 +32,7 @@ static int submit(int rw, struct block_device *bdev, sector_t sector,
        struct bio *bio;
 
        bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
-       bio->bi_sector = sector;
+       bio->bi_iter.bi_sector = sector;
        bio->bi_bdev = bdev;
        bio->bi_end_io = end_swap_bio_read;
 
index 802365ccd591826a60e08009a3927c9bed8c69bf..c54609faf233ba21a49835d32a9132eb56853f14 100644 (file)
@@ -200,17 +200,6 @@ void wait_rcu_gp(call_rcu_func_t crf)
 }
 EXPORT_SYMBOL_GPL(wait_rcu_gp);
 
-#ifdef CONFIG_PROVE_RCU
-/*
- * wrapper function to avoid #include problems.
- */
-int rcu_my_thread_group_empty(void)
-{
-       return thread_group_empty(current);
-}
-EXPORT_SYMBOL_GPL(rcu_my_thread_group_empty);
-#endif /* #ifdef CONFIG_PROVE_RCU */
-
 #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD
 static inline void debug_init_rcu_head(struct rcu_head *head)
 {
index 7fea865a810da70b72a8ae247bda8064f5b58193..b46131ef6aab0ac48149482a03f8354330adf188 100644 (file)
@@ -2476,7 +2476,7 @@ u64 scheduler_tick_max_deferment(void)
        if (time_before_eq(next, now))
                return 0;
 
-       return jiffies_to_usecs(next - now) * NSEC_PER_USEC;
+       return jiffies_to_nsecs(next - now);
 }
 #endif
 
@@ -4347,7 +4347,9 @@ SYSCALL_DEFINE2(sched_rr_get_interval, pid_t, pid,
                goto out_unlock;
 
        rq = task_rq_lock(p, &flags);
-       time_slice = p->sched_class->get_rr_interval(rq, p);
+       time_slice = 0;
+       if (p->sched_class->get_rr_interval)
+               time_slice = p->sched_class->get_rr_interval(rq, p);
        task_rq_unlock(rq, p, &flags);
 
        rcu_read_unlock();
index 0de248202879311be46a10b0ab855cba0c512ce6..0dd5e0971a0778a3e09ee8a91f5851dfa1dc25a9 100644 (file)
@@ -351,7 +351,8 @@ static void replenish_dl_entity(struct sched_dl_entity *dl_se,
  * disrupting the schedulability of the system. Otherwise, we should
  * refill the runtime and set the deadline a period in the future,
  * because keeping the current (absolute) deadline of the task would
- * result in breaking guarantees promised to other tasks.
+ * result in breaking guarantees promised to other tasks (refer to
+ * Documentation/scheduler/sched-deadline.txt for more informations).
  *
  * This function returns true if:
  *
index bd9f940288388f6986ce5c8b7f4311ca7471d287..ffee35bef1793107c33c31d7845e4b9c5e9e43d9 100644 (file)
@@ -23,17 +23,11 @@ enum {
 struct call_function_data {
        struct call_single_data __percpu *csd;
        cpumask_var_t           cpumask;
-       cpumask_var_t           cpumask_ipi;
 };
 
 static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_function_data, cfd_data);
 
-struct call_single_queue {
-       struct list_head        list;
-       raw_spinlock_t          lock;
-};
-
-static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_single_queue, call_single_queue);
+static DEFINE_PER_CPU_SHARED_ALIGNED(struct llist_head, call_single_queue);
 
 static int
 hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
@@ -47,14 +41,8 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
                if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,
                                cpu_to_node(cpu)))
                        return notifier_from_errno(-ENOMEM);
-               if (!zalloc_cpumask_var_node(&cfd->cpumask_ipi, GFP_KERNEL,
-                               cpu_to_node(cpu))) {
-                       free_cpumask_var(cfd->cpumask);
-                       return notifier_from_errno(-ENOMEM);
-               }
                cfd->csd = alloc_percpu(struct call_single_data);
                if (!cfd->csd) {
-                       free_cpumask_var(cfd->cpumask_ipi);
                        free_cpumask_var(cfd->cpumask);
                        return notifier_from_errno(-ENOMEM);
                }
@@ -67,7 +55,6 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
        case CPU_DEAD:
        case CPU_DEAD_FROZEN:
                free_cpumask_var(cfd->cpumask);
-               free_cpumask_var(cfd->cpumask_ipi);
                free_percpu(cfd->csd);
                break;
 #endif
@@ -85,12 +72,8 @@ void __init call_function_init(void)
        void *cpu = (void *)(long)smp_processor_id();
        int i;
 
-       for_each_possible_cpu(i) {
-               struct call_single_queue *q = &per_cpu(call_single_queue, i);
-
-               raw_spin_lock_init(&q->lock);
-               INIT_LIST_HEAD(&q->list);
-       }
+       for_each_possible_cpu(i)
+               init_llist_head(&per_cpu(call_single_queue, i));
 
        hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu);
        register_cpu_notifier(&hotplug_cfd_notifier);
@@ -141,18 +124,9 @@ static void csd_unlock(struct call_single_data *csd)
  */
 static void generic_exec_single(int cpu, struct call_single_data *csd, int wait)
 {
-       struct call_single_queue *dst = &per_cpu(call_single_queue, cpu);
-       unsigned long flags;
-       int ipi;
-
        if (wait)
                csd->flags |= CSD_FLAG_WAIT;
 
-       raw_spin_lock_irqsave(&dst->lock, flags);
-       ipi = list_empty(&dst->list);
-       list_add_tail(&csd->list, &dst->list);
-       raw_spin_unlock_irqrestore(&dst->lock, flags);
-
        /*
         * The list addition should be visible before sending the IPI
         * handler locks the list to pull the entry off it because of
@@ -164,7 +138,7 @@ static void generic_exec_single(int cpu, struct call_single_data *csd, int wait)
         * locking and barrier primitives. Generic code isn't really
         * equipped to do the right thing...
         */
-       if (ipi)
+       if (llist_add(&csd->llist, &per_cpu(call_single_queue, cpu)))
                arch_send_call_function_single_ipi(cpu);
 
        if (wait)
@@ -177,27 +151,26 @@ static void generic_exec_single(int cpu, struct call_single_data *csd, int wait)
  */
 void generic_smp_call_function_single_interrupt(void)
 {
-       struct call_single_queue *q = &__get_cpu_var(call_single_queue);
-       LIST_HEAD(list);
+       struct llist_node *entry, *next;
 
        /*
         * Shouldn't receive this interrupt on a cpu that is not yet online.
         */
        WARN_ON_ONCE(!cpu_online(smp_processor_id()));
 
-       raw_spin_lock(&q->lock);
-       list_replace_init(&q->list, &list);
-       raw_spin_unlock(&q->lock);
+       entry = llist_del_all(&__get_cpu_var(call_single_queue));
+       entry = llist_reverse_order(entry);
 
-       while (!list_empty(&list)) {
+       while (entry) {
                struct call_single_data *csd;
 
-               csd = list_entry(list.next, struct call_single_data, list);
-               list_del(&csd->list);
+               next = entry->next;
 
+               csd = llist_entry(entry, struct call_single_data, llist);
                csd->func(csd->info);
-
                csd_unlock(csd);
+
+               entry = next;
        }
 }
 
@@ -402,30 +375,17 @@ void smp_call_function_many(const struct cpumask *mask,
        if (unlikely(!cpumask_weight(cfd->cpumask)))
                return;
 
-       /*
-        * After we put an entry into the list, cfd->cpumask may be cleared
-        * again when another CPU sends another IPI for a SMP function call, so
-        * cfd->cpumask will be zero.
-        */
-       cpumask_copy(cfd->cpumask_ipi, cfd->cpumask);
-
        for_each_cpu(cpu, cfd->cpumask) {
                struct call_single_data *csd = per_cpu_ptr(cfd->csd, cpu);
-               struct call_single_queue *dst =
-                                       &per_cpu(call_single_queue, cpu);
-               unsigned long flags;
 
                csd_lock(csd);
                csd->func = func;
                csd->info = info;
-
-               raw_spin_lock_irqsave(&dst->lock, flags);
-               list_add_tail(&csd->list, &dst->list);
-               raw_spin_unlock_irqrestore(&dst->lock, flags);
+               llist_add(&csd->llist, &per_cpu(call_single_queue, cpu));
        }
 
        /* Send a message to all CPUs in the map */
-       arch_send_call_function_ipi_mask(cfd->cpumask_ipi);
+       arch_send_call_function_ipi_mask(cfd->cpumask);
 
        if (wait) {
                for_each_cpu(cpu, cfd->cpumask) {
index 8a1e6e104892daff68dded8f7ff2af9d72f3dd1e..490fcbb1dc5b41727408d28e17ae145754c2c051 100644 (file)
@@ -8,6 +8,8 @@
  *     Rewritten. Old one was good in 2.2, but in 2.3 it was immoral. --ANK (990903)
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/export.h>
 #include <linux/kernel_stat.h>
 #include <linux/interrupt.h>
@@ -54,7 +56,7 @@ static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp
 
 DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
 
-char *softirq_to_name[NR_SOFTIRQS] = {
+const char * const softirq_to_name[NR_SOFTIRQS] = {
        "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL",
        "TASKLET", "SCHED", "HRTIMER", "RCU"
 };
@@ -136,7 +138,6 @@ void _local_bh_enable(void)
        WARN_ON_ONCE(in_irq());
        __local_bh_enable(SOFTIRQ_DISABLE_OFFSET);
 }
-
 EXPORT_SYMBOL(_local_bh_enable);
 
 void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
@@ -153,7 +154,7 @@ void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
        /*
         * Keep preemption disabled until we are done with
         * softirq processing:
-        */
+        */
        preempt_count_sub(cnt - 1);
 
        if (unlikely(!in_interrupt() && local_softirq_pending())) {
@@ -229,6 +230,7 @@ asmlinkage void __do_softirq(void)
        struct softirq_action *h;
        bool in_hardirq;
        __u32 pending;
+       int softirq_bit;
        int cpu;
 
        /*
@@ -253,30 +255,30 @@ restart:
 
        h = softirq_vec;
 
-       do {
-               if (pending & 1) {
-                       unsigned int vec_nr = h - softirq_vec;
-                       int prev_count = preempt_count();
-
-                       kstat_incr_softirqs_this_cpu(vec_nr);
-
-                       trace_softirq_entry(vec_nr);
-                       h->action(h);
-                       trace_softirq_exit(vec_nr);
-                       if (unlikely(prev_count != preempt_count())) {
-                               printk(KERN_ERR "huh, entered softirq %u %s %p"
-                                      "with preempt_count %08x,"
-                                      " exited with %08x?\n", vec_nr,
-                                      softirq_to_name[vec_nr], h->action,
-                                      prev_count, preempt_count());
-                               preempt_count_set(prev_count);
-                       }
+       while ((softirq_bit = ffs(pending))) {
+               unsigned int vec_nr;
+               int prev_count;
 
-                       rcu_bh_qs(cpu);
+               h += softirq_bit - 1;
+
+               vec_nr = h - softirq_vec;
+               prev_count = preempt_count();
+
+               kstat_incr_softirqs_this_cpu(vec_nr);
+
+               trace_softirq_entry(vec_nr);
+               h->action(h);
+               trace_softirq_exit(vec_nr);
+               if (unlikely(prev_count != preempt_count())) {
+                       pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n",
+                              vec_nr, softirq_to_name[vec_nr], h->action,
+                              prev_count, preempt_count());
+                       preempt_count_set(prev_count);
                }
+               rcu_bh_qs(cpu);
                h++;
-               pending >>= 1;
-       } while (pending);
+               pending >>= softirq_bit;
+       }
 
        local_irq_disable();
 
@@ -326,7 +328,7 @@ void irq_enter(void)
                 * here, as softirq will be serviced on return from interrupt.
                 */
                local_bh_disable();
-               tick_check_idle();
+               tick_irq_enter();
                _local_bh_enable();
        }
 
@@ -433,8 +435,7 @@ void open_softirq(int nr, void (*action)(struct softirq_action *))
 /*
  * Tasklets
  */
-struct tasklet_head
-{
+struct tasklet_head {
        struct tasklet_struct *head;
        struct tasklet_struct **tail;
 };
@@ -453,7 +454,6 @@ void __tasklet_schedule(struct tasklet_struct *t)
        raise_softirq_irqoff(TASKLET_SOFTIRQ);
        local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL(__tasklet_schedule);
 
 void __tasklet_hi_schedule(struct tasklet_struct *t)
@@ -467,7 +467,6 @@ void __tasklet_hi_schedule(struct tasklet_struct *t)
        raise_softirq_irqoff(HI_SOFTIRQ);
        local_irq_restore(flags);
 }
-
 EXPORT_SYMBOL(__tasklet_hi_schedule);
 
 void __tasklet_hi_schedule_first(struct tasklet_struct *t)
@@ -478,7 +477,6 @@ void __tasklet_hi_schedule_first(struct tasklet_struct *t)
        __this_cpu_write(tasklet_hi_vec.head, t);
        __raise_softirq_irqoff(HI_SOFTIRQ);
 }
-
 EXPORT_SYMBOL(__tasklet_hi_schedule_first);
 
 static void tasklet_action(struct softirq_action *a)
@@ -498,7 +496,8 @@ static void tasklet_action(struct softirq_action *a)
 
                if (tasklet_trylock(t)) {
                        if (!atomic_read(&t->count)) {
-                               if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
+                               if (!test_and_clear_bit(TASKLET_STATE_SCHED,
+                                                       &t->state))
                                        BUG();
                                t->func(t->data);
                                tasklet_unlock(t);
@@ -533,7 +532,8 @@ static void tasklet_hi_action(struct softirq_action *a)
 
                if (tasklet_trylock(t)) {
                        if (!atomic_read(&t->count)) {
-                               if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
+                               if (!test_and_clear_bit(TASKLET_STATE_SCHED,
+                                                       &t->state))
                                        BUG();
                                t->func(t->data);
                                tasklet_unlock(t);
@@ -551,7 +551,6 @@ static void tasklet_hi_action(struct softirq_action *a)
        }
 }
 
-
 void tasklet_init(struct tasklet_struct *t,
                  void (*func)(unsigned long), unsigned long data)
 {
@@ -561,13 +560,12 @@ void tasklet_init(struct tasklet_struct *t,
        t->func = func;
        t->data = data;
 }
-
 EXPORT_SYMBOL(tasklet_init);
 
 void tasklet_kill(struct tasklet_struct *t)
 {
        if (in_interrupt())
-               printk("Attempt to kill tasklet from interrupt\n");
+               pr_notice("Attempt to kill tasklet from interrupt\n");
 
        while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
                do {
@@ -577,7 +575,6 @@ void tasklet_kill(struct tasklet_struct *t)
        tasklet_unlock_wait(t);
        clear_bit(TASKLET_STATE_SCHED, &t->state);
 }
-
 EXPORT_SYMBOL(tasklet_kill);
 
 /*
@@ -727,9 +724,8 @@ static void takeover_tasklets(unsigned int cpu)
 }
 #endif /* CONFIG_HOTPLUG_CPU */
 
-static int cpu_callback(struct notifier_block *nfb,
-                                 unsigned long action,
-                                 void *hcpu)
+static int cpu_callback(struct notifier_block *nfb, unsigned long action,
+                       void *hcpu)
 {
        switch (action) {
 #ifdef CONFIG_HOTPLUG_CPU
index 096db7452cbd29c8250a49741d3c8b210b82cf74..49e13e1f8fe6a5e481edb3026ae20360918986c3 100644 (file)
@@ -121,6 +121,8 @@ extern int blk_iopoll_enabled;
 static int sixty = 60;
 #endif
 
+static int __maybe_unused neg_one = -1;
+
 static int zero;
 static int __maybe_unused one = 1;
 static int __maybe_unused two = 2;
@@ -997,9 +999,10 @@ static struct ctl_table kern_table[] = {
        {
                .procname       = "hung_task_warnings",
                .data           = &sysctl_hung_task_warnings,
-               .maxlen         = sizeof(unsigned long),
+               .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_doulongvec_minmax,
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = &neg_one,
        },
 #endif
 #ifdef CONFIG_COMPAT
index 08cb0c3b8ccb49a34a6eea27ea945c017a84795c..9f8af69c67ecb27d54e5a59741e78c625eda703a 100644 (file)
@@ -533,12 +533,13 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
        struct clock_event_device *dev = __get_cpu_var(tick_cpu_device).evtdev;
        u64 time_delta;
 
+       time_delta = timekeeping_max_deferment();
+
        /* Read jiffies and the time when jiffies were updated last */
        do {
                seq = read_seqbegin(&jiffies_lock);
                last_update = last_jiffies_update;
                last_jiffies = jiffies;
-               time_delta = timekeeping_max_deferment();
        } while (read_seqretry(&jiffies_lock, seq));
 
        if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) ||
@@ -678,18 +679,18 @@ out:
 static void tick_nohz_full_stop_tick(struct tick_sched *ts)
 {
 #ifdef CONFIG_NO_HZ_FULL
-       int cpu = smp_processor_id();
+       int cpu = smp_processor_id();
 
-       if (!tick_nohz_full_cpu(cpu) || is_idle_task(current))
-               return;
+       if (!tick_nohz_full_cpu(cpu) || is_idle_task(current))
+               return;
 
-       if (!ts->tick_stopped && ts->nohz_mode == NOHZ_MODE_INACTIVE)
-              return;
+       if (!ts->tick_stopped && ts->nohz_mode == NOHZ_MODE_INACTIVE)
+               return;
 
-       if (!can_stop_full_tick())
-               return;
+       if (!can_stop_full_tick())
+               return;
 
-       tick_nohz_stop_sched_tick(ts, ktime_get(), cpu);
+       tick_nohz_stop_sched_tick(ts, ktime_get(), cpu);
 #endif
 }
 
@@ -1023,7 +1024,7 @@ static void tick_nohz_kick_tick(struct tick_sched *ts, ktime_t now)
 #endif
 }
 
-static inline void tick_check_nohz_this_cpu(void)
+static inline void tick_nohz_irq_enter(void)
 {
        struct tick_sched *ts = &__get_cpu_var(tick_cpu_sched);
        ktime_t now;
@@ -1042,17 +1043,17 @@ static inline void tick_check_nohz_this_cpu(void)
 #else
 
 static inline void tick_nohz_switch_to_nohz(void) { }
-static inline void tick_check_nohz_this_cpu(void) { }
+static inline void tick_nohz_irq_enter(void) { }
 
 #endif /* CONFIG_NO_HZ_COMMON */
 
 /*
  * Called from irq_enter to notify about the possible interruption of idle()
  */
-void tick_check_idle(void)
+void tick_irq_enter(void)
 {
        tick_check_oneshot_broadcast_this_cpu();
-       tick_check_nohz_this_cpu();
+       tick_nohz_irq_enter();
 }
 
 /*
index f785aef65799cdb0068f0016bb0183a3bfe312a6..b418cb0d72424ab454e66e3cde881784ce1f0fad 100644 (file)
@@ -781,8 +781,8 @@ static void blk_add_trace_bio(struct request_queue *q, struct bio *bio,
        if (!error && !bio_flagged(bio, BIO_UPTODATE))
                error = EIO;
 
-       __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw, what,
-                       error, 0, NULL);
+       __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
+                       bio->bi_rw, what, error, 0, NULL);
 }
 
 static void blk_add_trace_bio_bounce(void *ignore,
@@ -885,8 +885,9 @@ static void blk_add_trace_split(void *ignore,
        if (bt) {
                __be64 rpdu = cpu_to_be64(pdu);
 
-               __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw,
-                               BLK_TA_SPLIT, !bio_flagged(bio, BIO_UPTODATE),
+               __blk_add_trace(bt, bio->bi_iter.bi_sector,
+                               bio->bi_iter.bi_size, bio->bi_rw, BLK_TA_SPLIT,
+                               !bio_flagged(bio, BIO_UPTODATE),
                                sizeof(rpdu), &rpdu);
        }
 }
@@ -918,9 +919,9 @@ static void blk_add_trace_bio_remap(void *ignore,
        r.device_to   = cpu_to_be32(bio->bi_bdev->bd_dev);
        r.sector_from = cpu_to_be64(from);
 
-       __blk_add_trace(bt, bio->bi_sector, bio->bi_size, bio->bi_rw,
-                       BLK_TA_REMAP, !bio_flagged(bio, BIO_UPTODATE),
-                       sizeof(r), &r);
+       __blk_add_trace(bt, bio->bi_iter.bi_sector, bio->bi_iter.bi_size,
+                       bio->bi_rw, BLK_TA_REMAP,
+                       !bio_flagged(bio, BIO_UPTODATE), sizeof(r), &r);
 }
 
 /**
index 20c755e018cad3fdc59cb767eac7f604120793be..815c878f409bd94e08777d1b9f83b1553f4a2e24 100644 (file)
@@ -455,6 +455,9 @@ int __trace_puts(unsigned long ip, const char *str, int size)
        unsigned long irq_flags;
        int alloc;
 
+       if (unlikely(tracing_selftest_running || tracing_disabled))
+               return 0;
+
        alloc = sizeof(*entry) + size + 2; /* possible \n added */
 
        local_save_flags(irq_flags);
@@ -495,6 +498,9 @@ int __trace_bputs(unsigned long ip, const char *str)
        unsigned long irq_flags;
        int size = sizeof(struct bputs_entry);
 
+       if (unlikely(tracing_selftest_running || tracing_disabled))
+               return 0;
+
        local_save_flags(irq_flags);
        buffer = global_trace.trace_buffer.buffer;
        event = trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size,
@@ -3519,60 +3525,103 @@ static const char readme_msg[] =
        "  instances\t\t- Make sub-buffers with: mkdir instances/foo\n"
        "\t\t\t  Remove sub-buffer with rmdir\n"
        "  trace_options\t\t- Set format or modify how tracing happens\n"
-       "\t\t\t  Disable an option by adding a suffix 'no' to the option name\n"
+       "\t\t\t  Disable an option by adding a suffix 'no' to the\n"
+       "\t\t\t  option name\n"
 #ifdef CONFIG_DYNAMIC_FTRACE
        "\n  available_filter_functions - list of functions that can be filtered on\n"
-       "  set_ftrace_filter\t- echo function name in here to only trace these functions\n"
-       "            accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
-       "            modules: Can select a group via module\n"
-       "             Format: :mod:<module-name>\n"
-       "             example: echo :mod:ext3 > set_ftrace_filter\n"
-       "            triggers: a command to perform when function is hit\n"
-       "              Format: <function>:<trigger>[:count]\n"
-       "             trigger: traceon, traceoff\n"
-       "                      enable_event:<system>:<event>\n"
-       "                      disable_event:<system>:<event>\n"
+       "  set_ftrace_filter\t- echo function name in here to only trace these\n"
+       "\t\t\t  functions\n"
+       "\t     accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
+       "\t     modules: Can select a group via module\n"
+       "\t      Format: :mod:<module-name>\n"
+       "\t     example: echo :mod:ext3 > set_ftrace_filter\n"
+       "\t    triggers: a command to perform when function is hit\n"
+       "\t      Format: <function>:<trigger>[:count]\n"
+       "\t     trigger: traceon, traceoff\n"
+       "\t\t      enable_event:<system>:<event>\n"
+       "\t\t      disable_event:<system>:<event>\n"
 #ifdef CONFIG_STACKTRACE
-       "                      stacktrace\n"
+       "\t\t      stacktrace\n"
 #endif
 #ifdef CONFIG_TRACER_SNAPSHOT
-       "                      snapshot\n"
+       "\t\t      snapshot\n"
 #endif
-       "             example: echo do_fault:traceoff > set_ftrace_filter\n"
-       "                      echo do_trap:traceoff:3 > set_ftrace_filter\n"
-       "             The first one will disable tracing every time do_fault is hit\n"
-       "             The second will disable tracing at most 3 times when do_trap is hit\n"
-       "               The first time do trap is hit and it disables tracing, the counter\n"
-       "               will decrement to 2. If tracing is already disabled, the counter\n"
-       "               will not decrement. It only decrements when the trigger did work\n"
-       "             To remove trigger without count:\n"
-       "               echo '!<function>:<trigger> > set_ftrace_filter\n"
-       "             To remove trigger with a count:\n"
-       "               echo '!<function>:<trigger>:0 > set_ftrace_filter\n"
+       "\t     example: echo do_fault:traceoff > set_ftrace_filter\n"
+       "\t              echo do_trap:traceoff:3 > set_ftrace_filter\n"
+       "\t     The first one will disable tracing every time do_fault is hit\n"
+       "\t     The second will disable tracing at most 3 times when do_trap is hit\n"
+       "\t       The first time do trap is hit and it disables tracing, the\n"
+       "\t       counter will decrement to 2. If tracing is already disabled,\n"
+       "\t       the counter will not decrement. It only decrements when the\n"
+       "\t       trigger did work\n"
+       "\t     To remove trigger without count:\n"
+       "\t       echo '!<function>:<trigger> > set_ftrace_filter\n"
+       "\t     To remove trigger with a count:\n"
+       "\t       echo '!<function>:<trigger>:0 > set_ftrace_filter\n"
        "  set_ftrace_notrace\t- echo function name in here to never trace.\n"
-       "            accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
-       "            modules: Can select a group via module command :mod:\n"
-       "            Does not accept triggers\n"
+       "\t    accepts: func_full_name, *func_end, func_begin*, *func_middle*\n"
+       "\t    modules: Can select a group via module command :mod:\n"
+       "\t    Does not accept triggers\n"
 #endif /* CONFIG_DYNAMIC_FTRACE */
 #ifdef CONFIG_FUNCTION_TRACER
-       "  set_ftrace_pid\t- Write pid(s) to only function trace those pids (function)\n"
+       "  set_ftrace_pid\t- Write pid(s) to only function trace those pids\n"
+       "\t\t    (function)\n"
 #endif
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
        "  set_graph_function\t- Trace the nested calls of a function (function_graph)\n"
        "  max_graph_depth\t- Trace a limited depth of nested calls (0 is unlimited)\n"
 #endif
 #ifdef CONFIG_TRACER_SNAPSHOT
-       "\n  snapshot\t\t- Like 'trace' but shows the content of the static snapshot buffer\n"
-       "\t\t\t  Read the contents for more information\n"
+       "\n  snapshot\t\t- Like 'trace' but shows the content of the static\n"
+       "\t\t\t  snapshot buffer. Read the contents for more\n"
+       "\t\t\t  information\n"
 #endif
 #ifdef CONFIG_STACK_TRACER
        "  stack_trace\t\t- Shows the max stack trace when active\n"
        "  stack_max_size\t- Shows current max stack size that was traced\n"
-       "\t\t\t  Write into this file to reset the max size (trigger a new trace)\n"
+       "\t\t\t  Write into this file to reset the max size (trigger a\n"
+       "\t\t\t  new trace)\n"
 #ifdef CONFIG_DYNAMIC_FTRACE
-       "  stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace traces\n"
+       "  stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace\n"
+       "\t\t\t  traces\n"
 #endif
 #endif /* CONFIG_STACK_TRACER */
+       "  events/\t\t- Directory containing all trace event subsystems:\n"
+       "      enable\t\t- Write 0/1 to enable/disable tracing of all events\n"
+       "  events/<system>/\t- Directory containing all trace events for <system>:\n"
+       "      enable\t\t- Write 0/1 to enable/disable tracing of all <system>\n"
+       "\t\t\t  events\n"
+       "      filter\t\t- If set, only events passing filter are traced\n"
+       "  events/<system>/<event>/\t- Directory containing control files for\n"
+       "\t\t\t  <event>:\n"
+       "      enable\t\t- Write 0/1 to enable/disable tracing of <event>\n"
+       "      filter\t\t- If set, only events passing filter are traced\n"
+       "      trigger\t\t- If set, a command to perform when event is hit\n"
+       "\t    Format: <trigger>[:count][if <filter>]\n"
+       "\t   trigger: traceon, traceoff\n"
+       "\t            enable_event:<system>:<event>\n"
+       "\t            disable_event:<system>:<event>\n"
+#ifdef CONFIG_STACKTRACE
+       "\t\t    stacktrace\n"
+#endif
+#ifdef CONFIG_TRACER_SNAPSHOT
+       "\t\t    snapshot\n"
+#endif
+       "\t   example: echo traceoff > events/block/block_unplug/trigger\n"
+       "\t            echo traceoff:3 > events/block/block_unplug/trigger\n"
+       "\t            echo 'enable_event:kmem:kmalloc:3 if nr_rq > 1' > \\\n"
+       "\t                  events/block/block_unplug/trigger\n"
+       "\t   The first disables tracing every time block_unplug is hit.\n"
+       "\t   The second disables tracing the first 3 times block_unplug is hit.\n"
+       "\t   The third enables the kmalloc event the first 3 times block_unplug\n"
+       "\t     is hit and has value of greater than 1 for the 'nr_rq' event field.\n"
+       "\t   Like function triggers, the counter is only decremented if it\n"
+       "\t    enabled or disabled tracing.\n"
+       "\t   To remove a trigger without a count:\n"
+       "\t     echo '!<trigger> > <system>/<event>/trigger\n"
+       "\t   To remove a trigger with a count:\n"
+       "\t     echo '!<trigger>:0 > <system>/<event>/trigger\n"
+       "\t   Filters can be ignored when removing a trigger.\n"
 ;
 
 static ssize_t
index e0e2eebf7ab38502fc2c2f72f5076271cdb30edb..dbf94a7d25a8a1c7be60d62f29680e69e1261f1b 100644 (file)
@@ -1556,17 +1556,6 @@ config PROVIDE_OHCI1394_DMA_INIT
 
          See Documentation/debugging-via-ohci1394.txt for more information.
 
-config FIREWIRE_OHCI_REMOTE_DMA
-       bool "Remote debugging over FireWire with firewire-ohci"
-       depends on FIREWIRE_OHCI
-       help
-         This option lets you use the FireWire bus for remote debugging
-         with help of the firewire-ohci driver. It enables unfiltered
-         remote DMA in firewire-ohci.
-         See Documentation/debugging-via-ohci1394.txt for more information.
-
-         If unsure, say N.
-
 config BUILD_DOCSRC
        bool "Build targets in Documentation/ tree"
        depends on HEADERS_CHECK
index c38083871f11dbaf3f7252674b937fe5e161380a..2defd1308b045c46389a6232391999914573deb6 100644 (file)
@@ -463,7 +463,7 @@ static int active_pfn_set_overlap(unsigned long pfn, int overlap)
        int i;
 
        if (overlap > ACTIVE_PFN_MAX_OVERLAP || overlap < 0)
-               return 0;
+               return overlap;
 
        for (i = RADIX_TREE_MAX_TAGS - 1; i >= 0; i--)
                if (overlap & 1 << i)
@@ -486,7 +486,7 @@ static void active_pfn_inc_overlap(unsigned long pfn)
         * debug_dma_assert_idle() as the pfn may be marked idle
         * prematurely.
         */
-       WARN_ONCE(overlap == 0,
+       WARN_ONCE(overlap > ACTIVE_PFN_MAX_OVERLAP,
                  "DMA-API: exceeded %d overlapping mappings of pfn %lx\n",
                  ACTIVE_PFN_MAX_OVERLAP, pfn);
 }
@@ -517,7 +517,11 @@ static void active_pfn_remove(struct dma_debug_entry *entry)
        unsigned long flags;
 
        spin_lock_irqsave(&radix_lock, flags);
-       if (active_pfn_dec_overlap(entry->pfn) == 0)
+       /* since we are counting overlaps the final put of the
+        * entry->pfn will occur when the overlap count is 0.
+        * active_pfn_dec_overlap() returns -1 in that case
+        */
+       if (active_pfn_dec_overlap(entry->pfn) < 0)
                radix_tree_delete(&dma_active_pfn, entry->pfn);
        spin_unlock_irqrestore(&radix_lock, flags);
 }
index 600ac57e27777f429b77279d93cb9a483f1fbd15..7288e38e17575952664af1df3a69ba488812c8e3 100644 (file)
@@ -268,14 +268,12 @@ static int ddebug_tokenize(char *buf, char *words[], int maxwords)
  */
 static inline int parse_lineno(const char *str, unsigned int *val)
 {
-       char *end = NULL;
        BUG_ON(str == NULL);
        if (*str == '\0') {
                *val = 0;
                return 0;
        }
-       *val = simple_strtoul(str, &end, 10);
-       if (end == NULL || end == str || *end != '\0') {
+       if (kstrtouint(str, 10, val) < 0) {
                pr_err("bad line-number: %s\n", str);
                return -EINVAL;
        }
@@ -348,14 +346,14 @@ static int ddebug_parse_query(char *words[], int nwords,
                        }
                        if (last)
                                *last++ = '\0';
-                       if (parse_lineno(first, &query->first_lineno) < 0) {
-                               pr_err("line-number is <0\n");
+                       if (parse_lineno(first, &query->first_lineno) < 0)
                                return -EINVAL;
-                       }
                        if (last) {
                                /* range <first>-<last> */
-                               if (parse_lineno(last, &query->last_lineno)
-                                   < query->first_lineno) {
+                               if (parse_lineno(last, &query->last_lineno) < 0)
+                                       return -EINVAL;
+
+                               if (query->last_lineno < query->first_lineno) {
                                        pr_err("last-line:%d < 1st-line:%d\n",
                                                query->last_lineno,
                                                query->first_lineno);
index dda31168844f42c9c6fe2f9c9d25526e30884529..bdb9a456bcbb50471310b9f636df72c6bc377ddd 100644 (file)
@@ -316,7 +316,7 @@ EXPORT_SYMBOL(gen_pool_alloc);
  * gen_pool_dma_alloc - allocate special memory from the pool for DMA usage
  * @pool: pool to allocate from
  * @size: number of bytes to allocate from the pool
- * @dma: dma-view physical address
+ * @dma: dma-view physical address return value.  Use NULL if unneeded.
  *
  * Allocate the requested number of bytes from the specified pool.
  * Uses the pool allocation function (with first-fit algorithm by default).
@@ -334,7 +334,8 @@ void *gen_pool_dma_alloc(struct gen_pool *pool, size_t size, dma_addr_t *dma)
        if (!vaddr)
                return NULL;
 
-       *dma = gen_pool_virt_to_phys(pool, vaddr);
+       if (dma)
+               *dma = gen_pool_virt_to_phys(pool, vaddr);
 
        return (void *)vaddr;
 }
index b0b26665c61161d4f33d1dbdaf49fe74275f400e..cb14aeac4ccaeedfe537d423c41c3d0b021e1c9f 100644 (file)
@@ -779,6 +779,7 @@ const struct sysfs_ops kobj_sysfs_ops = {
        .show   = kobj_attr_show,
        .store  = kobj_attr_store,
 };
+EXPORT_SYMBOL_GPL(kobj_sysfs_ops);
 
 /**
  * kset_register - initialize and add a kset.
index 9d054bf91d0f3cd278494dedd3114dfd3b292bcb..7be235f1a70bed4c0e4b5c54b7af566e095a4396 100644 (file)
@@ -132,22 +132,22 @@ static inline unsigned alloc_local_tag(struct percpu_ida_cpu *tags)
 /**
  * percpu_ida_alloc - allocate a tag
  * @pool: pool to allocate from
- * @gfp: gfp flags
+ * @state: task state for prepare_to_wait
  *
  * Returns a tag - an integer in the range [0..nr_tags) (passed to
  * tag_pool_init()), or otherwise -ENOSPC on allocation failure.
  *
  * Safe to be called from interrupt context (assuming it isn't passed
- * __GFP_WAIT, of course).
+ * TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE, of course).
  *
  * @gfp indicates whether or not to wait until a free id is available (it's not
  * used for internal memory allocations); thus if passed __GFP_WAIT we may sleep
  * however long it takes until another thread frees an id (same semantics as a
  * mempool).
  *
- * Will not fail if passed __GFP_WAIT.
+ * Will not fail if passed TASK_UNINTERRUPTIBLE | TASK_INTERRUPTIBLE.
  */
-int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
+int percpu_ida_alloc(struct percpu_ida *pool, int state)
 {
        DEFINE_WAIT(wait);
        struct percpu_ida_cpu *tags;
@@ -174,7 +174,8 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
                 *
                 * global lock held and irqs disabled, don't need percpu lock
                 */
-               prepare_to_wait(&pool->wait, &wait, TASK_UNINTERRUPTIBLE);
+               if (state != TASK_RUNNING)
+                       prepare_to_wait(&pool->wait, &wait, state);
 
                if (!tags->nr_free)
                        alloc_global_tags(pool, tags);
@@ -191,16 +192,22 @@ int percpu_ida_alloc(struct percpu_ida *pool, gfp_t gfp)
                spin_unlock(&pool->lock);
                local_irq_restore(flags);
 
-               if (tag >= 0 || !(gfp & __GFP_WAIT))
+               if (tag >= 0 || state == TASK_RUNNING)
                        break;
 
+               if (signal_pending_state(state, current)) {
+                       tag = -ERESTARTSYS;
+                       break;
+               }
+
                schedule();
 
                local_irq_save(flags);
                tags = this_cpu_ptr(pool->tag_cpu);
        }
+       if (state != TASK_RUNNING)
+               finish_wait(&pool->wait, &wait);
 
-       finish_wait(&pool->wait, &wait);
        return tag;
 }
 EXPORT_SYMBOL_GPL(percpu_ida_alloc);
index 615f3de4b5ce2e3248a101f1adc174a03d65b6fb..b604b831f4d182c4cbc43ddcb23e7f98d3d8d177 100644 (file)
@@ -172,7 +172,7 @@ int __init swiotlb_init_with_tbl(char *tlb, unsigned long nslabs, int verbose)
        /*
         * Get the overflow emergency buffer
         */
-       v_overflow_buffer = memblock_virt_alloc_nopanic(
+       v_overflow_buffer = memblock_virt_alloc_low_nopanic(
                                                PAGE_ALIGN(io_tlb_overflow),
                                                PAGE_SIZE);
        if (!v_overflow_buffer)
@@ -220,7 +220,7 @@ swiotlb_init(int verbose)
        bytes = io_tlb_nslabs << IO_TLB_SHIFT;
 
        /* Get IO TLB memory from the low pages */
-       vstart = memblock_virt_alloc_nopanic(PAGE_ALIGN(bytes), PAGE_SIZE);
+       vstart = memblock_virt_alloc_low_nopanic(PAGE_ALIGN(bytes), PAGE_SIZE);
        if (vstart && !swiotlb_init_with_tbl(vstart, io_tlb_nslabs, verbose))
                return;
 
@@ -510,7 +510,8 @@ phys_addr_t swiotlb_tbl_map_single(struct device *hwdev,
 
 not_found:
        spin_unlock_irqrestore(&io_tlb_lock, flags);
-       dev_warn(hwdev, "swiotlb buffer is full\n");
+       if (printk_ratelimit())
+               dev_warn(hwdev, "swiotlb buffer is full (sz: %zd bytes)\n", size);
        return SWIOTLB_MAP_ERROR;
 found:
        spin_unlock_irqrestore(&io_tlb_lock, flags);
index 723bbe04a0b0511976d3778a4df94cb2974eb9c8..2d9f1504d75e26d45ddf58fe2db8c048ecbc8d83 100644 (file)
@@ -552,3 +552,28 @@ config MEM_SOFT_DIRTY
          it can be cleared by hands.
 
          See Documentation/vm/soft-dirty.txt for more details.
+
+config ZSMALLOC
+       bool "Memory allocator for compressed pages"
+       depends on MMU
+       default n
+       help
+         zsmalloc is a slab-based memory allocator designed to store
+         compressed RAM pages.  zsmalloc uses virtual memory mapping
+         in order to reduce fragmentation.  However, this results in a
+         non-standard allocator interface where a handle, not a pointer, is
+         returned by an alloc().  This handle must be mapped in order to
+         access the allocated space.
+
+config PGTABLE_MAPPING
+       bool "Use page table mapping to access object in zsmalloc"
+       depends on ZSMALLOC
+       help
+         By default, zsmalloc uses a copy-based object mapping method to
+         access allocations that span two pages. However, if a particular
+         architecture (ex, ARM) performs VM mapping faster than copying,
+         then you should select this. This causes zsmalloc to use page table
+         mapping rather than copying for object mapping.
+
+         You can check speed with zsmalloc benchmark[1].
+         [1] https://github.com/spartacus06/zsmalloc
index 305d10acd081842fd965550b299f5e5704b04b00..310c90a092646004d9519a476386053d57d4c847 100644 (file)
@@ -60,3 +60,4 @@ obj-$(CONFIG_DEBUG_KMEMLEAK_TEST) += kmemleak-test.o
 obj-$(CONFIG_CLEANCACHE) += cleancache.o
 obj-$(CONFIG_MEMORY_ISOLATION) += page_isolation.o
 obj-$(CONFIG_ZBUD)     += zbud.o
+obj-$(CONFIG_ZSMALLOC) += zsmalloc.o
index 5a7d58fb883bfa1c4917e48d251cd132c8d9baf9..523918b8c6dcbef6968c37e2fa38ee87a3b2518c 100644 (file)
@@ -98,27 +98,24 @@ int init_emergency_isa_pool(void)
 static void copy_to_high_bio_irq(struct bio *to, struct bio *from)
 {
        unsigned char *vfrom;
-       struct bio_vec *tovec, *fromvec;
-       int i;
-
-       bio_for_each_segment(tovec, to, i) {
-               fromvec = from->bi_io_vec + i;
-
-               /*
-                * not bounced
-                */
-               if (tovec->bv_page == fromvec->bv_page)
-                       continue;
-
-               /*
-                * fromvec->bv_offset and fromvec->bv_len might have been
-                * modified by the block layer, so use the original copy,
-                * bounce_copy_vec already uses tovec->bv_len
-                */
-               vfrom = page_address(fromvec->bv_page) + tovec->bv_offset;
+       struct bio_vec tovec, *fromvec = from->bi_io_vec;
+       struct bvec_iter iter;
+
+       bio_for_each_segment(tovec, to, iter) {
+               if (tovec.bv_page != fromvec->bv_page) {
+                       /*
+                        * fromvec->bv_offset and fromvec->bv_len might have
+                        * been modified by the block layer, so use the original
+                        * copy, bounce_copy_vec already uses tovec->bv_len
+                        */
+                       vfrom = page_address(fromvec->bv_page) +
+                               tovec.bv_offset;
+
+                       bounce_copy_vec(&tovec, vfrom);
+                       flush_dcache_page(tovec.bv_page);
+               }
 
-               bounce_copy_vec(tovec, vfrom);
-               flush_dcache_page(tovec->bv_page);
+               fromvec++;
        }
 }
 
@@ -201,13 +198,14 @@ static void __blk_queue_bounce(struct request_queue *q, struct bio **bio_orig,
 {
        struct bio *bio;
        int rw = bio_data_dir(*bio_orig);
-       struct bio_vec *to, *from;
+       struct bio_vec *to, from;
+       struct bvec_iter iter;
        unsigned i;
 
        if (force)
                goto bounce;
-       bio_for_each_segment(from, *bio_orig, i)
-               if (page_to_pfn(from->bv_page) > queue_bounce_pfn(q))
+       bio_for_each_segment(from, *bio_orig, iter)
+               if (page_to_pfn(from.bv_page) > queue_bounce_pfn(q))
                        goto bounce;
 
        return;
index 7a7f3e0db7384515b6e266029ef930e5c775ec0d..d56d3c145b9f26d3210ec8ad17430be6c46af2a9 100644 (file)
@@ -1428,30 +1428,28 @@ generic_file_aio_read(struct kiocb *iocb, const struct iovec *iov,
                if (!count)
                        goto out; /* skip atime */
                size = i_size_read(inode);
-               if (pos < size) {
-                       retval = filemap_write_and_wait_range(mapping, pos,
+               retval = filemap_write_and_wait_range(mapping, pos,
                                        pos + iov_length(iov, nr_segs) - 1);
-                       if (!retval) {
-                               retval = mapping->a_ops->direct_IO(READ, iocb,
-                                                       iov, pos, nr_segs);
-                       }
-                       if (retval > 0) {
-                               *ppos = pos + retval;
-                               count -= retval;
-                       }
+               if (!retval) {
+                       retval = mapping->a_ops->direct_IO(READ, iocb,
+                                                          iov, pos, nr_segs);
+               }
+               if (retval > 0) {
+                       *ppos = pos + retval;
+                       count -= retval;
+               }
 
-                       /*
-                        * Btrfs can have a short DIO read if we encounter
-                        * compressed extents, so if there was an error, or if
-                        * we've already read everything we wanted to, or if
-                        * there was a short read because we hit EOF, go ahead
-                        * and return.  Otherwise fallthrough to buffered io for
-                        * the rest of the read.
-                        */
-                       if (retval < 0 || !count || *ppos >= size) {
-                               file_accessed(filp);
-                               goto out;
-                       }
+               /*
+                * Btrfs can have a short DIO read if we encounter
+                * compressed extents, so if there was an error, or if
+                * we've already read everything we wanted to, or if
+                * there was a short read because we hit EOF, go ahead
+                * and return.  Otherwise fallthrough to buffered io for
+                * the rest of the read.
+                */
+               if (retval < 0 || !count || *ppos >= size) {
+                       file_accessed(filp);
+                       goto out;
                }
        }
 
index 65c98eb5483c24946321bbca51dd0ebc02da0a00..82166bf974e14262ecfb064ea7c173d006d3ab98 100644 (file)
@@ -1508,19 +1508,15 @@ int move_huge_pmd(struct vm_area_struct *vma, struct vm_area_struct *new_vma,
                        spin_lock_nested(new_ptl, SINGLE_DEPTH_NESTING);
                pmd = pmdp_get_and_clear(mm, old_addr, old_pmd);
                VM_BUG_ON(!pmd_none(*new_pmd));
-               set_pmd_at(mm, new_addr, new_pmd, pmd_mksoft_dirty(pmd));
-               if (new_ptl != old_ptl) {
-                       pgtable_t pgtable;
 
-                       /*
-                        * Move preallocated PTE page table if new_pmd is on
-                        * different PMD page table.
-                        */
+               if (pmd_move_must_withdraw(new_ptl, old_ptl)) {
+                       pgtable_t pgtable;
                        pgtable = pgtable_trans_huge_withdraw(mm, old_pmd);
                        pgtable_trans_huge_deposit(mm, new_pmd, pgtable);
-
-                       spin_unlock(new_ptl);
                }
+               set_pmd_at(mm, new_addr, new_pmd, pmd_mksoft_dirty(pmd));
+               if (new_ptl != old_ptl)
+                       spin_unlock(new_ptl);
                spin_unlock(old_ptl);
        }
 out:
index 612c14f5e0f570159fcf775991e88615fca26606..29e1e761f9ebe3fee42eea1b0e77589122a23d24 100644 (file)
@@ -83,7 +83,6 @@ extern unsigned long highest_memmap_pfn;
  */
 extern int isolate_lru_page(struct page *page);
 extern void putback_lru_page(struct page *page);
-extern unsigned long zone_reclaimable_pages(struct zone *zone);
 extern bool zone_reclaimable(struct zone *zone);
 
 /*
index 9c0aeef194404a93a0e64f94a25c337ff301749e..39a31e7f004505991e37219bdb1e17f571efb933 100644 (file)
@@ -984,9 +984,6 @@ static phys_addr_t __init memblock_alloc_base_nid(phys_addr_t size,
        if (!align)
                align = SMP_CACHE_BYTES;
 
-       /* align @size to avoid excessive fragmentation on reserved array */
-       size = round_up(size, align);
-
        found = memblock_find_in_range_node(size, align, 0, max_addr, nid);
        if (found && !memblock_reserve(found, size))
                return found;
@@ -1080,8 +1077,8 @@ static void * __init memblock_virt_alloc_internal(
        if (!align)
                align = SMP_CACHE_BYTES;
 
-       /* align @size to avoid excessive fragmentation on reserved array */
-       size = round_up(size, align);
+       if (max_addr > memblock.current_limit)
+               max_addr = memblock.current_limit;
 
 again:
        alloc = memblock_find_in_range_node(size, align, min_addr, max_addr,
index 19d5d4274e221fcab953063fb169125876ab0e37..53385cd4e6f02cfae85f99a2629f735094130c78 100644 (file)
@@ -3400,7 +3400,7 @@ void mem_cgroup_destroy_cache(struct kmem_cache *cachep)
 static struct kmem_cache *memcg_create_kmem_cache(struct mem_cgroup *memcg,
                                                  struct kmem_cache *s)
 {
-       struct kmem_cache *new;
+       struct kmem_cache *new = NULL;
        static char *tmp_name = NULL;
        static DEFINE_MUTEX(mutex);     /* protects tmp_name */
 
@@ -3416,7 +3416,7 @@ static struct kmem_cache *memcg_create_kmem_cache(struct mem_cgroup *memcg,
        if (!tmp_name) {
                tmp_name = kmalloc(PATH_MAX, GFP_KERNEL);
                if (!tmp_name)
-                       return NULL;
+                       goto out;
        }
 
        rcu_read_lock();
@@ -3426,12 +3426,11 @@ static struct kmem_cache *memcg_create_kmem_cache(struct mem_cgroup *memcg,
 
        new = kmem_cache_create_memcg(memcg, tmp_name, s->object_size, s->align,
                                      (s->flags & ~SLAB_PANIC), s->ctor, s);
-
        if (new)
                new->allocflags |= __GFP_KMEMCG;
        else
                new = s;
-
+out:
        mutex_unlock(&mutex);
        return new;
 }
index 463b7fbf0d1d0ffd3e422948f62b9605dd8f3f65..ae3c8f3595d4ff522f0427b05ace2f7e041da8ad 100644 (file)
@@ -613,7 +613,7 @@ static inline int queue_pages_pgd_range(struct vm_area_struct *vma,
        return 0;
 }
 
-#ifdef CONFIG_ARCH_USES_NUMA_PROT_NONE
+#ifdef CONFIG_NUMA_BALANCING
 /*
  * This is used to mark a range of virtual addresses to be inaccessible.
  * These are later cleared by a NUMA hinting fault. Depending on these
@@ -627,7 +627,6 @@ unsigned long change_prot_numa(struct vm_area_struct *vma,
                        unsigned long addr, unsigned long end)
 {
        int nr_updated;
-       BUILD_BUG_ON(_PAGE_NUMA != _PAGE_PROTNONE);
 
        nr_updated = change_protection(vma, addr, end, vma->vm_page_prot, 0, 1);
        if (nr_updated)
@@ -641,7 +640,7 @@ static unsigned long change_prot_numa(struct vm_area_struct *vma,
 {
        return 0;
 }
-#endif /* CONFIG_ARCH_USES_NUMA_PROT_NONE */
+#endif /* CONFIG_NUMA_BALANCING */
 
 /*
  * Walk through page tables and collect pages to be migrated.
@@ -2655,7 +2654,7 @@ void mpol_free_shared_policy(struct shared_policy *p)
 }
 
 #ifdef CONFIG_NUMA_BALANCING
-static bool __initdata numabalancing_override;
+static int __initdata numabalancing_override;
 
 static void __init check_numabalancing_enable(void)
 {
@@ -2664,9 +2663,15 @@ static void __init check_numabalancing_enable(void)
        if (IS_ENABLED(CONFIG_NUMA_BALANCING_DEFAULT_ENABLED))
                numabalancing_default = true;
 
+       /* Parsed by setup_numabalancing. override == 1 enables, -1 disables */
+       if (numabalancing_override)
+               set_numabalancing_state(numabalancing_override == 1);
+
        if (nr_node_ids > 1 && !numabalancing_override) {
-               printk(KERN_INFO "Enabling automatic NUMA balancing. "
-                       "Configure with numa_balancing= or the kernel.numa_balancing sysctl");
+               pr_info("%s automatic NUMA balancing. "
+                       "Configure with numa_balancing= or the "
+                       "kernel.numa_balancing sysctl",
+                       numabalancing_default ? "Enabling" : "Disabling");
                set_numabalancing_state(numabalancing_default);
        }
 }
@@ -2676,18 +2681,17 @@ static int __init setup_numabalancing(char *str)
        int ret = 0;
        if (!str)
                goto out;
-       numabalancing_override = true;
 
        if (!strcmp(str, "enable")) {
-               set_numabalancing_state(true);
+               numabalancing_override = 1;
                ret = 1;
        } else if (!strcmp(str, "disable")) {
-               set_numabalancing_state(false);
+               numabalancing_override = -1;
                ret = 1;
        }
 out:
        if (!ret)
-               printk(KERN_WARNING "Unable to parse numa_balancing=\n");
+               pr_warn("Unable to parse numa_balancing=\n");
 
        return ret;
 }
@@ -2926,7 +2930,7 @@ void mpol_to_str(char *buffer, int maxlen, struct mempolicy *pol)
        unsigned short mode = MPOL_DEFAULT;
        unsigned short flags = 0;
 
-       if (pol && pol != &default_policy) {
+       if (pol && pol != &default_policy && !(pol->flags & MPOL_F_MORON)) {
                mode = pol->mode;
                flags = pol->flags;
        }
index 734704f6f29b33dc8256463fcb9de1c23621d057..482a33d89134fd83e15d5f6863dae57f5cb05aac 100644 (file)
@@ -1548,8 +1548,6 @@ static struct page *alloc_misplaced_dst_page(struct page *page,
                                          __GFP_NOMEMALLOC | __GFP_NORETRY |
                                          __GFP_NOWARN) &
                                         ~GFP_IOFS, 0);
-       if (newpage)
-               page_cpupid_xchg_last(newpage, page_cpupid_last(page));
 
        return newpage;
 }
index 857a6434e3a58a85467df765ebeab08b8be6f88a..4074caf9936bf399a14fa488b40ac0b5cdb16bdd 100644 (file)
@@ -202,4 +202,4 @@ static int __init mm_sysfs_init(void)
 
        return 0;
 }
-pure_initcall(mm_sysfs_init);
+postcore_initcall(mm_sysfs_init);
index 37b1b1903fb2c6aa84d9e25faf7e53381121e647..3291e82d4352423cb1cd747eaa589da4b8a07a74 100644 (file)
@@ -178,7 +178,7 @@ unsigned long oom_badness(struct task_struct *p, struct mem_cgroup *memcg,
         * implementation used by LSMs.
         */
        if (has_capability_noaudit(p, CAP_SYS_ADMIN))
-               adj -= 30;
+               points -= (points * 3) / 100;
 
        /* Normalize to oom_score_adj units */
        adj *= totalpages / 1000;
index 63807583d8e89f1c96f8b05bcf5fe422ed200c26..2d30e2cfe8047606064f117fbaca4675540e00dd 100644 (file)
@@ -191,6 +191,26 @@ static unsigned long writeout_period_time = 0;
  * global dirtyable memory first.
  */
 
+/**
+ * zone_dirtyable_memory - number of dirtyable pages in a zone
+ * @zone: the zone
+ *
+ * Returns the zone's number of pages potentially available for dirty
+ * page cache.  This is the base value for the per-zone dirty limits.
+ */
+static unsigned long zone_dirtyable_memory(struct zone *zone)
+{
+       unsigned long nr_pages;
+
+       nr_pages = zone_page_state(zone, NR_FREE_PAGES);
+       nr_pages -= min(nr_pages, zone->dirty_balance_reserve);
+
+       nr_pages += zone_page_state(zone, NR_INACTIVE_FILE);
+       nr_pages += zone_page_state(zone, NR_ACTIVE_FILE);
+
+       return nr_pages;
+}
+
 static unsigned long highmem_dirtyable_memory(unsigned long total)
 {
 #ifdef CONFIG_HIGHMEM
@@ -198,11 +218,9 @@ static unsigned long highmem_dirtyable_memory(unsigned long total)
        unsigned long x = 0;
 
        for_each_node_state(node, N_HIGH_MEMORY) {
-               struct zone *z =
-                       &NODE_DATA(node)->node_zones[ZONE_HIGHMEM];
+               struct zone *z = &NODE_DATA(node)->node_zones[ZONE_HIGHMEM];
 
-               x += zone_page_state(z, NR_FREE_PAGES) +
-                    zone_reclaimable_pages(z) - z->dirty_balance_reserve;
+               x += zone_dirtyable_memory(z);
        }
        /*
         * Unreclaimable memory (kernel memory or anonymous memory
@@ -238,9 +256,12 @@ static unsigned long global_dirtyable_memory(void)
 {
        unsigned long x;
 
-       x = global_page_state(NR_FREE_PAGES) + global_reclaimable_pages();
+       x = global_page_state(NR_FREE_PAGES);
        x -= min(x, dirty_balance_reserve);
 
+       x += global_page_state(NR_INACTIVE_FILE);
+       x += global_page_state(NR_ACTIVE_FILE);
+
        if (!vm_highmem_is_dirtyable)
                x -= highmem_dirtyable_memory(x);
 
@@ -288,32 +309,6 @@ void global_dirty_limits(unsigned long *pbackground, unsigned long *pdirty)
        trace_global_dirty_state(background, dirty);
 }
 
-/**
- * zone_dirtyable_memory - number of dirtyable pages in a zone
- * @zone: the zone
- *
- * Returns the zone's number of pages potentially available for dirty
- * page cache.  This is the base value for the per-zone dirty limits.
- */
-static unsigned long zone_dirtyable_memory(struct zone *zone)
-{
-       /*
-        * The effective global number of dirtyable pages may exclude
-        * highmem as a big-picture measure to keep the ratio between
-        * dirty memory and lowmem reasonable.
-        *
-        * But this function is purely about the individual zone and a
-        * highmem zone can hold its share of dirty pages, so we don't
-        * care about vm_highmem_is_dirtyable here.
-        */
-       unsigned long nr_pages = zone_page_state(zone, NR_FREE_PAGES) +
-               zone_reclaimable_pages(zone);
-
-       /* don't allow this to underflow */
-       nr_pages -= min(nr_pages, zone->dirty_balance_reserve);
-       return nr_pages;
-}
-
 /**
  * zone_dirty_limit - maximum number of dirty pages allowed in a zone
  * @zone: the zone
index 7247be6114ac894523d8273743a4f168ceab3afa..7c59ef681381bb7afeef2cf5207d269e9a95c1f8 100644 (file)
@@ -31,13 +31,13 @@ static struct bio *get_swap_bio(gfp_t gfp_flags,
 
        bio = bio_alloc(gfp_flags, 1);
        if (bio) {
-               bio->bi_sector = map_swap_page(page, &bio->bi_bdev);
-               bio->bi_sector <<= PAGE_SHIFT - 9;
+               bio->bi_iter.bi_sector = map_swap_page(page, &bio->bi_bdev);
+               bio->bi_iter.bi_sector <<= PAGE_SHIFT - 9;
                bio->bi_io_vec[0].bv_page = page;
                bio->bi_io_vec[0].bv_len = PAGE_SIZE;
                bio->bi_io_vec[0].bv_offset = 0;
                bio->bi_vcnt = 1;
-               bio->bi_size = PAGE_SIZE;
+               bio->bi_iter.bi_size = PAGE_SIZE;
                bio->bi_end_io = end_io;
        }
        return bio;
@@ -62,7 +62,7 @@ void end_swap_bio_write(struct bio *bio, int err)
                printk(KERN_ALERT "Write-error on swap-device (%u:%u:%Lu)\n",
                                imajor(bio->bi_bdev->bd_inode),
                                iminor(bio->bi_bdev->bd_inode),
-                               (unsigned long long)bio->bi_sector);
+                               (unsigned long long)bio->bi_iter.bi_sector);
                ClearPageReclaim(page);
        }
        end_page_writeback(page);
@@ -80,7 +80,7 @@ void end_swap_bio_read(struct bio *bio, int err)
                printk(KERN_ALERT "Read-error on swap-device (%u:%u:%Lu)\n",
                                imajor(bio->bi_bdev->bd_inode),
                                iminor(bio->bi_bdev->bd_inode),
-                               (unsigned long long)bio->bi_sector);
+                               (unsigned long long)bio->bi_iter.bi_sector);
                goto out;
        }
 
index 7cdbb44aa90bd99bef05f43ee27cc13b2121ed7a..0de2360d65f3f4f4cce4e0ae94f02d78a51a2429 100644 (file)
@@ -211,8 +211,6 @@ out:
 int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
                pgoff_t offset, unsigned long nr_to_read)
 {
-       int ret = 0;
-
        if (unlikely(!mapping->a_ops->readpage && !mapping->a_ops->readpages))
                return -EINVAL;
 
@@ -226,15 +224,13 @@ int force_page_cache_readahead(struct address_space *mapping, struct file *filp,
                        this_chunk = nr_to_read;
                err = __do_page_cache_readahead(mapping, filp,
                                                offset, this_chunk, 0);
-               if (err < 0) {
-                       ret = err;
-                       break;
-               }
-               ret += err;
+               if (err < 0)
+                       return err;
+
                offset += this_chunk;
                nr_to_read -= this_chunk;
        }
-       return ret;
+       return 0;
 }
 
 /*
@@ -576,8 +572,7 @@ do_readahead(struct address_space *mapping, struct file *filp,
        if (!mapping || !mapping->a_ops)
                return -EINVAL;
 
-       force_page_cache_readahead(mapping, filp, index, nr);
-       return 0;
+       return force_page_cache_readahead(mapping, filp, index, nr);
 }
 
 SYSCALL_DEFINE3(readahead, int, fd, loff_t, offset, size_t, count)
index 8156f95ec0cfc638d93e8f6175e107384c83d7dd..1f18c9d0d93ea270ab01054b2febbdd6a7eb6f56 100644 (file)
@@ -45,7 +45,7 @@ static struct vfsmount *shm_mnt;
 #include <linux/xattr.h>
 #include <linux/exportfs.h>
 #include <linux/posix_acl.h>
-#include <linux/generic_acl.h>
+#include <linux/posix_acl_xattr.h>
 #include <linux/mman.h>
 #include <linux/string.h>
 #include <linux/slab.h>
@@ -620,10 +620,8 @@ static int shmem_setattr(struct dentry *dentry, struct iattr *attr)
        }
 
        setattr_copy(inode, attr);
-#ifdef CONFIG_TMPFS_POSIX_ACL
        if (attr->ia_valid & ATTR_MODE)
-               error = generic_acl_chmod(inode);
-#endif
+               error = posix_acl_chmod(inode, inode->i_mode);
        return error;
 }
 
@@ -1937,22 +1935,14 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
 
        inode = shmem_get_inode(dir->i_sb, dir, mode, dev, VM_NORESERVE);
        if (inode) {
-#ifdef CONFIG_TMPFS_POSIX_ACL
-               error = generic_acl_init(inode, dir);
-               if (error) {
-                       iput(inode);
-                       return error;
-               }
-#endif
+               error = simple_acl_create(dir, inode);
+               if (error)
+                       goto out_iput;
                error = security_inode_init_security(inode, dir,
                                                     &dentry->d_name,
                                                     shmem_initxattrs, NULL);
-               if (error) {
-                       if (error != -EOPNOTSUPP) {
-                               iput(inode);
-                               return error;
-                       }
-               }
+               if (error && error != -EOPNOTSUPP)
+                       goto out_iput;
 
                error = 0;
                dir->i_size += BOGO_DIRENT_SIZE;
@@ -1961,6 +1951,9 @@ shmem_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t dev)
                dget(dentry); /* Extra count - pin the dentry in core */
        }
        return error;
+out_iput:
+       iput(inode);
+       return error;
 }
 
 static int
@@ -1974,24 +1967,17 @@ shmem_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
                error = security_inode_init_security(inode, dir,
                                                     NULL,
                                                     shmem_initxattrs, NULL);
-               if (error) {
-                       if (error != -EOPNOTSUPP) {
-                               iput(inode);
-                               return error;
-                       }
-               }
-#ifdef CONFIG_TMPFS_POSIX_ACL
-               error = generic_acl_init(inode, dir);
-               if (error) {
-                       iput(inode);
-                       return error;
-               }
-#else
-               error = 0;
-#endif
+               if (error && error != -EOPNOTSUPP)
+                       goto out_iput;
+               error = simple_acl_create(dir, inode);
+               if (error)
+                       goto out_iput;
                d_tmpfile(dentry, inode);
        }
        return error;
+out_iput:
+       iput(inode);
+       return error;
 }
 
 static int shmem_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
@@ -2223,8 +2209,8 @@ static int shmem_initxattrs(struct inode *inode,
 
 static const struct xattr_handler *shmem_xattr_handlers[] = {
 #ifdef CONFIG_TMPFS_POSIX_ACL
-       &generic_acl_access_handler,
-       &generic_acl_default_handler,
+       &posix_acl_access_xattr_handler,
+       &posix_acl_default_xattr_handler,
 #endif
        NULL
 };
@@ -2740,6 +2726,7 @@ static const struct inode_operations shmem_inode_operations = {
        .getxattr       = shmem_getxattr,
        .listxattr      = shmem_listxattr,
        .removexattr    = shmem_removexattr,
+       .set_acl        = simple_set_acl,
 #endif
 };
 
@@ -2764,6 +2751,7 @@ static const struct inode_operations shmem_dir_inode_operations = {
 #endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
        .setattr        = shmem_setattr,
+       .set_acl        = simple_set_acl,
 #endif
 };
 
@@ -2776,6 +2764,7 @@ static const struct inode_operations shmem_special_inode_operations = {
 #endif
 #ifdef CONFIG_TMPFS_POSIX_ACL
        .setattr        = shmem_setattr,
+       .set_acl        = simple_set_acl,
 #endif
 };
 
index 8e40321da091b66f24f983b266acb344ce41d56c..1ec3c619ba04b955f0d64f32ae3d432d113488f6 100644 (file)
@@ -233,14 +233,17 @@ out_unlock:
        mutex_unlock(&slab_mutex);
        put_online_cpus();
 
-       /*
-        * There is no point in flooding logs with warnings or especially
-        * crashing the system if we fail to create a cache for a memcg. In
-        * this case we will be accounting the memcg allocation to the root
-        * cgroup until we succeed to create its own cache, but it isn't that
-        * critical.
-        */
-       if (err && !memcg) {
+       if (err) {
+               /*
+                * There is no point in flooding logs with warnings or
+                * especially crashing the system if we fail to create a cache
+                * for a memcg. In this case we will be accounting the memcg
+                * allocation to the root cgroup until we succeed to create its
+                * own cache, but it isn't that critical.
+                */
+               if (!memcg)
+                       return NULL;
+
                if (flags & SLAB_PANIC)
                        panic("kmem_cache_create: Failed to create slab '%s'. Error %d\n",
                                name, err);
index 34bb8c65a2d8d7e9973fa501fafbe10cf571b8f3..2b1a6970e46f05f3458aaab76102a976088906aa 100644 (file)
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -355,6 +355,21 @@ static __always_inline void slab_unlock(struct page *page)
        __bit_spin_unlock(PG_locked, &page->flags);
 }
 
+static inline void set_page_slub_counters(struct page *page, unsigned long counters_new)
+{
+       struct page tmp;
+       tmp.counters = counters_new;
+       /*
+        * page->counters can cover frozen/inuse/objects as well
+        * as page->_count.  If we assign to ->counters directly
+        * we run the risk of losing updates to page->_count, so
+        * be careful and only assign to the fields we need.
+        */
+       page->frozen  = tmp.frozen;
+       page->inuse   = tmp.inuse;
+       page->objects = tmp.objects;
+}
+
 /* Interrupts must be disabled (for the fallback code to work right) */
 static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
                void *freelist_old, unsigned long counters_old,
@@ -376,7 +391,7 @@ static inline bool __cmpxchg_double_slab(struct kmem_cache *s, struct page *page
                if (page->freelist == freelist_old &&
                                        page->counters == counters_old) {
                        page->freelist = freelist_new;
-                       page->counters = counters_new;
+                       set_page_slub_counters(page, counters_new);
                        slab_unlock(page);
                        return 1;
                }
@@ -415,7 +430,7 @@ static inline bool cmpxchg_double_slab(struct kmem_cache *s, struct page *page,
                if (page->freelist == freelist_old &&
                                        page->counters == counters_old) {
                        page->freelist = freelist_new;
-                       page->counters = counters_new;
+                       set_page_slub_counters(page, counters_new);
                        slab_unlock(page);
                        local_irq_restore(flags);
                        return 1;
@@ -1559,7 +1574,7 @@ static inline void *acquire_slab(struct kmem_cache *s,
                new.freelist = freelist;
        }
 
-       VM_BUG_ON_PAGE(new.frozen, &new);
+       VM_BUG_ON(new.frozen);
        new.frozen = 1;
 
        if (!__cmpxchg_double_slab(s, page,
@@ -1812,7 +1827,7 @@ static void deactivate_slab(struct kmem_cache *s, struct page *page,
                        set_freepointer(s, freelist, prior);
                        new.counters = counters;
                        new.inuse--;
-                       VM_BUG_ON_PAGE(!new.frozen, &new);
+                       VM_BUG_ON(!new.frozen);
 
                } while (!__cmpxchg_double_slab(s, page,
                        prior, counters,
@@ -1840,7 +1855,7 @@ redo:
 
        old.freelist = page->freelist;
        old.counters = page->counters;
-       VM_BUG_ON_PAGE(!old.frozen, &old);
+       VM_BUG_ON(!old.frozen);
 
        /* Determine target state of the slab */
        new.counters = old.counters;
@@ -1952,7 +1967,7 @@ static void unfreeze_partials(struct kmem_cache *s,
 
                        old.freelist = page->freelist;
                        old.counters = page->counters;
-                       VM_BUG_ON_PAGE(!old.frozen, &old);
+                       VM_BUG_ON(!old.frozen);
 
                        new.counters = old.counters;
                        new.freelist = old.freelist;
@@ -2225,7 +2240,7 @@ static inline void *get_freelist(struct kmem_cache *s, struct page *page)
                counters = page->counters;
 
                new.counters = counters;
-               VM_BUG_ON_PAGE(!new.frozen, &new);
+               VM_BUG_ON(!new.frozen);
 
                new.inuse = page->objects;
                new.frozen = freelist != NULL;
@@ -2319,7 +2334,7 @@ load_freelist:
         * page is pointing to the page from which the objects are obtained.
         * That page must be frozen for per cpu allocations to work.
         */
-       VM_BUG_ON_PAGE(!c->page->frozen, c->page);
+       VM_BUG_ON(!c->page->frozen);
        c->freelist = get_freepointer(s, freelist);
        c->tid = next_tid(c->tid);
        local_irq_restore(flags);
index e4f0db2a3eae5ea01f1a80e0d3b680a9c2fa7c08..0fdf96803c5b59623792a24e57015fb0e25098bb 100644 (file)
@@ -220,12 +220,12 @@ int is_vmalloc_or_module_addr(const void *x)
 }
 
 /*
- * Walk a vmap address to the physical pfn it maps to.
+ * Walk a vmap address to the struct page it maps.
  */
-unsigned long vmalloc_to_pfn(const void *vmalloc_addr)
+struct page *vmalloc_to_page(const void *vmalloc_addr)
 {
        unsigned long addr = (unsigned long) vmalloc_addr;
-       unsigned long pfn = 0;
+       struct page *page = NULL;
        pgd_t *pgd = pgd_offset_k(addr);
 
        /*
@@ -244,23 +244,23 @@ unsigned long vmalloc_to_pfn(const void *vmalloc_addr)
                                ptep = pte_offset_map(pmd, addr);
                                pte = *ptep;
                                if (pte_present(pte))
-                                       pfn = pte_pfn(pte);
+                                       page = pte_page(pte);
                                pte_unmap(ptep);
                        }
                }
        }
-       return pfn;
+       return page;
 }
-EXPORT_SYMBOL(vmalloc_to_pfn);
+EXPORT_SYMBOL(vmalloc_to_page);
 
 /*
- * Map a vmalloc()-space virtual address to the struct page.
+ * Map a vmalloc()-space virtual address to the physical page frame number.
  */
-struct page *vmalloc_to_page(const void *vmalloc_addr)
+unsigned long vmalloc_to_pfn(const void *vmalloc_addr)
 {
-       return pfn_to_page(vmalloc_to_pfn(vmalloc_addr));
+       return page_to_pfn(vmalloc_to_page(vmalloc_addr));
 }
-EXPORT_SYMBOL(vmalloc_to_page);
+EXPORT_SYMBOL(vmalloc_to_pfn);
 
 
 /*** Global kva allocator ***/
index 90c4075d8d75af6358ba6c789bc0747f53460a4d..a9c74b409681a460f2c2ef5f45b3f2283a81a4b8 100644 (file)
@@ -147,7 +147,7 @@ static bool global_reclaim(struct scan_control *sc)
 }
 #endif
 
-unsigned long zone_reclaimable_pages(struct zone *zone)
+static unsigned long zone_reclaimable_pages(struct zone *zone)
 {
        int nr;
 
@@ -3315,27 +3315,6 @@ void wakeup_kswapd(struct zone *zone, int order, enum zone_type classzone_idx)
        wake_up_interruptible(&pgdat->kswapd_wait);
 }
 
-/*
- * The reclaimable count would be mostly accurate.
- * The less reclaimable pages may be
- * - mlocked pages, which will be moved to unevictable list when encountered
- * - mapped pages, which may require several travels to be reclaimed
- * - dirty pages, which is not "instantly" reclaimable
- */
-unsigned long global_reclaimable_pages(void)
-{
-       int nr;
-
-       nr = global_page_state(NR_ACTIVE_FILE) +
-            global_page_state(NR_INACTIVE_FILE);
-
-       if (get_nr_swap_pages() > 0)
-               nr += global_page_state(NR_ACTIVE_ANON) +
-                     global_page_state(NR_INACTIVE_ANON);
-
-       return nr;
-}
-
 #ifdef CONFIG_HIBERNATION
 /*
  * Try to free `nr_to_reclaim' of memory, system-wide, and return the number of
similarity index 99%
rename from drivers/staging/zsmalloc/zsmalloc-main.c
rename to mm/zsmalloc.c
index 7660c87d8b2a94fdd59281bb34f4e3a64a35d57b..c03ca5e9fe15c8b9725db0ac41b6ba78f64b0e5d 100644 (file)
@@ -2,6 +2,7 @@
  * zsmalloc memory allocator
  *
  * Copyright (C) 2011  Nitin Gupta
+ * Copyright (C) 2012, 2013 Minchan Kim
  *
  * This code is released using a dual license strategy: BSD/GPL
  * You can choose the license that better fits your requirements.
@@ -90,8 +91,7 @@
 #include <linux/hardirq.h>
 #include <linux/spinlock.h>
 #include <linux/types.h>
-
-#include "zsmalloc.h"
+#include <linux/zsmalloc.h>
 
 /*
  * This must be power of 2 and greater than of equal to sizeof(link_free).
index bf3e6a13c215cd61cd7372e85ba19e7fc7974e9a..621b5f65407f739e7fb5f2f743b1421add43ddda 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/ceph/buffer.h>
 #include <linux/ceph/decode.h>
+#include <linux/ceph/libceph.h> /* for ceph_kv{malloc,free} */
 
 struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
 {
@@ -15,16 +16,10 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
        if (!b)
                return NULL;
 
-       b->vec.iov_base = kmalloc(len, gfp | __GFP_NOWARN);
-       if (b->vec.iov_base) {
-               b->is_vmalloc = false;
-       } else {
-               b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL);
-               if (!b->vec.iov_base) {
-                       kfree(b);
-                       return NULL;
-               }
-               b->is_vmalloc = true;
+       b->vec.iov_base = ceph_kvmalloc(len, gfp);
+       if (!b->vec.iov_base) {
+               kfree(b);
+               return NULL;
        }
 
        kref_init(&b->kref);
@@ -40,12 +35,7 @@ void ceph_buffer_release(struct kref *kref)
        struct ceph_buffer *b = container_of(kref, struct ceph_buffer, kref);
 
        dout("buffer_release %p\n", b);
-       if (b->vec.iov_base) {
-               if (b->is_vmalloc)
-                       vfree(b->vec.iov_base);
-               else
-                       kfree(b->vec.iov_base);
-       }
+       ceph_kvfree(b->vec.iov_base);
        kfree(b);
 }
 EXPORT_SYMBOL(ceph_buffer_release);
index 34b11ee8124ee9b04a7026063b9159e6ce864be2..67d7721d237e1638c21bc62da98f7275a9991026 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/statfs.h>
 #include <linux/string.h>
+#include <linux/vmalloc.h>
 #include <linux/nsproxy.h>
 #include <net/net_namespace.h>
 
@@ -170,6 +171,25 @@ int ceph_compare_options(struct ceph_options *new_opt,
 }
 EXPORT_SYMBOL(ceph_compare_options);
 
+void *ceph_kvmalloc(size_t size, gfp_t flags)
+{
+       if (size <= (PAGE_SIZE << PAGE_ALLOC_COSTLY_ORDER)) {
+               void *ptr = kmalloc(size, flags | __GFP_NOWARN);
+               if (ptr)
+                       return ptr;
+       }
+
+       return __vmalloc(size, flags | __GFP_HIGHMEM, PAGE_KERNEL);
+}
+
+void ceph_kvfree(const void *ptr)
+{
+       if (is_vmalloc_addr(ptr))
+               vfree(ptr);
+       else
+               kfree(ptr);
+}
+
 
 static int parse_fsid(const char *str, struct ceph_fsid *fsid)
 {
@@ -461,8 +481,8 @@ EXPORT_SYMBOL(ceph_client_id);
  * create a fresh client instance
  */
 struct ceph_client *ceph_create_client(struct ceph_options *opt, void *private,
-                                      unsigned int supported_features,
-                                      unsigned int required_features)
+                                      u64 supported_features,
+                                      u64 required_features)
 {
        struct ceph_client *client;
        struct ceph_entity_addr *myaddr = NULL;
index 089613234f032610c05f25a239c1d2053e768b45..16bc199d9a622e7ecb7957643b26e5c41977ff55 100644 (file)
@@ -116,11 +116,14 @@ void crush_destroy(struct crush_map *map)
        if (map->rules) {
                __u32 b;
                for (b = 0; b < map->max_rules; b++)
-                       kfree(map->rules[b]);
+                       crush_destroy_rule(map->rules[b]);
                kfree(map->rules);
        }
 
        kfree(map);
 }
 
-
+void crush_destroy_rule(struct crush_rule *rule)
+{
+       kfree(rule);
+}
index cbd06a91941c15f3e88b9dd6671694e2fe76dbe2..b703790b4e44788e109bb91ab61f272015000654 100644 (file)
@@ -189,7 +189,7 @@ static int terminal(int x)
 static int bucket_tree_choose(struct crush_bucket_tree *bucket,
                              int x, int r)
 {
-       int n, l;
+       int n;
        __u32 w;
        __u64 t;
 
@@ -197,6 +197,7 @@ static int bucket_tree_choose(struct crush_bucket_tree *bucket,
        n = bucket->num_nodes >> 1;
 
        while (!terminal(n)) {
+               int l;
                /* pick point in [0, w) */
                w = bucket->node_weights[n];
                t = (__u64)crush_hash32_4(bucket->h.hash, x, n, r,
@@ -264,8 +265,12 @@ static int crush_bucket_choose(struct crush_bucket *in, int x, int r)
  * true if device is marked "out" (failed, fully offloaded)
  * of the cluster
  */
-static int is_out(const struct crush_map *map, const __u32 *weight, int item, int x)
+static int is_out(const struct crush_map *map,
+                 const __u32 *weight, int weight_max,
+                 int item, int x)
 {
+       if (item >= weight_max)
+               return 1;
        if (weight[item] >= 0x10000)
                return 0;
        if (weight[item] == 0)
@@ -277,7 +282,7 @@ static int is_out(const struct crush_map *map, const __u32 *weight, int item, in
 }
 
 /**
- * crush_choose - choose numrep distinct items of given type
+ * crush_choose_firstn - choose numrep distinct items of given type
  * @map: the crush_map
  * @bucket: the bucket we are choose an item from
  * @x: crush input value
@@ -285,18 +290,24 @@ static int is_out(const struct crush_map *map, const __u32 *weight, int item, in
  * @type: the type of item to choose
  * @out: pointer to output vector
  * @outpos: our position in that vector
- * @firstn: true if choosing "first n" items, false if choosing "indep"
- * @recurse_to_leaf: true if we want one device under each item of given type
- * @descend_once: true if we should only try one descent before giving up
+ * @tries: number of attempts to make
+ * @recurse_tries: number of attempts to have recursive chooseleaf make
+ * @local_tries: localized retries
+ * @local_fallback_tries: localized fallback retries
+ * @recurse_to_leaf: true if we want one device under each item of given type (chooseleaf instead of choose)
  * @out2: second output vector for leaf items (if @recurse_to_leaf)
  */
-static int crush_choose(const struct crush_map *map,
-                       struct crush_bucket *bucket,
-                       const __u32 *weight,
-                       int x, int numrep, int type,
-                       int *out, int outpos,
-                       int firstn, int recurse_to_leaf,
-                       int descend_once, int *out2)
+static int crush_choose_firstn(const struct crush_map *map,
+                              struct crush_bucket *bucket,
+                              const __u32 *weight, int weight_max,
+                              int x, int numrep, int type,
+                              int *out, int outpos,
+                              unsigned int tries,
+                              unsigned int recurse_tries,
+                              unsigned int local_tries,
+                              unsigned int local_fallback_tries,
+                              int recurse_to_leaf,
+                              int *out2)
 {
        int rep;
        unsigned int ftotal, flocal;
@@ -325,35 +336,17 @@ static int crush_choose(const struct crush_map *map,
                                collide = 0;
                                retry_bucket = 0;
                                r = rep;
-                               if (in->alg == CRUSH_BUCKET_UNIFORM) {
-                                       /* be careful */
-                                       if (firstn || (__u32)numrep >= in->size)
-                                               /* r' = r + f_total */
-                                               r += ftotal;
-                                       else if (in->size % numrep == 0)
-                                               /* r'=r+(n+1)*f_local */
-                                               r += (numrep+1) *
-                                                       (flocal+ftotal);
-                                       else
-                                               /* r' = r + n*f_local */
-                                               r += numrep * (flocal+ftotal);
-                               } else {
-                                       if (firstn)
-                                               /* r' = r + f_total */
-                                               r += ftotal;
-                                       else
-                                               /* r' = r + n*f_local */
-                                               r += numrep * (flocal+ftotal);
-                               }
+                               /* r' = r + f_total */
+                               r += ftotal;
 
                                /* bucket choose */
                                if (in->size == 0) {
                                        reject = 1;
                                        goto reject;
                                }
-                               if (map->choose_local_fallback_tries > 0 &&
+                               if (local_fallback_tries > 0 &&
                                    flocal >= (in->size>>1) &&
-                                   flocal > map->choose_local_fallback_tries)
+                                   flocal > local_fallback_tries)
                                        item = bucket_perm_choose(in, x, r);
                                else
                                        item = crush_bucket_choose(in, x, r);
@@ -394,13 +387,15 @@ static int crush_choose(const struct crush_map *map,
                                reject = 0;
                                if (!collide && recurse_to_leaf) {
                                        if (item < 0) {
-                                               if (crush_choose(map,
+                                               if (crush_choose_firstn(map,
                                                         map->buckets[-1-item],
-                                                        weight,
+                                                        weight, weight_max,
                                                         x, outpos+1, 0,
                                                         out2, outpos,
-                                                        firstn, 0,
-                                                        map->chooseleaf_descend_once,
+                                                        recurse_tries, 0,
+                                                        local_tries,
+                                                        local_fallback_tries,
+                                                        0,
                                                         NULL) <= outpos)
                                                        /* didn't get leaf */
                                                        reject = 1;
@@ -414,6 +409,7 @@ static int crush_choose(const struct crush_map *map,
                                        /* out? */
                                        if (itemtype == 0)
                                                reject = is_out(map, weight,
+                                                               weight_max,
                                                                item, x);
                                        else
                                                reject = 0;
@@ -424,17 +420,14 @@ reject:
                                        ftotal++;
                                        flocal++;
 
-                                       if (reject && descend_once)
-                                               /* let outer call try again */
-                                               skip_rep = 1;
-                                       else if (collide && flocal <= map->choose_local_tries)
+                                       if (collide && flocal <= local_tries)
                                                /* retry locally a few times */
                                                retry_bucket = 1;
-                                       else if (map->choose_local_fallback_tries > 0 &&
-                                                flocal <= in->size + map->choose_local_fallback_tries)
+                                       else if (local_fallback_tries > 0 &&
+                                                flocal <= in->size + local_fallback_tries)
                                                /* exhaustive bucket search */
                                                retry_bucket = 1;
-                                       else if (ftotal <= map->choose_total_tries)
+                                       else if (ftotal <= tries)
                                                /* then retry descent */
                                                retry_descent = 1;
                                        else
@@ -463,6 +456,160 @@ reject:
 }
 
 
+/**
+ * crush_choose_indep: alternative breadth-first positionally stable mapping
+ *
+ */
+static void crush_choose_indep(const struct crush_map *map,
+                              struct crush_bucket *bucket,
+                              const __u32 *weight, int weight_max,
+                              int x, int left, int numrep, int type,
+                              int *out, int outpos,
+                              unsigned int tries,
+                              unsigned int recurse_tries,
+                              int recurse_to_leaf,
+                              int *out2,
+                              int parent_r)
+{
+       struct crush_bucket *in = bucket;
+       int endpos = outpos + left;
+       int rep;
+       unsigned int ftotal;
+       int r;
+       int i;
+       int item = 0;
+       int itemtype;
+       int collide;
+
+       dprintk("CHOOSE%s INDEP bucket %d x %d outpos %d numrep %d\n", recurse_to_leaf ? "_LEAF" : "",
+               bucket->id, x, outpos, numrep);
+
+       /* initially my result is undefined */
+       for (rep = outpos; rep < endpos; rep++) {
+               out[rep] = CRUSH_ITEM_UNDEF;
+               if (out2)
+                       out2[rep] = CRUSH_ITEM_UNDEF;
+       }
+
+       for (ftotal = 0; left > 0 && ftotal < tries; ftotal++) {
+               for (rep = outpos; rep < endpos; rep++) {
+                       if (out[rep] != CRUSH_ITEM_UNDEF)
+                               continue;
+
+                       in = bucket;  /* initial bucket */
+
+                       /* choose through intervening buckets */
+                       for (;;) {
+                               /* note: we base the choice on the position
+                                * even in the nested call.  that means that
+                                * if the first layer chooses the same bucket
+                                * in a different position, we will tend to
+                                * choose a different item in that bucket.
+                                * this will involve more devices in data
+                                * movement and tend to distribute the load.
+                                */
+                               r = rep + parent_r;
+
+                               /* be careful */
+                               if (in->alg == CRUSH_BUCKET_UNIFORM &&
+                                   in->size % numrep == 0)
+                                       /* r'=r+(n+1)*f_total */
+                                       r += (numrep+1) * ftotal;
+                               else
+                                       /* r' = r + n*f_total */
+                                       r += numrep * ftotal;
+
+                               /* bucket choose */
+                               if (in->size == 0) {
+                                       dprintk("   empty bucket\n");
+                                       break;
+                               }
+
+                               item = crush_bucket_choose(in, x, r);
+                               if (item >= map->max_devices) {
+                                       dprintk("   bad item %d\n", item);
+                                       out[rep] = CRUSH_ITEM_NONE;
+                                       if (out2)
+                                               out2[rep] = CRUSH_ITEM_NONE;
+                                       left--;
+                                       break;
+                               }
+
+                               /* desired type? */
+                               if (item < 0)
+                                       itemtype = map->buckets[-1-item]->type;
+                               else
+                                       itemtype = 0;
+                               dprintk("  item %d type %d\n", item, itemtype);
+
+                               /* keep going? */
+                               if (itemtype != type) {
+                                       if (item >= 0 ||
+                                           (-1-item) >= map->max_buckets) {
+                                               dprintk("   bad item type %d\n", type);
+                                               out[rep] = CRUSH_ITEM_NONE;
+                                               if (out2)
+                                                       out2[rep] =
+                                                               CRUSH_ITEM_NONE;
+                                               left--;
+                                               break;
+                                       }
+                                       in = map->buckets[-1-item];
+                                       continue;
+                               }
+
+                               /* collision? */
+                               collide = 0;
+                               for (i = outpos; i < endpos; i++) {
+                                       if (out[i] == item) {
+                                               collide = 1;
+                                               break;
+                                       }
+                               }
+                               if (collide)
+                                       break;
+
+                               if (recurse_to_leaf) {
+                                       if (item < 0) {
+                                               crush_choose_indep(map,
+                                                  map->buckets[-1-item],
+                                                  weight, weight_max,
+                                                  x, 1, numrep, 0,
+                                                  out2, rep,
+                                                  recurse_tries, 0,
+                                                  0, NULL, r);
+                                               if (out2[rep] == CRUSH_ITEM_NONE) {
+                                                       /* placed nothing; no leaf */
+                                                       break;
+                                               }
+                                       } else {
+                                               /* we already have a leaf! */
+                                               out2[rep] = item;
+                                       }
+                               }
+
+                               /* out? */
+                               if (itemtype == 0 &&
+                                   is_out(map, weight, weight_max, item, x))
+                                       break;
+
+                               /* yay! */
+                               out[rep] = item;
+                               left--;
+                               break;
+                       }
+               }
+       }
+       for (rep = outpos; rep < endpos; rep++) {
+               if (out[rep] == CRUSH_ITEM_UNDEF) {
+                       out[rep] = CRUSH_ITEM_NONE;
+               }
+               if (out2 && out2[rep] == CRUSH_ITEM_UNDEF) {
+                       out2[rep] = CRUSH_ITEM_NONE;
+               }
+       }
+}
+
 /**
  * crush_do_rule - calculate a mapping with the given input and rule
  * @map: the crush_map
@@ -470,15 +617,19 @@ reject:
  * @x: hash input
  * @result: pointer to result vector
  * @result_max: maximum result size
+ * @weight: weight vector (for map leaves)
+ * @weight_max: size of weight vector
+ * @scratch: scratch vector for private use; must be >= 3 * result_max
  */
 int crush_do_rule(const struct crush_map *map,
                  int ruleno, int x, int *result, int result_max,
-                 const __u32 *weight)
+                 const __u32 *weight, int weight_max,
+                 int *scratch)
 {
        int result_len;
-       int a[CRUSH_MAX_SET];
-       int b[CRUSH_MAX_SET];
-       int c[CRUSH_MAX_SET];
+       int *a = scratch;
+       int *b = scratch + result_max;
+       int *c = scratch + result_max*2;
        int recurse_to_leaf;
        int *w;
        int wsize = 0;
@@ -489,8 +640,10 @@ int crush_do_rule(const struct crush_map *map,
        __u32 step;
        int i, j;
        int numrep;
-       int firstn;
-       const int descend_once = 0;
+       int choose_tries = map->choose_total_tries;
+       int choose_local_tries = map->choose_local_tries;
+       int choose_local_fallback_tries = map->choose_local_fallback_tries;
+       int choose_leaf_tries = 0;
 
        if ((__u32)ruleno >= map->max_rules) {
                dprintk(" bad ruleno %d\n", ruleno);
@@ -503,29 +656,49 @@ int crush_do_rule(const struct crush_map *map,
        o = b;
 
        for (step = 0; step < rule->len; step++) {
+               int firstn = 0;
                struct crush_rule_step *curstep = &rule->steps[step];
 
-               firstn = 0;
                switch (curstep->op) {
                case CRUSH_RULE_TAKE:
                        w[0] = curstep->arg1;
                        wsize = 1;
                        break;
 
-               case CRUSH_RULE_CHOOSE_LEAF_FIRSTN:
+               case CRUSH_RULE_SET_CHOOSE_TRIES:
+                       if (curstep->arg1 > 0)
+                               choose_tries = curstep->arg1;
+                       break;
+
+               case CRUSH_RULE_SET_CHOOSELEAF_TRIES:
+                       if (curstep->arg1 > 0)
+                               choose_leaf_tries = curstep->arg1;
+                       break;
+
+               case CRUSH_RULE_SET_CHOOSE_LOCAL_TRIES:
+                       if (curstep->arg1 > 0)
+                               choose_local_tries = curstep->arg1;
+                       break;
+
+               case CRUSH_RULE_SET_CHOOSE_LOCAL_FALLBACK_TRIES:
+                       if (curstep->arg1 > 0)
+                               choose_local_fallback_tries = curstep->arg1;
+                       break;
+
+               case CRUSH_RULE_CHOOSELEAF_FIRSTN:
                case CRUSH_RULE_CHOOSE_FIRSTN:
                        firstn = 1;
                        /* fall through */
-               case CRUSH_RULE_CHOOSE_LEAF_INDEP:
+               case CRUSH_RULE_CHOOSELEAF_INDEP:
                case CRUSH_RULE_CHOOSE_INDEP:
                        if (wsize == 0)
                                break;
 
                        recurse_to_leaf =
                                curstep->op ==
-                                CRUSH_RULE_CHOOSE_LEAF_FIRSTN ||
+                                CRUSH_RULE_CHOOSELEAF_FIRSTN ||
                                curstep->op ==
-                               CRUSH_RULE_CHOOSE_LEAF_INDEP;
+                               CRUSH_RULE_CHOOSELEAF_INDEP;
 
                        /* reset output */
                        osize = 0;
@@ -543,22 +716,51 @@ int crush_do_rule(const struct crush_map *map,
                                                continue;
                                }
                                j = 0;
-                               osize += crush_choose(map,
-                                                     map->buckets[-1-w[i]],
-                                                     weight,
-                                                     x, numrep,
-                                                     curstep->arg2,
-                                                     o+osize, j,
-                                                     firstn,
-                                                     recurse_to_leaf,
-                                                     descend_once, c+osize);
+                               if (firstn) {
+                                       int recurse_tries;
+                                       if (choose_leaf_tries)
+                                               recurse_tries =
+                                                       choose_leaf_tries;
+                                       else if (map->chooseleaf_descend_once)
+                                               recurse_tries = 1;
+                                       else
+                                               recurse_tries = choose_tries;
+                                       osize += crush_choose_firstn(
+                                               map,
+                                               map->buckets[-1-w[i]],
+                                               weight, weight_max,
+                                               x, numrep,
+                                               curstep->arg2,
+                                               o+osize, j,
+                                               choose_tries,
+                                               recurse_tries,
+                                               choose_local_tries,
+                                               choose_local_fallback_tries,
+                                               recurse_to_leaf,
+                                               c+osize);
+                               } else {
+                                       crush_choose_indep(
+                                               map,
+                                               map->buckets[-1-w[i]],
+                                               weight, weight_max,
+                                               x, numrep, numrep,
+                                               curstep->arg2,
+                                               o+osize, j,
+                                               choose_tries,
+                                               choose_leaf_tries ?
+                                                  choose_leaf_tries : 1,
+                                               recurse_to_leaf,
+                                               c+osize,
+                                               0);
+                                       osize += numrep;
+                               }
                        }
 
                        if (recurse_to_leaf)
                                /* copy final _leaf_ values to output set */
                                memcpy(o, c, osize*sizeof(*o));
 
-                       /* swap t and w arrays */
+                       /* swap o and w arrays */
                        tmp = o;
                        o = w;
                        w = tmp;
index 83661cdc0766de24a458d06cdede00c3f3d6a4a2..258a382e75ed665a597d063a1234150e47d8f5f0 100644 (file)
@@ -132,7 +132,8 @@ static int osdc_show(struct seq_file *s, void *pp)
                           req->r_osd ? req->r_osd->o_osd : -1,
                           req->r_pgid.pool, req->r_pgid.seed);
 
-               seq_printf(s, "%.*s", req->r_oid_len, req->r_oid);
+               seq_printf(s, "%.*s", req->r_base_oid.name_len,
+                          req->r_base_oid.name);
 
                if (req->r_reassert_version.epoch)
                        seq_printf(s, "\t%u'%llu",
index 4a5df7b1cc9ff5652185e0248cf5a4df4006effd..0e478a0f4204b72ed19ae49c349d632cda009e02 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/dns_resolver.h>
 #include <net/tcp.h>
 
+#include <linux/ceph/ceph_features.h>
 #include <linux/ceph/libceph.h>
 #include <linux/ceph/messenger.h>
 #include <linux/ceph/decode.h>
@@ -777,13 +778,12 @@ static void ceph_msg_data_bio_cursor_init(struct ceph_msg_data_cursor *cursor,
 
        bio = data->bio;
        BUG_ON(!bio);
-       BUG_ON(!bio->bi_vcnt);
 
        cursor->resid = min(length, data->bio_length);
        cursor->bio = bio;
-       cursor->vector_index = 0;
-       cursor->vector_offset = 0;
-       cursor->last_piece = length <= bio->bi_io_vec[0].bv_len;
+       cursor->bvec_iter = bio->bi_iter;
+       cursor->last_piece =
+               cursor->resid <= bio_iter_len(bio, cursor->bvec_iter);
 }
 
 static struct page *ceph_msg_data_bio_next(struct ceph_msg_data_cursor *cursor,
@@ -792,71 +792,63 @@ static struct page *ceph_msg_data_bio_next(struct ceph_msg_data_cursor *cursor,
 {
        struct ceph_msg_data *data = cursor->data;
        struct bio *bio;
-       struct bio_vec *bio_vec;
-       unsigned int index;
+       struct bio_vec bio_vec;
 
        BUG_ON(data->type != CEPH_MSG_DATA_BIO);
 
        bio = cursor->bio;
        BUG_ON(!bio);
 
-       index = cursor->vector_index;
-       BUG_ON(index >= (unsigned int) bio->bi_vcnt);
+       bio_vec = bio_iter_iovec(bio, cursor->bvec_iter);
 
-       bio_vec = &bio->bi_io_vec[index];
-       BUG_ON(cursor->vector_offset >= bio_vec->bv_len);
-       *page_offset = (size_t) (bio_vec->bv_offset + cursor->vector_offset);
+       *page_offset = (size_t) bio_vec.bv_offset;
        BUG_ON(*page_offset >= PAGE_SIZE);
        if (cursor->last_piece) /* pagelist offset is always 0 */
                *length = cursor->resid;
        else
-               *length = (size_t) (bio_vec->bv_len - cursor->vector_offset);
+               *length = (size_t) bio_vec.bv_len;
        BUG_ON(*length > cursor->resid);
        BUG_ON(*page_offset + *length > PAGE_SIZE);
 
-       return bio_vec->bv_page;
+       return bio_vec.bv_page;
 }
 
 static bool ceph_msg_data_bio_advance(struct ceph_msg_data_cursor *cursor,
                                        size_t bytes)
 {
        struct bio *bio;
-       struct bio_vec *bio_vec;
-       unsigned int index;
+       struct bio_vec bio_vec;
 
        BUG_ON(cursor->data->type != CEPH_MSG_DATA_BIO);
 
        bio = cursor->bio;
        BUG_ON(!bio);
 
-       index = cursor->vector_index;
-       BUG_ON(index >= (unsigned int) bio->bi_vcnt);
-       bio_vec = &bio->bi_io_vec[index];
+       bio_vec = bio_iter_iovec(bio, cursor->bvec_iter);
 
        /* Advance the cursor offset */
 
        BUG_ON(cursor->resid < bytes);
        cursor->resid -= bytes;
-       cursor->vector_offset += bytes;
-       if (cursor->vector_offset < bio_vec->bv_len)
+
+       bio_advance_iter(bio, &cursor->bvec_iter, bytes);
+
+       if (bytes < bio_vec.bv_len)
                return false;   /* more bytes to process in this segment */
-       BUG_ON(cursor->vector_offset != bio_vec->bv_len);
 
        /* Move on to the next segment, and possibly the next bio */
 
-       if (++index == (unsigned int) bio->bi_vcnt) {
+       if (!cursor->bvec_iter.bi_size) {
                bio = bio->bi_next;
-               index = 0;
+               cursor->bvec_iter = bio->bi_iter;
        }
        cursor->bio = bio;
-       cursor->vector_index = index;
-       cursor->vector_offset = 0;
 
        if (!cursor->last_piece) {
                BUG_ON(!cursor->resid);
                BUG_ON(!bio);
                /* A short read is OK, so use <= rather than == */
-               if (cursor->resid <= bio->bi_io_vec[index].bv_len)
+               if (cursor->resid <= bio_iter_len(bio, cursor->bvec_iter))
                        cursor->last_piece = true;
        }
 
@@ -1865,7 +1857,9 @@ int ceph_parse_ips(const char *c, const char *end,
                                port = (port * 10) + (*p - '0');
                                p++;
                        }
-                       if (port > 65535 || port == 0)
+                       if (port == 0)
+                               port = CEPH_MON_PORT;
+                       else if (port > 65535)
                                goto bad;
                } else {
                        port = CEPH_MON_PORT;
@@ -1945,7 +1939,8 @@ static int process_connect(struct ceph_connection *con)
 {
        u64 sup_feat = con->msgr->supported_features;
        u64 req_feat = con->msgr->required_features;
-       u64 server_feat = le64_to_cpu(con->in_reply.features);
+       u64 server_feat = ceph_sanitize_features(
+                               le64_to_cpu(con->in_reply.features));
        int ret;
 
        dout("process_connect on %p tag %d\n", con, (int)con->in_tag);
@@ -2853,8 +2848,8 @@ static void con_fault(struct ceph_connection *con)
  */
 void ceph_messenger_init(struct ceph_messenger *msgr,
                        struct ceph_entity_addr *myaddr,
-                       u32 supported_features,
-                       u32 required_features,
+                       u64 supported_features,
+                       u64 required_features,
                        bool nocrc)
 {
        msgr->supported_features = supported_features;
@@ -3126,15 +3121,8 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags,
        INIT_LIST_HEAD(&m->data);
 
        /* front */
-       m->front_max = front_len;
        if (front_len) {
-               if (front_len > PAGE_CACHE_SIZE) {
-                       m->front.iov_base = __vmalloc(front_len, flags,
-                                                     PAGE_KERNEL);
-                       m->front_is_vmalloc = true;
-               } else {
-                       m->front.iov_base = kmalloc(front_len, flags);
-               }
+               m->front.iov_base = ceph_kvmalloc(front_len, flags);
                if (m->front.iov_base == NULL) {
                        dout("ceph_msg_new can't allocate %d bytes\n",
                             front_len);
@@ -3143,7 +3131,7 @@ struct ceph_msg *ceph_msg_new(int type, int front_len, gfp_t flags,
        } else {
                m->front.iov_base = NULL;
        }
-       m->front.iov_len = front_len;
+       m->front_alloc_len = m->front.iov_len = front_len;
 
        dout("ceph_msg_new %p front %d\n", m, front_len);
        return m;
@@ -3256,10 +3244,7 @@ static int ceph_con_in_msg_alloc(struct ceph_connection *con, int *skip)
 void ceph_msg_kfree(struct ceph_msg *m)
 {
        dout("msg_kfree %p\n", m);
-       if (m->front_is_vmalloc)
-               vfree(m->front.iov_base);
-       else
-               kfree(m->front.iov_base);
+       ceph_kvfree(m->front.iov_base);
        kmem_cache_free(ceph_msg_cache, m);
 }
 
@@ -3301,8 +3286,8 @@ EXPORT_SYMBOL(ceph_msg_last_put);
 
 void ceph_msg_dump(struct ceph_msg *msg)
 {
-       pr_debug("msg_dump %p (front_max %d length %zd)\n", msg,
-                msg->front_max, msg->data_length);
+       pr_debug("msg_dump %p (front_alloc_len %d length %zd)\n", msg,
+                msg->front_alloc_len, msg->data_length);
        print_hex_dump(KERN_DEBUG, "header: ",
                       DUMP_PREFIX_OFFSET, 16, 1,
                       &msg->hdr, sizeof(msg->hdr), true);
index 1fe25cd29d0eceb66bb4924ee85e5a62b598c48a..2ac9ef35110b3e9ea07363d6f2d3c0eb2e4ee27b 100644 (file)
@@ -152,7 +152,7 @@ static int __open_session(struct ceph_mon_client *monc)
                /* initiatiate authentication handshake */
                ret = ceph_auth_build_hello(monc->auth,
                                            monc->m_auth->front.iov_base,
-                                           monc->m_auth->front_max);
+                                           monc->m_auth->front_alloc_len);
                __send_prepared_auth_request(monc, ret);
        } else {
                dout("open_session mon%d already open\n", monc->cur_mon);
@@ -196,7 +196,7 @@ static void __send_subscribe(struct ceph_mon_client *monc)
                int num;
 
                p = msg->front.iov_base;
-               end = p + msg->front_max;
+               end = p + msg->front_alloc_len;
 
                num = 1 + !!monc->want_next_osdmap + !!monc->want_mdsmap;
                ceph_encode_32(&p, num);
@@ -897,7 +897,7 @@ static void handle_auth_reply(struct ceph_mon_client *monc,
        ret = ceph_handle_auth_reply(monc->auth, msg->front.iov_base,
                                     msg->front.iov_len,
                                     monc->m_auth->front.iov_base,
-                                    monc->m_auth->front_max);
+                                    monc->m_auth->front_alloc_len);
        if (ret < 0) {
                monc->client->auth_err = ret;
                wake_up_all(&monc->client->auth_wq);
@@ -939,7 +939,7 @@ static int __validate_auth(struct ceph_mon_client *monc)
                return 0;
 
        ret = ceph_build_auth(monc->auth, monc->m_auth->front.iov_base,
-                             monc->m_auth->front_max);
+                             monc->m_auth->front_alloc_len);
        if (ret <= 0)
                return ret; /* either an error, or no need to authenticate */
        __send_prepared_auth_request(monc, ret);
index 2b4b32aaa893b3117043e6a218fcde6c58f0aff4..010ff3bd58ade67373c0db7531a2ec8ea9bb1460 100644 (file)
@@ -338,7 +338,7 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
        msg_size = 4 + 4 + 8 + 8 + 4+8;
        msg_size += 2 + 4 + 8 + 4 + 4; /* oloc */
        msg_size += 1 + 8 + 4 + 4;     /* pg_t */
-       msg_size += 4 + MAX_OBJ_NAME_SIZE;
+       msg_size += 4 + CEPH_MAX_OID_NAME_LEN; /* oid */
        msg_size += 2 + num_ops*sizeof(struct ceph_osd_op);
        msg_size += 8;  /* snapid */
        msg_size += 8;  /* snap_seq */
@@ -368,6 +368,9 @@ struct ceph_osd_request *ceph_osdc_alloc_request(struct ceph_osd_client *osdc,
        INIT_LIST_HEAD(&req->r_req_lru_item);
        INIT_LIST_HEAD(&req->r_osd_item);
 
+       req->r_base_oloc.pool = -1;
+       req->r_target_oloc.pool = -1;
+
        /* create reply message */
        if (use_mempool)
                msg = ceph_msgpool_get(&osdc->msgpool_op_reply, 0);
@@ -761,11 +764,11 @@ struct ceph_osd_request *ceph_osdc_new_request(struct ceph_osd_client *osdc,
        if (num_ops > 1)
                osd_req_op_init(req, 1, CEPH_OSD_OP_STARTSYNC);
 
-       req->r_file_layout = *layout;  /* keep a copy */
+       req->r_base_oloc.pool = ceph_file_layout_pg_pool(*layout);
 
-       snprintf(req->r_oid, sizeof(req->r_oid), "%llx.%08llx",
-               vino.ino, objnum);
-       req->r_oid_len = strlen(req->r_oid);
+       snprintf(req->r_base_oid.name, sizeof(req->r_base_oid.name),
+                "%llx.%08llx", vino.ino, objnum);
+       req->r_base_oid.name_len = strlen(req->r_base_oid.name);
 
        return req;
 }
@@ -1044,8 +1047,8 @@ static int __reset_osd(struct ceph_osd_client *osdc, struct ceph_osd *osd)
                        !ceph_con_opened(&osd->o_con)) {
                struct ceph_osd_request *req;
 
-               dout(" osd addr hasn't changed and connection never opened,"
-                    " letting msgr retry");
+               dout("osd addr hasn't changed and connection never opened, "
+                    "letting msgr retry\n");
                /* touch each r_stamp for handle_timeout()'s benfit */
                list_for_each_entry(req, &osd->o_requests, r_osd_item)
                        req->r_stamp = jiffies;
@@ -1231,6 +1234,61 @@ void ceph_osdc_set_request_linger(struct ceph_osd_client *osdc,
 }
 EXPORT_SYMBOL(ceph_osdc_set_request_linger);
 
+/*
+ * Returns whether a request should be blocked from being sent
+ * based on the current osdmap and osd_client settings.
+ *
+ * Caller should hold map_sem for read.
+ */
+static bool __req_should_be_paused(struct ceph_osd_client *osdc,
+                                  struct ceph_osd_request *req)
+{
+       bool pauserd = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSERD);
+       bool pausewr = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSEWR) ||
+               ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL);
+       return (req->r_flags & CEPH_OSD_FLAG_READ && pauserd) ||
+               (req->r_flags & CEPH_OSD_FLAG_WRITE && pausewr);
+}
+
+/*
+ * Calculate mapping of a request to a PG.  Takes tiering into account.
+ */
+static int __calc_request_pg(struct ceph_osdmap *osdmap,
+                            struct ceph_osd_request *req,
+                            struct ceph_pg *pg_out)
+{
+       bool need_check_tiering;
+
+       need_check_tiering = false;
+       if (req->r_target_oloc.pool == -1) {
+               req->r_target_oloc = req->r_base_oloc; /* struct */
+               need_check_tiering = true;
+       }
+       if (req->r_target_oid.name_len == 0) {
+               ceph_oid_copy(&req->r_target_oid, &req->r_base_oid);
+               need_check_tiering = true;
+       }
+
+       if (need_check_tiering &&
+           (req->r_flags & CEPH_OSD_FLAG_IGNORE_OVERLAY) == 0) {
+               struct ceph_pg_pool_info *pi;
+
+               pi = ceph_pg_pool_by_id(osdmap, req->r_target_oloc.pool);
+               if (pi) {
+                       if ((req->r_flags & CEPH_OSD_FLAG_READ) &&
+                           pi->read_tier >= 0)
+                               req->r_target_oloc.pool = pi->read_tier;
+                       if ((req->r_flags & CEPH_OSD_FLAG_WRITE) &&
+                           pi->write_tier >= 0)
+                               req->r_target_oloc.pool = pi->write_tier;
+               }
+               /* !pi is caught in ceph_oloc_oid_to_pg() */
+       }
+
+       return ceph_oloc_oid_to_pg(osdmap, &req->r_target_oloc,
+                                  &req->r_target_oid, pg_out);
+}
+
 /*
  * Pick an osd (the first 'up' osd in the pg), allocate the osd struct
  * (as needed), and set the request r_osd appropriately.  If there is
@@ -1248,10 +1306,11 @@ static int __map_request(struct ceph_osd_client *osdc,
        int acting[CEPH_PG_MAX_SIZE];
        int o = -1, num = 0;
        int err;
+       bool was_paused;
 
        dout("map_request %p tid %lld\n", req, req->r_tid);
-       err = ceph_calc_ceph_pg(&pgid, req->r_oid, osdc->osdmap,
-                               ceph_file_layout_pg_pool(req->r_file_layout));
+
+       err = __calc_request_pg(osdc->osdmap, req, &pgid);
        if (err) {
                list_move(&req->r_req_lru_item, &osdc->req_notarget);
                return err;
@@ -1264,12 +1323,18 @@ static int __map_request(struct ceph_osd_client *osdc,
                num = err;
        }
 
+       was_paused = req->r_paused;
+       req->r_paused = __req_should_be_paused(osdc, req);
+       if (was_paused && !req->r_paused)
+               force_resend = 1;
+
        if ((!force_resend &&
             req->r_osd && req->r_osd->o_osd == o &&
             req->r_sent >= req->r_osd->o_incarnation &&
             req->r_num_pg_osds == num &&
             memcmp(req->r_pg_osds, acting, sizeof(acting[0])*num) == 0) ||
-           (req->r_osd == NULL && o == -1))
+           (req->r_osd == NULL && o == -1) ||
+           req->r_paused)
                return 0;  /* no change */
 
        dout("map_request tid %llu pgid %lld.%x osd%d (was osd%d)\n",
@@ -1331,7 +1396,7 @@ static void __send_request(struct ceph_osd_client *osdc,
        /* fill in message content that changes each time we send it */
        put_unaligned_le32(osdc->osdmap->epoch, req->r_request_osdmap_epoch);
        put_unaligned_le32(req->r_flags, req->r_request_flags);
-       put_unaligned_le64(req->r_pgid.pool, req->r_request_pool);
+       put_unaligned_le64(req->r_target_oloc.pool, req->r_request_pool);
        p = req->r_request_pgid;
        ceph_encode_64(&p, req->r_pgid.pool);
        ceph_encode_32(&p, req->r_pgid.seed);
@@ -1432,6 +1497,109 @@ static void handle_osds_timeout(struct work_struct *work)
                              round_jiffies_relative(delay));
 }
 
+static int ceph_oloc_decode(void **p, void *end,
+                           struct ceph_object_locator *oloc)
+{
+       u8 struct_v, struct_cv;
+       u32 len;
+       void *struct_end;
+       int ret = 0;
+
+       ceph_decode_need(p, end, 1 + 1 + 4, e_inval);
+       struct_v = ceph_decode_8(p);
+       struct_cv = ceph_decode_8(p);
+       if (struct_v < 3) {
+               pr_warn("got v %d < 3 cv %d of ceph_object_locator\n",
+                       struct_v, struct_cv);
+               goto e_inval;
+       }
+       if (struct_cv > 6) {
+               pr_warn("got v %d cv %d > 6 of ceph_object_locator\n",
+                       struct_v, struct_cv);
+               goto e_inval;
+       }
+       len = ceph_decode_32(p);
+       ceph_decode_need(p, end, len, e_inval);
+       struct_end = *p + len;
+
+       oloc->pool = ceph_decode_64(p);
+       *p += 4; /* skip preferred */
+
+       len = ceph_decode_32(p);
+       if (len > 0) {
+               pr_warn("ceph_object_locator::key is set\n");
+               goto e_inval;
+       }
+
+       if (struct_v >= 5) {
+               len = ceph_decode_32(p);
+               if (len > 0) {
+                       pr_warn("ceph_object_locator::nspace is set\n");
+                       goto e_inval;
+               }
+       }
+
+       if (struct_v >= 6) {
+               s64 hash = ceph_decode_64(p);
+               if (hash != -1) {
+                       pr_warn("ceph_object_locator::hash is set\n");
+                       goto e_inval;
+               }
+       }
+
+       /* skip the rest */
+       *p = struct_end;
+out:
+       return ret;
+
+e_inval:
+       ret = -EINVAL;
+       goto out;
+}
+
+static int ceph_redirect_decode(void **p, void *end,
+                               struct ceph_request_redirect *redir)
+{
+       u8 struct_v, struct_cv;
+       u32 len;
+       void *struct_end;
+       int ret;
+
+       ceph_decode_need(p, end, 1 + 1 + 4, e_inval);
+       struct_v = ceph_decode_8(p);
+       struct_cv = ceph_decode_8(p);
+       if (struct_cv > 1) {
+               pr_warn("got v %d cv %d > 1 of ceph_request_redirect\n",
+                       struct_v, struct_cv);
+               goto e_inval;
+       }
+       len = ceph_decode_32(p);
+       ceph_decode_need(p, end, len, e_inval);
+       struct_end = *p + len;
+
+       ret = ceph_oloc_decode(p, end, &redir->oloc);
+       if (ret)
+               goto out;
+
+       len = ceph_decode_32(p);
+       if (len > 0) {
+               pr_warn("ceph_request_redirect::object_name is set\n");
+               goto e_inval;
+       }
+
+       len = ceph_decode_32(p);
+       *p += len; /* skip osd_instructions */
+
+       /* skip the rest */
+       *p = struct_end;
+out:
+       return ret;
+
+e_inval:
+       ret = -EINVAL;
+       goto out;
+}
+
 static void complete_request(struct ceph_osd_request *req)
 {
        complete_all(&req->r_safe_completion);  /* fsync waiter */
@@ -1446,6 +1614,7 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
 {
        void *p, *end;
        struct ceph_osd_request *req;
+       struct ceph_request_redirect redir;
        u64 tid;
        int object_len;
        unsigned int numops;
@@ -1525,10 +1694,41 @@ static void handle_reply(struct ceph_osd_client *osdc, struct ceph_msg *msg,
        for (i = 0; i < numops; i++)
                req->r_reply_op_result[i] = ceph_decode_32(&p);
 
-       already_completed = req->r_got_reply;
+       if (le16_to_cpu(msg->hdr.version) >= 6) {
+               p += 8 + 4; /* skip replay_version */
+               p += 8; /* skip user_version */
 
-       if (!req->r_got_reply) {
+               err = ceph_redirect_decode(&p, end, &redir);
+               if (err)
+                       goto bad_put;
+       } else {
+               redir.oloc.pool = -1;
+       }
+
+       if (redir.oloc.pool != -1) {
+               dout("redirect pool %lld\n", redir.oloc.pool);
+
+               __unregister_request(osdc, req);
+               mutex_unlock(&osdc->request_mutex);
+
+               req->r_target_oloc = redir.oloc; /* struct */
+
+               /*
+                * Start redirect requests with nofail=true.  If
+                * mapping fails, request will end up on the notarget
+                * list, waiting for the new osdmap (which can take
+                * a while), even though the original request mapped
+                * successfully.  In the future we might want to follow
+                * original request's nofail setting here.
+                */
+               err = ceph_osdc_start_request(osdc, req, true);
+               BUG_ON(err);
 
+               goto done;
+       }
+
+       already_completed = req->r_got_reply;
+       if (!req->r_got_reply) {
                req->r_result = result;
                dout("handle_reply result %d bytes %d\n", req->r_result,
                     bytes);
@@ -1581,6 +1781,13 @@ done:
        return;
 
 bad_put:
+       req->r_result = -EIO;
+       __unregister_request(osdc, req);
+       if (req->r_callback)
+               req->r_callback(req, msg);
+       else
+               complete_all(&req->r_completion);
+       complete_request(req);
        ceph_osdc_put_request(req);
 bad_mutex:
        mutex_unlock(&osdc->request_mutex);
@@ -1613,14 +1820,17 @@ static void reset_changed_osds(struct ceph_osd_client *osdc)
  *
  * Caller should hold map_sem for read.
  */
-static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
+static void kick_requests(struct ceph_osd_client *osdc, bool force_resend,
+                         bool force_resend_writes)
 {
        struct ceph_osd_request *req, *nreq;
        struct rb_node *p;
        int needmap = 0;
        int err;
+       bool force_resend_req;
 
-       dout("kick_requests %s\n", force_resend ? " (force resend)" : "");
+       dout("kick_requests %s %s\n", force_resend ? " (force resend)" : "",
+               force_resend_writes ? " (force resend writes)" : "");
        mutex_lock(&osdc->request_mutex);
        for (p = rb_first(&osdc->requests); p; ) {
                req = rb_entry(p, struct ceph_osd_request, r_node);
@@ -1645,7 +1855,10 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
                        continue;
                }
 
-               err = __map_request(osdc, req, force_resend);
+               force_resend_req = force_resend ||
+                       (force_resend_writes &&
+                               req->r_flags & CEPH_OSD_FLAG_WRITE);
+               err = __map_request(osdc, req, force_resend_req);
                if (err < 0)
                        continue;  /* error */
                if (req->r_osd == NULL) {
@@ -1665,7 +1878,8 @@ static void kick_requests(struct ceph_osd_client *osdc, int force_resend)
                                 r_linger_item) {
                dout("linger req=%p req->r_osd=%p\n", req, req->r_osd);
 
-               err = __map_request(osdc, req, force_resend);
+               err = __map_request(osdc, req,
+                                   force_resend || force_resend_writes);
                dout("__map_request returned %d\n", err);
                if (err == 0)
                        continue;  /* no change and no osd was specified */
@@ -1707,6 +1921,7 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
        struct ceph_osdmap *newmap = NULL, *oldmap;
        int err;
        struct ceph_fsid fsid;
+       bool was_full;
 
        dout("handle_map have %u\n", osdc->osdmap ? osdc->osdmap->epoch : 0);
        p = msg->front.iov_base;
@@ -1720,6 +1935,8 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
 
        down_write(&osdc->map_sem);
 
+       was_full = ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL);
+
        /* incremental maps */
        ceph_decode_32_safe(&p, end, nr_maps, bad);
        dout(" %d inc maps\n", nr_maps);
@@ -1744,7 +1961,10 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                                ceph_osdmap_destroy(osdc->osdmap);
                                osdc->osdmap = newmap;
                        }
-                       kick_requests(osdc, 0);
+                       was_full = was_full ||
+                               ceph_osdmap_flag(osdc->osdmap,
+                                                CEPH_OSDMAP_FULL);
+                       kick_requests(osdc, 0, was_full);
                } else {
                        dout("ignoring incremental map %u len %d\n",
                             epoch, maplen);
@@ -1787,7 +2007,10 @@ void ceph_osdc_handle_map(struct ceph_osd_client *osdc, struct ceph_msg *msg)
                                        skipped_map = 1;
                                ceph_osdmap_destroy(oldmap);
                        }
-                       kick_requests(osdc, skipped_map);
+                       was_full = was_full ||
+                               ceph_osdmap_flag(osdc->osdmap,
+                                                CEPH_OSDMAP_FULL);
+                       kick_requests(osdc, skipped_map, was_full);
                }
                p += maplen;
                nr_maps--;
@@ -1804,7 +2027,9 @@ done:
         * we find out when we are no longer full and stop returning
         * ENOSPC.
         */
-       if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL))
+       if (ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_FULL) ||
+               ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSERD) ||
+               ceph_osdmap_flag(osdc->osdmap, CEPH_OSDMAP_PAUSEWR))
                ceph_monc_request_next_osdmap(&osdc->client->monc);
 
        mutex_lock(&osdc->request_mutex);
@@ -2068,10 +2293,11 @@ void ceph_osdc_build_request(struct ceph_osd_request *req, u64 off,
        ceph_encode_32(&p, -1);  /* preferred */
 
        /* oid */
-       ceph_encode_32(&p, req->r_oid_len);
-       memcpy(p, req->r_oid, req->r_oid_len);
-       dout("oid '%.*s' len %d\n", req->r_oid_len, req->r_oid, req->r_oid_len);
-       p += req->r_oid_len;
+       ceph_encode_32(&p, req->r_base_oid.name_len);
+       memcpy(p, req->r_base_oid.name, req->r_base_oid.name_len);
+       dout("oid '%.*s' len %d\n", req->r_base_oid.name_len,
+            req->r_base_oid.name, req->r_base_oid.name_len);
+       p += req->r_base_oid.name_len;
 
        /* ops--can imply data */
        ceph_encode_16(&p, (u16)req->r_num_ops);
@@ -2454,7 +2680,7 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
        struct ceph_osd_client *osdc = osd->o_osdc;
        struct ceph_msg *m;
        struct ceph_osd_request *req;
-       int front = le32_to_cpu(hdr->front_len);
+       int front_len = le32_to_cpu(hdr->front_len);
        int data_len = le32_to_cpu(hdr->data_len);
        u64 tid;
 
@@ -2474,12 +2700,13 @@ static struct ceph_msg *get_reply(struct ceph_connection *con,
                     req->r_reply, req->r_reply->con);
        ceph_msg_revoke_incoming(req->r_reply);
 
-       if (front > req->r_reply->front.iov_len) {
+       if (front_len > req->r_reply->front_alloc_len) {
                pr_warning("get_reply front %d > preallocated %d (%u#%llu)\n",
-                          front, (int)req->r_reply->front.iov_len,
+                          front_len, req->r_reply->front_alloc_len,
                           (unsigned int)con->peer_name.type,
                           le64_to_cpu(con->peer_name.num));
-               m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front, GFP_NOFS, false);
+               m = ceph_msg_new(CEPH_MSG_OSD_OPREPLY, front_len, GFP_NOFS,
+                                false);
                if (!m)
                        goto out;
                ceph_msg_put(req->r_reply);
index dbd9a4792427455e0a2dfdd7d2249c4abcbbb798..aade4a5c1c07f6ab0ca0f1ee66dfacbded110aed 100644 (file)
@@ -464,6 +464,11 @@ static struct ceph_pg_pool_info *__lookup_pg_pool(struct rb_root *root, u64 id)
        return NULL;
 }
 
+struct ceph_pg_pool_info *ceph_pg_pool_by_id(struct ceph_osdmap *map, u64 id)
+{
+       return __lookup_pg_pool(&map->pg_pools, id);
+}
+
 const char *ceph_pg_pool_name_by_id(struct ceph_osdmap *map, u64 id)
 {
        struct ceph_pg_pool_info *pi;
@@ -514,8 +519,8 @@ static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi)
                pr_warning("got v %d < 5 cv %d of ceph_pg_pool\n", ev, cv);
                return -EINVAL;
        }
-       if (cv > 7) {
-               pr_warning("got v %d cv %d > 7 of ceph_pg_pool\n", ev, cv);
+       if (cv > 9) {
+               pr_warning("got v %d cv %d > 9 of ceph_pg_pool\n", ev, cv);
                return -EINVAL;
        }
        len = ceph_decode_32(p);
@@ -543,12 +548,34 @@ static int __decode_pool(void **p, void *end, struct ceph_pg_pool_info *pi)
                *p += len;
        }
 
-       /* skip removed snaps */
+       /* skip removed_snaps */
        num = ceph_decode_32(p);
        *p += num * (8 + 8);
 
        *p += 8;  /* skip auid */
        pi->flags = ceph_decode_64(p);
+       *p += 4;  /* skip crash_replay_interval */
+
+       if (ev >= 7)
+               *p += 1;  /* skip min_size */
+
+       if (ev >= 8)
+               *p += 8 + 8;  /* skip quota_max_* */
+
+       if (ev >= 9) {
+               /* skip tiers */
+               num = ceph_decode_32(p);
+               *p += num * 8;
+
+               *p += 8;  /* skip tier_of */
+               *p += 1;  /* skip cache_mode */
+
+               pi->read_tier = ceph_decode_64(p);
+               pi->write_tier = ceph_decode_64(p);
+       } else {
+               pi->read_tier = -1;
+               pi->write_tier = -1;
+       }
 
        /* ignore the rest */
 
@@ -1090,25 +1117,40 @@ invalid:
 EXPORT_SYMBOL(ceph_calc_file_object_mapping);
 
 /*
- * calculate an object layout (i.e. pgid) from an oid,
- * file_layout, and osdmap
+ * Calculate mapping of a (oloc, oid) pair to a PG.  Should only be
+ * called with target's (oloc, oid), since tiering isn't taken into
+ * account.
  */
-int ceph_calc_ceph_pg(struct ceph_pg *pg, const char *oid,
-                       struct ceph_osdmap *osdmap, uint64_t pool)
+int ceph_oloc_oid_to_pg(struct ceph_osdmap *osdmap,
+                       struct ceph_object_locator *oloc,
+                       struct ceph_object_id *oid,
+                       struct ceph_pg *pg_out)
 {
-       struct ceph_pg_pool_info *pool_info;
+       struct ceph_pg_pool_info *pi;
 
-       BUG_ON(!osdmap);
-       pool_info = __lookup_pg_pool(&osdmap->pg_pools, pool);
-       if (!pool_info)
+       pi = __lookup_pg_pool(&osdmap->pg_pools, oloc->pool);
+       if (!pi)
                return -EIO;
-       pg->pool = pool;
-       pg->seed = ceph_str_hash(pool_info->object_hash, oid, strlen(oid));
 
-       dout("%s '%s' pgid %lld.%x\n", __func__, oid, pg->pool, pg->seed);
+       pg_out->pool = oloc->pool;
+       pg_out->seed = ceph_str_hash(pi->object_hash, oid->name,
+                                    oid->name_len);
+
+       dout("%s '%.*s' pgid %llu.%x\n", __func__, oid->name_len, oid->name,
+            pg_out->pool, pg_out->seed);
        return 0;
 }
-EXPORT_SYMBOL(ceph_calc_ceph_pg);
+EXPORT_SYMBOL(ceph_oloc_oid_to_pg);
+
+static int crush_do_rule_ary(const struct crush_map *map, int ruleno, int x,
+                            int *result, int result_max,
+                            const __u32 *weight, int weight_max)
+{
+       int scratch[result_max * 3];
+
+       return crush_do_rule(map, ruleno, x, result, result_max,
+                            weight, weight_max, scratch);
+}
 
 /*
  * Calculate raw osd vector for the given pgid.  Return pointer to osd
@@ -1163,9 +1205,9 @@ static int *calc_pg_raw(struct ceph_osdmap *osdmap, struct ceph_pg pgid,
                                      pool->pgp_num_mask) +
                        (unsigned)pgid.pool;
        }
-       r = crush_do_rule(osdmap->crush, ruleno, pps, osds,
-                         min_t(int, pool->size, *num),
-                         osdmap->osd_weight);
+       r = crush_do_rule_ary(osdmap->crush, ruleno, pps,
+                             osds, min_t(int, pool->size, *num),
+                             osdmap->osd_weight, osdmap->max_osd);
        if (r < 0) {
                pr_err("error %d from crush rule: pool %lld ruleset %d type %d"
                       " size %d\n", r, pgid.pool, pool->crush_ruleset,
index dd32e34c1e2c9481aa2db3c37437ef0d85ba5277..f50161fb812eace2eb659ae78bf12062c608b5b6 100644 (file)
@@ -780,21 +780,16 @@ asmlinkage long compat_sys_recvmmsg(int fd, struct compat_mmsghdr __user *mmsg,
        if (flags & MSG_CMSG_COMPAT)
                return -EINVAL;
 
-       if (COMPAT_USE_64BIT_TIME)
-               return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
-                                     flags | MSG_CMSG_COMPAT,
-                                     (struct timespec *) timeout);
-
        if (timeout == NULL)
                return __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                                      flags | MSG_CMSG_COMPAT, NULL);
 
-       if (get_compat_timespec(&ktspec, timeout))
+       if (compat_get_timespec(&ktspec, timeout))
                return -EFAULT;
 
        datagrams = __sys_recvmmsg(fd, (struct mmsghdr __user *)mmsg, vlen,
                                   flags | MSG_CMSG_COMPAT, &ktspec);
-       if (datagrams > 0 && put_compat_timespec(&ktspec, timeout))
+       if (datagrams > 0 && compat_put_timespec(&ktspec, timeout))
                datagrams = -EFAULT;
 
        return datagrams;
index 8f519dbb358b4b8ab8d2f497a000383fe7656341..5976ef0846bdda08db6289bb91f05a63b85e6e3a 100644 (file)
@@ -47,6 +47,8 @@
 #include <linux/in.h>
 #include <linux/inet.h>
 #include <linux/slab.h>
+#include <linux/tcp.h>
+#include <linux/udp.h>
 #include <linux/netdevice.h>
 #ifdef CONFIG_NET_CLS_ACT
 #include <net/pkt_sched.h>
@@ -2119,7 +2121,7 @@ EXPORT_SYMBOL_GPL(skb_zerocopy_headlen);
 /**
  *     skb_zerocopy - Zero copy skb to skb
  *     @to: destination buffer
- *     @source: source buffer
+ *     @from: source buffer
  *     @len: number of bytes to copy from source buffer
  *     @hlen: size of linear headroom in destination buffer
  *
@@ -3916,3 +3918,26 @@ void skb_scrub_packet(struct sk_buff *skb, bool xnet)
        nf_reset_trace(skb);
 }
 EXPORT_SYMBOL_GPL(skb_scrub_packet);
+
+/**
+ * skb_gso_transport_seglen - Return length of individual segments of a gso packet
+ *
+ * @skb: GSO skb
+ *
+ * skb_gso_transport_seglen is used to determine the real size of the
+ * individual segments, including Layer4 headers (TCP/UDP).
+ *
+ * The MAC/L2 or network (IP, IPv6) headers are not accounted for.
+ */
+unsigned int skb_gso_transport_seglen(const struct sk_buff *skb)
+{
+       const struct skb_shared_info *shinfo = skb_shinfo(skb);
+       unsigned int hdr_len;
+
+       if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
+               hdr_len = tcp_hdrlen(skb);
+       else
+               hdr_len = sizeof(struct udphdr);
+       return hdr_len + shinfo->gso_size;
+}
+EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);
index 083f905bf1096d748a90e3a2bff52983a936a680..860aa2d445bae361d5d588a6c1a4e41310d0d629 100644 (file)
@@ -678,7 +678,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
                        hc06_ptr += 3;
                } else {
                        /* compress nothing */
-                       memcpy(hc06_ptr, &hdr, 4);
+                       memcpy(hc06_ptr, hdr, 4);
                        /* replace the top byte with new ECN | DSCP format */
                        *hc06_ptr = tmp;
                        hc06_ptr += 4;
index e7a92fdb36f61b779e04b1da45acf12312302c6b..ec4f762efda50918254329d9cccfd493533fae4b 100644 (file)
@@ -178,7 +178,7 @@ static int ipgre_err(struct sk_buff *skb, u32 info,
        else
                itn = net_generic(net, ipgre_net_id);
 
-       iph = (const struct iphdr *)skb->data;
+       iph = (const struct iphdr *)(icmp_hdr(skb) + 1);
        t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
                             iph->daddr, iph->saddr, tpi->key);
 
index 054a3e97d822b61646cfff92c2ff2ed0f1e0740a..3d4da2c16b6a3c6d6bc41d8fec0ed182037b0801 100644 (file)
@@ -314,7 +314,7 @@ static int ip_rcv_finish(struct sk_buff *skb)
        const struct iphdr *iph = ip_hdr(skb);
        struct rtable *rt;
 
-       if (sysctl_ip_early_demux && !skb_dst(skb)) {
+       if (sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) {
                const struct net_protocol *ipprot;
                int protocol = iph->protocol;
 
index c0e3cb72ad70ad211f4801e13c5e207dc48318e3..bd28f386bd02020ef3adc4295a90021d6d43a0f7 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/if_ether.h>
 #include <linux/if_vlan.h>
 #include <linux/rculist.h>
+#include <linux/err.h>
 
 #include <net/sock.h>
 #include <net/ip.h>
@@ -930,7 +931,7 @@ int ip_tunnel_init_net(struct net *net, int ip_tnl_net_id,
        }
        rtnl_unlock();
 
-       return PTR_RET(itn->fb_tunnel_dev);
+       return PTR_ERR_OR_ZERO(itn->fb_tunnel_dev);
 }
 EXPORT_SYMBOL_GPL(ip_tunnel_init_net);
 
index 302d6fb1ff2b43fb027a633a0ba3f87eea58d4e9..51d54dc376f3b1862040f38e6f58e2c75001049c 100644 (file)
@@ -49,7 +49,7 @@
 
 int ip6_rcv_finish(struct sk_buff *skb)
 {
-       if (sysctl_ip_early_demux && !skb_dst(skb)) {
+       if (sysctl_ip_early_demux && !skb_dst(skb) && skb->sk == NULL) {
                const struct inet6_protocol *ipprot;
 
                ipprot = rcu_dereference(inet6_protos[ipv6_hdr(skb)->nexthdr]);
index 2dae8a5df23fe56f93620dcaf313a54d6e41b231..94425e421213a3fd2719428244156a890a98127a 100644 (file)
@@ -43,7 +43,7 @@ int llc_mac_hdr_init(struct sk_buff *skb,
                        rc = 0;
                break;
        default:
-               WARN(1, "device type not supported: %d\n", skb->dev->type);
+               break;
        }
        return rc;
 }
index 4106ca95ec86f43b8c235dd5d94e9fc016ea06f5..7bf5b5b9e8b9400af1cbaecaeaf9a8c222670492 100644 (file)
@@ -381,6 +381,8 @@ static int rxrpc_connect_exclusive(struct rxrpc_sock *rx,
 
                rxrpc_assign_connection_id(conn);
                rx->conn = conn;
+       } else {
+               spin_lock(&trans->client_lock);
        }
 
        /* we've got a connection with a free channel and we can now attach the
index 898492a8d61be8fde5bcdf66084d525bee23b5f0..34b5490dde655ccdbac5dcbbc7b0df1b88ab42ca 100644 (file)
@@ -180,7 +180,8 @@ int rxrpc_recvmsg(struct kiocb *iocb, struct socket *sock,
                if (copy > len - copied)
                        copy = len - copied;
 
-               if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+               if (skb->ip_summed == CHECKSUM_UNNECESSARY ||
+                   skb->ip_summed == CHECKSUM_PARTIAL) {
                        ret = skb_copy_datagram_iovec(skb, offset,
                                                      msg->msg_iov, copy);
                } else {
@@ -353,6 +354,10 @@ csum_copy_error:
        if (continue_call)
                rxrpc_put_call(continue_call);
        rxrpc_kill_skb(skb);
+       if (!(flags & MSG_PEEK)) {
+               if (skb_dequeue(&rx->sk.sk_receive_queue) != skb)
+                       BUG();
+       }
        skb_kill_datagram(&rx->sk, skb, flags);
        rxrpc_put_call(call);
        return -EAGAIN;
index fbba5b0ec1215be171d17c70fa5be3a7c79314b9..1cb413fead89522a64931a4e2472b39c4d6a720d 100644 (file)
@@ -21,7 +21,6 @@
 #include <net/netlink.h>
 #include <net/sch_generic.h>
 #include <net/pkt_sched.h>
-#include <net/tcp.h>
 
 
 /*     Simple Token Bucket Filter.
@@ -148,16 +147,10 @@ static u64 psched_ns_t2l(const struct psched_ratecfg *r,
  * Return length of individual segments of a gso packet,
  * including all headers (MAC, IP, TCP/UDP)
  */
-static unsigned int skb_gso_seglen(const struct sk_buff *skb)
+static unsigned int skb_gso_mac_seglen(const struct sk_buff *skb)
 {
        unsigned int hdr_len = skb_transport_header(skb) - skb_mac_header(skb);
-       const struct skb_shared_info *shinfo = skb_shinfo(skb);
-
-       if (likely(shinfo->gso_type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))
-               hdr_len += tcp_hdrlen(skb);
-       else
-               hdr_len += sizeof(struct udphdr);
-       return hdr_len + shinfo->gso_size;
+       return hdr_len + skb_gso_transport_seglen(skb);
 }
 
 /* GSO packet is too big, segment it so that tbf can transmit
@@ -202,7 +195,7 @@ static int tbf_enqueue(struct sk_buff *skb, struct Qdisc *sch)
        int ret;
 
        if (qdisc_pkt_len(skb) > q->max_size) {
-               if (skb_is_gso(skb) && skb_gso_seglen(skb) <= q->max_size)
+               if (skb_is_gso(skb) && skb_gso_mac_seglen(skb) <= q->max_size)
                        return tbf_segment(skb, sch);
                return qdisc_reshape_fail(skb, sch);
        }
index 42fdfc634e568a58bda35d2dbb1effbf44dd1bd4..6c0513a7f99232280f78067d56c5c369cb79630d 100644 (file)
@@ -532,14 +532,7 @@ gss_setup_upcall(struct gss_auth *gss_auth, struct rpc_cred *cred)
 
 static void warn_gssd(void)
 {
-       static unsigned long ratelimit;
-       unsigned long now = jiffies;
-
-       if (time_after(now, ratelimit)) {
-               printk(KERN_WARNING "RPC: AUTH_GSS upcall timed out.\n"
-                               "Please check user daemon is running.\n");
-               ratelimit = now + 15*HZ;
-       }
+       dprintk("AUTH_GSS upcall failed. Please check user daemon is running.\n");
 }
 
 static inline int
@@ -600,7 +593,6 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
        struct rpc_pipe *pipe;
        struct rpc_cred *cred = &gss_cred->gc_base;
        struct gss_upcall_msg *gss_msg;
-       unsigned long timeout;
        DEFINE_WAIT(wait);
        int err;
 
@@ -608,17 +600,16 @@ gss_create_upcall(struct gss_auth *gss_auth, struct gss_cred *gss_cred)
                __func__, from_kuid(&init_user_ns, cred->cr_uid));
 retry:
        err = 0;
-       /* Default timeout is 15s unless we know that gssd is not running */
-       timeout = 15 * HZ;
-       if (!sn->gssd_running)
-               timeout = HZ >> 2;
+       /* if gssd is down, just skip upcalling altogether */
+       if (!gssd_running(net)) {
+               warn_gssd();
+               return -EACCES;
+       }
        gss_msg = gss_setup_upcall(gss_auth, cred);
        if (PTR_ERR(gss_msg) == -EAGAIN) {
                err = wait_event_interruptible_timeout(pipe_version_waitqueue,
-                               sn->pipe_version >= 0, timeout);
+                               sn->pipe_version >= 0, 15 * HZ);
                if (sn->pipe_version < 0) {
-                       if (err == 0)
-                               sn->gssd_running = 0;
                        warn_gssd();
                        err = -EACCES;
                }
index 76e42e6be7558d9578b38506a28525350e0cf8bf..24589bd2a4b600cae5fdb8f5c0f54fb5198e2115 100644 (file)
@@ -59,6 +59,7 @@
 #include <linux/crypto.h>
 #include <linux/sunrpc/gss_krb5.h>
 #include <linux/sunrpc/xdr.h>
+#include <linux/lcm.h>
 
 #ifdef RPC_DEBUG
 # define RPCDBG_FACILITY        RPCDBG_AUTH
@@ -72,7 +73,7 @@
 static void krb5_nfold(u32 inbits, const u8 *in,
                       u32 outbits, u8 *out)
 {
-       int a, b, c, lcm;
+       unsigned long ulcm;
        int byte, i, msbit;
 
        /* the code below is more readable if I make these bytes
@@ -82,17 +83,7 @@ static void krb5_nfold(u32 inbits, const u8 *in,
        outbits >>= 3;
 
        /* first compute lcm(n,k) */
-
-       a = outbits;
-       b = inbits;
-
-       while (b != 0) {
-               c = b;
-               b = a%b;
-               a = c;
-       }
-
-       lcm = outbits*inbits/a;
+       ulcm = lcm(inbits, outbits);
 
        /* now do the real work */
 
@@ -101,7 +92,7 @@ static void krb5_nfold(u32 inbits, const u8 *in,
 
        /* this will end up cycling through k lcm(k,n)/k times, which
           is correct */
-       for (i = lcm-1; i >= 0; i--) {
+       for (i = ulcm-1; i >= 0; i--) {
                /* compute the msbit in k which gets added into this byte */
                msbit = (
                        /* first, start with the msbit in the first,
index 458f85e9b0ba088575a72ef6dd6ff8d21484d290..abbb7dcd16897125863098cb48f6a6411488225c 100644 (file)
@@ -137,7 +137,6 @@ void init_gssp_clnt(struct sunrpc_net *sn)
 {
        mutex_init(&sn->gssp_lock);
        sn->gssp_clnt = NULL;
-       init_waitqueue_head(&sn->gssp_wq);
 }
 
 int set_gssp_clnt(struct net *net)
@@ -154,7 +153,6 @@ int set_gssp_clnt(struct net *net)
                sn->gssp_clnt = clnt;
        }
        mutex_unlock(&sn->gssp_lock);
-       wake_up(&sn->gssp_wq);
        return ret;
 }
 
index 008cdade5aae387db601607c463aa20291777513..0f73f450774675da7666d10cb50c57571a11c27a 100644 (file)
@@ -1263,65 +1263,34 @@ out:
        return ret;
 }
 
-DEFINE_SPINLOCK(use_gssp_lock);
-
-static bool use_gss_proxy(struct net *net)
-{
-       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
-
-       if (sn->use_gss_proxy != -1)
-               return sn->use_gss_proxy;
-       spin_lock(&use_gssp_lock);
-       /*
-        * If you wanted gss-proxy, you should have said so before
-        * starting to accept requests:
-        */
-       sn->use_gss_proxy = 0;
-       spin_unlock(&use_gssp_lock);
-       return 0;
-}
-
-#ifdef CONFIG_PROC_FS
-
+/*
+ * Try to set the sn->use_gss_proxy variable to a new value. We only allow
+ * it to be changed if it's currently undefined (-1). If it's any other value
+ * then return -EBUSY unless the type wouldn't have changed anyway.
+ */
 static int set_gss_proxy(struct net *net, int type)
 {
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
-       int ret = 0;
+       int ret;
 
        WARN_ON_ONCE(type != 0 && type != 1);
-       spin_lock(&use_gssp_lock);
-       if (sn->use_gss_proxy == -1 || sn->use_gss_proxy == type)
-               sn->use_gss_proxy = type;
-       else
-               ret = -EBUSY;
-       spin_unlock(&use_gssp_lock);
-       wake_up(&sn->gssp_wq);
-       return ret;
-}
-
-static inline bool gssp_ready(struct sunrpc_net *sn)
-{
-       switch (sn->use_gss_proxy) {
-               case -1:
-                       return false;
-               case 0:
-                       return true;
-               case 1:
-                       return sn->gssp_clnt;
-       }
-       WARN_ON_ONCE(1);
-       return false;
+       ret = cmpxchg(&sn->use_gss_proxy, -1, type);
+       if (ret != -1 && ret != type)
+               return -EBUSY;
+       return 0;
 }
 
-static int wait_for_gss_proxy(struct net *net, struct file *file)
+static bool use_gss_proxy(struct net *net)
 {
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
-       if (file->f_flags & O_NONBLOCK && !gssp_ready(sn))
-               return -EAGAIN;
-       return wait_event_interruptible(sn->gssp_wq, gssp_ready(sn));
+       /* If use_gss_proxy is still undefined, then try to disable it */
+       if (sn->use_gss_proxy == -1)
+               set_gss_proxy(net, 0);
+       return sn->use_gss_proxy;
 }
 
+#ifdef CONFIG_PROC_FS
 
 static ssize_t write_gssp(struct file *file, const char __user *buf,
                         size_t count, loff_t *ppos)
@@ -1342,10 +1311,10 @@ static ssize_t write_gssp(struct file *file, const char __user *buf,
                return res;
        if (i != 1)
                return -EINVAL;
-       res = set_gss_proxy(net, 1);
+       res = set_gssp_clnt(net);
        if (res)
                return res;
-       res = set_gssp_clnt(net);
+       res = set_gss_proxy(net, 1);
        if (res)
                return res;
        return count;
@@ -1355,16 +1324,12 @@ static ssize_t read_gssp(struct file *file, char __user *buf,
                         size_t count, loff_t *ppos)
 {
        struct net *net = PDE_DATA(file_inode(file));
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
        unsigned long p = *ppos;
        char tbuf[10];
        size_t len;
-       int ret;
 
-       ret = wait_for_gss_proxy(net, file);
-       if (ret)
-               return ret;
-
-       snprintf(tbuf, sizeof(tbuf), "%d\n", use_gss_proxy(net));
+       snprintf(tbuf, sizeof(tbuf), "%d\n", sn->use_gss_proxy);
        len = strlen(tbuf);
        if (p >= len)
                return 0;
@@ -1626,8 +1591,7 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
        BUG_ON(integ_len % 4);
        *p++ = htonl(integ_len);
        *p++ = htonl(gc->gc_seq);
-       if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset,
-                               integ_len))
+       if (xdr_buf_subsegment(resbuf, &integ_buf, integ_offset, integ_len))
                BUG();
        if (resbuf->tail[0].iov_base == NULL) {
                if (resbuf->head[0].iov_len + RPC_MAX_AUTH_SIZE > PAGE_SIZE)
@@ -1635,10 +1599,8 @@ svcauth_gss_wrap_resp_integ(struct svc_rqst *rqstp)
                resbuf->tail[0].iov_base = resbuf->head[0].iov_base
                                                + resbuf->head[0].iov_len;
                resbuf->tail[0].iov_len = 0;
-               resv = &resbuf->tail[0];
-       } else {
-               resv = &resbuf->tail[0];
        }
+       resv = &resbuf->tail[0];
        mic.data = (u8 *)resv->iov_base + resv->iov_len + 4;
        if (gss_get_mic(gsd->rsci->mechctx, &integ_buf, &mic))
                goto out_err;
index e521d20e19701d917953e49033ce85fac8a96c8d..ae333c1845bb42f28198cdfb957cd03e7412c14c 100644 (file)
@@ -1111,9 +1111,7 @@ void qword_addhex(char **bpp, int *lp, char *buf, int blen)
                *bp++ = 'x';
                len -= 2;
                while (blen && len >= 2) {
-                       unsigned char c = *buf++;
-                       *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1);
-                       *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1);
+                       bp = hex_byte_pack(bp, *buf++);
                        len -= 2;
                        blen--;
                }
index f09b7db2c492f5a3f20a954e07e23b1a2f054c5e..0edada973434e4df883f63a85173f4a7a1de0885 100644 (file)
@@ -1529,9 +1529,13 @@ call_refreshresult(struct rpc_task *task)
        task->tk_action = call_refresh;
        switch (status) {
        case 0:
-               if (rpcauth_uptodatecred(task))
+               if (rpcauth_uptodatecred(task)) {
                        task->tk_action = call_allocate;
-               return;
+                       return;
+               }
+               /* Use rate-limiting and a max number of retries if refresh
+                * had status 0 but failed to update the cred.
+                */
        case -ETIMEDOUT:
                rpc_delay(task, 3*HZ);
        case -EAGAIN:
@@ -1729,6 +1733,7 @@ call_bind_status(struct rpc_task *task)
                return;
        case -ECONNREFUSED:             /* connection problems */
        case -ECONNRESET:
+       case -ECONNABORTED:
        case -ENOTCONN:
        case -EHOSTDOWN:
        case -EHOSTUNREACH:
@@ -1799,7 +1804,9 @@ call_connect_status(struct rpc_task *task)
                return;
        case -ECONNREFUSED:
        case -ECONNRESET:
+       case -ECONNABORTED:
        case -ENETUNREACH:
+       case -EHOSTUNREACH:
                /* retry with existing socket, after a delay */
                rpc_delay(task, 3*HZ);
                if (RPC_IS_SOFTCONN(task))
@@ -1902,6 +1909,7 @@ call_transmit_status(struct rpc_task *task)
                        break;
                }
        case -ECONNRESET:
+       case -ECONNABORTED:
        case -ENOTCONN:
        case -EPIPE:
                rpc_task_force_reencode(task);
@@ -2011,8 +2019,9 @@ call_status(struct rpc_task *task)
                        xprt_conditional_disconnect(req->rq_xprt,
                                        req->rq_connect_cookie);
                break;
-       case -ECONNRESET:
        case -ECONNREFUSED:
+       case -ECONNRESET:
+       case -ECONNABORTED:
                rpc_force_rebind(clnt);
                rpc_delay(task, 3*HZ);
        case -EPIPE:
index 779742cfc1ffe3178fc0c320b6d0832e0f420d64..df58268765351ebd1b4376f7504915cd1b9fff6b 100644 (file)
@@ -14,6 +14,7 @@ struct sunrpc_net {
        struct cache_detail *rsi_cache;
 
        struct super_block *pipefs_sb;
+       struct rpc_pipe *gssd_dummy;
        struct mutex pipefs_sb_lock;
 
        struct list_head all_clients;
@@ -26,14 +27,11 @@ struct sunrpc_net {
        unsigned int rpcb_is_af_local : 1;
 
        struct mutex gssp_lock;
-       wait_queue_head_t gssp_wq;
        struct rpc_clnt *gssp_clnt;
        int use_gss_proxy;
        int pipe_version;
        atomic_t pipe_users;
        struct proc_dir_entry *use_gssp_proc;
-
-       unsigned int gssd_running;
 };
 
 extern int sunrpc_net_id;
index bf04b30a788a5425b28ba70c11a50b77bfc9c697..b185548985622c0c23b1e0dc01acb783ee81246a 100644 (file)
@@ -17,6 +17,7 @@
 #include <linux/fsnotify.h>
 #include <linux/kernel.h>
 #include <linux/rcupdate.h>
+#include <linux/utsname.h>
 
 #include <asm/ioctls.h>
 #include <linux/poll.h>
@@ -38,7 +39,7 @@
 #define NET_NAME(net)  ((net == &init_net) ? " (init_net)" : "")
 
 static struct file_system_type rpc_pipe_fs_type;
-
+static const struct rpc_pipe_ops gssd_dummy_pipe_ops;
 
 static struct kmem_cache *rpc_inode_cachep __read_mostly;
 
@@ -216,14 +217,11 @@ rpc_destroy_inode(struct inode *inode)
 static int
 rpc_pipe_open(struct inode *inode, struct file *filp)
 {
-       struct net *net = inode->i_sb->s_fs_info;
-       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
        struct rpc_pipe *pipe;
        int first_open;
        int res = -ENXIO;
 
        mutex_lock(&inode->i_mutex);
-       sn->gssd_running = 1;
        pipe = RPC_I(inode)->pipe;
        if (pipe == NULL)
                goto out;
@@ -1159,6 +1157,7 @@ enum {
        RPCAUTH_nfsd4_cb,
        RPCAUTH_cache,
        RPCAUTH_nfsd,
+       RPCAUTH_gssd,
        RPCAUTH_RootEOF
 };
 
@@ -1195,6 +1194,10 @@ static const struct rpc_filelist files[] = {
                .name = "nfsd",
                .mode = S_IFDIR | S_IRUGO | S_IXUGO,
        },
+       [RPCAUTH_gssd] = {
+               .name = "gssd",
+               .mode = S_IFDIR | S_IRUGO | S_IXUGO,
+       },
 };
 
 /*
@@ -1208,13 +1211,24 @@ struct dentry *rpc_d_lookup_sb(const struct super_block *sb,
 }
 EXPORT_SYMBOL_GPL(rpc_d_lookup_sb);
 
-void rpc_pipefs_init_net(struct net *net)
+int rpc_pipefs_init_net(struct net *net)
 {
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
+       sn->gssd_dummy = rpc_mkpipe_data(&gssd_dummy_pipe_ops, 0);
+       if (IS_ERR(sn->gssd_dummy))
+               return PTR_ERR(sn->gssd_dummy);
+
        mutex_init(&sn->pipefs_sb_lock);
-       sn->gssd_running = 1;
        sn->pipe_version = -1;
+       return 0;
+}
+
+void rpc_pipefs_exit_net(struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+
+       rpc_destroy_pipe_data(sn->gssd_dummy);
 }
 
 /*
@@ -1244,11 +1258,134 @@ void rpc_put_sb_net(const struct net *net)
 }
 EXPORT_SYMBOL_GPL(rpc_put_sb_net);
 
+static const struct rpc_filelist gssd_dummy_clnt_dir[] = {
+       [0] = {
+               .name = "clntXX",
+               .mode = S_IFDIR | S_IRUGO | S_IXUGO,
+       },
+};
+
+static ssize_t
+dummy_downcall(struct file *filp, const char __user *src, size_t len)
+{
+       return -EINVAL;
+}
+
+static const struct rpc_pipe_ops gssd_dummy_pipe_ops = {
+       .upcall         = rpc_pipe_generic_upcall,
+       .downcall       = dummy_downcall,
+};
+
+/*
+ * Here we present a bogus "info" file to keep rpc.gssd happy. We don't expect
+ * that it will ever use this info to handle an upcall, but rpc.gssd expects
+ * that this file will be there and have a certain format.
+ */
+static int
+rpc_show_dummy_info(struct seq_file *m, void *v)
+{
+       seq_printf(m, "RPC server: %s\n", utsname()->nodename);
+       seq_printf(m, "service: foo (1) version 0\n");
+       seq_printf(m, "address: 127.0.0.1\n");
+       seq_printf(m, "protocol: tcp\n");
+       seq_printf(m, "port: 0\n");
+       return 0;
+}
+
+static int
+rpc_dummy_info_open(struct inode *inode, struct file *file)
+{
+       return single_open(file, rpc_show_dummy_info, NULL);
+}
+
+static const struct file_operations rpc_dummy_info_operations = {
+       .owner          = THIS_MODULE,
+       .open           = rpc_dummy_info_open,
+       .read           = seq_read,
+       .llseek         = seq_lseek,
+       .release        = single_release,
+};
+
+static const struct rpc_filelist gssd_dummy_info_file[] = {
+       [0] = {
+               .name = "info",
+               .i_fop = &rpc_dummy_info_operations,
+               .mode = S_IFREG | S_IRUSR,
+       },
+};
+
+/**
+ * rpc_gssd_dummy_populate - create a dummy gssd pipe
+ * @root:      root of the rpc_pipefs filesystem
+ * @pipe_data: pipe data created when netns is initialized
+ *
+ * Create a dummy set of directories and a pipe that gssd can hold open to
+ * indicate that it is up and running.
+ */
+static struct dentry *
+rpc_gssd_dummy_populate(struct dentry *root, struct rpc_pipe *pipe_data)
+{
+       int ret = 0;
+       struct dentry *gssd_dentry;
+       struct dentry *clnt_dentry = NULL;
+       struct dentry *pipe_dentry = NULL;
+       struct qstr q = QSTR_INIT(files[RPCAUTH_gssd].name,
+                                 strlen(files[RPCAUTH_gssd].name));
+
+       /* We should never get this far if "gssd" doesn't exist */
+       gssd_dentry = d_hash_and_lookup(root, &q);
+       if (!gssd_dentry)
+               return ERR_PTR(-ENOENT);
+
+       ret = rpc_populate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1, NULL);
+       if (ret) {
+               pipe_dentry = ERR_PTR(ret);
+               goto out;
+       }
+
+       q.name = gssd_dummy_clnt_dir[0].name;
+       q.len = strlen(gssd_dummy_clnt_dir[0].name);
+       clnt_dentry = d_hash_and_lookup(gssd_dentry, &q);
+       if (!clnt_dentry) {
+               pipe_dentry = ERR_PTR(-ENOENT);
+               goto out;
+       }
+
+       ret = rpc_populate(clnt_dentry, gssd_dummy_info_file, 0, 1, NULL);
+       if (ret) {
+               __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
+               pipe_dentry = ERR_PTR(ret);
+               goto out;
+       }
+
+       pipe_dentry = rpc_mkpipe_dentry(clnt_dentry, "gssd", NULL, pipe_data);
+       if (IS_ERR(pipe_dentry)) {
+               __rpc_depopulate(clnt_dentry, gssd_dummy_info_file, 0, 1);
+               __rpc_depopulate(gssd_dentry, gssd_dummy_clnt_dir, 0, 1);
+       }
+out:
+       dput(clnt_dentry);
+       dput(gssd_dentry);
+       return pipe_dentry;
+}
+
+static void
+rpc_gssd_dummy_depopulate(struct dentry *pipe_dentry)
+{
+       struct dentry *clnt_dir = pipe_dentry->d_parent;
+       struct dentry *gssd_dir = clnt_dir->d_parent;
+
+       __rpc_rmpipe(clnt_dir->d_inode, pipe_dentry);
+       __rpc_depopulate(clnt_dir, gssd_dummy_info_file, 0, 1);
+       __rpc_depopulate(gssd_dir, gssd_dummy_clnt_dir, 0, 1);
+       dput(pipe_dentry);
+}
+
 static int
 rpc_fill_super(struct super_block *sb, void *data, int silent)
 {
        struct inode *inode;
-       struct dentry *root;
+       struct dentry *root, *gssd_dentry;
        struct net *net = data;
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
        int err;
@@ -1266,6 +1403,13 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
                return -ENOMEM;
        if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
                return -ENOMEM;
+
+       gssd_dentry = rpc_gssd_dummy_populate(root, sn->gssd_dummy);
+       if (IS_ERR(gssd_dentry)) {
+               __rpc_depopulate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF);
+               return PTR_ERR(gssd_dentry);
+       }
+
        dprintk("RPC:       sending pipefs MOUNT notification for net %p%s\n",
                net, NET_NAME(net));
        mutex_lock(&sn->pipefs_sb_lock);
@@ -1280,6 +1424,7 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
        return 0;
 
 err_depopulate:
+       rpc_gssd_dummy_depopulate(gssd_dentry);
        blocking_notifier_call_chain(&rpc_pipefs_notifier_list,
                                           RPC_PIPEFS_UMOUNT,
                                           sb);
@@ -1289,6 +1434,16 @@ err_depopulate:
        return err;
 }
 
+bool
+gssd_running(struct net *net)
+{
+       struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       struct rpc_pipe *pipe = sn->gssd_dummy;
+
+       return pipe->nreaders || pipe->nwriters;
+}
+EXPORT_SYMBOL_GPL(gssd_running);
+
 static struct dentry *
 rpc_mount(struct file_system_type *fs_type,
                int flags, const char *dev_name, void *data)
index 3d6498af9adc1a1035005c735ee932de6488bee3..cd30120de9e4eb7ba413135dd2eb690311d784cb 100644 (file)
@@ -44,12 +44,17 @@ static __net_init int sunrpc_init_net(struct net *net)
        if (err)
                goto err_unixgid;
 
-       rpc_pipefs_init_net(net);
+       err = rpc_pipefs_init_net(net);
+       if (err)
+               goto err_pipefs;
+
        INIT_LIST_HEAD(&sn->all_clients);
        spin_lock_init(&sn->rpc_client_lock);
        spin_lock_init(&sn->rpcb_clnt_lock);
        return 0;
 
+err_pipefs:
+       unix_gid_cache_destroy(net);
 err_unixgid:
        ip_map_cache_destroy(net);
 err_ipmap:
@@ -60,6 +65,7 @@ err_proc:
 
 static __net_exit void sunrpc_exit_net(struct net *net)
 {
+       rpc_pipefs_exit_net(net);
        unix_gid_cache_destroy(net);
        ip_map_cache_destroy(net);
        rpc_proc_exit(net);
index e7fbe368b4a38f665c538ae98b3c8db1ce2a5b81..5de6801cd924ec8e71d216bd5ea9ebffd4a391a8 100644 (file)
@@ -916,9 +916,6 @@ static int __svc_register(struct net *net, const char *progname,
 #endif
        }
 
-       if (error < 0)
-               printk(KERN_WARNING "svc: failed to register %sv%u RPC "
-                       "service (errno %d).\n", progname, version, -error);
        return error;
 }
 
@@ -937,6 +934,7 @@ int svc_register(const struct svc_serv *serv, struct net *net,
                 const unsigned short port)
 {
        struct svc_program      *progp;
+       struct svc_version      *vers;
        unsigned int            i;
        int                     error = 0;
 
@@ -946,7 +944,8 @@ int svc_register(const struct svc_serv *serv, struct net *net,
 
        for (progp = serv->sv_program; progp; progp = progp->pg_next) {
                for (i = 0; i < progp->pg_nvers; i++) {
-                       if (progp->pg_vers[i] == NULL)
+                       vers = progp->pg_vers[i];
+                       if (vers == NULL)
                                continue;
 
                        dprintk("svc: svc_register(%sv%d, %s, %u, %u)%s\n",
@@ -955,16 +954,26 @@ int svc_register(const struct svc_serv *serv, struct net *net,
                                        proto == IPPROTO_UDP?  "udp" : "tcp",
                                        port,
                                        family,
-                                       progp->pg_vers[i]->vs_hidden?
-                                               " (but not telling portmap)" : "");
+                                       vers->vs_hidden ?
+                                       " (but not telling portmap)" : "");
 
-                       if (progp->pg_vers[i]->vs_hidden)
+                       if (vers->vs_hidden)
                                continue;
 
                        error = __svc_register(net, progp->pg_name, progp->pg_prog,
                                                i, family, proto, port);
-                       if (error < 0)
+
+                       if (vers->vs_rpcb_optnl) {
+                               error = 0;
+                               continue;
+                       }
+
+                       if (error < 0) {
+                               printk(KERN_WARNING "svc: failed to register "
+                                       "%sv%u RPC service (errno %d).\n",
+                                       progp->pg_name, i, -error);
                                break;
+                       }
                }
        }
 
index 1750048130a7c0d305a51c87c38d539ee3001fd7..7d4df99f761faa27de43af1b27640e412a3dc8a0 100644 (file)
@@ -749,6 +749,11 @@ static void xprt_connect_status(struct rpc_task *task)
        }
 
        switch (task->tk_status) {
+       case -ECONNREFUSED:
+       case -ECONNRESET:
+       case -ECONNABORTED:
+       case -ENETUNREACH:
+       case -EHOSTUNREACH:
        case -EAGAIN:
                dprintk("RPC: %5u xprt_connect_status: retrying\n", task->tk_pid);
                break;
index 75b045e1cd50b00096a3a2ec938c2f82423dffce..817a1e5239692e9fb3f5117f36eb0895d426ea5f 100644 (file)
@@ -257,6 +257,7 @@ struct sock_xprt {
        void                    (*old_data_ready)(struct sock *, int);
        void                    (*old_state_change)(struct sock *);
        void                    (*old_write_space)(struct sock *);
+       void                    (*old_error_report)(struct sock *);
 };
 
 /*
@@ -274,6 +275,11 @@ struct sock_xprt {
  */
 #define TCP_RPC_REPLY          (1UL << 6)
 
+static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
+{
+       return (struct rpc_xprt *) sk->sk_user_data;
+}
+
 static inline struct sockaddr *xs_addr(struct rpc_xprt *xprt)
 {
        return (struct sockaddr *) &xprt->addr;
@@ -799,6 +805,7 @@ static void xs_save_old_callbacks(struct sock_xprt *transport, struct sock *sk)
        transport->old_data_ready = sk->sk_data_ready;
        transport->old_state_change = sk->sk_state_change;
        transport->old_write_space = sk->sk_write_space;
+       transport->old_error_report = sk->sk_error_report;
 }
 
 static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *sk)
@@ -806,6 +813,34 @@ static void xs_restore_old_callbacks(struct sock_xprt *transport, struct sock *s
        sk->sk_data_ready = transport->old_data_ready;
        sk->sk_state_change = transport->old_state_change;
        sk->sk_write_space = transport->old_write_space;
+       sk->sk_error_report = transport->old_error_report;
+}
+
+/**
+ * xs_error_report - callback to handle TCP socket state errors
+ * @sk: socket
+ *
+ * Note: we don't call sock_error() since there may be a rpc_task
+ * using the socket, and so we don't want to clear sk->sk_err.
+ */
+static void xs_error_report(struct sock *sk)
+{
+       struct rpc_xprt *xprt;
+       int err;
+
+       read_lock_bh(&sk->sk_callback_lock);
+       if (!(xprt = xprt_from_sock(sk)))
+               goto out;
+
+       err = -sk->sk_err;
+       if (err == 0)
+               goto out;
+       dprintk("RPC:       xs_error_report client %p, error=%d...\n",
+                       xprt, -err);
+       trace_rpc_socket_error(xprt, sk->sk_socket, err);
+       xprt_wake_pending_tasks(xprt, err);
+ out:
+       read_unlock_bh(&sk->sk_callback_lock);
 }
 
 static void xs_reset_transport(struct sock_xprt *transport)
@@ -885,11 +920,6 @@ static void xs_destroy(struct rpc_xprt *xprt)
        module_put(THIS_MODULE);
 }
 
-static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
-{
-       return (struct rpc_xprt *) sk->sk_user_data;
-}
-
 static int xs_local_copy_to_xdr(struct xdr_buf *xdr, struct sk_buff *skb)
 {
        struct xdr_skb_reader desc = {
@@ -1869,6 +1899,7 @@ static int xs_local_finish_connecting(struct rpc_xprt *xprt,
                sk->sk_user_data = xprt;
                sk->sk_data_ready = xs_local_data_ready;
                sk->sk_write_space = xs_udp_write_space;
+               sk->sk_error_report = xs_error_report;
                sk->sk_allocation = GFP_ATOMIC;
 
                xprt_clear_connected(xprt);
@@ -2146,6 +2177,7 @@ static int xs_tcp_finish_connecting(struct rpc_xprt *xprt, struct socket *sock)
                sk->sk_data_ready = xs_tcp_data_ready;
                sk->sk_state_change = xs_tcp_state_change;
                sk->sk_write_space = xs_tcp_write_space;
+               sk->sk_error_report = xs_error_report;
                sk->sk_allocation = GFP_ATOMIC;
 
                /* socket options */
@@ -2932,10 +2964,9 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
 
        /*
         * Once we've associated a backchannel xprt with a connection,
-        * we want to keep it around as long as long as the connection
-        * lasts, in case we need to start using it for a backchannel
-        * again; this reference won't be dropped until bc_xprt is
-        * destroyed.
+        * we want to keep it around as long as the connection lasts,
+        * in case we need to start using it for a backchannel again;
+        * this reference won't be dropped until bc_xprt is destroyed.
         */
        xprt_get(xprt);
        args->bc_xprt->xpt_bc_xprt = xprt;
index 1dbd6d1cd1b5f45d62a86d5faa0d8f92eb4227f4..0ea2a1e24ade493ed22c6b817c91a07736b11563 100755 (executable)
@@ -2665,6 +2665,15 @@ sub process {
                                $herecurr);
                }
 
+# check for function declarations without arguments like "int foo()"
+               if ($line =~ /(\b$Type\s+$Ident)\s*\(\s*\)/) {
+                       if (ERROR("FUNCTION_WITHOUT_ARGS",
+                                 "Bad function definition - $1() should probably be $1(void)\n" . $herecurr) &&
+                           $fix) {
+                               $fixed[$linenr - 1] =~ s/(\b($Type)\s+($Ident))\s*\(\s*\)/$2 $3(void)/;
+                       }
+               }
+
 # check for uses of DEFINE_PCI_DEVICE_TABLE
                if ($line =~ /\bDEFINE_PCI_DEVICE_TABLE\s*\(\s*(\w+)\s*\)\s*=/) {
                        if (WARN("DEFINE_PCI_DEVICE_TABLE",
index 17855761e6b77c4c5c13600b76c8cf95fcb82c00..40610984a1b54b06c579f953dabeb5ddb1304525 100644 (file)
@@ -584,12 +584,16 @@ static int ignore_undef_symbol(struct elf_info *info, const char *symname)
                if (strncmp(symname, "_restgpr_", sizeof("_restgpr_") - 1) == 0 ||
                    strncmp(symname, "_savegpr_", sizeof("_savegpr_") - 1) == 0 ||
                    strncmp(symname, "_rest32gpr_", sizeof("_rest32gpr_") - 1) == 0 ||
-                   strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0)
+                   strncmp(symname, "_save32gpr_", sizeof("_save32gpr_") - 1) == 0 ||
+                   strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
+                   strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
                        return 1;
        if (info->hdr->e_machine == EM_PPC64)
                /* Special register function linked on all modules during final link of .ko */
                if (strncmp(symname, "_restgpr0_", sizeof("_restgpr0_") - 1) == 0 ||
-                   strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0)
+                   strncmp(symname, "_savegpr0_", sizeof("_savegpr0_") - 1) == 0 ||
+                   strncmp(symname, "_restvr_", sizeof("_restvr_") - 1) == 0 ||
+                   strncmp(symname, "_savevr_", sizeof("_savevr_") - 1) == 0)
                        return 1;
        /* Do not ignore this symbol */
        return 0;
index d105a44b68f664a55559e38217dcf27ccf025b70..63d91e22ed7ccd18a0cd77852af647112ed216bb 100755 (executable)
@@ -43,7 +43,8 @@ scm_version()
        fi
 
        # Check for git and a git repo.
-       if test -d .git && head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
+       if test -z "$(git rev-parse --show-cdup 2>/dev/null)" &&
+          head=`git rev-parse --verify --short HEAD 2>/dev/null`; then
 
                # If we are at a tagged commit (like "v2.6.30-rc6"), we ignore
                # it, because this version is defined in the top level Makefile.
index 1351f22f651cdf420ee3bfd7b550c3760b3d9a23..0d42fcda0de2805235ea7fd3a685633050132f23 100644 (file)
@@ -131,6 +131,31 @@ static inline int init_info_for_card(struct snd_card *card)
 #define init_info_for_card(card)
 #endif
 
+static int check_empty_slot(struct module *module, int slot)
+{
+       return !slots[slot] || !*slots[slot];
+}
+
+/* return an empty slot number (>= 0) found in the given bitmask @mask.
+ * @mask == -1 == 0xffffffff means: take any free slot up to 32
+ * when no slot is available, return the original @mask as is.
+ */
+static int get_slot_from_bitmask(int mask, int (*check)(struct module *, int),
+                                struct module *module)
+{
+       int slot;
+
+       for (slot = 0; slot < SNDRV_CARDS; slot++) {
+               if (slot < 32 && !(mask & (1U << slot)))
+                       continue;
+               if (!test_bit(slot, snd_cards_lock)) {
+                       if (check(module, slot))
+                               return slot; /* found */
+               }
+       }
+       return mask; /* unchanged */
+}
+
 /**
  *  snd_card_create - create and initialize a soundcard structure
  *  @idx: card index (address) [0 ... (SNDRV_CARDS-1)]
@@ -152,7 +177,7 @@ int snd_card_create(int idx, const char *xid,
                    struct snd_card **card_ret)
 {
        struct snd_card *card;
-       int err, idx2;
+       int err;
 
        if (snd_BUG_ON(!card_ret))
                return -EINVAL;
@@ -167,32 +192,10 @@ int snd_card_create(int idx, const char *xid,
                strlcpy(card->id, xid, sizeof(card->id));
        err = 0;
        mutex_lock(&snd_card_mutex);
-       if (idx < 0) {
-               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
-                       /* idx == -1 == 0xffff means: take any free slot */
-                       if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
-                               continue;
-                       if (!test_bit(idx2, snd_cards_lock)) {
-                               if (module_slot_match(module, idx2)) {
-                                       idx = idx2;
-                                       break;
-                               }
-                       }
-               }
-       }
-       if (idx < 0) {
-               for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
-                       /* idx == -1 == 0xffff means: take any free slot */
-                       if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
-                               continue;
-                       if (!test_bit(idx2, snd_cards_lock)) {
-                               if (!slots[idx2] || !*slots[idx2]) {
-                                       idx = idx2;
-                                       break;
-                               }
-                       }
-               }
-       }
+       if (idx < 0) /* first check the matching module-name slot */
+               idx = get_slot_from_bitmask(idx, module_slot_match, module);
+       if (idx < 0) /* if not matched, assign an empty slot */
+               idx = get_slot_from_bitmask(idx, check_empty_slot, module);
        if (idx < 0)
                err = -ENODEV;
        else if (idx < snd_ecards_limit) {
index f18e5878f58b42a195df536aedde6d80a3897700..062398ec5335f613b2b8e78e49d6374fc98bcdfc 100644 (file)
@@ -369,6 +369,7 @@ static void free_module_desc(struct dsp_module_desc *module)
                        kfree(module->segments[i].data);
                kfree(module->segments);
        }
+       kfree(module);
 }
 
 /* firmware binary format:
index 2b5d19e48a27320d71cb0516a779af125e494a6d..ab2a444ba5017b6cab3afa91119355f798e29917 100644 (file)
@@ -361,6 +361,7 @@ struct hda_codec {
        unsigned int epss:1;            /* supporting EPSS? */
        unsigned int cached_write:1;    /* write only to caches */
        unsigned int dp_mst:1; /* support DP1.2 Multi-stream transport */
+       unsigned int dump_coef:1; /* dump processing coefs in codec proc file */
 #ifdef CONFIG_PM
        unsigned int power_on :1;       /* current (global) power-state */
        unsigned int d3_stop_clk:1;     /* support D3 operation without BCLK */
index a8cb22eec89e5a6c1437267cacccf8b64f1b0dd3..ce5a6da834199bd2acd7e6ee18fd123b4f078820 100644 (file)
 #include <linux/init.h>
 #include <linux/slab.h>
 #include <sound/core.h>
+#include <linux/module.h>
 #include "hda_codec.h"
 #include "hda_local.h"
 
+static int dump_coef = -1;
+module_param(dump_coef, int, 0644);
+MODULE_PARM_DESC(dump_coef, "Dump processing coefficients in codec proc file (-1=auto, 0=disable, 1=enable)");
+
 static char *bits_names(unsigned int bits, char *names[], int size)
 {
        int i, n;
@@ -488,14 +493,39 @@ static void print_unsol_cap(struct snd_info_buffer *buffer,
                    (unsol & AC_UNSOL_ENABLED) ? 1 : 0);
 }
 
+static inline bool can_dump_coef(struct hda_codec *codec)
+{
+       switch (dump_coef) {
+       case 0: return false;
+       case 1: return true;
+       default: return codec->dump_coef;
+       }
+}
+
 static void print_proc_caps(struct snd_info_buffer *buffer,
                            struct hda_codec *codec, hda_nid_t nid)
 {
+       unsigned int i, ncoeff, oldindex;
        unsigned int proc_caps = snd_hda_param_read(codec, nid,
                                                    AC_PAR_PROC_CAP);
+       ncoeff = (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT;
        snd_iprintf(buffer, "  Processing caps: benign=%d, ncoeff=%d\n",
-                   proc_caps & AC_PCAP_BENIGN,
-                   (proc_caps & AC_PCAP_NUM_COEF) >> AC_PCAP_NUM_COEF_SHIFT);
+                   proc_caps & AC_PCAP_BENIGN, ncoeff);
+
+       if (!can_dump_coef(codec))
+               return;
+
+       /* Note: This is racy - another process could run in parallel and change
+          the coef index too. */
+       oldindex = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_COEF_INDEX, 0);
+       for (i = 0; i < ncoeff; i++) {
+               unsigned int val;
+               snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, i);
+               val = snd_hda_codec_read(codec, nid, 0, AC_VERB_GET_PROC_COEF,
+                                        0);
+               snd_iprintf(buffer, "    Coeff 0x%02x: 0x%04x\n", i, val);
+       }
+       snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_COEF_INDEX, oldindex);
 }
 
 static void print_conn_list(struct snd_info_buffer *buffer,
index 64f0a5e73a259b00fe43f89672f369ea9b751b8d..5ef95034d041410be9bd453ed555de99d4bb0374 100644 (file)
@@ -132,6 +132,9 @@ struct hdmi_spec {
 
        struct hdmi_eld temp_eld;
        struct hdmi_ops ops;
+
+       bool dyn_pin_out;
+
        /*
         * Non-generic VIA/NVIDIA specific
         */
@@ -500,15 +503,25 @@ static void hdmi_write_dip_byte(struct hda_codec *codec, hda_nid_t pin_nid,
 
 static void hdmi_init_pin(struct hda_codec *codec, hda_nid_t pin_nid)
 {
+       struct hdmi_spec *spec = codec->spec;
+       int pin_out;
+
        /* Unmute */
        if (get_wcaps(codec, pin_nid) & AC_WCAP_OUT_AMP)
                snd_hda_codec_write(codec, pin_nid, 0,
                                AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
-       /* Enable pin out: some machines with GM965 gets broken output when
-        * the pin is disabled or changed while using with HDMI
-        */
+
+       if (spec->dyn_pin_out)
+               /* Disable pin out until stream is active */
+               pin_out = 0;
+       else
+               /* Enable pin out: some machines with GM965 gets broken output
+                * when the pin is disabled or changed while using with HDMI
+                */
+               pin_out = PIN_OUT;
+
        snd_hda_codec_write(codec, pin_nid, 0,
-                           AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT);
+                           AC_VERB_SET_PIN_WIDGET_CONTROL, pin_out);
 }
 
 static int hdmi_get_channel_count(struct hda_codec *codec, hda_nid_t cvt_nid)
@@ -1735,6 +1748,7 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        struct hdmi_spec_per_pin *per_pin = get_pin(spec, pin_idx);
        hda_nid_t pin_nid = per_pin->pin_nid;
        bool non_pcm;
+       int pinctl;
 
        non_pcm = check_non_pcm_per_cvt(codec, cvt_nid);
        mutex_lock(&per_pin->lock);
@@ -1744,6 +1758,14 @@ static int generic_hdmi_playback_pcm_prepare(struct hda_pcm_stream *hinfo,
        hdmi_setup_audio_infoframe(codec, per_pin, non_pcm);
        mutex_unlock(&per_pin->lock);
 
+       if (spec->dyn_pin_out) {
+               pinctl = snd_hda_codec_read(codec, pin_nid, 0,
+                                           AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+               snd_hda_codec_write(codec, pin_nid, 0,
+                                   AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                   pinctl | PIN_OUT);
+       }
+
        return spec->ops.setup_stream(codec, cvt_nid, pin_nid, stream_tag, format);
 }
 
@@ -1763,6 +1785,7 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
        int cvt_idx, pin_idx;
        struct hdmi_spec_per_cvt *per_cvt;
        struct hdmi_spec_per_pin *per_pin;
+       int pinctl;
 
        if (hinfo->nid) {
                cvt_idx = cvt_nid_to_cvt_index(spec, hinfo->nid);
@@ -1779,6 +1802,14 @@ static int hdmi_pcm_close(struct hda_pcm_stream *hinfo,
                        return -EINVAL;
                per_pin = get_pin(spec, pin_idx);
 
+               if (spec->dyn_pin_out) {
+                       pinctl = snd_hda_codec_read(codec, per_pin->pin_nid, 0,
+                                       AC_VERB_GET_PIN_WIDGET_CONTROL, 0);
+                       snd_hda_codec_write(codec, per_pin->pin_nid, 0,
+                                           AC_VERB_SET_PIN_WIDGET_CONTROL,
+                                           pinctl & ~PIN_OUT);
+               }
+
                snd_hda_spdif_ctls_unassign(codec, pin_idx);
 
                mutex_lock(&per_pin->lock);
@@ -2840,6 +2871,7 @@ static int patch_nvhdmi(struct hda_codec *codec)
                return err;
 
        spec = codec->spec;
+       spec->dyn_pin_out = true;
 
        spec->ops.chmap_cea_alloc_validate_get_type =
                nvhdmi_chmap_cea_alloc_validate_get_type;
index f9b22fb6dd0b6d91166f7f6f647e54cea274ce5c..56a8f187660333a51149910648d00b0a944e685b 100644 (file)
@@ -1819,6 +1819,7 @@ enum {
        ALC889_FIXUP_DAC_ROUTE,
        ALC889_FIXUP_MBP_VREF,
        ALC889_FIXUP_IMAC91_VREF,
+       ALC889_FIXUP_MBA11_VREF,
        ALC889_FIXUP_MBA21_VREF,
        ALC882_FIXUP_INV_DMIC,
        ALC882_FIXUP_NO_PRIMARY_HP,
@@ -1949,6 +1950,16 @@ static void alc889_fixup_imac91_vref(struct hda_codec *codec,
                alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
 }
 
+/* Set VREF on speaker pins on mba11 */
+static void alc889_fixup_mba11_vref(struct hda_codec *codec,
+                                   const struct hda_fixup *fix, int action)
+{
+       static hda_nid_t nids[1] = { 0x18 };
+
+       if (action == HDA_FIXUP_ACT_INIT)
+               alc889_fixup_mac_pins(codec, nids, ARRAY_SIZE(nids));
+}
+
 /* Set VREF on speaker pins on mba21 */
 static void alc889_fixup_mba21_vref(struct hda_codec *codec,
                                    const struct hda_fixup *fix, int action)
@@ -2167,6 +2178,12 @@ static const struct hda_fixup alc882_fixups[] = {
                .chained = true,
                .chain_id = ALC882_FIXUP_GPIO1,
        },
+       [ALC889_FIXUP_MBA11_VREF] = {
+               .type = HDA_FIXUP_FUNC,
+               .v.func = alc889_fixup_mba11_vref,
+               .chained = true,
+               .chain_id = ALC889_FIXUP_MBP_VREF,
+       },
        [ALC889_FIXUP_MBA21_VREF] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc889_fixup_mba21_vref,
@@ -2242,7 +2259,7 @@ static const struct snd_pci_quirk alc882_fixup_tbl[] = {
        SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC889_FIXUP_MBP_VREF),
        SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889_FIXUP_MBP_VREF),
        SND_PCI_QUIRK(0x106b, 0x3200, "iMac 7,1 Aluminum", ALC882_FIXUP_EAPD),
-       SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBP_VREF),
+       SND_PCI_QUIRK(0x106b, 0x3400, "MacBookAir 1,1", ALC889_FIXUP_MBA11_VREF),
        SND_PCI_QUIRK(0x106b, 0x3500, "MacBookAir 2,1", ALC889_FIXUP_MBA21_VREF),
        SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889_FIXUP_MBP_VREF),
        SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC889_FIXUP_MBP_VREF),
@@ -3833,6 +3850,7 @@ enum {
        ALC269_FIXUP_ACER_AC700,
        ALC269_FIXUP_LIMIT_INT_MIC_BOOST,
        ALC269VB_FIXUP_ASUS_ZENBOOK,
+       ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A,
        ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED,
        ALC269VB_FIXUP_ORDISSIMO_EVE2,
        ALC283_FIXUP_CHROME_BOOK,
@@ -4126,6 +4144,17 @@ static const struct hda_fixup alc269_fixups[] = {
                .chained = true,
                .chain_id = ALC269VB_FIXUP_DMIC,
        },
+       [ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A] = {
+               .type = HDA_FIXUP_VERBS,
+               .v.verbs = (const struct hda_verb[]) {
+                       /* class-D output amp +5dB */
+                       { 0x20, AC_VERB_SET_COEF_INDEX, 0x12 },
+                       { 0x20, AC_VERB_SET_PROC_COEF, 0x2800 },
+                       {}
+               },
+               .chained = true,
+               .chain_id = ALC269VB_FIXUP_ASUS_ZENBOOK,
+       },
        [ALC269_FIXUP_LIMIT_INT_MIC_BOOST_MUTE_LED] = {
                .type = HDA_FIXUP_FUNC,
                .v.func = alc269_fixup_limit_int_mic_boost,
@@ -4265,6 +4294,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1028, 0x063e, "Dell", ALC269_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x063f, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0640, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
+       SND_PCI_QUIRK(0x1028, 0x064d, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0651, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0652, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
        SND_PCI_QUIRK(0x1028, 0x0653, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE),
@@ -4282,7 +4312,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
        SND_PCI_QUIRK(0x1043, 0x106d, "Asus K53BE", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x115d, "Asus 1015E", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
        SND_PCI_QUIRK(0x1043, 0x1427, "Asus Zenbook UX31E", ALC269VB_FIXUP_ASUS_ZENBOOK),
-       SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK),
+       SND_PCI_QUIRK(0x1043, 0x1517, "Asus Zenbook UX31A", ALC269VB_FIXUP_ASUS_ZENBOOK_UX31A),
        SND_PCI_QUIRK(0x1043, 0x16e3, "ASUS UX50", ALC269_FIXUP_STEREO_DMIC),
        SND_PCI_QUIRK(0x1043, 0x1a13, "Asus G73Jw", ALC269_FIXUP_ASUS_G73JW),
        SND_PCI_QUIRK(0x1043, 0x1b13, "Asus U41SV", ALC269_FIXUP_INV_DMIC),
index 0f8726551fde852df9d7858cbef075cf31513e55..8f4c409f7e4528984f1f4dd1326ab014d8a7f3ea 100644 (file)
@@ -1,5 +1,5 @@
 snd-oxygen-lib-objs := oxygen_io.o oxygen_lib.o oxygen_mixer.o oxygen_pcm.o
-snd-oxygen-objs := oxygen.o xonar_dg.o
+snd-oxygen-objs := oxygen.o xonar_dg_mixer.o xonar_dg.o
 snd-virtuoso-objs := virtuoso.o xonar_lib.o \
        xonar_pcm179x.o xonar_cs43xx.o xonar_wm87x6.o xonar_hdmi.o
 
index 5e0197e07dd1e50eb5ea4cea8e18fae458d37d3c..99098657695a4f4748bfb8cdac7a8984cc39ce98 100644 (file)
 #define CS4245_ADC_OVFL                0x02
 #define CS4245_ADC_UNDRFL      0x01
 
+#define CS4245_SPI_ADDRESS_S   (0x9e << 16)
+#define CS4245_SPI_WRITE_S     (0 << 16)
 
-#define CS4245_SPI_ADDRESS     (0x9e << 16)
-#define CS4245_SPI_WRITE       (0 << 16)
+#define CS4245_SPI_ADDRESS     0x9e
+#define CS4245_SPI_WRITE       0
+#define CS4245_SPI_READ                1
index 09a24b24958bedfa8797f52680e977c289dfb117..c10ab077afd89aa3ec03681093e6c50743a36bca 100644 (file)
@@ -198,7 +198,7 @@ void oxygen_write_ac97(struct oxygen *chip, unsigned int codec,
 void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
                              unsigned int index, u16 data, u16 mask);
 
-void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
+int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data);
 void oxygen_write_i2c(struct oxygen *chip, u8 device, u8 map, u8 data);
 
 void oxygen_reset_uart(struct oxygen *chip);
index 521eae458348c723bd87519cd4fcdbd0530c2f00..3274907189febb4b6e3939274417abb58c21ca18 100644 (file)
@@ -194,23 +194,36 @@ void oxygen_write_ac97_masked(struct oxygen *chip, unsigned int codec,
 }
 EXPORT_SYMBOL(oxygen_write_ac97_masked);
 
-void oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
+static int oxygen_wait_spi(struct oxygen *chip)
 {
        unsigned int count;
 
-       /* should not need more than 30.72 us (24 * 1.28 us) */
-       count = 10;
-       while ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) & OXYGEN_SPI_BUSY)
-              && count > 0) {
+       /*
+        * Higher timeout to be sure: 200 us;
+        * actual transaction should not need more than 40 us.
+        */
+       for (count = 50; count > 0; count--) {
                udelay(4);
-               --count;
+               if ((oxygen_read8(chip, OXYGEN_SPI_CONTROL) &
+                                               OXYGEN_SPI_BUSY) == 0)
+                       return 0;
        }
+       snd_printk(KERN_ERR "oxygen: SPI wait timeout\n");
+       return -EIO;
+}
 
+int oxygen_write_spi(struct oxygen *chip, u8 control, unsigned int data)
+{
+       /*
+        * We need to wait AFTER initiating the SPI transaction,
+        * otherwise read operations will not work.
+        */
        oxygen_write8(chip, OXYGEN_SPI_DATA1, data);
        oxygen_write8(chip, OXYGEN_SPI_DATA2, data >> 8);
        if (control & OXYGEN_SPI_DATA_LENGTH_3)
                oxygen_write8(chip, OXYGEN_SPI_DATA3, data >> 16);
        oxygen_write8(chip, OXYGEN_SPI_CONTROL, control);
+       return oxygen_wait_spi(chip);
 }
 EXPORT_SYMBOL(oxygen_write_spi);
 
index c0dbb52d45be5306799fb144e63e60d81348045e..5988e044c5194e0650ab78c2ec4cf1eff069f8d0 100644 (file)
@@ -190,6 +190,7 @@ void oxygen_update_dac_routing(struct oxygen *chip)
        if (chip->model.update_center_lfe_mix)
                chip->model.update_center_lfe_mix(chip, chip->dac_routing > 2);
 }
+EXPORT_SYMBOL(oxygen_update_dac_routing);
 
 static int upmix_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
 {
index 63dc7a0ab55592b9b3a82aea7ccbeb18bea46799..8c191badaae8cf5077ed55fd6849aab52fbf448b 100644 (file)
 #define  OXYGEN_PLAY_MUTE23            0x0002
 #define  OXYGEN_PLAY_MUTE45            0x0004
 #define  OXYGEN_PLAY_MUTE67            0x0008
+#define  OXYGEN_PLAY_MUTE_MASK         0x000f
 #define  OXYGEN_PLAY_MULTICH_MASK      0x0010
 #define  OXYGEN_PLAY_MULTICH_I2S_DAC   0x0000
 #define  OXYGEN_PLAY_MULTICH_AC97      0x0010
index 77acd790ea4796b94c779fd72c1a8be861c4aa9e..ed6f199f8a38ac3d1412fc8efa4010ba23ecee4d 100644 (file)
@@ -2,7 +2,7 @@
  * card driver for the Xonar DG/DGX
  *
  * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- *
+ * Copyright (c) Roman Volkov <v1ron@mail.ru>
  *
  *  This driver is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License, version 2.
  * Xonar DG/DGX
  * ------------
  *
+ * CS4245 and CS4361 both will mute all outputs if any clock ratio
+ * is invalid.
+ *
  * CMI8788:
  *
  *   SPI 0 -> CS4245
  *
+ *   Playback:
  *   I²S 1 -> CS4245
  *   I²S 2 -> CS4361 (center/LFE)
  *   I²S 3 -> CS4361 (surround)
  *   I²S 4 -> CS4361 (front)
+ *   Capture:
+ *   I²S ADC 1 <- CS4245
  *
  *   GPIO 3 <- ?
  *   GPIO 4 <- headphone detect
- *   GPIO 5 -> route input jack to line-in (0) or mic-in (1)
- *   GPIO 6 -> route input jack to line-in (0) or mic-in (1)
- *   GPIO 7 -> enable rear headphone amp
+ *   GPIO 5 -> enable ADC analog circuit for the left channel
+ *   GPIO 6 -> enable ADC analog circuit for the right channel
+ *   GPIO 7 -> switch green rear output jack between CS4245 and and the first
+ *             channel of CS4361 (mechanical relay)
  *   GPIO 8 -> enable output to speakers
  *
  * CS4245:
  *
+ *   input 0 <- mic
  *   input 1 <- aux
  *   input 2 <- front mic
- *   input 4 <- line/mic
+ *   input 4 <- line
  *   DAC out -> headphones
  *   aux out -> front panel headphones
  */
 #include "xonar_dg.h"
 #include "cs4245.h"
 
-#define GPIO_MAGIC             0x0008
-#define GPIO_HP_DETECT         0x0010
-#define GPIO_INPUT_ROUTE       0x0060
-#define GPIO_HP_REAR           0x0080
-#define GPIO_OUTPUT_ENABLE     0x0100
-
-struct dg {
-       unsigned int output_sel;
-       s8 input_vol[4][2];
-       unsigned int input_sel;
-       u8 hp_vol_att;
-       u8 cs4245_regs[0x11];
-};
-
-static void cs4245_write(struct oxygen *chip, unsigned int reg, u8 value)
+int cs4245_write_spi(struct oxygen *chip, u8 reg)
 {
        struct dg *data = chip->model_data;
+       unsigned int packet;
 
-       oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
-                        OXYGEN_SPI_DATA_LENGTH_3 |
-                        OXYGEN_SPI_CLOCK_1280 |
-                        (0 << OXYGEN_SPI_CODEC_SHIFT) |
-                        OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
-                        CS4245_SPI_ADDRESS |
-                        CS4245_SPI_WRITE |
-                        (reg << 8) | value);
-       data->cs4245_regs[reg] = value;
+       packet = reg << 8;
+       packet |= (CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 16;
+       packet |= data->cs4245_shadow[reg];
+
+       return oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+                               OXYGEN_SPI_DATA_LENGTH_3 |
+                               OXYGEN_SPI_CLOCK_1280 |
+                               (0 << OXYGEN_SPI_CODEC_SHIFT) |
+                               OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
+                               packet);
 }
 
-static void cs4245_write_cached(struct oxygen *chip, unsigned int reg, u8 value)
+int cs4245_read_spi(struct oxygen *chip, u8 addr)
 {
        struct dg *data = chip->model_data;
+       int ret;
+
+       ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+               OXYGEN_SPI_DATA_LENGTH_2 |
+               OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
+               OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
+               ((CS4245_SPI_ADDRESS | CS4245_SPI_WRITE) << 8) | addr);
+       if (ret < 0)
+               return ret;
+
+       ret = oxygen_write_spi(chip, OXYGEN_SPI_TRIGGER |
+               OXYGEN_SPI_DATA_LENGTH_2 |
+               OXYGEN_SPI_CEN_LATCH_CLOCK_HI |
+               OXYGEN_SPI_CLOCK_1280 | (0 << OXYGEN_SPI_CODEC_SHIFT),
+               (CS4245_SPI_ADDRESS | CS4245_SPI_READ) << 8);
+       if (ret < 0)
+               return ret;
+
+       data->cs4245_shadow[addr] = oxygen_read8(chip, OXYGEN_SPI_DATA1);
 
-       if (value != data->cs4245_regs[reg])
-               cs4245_write(chip, reg, value);
+       return 0;
 }
 
-static void cs4245_registers_init(struct oxygen *chip)
+int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op)
 {
        struct dg *data = chip->model_data;
-
-       cs4245_write(chip, CS4245_POWER_CTRL, CS4245_PDN);
-       cs4245_write(chip, CS4245_DAC_CTRL_1,
-                    data->cs4245_regs[CS4245_DAC_CTRL_1]);
-       cs4245_write(chip, CS4245_ADC_CTRL,
-                    data->cs4245_regs[CS4245_ADC_CTRL]);
-       cs4245_write(chip, CS4245_SIGNAL_SEL,
-                    data->cs4245_regs[CS4245_SIGNAL_SEL]);
-       cs4245_write(chip, CS4245_PGA_B_CTRL,
-                    data->cs4245_regs[CS4245_PGA_B_CTRL]);
-       cs4245_write(chip, CS4245_PGA_A_CTRL,
-                    data->cs4245_regs[CS4245_PGA_A_CTRL]);
-       cs4245_write(chip, CS4245_ANALOG_IN,
-                    data->cs4245_regs[CS4245_ANALOG_IN]);
-       cs4245_write(chip, CS4245_DAC_A_CTRL,
-                    data->cs4245_regs[CS4245_DAC_A_CTRL]);
-       cs4245_write(chip, CS4245_DAC_B_CTRL,
-                    data->cs4245_regs[CS4245_DAC_B_CTRL]);
-       cs4245_write(chip, CS4245_DAC_CTRL_2,
-                    CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC);
-       cs4245_write(chip, CS4245_INT_MASK, 0);
-       cs4245_write(chip, CS4245_POWER_CTRL, 0);
+       unsigned char addr;
+       int ret;
+
+       for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++) {
+               ret = (op == CS4245_SAVE_TO_SHADOW ?
+                       cs4245_read_spi(chip, addr) :
+                       cs4245_write_spi(chip, addr));
+               if (ret < 0)
+                       return ret;
+       }
+       return 0;
 }
 
 static void cs4245_init(struct oxygen *chip)
 {
        struct dg *data = chip->model_data;
 
-       data->cs4245_regs[CS4245_DAC_CTRL_1] =
+       /* save the initial state: codec version, registers */
+       cs4245_shadow_control(chip, CS4245_SAVE_TO_SHADOW);
+
+       /*
+        * Power up the CODEC internals, enable soft ramp & zero cross, work in
+        * async. mode, enable aux output from DAC. Invert DAC output as in the
+        * Windows driver.
+        */
+       data->cs4245_shadow[CS4245_POWER_CTRL] = 0;
+       data->cs4245_shadow[CS4245_SIGNAL_SEL] =
+               CS4245_A_OUT_SEL_DAC | CS4245_ASYNCH;
+       data->cs4245_shadow[CS4245_DAC_CTRL_1] =
                CS4245_DAC_FM_SINGLE | CS4245_DAC_DIF_LJUST;
-       data->cs4245_regs[CS4245_ADC_CTRL] =
+       data->cs4245_shadow[CS4245_DAC_CTRL_2] =
+               CS4245_DAC_SOFT | CS4245_DAC_ZERO | CS4245_INVERT_DAC;
+       data->cs4245_shadow[CS4245_ADC_CTRL] =
                CS4245_ADC_FM_SINGLE | CS4245_ADC_DIF_LJUST;
-       data->cs4245_regs[CS4245_SIGNAL_SEL] =
-               CS4245_A_OUT_SEL_HIZ | CS4245_ASYNCH;
-       data->cs4245_regs[CS4245_PGA_B_CTRL] = 0;
-       data->cs4245_regs[CS4245_PGA_A_CTRL] = 0;
-       data->cs4245_regs[CS4245_ANALOG_IN] =
-               CS4245_PGA_SOFT | CS4245_PGA_ZERO | CS4245_SEL_INPUT_4;
-       data->cs4245_regs[CS4245_DAC_A_CTRL] = 0;
-       data->cs4245_regs[CS4245_DAC_B_CTRL] = 0;
-       cs4245_registers_init(chip);
+       data->cs4245_shadow[CS4245_ANALOG_IN] =
+               CS4245_PGA_SOFT | CS4245_PGA_ZERO;
+       data->cs4245_shadow[CS4245_PGA_B_CTRL] = 0;
+       data->cs4245_shadow[CS4245_PGA_A_CTRL] = 0;
+       data->cs4245_shadow[CS4245_DAC_A_CTRL] = 8;
+       data->cs4245_shadow[CS4245_DAC_B_CTRL] = 8;
+
+       cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
        snd_component_add(chip->card, "CS4245");
 }
 
-static void dg_output_enable(struct oxygen *chip)
-{
-       msleep(2500);
-       oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
-}
-
-static void dg_init(struct oxygen *chip)
+void dg_init(struct oxygen *chip)
 {
        struct dg *data = chip->model_data;
 
-       data->output_sel = 0;
-       data->input_sel = 3;
-       data->hp_vol_att = 2 * 16;
+       data->output_sel = PLAYBACK_DST_HP_FP;
+       data->input_sel = CAPTURE_SRC_MIC;
 
        cs4245_init(chip);
-
-       oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL,
-                           GPIO_MAGIC | GPIO_HP_DETECT);
-       oxygen_set_bits16(chip, OXYGEN_GPIO_CONTROL,
-                         GPIO_INPUT_ROUTE | GPIO_HP_REAR | GPIO_OUTPUT_ENABLE);
-       oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA,
-                           GPIO_INPUT_ROUTE | GPIO_HP_REAR);
-       dg_output_enable(chip);
+       oxygen_write16(chip, OXYGEN_GPIO_CONTROL,
+                      GPIO_OUTPUT_ENABLE | GPIO_HP_REAR | GPIO_INPUT_ROUTE);
+       /* anti-pop delay, wait some time before enabling the output */
+       msleep(2500);
+       oxygen_write16(chip, OXYGEN_GPIO_DATA,
+                      GPIO_OUTPUT_ENABLE | GPIO_INPUT_ROUTE);
 }
 
-static void dg_cleanup(struct oxygen *chip)
+void dg_cleanup(struct oxygen *chip)
 {
        oxygen_clear_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
 }
 
-static void dg_suspend(struct oxygen *chip)
+void dg_suspend(struct oxygen *chip)
 {
        dg_cleanup(chip);
 }
 
-static void dg_resume(struct oxygen *chip)
+void dg_resume(struct oxygen *chip)
 {
-       cs4245_registers_init(chip);
-       dg_output_enable(chip);
-}
-
-static void set_cs4245_dac_params(struct oxygen *chip,
-                                 struct snd_pcm_hw_params *params)
-{
-       struct dg *data = chip->model_data;
-       u8 value;
-
-       value = data->cs4245_regs[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
-       if (params_rate(params) <= 50000)
-               value |= CS4245_DAC_FM_SINGLE;
-       else if (params_rate(params) <= 100000)
-               value |= CS4245_DAC_FM_DOUBLE;
-       else
-               value |= CS4245_DAC_FM_QUAD;
-       cs4245_write_cached(chip, CS4245_DAC_CTRL_1, value);
+       cs4245_shadow_control(chip, CS4245_LOAD_FROM_SHADOW);
+       msleep(2500);
+       oxygen_set_bits16(chip, OXYGEN_GPIO_DATA, GPIO_OUTPUT_ENABLE);
 }
 
-static void set_cs4245_adc_params(struct oxygen *chip,
+void set_cs4245_dac_params(struct oxygen *chip,
                                  struct snd_pcm_hw_params *params)
 {
        struct dg *data = chip->model_data;
-       u8 value;
-
-       value = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
-       if (params_rate(params) <= 50000)
-               value |= CS4245_ADC_FM_SINGLE;
-       else if (params_rate(params) <= 100000)
-               value |= CS4245_ADC_FM_DOUBLE;
-       else
-               value |= CS4245_ADC_FM_QUAD;
-       cs4245_write_cached(chip, CS4245_ADC_CTRL, value);
-}
-
-static inline unsigned int shift_bits(unsigned int value,
-                                     unsigned int shift_from,
-                                     unsigned int shift_to,
-                                     unsigned int mask)
-{
-       if (shift_from < shift_to)
-               return (value << (shift_to - shift_from)) & mask;
-       else
-               return (value >> (shift_from - shift_to)) & mask;
-}
-
-static unsigned int adjust_dg_dac_routing(struct oxygen *chip,
-                                         unsigned int play_routing)
-{
-       return (play_routing & OXYGEN_PLAY_DAC0_SOURCE_MASK) |
-              shift_bits(play_routing,
-                         OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
-                         OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
-                         OXYGEN_PLAY_DAC1_SOURCE_MASK) |
-              shift_bits(play_routing,
-                         OXYGEN_PLAY_DAC1_SOURCE_SHIFT,
-                         OXYGEN_PLAY_DAC2_SOURCE_SHIFT,
-                         OXYGEN_PLAY_DAC2_SOURCE_MASK) |
-              shift_bits(play_routing,
-                         OXYGEN_PLAY_DAC0_SOURCE_SHIFT,
-                         OXYGEN_PLAY_DAC3_SOURCE_SHIFT,
-                         OXYGEN_PLAY_DAC3_SOURCE_MASK);
-}
-
-static int output_switch_info(struct snd_kcontrol *ctl,
-                             struct snd_ctl_elem_info *info)
-{
-       static const char *const names[3] = {
-               "Speakers", "Headphones", "FP Headphones"
-       };
-
-       return snd_ctl_enum_info(info, 1, 3, names);
-}
-
-static int output_switch_get(struct snd_kcontrol *ctl,
-                            struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       struct dg *data = chip->model_data;
-
-       mutex_lock(&chip->mutex);
-       value->value.enumerated.item[0] = data->output_sel;
-       mutex_unlock(&chip->mutex);
-       return 0;
-}
-
-static int output_switch_put(struct snd_kcontrol *ctl,
-                            struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       struct dg *data = chip->model_data;
-       u8 reg;
-       int changed;
-
-       if (value->value.enumerated.item[0] > 2)
-               return -EINVAL;
-
-       mutex_lock(&chip->mutex);
-       changed = value->value.enumerated.item[0] != data->output_sel;
-       if (changed) {
-               data->output_sel = value->value.enumerated.item[0];
-
-               reg = data->cs4245_regs[CS4245_SIGNAL_SEL] &
-                                               ~CS4245_A_OUT_SEL_MASK;
-               reg |= data->output_sel == 2 ?
-                               CS4245_A_OUT_SEL_DAC : CS4245_A_OUT_SEL_HIZ;
-               cs4245_write_cached(chip, CS4245_SIGNAL_SEL, reg);
-
-               cs4245_write_cached(chip, CS4245_DAC_A_CTRL,
-                                   data->output_sel ? data->hp_vol_att : 0);
-               cs4245_write_cached(chip, CS4245_DAC_B_CTRL,
-                                   data->output_sel ? data->hp_vol_att : 0);
-
-               oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
-                                     data->output_sel == 1 ? GPIO_HP_REAR : 0,
-                                     GPIO_HP_REAR);
-       }
-       mutex_unlock(&chip->mutex);
-       return changed;
-}
-
-static int hp_volume_offset_info(struct snd_kcontrol *ctl,
-                                struct snd_ctl_elem_info *info)
-{
-       static const char *const names[3] = {
-               "< 64 ohms", "64-150 ohms", "150-300 ohms"
-       };
-
-       return snd_ctl_enum_info(info, 1, 3, names);
-}
-
-static int hp_volume_offset_get(struct snd_kcontrol *ctl,
-                               struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       struct dg *data = chip->model_data;
-
-       mutex_lock(&chip->mutex);
-       if (data->hp_vol_att > 2 * 7)
-               value->value.enumerated.item[0] = 0;
-       else if (data->hp_vol_att > 0)
-               value->value.enumerated.item[0] = 1;
-       else
-               value->value.enumerated.item[0] = 2;
-       mutex_unlock(&chip->mutex);
-       return 0;
-}
-
-static int hp_volume_offset_put(struct snd_kcontrol *ctl,
-                               struct snd_ctl_elem_value *value)
-{
-       static const s8 atts[3] = { 2 * 16, 2 * 7, 0 };
-       struct oxygen *chip = ctl->private_data;
-       struct dg *data = chip->model_data;
-       s8 att;
-       int changed;
-
-       if (value->value.enumerated.item[0] > 2)
-               return -EINVAL;
-       att = atts[value->value.enumerated.item[0]];
-       mutex_lock(&chip->mutex);
-       changed = att != data->hp_vol_att;
-       if (changed) {
-               data->hp_vol_att = att;
-               if (data->output_sel) {
-                       cs4245_write_cached(chip, CS4245_DAC_A_CTRL, att);
-                       cs4245_write_cached(chip, CS4245_DAC_B_CTRL, att);
-               }
+       unsigned char dac_ctrl;
+       unsigned char mclk_freq;
+
+       dac_ctrl = data->cs4245_shadow[CS4245_DAC_CTRL_1] & ~CS4245_DAC_FM_MASK;
+       mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK1_MASK;
+       if (params_rate(params) <= 50000) {
+               dac_ctrl |= CS4245_DAC_FM_SINGLE;
+               mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
+       } else if (params_rate(params) <= 100000) {
+               dac_ctrl |= CS4245_DAC_FM_DOUBLE;
+               mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK1_SHIFT;
+       } else {
+               dac_ctrl |= CS4245_DAC_FM_QUAD;
+               mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK1_SHIFT;
        }
-       mutex_unlock(&chip->mutex);
-       return changed;
-}
-
-static int input_vol_info(struct snd_kcontrol *ctl,
-                         struct snd_ctl_elem_info *info)
-{
-       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       info->count = 2;
-       info->value.integer.min = 2 * -12;
-       info->value.integer.max = 2 * 12;
-       return 0;
-}
-
-static int input_vol_get(struct snd_kcontrol *ctl,
-                        struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       struct dg *data = chip->model_data;
-       unsigned int idx = ctl->private_value;
-
-       mutex_lock(&chip->mutex);
-       value->value.integer.value[0] = data->input_vol[idx][0];
-       value->value.integer.value[1] = data->input_vol[idx][1];
-       mutex_unlock(&chip->mutex);
-       return 0;
-}
-
-static int input_vol_put(struct snd_kcontrol *ctl,
-                        struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       struct dg *data = chip->model_data;
-       unsigned int idx = ctl->private_value;
-       int changed = 0;
-
-       if (value->value.integer.value[0] < 2 * -12 ||
-           value->value.integer.value[0] > 2 * 12 ||
-           value->value.integer.value[1] < 2 * -12 ||
-           value->value.integer.value[1] > 2 * 12)
-               return -EINVAL;
-       mutex_lock(&chip->mutex);
-       changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
-                 data->input_vol[idx][1] != value->value.integer.value[1];
-       if (changed) {
-               data->input_vol[idx][0] = value->value.integer.value[0];
-               data->input_vol[idx][1] = value->value.integer.value[1];
-               if (idx == data->input_sel) {
-                       cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
-                                           data->input_vol[idx][0]);
-                       cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
-                                           data->input_vol[idx][1]);
-               }
-       }
-       mutex_unlock(&chip->mutex);
-       return changed;
-}
-
-static DECLARE_TLV_DB_SCALE(cs4245_pga_db_scale, -1200, 50, 0);
-
-static int input_sel_info(struct snd_kcontrol *ctl,
-                         struct snd_ctl_elem_info *info)
-{
-       static const char *const names[4] = {
-               "Mic", "Aux", "Front Mic", "Line"
-       };
-
-       return snd_ctl_enum_info(info, 1, 4, names);
-}
-
-static int input_sel_get(struct snd_kcontrol *ctl,
-                        struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       struct dg *data = chip->model_data;
-
-       mutex_lock(&chip->mutex);
-       value->value.enumerated.item[0] = data->input_sel;
-       mutex_unlock(&chip->mutex);
-       return 0;
+       data->cs4245_shadow[CS4245_DAC_CTRL_1] = dac_ctrl;
+       data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
+       cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
+       cs4245_write_spi(chip, CS4245_MCLK_FREQ);
 }
 
-static int input_sel_put(struct snd_kcontrol *ctl,
-                        struct snd_ctl_elem_value *value)
+void set_cs4245_adc_params(struct oxygen *chip,
+                                 struct snd_pcm_hw_params *params)
 {
-       static const u8 sel_values[4] = {
-               CS4245_SEL_MIC,
-               CS4245_SEL_INPUT_1,
-               CS4245_SEL_INPUT_2,
-               CS4245_SEL_INPUT_4
-       };
-       struct oxygen *chip = ctl->private_data;
        struct dg *data = chip->model_data;
-       int changed;
-
-       if (value->value.enumerated.item[0] > 3)
-               return -EINVAL;
-
-       mutex_lock(&chip->mutex);
-       changed = value->value.enumerated.item[0] != data->input_sel;
-       if (changed) {
-               data->input_sel = value->value.enumerated.item[0];
-
-               cs4245_write(chip, CS4245_ANALOG_IN,
-                            (data->cs4245_regs[CS4245_ANALOG_IN] &
-                                                       ~CS4245_SEL_MASK) |
-                            sel_values[data->input_sel]);
-
-               cs4245_write_cached(chip, CS4245_PGA_A_CTRL,
-                                   data->input_vol[data->input_sel][0]);
-               cs4245_write_cached(chip, CS4245_PGA_B_CTRL,
-                                   data->input_vol[data->input_sel][1]);
-
-               oxygen_write16_masked(chip, OXYGEN_GPIO_DATA,
-                                     data->input_sel ? 0 : GPIO_INPUT_ROUTE,
-                                     GPIO_INPUT_ROUTE);
+       unsigned char adc_ctrl;
+       unsigned char mclk_freq;
+
+       adc_ctrl = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_ADC_FM_MASK;
+       mclk_freq = data->cs4245_shadow[CS4245_MCLK_FREQ] & ~CS4245_MCLK2_MASK;
+       if (params_rate(params) <= 50000) {
+               adc_ctrl |= CS4245_ADC_FM_SINGLE;
+               mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
+       } else if (params_rate(params) <= 100000) {
+               adc_ctrl |= CS4245_ADC_FM_DOUBLE;
+               mclk_freq |= CS4245_MCLK_1 << CS4245_MCLK2_SHIFT;
+       } else {
+               adc_ctrl |= CS4245_ADC_FM_QUAD;
+               mclk_freq |= CS4245_MCLK_2 << CS4245_MCLK2_SHIFT;
        }
-       mutex_unlock(&chip->mutex);
-       return changed;
-}
-
-static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
-{
-       static const char *const names[2] = { "Active", "Frozen" };
-
-       return snd_ctl_enum_info(info, 1, 2, names);
+       data->cs4245_shadow[CS4245_ADC_CTRL] = adc_ctrl;
+       data->cs4245_shadow[CS4245_MCLK_FREQ] = mclk_freq;
+       cs4245_write_spi(chip, CS4245_ADC_CTRL);
+       cs4245_write_spi(chip, CS4245_MCLK_FREQ);
 }
 
-static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
-{
-       struct oxygen *chip = ctl->private_data;
-       struct dg *data = chip->model_data;
-
-       value->value.enumerated.item[0] =
-               !!(data->cs4245_regs[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
-       return 0;
-}
-
-static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+unsigned int adjust_dg_dac_routing(struct oxygen *chip,
+                                         unsigned int play_routing)
 {
-       struct oxygen *chip = ctl->private_data;
        struct dg *data = chip->model_data;
-       u8 reg;
-       int changed;
-
-       mutex_lock(&chip->mutex);
-       reg = data->cs4245_regs[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
-       if (value->value.enumerated.item[0])
-               reg |= CS4245_HPF_FREEZE;
-       changed = reg != data->cs4245_regs[CS4245_ADC_CTRL];
-       if (changed)
-               cs4245_write(chip, CS4245_ADC_CTRL, reg);
-       mutex_unlock(&chip->mutex);
-       return changed;
-}
-
-#define INPUT_VOLUME(xname, index) { \
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
-       .name = xname, \
-       .info = input_vol_info, \
-       .get = input_vol_get, \
-       .put = input_vol_put, \
-       .tlv = { .p = cs4245_pga_db_scale }, \
-       .private_value = index, \
-}
-static const struct snd_kcontrol_new dg_controls[] = {
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Analog Output Playback Enum",
-               .info = output_switch_info,
-               .get = output_switch_get,
-               .put = output_switch_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Headphones Impedance Playback Enum",
-               .info = hp_volume_offset_info,
-               .get = hp_volume_offset_get,
-               .put = hp_volume_offset_put,
-       },
-       INPUT_VOLUME("Mic Capture Volume", 0),
-       INPUT_VOLUME("Aux Capture Volume", 1),
-       INPUT_VOLUME("Front Mic Capture Volume", 2),
-       INPUT_VOLUME("Line Capture Volume", 3),
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "Capture Source",
-               .info = input_sel_info,
-               .get = input_sel_get,
-               .put = input_sel_put,
-       },
-       {
-               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-               .name = "ADC High-pass Filter Capture Enum",
-               .info = hpf_info,
-               .get = hpf_get,
-               .put = hpf_put,
-       },
-};
-
-static int dg_control_filter(struct snd_kcontrol_new *template)
-{
-       if (!strncmp(template->name, "Master Playback ", 16))
-               return 1;
-       return 0;
-}
-
-static int dg_mixer_init(struct oxygen *chip)
-{
-       unsigned int i;
-       int err;
-
-       for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
-               err = snd_ctl_add(chip->card,
-                                 snd_ctl_new1(&dg_controls[i], chip));
-               if (err < 0)
-                       return err;
+       unsigned int routing = 0;
+
+       switch (data->output_sel) {
+       case PLAYBACK_DST_HP:
+       case PLAYBACK_DST_HP_FP:
+               oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+                       OXYGEN_PLAY_MUTE23 | OXYGEN_PLAY_MUTE45 |
+                       OXYGEN_PLAY_MUTE67, OXYGEN_PLAY_MUTE_MASK);
+               break;
+       case PLAYBACK_DST_MULTICH:
+               routing = (0 << OXYGEN_PLAY_DAC0_SOURCE_SHIFT) |
+                         (2 << OXYGEN_PLAY_DAC1_SOURCE_SHIFT) |
+                         (1 << OXYGEN_PLAY_DAC2_SOURCE_SHIFT) |
+                         (0 << OXYGEN_PLAY_DAC3_SOURCE_SHIFT);
+               oxygen_write8_masked(chip, OXYGEN_PLAY_ROUTING,
+                       OXYGEN_PLAY_MUTE01, OXYGEN_PLAY_MUTE_MASK);
+               break;
        }
-       return 0;
+       return routing;
 }
 
-static void dump_cs4245_registers(struct oxygen *chip,
+void dump_cs4245_registers(struct oxygen *chip,
                                  struct snd_info_buffer *buffer)
 {
        struct dg *data = chip->model_data;
-       unsigned int i;
+       unsigned int addr;
 
        snd_iprintf(buffer, "\nCS4245:");
-       for (i = 1; i <= 0x10; ++i)
-               snd_iprintf(buffer, " %02x", data->cs4245_regs[i]);
+       cs4245_read_spi(chip, CS4245_INT_STATUS);
+       for (addr = 1; addr < ARRAY_SIZE(data->cs4245_shadow); addr++)
+               snd_iprintf(buffer, " %02x", data->cs4245_shadow[addr]);
        snd_iprintf(buffer, "\n");
 }
-
-struct oxygen_model model_xonar_dg = {
-       .longname = "C-Media Oxygen HD Audio",
-       .chip = "CMI8786",
-       .init = dg_init,
-       .control_filter = dg_control_filter,
-       .mixer_init = dg_mixer_init,
-       .cleanup = dg_cleanup,
-       .suspend = dg_suspend,
-       .resume = dg_resume,
-       .set_dac_params = set_cs4245_dac_params,
-       .set_adc_params = set_cs4245_adc_params,
-       .adjust_dac_routing = adjust_dg_dac_routing,
-       .dump_registers = dump_cs4245_registers,
-       .model_data_size = sizeof(struct dg),
-       .device_config = PLAYBACK_0_TO_I2S |
-                        PLAYBACK_1_TO_SPDIF |
-                        CAPTURE_0_FROM_I2S_2 |
-                        CAPTURE_1_FROM_SPDIF,
-       .dac_channels_pcm = 6,
-       .dac_channels_mixer = 0,
-       .function_flags = OXYGEN_FUNCTION_SPI,
-       .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
-       .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
-};
index 5688d78609a9ff027463f6636d40a611fb27e0ca..d461df357aa15f203b2b60e5de98d5da864d79ea 100644 (file)
@@ -3,6 +3,54 @@
 
 #include "oxygen.h"
 
+#define GPIO_MAGIC             0x0008
+#define GPIO_HP_DETECT         0x0010
+#define GPIO_INPUT_ROUTE       0x0060
+#define GPIO_HP_REAR           0x0080
+#define GPIO_OUTPUT_ENABLE     0x0100
+
+#define CAPTURE_SRC_MIC                0
+#define CAPTURE_SRC_FP_MIC     1
+#define CAPTURE_SRC_LINE       2
+#define CAPTURE_SRC_AUX                3
+
+#define PLAYBACK_DST_HP                0
+#define PLAYBACK_DST_HP_FP     1
+#define PLAYBACK_DST_MULTICH   2
+
+enum cs4245_shadow_operation {
+       CS4245_SAVE_TO_SHADOW,
+       CS4245_LOAD_FROM_SHADOW
+};
+
+struct dg {
+       /* shadow copy of the CS4245 register space */
+       unsigned char cs4245_shadow[17];
+       /* output select: headphone/speakers */
+       unsigned char output_sel;
+       /* volumes for all capture sources */
+       char input_vol[4][2];
+       /* input select: mic/fp mic/line/aux */
+       unsigned char input_sel;
+};
+
+/* Xonar DG control routines */
+int cs4245_write_spi(struct oxygen *chip, u8 reg);
+int cs4245_read_spi(struct oxygen *chip, u8 reg);
+int cs4245_shadow_control(struct oxygen *chip, enum cs4245_shadow_operation op);
+void dg_init(struct oxygen *chip);
+void set_cs4245_dac_params(struct oxygen *chip,
+                                 struct snd_pcm_hw_params *params);
+void set_cs4245_adc_params(struct oxygen *chip,
+                                 struct snd_pcm_hw_params *params);
+unsigned int adjust_dg_dac_routing(struct oxygen *chip,
+                                         unsigned int play_routing);
+void dump_cs4245_registers(struct oxygen *chip,
+                               struct snd_info_buffer *buffer);
+void dg_suspend(struct oxygen *chip);
+void dg_resume(struct oxygen *chip);
+void dg_cleanup(struct oxygen *chip);
+
 extern struct oxygen_model model_xonar_dg;
 
 #endif
diff --git a/sound/pci/oxygen/xonar_dg_mixer.c b/sound/pci/oxygen/xonar_dg_mixer.c
new file mode 100644 (file)
index 0000000..b885dac
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ * Mixer controls for the Xonar DG/DGX
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) Roman Volkov <v1ron@mail.ru>
+ *
+ *  This driver is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License, version 2.
+ *
+ *  This driver 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 driver; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/info.h>
+#include <sound/pcm.h>
+#include <sound/tlv.h>
+#include "oxygen.h"
+#include "xonar_dg.h"
+#include "cs4245.h"
+
+/* analog output select */
+
+static int output_select_apply(struct oxygen *chip)
+{
+       struct dg *data = chip->model_data;
+
+       data->cs4245_shadow[CS4245_SIGNAL_SEL] &= ~CS4245_A_OUT_SEL_MASK;
+       if (data->output_sel == PLAYBACK_DST_HP) {
+               /* mute FP (aux output) amplifier, switch rear jack to CS4245 */
+               oxygen_set_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+       } else if (data->output_sel == PLAYBACK_DST_HP_FP) {
+               /*
+                * Unmute FP amplifier, switch rear jack to CS4361;
+                * I2S channels 2,3,4 should be inactive.
+                */
+               oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+               data->cs4245_shadow[CS4245_SIGNAL_SEL] |= CS4245_A_OUT_SEL_DAC;
+       } else {
+               /*
+                * 2.0, 4.0, 5.1: switch to CS4361, mute FP amp.,
+                * and change playback routing.
+                */
+               oxygen_clear_bits8(chip, OXYGEN_GPIO_DATA, GPIO_HP_REAR);
+       }
+       return cs4245_write_spi(chip, CS4245_SIGNAL_SEL);
+}
+
+static int output_select_info(struct snd_kcontrol *ctl,
+                             struct snd_ctl_elem_info *info)
+{
+       static const char *const names[3] = {
+               "Stereo Headphones",
+               "Stereo Headphones FP",
+               "Multichannel",
+       };
+
+       return snd_ctl_enum_info(info, 1, 3, names);
+}
+
+static int output_select_get(struct snd_kcontrol *ctl,
+                            struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.enumerated.item[0] = data->output_sel;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int output_select_put(struct snd_kcontrol *ctl,
+                            struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       unsigned int new = value->value.enumerated.item[0];
+       int changed = 0;
+       int ret;
+
+       mutex_lock(&chip->mutex);
+       if (data->output_sel != new) {
+               data->output_sel = new;
+               ret = output_select_apply(chip);
+               changed = ret >= 0 ? 1 : ret;
+               oxygen_update_dac_routing(chip);
+       }
+       mutex_unlock(&chip->mutex);
+
+       return changed;
+}
+
+/* CS4245 Headphone Channels A&B Volume Control */
+
+static int hp_stereo_volume_info(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 2;
+       info->value.integer.min = 0;
+       info->value.integer.max = 255;
+       return 0;
+}
+
+static int hp_stereo_volume_get(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *val)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       unsigned int tmp;
+
+       mutex_lock(&chip->mutex);
+       tmp = (~data->cs4245_shadow[CS4245_DAC_A_CTRL]) & 255;
+       val->value.integer.value[0] = tmp;
+       tmp = (~data->cs4245_shadow[CS4245_DAC_B_CTRL]) & 255;
+       val->value.integer.value[1] = tmp;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int hp_stereo_volume_put(struct snd_kcontrol *ctl,
+                               struct snd_ctl_elem_value *val)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       int ret;
+       int changed = 0;
+       long new1 = val->value.integer.value[0];
+       long new2 = val->value.integer.value[1];
+
+       if ((new1 > 255) || (new1 < 0) || (new2 > 255) || (new2 < 0))
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       if ((data->cs4245_shadow[CS4245_DAC_A_CTRL] != ~new1) ||
+           (data->cs4245_shadow[CS4245_DAC_B_CTRL] != ~new2)) {
+               data->cs4245_shadow[CS4245_DAC_A_CTRL] = ~new1;
+               data->cs4245_shadow[CS4245_DAC_B_CTRL] = ~new2;
+               ret = cs4245_write_spi(chip, CS4245_DAC_A_CTRL);
+               if (ret >= 0)
+                       ret = cs4245_write_spi(chip, CS4245_DAC_B_CTRL);
+               changed = ret >= 0 ? 1 : ret;
+       }
+       mutex_unlock(&chip->mutex);
+
+       return changed;
+}
+
+/* Headphone Mute */
+
+static int hp_mute_get(struct snd_kcontrol *ctl,
+                       struct snd_ctl_elem_value *val)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+
+       mutex_lock(&chip->mutex);
+       val->value.integer.value[0] =
+               !(data->cs4245_shadow[CS4245_DAC_CTRL_1] & CS4245_MUTE_DAC);
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int hp_mute_put(struct snd_kcontrol *ctl,
+                       struct snd_ctl_elem_value *val)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       int ret;
+       int changed;
+
+       if (val->value.integer.value[0] > 1)
+               return -EINVAL;
+       mutex_lock(&chip->mutex);
+       data->cs4245_shadow[CS4245_DAC_CTRL_1] &= ~CS4245_MUTE_DAC;
+       data->cs4245_shadow[CS4245_DAC_CTRL_1] |=
+               (~val->value.integer.value[0] << 2) & CS4245_MUTE_DAC;
+       ret = cs4245_write_spi(chip, CS4245_DAC_CTRL_1);
+       changed = ret >= 0 ? 1 : ret;
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+/* capture volume for all sources */
+
+static int input_volume_apply(struct oxygen *chip, char left, char right)
+{
+       struct dg *data = chip->model_data;
+       int ret;
+
+       data->cs4245_shadow[CS4245_PGA_A_CTRL] = left;
+       data->cs4245_shadow[CS4245_PGA_B_CTRL] = right;
+       ret = cs4245_write_spi(chip, CS4245_PGA_A_CTRL);
+       if (ret < 0)
+               return ret;
+       return cs4245_write_spi(chip, CS4245_PGA_B_CTRL);
+}
+
+static int input_vol_info(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_info *info)
+{
+       info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       info->count = 2;
+       info->value.integer.min = 2 * -12;
+       info->value.integer.max = 2 * 12;
+       return 0;
+}
+
+static int input_vol_get(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       unsigned int idx = ctl->private_value;
+
+       mutex_lock(&chip->mutex);
+       value->value.integer.value[0] = data->input_vol[idx][0];
+       value->value.integer.value[1] = data->input_vol[idx][1];
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int input_vol_put(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       unsigned int idx = ctl->private_value;
+       int changed = 0;
+       int ret = 0;
+
+       if (value->value.integer.value[0] < 2 * -12 ||
+           value->value.integer.value[0] > 2 * 12 ||
+           value->value.integer.value[1] < 2 * -12 ||
+           value->value.integer.value[1] > 2 * 12)
+               return -EINVAL;
+       mutex_lock(&chip->mutex);
+       changed = data->input_vol[idx][0] != value->value.integer.value[0] ||
+                 data->input_vol[idx][1] != value->value.integer.value[1];
+       if (changed) {
+               data->input_vol[idx][0] = value->value.integer.value[0];
+               data->input_vol[idx][1] = value->value.integer.value[1];
+               if (idx == data->input_sel) {
+                       ret = input_volume_apply(chip,
+                               data->input_vol[idx][0],
+                               data->input_vol[idx][1]);
+               }
+               changed = ret >= 0 ? 1 : ret;
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+/* Capture Source */
+
+static int input_source_apply(struct oxygen *chip)
+{
+       struct dg *data = chip->model_data;
+
+       data->cs4245_shadow[CS4245_ANALOG_IN] &= ~CS4245_SEL_MASK;
+       if (data->input_sel == CAPTURE_SRC_FP_MIC)
+               data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_2;
+       else if (data->input_sel == CAPTURE_SRC_LINE)
+               data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_4;
+       else if (data->input_sel != CAPTURE_SRC_MIC)
+               data->cs4245_shadow[CS4245_ANALOG_IN] |= CS4245_SEL_INPUT_1;
+       return cs4245_write_spi(chip, CS4245_ANALOG_IN);
+}
+
+static int input_sel_info(struct snd_kcontrol *ctl,
+                         struct snd_ctl_elem_info *info)
+{
+       static const char *const names[4] = {
+               "Mic", "Front Mic", "Line", "Aux"
+       };
+
+       return snd_ctl_enum_info(info, 1, 4, names);
+}
+
+static int input_sel_get(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+
+       mutex_lock(&chip->mutex);
+       value->value.enumerated.item[0] = data->input_sel;
+       mutex_unlock(&chip->mutex);
+       return 0;
+}
+
+static int input_sel_put(struct snd_kcontrol *ctl,
+                        struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       int changed;
+       int ret;
+
+       if (value->value.enumerated.item[0] > 3)
+               return -EINVAL;
+
+       mutex_lock(&chip->mutex);
+       changed = value->value.enumerated.item[0] != data->input_sel;
+       if (changed) {
+               data->input_sel = value->value.enumerated.item[0];
+
+               ret = input_source_apply(chip);
+               if (ret >= 0)
+                       ret = input_volume_apply(chip,
+                               data->input_vol[data->input_sel][0],
+                               data->input_vol[data->input_sel][1]);
+               changed = ret >= 0 ? 1 : ret;
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+/* ADC high-pass filter */
+
+static int hpf_info(struct snd_kcontrol *ctl, struct snd_ctl_elem_info *info)
+{
+       static const char *const names[2] = { "Active", "Frozen" };
+
+       return snd_ctl_enum_info(info, 1, 2, names);
+}
+
+static int hpf_get(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+
+       value->value.enumerated.item[0] =
+               !!(data->cs4245_shadow[CS4245_ADC_CTRL] & CS4245_HPF_FREEZE);
+       return 0;
+}
+
+static int hpf_put(struct snd_kcontrol *ctl, struct snd_ctl_elem_value *value)
+{
+       struct oxygen *chip = ctl->private_data;
+       struct dg *data = chip->model_data;
+       u8 reg;
+       int changed;
+
+       mutex_lock(&chip->mutex);
+       reg = data->cs4245_shadow[CS4245_ADC_CTRL] & ~CS4245_HPF_FREEZE;
+       if (value->value.enumerated.item[0])
+               reg |= CS4245_HPF_FREEZE;
+       changed = reg != data->cs4245_shadow[CS4245_ADC_CTRL];
+       if (changed) {
+               data->cs4245_shadow[CS4245_ADC_CTRL] = reg;
+               cs4245_write_spi(chip, CS4245_ADC_CTRL);
+       }
+       mutex_unlock(&chip->mutex);
+       return changed;
+}
+
+#define INPUT_VOLUME(xname, index) { \
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+       .name = xname, \
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \
+                 SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
+       .info = input_vol_info, \
+       .get = input_vol_get, \
+       .put = input_vol_put, \
+       .tlv = { .p = pga_db_scale }, \
+       .private_value = index, \
+}
+static const DECLARE_TLV_DB_MINMAX(hp_db_scale, -12550, 0);
+static const DECLARE_TLV_DB_MINMAX(pga_db_scale, -1200, 1200);
+static const struct snd_kcontrol_new dg_controls[] = {
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Analog Output Playback Enum",
+               .info = output_select_info,
+               .get = output_select_get,
+               .put = output_select_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphone Playback Volume",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+                         SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+               .info = hp_stereo_volume_info,
+               .get = hp_stereo_volume_get,
+               .put = hp_stereo_volume_put,
+               .tlv = { .p = hp_db_scale, },
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Headphone Playback Switch",
+               .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+               .info = snd_ctl_boolean_mono_info,
+               .get = hp_mute_get,
+               .put = hp_mute_put,
+       },
+       INPUT_VOLUME("Mic Capture Volume", CAPTURE_SRC_MIC),
+       INPUT_VOLUME("Front Mic Capture Volume", CAPTURE_SRC_FP_MIC),
+       INPUT_VOLUME("Line Capture Volume", CAPTURE_SRC_LINE),
+       INPUT_VOLUME("Aux Capture Volume", CAPTURE_SRC_AUX),
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "Capture Source",
+               .info = input_sel_info,
+               .get = input_sel_get,
+               .put = input_sel_put,
+       },
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+               .name = "ADC High-pass Filter Capture Enum",
+               .info = hpf_info,
+               .get = hpf_get,
+               .put = hpf_put,
+       },
+};
+
+static int dg_control_filter(struct snd_kcontrol_new *template)
+{
+       if (!strncmp(template->name, "Master Playback ", 16))
+               return 1;
+       return 0;
+}
+
+static int dg_mixer_init(struct oxygen *chip)
+{
+       unsigned int i;
+       int err;
+
+       output_select_apply(chip);
+       input_source_apply(chip);
+       oxygen_update_dac_routing(chip);
+
+       for (i = 0; i < ARRAY_SIZE(dg_controls); ++i) {
+               err = snd_ctl_add(chip->card,
+                                 snd_ctl_new1(&dg_controls[i], chip));
+               if (err < 0)
+                       return err;
+       }
+
+       return 0;
+}
+
+struct oxygen_model model_xonar_dg = {
+       .longname = "C-Media Oxygen HD Audio",
+       .chip = "CMI8786",
+       .init = dg_init,
+       .control_filter = dg_control_filter,
+       .mixer_init = dg_mixer_init,
+       .cleanup = dg_cleanup,
+       .suspend = dg_suspend,
+       .resume = dg_resume,
+       .set_dac_params = set_cs4245_dac_params,
+       .set_adc_params = set_cs4245_adc_params,
+       .adjust_dac_routing = adjust_dg_dac_routing,
+       .dump_registers = dump_cs4245_registers,
+       .model_data_size = sizeof(struct dg),
+       .device_config = PLAYBACK_0_TO_I2S |
+                        PLAYBACK_1_TO_SPDIF |
+                        CAPTURE_0_FROM_I2S_1 |
+                        CAPTURE_1_FROM_SPDIF,
+       .dac_channels_pcm = 6,
+       .dac_channels_mixer = 0,
+       .function_flags = OXYGEN_FUNCTION_SPI,
+       .dac_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .adc_mclks = OXYGEN_MCLKS(256, 128, 128),
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+       .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
+};
index 385dec16eb8a18150a7d6005f310af8c44001938..688151ba309af2e3af8bdeea6a428850947d3773 100644 (file)
@@ -450,6 +450,17 @@ static int aic32x4_hw_params(struct snd_pcm_substream *substream,
        }
        snd_soc_write(codec, AIC32X4_IFACE1, data);
 
+       if (params_channels(params) == 1) {
+               data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2LCHN;
+       } else {
+               if (aic32x4->swapdacs)
+                       data = AIC32X4_RDAC2LCHN | AIC32X4_LDAC2RCHN;
+               else
+                       data = AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN;
+       }
+       snd_soc_update_bits(codec, AIC32X4_DACSETUP, AIC32X4_DAC_CHAN_MASK,
+                       data);
+
        return 0;
 }
 
@@ -606,20 +617,15 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
        }
        snd_soc_write(codec, AIC32X4_CMMODE, tmp_reg);
 
-       /* Do DACs need to be swapped? */
-       if (aic32x4->swapdacs) {
-               snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2RCHN | AIC32X4_RDAC2LCHN);
-       } else {
-               snd_soc_write(codec, AIC32X4_DACSETUP, AIC32X4_LDAC2LCHN | AIC32X4_RDAC2RCHN);
-       }
-
        /* Mic PGA routing */
-       if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K) {
+       if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_LMIC_IN2R_10K)
                snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_IN2R_10K);
-       }
-       if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K) {
+       else
+               snd_soc_write(codec, AIC32X4_LMICPGANIN, AIC32X4_LMICPGANIN_CM1L_10K);
+       if (aic32x4->micpga_routing & AIC32X4_MICPGA_ROUTE_RMIC_IN1L_10K)
                snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_IN1L_10K);
-       }
+       else
+               snd_soc_write(codec, AIC32X4_RMICPGANIN, AIC32X4_RMICPGANIN_CM1R_10K);
 
        aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
 
index 35774223fd91f2a03c4ce4ed56c45df3f3ff2a3d..995f033a855d64509b9dffa2dae6fd9ce810268c 100644 (file)
 #define AIC32X4_MICBIAS_2075V          0x60
 
 #define AIC32X4_LMICPGANIN_IN2R_10K    0x10
+#define AIC32X4_LMICPGANIN_CM1L_10K    0x40
 #define AIC32X4_RMICPGANIN_IN1L_10K    0x10
+#define AIC32X4_RMICPGANIN_CM1R_10K    0x40
 
 #define AIC32X4_LMICPGAVOL_NOGAIN      0x80
 #define AIC32X4_RMICPGAVOL_NOGAIN      0x80
 #define AIC32X4_LDAC2RCHN              (0x02 << 4)
 #define AIC32X4_LDAC2LCHN              (0x01 << 4)
 #define AIC32X4_RDAC2RCHN              (0x01 << 2)
+#define AIC32X4_DAC_CHAN_MASK          0x3c
 
 #define AIC32X4_SSTEP2WCLK             0x01
 #define AIC32X4_MUTEON                 0x0C
index 4cf91deabc0261dde5d470e5bef375dab415b0b7..4e3e31aaf5098e473391f578df6fe0c3c6042a95 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/moduleparam.h>
 #include <linux/init.h>
 #include <linux/delay.h>
+#include <linux/export.h>
 #include <linux/pm.h>
 #include <linux/gcd.h>
 #include <linux/gpio.h>
@@ -2141,6 +2142,7 @@ int wm5100_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(wm5100_detect);
 
 static irqreturn_t wm5100_irq(int irq, void *data)
 {
index d862f76b59f9ecba646e065863d2040a04a0d0b0..2c3c962d9a856fe12e391b4292cdf7dbd715cd6d 100644 (file)
@@ -81,6 +81,54 @@ static const struct reg_default wm5110_sysclk_revd_patch[] = {
        { 0x3133, 0x1201 },
        { 0x3183, 0x1501 },
        { 0x31D3, 0x1401 },
+       { 0x0049, 0x01ea },
+       { 0x004a, 0x01f2 },
+       { 0x0057, 0x01e7 },
+       { 0x0058, 0x01fb },
+       { 0x33ce, 0xc4f5 },
+       { 0x33cf, 0x1361 },
+       { 0x33d0, 0x0402 },
+       { 0x33d1, 0x4700 },
+       { 0x33d2, 0x026d },
+       { 0x33d3, 0xff00 },
+       { 0x33d4, 0x026d },
+       { 0x33d5, 0x0101 },
+       { 0x33d6, 0xc4f5 },
+       { 0x33d7, 0x0361 },
+       { 0x33d8, 0x0402 },
+       { 0x33d9, 0x6701 },
+       { 0x33da, 0xc4f5 },
+       { 0x33db, 0x136f },
+       { 0x33dc, 0xc4f5 },
+       { 0x33dd, 0x134f },
+       { 0x33de, 0xc4f5 },
+       { 0x33df, 0x131f },
+       { 0x33e0, 0x026d },
+       { 0x33e1, 0x4f01 },
+       { 0x33e2, 0x026d },
+       { 0x33e3, 0xf100 },
+       { 0x33e4, 0x026d },
+       { 0x33e5, 0x0001 },
+       { 0x33e6, 0xc4f5 },
+       { 0x33e7, 0x0361 },
+       { 0x33e8, 0x0402 },
+       { 0x33e9, 0x6601 },
+       { 0x33ea, 0xc4f5 },
+       { 0x33eb, 0x136f },
+       { 0x33ec, 0xc4f5 },
+       { 0x33ed, 0x134f },
+       { 0x33ee, 0xc4f5 },
+       { 0x33ef, 0x131f },
+       { 0x33f0, 0x026d },
+       { 0x33f1, 0x4e01 },
+       { 0x33f2, 0x026d },
+       { 0x33f3, 0xf000 },
+       { 0x33f6, 0xc4f5 },
+       { 0x33f7, 0x1361 },
+       { 0x33f8, 0x0402 },
+       { 0x33f9, 0x4600 },
+       { 0x33fa, 0x026d },
+       { 0x33fb, 0xfe00 },
 };
 
 static int wm5110_sysclk_ev(struct snd_soc_dapm_widget *w,
index f9090b167ad7c1ba2c3e91f1af2e042356c25841..5428a1fda2603850349fa2fb11680df9b63386eb 100644 (file)
@@ -164,6 +164,7 @@ struct fsl_ssi_private {
        bool baudclk_locked;
        bool irq_stats;
        bool offline_config;
+       bool use_dual_fifo;
        u8 i2s_mode;
        spinlock_t baudclk_lock;
        struct clk *baudclk;
@@ -721,6 +722,12 @@ static int fsl_ssi_setup(struct fsl_ssi_private *ssi_private)
                                CCSR_SSI_SxCCR_DC(2));
        }
 
+       if (ssi_private->use_dual_fifo) {
+               write_ssi_mask(&ssi->srcr, 0, CCSR_SSI_SRCR_RFEN1);
+               write_ssi_mask(&ssi->stcr, 0, CCSR_SSI_STCR_TFEN1);
+               write_ssi_mask(&ssi->scr, 0, CCSR_SSI_SCR_TCH_EN);
+       }
+
        return 0;
 }
 
@@ -752,6 +759,15 @@ static int fsl_ssi_startup(struct snd_pcm_substream *substream,
                spin_unlock_irqrestore(&ssi_private->baudclk_lock, flags);
        }
 
+       /* 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
+        * task from fifo0, fifo1 would be neglected at the end of each
+        * period. But SSI would still access fifo1 with an invalid data.
+        */
+       if (ssi_private->use_dual_fifo)
+               snd_pcm_hw_constraint_step(substream->runtime, 0,
+                               SNDRV_PCM_HW_PARAM_PERIOD_SIZE, 2);
+
        return 0;
 }
 
@@ -1262,18 +1278,13 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                return -EINVAL;
        hw_type = (enum fsl_ssi_type) of_id->data;
 
-       /* We only support the SSI in "I2S Slave" mode */
        sprop = of_get_property(np, "fsl,mode", NULL);
        if (!sprop) {
                dev_err(&pdev->dev, "fsl,mode property is necessary\n");
                return -EINVAL;
        }
-       if (!strcmp(sprop, "ac97-slave")) {
+       if (!strcmp(sprop, "ac97-slave"))
                ac97 = true;
-       } else if (strcmp(sprop, "i2s-slave")) {
-               dev_notice(&pdev->dev, "mode %s is unsupported\n", sprop);
-               return -ENODEV;
-       }
 
        /* The DAI name is the last part of the full name of the node. */
        p = strrchr(np->full_name, '/') + 1;
@@ -1370,7 +1381,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
 
        if (hw_type == FSL_SSI_MX21 || hw_type == FSL_SSI_MX51 ||
                        hw_type == FSL_SSI_MX35) {
-               u32 dma_events[2];
+               u32 dma_events[2], dmas[4];
                ssi_private->ssi_on_imx = true;
 
                ssi_private->clk = devm_clk_get(&pdev->dev, NULL);
@@ -1391,7 +1402,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                 */
                ssi_private->baudclk = devm_clk_get(&pdev->dev, "baud");
                if (IS_ERR(ssi_private->baudclk))
-                       dev_warn(&pdev->dev, "could not get baud clock: %ld\n",
+                       dev_dbg(&pdev->dev, "could not get baud clock: %ld\n",
                                 PTR_ERR(ssi_private->baudclk));
                else
                        clk_prepare_enable(ssi_private->baudclk);
@@ -1426,6 +1437,16 @@ static int fsl_ssi_probe(struct platform_device *pdev)
                                goto error_clk;
                        }
                }
+               /* Should this be merge with the above? */
+               if (!of_property_read_u32_array(pdev->dev.of_node, "dmas", dmas, 4)
+                               && dmas[2] == IMX_DMATYPE_SSI_DUAL) {
+                       ssi_private->use_dual_fifo = true;
+                       /* When using dual fifo mode, we need to keep watermark
+                        * as even numbers due to dma script limitation.
+                        */
+                       ssi_private->dma_params_tx.maxburst &= ~0x1;
+                       ssi_private->dma_params_rx.maxburst &= ~0x1;
+               }
 
                shared = of_device_is_compatible(of_get_parent(np),
                            "fsl,spba-bus");
index 4a07f7179690d36e3526cb8bcf9c4fc20e2ca509..22ad9c5654b5ebea99b6aecbc0b4271af62ef3e1 100644 (file)
@@ -30,6 +30,7 @@ config SND_OMAP_SOC_RX51
        select SND_OMAP_SOC_MCBSP
        select SND_SOC_TLV320AIC3X
        select SND_SOC_TPA6130A2
+       depends on GPIOLIB
        help
          Say Y if you want to add support for SoC audio on Nokia RX-51
          hardware. This is also known as Nokia N900 product.
index 27930fc432dcfe4b750ba3a9f2ff70bf50d78f1e..454f41cfc82847e98a6297b2db5822db35d717a6 100644 (file)
@@ -19,7 +19,7 @@ config SND_S3C_DMA_LEGACY
 
 config SND_S3C24XX_I2S
        tristate
-       select S3C2410_DMA
+       select S3C24XX_DMA
 
 config SND_S3C_I2SV2_SOC
        tristate
@@ -210,7 +210,7 @@ config SND_SOC_TOBERMORY
 
 config SND_SOC_BELLS
        tristate "Audio support for Wolfson Bells"
-       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410
+       depends on SND_SOC_SAMSUNG && MACH_WLF_CRAGG_6410 && MFD_ARIZONA
        select SND_SAMSUNG_I2S
        select SND_SOC_WM5102
        select SND_SOC_WM5110
index fa91376e323dc471c790ab80513448983645be99..fbced589d0778af46b92e3198534116767be3706 100644 (file)
@@ -23,6 +23,7 @@
 #include "regs-iis.h"
 #include <asm/mach-types.h>
 
+#include <mach/gpio-samsung.h>
 #include "s3c24xx-i2s.h"
 
 static unsigned int rates[] = {
index 92f64363427d44b741f2293fa84982c748a72d82..0a9b44c940cee4c962942d23ecccd85466cc56b8 100644 (file)
@@ -22,8 +22,6 @@
 #include <sound/soc.h>
 #include <sound/pcm_params.h>
 
-#include <mach/dma.h>
-
 #include <linux/platform_data/asoc-s3c.h>
 
 #include "dma.h"
@@ -1268,7 +1266,8 @@ static int samsung_i2s_probe(struct platform_device *pdev)
 
        return 0;
 err:
-       release_mem_region(regs_base, resource_size(res));
+       if (res)
+               release_mem_region(regs_base, resource_size(res));
 
        return ret;
 }
index 807db417d234a5d3571f6ff6be86893acad514d9..98a04c11202df7562475f4dd88bd4742f00492f3 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <sound/soc.h>
 
+#include <mach/gpio-samsung.h>
 #include <asm/mach-types.h>
 #include "regs-iis.h"
 
index 704460a3700541bcc28984cd522086efeb85935c..06ebdc061770d546ad997d9f301b4ee3706d77ed 100644 (file)
@@ -24,6 +24,7 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 
+#include <mach/gpio-samsung.h>
 #include "regs-iis.h"
 #include <asm/mach-types.h>
 
index fefc56100349d5c6c8d8c4a5015eebed545779ac..79e7efb9283cbf740e23b7310750bb4e0f2771f4 100644 (file)
@@ -729,7 +729,7 @@ int s3c_i2sv2_register_component(struct device *dev, int id,
                           struct snd_soc_component_driver *cmp_drv,
                           struct snd_soc_dai_driver *dai_drv)
 {
-       struct snd_soc_dai_ops *ops = drv->ops;
+       struct snd_soc_dai_ops *ops = dai_drv->ops;
 
        ops->trigger = s3c2412_i2s_trigger;
        if (!ops->hw_params)
@@ -742,8 +742,8 @@ int s3c_i2sv2_register_component(struct device *dev, int id,
        if (!ops->delay)
                ops->delay = s3c2412_i2s_delay;
 
-       drv->suspend = s3c2412_i2s_suspend;
-       drv->resume = s3c2412_i2s_resume;
+       dai_drv->suspend = s3c2412_i2s_suspend;
+       dai_drv->resume = s3c2412_i2s_resume;
 
        return snd_soc_register_component(dev, cmp_drv, dai_drv, 1);
 }
index ea885cb9f76c300645228a9b9daa75e81a560d82..d0794458963a6ad8de279eaae568a3bd95a32836 100644 (file)
@@ -26,6 +26,8 @@
 #include <sound/pcm_params.h>
 
 #include <mach/dma.h>
+#include <mach/gpio-samsung.h>
+#include <plat/gpio-cfg.h>
 
 #include "dma.h"
 #include "regs-i2s-v2.h"
index 9c8ebd872fac2ac67bcaecae2aca1c9e0a051e3b..f31e916dd8c4f78d394efc387f7f6f8ade83fdfd 100644 (file)
@@ -24,6 +24,8 @@
 #include <sound/pcm_params.h>
 
 #include <mach/dma.h>
+#include <mach/gpio-samsung.h>
+#include <plat/gpio-cfg.h>
 #include "regs-iis.h"
 
 #include "dma.h"
index 58ae3237ef6945c0f4e29f890ad5ddc8bd526fac..c3b2adafb7b552900b30583dd83dc65d1eefccd6 100644 (file)
@@ -19,6 +19,7 @@
 #include <sound/soc.h>
 #include <sound/jack.h>
 
+#include <mach/gpio-samsung.h>
 #include <asm/mach-types.h>
 
 #include "i2s.h"
index b072bd107b3150f8ca7e013e5190bfc285d78c4e..d38ae98e2f32c27e0118ee21c3685f2d4c95fb9d 100644 (file)
@@ -152,13 +152,11 @@ static struct snd_soc_card smdk = {
        .num_links = ARRAY_SIZE(smdk_dai),
 };
 
-#ifdef CONFIG_OF
 static const struct of_device_id samsung_wm8994_of_match[] = {
        { .compatible = "samsung,smdk-wm8994", .data = &smdk_board_data },
        {},
 };
 MODULE_DEVICE_TABLE(of, samsung_wm8994_of_match);
-#endif /* CONFIG_OF */
 
 static int smdk_audio_probe(struct platform_device *pdev)
 {
@@ -188,7 +186,7 @@ static int smdk_audio_probe(struct platform_device *pdev)
                smdk_dai[0].platform_of_node = smdk_dai[0].cpu_of_node;
        }
 
-       id = of_match_device(samsung_wm8994_of_match, &pdev->dev);
+       id = of_match_device(of_match_ptr(samsung_wm8994_of_match), &pdev->dev);
        if (id)
                *board = *((struct smdk_wm8994_data *)id->data);